From 81fe41fd2b53713cf4be39f5da1bd83470cb3388 Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Tue, 7 May 2024 16:45:24 +0200 Subject: [PATCH 01/38] Renderstate rewrite, and moving biomes to datapacks, mc-version and vanilla-resources and resource-extensions rewrite (wip) --- .../bluemap/common/BlueMapConfiguration.java | 5 +- .../bluemap/common/BlueMapService.java | 221 ++++++----- .../bluemap/common/api/RenderManagerImpl.java | 4 +- .../common/config/BlueMapConfigManager.java | 17 +- .../common/config/storage/Dialect.java | 19 +- .../common/config/storage/FileConfig.java | 3 +- .../common/config/storage/SQLConfig.java | 20 +- .../bluemap/common/plugin/Plugin.java | 32 +- .../common/plugin/RegionFileWatchService.java | 6 +- .../common/plugin/commands/Commands.java | 141 +++++-- .../rendermanager/CombinedRenderTask.java | 6 +- .../common/rendermanager/MapPurgeTask.java | 22 +- .../common/rendermanager/MapUpdateTask.java | 72 ++-- .../common/rendermanager/RenderManager.java | 18 +- .../rendermanager/WorldRegionRenderTask.java | 369 ++++++++++++------ .../common/serverinterface/Server.java | 4 +- .../common/web/LoggingRequestHandler.java | 2 + .../common/web/RoutingRequestHandler.java | 36 +- .../bluemap/common/web/http/HttpServer.java | 9 +- .../common/web/http/HttpStatusCode.java | 12 +- .../de/bluecolored/bluemap/config/core.conf | 2 +- .../bluemap/config/storages/file.conf | 8 +- .../bluemap/config/storages/sql.conf | 2 + BlueMapCommon/webapp/public/sql.php | 147 ++++--- BlueMapCore/build.gradle.kts | 2 +- .../bluemap/core/MinecraftVersion.java | 181 --------- .../bluecolored/bluemap/core/map/BmMap.java | 118 +++--- .../bluemap/core/map/MapRenderState.java | 119 ------ .../bluemap/core/map/TextureGallery.java | 4 +- .../core/map/hires/HiresModelManager.java | 20 +- .../core/map/hires/HiresModelRenderer.java | 6 +- .../core/map/hires/RenderSettings.java | 24 +- .../blockmodel/BlockStateModelFactory.java | 6 +- .../hires/blockmodel/LiquidModelBuilder.java | 12 +- .../blockmodel/ResourceModelBuilder.java | 12 +- .../core/map/renderstate/CellStorage.java | 116 ++++++ .../core/map/renderstate/ChunkInfoRegion.java | 55 +++ .../renderstate/MapChunkState.java} | 47 +-- .../core/map/renderstate/MapTileState.java | 101 +++++ .../map/renderstate/TileActionResolver.java | 42 ++ .../core/map/renderstate/TileInfoRegion.java | 101 +++++ .../core/map/renderstate/TileState.java | 102 +++++ .../BlockColorCalculatorFactory.java | 58 +-- .../core/resources/MinecraftVersion.java | 245 ++++++++++++ .../bluemap/core/resources/PackMeta.java | 86 ++++ .../core/resources/VersionManifest.java | 133 +++++++ .../adapter/LocalDateTimeAdapter.java | 23 ++ .../core/resources/adapter/ResourcesGson.java | 2 +- .../core/resources/biome/BiomeConfig.java | 90 ----- .../resources/biome/BiomeConfigEntry.java | 70 ---- .../biome/datapack/DpBiomeEffects.java | 39 -- .../bluemap/core/resources/pack/Pack.java | 125 ++++++ .../{ => pack}/datapack/DataPack.java | 108 +++-- .../pack/datapack/biome/DatapackBiome.java | 61 +++ .../datapack/dimension/DimensionTypeData.java | 2 +- .../{ => pack}/resourcepack/ResourcePack.java | 275 ++++--------- .../resourcepack/blockmodel/BlockModel.java | 6 +- .../resourcepack/blockmodel/Element.java | 4 +- .../resourcepack/blockmodel/Face.java | 4 +- .../resourcepack/blockmodel/Rotation.java | 2 +- .../blockmodel/TextureVariable.java | 6 +- .../resourcepack/blockstate/BlockState.java | 2 +- .../blockstate/BlockStateCondition.java | 2 +- .../resourcepack/blockstate/Multipart.java | 2 +- .../resourcepack/blockstate/Variant.java | 6 +- .../resourcepack/blockstate/VariantSet.java | 2 +- .../resourcepack/blockstate/Variants.java | 2 +- .../resourcepack/texture/AnimationMeta.java | 2 +- .../resourcepack/texture/Texture.java | 2 +- .../bluemap/core/storage/GridStorage.java | 7 +- ...ingleItemStorage.java => ItemStorage.java} | 2 +- .../bluemap/core/storage/KeyedMapStorage.java | 77 ++++ .../bluemap/core/storage/MapStorage.java | 29 +- .../bluemap/core/storage/Storage.java | 5 +- .../compression/CompressedInputStream.java | 8 + ...dGridStorage.java => FileGridStorage.java} | 95 ++--- .../core/storage/file/FileItemStorage.java | 61 +++ .../core/storage/file/FileMapStorage.java | 157 +++++--- .../core/storage/file/FileStorage.java | 4 +- .../storage/file/PathBasedMapStorage.java | 126 ------ .../bluemap/core/storage/sql/Database.java | 1 + ...QLTileStorage.java => SQLGridStorage.java} | 23 +- ...taItemStorage.java => SQLItemStorage.java} | 17 +- .../core/storage/sql/SQLMapStorage.java | 97 +---- .../sql/commandset/AbstractCommandSet.java | 318 +++++++++------ .../storage/sql/commandset/CommandSet.java | 41 +- .../sql/commandset/MySQLCommandSet.java | 276 +++++++------ .../sql/commandset/PostgreSQLCommandSet.java | 282 +++++++------ .../sql/commandset/SqliteCommandSet.java | 280 +++++++------ .../bluemap/core/util/BiIntConsumer.java | 8 + .../bluemap/core/util/FileHelper.java | 11 +- .../bluecolored/bluemap/core/util/Grid.java | 32 +- .../bluecolored/bluemap/core/util/Lazy.java | 12 +- .../core/util/PalettedArrayAdapter.java | 75 ++++ .../bluemap/core/util/Registry.java | 23 +- .../bluemap/core/util/RegistryAdapter.java | 39 ++ .../bluecolored/bluemap/core/world/Biome.java | 68 +--- .../bluecolored/bluemap/core/world/Chunk.java | 8 +- .../bluemap/core/world/ChunkConsumer.java | 6 +- .../bluemap/core/world/Region.java | 4 +- .../bluecolored/bluemap/core/world/World.java | 7 +- .../bluemap/core/world/block/Block.java | 23 +- .../core/world/block/BlockNeighborhood.java | 2 +- .../core/world/block/ExtendedBlock.java | 13 +- .../bluemap/core/world/mca/MCAWorld.java | 54 ++- .../core/world/mca/chunk/Chunk_1_13.java | 8 +- .../core/world/mca/chunk/Chunk_1_15.java | 7 +- .../core/world/mca/chunk/Chunk_1_16.java | 7 +- .../core/world/mca/chunk/Chunk_1_18.java | 26 +- .../core/world/mca/chunk/LegacyBiomes.java | 174 +++++---- .../core/world/mca/chunk/MCAChunk.java | 3 +- .../core/world/mca/data/KeyDeserializer.java | 2 +- .../core/world/mca/region/LinearRegion.java | 4 +- .../core/world/mca/region/MCARegion.java | 26 +- .../core/world/mca/region/RegionType.java | 84 ++-- build.gradle.kts | 9 +- .../bluecolored/bluemap/cli/BlueMapCLI.java | 39 +- .../bluecolored/bluemap/fabric/FabricMod.java | 8 +- .../bluecolored/bluemap/fabric/FabricMod.java | 11 +- .../bluecolored/bluemap/fabric/FabricMod.java | 11 +- .../bluecolored/bluemap/forge/ForgeMod.java | 8 +- .../bluecolored/bluemap/forge/ForgeMod.java | 9 +- .../bluecolored/bluemap/forge/ForgeMod.java | 11 +- .../bluecolored/bluemap/forge/ForgeMod.java | 9 +- .../bluemap/bukkit/BukkitPlayer.java | 11 +- .../bluemap/bukkit/BukkitPlugin.java | 22 +- .../bluemap/bukkit/BukkitWorld.java | 2 +- .../bluemap/bukkit/BukkitPlugin.java | 15 +- .../bluemap/bukkit/BukkitWorld.java | 2 +- .../bluemap/sponge/SpongePlugin.java | 15 +- .../bluemap/sponge/SpongeWorld.java | 2 +- 131 files changed, 3759 insertions(+), 2661 deletions(-) delete mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/MinecraftVersion.java delete mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/MapRenderState.java create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/CellStorage.java create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/ChunkInfoRegion.java rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/{resources/biome/datapack/DpBiome.java => map/renderstate/MapChunkState.java} (64%) create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/MapTileState.java create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileActionResolver.java create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileInfoRegion.java create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileState.java create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/MinecraftVersion.java create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/PackMeta.java create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/VersionManifest.java create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/LocalDateTimeAdapter.java delete mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/biome/BiomeConfig.java delete mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/biome/BiomeConfigEntry.java delete mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/biome/datapack/DpBiomeEffects.java create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/Pack.java rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/{ => pack}/datapack/DataPack.java (57%) create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/biome/DatapackBiome.java rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/{ => pack}/datapack/dimension/DimensionTypeData.java (96%) rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/{ => pack}/resourcepack/ResourcePack.java (68%) rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/{ => pack}/resourcepack/blockmodel/BlockModel.java (95%) rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/{ => pack}/resourcepack/blockmodel/Element.java (97%) rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/{ => pack}/resourcepack/blockmodel/Face.java (95%) rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/{ => pack}/resourcepack/blockmodel/Rotation.java (98%) rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/{ => pack}/resourcepack/blockmodel/TextureVariable.java (95%) rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/{ => pack}/resourcepack/blockstate/BlockState.java (96%) rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/{ => pack}/resourcepack/blockstate/BlockStateCondition.java (98%) rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/{ => pack}/resourcepack/blockstate/Multipart.java (98%) rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/{ => pack}/resourcepack/blockstate/Variant.java (92%) rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/{ => pack}/resourcepack/blockstate/VariantSet.java (98%) rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/{ => pack}/resourcepack/blockstate/Variants.java (98%) rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/{ => pack}/resourcepack/texture/AnimationMeta.java (98%) rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/{ => pack}/resourcepack/texture/Texture.java (98%) rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/{SingleItemStorage.java => ItemStorage.java} (98%) create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/KeyedMapStorage.java rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/{PathBasedGridStorage.java => FileGridStorage.java} (67%) create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/FileItemStorage.java delete mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/PathBasedMapStorage.java rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/{SQLTileStorage.java => SQLGridStorage.java} (81%) rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/{SQLMetaItemStorage.java => SQLItemStorage.java} (84%) create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/BiIntConsumer.java create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/PalettedArrayAdapter.java create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/RegistryAdapter.java diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapConfiguration.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapConfiguration.java index 514063855..c51af95af 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapConfiguration.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapConfiguration.java @@ -26,7 +26,6 @@ import de.bluecolored.bluemap.common.config.*; import de.bluecolored.bluemap.common.config.storage.StorageConfig; -import de.bluecolored.bluemap.core.MinecraftVersion; import org.jetbrains.annotations.Nullable; import java.nio.file.Path; @@ -34,7 +33,7 @@ public interface BlueMapConfiguration { - MinecraftVersion getMinecraftVersion(); + @Nullable String getMinecraftVersion(); CoreConfig getCoreConfig(); @@ -48,7 +47,7 @@ public interface BlueMapConfiguration { Map getStorageConfigs(); - @Nullable Path getResourcePacksFolder(); + @Nullable Path getPacksFolder(); @Nullable Path getModsFolder(); diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapService.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapService.java index 9a05c83dd..0ab90b724 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapService.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapService.java @@ -36,12 +36,13 @@ import de.bluecolored.bluemap.common.config.MapConfig; import de.bluecolored.bluemap.common.config.storage.StorageConfig; import de.bluecolored.bluemap.common.plugin.Plugin; -import de.bluecolored.bluemap.core.MinecraftVersion; import de.bluecolored.bluemap.core.debug.StateDumper; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.map.BmMap; -import de.bluecolored.bluemap.core.resources.datapack.DataPack; -import de.bluecolored.bluemap.core.resources.resourcepack.ResourcePack; +import de.bluecolored.bluemap.core.resources.MinecraftVersion; +import de.bluecolored.bluemap.core.resources.VersionManifest; +import de.bluecolored.bluemap.core.resources.pack.datapack.DataPack; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; import de.bluecolored.bluemap.core.storage.Storage; import de.bluecolored.bluemap.core.util.FileHelper; import de.bluecolored.bluemap.core.util.Key; @@ -74,6 +75,7 @@ public class BlueMapService implements Closeable { private final BlueMapConfiguration config; private final WebFilesManager webFilesManager; + private MinecraftVersion minecraftVersion; private ResourcePack resourcePack; private final Map worlds; private final Map maps; @@ -225,7 +227,7 @@ private synchronized void loadMap(String id, MapConfig mapConfig) throws Configu if (world == null) { try { Logger.global.logDebug("Loading world " + worldId + " ..."); - world = MCAWorld.load(worldFolder, dimension); + world = MCAWorld.load(worldFolder, dimension, loadDataPack(worldFolder)); worlds.put(worldId, world); } catch (IOException ex) { throw new ConfigurationException( @@ -320,129 +322,146 @@ public synchronized Storage getOrLoadStorage(String storageId) throws Configurat public synchronized ResourcePack getOrLoadResourcePack() throws ConfigurationException, InterruptedException { if (resourcePack == null) { - MinecraftVersion minecraftVersion = config.getMinecraftVersion(); - @Nullable Path resourcePackFolder = config.getResourcePacksFolder(); - @Nullable Path modsFolder = config.getModsFolder(); - - Path defaultResourceFile = config.getCoreConfig().getData().resolve("minecraft-client-" + minecraftVersion.getResource().getVersion().getVersionString() + ".jar"); - Path resourceExtensionsFile = config.getCoreConfig().getData().resolve("resourceExtensions.zip"); - - try { - FileHelper.createDirectories(resourcePackFolder); - } catch (IOException ex) { - throw new ConfigurationException( - "BlueMap failed to create this folder:\n" + - resourcePackFolder + "\n" + - "Does BlueMap have sufficient permissions?", - ex); - } + MinecraftVersion minecraftVersion = getOrLoadMinecraftVersion(); + Path vanillaResourcePack = minecraftVersion.getResourcePack(); if (Thread.interrupted()) throw new InterruptedException(); - if (!Files.exists(defaultResourceFile)) { - if (config.getCoreConfig().isAcceptDownload()) { - //download file - try { - Logger.global.logInfo("Downloading " + minecraftVersion.getResource().getClientUrl() + " to " + defaultResourceFile + " ..."); - - FileHelper.createDirectories(defaultResourceFile.getParent()); - Path tempResourceFile = defaultResourceFile.getParent().resolve(defaultResourceFile.getFileName() + ".filepart"); - Files.deleteIfExists(tempResourceFile); - FileUtils.copyURLToFile(new URL(minecraftVersion.getResource().getClientUrl()), tempResourceFile.toFile(), 10000, 10000); - FileHelper.move(tempResourceFile, defaultResourceFile); - } catch (IOException ex) { - throw new ConfigurationException("Failed to download resources!", ex); - } + Deque packRoots = getPackRoots(); + packRoots.addLast(vanillaResourcePack); - } else { - throw new MissingResourcesException(); - } + try { + ResourcePack resourcePack = new ResourcePack(minecraftVersion.getResourcePackVersion()); + resourcePack.loadResources(packRoots); + this.resourcePack = resourcePack; + } catch (IOException | RuntimeException e) { + throw new ConfigurationException("Failed to parse resources!\n" + + "Is one of your resource-packs corrupted?", e); } + } - if (Thread.interrupted()) throw new InterruptedException(); + return this.resourcePack; + } - try { - Files.deleteIfExists(resourceExtensionsFile); - FileHelper.createDirectories(resourceExtensionsFile.getParent()); - URL resourceExtensionsUrl = Objects.requireNonNull( - Plugin.class.getResource( - "/de/bluecolored/bluemap/" + minecraftVersion.getResource().getResourcePrefix() + - "/resourceExtensions.zip") - ); - FileUtils.copyURLToFile(resourceExtensionsUrl, resourceExtensionsFile.toFile(), 10000, 10000); - } catch (IOException ex) { - throw new ConfigurationException( - "Failed to create resourceExtensions.zip!\n" + - "Does BlueMap has sufficient write permissions?", - ex); - } + public synchronized DataPack loadDataPack(Path worldFolder) throws ConfigurationException, InterruptedException { + MinecraftVersion minecraftVersion = getOrLoadMinecraftVersion(); + Path vanillaDataPack = minecraftVersion.getDataPack(); - if (Thread.interrupted()) throw new InterruptedException(); + if (Thread.interrupted()) throw new InterruptedException(); - try { - ResourcePack resourcePack = new ResourcePack(); + // also load world datapacks + Iterable worldPacks = List.of(); + Path worldPacksFolder = worldFolder.resolve("datapacks"); + if (Files.isDirectory(worldPacksFolder)) { + try (Stream worldPacksStream = Files.list(worldPacksFolder)) { + worldPacks = worldPacksStream.toList(); + } catch (IOException e) { + throw new ConfigurationException("Failed to access the worlds datapacks folder.", e); + } + } - List resourcePackRoots = new ArrayList<>(); + Deque packRoots = getPackRoots(worldPacks); + packRoots.addLast(vanillaDataPack); - if (resourcePackFolder != null) { - // load from resourcepack folder - try (Stream resourcepackFiles = Files.list(resourcePackFolder)) { - resourcepackFiles - .sorted(Comparator.reverseOrder()) - .forEach(resourcePackRoots::add); - } - } + try { + DataPack datapack = new DataPack(minecraftVersion.getDataPackVersion()); + datapack.loadResources(packRoots); + return datapack; + } catch (IOException | RuntimeException e) { + throw new ConfigurationException("Failed to parse resources!\n" + + "Is one of your resource-packs corrupted?", e); + } + } - if (config.getCoreConfig().isScanForModResources()) { + private synchronized Deque getPackRoots(Path... additionalRoots) throws ConfigurationException, InterruptedException { + return getPackRoots(List.of(additionalRoots)); + } - // load from mods folder - if (modsFolder != null && Files.isDirectory(modsFolder)) { - try (Stream resourcepackFiles = Files.list(modsFolder)) { - resourcepackFiles - .filter(Files::isRegularFile) - .filter(file -> file.getFileName().toString().endsWith(".jar")) - .forEach(resourcePackRoots::add); - } - } + private synchronized Deque getPackRoots(Iterable additionalRoots) throws ConfigurationException, InterruptedException { + @Nullable Path packsFolder = config.getPacksFolder(); + @Nullable Path modsFolder = config.getModsFolder(); - // load from datapacks - for (Path worldFolder : getWorldFolders()) { - Path datapacksFolder = worldFolder.resolve("datapacks"); - if (!Files.isDirectory(datapacksFolder)) continue; + try { + FileHelper.createDirectories(packsFolder); + } catch (IOException ex) { + throw new ConfigurationException( + "BlueMap failed to create this folder:\n" + + packsFolder + "\n" + + "Does BlueMap have sufficient permissions?", + ex); + } - try (Stream resourcepackFiles = Files.list(worldFolder.resolve("datapacks"))) { - resourcepackFiles.forEach(resourcePackRoots::add); - } - } + Path resourceExtensionsFile = config.getCoreConfig().getData().resolve("resourceExtensions.zip"); - } + if (Thread.interrupted()) throw new InterruptedException(); + + try { + Files.deleteIfExists(resourceExtensionsFile); + FileHelper.createDirectories(resourceExtensionsFile.getParent()); + URL resourceExtensionsUrl = Objects.requireNonNull( + Plugin.class.getResource("/de/bluecolored/bluemap/resourceExtensions.zip") + ); + FileUtils.copyURLToFile(resourceExtensionsUrl, resourceExtensionsFile.toFile(), 10000, 10000); + } catch (IOException ex) { + throw new ConfigurationException( + "Failed to create resourceExtensions.zip!\n" + + "Does BlueMap has sufficient write permissions?", + ex); + } - resourcePackRoots.add(resourceExtensionsFile); - resourcePackRoots.add(defaultResourceFile); + Deque packRoots = new LinkedList<>(); - resourcePack.loadResources(resourcePackRoots); + // load from pack folder + if (packsFolder != null && Files.isDirectory(packsFolder)) { + try (Stream packFiles = Files.list(packsFolder)) { + packFiles + .sorted(Comparator.reverseOrder()) + .forEach(packRoots::add); + } catch (IOException e) { + throw new ConfigurationException("Failed to access packs folder.", e); + } + } - this.resourcePack = resourcePack; - } catch (IOException | RuntimeException e) { - throw new ConfigurationException("Failed to parse resources!\n" + - "Is one of your resource-packs corrupted?", e); + // add additional roots + additionalRoots.forEach(packRoots::add); + + // load from mods folder + if (config.getCoreConfig().isScanForModResources() && modsFolder != null && Files.isDirectory(modsFolder)) { + try (Stream packFiles = Files.list(modsFolder)) { + packFiles + .filter(Files::isRegularFile) + .filter(file -> file.getFileName().toString().endsWith(".jar")) + .forEach(packRoots::add); + } catch (IOException e) { + throw new ConfigurationException("Failed to access packs folder.", e); } } - return this.resourcePack; + packRoots.add(resourceExtensionsFile); + return packRoots; } - private Collection getWorldFolders() { - Set folders = new HashSet<>(); - for (MapConfig mapConfig : config.getMapConfigs().values()) { - Path folder = mapConfig.getWorld(); - if (folder == null) continue; - folder = folder.toAbsolutePath().normalize(); - if (Files.isDirectory(folder)) { - folders.add(folder); + public synchronized MinecraftVersion getOrLoadMinecraftVersion() throws ConfigurationException { + if (this.minecraftVersion == null) { + try { + this.minecraftVersion = MinecraftVersion.load( + config.getMinecraftVersion(), + config.getCoreConfig().getData(), + config.getCoreConfig().isAcceptDownload() + ); + } catch (IOException ex) { + if (!config.getCoreConfig().isAcceptDownload()) { + throw new MissingResourcesException(); + } else { + throw new ConfigurationException(""" + BlueMap was not able to download some important resources! + Make sure BlueMap is able to connect to mojang-servers (%s).""" + .formatted(VersionManifest.DOMAIN), ex); + } } } - return folders; + + return this.minecraftVersion; } public BlueMapConfiguration getConfig() { diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/RenderManagerImpl.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/RenderManagerImpl.java index e56d53f20..69703f274 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/RenderManagerImpl.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/RenderManagerImpl.java @@ -49,13 +49,13 @@ public RenderManagerImpl(BlueMapAPIImpl api, Plugin plugin) { @Override public boolean scheduleMapUpdateTask(BlueMapMap map, boolean force) { BlueMapMapImpl cmap = castMap(map); - return renderManager.scheduleRenderTask(new MapUpdateTask(cmap.getBmMap(), force)); + return renderManager.scheduleRenderTask(new MapUpdateTask(cmap.getBmMap(), s -> force)); } @Override public boolean scheduleMapUpdateTask(BlueMapMap map, Collection regions, boolean force) { BlueMapMapImpl cmap = castMap(map); - return renderManager.scheduleRenderTask(new MapUpdateTask(cmap.getBmMap(), regions, force)); + return renderManager.scheduleRenderTask(new MapUpdateTask(cmap.getBmMap(), regions, s -> force)); } @Override diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigManager.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigManager.java index eed564cd9..aec0deb7c 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigManager.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigManager.java @@ -29,9 +29,8 @@ import de.bluecolored.bluemap.common.config.storage.StorageConfig; import de.bluecolored.bluemap.common.serverinterface.ServerWorld; import de.bluecolored.bluemap.core.BlueMap; -import de.bluecolored.bluemap.core.MinecraftVersion; import de.bluecolored.bluemap.core.logger.Logger; -import de.bluecolored.bluemap.core.resources.datapack.DataPack; +import de.bluecolored.bluemap.core.resources.pack.datapack.DataPack; import de.bluecolored.bluemap.core.util.FileHelper; import de.bluecolored.bluemap.core.util.Key; import lombok.Builder; @@ -51,26 +50,26 @@ public class BlueMapConfigManager implements BlueMapConfiguration { private final ConfigManager configManager; - private final MinecraftVersion minecraftVersion; private final CoreConfig coreConfig; private final WebserverConfig webserverConfig; private final WebappConfig webappConfig; private final PluginConfig pluginConfig; private final Map mapConfigs; private final Map storageConfigs; - private final Path resourcePacksFolder; + private final Path packsFolder; + private final @Nullable String minecraftVersion; private final @Nullable Path modsFolder; @Builder private BlueMapConfigManager( - @NonNull MinecraftVersion minecraftVersion, @NonNull Path configRoot, + @Nullable String minecraftVersion, @Nullable Path defaultDataFolder, @Nullable Path defaultWebroot, @Nullable Collection autoConfigWorlds, @Nullable Boolean usePluginConfig, @Nullable Boolean useMetricsConfig, - @Nullable Path resourcePacksFolder, + @Nullable Path packsFolder, @Nullable Path modsFolder ) throws ConfigurationException { // set defaults @@ -79,10 +78,9 @@ private BlueMapConfigManager( if (autoConfigWorlds == null) autoConfigWorlds = Collections.emptyList(); if (usePluginConfig == null) usePluginConfig = true; if (useMetricsConfig == null) useMetricsConfig = true; - if (resourcePacksFolder == null) resourcePacksFolder = configRoot.resolve("resourcepacks"); + if (packsFolder == null) packsFolder = configRoot.resolve("packs"); // load - this.minecraftVersion = minecraftVersion; this.configManager = new ConfigManager(configRoot); this.coreConfig = loadCoreConfig(defaultDataFolder, useMetricsConfig); this.webappConfig = loadWebappConfig(defaultWebroot); @@ -90,7 +88,8 @@ private BlueMapConfigManager( this.pluginConfig = usePluginConfig ? loadPluginConfig() : new PluginConfig(); this.storageConfigs = Collections.unmodifiableMap(loadStorageConfigs(webappConfig.getWebroot())); this.mapConfigs = Collections.unmodifiableMap(loadMapConfigs(autoConfigWorlds)); - this.resourcePacksFolder = resourcePacksFolder; + this.packsFolder = packsFolder; + this.minecraftVersion = minecraftVersion; this.modsFolder = modsFolder; } diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/Dialect.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/Dialect.java index 92539a7ae..1aadf3be1 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/Dialect.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/Dialect.java @@ -39,10 +39,10 @@ public interface Dialect extends Keyed { - Dialect MYSQL = new Impl(Key.bluemap("mysql"), MySQLCommandSet::new); - Dialect MARIADB = new Impl(Key.bluemap("mariadb"), MySQLCommandSet::new); - Dialect POSTGRESQL = new Impl(Key.bluemap("postgresql"), PostgreSQLCommandSet::new); - Dialect SQLITE = new Impl(Key.bluemap("sqlite"), SqliteCommandSet::new); + Dialect MYSQL = new Impl(Key.bluemap("mysql"), "jdbc:mysql:", MySQLCommandSet::new); + Dialect MARIADB = new Impl(Key.bluemap("mariadb"), "jdbc:mariadb:", MySQLCommandSet::new); + Dialect POSTGRESQL = new Impl(Key.bluemap("postgresql"), "jdbc:postgresql:", PostgreSQLCommandSet::new); + Dialect SQLITE = new Impl(Key.bluemap("sqlite"), "jdbc:sqlite:", SqliteCommandSet::new); Registry REGISTRY = new Registry<>( MYSQL, @@ -51,16 +51,23 @@ public interface Dialect extends Keyed { SQLITE ); + boolean supports(String connectionUrl); + CommandSet createCommandSet(Database database); @RequiredArgsConstructor class Impl implements Dialect { - @Getter - private final Key key; + @Getter private final Key key; + private final String protocol; private final Function commandSetProvider; + @Override + public boolean supports(String connectionUrl) { + return connectionUrl.startsWith(protocol); + } + @Override public CommandSet createCommandSet(Database database) { return commandSetProvider.apply(database); diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/FileConfig.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/FileConfig.java index e4a4f1b5b..5065504fa 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/FileConfig.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/FileConfig.java @@ -41,6 +41,7 @@ public class FileConfig extends StorageConfig { private Path root = Path.of("bluemap", "web", "maps"); private String compression = Compression.GZIP.getKey().getFormatted(); + private boolean atomic = true; public Compression getCompression() throws ConfigurationException { return parseKey(Compression.REGISTRY, compression, "compression"); @@ -48,7 +49,7 @@ public Compression getCompression() throws ConfigurationException { @Override public FileStorage createStorage() throws ConfigurationException { - return new FileStorage(root, getCompression()); + return new FileStorage(root, getCompression(), atomic); } } diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLConfig.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLConfig.java index 9dd7e8a82..68de7b2de 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLConfig.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLConfig.java @@ -30,7 +30,6 @@ import de.bluecolored.bluemap.core.storage.sql.Database; import de.bluecolored.bluemap.core.storage.sql.SQLStorage; import de.bluecolored.bluemap.core.storage.sql.commandset.CommandSet; -import de.bluecolored.bluemap.core.util.Key; import lombok.AccessLevel; import lombok.Getter; import org.jetbrains.annotations.Nullable; @@ -46,16 +45,12 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"}) @ConfigSerializable @Getter public class SQLConfig extends StorageConfig { - private static final Pattern URL_DIALECT_PATTERN = Pattern.compile("jdbc:([^:]*):.*"); - private String connectionUrl = "jdbc:mysql://localhost/bluemap?permitMysqlScheme"; private Map connectionProperties = new HashMap<>(); @DebugDump private String dialect = null; @@ -101,14 +96,17 @@ public Dialect getDialect() throws ConfigurationException { // default from connection-url if (key == null) { - Matcher matcher = URL_DIALECT_PATTERN.matcher(connectionUrl); - if (!matcher.find()) { - throw new ConfigurationException(""" - Failed to parse the provided connection-url! + for (Dialect d : Dialect.REGISTRY.values()) { + if (d.supports(connectionUrl)) { + key = d.getKey().getFormatted(); + break; + } + } + + if (key == null) throw new ConfigurationException(""" + Could not find any sql-dialect that is matching the given connection-url. Please check your 'connection-url' setting in your configuration and make sure it is in the correct format. """.strip()); - } - key = Key.bluemap(matcher.group(1)).getFormatted(); } return parseKey(Dialect.REGISTRY, key, "dialect"); diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java index cabbc475f..822e8944b 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java @@ -44,7 +44,8 @@ import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.map.BmMap; import de.bluecolored.bluemap.core.metrics.Metrics; -import de.bluecolored.bluemap.core.resources.resourcepack.ResourcePack; +import de.bluecolored.bluemap.core.resources.MinecraftVersion; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; import de.bluecolored.bluemap.core.storage.Storage; import de.bluecolored.bluemap.core.util.FileHelper; import de.bluecolored.bluemap.core.util.Tristate; @@ -124,7 +125,7 @@ private void load(@Nullable ResourcePack preloadedResourcePack) throws IOExcepti BlueMapConfigManager configManager = BlueMapConfigManager.builder() .minecraftVersion(serverInterface.getMinecraftVersion()) .configRoot(serverInterface.getConfigFolder()) - .resourcePacksFolder(serverInterface.getConfigFolder().resolve("resourcepacks")) + .packsFolder(serverInterface.getConfigFolder().resolve("packs")) .modsFolder(serverInterface.getModsFolder().orElse(null)) .useMetricsConfig(serverInterface.isMetricsEnabled() == Tristate.UNDEFINED) .autoConfigWorlds(serverInterface.getLoadedServerWorlds()) @@ -287,7 +288,7 @@ public void run() { save(); } }; - daemonTimer.schedule(saveTask, TimeUnit.MINUTES.toMillis(2), TimeUnit.MINUTES.toMillis(2)); + daemonTimer.schedule(saveTask, TimeUnit.MINUTES.toMillis(10), TimeUnit.MINUTES.toMillis(10)); //periodically save markers int writeMarkersInterval = pluginConfig.getWriteMarkersInterval(); @@ -341,11 +342,12 @@ public void run() { } //metrics + MinecraftVersion minecraftVersion = blueMap.getOrLoadMinecraftVersion(); TimerTask metricsTask = new TimerTask() { @Override public void run() { if (serverInterface.isMetricsEnabled().getOr(coreConfig::isMetrics)) - Metrics.sendReport(implementationType, configManager.getMinecraftVersion().getVersionString()); + Metrics.sendReport(implementationType, minecraftVersion.getId()); } }; daemonTimer.scheduleAtFixedRate(metricsTask, TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(30)); @@ -389,12 +391,11 @@ public void run() { public void unload() { this.unload(false); } + public void unload(boolean keepWebserver) { loadingLock.interruptAndLock(); try { synchronized (this) { - //save - save(); //disable api if (api != null) api.unregister(); @@ -415,8 +416,18 @@ public void unload(boolean keepWebserver) { } regionFileWatchServices = null; - //stop services + // stop render-manager if (renderManager != null){ + if (renderManager.getCurrentRenderTask() != null) { + renderManager.removeAllRenderTasks(); + if (!renderManager.isRunning()) renderManager.start(1); + try { + renderManager.awaitIdle(true); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + renderManager.stop(); try { renderManager.awaitShutdown(); @@ -424,8 +435,11 @@ public void unload(boolean keepWebserver) { Thread.currentThread().interrupt(); } } - renderManager = null; + //save + save(); + + // stop webserver if (webServer != null && !keepWebserver) { try { webServer.close(); @@ -435,7 +449,7 @@ public void unload(boolean keepWebserver) { webServer = null; } - if (webLogger != null) { + if (webLogger != null && !keepWebserver) { try { webLogger.close(); } catch (Exception ex) { diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/RegionFileWatchService.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/RegionFileWatchService.java index 6842addd1..21a7324b2 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/RegionFileWatchService.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/RegionFileWatchService.java @@ -67,7 +67,11 @@ public RegionFileWatchService(RenderManager renderManager, BmMap map) throws IOE FileHelper.createDirectories(folder); this.watchService = folder.getFileSystem().newWatchService(); - folder.register(this.watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY); + folder.register(this.watchService, + StandardWatchEventKinds.ENTRY_CREATE, + StandardWatchEventKinds.ENTRY_MODIFY, + StandardWatchEventKinds.ENTRY_DELETE + ); Logger.global.logDebug("Created region-file watch-service for map '" + map.getId() + "' at '" + folder + "'."); } diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java index 4811a41a1..26a16017e 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java @@ -24,6 +24,7 @@ */ package de.bluecolored.bluemap.common.plugin.commands; +import com.flowpowered.math.vector.Vector2d; import com.flowpowered.math.vector.Vector2i; import com.flowpowered.math.vector.Vector3d; import com.flowpowered.math.vector.Vector3i; @@ -47,14 +48,15 @@ import de.bluecolored.bluemap.common.rendermanager.*; import de.bluecolored.bluemap.common.serverinterface.CommandSource; import de.bluecolored.bluemap.core.BlueMap; -import de.bluecolored.bluemap.core.MinecraftVersion; import de.bluecolored.bluemap.core.debug.StateDumper; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.map.BmMap; -import de.bluecolored.bluemap.core.map.MapRenderState; +import de.bluecolored.bluemap.core.map.renderstate.TileInfoRegion; import de.bluecolored.bluemap.core.storage.MapStorage; import de.bluecolored.bluemap.core.storage.Storage; +import de.bluecolored.bluemap.core.util.Grid; import de.bluecolored.bluemap.core.world.Chunk; +import de.bluecolored.bluemap.core.world.ChunkConsumer; import de.bluecolored.bluemap.core.world.World; import de.bluecolored.bluemap.core.world.block.Block; import de.bluecolored.bluemap.core.world.block.entity.BlockEntity; @@ -123,6 +125,15 @@ public void init() { .then(argument("z", DoubleArgumentType.doubleArg()) .executes(this::debugBlockCommand)))))) + .then(literal("map") + .requires(requirements("bluemap.debug")) + .then(argument("map", StringArgumentType.string()).suggests(new MapSuggestionProvider<>(plugin)) + .executes(this::debugMapCommand) + + .then(argument("x", IntegerArgumentType.integer()) + .then(argument("z", IntegerArgumentType.integer()) + .executes(this::debugMapCommand))))) + .then(literal("flush") .requires(requirements("bluemap.debug")) .executes(this::debugFlushCommand) @@ -329,32 +340,27 @@ public int versionCommand(CommandContext context) { renderThreadCount = plugin.getRenderManager().getWorkerThreadCount(); } - MinecraftVersion minecraftVersion = plugin.getServerInterface().getMinecraftVersion(); + String minecraftVersion = plugin.getServerInterface().getMinecraftVersion(); source.sendMessage(Text.of(TextFormat.BOLD, TextColor.BLUE, "Version: ", TextColor.WHITE, BlueMap.VERSION)); source.sendMessage(Text.of(TextColor.GRAY, "Commit: ", TextColor.WHITE, BlueMap.GIT_HASH)); source.sendMessage(Text.of(TextColor.GRAY, "Implementation: ", TextColor.WHITE, plugin.getImplementationType())); - source.sendMessage(Text.of( - TextColor.GRAY, "Minecraft compatibility: ", TextColor.WHITE, minecraftVersion.getVersionString(), - TextColor.GRAY, " (" + minecraftVersion.getResource().getVersion().getVersionString() + ")" - )); + source.sendMessage(Text.of(TextColor.GRAY, "Minecraft: ", TextColor.WHITE, minecraftVersion)); source.sendMessage(Text.of(TextColor.GRAY, "Render-threads: ", TextColor.WHITE, renderThreadCount)); source.sendMessage(Text.of(TextColor.GRAY, "Available processors: ", TextColor.WHITE, Runtime.getRuntime().availableProcessors())); source.sendMessage(Text.of(TextColor.GRAY, "Available memory: ", TextColor.WHITE, (Runtime.getRuntime().maxMemory() / 1024L / 1024L) + " MiB")); - if (minecraftVersion.isAtLeast(new MinecraftVersion(1, 15))) { - String clipboardValue = - "Version: " + BlueMap.VERSION + "\n" + - "Commit: " + BlueMap.GIT_HASH + "\n" + - "Implementation: " + plugin.getImplementationType() + "\n" + - "Minecraft compatibility: " + minecraftVersion.getVersionString() + " (" + minecraftVersion.getResource().getVersion().getVersionString() + ")\n" + - "Render-threads: " + renderThreadCount + "\n" + - "Available processors: " + Runtime.getRuntime().availableProcessors() + "\n" + - "Available memory: " + Runtime.getRuntime().maxMemory() / 1024L / 1024L + " MiB"; - source.sendMessage(Text.of(TextColor.DARK_GRAY, "[copy to clipboard]") - .setClickAction(Text.ClickAction.COPY_TO_CLIPBOARD, clipboardValue) - .setHoverText(Text.of(TextColor.GRAY, "click to copy the above text .. ", TextFormat.ITALIC, TextColor.GRAY, "duh!"))); - } + String clipboardValue = + "Version: " + BlueMap.VERSION + "\n" + + "Commit: " + BlueMap.GIT_HASH + "\n" + + "Implementation: " + plugin.getImplementationType() + "\n" + + "Minecraft: " + minecraftVersion + "\n" + + "Render-threads: " + renderThreadCount + "\n" + + "Available processors: " + Runtime.getRuntime().availableProcessors() + "\n" + + "Available memory: " + Runtime.getRuntime().maxMemory() / 1024L / 1024L + " MiB"; + source.sendMessage(Text.of(TextColor.DARK_GRAY, "[copy to clipboard]") + .setClickAction(Text.ClickAction.COPY_TO_CLIPBOARD, clipboardValue) + .setHoverText(Text.of(TextColor.GRAY, "click to copy the above text .. ", TextFormat.ITALIC, TextColor.GRAY, "duh!"))); return 1; } @@ -467,6 +473,86 @@ public int debugFlushCommand(CommandContext context) { return 1; } + public int debugMapCommand(CommandContext context) { + final CommandSource source = commandSourceInterface.apply(context.getSource()); + + // parse arguments + String mapId = context.getArgument("map", String.class); + Optional x = getOptionalArgument(context, "x", Integer.class); + Optional z = getOptionalArgument(context, "z", Integer.class); + + final BmMap map = parseMap(mapId).orElse(null); + if (map == null) { + source.sendMessage(Text.of(TextColor.RED, "There is no ", helper.mapHelperHover(), " with this id: ", TextColor.WHITE, mapId)); + return 0; + } + + final Vector2i position; + if (x.isPresent() && z.isPresent()) { + position = new Vector2i(x.get(), z.get()); + } else { + position = source.getPosition() + .map(v -> v.toVector2(true)) + .map(Vector2d::floor) + .map(Vector2d::toInt) + .orElse(null); + + if (position == null) { + source.sendMessage(Text.of(TextColor.RED, "Can't detect a location from this command-source, you'll have to define a position!")); + return 0; + } + } + + new Thread(() -> { + // collect and output debug info + Grid chunkGrid = map.getWorld().getChunkGrid(); + Grid regionGrid = map.getWorld().getRegionGrid(); + Grid tileGrid = map.getHiresModelManager().getTileGrid(); + + Vector2i regionPos = regionGrid.getCell(position); + Vector2i chunkPos = chunkGrid.getCell(position); + Vector2i tilePos = tileGrid.getCell(position); + + TileInfoRegion.TileInfo tileInfo = map.getMapTileState().get(tilePos.getX(), tilePos.getY()); + + int lastChunkHash = map.getMapChunkState().get(chunkPos.getX(), chunkPos.getY()); + int currentChunkHash = 0; + + class FindHashConsumer implements ChunkConsumer.ListOnly { + public int timestamp = 0; + + @Override + public void accept(int chunkX, int chunkZ, int timestamp) { + if (chunkPos.getX() == chunkX && chunkPos.getY() == chunkZ) + this.timestamp = timestamp; + } + } + + try { + FindHashConsumer findHashConsumer = new FindHashConsumer(); + map.getWorld().getRegion(regionPos.getX(), regionPos.getY()) + .iterateAllChunks(findHashConsumer); + currentChunkHash = findHashConsumer.timestamp; + } catch (IOException e) { + Logger.global.logError("Failed to load chunk-hash.", e); + } + + Map lines = new LinkedHashMap<>(); + lines.put("region-pos", regionPos); + lines.put("chunk-pos", chunkPos); + lines.put("chunk-curr-hash", currentChunkHash); + lines.put("chunk-last-hash", lastChunkHash); + lines.put("tile-pos", tilePos); + lines.put("tile-render-time", tileInfo.getRenderTime()); + lines.put("tile-state", tileInfo.getState().getKey().getFormatted()); + + source.sendMessage(Text.of(TextColor.GOLD, "Map tile info:")); + source.sendMessage(formatMap(lines)); + }, "BlueMap-Plugin-DebugMapCommand").start(); + + return 1; + } + public int debugBlockCommand(CommandContext context) { final CommandSource source = commandSourceInterface.apply(context.getSource()); @@ -523,7 +609,7 @@ private Text formatBlock(Block block) { lines.put("chunk-has-lightdata", chunk.hasLightData()); lines.put("chunk-inhabited-time", chunk.getInhabitedTime()); lines.put("block-state", block.getBlockState()); - lines.put("biome", block.getBiomeId()); + lines.put("biome", block.getBiome().getKey()); lines.put("position", block.getX() + " | " + block.getY() + " | " + block.getZ()); lines.put("block-light", block.getBlockLightLevel()); lines.put("sun-light", block.getSunLightLevel()); @@ -533,6 +619,10 @@ private Text formatBlock(Block block) { lines.put("block-entity", blockEntity); } + return formatMap(lines); + } + + private Text formatMap(Map lines) { Object[] textElements = lines.entrySet().stream() .flatMap(e -> Stream.of(TextColor.GRAY, e.getKey(), ": ", TextColor.WHITE, e.getValue(), "\n")) .toArray(Object[]::new); @@ -754,14 +844,9 @@ public int updateCommand(CommandContext context, boolean force) { } for (BmMap map : maps) { - MapUpdateTask updateTask = new MapUpdateTask(map, center, radius); + MapUpdateTask updateTask = new MapUpdateTask(map, center, radius, s -> force); plugin.getRenderManager().scheduleRenderTask(updateTask); - if (force) { - MapRenderState state = map.getRenderState(); - updateTask.getRegions().forEach(region -> state.setRenderTime(region, -1)); - } - source.sendMessage(Text.of(TextColor.GREEN, "Created new Update-Task for map '" + map.getId() + "' ", TextColor.GRAY, "(" + updateTask.getRegions().size() + " regions, ~" + updateTask.getRegions().size() * 1024L + " chunks)")); } @@ -874,7 +959,7 @@ public int mapsCommand(CommandContext context) { lines.add(Text.of(TextColor.GRAY, "\u00A0\u00A0\u00A0World: ", TextColor.DARK_GRAY, map.getWorld().getId())); lines.add(Text.of(TextColor.GRAY, "\u00A0\u00A0\u00A0Last Update: ", - TextColor.DARK_GRAY, helper.formatTime(map.getRenderState().getLatestRenderTime()))); + TextColor.DARK_GRAY, helper.formatTime(map.getMapTileState().getLastRenderTime() * 1000L))); if (frozen) lines.add(Text.of(TextColor.AQUA, TextFormat.ITALIC, "\u00A0\u00A0\u00A0This map is frozen!")); diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/CombinedRenderTask.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/CombinedRenderTask.java index 6a2e89696..f239f60fa 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/CombinedRenderTask.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/CombinedRenderTask.java @@ -84,13 +84,10 @@ public void cancel() { public boolean contains(RenderTask task) { if (this.equals(task)) return true; - if (task instanceof CombinedRenderTask) { - CombinedRenderTask combinedTask = (CombinedRenderTask) task; - + if (task instanceof CombinedRenderTask combinedTask) { for (RenderTask subTask : combinedTask.tasks) { if (!this.contains(subTask)) return false; } - return true; } @@ -111,4 +108,5 @@ public Optional getDetail() { if (this.currentTaskIndex >= this.tasks.size()) return Optional.empty(); return Optional.ofNullable(this.tasks.get(this.currentTaskIndex).getDescription()); } + } diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapPurgeTask.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapPurgeTask.java index 0e9506456..20f6a6911 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapPurgeTask.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapPurgeTask.java @@ -55,19 +55,15 @@ public void doWork() throws Exception { // save lowres-tile-manager to clear/flush any buffered data this.map.getLowresTileManager().save(); - try { - // purge the map - map.getStorage().delete(progress -> { - this.progress = progress; - return !this.cancelled; - }); - - // reset texture gallery - map.resetTextureGallery(); - } finally { - // reset renderstate - map.getRenderState().reset(); - } + // purge the map + map.getStorage().delete(progress -> { + this.progress = progress; + return !this.cancelled; + }); + + map.resetTextureGallery(); + map.getMapTileState().reset(); + map.getMapChunkState().reset(); } @Override diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapUpdateTask.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapUpdateTask.java index 4f19ab214..d5224cddd 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapUpdateTask.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapUpdateTask.java @@ -26,16 +26,18 @@ import com.flowpowered.math.vector.Vector2i; import de.bluecolored.bluemap.api.debug.DebugDump; +import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.map.BmMap; +import de.bluecolored.bluemap.core.map.renderstate.MapTileState; +import de.bluecolored.bluemap.core.map.renderstate.TileState; +import de.bluecolored.bluemap.core.storage.GridStorage; import de.bluecolored.bluemap.core.util.Grid; import de.bluecolored.bluemap.core.world.World; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.io.IOException; +import java.util.*; import java.util.function.Predicate; -import java.util.stream.Collectors; +import java.util.stream.Stream; @DebugDump public class MapUpdateTask extends CombinedRenderTask { @@ -47,7 +49,7 @@ public MapUpdateTask(BmMap map) { this(map, getRegions(map)); } - public MapUpdateTask(BmMap map, boolean force) { + public MapUpdateTask(BmMap map, Predicate force) { this(map, getRegions(map), force); } @@ -55,15 +57,15 @@ public MapUpdateTask(BmMap map, Vector2i center, int radius) { this(map, getRegions(map, center, radius)); } - public MapUpdateTask(BmMap map, Vector2i center, int radius, boolean force) { + public MapUpdateTask(BmMap map, Vector2i center, int radius, Predicate force) { this(map, getRegions(map, center, radius), force); } public MapUpdateTask(BmMap map, Collection regions) { - this(map, regions, false); + this(map, regions, s -> false); } - public MapUpdateTask(BmMap map, Collection regions, boolean force) { + public MapUpdateTask(BmMap map, Collection regions, Predicate force) { super("Update map '" + map.getId() + "'", createTasks(map, regions, force)); this.map = map; this.regions = Collections.unmodifiableCollection(new ArrayList<>(regions)); @@ -77,7 +79,7 @@ public Collection getRegions() { return regions; } - private static Collection createTasks(BmMap map, Collection regions, boolean force) { + private static Collection createTasks(BmMap map, Collection regions, Predicate force) { ArrayList regionTasks = new ArrayList<>(regions.size()); regions.forEach(region -> regionTasks.add(new WorldRegionRenderTask(map, region, force))); @@ -99,33 +101,47 @@ private static Collection createTasks(BmMap map, Collection getRegions(BmMap map) { + private static Collection getRegions(BmMap map) { return getRegions(map, null, -1); } - private static List getRegions(BmMap map, Vector2i center, int radius) { + private static Collection getRegions(BmMap map, Vector2i center, int radius) { World world = map.getWorld(); Grid regionGrid = world.getRegionGrid(); - Predicate regionFilter = map.getMapSettings().getRenderBoundariesCellFilter(regionGrid); + Predicate regionBoundsFilter = map.getMapSettings().getCellRenderBoundariesFilter(regionGrid, true); + Predicate regionRadiusFilter; if (center == null || radius < 0) { - return world.listRegions().stream() - .filter(regionFilter) - .collect(Collectors.toList()); + regionRadiusFilter = r -> true; + } else { + Vector2i halfCell = regionGrid.getGridSize().div(2); + long increasedRadiusSquared = (long) Math.pow(radius + Math.ceil(halfCell.length()), 2); + regionRadiusFilter = r -> { + Vector2i min = regionGrid.getCellMin(r); + Vector2i regionCenter = min.add(halfCell); + return regionCenter.toLong().distanceSquared(center.toLong()) <= increasedRadiusSquared; + }; } - List regions = new ArrayList<>(); - Vector2i halfCell = regionGrid.getGridSize().div(2); - long increasedRadiusSquared = (long) Math.pow(radius + Math.ceil(halfCell.length()), 2); - - for (Vector2i region : world.listRegions()) { - if (!regionFilter.test(region)) continue; - - Vector2i min = regionGrid.getCellMin(region); - Vector2i regionCenter = min.add(halfCell); - - if (regionCenter.toLong().distanceSquared(center.toLong()) <= increasedRadiusSquared) - regions.add(region); + Set regions = new HashSet<>(); + + // update all regions in the world-files + world.listRegions().stream() + .filter(regionBoundsFilter) + .filter(regionRadiusFilter) + .forEach(regions::add); + + // also update regions that are present as map-tile-state files (they might have been rendered before but deleted now) + Grid tileGrid = map.getHiresModelManager().getTileGrid(); + Grid cellGrid = MapTileState.GRID.multiply(tileGrid); + try (Stream stream = map.getStorage().tileState().stream()) { + stream + .map(c -> new Vector2i(c.getX(), c.getZ())) + .flatMap(v -> cellGrid.getIntersecting(v, regionGrid).stream()) + .filter(regionRadiusFilter) + .forEach(regions::add); + } catch (IOException ex) { + Logger.global.logError("Failed to load map tile state!", ex); } return regions; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/RenderManager.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/RenderManager.java index 222a54faf..d5d6112fc 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/RenderManager.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/RenderManager.java @@ -106,9 +106,23 @@ public boolean isRunning() { } public void awaitIdle() throws InterruptedException { + awaitIdle(false); + } + + public void awaitIdle(boolean log) throws InterruptedException { synchronized (this.renderTasks) { - while (!this.renderTasks.isEmpty()) - this.renderTasks.wait(10000); + while (!this.renderTasks.isEmpty()) { + this.renderTasks.wait(5000); + + if (log) { + RenderTask task = this.getCurrentRenderTask(); + if (task != null) { + Logger.global.logInfo("Waiting for task '" + task.getDescription() + "' to stop.. (" + + (Math.round(task.estimateProgress() * 10000) / 100.0) + "%)"); + } + } + + } } } diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/WorldRegionRenderTask.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/WorldRegionRenderTask.java index 5359ef7f5..33f8862a8 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/WorldRegionRenderTask.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/WorldRegionRenderTask.java @@ -29,205 +29,246 @@ import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.map.BmMap; +import de.bluecolored.bluemap.core.map.renderstate.TileActionResolver.ActionAndNextState; +import de.bluecolored.bluemap.core.map.renderstate.TileActionResolver.BoundsSituation; +import de.bluecolored.bluemap.core.map.renderstate.TileInfoRegion; +import de.bluecolored.bluemap.core.map.renderstate.TileState; import de.bluecolored.bluemap.core.util.Grid; import de.bluecolored.bluemap.core.world.Chunk; import de.bluecolored.bluemap.core.world.ChunkConsumer; -import de.bluecolored.bluemap.core.world.Region; +import lombok.Getter; +import org.jetbrains.annotations.Nullable; import java.io.IOException; -import java.util.*; +import java.util.Comparator; +import java.util.concurrent.TimeUnit; import java.util.function.Predicate; -import java.util.stream.Collectors; + +import static de.bluecolored.bluemap.core.map.renderstate.TileActionResolver.Action.DELETE; +import static de.bluecolored.bluemap.core.map.renderstate.TileActionResolver.Action.RENDER; @DebugDump public class WorldRegionRenderTask implements RenderTask { - private final BmMap map; - private final Vector2i worldRegion; - private final boolean force; + @Getter private final BmMap map; + @Getter private final Vector2i regionPos; + @Getter private final Predicate force; + + private Grid regionGrid, chunkGrid, tileGrid; + private Vector2i chunkMin, chunkMax, chunksSize; + private Vector2i tileMin, tileMax, tileSize; - private Deque tiles; - private int tileCount; - private long startTime; + private int[] chunkHashes; + private ActionAndNextState[] tileActions; + private volatile int nextTileX, nextTileZ; private volatile int atWork; - private volatile boolean cancelled; + private volatile boolean completed, cancelled; - public WorldRegionRenderTask(BmMap map, Vector2i worldRegion) { - this(map, worldRegion, false); + public WorldRegionRenderTask(BmMap map, Vector2i regionPos) { + this(map, regionPos, false); } - public WorldRegionRenderTask(BmMap map, Vector2i worldRegion, boolean force) { + public WorldRegionRenderTask(BmMap map, Vector2i regionPos, boolean force) { + this(map, regionPos, s -> force); + } + + public WorldRegionRenderTask(BmMap map, Vector2i regionPos, Predicate force) { this.map = map; - this.worldRegion = worldRegion; + this.regionPos = regionPos; this.force = force; - this.tiles = null; - this.tileCount = -1; - this.startTime = -1; + this.nextTileX = 0; + this.nextTileZ = 0; this.atWork = 0; + this.completed = false; this.cancelled = false; } private synchronized void init() { - Set tileSet = new HashSet<>(); - startTime = System.currentTimeMillis(); - // collect chunks - long changesSince = force ? 0 : map.getRenderState().getRenderTime(worldRegion); - Region region = map.getWorld().getRegion(worldRegion.getX(), worldRegion.getY()); - Collection chunks = new ArrayList<>(1024); + // calculate bounds + this.regionGrid = map.getWorld().getRegionGrid(); + this.chunkGrid = map.getWorld().getChunkGrid(); + this.tileGrid = map.getHiresModelManager().getTileGrid(); + this.chunkMin = regionGrid.getCellMin(regionPos, chunkGrid); + this.chunkMax = regionGrid.getCellMax(regionPos, chunkGrid); + this.chunksSize = chunkMax.sub(chunkMin).add(1, 1); + this.tileMin = regionGrid.getCellMin(regionPos, tileGrid); + this.tileMax = regionGrid.getCellMax(regionPos, tileGrid); + this.tileSize = tileMax.sub(tileMin).add(1, 1); + + // load chunk-hash array + int chunkMaxCount = chunksSize.getX() * chunksSize.getY(); try { - region.iterateAllChunks((ChunkConsumer.ListOnly) (x, z, timestamp) -> { - if (timestamp >= changesSince) chunks.add(new Vector2i(x, z)); - }); + chunkHashes = new int[chunkMaxCount]; + map.getWorld().getRegion(regionPos.getX(), regionPos.getY()) + .iterateAllChunks( (ChunkConsumer.ListOnly) (x, z, timestamp) -> { + chunkHashes[chunkIndex( + x - chunkMin.getX(), + z - chunkMin.getY() + )] = timestamp; + map.getWorld().invalidateChunkCache(x, z); + }); } catch (IOException ex) { - Logger.global.logWarning("Failed to read region " + worldRegion + " from world " + map.getWorld().getName() + " (" + ex + ")"); + Logger.global.logError("Failed to load chunks for region " + regionPos, ex); + cancel(); } - Grid tileGrid = map.getHiresModelManager().getTileGrid(); - Grid chunkGrid = map.getWorld().getChunkGrid(); - Predicate boundsTileFilter = map.getMapSettings().getRenderBoundariesCellFilter(tileGrid); - - for (Vector2i chunk : chunks) { - Vector2i tileMin = chunkGrid.getCellMin(chunk, tileGrid); - Vector2i tileMax = chunkGrid.getCellMax(chunk, tileGrid); - - for (int x = tileMin.getX(); x <= tileMax.getX(); x++) { - for (int z = tileMin.getY(); z <= tileMax.getY(); z++) { - tileSet.add(new Vector2l(x, z)); - } + // check tile actions + int tileMaxCount = tileSize.getX() * tileSize.getY(); + int tileRenderCount = 0; + int tileDeleteCount = 0; + tileActions = new ActionAndNextState[tileMaxCount]; + for (int x = 0; x < tileSize.getX(); x++) { + for (int z = 0; z < tileSize.getY(); z++) { + Vector2i tile = new Vector2i(tileMin.getX() + x, tileMin.getY() + z); + TileState tileState = map.getMapTileState().get(tile.getX(), tile.getY()).getState(); + + int tileIndex = tileIndex(x, z); + tileActions[tileIndex] = tileState.findActionAndNextState( + force.test(tileState) || checkChunksHaveChanges(tile), + checkTileBounds(tile) + ); + + if (tileActions[tileIndex].action() == RENDER) + tileRenderCount++; + if (tileActions[tileIndex].action() == DELETE) + tileDeleteCount++; } - - // make sure chunk gets re-loaded from disk - map.getWorld().invalidateChunkCache(chunk.getX(), chunk.getY()); } - this.tileCount = tileSet.size(); - this.tiles = tileSet.stream() - .sorted(WorldRegionRenderTask::compareVec2L) //sort with longs to avoid overflow (comparison uses distanceSquared) - .map(Vector2l::toInt) // back to ints - .filter(boundsTileFilter) - .filter(map.getTileFilter()) - .collect(Collectors.toCollection(ArrayDeque::new)); - - if (tiles.isEmpty()) complete(); - else { - // preload chunks - map.getWorld().preloadRegionChunks(worldRegion.getX(), worldRegion.getY()); - } + if (tileRenderCount >= tileMaxCount * 0.75) + map.getWorld().preloadRegionChunks(regionPos.getX(), regionPos.getY()); + + if (tileRenderCount + tileDeleteCount == 0) + completed = true; + } @Override public void doWork() { - if (cancelled) return; + if (cancelled || completed) return; - Vector2i tile; + int tileX, tileZ; synchronized (this) { - if (tiles == null) init(); - if (tiles.isEmpty()) return; + if (cancelled || completed) return; - tile = tiles.pollFirst(); + tileX = nextTileX; + tileZ = nextTileZ; + + if (tileX == 0 && tileZ == 0) { + init(); + if (cancelled || completed) return; + } + + nextTileX = tileX + 1; + if (nextTileX >= tileSize.getX()) { + nextTileZ = tileZ + 1; + nextTileX = 0; + } + if (nextTileZ >= tileSize.getY()) { + completed = true; + } this.atWork++; } - if (tileRenderPreconditions(tile)) { - map.renderTile(tile); // <- actual work - } + processTile(tileX, tileZ); synchronized (this) { this.atWork--; - if (atWork <= 0 && tiles.isEmpty() && !cancelled) { + if (atWork <= 0 && completed && !cancelled) { complete(); } } } - private boolean tileRenderPreconditions(Vector2i tile) { - Grid tileGrid = map.getHiresModelManager().getTileGrid(); - Grid chunkGrid = map.getWorld().getChunkGrid(); - - Vector2i minChunk = tileGrid.getCellMin(tile, chunkGrid); - Vector2i maxChunk = tileGrid.getCellMax(tile, chunkGrid); - - long minInhab = map.getMapSettings().getMinInhabitedTime(); - int minInhabRadius = map.getMapSettings().getMinInhabitedTimeRadius(); - if (minInhabRadius < 0) minInhabRadius = 0; - if (minInhabRadius > 16) minInhabRadius = 16; // sanity check - boolean isInhabited = false; - - for (int x = minChunk.getX(); x <= maxChunk.getX(); x++) { - for (int z = minChunk.getY(); z <= maxChunk.getY(); z++) { - Chunk chunk = map.getWorld().getChunk(x, z); - if (!chunk.isGenerated()) return false; - if (!chunk.hasLightData() && !map.getMapSettings().isIgnoreMissingLightData()) return false; - if (chunk.getInhabitedTime() >= minInhab) isInhabited = true; - } - } + private void processTile(int x, int z) { + Vector2i tile = new Vector2i(tileMin.getX() + x, tileMin.getY() + z); + ActionAndNextState action = tileActions[tileIndex(x, z)]; + TileState resultState = TileState.RENDER_ERROR; + + try { + + resultState = switch (action.action()) { + + case NONE -> action.state(); - if (minInhabRadius > 0 && !isInhabited) { - for (int x = minChunk.getX() - minInhabRadius; x <= maxChunk.getX() + minInhabRadius; x++) { - for (int z = minChunk.getY() - minInhabRadius; z <= maxChunk.getY() + minInhabRadius; z++) { - Chunk chunk = map.getWorld().getChunk(x, z); - if (chunk.getInhabitedTime() >= minInhab) { - isInhabited = true; - break; + case RENDER -> { + TileState failedState = checkTileRenderPreconditions(tile); + if (failedState != null){ + map.unrenderTile(tile); + yield failedState; } + + map.renderTile(tile); + yield action.state(); } - } + + case DELETE -> { + map.unrenderTile(tile); + yield action.state(); + } + + }; + + } catch (Exception ex) { + + Logger.global.logError("Error while processing map-tile " + tile + " for map '" + map.getId() + "'", ex); + + } finally { + + // mark tile with new state + map.getMapTileState().set(tile.getX(), tile.getY(), new TileInfoRegion.TileInfo( + (int) (System.currentTimeMillis() / 1000), + resultState + )); + } - return isInhabited; } - private void complete() { - map.getRenderState().setRenderTime(worldRegion, startTime); + private synchronized void complete() { + // save chunk-hashes + if (chunkHashes != null) { + for (int x = 0; x < chunksSize.getX(); x++) { + for (int z = 0; z < chunksSize.getY(); z++) { + int hash = chunkHashes[chunkIndex(x, z)]; + map.getMapChunkState().set(chunkMin.getX() + x, chunkMin.getY() + z, hash); + } + } + chunkHashes = null; + } + + // save map (at most, every minute) + map.save(TimeUnit.MINUTES.toMillis(1)); } @Override @DebugDump public synchronized boolean hasMoreWork() { - return !cancelled && (tiles == null || !tiles.isEmpty()); + return !completed && !cancelled; } @Override @DebugDump public double estimateProgress() { - if (tiles == null) return 0; - if (tileCount == 0) return 1; - - double remainingTiles = tiles.size(); - return 1 - (remainingTiles / this.tileCount); + if (tileSize == null) return 0; + return Math.min((double) (nextTileZ * tileSize.getX() + nextTileX) / (tileSize.getX() * tileSize.getY()), 1); } @Override public void cancel() { this.cancelled = true; - - synchronized (this) { - if (tiles != null) this.tiles.clear(); - } - } - - public BmMap getMap() { - return map; - } - - public Vector2i getWorldRegion() { - return worldRegion; - } - - public boolean isForce() { - return force; } @Override public String getDescription() { - return "Update region " + getWorldRegion() + " for map '" + map.getId() + "'"; + return "Update region " + regionPos + " for map '" + map.getId() + "'"; } @Override @@ -235,19 +276,101 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; WorldRegionRenderTask that = (WorldRegionRenderTask) o; - return force == that.force && map.getId().equals(that.map.getId()) && worldRegion.equals(that.worldRegion); + return force == that.force && map.getId().equals(that.map.getId()) && regionPos.equals(that.regionPos); } @Override public int hashCode() { - return worldRegion.hashCode(); + return regionPos.hashCode(); + } + + private int chunkIndex(int x, int z) { + return z * chunksSize.getX() + x; + } + + private int tileIndex(int x, int z) { + return z * tileSize.getX() + x; + } + + private boolean checkChunksHaveChanges(Vector2i tile) { + int minX = tileGrid.getCellMinX(tile.getX(), chunkGrid), + maxX = tileGrid.getCellMaxX(tile.getX(), chunkGrid), + minZ = tileGrid.getCellMinY(tile.getY(), chunkGrid), + maxZ = tileGrid.getCellMaxY(tile.getY(), chunkGrid); + + for (int chunkX = minX; chunkX <= maxX; chunkX++) { + for (int chunkZ = minZ; chunkZ <= maxZ; chunkZ++) { + int dx = chunkX - chunkMin.getX(); + int dz = chunkZ - chunkMin.getY(); + + // only check hash for chunks inside the current region + if ( + chunkX >= chunkMin.getX() && chunkX <= chunkMax.getX() && + chunkZ >= chunkMin.getY() && chunkZ <= chunkMax.getY() + ) { + int hash = chunkHashes[chunkIndex(dx, dz)]; + int lastHash = map.getMapChunkState().get(chunkX, chunkZ); + + if (lastHash != hash) return true; + } + } + } + + return false; + } + + private BoundsSituation checkTileBounds(Vector2i tile) { + boolean isInsideBounds = map.getMapSettings().isInsideRenderBoundaries(tile, tileGrid, true); + if (!isInsideBounds) return BoundsSituation.OUTSIDE; + + boolean isFullyInsideBounds = map.getMapSettings().isInsideRenderBoundaries(tile, tileGrid, false); + return isFullyInsideBounds ? BoundsSituation.INSIDE : BoundsSituation.EDGE; + } + + private @Nullable TileState checkTileRenderPreconditions(Vector2i tile) { + boolean chunksAreInhabited = false; + + long minInhabitedTime = map.getMapSettings().getMinInhabitedTime(); + int minInhabitedTimeRadius = map.getMapSettings().getMinInhabitedTimeRadius(); + boolean requireLight = !map.getMapSettings().isIgnoreMissingLightData(); + + int minX = tileGrid.getCellMinX(tile.getX(), chunkGrid), + maxX = tileGrid.getCellMaxX(tile.getX(), chunkGrid), + minZ = tileGrid.getCellMinY(tile.getY(), chunkGrid), + maxZ = tileGrid.getCellMaxY(tile.getY(), chunkGrid); + + for (int chunkX = minX; chunkX <= maxX; chunkX++) { + for (int chunkZ = minZ; chunkZ <= maxZ; chunkZ++) { + Chunk chunk = map.getWorld().getChunk(chunkX, chunkZ); + if (chunk == Chunk.ERRORED_CHUNK) return TileState.CHUNK_ERROR; + if (!chunk.isGenerated()) return TileState.NOT_GENERATED; + if (requireLight && !chunk.hasLightData()) return TileState.MISSING_LIGHT; + if (chunk.getInhabitedTime() >= minInhabitedTime) chunksAreInhabited = true; + } + } + + // second pass for increased inhabited-time-radius + if (!chunksAreInhabited && minInhabitedTimeRadius > 0) { + inhabitedRadiusCheck: + for (int chunkX = minX - minInhabitedTimeRadius; chunkX <= maxX + minInhabitedTimeRadius; chunkX++) { + for (int chunkZ = minZ - minInhabitedTimeRadius; chunkZ <= maxZ + minInhabitedTimeRadius; chunkZ++) { + Chunk chunk = map.getWorld().getChunk(chunkX, chunkZ); + if (chunk.getInhabitedTime() >= minInhabitedTime) { + chunksAreInhabited = true; + break inhabitedRadiusCheck; + } + } + } + } + + return chunksAreInhabited ? null : TileState.LOW_INHABITED_TIME; } public static Comparator defaultComparator(final Vector2i centerRegion) { return (task1, task2) -> { // use long to compare to avoid overflow (comparison uses distanceSquared) - Vector2l task1Rel = new Vector2l(task1.worldRegion.getX() - centerRegion.getX(), task1.worldRegion.getY() - centerRegion.getY()); - Vector2l task2Rel = new Vector2l(task2.worldRegion.getX() - centerRegion.getX(), task2.worldRegion.getY() - centerRegion.getY()); + Vector2l task1Rel = new Vector2l(task1.regionPos.getX() - centerRegion.getX(), task1.regionPos.getY() - centerRegion.getY()); + Vector2l task2Rel = new Vector2l(task2.regionPos.getX() - centerRegion.getX(), task2.regionPos.getY() - centerRegion.getY()); return compareVec2L(task1Rel, task2Rel); }; } diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/serverinterface/Server.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/serverinterface/Server.java index 1a853a137..1b00db5b1 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/serverinterface/Server.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/serverinterface/Server.java @@ -25,10 +25,10 @@ package de.bluecolored.bluemap.common.serverinterface; import de.bluecolored.bluemap.api.debug.DebugDump; -import de.bluecolored.bluemap.core.MinecraftVersion; import de.bluecolored.bluemap.core.util.Tristate; import de.bluecolored.bluemap.core.world.World; import de.bluecolored.bluemap.core.world.mca.MCAWorld; +import org.jetbrains.annotations.Nullable; import java.nio.file.Path; import java.util.Collection; @@ -37,7 +37,7 @@ public interface Server { @DebugDump - MinecraftVersion getMinecraftVersion(); + @Nullable String getMinecraftVersion(); /** * Returns the Folder containing the configurations for the plugin diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/LoggingRequestHandler.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/LoggingRequestHandler.java index e71ad860c..f54834579 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/LoggingRequestHandler.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/LoggingRequestHandler.java @@ -27,8 +27,10 @@ import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.common.web.http.*; import de.bluecolored.bluemap.core.logger.Logger; +import lombok.Getter; @DebugDump +@Getter public class LoggingRequestHandler implements HttpRequestHandler { private final HttpRequestHandler delegate; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/RoutingRequestHandler.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/RoutingRequestHandler.java index b21f6e317..0f2f8cd4a 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/RoutingRequestHandler.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/RoutingRequestHandler.java @@ -29,6 +29,10 @@ import de.bluecolored.bluemap.common.web.http.HttpRequestHandler; import de.bluecolored.bluemap.common.web.http.HttpResponse; import de.bluecolored.bluemap.common.web.http.HttpStatusCode; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NonNull; +import lombok.Setter; import org.intellij.lang.annotations.Language; import java.util.LinkedList; @@ -38,7 +42,7 @@ @DebugDump public class RoutingRequestHandler implements HttpRequestHandler { - public LinkedList routes; + public final LinkedList routes; public RoutingRequestHandler() { this.routes = new LinkedList<>(); @@ -80,36 +84,20 @@ public HttpResponse handle(HttpRequest request) { } @DebugDump - private static class Route { + @AllArgsConstructor + @Getter @Setter + public static class Route { - private final Pattern routePattern; - private final HttpRequestHandler handler; - private final String replacementRoute; + private @NonNull Pattern routePattern; + private @NonNull String replacementRoute; + private @NonNull HttpRequestHandler handler; - public Route(Pattern routePattern, HttpRequestHandler handler) { + public Route(@NonNull Pattern routePattern, @NonNull HttpRequestHandler handler) { this.routePattern = routePattern; this.replacementRoute = "$0"; this.handler = handler; } - public Route(Pattern routePattern, String replacementRoute, HttpRequestHandler handler) { - this.routePattern = routePattern; - this.replacementRoute = replacementRoute; - this.handler = handler; - } - - public Pattern getRoutePattern() { - return routePattern; - } - - public HttpRequestHandler getHandler() { - return handler; - } - - public String getReplacementRoute() { - return replacementRoute; - } - } } diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/http/HttpServer.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/http/HttpServer.java index 562d15f95..e11e72248 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/http/HttpServer.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/http/HttpServer.java @@ -25,13 +25,16 @@ package de.bluecolored.bluemap.common.web.http; import de.bluecolored.bluemap.api.debug.DebugDump; +import lombok.Getter; +import lombok.Setter; import java.io.IOException; @DebugDump public class HttpServer extends Server { - private final HttpRequestHandler requestHandler; + @Getter @Setter + private HttpRequestHandler requestHandler; public HttpServer(HttpRequestHandler requestHandler) throws IOException { this.requestHandler = requestHandler; @@ -40,10 +43,6 @@ public HttpServer(HttpRequestHandler requestHandler) throws IOException { @Override public SelectionConsumer createConnectionHandler() { return new HttpConnection(requestHandler); - - // Enable async request handling ... - // TODO: maybe find a better/separate executor than using bluemap's common thread-pool - //return new HttpConnection(requestHandler, BlueMap.THREAD_POOL); } } diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/http/HttpStatusCode.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/http/HttpStatusCode.java index 694070964..2787ee2ee 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/http/HttpStatusCode.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/http/HttpStatusCode.java @@ -24,6 +24,9 @@ */ package de.bluecolored.bluemap.common.web.http; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor public enum HttpStatusCode { CONTINUE (100, "Continue"), @@ -47,13 +50,8 @@ public enum HttpStatusCode { SERVICE_UNAVAILABLE (503, "Service Unavailable"), HTTP_VERSION_NOT_SUPPORTED (505, "HTTP Version not supported"); - private int code; - private String message; - - private HttpStatusCode(int code, String message) { - this.code = code; - this.message = message; - } + private final int code; + private final String message; public int getCode(){ return code; diff --git a/BlueMapCommon/src/main/resources/de/bluecolored/bluemap/config/core.conf b/BlueMapCommon/src/main/resources/de/bluecolored/bluemap/config/core.conf index b7605fa25..7745e2f75 100644 --- a/BlueMapCommon/src/main/resources/de/bluecolored/bluemap/config/core.conf +++ b/BlueMapCommon/src/main/resources/de/bluecolored/bluemap/config/core.conf @@ -5,7 +5,7 @@ # 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 a minecraft-client file (depending on the minecraft-version) from mojangs servers (https://launcher.mojang.com/) for you. +# and you agree that BlueMap will download and use a minecraft-client file (depending on the minecraft-version) from mojangs servers (https://piston-meta.mojang.com/) for you. # This file contains resources that belong to mojang and you must not redistribute it or do anything else that is not compliant 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.) # ${timestamp} diff --git a/BlueMapCommon/src/main/resources/de/bluecolored/bluemap/config/storages/file.conf b/BlueMapCommon/src/main/resources/de/bluecolored/bluemap/config/storages/file.conf index 18aae94d2..ca685b91d 100644 --- a/BlueMapCommon/src/main/resources/de/bluecolored/bluemap/config/storages/file.conf +++ b/BlueMapCommon/src/main/resources/de/bluecolored/bluemap/config/storages/file.conf @@ -14,7 +14,9 @@ root: "${root}" # The compression-type that bluemap will use to compress generated map-data. # Available compression-types are: -# - GZIP -# - NONE -# The default is: GZIP +# - gzip +# - zstd +# - deflate +# - none +# The default is: gzip compression: gzip diff --git a/BlueMapCommon/src/main/resources/de/bluecolored/bluemap/config/storages/sql.conf b/BlueMapCommon/src/main/resources/de/bluecolored/bluemap/config/storages/sql.conf index 807a04182..e8776244e 100644 --- a/BlueMapCommon/src/main/resources/de/bluecolored/bluemap/config/storages/sql.conf +++ b/BlueMapCommon/src/main/resources/de/bluecolored/bluemap/config/storages/sql.conf @@ -40,6 +40,8 @@ max-connections: -1 # The compression-type that bluemap will use to compress generated map-data. # Available compression-types are: # - gzip +# - zstd +# - deflate # - none # The default is: gzip compression: gzip diff --git a/BlueMapCommon/webapp/public/sql.php b/BlueMapCommon/webapp/public/sql.php index 504b64348..6f3382412 100644 --- a/BlueMapCommon/webapp/public/sql.php +++ b/BlueMapCommon/webapp/public/sql.php @@ -9,30 +9,27 @@ $password = ''; $database = 'bluemap'; -// set this to "none" if you disabled compression on your maps -$hiresCompression = 'gzip'; - // !!! END - DONT CHANGE ANYTHING AFTER THIS LINE !!! +// compression +$compressionHeaderMap = [ + "bluemap:none" => null, + "bluemap:gzip" => "gzip", + "bluemap:deflate" => "deflate", + "bluemap:zstd" => "zstd", + "bluemap:lz4" => "lz4" +] -// some helper functions -function error($code, $message = null) { - global $path; - - http_response_code($code); - header("Content-Type: text/plain"); - echo "BlueMap php-script - $code\n"; - if ($message != null) echo $message."\n"; - echo "Requested Path: $path"; - exit; -} - -function startsWith($haystack, $needle) { - return substr($haystack, 0, strlen($needle)) === $needle; -} +// meta files +$metaFileKeys = [ + "settings.json" => "bluemap:settings", + "textures.json" => "bluemap:textures", + "live/markers.json" => "bluemap:markers", + "live/players.json" => "bluemap:players", +] // mime-types for meta-files $mimeDefault = "application/octet-stream"; @@ -70,6 +67,34 @@ function startsWith($haystack, $needle) { "woff2" => "font/woff2" ]; +// some helper functions +function error($code, $message = null) { + global $path; + + http_response_code($code); + header("Content-Type: text/plain"); + echo "BlueMap php-script - $code\n"; + if ($message != null) echo $message."\n"; + echo "Requested Path: $path"; + exit; +} + +function startsWith($haystack, $needle) { + return substr($haystack, 0, strlen($needle)) === $needle; +} + +function issetOrElse(& $var, $fallback) { + return isset($var) ? $var : $fallback; +} + +function compressionHeader($compressionKey) { + global $compressionHeaderMap; + + $compressionHeader = issetOrElse($compressionHeaderMap[$compressionKey], null); + if ($compressionHeader) + header("Content-Encoding: ".$compressionHeader); +} + function getMimeType($path) { global $mimeDefault, $mimeTypes; @@ -122,55 +147,55 @@ function send($data) { // Initialize PDO try { - $sql = new PDO("$driver:host=$hostname;dbname=$database", $username, $password); + $sql = new PDO("$driver:host=$hostname;port=$port;dbname=$database", $username, $password); $sql->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException $e ) { error(500, "Failed to connect to database"); } - // provide map-tiles if (startsWith($mapPath, "tiles/")) { // parse tile-coordinates preg_match_all("/tiles\/([\d\/]+)\/x(-?[\d\/]+)z(-?[\d\/]+).*/", $mapPath, $matches); $lod = intval($matches[1][0]); + $storage = $lod === 0 ? "bluemap:hires" : "bluemap:lowres/".$lod $tileX = intval(str_replace("/", "", $matches[2][0])); $tileZ = intval(str_replace("/", "", $matches[3][0])); - $compression = $lod === 0 ? $hiresCompression : "none"; // query for tile try { $statement = $sql->prepare(" - SELECT t.data - FROM bluemap_map_tile t + SELECT d.data, c.compression + FROM bluemap_grid_storage_data d INNER JOIN bluemap_map m - ON t.map = m.id - INNER JOIN bluemap_map_tile_compression c - ON t.compression = c.id + ON d.map = m.id + INNER JOIN bluemap_grid_storage s + ON d.storage = s.id + INNER JOIN bluemap_compression c + ON d.compression = c.id WHERE m.map_id = :map_id - AND t.lod = :lod - AND t.x = :x - AND t.z = :z - AND c.compression = :compression + AND s.key = :storage + AND d.x = :x + AND d.z = :z "); $statement->bindParam( ':map_id', $mapId, PDO::PARAM_STR ); - $statement->bindParam( ':lod', $lod, PDO::PARAM_INT ); + $statement->bindParam( ':storage', $storage, PDO::PARAM_STR ); $statement->bindParam( ':x', $tileX, PDO::PARAM_INT ); $statement->bindParam( ':z', $tileZ, PDO::PARAM_INT ); - $statement->bindParam( ':compression', $compression, PDO::PARAM_STR); + $statement->bindParam( ':compression', $compression, PDO::PARAM_STR ); $statement->setFetchMode(PDO::FETCH_ASSOC); $statement->execute(); // return result if ($line = $statement->fetch()) { header("Cache-Control: public,max-age=86400"); + compressionHeader($line["compression"]); - if ($compression !== "none") - header("Content-Encoding: $compression"); if ($lod === 0) { header("Content-Type: application/octet-stream"); } else { header("Content-Type: image/png"); } + send($line["data"]); exit; } @@ -183,27 +208,39 @@ function send($data) { } // provide meta-files - try { - $statement = $sql->prepare(" - SELECT t.value - FROM bluemap_map_meta t - INNER JOIN bluemap_map m - ON t.map = m.id - WHERE m.map_id = :map_id - AND t.key = :map_path - "); - $statement->bindParam( ':map_id', $mapId, PDO::PARAM_STR ); - $statement->bindParam( ':map_path', $mapPath, PDO::PARAM_STR ); - $statement->setFetchMode(PDO::FETCH_ASSOC); - $statement->execute(); - - if ($line = $statement->fetch()) { - header("Cache-Control: public,max-age=86400"); - header("Content-Type: ".getMimeType($mapPath)); - send($line["value"]); - exit; - } - } catch (PDOException $e) { error(500, "Failed to fetch data"); } + $storage = issetOrElse($metaFileKeys[$mapPath], null); + if ($storage === null && startsWith($mapPath, "assets/")) + $storage = "bluemap:asset/".substr($mapPath, strlen("assets/")); + + if ($storage !== null) { + try { + $statement = $sql->prepare(" + SELECT d.data, c.compression + FROM bluemap_item_storage_data d + INNER JOIN bluemap_map m + ON d.map = m.id + INNER JOIN bluemap_item_storage s + ON d.storage = s.id + INNER JOIN bluemap_compression c + ON d.compression = c.id + WHERE m.map_id = :map_id + AND s.key = :storage + "); + $statement->bindParam( ':map_id', $mapId, PDO::PARAM_STR ); + $statement->bindParam( ':storage', $storage, PDO::PARAM_STR ); + $statement->setFetchMode(PDO::FETCH_ASSOC); + $statement->execute(); + + if ($line = $statement->fetch()) { + header("Cache-Control: public,max-age=86400"); + header("Content-Type: ".getMimeType($mapPath)); + compressionHeader($line["compression"]); + + send($line["data"]); + exit; + } + } catch (PDOException $e) { error(500, "Failed to fetch data"); } + } } diff --git a/BlueMapCore/build.gradle.kts b/BlueMapCore/build.gradle.kts index 8cf173049..1f5dca185 100644 --- a/BlueMapCore/build.gradle.kts +++ b/BlueMapCore/build.gradle.kts @@ -65,7 +65,7 @@ dependencies { api ("commons-io:commons-io:2.5") api ("org.spongepowered:configurate-hocon:4.1.2") api ("org.spongepowered:configurate-gson:4.1.2") - api ("de.bluecolored.bluenbt:BlueNBT:2.2.1") + api ("de.bluecolored.bluenbt:BlueNBT:2.3.0") api ("org.apache.commons:commons-dbcp2:2.9.0") api ("io.airlift:aircompressor:0.24") api ("org.lz4:lz4-java:1.8.0") diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/MinecraftVersion.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/MinecraftVersion.java deleted file mode 100644 index 876a2cabd..000000000 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/MinecraftVersion.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * This file is part of BlueMap, licensed under the MIT License (MIT). - * - * Copyright (c) Blue (Lukas Rieger) - * 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; - -import de.bluecolored.bluemap.api.debug.DebugDump; -import de.bluecolored.bluemap.core.util.Lazy; - -import java.util.Arrays; -import java.util.Comparator; -import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -@DebugDump -public class MinecraftVersion implements Comparable { - - private static final Pattern VERSION_REGEX = Pattern.compile("(?\\d+)\\.(?\\d+)(?:\\.(?\\d+))?(?:-(?:pre|rc)\\d+)?"); - - public static final MinecraftVersion LATEST_SUPPORTED = new MinecraftVersion(1, 20, 3); - public static final MinecraftVersion EARLIEST_SUPPORTED = new MinecraftVersion(1, 13); - - private final int major, minor, patch; - - private final Lazy resource; - - public MinecraftVersion(int major, int minor) { - this(major, minor, 0); - } - - public MinecraftVersion(int major, int minor, int patch) { - this.major = major; - this.minor = minor; - this.patch = patch; - - this.resource = new Lazy<>(this::findBestMatchingResource); - } - - public String getVersionString() { - return major + "." + minor + "." + patch; - } - - public MinecraftResource getResource() { - return this.resource.getValue(); - } - - public boolean isAtLeast(MinecraftVersion minVersion) { - return compareTo(minVersion) >= 0; - } - - public boolean isAtMost(MinecraftVersion maxVersion) { - return compareTo(maxVersion) <= 0; - } - - public boolean isBefore(MinecraftVersion minVersion) { - return compareTo(minVersion) < 0; - } - - public boolean isAfter(MinecraftVersion minVersion) { - return compareTo(minVersion) > 0; - } - - @Override - public int compareTo(MinecraftVersion other) { - int result; - - result = Integer.compare(major, other.major); - if (result != 0) return result; - - result = Integer.compare(minor, other.minor); - if (result != 0) return result; - - result = Integer.compare(patch, other.patch); - return result; - } - - public boolean majorEquals(MinecraftVersion that) { - return major == that.major; - } - - public boolean minorEquals(MinecraftVersion that) { - return major == that.major && minor == that.minor; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - MinecraftVersion that = (MinecraftVersion) o; - return major == that.major && minor == that.minor && patch == that.patch; - } - - @Override - public int hashCode() { - return Objects.hash(major, minor, patch); - } - - private MinecraftResource findBestMatchingResource() { - MinecraftResource[] resources = MinecraftResource.values(); - Arrays.sort(resources, Comparator.comparing(MinecraftResource::getVersion).reversed()); - - for (MinecraftResource resource : resources){ - if (isAtLeast(resource.version)) return resource; - } - - return resources[resources.length - 1]; - } - - public static MinecraftVersion of(String versionString) { - Matcher matcher = VERSION_REGEX.matcher(versionString); - if (!matcher.matches()) throw new IllegalArgumentException("Not a valid version string!"); - - int major = Integer.parseInt(matcher.group("major")); - int minor = Integer.parseInt(matcher.group("minor")); - int patch = 0; - String patchString = matcher.group("patch"); - if (patchString != null) patch = Integer.parseInt(patchString); - - return new MinecraftVersion(major, minor, patch); - } - - @DebugDump - public enum MinecraftResource { - - MC_1_13 (new MinecraftVersion(1, 13), "mc1_13", "https://piston-data.mojang.com/v1/objects/30bfe37a8db404db11c7edf02cb5165817afb4d9/client.jar"), - MC_1_14 (new MinecraftVersion(1, 14), "mc1_13", "https://piston-data.mojang.com/v1/objects/8c325a0c5bd674dd747d6ebaa4c791fd363ad8a9/client.jar"), - MC_1_15 (new MinecraftVersion(1, 15), "mc1_15", "https://piston-data.mojang.com/v1/objects/e3f78cd16f9eb9a52307ed96ebec64241cc5b32d/client.jar"), - MC_1_16 (new MinecraftVersion(1, 16), "mc1_16", "https://piston-data.mojang.com/v1/objects/228fdf45541c4c2fe8aec4f20e880cb8fcd46621/client.jar"), - MC_1_16_2 (new MinecraftVersion(1, 16, 2), "mc1_16", "https://piston-data.mojang.com/v1/objects/653e97a2d1d76f87653f02242d243cdee48a5144/client.jar"), - MC_1_17 (new MinecraftVersion(1, 17), "mc1_16", "https://piston-data.mojang.com/v1/objects/1cf89c77ed5e72401b869f66410934804f3d6f52/client.jar"), - MC_1_18 (new MinecraftVersion(1, 18), "mc1_18", "https://piston-data.mojang.com/v1/objects/020aa79e63a7aab5d6f30e5ec7a6c08baee6b64c/client.jar"), - MC_1_19 (new MinecraftVersion(1, 19), "mc1_18", "https://piston-data.mojang.com/v1/objects/a45634ab061beb8c878ccbe4a59c3315f9c0266f/client.jar"), - MC_1_19_4 (new MinecraftVersion(1, 19, 4), "mc1_18", "https://piston-data.mojang.com/v1/objects/958928a560c9167687bea0cefeb7375da1e552a8/client.jar"), - MC_1_20 (new MinecraftVersion(1, 20), "mc1_18", "https://piston-data.mojang.com/v1/objects/e575a48efda46cf88111ba05b624ef90c520eef1/client.jar"), - MC_1_20_3 (new MinecraftVersion(1, 20, 3), "mc1_20_3", "https://piston-data.mojang.com/v1/objects/b178a327a96f2cf1c9f98a45e5588d654a3e4369/client.jar"); - - private final MinecraftVersion version; - private final String resourcePrefix; - private final String clientUrl; - - MinecraftResource(MinecraftVersion version, String resourcePrefix, String clientUrl) { - this.version = version; - this.resourcePrefix = resourcePrefix; - this.clientUrl = clientUrl; - } - - public MinecraftVersion getVersion() { - return version; - } - - public String getResourcePrefix() { - return resourcePrefix; - } - - public String getClientUrl() { - return clientUrl; - } - } - -} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/BmMap.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/BmMap.java index c1ac40006..01851a380 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/BmMap.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/BmMap.java @@ -34,21 +34,29 @@ import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.map.hires.HiresModelManager; import de.bluecolored.bluemap.core.map.lowres.LowresTileManager; +import de.bluecolored.bluemap.core.map.renderstate.MapChunkState; +import de.bluecolored.bluemap.core.map.renderstate.MapTileState; import de.bluecolored.bluemap.core.resources.adapter.ResourcesGson; -import de.bluecolored.bluemap.core.resources.resourcepack.ResourcePack; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; import de.bluecolored.bluemap.core.storage.MapStorage; import de.bluecolored.bluemap.core.storage.compression.CompressedInputStream; import de.bluecolored.bluemap.core.util.Grid; import de.bluecolored.bluemap.core.world.World; - -import java.io.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; import java.nio.charset.StandardCharsets; -import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Predicate; @DebugDump +@Getter public class BmMap { private static final Gson GSON = ResourcesGson.addAdapter(new GsonBuilder()) @@ -63,20 +71,23 @@ public class BmMap { private final MapSettings mapSettings; private final ResourcePack resourcePack; - private final MapRenderState renderState; private final TextureGallery textureGallery; + private final MapTileState mapTileState; + private final MapChunkState mapChunkState; + private final HiresModelManager hiresModelManager; private final LowresTileManager lowresTileManager; private final ConcurrentHashMap markerSets; - private Predicate tileFilter; + @Setter private Predicate tileFilter; - private long renderTimeSumNanos; - private long tilesRendered; + @Getter(AccessLevel.NONE) private long renderTimeSumNanos; + @Getter(AccessLevel.NONE) private long tilesRendered; + @Getter(AccessLevel.NONE) private long lastSaveTime; - public BmMap(String id, String name, World world, MapStorage storage, ResourcePack resourcePack, MapSettings settings) throws IOException { + public BmMap(String id, String name, World world, MapStorage storage, ResourcePack resourcePack, MapSettings settings) throws IOException, InterruptedException { this.id = Objects.requireNonNull(id); this.name = Objects.requireNonNull(name); this.world = Objects.requireNonNull(world); @@ -84,9 +95,14 @@ public BmMap(String id, String name, World world, MapStorage storage, ResourcePa this.resourcePack = Objects.requireNonNull(resourcePack); this.mapSettings = Objects.requireNonNull(settings); - this.renderState = new MapRenderState(); - loadRenderState(); + Logger.global.logDebug("Loading render-state for map '" + id + "'"); + this.mapTileState = new MapTileState(storage.tileState()); + this.mapTileState.load(); + this.mapChunkState = new MapChunkState(storage.chunkState()); + + if (Thread.interrupted()) throw new InterruptedException(); + Logger.global.logDebug("Loading textures for map '" + id + "'"); this.textureGallery = loadTextureGallery(); this.textureGallery.put(resourcePack); saveTextureGallery(); @@ -112,6 +128,7 @@ public BmMap(String id, String name, World world, MapStorage storage, ResourcePa this.renderTimeSumNanos = 0; this.tilesRendered = 0; + this.lastSaveTime = -1; saveMapSettings(); } @@ -130,9 +147,23 @@ public void renderTile(Vector2i tile) { tilesRendered ++; } + public void unrenderTile(Vector2i tile) { + hiresModelManager.unrender(tile, lowresTileManager); + } + + public synchronized boolean save(long minTimeSinceLastSave) { + long now = System.currentTimeMillis(); + if (now - lastSaveTime < minTimeSinceLastSave) + return false; + + save(); + return true; + } + public synchronized void save() { lowresTileManager.save(); - saveRenderState(); + mapTileState.save(); + mapChunkState.save(); saveMarkerState(); savePlayerState(); saveMapSettings(); @@ -142,25 +173,10 @@ public synchronized void save() { if (!storage.textures().exists()) saveTextureGallery(); } catch (IOException e) { - Logger.global.logError("Failed to read texture gallery", e); + Logger.global.logError("Failed to read texture gallery for map '" + getId() + "'!", e); } - } - private void loadRenderState() throws IOException { - try (CompressedInputStream in = storage.renderState().read()){ - if (in != null) - this.renderState.load(in.decompress()); - } catch (IOException ex) { - Logger.global.logWarning("Failed to load render-state for map '" + getId() + "': " + ex); - } - } - - public synchronized void saveRenderState() { - try (OutputStream out = storage.renderState().write()) { - this.renderState.save(out); - } catch (IOException ex){ - Logger.global.logError("Failed to save render-state for map: '" + this.id + "'!", ex); - } + lastSaveTime = System.currentTimeMillis(); } private TextureGallery loadTextureGallery() throws IOException { @@ -217,50 +233,6 @@ public synchronized void savePlayerState() { } } - public String getId() { - return id; - } - - public String getName() { - return name; - } - - public World getWorld() { - return world; - } - - public MapStorage getStorage() { - return storage; - } - - public MapSettings getMapSettings() { - return mapSettings; - } - - public MapRenderState getRenderState() { - return renderState; - } - - public HiresModelManager getHiresModelManager() { - return hiresModelManager; - } - - public LowresTileManager getLowresTileManager() { - return lowresTileManager; - } - - public Map getMarkerSets() { - return markerSets; - } - - public Predicate getTileFilter() { - return tileFilter; - } - - public void setTileFilter(Predicate tileFilter) { - this.tileFilter = tileFilter; - } - public long getAverageNanosPerTile() { return renderTimeSumNanos / tilesRendered; } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/MapRenderState.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/MapRenderState.java deleted file mode 100644 index 5adeabdf5..000000000 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/MapRenderState.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * This file is part of BlueMap, licensed under the MIT License (MIT). - * - * Copyright (c) Blue (Lukas Rieger) - * 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.map; - -import com.flowpowered.math.vector.Vector2i; -import de.bluecolored.bluemap.api.debug.DebugDump; - -import java.io.*; -import java.util.HashMap; -import java.util.Map; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; - -@DebugDump -public class MapRenderState { - - private final Map regionRenderTimes; - private transient long latestRenderTime = -1; - - public MapRenderState() { - regionRenderTimes = new HashMap<>(); - } - - public synchronized void setRenderTime(Vector2i regionPos, long renderTime) { - regionRenderTimes.put(regionPos, renderTime); - - if (latestRenderTime != -1) { - if (renderTime > latestRenderTime) - latestRenderTime = renderTime; - else - latestRenderTime = -1; - } - } - - public synchronized long getRenderTime(Vector2i regionPos) { - Long renderTime = regionRenderTimes.get(regionPos); - if (renderTime == null) return -1; - else return renderTime; - } - - public long getLatestRenderTime() { - if (latestRenderTime == -1) { - synchronized (this) { - latestRenderTime = regionRenderTimes.values().stream() - .mapToLong(Long::longValue) - .max() - .orElse(-1); - } - } - - return latestRenderTime; - } - - public synchronized void reset() { - regionRenderTimes.clear(); - } - - public synchronized void save(OutputStream out) throws IOException { - try ( - DataOutputStream dOut = new DataOutputStream(new GZIPOutputStream(out)) - ) { - dOut.writeInt(regionRenderTimes.size()); - - for (Map.Entry entry : regionRenderTimes.entrySet()) { - Vector2i regionPos = entry.getKey(); - long renderTime = entry.getValue(); - - dOut.writeInt(regionPos.getX()); - dOut.writeInt(regionPos.getY()); - dOut.writeLong(renderTime); - } - - dOut.flush(); - } - } - - public synchronized void load(InputStream in) throws IOException { - regionRenderTimes.clear(); - - try ( - DataInputStream dIn = new DataInputStream(new GZIPInputStream(in)) - ) { - int size = dIn.readInt(); - - for (int i = 0; i < size; i++) { - Vector2i regionPos = new Vector2i( - dIn.readInt(), - dIn.readInt() - ); - long renderTime = dIn.readLong(); - - regionRenderTimes.put(regionPos, renderTime); - } - } catch (EOFException ignore){} // ignoring a sudden end of stream, since it is save to only read as many as we can - } - -} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/TextureGallery.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/TextureGallery.java index 75f7f9d89..2a5c89773 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/TextureGallery.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/TextureGallery.java @@ -32,8 +32,8 @@ import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.resources.ResourcePath; import de.bluecolored.bluemap.core.resources.adapter.ResourcesGson; -import de.bluecolored.bluemap.core.resources.resourcepack.ResourcePack; -import de.bluecolored.bluemap.core.resources.resourcepack.texture.Texture; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.texture.Texture; import de.bluecolored.bluemap.core.util.Key; import org.jetbrains.annotations.Nullable; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/HiresModelManager.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/HiresModelManager.java index 89e095e90..d2ebdfdb5 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/HiresModelManager.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/HiresModelManager.java @@ -29,9 +29,10 @@ import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.map.TextureGallery; import de.bluecolored.bluemap.core.map.TileMetaConsumer; -import de.bluecolored.bluemap.core.resources.resourcepack.ResourcePack; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; import de.bluecolored.bluemap.core.storage.GridStorage; import de.bluecolored.bluemap.core.util.Grid; +import de.bluecolored.bluemap.core.util.math.Color; import de.bluecolored.bluemap.core.world.World; import lombok.Getter; @@ -79,6 +80,23 @@ public void render(World world, Vector2i tile, TileMetaConsumer tileMetaConsumer TileModel.instancePool().recycleInstance(model); } + /** + * Un-renders a tile. + * The hires tile is deleted and the tileMetaConsumer (lowres) is updated with default values in the tiles area. + */ + public void unrender(Vector2i tile, TileMetaConsumer tileMetaConsumer) { + try { + storage.delete(tile.getX(), tile.getY()); + } catch (IOException ex) { + Logger.global.logError("Failed to delete hires model: " + tile, ex); + } + + Color color = new Color(); + tileGrid.forEachIntersecting(tile, Grid.UNIT, (x, z) -> + tileMetaConsumer.set(x, z, color, 0, 0) + ); + } + private void save(final TileModel model, Vector2i tile) { try ( OutputStream out = storage.write(tile.getX(), tile.getY()); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/HiresModelRenderer.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/HiresModelRenderer.java index 522e7c6bc..e88c114b1 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/HiresModelRenderer.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/HiresModelRenderer.java @@ -28,7 +28,7 @@ import de.bluecolored.bluemap.core.map.TextureGallery; import de.bluecolored.bluemap.core.map.TileMetaConsumer; import de.bluecolored.bluemap.core.map.hires.blockmodel.BlockStateModelFactory; -import de.bluecolored.bluemap.core.resources.resourcepack.ResourcePack; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; import de.bluecolored.bluemap.core.util.math.Color; import de.bluecolored.bluemap.core.world.Chunk; import de.bluecolored.bluemap.core.world.block.BlockNeighborhood; @@ -65,8 +65,8 @@ public void render(World world, Vector3i modelMin, Vector3i modelMax, TileModel BlockModelView blockModel = new BlockModelView(model); int x, y, z; - for (x = min.getX(); x <= max.getX(); x++){ - for (z = min.getZ(); z <= max.getZ(); z++){ + for (x = modelMin.getX(); x <= modelMax.getX(); x++){ + for (z = modelMin.getZ(); z <= modelMax.getZ(); z++){ maxHeight = 0; topBlockLight = 0; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/RenderSettings.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/RenderSettings.java index 6d85cb171..ff97d1158 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/RenderSettings.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/RenderSettings.java @@ -105,20 +105,22 @@ default boolean isInsideRenderBoundaries(int x, int y, int z) { y <= max.getY(); } + default boolean isInsideRenderBoundaries(Vector2i cell, Grid grid, boolean allowPartiallyIncludedCells) { + Vector2i cellMin = allowPartiallyIncludedCells ? grid.getCellMin(cell) : grid.getCellMax(cell); + if (cellMin.getX() > getMaxPos().getX()) return false; + if (cellMin.getY() > getMaxPos().getZ()) return false; + + Vector2i cellMax = allowPartiallyIncludedCells ? grid.getCellMax(cell) : grid.getCellMin(cell); + if (cellMax.getX() < getMinPos().getX()) return false; + return cellMax.getY() >= getMinPos().getZ(); + } + /** * Returns a predicate which is filtering out all cells of a {@link Grid} - * that are completely outside the render boundaries. + * that are outside the render boundaries. */ - default Predicate getRenderBoundariesCellFilter(Grid grid) { - return t -> { - Vector2i cellMin = grid.getCellMin(t); - if (cellMin.getX() > getMaxPos().getX()) return false; - if (cellMin.getY() > getMaxPos().getZ()) return false; - - Vector2i cellMax = grid.getCellMax(t); - if (cellMax.getX() < getMinPos().getX()) return false; - return cellMax.getY() >= getMinPos().getZ(); - }; + default Predicate getCellRenderBoundariesFilter(Grid grid, boolean allowPartiallyIncludedCells) { + return cell -> isInsideRenderBoundaries(cell, grid, allowPartiallyIncludedCells); } boolean isSaveHiresLayer(); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/blockmodel/BlockStateModelFactory.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/blockmodel/BlockStateModelFactory.java index 3539043c9..c3a2af9b4 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/blockmodel/BlockStateModelFactory.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/blockmodel/BlockStateModelFactory.java @@ -27,9 +27,9 @@ import de.bluecolored.bluemap.core.map.TextureGallery; import de.bluecolored.bluemap.core.map.hires.BlockModelView; import de.bluecolored.bluemap.core.map.hires.RenderSettings; -import de.bluecolored.bluemap.core.resources.resourcepack.ResourcePack; -import de.bluecolored.bluemap.core.resources.resourcepack.blockmodel.BlockModel; -import de.bluecolored.bluemap.core.resources.resourcepack.blockstate.Variant; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.BlockModel; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate.Variant; import de.bluecolored.bluemap.core.util.math.Color; import de.bluecolored.bluemap.core.world.block.BlockNeighborhood; import de.bluecolored.bluemap.core.world.BlockState; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/blockmodel/LiquidModelBuilder.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/blockmodel/LiquidModelBuilder.java index 1b915f361..f4b6d00c3 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/blockmodel/LiquidModelBuilder.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/blockmodel/LiquidModelBuilder.java @@ -32,11 +32,11 @@ import de.bluecolored.bluemap.core.map.hires.RenderSettings; import de.bluecolored.bluemap.core.resources.BlockColorCalculatorFactory; import de.bluecolored.bluemap.core.resources.ResourcePath; -import de.bluecolored.bluemap.core.resources.resourcepack.ResourcePack; -import de.bluecolored.bluemap.core.resources.resourcepack.blockmodel.BlockModel; -import de.bluecolored.bluemap.core.resources.resourcepack.blockmodel.TextureVariable; -import de.bluecolored.bluemap.core.resources.resourcepack.blockstate.Variant; -import de.bluecolored.bluemap.core.resources.resourcepack.texture.Texture; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.BlockModel; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.TextureVariable; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate.Variant; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.texture.Texture; import de.bluecolored.bluemap.core.util.Direction; import de.bluecolored.bluemap.core.util.math.Color; import de.bluecolored.bluemap.core.util.math.MatrixM3f; @@ -138,7 +138,7 @@ private void build() { tintcolor.set(1f, 1f, 1f, 1f, true); if (blockState.isWater()) { - blockColorCalculator.getWaterAverageColor(block, tintcolor); + blockColorCalculator.getBlendedWaterColor(block, tintcolor); } int modelStart = blockModel.getStart(); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/blockmodel/ResourceModelBuilder.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/blockmodel/ResourceModelBuilder.java index 686eb6ca0..3e709484d 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/blockmodel/ResourceModelBuilder.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/blockmodel/ResourceModelBuilder.java @@ -34,12 +34,12 @@ import de.bluecolored.bluemap.core.map.hires.RenderSettings; import de.bluecolored.bluemap.core.resources.BlockColorCalculatorFactory; import de.bluecolored.bluemap.core.resources.ResourcePath; -import de.bluecolored.bluemap.core.resources.resourcepack.ResourcePack; -import de.bluecolored.bluemap.core.resources.resourcepack.blockmodel.BlockModel; -import de.bluecolored.bluemap.core.resources.resourcepack.blockmodel.Element; -import de.bluecolored.bluemap.core.resources.resourcepack.blockmodel.Face; -import de.bluecolored.bluemap.core.resources.resourcepack.blockstate.Variant; -import de.bluecolored.bluemap.core.resources.resourcepack.texture.Texture; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.BlockModel; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.Element; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.Face; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate.Variant; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.texture.Texture; import de.bluecolored.bluemap.core.util.Direction; import de.bluecolored.bluemap.core.util.math.Color; import de.bluecolored.bluemap.core.util.math.MatrixM4f; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/CellStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/CellStorage.java new file mode 100644 index 000000000..f133d88bf --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/CellStorage.java @@ -0,0 +1,116 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.map.renderstate; + +import com.flowpowered.math.vector.Vector2i; +import com.google.gson.reflect.TypeToken; +import de.bluecolored.bluemap.api.debug.DebugDump; +import de.bluecolored.bluemap.core.logger.Logger; +import de.bluecolored.bluemap.core.storage.GridStorage; +import de.bluecolored.bluemap.core.storage.compression.CompressedInputStream; +import de.bluecolored.bluemap.core.util.Key; +import de.bluecolored.bluemap.core.util.PalettedArrayAdapter; +import de.bluecolored.bluemap.core.util.RegistryAdapter; +import de.bluecolored.bluenbt.BlueNBT; +import lombok.Getter; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.LinkedHashMap; +import java.util.Map; + +@DebugDump +abstract class CellStorage { + + private static final BlueNBT BLUE_NBT = new BlueNBT(); + static { + BLUE_NBT.register(TypeToken.get(TileState.class), new RegistryAdapter<>(TileState.REGISTRY, Key.BLUEMAP_NAMESPACE, TileState.UNKNOWN)); + BLUE_NBT.register(TypeToken.get(TileState[].class), new PalettedArrayAdapter<>(BLUE_NBT, TileState.class)); + } + + private static final int CACHE_SIZE = 4; + + @Getter private final GridStorage storage; + private final Class type; + private final LinkedHashMap cells = new LinkedHashMap<>( + 8, + 0.75f, + true + ) { + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + if (this.size() <= CACHE_SIZE) return false; + saveCell(eldest.getKey(), eldest.getValue()); + return true; + } + }; + + public CellStorage(GridStorage storage, Class type) { + this.storage = storage; + this.type = type; + } + + public synchronized void save() { + cells.forEach(this::saveCell); + } + + public synchronized void reset() { + cells.clear(); + } + + T cell(int x, int z) { + return cell(new Vector2i(x, z)); + } + + synchronized T cell(Vector2i pos) { + return cells.computeIfAbsent(pos, this::loadCell); + } + + private synchronized T loadCell(Vector2i pos) { + try (CompressedInputStream in = storage.read(pos.getX(), pos.getY())) { + if (in != null) + return BLUE_NBT.read(in.decompress(), type); + } catch (IOException ex) { + Logger.global.logError("Failed to load render-state cell " + pos, ex); + } + return createNewCell(); + } + + protected abstract T createNewCell(); + + private synchronized void saveCell(Vector2i pos, T cell) { + if (!cell.isModified()) return; + try (OutputStream in = storage.write(pos.getX(), pos.getY())) { + BLUE_NBT.write(cell, in, type); + } catch (IOException ex) { + Logger.global.logError("Failed to save render-state cell " + pos, ex); + } + } + + public interface Cell { + boolean isModified(); + } + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/ChunkInfoRegion.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/ChunkInfoRegion.java new file mode 100644 index 000000000..29e7544dd --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/ChunkInfoRegion.java @@ -0,0 +1,55 @@ +package de.bluecolored.bluemap.core.map.renderstate; + +import de.bluecolored.bluenbt.NBTName; +import de.bluecolored.bluenbt.NBTPostDeserialize; +import lombok.Getter; + +import static de.bluecolored.bluemap.core.map.renderstate.MapChunkState.SHIFT; + +public class ChunkInfoRegion implements CellStorage.Cell { + + static final int REGION_LENGTH = 1 << SHIFT; + static final int REGION_MASK = REGION_LENGTH - 1; + static final int CHUNKS_PER_REGION = REGION_LENGTH * REGION_LENGTH; + + @NBTName("chunk-hashes") + private int[] chunkHashes; + + @Getter + private transient boolean modified; + + private ChunkInfoRegion() {} + + @NBTPostDeserialize + public void init() { + if (chunkHashes == null || chunkHashes.length != CHUNKS_PER_REGION) + chunkHashes = new int[CHUNKS_PER_REGION]; + } + + public int get(int x, int z) { + return chunkHashes[index(x, z)]; + } + + public int set(int x, int z, int hash) { + int index = index(x, z); + int previous = chunkHashes[index]; + + chunkHashes[index] = hash; + + if (previous != hash) + modified = true; + + return previous; + } + + private static int index(int x, int z) { + return (z & REGION_MASK) << SHIFT | (x & REGION_MASK); + } + + public static ChunkInfoRegion create() { + ChunkInfoRegion region = new ChunkInfoRegion(); + region.init(); + return region; + } + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/biome/datapack/DpBiome.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/MapChunkState.java similarity index 64% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/biome/datapack/DpBiome.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/MapChunkState.java index 601b07007..945a888c4 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/biome/datapack/DpBiome.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/MapChunkState.java @@ -22,28 +22,31 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package de.bluecolored.bluemap.core.resources.biome.datapack; - -import de.bluecolored.bluemap.core.world.Biome; -import lombok.Getter; - -@SuppressWarnings("FieldMayBeFinal") -@Getter -public class DpBiome { - - private DpBiomeEffects effects = new DpBiomeEffects(); - private float temperature = Biome.DEFAULT.getTemp(); - private float downfall = Biome.DEFAULT.getHumidity(); - - public Biome createBiome(String formatted) { - return new Biome( - formatted, - downfall, - temperature, - effects.getWaterColor(), - effects.getFoliageColor(), - effects.getGrassColor() - ); +package de.bluecolored.bluemap.core.map.renderstate; + +import de.bluecolored.bluemap.api.debug.DebugDump; +import de.bluecolored.bluemap.core.storage.GridStorage; + +@DebugDump +public class MapChunkState extends CellStorage { + + static final int SHIFT = 7; + + public MapChunkState(GridStorage storage) { + super(storage, ChunkInfoRegion.class); + } + + public int get(int x, int z) { + return cell(x >> SHIFT, z >> SHIFT).get(x, z); + } + + public synchronized int set(int x, int z, int hash) { + return cell(x >> SHIFT, z >> SHIFT).set(x, z, hash); + } + + @Override + protected ChunkInfoRegion createNewCell() { + return ChunkInfoRegion.create(); } } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/MapTileState.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/MapTileState.java new file mode 100644 index 000000000..f3796698d --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/MapTileState.java @@ -0,0 +1,101 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.map.renderstate; + +import de.bluecolored.bluemap.api.debug.DebugDump; +import de.bluecolored.bluemap.core.logger.Logger; +import de.bluecolored.bluemap.core.storage.GridStorage; +import de.bluecolored.bluemap.core.util.Grid; +import lombok.Getter; + +import java.io.IOException; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; + +@DebugDump +public class MapTileState extends CellStorage { + + static final int SHIFT = 5; + public static final Grid GRID = new Grid(1 << SHIFT); + + @Getter private int lastRenderTime = -1; + private final Map chunkStateCounts = new ConcurrentHashMap<>(); + + public MapTileState(GridStorage storage) { + super(storage, TileInfoRegion.class); + } + + public synchronized void load() { + lastRenderTime = -1; + chunkStateCounts.clear(); + + try (Stream stream = getStorage().stream()) { + stream.forEach(cell -> { + TileInfoRegion region = cell(cell.getX(), cell.getZ()); + lastRenderTime = Math.max(lastRenderTime, region.findLatestRenderTime()); + region.populateSummaryMap(chunkStateCounts); + }); + } catch (IOException e) { + Logger.global.logError("Failed to load render-state regions", e); + } + } + + public synchronized void reset() { + super.reset(); + load(); + } + + public TileInfoRegion.TileInfo get(int x, int z) { + return cell(x >> SHIFT, z >> SHIFT).get(x, z); + } + + public synchronized TileInfoRegion.TileInfo set(int x, int z, TileInfoRegion.TileInfo info) { + TileInfoRegion.TileInfo old = cell(x >> SHIFT, z >> SHIFT).set(x, z, info); + + if (info.getRenderTime() > lastRenderTime) + lastRenderTime = info.getRenderTime(); + + if (old.getState() != info.getState()) { + chunkStateCounts.merge(old.getState(), -1, Integer::sum); + chunkStateCounts.merge(info.getState(), 1, Integer::sum); + } + + return old; + } + + public Map getChunkStateCounts() { + return Collections.unmodifiableMap(chunkStateCounts); + } + + @Override + protected synchronized TileInfoRegion createNewCell() { + TileInfoRegion region = TileInfoRegion.create(); + region.populateSummaryMap(chunkStateCounts); + return region; + } + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileActionResolver.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileActionResolver.java new file mode 100644 index 000000000..3816e3cb9 --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileActionResolver.java @@ -0,0 +1,42 @@ +package de.bluecolored.bluemap.core.map.renderstate; + +import java.util.Objects; + +import static de.bluecolored.bluemap.core.map.renderstate.TileState.*; + +@FunctionalInterface +public interface TileActionResolver { + + ActionAndNextState findActionAndNextState( + boolean chunksChanged, + BoundsSituation bounds + ); + + enum BoundsSituation { + INSIDE, + EDGE, + OUTSIDE + } + + enum Action { + NONE, + RENDER, + DELETE + } + + record ActionAndNextState (Action action, TileState state) { + + public ActionAndNextState(Action action, TileState state) { + this.action = Objects.requireNonNull(action); + this.state = Objects.requireNonNull(state); + } + + public static final ActionAndNextState RENDER_RENDERED = new ActionAndNextState(Action.RENDER, RENDERED); + public static final ActionAndNextState NONE_RENDERED = new ActionAndNextState(Action.NONE, RENDERED); + public static final ActionAndNextState RENDER_RENDERED_EDGE = new ActionAndNextState(Action.RENDER, RENDERED_EDGE); + public static final ActionAndNextState NONE_RENDERED_EDGE = new ActionAndNextState(Action.NONE, RENDERED_EDGE); + public static final ActionAndNextState DELETE_OUT_OF_BOUNDS = new ActionAndNextState(Action.DELETE, OUT_OF_BOUNDS); + public static final ActionAndNextState NONE_OUT_OF_BOUNDS = new ActionAndNextState(Action.NONE, OUT_OF_BOUNDS); + } + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileInfoRegion.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileInfoRegion.java new file mode 100644 index 000000000..600b6fb02 --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileInfoRegion.java @@ -0,0 +1,101 @@ +package de.bluecolored.bluemap.core.map.renderstate; + +import de.bluecolored.bluenbt.NBTName; +import de.bluecolored.bluenbt.NBTPostDeserialize; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; + +import java.util.Arrays; +import java.util.Map; +import java.util.Objects; + +import static de.bluecolored.bluemap.core.map.renderstate.MapTileState.SHIFT; + +public class TileInfoRegion implements CellStorage.Cell { + + private static final int REGION_LENGTH = 1 << SHIFT; + private static final int REGION_MASK = REGION_LENGTH - 1; + private static final int TILES_PER_REGION = REGION_LENGTH * REGION_LENGTH; + + @NBTName("last-render-times") + private int[] lastRenderTimes; + + @NBTName("tile-states") + private TileState[] tileStates; + + @Getter + private transient boolean modified; + + private TileInfoRegion() {} + + @NBTPostDeserialize + public void init() { + if (lastRenderTimes == null || lastRenderTimes.length != TILES_PER_REGION) + lastRenderTimes = new int[TILES_PER_REGION]; + + if (tileStates == null || tileStates.length != TILES_PER_REGION) { + tileStates = new TileState[TILES_PER_REGION]; + Arrays.fill(tileStates, TileState.UNKNOWN); + } + } + + public TileInfo get(int x, int z) { + int index = index(x, z); + return new TileInfo( + lastRenderTimes[index], + tileStates[index] + ); + } + + public TileInfo set(int x, int z, TileInfo info) { + int index = index(x, z); + + TileInfo previous = new TileInfo( + lastRenderTimes[index], + tileStates[index] + ); + + lastRenderTimes[index] = info.getRenderTime(); + tileStates[index] = Objects.requireNonNull(info.getState()); + + if (!previous.equals(info)) + this.modified = true; + + return previous; + } + + int findLatestRenderTime() { + if (lastRenderTimes == null) return -1; + return Arrays.stream(lastRenderTimes) + .max() + .orElse(-1); + } + + void populateSummaryMap(Map map) { + for (int i = 0; i < TILES_PER_REGION; i++) { + TileState tileState = tileStates[i]; + map.merge(tileState, 1, Integer::sum); + } + } + + private static int index(int x, int z) { + return (z & REGION_MASK) << SHIFT | (x & REGION_MASK); + } + + @Data + @AllArgsConstructor + public static class TileInfo { + + private int renderTime; + private TileState state; + + } + + public static TileInfoRegion create() { + TileInfoRegion region = new TileInfoRegion(); + region.init(); + return region; + } + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileState.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileState.java new file mode 100644 index 000000000..e870016fa --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileState.java @@ -0,0 +1,102 @@ +package de.bluecolored.bluemap.core.map.renderstate; + +import de.bluecolored.bluemap.core.util.Key; +import de.bluecolored.bluemap.core.util.Keyed; +import de.bluecolored.bluemap.core.util.Registry; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import static de.bluecolored.bluemap.core.map.renderstate.TileActionResolver.ActionAndNextState.*; + +public interface TileState extends Keyed, TileActionResolver { + + TileState UNKNOWN = new Impl( Key.bluemap("unknown")); + + TileState RENDERED = new Impl(Key.bluemap("rendered"), (changed, bounds) -> + switch (bounds) { + case INSIDE -> changed ? RENDER_RENDERED : NONE_RENDERED; + case EDGE -> RENDER_RENDERED_EDGE; + case OUTSIDE -> DELETE_OUT_OF_BOUNDS; + } + ); + TileState RENDERED_EDGE = new Impl(Key.bluemap("rendered-edge"), (changed, bounds) -> + switch (bounds) { + case INSIDE -> RENDER_RENDERED; + case EDGE -> changed ? RENDER_RENDERED_EDGE : NONE_RENDERED_EDGE; + case OUTSIDE -> DELETE_OUT_OF_BOUNDS; + } + ); + TileState OUT_OF_BOUNDS = new Impl(Key.bluemap("out-of-bounds"), (changed, bounds) -> + switch (bounds) { + case INSIDE -> RENDER_RENDERED; + case EDGE -> RENDER_RENDERED_EDGE; + case OUTSIDE -> NONE_OUT_OF_BOUNDS; + } + ); + + TileState NOT_GENERATED = new Impl(Key.bluemap("not-generated")); + TileState MISSING_LIGHT = new Impl(Key.bluemap("missing-light")); + TileState LOW_INHABITED_TIME = new Impl(Key.bluemap("low-inhabited-time")); + TileState CHUNK_ERROR = new Impl(Key.bluemap("chunk-error")); + + TileState RENDER_ERROR = new Impl(Key.bluemap("render-error"), (changed, bounds) -> + switch (bounds) { + case INSIDE -> RENDER_RENDERED; + case EDGE -> RENDER_RENDERED_EDGE; + case OUTSIDE -> DELETE_OUT_OF_BOUNDS; + } + ); + + Registry REGISTRY = new Registry<>( + UNKNOWN, + RENDERED, + RENDERED_EDGE, + OUT_OF_BOUNDS, + NOT_GENERATED, + MISSING_LIGHT, + LOW_INHABITED_TIME, + CHUNK_ERROR, + RENDER_ERROR + ); + + @Getter + @RequiredArgsConstructor + class Impl implements TileState { + private final Key key; + private final TileActionResolver resolver; + + public Impl(Key key) { + this.key = key; + this.resolver = (changed, bounds) -> { + if (!changed) return noActionThisNextState(); + return switch (bounds) { + case INSIDE -> RENDER_RENDERED; + case EDGE -> RENDER_RENDERED_EDGE; + case OUTSIDE -> DELETE_OUT_OF_BOUNDS; + }; + }; + } + + @Override + public String toString() { + return key.getFormatted(); + } + + @Override + public ActionAndNextState findActionAndNextState( + boolean changed, + BoundsSituation bounds + ) { + return resolver.findActionAndNextState(changed, bounds); + } + + private ActionAndNextState noActionThisNextState; + private ActionAndNextState noActionThisNextState() { + if (noActionThisNextState == null) + noActionThisNextState = new ActionAndNextState(Action.NONE, this); + return noActionThisNextState; + } + + } + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/BlockColorCalculatorFactory.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/BlockColorCalculatorFactory.java index e745c5e73..9b8ebad92 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/BlockColorCalculatorFactory.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/BlockColorCalculatorFactory.java @@ -29,6 +29,7 @@ import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.util.math.Color; import de.bluecolored.bluemap.core.world.Biome; +import de.bluecolored.bluemap.core.world.block.Block; import de.bluecolored.bluemap.core.world.block.BlockNeighborhood; import java.awt.image.BufferedImage; @@ -42,13 +43,15 @@ @DebugDump public class BlockColorCalculatorFactory { + private static final int BLEND_RADIUS_H = 2; + private static final int BLEND_RADIUS_V = 1; private static final int - AVERAGE_MIN_X = - 2, - AVERAGE_MAX_X = 2, - AVERAGE_MIN_Y = - 1, - AVERAGE_MAX_Y = 1, - AVERAGE_MIN_Z = - 2, - AVERAGE_MAX_Z = 2; + BLEND_MIN_X = - BLEND_RADIUS_H, + BLEND_MAX_X = BLEND_RADIUS_H, + BLEND_MIN_Y = - BLEND_RADIUS_V, + BLEND_MAX_Y = BLEND_RADIUS_V, + BLEND_MIN_Z = - BLEND_RADIUS_H, + BLEND_MAX_Z = BLEND_RADIUS_H; private final int[] foliageMap = new int[65536]; private final int[] grassMap = new int[65536]; @@ -73,13 +76,13 @@ public void load(Path configFile) throws IOException { ColorFunction colorFunction; switch (value) { case "@foliage": - colorFunction = BlockColorCalculator::getFoliageAverageColor; + colorFunction = BlockColorCalculator::getBlendedFoliageColor; break; case "@grass": - colorFunction = BlockColorCalculator::getGrassAverageColor; + colorFunction = BlockColorCalculator::getBlendedGrassColor; break; case "@water": - colorFunction = BlockColorCalculator::getWaterAverageColor; + colorFunction = BlockColorCalculator::getBlendedWaterColor; break; case "@redstone": colorFunction = BlockColorCalculator::getRedstoneColor; @@ -120,17 +123,18 @@ public class BlockColorCalculator { private final Color tempColor = new Color(); + @SuppressWarnings("UnusedReturnValue") public Color getBlockColor(BlockNeighborhood block, Color target) { String blockId = block.getBlockState().getFormatted(); ColorFunction colorFunction = blockColorMap.get(blockId); if (colorFunction == null) colorFunction = blockColorMap.get("default"); - if (colorFunction == null) colorFunction = BlockColorCalculator::getFoliageAverageColor; + if (colorFunction == null) colorFunction = BlockColorCalculator::getBlendedFoliageColor; return colorFunction.invoke(this, block, target); } - public Color getRedstoneColor(BlockNeighborhood block, Color target) { + public Color getRedstoneColor(Block block, Color target) { int power = block.getBlockState().getRedstonePower(); return target.set( (power + 5f) / 20f, 0f, 0f, @@ -138,15 +142,15 @@ public Color getRedstoneColor(BlockNeighborhood block, Color target) { ); } - public Color getWaterAverageColor(BlockNeighborhood block, Color target) { + public Color getBlendedWaterColor(BlockNeighborhood block, Color target) { target.set(0, 0, 0, 0, true); int x, y, z; Biome biome; - for (y = AVERAGE_MIN_Y; y <= AVERAGE_MAX_Y; y++) { - for (x = AVERAGE_MIN_X; x <= AVERAGE_MAX_X; x++) { - for (z = AVERAGE_MIN_Z; z <= AVERAGE_MAX_Z; z++) { + for (y = BLEND_MIN_Y; y <= BLEND_MAX_Y; y++) { + for (x = BLEND_MIN_X; x <= BLEND_MAX_X; x++) { + for (z = BLEND_MIN_Z; z <= BLEND_MAX_Z; z++) { biome = block.getNeighborBlock(x, y, z).getBiome(); target.add(biome.getWaterColor()); } @@ -156,15 +160,15 @@ public Color getWaterAverageColor(BlockNeighborhood block, Color target) { return target.flatten(); } - public Color getFoliageAverageColor(BlockNeighborhood block, Color target) { + public Color getBlendedFoliageColor(BlockNeighborhood block, Color target) { target.set(0, 0, 0, 0, true); int x, y, z; Biome biome; - for (y = AVERAGE_MIN_Y; y <= AVERAGE_MAX_Y; y++) { - for (x = AVERAGE_MIN_X; x <= AVERAGE_MAX_X; x++) { - for (z = AVERAGE_MIN_Z; z <= AVERAGE_MAX_Z; z++) { + for (y = BLEND_MIN_Y; y <= BLEND_MAX_Y; y++) { + for (x = BLEND_MIN_X; x <= BLEND_MAX_X; x++) { + for (z = BLEND_MIN_Z; z <= BLEND_MAX_Z; z++) { biome = block.getNeighborBlock(x, y, z).getBiome(); target.add(getFoliageColor(biome, tempColor)); } @@ -179,15 +183,15 @@ public Color getFoliageColor(Biome biome, Color target) { return target.overlay(biome.getOverlayFoliageColor()); } - public Color getGrassAverageColor(BlockNeighborhood block, Color target) { + public Color getBlendedGrassColor(BlockNeighborhood block, Color target) { target.set(0, 0, 0, 0, true); int x, y, z; Biome biome; - for (y = AVERAGE_MIN_Y; y <= AVERAGE_MAX_Y; y++) { - for (x = AVERAGE_MIN_X; x <= AVERAGE_MAX_X; x++) { - for (z = AVERAGE_MIN_Z; z <= AVERAGE_MAX_Z; z++) { + for (y = BLEND_MIN_Y; y <= BLEND_MAX_Y; y++) { + for (x = BLEND_MIN_X; x <= BLEND_MAX_X; x++) { + for (z = BLEND_MIN_Z; z <= BLEND_MAX_Z; z++) { biome = block.getNeighborBlock(x, y, z).getBiome(); target.add(getGrassColor(biome, tempColor)); } @@ -203,13 +207,13 @@ public Color getGrassColor(Biome biome, Color target) { } private void getColorFromMap(Biome biome, int[] colorMap, int defaultColor, Color target) { - double temperature = GenericMath.clamp(biome.getTemp(), 0.0, 1.0); - double humidity = GenericMath.clamp(biome.getHumidity(), 0.0, 1.0); + double temperature = GenericMath.clamp(biome.getTemperature(), 0.0, 1.0); + double downfall = GenericMath.clamp(biome.getDownfall(), 0.0, 1.0); - humidity *= temperature; + downfall *= temperature; int x = (int) ((1.0 - temperature) * 255.0); - int y = (int) ((1.0 - humidity) * 255.0); + int y = (int) ((1.0 - downfall) * 255.0); int index = y << 8 | x; int color = (index >= colorMap.length ? defaultColor : colorMap[index]) | 0xFF000000; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/MinecraftVersion.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/MinecraftVersion.java new file mode 100644 index 000000000..949ea09fd --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/MinecraftVersion.java @@ -0,0 +1,245 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.resources; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.stream.JsonReader; +import de.bluecolored.bluemap.api.debug.DebugDump; +import de.bluecolored.bluemap.core.logger.Logger; +import de.bluecolored.bluemap.core.util.FileHelper; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Reader; +import java.net.URL; +import java.nio.file.*; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + +@DebugDump +@Getter +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class MinecraftVersion { + private static final Gson GSON = new Gson(); + + private static final String LATEST_KNOWN_VERSION = "1.20.6"; + private static final String EARLIEST_RESOURCEPACK_VERSION = "1.13"; + private static final String EARLIEST_DATAPACK_VERSION = "1.19.4"; + + private final String id; + + private final Path resourcePack; + private final int resourcePackVersion; + + private final Path dataPack; + private final int dataPackVersion; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MinecraftVersion that = (MinecraftVersion) o; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + public static MinecraftVersion load(@Nullable String id, Path dataRoot, boolean allowDownload) throws IOException { + Path resourcePack; + Path dataPack; + + try { + VersionManifest manifest = VersionManifest.getOrFetch(); + if (id == null) id = manifest.getLatest().getRelease(); + + VersionManifest.Version version = manifest.getVersion(id); + VersionManifest.Version resourcePackVersion = manifest.getVersion(EARLIEST_RESOURCEPACK_VERSION); + VersionManifest.Version dataPackVersion = manifest.getVersion(EARLIEST_DATAPACK_VERSION); + + if (version == null) { + Logger.global.logWarning("Could not find any version for id '" + id + "'. Using fallback-version: " + LATEST_KNOWN_VERSION); + version = manifest.getVersion(LATEST_KNOWN_VERSION); + } + + if (version == null || resourcePackVersion == null || dataPackVersion == null) { + throw new IOException("Manifest is missing versions."); + } + + if (version.compareTo(resourcePackVersion) > 0) resourcePackVersion = version; + if (version.compareTo(dataPackVersion) > 0) dataPackVersion = version; + + resourcePack = dataRoot.resolve(getClientVersionFileName(resourcePackVersion.getId())); + dataPack = dataRoot.resolve(getClientVersionFileName(dataPackVersion.getId())); + + if (allowDownload) { + if (!Files.exists(resourcePack)) download(resourcePackVersion, resourcePack); + if (!Files.exists(dataPack)) download(dataPackVersion, dataPack); + } + + } catch (IOException ex) { + if (id == null) throw ex; + + Logger.global.logWarning("Failed to fetch version-info from mojang-servers: " + ex); + + resourcePack = dataRoot.resolve(getClientVersionFileName(id)); + dataPack = resourcePack; + } + + if (!Files.exists(resourcePack)) throw new IOException("Resource-File missing: " + resourcePack); + if (!Files.exists(dataPack)) throw new IOException("Resource-File missing: " + dataPack); + + VersionInfo resourcePackVersionInfo = loadVersionInfo(resourcePack); + VersionInfo dataPackVersionInfo = resourcePack.equals(dataPack) ? resourcePackVersionInfo : loadVersionInfo(dataPack); + + return new MinecraftVersion( + id, + resourcePack, resourcePackVersionInfo.getResourcePackVersion(), + dataPack, dataPackVersionInfo.getDataPackVersion() + ); + + } + + private static void download(VersionManifest.Version version, Path file) throws IOException { + boolean downloadCompletedAndVerified = false; + VersionManifest.Download download = version.fetchDetail().getDownloads().getClient(); + Logger.global.logInfo("Downloading '" + download.getUrl() + "' to '" + file + "'..."); + + FileHelper.createDirectories(file.toAbsolutePath().normalize().getParent()); + + try ( + DigestInputStream in = new DigestInputStream(new URL(download.getUrl()).openStream(), MessageDigest.getInstance("SHA-1")); + OutputStream out = Files.newOutputStream(file, StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW, StandardOpenOption.TRUNCATE_EXISTING) + ) { + in.transferTo(out); + + // verify sha-1 + if (!Arrays.equals( + in.getMessageDigest().digest(), + hexStringToByteArray(download.getSha1()) + )) { + throw new IOException("SHA-1 of the downloaded file does not match!"); + } + + downloadCompletedAndVerified = true; + } catch (NoSuchAlgorithmException | IOException ex) { + Logger.global.logWarning("Failed to download '" + download.getUrl() + "': " + ex); + } finally { + if (!downloadCompletedAndVerified) + Files.deleteIfExists(file); + } + + } + + private static String getClientVersionFileName(String versionId) { + return "minecraft-client-" + versionId + ".jar"; + } + + public static byte[] hexStringToByteArray(String hexString) { + int length = hexString.length(); + if (length % 2 != 0) + throw new IllegalArgumentException("Invalid hex-string."); + + int halfLength = length / 2; + + byte[] data = new byte[halfLength]; + int c; + for (int i = 0; i < halfLength; i += 1) { + c = i * 2; + data[i] = (byte) ( + (Character.digit(hexString.charAt(c), 16) << 4) + + Character.digit(hexString.charAt(c + 1), 16) + ); + } + + return data; + } + + private static VersionInfo loadVersionInfo(Path file) throws IOException { + try (FileSystem fileSystem = FileSystems.newFileSystem(file, (ClassLoader) null)) { + for (Path fsRoot : fileSystem.getRootDirectories()) { + if (!Files.isDirectory(fsRoot)) continue; + + Path versionFile = fsRoot.resolve("version.json"); + if (!Files.exists(versionFile)) continue; + + try (Reader reader = Files.newBufferedReader(file)) { + return GSON.fromJson(reader, VersionInfo.class); + } + } + + throw new IOException("'" + file + "' does not contain a 'version.json'"); + } + } + + @Getter + @RequiredArgsConstructor + @JsonAdapter(VersionInfoAdapter.class) + public static class VersionInfo { + + private final int resourcePackVersion; + private final int dataPackVersion; + + } + + public static class VersionInfoAdapter extends AbstractTypeAdapterFactory { + + public VersionInfoAdapter(Class type) { + super(type); + } + + @Override + public VersionInfo read(JsonReader in, Gson gson) throws IOException { + JsonObject object = gson.fromJson(in, JsonObject.class); + + JsonElement packVersion = object.get("pack_version"); + if (packVersion instanceof JsonObject packVersionObject) { + return new VersionInfo( + packVersionObject.get("resource").getAsInt(), + packVersionObject.get("data").getAsInt() + ); + } else { + int version = packVersion.getAsInt(); + return new VersionInfo( + version, + version + ); + } + } + + } + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/PackMeta.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/PackMeta.java new file mode 100644 index 000000000..6af44dfd5 --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/PackMeta.java @@ -0,0 +1,86 @@ +package de.bluecolored.bluemap.core.resources; + +import com.google.gson.Gson; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; + +@Getter +@SuppressWarnings({"FieldMayBeFinal", "unused"}) +public class PackMeta { + + private Pack pack = new Pack(); + private Overlays overlays = new Overlays(); + + @Getter + public static class Pack { + private VersionRange packFormat = new VersionRange(); + private @Nullable VersionRange supportedFormats; + } + + @Getter + public static class Overlays { + private Overlay[] entries = new Overlay[0]; + } + + @Getter + public static class Overlay { + private VersionRange formats = new VersionRange(); + private @Nullable String directory; + } + + @Getter + @NoArgsConstructor + @AllArgsConstructor + @JsonAdapter(VersionRange.Adapter.class) + public static class VersionRange { + private int minInclusive = Integer.MIN_VALUE; + private int maxInclusive = Integer.MAX_VALUE; + + public boolean includes(int version) { + return version >= minInclusive && version <= maxInclusive; + } + + private static class Adapter extends AbstractTypeAdapterFactory { + + public Adapter(Class type) { + super(type); + } + + @Override + public VersionRange read(JsonReader in, Gson gson) throws IOException { + return switch (in.peek()) { + case NUMBER -> { + int version = in.nextInt(); + yield new VersionRange(version, version); + } + case BEGIN_ARRAY -> { + in.beginArray(); + VersionRange range = new VersionRange( + in.nextInt(), + in.nextInt() + ); + + while (in.peek() != JsonToken.END_ARRAY) + in.skipValue(); + in.endArray(); + + yield range; + } + default -> gson + .getDelegateAdapter(this, TypeToken.get(VersionRange.class)) + .read(in); + }; + } + + } + } + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/VersionManifest.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/VersionManifest.java new file mode 100644 index 000000000..a398264fe --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/VersionManifest.java @@ -0,0 +1,133 @@ +package de.bluecolored.bluemap.core.resources; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import de.bluecolored.bluemap.core.resources.adapter.LocalDateTimeAdapter; +import lombok.AccessLevel; +import lombok.Getter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.*; +import java.net.URL; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; + +@Getter +@SuppressWarnings({"FieldMayBeFinal", "unused"}) +public class VersionManifest { + + public static final String DOMAIN = "https://piston-meta.mojang.com/"; + public static final String MANIFEST_URL = DOMAIN + "mc/game/version_manifest.json"; + + private static final Gson GSON = new GsonBuilder() + .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeAdapter()) + .create(); + + private static VersionManifest instance; + + private Latest latest; + private Version[] versions; + + @Getter(AccessLevel.NONE) + private transient @Nullable Map versionMap; + + @Getter(AccessLevel.NONE) + private transient boolean sorted; + + + public static VersionManifest getOrFetch() throws IOException { + if (instance == null) return fetch(); + return instance; + } + + public static VersionManifest fetch() throws IOException { + try ( + InputStream in = new URL(MANIFEST_URL).openStream(); + Reader reader = new BufferedReader(new InputStreamReader(in)) + ) { + instance = GSON.fromJson(reader, VersionManifest.class); + } + return instance; + } + + /** + * An array of versions, ordered newest first + */ + public synchronized Version[] getVersions() { + if (!sorted) Arrays.sort(versions, Comparator.reverseOrder()); + return versions; + } + + public synchronized @Nullable Version getVersion(String id) { + if (versionMap == null) { + versionMap = new HashMap<>(); + for (Version version : versions) + versionMap.put(version.id, version); + } + + return versionMap.get(id); + } + + @Getter + public static class Latest { + private String release; + private String snapshot; + } + + @Getter + public static class Version implements Comparable { + + private String id; + private String type; + private String url; + private LocalDateTime time; + private LocalDateTime releaseTime; + + @Getter(AccessLevel.NONE) + private transient @Nullable VersionDetail detail; + + public synchronized VersionDetail fetchDetail() throws IOException { + if (detail == null) { + try ( + InputStream in = new URL(url).openStream(); + Reader reader = new BufferedReader(new InputStreamReader(in)) + ) { + detail = GSON.fromJson(reader, VersionDetail.class); + } + } + + return detail; + } + + @Override + public int compareTo(@NotNull VersionManifest.Version version) { + return releaseTime.compareTo(version.releaseTime); + } + + } + + @Getter + public static class VersionDetail { + private String id; + private String type; + private Downloads downloads; + } + + @Getter + public static class Downloads { + private Download client; + private Download server; + } + + @Getter + public static class Download { + private String url; + private long size; + private String sha1; + } + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/LocalDateTimeAdapter.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/LocalDateTimeAdapter.java new file mode 100644 index 000000000..76c87314e --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/LocalDateTimeAdapter.java @@ -0,0 +1,23 @@ +package de.bluecolored.bluemap.core.resources.adapter; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class LocalDateTimeAdapter extends TypeAdapter { + + @Override + public void write(JsonWriter out, LocalDateTime value) throws IOException { + out.value(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(value)); + } + + @Override + public LocalDateTime read(JsonReader in) throws IOException { + return LocalDateTime.from(DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(in.nextString())); + } + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/ResourcesGson.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/ResourcesGson.java index 5dfc46e19..9577390bf 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/ResourcesGson.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/ResourcesGson.java @@ -29,7 +29,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; -import de.bluecolored.bluemap.core.resources.resourcepack.blockmodel.Face; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.Face; import de.bluecolored.bluemap.core.util.Direction; import de.bluecolored.bluemap.core.util.math.Axis; import de.bluecolored.bluemap.core.util.math.Color; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/biome/BiomeConfig.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/biome/BiomeConfig.java deleted file mode 100644 index c7d3a8f9b..000000000 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/biome/BiomeConfig.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * This file is part of BlueMap, licensed under the MIT License (MIT). - * - * Copyright (c) Blue (Lukas Rieger) - * 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.resources.biome; - -import com.google.gson.stream.JsonReader; -import de.bluecolored.bluemap.api.debug.DebugDump; -import de.bluecolored.bluemap.core.resources.adapter.ResourcesGson; -import de.bluecolored.bluemap.core.resources.biome.datapack.DpBiome; -import de.bluecolored.bluemap.core.world.Biome; - -import java.io.BufferedReader; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; - -@DebugDump -public class BiomeConfig { - - private final Map biomes; - - public BiomeConfig() { - biomes = new HashMap<>(); - } - - public void load(Path configFile) throws IOException { - try (BufferedReader reader = Files.newBufferedReader(configFile)) { - JsonReader json = new JsonReader(reader); - json.setLenient(true); - - json.beginObject(); - - while (json.hasNext()) { - String formatted = json.nextName(); - BiomeConfigEntry entry = ResourcesGson.INSTANCE.fromJson(json, BiomeConfigEntry.class); - Biome biome = entry.createBiome(formatted); - - // don't overwrite already present values, higher priority resources are loaded first - biomes.putIfAbsent(biome.getFormatted(), biome); - } - - json.endObject(); - } - } - - public void loadDatapackBiome(String namespace, Path biomeFile) throws IOException { - try (BufferedReader reader = Files.newBufferedReader(biomeFile)) { - JsonReader json = new JsonReader(reader); - json.setLenient(true); - DpBiome dpBiome = ResourcesGson.INSTANCE.fromJson(json, DpBiome.class); - - String formatted = namespace + ":" + biomeFile.getFileName().toString(); - int fileEndingDot = formatted.lastIndexOf('.'); - if (fileEndingDot != -1) formatted = formatted.substring(0, fileEndingDot); - - Biome biome = dpBiome.createBiome(formatted); - - // don't overwrite already present values, higher priority resources are loaded first - biomes.putIfAbsent(biome.getFormatted(), biome); - } - } - - public Biome getBiome(String formatted) { - return biomes.getOrDefault(formatted, Biome.DEFAULT); - } - -} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/biome/BiomeConfigEntry.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/biome/BiomeConfigEntry.java deleted file mode 100644 index 0b93d8818..000000000 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/biome/BiomeConfigEntry.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * This file is part of BlueMap, licensed under the MIT License (MIT). - * - * Copyright (c) Blue (Lukas Rieger) - * 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.resources.biome; - -import de.bluecolored.bluemap.core.util.math.Color; -import de.bluecolored.bluemap.core.world.Biome; - -@SuppressWarnings("FieldMayBeFinal") -public class BiomeConfigEntry { - - private float humidity = Biome.DEFAULT.getHumidity(); - private float temperature = Biome.DEFAULT.getTemp(); - private Color watercolor = Biome.DEFAULT.getWaterColor(); - private Color grasscolor = new Color(); - private Color foliagecolor = new Color(); - - public Biome createBiome(String formatted) { - return new Biome( - formatted, - humidity, - temperature, - watercolor.premultiplied(), - foliagecolor.premultiplied(), - grasscolor.premultiplied() - ); - } - - public float getHumidity() { - return humidity; - } - - public float getTemperature() { - return temperature; - } - - public Color getWatercolor() { - return watercolor; - } - - public Color getGrasscolor() { - return grasscolor; - } - - public Color getFoliagecolor() { - return foliagecolor; - } - -} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/biome/datapack/DpBiomeEffects.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/biome/datapack/DpBiomeEffects.java deleted file mode 100644 index 807b80b62..000000000 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/biome/datapack/DpBiomeEffects.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file is part of BlueMap, licensed under the MIT License (MIT). - * - * Copyright (c) Blue (Lukas Rieger) - * 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.resources.biome.datapack; - -import de.bluecolored.bluemap.core.util.math.Color; -import de.bluecolored.bluemap.core.world.Biome; -import lombok.Getter; - -@SuppressWarnings("FieldMayBeFinal") -@Getter -public class DpBiomeEffects { - - private Color waterColor = Biome.DEFAULT.getWaterColor(); - private Color foliageColor = Biome.DEFAULT.getOverlayFoliageColor(); - private Color grassColor = Biome.DEFAULT.getOverlayGrassColor(); - -} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/Pack.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/Pack.java new file mode 100644 index 000000000..f37b712f1 --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/Pack.java @@ -0,0 +1,125 @@ +package de.bluecolored.bluemap.core.resources.pack; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import de.bluecolored.bluemap.core.logger.Logger; +import de.bluecolored.bluemap.core.resources.PackMeta; +import de.bluecolored.bluemap.core.resources.ResourcePath; +import de.bluecolored.bluemap.core.resources.adapter.ResourcesGson; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.io.BufferedReader; +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; +import java.util.concurrent.CompletionException; +import java.util.stream.Stream; + +@RequiredArgsConstructor +@Getter +public abstract class Pack { + + private final int packVersion; + + public abstract void loadResources(Iterable roots) throws IOException, InterruptedException; + + protected void loadResourcePath(Path root, ResourcePack.PathLoader resourceLoader) throws IOException, InterruptedException { + if (Thread.interrupted()) throw new InterruptedException(); + if (!Files.isDirectory(root)) { + try (FileSystem fileSystem = FileSystems.newFileSystem(root, (ClassLoader) null)) { + for (Path fsRoot : fileSystem.getRootDirectories()) { + if (!Files.isDirectory(fsRoot)) continue; + loadResourcePath(fsRoot, resourceLoader); + } + } catch (Exception ex) { + Logger.global.logDebug("Failed to read '" + root + "': " + ex); + } + return; + } + + // load nested jars from fabric.mod.json if present + Path fabricModJson = root.resolve("fabric.mod.json"); + if (Files.isRegularFile(fabricModJson)) { + try (BufferedReader reader = Files.newBufferedReader(fabricModJson)) { + JsonObject rootElement = ResourcesGson.INSTANCE.fromJson(reader, JsonObject.class); + if (rootElement.has("jars")) { + for (JsonElement element : rootElement.getAsJsonArray("jars")) { + Path file = root.resolve(element.getAsJsonObject().get("file").getAsString()); + if (Files.exists(file)) loadResourcePath(file, resourceLoader); + } + } + } catch (Exception ex) { + Logger.global.logDebug("Failed to read fabric.mod.json: " + ex); + } + } + + // load overlays + Path packMetaFile = root.resolve("pack.mcmeta"); + if (Files.isRegularFile(packMetaFile)) { + try (BufferedReader reader = Files.newBufferedReader(packMetaFile)) { + PackMeta packMeta = ResourcesGson.INSTANCE.fromJson(reader, PackMeta.class); + PackMeta.Overlay[] overlays = packMeta.getOverlays().getEntries(); + for (int i = overlays.length - 1; i >= 0; i--) { + PackMeta.Overlay overlay = overlays[i]; + String dir = overlay.getDirectory(); + if (dir != null && overlay.getFormats().includes(this.packVersion)) { + Path overlayRoot = root.resolve(dir); + if (Files.exists(overlayRoot)) loadResourcePath(overlayRoot, resourceLoader); + } + } + } catch (Exception ex) { + Logger.global.logDebug("Failed to read pack.mcmeta: " + ex); + } + } + + resourceLoader.load(root); + } + + protected void loadResource(Path root, Path file, Loader loader, Map, T> resultMap) { + try { + ResourcePath resourcePath = new ResourcePath<>(root.relativize(file)); + if (resultMap.containsKey(resourcePath)) return; // don't load already present resources + + T resource = loader.load(resourcePath); + if (resource == null) return; // don't load missing resources + + resourcePath.setResource(resource); + resultMap.put(resourcePath, resource); + } catch (Exception ex) { + Logger.global.logDebug("Failed to parse resource-file '" + file + "': " + ex); + } + } + + protected static Stream list(Path root) { + if (!Files.isDirectory(root)) return Stream.empty(); + try { + return Files.list(root); + } catch (IOException ex) { + throw new CompletionException(ex); + } + } + + protected static Stream walk(Path root) { + if (!Files.exists(root)) return Stream.empty(); + if (Files.isRegularFile(root)) return Stream.of(root); + try { + return Files.walk(root); + } catch (IOException ex) { + throw new CompletionException(ex); + } + } + + protected interface Loader { + T load(ResourcePath resourcePath) throws IOException; + } + + protected interface PathLoader { + void load(Path root) throws IOException; + } + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/datapack/DataPack.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/DataPack.java similarity index 57% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/datapack/DataPack.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/DataPack.java index 632565cb4..9653a17cd 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/datapack/DataPack.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/DataPack.java @@ -22,28 +22,27 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package de.bluecolored.bluemap.core.resources.datapack; +package de.bluecolored.bluemap.core.resources.pack.datapack; import de.bluecolored.bluemap.core.logger.Logger; -import de.bluecolored.bluemap.core.resources.ResourcePath; import de.bluecolored.bluemap.core.resources.adapter.ResourcesGson; -import de.bluecolored.bluemap.core.resources.datapack.dimension.DimensionTypeData; +import de.bluecolored.bluemap.core.resources.pack.Pack; +import de.bluecolored.bluemap.core.resources.pack.datapack.biome.DatapackBiome; +import de.bluecolored.bluemap.core.resources.pack.datapack.dimension.DimensionTypeData; import de.bluecolored.bluemap.core.util.Key; +import de.bluecolored.bluemap.core.world.Biome; import de.bluecolored.bluemap.core.world.DimensionType; +import de.bluecolored.bluemap.core.world.mca.chunk.LegacyBiomes; import org.jetbrains.annotations.Nullable; import java.io.BufferedReader; import java.io.IOException; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.CompletionException; -import java.util.stream.Stream; -public class DataPack { +public class DataPack extends Pack { public static final Key DIMENSION_OVERWORLD = new Key("minecraft", "overworld"); public static final Key DIMENSION_THE_NETHER = new Key("minecraft", "the_nether"); @@ -55,57 +54,57 @@ public class DataPack { public static final Key DIMENSION_TYPE_THE_END = new Key("minecraft", "the_end"); private final Map dimensionTypes = new HashMap<>(); + private final Map biomes = new HashMap<>(); - @Nullable - public DimensionType getDimensionType(Key key) { - return dimensionTypes.get(key); - } + private LegacyBiomes legacyBiomes; - public void load(Path root) throws InterruptedException { - Logger.global.logDebug("Loading datapack from: " + root + " ..."); - loadPath(root); + public DataPack(int packVersion) { + super(packVersion); } - private void loadPath(Path root) throws InterruptedException { - if (Thread.interrupted()) throw new InterruptedException(); - if (!Files.isDirectory(root)) { - try (FileSystem fileSystem = FileSystems.newFileSystem(root, (ClassLoader) null)) { - for (Path fsRoot : fileSystem.getRootDirectories()) { - if (!Files.isDirectory(fsRoot)) continue; - loadPath(fsRoot); - } - } catch (Exception ex) { - Logger.global.logDebug("Failed to read '" + root + "': " + ex); - } - return; + @Override + public void loadResources(Iterable roots) throws IOException, InterruptedException { + Logger.global.logInfo("Loading datapack..."); + + for (Path root : roots) { + Logger.global.logDebug("Loading datapack from: " + root + " ..."); + loadResources(root); } + Logger.global.logInfo("Baking datapack..."); + bake(); + + Logger.global.logInfo("Datapack loaded."); + } + + private void loadResources(Path root) throws InterruptedException, IOException { + loadResourcePath(root, this::loadPath); + } + + private void loadPath(Path root) { list(root.resolve("data")) .map(path -> path.resolve("dimension_type")) .filter(Files::isDirectory) .flatMap(DataPack::walk) .filter(path -> path.getFileName().toString().endsWith(".json")) .filter(Files::isRegularFile) - .forEach(file -> loadResource(root, file, () -> { + .forEach(file -> loadResource(root, file, key -> { try (BufferedReader reader = Files.newBufferedReader(file)) { return ResourcesGson.INSTANCE.fromJson(reader, DimensionTypeData.class); } }, dimensionTypes)); - } - private void loadResource(Path root, Path file, Loader loader, Map resultMap) { - try { - ResourcePath resourcePath = new ResourcePath<>(root.relativize(file)); - if (resultMap.containsKey(resourcePath)) return; // don't load already present resources - - T resource = loader.load(); - if (resource == null) return; // don't load missing resources - - resourcePath.setResource(resource); - resultMap.put(resourcePath, resource); - } catch (Exception ex) { - Logger.global.logDebug("Failed to parse resource-file '" + file + "': " + ex); - } + list(root.resolve("data")) + .map(path -> path.resolve("worldgen").resolve("biome")) + .filter(Files::isDirectory) + .flatMap(DataPack::walk) + .filter(path -> path.getFileName().toString().endsWith(".json")) + .filter(Files::isRegularFile) + .forEach(file -> loadResource(root, file, key -> { + try (BufferedReader reader = Files.newBufferedReader(file)) { + return new DatapackBiome(key, ResourcesGson.INSTANCE.fromJson(reader, DatapackBiome.Data.class)); + } + }, biomes)); } public void bake() { @@ -113,29 +112,20 @@ public void bake() { dimensionTypes.putIfAbsent(DIMENSION_TYPE_OVERWORLD_CAVES, DimensionType.OVERWORLD_CAVES); dimensionTypes.putIfAbsent(DIMENSION_TYPE_THE_NETHER, DimensionType.NETHER); dimensionTypes.putIfAbsent(DIMENSION_TYPE_THE_END, DimensionType.END); + + legacyBiomes = new LegacyBiomes(this); } - private static Stream list(Path root) { - if (!Files.isDirectory(root)) return Stream.empty(); - try { - return Files.list(root); - } catch (IOException ex) { - throw new CompletionException(ex); - } + public @Nullable DimensionType getDimensionType(Key key) { + return dimensionTypes.get(key); } - private static Stream walk(Path root) { - if (!Files.exists(root)) return Stream.empty(); - if (Files.isRegularFile(root)) return Stream.of(root); - try { - return Files.walk(root); - } catch (IOException ex) { - throw new CompletionException(ex); - } + public @Nullable Biome getBiome(Key key) { + return biomes.get(key); } - private interface Loader { - T load() throws IOException; + public @Nullable Biome getBiome(int legacyId) { + return legacyBiomes.forId(legacyId); } } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/biome/DatapackBiome.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/biome/DatapackBiome.java new file mode 100644 index 000000000..293530a88 --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/biome/DatapackBiome.java @@ -0,0 +1,61 @@ +package de.bluecolored.bluemap.core.resources.pack.datapack.biome; + +import de.bluecolored.bluemap.core.util.Key; +import de.bluecolored.bluemap.core.util.math.Color; +import de.bluecolored.bluemap.core.world.Biome; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Getter +public class DatapackBiome implements Biome { + + private final Key key; + private final Data data; + + @Override + public float getDownfall() { + return data.downfall; + } + + @Override + public float getTemperature() { + return data.temperature; + } + + @Override + public Color getWaterColor() { + return data.effects.waterColor; + } + + @Override + public Color getOverlayFoliageColor() { + return data.effects.foliageColor; + } + + @Override + public Color getOverlayGrassColor() { + return data.effects.grassColor; + } + + @SuppressWarnings("FieldMayBeFinal") + @Getter + public static class Data { + + private Effects effects = new Effects(); + private float temperature = Biome.DEFAULT.getTemperature(); + private float downfall = Biome.DEFAULT.getDownfall(); + + } + + @SuppressWarnings("FieldMayBeFinal") + @Getter + public static class Effects { + + private Color waterColor = Biome.DEFAULT.getWaterColor(); + private Color foliageColor = Biome.DEFAULT.getOverlayFoliageColor(); + private Color grassColor = Biome.DEFAULT.getOverlayGrassColor(); + + } + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/datapack/dimension/DimensionTypeData.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/dimension/DimensionTypeData.java similarity index 96% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/datapack/dimension/DimensionTypeData.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/dimension/DimensionTypeData.java index 44199368e..647b8f187 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/datapack/dimension/DimensionTypeData.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/dimension/DimensionTypeData.java @@ -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.resources.datapack.dimension; +package de.bluecolored.bluemap.core.resources.pack.datapack.dimension; import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.world.DimensionType; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/ResourcePack.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/ResourcePack.java similarity index 68% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/ResourcePack.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/ResourcePack.java index 06df48094..d1eff6793 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/ResourcePack.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/ResourcePack.java @@ -22,12 +22,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package de.bluecolored.bluemap.core.resources.resourcepack; +package de.bluecolored.bluemap.core.resources.pack.resourcepack; import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.LoadingCache; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.BlueMap; import de.bluecolored.bluemap.core.logger.Logger; @@ -35,14 +33,13 @@ import de.bluecolored.bluemap.core.resources.BlockPropertiesConfig; import de.bluecolored.bluemap.core.resources.ResourcePath; import de.bluecolored.bluemap.core.resources.adapter.ResourcesGson; -import de.bluecolored.bluemap.core.resources.biome.BiomeConfig; -import de.bluecolored.bluemap.core.resources.resourcepack.blockmodel.BlockModel; -import de.bluecolored.bluemap.core.resources.resourcepack.blockmodel.TextureVariable; -import de.bluecolored.bluemap.core.resources.resourcepack.blockstate.BlockState; -import de.bluecolored.bluemap.core.resources.resourcepack.texture.AnimationMeta; -import de.bluecolored.bluemap.core.resources.resourcepack.texture.Texture; +import de.bluecolored.bluemap.core.resources.pack.Pack; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.BlockModel; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.TextureVariable; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate.BlockState; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.texture.AnimationMeta; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.texture.Texture; import de.bluecolored.bluemap.core.util.Tristate; -import de.bluecolored.bluemap.core.world.Biome; import de.bluecolored.bluemap.core.world.BlockProperties; import org.jetbrains.annotations.Nullable; @@ -53,8 +50,6 @@ import java.io.InputStream; import java.io.Reader; import java.nio.charset.StandardCharsets; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.util.HashMap; @@ -62,40 +57,36 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; -import java.util.stream.Stream; @DebugDump -public class ResourcePack { +public class ResourcePack extends Pack { public static final ResourcePath MISSING_BLOCK_STATE = new ResourcePath<>("bluemap", "missing"); public static final ResourcePath MISSING_BLOCK_MODEL = new ResourcePath<>("bluemap", "block/missing"); public static final ResourcePath MISSING_TEXTURE = new ResourcePath<>("bluemap", "block/missing"); - private final Map> blockStatePaths; private final Map, BlockState> blockStates; - private final Map> blockModelPaths; private final Map, BlockModel> blockModels; - private final Map> texturePaths; private final Map, Texture> textures; - private final Map, BufferedImage> colormaps; + private final Map, BufferedImage> colormaps; private final BlockColorCalculatorFactory colorCalculatorFactory; - private final BiomeConfig biomeConfig; private final BlockPropertiesConfig blockPropertiesConfig; + private final Map> blockStatePaths; + private final Map> texturePaths; private final LoadingCache blockPropertiesCache; - public ResourcePack() { + public ResourcePack(int packVersion) { + super(packVersion); + this.blockStatePaths = new HashMap<>(); this.blockStates = new HashMap<>(); - this.blockModelPaths = new HashMap<>(); this.blockModels = new HashMap<>(); this.texturePaths = new HashMap<>(); this.textures = new HashMap<>(); this.colormaps = new HashMap<>(); this.colorCalculatorFactory = new BlockColorCalculatorFactory(); - this.biomeConfig = new BiomeConfig(); this.blockPropertiesConfig = new BlockPropertiesConfig(); this.blockPropertiesCache = Caffeine.newBuilder() @@ -104,88 +95,6 @@ public ResourcePack() { .build(this::loadBlockProperties); } - @Nullable - public ResourcePath getBlockStatePath(String formatted) { - return blockStatePaths.get(formatted); - } - - @Nullable - public BlockState getBlockState(de.bluecolored.bluemap.core.world.BlockState blockState) { - ResourcePath path = blockStatePaths.get(blockState.getFormatted()); - return path != null ? path.getResource(this::getBlockState) : MISSING_BLOCK_STATE.getResource(this::getBlockState); - } - - @Nullable - public BlockState getBlockState(ResourcePath path) { - BlockState blockState = blockStates.get(path); - return blockState != null ? blockState : MISSING_BLOCK_STATE.getResource(blockStates::get); - } - - public Map, BlockState> getBlockStates() { - return blockStates; - } - - @Nullable - public ResourcePath getBlockModelPath(String formatted) { - return blockModelPaths.get(formatted); - } - - @Nullable - public BlockModel getBlockModel(ResourcePath path) { - BlockModel blockModel = blockModels.get(path); - return blockModel != null ? blockModel : MISSING_BLOCK_MODEL.getResource(blockModels::get); - } - - public Map, BlockModel> getBlockModels() { - return blockModels; - } - - @Nullable - public ResourcePath getTexturePath(String formatted) { - return texturePaths.get(formatted); - } - - @Nullable - public Texture getTexture(ResourcePath path) { - Texture texture = textures.get(path); - return texture != null ? texture : MISSING_TEXTURE.getResource(textures::get); - } - - public Map, Texture> getTextures() { - return textures; - } - - public BlockColorCalculatorFactory getColorCalculatorFactory() { - return colorCalculatorFactory; - } - - public Biome getBiome(String formatted) { - return biomeConfig.getBiome(formatted); - } - - public BlockProperties getBlockProperties(de.bluecolored.bluemap.core.world.BlockState state) { - return blockPropertiesCache.get(state); - } - - private BlockProperties loadBlockProperties(de.bluecolored.bluemap.core.world.BlockState state) { - BlockProperties.Builder props = blockPropertiesConfig.getBlockProperties(state).toBuilder(); - - if (props.isOccluding() == Tristate.UNDEFINED || props.isCulling() == Tristate.UNDEFINED) { - BlockState resource = getBlockState(state); - if (resource != null) { - resource.forEach(state,0, 0, 0, variant -> { - BlockModel model = variant.getModel().getResource(this::getBlockModel); - if (model != null) { - if (props.isOccluding() == Tristate.UNDEFINED) props.occluding(model.isOccluding()); - if (props.isCulling() == Tristate.UNDEFINED) props.culling(model.isCulling()); - } - }); - } - } - - return props.build(); - } - public synchronized void loadResources(Iterable roots) throws IOException, InterruptedException { Logger.global.logInfo("Loading resources..."); @@ -209,43 +118,9 @@ public synchronized void loadResources(Iterable roots) throws IOException, Logger.global.logInfo("Baking resources..."); bake(); - Logger.global.logInfo("Resources loaded."); } - private void loadResourcePath(Path root, PathLoader resourceLoader) throws IOException, InterruptedException { - if (Thread.interrupted()) throw new InterruptedException(); - if (!Files.isDirectory(root)) { - try (FileSystem fileSystem = FileSystems.newFileSystem(root, (ClassLoader) null)) { - for (Path fsRoot : fileSystem.getRootDirectories()) { - if (!Files.isDirectory(fsRoot)) continue; - loadResourcePath(fsRoot, resourceLoader); - } - } catch (Exception ex) { - Logger.global.logDebug("Failed to read '" + root + "': " + ex); - } - return; - } - - // load nested jars from fabric.mod.json if present - Path fabricModJson = root.resolve("fabric.mod.json"); - if (Files.isRegularFile(fabricModJson)) { - try (BufferedReader reader = Files.newBufferedReader(fabricModJson)) { - JsonObject rootElement = ResourcesGson.INSTANCE.fromJson(reader, JsonObject.class); - if (rootElement.has("jars")) { - for (JsonElement element : rootElement.getAsJsonArray("jars")) { - Path file = root.resolve(element.getAsJsonObject().get("file").getAsString()); - if (Files.exists(file)) loadResourcePath(file, resourceLoader); - } - } - } catch (Exception ex) { - Logger.global.logDebug("Failed to read fabric.mod.json: " + ex); - } - } - - resourceLoader.load(root); - } - private void loadResources(Path root) throws IOException { try { // do those in parallel @@ -259,7 +134,7 @@ private void loadResources(Path root) throws IOException { .flatMap(ResourcePack::walk) .filter(path -> path.getFileName().toString().endsWith(".json")) .filter(Files::isRegularFile) - .forEach(file -> loadResource(root, file, () -> { + .forEach(file -> loadResource(root, file, key -> { try (BufferedReader reader = Files.newBufferedReader(file)) { return ResourcesGson.INSTANCE.fromJson(reader, BlockState.class); } @@ -275,7 +150,7 @@ private void loadResources(Path root) throws IOException { .flatMap(ResourcePack::walk) .filter(path -> path.getFileName().toString().endsWith(".json")) .filter(Files::isRegularFile) - .forEach(file -> loadResource(root, file, () -> { + .forEach(file -> loadResource(root, file, key -> { try (BufferedReader reader = Files.newBufferedReader(file)) { return ResourcesGson.INSTANCE.fromJson(reader, BlockModel.class); } @@ -287,7 +162,7 @@ private void loadResources(Path root) throws IOException { walk(root.resolve("assets").resolve("minecraft").resolve("textures").resolve("colormap")) .filter(path -> path.getFileName().toString().endsWith(".png")) .filter(Files::isRegularFile) - .forEach(file -> loadResource(root, file, () -> { + .forEach(file -> loadResource(root, file, key -> { try (InputStream in = Files.newInputStream(file)) { return ImageIO.read(in); } @@ -308,35 +183,6 @@ private void loadResources(Path root) throws IOException { }); }, BlueMap.THREAD_POOL), - // load biome configs - // TODO: move this to datapacks? - CompletableFuture.runAsync(() -> { - list(root.resolve("assets")) - .map(path -> path.resolve("biomes.json")) - .filter(Files::isRegularFile) - .forEach(file -> { - try { - biomeConfig.load(file); - } catch (Exception ex) { - Logger.global.logDebug("Failed to parse resource-file '" + file + "': " + ex); - } - }); - - list(root.resolve("data")) - .filter(Files::isDirectory) - .forEach(namespace -> list(namespace.resolve("worldgen").resolve("biome")) - .filter(path -> path.getFileName().toString().endsWith(".json")) - .filter(Files::isRegularFile) - .forEach(file -> { - try { - biomeConfig.loadDatapackBiome(namespace.getFileName().toString(), file); - } catch (Exception ex) { - Logger.global.logDebug("Failed to parse resource-file '" + file + "': " + ex); - } - }) - ); - }, BlueMap.THREAD_POOL), - // load block-properties configs CompletableFuture.runAsync(() -> { list(root.resolve("assets")) @@ -380,9 +226,8 @@ private void loadTextures(Path root) throws IOException { .flatMap(ResourcePack::walk) .filter(path -> path.getFileName().toString().endsWith(".png")) .filter(Files::isRegularFile) - .forEach(file -> loadResource(root, file, () -> { - ResourcePath resourcePath = new ResourcePath<>(root.relativize(file)); - if (!usedTextures.contains(resourcePath)) return null; // don't load unused textures + .forEach(file -> loadResource(root, file, key -> { + if (!usedTextures.contains(key)) return null; // don't load unused textures // load image BufferedImage image; @@ -399,8 +244,7 @@ private void loadTextures(Path root) throws IOException { } } - return Texture.from(resourcePath, image, animation); - + return Texture.from(key, image, animation); }, textures)); } catch (RuntimeException ex) { @@ -415,7 +259,6 @@ private void bake() throws IOException, InterruptedException { // fill path maps blockStates.keySet().forEach(path -> blockStatePaths.put(path.getFormatted(), path)); - blockModels.keySet().forEach(path -> blockModelPaths.put(path.getFormatted(), path)); textures.keySet().forEach(path -> texturePaths.put(path.getFormatted(), path)); // optimize references @@ -447,46 +290,64 @@ private void bake() throws IOException, InterruptedException { } - private void loadResource(Path root, Path file, Loader loader, Map, T> resultMap) { - try { - ResourcePath resourcePath = new ResourcePath<>(root.relativize(file)); - if (resultMap.containsKey(resourcePath)) return; // don't load already present resources + @Nullable + public BlockState getBlockState(de.bluecolored.bluemap.core.world.BlockState blockState) { + ResourcePath path = blockStatePaths.get(blockState.getFormatted()); + return path != null ? path.getResource(this::getBlockState) : MISSING_BLOCK_STATE.getResource(this::getBlockState); + } - T resource = loader.load(); - if (resource == null) return; // don't load missing resources + @Nullable + public BlockState getBlockState(ResourcePath path) { + BlockState blockState = blockStates.get(path); + return blockState != null ? blockState : MISSING_BLOCK_STATE.getResource(blockStates::get); + } - resourcePath.setResource(resource); - resultMap.put(resourcePath, resource); - } catch (Exception ex) { - Logger.global.logDebug("Failed to parse resource-file '" + file + "': " + ex); - } + @Nullable + public BlockModel getBlockModel(ResourcePath path) { + BlockModel blockModel = blockModels.get(path); + return blockModel != null ? blockModel : MISSING_BLOCK_MODEL.getResource(blockModels::get); } - private static Stream list(Path root) { - if (!Files.isDirectory(root)) return Stream.empty(); - try { - return Files.list(root); - } catch (IOException ex) { - throw new CompletionException(ex); - } + @Nullable + public ResourcePath getTexturePath(String formatted) { + return texturePaths.get(formatted); } - private static Stream walk(Path root) { - if (!Files.exists(root)) return Stream.empty(); - if (Files.isRegularFile(root)) return Stream.of(root); - try { - return Files.walk(root); - } catch (IOException ex) { - throw new CompletionException(ex); - } + @Nullable + public Texture getTexture(ResourcePath path) { + Texture texture = textures.get(path); + return texture != null ? texture : MISSING_TEXTURE.getResource(textures::get); + } + + public Map, Texture> getTextures() { + return textures; + } + + public BlockColorCalculatorFactory getColorCalculatorFactory() { + return colorCalculatorFactory; } - private interface Loader { - T load() throws IOException; + public BlockProperties getBlockProperties(de.bluecolored.bluemap.core.world.BlockState state) { + return blockPropertiesCache.get(state); } - private interface PathLoader { - void load(Path root) throws IOException; + private BlockProperties loadBlockProperties(de.bluecolored.bluemap.core.world.BlockState state) { + BlockProperties.Builder props = blockPropertiesConfig.getBlockProperties(state).toBuilder(); + + if (props.isOccluding() == Tristate.UNDEFINED || props.isCulling() == Tristate.UNDEFINED) { + BlockState resource = getBlockState(state); + if (resource != null) { + resource.forEach(state,0, 0, 0, variant -> { + BlockModel model = variant.getModel().getResource(this::getBlockModel); + if (model != null) { + if (props.isOccluding() == Tristate.UNDEFINED) props.occluding(model.isOccluding()); + if (props.isCulling() == Tristate.UNDEFINED) props.culling(model.isCulling()); + } + }); + } + } + + return props.build(); } } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockmodel/BlockModel.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/BlockModel.java similarity index 95% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockmodel/BlockModel.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/BlockModel.java index 23a3eba36..00dbae8d1 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockmodel/BlockModel.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/BlockModel.java @@ -22,12 +22,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package de.bluecolored.bluemap.core.resources.resourcepack.blockmodel; +package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel; import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.resources.ResourcePath; -import de.bluecolored.bluemap.core.resources.resourcepack.ResourcePack; -import de.bluecolored.bluemap.core.resources.resourcepack.texture.Texture; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.texture.Texture; import de.bluecolored.bluemap.core.util.Direction; import org.jetbrains.annotations.Nullable; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockmodel/Element.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Element.java similarity index 97% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockmodel/Element.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Element.java index aa74e1869..a022d063c 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockmodel/Element.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Element.java @@ -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.resources.resourcepack.blockmodel; +package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel; import com.flowpowered.math.vector.Vector3f; import com.flowpowered.math.vector.Vector4f; @@ -32,7 +32,7 @@ import com.google.gson.stream.JsonReader; import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.resources.AbstractTypeAdapterFactory; -import de.bluecolored.bluemap.core.resources.resourcepack.ResourcePack; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; import de.bluecolored.bluemap.core.util.Direction; import java.io.IOException; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockmodel/Face.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Face.java similarity index 95% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockmodel/Face.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Face.java index b5956a8b0..5c6ca23a5 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockmodel/Face.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Face.java @@ -22,11 +22,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package de.bluecolored.bluemap.core.resources.resourcepack.blockmodel; +package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel; import com.flowpowered.math.vector.Vector4f; import de.bluecolored.bluemap.api.debug.DebugDump; -import de.bluecolored.bluemap.core.resources.resourcepack.ResourcePack; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; import de.bluecolored.bluemap.core.util.Direction; import java.util.function.Function; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockmodel/Rotation.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Rotation.java similarity index 98% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockmodel/Rotation.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Rotation.java index fe3920d1b..009d9993b 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockmodel/Rotation.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Rotation.java @@ -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.resources.resourcepack.blockmodel; +package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel; import com.flowpowered.math.TrigMath; import com.flowpowered.math.vector.Vector3f; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockmodel/TextureVariable.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/TextureVariable.java similarity index 95% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockmodel/TextureVariable.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/TextureVariable.java index 6984d5013..f29b59969 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockmodel/TextureVariable.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/TextureVariable.java @@ -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.resources.resourcepack.blockmodel; +package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel; import com.google.gson.TypeAdapter; import com.google.gson.annotations.JsonAdapter; @@ -30,8 +30,8 @@ import com.google.gson.stream.JsonWriter; import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.resources.ResourcePath; -import de.bluecolored.bluemap.core.resources.resourcepack.ResourcePack; -import de.bluecolored.bluemap.core.resources.resourcepack.texture.Texture; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.texture.Texture; import org.jetbrains.annotations.Nullable; import java.io.IOException; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockstate/BlockState.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/BlockState.java similarity index 96% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockstate/BlockState.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/BlockState.java index 2a83f4705..26b01521a 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockstate/BlockState.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/BlockState.java @@ -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.resources.resourcepack.blockstate; +package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate; import de.bluecolored.bluemap.api.debug.DebugDump; import org.jetbrains.annotations.Nullable; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockstate/BlockStateCondition.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/BlockStateCondition.java similarity index 98% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockstate/BlockStateCondition.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/BlockStateCondition.java index 4663e214b..858907495 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockstate/BlockStateCondition.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/BlockStateCondition.java @@ -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.resources.resourcepack.blockstate; +package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate; import de.bluecolored.bluemap.api.debug.DebugDump; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockstate/Multipart.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Multipart.java similarity index 98% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockstate/Multipart.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Multipart.java index bdcc2dc35..87223503c 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockstate/Multipart.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Multipart.java @@ -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.resources.resourcepack.blockstate; +package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate; import com.google.gson.Gson; import com.google.gson.annotations.JsonAdapter; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockstate/Variant.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variant.java similarity index 92% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockstate/Variant.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variant.java index 192cc9143..ed491195b 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockstate/Variant.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variant.java @@ -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.resources.resourcepack.blockstate; +package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate; import com.google.gson.Gson; import com.google.gson.annotations.JsonAdapter; @@ -31,8 +31,8 @@ import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.resources.AbstractTypeAdapterFactory; import de.bluecolored.bluemap.core.resources.ResourcePath; -import de.bluecolored.bluemap.core.resources.resourcepack.ResourcePack; -import de.bluecolored.bluemap.core.resources.resourcepack.blockmodel.BlockModel; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.BlockModel; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; import de.bluecolored.bluemap.core.util.math.MatrixM3f; import java.io.IOException; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockstate/VariantSet.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/VariantSet.java similarity index 98% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockstate/VariantSet.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/VariantSet.java index 3275cbe58..b1e51482a 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockstate/VariantSet.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/VariantSet.java @@ -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.resources.resourcepack.blockstate; +package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate; import com.google.gson.Gson; import com.google.gson.annotations.JsonAdapter; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockstate/Variants.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variants.java similarity index 98% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockstate/Variants.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variants.java index f301c48b7..0630025b1 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/blockstate/Variants.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variants.java @@ -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.resources.resourcepack.blockstate; +package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate; import com.google.gson.Gson; import com.google.gson.annotations.JsonAdapter; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/texture/AnimationMeta.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/texture/AnimationMeta.java similarity index 98% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/texture/AnimationMeta.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/texture/AnimationMeta.java index 3aec544ee..2ff9bc3cf 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/texture/AnimationMeta.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/texture/AnimationMeta.java @@ -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.resources.resourcepack.texture; +package de.bluecolored.bluemap.core.resources.pack.resourcepack.texture; import com.google.gson.Gson; import com.google.gson.annotations.JsonAdapter; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/texture/Texture.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/texture/Texture.java similarity index 98% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/texture/Texture.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/texture/Texture.java index 0e5c58f37..ea7fcb87f 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/resourcepack/texture/Texture.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/texture/Texture.java @@ -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.resources.resourcepack.texture; +package de.bluecolored.bluemap.core.resources.pack.resourcepack.texture; import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.resources.ResourcePath; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/GridStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/GridStorage.java index 83a8566be..baaac7e69 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/GridStorage.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/GridStorage.java @@ -62,6 +62,11 @@ public interface GridStorage { */ boolean exists(int x, int z) throws IOException; + /** + * Returns a {@link ItemStorage} for the given position + */ + ItemStorage cell(int x, int z); + /** * Returns a stream over all existing items in this storage */ @@ -72,7 +77,7 @@ public interface GridStorage { */ boolean isClosed(); - interface Cell extends SingleItemStorage { + interface Cell extends ItemStorage { /** * Returns the x position of this item in the grid diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/SingleItemStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/ItemStorage.java similarity index 98% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/SingleItemStorage.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/ItemStorage.java index 4d4338aa6..698b76291 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/SingleItemStorage.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/ItemStorage.java @@ -30,7 +30,7 @@ import java.io.IOException; import java.io.OutputStream; -public interface SingleItemStorage { +public interface ItemStorage { /** * Returns an {@link OutputStream} that can be used to write the item-data of this storage diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/KeyedMapStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/KeyedMapStorage.java new file mode 100644 index 000000000..c0e565655 --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/KeyedMapStorage.java @@ -0,0 +1,77 @@ +package de.bluecolored.bluemap.core.storage; + +import de.bluecolored.bluemap.core.storage.compression.Compression; +import de.bluecolored.bluemap.core.util.Key; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public abstract class KeyedMapStorage implements MapStorage { + + private static final Key HIRES_TILES_KEY = Key.bluemap("hires"); + private static final Key TILE_STATE_KEY = Key.bluemap("tile-state"); + private static final Key CHUNK_STATE_KEY = Key.bluemap("chunk-state"); + private static final Key SETTINGS_KEY = Key.bluemap("settings"); + private static final Key TEXTURES_KEY = Key.bluemap("textures"); + private static final Key MARKERS_KEY = Key.bluemap("markers"); + private static final Key PLAYERS_KEY = Key.bluemap("players"); + + private final Compression compression; + + @Override + public GridStorage hiresTiles() { + return grid(HIRES_TILES_KEY, compression); + } + + @Override + public GridStorage lowresTiles(int lod) { + return grid(Key.bluemap("lowres/" + lod), Compression.NONE); + } + + @Override + public GridStorage tileState() { + return grid(TILE_STATE_KEY, Compression.GZIP); + } + + @Override + public GridStorage chunkState() { + return grid(CHUNK_STATE_KEY, Compression.GZIP); + } + + @Override + public ItemStorage asset(String name) { + return item(Key.bluemap("asset/" + MapStorage.escapeAssetName(name)), Compression.NONE); + } + + @Override + public ItemStorage settings() { + return item(SETTINGS_KEY, Compression.NONE); + } + + @Override + public ItemStorage textures() { + return item(TEXTURES_KEY, compression); + } + + @Override + public ItemStorage markers() { + return item(MARKERS_KEY, Compression.NONE); + } + + @Override + public ItemStorage players() { + return item(PLAYERS_KEY, Compression.NONE); + } + + /** + * Returns a {@link GridStorage} for the given {@link Key}.
+ * The compressionHint can be used if a new {@link GridStorage} needs to be created, but is not guaranteed. + */ + public abstract GridStorage grid(Key key, Compression compressionHint); + + /** + * Returns a {@link ItemStorage} for the given {@link Key}.
+ * The compressionHint can be used if a new {@link ItemStorage} needs to be created, but is not guaranteed. + */ + public abstract ItemStorage item(Key key, Compression compressionHint); + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/MapStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/MapStorage.java index bc2804027..711e0ee2b 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/MapStorage.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/MapStorage.java @@ -40,34 +40,39 @@ public interface MapStorage { GridStorage lowresTiles(int lod); /** - * Returns a {@link SingleItemStorage} for a map asset with the given name + * Returns a {@link GridStorage} for the tile-state (meta-) data of this map */ - SingleItemStorage asset(String name); + GridStorage tileState(); /** - * Returns a {@link SingleItemStorage} for the render-state data of this map + * Returns a {@link GridStorage} for the chunk-state (meta-) data of this map */ - SingleItemStorage renderState(); + GridStorage chunkState(); /** - * Returns a {@link SingleItemStorage} for the settings (settings.json) of this map + * Returns a {@link ItemStorage} for a map asset with the given name */ - SingleItemStorage settings(); + ItemStorage asset(String name); /** - * Returns a {@link SingleItemStorage} for the texture-data (textures.json) of this map + * Returns a {@link ItemStorage} for the settings (settings.json) of this map */ - SingleItemStorage textures(); + ItemStorage settings(); /** - * Returns a {@link SingleItemStorage} for the marker-data (live/markers.json) of this map + * Returns a {@link ItemStorage} for the texture-data (textures.json) of this map */ - SingleItemStorage markers(); + ItemStorage textures(); /** - * Returns a {@link SingleItemStorage} for the player-data (live/players.json) of this map + * Returns a {@link ItemStorage} for the marker-data (live/markers.json) of this map */ - SingleItemStorage players(); + ItemStorage markers(); + + /** + * Returns a {@link ItemStorage} for the player-data (live/players.json) of this map + */ + ItemStorage players(); /** * Deletes the entire map from the storage diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/Storage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/Storage.java index 274e78bdb..f75cdca0f 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/Storage.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/Storage.java @@ -37,7 +37,10 @@ public interface Storage extends Closeable { void initialize() throws IOException; /** - * Returns the {@link MapStorage} for the given mapId + * Returns the {@link MapStorage} for the given mapId.
+ *
+ * If this method is invoked multiple times with the same mapId, it is important that the returned MapStorage should at least + * be equal (equals() == true) to the previously returned storages! */ MapStorage map(String mapId); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/compression/CompressedInputStream.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/compression/CompressedInputStream.java index c7055a2cc..597d54a4b 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/compression/CompressedInputStream.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/compression/CompressedInputStream.java @@ -36,6 +36,14 @@ public class CompressedInputStream extends DelegateInputStream { private final Compression compression; + /** + * Creates a new CompressedInputStream with {@link Compression#NONE} from an (uncompressed) {@link InputStream}. + * This does not compress the provided InputStream. + */ + public CompressedInputStream(InputStream in) { + this(in, Compression.NONE); + } + /** * Creates a new CompressedInputStream from an already compressed {@link InputStream} and the {@link Compression} * it is compressed with. diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/PathBasedGridStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/FileGridStorage.java similarity index 67% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/PathBasedGridStorage.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/FileGridStorage.java index e27d1debe..81703b557 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/PathBasedGridStorage.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/FileGridStorage.java @@ -24,15 +24,17 @@ */ package de.bluecolored.bluemap.core.storage.file; +import de.bluecolored.bluemap.core.storage.GridStorage; +import de.bluecolored.bluemap.core.storage.ItemStorage; import de.bluecolored.bluemap.core.storage.compression.CompressedInputStream; import de.bluecolored.bluemap.core.storage.compression.Compression; -import de.bluecolored.bluemap.core.storage.GridStorage; -import de.bluecolored.bluemap.core.storage.SingleItemStorage; import lombok.Getter; import lombok.RequiredArgsConstructor; +import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.io.OutputStream; +import java.nio.file.Files; import java.nio.file.Path; import java.util.LinkedList; import java.util.Objects; @@ -41,68 +43,72 @@ import java.util.stream.Stream; @RequiredArgsConstructor -class PathBasedGridStorage implements GridStorage { +class FileGridStorage implements GridStorage { private static final Pattern ITEM_PATH_PATTERN = Pattern.compile("x(-?\\d+)z(-?\\d+)"); - private final PathBasedMapStorage storage; private final Path root; private final String suffix; private final Compression compression; + private final boolean atomic; @Override public OutputStream write(int x, int z) throws IOException { - return item(x, z).write(); + return cell(x, z).write(); } @Override - public CompressedInputStream read(int x, int z) throws IOException { - return item(x, z).read(); + public @Nullable CompressedInputStream read(int x, int z) throws IOException { + return cell(x, z).read(); } @Override public void delete(int x, int z) throws IOException { - item(x, z).delete(); + cell(x, z).delete(); } @Override public boolean exists(int x, int z) throws IOException { - return item(x, z).exists(); + return cell(x, z).exists(); + } + + @Override + public ItemStorage cell(int x, int z) { + return new FileItemStorage(getItemPath(x, z), compression, atomic); } + @SuppressWarnings("resource") @Override public Stream stream() throws IOException { - return storage.files(root) + if (!Files.exists(root)) return Stream.empty(); + return Files.walk(root) + .filter(Files::isRegularFile) .map(itemPath -> { Path path = itemPath; if (!path.startsWith(root)) return null; path = root.relativize(path); String name = path.toString(); - name = name.replace(root.getFileSystem().getSeparator(), ""); if (!name.endsWith(suffix)) return null; - name = name.substring(name.length() - suffix.length()); + name = name.substring(0, name.length() - suffix.length()); + name = name.replace(root.getFileSystem().getSeparator(), ""); Matcher matcher = ITEM_PATH_PATTERN.matcher(name); if (!matcher.matches()) return null; int x = Integer.parseInt(matcher.group(1)); int z = Integer.parseInt(matcher.group(2)); - return new PathCell(x, z, itemPath); + return new PathCell(x, z, itemPath, compression, atomic); }) .filter(Objects::nonNull); } @Override public boolean isClosed() { - return storage.isClosed(); - } - - public SingleItemStorage item(int x, int z) { - return storage.file(root.resolve(getGridPath(x, z)), compression); + return false; } - public Path getGridPath(int x, int z) { + public Path getItemPath(int x, int z) { StringBuilder sb = new StringBuilder() .append('x') .append(x) @@ -111,59 +117,34 @@ public Path getGridPath(int x, int z) { LinkedList folders = new LinkedList<>(); StringBuilder folder = new StringBuilder(); - sb.chars().forEach(i -> { - char c = (char) i; + for (int i = 0; i < sb.length(); i++) { + char c = sb.charAt(i); folder.append(c); if (c >= '0' && c <= '9') { folders.add(folder.toString()); folder.delete(0, folder.length()); } - }); + } String fileName = folders.removeLast(); folders.add(fileName + suffix); - return Path.of(folders.removeFirst(), folders.toArray(String[]::new)); + Path gridPath = root; + for (String part : folders) + gridPath = gridPath.resolve(part); + + return gridPath; } - @RequiredArgsConstructor - private class PathCell implements Cell { + private static class PathCell extends FileItemStorage implements Cell { @Getter private final int x, z; - private final Path path; - private SingleItemStorage storage; - - @Override - public OutputStream write() throws IOException { - return storage().write(); - } - - @Override - public CompressedInputStream read() throws IOException { - return storage().read(); - } - - @Override - public void delete() throws IOException { - storage().delete(); - } - - @Override - public boolean exists() throws IOException { - return storage().exists(); - } - - @Override - public boolean isClosed() { - return PathBasedGridStorage.this.isClosed(); - } - - private SingleItemStorage storage() { - if (storage == null) - storage = PathBasedGridStorage.this.storage.file(path, compression); - return storage; + public PathCell(int x, int z, Path itemPath, Compression compression, boolean atomic) { + super(itemPath, compression, atomic); + this.x = x; + this.z = z; } } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/FileItemStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/FileItemStorage.java new file mode 100644 index 000000000..1a51d76a2 --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/FileItemStorage.java @@ -0,0 +1,61 @@ +package de.bluecolored.bluemap.core.storage.file; + +import de.bluecolored.bluemap.core.storage.ItemStorage; +import de.bluecolored.bluemap.core.storage.compression.CompressedInputStream; +import de.bluecolored.bluemap.core.storage.compression.Compression; +import de.bluecolored.bluemap.core.util.FileHelper; +import lombok.RequiredArgsConstructor; +import org.jetbrains.annotations.Nullable; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; + +@RequiredArgsConstructor +public class FileItemStorage implements ItemStorage { + + private final Path file; + private final Compression compression; + private final boolean atomic; + + @Override + public OutputStream write() throws IOException { + if (atomic) + return compression.compress(FileHelper.createFilepartOutputStream(file)); + + Path folder = file.toAbsolutePath().normalize().getParent(); + FileHelper.createDirectories(folder); + return compression.compress(Files.newOutputStream(file, + StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE)); + } + + @Override + public @Nullable CompressedInputStream read() throws IOException { + if (!Files.exists(file)) return null; + try { + return new CompressedInputStream(Files.newInputStream(file), compression); + } catch (FileNotFoundException | NoSuchFileException ex) { + return null; + } + } + + @Override + public void delete() throws IOException { + if (Files.exists(file)) Files.delete(file); + } + + @Override + public boolean exists() { + return Files.exists(file); + } + + @Override + public boolean isClosed() { + return false; + } + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/FileMapStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/FileMapStorage.java index 95b009902..d909e8364 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/FileMapStorage.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/FileMapStorage.java @@ -24,49 +24,126 @@ */ package de.bluecolored.bluemap.core.storage.file; -import de.bluecolored.bluemap.core.storage.compression.CompressedInputStream; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; +import de.bluecolored.bluemap.core.storage.GridStorage; +import de.bluecolored.bluemap.core.storage.ItemStorage; +import de.bluecolored.bluemap.core.storage.MapStorage; import de.bluecolored.bluemap.core.storage.compression.Compression; -import de.bluecolored.bluemap.core.storage.SingleItemStorage; import de.bluecolored.bluemap.core.util.DeletingPathVisitor; -import de.bluecolored.bluemap.core.util.FileHelper; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import java.io.FileNotFoundException; import java.io.IOException; -import java.io.OutputStream; import java.nio.file.Files; -import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.util.LinkedList; import java.util.function.DoublePredicate; import java.util.stream.Collectors; import java.util.stream.Stream; -@Getter -public class FileMapStorage extends PathBasedMapStorage { +public class FileMapStorage implements MapStorage { + + private static final String TILES_PATH = "tiles"; + private static final String RENDER_STATE_PATH = "rstate"; + private static final String LIVE_PATH = "live"; private final Path root; + private final Compression compression; + private final boolean atomic; + + private final GridStorage hiresGridStorage; + private final LoadingCache lowresGridStorages; + private final GridStorage tileStateStorage; + private final GridStorage chunkStateStorage; + + public FileMapStorage(Path root, Compression compression, boolean atomic) { + this.root = root; + this.compression = compression; + this.atomic = atomic; - public FileMapStorage(Path root, Compression compression) { - super( + this.hiresGridStorage = new FileGridStorage( + root.resolve(TILES_PATH).resolve("0"), + ".prbm" + compression.getFileSuffix(), compression, - ".prbm", - ".png" + atomic ); - this.root = root; + + this.lowresGridStorages = Caffeine.newBuilder().build(lod -> new FileGridStorage( + root.resolve(TILES_PATH).resolve(String.valueOf(lod)), + ".png", + Compression.NONE, + atomic + )); + + this.tileStateStorage = new FileGridStorage( + root.resolve(RENDER_STATE_PATH), + ".tiles.dat", + Compression.GZIP, + atomic + ); + + this.chunkStateStorage = new FileGridStorage( + root.resolve(RENDER_STATE_PATH).resolve(""), + ".chunks.dat", + Compression.GZIP, + atomic + ); + + } + + @Override + public GridStorage hiresTiles() { + return hiresGridStorage; } @Override - public SingleItemStorage file(Path file, Compression compression) { - return new FileItemStorage(root.resolve(file), compression); + public GridStorage lowresTiles(int lod) { + return lowresGridStorages.get(lod); } @Override - @SuppressWarnings("resource") - public Stream files(Path path) throws IOException { - return Files.walk(root.resolve(path)) - .filter(Files::isRegularFile); + public GridStorage tileState() { + return tileStateStorage; + } + + @Override + public GridStorage chunkState() { + return chunkStateStorage; + } + + public Path getAssetPath(String name) { + String[] parts = MapStorage.escapeAssetName(name) + .split("/"); + + Path assetPath = root.resolve("assets"); + for (String part : parts) + assetPath = assetPath.resolve(part); + + return assetPath; + } + + @Override + public ItemStorage asset(String name) { + return new FileItemStorage(getAssetPath(name), Compression.NONE, atomic); + } + + @Override + public ItemStorage settings() { + return new FileItemStorage(root.resolve("settings.json"), Compression.NONE, atomic); + } + + @Override + public ItemStorage textures() { + return new FileItemStorage(root.resolve("textures.json" + compression.getFileSuffix()), compression, atomic); + } + + @Override + public ItemStorage markers() { + return new FileItemStorage(root.resolve(LIVE_PATH).resolve("markers.json"), Compression.NONE, atomic); + } + + @Override + public ItemStorage players() { + return new FileItemStorage(root.resolve(LIVE_PATH).resolve("players.json"), Compression.NONE, atomic); } @Override @@ -107,42 +184,4 @@ public boolean isClosed() { return false; } - @RequiredArgsConstructor - private static class FileItemStorage implements SingleItemStorage { - - private final Path file; - private final Compression compression; - - @Override - public OutputStream write() throws IOException { - return compression.compress(FileHelper.createFilepartOutputStream(file)); - } - - @Override - public CompressedInputStream read() throws IOException { - if (!Files.exists(file)) return null; - try { - return new CompressedInputStream(Files.newInputStream(file), compression); - } catch (FileNotFoundException | NoSuchFileException ex) { - return null; - } - } - - @Override - public void delete() throws IOException { - Files.delete(file); - } - - @Override - public boolean exists() { - return Files.exists(file); - } - - @Override - public boolean isClosed() { - return false; - } - - } - } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/FileStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/FileStorage.java index b23e6ca1e..97aa487f1 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/FileStorage.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/FileStorage.java @@ -39,11 +39,11 @@ public class FileStorage implements Storage { private final Path root; private final LoadingCache mapStorages; - public FileStorage(Path root, Compression compression) { + public FileStorage(Path root, Compression compression, boolean atomic) { this.root = root; mapStorages = Caffeine.newBuilder() - .build(id -> new FileMapStorage(root.resolve(id), compression)); + .build(id -> new FileMapStorage(root.resolve(id), compression, atomic)); } @Override diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/PathBasedMapStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/PathBasedMapStorage.java deleted file mode 100644 index 25001a25f..000000000 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/PathBasedMapStorage.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * This file is part of BlueMap, licensed under the MIT License (MIT). - * - * Copyright (c) Blue (Lukas Rieger) - * 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.storage.file; - -import com.github.benmanes.caffeine.cache.Caffeine; -import com.github.benmanes.caffeine.cache.LoadingCache; -import de.bluecolored.bluemap.core.storage.compression.Compression; -import de.bluecolored.bluemap.core.storage.GridStorage; -import de.bluecolored.bluemap.core.storage.MapStorage; -import de.bluecolored.bluemap.core.storage.SingleItemStorage; - -import java.io.IOException; -import java.nio.file.FileVisitOption; -import java.nio.file.Path; -import java.util.stream.Stream; - -public abstract class PathBasedMapStorage implements MapStorage { - - public static final Path SETTINGS_PATH = Path.of("settings.json"); - public static final Path TEXTURES_PATH = Path.of("textures.json"); - public static final Path RENDER_STATE_PATH = Path.of(".rstate"); - public static final Path MARKERS_PATH = Path.of("live", "markers.json"); - public static final Path PLAYERS_PATH = Path.of("live", "players.json"); - - private final GridStorage hiresGridStorage; - private final LoadingCache lowresGridStorages; - - public PathBasedMapStorage(Compression compression, String hiresSuffix, String lowresSuffix) { - this.hiresGridStorage = new PathBasedGridStorage( - this, - Path.of("tiles", "0"), - hiresSuffix + compression.getFileSuffix(), - compression - ); - - this.lowresGridStorages = Caffeine.newBuilder().build(lod -> new PathBasedGridStorage( - this, - Path.of("tiles", String.valueOf(lod)), - lowresSuffix, - Compression.NONE - )); - } - - @Override - public GridStorage hiresTiles() { - return hiresGridStorage; - } - - @Override - public GridStorage lowresTiles(int lod) { - return lowresGridStorages.get(lod); - } - - public Path getAssetPath(String name) { - String[] parts = MapStorage.escapeAssetName(name) - .split("/"); - return Path.of("assets", parts); - } - - @Override - public SingleItemStorage asset(String name) { - return file(getAssetPath(name), Compression.NONE); - } - - @Override - public SingleItemStorage renderState() { - return file(RENDER_STATE_PATH, Compression.NONE); - } - - @Override - public SingleItemStorage settings() { - return file(SETTINGS_PATH, Compression.NONE); - } - - @Override - public SingleItemStorage textures() { - return file(TEXTURES_PATH, Compression.NONE); - } - - @Override - public SingleItemStorage markers() { - return file(MARKERS_PATH, Compression.NONE); - } - - @Override - public SingleItemStorage players() { - return file(PLAYERS_PATH, Compression.NONE); - } - - /** - * Returns a {@link SingleItemStorage} for a file with the given path and compression. - * The file does not have to actually exist. - */ - public abstract SingleItemStorage file(Path file, Compression compression); - - /** - * Returns a stream with all file-paths of existing files at or below the given path. - * (Including files in potential sub-folders)
- * Basically, this method should mimic the functionality of - * {@link java.nio.file.Files#walk(Path, FileVisitOption...)} - */ - public abstract Stream files(Path path) throws IOException; - -} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/Database.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/Database.java index 50c7e1d41..c1bcb1a81 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/Database.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/Database.java @@ -78,6 +78,7 @@ public R run(ConnectionFunction action) throws IOException { SQLException sqlException = null; try { + // try the action 2 times if a "recoverable" exception is thrown for (int i = 0; i < 2; i++) { try (Connection connection = dataSource.getConnection()) { try { diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLTileStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLGridStorage.java similarity index 81% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLTileStorage.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLGridStorage.java index dc0194991..6c527ff7c 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLTileStorage.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLGridStorage.java @@ -24,10 +24,12 @@ */ package de.bluecolored.bluemap.core.storage.sql; +import de.bluecolored.bluemap.core.storage.ItemStorage; import de.bluecolored.bluemap.core.storage.compression.CompressedInputStream; import de.bluecolored.bluemap.core.storage.compression.Compression; import de.bluecolored.bluemap.core.storage.GridStorage; import de.bluecolored.bluemap.core.storage.sql.commandset.CommandSet; +import de.bluecolored.bluemap.core.util.Key; import de.bluecolored.bluemap.core.util.stream.OnCloseOutputStream; import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.Nullable; @@ -37,36 +39,41 @@ import java.util.stream.StreamSupport; @RequiredArgsConstructor -public class SQLTileStorage implements GridStorage { +public class SQLGridStorage implements GridStorage { private final CommandSet sql; - private final String mapId; - private final int lod; + private final String map; + private final Key storage; private final Compression compression; @Override public OutputStream write(int x, int z) throws IOException { ByteArrayOutputStream bytes = new ByteArrayOutputStream(); return new OnCloseOutputStream(compression.compress(bytes), - () -> sql.writeMapTile(mapId, lod, x, z, compression, bytes.toByteArray()) + () -> sql.writeGridItem(map, storage, x, z, compression, bytes.toByteArray()) ); } @Override public @Nullable CompressedInputStream read(int x, int z) throws IOException { - byte[] data = sql.readMapTile(mapId, lod, x, z, compression); + byte[] data = sql.readGridItem(map, storage, x, z, compression); if (data == null) return null; return new CompressedInputStream(new ByteArrayInputStream(data), compression); } @Override public void delete(int x, int z) throws IOException { - sql.deleteMapTile(mapId, lod, x, z, compression); + sql.deleteGridItem(map, storage, x, z); } @Override public boolean exists(int x, int z) throws IOException { - return sql.hasMapTile(mapId, lod, x, z, compression); + return sql.hasGridItem(map, storage, x, z, compression); + } + + @Override + public ItemStorage cell(int x, int z) { + return new GridStorageCell(this, x, z); } @Override @@ -74,7 +81,7 @@ public Stream stream() throws IOException { return StreamSupport.stream( new PageSpliterator<>(page -> { try { - return sql.listMapTiles(mapId, lod, compression, page * 1000, 1000); + return sql.listGridItems(map, storage, compression, page * 1000, 1000); } catch (IOException ex) { throw new RuntimeException(ex); } }), false diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLMetaItemStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLItemStorage.java similarity index 84% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLMetaItemStorage.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLItemStorage.java index 99075f1fb..0881470b8 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLMetaItemStorage.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLItemStorage.java @@ -26,8 +26,9 @@ import de.bluecolored.bluemap.core.storage.compression.CompressedInputStream; import de.bluecolored.bluemap.core.storage.compression.Compression; -import de.bluecolored.bluemap.core.storage.SingleItemStorage; +import de.bluecolored.bluemap.core.storage.ItemStorage; import de.bluecolored.bluemap.core.storage.sql.commandset.CommandSet; +import de.bluecolored.bluemap.core.util.Key; import de.bluecolored.bluemap.core.util.stream.OnCloseOutputStream; import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.Nullable; @@ -35,36 +36,36 @@ import java.io.*; @RequiredArgsConstructor -public class SQLMetaItemStorage implements SingleItemStorage { +public class SQLItemStorage implements ItemStorage { private final CommandSet sql; - private final String mapId; - private final String itemName; + private final String map; + private final Key storage; private final Compression compression; @Override public OutputStream write() throws IOException { ByteArrayOutputStream bytes = new ByteArrayOutputStream(); return new OnCloseOutputStream(compression.compress(bytes), - () -> sql.writeMapMeta(mapId, itemName, bytes.toByteArray()) + () -> sql.writeItem(map, storage, compression, bytes.toByteArray()) ); } @Override public @Nullable CompressedInputStream read() throws IOException { - byte[] data = sql.readMapMeta(mapId, itemName); + byte[] data = sql.readItem(map, storage, compression); if (data == null) return null; return new CompressedInputStream(new ByteArrayInputStream(data), compression); } @Override public void delete() throws IOException { - sql.deleteMapMeta(mapId, itemName); + sql.deleteItem(map, storage); } @Override public boolean exists() throws IOException { - return sql.hasMapMeta(mapId, itemName); + return sql.hasItem(map, storage, compression); } @Override diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLMapStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLMapStorage.java index d55abebf2..0f3377fc7 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLMapStorage.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/SQLMapStorage.java @@ -24,116 +24,53 @@ */ package de.bluecolored.bluemap.core.storage.sql; +import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; -import com.github.benmanes.caffeine.cache.LoadingCache; import de.bluecolored.bluemap.core.storage.GridStorage; -import de.bluecolored.bluemap.core.storage.MapStorage; -import de.bluecolored.bluemap.core.storage.SingleItemStorage; +import de.bluecolored.bluemap.core.storage.ItemStorage; +import de.bluecolored.bluemap.core.storage.KeyedMapStorage; import de.bluecolored.bluemap.core.storage.compression.Compression; import de.bluecolored.bluemap.core.storage.sql.commandset.CommandSet; +import de.bluecolored.bluemap.core.util.Key; import java.io.IOException; import java.util.function.DoublePredicate; -public class SQLMapStorage implements MapStorage { - - public static final String SETTINGS_META_NAME = "settings.json"; - public static final String TEXTURES_META_NAME = "textures.json"; - public static final String RENDER_STATE_META_NAME = ".rstate"; - public static final String MARKERS_META_NAME = "live/markers.json"; - public static final String PLAYERS_META_NAME = "live/players.json"; +public class SQLMapStorage extends KeyedMapStorage { private final String mapId; private final CommandSet sql; - private final SQLTileStorage hiresTileStorage; - private final LoadingCache lowresGridStorages; - - private final SingleItemStorage renderStateStorage; - private final SingleItemStorage settingsStorage; - private final SingleItemStorage texturesStorage; - private final SingleItemStorage markersStorage; - private final SingleItemStorage playersStorage; + private final Cache itemStorages = Caffeine.newBuilder().build(); + private final Cache gridStorages = Caffeine.newBuilder().build(); public SQLMapStorage(String mapId, CommandSet sql, Compression compression) { + super(compression); + this.mapId = mapId; this.sql = sql; - - this.hiresTileStorage = new SQLTileStorage( - sql, - mapId, - 0, - compression - ); - - this.lowresGridStorages = Caffeine.newBuilder().build(lod -> new SQLTileStorage( - sql, - mapId, - lod, - Compression.NONE - )); - - renderStateStorage = meta(RENDER_STATE_META_NAME, Compression.NONE); - settingsStorage = meta(SETTINGS_META_NAME, Compression.NONE); - texturesStorage = meta(TEXTURES_META_NAME, Compression.NONE); - markersStorage = meta(MARKERS_META_NAME, Compression.NONE); - playersStorage = meta(PLAYERS_META_NAME, Compression.NONE); - } - - @Override - public GridStorage hiresTiles() { - return hiresTileStorage; - } - - @Override - public GridStorage lowresTiles(int lod) { - return lowresGridStorages.get(lod); - } - - public String getAssetMetaName(String assetName) { - return "assets/" + MapStorage.escapeAssetName(assetName); - } - - @Override - public SingleItemStorage asset(String name) { - return meta(getAssetMetaName(name), Compression.NONE); } @Override - public SingleItemStorage renderState() { - return renderStateStorage; + public ItemStorage item(Key key, Compression compression) { + return itemStorages.get(key, k -> new SQLItemStorage(sql, mapId, key, compression)); } @Override - public SingleItemStorage settings() { - return settingsStorage; - } - - @Override - public SingleItemStorage textures() { - return texturesStorage; - } - - @Override - public SingleItemStorage markers() { - return markersStorage; - } - - @Override - public SingleItemStorage players() { - return playersStorage; + public GridStorage grid(Key key, Compression compression) { + return gridStorages.get(key, k -> new SQLGridStorage(sql, mapId, key, compression)); } @Override public void delete(DoublePredicate onProgress) throws IOException { // delete tiles in 1000er steps to track progress - int tileCount = sql.countAllMapTiles(mapId); + int tileCount = sql.countMapGridsItems(mapId); if (tileCount > 0) { int totalDeleted = 0; int deleted = 0; do { - deleted = sql.purgeMapTiles(mapId, 1000); + deleted = sql.purgeMapGrids(mapId, 1000); totalDeleted += deleted; if (!onProgress.test((double) totalDeleted / tileCount)) @@ -152,10 +89,6 @@ public boolean exists() throws IOException { return sql.hasMap(mapId); } - private SingleItemStorage meta(String name, Compression compression) { - return new SQLMetaItemStorage(sql, mapId, name, compression); - } - @Override public boolean isClosed() { return sql.isClosed(); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/commandset/AbstractCommandSet.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/commandset/AbstractCommandSet.java index 43b4de111..e5f71cf6b 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/commandset/AbstractCommandSet.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/commandset/AbstractCommandSet.java @@ -28,6 +28,7 @@ import com.github.benmanes.caffeine.cache.LoadingCache; import de.bluecolored.bluemap.core.storage.compression.Compression; import de.bluecolored.bluemap.core.storage.sql.Database; +import de.bluecolored.bluemap.core.util.Key; import lombok.RequiredArgsConstructor; import org.intellij.lang.annotations.Language; import org.jetbrains.annotations.Nullable; @@ -41,12 +42,16 @@ @RequiredArgsConstructor public abstract class AbstractCommandSet implements CommandSet { - private final Database db; + protected final Database db; - final LoadingCache mapKeys = Caffeine.newBuilder() + protected final LoadingCache mapKeys = Caffeine.newBuilder() .build(this::findOrCreateMapKey); - final LoadingCache compressionKeys = Caffeine.newBuilder() + protected final LoadingCache compressionKeys = Caffeine.newBuilder() .build(this::findOrCreateCompressionKey); + protected final LoadingCache itemStorageKeys = Caffeine.newBuilder() + .build(this::findOrCreateItemStorageKey); + protected final LoadingCache gridStorageKeys = Caffeine.newBuilder() + .build(this::findOrCreateGridStorageKey); @Language("sql") public abstract String createMapTableStatement(); @@ -55,53 +60,55 @@ public abstract class AbstractCommandSet implements CommandSet { public abstract String createCompressionTableStatement(); @Language("sql") - public abstract String createMapMetaTableStatement(); + public abstract String createItemStorageTableStatement(); @Language("sql") - public abstract String createMapTileTableStatement(); + public abstract String createItemStorageDataTableStatement(); @Language("sql") - public abstract String fixLegacyCompressionIdsStatement(); + public abstract String createGridStorageTableStatement(); + + @Language("sql") + public abstract String createGridStorageDataTableStatement(); public void initializeTables() throws IOException { db.run(connection -> { executeUpdate(connection, createMapTableStatement()); executeUpdate(connection, createCompressionTableStatement()); - executeUpdate(connection, createMapMetaTableStatement()); - executeUpdate(connection, createMapTileTableStatement()); + executeUpdate(connection, createItemStorageTableStatement()); + executeUpdate(connection, createItemStorageDataTableStatement()); + executeUpdate(connection, createGridStorageTableStatement()); + executeUpdate(connection, createGridStorageDataTableStatement()); }); - - db.run(connection -> executeUpdate(connection, fixLegacyCompressionIdsStatement())); } @Language("sql") - public abstract String writeMapTileStatement(); + public abstract String itemStorageWriteStatement(); @Override - public int writeMapTile( - String mapId, int lod, int x, int z, Compression compression, - byte[] bytes - ) throws IOException { + public void writeItem(String mapId, Key key, Compression compression, byte[] bytes) throws IOException { int mapKey = mapKey(mapId); + int storageKey = itemStorageKey(key); int compressionKey = compressionKey(compression); - return db.run(connection -> { - return executeUpdate(connection, - writeMapTileStatement(), - mapKey, lod, x, z, compressionKey, - bytes - ); - }); + db.run(connection -> executeUpdate(connection, + itemStorageWriteStatement(), + mapKey, storageKey, compressionKey, + bytes + )); } @Language("sql") - public abstract String readMapTileStatement(); + public abstract String itemStorageReadStatement(); @Override - public byte @Nullable [] readMapTile(String mapId, int lod, int x, int z, Compression compression) throws IOException { + public byte @Nullable [] readItem(String mapId, Key key, Compression compression) throws IOException { + int mapKey = mapKey(mapId); + int storageKey = itemStorageKey(key); + int compressionKey = compressionKey(compression); return db.run(connection -> { ResultSet result = executeQuery(connection, - readMapTileStatement(), - mapId, lod, x, z, compression.getKey().getFormatted() + itemStorageReadStatement(), + mapKey, storageKey, compressionKey ); if (!result.next()) return null; return result.getBytes(1); @@ -109,29 +116,30 @@ public int writeMapTile( } @Language("sql") - public abstract String deleteMapTileStatement(); + public abstract String itemStorageDeleteStatement(); @Override - public int deleteMapTile(String mapId, int lod, int x, int z, Compression compression) throws IOException { + public void deleteItem(String mapId, Key key) throws IOException { int mapKey = mapKey(mapId); - int compressionKey = compressionKey(compression); - return db.run(connection -> { - return executeUpdate(connection, - deleteMapTileStatement(), - mapKey, lod, x, z, compressionKey - ); - }); + int storageKey = itemStorageKey(key); + db.run(connection -> executeUpdate(connection, + itemStorageDeleteStatement(), + mapKey, storageKey + )); } @Language("sql") - public abstract String hasMapTileStatement(); + public abstract String itemStorageHasStatement(); @Override - public boolean hasMapTile(String mapId, int lod, int x, int z, Compression compression) throws IOException { + public boolean hasItem(String mapId, Key key, Compression compression) throws IOException { + int mapKey = mapKey(mapId); + int storageKey = itemStorageKey(key); + int compressionKey = compressionKey(compression); return db.run(connection -> { ResultSet result = executeQuery(connection, - hasMapTileStatement(), - mapId, lod, x, z, compression.getKey().getFormatted() + itemStorageHasStatement(), + mapKey, storageKey, compressionKey ); if (!result.next()) throw new IllegalStateException("Counting query returned empty result!"); return result.getBoolean(1); @@ -139,43 +147,93 @@ public boolean hasMapTile(String mapId, int lod, int x, int z, Compression compr } @Language("sql") - public abstract String countAllMapTilesStatement(); + public abstract String gridStorageWriteStatement(); @Override - public int countAllMapTiles(String mapId) throws IOException { + public void writeGridItem( + String mapId, Key key, int x, int z, Compression compression, + byte[] bytes + ) throws IOException { + int mapKey = mapKey(mapId); + int storageKey = gridStorageKey(key); + int compressionKey = compressionKey(compression); + db.run(connection -> executeUpdate(connection, + gridStorageWriteStatement(), + mapKey, storageKey, x, z, compressionKey, + bytes + )); + } + + @Language("sql") + public abstract String gridStorageReadStatement(); + + @Override + public byte @Nullable [] readGridItem( + String mapId, Key key, int x, int z, Compression compression + ) throws IOException { + int mapKey = mapKey(mapId); + int storageKey = gridStorageKey(key); + int compressionKey = compressionKey(compression); return db.run(connection -> { ResultSet result = executeQuery(connection, - countAllMapTilesStatement(), - mapId + gridStorageReadStatement(), + mapKey, storageKey, x, z, compressionKey ); - if (!result.next()) throw new IllegalStateException("Counting query returned empty result!"); - return result.getInt(1); + if (!result.next()) return null; + return result.getBytes(1); }); } @Language("sql") - public abstract String purgeMapTilesStatement(); + public abstract String gridStorageDeleteStatement(); @Override - public int purgeMapTiles(String mapId, int limit) throws IOException { + public void deleteGridItem( + String mapId, Key key, int x, int z + ) throws IOException { int mapKey = mapKey(mapId); + int storageKey = gridStorageKey(key); + db.run(connection -> executeUpdate(connection, + gridStorageDeleteStatement(), + mapKey, storageKey, x, z + )); + } + + @Language("sql") + public abstract String gridStorageHasStatement(); + + @Override + public boolean hasGridItem( + String mapId, Key key, int x, int z, Compression compression + ) throws IOException { + int mapKey = mapKey(mapId); + int storageKey = gridStorageKey(key); + int compressionKey = compressionKey(compression); return db.run(connection -> { - return executeUpdate(connection, - purgeMapTilesStatement(), - mapKey, limit + ResultSet result = executeQuery(connection, + gridStorageHasStatement(), + mapKey, storageKey, x, z, compressionKey ); + if (!result.next()) throw new IllegalStateException("Counting query returned empty result!"); + return result.getBoolean(1); }); } @Language("sql") - public abstract String listMapTilesStatement(); + public abstract String gridStorageListStatement(); @Override - public TilePosition[] listMapTiles(String mapId, int lod, Compression compression, int start, int count) throws IOException { + public TilePosition[] listGridItems( + String mapId, Key key, Compression compression, + int start, int count + ) throws IOException { + int mapKey = mapKey(mapId); + int storageKey = gridStorageKey(key); + int compressionKey = compressionKey(compression); return db.run(connection -> { ResultSet result = executeQuery(connection, - listMapTilesStatement(), - mapId, lod, compression.getKey().getFormatted(), + gridStorageListStatement(), + mapKey, storageKey, compressionKey, count, start ); @@ -199,96 +257,46 @@ public TilePosition[] listMapTiles(String mapId, int lod, Compression compressio } @Language("sql") - public abstract String writeMapMetaStatement(); + public abstract String gridStorageCountMapItemsStatement(); @Override - public int writeMapMeta(String mapId, String itemName, byte[] bytes) throws IOException { + public int countMapGridsItems(String mapId) throws IOException { int mapKey = mapKey(mapId); - return db.run(connection -> { - return executeUpdate(connection, - writeMapMetaStatement(), - mapKey, itemName, - bytes - ); - }); - } - - @Language("sql") - public abstract String readMapMetaStatement(); - - @Override - public byte @Nullable [] readMapMeta(String mapId, String itemName) throws IOException { return db.run(connection -> { ResultSet result = executeQuery(connection, - readMapMetaStatement(), - mapId, itemName + gridStorageCountMapItemsStatement(), + mapKey ); - if (!result.next()) return null; - return result.getBytes(1); + if (!result.next()) throw new IllegalStateException("Counting query returned empty result!"); + return result.getInt(1); }); } @Language("sql") - public abstract String deleteMapMetaStatement(); + public abstract String gridStoragePurgeMapStatement(); @Override - public int deleteMapMeta(String mapId, String itemName) throws IOException { + public int purgeMapGrids(String mapId, int limit) throws IOException { int mapKey = mapKey(mapId); return db.run(connection -> { return executeUpdate(connection, - deleteMapMetaStatement(), - mapKey, itemName - ); - }); - } - - @Language("sql") - public abstract String hasMapMetaStatement(); - - @Override - public boolean hasMapMeta(String mapId, String itemName) throws IOException { - return db.run(connection -> { - ResultSet result = executeQuery(connection, - hasMapMetaStatement(), - mapId, itemName + gridStoragePurgeMapStatement(), + mapKey, limit ); - if (!result.next()) throw new IllegalStateException("Counting query returned empty result!"); - return result.getBoolean(1); }); } @Language("sql") - public abstract String purgeMapTileTableStatement(); - - @Language("sql") - public abstract String purgeMapMetaTableStatement(); - - @Language("sql") - public abstract String deleteMapStatement(); + public abstract String purgeMapStatement(); @Override public void purgeMap(String mapId) throws IOException { synchronized (mapKeys) { int mapKey = mapKey(mapId); - db.run(connection -> { - - executeUpdate(connection, - purgeMapTileTableStatement(), - mapKey - ); - - executeUpdate(connection, - purgeMapMetaTableStatement(), - mapKey - ); - - executeUpdate(connection, - deleteMapStatement(), - mapKey - ); - - }); - + db.run(connection -> executeUpdate(connection, + purgeMapStatement(), + mapKey + )); mapKeys.invalidate(mapId); } } @@ -398,6 +406,78 @@ public int findOrCreateCompressionKey(Compression compression) throws IOExceptio }); } + @Language("sql") + public abstract String findItemStorageKeyStatement(); + + @Language("sql") + public abstract String createItemStorageKeyStatement(); + + public int itemStorageKey(Key key) { + synchronized (itemStorageKeys) { + //noinspection DataFlowIssue + return itemStorageKeys.get(key); + } + } + + public int findOrCreateItemStorageKey(Key key) throws IOException { + return db.run(connection -> { + ResultSet result = executeQuery(connection, + findItemStorageKeyStatement(), + key.getFormatted() + ); + + if (result.next()) + return result.getInt(1); + + PreparedStatement statement = connection.prepareStatement( + createItemStorageKeyStatement(), + Statement.RETURN_GENERATED_KEYS + ); + statement.setString(1, key.getFormatted()); + statement.executeUpdate(); + + ResultSet keys = statement.getGeneratedKeys(); + if (!keys.next()) throw new IllegalStateException("No generated key returned!"); + return keys.getInt(1); + }); + } + + @Language("sql") + public abstract String findGridStorageKeyStatement(); + + @Language("sql") + public abstract String createGridStorageKeyStatement(); + + public int gridStorageKey(Key key) { + synchronized (gridStorageKeys) { + //noinspection DataFlowIssue + return gridStorageKeys.get(key); + } + } + + public int findOrCreateGridStorageKey(Key key) throws IOException { + return db.run(connection -> { + ResultSet result = executeQuery(connection, + findGridStorageKeyStatement(), + key.getFormatted() + ); + + if (result.next()) + return result.getInt(1); + + PreparedStatement statement = connection.prepareStatement( + createGridStorageKeyStatement(), + Statement.RETURN_GENERATED_KEYS + ); + statement.setString(1, key.getFormatted()); + statement.executeUpdate(); + + ResultSet keys = statement.getGeneratedKeys(); + if (!keys.next()) throw new IllegalStateException("No generated key returned!"); + return keys.getInt(1); + }); + } + @Override public boolean isClosed() { return db.isClosed(); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/commandset/CommandSet.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/commandset/CommandSet.java index 2ebc14900..f1e00cab8 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/commandset/CommandSet.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/commandset/CommandSet.java @@ -25,6 +25,7 @@ package de.bluecolored.bluemap.core.storage.sql.commandset; import de.bluecolored.bluemap.core.storage.compression.Compression; +import de.bluecolored.bluemap.core.util.Key; import org.jetbrains.annotations.Nullable; import java.io.Closeable; @@ -34,39 +35,39 @@ public interface CommandSet extends Closeable { void initializeTables() throws IOException; - int writeMapTile( - String mapId, int lod, int x, int z, Compression compression, + void writeItem(String mapId, Key key, Compression compression, byte[] bytes) throws IOException; + + byte @Nullable [] readItem(String mapId, Key key, Compression compression) throws IOException; + + void deleteItem(String mapId, Key key) throws IOException; + + boolean hasItem(String mapId, Key key, Compression compression) throws IOException; + + void writeGridItem( + String mapId, Key key, int x, int z, Compression compression, byte[] bytes ) throws IOException; - byte @Nullable [] readMapTile( - String mapId, int lod, int x, int z, Compression compression + byte @Nullable [] readGridItem( + String mapId, Key key, int x, int z, Compression compression ) throws IOException; - int deleteMapTile( - String mapId, int lod, int x, int z, Compression compression + void deleteGridItem( + String mapId, Key key, int x, int z ) throws IOException; - boolean hasMapTile( - String mapId, int lod, int x, int z, Compression compression + boolean hasGridItem( + String mapId, Key key, int x, int z, Compression compression ) throws IOException; - TilePosition[] listMapTiles( - String mapId, int lod, Compression compression, + TilePosition[] listGridItems( + String mapId, Key key, Compression compression, int start, int count ) throws IOException; - int countAllMapTiles(String mapId) throws IOException; - - int purgeMapTiles(String mapId, int limit) throws IOException; - - int writeMapMeta(String mapId, String itemName, byte[] bytes) throws IOException; - - byte @Nullable [] readMapMeta(String mapId, String itemName) throws IOException; - - int deleteMapMeta(String mapId, String itemName) throws IOException; + int countMapGridsItems(String mapId) throws IOException; - boolean hasMapMeta(String mapId, String itemName) throws IOException; + int purgeMapGrids(String mapId, int limit) throws IOException; void purgeMap(String mapId) throws IOException; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/commandset/MySQLCommandSet.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/commandset/MySQLCommandSet.java index b04db4f76..03d4410a1 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/commandset/MySQLCommandSet.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/commandset/MySQLCommandSet.java @@ -50,53 +50,51 @@ PRIMARY KEY (`id`), @Language("mysql") public String createCompressionTableStatement() { return """ - CREATE TABLE IF NOT EXISTS `bluemap_map_tile_compression` ( + CREATE TABLE IF NOT EXISTS `bluemap_compression` ( `id` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, - `compression` VARCHAR(190) NOT NULL, + `key` VARCHAR(190) NOT NULL, PRIMARY KEY (`id`), - UNIQUE INDEX `compression` (`compression`) + UNIQUE INDEX `key` (`key`) ) COLLATE 'utf8mb4_bin' """; } @Override @Language("mysql") - public String createMapMetaTableStatement() { + public String createItemStorageTableStatement() { return """ - CREATE TABLE IF NOT EXISTS `bluemap_map_meta` ( - `map` SMALLINT UNSIGNED NOT NULL, - `key` varchar(190) NOT NULL, - `value` LONGBLOB NOT NULL, - PRIMARY KEY (`map`, `key`), - CONSTRAINT `fk_bluemap_map_meta_map` - FOREIGN KEY (`map`) - REFERENCES `bluemap_map` (`id`) - ON UPDATE RESTRICT - ON DELETE CASCADE + CREATE TABLE IF NOT EXISTS `bluemap_item_storage` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `key` VARCHAR(190) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE INDEX `key` (`key`) ) COLLATE 'utf8mb4_bin' """; } @Override @Language("mysql") - public String createMapTileTableStatement() { + public String createItemStorageDataTableStatement() { return """ - CREATE TABLE IF NOT EXISTS `bluemap_map_tile` ( + CREATE TABLE IF NOT EXISTS `bluemap_item_storage_data` ( `map` SMALLINT UNSIGNED NOT NULL, - `lod` SMALLINT UNSIGNED NOT NULL, - `x` INT NOT NULL, - `z` INT NOT NULL, + `storage` INT UNSIGNED NOT NULL, `compression` SMALLINT UNSIGNED NOT NULL, `data` LONGBLOB NOT NULL, - PRIMARY KEY (`map`, `lod`, `x`, `z`), - CONSTRAINT `fk_bluemap_map_tile_map` + PRIMARY KEY (`map`, `storage`), + CONSTRAINT `fk_bluemap_item_map` FOREIGN KEY (`map`) REFERENCES `bluemap_map` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, - CONSTRAINT `fk_bluemap_map_tile_compression` + CONSTRAINT `fk_bluemap_item` + FOREIGN KEY (`storage`) + REFERENCES `bluemap_item_storage` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE, + CONSTRAINT `fk_bluemap_item_compression` FOREIGN KEY (`compression`) - REFERENCES `bluemap_map_tile_compression` (`id`) + REFERENCES `bluemap_compression` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE ) COLLATE 'utf8mb4_bin' @@ -105,188 +103,186 @@ FOREIGN KEY (`compression`) @Override @Language("mysql") - public String fixLegacyCompressionIdsStatement() { + public String createGridStorageTableStatement() { return """ - UPDATE IGNORE `bluemap_map_tile_compression` - SET `compression` = CONCAT('bluemap:', `compression`) - WHERE NOT `compression` LIKE '%:%' + CREATE TABLE IF NOT EXISTS `bluemap_grid_storage` ( + `id` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, + `key` VARCHAR(190) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE INDEX `key` (`key`) + ) COLLATE 'utf8mb4_bin' """; } @Override @Language("mysql") - public String writeMapTileStatement() { + public String createGridStorageDataTableStatement() { return """ - REPLACE - INTO `bluemap_map_tile` (`map`, `lod`, `x`, `z`, `compression`, `data`) - VALUES (?, ?, ?, ?, ?, ?) + CREATE TABLE IF NOT EXISTS `bluemap_grid_storage_data` ( + `map` SMALLINT UNSIGNED NOT NULL, + `storage` SMALLINT UNSIGNED NOT NULL, + `x` INT NOT NULL, + `z` INT NOT NULL, + `compression` SMALLINT UNSIGNED NOT NULL, + `data` LONGBLOB NOT NULL, + PRIMARY KEY (`map`, `storage`, `x`, `z`), + CONSTRAINT `fk_bluemap_grid_map` + FOREIGN KEY (`map`) + REFERENCES `bluemap_map` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE, + CONSTRAINT `fk_bluemap_grid` + FOREIGN KEY (`storage`) + REFERENCES `bluemap_grid_storage` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE, + CONSTRAINT `fk_bluemap_grid_compression` + FOREIGN KEY (`compression`) + REFERENCES `bluemap_compression` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE + ) COLLATE 'utf8mb4_bin' """; } @Override @Language("mysql") - public String readMapTileStatement() { + public String itemStorageWriteStatement() { return """ - SELECT t.`data` - FROM `bluemap_map_tile` t - INNER JOIN `bluemap_map` m - ON t.`map` = m.`id` - INNER JOIN `bluemap_map_tile_compression` c - ON t.`compression` = c.`id` - WHERE m.`map_id` = ? - AND t.`lod` = ? - AND t.`x` = ? - AND t.`z` = ? - AND c.`compression` = ? + REPLACE + INTO `bluemap_item_storage_data` (`map`, `storage`, `compression`, `data`) + VALUES (?, ?, ?, ?) """; } @Override @Language("mysql") - public String deleteMapTileStatement() { + public String itemStorageReadStatement() { return """ - DELETE - FROM `bluemap_map_tile` + SELECT `data` + FROM `bluemap_item_storage_data` WHERE `map` = ? - AND `lod` = ? - AND `x` = ? - AND `z` = ? + AND `storage` = ? AND `compression` = ? """; } @Override @Language("mysql") - public String hasMapTileStatement() { + public String itemStorageDeleteStatement() { return """ - SELECT COUNT(*) > 0 - FROM `bluemap_map_tile` t - INNER JOIN `bluemap_map` m - ON t.`map` = m.`id` - INNER JOIN `bluemap_map_tile_compression` c - ON t.`compression` = c.`id` - WHERE m.`map_id` = ? - AND t.`lod` = ? - AND t.`x` = ? - AND t.`z` = ? - AND c.`compression` = ? - """; - } - - @Override - @Language("mysql") - public String countAllMapTilesStatement() { - return """ - SELECT COUNT(*) - FROM `bluemap_map_tile` t - INNER JOIN `bluemap_map` m - ON t.`map` = m.`id` - WHERE m.`map_id` = ? + DELETE + FROM `bluemap_item_storage_data` + WHERE `map` = ? + AND `storage` = ? """; } @Override @Language("mysql") - public String purgeMapTilesStatement() { + public String itemStorageHasStatement() { return """ - DELETE - FROM `bluemap_map_tile` + SELECT COUNT(*) > 0 + FROM `bluemap_item_storage_data` WHERE `map` = ? - LIMIT ? + AND `storage` = ? + AND `compression` = ? """; } + @Override @Language("mysql") - public String listMapTilesStatement() { + public String gridStorageWriteStatement() { return """ - SELECT t.`x`, t.`z` - FROM `bluemap_map_tile` t - INNER JOIN `bluemap_map` m - ON t.`map` = m.`id` - INNER JOIN `bluemap_map_tile_compression` c - ON t.`compression` = c.`id` - WHERE m.`map_id` = ? - AND t.`lod` = ? - AND c.`compression` = ? - LIMIT ? OFFSET ? + REPLACE + INTO `bluemap_grid_storage_data` (`map`, `storage`, `x`, `z`, `compression`, `data`) + VALUES (?, ?, ?, ?, ?, ?) """; } @Override @Language("mysql") - public String writeMapMetaStatement() { + public String gridStorageReadStatement() { return """ - REPLACE - INTO `bluemap_map_meta` (`map`, `key`, `value`) - VALUES (?, ?, ?) + SELECT `data` + FROM `bluemap_grid_storage_data` + WHERE `map` = ? + AND `storage` = ? + AND `x` = ? + AND `z` = ? + AND `compression` = ? """; } @Override @Language("mysql") - public String readMapMetaStatement() { + public String gridStorageDeleteStatement() { return """ - SELECT t.`value` - FROM `bluemap_map_meta` t - INNER JOIN `bluemap_map` m - ON t.`map` = m.`id` - WHERE m.`map_id` = ? - AND t.`key` = ? + DELETE + FROM `bluemap_grid_storage_data` + WHERE `map` = ? + AND `storage` = ? + AND `x` = ? + AND `z` = ? """; } @Override @Language("mysql") - public String deleteMapMetaStatement() { + public String gridStorageHasStatement() { return """ - DELETE - FROM `bluemap_map_meta` + SELECT COUNT(*) > 0 + FROM `bluemap_grid_storage_data` WHERE `map` = ? - AND `key` = ? + AND `storage` = ? + AND `x` = ? + AND `z` = ? + AND `compression` = ? """; } @Override @Language("mysql") - public String hasMapMetaStatement() { + public String gridStorageListStatement() { return """ - SELECT COUNT(*) > 0 - FROM `bluemap_map_meta` t - INNER JOIN `bluemap_map` m - ON t.`map` = m.`id` - WHERE m.`map_id` = ? - AND t.`key` = ? + SELECT `x`, `z` + FROM `bluemap_grid_storage_data` + WHERE `map` = ? + AND `storage` = ? + AND `compression` = ? + LIMIT ? OFFSET ? """; } @Override @Language("mysql") - public String purgeMapTileTableStatement() { + public String gridStorageCountMapItemsStatement() { return """ - DELETE - FROM `bluemap_map_tile` + SELECT COUNT(*) + FROM `bluemap_grid_storage_data` WHERE `map` = ? """; } @Override @Language("mysql") - public String purgeMapMetaTableStatement() { + public String gridStoragePurgeMapStatement() { return """ DELETE - FROM `bluemap_map_meta` + FROM `bluemap_grid_storage_data` WHERE `map` = ? + LIMIT ? """; } @Override @Language("mysql") - public String deleteMapStatement() { + public String purgeMapStatement() { return """ DELETE FROM `bluemap_map` - WHERE `map` = ? + WHERE `id` = ? """; } @@ -335,8 +331,8 @@ public String createMapKeyStatement() { public String findCompressionKeyStatement() { return """ SELECT `id` - FROM `bluemap_map_tile_compression` - WHERE `compression` = ? + FROM `bluemap_compression` + WHERE `key` = ? """; } @@ -345,7 +341,47 @@ public String findCompressionKeyStatement() { public String createCompressionKeyStatement() { return """ INSERT - INTO `bluemap_map_tile_compression` (`compression`) + INTO `bluemap_compression` (`key`) + VALUES (?) + """; + } + + @Override + @Language("mysql") + public String findItemStorageKeyStatement() { + return """ + SELECT `id` + FROM `bluemap_item_storage` + WHERE `key` = ? + """; + } + + @Override + @Language("mysql") + public String createItemStorageKeyStatement() { + return """ + INSERT + INTO `bluemap_item_storage` (`key`) + VALUES (?) + """; + } + + @Override + @Language("mysql") + public String findGridStorageKeyStatement() { + return """ + SELECT `id` + FROM `bluemap_grid_storage` + WHERE `key` = ? + """; + } + + @Override + @Language("mysql") + public String createGridStorageKeyStatement() { + return """ + INSERT + INTO `bluemap_grid_storage` (`key`) VALUES (?) """; } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/commandset/PostgreSQLCommandSet.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/commandset/PostgreSQLCommandSet.java index 69a57592e..b632928ae 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/commandset/PostgreSQLCommandSet.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/commandset/PostgreSQLCommandSet.java @@ -48,246 +48,232 @@ map_id VARCHAR(190) UNIQUE NOT NULL @Language("postgresql") public String createCompressionTableStatement() { return """ - CREATE TABLE IF NOT EXISTS bluemap_map_tile_compression ( + CREATE TABLE IF NOT EXISTS bluemap_compression ( id SMALLSERIAL PRIMARY KEY, - compression VARCHAR(190) UNIQUE NOT NULL + key VARCHAR(190) UNIQUE NOT NULL ) """; } @Override @Language("postgresql") - public String createMapMetaTableStatement() { + public String createItemStorageTableStatement() { return """ - CREATE TABLE IF NOT EXISTS bluemap_map_meta ( - map SMALLINT NOT NULL - REFERENCES bluemap_map(id) - ON UPDATE RESTRICT - ON DELETE CASCADE, - key VARCHAR(190) NOT NULL, - value BYTEA NOT NULL, - PRIMARY KEY (map, key) + CREATE TABLE IF NOT EXISTS bluemap_item_storage ( + id SERIAL PRIMARY KEY, + key VARCHAR(190) UNIQUE NOT NULL ) """; } @Override @Language("postgresql") - public String createMapTileTableStatement() { + public String createItemStorageDataTableStatement() { return """ - CREATE TABLE IF NOT EXISTS bluemap_map_tile ( + CREATE TABLE IF NOT EXISTS bluemap_item_storage_data ( map SMALLINT NOT NULL REFERENCES bluemap_map (id) ON UPDATE RESTRICT ON DELETE CASCADE, - lod SMALLINT NOT NULL, - x INT NOT NULL, - z INT NOT NULL, + storage INT NOT NULL + REFERENCES bluemap_item_storage (id) + ON UPDATE RESTRICT + ON DELETE CASCADE, compression SMALLINT NOT NULL - REFERENCES bluemap_map_tile_compression (id) + REFERENCES bluemap_compression (id) ON UPDATE RESTRICT ON DELETE CASCADE, data BYTEA NOT NULL, - PRIMARY KEY (map, lod, x, z) + PRIMARY KEY (map, storage) ) """; } @Override @Language("postgresql") - public String fixLegacyCompressionIdsStatement() { + public String createGridStorageTableStatement() { return """ - UPDATE bluemap_map_tile_compression - SET compression = CONCAT('bluemap:', compression) - WHERE NOT compression LIKE '%:%' + CREATE TABLE IF NOT EXISTS bluemap_grid_storage ( + id SMALLSERIAL PRIMARY KEY, + key VARCHAR(190) UNIQUE NOT NULL + ) """; } @Override @Language("postgresql") - public String writeMapTileStatement() { + public String createGridStorageDataTableStatement() { return """ - INSERT - INTO bluemap_map_tile (map, lod, x, z, compression, data) - VALUES (?, ?, ?, ?, ?, ?) - ON CONFLICT (map, lod, x, z) - DO UPDATE SET - compression = excluded.compression, - data = excluded.data + CREATE TABLE IF NOT EXISTS bluemap_grid_storage_data ( + map SMALLINT NOT NULL + REFERENCES bluemap_map (id) + ON UPDATE RESTRICT + ON DELETE CASCADE, + storage SMALLINT NOT NULL + REFERENCES bluemap_grid_storage (id) + ON UPDATE RESTRICT + ON DELETE CASCADE, + x INT NOT NULL, + z INT NOT NULL, + compression SMALLINT NOT NULL + REFERENCES bluemap_compression (id) + ON UPDATE RESTRICT + ON DELETE CASCADE, + data BYTEA NOT NULL, + PRIMARY KEY (map, storage, x, z) + ) """; } @Override @Language("postgresql") - public String readMapTileStatement() { + public String itemStorageWriteStatement() { return """ - SELECT t.data - FROM bluemap_map_tile t - INNER JOIN bluemap_map m - ON t.map = m.id - INNER JOIN bluemap_map_tile_compression c - ON t.compression = c.id - WHERE m.map_id = ? - AND t.lod = ? - AND t.x = ? - AND t.z = ? - AND c.compression = ? + INSERT + INTO bluemap_item_storage_data (map, storage, compression, data) + VALUES (?, ?, ?, ?) + ON CONFLICT (map, storage) + DO UPDATE SET + compression = excluded.compression, + data = excluded.data """; } @Override @Language("postgresql") - public String deleteMapTileStatement() { + public String itemStorageReadStatement() { return """ - DELETE - FROM bluemap_map_tile + SELECT data + FROM bluemap_item_storage_data WHERE map = ? - AND lod = ? - AND x = ? - AND z = ? + AND storage = ? AND compression = ? """; } @Override @Language("postgresql") - public String hasMapTileStatement() { - return """ - SELECT COUNT(*) > 0 - FROM bluemap_map_tile t - INNER JOIN bluemap_map m - ON t.map = m.id - INNER JOIN bluemap_map_tile_compression c - ON t.compression = c.id - WHERE m.map_id = ? - AND t.lod = ? - AND t.x = ? - AND t.z = ? - AND c.compression = ? - """; - } - - @Override - @Language("postgresql") - public String countAllMapTilesStatement() { + public String itemStorageDeleteStatement() { return """ - SELECT COUNT(*) - FROM bluemap_map_tile t - INNER JOIN bluemap_map m - ON t.map = m.id - WHERE m.map_id = ? + DELETE + FROM bluemap_item_storage_data + WHERE map = ? + AND storage = ? """; } @Override @Language("postgresql") - public String purgeMapTilesStatement() { + public String itemStorageHasStatement() { return """ - DELETE - FROM bluemap_map_tile - WHERE CTID IN ( - SELECT CTID - FROM bluemap_map_tile t - WHERE t.map = ? - LIMIT ? - ) + SELECT COUNT(*) > 0 + FROM bluemap_item_storage_data + WHERE map = ? + AND storage = ? + AND compression = ? """; } @Override @Language("postgresql") - public String listMapTilesStatement() { + public String gridStorageWriteStatement() { return """ - SELECT t.x, t.z - FROM bluemap_map_tile t - INNER JOIN bluemap_map m - ON t.map = m.id - INNER JOIN bluemap_map_tile_compression c - ON t.compression = c.id - WHERE m.map_id = ? - AND t.lod = ? - AND c.compression = ? - LIMIT ? OFFSET ? + INSERT + INTO bluemap_grid_storage_data (map, storage, x, z, compression, data) + VALUES (?, ?, ?, ?, ?, ?) + ON CONFLICT (map, storage, x, z) + DO UPDATE SET + compression = excluded.compression, + data = excluded.data """; } @Override @Language("postgresql") - public String writeMapMetaStatement() { + public String gridStorageReadStatement() { return """ - INSERT - INTO bluemap_map_meta (map, key, value) - VALUES (?, ?, ?) - ON CONFLICT (map, key) - DO UPDATE SET - value = excluded.value + SELECT data + FROM bluemap_grid_storage_data + WHERE map = ? + AND storage = ? + AND x = ? + AND z = ? + AND compression = ? """; } @Override @Language("postgresql") - public String readMapMetaStatement() { + public String gridStorageDeleteStatement() { return """ - SELECT t.value - FROM bluemap_map_meta t - INNER JOIN bluemap_map m - ON t.map = m.id - WHERE m.map_id = ? - AND t.key = ? + DELETE + FROM bluemap_grid_storage_data + WHERE map = ? + AND storage = ? + AND x = ? + AND z = ? """; } @Override @Language("postgresql") - public String deleteMapMetaStatement() { + public String gridStorageHasStatement() { return """ - DELETE - FROM bluemap_map_meta + SELECT COUNT(*) > 0 + FROM bluemap_grid_storage_data WHERE map = ? - AND key = ? + AND storage = ? + AND x = ? + AND z = ? + AND compression = ? """; } @Override @Language("postgresql") - public String hasMapMetaStatement() { + public String gridStorageListStatement() { return """ - SELECT COUNT(*) > 0 - FROM bluemap_map_meta t - INNER JOIN bluemap_map m - ON t.map = m.id - WHERE m.map_id = ? - AND t.key = ? + SELECT x, z + FROM bluemap_grid_storage_data + WHERE map = ? + AND storage = ? + AND compression = ? + LIMIT ? OFFSET ? """; } @Override @Language("postgresql") - public String purgeMapTileTableStatement() { + public String gridStorageCountMapItemsStatement() { return """ - DELETE - FROM bluemap_map_tile + SELECT COUNT(*) + FROM bluemap_grid_storage_data WHERE map = ? """; } @Override @Language("postgresql") - public String purgeMapMetaTableStatement() { + public String gridStoragePurgeMapStatement() { return """ DELETE - FROM bluemap_map_meta - WHERE map = ? + FROM bluemap_grid_storage_data + WHERE CTID IN ( + SELECT CTID + FROM bluemap_grid_storage_data t + WHERE t.map = ? + LIMIT ? + ) """; } @Override @Language("postgresql") - public String deleteMapStatement() { + public String purgeMapStatement() { return """ DELETE FROM bluemap_map - WHERE map = ? + WHERE id = ? """; } @@ -336,8 +322,8 @@ INTO bluemap_map (map_id) public String findCompressionKeyStatement() { return """ SELECT id - FROM bluemap_map_tile_compression - WHERE compression = ? + FROM bluemap_compression + WHERE key = ? """; } @@ -346,7 +332,47 @@ public String findCompressionKeyStatement() { public String createCompressionKeyStatement() { return """ INSERT - INTO bluemap_map_tile_compression (compression) + INTO bluemap_compression (key) + VALUES (?) + """; + } + + @Override + @Language("postgresql") + public String findItemStorageKeyStatement() { + return """ + SELECT id + FROM bluemap_item_storage + WHERE key = ? + """; + } + + @Override + @Language("postgresql") + public String createItemStorageKeyStatement() { + return """ + INSERT + INTO bluemap_item_storage (key) + VALUES (?) + """; + } + + @Override + @Language("postgresql") + public String findGridStorageKeyStatement() { + return """ + SELECT id + FROM bluemap_grid_storage + WHERE key = ? + """; + } + + @Override + @Language("postgresql") + public String createGridStorageKeyStatement() { + return """ + INSERT + INTO bluemap_grid_storage (key) VALUES (?) """; } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/commandset/SqliteCommandSet.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/commandset/SqliteCommandSet.java index 2d35782a1..6815cc99d 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/commandset/SqliteCommandSet.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/sql/commandset/SqliteCommandSet.java @@ -48,51 +48,47 @@ public String createMapTableStatement() { @Language("sqlite") public String createCompressionTableStatement() { return """ - CREATE TABLE IF NOT EXISTS `bluemap_map_tile_compression` ( + CREATE TABLE IF NOT EXISTS `bluemap_compression` ( `id` INTEGER PRIMARY KEY AUTOINCREMENT, - `compression` TEXT UNIQUE NOT NULL + `key` TEXT UNIQUE NOT NULL ) STRICT """; } @Override @Language("sqlite") - public String createMapMetaTableStatement() { + public String createItemStorageTableStatement() { return """ - CREATE TABLE IF NOT EXISTS `bluemap_map_meta` ( - `map` INTEGER NOT NULL, - `key` TEXT NOT NULL, - `value` BLOB NOT NULL, - PRIMARY KEY (`map`, `key`), - CONSTRAINT `fk_bluemap_map_meta_map` - FOREIGN KEY (`map`) - REFERENCES `bluemap_map` (`id`) - ON UPDATE RESTRICT - ON DELETE CASCADE + CREATE TABLE IF NOT EXISTS `bluemap_item_storage` ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, + `key` TEXT UNIQUE NOT NULL ) STRICT """; } @Override @Language("sqlite") - public String createMapTileTableStatement() { + public String createItemStorageDataTableStatement() { return """ - CREATE TABLE IF NOT EXISTS `bluemap_map_tile` ( + CREATE TABLE IF NOT EXISTS `bluemap_item_storage_data` ( `map` INTEGER NOT NULL, - `lod` INTEGER NOT NULL, - `x` INTEGER NOT NULL, - `z` INTEGER NOT NULL, + `storage` INTEGER NOT NULL, `compression` INTEGER NOT NULL, `data` BLOB NOT NULL, - PRIMARY KEY (`map`, `lod`, `x`, `z`), - CONSTRAINT `fk_bluemap_map_tile_map` + PRIMARY KEY (`map`, `storage`), + CONSTRAINT `fk_bluemap_item_map` FOREIGN KEY (`map`) REFERENCES `bluemap_map` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, - CONSTRAINT `fk_bluemap_map_tile_compression` + CONSTRAINT `fk_bluemap_item` + FOREIGN KEY (`storage`) + REFERENCES `bluemap_item_storage` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE, + CONSTRAINT `fk_bluemap_item_compression` FOREIGN KEY (`compression`) - REFERENCES `bluemap_map_tile_compression` (`id`) + REFERENCES `bluemap_compression` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE ) STRICT @@ -101,192 +97,188 @@ FOREIGN KEY (`compression`) @Override @Language("sqlite") - public String fixLegacyCompressionIdsStatement() { + public String createGridStorageTableStatement() { return """ - UPDATE `bluemap_map_tile_compression` - SET `compression` = 'bluemap:' || `compression` - WHERE NOT `compression` LIKE '%:%' + CREATE TABLE IF NOT EXISTS `bluemap_grid_storage` ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, + `key` TEXT UNIQUE NOT NULL + ) STRICT """; } @Override @Language("sqlite") - public String writeMapTileStatement() { + public String createGridStorageDataTableStatement() { return """ - REPLACE - INTO `bluemap_map_tile` (`map`, `lod`, `x`, `z`, `compression`, `data`) - VALUES (?, ?, ?, ?, ?, ?) + CREATE TABLE IF NOT EXISTS `bluemap_grid_storage_data` ( + `map` INTEGER NOT NULL, + `storage` INTEGER NOT NULL, + `x` INTEGER NOT NULL, + `z` INTEGER NOT NULL, + `compression` INTEGER NOT NULL, + `data` BLOB NOT NULL, + PRIMARY KEY (`map`, `storage`, `x`, `z`), + CONSTRAINT `fk_bluemap_grid_map` + FOREIGN KEY (`map`) + REFERENCES `bluemap_map` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE, + CONSTRAINT `fk_bluemap_grid` + FOREIGN KEY (`storage`) + REFERENCES `bluemap_grid_storage` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE, + CONSTRAINT `fk_bluemap_grid_compression` + FOREIGN KEY (`compression`) + REFERENCES `bluemap_compression` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE + ) STRICT """; } @Override @Language("sqlite") - public String readMapTileStatement() { + public String itemStorageWriteStatement() { return """ - SELECT t.`data` - FROM `bluemap_map_tile` t - INNER JOIN `bluemap_map` m - ON t.`map` = m.`id` - INNER JOIN `bluemap_map_tile_compression` c - ON t.`compression` = c.`id` - WHERE m.`map_id` = ? - AND t.`lod` = ? - AND t.`x` = ? - AND t.`z` = ? - AND c.`compression` = ? + REPLACE + INTO `bluemap_item_storage_data` (`map`, `storage`, `compression`, `data`) + VALUES (?, ?, ?, ?) """; } @Override @Language("sqlite") - public String deleteMapTileStatement() { + public String itemStorageReadStatement() { return """ - DELETE - FROM `bluemap_map_tile` + SELECT `data` + FROM `bluemap_item_storage_data` WHERE `map` = ? - AND `lod` = ? - AND `x` = ? - AND `z` = ? + AND `storage` = ? AND `compression` = ? """; } @Override @Language("sqlite") - public String hasMapTileStatement() { + public String itemStorageDeleteStatement() { return """ - SELECT COUNT(*) > 0 - FROM `bluemap_map_tile` t - INNER JOIN `bluemap_map` m - ON t.`map` = m.`id` - INNER JOIN `bluemap_map_tile_compression` c - ON t.`compression` = c.`id` - WHERE m.`map_id` = ? - AND t.`lod` = ? - AND t.`x` = ? - AND t.`z` = ? - AND c.`compression` = ? + DELETE + FROM `bluemap_item_storage_data` + WHERE `map` = ? + AND `storage` = ? """; } @Override @Language("sqlite") - public String countAllMapTilesStatement() { + public String itemStorageHasStatement() { return """ - SELECT COUNT(*) - FROM `bluemap_map_tile` t - INNER JOIN `bluemap_map` m - ON t.`map` = m.`id` - WHERE m.`map_id` = ? + SELECT COUNT(*) > 0 + FROM `bluemap_item_storage_data` + WHERE `map` = ? + AND `storage` = ? + AND `compression` = ? """; } - @Override - @Language("sqlite") - public String purgeMapTilesStatement() { - return """ - DELETE - FROM bluemap_map_tile - WHERE ROWID IN ( - SELECT t.ROWID - FROM bluemap_map_tile t - WHERE t.map = ? - LIMIT ? - ) - """; - } @Override @Language("sqlite") - public String listMapTilesStatement() { + public String gridStorageWriteStatement() { return """ - SELECT t.`x`, t.`z` - FROM `bluemap_map_tile` t - INNER JOIN `bluemap_map` m - ON t.`map` = m.`id` - INNER JOIN `bluemap_map_tile_compression` c - ON t.`compression` = c.`id` - WHERE m.`map_id` = ? - AND t.`lod` = ? - AND c.`compression` = ? - LIMIT ? OFFSET ? + REPLACE + INTO `bluemap_grid_storage_data` (`map`, `storage`, `x`, `z`, `compression`, `data`) + VALUES (?, ?, ?, ?, ?, ?) """; } @Override @Language("sqlite") - public String writeMapMetaStatement() { + public String gridStorageReadStatement() { return """ - REPLACE - INTO `bluemap_map_meta` (`map`, `key`, `value`) - VALUES (?, ?, ?) + SELECT `data` + FROM `bluemap_grid_storage_data` + WHERE `map` = ? + AND `storage` = ? + AND `x` = ? + AND `z` = ? + AND `compression` = ? """; } @Override @Language("sqlite") - public String readMapMetaStatement() { + public String gridStorageDeleteStatement() { return """ - SELECT t.`value` - FROM `bluemap_map_meta` t - INNER JOIN `bluemap_map` m - ON t.`map` = m.`id` - WHERE m.`map_id` = ? - AND t.`key` = ? + DELETE + FROM `bluemap_grid_storage_data` + WHERE `map` = ? + AND `storage` = ? + AND `x` = ? + AND `z` = ? """; } @Override @Language("sqlite") - public String deleteMapMetaStatement() { + public String gridStorageHasStatement() { return """ - DELETE - FROM `bluemap_map_meta` + SELECT COUNT(*) > 0 + FROM `bluemap_grid_storage_data` WHERE `map` = ? - AND `key` = ? + AND `storage` = ? + AND `x` = ? + AND `z` = ? + AND `compression` = ? """; } @Override @Language("sqlite") - public String hasMapMetaStatement() { + public String gridStorageListStatement() { return """ - SELECT COUNT(*) > 0 - FROM `bluemap_map_meta` t - INNER JOIN `bluemap_map` m - ON t.`map` = m.`id` - WHERE m.`map_id` = ? - AND t.`key` = ? + SELECT `x`, `z` + FROM `bluemap_grid_storage_data` + WHERE `map` = ? + AND `storage` = ? + AND `compression` = ? + LIMIT ? OFFSET ? """; } @Override @Language("sqlite") - public String purgeMapTileTableStatement() { + public String gridStorageCountMapItemsStatement() { return """ - DELETE - FROM `bluemap_map_tile` + SELECT COUNT(*) + FROM `bluemap_grid_storage_data` WHERE `map` = ? """; } @Override @Language("sqlite") - public String purgeMapMetaTableStatement() { + public String gridStoragePurgeMapStatement() { return """ DELETE - FROM `bluemap_map_meta` - WHERE `map` = ? + FROM `bluemap_grid_storage_data` + WHERE ROWID IN ( + SELECT t.ROWID + FROM `bluemap_grid_storage_data` t + WHERE t.`map` = ? + LIMIT ? + ) """; } @Override @Language("sqlite") - public String deleteMapStatement() { + public String purgeMapStatement() { return """ DELETE FROM `bluemap_map` - WHERE `map` = ? + WHERE `id` = ? """; } @@ -335,8 +327,8 @@ public String createMapKeyStatement() { public String findCompressionKeyStatement() { return """ SELECT `id` - FROM `bluemap_map_tile_compression` - WHERE `compression` = ? + FROM `bluemap_compression` + WHERE `key` = ? """; } @@ -345,7 +337,47 @@ public String findCompressionKeyStatement() { public String createCompressionKeyStatement() { return """ INSERT - INTO `bluemap_map_tile_compression` (`compression`) + INTO `bluemap_compression` (`key`) + VALUES (?) + """; + } + + @Override + @Language("sqlite") + public String findItemStorageKeyStatement() { + return """ + SELECT `id` + FROM `bluemap_item_storage` + WHERE `key` = ? + """; + } + + @Override + @Language("sqlite") + public String createItemStorageKeyStatement() { + return """ + INSERT + INTO `bluemap_item_storage` (`key`) + VALUES (?) + """; + } + + @Override + @Language("sqlite") + public String findGridStorageKeyStatement() { + return """ + SELECT `id` + FROM `bluemap_grid_storage` + WHERE `key` = ? + """; + } + + @Override + @Language("sqlite") + public String createGridStorageKeyStatement() { + return """ + INSERT + INTO `bluemap_grid_storage` (`key`) VALUES (?) """; } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/BiIntConsumer.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/BiIntConsumer.java new file mode 100644 index 000000000..9ab4da271 --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/BiIntConsumer.java @@ -0,0 +1,8 @@ +package de.bluecolored.bluemap.core.util; + +@FunctionalInterface +public interface BiIntConsumer { + + void accept(int a, int b); + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/FileHelper.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/FileHelper.java index 08d3b4671..5fb271380 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/FileHelper.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/FileHelper.java @@ -39,12 +39,13 @@ public class FileHelper { * once the stream gets closed. */ public static OutputStream createFilepartOutputStream(final Path file) throws IOException { - final Path partFile = getPartFile(file); - FileHelper.createDirectories(partFile.getParent()); + Path folder = file.toAbsolutePath().normalize().getParent(); + final Path partFile = folder.resolve(file.getFileName() + ".filepart"); + FileHelper.createDirectories(folder); OutputStream os = Files.newOutputStream(partFile, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE); return new OnCloseOutputStream(os, () -> { if (!Files.exists(partFile)) return; - FileHelper.createDirectories(file.getParent()); + FileHelper.createDirectories(folder); FileHelper.move(partFile, file); }); } @@ -76,8 +77,4 @@ public static Path createDirectories(Path dir, FileAttribute... attrs) throws return Files.createDirectories(dir, attrs); } - private static Path getPartFile(Path file) { - return file.normalize().getParent().resolve(file.getFileName() + ".filepart"); - } - } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Grid.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Grid.java index 83fcd7992..7cb53e525 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Grid.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Grid.java @@ -30,10 +30,24 @@ import java.util.Collection; import java.util.Collections; import java.util.Objects; +import java.util.function.Consumer; public class Grid { - public static final Grid UNIT = new Grid(Vector2i.ONE); + public static final Grid UNIT = new Grid(Vector2i.ONE, Vector2i.ZERO) { + @Override public int getCellX(int posX) { return posX; } + @Override public int getCellY(int posY) { return posY; } + @Override public Vector2i getCell(Vector2i pos) { return pos; } + @Override public int getLocalX(int posX) { return 0; } + @Override public int getLocalY(int posY) { return 0; } + @Override public Vector2i getLocal(Vector2i pos) { return pos; } + @Override public int getCellMinX(int cellX) { return cellX; } + @Override public int getCellMinY(int cellY) { return cellY; } + @Override public Vector2i getCellMin(Vector2i cell) { return cell; } + @Override public int getCellMaxX(int cellX) { return cellX; } + @Override public int getCellMaxY(int cellY) { return cellY; } + @Override public Vector2i getCellMax(Vector2i cell) { return cell; } + }; private final Vector2i gridSize; private final Vector2i offset; @@ -158,13 +172,27 @@ public Vector2i getCellMax(Vector2i cell, Grid targetGrid) { ); } + public void forEachIntersecting(Vector2i cell, Grid targetGrid, Consumer action) { + forEachIntersecting(cell, targetGrid, (x, y) -> action.accept(new Vector2i(x, y))); + } + + public void forEachIntersecting(Vector2i cell, Grid targetGrid, BiIntConsumer action) { + Vector2i min = getCellMin(cell, targetGrid); + Vector2i max = getCellMax(cell, targetGrid); + for (int x = min.getX(); x <= max.getX(); x++){ + for (int y = min.getY(); y <= max.getY(); y++){ + action.accept(x, y); + } + } + } + public Collection getIntersecting(Vector2i cell, Grid targetGrid) { Vector2i min = getCellMin(cell, targetGrid); Vector2i max = getCellMax(cell, targetGrid); if (min.equals(max)) return Collections.singleton(min); - Collection intersects = new ArrayList<>(); + Collection intersects = new ArrayList<>((max.getX() - min.getX() + 1) * (max.getY() - min.getY() + 1)); for (int x = min.getX(); x <= max.getX(); x++){ for (int y = min.getY(); y <= max.getY(); y++){ intersects.add(new Vector2i(x, y)); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Lazy.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Lazy.java index 778c933e7..8d968ce35 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Lazy.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Lazy.java @@ -34,7 +34,7 @@ public class Lazy { private Supplier loader; @DebugDump - private T value; + private volatile T value; public Lazy(Supplier loader) { Objects.requireNonNull(loader); @@ -51,9 +51,13 @@ public Lazy(T value) { } public T getValue() { - if (!isLoaded()) { - this.value = loader.get(); - this.loader = null; + if (value == null) { + synchronized (this) { + if (value == null) { + this.value = loader.get(); + this.loader = null; + } + } } return this.value; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/PalettedArrayAdapter.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/PalettedArrayAdapter.java new file mode 100644 index 000000000..7498d4a7d --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/PalettedArrayAdapter.java @@ -0,0 +1,75 @@ +package de.bluecolored.bluemap.core.util; + +import com.google.gson.reflect.TypeToken; +import de.bluecolored.bluenbt.BlueNBT; +import de.bluecolored.bluenbt.NBTReader; +import de.bluecolored.bluenbt.NBTWriter; +import de.bluecolored.bluenbt.TypeAdapter; +import de.bluecolored.bluenbt.adapter.ArrayAdapterFactory; +import lombok.RequiredArgsConstructor; + +import java.io.IOException; +import java.lang.reflect.Array; +import java.util.HashMap; + +@RequiredArgsConstructor +public class PalettedArrayAdapter implements TypeAdapter { + + private final Class type; + private final TypeAdapter paletteAdapter; + + @SuppressWarnings("unchecked") + public PalettedArrayAdapter(BlueNBT blueNBT, Class type) { + this.type = type; + this.paletteAdapter = ArrayAdapterFactory.INSTANCE.create((TypeToken) TypeToken.getArray(type), blueNBT).orElseThrow(); + } + + @SuppressWarnings("unchecked") + @Override + public T[] read(NBTReader reader) throws IOException { + reader.beginCompound(); + T[] palette = null; + byte[] data = null; + while (reader.hasNext()) { + String name = reader.name(); + switch (name) { + case "palette" -> palette = paletteAdapter.read(reader); + case "data" -> data = reader.nextArrayAsByteArray(); + default -> reader.skip(); + } + } + reader.endCompound(); + + if (palette == null || palette.length == 0) throw new IOException("Missing or empty palette"); + if (data == null) return (T[]) Array.newInstance(type, 0); + T[] result = (T[]) Array.newInstance(type, data.length); + for (int i = 0; i < data.length; i++) { + byte index = data[i]; + if (index >= palette.length) throw new IOException("Palette (size: " + palette.length + ") does not contain entry-index (" + index + ")"); + result[i] = palette[data[i]]; + } + + return result; + } + + @SuppressWarnings("unchecked") + @Override + public void write(T[] value, NBTWriter writer) throws IOException { + HashMap paletteMap = new HashMap<>(); + byte[] data = new byte[value.length]; + for (int i = 0; i < value.length; i++) { + byte index = paletteMap.computeIfAbsent(value[i], v -> (byte) paletteMap.size()); + data[i] = index; + } + + T[] palette = (T[]) Array.newInstance(type, paletteMap.size()); + paletteMap.forEach((k, v) -> palette[v] = k); + + writer.beginCompound(); + writer.name("palette"); + paletteAdapter.write(palette, writer); + writer.name("data").value(data); + writer.endCompound(); + } + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Registry.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Registry.java index a534c0883..ff177f671 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Registry.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Registry.java @@ -24,26 +24,23 @@ */ package de.bluecolored.bluemap.core.util; +import lombok.NoArgsConstructor; import org.jetbrains.annotations.Nullable; -import java.util.Collection; -import java.util.Collections; -import java.util.Objects; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; +@NoArgsConstructor public class Registry { - private final ConcurrentHashMap entries; + private final ConcurrentHashMap entries = new ConcurrentHashMap<>(); - public Registry() { - this.entries = new ConcurrentHashMap<>(); - } + private final Set keys = Collections.unmodifiableSet(entries.keySet()); + private final Collection values = Collections.unmodifiableCollection(entries.values()); @SafeVarargs - public Registry(T... defaultEntires) { - this(); - for (T entry : defaultEntires) + public Registry(T... defaultEntries) { + for (T entry : defaultEntries) register(entry); } @@ -71,14 +68,14 @@ public boolean register(T entry) { * Returns an unmodifiable set of all keys this registry contains entries for */ public Set keys() { - return Collections.unmodifiableSet(entries.keySet()); + return keys; } /** * Returns an unmodifiable collection of entries in this registry */ public Collection values() { - return Collections.unmodifiableCollection(entries.values()); + return values; } } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/RegistryAdapter.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/RegistryAdapter.java new file mode 100644 index 000000000..23a8e059a --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/RegistryAdapter.java @@ -0,0 +1,39 @@ +package de.bluecolored.bluemap.core.util; + +import de.bluecolored.bluemap.core.logger.Logger; +import de.bluecolored.bluenbt.NBTReader; +import de.bluecolored.bluenbt.NBTWriter; +import de.bluecolored.bluenbt.TagType; +import de.bluecolored.bluenbt.TypeAdapter; +import lombok.RequiredArgsConstructor; + +import java.io.IOException; + +@RequiredArgsConstructor +public class RegistryAdapter implements TypeAdapter { + + private final Registry registry; + private final String defaultNamespace; + private final T fallback; + + @Override + public T read(NBTReader reader) throws IOException { + Key key = Key.parse(reader.nextString(), defaultNamespace); + T value = registry.get(key); + if (value != null) return value; + + Logger.global.noFloodWarning("unknown-registry-key-" + key.getFormatted(), "Failed to find registry-entry for key: " + key); + return fallback; + } + + @Override + public void write(T value, NBTWriter writer) throws IOException { + writer.value(value.getKey().getFormatted()); + } + + @Override + public TagType type() { + return TagType.STRING; + } + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/Biome.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/Biome.java index 23431efc4..e66d7b570 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/Biome.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/Biome.java @@ -26,69 +26,35 @@ import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.util.Key; +import de.bluecolored.bluemap.core.util.Keyed; import de.bluecolored.bluemap.core.util.math.Color; +import lombok.Getter; @DebugDump -public class Biome extends Key { +public interface Biome extends Keyed { - public static final Biome DEFAULT = new Biome("minecraft:ocean"); + Biome DEFAULT = new Default(); - private float humidity = 0.5f; - private float temp = 0.5f; - private final Color waterColor = new Color().set(4159204 | 0xFF000000).premultiplied(); + float getDownfall(); - private final Color overlayFoliageColor = new Color().premultiplied(); - private final Color overlayGrassColor = new Color().premultiplied(); + float getTemperature(); - public Biome(String formatted) { - super(formatted); - } - - public Biome(String formatted, float humidity, float temp, Color waterColor) { - this(formatted); - this.humidity = humidity; - this.temp = temp; - this.waterColor.set(waterColor).premultiplied(); - } + Color getWaterColor(); - public Biome(String formatted, float humidity, float temp, Color waterColor, Color overlayFoliageColor, Color overlayGrassColor) { - this(formatted, humidity, temp, waterColor); - this.overlayFoliageColor.set(overlayFoliageColor).premultiplied(); - this.overlayGrassColor.set(overlayGrassColor).premultiplied(); - } + Color getOverlayFoliageColor(); - public float getHumidity() { - return humidity; - } + Color getOverlayGrassColor(); - public float getTemp() { - return temp; - } + @Getter + class Default implements Biome { - public Color getWaterColor() { - return waterColor; - } - - public Color getOverlayFoliageColor() { - return overlayFoliageColor; - } - - public Color getOverlayGrassColor() { - return overlayGrassColor; - } + private final Key key = Key.bluemap("default"); + private final float downfall = 0.5f; + private final float temperature = 0.5f; + private final Color waterColor = new Color().set(4159204 | 0xFF000000).premultiplied(); + private final Color overlayFoliageColor = new Color().premultiplied(); + private final Color overlayGrassColor = new Color().premultiplied(); - @Override - public String toString() { - return "Biome{" + - "value='" + getValue() + '\'' + - ", namespace=" + getNamespace() + - ", formatted=" + getFormatted() + - ", humidity=" + humidity + - ", temp=" + temp + - ", waterColor=" + waterColor + - ", overlayFoliageColor=" + overlayFoliageColor + - ", overlayGrassColor=" + overlayGrassColor + - '}'; } } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/Chunk.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/Chunk.java index 6a643cdd4..7b5916eef 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/Chunk.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/Chunk.java @@ -30,6 +30,7 @@ public interface Chunk { Chunk EMPTY_CHUNK = new Chunk() {}; + Chunk ERRORED_CHUNK = new Chunk() {}; default boolean isGenerated() { return false; @@ -51,8 +52,8 @@ default LightData getLightData(int x, int y, int z, LightData target) { return target.set(0, 0); } - default String getBiome(int x, int y, int z) { - return Biome.DEFAULT.getFormatted(); + default Biome getBiome(int x, int y, int z) { + return Biome.DEFAULT; } default int getMaxY(int x, int z) { @@ -75,5 +76,6 @@ default boolean hasOceanFloorHeights() { default int getOceanFloorY(int x, int z) { return 0; } - default @Nullable BlockEntity getBlockEntity(int x, int y, int z) { return null; }; + default @Nullable BlockEntity getBlockEntity(int x, int y, int z) { return null; } + } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/ChunkConsumer.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/ChunkConsumer.java index f473fbc77..9f893a191 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/ChunkConsumer.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/ChunkConsumer.java @@ -27,7 +27,7 @@ @FunctionalInterface public interface ChunkConsumer { - default boolean filter(int chunkX, int chunkZ, long lastModified) { + default boolean filter(int chunkX, int chunkZ, int lastModified) { return true; } @@ -36,10 +36,10 @@ default boolean filter(int chunkX, int chunkZ, long lastModified) { @FunctionalInterface interface ListOnly extends ChunkConsumer { - void accept(int chunkX, int chunkZ, long lastModified); + void accept(int chunkX, int chunkZ, int lastModified); @Override - default boolean filter(int chunkX, int chunkZ, long lastModified) { + default boolean filter(int chunkX, int chunkZ, int lastModified) { accept(chunkX, chunkZ, lastModified); return false; } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/Region.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/Region.java index 01da07c69..d5ac390f9 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/Region.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/Region.java @@ -37,7 +37,7 @@ class SingleChunkConsumer implements ChunkConsumer { private Chunk foundChunk = Chunk.EMPTY_CHUNK; @Override - public boolean filter(int x, int z, long lastModified) { + public boolean filter(int x, int z, int lastModified) { return x == chunkX && z == chunkZ; } @@ -53,7 +53,7 @@ public void accept(int chunkX, int chunkZ, Chunk chunk) { } /** - * Iterates over all chunks in this region and first calls {@link ChunkConsumer#filter(int, int, long)}.
+ * Iterates over all chunks in this region and first calls {@link ChunkConsumer#filter(int, int, int)}.
* And if (any only if) that method returned true, the chunk will be loaded and {@link ChunkConsumer#accept(int, int, Chunk)} * will be called with the loaded chunk. * @param consumer the consumer choosing which chunks to load and accepting them diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/World.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/World.java index 66ba83c72..8015bd6f8 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/World.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/World.java @@ -29,6 +29,7 @@ import de.bluecolored.bluemap.core.util.Grid; import java.util.Collection; +import java.util.function.Predicate; /** * Represents a World on the Server.
@@ -74,7 +75,11 @@ public interface World { /** * Loads all chunks from the specified region into the chunk cache (if there is a cache) */ - void preloadRegionChunks(int x, int z); + default void preloadRegionChunks(int x, int z) { + preloadRegionChunks(x, z, pos -> true); + } + + void preloadRegionChunks(int x, int z, Predicate chunkFilter); /** * Invalidates the complete chunk cache (if there is a cache), so that every chunk has to be reloaded from disk diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/Block.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/Block.java index b9fc92577..f2eef512e 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/Block.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/Block.java @@ -24,10 +24,7 @@ */ package de.bluecolored.bluemap.core.world.block; -import de.bluecolored.bluemap.core.world.BlockState; -import de.bluecolored.bluemap.core.world.Chunk; -import de.bluecolored.bluemap.core.world.LightData; -import de.bluecolored.bluemap.core.world.World; +import de.bluecolored.bluemap.core.world.*; import de.bluecolored.bluemap.core.world.block.entity.BlockEntity; import org.jetbrains.annotations.Nullable; @@ -36,11 +33,11 @@ public class Block> { private World world; private int x, y, z; - private Chunk chunk; + private @Nullable Chunk chunk; - private BlockState blockState; + private @Nullable BlockState blockState; private final LightData lightData = new LightData(-1, -1); - private String biomeId; + private @Nullable Biome biome; public Block(World world, int x, int y, int z) { set(world, x, y, z); @@ -82,7 +79,7 @@ public T set(int x, int y, int z) { protected void reset() { this.blockState = null; this.lightData.set(-1, -1); - this.biomeId = null; + this.biome = null; } public T add(int dx, int dy, int dz) { @@ -100,7 +97,7 @@ public T copy(Block source) { this.blockState = source.blockState; this.lightData.set(source.lightData.getSkyLight(), source.lightData.getBlockLight()); - this.biomeId = source.biomeId; + this.biome = source.biome; return self(); } @@ -136,9 +133,9 @@ public LightData getLightData() { return lightData; } - public String getBiomeId() { - if (biomeId == null) biomeId = getChunk().getBiome(x, y, z); - return biomeId; + public Biome getBiome() { + if (biome == null) biome = getChunk().getBiome(x, y, z); + return biome; } public int getSunLightLevel() { @@ -164,7 +161,7 @@ public String toString() { ", chunk=" + getChunk() + ", blockState=" + getBlockState() + ", lightData=" + getLightData() + - ", biomeId=" + getBiomeId() + + ", biome=" + getBiome() + '}'; } else { return "Block{" + diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/BlockNeighborhood.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/BlockNeighborhood.java index 24e08e42b..82d112d78 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/BlockNeighborhood.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/BlockNeighborhood.java @@ -25,7 +25,7 @@ package de.bluecolored.bluemap.core.world.block; import de.bluecolored.bluemap.core.map.hires.RenderSettings; -import de.bluecolored.bluemap.core.resources.resourcepack.ResourcePack; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; import de.bluecolored.bluemap.core.world.World; public class BlockNeighborhood> extends ExtendedBlock { diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/ExtendedBlock.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/ExtendedBlock.java index 50e1b1819..ca7cb94f0 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/ExtendedBlock.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/ExtendedBlock.java @@ -25,8 +25,9 @@ package de.bluecolored.bluemap.core.world.block; import de.bluecolored.bluemap.core.map.hires.RenderSettings; -import de.bluecolored.bluemap.core.resources.resourcepack.ResourcePack; +import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; import de.bluecolored.bluemap.core.world.*; +import org.jetbrains.annotations.Nullable; import java.util.Objects; @@ -34,8 +35,7 @@ public class ExtendedBlock> extends Block { private final ResourcePack resourcePack; private final RenderSettings renderSettings; - private BlockProperties properties; - private Biome biome; + private @Nullable BlockProperties properties; private boolean insideRenderBoundsCalculated, insideRenderBounds; private boolean isCaveCalculated, isCave; @@ -51,7 +51,6 @@ protected void reset() { super.reset(); this.properties = null; - this.biome = null; this.insideRenderBoundsCalculated = false; this.isCaveCalculated = false; @@ -61,7 +60,6 @@ public T copy(ExtendedBlock source) { super.copy(source); this.properties = source.properties; - this.biome = source.biome; this.insideRenderBoundsCalculated = source.insideRenderBoundsCalculated; this.insideRenderBounds = source.insideRenderBounds; @@ -90,11 +88,6 @@ public BlockProperties getProperties() { return properties; } - public Biome getBiome() { - if (biome == null) biome = resourcePack.getBiome(getBiomeId()); - return biome; - } - public RenderSettings getRenderSettings() { return renderSettings; } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java index 73b3efa39..57eb3c542 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java @@ -31,15 +31,12 @@ import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.BlueMap; import de.bluecolored.bluemap.core.logger.Logger; -import de.bluecolored.bluemap.core.resources.datapack.DataPack; +import de.bluecolored.bluemap.core.resources.pack.datapack.DataPack; import de.bluecolored.bluemap.core.storage.compression.Compression; import de.bluecolored.bluemap.core.util.Grid; import de.bluecolored.bluemap.core.util.Key; import de.bluecolored.bluemap.core.util.Vector2iCache; -import de.bluecolored.bluemap.core.world.Chunk; -import de.bluecolored.bluemap.core.world.DimensionType; -import de.bluecolored.bluemap.core.world.Region; -import de.bluecolored.bluemap.core.world.World; +import de.bluecolored.bluemap.core.world.*; import de.bluecolored.bluemap.core.world.mca.chunk.ChunkLoader; import de.bluecolored.bluemap.core.world.mca.data.LevelData; import de.bluecolored.bluemap.core.world.mca.region.RegionType; @@ -53,7 +50,7 @@ import java.nio.file.Path; import java.util.*; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; +import java.util.function.Predicate; @Getter @ToString @@ -68,8 +65,8 @@ public class MCAWorld implements World { private final String id; private final Path worldFolder; private final Key dimension; - private final LevelData levelData; private final DataPack dataPack; + private final LevelData levelData; private final DimensionType dimensionType; private final Vector3i spawnPoint; @@ -88,12 +85,12 @@ public class MCAWorld implements World { .expireAfterWrite(10, TimeUnit.MINUTES) .build(this::loadChunk); - private MCAWorld(Path worldFolder, Key dimension, LevelData levelData, DataPack dataPack) { + private MCAWorld(Path worldFolder, Key dimension, DataPack dataPack, LevelData levelData) { this.id = id(worldFolder, dimension); this.worldFolder = worldFolder; this.dimension = dimension; - this.levelData = levelData; this.dataPack = dataPack; + this.levelData = levelData; LevelData.Dimension dimensionData = levelData.getData().getWorldGenSettings().getDimensions().get(dimension.getFormatted()); if (dimensionData == null) { @@ -186,11 +183,20 @@ public Collection listRegions() { } @Override - public void preloadRegionChunks(int x, int z) { + public void preloadRegionChunks(int x, int z, Predicate chunkFilter) { try { - getRegion(x, z).iterateAllChunks((cx, cz, chunk) -> { - Vector2i chunkPos = VECTOR_2_I_CACHE.get(cx, cz); - chunkCache.put(chunkPos, chunk); + getRegion(x, z).iterateAllChunks(new ChunkConsumer() { + @Override + public boolean filter(int chunkX, int chunkZ, int lastModified) { + Vector2i chunkPos = VECTOR_2_I_CACHE.get(chunkX, chunkZ); + return chunkFilter.test(chunkPos); + } + + @Override + public void accept(int chunkX, int chunkZ, Chunk chunk) { + Vector2i chunkPos = VECTOR_2_I_CACHE.get(chunkX, chunkZ); + chunkCache.put(chunkPos, chunk); + } }); } catch (IOException ex) { Logger.global.logDebug("Unexpected exception trying to load preload region (x:" + x + ", z:" + z + "):" + ex); @@ -253,33 +259,17 @@ private Chunk loadChunk(int x, int z) { } Logger.global.logDebug("Unexpected exception trying to load chunk (x:" + x + ", z:" + z + "):" + loadException); - return Chunk.EMPTY_CHUNK; + return Chunk.ERRORED_CHUNK; } - public static MCAWorld load(Path worldFolder, Key dimension) throws IOException, InterruptedException { + public static MCAWorld load(Path worldFolder, Key dimension, DataPack dataPack) throws IOException, InterruptedException { // load level.dat Path levelFile = worldFolder.resolve("level.dat"); InputStream levelFileIn = Compression.GZIP.decompress(Files.newInputStream(levelFile)); LevelData levelData = MCAUtil.BLUENBT.read(levelFileIn, LevelData.class); - // load datapacks - DataPack dataPack = new DataPack(); - Path dataPackFolder = worldFolder.resolve("datapacks"); - if (Files.exists(dataPackFolder)) { - List roots; - try (var stream = Files.list(dataPackFolder)) { - roots = stream - .sorted(Comparator.reverseOrder()) - .collect(Collectors.toList()); - } - for (Path root : roots) { - dataPack.load(root); - } - } - dataPack.bake(); - // create world - return new MCAWorld(worldFolder, dimension, levelData, dataPack); + return new MCAWorld(worldFolder, dimension, dataPack, levelData); } public static String id(Path worldFolder, Key dimension) { diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_13.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_13.java index 979c12648..1d2c96be8 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_13.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_13.java @@ -149,11 +149,13 @@ public BlockState getBlockState(int x, int y, int z) { } @Override - public String getBiome(int x, int y, int z) { - if (this.biomes.length < 256) return Biome.DEFAULT.getFormatted(); + public Biome getBiome(int x, int y, int z) { + if (this.biomes.length < 256) return Biome.DEFAULT; int biomeIntIndex = (z & 0xF) << 4 | x & 0xF; - return LegacyBiomes.idFor(biomes[biomeIntIndex]); + + Biome biome = getWorld().getDataPack().getBiome(biomes[biomeIntIndex]); + return biome != null ? biome : Biome.DEFAULT; } @Override diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_15.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_15.java index 408438f90..0d1b4be7f 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_15.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_15.java @@ -34,8 +34,8 @@ public Chunk_1_15(MCAWorld world, Data data) { } @Override - public String getBiome(int x, int y, int z) { - if (this.biomes.length < 16) return Biome.DEFAULT.getFormatted(); + public Biome getBiome(int x, int y, int z) { + if (this.biomes.length < 16) return Biome.DEFAULT; int biomeIntIndex = (y & 0b1100) << 2 | z & 0b1100 | (x & 0b1100) >> 2; @@ -43,7 +43,8 @@ public String getBiome(int x, int y, int z) { if (biomeIntIndex >= biomes.length) biomeIntIndex -= (((biomeIntIndex - biomes.length) >> 4) + 1) * 16; if (biomeIntIndex < 0) biomeIntIndex -= (biomeIntIndex >> 4) * 16; - return LegacyBiomes.idFor(biomes[biomeIntIndex]); + Biome biome = getWorld().getDataPack().getBiome(biomes[biomeIntIndex]); + return biome != null ? biome : Biome.DEFAULT; } } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_16.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_16.java index 648c338dd..f3918574a 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_16.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_16.java @@ -148,8 +148,8 @@ public BlockState getBlockState(int x, int y, int z) { } @Override - public String getBiome(int x, int y, int z) { - if (this.biomes.length < 16) return Biome.DEFAULT.getFormatted(); + public Biome getBiome(int x, int y, int z) { + if (this.biomes.length < 16) return Biome.DEFAULT; int biomeIntIndex = (y & 0b1100) << 2 | z & 0b1100 | (x & 0b1100) >> 2; @@ -157,7 +157,8 @@ public String getBiome(int x, int y, int z) { if (biomeIntIndex >= biomes.length) biomeIntIndex -= (((biomeIntIndex - biomes.length) >> 4) + 1) * 16; if (biomeIntIndex < 0) biomeIntIndex -= (biomeIntIndex >> 4) * 16; - return LegacyBiomes.idFor(biomes[biomeIntIndex]); + Biome biome = getWorld().getDataPack().getBiome(biomes[biomeIntIndex]); + return biome != null ? biome : Biome.DEFAULT; } @Override diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_18.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_18.java index 9e65f541c..b80b195cf 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_18.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_18.java @@ -99,7 +99,7 @@ public Chunk_1_18(MCAWorld world, Data data) { // load sections into ordered array this.sections = new Section[1 + max - min]; for (SectionData sectionData : sectionsData) { - Section section = new Section(sectionData); + Section section = new Section(getWorld(), sectionData); int y = section.getSectionY(); if (min > y) min = y; @@ -145,9 +145,9 @@ public BlockState getBlockState(int x, int y, int z) { } @Override - public String getBiome(int x, int y, int z) { + public Biome getBiome(int x, int y, int z) { Section section = getSection(y >> 4); - if (section == null) return Biome.DEFAULT.getFormatted(); + if (section == null) return Biome.DEFAULT; return section.getBiome(x, y, z); } @@ -208,17 +208,23 @@ protected static class Section { private final int sectionY; private final BlockState[] blockPalette; - private final String[] biomePalette; + private final Biome[] biomePalette; private final PackedIntArrayAccess blocks; private final PackedIntArrayAccess biomes; private final byte[] blockLight; private final byte[] skyLight; - public Section(SectionData sectionData) { + public Section(MCAWorld world, SectionData sectionData) { this.sectionY = sectionData.y; this.blockPalette = sectionData.blockStates.palette; - this.biomePalette = sectionData.biomes.palette; + + this.biomePalette = new Biome[sectionData.biomes.palette.length]; + for (int i = 0; i < this.biomePalette.length; i++) { + Biome biome = world.getDataPack().getBiome(sectionData.biomes.palette[i]); + if (biome == null) biome = Biome.DEFAULT; + this.biomePalette[i] = biome; + } this.blocks = new PackedIntArrayAccess(sectionData.blockStates.data, BLOCKS_PER_SECTION); this.biomes = new PackedIntArrayAccess(Math.max(MCAUtil.ceilLog2(this.biomePalette.length), 1), sectionData.biomes.data); @@ -240,14 +246,14 @@ public BlockState getBlockState(int x, int y, int z) { return blockPalette[id]; } - public String getBiome(int x, int y, int z) { + public Biome getBiome(int x, int y, int z) { if (biomePalette.length == 1) return biomePalette[0]; - if (biomePalette.length == 0) return Biome.DEFAULT.getValue(); + if (biomePalette.length == 0) return Biome.DEFAULT; int id = biomes.get((y & 0b1100) << 2 | z & 0b1100 | (x & 0b1100) >> 2); if (id >= biomePalette.length) { Logger.global.noFloodWarning("biome-palette-warning", "Got biome-palette id " + id + " but palette has size of " + biomePalette.length + "."); - return Biome.DEFAULT.getValue(); + return Biome.DEFAULT; } return biomePalette[id]; @@ -309,7 +315,7 @@ public static class BlockStatesData { @Getter @SuppressWarnings("FieldMayBeFinal") public static class BiomesData { - private String[] palette = EMPTY_STRING_ARRAY; + private Key[] palette = EMPTY_KEY_ARRAY; private long[] data = EMPTY_LONG_ARRAY; } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/LegacyBiomes.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/LegacyBiomes.java index a998ee1a9..b5df53546 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/LegacyBiomes.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/LegacyBiomes.java @@ -24,93 +24,105 @@ */ package de.bluecolored.bluemap.core.world.mca.chunk; -import java.util.Arrays; +import de.bluecolored.bluemap.core.resources.pack.datapack.DataPack; +import de.bluecolored.bluemap.core.util.Key; +import de.bluecolored.bluemap.core.world.Biome; +import org.jetbrains.annotations.Nullable; public class LegacyBiomes { - private static final String[] BIOME_IDS = new String[170]; + private static final @Nullable Key [] BIOME_KEYS = new Key[170]; static { - Arrays.fill(BIOME_IDS, "minecraft:ocean"); - BIOME_IDS[0] = "minecraft:ocean"; - BIOME_IDS[1] = "minecraft:plains"; - BIOME_IDS[2] = "minecraft:desert"; - BIOME_IDS[3] = "minecraft:mountains"; - BIOME_IDS[4] = "minecraft:forest"; - BIOME_IDS[5] = "minecraft:taiga"; - BIOME_IDS[6] = "minecraft:swamp"; - BIOME_IDS[7] = "minecraft:river"; - BIOME_IDS[8] = "minecraft:nether"; - BIOME_IDS[9] = "minecraft:the_end"; - BIOME_IDS[10] = "minecraft:frozen_ocean"; - BIOME_IDS[11] = "minecraft:frozen_river"; - BIOME_IDS[12] = "minecraft:snowy_tundra"; - BIOME_IDS[13] = "minecraft:snowy_mountains"; - BIOME_IDS[14] = "minecraft:mushroom_fields"; - BIOME_IDS[15] = "minecraft:mushroom_field_shore"; - BIOME_IDS[16] = "minecraft:beach"; - BIOME_IDS[17] = "minecraft:desert_hills"; - BIOME_IDS[18] = "minecraft:wooded_hills"; - BIOME_IDS[19] = "minecraft:taiga_hills"; - BIOME_IDS[20] = "minecraft:mountain_edge"; - BIOME_IDS[21] = "minecraft:jungle"; - BIOME_IDS[22] = "minecraft:jungle_hills"; - BIOME_IDS[23] = "minecraft:jungle_edge"; - BIOME_IDS[24] = "minecraft:deep_ocean"; - BIOME_IDS[25] = "minecraft:stone_shore"; - BIOME_IDS[26] = "minecraft:snowy_beach"; - BIOME_IDS[27] = "minecraft:birch_forest"; - BIOME_IDS[28] = "minecraft:birch_forest_hills"; - BIOME_IDS[29] = "minecraft:dark_forest"; - BIOME_IDS[30] = "minecraft:snowy_taiga"; - BIOME_IDS[31] = "minecraft:snowy_taiga_hills"; - BIOME_IDS[32] = "minecraft:giant_tree_taiga"; - BIOME_IDS[33] = "minecraft:giant_tree_taiga_hills"; - BIOME_IDS[34] = "minecraft:wooded_mountains"; - BIOME_IDS[35] = "minecraft:savanna"; - BIOME_IDS[36] = "minecraft:savanna_plateau"; - BIOME_IDS[37] = "minecraft:badlands"; - BIOME_IDS[38] = "minecraft:wooded_badlands_plateau"; - BIOME_IDS[39] = "minecraft:badlands_plateau"; - BIOME_IDS[40] = "minecraft:small_end_islands"; - BIOME_IDS[41] = "minecraft:end_midlands"; - BIOME_IDS[42] = "minecraft:end_highlands"; - BIOME_IDS[43] = "minecraft:end_barrens"; - BIOME_IDS[44] = "minecraft:warm_ocean"; - BIOME_IDS[45] = "minecraft:lukewarm_ocean"; - BIOME_IDS[46] = "minecraft:cold_ocean"; - BIOME_IDS[47] = "minecraft:deep_warm_ocean"; - BIOME_IDS[48] = "minecraft:deep_lukewarm_ocean"; - BIOME_IDS[49] = "minecraft:deep_cold_ocean"; - BIOME_IDS[50] = "minecraft:deep_frozen_ocean"; - BIOME_IDS[127] = "minecraft:the_void"; - BIOME_IDS[129] = "minecraft:sunflower_plains"; - BIOME_IDS[130] = "minecraft:desert_lakes"; - BIOME_IDS[131] = "minecraft:gravelly_mountains"; - BIOME_IDS[132] = "minecraft:flower_forest"; - BIOME_IDS[133] = "minecraft:taiga_mountains"; - BIOME_IDS[134] = "minecraft:swamp_hills"; - BIOME_IDS[140] = "minecraft:ice_spikes"; - BIOME_IDS[149] = "minecraft:modified_jungle"; - BIOME_IDS[151] = "minecraft:modified_jungle_edge"; - BIOME_IDS[155] = "minecraft:tall_birch_forest"; - BIOME_IDS[156] = "minecraft:tall_birch_hills"; - BIOME_IDS[157] = "minecraft:dark_forest_hills"; - BIOME_IDS[158] = "minecraft:snowy_taiga_mountains"; - BIOME_IDS[160] = "minecraft:giant_spruce_taiga"; - BIOME_IDS[161] = "minecraft:giant_spruce_taiga_hills"; - BIOME_IDS[162] = "minecraft:modified_gravelly_mountains"; - BIOME_IDS[163] = "minecraft:shattered_savanna"; - BIOME_IDS[164] = "minecraft:shattered_savanna_plateau"; - BIOME_IDS[165] = "minecraft:eroded_badlands"; - BIOME_IDS[166] = "minecraft:modified_wooded_badlands_plateau"; - BIOME_IDS[167] = "minecraft:modified_badlands_plateau"; - BIOME_IDS[168] = "minecraft:bamboo_jungle"; - BIOME_IDS[169] = "minecraft:bamboo_jungle_hills"; + BIOME_KEYS[ 0] = Key.minecraft("ocean"); + BIOME_KEYS[ 1] = Key.minecraft("plains"); + BIOME_KEYS[ 2] = Key.minecraft("desert"); + BIOME_KEYS[ 3] = Key.minecraft("mountains"); + BIOME_KEYS[ 4] = Key.minecraft("forest"); + BIOME_KEYS[ 5] = Key.minecraft("taiga"); + BIOME_KEYS[ 6] = Key.minecraft("swamp"); + BIOME_KEYS[ 7] = Key.minecraft("river"); + BIOME_KEYS[ 8] = Key.minecraft("nether"); + BIOME_KEYS[ 9] = Key.minecraft("the_end"); + BIOME_KEYS[ 10] = Key.minecraft("frozen_ocean"); + BIOME_KEYS[ 11] = Key.minecraft("frozen_river"); + BIOME_KEYS[ 12] = Key.minecraft("snowy_tundra"); + BIOME_KEYS[ 13] = Key.minecraft("snowy_mountains"); + BIOME_KEYS[ 14] = Key.minecraft("mushroom_fields"); + BIOME_KEYS[ 15] = Key.minecraft("mushroom_field_shore"); + BIOME_KEYS[ 16] = Key.minecraft("beach"); + BIOME_KEYS[ 17] = Key.minecraft("desert_hills"); + BIOME_KEYS[ 18] = Key.minecraft("wooded_hills"); + BIOME_KEYS[ 19] = Key.minecraft("taiga_hills"); + BIOME_KEYS[ 20] = Key.minecraft("mountain_edge"); + BIOME_KEYS[ 21] = Key.minecraft("jungle"); + BIOME_KEYS[ 22] = Key.minecraft("jungle_hills"); + BIOME_KEYS[ 23] = Key.minecraft("jungle_edge"); + BIOME_KEYS[ 24] = Key.minecraft("deep_ocean"); + BIOME_KEYS[ 25] = Key.minecraft("stone_shore"); + BIOME_KEYS[ 26] = Key.minecraft("snowy_beach"); + BIOME_KEYS[ 27] = Key.minecraft("birch_forest"); + BIOME_KEYS[ 28] = Key.minecraft("birch_forest_hills"); + BIOME_KEYS[ 29] = Key.minecraft("dark_forest"); + BIOME_KEYS[ 30] = Key.minecraft("snowy_taiga"); + BIOME_KEYS[ 31] = Key.minecraft("snowy_taiga_hills"); + BIOME_KEYS[ 32] = Key.minecraft("giant_tree_taiga"); + BIOME_KEYS[ 33] = Key.minecraft("giant_tree_taiga_hills"); + BIOME_KEYS[ 34] = Key.minecraft("wooded_mountains"); + BIOME_KEYS[ 35] = Key.minecraft("savanna"); + BIOME_KEYS[ 36] = Key.minecraft("savanna_plateau"); + BIOME_KEYS[ 37] = Key.minecraft("badlands"); + BIOME_KEYS[ 38] = Key.minecraft("wooded_badlands_plateau"); + BIOME_KEYS[ 39] = Key.minecraft("badlands_plateau"); + BIOME_KEYS[ 40] = Key.minecraft("small_end_islands"); + BIOME_KEYS[ 41] = Key.minecraft("end_midlands"); + BIOME_KEYS[ 42] = Key.minecraft("end_highlands"); + BIOME_KEYS[ 43] = Key.minecraft("end_barrens"); + BIOME_KEYS[ 44] = Key.minecraft("warm_ocean"); + BIOME_KEYS[ 45] = Key.minecraft("lukewarm_ocean"); + BIOME_KEYS[ 46] = Key.minecraft("cold_ocean"); + BIOME_KEYS[ 47] = Key.minecraft("deep_warm_ocean"); + BIOME_KEYS[ 48] = Key.minecraft("deep_lukewarm_ocean"); + BIOME_KEYS[ 49] = Key.minecraft("deep_cold_ocean"); + BIOME_KEYS[ 50] = Key.minecraft("deep_frozen_ocean"); + BIOME_KEYS[127] = Key.minecraft("the_void"); + BIOME_KEYS[129] = Key.minecraft("sunflower_plains"); + BIOME_KEYS[130] = Key.minecraft("desert_lakes"); + BIOME_KEYS[131] = Key.minecraft("gravelly_mountains"); + BIOME_KEYS[132] = Key.minecraft("flower_forest"); + BIOME_KEYS[133] = Key.minecraft("taiga_mountains"); + BIOME_KEYS[134] = Key.minecraft("swamp_hills"); + BIOME_KEYS[140] = Key.minecraft("ice_spikes"); + BIOME_KEYS[149] = Key.minecraft("modified_jungle"); + BIOME_KEYS[151] = Key.minecraft("modified_jungle_edge"); + BIOME_KEYS[155] = Key.minecraft("tall_birch_forest"); + BIOME_KEYS[156] = Key.minecraft("tall_birch_hills"); + BIOME_KEYS[157] = Key.minecraft("dark_forest_hills"); + BIOME_KEYS[158] = Key.minecraft("snowy_taiga_mountains"); + BIOME_KEYS[160] = Key.minecraft("giant_spruce_taiga"); + BIOME_KEYS[161] = Key.minecraft("giant_spruce_taiga_hills"); + BIOME_KEYS[162] = Key.minecraft("modified_gravelly_mountains"); + BIOME_KEYS[163] = Key.minecraft("shattered_savanna"); + BIOME_KEYS[164] = Key.minecraft("shattered_savanna_plateau"); + BIOME_KEYS[165] = Key.minecraft("eroded_badlands"); + BIOME_KEYS[166] = Key.minecraft("modified_wooded_badlands_plateau"); + BIOME_KEYS[167] = Key.minecraft("modified_badlands_plateau"); + BIOME_KEYS[168] = Key.minecraft("bamboo_jungle"); + BIOME_KEYS[169] = Key.minecraft("bamboo_jungle_hills"); } - public static String idFor(int legacyId) { - if (legacyId < 0 || legacyId >= BIOME_IDS.length) legacyId = 0; - return BIOME_IDS[legacyId]; + private final @Nullable Biome [] biomes = new Biome[BIOME_KEYS.length]; + + public LegacyBiomes(DataPack dataPack) { + for (int i = 0; i < biomes.length; i++) { + Key key = BIOME_KEYS[i]; + if (key != null) + biomes[i] = dataPack.getBiome(key); + } + } + + public @Nullable Biome forId(int legacyId) { + if (legacyId < 0 || legacyId >= biomes.length) return null; + return biomes[legacyId]; } } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/MCAChunk.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/MCAChunk.java index 1cc0c766f..e3be9503a 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/MCAChunk.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/MCAChunk.java @@ -24,6 +24,7 @@ */ package de.bluecolored.bluemap.core.world.mca.chunk; +import de.bluecolored.bluemap.core.util.Key; import de.bluecolored.bluemap.core.world.BlockState; import de.bluecolored.bluemap.core.world.Chunk; import de.bluecolored.bluemap.core.world.mca.MCAWorld; @@ -41,7 +42,7 @@ public abstract class MCAChunk implements Chunk { protected static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; protected static final int[] EMPTY_INT_ARRAY = new int[0]; protected static final long[] EMPTY_LONG_ARRAY = new long[0]; - protected static final String[] EMPTY_STRING_ARRAY = new String[0]; + protected static final Key[] EMPTY_KEY_ARRAY = new Key[0]; protected static final BlockState[] EMPTY_BLOCKSTATE_ARRAY = new BlockState[0]; private final MCAWorld world; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/KeyDeserializer.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/KeyDeserializer.java index c5021d941..2f74341b2 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/KeyDeserializer.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/KeyDeserializer.java @@ -34,7 +34,7 @@ public class KeyDeserializer implements TypeDeserializer { @Override public Key read(NBTReader reader) throws IOException { - return new Key(reader.nextString()); + return Key.parse(reader.nextString(), Key.MINECRAFT_NAMESPACE); } } \ No newline at end of file diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/LinearRegion.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/LinearRegion.java index 95764ef18..d1294dc27 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/LinearRegion.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/LinearRegion.java @@ -30,6 +30,7 @@ import de.bluecolored.bluemap.core.world.Region; import de.bluecolored.bluemap.core.world.mca.MCAWorld; import de.bluecolored.bluemap.core.world.mca.chunk.MCAChunk; +import lombok.Getter; import java.io.*; import java.nio.file.Files; @@ -58,6 +59,7 @@ * */ +@Getter public class LinearRegion implements Region { public static final String FILE_SUFFIX = ".linear"; @@ -164,7 +166,7 @@ public void iterateAllChunks(ChunkConsumer consumer) throws IOException { if (length > 0) { int chunkX = chunkStartX + x; int chunkZ = chunkStartZ + z; - long timestamp = version == 2 ? chunkTimestamps[i] : newestTimestamp; + int timestamp = version == 2 ? chunkTimestamps[i] : (int) newestTimestamp; //TODO: check if in seconds or milliseconds if (consumer.filter(chunkX, chunkZ, timestamp)) { if (toBeSkipped > 0) skipNBytes(dIn, toBeSkipped); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/MCARegion.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/MCARegion.java index 03e029fd8..d1e420bc6 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/MCARegion.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/MCARegion.java @@ -32,7 +32,6 @@ import de.bluecolored.bluemap.core.world.mca.MCAWorld; import de.bluecolored.bluemap.core.world.mca.chunk.MCAChunk; import lombok.Getter; -import lombok.ToString; import java.io.IOException; import java.nio.ByteBuffer; @@ -43,10 +42,17 @@ import java.nio.file.StandardOpenOption; @Getter -@ToString public class MCARegion implements Region { public static final String FILE_SUFFIX = ".mca"; + public static final Compression[] CHUNK_COMPRESSION_MAP = new Compression[255]; + static { + CHUNK_COMPRESSION_MAP[0] = Compression.NONE; + CHUNK_COMPRESSION_MAP[1] = Compression.GZIP; + CHUNK_COMPRESSION_MAP[2] = Compression.DEFLATE; + CHUNK_COMPRESSION_MAP[3] = Compression.NONE; + CHUNK_COMPRESSION_MAP[4] = Compression.LZ4; + } private final MCAWorld world; private final Path regionFile; @@ -135,7 +141,7 @@ public void iterateAllChunks(ChunkConsumer consumer) throws IOException { timestamp |= header[i] & 0xFF; // load chunk only if consumers filter returns true - if (consumer.filter(chunkX, chunkZ, timestamp * 1000L)) { + if (consumer.filter(chunkX, chunkZ, timestamp)) { i = xzChunk * 4; int offset = header[i++] << 16; offset |= (header[i++] & 0xFF) << 8; @@ -157,16 +163,10 @@ public void iterateAllChunks(ChunkConsumer consumer) throws IOException { } private MCAChunk loadChunk(byte[] data, int size) throws IOException { - int compressionTypeId = data[4]; - Compression compression; - switch (compressionTypeId) { - case 0 : - case 3 : compression = Compression.NONE; break; - case 1 : compression = Compression.GZIP; break; - case 2 : compression = Compression.DEFLATE; break; - case 4 : compression = Compression.LZ4; break; - default: throw new IOException("Unknown chunk compression-id: " + compressionTypeId); - } + int compressionTypeId = Byte.toUnsignedInt(data[4]); + Compression compression = CHUNK_COMPRESSION_MAP[compressionTypeId]; + if (compression == null) + throw new IOException("Unknown chunk compression-id: " + compressionTypeId); return world.getChunkLoader().load(data, 5, size - 5, compression); } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/RegionType.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/RegionType.java index edf917394..85956eaf8 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/RegionType.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/RegionType.java @@ -24,71 +24,75 @@ */ package de.bluecolored.bluemap.core.world.mca.region; +import de.bluecolored.bluemap.core.util.Key; +import de.bluecolored.bluemap.core.util.Keyed; +import de.bluecolored.bluemap.core.util.Registry; import de.bluecolored.bluemap.core.world.Region; import de.bluecolored.bluemap.core.world.mca.MCAWorld; +import lombok.Getter; +import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.nio.file.Files; import java.nio.file.Path; -public enum RegionType { +public interface RegionType extends Keyed { - MCA (MCARegion::new, MCARegion.FILE_SUFFIX, MCARegion::getRegionFileName), - LINEAR (LinearRegion::new, LinearRegion.FILE_SUFFIX, LinearRegion::getRegionFileName); + RegionType MCA = new Impl(Key.bluemap("mca"), MCARegion.FILE_SUFFIX, MCARegion::new, MCARegion::getRegionFileName); + RegionType LINEAR = new Impl(Key.bluemap("linear"), LinearRegion.FILE_SUFFIX, LinearRegion::new, LinearRegion::getRegionFileName); - // we do this to improve performance, as calling values() creates a new array each time - private final static RegionType[] VALUES = values(); - private final static RegionType DEFAULT = MCA; + RegionType DEFAULT = MCA; + Registry REGISTRY = new Registry<>( + MCA, + LINEAR + ); - private final String fileSuffix; - private final RegionFactory regionFactory; - private final RegionFileNameFunction regionFileNameFunction; + String getFileSuffix(); - RegionType(RegionFactory regionFactory, String fileSuffix, RegionFileNameFunction regionFileNameFunction) { - this.fileSuffix = fileSuffix; - this.regionFactory = regionFactory; - this.regionFileNameFunction = regionFileNameFunction; - } - - public String getFileSuffix() { - return fileSuffix; - } - - public Region createRegion(MCAWorld world, Path regionFile) { - return this.regionFactory.create(world, regionFile); - } + Region createRegion(MCAWorld world, Path regionFile); - public String getRegionFileName(int regionX, int regionZ) { - return regionFileNameFunction.getRegionFileName(regionX, regionZ); - } - - public Path getRegionFile(Path regionFolder, int regionX, int regionZ) { - return regionFolder.resolve(getRegionFileName(regionX, regionZ)); - } + Path getRegionFile(Path regionFolder, int regionX, int regionZ); - @Nullable - public static RegionType forFileName(String fileName) { - //noinspection ForLoopReplaceableByForEach - for (int i = 0; i < VALUES.length; i++) { - RegionType regionType = VALUES[i]; - if (fileName.endsWith(regionType.fileSuffix)) + static @Nullable RegionType forFileName(String fileName) { + for (RegionType regionType : REGISTRY.values()) { + if (fileName.endsWith(regionType.getFileSuffix())) return regionType; } + return null; } - @NotNull - public static Region loadRegion(MCAWorld world, Path regionFolder, int regionX, int regionZ) { - //noinspection ForLoopReplaceableByForEach - for (int i = 0; i < VALUES.length; i++) { - RegionType regionType = VALUES[i]; + static @NotNull Region loadRegion(MCAWorld world, Path regionFolder, int regionX, int regionZ) { + for (RegionType regionType : REGISTRY.values()) { Path regionFile = regionType.getRegionFile(regionFolder, regionX, regionZ); if (Files.exists(regionFile)) return regionType.createRegion(world, regionFile); } return DEFAULT.createRegion(world, DEFAULT.getRegionFile(regionFolder, regionX, regionZ)); } + @RequiredArgsConstructor + class Impl implements RegionType { + + @Getter private final Key key; + @Getter private final String fileSuffix; + private final RegionFactory regionFactory; + private final RegionFileNameFunction regionFileNameFunction; + + public Region createRegion(MCAWorld world, Path regionFile) { + return this.regionFactory.create(world, regionFile); + } + + public String getRegionFileName(int regionX, int regionZ) { + return regionFileNameFunction.getRegionFileName(regionX, regionZ); + } + + public Path getRegionFile(Path regionFolder, int regionX, int regionZ) { + return regionFolder.resolve(getRegionFileName(regionX, regionZ)); + } + + } + @FunctionalInterface interface RegionFactory { Region create(MCAWorld world, Path regionFile); diff --git a/build.gradle.kts b/build.gradle.kts index c012da6fb..ea5f63477 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,4 +1,3 @@ - tasks.register("clean") { gradle.includedBuilds.forEach { // workaround for https://github.com/neoforged/NeoGradle/issues/18 @@ -48,3 +47,11 @@ tasks.register("publish") { dependsOn(it.task(":publish")) } } + +// adding repositories here so intellij can download source-files and javadocs +repositories { + mavenCentral() + maven ("https://libraries.minecraft.net") + maven ("https://repo.papermc.io/repository/maven-public/") + maven ("https://repo.bluecolored.de/releases") +} diff --git a/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java b/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java index 176130053..c3e9714b2 100644 --- a/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java +++ b/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java @@ -39,7 +39,6 @@ import de.bluecolored.bluemap.common.web.http.HttpRequestHandler; import de.bluecolored.bluemap.common.web.http.HttpServer; import de.bluecolored.bluemap.core.BlueMap; -import de.bluecolored.bluemap.core.MinecraftVersion; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.map.BmMap; import de.bluecolored.bluemap.core.metrics.Metrics; @@ -65,18 +64,12 @@ public class BlueMapCLI { - private MinecraftVersion minecraftVersion = MinecraftVersion.LATEST_SUPPORTED; + private String minecraftVersion = null; private Path configFolder = Path.of("config"); public void renderMaps(BlueMapService blueMap, boolean watch, boolean forceRender, boolean forceGenerateWebapp, @Nullable String mapsToRender) throws ConfigurationException, IOException, InterruptedException { - //metrics report - if (blueMap.getConfig().getCoreConfig().isMetrics()) Metrics.sendReportAsync( - "cli", - blueMap.getConfig().getMinecraftVersion().getVersionString() - ); - if (blueMap.getConfig().getWebappConfig().isEnabled()) blueMap.createOrUpdateWebApp(forceGenerateWebapp); @@ -112,7 +105,7 @@ public void renderMaps(BlueMapService blueMap, boolean watch, boolean forceRende //update all maps int totalRegions = 0; for (BmMap map : maps.values()) { - MapUpdateTask updateTask = new MapUpdateTask(map, forceRender); + MapUpdateTask updateTask = new MapUpdateTask(map, s -> forceRender); renderManager.scheduleRenderTask(updateTask); totalRegions += updateTask.getRegions().size(); } @@ -156,13 +149,18 @@ public void run() { Logger.global.logInfo("Stopping..."); updateInfoTask.cancel(); saveTask.cancel(); - renderManager.stop(); - for (RegionFileWatchService watcher : regionFileWatchServices) { - watcher.close(); - } + regionFileWatchServices.forEach(RegionFileWatchService::close); regionFileWatchServices.clear(); + renderManager.removeAllRenderTasks(); + try { + renderManager.awaitIdle(true); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + + renderManager.stop(); try { renderManager.awaitShutdown(); } catch (InterruptedException e) { @@ -178,6 +176,12 @@ public void run() { Thread shutdownHook = new Thread(shutdown, "BlueMap-CLI-ShutdownHook"); Runtime.getRuntime().addShutdownHook(shutdownHook); + //metrics report + if (blueMap.getConfig().getCoreConfig().isMetrics()) Metrics.sendReportAsync( + "cli", + blueMap.getOrLoadMinecraftVersion().getId() + ); + // wait until done, then shutdown if not watching renderManager.awaitIdle(); Logger.global.logInfo("Your maps are now all up-to-date!"); @@ -291,14 +295,7 @@ public static void main(String[] args) { //minecraft version if (cmd.hasOption("v")) { - String versionString = cmd.getOptionValue("v"); - try { - cli.minecraftVersion = MinecraftVersion.of(versionString); - } catch (IllegalArgumentException e) { - Logger.global.logWarning("Could not determine a version from the provided version-string: '" + versionString + "'"); - System.exit(1); - return; - } + cli.minecraftVersion = cmd.getOptionValue("v"); } BlueMapConfigManager configs = BlueMapConfigManager.builder() diff --git a/implementations/fabric-1.18/src/main/java/de/bluecolored/bluemap/fabric/FabricMod.java b/implementations/fabric-1.18/src/main/java/de/bluecolored/bluemap/fabric/FabricMod.java index bea3506bd..1213b877b 100644 --- a/implementations/fabric-1.18/src/main/java/de/bluecolored/bluemap/fabric/FabricMod.java +++ b/implementations/fabric-1.18/src/main/java/de/bluecolored/bluemap/fabric/FabricMod.java @@ -29,17 +29,17 @@ import de.bluecolored.bluemap.common.plugin.Plugin; import de.bluecolored.bluemap.common.plugin.commands.Commands; import de.bluecolored.bluemap.common.serverinterface.Player; -import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; import de.bluecolored.bluemap.common.serverinterface.Server; +import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; import de.bluecolored.bluemap.common.serverinterface.ServerWorld; import de.bluecolored.bluemap.core.BlueMap; -import de.bluecolored.bluemap.core.MinecraftVersion; import de.bluecolored.bluemap.core.logger.Logger; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; +import net.minecraft.SharedConstants; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.Identifier; @@ -128,8 +128,8 @@ public void onInitialize() { } @Override - public MinecraftVersion getMinecraftVersion() { - return new MinecraftVersion(1, 18); + public String getMinecraftVersion() { + return SharedConstants.getGameVersion().getId(); } @Override diff --git a/implementations/fabric-1.19.4/src/main/java/de/bluecolored/bluemap/fabric/FabricMod.java b/implementations/fabric-1.19.4/src/main/java/de/bluecolored/bluemap/fabric/FabricMod.java index c0e9eeb8e..7a4a8d92a 100644 --- a/implementations/fabric-1.19.4/src/main/java/de/bluecolored/bluemap/fabric/FabricMod.java +++ b/implementations/fabric-1.19.4/src/main/java/de/bluecolored/bluemap/fabric/FabricMod.java @@ -29,11 +29,10 @@ import de.bluecolored.bluemap.common.plugin.Plugin; import de.bluecolored.bluemap.common.plugin.commands.Commands; import de.bluecolored.bluemap.common.serverinterface.Player; -import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; import de.bluecolored.bluemap.common.serverinterface.Server; +import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; import de.bluecolored.bluemap.common.serverinterface.ServerWorld; import de.bluecolored.bluemap.core.BlueMap; -import de.bluecolored.bluemap.core.MinecraftVersion; import de.bluecolored.bluemap.core.logger.Logger; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; @@ -129,12 +128,8 @@ public void onInitialize() { } @Override - public MinecraftVersion getMinecraftVersion() { - try { - return MinecraftVersion.of(SharedConstants.getGameVersion().getId()); - } catch (IllegalArgumentException ex) { - return MinecraftVersion.LATEST_SUPPORTED; - } + public String getMinecraftVersion() { + return SharedConstants.getGameVersion().getId(); } @Override diff --git a/implementations/fabric-1.20/src/main/java/de/bluecolored/bluemap/fabric/FabricMod.java b/implementations/fabric-1.20/src/main/java/de/bluecolored/bluemap/fabric/FabricMod.java index f964fe3c5..2a40f4b95 100644 --- a/implementations/fabric-1.20/src/main/java/de/bluecolored/bluemap/fabric/FabricMod.java +++ b/implementations/fabric-1.20/src/main/java/de/bluecolored/bluemap/fabric/FabricMod.java @@ -29,11 +29,10 @@ import de.bluecolored.bluemap.common.plugin.Plugin; import de.bluecolored.bluemap.common.plugin.commands.Commands; import de.bluecolored.bluemap.common.serverinterface.Player; -import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; import de.bluecolored.bluemap.common.serverinterface.Server; +import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; import de.bluecolored.bluemap.common.serverinterface.ServerWorld; import de.bluecolored.bluemap.core.BlueMap; -import de.bluecolored.bluemap.core.MinecraftVersion; import de.bluecolored.bluemap.core.logger.Logger; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; @@ -129,12 +128,8 @@ public void onInitialize() { } @Override - public MinecraftVersion getMinecraftVersion() { - try { - return MinecraftVersion.of(SharedConstants.getGameVersion().getId()); - } catch (IllegalArgumentException ex) { - return MinecraftVersion.LATEST_SUPPORTED; - } + public String getMinecraftVersion() { + return SharedConstants.getGameVersion().getId(); } @Override diff --git a/implementations/forge-1.18.1/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java b/implementations/forge-1.18.1/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java index e899f1829..41c0baf8a 100644 --- a/implementations/forge-1.18.1/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java +++ b/implementations/forge-1.18.1/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java @@ -29,12 +29,12 @@ import de.bluecolored.bluemap.common.plugin.Plugin; import de.bluecolored.bluemap.common.plugin.commands.Commands; import de.bluecolored.bluemap.common.serverinterface.Player; -import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; import de.bluecolored.bluemap.common.serverinterface.Server; +import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; import de.bluecolored.bluemap.common.serverinterface.ServerWorld; import de.bluecolored.bluemap.core.BlueMap; -import de.bluecolored.bluemap.core.MinecraftVersion; import de.bluecolored.bluemap.core.logger.Logger; +import net.minecraft.SharedConstants; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; @@ -140,8 +140,8 @@ public void onTick(ServerTickEvent evt) { } @Override - public MinecraftVersion getMinecraftVersion() { - return new MinecraftVersion(1, 18, 1); + public String getMinecraftVersion() { + return SharedConstants.getCurrentVersion().getId(); } @Override diff --git a/implementations/forge-1.19.4/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java b/implementations/forge-1.19.4/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java index 2a9972112..c774f3dbd 100644 --- a/implementations/forge-1.19.4/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java +++ b/implementations/forge-1.19.4/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java @@ -33,7 +33,6 @@ import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; import de.bluecolored.bluemap.common.serverinterface.ServerWorld; import de.bluecolored.bluemap.core.BlueMap; -import de.bluecolored.bluemap.core.MinecraftVersion; import de.bluecolored.bluemap.core.logger.Logger; import net.minecraft.SharedConstants; import net.minecraft.core.registries.Registries; @@ -141,12 +140,8 @@ public void onTick(ServerTickEvent evt) { } @Override - public MinecraftVersion getMinecraftVersion() { - try { - return MinecraftVersion.of(SharedConstants.getCurrentVersion().getId()); - } catch (IllegalArgumentException ex) { - return MinecraftVersion.LATEST_SUPPORTED; - } + public String getMinecraftVersion() { + return SharedConstants.getCurrentVersion().getId(); } @Override diff --git a/implementations/forge-1.20/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java b/implementations/forge-1.20/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java index 50ccc1a18..77ed826e0 100644 --- a/implementations/forge-1.20/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java +++ b/implementations/forge-1.20/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java @@ -29,11 +29,10 @@ import de.bluecolored.bluemap.common.plugin.Plugin; import de.bluecolored.bluemap.common.plugin.commands.Commands; import de.bluecolored.bluemap.common.serverinterface.Player; -import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; import de.bluecolored.bluemap.common.serverinterface.Server; +import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; import de.bluecolored.bluemap.common.serverinterface.ServerWorld; import de.bluecolored.bluemap.core.BlueMap; -import de.bluecolored.bluemap.core.MinecraftVersion; import de.bluecolored.bluemap.core.logger.Logger; import net.minecraft.SharedConstants; import net.minecraft.core.registries.Registries; @@ -141,12 +140,8 @@ public void onTick(ServerTickEvent evt) { } @Override - public MinecraftVersion getMinecraftVersion() { - try { - return MinecraftVersion.of(SharedConstants.getCurrentVersion().getId()); - } catch (IllegalArgumentException ex) { - return MinecraftVersion.LATEST_SUPPORTED; - } + public String getMinecraftVersion() { + return SharedConstants.getCurrentVersion().getId(); } @Override diff --git a/implementations/neoforge-1.20.2/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java b/implementations/neoforge-1.20.2/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java index 94d4f607e..6f8d4da3b 100644 --- a/implementations/neoforge-1.20.2/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java +++ b/implementations/neoforge-1.20.2/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java @@ -33,7 +33,6 @@ import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; import de.bluecolored.bluemap.common.serverinterface.ServerWorld; import de.bluecolored.bluemap.core.BlueMap; -import de.bluecolored.bluemap.core.MinecraftVersion; import de.bluecolored.bluemap.core.logger.Logger; import net.minecraft.SharedConstants; import net.minecraft.core.registries.Registries; @@ -140,12 +139,8 @@ public void onTick(TickEvent.ServerTickEvent evt) { } @Override - public MinecraftVersion getMinecraftVersion() { - try { - return MinecraftVersion.of(SharedConstants.getCurrentVersion().getId()); - } catch (IllegalArgumentException ex) { - return MinecraftVersion.LATEST_SUPPORTED; - } + public String getMinecraftVersion() { + return SharedConstants.getCurrentVersion().getId(); } @Override diff --git a/implementations/paper/src/main/java/de/bluecolored/bluemap/bukkit/BukkitPlayer.java b/implementations/paper/src/main/java/de/bluecolored/bluemap/bukkit/BukkitPlayer.java index 26de00f7e..fd9c1aeea 100644 --- a/implementations/paper/src/main/java/de/bluecolored/bluemap/bukkit/BukkitPlayer.java +++ b/implementations/paper/src/main/java/de/bluecolored/bluemap/bukkit/BukkitPlayer.java @@ -32,12 +32,11 @@ import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.metadata.MetadataValue; import org.bukkit.potion.PotionEffectType; -import java.util.EnumMap; -import java.util.Map; -import java.util.UUID; +import java.util.*; public class BukkitPlayer implements Player { @@ -64,6 +63,12 @@ public class BukkitPlayer implements Player { public BukkitPlayer(UUID playerUUID) { this.uuid = playerUUID; update(); + + Material[] bestItems = Arrays.stream( Material.values() ) + .filter( Material::isItem ) + .sorted( Comparator.comparing( Material::isEdible, Boolean::compare ) ) + .toArray( Material[]::new ); + } @Override diff --git a/implementations/paper/src/main/java/de/bluecolored/bluemap/bukkit/BukkitPlugin.java b/implementations/paper/src/main/java/de/bluecolored/bluemap/bukkit/BukkitPlugin.java index 6589c383b..661fdf906 100644 --- a/implementations/paper/src/main/java/de/bluecolored/bluemap/bukkit/BukkitPlugin.java +++ b/implementations/paper/src/main/java/de/bluecolored/bluemap/bukkit/BukkitPlugin.java @@ -28,11 +28,10 @@ import com.github.benmanes.caffeine.cache.LoadingCache; import de.bluecolored.bluemap.common.plugin.Plugin; import de.bluecolored.bluemap.common.serverinterface.Player; -import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; import de.bluecolored.bluemap.common.serverinterface.Server; +import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; import de.bluecolored.bluemap.common.serverinterface.ServerWorld; import de.bluecolored.bluemap.core.BlueMap; -import de.bluecolored.bluemap.core.MinecraftVersion; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.util.Key; import io.papermc.paper.threadedregions.scheduler.ScheduledTask; @@ -53,8 +52,6 @@ import java.nio.file.Path; import java.util.*; import java.util.concurrent.ConcurrentHashMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; public class BukkitPlugin extends JavaPlugin implements Server, Listener { @@ -63,7 +60,6 @@ public class BukkitPlugin extends JavaPlugin implements Server, Listener { private final Plugin pluginInstance; private final EventForwarder eventForwarder; private final BukkitCommands commands; - private final MinecraftVersion minecraftVersion; private final Map onlinePlayerMap; private final List onlinePlayerList; @@ -76,18 +72,6 @@ public BukkitPlugin() { Logger.global.clear(); Logger.global.put(new JavaLogger(getLogger())); - //try to get best matching minecraft-version - MinecraftVersion version = MinecraftVersion.LATEST_SUPPORTED; - try { - String versionString = getServer().getBukkitVersion(); - Matcher versionMatcher = Pattern.compile("(\\d+(?:\\.\\d+){1,2})[-_].*").matcher(versionString); - if (!versionMatcher.matches()) throw new IllegalArgumentException(); - version = MinecraftVersion.of(versionMatcher.group(1)); - } catch (IllegalArgumentException e) { - Logger.global.logWarning("Failed to detect the minecraft version of this server! Using latest version: " + version.getVersionString()); - } - this.minecraftVersion = version; - this.onlinePlayerMap = new ConcurrentHashMap<>(); this.onlinePlayerList = Collections.synchronizedList(new ArrayList<>()); @@ -173,8 +157,8 @@ public void onDisable() { } @Override - public MinecraftVersion getMinecraftVersion() { - return minecraftVersion; + public String getMinecraftVersion() { + return Bukkit.getMinecraftVersion(); } @Override diff --git a/implementations/paper/src/main/java/de/bluecolored/bluemap/bukkit/BukkitWorld.java b/implementations/paper/src/main/java/de/bluecolored/bluemap/bukkit/BukkitWorld.java index f9030f966..5f8ca375f 100644 --- a/implementations/paper/src/main/java/de/bluecolored/bluemap/bukkit/BukkitWorld.java +++ b/implementations/paper/src/main/java/de/bluecolored/bluemap/bukkit/BukkitWorld.java @@ -25,7 +25,7 @@ package de.bluecolored.bluemap.bukkit; import de.bluecolored.bluemap.common.serverinterface.ServerWorld; -import de.bluecolored.bluemap.core.resources.datapack.DataPack; +import de.bluecolored.bluemap.core.resources.pack.datapack.DataPack; import de.bluecolored.bluemap.core.util.Key; import de.bluecolored.bluemap.core.world.mca.MCAWorld; import org.bukkit.Bukkit; diff --git a/implementations/spigot/src/main/java/de/bluecolored/bluemap/bukkit/BukkitPlugin.java b/implementations/spigot/src/main/java/de/bluecolored/bluemap/bukkit/BukkitPlugin.java index 6ca7fd122..77ba2ff9c 100644 --- a/implementations/spigot/src/main/java/de/bluecolored/bluemap/bukkit/BukkitPlugin.java +++ b/implementations/spigot/src/main/java/de/bluecolored/bluemap/bukkit/BukkitPlugin.java @@ -28,11 +28,10 @@ import com.github.benmanes.caffeine.cache.LoadingCache; import de.bluecolored.bluemap.common.plugin.Plugin; import de.bluecolored.bluemap.common.serverinterface.Player; -import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; import de.bluecolored.bluemap.common.serverinterface.Server; +import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; import de.bluecolored.bluemap.common.serverinterface.ServerWorld; import de.bluecolored.bluemap.core.BlueMap; -import de.bluecolored.bluemap.core.MinecraftVersion; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.util.Key; import org.bstats.bukkit.Metrics; @@ -62,7 +61,7 @@ public class BukkitPlugin extends JavaPlugin implements Server, Listener { private final Plugin pluginInstance; private final EventForwarder eventForwarder; private final BukkitCommands commands; - private final MinecraftVersion minecraftVersion; + private final String minecraftVersion; private int playerUpdateIndex = 0; private final Map onlinePlayerMap; @@ -75,14 +74,14 @@ public BukkitPlugin() { Logger.global.put(new JavaLogger(getLogger())); //try to get best matching minecraft-version - MinecraftVersion version = MinecraftVersion.LATEST_SUPPORTED; + String version = null; try { String versionString = getServer().getBukkitVersion(); Matcher versionMatcher = Pattern.compile("(\\d+(?:\\.\\d+){1,2})[-_].*").matcher(versionString); if (!versionMatcher.matches()) throw new IllegalArgumentException(); - version = MinecraftVersion.of(versionMatcher.group(1)); + version = versionMatcher.group(1); } catch (IllegalArgumentException e) { - Logger.global.logWarning("Failed to detect the minecraft version of this server! Using latest version: " + version.getVersionString()); + Logger.global.logWarning("Failed to detect the minecraft version of this server! Using latest version."); } this.minecraftVersion = version; @@ -169,8 +168,8 @@ public void onDisable() { } @Override - public MinecraftVersion getMinecraftVersion() { - return minecraftVersion; + public String getMinecraftVersion() { + return this.minecraftVersion; } @Override diff --git a/implementations/spigot/src/main/java/de/bluecolored/bluemap/bukkit/BukkitWorld.java b/implementations/spigot/src/main/java/de/bluecolored/bluemap/bukkit/BukkitWorld.java index 906cf3f85..253090de5 100644 --- a/implementations/spigot/src/main/java/de/bluecolored/bluemap/bukkit/BukkitWorld.java +++ b/implementations/spigot/src/main/java/de/bluecolored/bluemap/bukkit/BukkitWorld.java @@ -25,7 +25,7 @@ package de.bluecolored.bluemap.bukkit; import de.bluecolored.bluemap.common.serverinterface.ServerWorld; -import de.bluecolored.bluemap.core.resources.datapack.DataPack; +import de.bluecolored.bluemap.core.resources.pack.datapack.DataPack; import de.bluecolored.bluemap.core.util.Key; import de.bluecolored.bluemap.core.world.mca.MCAWorld; import org.bukkit.Bukkit; diff --git a/implementations/sponge/src/main/java/de/bluecolored/bluemap/sponge/SpongePlugin.java b/implementations/sponge/src/main/java/de/bluecolored/bluemap/sponge/SpongePlugin.java index ef46c02b4..0ed3f60c8 100644 --- a/implementations/sponge/src/main/java/de/bluecolored/bluemap/sponge/SpongePlugin.java +++ b/implementations/sponge/src/main/java/de/bluecolored/bluemap/sponge/SpongePlugin.java @@ -36,11 +36,8 @@ import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; import de.bluecolored.bluemap.common.serverinterface.ServerWorld; import de.bluecolored.bluemap.core.BlueMap; -import de.bluecolored.bluemap.core.MinecraftVersion; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.sponge.SpongeCommands.SpongeCommandProxy; -import org.apache.maven.artifact.versioning.ArtifactVersion; -import org.spongepowered.api.Platform; import org.spongepowered.api.ResourceKey; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.Command; @@ -85,7 +82,6 @@ public class SpongePlugin implements Server { private final Map onlinePlayerMap; private final List onlinePlayerList; - private final MinecraftVersion minecraftVersion; private final LoadingCache worlds; @Inject @@ -98,13 +94,6 @@ public SpongePlugin(org.apache.logging.log4j.Logger logger, PluginContainer plug this.onlinePlayerMap = new ConcurrentHashMap<>(); this.onlinePlayerList = Collections.synchronizedList(new ArrayList<>()); - final ArtifactVersion versionFromSponge = Sponge.platform().container(Platform.Component.GAME).metadata().version(); - this.minecraftVersion = new MinecraftVersion( - versionFromSponge.getMajorVersion(), - versionFromSponge.getMinorVersion(), - versionFromSponge.getIncrementalVersion() - ); - this.pluginInstance = new Plugin("sponge", this); this.commands = new SpongeCommands(pluginInstance); @@ -204,8 +193,8 @@ public void onPlayerLeave(ServerSideConnectionEvent.Disconnect evt) { } @Override - public MinecraftVersion getMinecraftVersion() { - return minecraftVersion; + public String getMinecraftVersion() { + return Sponge.platform().minecraftVersion().name(); } @Override diff --git a/implementations/sponge/src/main/java/de/bluecolored/bluemap/sponge/SpongeWorld.java b/implementations/sponge/src/main/java/de/bluecolored/bluemap/sponge/SpongeWorld.java index 16e496ab8..5b5eb26de 100644 --- a/implementations/sponge/src/main/java/de/bluecolored/bluemap/sponge/SpongeWorld.java +++ b/implementations/sponge/src/main/java/de/bluecolored/bluemap/sponge/SpongeWorld.java @@ -25,7 +25,7 @@ package de.bluecolored.bluemap.sponge; import de.bluecolored.bluemap.common.serverinterface.ServerWorld; -import de.bluecolored.bluemap.core.resources.datapack.DataPack; +import de.bluecolored.bluemap.core.resources.pack.datapack.DataPack; import de.bluecolored.bluemap.core.util.Key; import org.spongepowered.api.world.WorldTypes; From a311fc1cefec1c43a8894da86b4c0743284bb2b9 Mon Sep 17 00:00:00 2001 From: TyBraniff Date: Tue, 7 May 2024 10:48:22 -0400 Subject: [PATCH 02/38] Devolvement of issues #145 + missing signs (#536) * Create cherry.json * Create bamboo.json * Create wall_cherry.json * Create wall_bamboo.json * Merging project Merging TysFixes resource pack with main Bluemap * Update blockColors.json Merging TysFixes Phase3 * Merging projects Adding everything from TysFixes Resource pack to core bluemap * Update decorated_pot.json * Update dragon_head.json * Update dragon_wall_head.json --- .../assets/minecraft/blockColors.json | 86 ++++++++++--- .../blockstates/acacia_hanging_sign.json | 67 ++++++++++ .../blockstates/acacia_wall_hanging_sign.json | 19 +++ .../blockstates/bamboo_hanging_sign.json | 67 ++++++++++ .../blockstates/bamboo_wall_hanging_sign.json | 19 +++ .../blockstates/birch_hanging_sign.json | 67 ++++++++++ .../blockstates/birch_wall_hanging_sign.json | 19 +++ .../minecraft/blockstates/black_banner.json | 67 ++++++++++ .../blockstates/black_shulker_box.json | 30 +++++ .../blockstates/black_wall_banner.json | 19 +++ .../minecraft/blockstates/blue_banner.json | 67 ++++++++++ .../blockstates/blue_shulker_box.json | 30 +++++ .../blockstates/blue_wall_banner.json | 19 +++ .../minecraft/blockstates/brown_banner.json | 67 ++++++++++ .../blockstates/brown_shulker_box.json | 30 +++++ .../blockstates/brown_wall_banner.json | 19 +++ .../blockstates/cherry_hanging_sign.json | 67 ++++++++++ .../blockstates/cherry_wall_hanging_sign.json | 19 +++ .../minecraft/blockstates/creeper_head.json | 67 ++++++++++ .../blockstates/creeper_wall_head.json | 19 +++ .../blockstates/crimson_hanging_sign.json | 67 ++++++++++ .../crimson_wall_hanging_sign.json | 19 +++ .../minecraft/blockstates/cyan_banner.json | 67 ++++++++++ .../blockstates/cyan_shulker_box.json | 30 +++++ .../blockstates/cyan_wall_banner.json | 19 +++ .../blockstates/dark_oak_hanging_sign.json | 67 ++++++++++ .../dark_oak_wall_hanging_sign.json | 19 +++ .../minecraft/blockstates/decorated_pot.json | 19 +++ .../minecraft/blockstates/dragon_head.json | 67 ++++++++++ .../blockstates/dragon_wall_head.json | 19 +++ .../minecraft/blockstates/gray_banner.json | 67 ++++++++++ .../blockstates/gray_shulker_box.json | 30 +++++ .../blockstates/gray_wall_banner.json | 19 +++ .../minecraft/blockstates/green_banner.json | 67 ++++++++++ .../blockstates/green_shulker_box.json | 30 +++++ .../blockstates/green_wall_banner.json | 19 +++ .../blockstates/jungle_hanging_sign.json | 67 ++++++++++ .../blockstates/jungle_wall_hanging_sign.json | 19 +++ .../blockstates/light_blue_banner.json | 67 ++++++++++ .../blockstates/light_blue_shulker_box.json | 30 +++++ .../blockstates/light_blue_wall_banner.json | 19 +++ .../blockstates/light_gray_banner.json | 67 ++++++++++ .../blockstates/light_gray_shulker_box.json | 30 +++++ .../blockstates/light_gray_wall_banner.json | 19 +++ .../minecraft/blockstates/lime_banner.json | 67 ++++++++++ .../blockstates/lime_shulker_box.json | 30 +++++ .../blockstates/lime_wall_banner.json | 19 +++ .../minecraft/blockstates/magenta_banner.json | 67 ++++++++++ .../blockstates/magenta_shulker_box.json | 30 +++++ .../blockstates/magenta_wall_banner.json | 19 +++ .../blockstates/mangrove_hanging_sign.json | 67 ++++++++++ .../mangrove_wall_hanging_sign.json | 19 +++ .../blockstates/oak_hanging_sign.json | 67 ++++++++++ .../blockstates/oak_wall_hanging_sign.json | 19 +++ .../minecraft/blockstates/orange_banner.json | 67 ++++++++++ .../blockstates/orange_shulker_box.json | 30 +++++ .../blockstates/orange_wall_banner.json | 19 +++ .../minecraft/blockstates/piglin_head.json | 67 ++++++++++ .../blockstates/piglin_wall_head.json | 19 +++ .../minecraft/blockstates/pink_banner.json | 67 ++++++++++ .../blockstates/pink_shulker_box.json | 30 +++++ .../blockstates/pink_wall_banner.json | 19 +++ .../minecraft/blockstates/player_head.json | 67 ++++++++++ .../blockstates/player_wall_head.json | 19 +++ .../minecraft/blockstates/purple_banner.json | 67 ++++++++++ .../blockstates/purple_shulker_box.json | 30 +++++ .../blockstates/purple_wall_banner.json | 19 +++ .../minecraft/blockstates/red_banner.json | 67 ++++++++++ .../blockstates/red_shulker_box.json | 30 +++++ .../blockstates/red_wall_banner.json | 19 +++ .../minecraft/blockstates/shulker_box.json | 30 +++++ .../minecraft/blockstates/skeleton_skull.json | 67 ++++++++++ .../blockstates/skeleton_wall_skull.json | 19 +++ .../blockstates/spruce_hanging_sign.json | 67 ++++++++++ .../blockstates/spruce_wall_hanging_sign.json | 19 +++ .../blockstates/warped_hanging_sign.json | 67 ++++++++++ .../blockstates/warped_wall_hanging_sign.json | 19 +++ .../minecraft/blockstates/white_banner.json | 67 ++++++++++ .../blockstates/white_shulker_box.json | 30 +++++ .../blockstates/white_wall_banner.json | 19 +++ .../blockstates/wither_skeleton_skull.json | 67 ++++++++++ .../wither_skeleton_wall_skull.json | 19 +++ .../minecraft/blockstates/yellow_banner.json | 67 ++++++++++ .../blockstates/yellow_shulker_box.json | 30 +++++ .../blockstates/yellow_wall_banner.json | 19 +++ .../minecraft/blockstates/zombie_head.json | 67 ++++++++++ .../blockstates/zombie_wall_head.json | 19 +++ .../models/block/bell_between_walls.json | 49 ++++++++ .../minecraft/models/block/bell_ceiling.json | 48 ++++++++ .../minecraft/models/block/bell_floor.json | 75 ++++++++++++ .../minecraft/models/block/bell_wall.json | 49 ++++++++ .../assets/minecraft/models/block/cake.json | 21 ++++ .../minecraft/models/block/cake_slice1.json | 24 ++++ .../minecraft/models/block/cake_slice2.json | 25 ++++ .../minecraft/models/block/cake_slice3.json | 25 ++++ .../minecraft/models/block/cake_slice4.json | 25 ++++ .../minecraft/models/block/cake_slice5.json | 25 ++++ .../minecraft/models/block/cake_slice6.json | 25 ++++ .../minecraft/models/block/sign/bamboo.json | 6 + .../minecraft/models/block/sign/cherry.json | 6 + .../models/block/sign/wall_bamboo.json | 6 + .../models/block/sign/wall_cherry.json | 6 + .../models/entity/acacia_hanging_sign.json | 7 ++ .../entity/acacia_wall_hanging_sign.json | 7 ++ .../models/entity/bamboo_hanging_sign.json | 7 ++ .../entity/bamboo_wall_hanging_sign.json | 7 ++ .../minecraft/models/entity/banner.json | 48 ++++++++ .../models/entity/birch_hanging_sign.json | 7 ++ .../entity/birch_wall_hanging_sign.json | 7 ++ .../models/entity/cherry_hanging_sign.json | 7 ++ .../entity/cherry_wall_hanging_sign.json | 7 ++ .../minecraft/models/entity/creeper_head.json | 7 ++ .../models/entity/creeper_wall_head.json | 7 ++ .../models/entity/crimson_hanging_sign.json | 7 ++ .../entity/crimson_wall_hanging_sign.json | 7 ++ .../models/entity/dark_oak_hanging_sign.json | 7 ++ .../entity/dark_oak_wall_hanging_sign.json | 7 ++ .../models/entity/decorated_pot.json | 48 ++++++++ .../minecraft/models/entity/dragon_head.json | 101 +++++++++++++++ .../models/entity/dragon_wall_head.json | 115 ++++++++++++++++++ .../models/entity/dyed_shulker_box.json | 33 +++++ .../minecraft/models/entity/hanging_sign.json | 35 ++++++ .../models/entity/jungle_hanging_sign.json | 7 ++ .../entity/jungle_wall_hanging_sign.json | 7 ++ .../models/entity/mangrove_hanging_sign.json | 7 ++ .../entity/mangrove_wall_hanging_sign.json | 7 ++ .../models/entity/oak_hanging_sign.json | 7 ++ .../models/entity/oak_wall_hanging_sign.json | 7 ++ .../minecraft/models/entity/piglin_head.json | 102 ++++++++++++++++ .../models/entity/piglin_wall_head.json | 107 ++++++++++++++++ .../minecraft/models/entity/player_head.json | 7 ++ .../models/entity/player_wall_head.json | 7 ++ .../minecraft/models/entity/shulker_box.json | 33 +++++ .../models/entity/skeleton_skull.json | 7 ++ .../models/entity/skeleton_wall_skull.json | 7 ++ .../minecraft/models/entity/skull_32.json | 32 +++++ .../minecraft/models/entity/skull_64.json | 32 +++++ .../models/entity/spruce_hanging_sign.json | 7 ++ .../entity/spruce_wall_hanging_sign.json | 7 ++ .../minecraft/models/entity/wall_banner.json | 35 ++++++ .../models/entity/wall_hanging_sign.json | 82 +++++++++++++ .../models/entity/wall_skull_32.json | 32 +++++ .../models/entity/wall_skull_64.json | 32 +++++ .../models/entity/warped_hanging_sign.json | 7 ++ .../entity/warped_wall_hanging_sign.json | 7 ++ .../models/entity/wither_skeleton_skull.json | 7 ++ .../entity/wither_skeleton_wall_skull.json | 7 ++ .../minecraft/models/entity/zombie_head.json | 7 ++ .../models/entity/zombie_wall_head.json | 7 ++ 149 files changed, 5026 insertions(+), 19 deletions(-) create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/acacia_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/acacia_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/bamboo_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/bamboo_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/birch_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/birch_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/black_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/black_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/black_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/blue_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/blue_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/blue_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/brown_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/brown_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/brown_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cherry_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cherry_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/creeper_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/creeper_wall_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/crimson_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/crimson_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cyan_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cyan_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cyan_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dark_oak_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dark_oak_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/decorated_pot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dragon_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dragon_wall_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/gray_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/gray_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/gray_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/green_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/green_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/green_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/jungle_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/jungle_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_blue_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_blue_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_blue_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_gray_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_gray_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_gray_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/lime_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/lime_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/lime_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/magenta_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/magenta_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/magenta_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/mangrove_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/mangrove_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/oak_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/oak_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/orange_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/orange_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/orange_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/piglin_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/piglin_wall_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/pink_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/pink_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/pink_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/player_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/player_wall_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/purple_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/purple_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/purple_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/red_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/red_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/red_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/skeleton_skull.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/skeleton_wall_skull.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/spruce_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/spruce_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/warped_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/warped_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/white_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/white_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/white_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/wither_skeleton_skull.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/wither_skeleton_wall_skull.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/yellow_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/yellow_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/yellow_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/zombie_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/zombie_wall_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bell_between_walls.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bell_ceiling.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bell_floor.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bell_wall.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice1.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice2.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice3.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice4.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice5.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice6.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/bamboo.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/cherry.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/wall_bamboo.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/wall_cherry.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/acacia_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/acacia_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/bamboo_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/bamboo_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/birch_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/birch_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/cherry_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/cherry_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/creeper_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/creeper_wall_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/crimson_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/crimson_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dark_oak_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dark_oak_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/decorated_pot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dragon_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dragon_wall_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dyed_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/jungle_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/jungle_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/mangrove_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/mangrove_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/oak_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/oak_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/piglin_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/piglin_wall_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/player_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/player_wall_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/skeleton_skull.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/skeleton_wall_skull.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/skull_32.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/skull_64.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/spruce_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/spruce_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wall_skull_32.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wall_skull_64.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/warped_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/warped_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wither_skeleton_skull.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wither_skeleton_wall_skull.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/zombie_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/zombie_wall_head.json diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockColors.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockColors.json index f948d0752..5c5e3f55e 100644 --- a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockColors.json +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockColors.json @@ -1,20 +1,68 @@ { - "default": "@foliage", - "minecraft:water": "@water", - "minecraft:cauldron": "@water", - "minecraft:water_cauldron": "@water", - "minecraft:powder_snow_cauldron": "#ffffff", - "minecraft:lava_cauldron": "#ffffff", - "minecraft:grass_block": "@grass", - "minecraft:grass": "@grass", - "minecraft:short_grass": "@grass", - "minecraft:tall_grass": "@grass", - "minecraft:fern": "@grass", - "minecraft:large_fern": "@grass", - "minecraft:redstone_wire": "@redstone", - "minecraft:birch_leaves": 8431445, - "minecraft:spruce_leaves": 6396257, - "minecraft:stonecutter": "#ffffff", - "minecraft:snow": "#ffffff", - "minecraft:cherry_leaves": "#ffffff" -} \ No newline at end of file + "default": "@foliage", + "minecraft:water": "@water", + "minecraft:cauldron": "@water", + "minecraft:water_cauldron": "@water", + "minecraft:powder_snow_cauldron": "#ffffff", + "minecraft:lava_cauldron": "#ffffff", + "minecraft:grass_block": "@grass", + "minecraft:grass": "@grass", + "minecraft:short_grass": "@grass", + "minecraft:tall_grass": "@grass", + "minecraft:fern": "@grass", + "minecraft:large_fern": "@grass", + "minecraft:redstone_wire": "@redstone", + "minecraft:birch_leaves": 8431445, + "minecraft:spruce_leaves": 6396257, + "minecraft:stonecutter": "#ffffff", + "minecraft:snow": "#ffffff", + "minecraft:cherry_leaves": "#ffffff", + "minecraft:white_banner": "#F9FFFE", + "minecraft:light_gray_banner": "#9D9D97", + "minecraft:gray_banner": "#474F52", + "minecraft:black_banner": "#1D1D21", + "minecraft:brown_banner": "#835432", + "minecraft:red_banner": "#B02E26", + "minecraft:orange_banner": "#F9801D", + "minecraft:yellow_banner": "#FED83D", + "minecraft:lime_banner": "#80C71F", + "minecraft:green_banner": "#5E7C16", + "minecraft:cyan_banner": "#169C9C", + "minecraft:light_blue_banner": "#3AB3DA", + "minecraft:blue_banner": "#3C44AA", + "minecraft:purple_banner": "#8932B8", + "minecraft:magenta_banner": "#C74EBD", + "minecraft:pink_banner": "#F38BAA", + "minecraft:white_wall_banner": "#F9FFFE", + "minecraft:light_gray_wall_banner": "#9D9D97", + "minecraft:gray_wall_banner": "#474F52", + "minecraft:black_wall_banner": "#1D1D21", + "minecraft:brown_wall_banner": "#835432", + "minecraft:red_wall_banner": "#B02E26", + "minecraft:orange_wall_banner": "#F9801D", + "minecraft:yellow_wall_banner": "#FED83D", + "minecraft:lime_wall_banner": "#80C71F", + "minecraft:green_wall_banner": "#5E7C16", + "minecraft:cyan_wall_banner": "#169C9C", + "minecraft:light_blue_wall_banner": "#3AB3DA", + "minecraft:blue_wall_banner": "#3C44AA", + "minecraft:purple_wall_banner": "#8932B8", + "minecraft:magenta_wall_banner": "#C74EBD", + "minecraft:pink_wall_banner": "#F38BAA", + "minecraft:white_shulker_box": "#F9FFFE", + "minecraft:light_gray_shulker_box": "#9D9D97", + "minecraft:gray_shulker_box": "#474F52", + "minecraft:black_shulker_box": "#1D1D21", + "minecraft:brown_shulker_box": "#835432", + "minecraft:red_shulker_box": "#B02E26", + "minecraft:orange_shulker_box": "#F9801D", + "minecraft:yellow_shulker_box": "#FED83D", + "minecraft:lime_shulker_box": "#80C71F", + "minecraft:green_shulker_box": "#5E7C16", + "minecraft:cyan_shulker_box": "#169C9C", + "minecraft:light_blue_shulker_box": "#3AB3DA", + "minecraft:blue_shulker_box": "#3C44AA", + "minecraft:purple_shulker_box": "#8932B8", + "minecraft:magenta_shulker_box": "#C74EBD", + "minecraft:pink_shulker_box": "#F38BAA" +} diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/acacia_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/acacia_hanging_sign.json new file mode 100644 index 000000000..7c36b4f03 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/acacia_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/acacia_hanging_sign", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/acacia_hanging_sign", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/acacia_hanging_sign", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/acacia_hanging_sign", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/acacia_hanging_sign", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/acacia_hanging_sign", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/acacia_hanging_sign", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/acacia_hanging_sign", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/acacia_hanging_sign" + }, + "rotation=9": { + "model": "minecraft:entity/acacia_hanging_sign", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/acacia_hanging_sign", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/acacia_hanging_sign", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/acacia_hanging_sign", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/acacia_hanging_sign", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/acacia_hanging_sign", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/acacia_hanging_sign", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/acacia_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/acacia_wall_hanging_sign.json new file mode 100644 index 000000000..d5d3852bc --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/acacia_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/acacia_wall_hanging_sign", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/acacia_wall_hanging_sign", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/acacia_wall_hanging_sign", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/acacia_wall_hanging_sign" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/bamboo_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/bamboo_hanging_sign.json new file mode 100644 index 000000000..423e28c83 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/bamboo_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/bamboo_hanging_sign", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/bamboo_hanging_sign", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/bamboo_hanging_sign", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/bamboo_hanging_sign", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/bamboo_hanging_sign", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/bamboo_hanging_sign", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/bamboo_hanging_sign", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/bamboo_hanging_sign", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/bamboo_hanging_sign" + }, + "rotation=9": { + "model": "minecraft:entity/bamboo_hanging_sign", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/bamboo_hanging_sign", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/bamboo_hanging_sign", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/bamboo_hanging_sign", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/bamboo_hanging_sign", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/bamboo_hanging_sign", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/bamboo_hanging_sign", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/bamboo_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/bamboo_wall_hanging_sign.json new file mode 100644 index 000000000..f86d43301 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/bamboo_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/bamboo_wall_hanging_sign", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/bamboo_wall_hanging_sign", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/bamboo_wall_hanging_sign", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/bamboo_wall_hanging_sign" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/birch_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/birch_hanging_sign.json new file mode 100644 index 000000000..23ec9b389 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/birch_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/birch_hanging_sign", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/birch_hanging_sign", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/birch_hanging_sign", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/birch_hanging_sign", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/birch_hanging_sign", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/birch_hanging_sign", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/birch_hanging_sign", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/birch_hanging_sign", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/birch_hanging_sign" + }, + "rotation=9": { + "model": "minecraft:entity/birch_hanging_sign", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/birch_hanging_sign", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/birch_hanging_sign", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/birch_hanging_sign", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/birch_hanging_sign", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/birch_hanging_sign", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/birch_hanging_sign", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/birch_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/birch_wall_hanging_sign.json new file mode 100644 index 000000000..4ea80412f --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/birch_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/birch_wall_hanging_sign", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/birch_wall_hanging_sign", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/birch_wall_hanging_sign", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/birch_wall_hanging_sign" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/black_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/black_banner.json new file mode 100644 index 000000000..1d4b95bd3 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/black_banner.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/banner", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/banner", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/banner", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/banner", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/banner", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/banner", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/banner", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/banner", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/banner" + }, + "rotation=9": { + "model": "minecraft:entity/banner", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/banner", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/banner", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/banner", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/banner", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/banner", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/banner", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/black_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/black_shulker_box.json new file mode 100644 index 000000000..49b0f9b0c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/black_shulker_box.json @@ -0,0 +1,30 @@ +{ + "variants": { + "facing=up": { + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=down": { + "x": 180, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=north": { + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=east": { + "y": 90, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=south": { + "y": 180, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=west": { + "y": 270, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/black_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/black_wall_banner.json new file mode 100644 index 000000000..e5220b763 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/black_wall_banner.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/wall_banner", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/wall_banner", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/wall_banner", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/wall_banner" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/blue_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/blue_banner.json new file mode 100644 index 000000000..a609ab6fb --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/blue_banner.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/banner", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/banner", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/banner", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/banner", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/banner", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/banner", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/banner", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/banner", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/banner" + }, + "rotation=9": { + "model": "minecraft:entity/banner", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/banner", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/banner", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/banner", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/banner", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/banner", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/banner", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/blue_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/blue_shulker_box.json new file mode 100644 index 000000000..49b0f9b0c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/blue_shulker_box.json @@ -0,0 +1,30 @@ +{ + "variants": { + "facing=up": { + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=down": { + "x": 180, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=north": { + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=east": { + "y": 90, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=south": { + "y": 180, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=west": { + "y": 270, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/blue_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/blue_wall_banner.json new file mode 100644 index 000000000..ad109b5f9 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/blue_wall_banner.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/wall_banner", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/wall_banner", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/wall_banner", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/wall_banner" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/brown_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/brown_banner.json new file mode 100644 index 000000000..a609ab6fb --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/brown_banner.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/banner", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/banner", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/banner", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/banner", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/banner", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/banner", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/banner", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/banner", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/banner" + }, + "rotation=9": { + "model": "minecraft:entity/banner", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/banner", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/banner", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/banner", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/banner", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/banner", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/banner", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/brown_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/brown_shulker_box.json new file mode 100644 index 000000000..49b0f9b0c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/brown_shulker_box.json @@ -0,0 +1,30 @@ +{ + "variants": { + "facing=up": { + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=down": { + "x": 180, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=north": { + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=east": { + "y": 90, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=south": { + "y": 180, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=west": { + "y": 270, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/brown_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/brown_wall_banner.json new file mode 100644 index 000000000..ad109b5f9 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/brown_wall_banner.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/wall_banner", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/wall_banner", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/wall_banner", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/wall_banner" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cherry_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cherry_hanging_sign.json new file mode 100644 index 000000000..35dda4600 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cherry_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/cherry_hanging_sign", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/cherry_hanging_sign", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/cherry_hanging_sign", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/cherry_hanging_sign", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/cherry_hanging_sign", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/cherry_hanging_sign", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/cherry_hanging_sign", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/cherry_hanging_sign", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/cherry_hanging_sign" + }, + "rotation=9": { + "model": "minecraft:entity/cherry_hanging_sign", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/cherry_hanging_sign", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/cherry_hanging_sign", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/cherry_hanging_sign", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/cherry_hanging_sign", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/cherry_hanging_sign", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/cherry_hanging_sign", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cherry_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cherry_wall_hanging_sign.json new file mode 100644 index 000000000..c9d5895a1 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cherry_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/cherry_wall_hanging_sign", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/cherry_wall_hanging_sign", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/cherry_wall_hanging_sign", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/cherry_wall_hanging_sign" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/creeper_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/creeper_head.json new file mode 100644 index 000000000..0bfc39f8b --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/creeper_head.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/creeper_head", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/creeper_head", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/creeper_head", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/creeper_head", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/creeper_head", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/creeper_head", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/creeper_head", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/creeper_head", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/creeper_head" + }, + "rotation=9": { + "model": "minecraft:entity/creeper_head", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/creeper_head", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/creeper_head", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/creeper_head", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/creeper_head", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/creeper_head", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/creeper_head", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/creeper_wall_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/creeper_wall_head.json new file mode 100644 index 000000000..6c5daf11e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/creeper_wall_head.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/creeper_wall_head", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/creeper_wall_head", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/creeper_wall_head", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/creeper_wall_head" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/crimson_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/crimson_hanging_sign.json new file mode 100644 index 000000000..b997b0918 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/crimson_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/crimson_hanging_sign", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/crimson_hanging_sign", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/crimson_hanging_sign", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/crimson_hanging_sign", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/crimson_hanging_sign", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/crimson_hanging_sign", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/crimson_hanging_sign", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/crimson_hanging_sign", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/crimson_hanging_sign" + }, + "rotation=9": { + "model": "minecraft:entity/crimson_hanging_sign", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/crimson_hanging_sign", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/crimson_hanging_sign", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/crimson_hanging_sign", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/crimson_hanging_sign", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/crimson_hanging_sign", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/crimson_hanging_sign", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/crimson_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/crimson_wall_hanging_sign.json new file mode 100644 index 000000000..80a746a3f --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/crimson_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/crimson_wall_hanging_sign", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/crimson_wall_hanging_sign", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/crimson_wall_hanging_sign", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/crimson_wall_hanging_sign" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cyan_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cyan_banner.json new file mode 100644 index 000000000..a609ab6fb --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cyan_banner.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/banner", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/banner", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/banner", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/banner", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/banner", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/banner", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/banner", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/banner", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/banner" + }, + "rotation=9": { + "model": "minecraft:entity/banner", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/banner", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/banner", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/banner", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/banner", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/banner", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/banner", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cyan_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cyan_shulker_box.json new file mode 100644 index 000000000..49b0f9b0c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cyan_shulker_box.json @@ -0,0 +1,30 @@ +{ + "variants": { + "facing=up": { + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=down": { + "x": 180, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=north": { + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=east": { + "y": 90, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=south": { + "y": 180, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=west": { + "y": 270, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cyan_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cyan_wall_banner.json new file mode 100644 index 000000000..ad109b5f9 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cyan_wall_banner.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/wall_banner", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/wall_banner", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/wall_banner", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/wall_banner" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dark_oak_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dark_oak_hanging_sign.json new file mode 100644 index 000000000..cf55d6165 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dark_oak_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/dark_oak_hanging_sign", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/dark_oak_hanging_sign", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/dark_oak_hanging_sign", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/dark_oak_hanging_sign", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/dark_oak_hanging_sign", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/dark_oak_hanging_sign", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/dark_oak_hanging_sign", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/dark_oak_hanging_sign", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/dark_oak_hanging_sign" + }, + "rotation=9": { + "model": "minecraft:entity/dark_oak_hanging_sign", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/dark_oak_hanging_sign", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/dark_oak_hanging_sign", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/dark_oak_hanging_sign", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/dark_oak_hanging_sign", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/dark_oak_hanging_sign", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/dark_oak_hanging_sign", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dark_oak_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dark_oak_wall_hanging_sign.json new file mode 100644 index 000000000..a62631b55 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dark_oak_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/dark_oak_wall_hanging_sign", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/dark_oak_wall_hanging_sign", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/dark_oak_wall_hanging_sign", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/dark_oak_wall_hanging_sign" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/decorated_pot.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/decorated_pot.json new file mode 100644 index 000000000..a93167c79 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/decorated_pot.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/decorated_pot", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/decorated_pot", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/decorated_pot", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/decorated_pot", + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dragon_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dragon_head.json new file mode 100644 index 000000000..935c6e101 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dragon_head.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/dragon_head", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/dragon_head", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/dragon_head", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/dragon_head", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/dragon_head", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/dragon_head", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/dragon_head", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/dragon_head", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/dragon_head" + }, + "rotation=9": { + "model": "minecraft:entity/dragon_head", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/dragon_head", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/dragon_head", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/dragon_head", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/dragon_head", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/dragon_head", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/dragon_head", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dragon_wall_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dragon_wall_head.json new file mode 100644 index 000000000..d1a1507fb --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dragon_wall_head.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/dragon_wall_head", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/dragon_wall_head", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/dragon_wall_head", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/dragon_wall_head" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/gray_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/gray_banner.json new file mode 100644 index 000000000..a609ab6fb --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/gray_banner.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/banner", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/banner", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/banner", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/banner", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/banner", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/banner", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/banner", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/banner", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/banner" + }, + "rotation=9": { + "model": "minecraft:entity/banner", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/banner", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/banner", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/banner", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/banner", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/banner", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/banner", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/gray_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/gray_shulker_box.json new file mode 100644 index 000000000..49b0f9b0c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/gray_shulker_box.json @@ -0,0 +1,30 @@ +{ + "variants": { + "facing=up": { + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=down": { + "x": 180, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=north": { + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=east": { + "y": 90, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=south": { + "y": 180, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=west": { + "y": 270, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/gray_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/gray_wall_banner.json new file mode 100644 index 000000000..ad109b5f9 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/gray_wall_banner.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/wall_banner", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/wall_banner", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/wall_banner", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/wall_banner" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/green_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/green_banner.json new file mode 100644 index 000000000..a609ab6fb --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/green_banner.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/banner", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/banner", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/banner", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/banner", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/banner", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/banner", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/banner", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/banner", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/banner" + }, + "rotation=9": { + "model": "minecraft:entity/banner", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/banner", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/banner", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/banner", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/banner", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/banner", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/banner", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/green_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/green_shulker_box.json new file mode 100644 index 000000000..49b0f9b0c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/green_shulker_box.json @@ -0,0 +1,30 @@ +{ + "variants": { + "facing=up": { + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=down": { + "x": 180, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=north": { + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=east": { + "y": 90, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=south": { + "y": 180, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=west": { + "y": 270, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/green_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/green_wall_banner.json new file mode 100644 index 000000000..ad109b5f9 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/green_wall_banner.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/wall_banner", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/wall_banner", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/wall_banner", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/wall_banner" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/jungle_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/jungle_hanging_sign.json new file mode 100644 index 000000000..13630fe79 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/jungle_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/jungle_hanging_sign", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/jungle_hanging_sign", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/jungle_hanging_sign", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/jungle_hanging_sign", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/jungle_hanging_sign", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/jungle_hanging_sign", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/jungle_hanging_sign", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/jungle_hanging_sign", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/jungle_hanging_sign" + }, + "rotation=9": { + "model": "minecraft:entity/jungle_hanging_sign", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/jungle_hanging_sign", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/jungle_hanging_sign", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/jungle_hanging_sign", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/jungle_hanging_sign", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/jungle_hanging_sign", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/jungle_hanging_sign", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/jungle_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/jungle_wall_hanging_sign.json new file mode 100644 index 000000000..1e6863322 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/jungle_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/jungle_wall_hanging_sign", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/jungle_wall_hanging_sign", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/jungle_wall_hanging_sign", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/jungle_wall_hanging_sign" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_blue_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_blue_banner.json new file mode 100644 index 000000000..a609ab6fb --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_blue_banner.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/banner", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/banner", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/banner", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/banner", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/banner", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/banner", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/banner", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/banner", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/banner" + }, + "rotation=9": { + "model": "minecraft:entity/banner", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/banner", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/banner", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/banner", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/banner", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/banner", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/banner", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_blue_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_blue_shulker_box.json new file mode 100644 index 000000000..49b0f9b0c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_blue_shulker_box.json @@ -0,0 +1,30 @@ +{ + "variants": { + "facing=up": { + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=down": { + "x": 180, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=north": { + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=east": { + "y": 90, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=south": { + "y": 180, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=west": { + "y": 270, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_blue_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_blue_wall_banner.json new file mode 100644 index 000000000..ad109b5f9 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_blue_wall_banner.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/wall_banner", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/wall_banner", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/wall_banner", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/wall_banner" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_gray_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_gray_banner.json new file mode 100644 index 000000000..a609ab6fb --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_gray_banner.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/banner", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/banner", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/banner", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/banner", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/banner", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/banner", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/banner", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/banner", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/banner" + }, + "rotation=9": { + "model": "minecraft:entity/banner", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/banner", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/banner", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/banner", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/banner", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/banner", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/banner", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_gray_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_gray_shulker_box.json new file mode 100644 index 000000000..49b0f9b0c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_gray_shulker_box.json @@ -0,0 +1,30 @@ +{ + "variants": { + "facing=up": { + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=down": { + "x": 180, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=north": { + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=east": { + "y": 90, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=south": { + "y": 180, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=west": { + "y": 270, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_gray_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_gray_wall_banner.json new file mode 100644 index 000000000..ad109b5f9 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_gray_wall_banner.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/wall_banner", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/wall_banner", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/wall_banner", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/wall_banner" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/lime_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/lime_banner.json new file mode 100644 index 000000000..a609ab6fb --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/lime_banner.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/banner", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/banner", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/banner", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/banner", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/banner", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/banner", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/banner", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/banner", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/banner" + }, + "rotation=9": { + "model": "minecraft:entity/banner", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/banner", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/banner", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/banner", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/banner", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/banner", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/banner", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/lime_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/lime_shulker_box.json new file mode 100644 index 000000000..49b0f9b0c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/lime_shulker_box.json @@ -0,0 +1,30 @@ +{ + "variants": { + "facing=up": { + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=down": { + "x": 180, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=north": { + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=east": { + "y": 90, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=south": { + "y": 180, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=west": { + "y": 270, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/lime_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/lime_wall_banner.json new file mode 100644 index 000000000..ad109b5f9 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/lime_wall_banner.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/wall_banner", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/wall_banner", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/wall_banner", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/wall_banner" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/magenta_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/magenta_banner.json new file mode 100644 index 000000000..a609ab6fb --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/magenta_banner.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/banner", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/banner", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/banner", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/banner", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/banner", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/banner", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/banner", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/banner", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/banner" + }, + "rotation=9": { + "model": "minecraft:entity/banner", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/banner", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/banner", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/banner", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/banner", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/banner", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/banner", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/magenta_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/magenta_shulker_box.json new file mode 100644 index 000000000..49b0f9b0c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/magenta_shulker_box.json @@ -0,0 +1,30 @@ +{ + "variants": { + "facing=up": { + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=down": { + "x": 180, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=north": { + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=east": { + "y": 90, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=south": { + "y": 180, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=west": { + "y": 270, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/magenta_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/magenta_wall_banner.json new file mode 100644 index 000000000..ad109b5f9 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/magenta_wall_banner.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/wall_banner", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/wall_banner", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/wall_banner", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/wall_banner" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/mangrove_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/mangrove_hanging_sign.json new file mode 100644 index 000000000..56c0c256c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/mangrove_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/mangrove_hanging_sign", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/mangrove_hanging_sign", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/mangrove_hanging_sign", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/mangrove_hanging_sign", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/mangrove_hanging_sign", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/mangrove_hanging_sign", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/mangrove_hanging_sign", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/mangrove_hanging_sign", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/mangrove_hanging_sign" + }, + "rotation=9": { + "model": "minecraft:entity/mangrove_hanging_sign", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/mangrove_hanging_sign", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/mangrove_hanging_sign", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/mangrove_hanging_sign", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/mangrove_hanging_sign", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/mangrove_hanging_sign", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/mangrove_hanging_sign", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/mangrove_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/mangrove_wall_hanging_sign.json new file mode 100644 index 000000000..929b3c727 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/mangrove_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/mangrove_wall_hanging_sign", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/mangrove_wall_hanging_sign", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/mangrove_wall_hanging_sign", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/mangrove_wall_hanging_sign" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/oak_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/oak_hanging_sign.json new file mode 100644 index 000000000..d31d6229b --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/oak_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/oak_hanging_sign", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/oak_hanging_sign", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/oak_hanging_sign", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/oak_hanging_sign", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/oak_hanging_sign", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/oak_hanging_sign", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/oak_hanging_sign", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/oak_hanging_sign", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/oak_hanging_sign" + }, + "rotation=9": { + "model": "minecraft:entity/oak_hanging_sign", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/oak_hanging_sign", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/oak_hanging_sign", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/oak_hanging_sign", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/oak_hanging_sign", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/oak_hanging_sign", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/oak_hanging_sign", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/oak_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/oak_wall_hanging_sign.json new file mode 100644 index 000000000..536431b0a --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/oak_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/oak_wall_hanging_sign", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/oak_wall_hanging_sign", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/oak_wall_hanging_sign", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/oak_wall_hanging_sign" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/orange_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/orange_banner.json new file mode 100644 index 000000000..a609ab6fb --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/orange_banner.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/banner", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/banner", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/banner", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/banner", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/banner", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/banner", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/banner", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/banner", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/banner" + }, + "rotation=9": { + "model": "minecraft:entity/banner", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/banner", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/banner", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/banner", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/banner", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/banner", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/banner", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/orange_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/orange_shulker_box.json new file mode 100644 index 000000000..49b0f9b0c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/orange_shulker_box.json @@ -0,0 +1,30 @@ +{ + "variants": { + "facing=up": { + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=down": { + "x": 180, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=north": { + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=east": { + "y": 90, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=south": { + "y": 180, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=west": { + "y": 270, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/orange_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/orange_wall_banner.json new file mode 100644 index 000000000..ad109b5f9 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/orange_wall_banner.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/wall_banner", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/wall_banner", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/wall_banner", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/wall_banner" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/piglin_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/piglin_head.json new file mode 100644 index 000000000..abc9d8cb1 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/piglin_head.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/piglin_head", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/piglin_head", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/piglin_head", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/piglin_head", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/piglin_head", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/piglin_head", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/piglin_head", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/piglin_head", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/piglin_head" + }, + "rotation=9": { + "model": "minecraft:entity/piglin_head", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/piglin_head", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/piglin_head", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/piglin_head", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/piglin_head", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/piglin_head", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/piglin_head", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/piglin_wall_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/piglin_wall_head.json new file mode 100644 index 000000000..93fcbb679 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/piglin_wall_head.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/piglin_wall_head", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/piglin_wall_head", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/piglin_wall_head", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/piglin_wall_head" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/pink_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/pink_banner.json new file mode 100644 index 000000000..a609ab6fb --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/pink_banner.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/banner", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/banner", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/banner", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/banner", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/banner", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/banner", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/banner", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/banner", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/banner" + }, + "rotation=9": { + "model": "minecraft:entity/banner", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/banner", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/banner", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/banner", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/banner", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/banner", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/banner", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/pink_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/pink_shulker_box.json new file mode 100644 index 000000000..49b0f9b0c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/pink_shulker_box.json @@ -0,0 +1,30 @@ +{ + "variants": { + "facing=up": { + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=down": { + "x": 180, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=north": { + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=east": { + "y": 90, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=south": { + "y": 180, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=west": { + "y": 270, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/pink_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/pink_wall_banner.json new file mode 100644 index 000000000..ad109b5f9 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/pink_wall_banner.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/wall_banner", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/wall_banner", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/wall_banner", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/wall_banner" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/player_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/player_head.json new file mode 100644 index 000000000..75fb1793d --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/player_head.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/player_head", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/player_head", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/player_head", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/player_head", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/player_head", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/player_head", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/player_head", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/player_head", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/player_head" + }, + "rotation=9": { + "model": "minecraft:entity/player_head", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/player_head", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/player_head", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/player_head", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/player_head", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/player_head", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/player_head", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/player_wall_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/player_wall_head.json new file mode 100644 index 000000000..98c6dbd3c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/player_wall_head.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/player_wall_head", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/player_wall_head", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/player_wall_head", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/player_wall_head" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/purple_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/purple_banner.json new file mode 100644 index 000000000..a609ab6fb --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/purple_banner.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/banner", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/banner", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/banner", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/banner", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/banner", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/banner", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/banner", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/banner", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/banner" + }, + "rotation=9": { + "model": "minecraft:entity/banner", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/banner", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/banner", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/banner", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/banner", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/banner", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/banner", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/purple_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/purple_shulker_box.json new file mode 100644 index 000000000..49b0f9b0c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/purple_shulker_box.json @@ -0,0 +1,30 @@ +{ + "variants": { + "facing=up": { + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=down": { + "x": 180, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=north": { + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=east": { + "y": 90, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=south": { + "y": 180, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=west": { + "y": 270, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/purple_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/purple_wall_banner.json new file mode 100644 index 000000000..ad109b5f9 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/purple_wall_banner.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/wall_banner", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/wall_banner", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/wall_banner", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/wall_banner" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/red_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/red_banner.json new file mode 100644 index 000000000..a609ab6fb --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/red_banner.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/banner", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/banner", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/banner", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/banner", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/banner", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/banner", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/banner", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/banner", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/banner" + }, + "rotation=9": { + "model": "minecraft:entity/banner", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/banner", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/banner", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/banner", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/banner", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/banner", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/banner", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/red_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/red_shulker_box.json new file mode 100644 index 000000000..49b0f9b0c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/red_shulker_box.json @@ -0,0 +1,30 @@ +{ + "variants": { + "facing=up": { + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=down": { + "x": 180, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=north": { + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=east": { + "y": 90, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=south": { + "y": 180, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=west": { + "y": 270, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/red_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/red_wall_banner.json new file mode 100644 index 000000000..ad109b5f9 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/red_wall_banner.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/wall_banner", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/wall_banner", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/wall_banner", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/wall_banner" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/shulker_box.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/shulker_box.json new file mode 100644 index 000000000..6a88ff15c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/shulker_box.json @@ -0,0 +1,30 @@ +{ + "variants": { + "facing=up": { + "model": "minecraft:entity/shulker_box" + }, + "facing=down": { + "x": 180, + "model": "minecraft:entity/shulker_box" + }, + "facing=north": { + "x": 90, + "model": "minecraft:entity/shulker_box" + }, + "facing=east": { + "y": 90, + "x": 90, + "model": "minecraft:entity/shulker_box" + }, + "facing=south": { + "y": 180, + "x": 90, + "model": "minecraft:entity/shulker_box" + }, + "facing=west": { + "y": 270, + "x": 90, + "model": "minecraft:entity/shulker_box" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/skeleton_skull.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/skeleton_skull.json new file mode 100644 index 000000000..446ae8972 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/skeleton_skull.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/skeleton_skull", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/skeleton_skull", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/skeleton_skull", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/skeleton_skull", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/skeleton_skull", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/skeleton_skull", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/skeleton_skull", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/skeleton_skull", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/skeleton_skull" + }, + "rotation=9": { + "model": "minecraft:entity/skeleton_skull", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/skeleton_skull", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/skeleton_skull", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/skeleton_skull", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/skeleton_skull", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/skeleton_skull", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/skeleton_skull", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/skeleton_wall_skull.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/skeleton_wall_skull.json new file mode 100644 index 000000000..039179543 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/skeleton_wall_skull.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/skeleton_wall_skull", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/skeleton_wall_skull", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/skeleton_wall_skull", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/skeleton_wall_skull" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/spruce_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/spruce_hanging_sign.json new file mode 100644 index 000000000..6e55d2281 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/spruce_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/spruce_hanging_sign", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/spruce_hanging_sign", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/spruce_hanging_sign", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/spruce_hanging_sign", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/spruce_hanging_sign", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/spruce_hanging_sign", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/spruce_hanging_sign", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/spruce_hanging_sign", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/spruce_hanging_sign" + }, + "rotation=9": { + "model": "minecraft:entity/spruce_hanging_sign", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/spruce_hanging_sign", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/spruce_hanging_sign", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/spruce_hanging_sign", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/spruce_hanging_sign", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/spruce_hanging_sign", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/spruce_hanging_sign", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/spruce_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/spruce_wall_hanging_sign.json new file mode 100644 index 000000000..798200b4e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/spruce_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/spruce_wall_hanging_sign", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/spruce_wall_hanging_sign", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/spruce_wall_hanging_sign", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/spruce_wall_hanging_sign" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/warped_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/warped_hanging_sign.json new file mode 100644 index 000000000..0bd54b197 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/warped_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/warped_hanging_sign", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/warped_hanging_sign", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/warped_hanging_sign", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/warped_hanging_sign", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/warped_hanging_sign", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/warped_hanging_sign", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/warped_hanging_sign", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/warped_hanging_sign", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/warped_hanging_sign" + }, + "rotation=9": { + "model": "minecraft:entity/warped_hanging_sign", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/warped_hanging_sign", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/warped_hanging_sign", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/warped_hanging_sign", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/warped_hanging_sign", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/warped_hanging_sign", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/warped_hanging_sign", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/warped_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/warped_wall_hanging_sign.json new file mode 100644 index 000000000..498c32651 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/warped_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/warped_wall_hanging_sign", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/warped_wall_hanging_sign", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/warped_wall_hanging_sign", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/warped_wall_hanging_sign" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/white_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/white_banner.json new file mode 100644 index 000000000..1d4b95bd3 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/white_banner.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/banner", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/banner", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/banner", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/banner", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/banner", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/banner", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/banner", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/banner", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/banner" + }, + "rotation=9": { + "model": "minecraft:entity/banner", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/banner", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/banner", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/banner", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/banner", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/banner", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/banner", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/white_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/white_shulker_box.json new file mode 100644 index 000000000..49b0f9b0c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/white_shulker_box.json @@ -0,0 +1,30 @@ +{ + "variants": { + "facing=up": { + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=down": { + "x": 180, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=north": { + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=east": { + "y": 90, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=south": { + "y": 180, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=west": { + "y": 270, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/white_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/white_wall_banner.json new file mode 100644 index 000000000..e5220b763 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/white_wall_banner.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/wall_banner", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/wall_banner", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/wall_banner", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/wall_banner" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/wither_skeleton_skull.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/wither_skeleton_skull.json new file mode 100644 index 000000000..92bfa7665 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/wither_skeleton_skull.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/wither_skeleton_skull", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/wither_skeleton_skull", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/wither_skeleton_skull", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/wither_skeleton_skull", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/wither_skeleton_skull", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/wither_skeleton_skull", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/wither_skeleton_skull", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/wither_skeleton_skull", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/wither_skeleton_skull" + }, + "rotation=9": { + "model": "minecraft:entity/wither_skeleton_skull", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/wither_skeleton_skull", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/wither_skeleton_skull", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/wither_skeleton_skull", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/wither_skeleton_skull", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/wither_skeleton_skull", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/wither_skeleton_skull", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/wither_skeleton_wall_skull.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/wither_skeleton_wall_skull.json new file mode 100644 index 000000000..14ac15c9d --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/wither_skeleton_wall_skull.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/wither_skeleton_wall_skull", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/wither_skeleton_wall_skull", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/wither_skeleton_wall_skull", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/wither_skeleton_wall_skull" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/yellow_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/yellow_banner.json new file mode 100644 index 000000000..a609ab6fb --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/yellow_banner.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/banner", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/banner", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/banner", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/banner", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/banner", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/banner", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/banner", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/banner", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/banner" + }, + "rotation=9": { + "model": "minecraft:entity/banner", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/banner", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/banner", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/banner", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/banner", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/banner", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/banner", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/yellow_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/yellow_shulker_box.json new file mode 100644 index 000000000..49b0f9b0c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/yellow_shulker_box.json @@ -0,0 +1,30 @@ +{ + "variants": { + "facing=up": { + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=down": { + "x": 180, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=north": { + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=east": { + "y": 90, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=south": { + "y": 180, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + }, + "facing=west": { + "y": 270, + "x": 90, + "model": "minecraft:entity/dyed_shulker_box" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/yellow_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/yellow_wall_banner.json new file mode 100644 index 000000000..ad109b5f9 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/yellow_wall_banner.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/wall_banner", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/wall_banner", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/wall_banner", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/wall_banner" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/zombie_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/zombie_head.json new file mode 100644 index 000000000..358676f7a --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/zombie_head.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "minecraft:entity/zombie_head", + "y": 180 + }, + "rotation=1": { + "model": "minecraft:entity/zombie_head", + "y": 202 + }, + "rotation=2": { + "model": "minecraft:entity/zombie_head", + "y": 225 + }, + "rotation=3": { + "model": "minecraft:entity/zombie_head", + "y": 247 + }, + "rotation=4": { + "model": "minecraft:entity/zombie_head", + "y": 270 + }, + "rotation=5": { + "model": "minecraft:entity/zombie_head", + "y": 292 + }, + "rotation=6": { + "model": "minecraft:entity/zombie_head", + "y": 315 + }, + "rotation=7": { + "model": "minecraft:entity/zombie_head", + "y": 337 + }, + "rotation=8": { + "model": "minecraft:entity/zombie_head" + }, + "rotation=9": { + "model": "minecraft:entity/zombie_head", + "y": 22 + }, + "rotation=10": { + "model": "minecraft:entity/zombie_head", + "y": 45 + }, + "rotation=11": { + "model": "minecraft:entity/zombie_head", + "y": 67 + }, + "rotation=12": { + "model": "minecraft:entity/zombie_head", + "y": 90 + }, + "rotation=13": { + "model": "minecraft:entity/zombie_head", + "y": 112 + }, + "rotation=14": { + "model": "minecraft:entity/zombie_head", + "y": 135 + }, + "rotation=15": { + "model": "minecraft:entity/zombie_head", + "y": 157 + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/zombie_wall_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/zombie_wall_head.json new file mode 100644 index 000000000..7805152f7 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/zombie_wall_head.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "minecraft:entity/zombie_wall_head", + "y": 90 + }, + "facing=south": { + "model": "minecraft:entity/zombie_wall_head", + "y": 180 + }, + "facing=west": { + "model": "minecraft:entity/zombie_wall_head", + "y": 270 + }, + "facing=north": { + "model": "minecraft:entity/zombie_wall_head" + } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bell_between_walls.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bell_between_walls.json new file mode 100644 index 000000000..c2d74786e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bell_between_walls.json @@ -0,0 +1,49 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "2": "block/bell_bottom", + "3": "block/bell_side", + "4": "block/bell_top", + "bar": "block/dark_oak_planks" + }, + "elements": [ + { + "from": [0, 13, 7], + "to": [16, 15, 9], + "faces": { + "north": {"uv": [2, 2, 14, 4], "texture": "#bar"}, + "east": {"uv": [5, 4, 7, 6], "texture": "#bar", "cullface": "east"}, + "south": {"uv": [2, 3, 14, 5], "texture": "#bar"}, + "west": {"uv": [5, 4, 7, 6], "texture": "#bar", "cullface": "west"}, + "up": {"uv": [2, 3, 14, 5], "texture": "#bar"}, + "down": {"uv": [2, 3, 14, 5], "texture": "#bar"} + } + }, + { + "name": "BellBase", + "from": [4, 4, 4], + "to": [12, 6, 12], + "faces": { + "north": {"uv": [0, 7, 8, 9], "texture": "#3"}, + "east": {"uv": [0, 7, 8, 9], "texture": "#3"}, + "south": {"uv": [0, 7, 8, 9], "texture": "#3"}, + "west": {"uv": [0, 7, 8, 9], "texture": "#3"}, + "up": {"uv": [0, 0, 8, 8], "texture": "#4"}, + "down": {"uv": [0, 0, 8, 8], "texture": "#2"} + } + }, + { + "name": "BellTop", + "from": [5, 6, 5], + "to": [11, 13, 11], + "faces": { + "north": {"uv": [1, 0, 7, 7], "texture": "#3"}, + "east": {"uv": [1, 0, 7, 7], "texture": "#3"}, + "south": {"uv": [1, 0, 7, 7], "texture": "#3"}, + "west": {"uv": [1, 0, 7, 7], "texture": "#3"}, + "up": {"uv": [1, 1, 7, 7], "texture": "#4"}, + "down": {"uv": [8, 1, 9, 2], "texture": "#2"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bell_ceiling.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bell_ceiling.json new file mode 100644 index 000000000..a0ce7068f --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bell_ceiling.json @@ -0,0 +1,48 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "2": "block/bell_side", + "3": "block/bell_top", + "4": "block/bell_bottom", + "bar": "block/dark_oak_planks" + }, + "elements": [ + { + "from": [7, 13, 7], + "to": [9, 16, 9], + "faces": { + "north": {"uv": [7, 2, 9, 5], "texture": "#bar"}, + "east": {"uv": [1, 2, 3, 5], "texture": "#bar"}, + "south": {"uv": [6, 2, 8, 5], "texture": "#bar"}, + "west": {"uv": [4, 2, 6, 5], "texture": "#bar"}, + "up": {"uv": [1, 3, 3, 5], "texture": "#bar", "cullface": "up"} + } + }, + { + "name": "BellBase", + "from": [4, 4, 4], + "to": [12, 6, 12], + "faces": { + "north": {"uv": [0, 7, 8, 9], "texture": "#2"}, + "east": {"uv": [0, 7, 8, 9], "texture": "#2"}, + "south": {"uv": [0, 7, 8, 9], "texture": "#2"}, + "west": {"uv": [0, 7, 8, 9], "texture": "#2"}, + "up": {"uv": [0, 0, 8, 8], "texture": "#3"}, + "down": {"uv": [0, 0, 8, 8], "texture": "#4"} + } + }, + { + "name": "BellTop", + "from": [5, 6, 5], + "to": [11, 13, 11], + "faces": { + "north": {"uv": [1, 0, 7, 7], "texture": "#2"}, + "east": {"uv": [1, 0, 7, 7], "texture": "#2"}, + "south": {"uv": [1, 0, 7, 7], "texture": "#2"}, + "west": {"uv": [1, 0, 7, 7], "texture": "#2"}, + "up": {"uv": [1, 1, 7, 7], "texture": "#2"}, + "down": {"uv": [8, 1, 9, 2], "texture": "#4"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bell_floor.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bell_floor.json new file mode 100644 index 000000000..433650e92 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bell_floor.json @@ -0,0 +1,75 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "3": "block/bell_top", + "4": "block/bell_bottom", + "5": "block/bell_side", + "bar": "block/dark_oak_planks", + "post": "block/stone" + }, + "elements": [ + { + "name": "Topbar", + "from": [2, 13, 7], + "to": [14, 15, 9], + "faces": { + "north": {"uv": [2, 2, 14, 4], "texture": "#bar"}, + "south": {"uv": [2, 3, 14, 5], "texture": "#bar"}, + "up": {"uv": [2, 3, 14, 5], "texture": "#bar"}, + "down": {"uv": [2, 3, 14, 5], "texture": "#bar"} + } + }, + { + "name": "Eastpost", + "from": [14, 0, 6], + "to": [16, 16, 10], + "faces": { + "north": {"uv": [0, 1, 2, 16], "texture": "#post"}, + "east": {"uv": [0, 1, 4, 16], "texture": "#post"}, + "south": {"uv": [0, 1, 2, 16], "texture": "#post"}, + "west": {"uv": [0, 1, 4, 16], "texture": "#post"}, + "up": {"uv": [0, 0, 2, 4], "texture": "#post", "cullface": "up"}, + "down": {"uv": [0, 0, 2, 4], "texture": "#post", "cullface": "down"} + } + }, + { + "name": "Westpost", + "from": [0, 0, 6], + "to": [2, 16, 10], + "faces": { + "north": {"uv": [0, 1, 2, 16], "texture": "#post"}, + "east": {"uv": [0, 1, 4, 16], "texture": "#post"}, + "south": {"uv": [0, 1, 2, 16], "texture": "#post"}, + "west": {"uv": [0, 1, 4, 16], "texture": "#post"}, + "up": {"uv": [0, 0, 2, 4], "texture": "#post", "cullface": "up"}, + "down": {"uv": [0, 0, 2, 4], "texture": "#post", "cullface": "down"} + } + }, + { + "name": "BellBase", + "from": [4, 4, 4], + "to": [12, 6, 12], + "faces": { + "north": {"uv": [0, 7, 8, 9], "texture": "#5"}, + "east": {"uv": [0, 7, 8, 9], "texture": "#5"}, + "south": {"uv": [0, 7, 8, 9], "texture": "#5"}, + "west": {"uv": [0, 7, 8, 9], "texture": "#5"}, + "up": {"uv": [0, 0, 8, 8], "texture": "#3"}, + "down": {"uv": [0, 0, 8, 8], "texture": "#4"} + } + }, + { + "name": "BellTop", + "from": [5, 6, 5], + "to": [11, 13, 11], + "faces": { + "north": {"uv": [1, 0, 7, 7], "texture": "#5"}, + "east": {"uv": [1, 0, 7, 7], "texture": "#5"}, + "south": {"uv": [1, 0, 7, 7], "texture": "#5"}, + "west": {"uv": [1, 0, 7, 7], "texture": "#5"}, + "up": {"uv": [1, 1, 7, 7], "texture": "#3"}, + "down": {"uv": [8, 1, 9, 2], "texture": "#4"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bell_wall.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bell_wall.json new file mode 100644 index 000000000..3a48dcd98 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bell_wall.json @@ -0,0 +1,49 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "2": "block/bell_side", + "3": "block/bell_top", + "4": "block/bell_bottom", + "bar": "block/dark_oak_planks" + }, + "elements": [ + { + "from": [3, 13, 7], + "to": [16, 15, 9], + "faces": { + "north": {"uv": [2, 2, 14, 4], "texture": "#bar"}, + "east": {"uv": [5, 4, 7, 6], "texture": "#bar", "cullface": "east"}, + "south": {"uv": [2, 3, 14, 5], "texture": "#bar"}, + "west": {"uv": [5, 4, 7, 6], "texture": "#bar"}, + "up": {"uv": [2, 3, 14, 5], "texture": "#bar"}, + "down": {"uv": [2, 3, 14, 5], "texture": "#bar"} + } + }, + { + "name": "BellBase", + "from": [4, 4, 4], + "to": [12, 6, 12], + "faces": { + "north": {"uv": [0, 7, 8, 9], "texture": "#2"}, + "east": {"uv": [0, 7, 8, 9], "texture": "#2"}, + "south": {"uv": [0, 7, 8, 9], "texture": "#2"}, + "west": {"uv": [0, 7, 8, 9], "texture": "#2"}, + "up": {"uv": [0, 0, 8, 8], "texture": "#3"}, + "down": {"uv": [0, 0, 8, 8], "texture": "#4"} + } + }, + { + "name": "BellTop", + "from": [5, 6, 5], + "to": [11, 13, 11], + "faces": { + "north": {"uv": [1, 0, 7, 7], "texture": "#2"}, + "east": {"uv": [1, 0, 7, 7], "texture": "#2"}, + "south": {"uv": [1, 0, 7, 7], "texture": "#2"}, + "west": {"uv": [1, 0, 7, 7], "texture": "#2"}, + "up": {"uv": [1, 1, 7, 7], "texture": "#3"}, + "down": {"uv": [8, 1, 9, 2], "texture": "#4"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake.json new file mode 100644 index 000000000..9aba67bb0 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake.json @@ -0,0 +1,21 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "textures": { + "top": "block/cake_top", + "side": "block/cake_side" + }, + "elements": [ + { + "from": [1, 0, 1], + "to": [15, 8, 15], + "faces": { + "north": {"uv": [1, 8, 15, 16], "texture": "#side"}, + "east": {"uv": [1, 8, 15, 16], "texture": "#side"}, + "south": {"uv": [1, 8, 15, 16], "texture": "#side"}, + "west": {"uv": [1, 8, 15, 16], "texture": "#side"}, + "up": {"uv": [1, 1, 15, 15], "texture": "#top"}, + "down": {"uv": [0, 0, 1, 1], "texture": "#top"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice1.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice1.json new file mode 100644 index 000000000..789fe0788 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice1.json @@ -0,0 +1,24 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "ambientocclusion": false, + "textures": { + "3": "block/cake_inner", + "particle": "block/cake_inner", + "top": "block/cake_top", + "side": "block/cake_side" + }, + "elements": [ + { + "from": [3, 0, 1], + "to": [15, 8, 15], + "faces": { + "north": {"uv": [1, 8, 13, 16], "texture": "#side"}, + "east": {"uv": [1, 8, 15, 16], "texture": "#side"}, + "south": {"uv": [3, 8, 15, 16], "texture": "#side"}, + "west": {"uv": [1, 8, 15, 16], "texture": "#3"}, + "up": {"uv": [3, 1, 15, 15], "texture": "#top"}, + "down": {"uv": [0, 0, 1, 1], "texture": "#top"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice2.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice2.json new file mode 100644 index 000000000..f7aecbbd0 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice2.json @@ -0,0 +1,25 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "ambientocclusion": false, + "textures": { + "3": "block/cake_inner", + "bottom": "block/cake_bottom", + "top": "block/cake_top", + "side": "block/cake_side", + "particle": "block/cake_inner" + }, + "elements": [ + { + "from": [5, 0, 1], + "to": [15, 8, 15], + "faces": { + "north": {"uv": [1, 8, 11, 16], "texture": "#side"}, + "east": {"uv": [1, 8, 15, 16], "texture": "#side"}, + "south": {"uv": [5, 8, 15, 16], "texture": "#side"}, + "west": {"uv": [1, 8, 15, 16], "texture": "#3"}, + "up": {"uv": [5, 1, 15, 15], "texture": "#top"}, + "down": {"uv": [1, 1, 0, 15], "texture": "#bottom"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice3.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice3.json new file mode 100644 index 000000000..a4c97c982 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice3.json @@ -0,0 +1,25 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "ambientocclusion": false, + "textures": { + "3": "block/cake_inner", + "bottom": "block/cake_bottom", + "top": "block/cake_top", + "side": "block/cake_side", + "particle": "block/cake_inner" + }, + "elements": [ + { + "from": [7, 0, 1], + "to": [15, 8, 15], + "faces": { + "north": {"uv": [1, 8, 9, 16], "texture": "#side"}, + "east": {"uv": [1, 8, 15, 16], "texture": "#side"}, + "south": {"uv": [7, 8, 15, 16], "texture": "#side"}, + "west": {"uv": [1, 8, 15, 16], "texture": "#3"}, + "up": {"uv": [7, 1, 15, 15], "texture": "#top"}, + "down": {"uv": [1, 1, 0, 15], "texture": "#bottom"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice4.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice4.json new file mode 100644 index 000000000..c4d2cb8bb --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice4.json @@ -0,0 +1,25 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "ambientocclusion": false, + "textures": { + "3": "block/cake_inner", + "bottom": "block/cake_bottom", + "top": "block/cake_top", + "side": "block/cake_side", + "particle": "block/cake_inner" + }, + "elements": [ + { + "from": [9, 0, 1], + "to": [15, 8, 15], + "faces": { + "north": {"uv": [1, 8, 7, 16], "texture": "#side"}, + "east": {"uv": [1, 8, 15, 16], "texture": "#side"}, + "south": {"uv": [9, 8, 15, 16], "texture": "#side"}, + "west": {"uv": [1, 8, 15, 16], "texture": "#3"}, + "up": {"uv": [9, 1, 15, 15], "texture": "#top"}, + "down": {"uv": [1, 1, 0, 15], "texture": "#bottom"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice5.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice5.json new file mode 100644 index 000000000..299c92452 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice5.json @@ -0,0 +1,25 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "ambientocclusion": false, + "textures": { + "3": "block/cake_inner", + "bottom": "block/cake_bottom", + "top": "block/cake_top", + "side": "block/cake_side", + "particle": "block/cake_inner" + }, + "elements": [ + { + "from": [11, 0, 1], + "to": [15, 8, 15], + "faces": { + "north": {"uv": [1, 8, 5, 16], "texture": "#side"}, + "east": {"uv": [1, 8, 15, 16], "texture": "#side"}, + "south": {"uv": [11, 8, 15, 16], "texture": "#side"}, + "west": {"uv": [1, 8, 15, 16], "texture": "#3"}, + "up": {"uv": [11, 1, 15, 15], "texture": "#top"}, + "down": {"uv": [1, 1, 0, 15], "texture": "#bottom"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice6.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice6.json new file mode 100644 index 000000000..03ea09b63 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice6.json @@ -0,0 +1,25 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "ambientocclusion": false, + "textures": { + "3": "block/cake_inner", + "bottom": "block/cake_bottom", + "top": "block/cake_top", + "side": "block/cake_side", + "particle": "block/cake_inner" + }, + "elements": [ + { + "from": [13, 0, 1], + "to": [15, 8, 15], + "faces": { + "north": {"uv": [1, 8, 3, 16], "texture": "#side"}, + "east": {"uv": [1, 8, 15, 16], "texture": "#side"}, + "south": {"uv": [13, 8, 15, 16], "texture": "#side"}, + "west": {"uv": [1, 8, 15, 16], "texture": "#3"}, + "up": {"uv": [13, 1, 15, 15], "texture": "#top"}, + "down": {"uv": [1, 1, 0, 15], "texture": "#bottom"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/bamboo.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/bamboo.json new file mode 100644 index 000000000..37d77c72f --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/bamboo.json @@ -0,0 +1,6 @@ +{ + "parent":"block/sign/sign", + "textures": { + "sign": "entity/signs/bamboo" + } +} diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/cherry.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/cherry.json new file mode 100644 index 000000000..241c35f3e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/cherry.json @@ -0,0 +1,6 @@ +{ + "parent":"block/sign/sign", + "textures": { + "sign": "entity/signs/cherry" + } +} diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/wall_bamboo.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/wall_bamboo.json new file mode 100644 index 000000000..8ef501af7 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/wall_bamboo.json @@ -0,0 +1,6 @@ +{ + "parent":"block/sign/wall_sign", + "textures": { + "sign": "entity/signs/bamboo" + } +} diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/wall_cherry.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/wall_cherry.json new file mode 100644 index 000000000..6b7fd4cf0 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/wall_cherry.json @@ -0,0 +1,6 @@ +{ + "parent":"block/sign/wall_sign", + "textures": { + "sign": "entity/signs/cherry" + } +} diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/acacia_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/acacia_hanging_sign.json new file mode 100644 index 000000000..89dea18cf --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/acacia_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/acacia" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/acacia_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/acacia_wall_hanging_sign.json new file mode 100644 index 000000000..8dbc076b3 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/acacia_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/acacia" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/bamboo_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/bamboo_hanging_sign.json new file mode 100644 index 000000000..dc63d4b56 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/bamboo_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/bamboo" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/bamboo_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/bamboo_wall_hanging_sign.json new file mode 100644 index 000000000..d793a37a8 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/bamboo_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/bamboo" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/banner.json new file mode 100644 index 000000000..eeeaecde2 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/banner.json @@ -0,0 +1,48 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [64, 64], + "textures": { + "0": "entity/banner_base" + }, + "elements": [ + { + "name": "Handle", + "from": [1.2, 28.4, 7.5], + "to": [14.8, 29.4, 8.5], + "faces": { + "north": {"uv": [0.5, 11.5, 5.5, 12], "texture": "#0"}, + "east": {"uv": [0, 11, 0.5, 11.5], "texture": "#0"}, + "south": {"uv": [5.5, 10.5, 10.5, 11], "texture": "#0"}, + "west": {"uv": [5.5, 11, 6, 11.5], "texture": "#0"}, + "up": {"uv": [5.5, 11, 0.5, 10.5], "texture": "#0"}, + "down": {"uv": [5.5, 11, 0.5, 11.5], "texture": "#0"} + } + }, + { + "name": "Cloth", + "from": [1.2, 1.4, 7], + "to": [14.8, 29.4, 7.5], + "faces": { + "north": {"uv": [0.25, 0.25, 5.5, 10.25], "texture": "#0", "tintindex": 0}, + "east": {"uv": [0, 0.25, 0.25, 10.25], "texture": "#0", "tintindex": 0}, + "south": {"uv": [5.5, 0.25, 10.5, 10.25], "texture": "#0", "tintindex": 0}, + "west": {"uv": [5.5, 0.25, 5.25, 10], "texture": "#0", "tintindex": 0}, + "up": {"uv": [5.25, 0, 0.25, 0.25], "texture": "#0", "tintindex": 0}, + "down": {"uv": [5, 0.25, 0.25, 0], "texture": "#0", "tintindex": 0} + } + }, + { + "name": "Pole", + "from": [7.5, 0, 7.5], + "to": [8.5, 28.4, 8.5], + "faces": { + "north": {"uv": [11.5, 0.5, 12, 11], "texture": "#0"}, + "east": {"uv": [11, 0.5, 11.5, 11], "texture": "#0"}, + "south": {"uv": [12.5, 0.5, 13, 11], "texture": "#0"}, + "west": {"uv": [12, 0.5, 12.5, 11], "texture": "#0"}, + "up": {"uv": [11.5, 0.5, 11, 0], "texture": "#0"}, + "down": {"uv": [13, 0, 12.5, 0.5], "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/birch_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/birch_hanging_sign.json new file mode 100644 index 000000000..86a1dc2e2 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/birch_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/birch" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/birch_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/birch_wall_hanging_sign.json new file mode 100644 index 000000000..31488b8a3 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/birch_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/birch" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/cherry_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/cherry_hanging_sign.json new file mode 100644 index 000000000..68e3aef10 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/cherry_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/cherry" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/cherry_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/cherry_wall_hanging_sign.json new file mode 100644 index 000000000..4632824a0 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/cherry_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/cherry" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/creeper_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/creeper_head.json new file mode 100644 index 000000000..6b009acf4 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/creeper_head.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/skull_32", + "textures": { + "entity": "entity/creeper/creeper" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/creeper_wall_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/creeper_wall_head.json new file mode 100644 index 000000000..efe35c69e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/creeper_wall_head.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_skull_32", + "textures": { + "entity": "entity/creeper/creeper" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/crimson_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/crimson_hanging_sign.json new file mode 100644 index 000000000..9d51d6a77 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/crimson_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/crimson" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/crimson_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/crimson_wall_hanging_sign.json new file mode 100644 index 000000000..680f2efa4 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/crimson_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/crimson" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dark_oak_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dark_oak_hanging_sign.json new file mode 100644 index 000000000..2480737b1 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dark_oak_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/dark_oak" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dark_oak_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dark_oak_wall_hanging_sign.json new file mode 100644 index 000000000..97288c4e2 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dark_oak_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/dark_oak" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/decorated_pot.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/decorated_pot.json new file mode 100644 index 000000000..6c19ac938 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/decorated_pot.json @@ -0,0 +1,48 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [32, 32], + "textures": { + "0": "entity/decorated_pot/decorated_pot_base" + }, + "elements": [ + { + "name": "Body", + "from": [1, 0, 1], + "to": [15, 16, 15], + "faces": { + "north": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "east": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "south": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "west": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "up": {"uv": [7, 6.5, 14, 13.5], "texture": "#0"}, + "down": {"uv": [7, 6.5, 14, 13.5], "texture": "#0"} + } + }, + { + "name": "Neck", + "from": [5, 16, 5], + "to": [11, 17, 11], + "faces": { + "north": {"uv": [6, 5.5, 9, 6], "texture": "#0"}, + "east": {"uv": [9, 5.5, 12, 6], "texture": "#0"}, + "south": {"uv": [2.5, 5.5, 5.5, 6], "texture": "#0"}, + "west": {"uv": [0, 5.5, 3, 6], "texture": "#0"}, + "up": {"uv": [0, 0, 3, 3], "texture": "#0"}, + "down": {"uv": [0, 0, 3, 3], "texture": "#0"} + } + }, + { + "name": "Head", + "from": [4, 17, 4], + "to": [12, 20, 12], + "faces": { + "north": {"uv": [0, 4, 4, 5.5], "texture": "#0"}, + "east": {"uv": [4, 4, 8, 5.5], "texture": "#0"}, + "south": {"uv": [8, 4, 12, 5.5], "texture": "#0"}, + "west": {"uv": [12, 4, 16, 5.5], "texture": "#0"}, + "up": {"uv": [4, 0, 8, 4], "texture": "#0"}, + "down": {"uv": [8, 0, 12, 4], "texture": "#0"} + } + } + ] +} diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dragon_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dragon_head.json new file mode 100644 index 000000000..7ccefe476 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dragon_head.json @@ -0,0 +1,101 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [256, 256], + "textures": { + "0": "entity/enderdragon/dragon" + }, + "elements": [ + { + "name": "Skull", + "from": [2, 0, 3.5], + "to": [14, 12, 15.5], + "faces": { + "north": {"uv": [9.9375, 2.875, 10.9375, 3.875], "texture": "#0"}, + "east": {"uv": [9, 2.875, 10, 3.875], "texture": "#0"}, + "south": {"uv": [8, 2.875, 9, 3.875], "texture": "#0"}, + "west": {"uv": [7, 2.875, 8, 3.875], "texture": "#0"}, + "up": {"uv": [9, 1.875, 8, 2.875], "texture": "#0"}, + "down": {"uv": [11, 1.875, 10, 2.875], "texture": "#0"} + } + }, + { + "name": "Horn1", + "from": [4, 12, 6], + "to": [6, 16, 12], + "faces": { + "north": {"uv": [0.875, 0.375, 1, 0.625], "texture": "#0"}, + "east": {"uv": [0.5, 0.375, 0.875, 0.625], "texture": "#0"}, + "south": {"uv": [0.375, 0.375, 0.5, 0.625], "texture": "#0"}, + "west": {"uv": [0, 0.375, 0.375, 0.625], "texture": "#0"}, + "up": {"uv": [0.375, 0, 0.5, 0.375], "texture": "#0"}, + "down": {"uv": [0, 0, 0.125, 0.375], "texture": "#0"} + } + }, + { + "name": "Horn2", + "from": [10, 12, 6], + "to": [12, 16, 12], + "faces": { + "north": {"uv": [0.875, 0.375, 1, 0.625], "texture": "#0"}, + "east": {"uv": [0.5, 0.375, 0.875, 0.625], "texture": "#0"}, + "south": {"uv": [0.375, 0.375, 0.5, 0.625], "texture": "#0"}, + "west": {"uv": [0, 0.375, 0.375, 0.625], "texture": "#0"}, + "up": {"uv": [0.375, 0, 0.5, 0.375], "texture": "#0"}, + "down": {"uv": [0, 0, 0.125, 0.375], "texture": "#0"} + } + }, + { + "name": "TopJaw", + "from": [2.5, 3, 15.5], + "to": [13.5, 7, 26], + "faces": { + "north": {"uv": [0.375, 3.375, 1.0625, 3.625], "texture": "#0"}, + "east": {"uv": [11, 3.75, 12.00625, 4.0625], "texture": "#0"}, + "south": {"uv": [12, 3.75, 12.8125, 4.0625], "texture": "#0"}, + "west": {"uv": [13.5, 3.75, 14.46875, 4.0625], "texture": "#0"}, + "up": {"uv": [12, 2.75, 12.75, 3.71875], "texture": "#0"}, + "down": {"uv": [12.74375, 3.75, 13.49375, 2.75], "texture": "#0"} + } + }, + { + "name": "Bottom Jaw", + "from": [2.5, 0.5, 14.5], + "to": [13.5, 2.5, 26], + "rotation": {"angle": 22.5, "axis": "x", "origin": [8, 2, 16]}, + "faces": { + "north": {"uv": [8.1875, 4.8125, 8.875, 4.9375], "texture": "#0"}, + "east": {"uv": [11, 5.0625, 12, 5.3125], "texture": "#0"}, + "south": {"uv": [8.0625, 5.3125, 8.75, 5.4375], "texture": "#0"}, + "west": {"uv": [13.74375, 5.06875, 14.49375, 5.31875], "texture": "#0"}, + "up": {"uv": [12, 4.0625, 12.75, 5.0625], "texture": "#0"}, + "down": {"uv": [12.6875, 4.0625, 13.5, 5.0625], "texture": "#0"} + } + }, + { + "name": "Nostril1", + "from": [4, 7, 20], + "to": [6, 9, 24], + "faces": { + "north": {"uv": [7.25, 0.25, 7.375, 0.375], "texture": "#0"}, + "east": {"uv": [7, 0.25, 7.25, 0.375], "texture": "#0"}, + "south": {"uv": [7.625, 0.25, 7.75, 0.375], "texture": "#0"}, + "west": {"uv": [7.375, 0.25, 7.625, 0.375], "texture": "#0"}, + "up": {"uv": [7.25, 0, 7.375, 0.25], "texture": "#0"}, + "down": {"uv": [7.125, 0, 7.25, 0.25], "texture": "#0"} + } + }, + { + "name": "Nostril2", + "from": [10, 7, 20], + "to": [12, 9, 24], + "faces": { + "north": {"uv": [7.25, 0.25, 7.375, 0.375], "texture": "#0"}, + "east": {"uv": [7.375, 0.25, 7.625, 0.375], "texture": "#0"}, + "south": {"uv": [7.625, 0.25, 7.75, 0.375], "texture": "#0"}, + "west": {"uv": [7, 0.25, 7.25, 0.375], "texture": "#0"}, + "up": {"uv": [7.25, 0, 7.375, 0.25], "texture": "#0"}, + "down": {"uv": [7.125, 0, 7.25, 0.25], "texture": "#0"} + } + } + ] +} diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dragon_wall_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dragon_wall_head.json new file mode 100644 index 000000000..7015011d1 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dragon_wall_head.json @@ -0,0 +1,115 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [256, 256], + "textures": { + "0": "entity/enderdragon/dragon" + }, + "elements": [ + { + "name": "Skull", + "from": [2, 4, 4], + "to": [14, 16, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 4, 7.5]}, + "faces": { + "north": {"uv": [8, 2.875, 9, 3.875], "texture": "#0"}, + "east": {"uv": [7, 2.875, 8, 3.875], "texture": "#0"}, + "south": {"uv": [9.9375, 2.875, 10.9375, 3.875], "texture": "#0"}, + "west": {"uv": [9, 2.875, 10, 3.875], "texture": "#0"}, + "up": {"uv": [9, 1.875, 8, 2.875], "rotation": 180, "texture": "#0"}, + "down": {"uv": [10, 1.875, 9, 2.875], "rotation": 180, "texture": "#0"} + } + }, + { + "name": "Horn1", + "from": [10, 16, 7.5], + "to": [12, 20, 13.5], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 4, 7.5]}, + "faces": { + "north": {"uv": [0.375, 0.375, 0.5, 0.625], "texture": "#0"}, + "east": {"uv": [0, 0.375, 0.375, 0.625], "texture": "#0"}, + "south": {"uv": [0.875, 0.375, 1, 0.625], "texture": "#0"}, + "west": {"uv": [0.5, 0.375, 0.875, 0.625], "texture": "#0"}, + "up": {"uv": [0.375, 0, 0.5, 0.375], "rotation": 180, "texture": "#0"}, + "down": {"uv": [0, 0, 0.125, 0.375], "rotation": 180, "texture": "#0"} + } + }, + { + "name": "Horn2", + "from": [4, 16, 7.5], + "to": [6, 20, 13.5], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 4, 7.5]}, + "faces": { + "north": {"uv": [0.375, 0.375, 0.5, 0.625], "texture": "#0"}, + "east": {"uv": [0, 0.375, 0.375, 0.625], "texture": "#0"}, + "south": {"uv": [0.875, 0.375, 1, 0.625], "texture": "#0"}, + "west": {"uv": [0.5, 0.375, 0.875, 0.625], "texture": "#0"}, + "up": {"uv": [0.375, 0, 0.5, 0.375], "rotation": 180, "texture": "#0"}, + "down": {"uv": [0, 0, 0.125, 0.375], "rotation": 180, "texture": "#0"} + } + }, + { + "name": "TopJaw", + "from": [2.5, 7, -6.5], + "to": [13.5, 11, 4], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 4, 7.5]}, + "faces": { + "north": {"uv": [12, 3.75, 12.8125, 4.0625], "texture": "#0"}, + "east": {"uv": [13.5, 3.75, 14.46875, 4.0625], "texture": "#0"}, + "south": {"uv": [0.375, 3.375, 1.0625, 3.625], "texture": "#0"}, + "west": {"uv": [11, 3.75, 12.00625, 4.0625], "texture": "#0"}, + "up": {"uv": [12, 2.75, 12.75, 3.71875], "rotation": 180, "texture": "#0"}, + "down": {"uv": [12.74375, 3.75, 13.49375, 2.75], "rotation": 180, "texture": "#0"} + } + }, + { + "name": "Bottom Jaw", + "from": [2.5, 4.5, -6.5], + "to": [13.5, 6.5, 5], + "rotation": {"angle": -22.5, "axis": "x", "origin": [8, 6, 4.5]}, + "faces": { + "north": {"uv": [8.0625, 5.3125, 8.75, 5.4375], "texture": "#0"}, + "east": {"uv": [13.74375, 5.06875, 14.49375, 5.31875], "texture": "#0"}, + "south": {"uv": [8.1875, 4.8125, 8.875, 4.9375], "texture": "#0"}, + "west": {"uv": [11, 5.0625, 12, 5.3125], "texture": "#0"}, + "up": {"uv": [12, 4.0625, 12.75, 5.0625], "rotation": 180, "texture": "#0"}, + "down": {"uv": [12.6875, 4.0625, 13.5, 5.0625], "rotation": 180, "texture": "#0"} + } + }, + { + "name": "Nostril1", + "from": [10, 11, -4.5], + "to": [12, 13, -0.5], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 4, 7.5]}, + "faces": { + "north": {"uv": [7.625, 0.25, 7.75, 0.375], "texture": "#0"}, + "east": {"uv": [7.375, 0.25, 7.625, 0.375], "texture": "#0"}, + "south": {"uv": [7.25, 0.25, 7.375, 0.375], "texture": "#0"}, + "west": {"uv": [7, 0.25, 7.25, 0.375], "texture": "#0"}, + "up": {"uv": [7.25, 0, 7.375, 0.25], "rotation": 180, "texture": "#0"}, + "down": {"uv": [7.125, 0, 7.25, 0.25], "rotation": 180, "texture": "#0"} + } + }, + { + "name": "Nostril2", + "from": [4, 11, -4.5], + "to": [6, 13, -0.5], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 4, 7.5]}, + "faces": { + "north": {"uv": [7.625, 0.25, 7.75, 0.375], "texture": "#0"}, + "east": {"uv": [7, 0.25, 7.25, 0.375], "texture": "#0"}, + "south": {"uv": [7.25, 0.25, 7.375, 0.375], "texture": "#0"}, + "west": {"uv": [7.375, 0.25, 7.625, 0.375], "texture": "#0"}, + "up": {"uv": [7.25, 0, 7.375, 0.25], "rotation": 180, "texture": "#0"}, + "down": {"uv": [7.125, 0, 7.25, 0.25], "rotation": 180, "texture": "#0"} + } + } + ], + "groups": [ + { + "name": "group", + "origin": [0, 4, -3.5], + "color": 0, + "children": [0, 1, 2, 3, 4, 5, 6] + } + ] +} diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dyed_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dyed_shulker_box.json new file mode 100644 index 000000000..5490afd16 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dyed_shulker_box.json @@ -0,0 +1,33 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [64, 64], + "textures": { + "0": "entity/shulker/shulker_white" + }, + "elements": [ + { + "from": [0, 0, 0], + "to": [16, 8, 16], + "faces": { + "north": {"uv": [0, 11, 4, 13], "texture": "#0", "tintindex": 0}, + "east": {"uv": [0, 11, 4, 13], "texture": "#0", "tintindex": 0}, + "south": {"uv": [0, 11, 4, 13], "texture": "#0", "tintindex": 0}, + "west": {"uv": [0, 11, 4, 13], "texture": "#0", "tintindex": 0}, + "up": {"uv": [0, 0, 4, 4], "texture": "#0", "tintindex": 0}, + "down": {"uv": [8.25, 7.25, 12, 11], "texture": "#0", "tintindex": 0} + } + }, + { + "from": [0, 4, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 4, 4, 7], "texture": "#0", "tintindex": 0}, + "east": {"uv": [0, 4, 4, 7], "texture": "#0", "tintindex": 0}, + "south": {"uv": [0, 4, 4, 7], "texture": "#0", "tintindex": 0}, + "west": {"uv": [0, 4, 4, 7], "texture": "#0", "tintindex": 0}, + "up": {"uv": [4, 0, 8, 4], "texture": "#0", "tintindex": 0}, + "down": {"uv": [0, 0, 4, 4], "texture": "#0", "tintindex": 0} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/hanging_sign.json new file mode 100644 index 000000000..fcb82190a --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/hanging_sign.json @@ -0,0 +1,35 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "ambientocclusion": false, + "texture_size": [64, 32], + "textures": { + "wood": "entity/signs/hanging/oak" + }, + "elements": [ + { + "name": "Sign", + "from": [1, 0, 7], + "to": [15, 10, 9], + "faces": { + "north": {"uv": [4.5, 7, 8, 12], "texture": "#wood"}, + "east": {"uv": [4, 7, 4.5, 12], "texture": "#wood"}, + "south": {"uv": [0.5, 7, 4, 12], "texture": "#wood"}, + "west": {"uv": [0, 7, 0.5, 12], "texture": "#wood"}, + "up": {"uv": [4, 6, 0.5, 7], "rotation": 180, "texture": "#wood"}, + "down": {"uv": [4, 7, 7.5, 6], "texture": "#wood"} + } + }, + { + "from": [2, 10, 8], + "to": [14, 16, 8], + "faces": { + "north": {"uv": [3.5, 3, 6.5, 6], "texture": "#wood"}, + "east": {"uv": [0, 0, 0, 3], "texture": "#missing"}, + "south": {"uv": [3.5, 3, 6.5, 6], "texture": "#wood"}, + "west": {"uv": [0, 0, 0, 3], "texture": "#missing"}, + "up": {"uv": [0, 0, 0, 6], "rotation": 90, "texture": "#missing"}, + "down": {"uv": [0, 0, 0, 6], "rotation": 270, "texture": "#missing"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/jungle_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/jungle_hanging_sign.json new file mode 100644 index 000000000..ddb78a49e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/jungle_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/jungle" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/jungle_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/jungle_wall_hanging_sign.json new file mode 100644 index 000000000..0fb0692c7 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/jungle_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/jungle" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/mangrove_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/mangrove_hanging_sign.json new file mode 100644 index 000000000..2ae729a76 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/mangrove_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/mangrove" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/mangrove_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/mangrove_wall_hanging_sign.json new file mode 100644 index 000000000..10c9b4fd7 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/mangrove_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/mangrove" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/oak_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/oak_hanging_sign.json new file mode 100644 index 000000000..d3b0234d7 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/oak_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/oak" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/oak_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/oak_wall_hanging_sign.json new file mode 100644 index 000000000..1e88c5a76 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/oak_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/oak" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/piglin_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/piglin_head.json new file mode 100644 index 000000000..4d394b6ba --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/piglin_head.json @@ -0,0 +1,102 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [64, 64], + "textures": { + "0": "entity/piglin/piglin" + }, + "elements": [ + { + "name": "Skull", + "from": [3, 0, 4], + "to": [13, 8, 12], + "faces": { + "north": {"uv": [6.5, 2, 9, 4], "texture": "#0"}, + "east": {"uv": [4.5, 2, 6.5, 4], "texture": "#0"}, + "south": {"uv": [2, 2, 4.5, 4], "texture": "#0"}, + "west": {"uv": [0, 2, 2, 4], "texture": "#0"}, + "up": {"uv": [2, 0, 4.5, 2], "texture": "#0"}, + "down": {"uv": [11.25, 0, 13.75, 2], "texture": "#0"} + } + }, + { + "name": "SnoutBottom", + "from": [6, 0, 12], + "to": [10, 2, 13], + "faces": { + "north": {"uv": [3, 4, 4.5, 4.5], "texture": "#0"}, + "east": {"uv": [9, 1.5, 9.25, 2], "texture": "#0"}, + "south": {"uv": [8, 1, 9, 1.5], "texture": "#0"}, + "west": {"uv": [9, 1.5, 9.25, 2], "texture": "#0"}, + "up": {"uv": [8, 0, 9, 0.25], "texture": "#0"}, + "down": {"uv": [8, 1.5, 9, 1.75], "texture": "#0"} + } + }, + { + "name": "Snouttop", + "from": [6, 2, 12], + "to": [10, 4, 13], + "faces": { + "north": {"uv": [3, 4, 4, 4.5], "texture": "#0"}, + "east": {"uv": [7.75, 0.5, 8, 1], "texture": "#0"}, + "south": {"uv": [8, 0.5, 9, 1], "texture": "#0"}, + "west": {"uv": [9, 0.5, 9.25, 1], "texture": "#0"}, + "up": {"uv": [8, 0.25, 9, 0.5], "texture": "#0"}, + "down": {"uv": [10.25, 0.25, 11.25, 0.5], "texture": "#0"} + } + }, + { + "name": "Ear1", + "from": [3, 2, 6], + "to": [4, 7, 10], + "rotation": {"angle": -22.5, "axis": "z", "origin": [3, 7, 8]}, + "faces": { + "north": {"uv": [11, 2.5, 11.25, 3.75], "texture": "#0"}, + "east": {"uv": [11.25, 2.5, 12.25, 3.75], "texture": "#0"}, + "south": {"uv": [10.75, 2.5, 11, 3.75], "texture": "#0"}, + "west": {"uv": [9.75, 2.5, 10.75, 3.75], "texture": "#0"}, + "up": {"uv": [10.75, 1.5, 11, 2.5], "texture": "#0"}, + "down": {"uv": [11, 1.5, 11.25, 2.5], "texture": "#0"} + } + }, + { + "name": "Ear2", + "from": [12, 2, 6], + "to": [13, 7, 10], + "rotation": {"angle": 22.5, "axis": "z", "origin": [13, 7, 8]}, + "faces": { + "north": {"uv": [14, 2.5, 14.25, 3.75], "texture": "#0"}, + "east": {"uv": [14.25, 2.5, 15.25, 3.75], "texture": "#0"}, + "south": {"uv": [13.75, 2.5, 14, 3.75], "texture": "#0"}, + "west": {"uv": [12.75, 2.5, 13.75, 3.75], "texture": "#0"}, + "up": {"uv": [13.75, 1.5, 14, 2.5], "texture": "#0"}, + "down": {"uv": [14, 1.5, 14.25, 2.5], "texture": "#0"} + } + }, + { + "name": "Tusk1", + "from": [5, 0, 12], + "to": [6, 2, 13], + "faces": { + "north": {"uv": [0, 1.25, 0.25, 1.75], "texture": "#0"}, + "east": {"uv": [0.25, 0.25, 0.5, 0.75], "texture": "#0"}, + "south": {"uv": [0.75, 0.25, 1, 0.75], "texture": "#0"}, + "west": {"uv": [0.75, 0.25, 1, 0.75], "texture": "#0"}, + "up": {"uv": [0.75, 0, 1, 0.25], "texture": "#0"}, + "down": {"uv": [1.25, 0, 1.5, 0.25], "texture": "#0"} + } + }, + { + "name": "Tusk2", + "from": [10, 0, 12], + "to": [11, 2, 13], + "faces": { + "north": {"uv": [0, 1.25, 0.25, 1.75], "texture": "#0"}, + "east": {"uv": [1, 0.25, 1.25, 0.75], "texture": "#0"}, + "south": {"uv": [0.75, 0.25, 1, 0.75], "texture": "#0"}, + "west": {"uv": [0.25, 0.25, 0.5, 0.75], "texture": "#0"}, + "up": {"uv": [0.75, 0, 1, 0.25], "texture": "#0"}, + "down": {"uv": [1.25, 0, 1.5, 0.25], "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/piglin_wall_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/piglin_wall_head.json new file mode 100644 index 000000000..18bfe76ed --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/piglin_wall_head.json @@ -0,0 +1,107 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [64, 64], + "textures": { + "0": "entity/piglin/piglin" + }, + "elements": [ + { + "name": "Skull", + "from": [3, 4, 8], + "to": [13, 12, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 7, 8]}, + "faces": { + "north": {"uv": [2, 2, 4.5, 4], "texture": "#0"}, + "east": {"uv": [0, 2, 2, 4], "texture": "#0"}, + "south": {"uv": [6.5, 2, 9, 4], "texture": "#0"}, + "west": {"uv": [4.5, 2, 6.5, 4], "texture": "#0"}, + "up": {"uv": [2, 0, 4.5, 2], "rotation": 180, "texture": "#0"}, + "down": {"uv": [11.25, 0, 13.75, 2], "rotation": 180, "texture": "#0"} + } + }, + { + "name": "SnoutBottom", + "from": [6, 4, 7], + "to": [10, 6, 8], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 7, 8]}, + "faces": { + "north": {"uv": [8, 1, 9, 1.5], "texture": "#0"}, + "east": {"uv": [9, 1.5, 9.25, 2], "texture": "#0"}, + "south": {"uv": [3, 4, 4.5, 4.5], "texture": "#0"}, + "west": {"uv": [9, 1.5, 9.25, 2], "texture": "#0"}, + "up": {"uv": [8, 0, 9, 0.25], "rotation": 180, "texture": "#0"}, + "down": {"uv": [8, 1.5, 9, 1.75], "rotation": 180, "texture": "#0"} + } + }, + { + "name": "Snouttop", + "from": [6, 6, 7], + "to": [10, 8, 8], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 7, 8]}, + "faces": { + "north": {"uv": [8, 0.5, 9, 1], "texture": "#0"}, + "east": {"uv": [9, 0.5, 9.25, 1], "texture": "#0"}, + "south": {"uv": [3, 4, 4, 4.5], "texture": "#0"}, + "west": {"uv": [7.75, 0.5, 8, 1], "texture": "#0"}, + "up": {"uv": [8, 0.25, 9, 0.5], "rotation": 180, "texture": "#0"}, + "down": {"uv": [10.25, 0.25, 11.25, 0.5], "rotation": 180, "texture": "#0"} + } + }, + { + "name": "Ear1", + "from": [12, 6, 10], + "to": [13, 11, 14], + "rotation": {"angle": 22.5, "axis": "z", "origin": [12, 11, 12]}, + "faces": { + "north": {"uv": [10.75, 2.5, 11, 3.75], "texture": "#0"}, + "east": {"uv": [9.75, 2.5, 10.75, 3.75], "texture": "#0"}, + "south": {"uv": [11, 2.5, 11.25, 3.75], "texture": "#0"}, + "west": {"uv": [11.25, 2.5, 12.25, 3.75], "texture": "#0"}, + "up": {"uv": [10.75, 1.5, 11, 2.5], "rotation": 180, "texture": "#0"}, + "down": {"uv": [11, 1.5, 11.25, 2.5], "rotation": 180, "texture": "#0"} + } + }, + { + "name": "Ear2", + "from": [3, 6, 10], + "to": [4, 11, 14], + "rotation": {"angle": -22.5, "axis": "z", "origin": [4, 11, 12]}, + "faces": { + "north": {"uv": [13.75, 2.5, 14, 3.75], "texture": "#0"}, + "east": {"uv": [12.75, 2.5, 13.75, 3.75], "texture": "#0"}, + "south": {"uv": [14, 2.5, 14.25, 3.75], "texture": "#0"}, + "west": {"uv": [14.25, 2.5, 15.25, 3.75], "texture": "#0"}, + "up": {"uv": [13.75, 1.5, 14, 2.5], "rotation": 180, "texture": "#0"}, + "down": {"uv": [14, 1.5, 14.25, 2.5], "rotation": 180, "texture": "#0"} + } + }, + { + "name": "Tusk1", + "from": [10, 4, 7], + "to": [11, 6, 8], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 7, 8]}, + "faces": { + "north": {"uv": [0.75, 0.25, 1, 0.75], "texture": "#0"}, + "east": {"uv": [0.75, 0.25, 1, 0.75], "texture": "#0"}, + "south": {"uv": [0, 1.25, 0.25, 1.75], "texture": "#0"}, + "west": {"uv": [0.25, 0.25, 0.5, 0.75], "texture": "#0"}, + "up": {"uv": [0.75, 0, 1, 0.25], "rotation": 180, "texture": "#0"}, + "down": {"uv": [1.25, 0, 1.5, 0.25], "rotation": 180, "texture": "#0"} + } + }, + { + "name": "Tusk2", + "from": [5, 4, 7], + "to": [6, 6, 8], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 7, 8]}, + "faces": { + "north": {"uv": [0.75, 0.25, 1, 0.75], "texture": "#0"}, + "east": {"uv": [0.25, 0.25, 0.5, 0.75], "texture": "#0"}, + "south": {"uv": [0, 1.25, 0.25, 1.75], "texture": "#0"}, + "west": {"uv": [1, 0.25, 1.25, 0.75], "texture": "#0"}, + "up": {"uv": [0.75, 0, 1, 0.25], "rotation": 180, "texture": "#0"}, + "down": {"uv": [1.25, 0, 1.5, 0.25], "rotation": 180, "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/player_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/player_head.json new file mode 100644 index 000000000..807233c53 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/player_head.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/skull_64", + "textures": { + "entity": "entity/player/slim/steve" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/player_wall_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/player_wall_head.json new file mode 100644 index 000000000..683404433 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/player_wall_head.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_skull_64", + "textures": { + "entity": "entity/player/slim/steve" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/shulker_box.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/shulker_box.json new file mode 100644 index 000000000..ce6999451 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/shulker_box.json @@ -0,0 +1,33 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [64, 64], + "textures": { + "0": "entity/shulker/shulker" + }, + "elements": [ + { + "from": [0, 0, 0], + "to": [16, 8, 16], + "faces": { + "north": {"uv": [0, 11, 4, 13], "texture": "#0"}, + "east": {"uv": [0, 11, 4, 13], "texture": "#0"}, + "south": {"uv": [0, 11, 4, 13], "texture": "#0"}, + "west": {"uv": [0, 11, 4, 13], "texture": "#0"}, + "up": {"uv": [0, 0, 4, 4], "texture": "#0"}, + "down": {"uv": [8.25, 7.25, 12, 11], "texture": "#0"} + } + }, + { + "from": [0, 4, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 4, 4, 7], "texture": "#0"}, + "east": {"uv": [0, 4, 4, 7], "texture": "#0"}, + "south": {"uv": [0, 4, 4, 7], "texture": "#0"}, + "west": {"uv": [0, 4, 4, 7], "texture": "#0"}, + "up": {"uv": [4, 0, 8, 4], "texture": "#0"}, + "down": {"uv": [0, 0, 4, 4], "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/skeleton_skull.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/skeleton_skull.json new file mode 100644 index 000000000..450f9855c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/skeleton_skull.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/skull_32", + "textures": { + "entity": "entity/skeleton/skeleton" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/skeleton_wall_skull.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/skeleton_wall_skull.json new file mode 100644 index 000000000..6068e0375 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/skeleton_wall_skull.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_skull_32", + "textures": { + "entity": "entity/skeleton/skeleton" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/skull_32.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/skull_32.json new file mode 100644 index 000000000..8aed9a82c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/skull_32.json @@ -0,0 +1,32 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [64, 32], + "elements": [ + { + "name": "Skull", + "from": [4.1, 0, 4.1], + "to": [11.9, 7.9, 11.9], + "faces": { + "north": {"uv": [6, 4, 8, 8], "texture": "#entity"}, + "east": {"uv": [4, 4, 6, 8], "texture": "#entity"}, + "south": {"uv": [2, 4, 4, 8], "texture": "#entity"}, + "west": {"uv": [0, 4, 2, 8], "texture": "#entity"}, + "up": {"uv": [4, 4, 2, 0], "rotation": 180, "texture": "#entity"}, + "down": {"uv": [5.5, 0.5, 3.75, 4], "rotation": 180, "texture": "#entity"} + } + }, + { + "name": "Overlay", + "from": [4, 0, 4], + "to": [12, 8, 12], + "faces": { + "north": {"uv": [14, 4, 16, 8], "texture": "#entity"}, + "east": {"uv": [12, 4, 14, 8], "texture": "#entity"}, + "south": {"uv": [10, 4, 12, 8], "texture": "#entity"}, + "west": {"uv": [8, 4, 10, 8], "texture": "#entity"}, + "up": {"uv": [12, 4, 10, 0], "rotation": 180, "texture": "#entity"}, + "down": {"uv": [14, 0, 12, 4], "rotation": 180, "texture": "#entity"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/skull_64.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/skull_64.json new file mode 100644 index 000000000..ac8649222 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/skull_64.json @@ -0,0 +1,32 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [64, 64], + "elements": [ + { + "name": "Skull", + "from": [4.1, 0, 4.1], + "to": [11.9, 7.9, 11.9], + "faces": { + "north": {"uv": [5.5, 2, 7.5, 4], "texture": "#entity"}, + "east": {"uv": [3.75, 2, 5.75, 4], "texture": "#entity"}, + "south": {"uv": [2, 2, 4, 4], "texture": "#entity"}, + "west": {"uv": [0, 2, 2, 4], "texture": "#entity"}, + "up": {"uv": [4, 2, 2, 0], "rotation": 180, "texture": "#entity"}, + "down": {"uv": [6, 0, 4, 2], "rotation": 180, "texture": "#entity"} + } + }, + { + "name": "Overlay", + "from": [4, 0, 4], + "to": [12, 8, 12], + "faces": { + "north": {"uv": [14, 2, 16, 4], "texture": "#entity"}, + "east": {"uv": [12, 2, 14, 4], "texture": "#entity"}, + "south": {"uv": [10, 2, 12, 4], "texture": "#entity"}, + "west": {"uv": [8, 2, 10, 4], "texture": "#entity"}, + "up": {"uv": [12, 2, 10, 0], "rotation": 180, "texture": "#entity"}, + "down": {"uv": [14, 0, 12, 2], "rotation": 180, "texture": "#entity"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/spruce_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/spruce_hanging_sign.json new file mode 100644 index 000000000..47d9dd185 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/spruce_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/spruce" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/spruce_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/spruce_wall_hanging_sign.json new file mode 100644 index 000000000..773f3fea7 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/spruce_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/spruce" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wall_banner.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wall_banner.json new file mode 100644 index 000000000..21eeeaf7d --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wall_banner.json @@ -0,0 +1,35 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [64, 64], + "textures": { + "0": "entity/banner_base" + }, + "elements": [ + { + "name": "Handle", + "from": [1.2, 12.4, 15], + "to": [14.8, 13.4, 16], + "faces": { + "north": {"uv": [0.5, 11.5, 5.5, 12], "texture": "#0"}, + "east": {"uv": [0, 11, 0.5, 11.5], "texture": "#0"}, + "south": {"uv": [5.5, 11.5, 10.5, 12], "texture": "#0"}, + "west": {"uv": [5.5, 11, 6, 11.5], "texture": "#0"}, + "up": {"uv": [5.5, 11, 0.5, 10.5], "texture": "#0"}, + "down": {"uv": [5.5, 11, 0.5, 11.5], "texture": "#0"} + } + }, + { + "name": "Cloth", + "from": [1.2, -14.6, 14.5], + "to": [14.8, 13.4, 15], + "faces": { + "north": {"uv": [0.25, 0.25, 5.5, 10.25], "texture": "#0", "tintindex": 0}, + "east": {"uv": [0, 0.25, 0.25, 10.25], "texture": "#0", "tintindex": 0}, + "south": {"uv": [5.5, 0.25, 10.5, 10.25], "texture": "#0", "tintindex": 0}, + "west": {"uv": [5.5, 0.25, 5.25, 10], "texture": "#0", "tintindex": 0}, + "up": {"uv": [5.25, 0, 0.25, 0.25], "texture": "#0", "tintindex": 0}, + "down": {"uv": [5, 0.25, 0.25, 0], "texture": "#0", "tintindex": 0} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wall_hanging_sign.json new file mode 100644 index 000000000..622794052 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wall_hanging_sign.json @@ -0,0 +1,82 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "ambientocclusion": false, + "texture_size": [64, 32], + "textures": { + "wood": "entity/signs/hanging/oak" + }, + "elements": [ + { + "name": "Sign", + "from": [1, 0, 7], + "to": [15, 10, 9], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [4.5, 7, 8, 12], "texture": "#wood"}, + "east": {"uv": [4, 7, 4.5, 12], "texture": "#wood"}, + "south": {"uv": [0.5, 7, 4, 12], "texture": "#wood"}, + "west": {"uv": [0, 7, 0.5, 12], "texture": "#wood"}, + "up": {"uv": [4, 6, 0.5, 7], "rotation": 180, "texture": "#wood"}, + "down": {"uv": [4, 7, 7.5, 6], "texture": "#wood"} + } + }, + { + "name": "Hanger", + "from": [0, 14, 6], + "to": [16, 16, 10], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [6, 2, 10, 3], "texture": "#wood"}, + "east": {"uv": [0, 2, 1, 3], "texture": "#wood"}, + "south": {"uv": [1, 2, 5, 3], "texture": "#wood"}, + "west": {"uv": [0, 2, 1, 3], "texture": "#wood"}, + "up": {"uv": [1, 0, 5, 2], "rotation": 180, "texture": "#wood"}, + "down": {"uv": [5, 0, 9, 2], "texture": "#wood"} + } + }, + { + "name": "ChainA1", + "from": [4.8, 10, 10.5], + "to": [6.2, 14, 10.5], + "shade": false, + "rotation": {"angle": -45, "axis": "y", "origin": [8, 8, 8], "rescale": true}, + "faces": { + "north": {"uv": [1.5, 3, 2.25, 6], "texture": "#wood"}, + "south": {"uv": [1.5, 3, 2.25, 6], "texture": "#wood"} + } + }, + { + "name": "ChainB2", + "from": [10.5, 10, 4.8], + "to": [10.5, 14, 6.2], + "shade": false, + "rotation": {"angle": -45, "axis": "y", "origin": [8, 8, 8], "rescale": true}, + "faces": { + "east": {"uv": [0, 3, 0.75, 6], "texture": "#wood"}, + "west": {"uv": [0, 3, 0.75, 6], "texture": "#wood"} + } + }, + { + "name": "ChainB1", + "from": [9.8, 10, 5.5], + "to": [11.2, 14, 5.5], + "shade": false, + "rotation": {"angle": -45, "axis": "y", "origin": [8, 8, 8], "rescale": true}, + "faces": { + "north": {"uv": [1.5, 3, 2.25, 6], "texture": "#wood"}, + "south": {"uv": [1.5, 3, 2.25, 6], "texture": "#wood"} + } + }, + { + "name": "ChainA2", + "from": [5.5, 10, 9.8], + "to": [5.5, 14, 11.2], + "shade": false, + "rotation": {"angle": -45, "axis": "y", "origin": [8, 8, 8], "rescale": true}, + "faces": { + "east": {"uv": [0, 3, 0.75, 6], "texture": "#wood"}, + "west": {"uv": [0, 3, 0.75, 6], "texture": "#wood"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wall_skull_32.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wall_skull_32.json new file mode 100644 index 000000000..a98d801b5 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wall_skull_32.json @@ -0,0 +1,32 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [64, 32], + "elements": [ + { + "name": "Skull", + "from": [4.1, 4.1, 8.1], + "to": [11.9, 11.9, 16], + "faces": { + "north": {"uv": [2, 4, 4, 8], "texture": "#entity"}, + "east": {"uv": [0, 4, 2, 8], "texture": "#entity"}, + "south": {"uv": [6, 4, 8, 8], "texture": "#entity"}, + "west": {"uv": [4, 4, 6, 8], "texture": "#entity"}, + "up": {"uv": [4, 4, 2, 0], "texture": "#entity"}, + "down": {"uv": [5.5, 0.5, 3.75, 4], "texture": "#entity"} + } + }, + { + "name": "Overlay", + "from": [4, 4, 8], + "to": [12, 12, 16], + "faces": { + "north": {"uv": [10, 4, 12, 8], "texture": "#entity"}, + "east": {"uv": [8.25, 4, 10.25, 8], "texture": "#entity"}, + "south": {"uv": [14, 4, 16, 8], "texture": "#entity"}, + "west": {"uv": [12, 4, 14, 8], "texture": "#entity"}, + "up": {"uv": [12, 4, 10, 0], "texture": "#entity"}, + "down": {"uv": [14, 0, 12, 4], "texture": "#entity"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wall_skull_64.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wall_skull_64.json new file mode 100644 index 000000000..b127243e2 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wall_skull_64.json @@ -0,0 +1,32 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [64, 64], + "elements": [ + { + "name": "Skull", + "from": [4.1, 4.1, 8.2], + "to": [11.9, 11.9, 16], + "faces": { + "north": {"uv": [2, 2, 4, 4], "texture": "#entity"}, + "east": {"uv": [0, 2, 2, 4], "texture": "#entity"}, + "south": {"uv": [5.5, 2, 7.5, 4], "texture": "#entity"}, + "west": {"uv": [3.75, 2, 5.75, 4], "texture": "#entity"}, + "up": {"uv": [4, 2, 2, 0], "texture": "#entity"}, + "down": {"uv": [6, 0, 4, 2], "texture": "#entity"} + } + }, + { + "name": "Overlay", + "from": [4, 4, 8], + "to": [12, 12, 16], + "faces": { + "north": {"uv": [10, 2, 12, 4], "texture": "#entity"}, + "east": {"uv": [8, 2, 10, 4], "texture": "#entity"}, + "south": {"uv": [14, 2, 16, 4], "texture": "#entity"}, + "west": {"uv": [12, 2, 14, 4], "texture": "#entity"}, + "up": {"uv": [12, 2, 10, 0], "texture": "#entity"}, + "down": {"uv": [14, 0, 12, 2], "texture": "#entity"} + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/warped_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/warped_hanging_sign.json new file mode 100644 index 000000000..73c14b487 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/warped_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/warped" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/warped_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/warped_wall_hanging_sign.json new file mode 100644 index 000000000..f4b1c19ee --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/warped_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/warped" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wither_skeleton_skull.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wither_skeleton_skull.json new file mode 100644 index 000000000..608ee0f10 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wither_skeleton_skull.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/skull_32", + "textures": { + "entity": "entity/skeleton/wither_skeleton" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wither_skeleton_wall_skull.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wither_skeleton_wall_skull.json new file mode 100644 index 000000000..c0d2957d8 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wither_skeleton_wall_skull.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_skull_32", + "textures": { + "entity": "entity/skeleton/wither_skeleton" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/zombie_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/zombie_head.json new file mode 100644 index 000000000..6a6d1c14e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/zombie_head.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/skull_64", + "textures": { + "entity": "entity/zombie/zombie" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/zombie_wall_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/zombie_wall_head.json new file mode 100644 index 000000000..e420b1cb0 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/zombie_wall_head.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_skull_64", + "textures": { + "entity": "entity/zombie/zombie" + } +} \ No newline at end of file From 36c1d3f7ac528e10e3cceacaebaeb7b67d693d8d Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Wed, 8 May 2024 19:31:36 +0200 Subject: [PATCH 03/38] Restructure resource-extensions, fix some issues and add support for biome grass_color_modifier --- .gitignore | 2 +- BlueMapAPI | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- BlueMapCore/build.gradle.kts | 27 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../BlockColorCalculatorFactory.java | 13 +- .../core/resources/MinecraftVersion.java | 7 +- .../bluemap/core/resources/ResourcePath.java | 14 +- .../core/resources/VersionManifest.java | 5 +- .../resources/adapter/RegistryAdapter.java | 36 ++ .../core/resources/adapter/ResourcesGson.java | 9 +- .../bluemap/core/resources/pack/Pack.java | 5 +- .../core/resources/{ => pack}/PackMeta.java | 7 +- .../resources/pack/datapack/DataPack.java | 6 +- .../pack/datapack/biome/DatapackBiome.java | 9 +- .../pack/resourcepack/ResourcePack.java | 8 +- .../de/bluecolored/bluemap/core/util/Key.java | 8 +- .../bluemap/core/world/BlockState.java | 11 +- .../bluecolored/bluemap/core/world/Chunk.java | 1 + .../bluemap/core/world/{ => biome}/Biome.java | 5 +- .../core/world/biome/ColorModifier.java | 10 + .../core/world/biome/GrassColorModifier.java | 48 +++ .../bluemap/core/world/block/Block.java | 1 + .../core/world/mca/chunk/Chunk_1_13.java | 2 +- .../core/world/mca/chunk/Chunk_1_15.java | 2 +- .../core/world/mca/chunk/Chunk_1_16.java | 2 +- .../core/world/mca/chunk/Chunk_1_18.java | 2 +- .../core/world/mca/chunk/LegacyBiomes.java | 2 +- .../assets/bluemap/blockstates/missing.json | 5 + .../assets/bluemap/models/block/missing.json | 6 + .../assets/bluemap/textures/block/missing.png | Bin .../assets/minecraft/blockColors.json | 68 +++ .../assets/minecraft/blockProperties.json | 0 .../blockstates/acacia_hanging_sign.json | 20 + .../minecraft/blockstates/acacia_sign.json | 20 + .../blockstates/acacia_wall_hanging_sign.json | 8 + .../blockstates/acacia_wall_sign.json | 0 .../blockstates/bamboo_hanging_sign.json | 20 + .../blockstates/bamboo_wall_hanging_sign.json | 8 + .../blockstates/birch_hanging_sign.json | 20 + .../minecraft/blockstates/birch_sign.json | 20 + .../blockstates/birch_wall_hanging_sign.json | 8 + .../blockstates/birch_wall_sign.json | 0 .../minecraft/blockstates/black_banner.json | 20 + .../minecraft/blockstates/black_bed.json | 12 + .../blockstates/black_shulker_box.json | 10 + .../blockstates/black_wall_banner.json | 8 + .../minecraft/blockstates/blue_banner.json | 20 + .../minecraft/blockstates/blue_bed.json | 12 + .../blockstates/blue_shulker_box.json | 10 + .../blockstates/blue_wall_banner.json | 8 + .../minecraft/blockstates/brown_banner.json | 20 + .../minecraft/blockstates/brown_bed.json | 12 + .../blockstates/brown_shulker_box.json | 10 + .../blockstates/brown_wall_banner.json | 8 + .../minecraft/blockstates/bubble_column.json | 5 + .../blockstates/cherry_hanging_sign.json | 20 + .../blockstates/cherry_wall_hanging_sign.json | 8 + .../assets/minecraft/blockstates/chest.json | 13 + .../minecraft/blockstates/creeper_head.json | 20 + .../blockstates/creeper_wall_head.json | 8 + .../blockstates/crimson_hanging_sign.json | 20 + .../minecraft/blockstates/crimson_sign.json | 20 + .../crimson_wall_hanging_sign.json | 8 + .../blockstates/crimson_wall_sign.json | 0 .../minecraft/blockstates/cyan_banner.json | 20 + .../minecraft/blockstates/cyan_bed.json | 12 + .../blockstates/cyan_shulker_box.json | 10 + .../blockstates/cyan_wall_banner.json | 8 + .../blockstates/dark_oak_hanging_sign.json | 20 + .../minecraft/blockstates/dark_oak_sign.json | 20 + .../dark_oak_wall_hanging_sign.json | 8 + .../blockstates/dark_oak_wall_sign.json | 0 .../minecraft/blockstates/decorated_pot.json | 8 + .../minecraft/blockstates/dragon_head.json | 20 + .../blockstates/dragon_wall_head.json | 8 + .../minecraft/blockstates/ender_chest.json | 8 + .../minecraft/blockstates/gray_banner.json | 20 + .../minecraft/blockstates/gray_bed.json | 12 + .../blockstates/gray_shulker_box.json | 10 + .../blockstates/gray_wall_banner.json | 8 + .../minecraft/blockstates/green_banner.json | 20 + .../minecraft/blockstates/green_bed.json | 12 + .../blockstates/green_shulker_box.json | 10 + .../blockstates/green_wall_banner.json | 8 + .../blockstates/jungle_hanging_sign.json | 20 + .../minecraft/blockstates/jungle_sign.json | 20 + .../blockstates/jungle_wall_hanging_sign.json | 8 + .../blockstates/jungle_wall_sign.json | 0 .../assets/minecraft/blockstates/lava.json | 5 + .../blockstates/light_blue_banner.json | 20 + .../minecraft/blockstates/light_blue_bed.json | 0 .../blockstates/light_blue_shulker_box.json | 10 + .../blockstates/light_blue_wall_banner.json | 8 + .../blockstates/light_gray_banner.json | 20 + .../minecraft/blockstates/light_gray_bed.json | 0 .../blockstates/light_gray_shulker_box.json | 10 + .../blockstates/light_gray_wall_banner.json | 8 + .../minecraft/blockstates/lime_banner.json | 20 + .../minecraft/blockstates/lime_bed.json | 12 + .../blockstates/lime_shulker_box.json | 10 + .../blockstates/lime_wall_banner.json | 8 + .../minecraft/blockstates/magenta_banner.json | 20 + .../minecraft/blockstates/magenta_bed.json | 12 + .../blockstates/magenta_shulker_box.json | 10 + .../blockstates/magenta_wall_banner.json | 8 + .../blockstates/mangrove_hanging_sign.json | 20 + .../minecraft/blockstates/mangrove_sign.json | 0 .../mangrove_wall_hanging_sign.json | 8 + .../blockstates/mangrove_wall_sign.json | 0 .../blockstates/oak_hanging_sign.json | 20 + .../minecraft/blockstates/oak_sign.json | 20 + .../blockstates/oak_wall_hanging_sign.json | 8 + .../minecraft/blockstates/oak_wall_sign.json | 0 .../minecraft/blockstates/orange_banner.json | 20 + .../minecraft/blockstates/orange_bed.json | 12 + .../blockstates/orange_shulker_box.json | 10 + .../blockstates/orange_wall_banner.json | 8 + .../minecraft/blockstates/piglin_head.json | 20 + .../blockstates/piglin_wall_head.json | 8 + .../minecraft/blockstates/pink_banner.json | 20 + .../minecraft/blockstates/pink_bed.json | 12 + .../blockstates/pink_shulker_box.json | 10 + .../blockstates/pink_wall_banner.json | 8 + .../minecraft/blockstates/player_head.json | 20 + .../blockstates/player_wall_head.json | 8 + .../minecraft/blockstates/purple_banner.json | 20 + .../minecraft/blockstates/purple_bed.json | 12 + .../blockstates/purple_shulker_box.json | 10 + .../blockstates/purple_wall_banner.json | 8 + .../minecraft/blockstates/red_banner.json | 20 + .../assets/minecraft/blockstates/red_bed.json | 12 + .../blockstates/red_shulker_box.json | 10 + .../blockstates/red_wall_banner.json | 8 + .../minecraft/blockstates/shulker_box.json | 10 + .../minecraft/blockstates/skeleton_skull.json | 20 + .../blockstates/skeleton_wall_skull.json | 8 + .../blockstates/spruce_hanging_sign.json | 20 + .../minecraft/blockstates/spruce_sign.json | 20 + .../blockstates/spruce_wall_hanging_sign.json | 8 + .../blockstates/spruce_wall_sign.json | 0 .../minecraft/blockstates/trapped_chest.json | 0 .../blockstates/warped_hanging_sign.json | 20 + .../minecraft/blockstates/warped_sign.json | 20 + .../blockstates/warped_wall_hanging_sign.json | 8 + .../blockstates/warped_wall_sign.json | 0 .../assets/minecraft/blockstates/water.json | 5 + .../minecraft/blockstates/white_banner.json | 20 + .../minecraft/blockstates/white_bed.json | 12 + .../blockstates/white_shulker_box.json | 10 + .../blockstates/white_wall_banner.json | 8 + .../blockstates/wither_skeleton_skull.json | 20 + .../wither_skeleton_wall_skull.json | 8 + .../minecraft/blockstates/yellow_banner.json | 20 + .../minecraft/blockstates/yellow_bed.json | 12 + .../blockstates/yellow_shulker_box.json | 10 + .../blockstates/yellow_wall_banner.json | 8 + .../minecraft/blockstates/zombie_head.json | 20 + .../blockstates/zombie_wall_head.json | 8 + .../minecraft/models/block/bed/bed_foot.json | 39 ++ .../minecraft/models/block/bed/bed_head.json | 39 ++ .../models/block/bed/black_foot.json | 6 + .../models/block/bed/black_head.json | 6 + .../minecraft/models/block/bed/blue_foot.json | 6 + .../minecraft/models/block/bed/blue_head.json | 6 + .../models/block/bed/brown_foot.json | 6 + .../models/block/bed/brown_head.json | 6 + .../minecraft/models/block/bed/cyan_foot.json | 6 + .../minecraft/models/block/bed/cyan_head.json | 6 + .../minecraft/models/block/bed/gray_foot.json | 6 + .../minecraft/models/block/bed/gray_head.json | 6 + .../models/block/bed/green_foot.json | 6 + .../models/block/bed/green_head.json | 6 + .../models/block/bed/light_blue_foot.json | 6 + .../models/block/bed/light_blue_head.json | 6 + .../models/block/bed/light_gray_foot.json | 6 + .../models/block/bed/light_gray_head.json | 6 + .../minecraft/models/block/bed/lime_foot.json | 6 + .../minecraft/models/block/bed/lime_head.json | 6 + .../models/block/bed/magenta_foot.json | 6 + .../models/block/bed/magenta_head.json | 6 + .../models/block/bed/orange_foot.json | 6 + .../models/block/bed/orange_head.json | 6 + .../minecraft/models/block/bed/pink_foot.json | 6 + .../minecraft/models/block/bed/pink_head.json | 6 + .../models/block/bed/purple_foot.json | 6 + .../models/block/bed/purple_head.json | 6 + .../minecraft/models/block/bed/red_foot.json | 6 + .../minecraft/models/block/bed/red_head.json | 6 + .../models/block/bed/white_foot.json | 6 + .../models/block/bed/white_head.json | 6 + .../models/block/bed/yellow_foot.json | 6 + .../models/block/bed/yellow_head.json | 6 + .../models/block/bell_between_walls.json | 49 +++ .../minecraft/models/block/bell_ceiling.json | 48 +++ .../minecraft/models/block/bell_floor.json | 75 ++++ .../minecraft/models/block/bell_wall.json | 49 +++ .../models/block/bubble_column.json} | 0 .../assets/minecraft/models/block/cake.json | 21 + .../minecraft/models/block/cake_slice1.json | 24 ++ .../minecraft/models/block/cake_slice2.json | 25 ++ .../minecraft/models/block/cake_slice3.json | 25 ++ .../minecraft/models/block/cake_slice4.json | 25 ++ .../minecraft/models/block/cake_slice5.json | 25 ++ .../minecraft/models/block/cake_slice6.json | 25 ++ .../minecraft/models/block/chest/chest.json | 40 ++ .../models/block/chest/chest_double.json | 40 ++ .../minecraft/models/block/chest/ender.json | 6 + .../minecraft/models/block/chest/left.json | 1 + .../minecraft/models/block/chest/normal.json | 6 + .../models/block/chest/normal_double.json | 6 + .../minecraft/models/block/chest/trapped.json | 6 + .../models/block/chest/trapped_double.json | 6 + .../assets/minecraft/models/block/lava.json | 8 + .../minecraft/models/block/sign/acacia.json | 6 + .../minecraft/models/block/sign/bamboo.json | 6 + .../minecraft/models/block/sign/birch.json | 6 + .../minecraft/models/block/sign/cherry.json | 6 + .../minecraft/models/block/sign/crimson.json | 6 + .../minecraft/models/block/sign/dark_oak.json | 6 + .../minecraft/models/block/sign/jungle.json | 6 + .../minecraft/models/block/sign/mangrove.json | 6 + .../minecraft/models/block/sign/oak.json | 6 + .../minecraft/models/block/sign/sign.json | 28 ++ .../minecraft/models/block/sign/spruce.json | 6 + .../models/block/sign/wall_acacia.json | 6 + .../models/block/sign/wall_bamboo.json | 6 + .../models/block/sign/wall_birch.json | 6 + .../models/block/sign/wall_cherry.json | 6 + .../models/block/sign/wall_crimson.json | 6 + .../models/block/sign/wall_dark_oak.json | 6 + .../models/block/sign/wall_jungle.json | 6 + .../models/block/sign/wall_mangrove.json | 6 + .../minecraft/models/block/sign/wall_oak.json | 6 + .../models/block/sign/wall_sign.json | 16 + .../models/block/sign/wall_spruce.json | 6 + .../models/block/sign/wall_warped.json | 6 + .../minecraft/models/block/sign/warped.json | 6 + .../assets/minecraft/models/block/water.json | 8 + .../models/entity/acacia_hanging_sign.json | 7 + .../entity/acacia_wall_hanging_sign.json | 7 + .../models/entity/bamboo_hanging_sign.json | 7 + .../entity/bamboo_wall_hanging_sign.json | 7 + .../minecraft/models/entity/banner.json | 48 +++ .../models/entity/birch_hanging_sign.json | 7 + .../entity/birch_wall_hanging_sign.json | 7 + .../models/entity/cherry_hanging_sign.json | 7 + .../entity/cherry_wall_hanging_sign.json | 7 + .../minecraft/models/entity/creeper_head.json | 7 + .../models/entity/creeper_wall_head.json | 7 + .../models/entity/crimson_hanging_sign.json | 7 + .../entity/crimson_wall_hanging_sign.json | 7 + .../models/entity/dark_oak_hanging_sign.json | 7 + .../entity/dark_oak_wall_hanging_sign.json | 7 + .../models/entity/decorated_pot.json | 48 +++ .../minecraft/models/entity/dragon_head.json | 105 +++++ .../models/entity/dragon_wall_head.json | 143 +++++++ .../models/entity/dyed_shulker_box.json | 33 ++ .../minecraft/models/entity/hanging_sign.json | 35 ++ .../models/entity/jungle_hanging_sign.json | 7 + .../entity/jungle_wall_hanging_sign.json | 7 + .../models/entity/mangrove_hanging_sign.json | 7 + .../entity/mangrove_wall_hanging_sign.json | 7 + .../models/entity/oak_hanging_sign.json | 7 + .../models/entity/oak_wall_hanging_sign.json | 7 + .../minecraft/models/entity/piglin_head.json | 110 +++++ .../models/entity/piglin_wall_head.json | 135 ++++++ .../minecraft/models/entity/player_head.json | 7 + .../models/entity/player_wall_head.json | 7 + .../minecraft/models/entity/shulker_box.json | 33 ++ .../models/entity/skeleton_skull.json | 7 + .../models/entity/skeleton_wall_skull.json | 7 + .../minecraft/models/entity/skull_32.json | 32 ++ .../minecraft/models/entity/skull_64.json | 32 ++ .../models/entity/spruce_hanging_sign.json | 7 + .../entity/spruce_wall_hanging_sign.json | 7 + .../minecraft/models/entity/wall_banner.json | 35 ++ .../models/entity/wall_hanging_sign.json | 110 +++++ .../models/entity/wall_skull_32.json | 32 ++ .../models/entity/wall_skull_64.json | 32 ++ .../models/entity/warped_hanging_sign.json | 7 + .../entity/warped_wall_hanging_sign.json | 7 + .../models/entity/wither_skeleton_skull.json | 7 + .../entity/wither_skeleton_wall_skull.json | 7 + .../minecraft/models/entity/zombie_head.json | 7 + .../models/entity/zombie_wall_head.json | 7 + .../assets/bluemap/blockstates/missing.json | 5 - .../assets/bluemap/models/block/missing.json | 6 - .../mc1_13/assets/minecraft/biomes.json | 395 ------------------ .../mc1_13/assets/minecraft/blockColors.json | 15 - .../assets/minecraft/blockProperties.json | 54 --- .../minecraft/blockstates/acacia_sign.json | 20 - .../minecraft/blockstates/birch_sign.json | 20 - .../minecraft/blockstates/black_bed.json | 12 - .../minecraft/blockstates/blue_bed.json | 12 - .../minecraft/blockstates/brown_bed.json | 12 - .../minecraft/blockstates/bubble_column.json | 5 - .../assets/minecraft/blockstates/chest.json | 13 - .../minecraft/blockstates/cyan_bed.json | 12 - .../minecraft/blockstates/dark_oak_sign.json | 20 - .../minecraft/blockstates/ender_chest.json | 8 - .../minecraft/blockstates/gray_bed.json | 12 - .../minecraft/blockstates/green_bed.json | 12 - .../minecraft/blockstates/jungle_sign.json | 20 - .../assets/minecraft/blockstates/lava.json | 5 - .../minecraft/blockstates/lime_bed.json | 12 - .../minecraft/blockstates/magenta_bed.json | 12 - .../minecraft/blockstates/oak_sign.json | 20 - .../minecraft/blockstates/orange_bed.json | 12 - .../minecraft/blockstates/pink_bed.json | 12 - .../minecraft/blockstates/purple_bed.json | 12 - .../assets/minecraft/blockstates/red_bed.json | 12 - .../minecraft/blockstates/spruce_sign.json | 20 - .../assets/minecraft/blockstates/water.json | 5 - .../minecraft/blockstates/white_bed.json | 12 - .../minecraft/blockstates/yellow_bed.json | 12 - .../minecraft/models/block/bed/bed_foot.json | 39 -- .../minecraft/models/block/bed/bed_head.json | 39 -- .../models/block/bed/black_foot.json | 6 - .../models/block/bed/black_head.json | 6 - .../minecraft/models/block/bed/blue_foot.json | 6 - .../minecraft/models/block/bed/blue_head.json | 6 - .../models/block/bed/brown_foot.json | 6 - .../models/block/bed/brown_head.json | 6 - .../minecraft/models/block/bed/cyan_foot.json | 6 - .../minecraft/models/block/bed/cyan_head.json | 6 - .../minecraft/models/block/bed/gray_foot.json | 6 - .../minecraft/models/block/bed/gray_head.json | 6 - .../models/block/bed/green_foot.json | 6 - .../models/block/bed/green_head.json | 6 - .../models/block/bed/light_blue_foot.json | 6 - .../models/block/bed/light_blue_head.json | 6 - .../models/block/bed/light_gray_foot.json | 6 - .../models/block/bed/light_gray_head.json | 6 - .../minecraft/models/block/bed/lime_foot.json | 6 - .../minecraft/models/block/bed/lime_head.json | 6 - .../models/block/bed/magenta_foot.json | 6 - .../models/block/bed/magenta_head.json | 6 - .../models/block/bed/orange_foot.json | 6 - .../models/block/bed/orange_head.json | 6 - .../minecraft/models/block/bed/pink_foot.json | 6 - .../minecraft/models/block/bed/pink_head.json | 6 - .../models/block/bed/purple_foot.json | 6 - .../models/block/bed/purple_head.json | 6 - .../minecraft/models/block/bed/red_foot.json | 6 - .../minecraft/models/block/bed/red_head.json | 6 - .../models/block/bed/white_foot.json | 6 - .../models/block/bed/white_head.json | 6 - .../models/block/bed/yellow_foot.json | 6 - .../models/block/bed/yellow_head.json | 6 - .../minecraft/models/block/bubble_column.json | 2 - .../minecraft/models/block/chest/chest.json | 40 -- .../models/block/chest/chest_double.json | 40 -- .../minecraft/models/block/chest/ender.json | 6 - .../minecraft/models/block/chest/normal.json | 6 - .../models/block/chest/normal_double.json | 6 - .../minecraft/models/block/chest/trapped.json | 6 - .../models/block/chest/trapped_double.json | 6 - .../assets/minecraft/models/block/lava.json | 8 - .../minecraft/models/block/sign/acacia.json | 6 - .../minecraft/models/block/sign/birch.json | 6 - .../minecraft/models/block/sign/dark_oak.json | 6 - .../minecraft/models/block/sign/jungle.json | 6 - .../minecraft/models/block/sign/oak.json | 6 - .../minecraft/models/block/sign/sign.json | 28 -- .../minecraft/models/block/sign/spruce.json | 6 - .../models/block/sign/wall_acacia.json | 6 - .../models/block/sign/wall_birch.json | 6 - .../models/block/sign/wall_dark_oak.json | 6 - .../models/block/sign/wall_jungle.json | 6 - .../minecraft/models/block/sign/wall_oak.json | 6 - .../models/block/sign/wall_sign.json | 16 - .../models/block/sign/wall_spruce.json | 6 - .../assets/minecraft/models/block/water.json | 8 - .../assets/bluemap/blockstates/missing.json | 5 - .../assets/bluemap/models/block/missing.json | 6 - .../assets/bluemap/textures/block/missing.png | Bin 2826 -> 0 bytes .../mc1_15/assets/minecraft/biomes.json | 395 ------------------ .../mc1_15/assets/minecraft/blockColors.json | 15 - .../assets/minecraft/blockProperties.json | 54 --- .../minecraft/blockstates/acacia_sign.json | 20 - .../blockstates/acacia_wall_sign.json | 8 - .../minecraft/blockstates/birch_sign.json | 20 - .../blockstates/birch_wall_sign.json | 8 - .../minecraft/blockstates/black_bed.json | 12 - .../minecraft/blockstates/blue_bed.json | 12 - .../minecraft/blockstates/brown_bed.json | 12 - .../minecraft/blockstates/bubble_column.json | 5 - .../minecraft/blockstates/cyan_bed.json | 12 - .../minecraft/blockstates/dark_oak_sign.json | 20 - .../blockstates/dark_oak_wall_sign.json | 8 - .../minecraft/blockstates/gray_bed.json | 12 - .../minecraft/blockstates/green_bed.json | 12 - .../minecraft/blockstates/jungle_sign.json | 20 - .../blockstates/jungle_wall_sign.json | 8 - .../assets/minecraft/blockstates/lava.json | 5 - .../minecraft/blockstates/light_blue_bed.json | 12 - .../minecraft/blockstates/light_gray_bed.json | 12 - .../minecraft/blockstates/lime_bed.json | 12 - .../minecraft/blockstates/magenta_bed.json | 12 - .../minecraft/blockstates/oak_sign.json | 20 - .../minecraft/blockstates/oak_wall_sign.json | 8 - .../minecraft/blockstates/orange_bed.json | 12 - .../minecraft/blockstates/pink_bed.json | 12 - .../minecraft/blockstates/purple_bed.json | 12 - .../assets/minecraft/blockstates/red_bed.json | 12 - .../minecraft/blockstates/spruce_sign.json | 20 - .../blockstates/spruce_wall_sign.json | 8 - .../assets/minecraft/blockstates/water.json | 5 - .../minecraft/blockstates/white_bed.json | 12 - .../minecraft/blockstates/yellow_bed.json | 12 - .../minecraft/models/block/bed/bed_foot.json | 39 -- .../minecraft/models/block/bed/bed_head.json | 39 -- .../models/block/bed/black_foot.json | 6 - .../models/block/bed/black_head.json | 6 - .../minecraft/models/block/bed/blue_foot.json | 6 - .../minecraft/models/block/bed/blue_head.json | 6 - .../models/block/bed/brown_foot.json | 6 - .../models/block/bed/brown_head.json | 6 - .../minecraft/models/block/bed/cyan_foot.json | 6 - .../minecraft/models/block/bed/cyan_head.json | 6 - .../minecraft/models/block/bed/gray_foot.json | 6 - .../minecraft/models/block/bed/gray_head.json | 6 - .../models/block/bed/green_foot.json | 6 - .../models/block/bed/green_head.json | 6 - .../models/block/bed/light_blue_foot.json | 6 - .../models/block/bed/light_blue_head.json | 6 - .../models/block/bed/light_gray_foot.json | 6 - .../models/block/bed/light_gray_head.json | 6 - .../minecraft/models/block/bed/lime_foot.json | 6 - .../minecraft/models/block/bed/lime_head.json | 6 - .../models/block/bed/magenta_foot.json | 6 - .../models/block/bed/magenta_head.json | 6 - .../models/block/bed/orange_foot.json | 6 - .../models/block/bed/orange_head.json | 6 - .../minecraft/models/block/bed/pink_foot.json | 6 - .../minecraft/models/block/bed/pink_head.json | 6 - .../models/block/bed/purple_foot.json | 6 - .../models/block/bed/purple_head.json | 6 - .../minecraft/models/block/bed/red_foot.json | 6 - .../minecraft/models/block/bed/red_head.json | 6 - .../models/block/bed/white_foot.json | 6 - .../models/block/bed/white_head.json | 6 - .../models/block/bed/yellow_foot.json | 6 - .../models/block/bed/yellow_head.json | 6 - .../minecraft/models/block/bubble_column.json | 2 - .../minecraft/models/block/chest/ender.json | 6 - .../minecraft/models/block/chest/normal.json | 6 - .../minecraft/models/block/chest/trapped.json | 6 - .../assets/minecraft/models/block/lava.json | 8 - .../minecraft/models/block/sign/acacia.json | 6 - .../minecraft/models/block/sign/birch.json | 6 - .../minecraft/models/block/sign/dark_oak.json | 6 - .../minecraft/models/block/sign/jungle.json | 6 - .../minecraft/models/block/sign/oak.json | 6 - .../minecraft/models/block/sign/sign.json | 28 -- .../minecraft/models/block/sign/spruce.json | 6 - .../models/block/sign/wall_acacia.json | 6 - .../models/block/sign/wall_birch.json | 6 - .../models/block/sign/wall_dark_oak.json | 6 - .../models/block/sign/wall_jungle.json | 6 - .../minecraft/models/block/sign/wall_oak.json | 6 - .../models/block/sign/wall_sign.json | 16 - .../models/block/sign/wall_spruce.json | 6 - .../assets/minecraft/models/block/water.json | 8 - .../assets/bluemap/blockstates/missing.json | 5 - .../assets/bluemap/models/block/missing.json | 6 - .../assets/bluemap/textures/block/missing.png | Bin 2826 -> 0 bytes .../mc1_16/assets/minecraft/biomes.json | 395 ------------------ .../mc1_16/assets/minecraft/blockColors.json | 18 - .../assets/minecraft/blockProperties.json | 54 --- .../minecraft/blockstates/acacia_sign.json | 20 - .../blockstates/acacia_wall_sign.json | 8 - .../minecraft/blockstates/birch_sign.json | 20 - .../blockstates/birch_wall_sign.json | 8 - .../minecraft/blockstates/black_bed.json | 12 - .../minecraft/blockstates/blue_bed.json | 12 - .../minecraft/blockstates/brown_bed.json | 12 - .../minecraft/blockstates/bubble_column.json | 5 - .../assets/minecraft/blockstates/chest.json | 16 - .../minecraft/blockstates/crimson_sign.json | 20 - .../minecraft/blockstates/cyan_bed.json | 12 - .../minecraft/blockstates/dark_oak_sign.json | 20 - .../blockstates/dark_oak_wall_sign.json | 8 - .../minecraft/blockstates/ender_chest.json | 8 - .../minecraft/blockstates/gray_bed.json | 12 - .../minecraft/blockstates/green_bed.json | 12 - .../minecraft/blockstates/jungle_sign.json | 20 - .../blockstates/jungle_wall_sign.json | 8 - .../assets/minecraft/blockstates/lava.json | 5 - .../minecraft/blockstates/light_blue_bed.json | 12 - .../minecraft/blockstates/light_gray_bed.json | 12 - .../minecraft/blockstates/lime_bed.json | 12 - .../minecraft/blockstates/magenta_bed.json | 12 - .../minecraft/blockstates/oak_sign.json | 20 - .../minecraft/blockstates/oak_wall_sign.json | 8 - .../minecraft/blockstates/orange_bed.json | 12 - .../minecraft/blockstates/pink_bed.json | 12 - .../minecraft/blockstates/purple_bed.json | 12 - .../assets/minecraft/blockstates/red_bed.json | 12 - .../minecraft/blockstates/spruce_sign.json | 20 - .../blockstates/spruce_wall_sign.json | 8 - .../minecraft/blockstates/trapped_chest.json | 16 - .../minecraft/blockstates/warped_sign.json | 20 - .../assets/minecraft/blockstates/water.json | 5 - .../minecraft/blockstates/white_bed.json | 12 - .../minecraft/blockstates/yellow_bed.json | 12 - .../minecraft/models/block/bed/bed_foot.json | 39 -- .../minecraft/models/block/bed/bed_head.json | 39 -- .../models/block/bed/black_foot.json | 6 - .../models/block/bed/black_head.json | 6 - .../minecraft/models/block/bed/blue_foot.json | 6 - .../minecraft/models/block/bed/blue_head.json | 6 - .../models/block/bed/brown_foot.json | 6 - .../models/block/bed/brown_head.json | 6 - .../minecraft/models/block/bed/cyan_foot.json | 6 - .../minecraft/models/block/bed/cyan_head.json | 6 - .../minecraft/models/block/bed/gray_foot.json | 6 - .../minecraft/models/block/bed/gray_head.json | 6 - .../models/block/bed/green_foot.json | 6 - .../models/block/bed/green_head.json | 6 - .../models/block/bed/light_blue_foot.json | 6 - .../models/block/bed/light_blue_head.json | 6 - .../models/block/bed/light_gray_foot.json | 6 - .../models/block/bed/light_gray_head.json | 6 - .../minecraft/models/block/bed/lime_foot.json | 6 - .../minecraft/models/block/bed/lime_head.json | 6 - .../models/block/bed/magenta_foot.json | 6 - .../models/block/bed/magenta_head.json | 6 - .../models/block/bed/orange_foot.json | 6 - .../models/block/bed/orange_head.json | 6 - .../minecraft/models/block/bed/pink_foot.json | 6 - .../minecraft/models/block/bed/pink_head.json | 6 - .../models/block/bed/purple_foot.json | 6 - .../models/block/bed/purple_head.json | 6 - .../minecraft/models/block/bed/red_foot.json | 6 - .../minecraft/models/block/bed/red_head.json | 6 - .../models/block/bed/white_foot.json | 6 - .../models/block/bed/white_head.json | 6 - .../models/block/bed/yellow_foot.json | 6 - .../models/block/bed/yellow_head.json | 6 - .../minecraft/models/block/bubble_column.json | 2 - .../minecraft/models/block/chest/chest.json | 39 -- .../models/block/chest/chest_double_left.json | 37 -- .../block/chest/chest_double_right.json | 36 -- .../minecraft/models/block/chest/ender.json | 6 - .../minecraft/models/block/chest/normal.json | 6 - .../block/chest/normal_double_left.json | 6 - .../block/chest/normal_double_right.json | 6 - .../minecraft/models/block/chest/trapped.json | 6 - .../block/chest/trapped_double_left.json | 6 - .../block/chest/trapped_double_right.json | 6 - .../assets/minecraft/models/block/lava.json | 8 - .../minecraft/models/block/sign/acacia.json | 6 - .../minecraft/models/block/sign/birch.json | 6 - .../minecraft/models/block/sign/crimson.json | 6 - .../minecraft/models/block/sign/dark_oak.json | 6 - .../minecraft/models/block/sign/jungle.json | 6 - .../minecraft/models/block/sign/oak.json | 6 - .../minecraft/models/block/sign/sign.json | 28 -- .../minecraft/models/block/sign/spruce.json | 6 - .../models/block/sign/wall_acacia.json | 6 - .../models/block/sign/wall_birch.json | 6 - .../models/block/sign/wall_crimson.json | 6 - .../models/block/sign/wall_dark_oak.json | 6 - .../models/block/sign/wall_jungle.json | 6 - .../minecraft/models/block/sign/wall_oak.json | 6 - .../models/block/sign/wall_sign.json | 16 - .../models/block/sign/wall_spruce.json | 6 - .../models/block/sign/wall_warped.json | 6 - .../minecraft/models/block/sign/warped.json | 6 - .../assets/minecraft/models/block/water.json | 8 - .../minecraft/blockstates/grass_path.json | 21 + .../assets/bluemap/blockstates/missing.json | 5 - .../assets/bluemap/models/block/missing.json | 6 - .../assets/bluemap/textures/block/missing.png | Bin 2826 -> 0 bytes .../mc1_18/assets/minecraft/biomes.json | 324 -------------- .../mc1_18/assets/minecraft/blockColors.json | 20 - .../minecraft/blockstates/acacia_sign.json | 20 - .../blockstates/acacia_wall_sign.json | 8 - .../minecraft/blockstates/birch_sign.json | 20 - .../blockstates/birch_wall_sign.json | 8 - .../minecraft/blockstates/black_bed.json | 12 - .../minecraft/blockstates/blue_bed.json | 12 - .../minecraft/blockstates/brown_bed.json | 12 - .../minecraft/blockstates/bubble_column.json | 5 - .../assets/minecraft/blockstates/chest.json | 16 - .../minecraft/blockstates/crimson_sign.json | 20 - .../blockstates/crimson_wall_sign.json | 8 - .../minecraft/blockstates/cyan_bed.json | 12 - .../minecraft/blockstates/dark_oak_sign.json | 20 - .../blockstates/dark_oak_wall_sign.json | 8 - .../minecraft/blockstates/ender_chest.json | 8 - .../minecraft/blockstates/gray_bed.json | 12 - .../minecraft/blockstates/green_bed.json | 12 - .../minecraft/blockstates/jungle_sign.json | 20 - .../blockstates/jungle_wall_sign.json | 8 - .../assets/minecraft/blockstates/lava.json | 5 - .../minecraft/blockstates/light_blue_bed.json | 12 - .../minecraft/blockstates/light_gray_bed.json | 12 - .../minecraft/blockstates/lime_bed.json | 12 - .../minecraft/blockstates/magenta_bed.json | 12 - .../minecraft/blockstates/oak_sign.json | 20 - .../minecraft/blockstates/oak_wall_sign.json | 8 - .../minecraft/blockstates/orange_bed.json | 12 - .../minecraft/blockstates/pink_bed.json | 12 - .../minecraft/blockstates/purple_bed.json | 12 - .../assets/minecraft/blockstates/red_bed.json | 12 - .../minecraft/blockstates/spruce_sign.json | 20 - .../blockstates/spruce_wall_sign.json | 8 - .../minecraft/blockstates/trapped_chest.json | 16 - .../minecraft/blockstates/warped_sign.json | 20 - .../blockstates/warped_wall_sign.json | 8 - .../assets/minecraft/blockstates/water.json | 5 - .../minecraft/blockstates/white_bed.json | 12 - .../minecraft/blockstates/yellow_bed.json | 12 - .../minecraft/models/block/bed/bed_foot.json | 39 -- .../minecraft/models/block/bed/bed_head.json | 39 -- .../models/block/bed/black_foot.json | 6 - .../models/block/bed/black_head.json | 6 - .../minecraft/models/block/bed/blue_foot.json | 6 - .../minecraft/models/block/bed/blue_head.json | 6 - .../models/block/bed/brown_foot.json | 6 - .../models/block/bed/brown_head.json | 6 - .../minecraft/models/block/bed/cyan_foot.json | 6 - .../minecraft/models/block/bed/cyan_head.json | 6 - .../minecraft/models/block/bed/gray_foot.json | 6 - .../minecraft/models/block/bed/gray_head.json | 6 - .../models/block/bed/green_foot.json | 6 - .../models/block/bed/green_head.json | 6 - .../models/block/bed/light_blue_foot.json | 6 - .../models/block/bed/light_blue_head.json | 6 - .../models/block/bed/light_gray_foot.json | 6 - .../models/block/bed/light_gray_head.json | 6 - .../minecraft/models/block/bed/lime_foot.json | 6 - .../minecraft/models/block/bed/lime_head.json | 6 - .../models/block/bed/magenta_foot.json | 6 - .../models/block/bed/magenta_head.json | 6 - .../models/block/bed/orange_foot.json | 6 - .../models/block/bed/orange_head.json | 6 - .../minecraft/models/block/bed/pink_foot.json | 6 - .../minecraft/models/block/bed/pink_head.json | 6 - .../models/block/bed/purple_foot.json | 6 - .../models/block/bed/purple_head.json | 6 - .../minecraft/models/block/bed/red_foot.json | 6 - .../minecraft/models/block/bed/red_head.json | 6 - .../models/block/bed/white_foot.json | 6 - .../models/block/bed/white_head.json | 6 - .../models/block/bed/yellow_foot.json | 6 - .../models/block/bed/yellow_head.json | 6 - .../minecraft/models/block/bubble_column.json | 2 - .../minecraft/models/block/chest/chest.json | 39 -- .../models/block/chest/chest_double_left.json | 37 -- .../block/chest/chest_double_right.json | 36 -- .../minecraft/models/block/chest/ender.json | 6 - .../minecraft/models/block/chest/normal.json | 6 - .../block/chest/normal_double_left.json | 6 - .../block/chest/normal_double_right.json | 6 - .../minecraft/models/block/chest/trapped.json | 6 - .../block/chest/trapped_double_left.json | 6 - .../block/chest/trapped_double_right.json | 6 - .../assets/minecraft/models/block/lava.json | 8 - .../minecraft/models/block/sign/acacia.json | 6 - .../minecraft/models/block/sign/birch.json | 6 - .../minecraft/models/block/sign/crimson.json | 6 - .../minecraft/models/block/sign/dark_oak.json | 6 - .../minecraft/models/block/sign/jungle.json | 6 - .../minecraft/models/block/sign/mangrove.json | 6 - .../minecraft/models/block/sign/oak.json | 6 - .../minecraft/models/block/sign/sign.json | 28 -- .../minecraft/models/block/sign/spruce.json | 6 - .../models/block/sign/wall_acacia.json | 6 - .../models/block/sign/wall_birch.json | 6 - .../models/block/sign/wall_crimson.json | 6 - .../models/block/sign/wall_dark_oak.json | 6 - .../models/block/sign/wall_jungle.json | 6 - .../models/block/sign/wall_mangrove.json | 6 - .../minecraft/models/block/sign/wall_oak.json | 6 - .../models/block/sign/wall_sign.json | 16 - .../models/block/sign/wall_spruce.json | 6 - .../models/block/sign/wall_warped.json | 6 - .../minecraft/models/block/sign/warped.json | 6 - .../assets/minecraft/models/block/water.json | 8 - .../assets/bluemap/blockstates/missing.json | 5 - .../assets/bluemap/models/block/missing.json | 6 - .../assets/bluemap/textures/block/missing.png | Bin 2826 -> 0 bytes .../mc1_20_3/assets/minecraft/biomes.json | 324 -------------- .../assets/minecraft/blockColors.json | 68 --- .../assets/minecraft/blockProperties.json | 55 --- .../blockstates/acacia_hanging_sign.json | 67 --- .../minecraft/blockstates/acacia_sign.json | 20 - .../blockstates/acacia_wall_hanging_sign.json | 19 - .../blockstates/acacia_wall_sign.json | 8 - .../blockstates/bamboo_hanging_sign.json | 67 --- .../blockstates/bamboo_wall_hanging_sign.json | 19 - .../blockstates/birch_hanging_sign.json | 67 --- .../minecraft/blockstates/birch_sign.json | 20 - .../blockstates/birch_wall_hanging_sign.json | 19 - .../blockstates/birch_wall_sign.json | 8 - .../minecraft/blockstates/black_banner.json | 67 --- .../minecraft/blockstates/black_bed.json | 12 - .../blockstates/black_shulker_box.json | 30 -- .../blockstates/black_wall_banner.json | 19 - .../minecraft/blockstates/blue_banner.json | 67 --- .../minecraft/blockstates/blue_bed.json | 12 - .../blockstates/blue_shulker_box.json | 30 -- .../blockstates/blue_wall_banner.json | 19 - .../minecraft/blockstates/brown_banner.json | 67 --- .../minecraft/blockstates/brown_bed.json | 12 - .../blockstates/brown_shulker_box.json | 30 -- .../blockstates/brown_wall_banner.json | 19 - .../minecraft/blockstates/bubble_column.json | 5 - .../blockstates/cherry_hanging_sign.json | 67 --- .../blockstates/cherry_wall_hanging_sign.json | 19 - .../assets/minecraft/blockstates/chest.json | 16 - .../minecraft/blockstates/creeper_head.json | 67 --- .../blockstates/creeper_wall_head.json | 19 - .../blockstates/crimson_hanging_sign.json | 67 --- .../minecraft/blockstates/crimson_sign.json | 20 - .../crimson_wall_hanging_sign.json | 19 - .../blockstates/crimson_wall_sign.json | 8 - .../minecraft/blockstates/cyan_banner.json | 67 --- .../minecraft/blockstates/cyan_bed.json | 12 - .../blockstates/cyan_shulker_box.json | 30 -- .../blockstates/cyan_wall_banner.json | 19 - .../blockstates/dark_oak_hanging_sign.json | 67 --- .../minecraft/blockstates/dark_oak_sign.json | 20 - .../dark_oak_wall_hanging_sign.json | 19 - .../blockstates/dark_oak_wall_sign.json | 8 - .../minecraft/blockstates/decorated_pot.json | 19 - .../minecraft/blockstates/dragon_head.json | 67 --- .../blockstates/dragon_wall_head.json | 19 - .../minecraft/blockstates/ender_chest.json | 8 - .../minecraft/blockstates/gray_banner.json | 67 --- .../minecraft/blockstates/gray_bed.json | 12 - .../blockstates/gray_shulker_box.json | 30 -- .../blockstates/gray_wall_banner.json | 19 - .../minecraft/blockstates/green_banner.json | 67 --- .../minecraft/blockstates/green_bed.json | 12 - .../blockstates/green_shulker_box.json | 30 -- .../blockstates/green_wall_banner.json | 19 - .../blockstates/jungle_hanging_sign.json | 67 --- .../minecraft/blockstates/jungle_sign.json | 20 - .../blockstates/jungle_wall_hanging_sign.json | 19 - .../blockstates/jungle_wall_sign.json | 8 - .../assets/minecraft/blockstates/lava.json | 5 - .../blockstates/light_blue_banner.json | 67 --- .../minecraft/blockstates/light_blue_bed.json | 12 - .../blockstates/light_blue_shulker_box.json | 30 -- .../blockstates/light_blue_wall_banner.json | 19 - .../blockstates/light_gray_banner.json | 67 --- .../minecraft/blockstates/light_gray_bed.json | 12 - .../blockstates/light_gray_shulker_box.json | 30 -- .../blockstates/light_gray_wall_banner.json | 19 - .../minecraft/blockstates/lime_banner.json | 67 --- .../minecraft/blockstates/lime_bed.json | 12 - .../blockstates/lime_shulker_box.json | 30 -- .../blockstates/lime_wall_banner.json | 19 - .../minecraft/blockstates/magenta_banner.json | 67 --- .../minecraft/blockstates/magenta_bed.json | 12 - .../blockstates/magenta_shulker_box.json | 30 -- .../blockstates/magenta_wall_banner.json | 19 - .../blockstates/mangrove_hanging_sign.json | 67 --- .../minecraft/blockstates/mangrove_sign.json | 20 - .../mangrove_wall_hanging_sign.json | 19 - .../blockstates/mangrove_wall_sign.json | 8 - .../blockstates/oak_hanging_sign.json | 67 --- .../minecraft/blockstates/oak_sign.json | 20 - .../blockstates/oak_wall_hanging_sign.json | 19 - .../minecraft/blockstates/oak_wall_sign.json | 8 - .../minecraft/blockstates/orange_banner.json | 67 --- .../minecraft/blockstates/orange_bed.json | 12 - .../blockstates/orange_shulker_box.json | 30 -- .../blockstates/orange_wall_banner.json | 19 - .../minecraft/blockstates/piglin_head.json | 67 --- .../blockstates/piglin_wall_head.json | 19 - .../minecraft/blockstates/pink_banner.json | 67 --- .../minecraft/blockstates/pink_bed.json | 12 - .../blockstates/pink_shulker_box.json | 30 -- .../blockstates/pink_wall_banner.json | 19 - .../minecraft/blockstates/player_head.json | 67 --- .../blockstates/player_wall_head.json | 19 - .../minecraft/blockstates/purple_banner.json | 67 --- .../minecraft/blockstates/purple_bed.json | 12 - .../blockstates/purple_shulker_box.json | 30 -- .../blockstates/purple_wall_banner.json | 19 - .../minecraft/blockstates/red_banner.json | 67 --- .../assets/minecraft/blockstates/red_bed.json | 12 - .../blockstates/red_shulker_box.json | 30 -- .../blockstates/red_wall_banner.json | 19 - .../minecraft/blockstates/shulker_box.json | 30 -- .../minecraft/blockstates/skeleton_skull.json | 67 --- .../blockstates/skeleton_wall_skull.json | 19 - .../blockstates/spruce_hanging_sign.json | 67 --- .../minecraft/blockstates/spruce_sign.json | 20 - .../blockstates/spruce_wall_hanging_sign.json | 19 - .../blockstates/spruce_wall_sign.json | 8 - .../minecraft/blockstates/trapped_chest.json | 16 - .../blockstates/warped_hanging_sign.json | 67 --- .../minecraft/blockstates/warped_sign.json | 20 - .../blockstates/warped_wall_hanging_sign.json | 19 - .../blockstates/warped_wall_sign.json | 8 - .../assets/minecraft/blockstates/water.json | 5 - .../minecraft/blockstates/white_banner.json | 67 --- .../minecraft/blockstates/white_bed.json | 12 - .../blockstates/white_shulker_box.json | 30 -- .../blockstates/white_wall_banner.json | 19 - .../blockstates/wither_skeleton_skull.json | 67 --- .../wither_skeleton_wall_skull.json | 19 - .../minecraft/blockstates/yellow_banner.json | 67 --- .../minecraft/blockstates/yellow_bed.json | 12 - .../blockstates/yellow_shulker_box.json | 30 -- .../blockstates/yellow_wall_banner.json | 19 - .../minecraft/blockstates/zombie_head.json | 67 --- .../blockstates/zombie_wall_head.json | 19 - .../minecraft/models/block/bed/bed_foot.json | 39 -- .../minecraft/models/block/bed/bed_head.json | 39 -- .../models/block/bed/black_foot.json | 6 - .../models/block/bed/black_head.json | 6 - .../minecraft/models/block/bed/blue_foot.json | 6 - .../minecraft/models/block/bed/blue_head.json | 6 - .../models/block/bed/brown_foot.json | 6 - .../models/block/bed/brown_head.json | 6 - .../minecraft/models/block/bed/cyan_foot.json | 6 - .../minecraft/models/block/bed/cyan_head.json | 6 - .../minecraft/models/block/bed/gray_foot.json | 6 - .../minecraft/models/block/bed/gray_head.json | 6 - .../models/block/bed/green_foot.json | 6 - .../models/block/bed/green_head.json | 6 - .../models/block/bed/light_blue_foot.json | 6 - .../models/block/bed/light_blue_head.json | 6 - .../models/block/bed/light_gray_foot.json | 6 - .../models/block/bed/light_gray_head.json | 6 - .../minecraft/models/block/bed/lime_foot.json | 6 - .../minecraft/models/block/bed/lime_head.json | 6 - .../models/block/bed/magenta_foot.json | 6 - .../models/block/bed/magenta_head.json | 6 - .../models/block/bed/orange_foot.json | 6 - .../models/block/bed/orange_head.json | 6 - .../minecraft/models/block/bed/pink_foot.json | 6 - .../minecraft/models/block/bed/pink_head.json | 6 - .../models/block/bed/purple_foot.json | 6 - .../models/block/bed/purple_head.json | 6 - .../minecraft/models/block/bed/red_foot.json | 6 - .../minecraft/models/block/bed/red_head.json | 6 - .../models/block/bed/white_foot.json | 6 - .../models/block/bed/white_head.json | 6 - .../models/block/bed/yellow_foot.json | 6 - .../models/block/bed/yellow_head.json | 6 - .../models/block/bell_between_walls.json | 49 --- .../minecraft/models/block/bell_ceiling.json | 48 --- .../minecraft/models/block/bell_floor.json | 75 ---- .../minecraft/models/block/bell_wall.json | 49 --- .../minecraft/models/block/bubble_column.json | 2 - .../assets/minecraft/models/block/cake.json | 21 - .../minecraft/models/block/cake_slice1.json | 24 -- .../minecraft/models/block/cake_slice2.json | 25 -- .../minecraft/models/block/cake_slice3.json | 25 -- .../minecraft/models/block/cake_slice4.json | 25 -- .../minecraft/models/block/cake_slice5.json | 25 -- .../minecraft/models/block/cake_slice6.json | 25 -- .../minecraft/models/block/chest/chest.json | 39 -- .../models/block/chest/chest_double_left.json | 37 -- .../block/chest/chest_double_right.json | 36 -- .../minecraft/models/block/chest/ender.json | 6 - .../minecraft/models/block/chest/normal.json | 6 - .../block/chest/normal_double_left.json | 6 - .../block/chest/normal_double_right.json | 6 - .../minecraft/models/block/chest/trapped.json | 6 - .../block/chest/trapped_double_left.json | 6 - .../block/chest/trapped_double_right.json | 6 - .../assets/minecraft/models/block/lava.json | 8 - .../minecraft/models/block/sign/acacia.json | 6 - .../minecraft/models/block/sign/bamboo.json | 6 - .../minecraft/models/block/sign/birch.json | 6 - .../minecraft/models/block/sign/cherry.json | 6 - .../minecraft/models/block/sign/crimson.json | 6 - .../minecraft/models/block/sign/dark_oak.json | 6 - .../minecraft/models/block/sign/jungle.json | 6 - .../minecraft/models/block/sign/mangrove.json | 6 - .../minecraft/models/block/sign/oak.json | 6 - .../minecraft/models/block/sign/sign.json | 28 -- .../minecraft/models/block/sign/spruce.json | 6 - .../models/block/sign/wall_acacia.json | 6 - .../models/block/sign/wall_bamboo.json | 6 - .../models/block/sign/wall_birch.json | 6 - .../models/block/sign/wall_cherry.json | 6 - .../models/block/sign/wall_crimson.json | 6 - .../models/block/sign/wall_dark_oak.json | 6 - .../models/block/sign/wall_jungle.json | 6 - .../models/block/sign/wall_mangrove.json | 6 - .../minecraft/models/block/sign/wall_oak.json | 6 - .../models/block/sign/wall_sign.json | 16 - .../models/block/sign/wall_spruce.json | 6 - .../models/block/sign/wall_warped.json | 6 - .../minecraft/models/block/sign/warped.json | 6 - .../assets/minecraft/models/block/water.json | 8 - .../models/entity/acacia_hanging_sign.json | 7 - .../entity/acacia_wall_hanging_sign.json | 7 - .../models/entity/bamboo_hanging_sign.json | 7 - .../entity/bamboo_wall_hanging_sign.json | 7 - .../minecraft/models/entity/banner.json | 48 --- .../models/entity/birch_hanging_sign.json | 7 - .../entity/birch_wall_hanging_sign.json | 7 - .../models/entity/cherry_hanging_sign.json | 7 - .../entity/cherry_wall_hanging_sign.json | 7 - .../minecraft/models/entity/creeper_head.json | 7 - .../models/entity/creeper_wall_head.json | 7 - .../models/entity/crimson_hanging_sign.json | 7 - .../entity/crimson_wall_hanging_sign.json | 7 - .../models/entity/dark_oak_hanging_sign.json | 7 - .../entity/dark_oak_wall_hanging_sign.json | 7 - .../models/entity/decorated_pot.json | 48 --- .../minecraft/models/entity/dragon_head.json | 101 ----- .../models/entity/dragon_wall_head.json | 115 ----- .../models/entity/dyed_shulker_box.json | 33 -- .../minecraft/models/entity/hanging_sign.json | 35 -- .../models/entity/jungle_hanging_sign.json | 7 - .../entity/jungle_wall_hanging_sign.json | 7 - .../models/entity/mangrove_hanging_sign.json | 7 - .../entity/mangrove_wall_hanging_sign.json | 7 - .../models/entity/oak_hanging_sign.json | 7 - .../models/entity/oak_wall_hanging_sign.json | 7 - .../minecraft/models/entity/piglin_head.json | 102 ----- .../models/entity/piglin_wall_head.json | 107 ----- .../minecraft/models/entity/player_head.json | 7 - .../models/entity/player_wall_head.json | 7 - .../minecraft/models/entity/shulker_box.json | 33 -- .../models/entity/skeleton_skull.json | 7 - .../models/entity/skeleton_wall_skull.json | 7 - .../minecraft/models/entity/skull_32.json | 32 -- .../minecraft/models/entity/skull_64.json | 32 -- .../models/entity/spruce_hanging_sign.json | 7 - .../entity/spruce_wall_hanging_sign.json | 7 - .../minecraft/models/entity/wall_banner.json | 35 -- .../models/entity/wall_hanging_sign.json | 82 ---- .../models/entity/wall_skull_32.json | 32 -- .../models/entity/wall_skull_64.json | 32 -- .../models/entity/warped_hanging_sign.json | 7 - .../entity/warped_wall_hanging_sign.json | 7 - .../models/entity/wither_skeleton_skull.json | 7 - .../entity/wither_skeleton_wall_skull.json | 7 - .../minecraft/models/entity/zombie_head.json | 7 - .../models/entity/zombie_wall_head.json | 7 - .../src/main/resourceExtensions/pack.mcmeta | 18 + gradle/wrapper/gradle-wrapper.properties | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- implementations/paper/build.gradle.kts | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- 957 files changed, 3952 insertions(+), 12113 deletions(-) create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/RegistryAdapter.java rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/{ => pack}/PackMeta.java (92%) rename BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/{ => biome}/Biome.java (92%) create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/ColorModifier.java create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/GrassColorModifier.java create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/bluemap/blockstates/missing.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/bluemap/models/block/missing.json rename BlueMapCore/src/main/resourceExtensions/{mc1_13 => }/assets/bluemap/textures/block/missing.png (100%) create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockColors.json rename BlueMapCore/src/main/resourceExtensions/{mc1_18 => }/assets/minecraft/blockProperties.json (100%) create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/acacia_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/acacia_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/acacia_wall_hanging_sign.json rename BlueMapCore/src/main/resourceExtensions/{mc1_13 => }/assets/minecraft/blockstates/acacia_wall_sign.json (100%) create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/bamboo_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/bamboo_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/birch_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/birch_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/birch_wall_hanging_sign.json rename BlueMapCore/src/main/resourceExtensions/{mc1_13 => }/assets/minecraft/blockstates/birch_wall_sign.json (100%) create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/black_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/black_bed.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/black_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/black_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/blue_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/blue_bed.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/blue_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/blue_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/brown_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/brown_bed.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/brown_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/brown_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/bubble_column.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cherry_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cherry_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/chest.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/creeper_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/creeper_wall_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/crimson_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/crimson_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/crimson_wall_hanging_sign.json rename BlueMapCore/src/main/resourceExtensions/{mc1_16 => }/assets/minecraft/blockstates/crimson_wall_sign.json (100%) create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cyan_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cyan_bed.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cyan_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cyan_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dark_oak_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dark_oak_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dark_oak_wall_hanging_sign.json rename BlueMapCore/src/main/resourceExtensions/{mc1_13 => }/assets/minecraft/blockstates/dark_oak_wall_sign.json (100%) create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/decorated_pot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dragon_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dragon_wall_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/ender_chest.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/gray_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/gray_bed.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/gray_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/gray_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/green_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/green_bed.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/green_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/green_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/jungle_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/jungle_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/jungle_wall_hanging_sign.json rename BlueMapCore/src/main/resourceExtensions/{mc1_13 => }/assets/minecraft/blockstates/jungle_wall_sign.json (100%) create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/lava.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_blue_banner.json rename BlueMapCore/src/main/resourceExtensions/{mc1_13 => }/assets/minecraft/blockstates/light_blue_bed.json (100%) create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_blue_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_blue_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_gray_banner.json rename BlueMapCore/src/main/resourceExtensions/{mc1_13 => }/assets/minecraft/blockstates/light_gray_bed.json (100%) create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_gray_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_gray_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/lime_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/lime_bed.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/lime_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/lime_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/magenta_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/magenta_bed.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/magenta_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/magenta_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/mangrove_hanging_sign.json rename BlueMapCore/src/main/resourceExtensions/{mc1_18 => }/assets/minecraft/blockstates/mangrove_sign.json (100%) create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/mangrove_wall_hanging_sign.json rename BlueMapCore/src/main/resourceExtensions/{mc1_18 => }/assets/minecraft/blockstates/mangrove_wall_sign.json (100%) create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/oak_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/oak_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/oak_wall_hanging_sign.json rename BlueMapCore/src/main/resourceExtensions/{mc1_13 => }/assets/minecraft/blockstates/oak_wall_sign.json (100%) create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/orange_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/orange_bed.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/orange_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/orange_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/piglin_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/piglin_wall_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/pink_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/pink_bed.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/pink_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/pink_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/player_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/player_wall_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/purple_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/purple_bed.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/purple_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/purple_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/red_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/red_bed.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/red_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/red_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/skeleton_skull.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/skeleton_wall_skull.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/spruce_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/spruce_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/spruce_wall_hanging_sign.json rename BlueMapCore/src/main/resourceExtensions/{mc1_13 => }/assets/minecraft/blockstates/spruce_wall_sign.json (100%) rename BlueMapCore/src/main/resourceExtensions/{mc1_13 => }/assets/minecraft/blockstates/trapped_chest.json (100%) create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/warped_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/warped_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/warped_wall_hanging_sign.json rename BlueMapCore/src/main/resourceExtensions/{mc1_16 => }/assets/minecraft/blockstates/warped_wall_sign.json (100%) create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/water.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/white_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/white_bed.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/white_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/white_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/wither_skeleton_skull.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/wither_skeleton_wall_skull.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/yellow_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/yellow_bed.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/yellow_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/yellow_wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/zombie_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/zombie_wall_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/bed_foot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/bed_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/black_foot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/black_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/blue_foot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/blue_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/brown_foot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/brown_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/cyan_foot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/cyan_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/gray_foot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/gray_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/green_foot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/green_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/light_blue_foot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/light_blue_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/light_gray_foot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/light_gray_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/lime_foot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/lime_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/magenta_foot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/magenta_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/orange_foot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/orange_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/pink_foot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/pink_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/purple_foot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/purple_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/red_foot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/red_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/white_foot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/white_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/yellow_foot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/yellow_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bell_between_walls.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bell_ceiling.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bell_floor.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bell_wall.json rename BlueMapCore/src/main/resourceExtensions/{mc1_13/assets/minecraft/models/block/chest/left.json => assets/minecraft/models/block/bubble_column.json} (100%) create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice1.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice2.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice3.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice4.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice5.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice6.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/chest.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/chest_double.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/ender.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/left.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/normal.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/normal_double.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/trapped.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/trapped_double.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/lava.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/acacia.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/bamboo.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/birch.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/cherry.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/crimson.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/dark_oak.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/jungle.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/mangrove.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/oak.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/spruce.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_acacia.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_bamboo.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_birch.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_cherry.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_crimson.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_dark_oak.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_jungle.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_mangrove.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_oak.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_spruce.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_warped.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/warped.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/water.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/acacia_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/acacia_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/bamboo_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/bamboo_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/birch_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/birch_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/cherry_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/cherry_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/creeper_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/creeper_wall_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/crimson_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/crimson_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/dark_oak_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/dark_oak_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/decorated_pot.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/dragon_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/dragon_wall_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/dyed_shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/jungle_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/jungle_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/mangrove_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/mangrove_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/oak_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/oak_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/piglin_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/piglin_wall_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/player_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/player_wall_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/shulker_box.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/skeleton_skull.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/skeleton_wall_skull.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/skull_32.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/skull_64.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/spruce_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/spruce_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wall_banner.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wall_skull_32.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wall_skull_64.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/warped_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/warped_wall_hanging_sign.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wither_skeleton_skull.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wither_skeleton_wall_skull.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/zombie_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/zombie_wall_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/bluemap/blockstates/missing.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/bluemap/models/block/missing.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/biomes.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockColors.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockProperties.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/acacia_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/birch_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/black_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/blue_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/brown_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/bubble_column.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/chest.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/cyan_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/dark_oak_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/ender_chest.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/gray_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/green_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/jungle_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/lava.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/lime_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/magenta_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/oak_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/orange_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/pink_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/purple_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/red_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/spruce_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/water.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/white_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/yellow_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/bed_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/bed_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/black_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/black_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/blue_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/blue_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/brown_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/brown_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/cyan_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/cyan_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/gray_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/gray_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/green_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/green_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/light_blue_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/light_blue_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/light_gray_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/light_gray_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/lime_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/lime_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/magenta_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/magenta_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/orange_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/orange_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/pink_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/pink_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/purple_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/purple_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/red_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/red_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/white_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/white_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/yellow_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/yellow_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bubble_column.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/chest.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/chest_double.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/ender.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/normal.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/normal_double.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/trapped.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/trapped_double.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/lava.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/acacia.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/birch.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/dark_oak.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/jungle.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/oak.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/spruce.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_acacia.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_birch.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_dark_oak.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_jungle.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_oak.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_spruce.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/water.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/bluemap/blockstates/missing.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/bluemap/models/block/missing.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/bluemap/textures/block/missing.png delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/biomes.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockColors.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockProperties.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/acacia_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/acacia_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/birch_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/birch_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/black_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/blue_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/brown_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/bubble_column.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/cyan_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/dark_oak_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/dark_oak_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/gray_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/green_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/jungle_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/jungle_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/lava.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/light_blue_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/light_gray_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/lime_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/magenta_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/oak_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/oak_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/orange_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/pink_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/purple_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/red_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/spruce_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/spruce_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/water.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/white_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/blockstates/yellow_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/bed_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/bed_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/black_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/black_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/blue_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/blue_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/brown_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/brown_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/cyan_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/cyan_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/gray_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/gray_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/green_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/green_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/light_blue_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/light_blue_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/light_gray_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/light_gray_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/lime_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/lime_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/magenta_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/magenta_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/orange_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/orange_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/pink_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/pink_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/purple_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/purple_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/red_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/red_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/white_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/white_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/yellow_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bed/yellow_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/bubble_column.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/chest/ender.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/chest/normal.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/chest/trapped.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/lava.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/sign/acacia.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/sign/birch.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/sign/dark_oak.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/sign/jungle.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/sign/oak.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/sign/sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/sign/spruce.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/sign/wall_acacia.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/sign/wall_birch.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/sign/wall_dark_oak.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/sign/wall_jungle.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/sign/wall_oak.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/sign/wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/sign/wall_spruce.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_15/assets/minecraft/models/block/water.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/bluemap/blockstates/missing.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/bluemap/models/block/missing.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/bluemap/textures/block/missing.png delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/biomes.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockColors.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockProperties.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/acacia_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/acacia_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/birch_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/birch_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/black_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/blue_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/brown_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/bubble_column.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/chest.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/crimson_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/cyan_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/dark_oak_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/dark_oak_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/ender_chest.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/gray_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/green_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/jungle_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/jungle_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/lava.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/light_blue_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/light_gray_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/lime_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/magenta_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/oak_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/oak_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/orange_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/pink_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/purple_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/red_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/spruce_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/spruce_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/trapped_chest.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/warped_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/water.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/white_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/yellow_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/bed_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/bed_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/black_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/black_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/blue_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/blue_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/brown_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/brown_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/cyan_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/cyan_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/gray_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/gray_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/green_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/green_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/light_blue_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/light_blue_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/light_gray_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/light_gray_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/lime_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/lime_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/magenta_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/magenta_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/orange_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/orange_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/pink_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/pink_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/purple_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/purple_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/red_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/red_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/white_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/white_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/yellow_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bed/yellow_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/bubble_column.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/chest/chest.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/chest/chest_double_left.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/chest/chest_double_right.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/chest/ender.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/chest/normal.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/chest/normal_double_left.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/chest/normal_double_right.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/chest/trapped.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/chest/trapped_double_left.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/chest/trapped_double_right.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/lava.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/sign/acacia.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/sign/birch.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/sign/crimson.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/sign/dark_oak.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/sign/jungle.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/sign/oak.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/sign/sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/sign/spruce.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/sign/wall_acacia.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/sign/wall_birch.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/sign/wall_crimson.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/sign/wall_dark_oak.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/sign/wall_jungle.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/sign/wall_oak.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/sign/wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/sign/wall_spruce.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/sign/wall_warped.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/sign/warped.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/models/block/water.json create mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_17/assets/minecraft/blockstates/grass_path.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/bluemap/blockstates/missing.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/bluemap/models/block/missing.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/bluemap/textures/block/missing.png delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/biomes.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockColors.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/acacia_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/acacia_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/birch_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/birch_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/black_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/blue_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/brown_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/bubble_column.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/chest.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/crimson_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/crimson_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/cyan_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/dark_oak_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/dark_oak_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/ender_chest.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/gray_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/green_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/jungle_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/jungle_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/lava.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/light_blue_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/light_gray_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/lime_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/magenta_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/oak_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/oak_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/orange_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/pink_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/purple_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/red_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/spruce_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/spruce_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/trapped_chest.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/warped_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/warped_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/water.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/white_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/yellow_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/bed_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/bed_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/black_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/black_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/blue_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/blue_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/brown_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/brown_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/cyan_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/cyan_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/gray_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/gray_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/green_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/green_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/light_blue_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/light_blue_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/light_gray_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/light_gray_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/lime_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/lime_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/magenta_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/magenta_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/orange_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/orange_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/pink_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/pink_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/purple_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/purple_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/red_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/red_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/white_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/white_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/yellow_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bed/yellow_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/bubble_column.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/chest/chest.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/chest/chest_double_left.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/chest/chest_double_right.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/chest/ender.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/chest/normal.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/chest/normal_double_left.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/chest/normal_double_right.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/chest/trapped.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/chest/trapped_double_left.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/chest/trapped_double_right.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/lava.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/sign/acacia.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/sign/birch.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/sign/crimson.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/sign/dark_oak.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/sign/jungle.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/sign/mangrove.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/sign/oak.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/sign/sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/sign/spruce.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/sign/wall_acacia.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/sign/wall_birch.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/sign/wall_crimson.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/sign/wall_dark_oak.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/sign/wall_jungle.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/sign/wall_mangrove.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/sign/wall_oak.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/sign/wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/sign/wall_spruce.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/sign/wall_warped.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/sign/warped.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/models/block/water.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/bluemap/blockstates/missing.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/bluemap/models/block/missing.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/bluemap/textures/block/missing.png delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/biomes.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockColors.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockProperties.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/acacia_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/acacia_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/acacia_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/acacia_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/bamboo_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/bamboo_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/birch_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/birch_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/birch_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/birch_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/black_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/black_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/black_shulker_box.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/black_wall_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/blue_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/blue_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/blue_shulker_box.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/blue_wall_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/brown_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/brown_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/brown_shulker_box.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/brown_wall_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/bubble_column.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cherry_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cherry_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/chest.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/creeper_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/creeper_wall_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/crimson_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/crimson_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/crimson_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/crimson_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cyan_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cyan_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cyan_shulker_box.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/cyan_wall_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dark_oak_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dark_oak_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dark_oak_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dark_oak_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/decorated_pot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dragon_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/dragon_wall_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/ender_chest.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/gray_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/gray_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/gray_shulker_box.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/gray_wall_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/green_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/green_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/green_shulker_box.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/green_wall_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/jungle_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/jungle_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/jungle_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/jungle_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/lava.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_blue_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_blue_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_blue_shulker_box.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_blue_wall_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_gray_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_gray_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_gray_shulker_box.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/light_gray_wall_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/lime_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/lime_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/lime_shulker_box.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/lime_wall_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/magenta_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/magenta_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/magenta_shulker_box.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/magenta_wall_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/mangrove_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/mangrove_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/mangrove_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/mangrove_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/oak_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/oak_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/oak_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/oak_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/orange_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/orange_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/orange_shulker_box.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/orange_wall_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/piglin_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/piglin_wall_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/pink_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/pink_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/pink_shulker_box.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/pink_wall_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/player_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/player_wall_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/purple_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/purple_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/purple_shulker_box.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/purple_wall_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/red_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/red_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/red_shulker_box.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/red_wall_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/shulker_box.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/skeleton_skull.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/skeleton_wall_skull.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/spruce_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/spruce_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/spruce_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/spruce_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/trapped_chest.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/warped_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/warped_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/warped_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/warped_wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/water.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/white_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/white_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/white_shulker_box.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/white_wall_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/wither_skeleton_skull.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/wither_skeleton_wall_skull.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/yellow_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/yellow_bed.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/yellow_shulker_box.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/yellow_wall_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/zombie_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/zombie_wall_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/bed_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/bed_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/black_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/black_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/blue_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/blue_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/brown_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/brown_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/cyan_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/cyan_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/gray_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/gray_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/green_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/green_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/light_blue_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/light_blue_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/light_gray_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/light_gray_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/lime_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/lime_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/magenta_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/magenta_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/orange_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/orange_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/pink_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/pink_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/purple_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/purple_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/red_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/red_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/white_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/white_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/yellow_foot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bed/yellow_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bell_between_walls.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bell_ceiling.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bell_floor.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bell_wall.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/bubble_column.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice1.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice2.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice3.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice4.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice5.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/cake_slice6.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/chest/chest.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/chest/chest_double_left.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/chest/chest_double_right.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/chest/ender.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/chest/normal.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/chest/normal_double_left.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/chest/normal_double_right.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/chest/trapped.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/chest/trapped_double_left.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/chest/trapped_double_right.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/lava.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/acacia.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/bamboo.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/birch.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/cherry.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/crimson.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/dark_oak.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/jungle.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/mangrove.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/oak.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/spruce.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/wall_acacia.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/wall_bamboo.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/wall_birch.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/wall_cherry.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/wall_crimson.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/wall_dark_oak.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/wall_jungle.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/wall_mangrove.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/wall_oak.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/wall_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/wall_spruce.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/wall_warped.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/sign/warped.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/block/water.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/acacia_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/acacia_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/bamboo_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/bamboo_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/birch_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/birch_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/cherry_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/cherry_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/creeper_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/creeper_wall_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/crimson_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/crimson_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dark_oak_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dark_oak_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/decorated_pot.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dragon_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dragon_wall_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/dyed_shulker_box.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/jungle_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/jungle_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/mangrove_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/mangrove_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/oak_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/oak_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/piglin_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/piglin_wall_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/player_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/player_wall_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/shulker_box.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/skeleton_skull.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/skeleton_wall_skull.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/skull_32.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/skull_64.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/spruce_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/spruce_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wall_banner.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wall_skull_32.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wall_skull_64.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/warped_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/warped_wall_hanging_sign.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wither_skeleton_skull.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/wither_skeleton_wall_skull.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/zombie_head.json delete mode 100644 BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/models/entity/zombie_wall_head.json create mode 100644 BlueMapCore/src/main/resourceExtensions/pack.mcmeta diff --git a/.gitignore b/.gitignore index 2fb7f3a9b..a211e5a76 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,7 @@ release.md # exclude generated resource BlueMapCommon/src/main/resources/de/bluecolored/bluemap/webapp.zip -BlueMapCore/src/main/resources/de/bluecolored/bluemap/*/resourceExtensions.zip +BlueMapCore/src/main/resources/de/bluecolored/bluemap/resourceExtensions.zip #exclude-test-data data/test-render diff --git a/BlueMapAPI b/BlueMapAPI index b200d339f..6c84500df 160000 --- a/BlueMapAPI +++ b/BlueMapAPI @@ -1 +1 @@ -Subproject commit b200d339f1a20c5d0def4e134237c756e6294c50 +Subproject commit 6c84500dfc560ec9588c89f71cc4a2d7edef2b2d diff --git a/BlueMapCommon/gradle/wrapper/gradle-wrapper.properties b/BlueMapCommon/gradle/wrapper/gradle-wrapper.properties index db9a6b825..48c0a02ca 100644 --- a/BlueMapCommon/gradle/wrapper/gradle-wrapper.properties +++ b/BlueMapCommon/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/BlueMapCore/build.gradle.kts b/BlueMapCore/build.gradle.kts index 1f5dca185..1d7587646 100644 --- a/BlueMapCore/build.gradle.kts +++ b/BlueMapCore/build.gradle.kts @@ -121,28 +121,11 @@ tasks.processResources { } } -//resource Extensions -val resourceIds: Array = arrayOf( - "1_13", "1_15", "1_16", "1_18", "1_20_3" -) - -tasks.register("zipResourceExtensions") { - resourceIds.forEach { - dependsOn("zipResourceExtensions$it") - } -} - -resourceIds.forEach { - zipResourcesTask(it) -} - -fun zipResourcesTask(resourceId: String) { - tasks.register ("zipResourceExtensions$resourceId", type = Zip::class) { - from(fileTree("src/main/resourceExtensions/mc$resourceId")) - archiveFileName.set("resourceExtensions.zip") - destinationDirectory.set(file("src/main/resources/de/bluecolored/bluemap/mc$resourceId/")) - outputs.upToDateWhen{ false } - } +tasks.register("zipResourceExtensions", type = Zip::class) { + from(fileTree("src/main/resourceExtensions")) + archiveFileName.set("resourceExtensions.zip") + destinationDirectory.set(file("src/main/resources/de/bluecolored/bluemap/")) + outputs.upToDateWhen{ false } } //always update the zip before build diff --git a/BlueMapCore/gradle/wrapper/gradle-wrapper.properties b/BlueMapCore/gradle/wrapper/gradle-wrapper.properties index db9a6b825..48c0a02ca 100644 --- a/BlueMapCore/gradle/wrapper/gradle-wrapper.properties +++ b/BlueMapCore/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/BlockColorCalculatorFactory.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/BlockColorCalculatorFactory.java index 9b8ebad92..913c08cdf 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/BlockColorCalculatorFactory.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/BlockColorCalculatorFactory.java @@ -28,7 +28,7 @@ import com.google.gson.stream.JsonReader; import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.util.math.Color; -import de.bluecolored.bluemap.core.world.Biome; +import de.bluecolored.bluemap.core.world.biome.Biome; import de.bluecolored.bluemap.core.world.block.Block; import de.bluecolored.bluemap.core.world.block.BlockNeighborhood; @@ -188,12 +188,10 @@ public Color getBlendedGrassColor(BlockNeighborhood block, Color target) { int x, y, z; - Biome biome; for (y = BLEND_MIN_Y; y <= BLEND_MAX_Y; y++) { for (x = BLEND_MIN_X; x <= BLEND_MAX_X; x++) { for (z = BLEND_MIN_Z; z <= BLEND_MAX_Z; z++) { - biome = block.getNeighborBlock(x, y, z).getBiome(); - target.add(getGrassColor(biome, tempColor)); + target.add(getGrassColor(block.getNeighborBlock(x, y, z), tempColor)); } } } @@ -201,9 +199,12 @@ public Color getBlendedGrassColor(BlockNeighborhood block, Color target) { return target.flatten(); } - public Color getGrassColor(Biome biome, Color target) { + public Color getGrassColor(Block block, Color target) { + Biome biome = block.getBiome(); getColorFromMap(biome, grassMap, 0xff52952f, target); - return target.overlay(biome.getOverlayGrassColor()); + target.overlay(biome.getOverlayGrassColor()); + biome.getGrassColorModifier().apply(block, target); + return target; } private void getColorFromMap(Biome biome, int[] colorMap, int defaultColor, Color target) { diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/MinecraftVersion.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/MinecraftVersion.java index 949ea09fd..2b2067ff1 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/MinecraftVersion.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/MinecraftVersion.java @@ -41,6 +41,7 @@ import java.io.OutputStream; import java.io.Reader; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.nio.file.*; import java.security.DigestInputStream; import java.security.MessageDigest; @@ -196,7 +197,7 @@ private static VersionInfo loadVersionInfo(Path file) throws IOException { Path versionFile = fsRoot.resolve("version.json"); if (!Files.exists(versionFile)) continue; - try (Reader reader = Files.newBufferedReader(file)) { + try (Reader reader = Files.newBufferedReader(versionFile, StandardCharsets.UTF_8)) { return GSON.fromJson(reader, VersionInfo.class); } } @@ -217,8 +218,8 @@ public static class VersionInfo { public static class VersionInfoAdapter extends AbstractTypeAdapterFactory { - public VersionInfoAdapter(Class type) { - super(type); + public VersionInfoAdapter() { + super(VersionInfo.class); } @Override diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/ResourcePath.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/ResourcePath.java index 877628b10..ef357ed9a 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/ResourcePath.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/ResourcePath.java @@ -54,8 +54,8 @@ public ResourcePath(String namespace, String value) { super(namespace.toLowerCase(Locale.ROOT), value.toLowerCase(Locale.ROOT)); } - public ResourcePath(Path filePath) { - super(parsePath(filePath).toLowerCase(Locale.ROOT)); + public ResourcePath(Path filePath, int namespacePos, int valuePos) { + super(parsePath(filePath, namespacePos, valuePos).toLowerCase(Locale.ROOT)); } @Nullable @@ -73,12 +73,12 @@ public void setResource(T resource) { this.resource = resource; } - private static String parsePath(Path filePath) { - if (filePath.getNameCount() < 4) - throw new IllegalArgumentException("The provided filePath has less than 4 segments!"); + private static String parsePath(Path filePath, int namespacePos, int valuePos) { + if (filePath.getNameCount() <= valuePos) + throw new IllegalArgumentException("The provided filePath has not enough segments!"); - String namespace = filePath.getName(1).toString(); - String path = filePath.subpath(3, filePath.getNameCount()).toString().replace(filePath.getFileSystem().getSeparator(), "/"); + String namespace = filePath.getName(namespacePos).toString(); + String path = filePath.subpath(valuePos, filePath.getNameCount()).toString().replace(filePath.getFileSystem().getSeparator(), "/"); // remove file-ending int dotIndex = path.lastIndexOf('.'); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/VersionManifest.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/VersionManifest.java index a398264fe..2c7adc7e7 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/VersionManifest.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/VersionManifest.java @@ -10,6 +10,7 @@ import java.io.*; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.util.Arrays; import java.util.Comparator; @@ -47,7 +48,7 @@ public static VersionManifest getOrFetch() throws IOException { public static VersionManifest fetch() throws IOException { try ( InputStream in = new URL(MANIFEST_URL).openStream(); - Reader reader = new BufferedReader(new InputStreamReader(in)) + Reader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)) ) { instance = GSON.fromJson(reader, VersionManifest.class); } @@ -94,7 +95,7 @@ public synchronized VersionDetail fetchDetail() throws IOException { if (detail == null) { try ( InputStream in = new URL(url).openStream(); - Reader reader = new BufferedReader(new InputStreamReader(in)) + Reader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)) ) { detail = GSON.fromJson(reader, VersionDetail.class); } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/RegistryAdapter.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/RegistryAdapter.java new file mode 100644 index 000000000..fc0eb82c4 --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/RegistryAdapter.java @@ -0,0 +1,36 @@ +package de.bluecolored.bluemap.core.resources.adapter; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import de.bluecolored.bluemap.core.logger.Logger; +import de.bluecolored.bluemap.core.util.Key; +import de.bluecolored.bluemap.core.util.Keyed; +import de.bluecolored.bluemap.core.util.Registry; +import lombok.RequiredArgsConstructor; + +import java.io.IOException; + +@RequiredArgsConstructor +public class RegistryAdapter extends TypeAdapter { + + private final Registry registry; + private final String defaultNamespace; + private final T fallback; + + @Override + public T read(JsonReader in) throws IOException { + Key key = Key.parse(in.nextString(), defaultNamespace); + T value = registry.get(key); + if (value != null) return value; + + Logger.global.noFloodWarning("unknown-registry-key-" + key.getFormatted(), "Failed to find registry-entry for key: " + key); + return fallback; + } + + @Override + public void write(JsonWriter out, T value) throws IOException { + out.value(value.getKey().getFormatted()); + } + +} \ No newline at end of file diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/ResourcesGson.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/ResourcesGson.java index 9577390bf..212b3b1f7 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/ResourcesGson.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/ResourcesGson.java @@ -31,8 +31,10 @@ import com.google.gson.reflect.TypeToken; import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.Face; import de.bluecolored.bluemap.core.util.Direction; +import de.bluecolored.bluemap.core.util.Key; import de.bluecolored.bluemap.core.util.math.Axis; import de.bluecolored.bluemap.core.util.math.Color; +import de.bluecolored.bluemap.core.world.biome.GrassColorModifier; import java.util.EnumMap; @@ -56,7 +58,12 @@ public static GsonBuilder addAdapter(GsonBuilder builder) { .registerTypeAdapter( new TypeToken>(){}.getType(), new EnumMapInstanceCreator(Direction.class) - ); + ) + .registerTypeAdapter(GrassColorModifier.class, new RegistryAdapter<>( + GrassColorModifier.REGISTRY, + Key.MINECRAFT_NAMESPACE, + GrassColorModifier.NONE + )); } } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/Pack.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/Pack.java index f37b712f1..4e1006f26 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/Pack.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/Pack.java @@ -3,7 +3,6 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import de.bluecolored.bluemap.core.logger.Logger; -import de.bluecolored.bluemap.core.resources.PackMeta; import de.bluecolored.bluemap.core.resources.ResourcePath; import de.bluecolored.bluemap.core.resources.adapter.ResourcesGson; import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; @@ -80,9 +79,9 @@ protected void loadResourcePath(Path root, ResourcePack.PathLoader resourceLoade resourceLoader.load(root); } - protected void loadResource(Path root, Path file, Loader loader, Map, T> resultMap) { + protected void loadResource(Path root, Path file, int namespacePos, int valuePos, Loader loader, Map, T> resultMap) { try { - ResourcePath resourcePath = new ResourcePath<>(root.relativize(file)); + ResourcePath resourcePath = new ResourcePath<>(root.relativize(file), namespacePos, valuePos); if (resultMap.containsKey(resourcePath)) return; // don't load already present resources T resource = loader.load(resourcePath); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/PackMeta.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/PackMeta.java similarity index 92% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/PackMeta.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/PackMeta.java index 6af44dfd5..c7bb8afca 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/PackMeta.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/PackMeta.java @@ -1,10 +1,11 @@ -package de.bluecolored.bluemap.core.resources; +package de.bluecolored.bluemap.core.resources.pack; import com.google.gson.Gson; import com.google.gson.annotations.JsonAdapter; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; +import de.bluecolored.bluemap.core.resources.AbstractTypeAdapterFactory; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -50,8 +51,8 @@ public boolean includes(int version) { private static class Adapter extends AbstractTypeAdapterFactory { - public Adapter(Class type) { - super(type); + public Adapter() { + super(VersionRange.class); } @Override diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/DataPack.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/DataPack.java index 9653a17cd..238d84bb1 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/DataPack.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/DataPack.java @@ -30,7 +30,7 @@ import de.bluecolored.bluemap.core.resources.pack.datapack.biome.DatapackBiome; import de.bluecolored.bluemap.core.resources.pack.datapack.dimension.DimensionTypeData; import de.bluecolored.bluemap.core.util.Key; -import de.bluecolored.bluemap.core.world.Biome; +import de.bluecolored.bluemap.core.world.biome.Biome; import de.bluecolored.bluemap.core.world.DimensionType; import de.bluecolored.bluemap.core.world.mca.chunk.LegacyBiomes; import org.jetbrains.annotations.Nullable; @@ -88,7 +88,7 @@ private void loadPath(Path root) { .flatMap(DataPack::walk) .filter(path -> path.getFileName().toString().endsWith(".json")) .filter(Files::isRegularFile) - .forEach(file -> loadResource(root, file, key -> { + .forEach(file -> loadResource(root, file, 1, 3, key -> { try (BufferedReader reader = Files.newBufferedReader(file)) { return ResourcesGson.INSTANCE.fromJson(reader, DimensionTypeData.class); } @@ -100,7 +100,7 @@ private void loadPath(Path root) { .flatMap(DataPack::walk) .filter(path -> path.getFileName().toString().endsWith(".json")) .filter(Files::isRegularFile) - .forEach(file -> loadResource(root, file, key -> { + .forEach(file -> loadResource(root, file, 1, 4, key -> { try (BufferedReader reader = Files.newBufferedReader(file)) { return new DatapackBiome(key, ResourcesGson.INSTANCE.fromJson(reader, DatapackBiome.Data.class)); } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/biome/DatapackBiome.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/biome/DatapackBiome.java index 293530a88..3a3b1d613 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/biome/DatapackBiome.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/biome/DatapackBiome.java @@ -2,7 +2,8 @@ import de.bluecolored.bluemap.core.util.Key; import de.bluecolored.bluemap.core.util.math.Color; -import de.bluecolored.bluemap.core.world.Biome; +import de.bluecolored.bluemap.core.world.biome.Biome; +import de.bluecolored.bluemap.core.world.biome.GrassColorModifier; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -38,6 +39,11 @@ public Color getOverlayGrassColor() { return data.effects.grassColor; } + @Override + public GrassColorModifier getGrassColorModifier() { + return data.effects.grassColorModifier; + } + @SuppressWarnings("FieldMayBeFinal") @Getter public static class Data { @@ -55,6 +61,7 @@ public static class Effects { private Color waterColor = Biome.DEFAULT.getWaterColor(); private Color foliageColor = Biome.DEFAULT.getOverlayFoliageColor(); private Color grassColor = Biome.DEFAULT.getOverlayGrassColor(); + private GrassColorModifier grassColorModifier = Biome.DEFAULT.getGrassColorModifier(); } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/ResourcePack.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/ResourcePack.java index d1eff6793..b85d111cd 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/ResourcePack.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/ResourcePack.java @@ -134,7 +134,7 @@ private void loadResources(Path root) throws IOException { .flatMap(ResourcePack::walk) .filter(path -> path.getFileName().toString().endsWith(".json")) .filter(Files::isRegularFile) - .forEach(file -> loadResource(root, file, key -> { + .forEach(file -> loadResource(root, file, 1, 3, key -> { try (BufferedReader reader = Files.newBufferedReader(file)) { return ResourcesGson.INSTANCE.fromJson(reader, BlockState.class); } @@ -150,7 +150,7 @@ private void loadResources(Path root) throws IOException { .flatMap(ResourcePack::walk) .filter(path -> path.getFileName().toString().endsWith(".json")) .filter(Files::isRegularFile) - .forEach(file -> loadResource(root, file, key -> { + .forEach(file -> loadResource(root, file, 1, 3, key -> { try (BufferedReader reader = Files.newBufferedReader(file)) { return ResourcesGson.INSTANCE.fromJson(reader, BlockModel.class); } @@ -162,7 +162,7 @@ private void loadResources(Path root) throws IOException { walk(root.resolve("assets").resolve("minecraft").resolve("textures").resolve("colormap")) .filter(path -> path.getFileName().toString().endsWith(".png")) .filter(Files::isRegularFile) - .forEach(file -> loadResource(root, file, key -> { + .forEach(file -> loadResource(root, file, 1, 3, key -> { try (InputStream in = Files.newInputStream(file)) { return ImageIO.read(in); } @@ -226,7 +226,7 @@ private void loadTextures(Path root) throws IOException { .flatMap(ResourcePack::walk) .filter(path -> path.getFileName().toString().endsWith(".png")) .filter(Files::isRegularFile) - .forEach(file -> loadResource(root, file, key -> { + .forEach(file -> loadResource(root, file, 1, 3, key -> { if (!usedTextures.contains(key)) return null; // don't load unused textures // load image diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Key.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Key.java index cd8db23c4..24c377ad4 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Key.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Key.java @@ -81,11 +81,15 @@ public Key getKey() { @Override public boolean equals(Object o) { if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Key that = (Key) o; + if (!(o instanceof Key that)) return false; + if (!that.canEqual(this)) return false; return formatted == that.formatted; } + protected boolean canEqual(Object o) { + return o instanceof Key; + } + @Override public int hashCode() { return formatted.hashCode(); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/BlockState.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/BlockState.java index 3ea5e56c3..51164c8c6 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/BlockState.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/BlockState.java @@ -66,7 +66,6 @@ public BlockState(String value, Map properties) { this.hashed = false; this.hash = 0; - //this.properties = Collections.unmodifiableMap(new HashMap<>(properties)); // <- not doing this to reduce object-creation this.properties = properties; this.propertiesArray = properties.entrySet().stream() .map(e -> new Property(e.getKey(), e.getValue())) @@ -141,13 +140,17 @@ public int getRedstonePower() { @Override public boolean equals(Object obj) { if (this == obj) return true; - - if (!(obj instanceof BlockState)) return false; - BlockState b = (BlockState) obj; + if (!(obj instanceof BlockState b)) return false; + if (!b.canEqual(this)) return false; if (getFormatted() != b.getFormatted()) return false; return Arrays.equals(propertiesArray, b.propertiesArray); } + @Override + protected boolean canEqual(Object o) { + return o instanceof BlockState; + } + @Override public int hashCode() { if (!hashed){ diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/Chunk.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/Chunk.java index 7b5916eef..7cbe0b36c 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/Chunk.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/Chunk.java @@ -24,6 +24,7 @@ */ package de.bluecolored.bluemap.core.world; +import de.bluecolored.bluemap.core.world.biome.Biome; import de.bluecolored.bluemap.core.world.block.entity.BlockEntity; import org.jetbrains.annotations.Nullable; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/Biome.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/Biome.java similarity index 92% rename from BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/Biome.java rename to BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/Biome.java index e66d7b570..799028be3 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/Biome.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/Biome.java @@ -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.world; +package de.bluecolored.bluemap.core.world.biome; import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.util.Key; @@ -45,6 +45,8 @@ public interface Biome extends Keyed { Color getOverlayGrassColor(); + GrassColorModifier getGrassColorModifier(); + @Getter class Default implements Biome { @@ -54,6 +56,7 @@ class Default implements Biome { private final Color waterColor = new Color().set(4159204 | 0xFF000000).premultiplied(); private final Color overlayFoliageColor = new Color().premultiplied(); private final Color overlayGrassColor = new Color().premultiplied(); + private final GrassColorModifier grassColorModifier = GrassColorModifier.NONE; } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/ColorModifier.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/ColorModifier.java new file mode 100644 index 000000000..46b55dd03 --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/ColorModifier.java @@ -0,0 +1,10 @@ +package de.bluecolored.bluemap.core.world.biome; + +import de.bluecolored.bluemap.core.util.math.Color; +import de.bluecolored.bluemap.core.world.block.Block; + +public interface ColorModifier { + + void apply(Block block, Color color); + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/GrassColorModifier.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/GrassColorModifier.java new file mode 100644 index 000000000..f505b4ae3 --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/GrassColorModifier.java @@ -0,0 +1,48 @@ +package de.bluecolored.bluemap.core.world.biome; + +import de.bluecolored.bluemap.core.util.Key; +import de.bluecolored.bluemap.core.util.Keyed; +import de.bluecolored.bluemap.core.util.Registry; +import de.bluecolored.bluemap.core.util.math.Color; +import de.bluecolored.bluemap.core.world.block.Block; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +public interface GrassColorModifier extends Keyed, ColorModifier { + + GrassColorModifier NONE = new Impl(Key.minecraft("none"), (Block block, Color color) -> {}); + GrassColorModifier DARK_FOREST = new Impl(Key.minecraft("dark_forest"), (Block block, Color color) -> + color.set(((color.getInt() & 0xfefefe) + 0x28340a >> 1) | 0xff000000, true) + ); + GrassColorModifier SWAMP = new Impl(Key.minecraft("swamp"), (Block block, Color color) -> { + color.set(0xff6a7039, true); + + /* Vanilla code with noise: + double f = FOLIAGE_NOISE.sample(block.getX() * 0.0225, block.getZ() * 0.0225, false); + + if (f < -0.1) color.set(5011004) + else color.set(6975545); + */ + }); + + Registry REGISTRY = new Registry<>( + NONE, + DARK_FOREST, + SWAMP + ); + + @RequiredArgsConstructor + @Getter + class Impl implements GrassColorModifier { + + private final Key key; + private final ColorModifier modifier; + + @Override + public void apply(Block block, Color color) { + modifier.apply(block, color); + } + + } + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/Block.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/Block.java index f2eef512e..9347b4e37 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/Block.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/Block.java @@ -25,6 +25,7 @@ package de.bluecolored.bluemap.core.world.block; import de.bluecolored.bluemap.core.world.*; +import de.bluecolored.bluemap.core.world.biome.Biome; import de.bluecolored.bluemap.core.world.block.entity.BlockEntity; import org.jetbrains.annotations.Nullable; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_13.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_13.java index 1d2c96be8..976952276 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_13.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_13.java @@ -26,7 +26,7 @@ import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.util.Key; -import de.bluecolored.bluemap.core.world.Biome; +import de.bluecolored.bluemap.core.world.biome.Biome; import de.bluecolored.bluemap.core.world.BlockState; import de.bluecolored.bluemap.core.world.DimensionType; import de.bluecolored.bluemap.core.world.LightData; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_15.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_15.java index 0d1b4be7f..1018a0bbe 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_15.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_15.java @@ -24,7 +24,7 @@ */ package de.bluecolored.bluemap.core.world.mca.chunk; -import de.bluecolored.bluemap.core.world.Biome; +import de.bluecolored.bluemap.core.world.biome.Biome; import de.bluecolored.bluemap.core.world.mca.MCAWorld; public class Chunk_1_15 extends Chunk_1_13 { diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_16.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_16.java index f3918574a..6481d440d 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_16.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_16.java @@ -26,7 +26,7 @@ import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.util.Key; -import de.bluecolored.bluemap.core.world.Biome; +import de.bluecolored.bluemap.core.world.biome.Biome; import de.bluecolored.bluemap.core.world.BlockState; import de.bluecolored.bluemap.core.world.DimensionType; import de.bluecolored.bluemap.core.world.LightData; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_18.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_18.java index b80b195cf..91c035ce9 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_18.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_18.java @@ -26,7 +26,7 @@ import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.util.Key; -import de.bluecolored.bluemap.core.world.Biome; +import de.bluecolored.bluemap.core.world.biome.Biome; import de.bluecolored.bluemap.core.world.BlockState; import de.bluecolored.bluemap.core.world.DimensionType; import de.bluecolored.bluemap.core.world.LightData; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/LegacyBiomes.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/LegacyBiomes.java index b5df53546..b395bb24e 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/LegacyBiomes.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/LegacyBiomes.java @@ -26,7 +26,7 @@ import de.bluecolored.bluemap.core.resources.pack.datapack.DataPack; import de.bluecolored.bluemap.core.util.Key; -import de.bluecolored.bluemap.core.world.Biome; +import de.bluecolored.bluemap.core.world.biome.Biome; import org.jetbrains.annotations.Nullable; public class LegacyBiomes { diff --git a/BlueMapCore/src/main/resourceExtensions/assets/bluemap/blockstates/missing.json b/BlueMapCore/src/main/resourceExtensions/assets/bluemap/blockstates/missing.json new file mode 100644 index 000000000..55827a939 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/bluemap/blockstates/missing.json @@ -0,0 +1,5 @@ +{ + "variants": { + "": { "model": "bluemap:block/missing" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/bluemap/models/block/missing.json b/BlueMapCore/src/main/resourceExtensions/assets/bluemap/models/block/missing.json new file mode 100644 index 000000000..206494b39 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/bluemap/models/block/missing.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "bluemap:block/missing" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/bluemap/textures/block/missing.png b/BlueMapCore/src/main/resourceExtensions/assets/bluemap/textures/block/missing.png similarity index 100% rename from BlueMapCore/src/main/resourceExtensions/mc1_13/assets/bluemap/textures/block/missing.png rename to BlueMapCore/src/main/resourceExtensions/assets/bluemap/textures/block/missing.png diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockColors.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockColors.json new file mode 100644 index 000000000..76a76a78c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockColors.json @@ -0,0 +1,68 @@ +{ + "default": "@foliage", + "minecraft:water": "@water", + "minecraft:cauldron": "@water", + "minecraft:water_cauldron": "@water", + "minecraft:powder_snow_cauldron": "#ffffff", + "minecraft:lava_cauldron": "#ffffff", + "minecraft:grass_block": "@grass", + "minecraft:grass": "@grass", + "minecraft:short_grass": "@grass", + "minecraft:tall_grass": "@grass", + "minecraft:fern": "@grass", + "minecraft:large_fern": "@grass", + "minecraft:redstone_wire": "@redstone", + "minecraft:birch_leaves": 8431445, + "minecraft:spruce_leaves": 6396257, + "minecraft:stonecutter": "#ffffff", + "minecraft:snow": "#ffffff", + "minecraft:cherry_leaves": "#ffffff", + "minecraft:white_banner": "#f9fffe", + "minecraft:light_gray_banner": "#9d9d97", + "minecraft:gray_banner": "#474f52", + "minecraft:black_banner": "#1d1d21", + "minecraft:brown_banner": "#835432", + "minecraft:red_banner": "#b02e26", + "minecraft:orange_banner": "#f9801d", + "minecraft:yellow_banner": "#fed83d", + "minecraft:lime_banner": "#80c71f", + "minecraft:green_banner": "#5e7c16", + "minecraft:cyan_banner": "#169c9c", + "minecraft:light_blue_banner": "#3ab3da", + "minecraft:blue_banner": "#3c44aa", + "minecraft:purple_banner": "#8932b8", + "minecraft:magenta_banner": "#c74ebd", + "minecraft:pink_banner": "#f38baa", + "minecraft:white_wall_banner": "#f9fffe", + "minecraft:light_gray_wall_banner": "#9d9d97", + "minecraft:gray_wall_banner": "#474f52", + "minecraft:black_wall_banner": "#1d1d21", + "minecraft:brown_wall_banner": "#835432", + "minecraft:red_wall_banner": "#b02e26", + "minecraft:orange_wall_banner": "#f9801d", + "minecraft:yellow_wall_banner": "#fed83d", + "minecraft:lime_wall_banner": "#80c71f", + "minecraft:green_wall_banner": "#5e7c16", + "minecraft:cyan_wall_banner": "#169c9c", + "minecraft:light_blue_wall_banner": "#3ab3da", + "minecraft:blue_wall_banner": "#3c44aa", + "minecraft:purple_wall_banner": "#8932b8", + "minecraft:magenta_wall_banner": "#c74ebd", + "minecraft:pink_wall_banner": "#f38baa", + "minecraft:white_shulker_box": "#f9fffe", + "minecraft:light_gray_shulker_box": "#9d9d97", + "minecraft:gray_shulker_box": "#474f52", + "minecraft:black_shulker_box": "#1d1d21", + "minecraft:brown_shulker_box": "#835432", + "minecraft:red_shulker_box": "#b02e26", + "minecraft:orange_shulker_box": "#f9801d", + "minecraft:yellow_shulker_box": "#fed83d", + "minecraft:lime_shulker_box": "#80c71f", + "minecraft:green_shulker_box": "#5e7c16", + "minecraft:cyan_shulker_box": "#169c9c", + "minecraft:light_blue_shulker_box": "#3ab3da", + "minecraft:blue_shulker_box": "#3c44aa", + "minecraft:purple_shulker_box": "#8932b8", + "minecraft:magenta_shulker_box": "#c74ebd", + "minecraft:pink_shulker_box": "#f38baa" +} diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockProperties.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockProperties.json similarity index 100% rename from BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockProperties.json rename to BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockProperties.json diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/acacia_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/acacia_hanging_sign.json new file mode 100644 index 000000000..2531cfe80 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/acacia_hanging_sign.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/acacia_hanging_sign", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/acacia_hanging_sign", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/acacia_hanging_sign", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/acacia_hanging_sign", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/acacia_hanging_sign", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/acacia_hanging_sign", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/acacia_hanging_sign", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/acacia_hanging_sign", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/acacia_hanging_sign" }, + "rotation=9": { "model": "minecraft:entity/acacia_hanging_sign", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/acacia_hanging_sign", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/acacia_hanging_sign", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/acacia_hanging_sign", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/acacia_hanging_sign", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/acacia_hanging_sign", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/acacia_hanging_sign", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/acacia_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/acacia_sign.json new file mode 100644 index 000000000..b955118af --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/acacia_sign.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "block/sign/acacia" }, + "rotation=1": { "model": "block/sign/acacia", "y": 22.5 }, + "rotation=2": { "model": "block/sign/acacia", "y": 45 }, + "rotation=3": { "model": "block/sign/acacia", "y": 67.5 }, + "rotation=4": { "model": "block/sign/acacia", "y": 90 }, + "rotation=5": { "model": "block/sign/acacia", "y": 112.5 }, + "rotation=6": { "model": "block/sign/acacia", "y": 135 }, + "rotation=7": { "model": "block/sign/acacia", "y": 157.5 }, + "rotation=8": { "model": "block/sign/acacia", "y": 180 }, + "rotation=9": { "model": "block/sign/acacia", "y": 202.5 }, + "rotation=10": { "model": "block/sign/acacia", "y": 225 }, + "rotation=11": { "model": "block/sign/acacia", "y": 247.5 }, + "rotation=12": { "model": "block/sign/acacia", "y": 270 }, + "rotation=13": { "model": "block/sign/acacia", "y": 292.5 }, + "rotation=14": { "model": "block/sign/acacia", "y": 315 }, + "rotation=15": { "model": "block/sign/acacia", "y": 337.5 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/acacia_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/acacia_wall_hanging_sign.json new file mode 100644 index 000000000..04a2f7020 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/acacia_wall_hanging_sign.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/acacia_wall_hanging_sign", "y": 90 }, + "facing=south": { "model": "minecraft:entity/acacia_wall_hanging_sign", "y": 180 }, + "facing=west": { "model": "minecraft:entity/acacia_wall_hanging_sign", "y": 270 }, + "facing=north": { "model": "minecraft:entity/acacia_wall_hanging_sign" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/acacia_wall_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/acacia_wall_sign.json similarity index 100% rename from BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/acacia_wall_sign.json rename to BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/acacia_wall_sign.json diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/bamboo_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/bamboo_hanging_sign.json new file mode 100644 index 000000000..aa8587a3e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/bamboo_hanging_sign.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/bamboo_hanging_sign", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/bamboo_hanging_sign", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/bamboo_hanging_sign", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/bamboo_hanging_sign", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/bamboo_hanging_sign", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/bamboo_hanging_sign", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/bamboo_hanging_sign", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/bamboo_hanging_sign", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/bamboo_hanging_sign" }, + "rotation=9": { "model": "minecraft:entity/bamboo_hanging_sign", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/bamboo_hanging_sign", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/bamboo_hanging_sign", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/bamboo_hanging_sign", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/bamboo_hanging_sign", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/bamboo_hanging_sign", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/bamboo_hanging_sign", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/bamboo_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/bamboo_wall_hanging_sign.json new file mode 100644 index 000000000..2b267af71 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/bamboo_wall_hanging_sign.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/bamboo_wall_hanging_sign", "y": 90 }, + "facing=south": { "model": "minecraft:entity/bamboo_wall_hanging_sign", "y": 180 }, + "facing=west": { "model": "minecraft:entity/bamboo_wall_hanging_sign", "y": 270 }, + "facing=north": { "model": "minecraft:entity/bamboo_wall_hanging_sign" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/birch_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/birch_hanging_sign.json new file mode 100644 index 000000000..6858dfa05 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/birch_hanging_sign.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/birch_hanging_sign", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/birch_hanging_sign", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/birch_hanging_sign", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/birch_hanging_sign", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/birch_hanging_sign", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/birch_hanging_sign", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/birch_hanging_sign", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/birch_hanging_sign", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/birch_hanging_sign" }, + "rotation=9": { "model": "minecraft:entity/birch_hanging_sign", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/birch_hanging_sign", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/birch_hanging_sign", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/birch_hanging_sign", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/birch_hanging_sign", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/birch_hanging_sign", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/birch_hanging_sign", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/birch_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/birch_sign.json new file mode 100644 index 000000000..996e831bf --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/birch_sign.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "block/sign/birch" }, + "rotation=1": { "model": "block/sign/birch", "y": 22.5 }, + "rotation=2": { "model": "block/sign/birch", "y": 45 }, + "rotation=3": { "model": "block/sign/birch", "y": 67.5 }, + "rotation=4": { "model": "block/sign/birch", "y": 90 }, + "rotation=5": { "model": "block/sign/birch", "y": 112.5 }, + "rotation=6": { "model": "block/sign/birch", "y": 135 }, + "rotation=7": { "model": "block/sign/birch", "y": 157.5 }, + "rotation=8": { "model": "block/sign/birch", "y": 180 }, + "rotation=9": { "model": "block/sign/birch", "y": 202.5 }, + "rotation=10": { "model": "block/sign/birch", "y": 225 }, + "rotation=11": { "model": "block/sign/birch", "y": 247.5 }, + "rotation=12": { "model": "block/sign/birch", "y": 270 }, + "rotation=13": { "model": "block/sign/birch", "y": 292.5 }, + "rotation=14": { "model": "block/sign/birch", "y": 315 }, + "rotation=15": { "model": "block/sign/birch", "y": 337.5 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/birch_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/birch_wall_hanging_sign.json new file mode 100644 index 000000000..9c860d087 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/birch_wall_hanging_sign.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/birch_wall_hanging_sign", "y": 90 }, + "facing=south": { "model": "minecraft:entity/birch_wall_hanging_sign", "y": 180 }, + "facing=west": { "model": "minecraft:entity/birch_wall_hanging_sign", "y": 270 }, + "facing=north": { "model": "minecraft:entity/birch_wall_hanging_sign" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/birch_wall_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/birch_wall_sign.json similarity index 100% rename from BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/birch_wall_sign.json rename to BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/birch_wall_sign.json diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/black_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/black_banner.json new file mode 100644 index 000000000..e68d0f33e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/black_banner.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/banner", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/banner", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/banner", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/banner", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/banner", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/banner", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/banner", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/banner", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/banner" }, + "rotation=9": { "model": "minecraft:entity/banner", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/banner", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/banner", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/banner", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/banner", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/banner", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/banner", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/black_bed.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/black_bed.json new file mode 100644 index 000000000..c1d14174b --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/black_bed.json @@ -0,0 +1,12 @@ +{ + "variants": { + "part=head,facing=north": { "model": "block/bed/black_head" }, + "part=head,facing=east": { "model": "block/bed/black_head", "y": 90 }, + "part=head,facing=south": { "model": "block/bed/black_head", "y": 180 }, + "part=head,facing=west": { "model": "block/bed/black_head", "y": 270 }, + "part=foot,facing=north": { "model": "block/bed/black_foot" }, + "part=foot,facing=east": { "model": "block/bed/black_foot", "y": 90 }, + "part=foot,facing=south": { "model": "block/bed/black_foot", "y": 180 }, + "part=foot,facing=west": { "model": "block/bed/black_foot", "y": 270 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/black_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/black_shulker_box.json new file mode 100644 index 000000000..0aaa93799 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/black_shulker_box.json @@ -0,0 +1,10 @@ +{ + "variants": { + "facing=up": { "model": "minecraft:entity/dyed_shulker_box" }, + "facing=down": { "model": "minecraft:entity/dyed_shulker_box", "x": 180 }, + "facing=north": { "model": "minecraft:entity/dyed_shulker_box", "x": 90 }, + "facing=east": { "model": "minecraft:entity/dyed_shulker_box", "y": 90, "x": 90 }, + "facing=south": { "model": "minecraft:entity/dyed_shulker_box", "y": 180, "x": 90 }, + "facing=west": { "model": "minecraft:entity/dyed_shulker_box", "y": 270, "x": 90 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/black_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/black_wall_banner.json new file mode 100644 index 000000000..72dc27179 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/black_wall_banner.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/wall_banner", "y": 90 }, + "facing=south": { "model": "minecraft:entity/wall_banner", "y": 180 }, + "facing=west": { "model": "minecraft:entity/wall_banner", "y": 270 }, + "facing=north": { "model": "minecraft:entity/wall_banner" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/blue_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/blue_banner.json new file mode 100644 index 000000000..e68d0f33e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/blue_banner.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/banner", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/banner", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/banner", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/banner", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/banner", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/banner", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/banner", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/banner", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/banner" }, + "rotation=9": { "model": "minecraft:entity/banner", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/banner", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/banner", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/banner", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/banner", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/banner", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/banner", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/blue_bed.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/blue_bed.json new file mode 100644 index 000000000..7ee41097e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/blue_bed.json @@ -0,0 +1,12 @@ +{ + "variants": { + "part=head,facing=north": { "model": "block/bed/blue_head" }, + "part=head,facing=east": { "model": "block/bed/blue_head", "y": 90 }, + "part=head,facing=south": { "model": "block/bed/blue_head", "y": 180 }, + "part=head,facing=west": { "model": "block/bed/blue_head", "y": 270 }, + "part=foot,facing=north": { "model": "block/bed/blue_foot" }, + "part=foot,facing=east": { "model": "block/bed/blue_foot", "y": 90 }, + "part=foot,facing=south": { "model": "block/bed/blue_foot", "y": 180 }, + "part=foot,facing=west": { "model": "block/bed/blue_foot", "y": 270 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/blue_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/blue_shulker_box.json new file mode 100644 index 000000000..0aaa93799 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/blue_shulker_box.json @@ -0,0 +1,10 @@ +{ + "variants": { + "facing=up": { "model": "minecraft:entity/dyed_shulker_box" }, + "facing=down": { "model": "minecraft:entity/dyed_shulker_box", "x": 180 }, + "facing=north": { "model": "minecraft:entity/dyed_shulker_box", "x": 90 }, + "facing=east": { "model": "minecraft:entity/dyed_shulker_box", "y": 90, "x": 90 }, + "facing=south": { "model": "minecraft:entity/dyed_shulker_box", "y": 180, "x": 90 }, + "facing=west": { "model": "minecraft:entity/dyed_shulker_box", "y": 270, "x": 90 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/blue_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/blue_wall_banner.json new file mode 100644 index 000000000..72dc27179 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/blue_wall_banner.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/wall_banner", "y": 90 }, + "facing=south": { "model": "minecraft:entity/wall_banner", "y": 180 }, + "facing=west": { "model": "minecraft:entity/wall_banner", "y": 270 }, + "facing=north": { "model": "minecraft:entity/wall_banner" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/brown_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/brown_banner.json new file mode 100644 index 000000000..e68d0f33e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/brown_banner.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/banner", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/banner", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/banner", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/banner", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/banner", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/banner", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/banner", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/banner", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/banner" }, + "rotation=9": { "model": "minecraft:entity/banner", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/banner", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/banner", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/banner", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/banner", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/banner", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/banner", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/brown_bed.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/brown_bed.json new file mode 100644 index 000000000..b334dce17 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/brown_bed.json @@ -0,0 +1,12 @@ +{ + "variants": { + "part=head,facing=north": { "model": "block/bed/brown_head" }, + "part=head,facing=east": { "model": "block/bed/brown_head", "y": 90 }, + "part=head,facing=south": { "model": "block/bed/brown_head", "y": 180 }, + "part=head,facing=west": { "model": "block/bed/brown_head", "y": 270 }, + "part=foot,facing=north": { "model": "block/bed/brown_foot" }, + "part=foot,facing=east": { "model": "block/bed/brown_foot", "y": 90 }, + "part=foot,facing=south": { "model": "block/bed/brown_foot", "y": 180 }, + "part=foot,facing=west": { "model": "block/bed/brown_foot", "y": 270 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/brown_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/brown_shulker_box.json new file mode 100644 index 000000000..0aaa93799 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/brown_shulker_box.json @@ -0,0 +1,10 @@ +{ + "variants": { + "facing=up": { "model": "minecraft:entity/dyed_shulker_box" }, + "facing=down": { "model": "minecraft:entity/dyed_shulker_box", "x": 180 }, + "facing=north": { "model": "minecraft:entity/dyed_shulker_box", "x": 90 }, + "facing=east": { "model": "minecraft:entity/dyed_shulker_box", "y": 90, "x": 90 }, + "facing=south": { "model": "minecraft:entity/dyed_shulker_box", "y": 180, "x": 90 }, + "facing=west": { "model": "minecraft:entity/dyed_shulker_box", "y": 270, "x": 90 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/brown_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/brown_wall_banner.json new file mode 100644 index 000000000..72dc27179 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/brown_wall_banner.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/wall_banner", "y": 90 }, + "facing=south": { "model": "minecraft:entity/wall_banner", "y": 180 }, + "facing=west": { "model": "minecraft:entity/wall_banner", "y": 270 }, + "facing=north": { "model": "minecraft:entity/wall_banner" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/bubble_column.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/bubble_column.json new file mode 100644 index 000000000..a2a5f27ee --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/bubble_column.json @@ -0,0 +1,5 @@ +{ + "variants": { + "": { "model": "block/bubble_column" } + } +} diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cherry_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cherry_hanging_sign.json new file mode 100644 index 000000000..7ecf26273 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cherry_hanging_sign.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/cherry_hanging_sign", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/cherry_hanging_sign", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/cherry_hanging_sign", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/cherry_hanging_sign", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/cherry_hanging_sign", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/cherry_hanging_sign", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/cherry_hanging_sign", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/cherry_hanging_sign", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/cherry_hanging_sign" }, + "rotation=9": { "model": "minecraft:entity/cherry_hanging_sign", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/cherry_hanging_sign", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/cherry_hanging_sign", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/cherry_hanging_sign", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/cherry_hanging_sign", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/cherry_hanging_sign", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/cherry_hanging_sign", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cherry_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cherry_wall_hanging_sign.json new file mode 100644 index 000000000..60bb9be75 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cherry_wall_hanging_sign.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/cherry_wall_hanging_sign", "y": 90 }, + "facing=south": { "model": "minecraft:entity/cherry_wall_hanging_sign", "y": 180 }, + "facing=west": { "model": "minecraft:entity/cherry_wall_hanging_sign", "y": 270 }, + "facing=north": { "model": "minecraft:entity/cherry_wall_hanging_sign" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/chest.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/chest.json new file mode 100644 index 000000000..765228487 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/chest.json @@ -0,0 +1,13 @@ +{ + "variants": { + "type=single,facing=north": { "model": "block/chest/normal", "y": 180 }, + "type=single,facing=east": { "model": "block/chest/normal", "y": 270 }, + "type=single,facing=south": { "model": "block/chest/normal" }, + "type=single,facing=west": { "model": "block/chest/normal", "y": 90 }, + "type=right,facing=north": { "model": "block/chest/normal_double", "y": 180 }, + "type=right,facing=east": { "model": "block/chest/normal_double", "y": 270 }, + "type=right,facing=south": { "model": "block/chest/normal_double" }, + "type=right,facing=west": { "model": "block/chest/normal_double", "y": 90 }, + "type=left": { "model": "block/chest/left" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/creeper_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/creeper_head.json new file mode 100644 index 000000000..364643532 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/creeper_head.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/creeper_head", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/creeper_head", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/creeper_head", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/creeper_head", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/creeper_head", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/creeper_head", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/creeper_head", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/creeper_head", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/creeper_head" }, + "rotation=9": { "model": "minecraft:entity/creeper_head", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/creeper_head", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/creeper_head", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/creeper_head", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/creeper_head", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/creeper_head", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/creeper_head", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/creeper_wall_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/creeper_wall_head.json new file mode 100644 index 000000000..d024217a1 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/creeper_wall_head.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/creeper_wall_head", "y": 90 }, + "facing=south": { "model": "minecraft:entity/creeper_wall_head", "y": 180 }, + "facing=west": { "model": "minecraft:entity/creeper_wall_head", "y": 270 }, + "facing=north": { "model": "minecraft:entity/creeper_wall_head" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/crimson_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/crimson_hanging_sign.json new file mode 100644 index 000000000..373cae39b --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/crimson_hanging_sign.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/crimson_hanging_sign", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/crimson_hanging_sign", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/crimson_hanging_sign", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/crimson_hanging_sign", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/crimson_hanging_sign", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/crimson_hanging_sign", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/crimson_hanging_sign", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/crimson_hanging_sign", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/crimson_hanging_sign" }, + "rotation=9": { "model": "minecraft:entity/crimson_hanging_sign", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/crimson_hanging_sign", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/crimson_hanging_sign", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/crimson_hanging_sign", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/crimson_hanging_sign", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/crimson_hanging_sign", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/crimson_hanging_sign", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/crimson_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/crimson_sign.json new file mode 100644 index 000000000..05ebd657f --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/crimson_sign.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "block/sign/crimson" }, + "rotation=1": { "model": "block/sign/crimson", "y": 22.5 }, + "rotation=2": { "model": "block/sign/crimson", "y": 45 }, + "rotation=3": { "model": "block/sign/crimson", "y": 67.5 }, + "rotation=4": { "model": "block/sign/crimson", "y": 90 }, + "rotation=5": { "model": "block/sign/crimson", "y": 112.5 }, + "rotation=6": { "model": "block/sign/crimson", "y": 135 }, + "rotation=7": { "model": "block/sign/crimson", "y": 157.5 }, + "rotation=8": { "model": "block/sign/crimson", "y": 180 }, + "rotation=9": { "model": "block/sign/crimson", "y": 202.5 }, + "rotation=10": { "model": "block/sign/crimson", "y": 225 }, + "rotation=11": { "model": "block/sign/crimson", "y": 247.5 }, + "rotation=12": { "model": "block/sign/crimson", "y": 270 }, + "rotation=13": { "model": "block/sign/crimson", "y": 292.5 }, + "rotation=14": { "model": "block/sign/crimson", "y": 315 }, + "rotation=15": { "model": "block/sign/crimson", "y": 337.5 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/crimson_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/crimson_wall_hanging_sign.json new file mode 100644 index 000000000..bb58a897b --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/crimson_wall_hanging_sign.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/crimson_wall_hanging_sign", "y": 90 }, + "facing=south": { "model": "minecraft:entity/crimson_wall_hanging_sign", "y": 180 }, + "facing=west": { "model": "minecraft:entity/crimson_wall_hanging_sign", "y": 270 }, + "facing=north": { "model": "minecraft:entity/crimson_wall_hanging_sign" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/crimson_wall_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/crimson_wall_sign.json similarity index 100% rename from BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/crimson_wall_sign.json rename to BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/crimson_wall_sign.json diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cyan_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cyan_banner.json new file mode 100644 index 000000000..e68d0f33e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cyan_banner.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/banner", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/banner", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/banner", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/banner", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/banner", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/banner", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/banner", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/banner", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/banner" }, + "rotation=9": { "model": "minecraft:entity/banner", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/banner", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/banner", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/banner", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/banner", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/banner", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/banner", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cyan_bed.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cyan_bed.json new file mode 100644 index 000000000..f14cb28a2 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cyan_bed.json @@ -0,0 +1,12 @@ +{ + "variants": { + "part=head,facing=north": { "model": "block/bed/cyan_head" }, + "part=head,facing=east": { "model": "block/bed/cyan_head", "y": 90 }, + "part=head,facing=south": { "model": "block/bed/cyan_head", "y": 180 }, + "part=head,facing=west": { "model": "block/bed/cyan_head", "y": 270 }, + "part=foot,facing=north": { "model": "block/bed/cyan_foot" }, + "part=foot,facing=east": { "model": "block/bed/cyan_foot", "y": 90 }, + "part=foot,facing=south": { "model": "block/bed/cyan_foot", "y": 180 }, + "part=foot,facing=west": { "model": "block/bed/cyan_foot", "y": 270 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cyan_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cyan_shulker_box.json new file mode 100644 index 000000000..0aaa93799 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cyan_shulker_box.json @@ -0,0 +1,10 @@ +{ + "variants": { + "facing=up": { "model": "minecraft:entity/dyed_shulker_box" }, + "facing=down": { "model": "minecraft:entity/dyed_shulker_box", "x": 180 }, + "facing=north": { "model": "minecraft:entity/dyed_shulker_box", "x": 90 }, + "facing=east": { "model": "minecraft:entity/dyed_shulker_box", "y": 90, "x": 90 }, + "facing=south": { "model": "minecraft:entity/dyed_shulker_box", "y": 180, "x": 90 }, + "facing=west": { "model": "minecraft:entity/dyed_shulker_box", "y": 270, "x": 90 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cyan_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cyan_wall_banner.json new file mode 100644 index 000000000..72dc27179 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/cyan_wall_banner.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/wall_banner", "y": 90 }, + "facing=south": { "model": "minecraft:entity/wall_banner", "y": 180 }, + "facing=west": { "model": "minecraft:entity/wall_banner", "y": 270 }, + "facing=north": { "model": "minecraft:entity/wall_banner" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dark_oak_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dark_oak_hanging_sign.json new file mode 100644 index 000000000..c7f4ef8d2 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dark_oak_hanging_sign.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/dark_oak_hanging_sign", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/dark_oak_hanging_sign", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/dark_oak_hanging_sign", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/dark_oak_hanging_sign", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/dark_oak_hanging_sign", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/dark_oak_hanging_sign", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/dark_oak_hanging_sign", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/dark_oak_hanging_sign", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/dark_oak_hanging_sign" }, + "rotation=9": { "model": "minecraft:entity/dark_oak_hanging_sign", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/dark_oak_hanging_sign", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/dark_oak_hanging_sign", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/dark_oak_hanging_sign", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/dark_oak_hanging_sign", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/dark_oak_hanging_sign", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/dark_oak_hanging_sign", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dark_oak_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dark_oak_sign.json new file mode 100644 index 000000000..ec59ec534 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dark_oak_sign.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "block/sign/dark_oak" }, + "rotation=1": { "model": "block/sign/dark_oak", "y": 22.5 }, + "rotation=2": { "model": "block/sign/dark_oak", "y": 45 }, + "rotation=3": { "model": "block/sign/dark_oak", "y": 67.5 }, + "rotation=4": { "model": "block/sign/dark_oak", "y": 90 }, + "rotation=5": { "model": "block/sign/dark_oak", "y": 112.5 }, + "rotation=6": { "model": "block/sign/dark_oak", "y": 135 }, + "rotation=7": { "model": "block/sign/dark_oak", "y": 157.5 }, + "rotation=8": { "model": "block/sign/dark_oak", "y": 180 }, + "rotation=9": { "model": "block/sign/dark_oak", "y": 202.5 }, + "rotation=10": { "model": "block/sign/dark_oak", "y": 225 }, + "rotation=11": { "model": "block/sign/dark_oak", "y": 247.5 }, + "rotation=12": { "model": "block/sign/dark_oak", "y": 270 }, + "rotation=13": { "model": "block/sign/dark_oak", "y": 292.5 }, + "rotation=14": { "model": "block/sign/dark_oak", "y": 315 }, + "rotation=15": { "model": "block/sign/dark_oak", "y": 337.5 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dark_oak_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dark_oak_wall_hanging_sign.json new file mode 100644 index 000000000..c8ad76dd8 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dark_oak_wall_hanging_sign.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/dark_oak_wall_hanging_sign", "y": 90 }, + "facing=south": { "model": "minecraft:entity/dark_oak_wall_hanging_sign", "y": 180 }, + "facing=west": { "model": "minecraft:entity/dark_oak_wall_hanging_sign", "y": 270 }, + "facing=north": { "model": "minecraft:entity/dark_oak_wall_hanging_sign" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/dark_oak_wall_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dark_oak_wall_sign.json similarity index 100% rename from BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/dark_oak_wall_sign.json rename to BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dark_oak_wall_sign.json diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/decorated_pot.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/decorated_pot.json new file mode 100644 index 000000000..43e77d879 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/decorated_pot.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/decorated_pot", "y": 90 }, + "facing=south": { "model": "minecraft:entity/decorated_pot", "y": 180 }, + "facing=west": { "model": "minecraft:entity/decorated_pot", "y": 270 }, + "facing=north": { "model": "minecraft:entity/decorated_pot" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dragon_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dragon_head.json new file mode 100644 index 000000000..3250ed9b1 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dragon_head.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/dragon_head", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/dragon_head", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/dragon_head", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/dragon_head", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/dragon_head", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/dragon_head", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/dragon_head", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/dragon_head", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/dragon_head" }, + "rotation=9": { "model": "minecraft:entity/dragon_head", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/dragon_head", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/dragon_head", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/dragon_head", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/dragon_head", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/dragon_head", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/dragon_head", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dragon_wall_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dragon_wall_head.json new file mode 100644 index 000000000..36213f49d --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/dragon_wall_head.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/dragon_wall_head", "y": 90 }, + "facing=south": { "model": "minecraft:entity/dragon_wall_head", "y": 180 }, + "facing=west": { "model": "minecraft:entity/dragon_wall_head", "y": 270 }, + "facing=north": { "model": "minecraft:entity/dragon_wall_head" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/ender_chest.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/ender_chest.json new file mode 100644 index 000000000..47542c67b --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/ender_chest.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=north": { "model": "block/chest/ender", "y": 180 }, + "facing=east": { "model": "block/chest/ender", "y": 270 }, + "facing=south": { "model": "block/chest/ender" }, + "facing=west": { "model": "block/chest/ender", "y": 90 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/gray_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/gray_banner.json new file mode 100644 index 000000000..e68d0f33e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/gray_banner.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/banner", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/banner", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/banner", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/banner", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/banner", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/banner", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/banner", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/banner", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/banner" }, + "rotation=9": { "model": "minecraft:entity/banner", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/banner", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/banner", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/banner", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/banner", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/banner", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/banner", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/gray_bed.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/gray_bed.json new file mode 100644 index 000000000..2c58888c0 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/gray_bed.json @@ -0,0 +1,12 @@ +{ + "variants": { + "part=head,facing=north": { "model": "block/bed/gray_head" }, + "part=head,facing=east": { "model": "block/bed/gray_head", "y": 90 }, + "part=head,facing=south": { "model": "block/bed/gray_head", "y": 180 }, + "part=head,facing=west": { "model": "block/bed/gray_head", "y": 270 }, + "part=foot,facing=north": { "model": "block/bed/gray_foot" }, + "part=foot,facing=east": { "model": "block/bed/gray_foot", "y": 90 }, + "part=foot,facing=south": { "model": "block/bed/gray_foot", "y": 180 }, + "part=foot,facing=west": { "model": "block/bed/gray_foot", "y": 270 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/gray_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/gray_shulker_box.json new file mode 100644 index 000000000..0aaa93799 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/gray_shulker_box.json @@ -0,0 +1,10 @@ +{ + "variants": { + "facing=up": { "model": "minecraft:entity/dyed_shulker_box" }, + "facing=down": { "model": "minecraft:entity/dyed_shulker_box", "x": 180 }, + "facing=north": { "model": "minecraft:entity/dyed_shulker_box", "x": 90 }, + "facing=east": { "model": "minecraft:entity/dyed_shulker_box", "y": 90, "x": 90 }, + "facing=south": { "model": "minecraft:entity/dyed_shulker_box", "y": 180, "x": 90 }, + "facing=west": { "model": "minecraft:entity/dyed_shulker_box", "y": 270, "x": 90 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/gray_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/gray_wall_banner.json new file mode 100644 index 000000000..72dc27179 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/gray_wall_banner.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/wall_banner", "y": 90 }, + "facing=south": { "model": "minecraft:entity/wall_banner", "y": 180 }, + "facing=west": { "model": "minecraft:entity/wall_banner", "y": 270 }, + "facing=north": { "model": "minecraft:entity/wall_banner" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/green_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/green_banner.json new file mode 100644 index 000000000..e68d0f33e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/green_banner.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/banner", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/banner", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/banner", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/banner", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/banner", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/banner", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/banner", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/banner", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/banner" }, + "rotation=9": { "model": "minecraft:entity/banner", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/banner", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/banner", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/banner", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/banner", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/banner", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/banner", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/green_bed.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/green_bed.json new file mode 100644 index 000000000..af72506f5 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/green_bed.json @@ -0,0 +1,12 @@ +{ + "variants": { + "part=head,facing=north": { "model": "block/bed/green_head" }, + "part=head,facing=east": { "model": "block/bed/green_head", "y": 90 }, + "part=head,facing=south": { "model": "block/bed/green_head", "y": 180 }, + "part=head,facing=west": { "model": "block/bed/green_head", "y": 270 }, + "part=foot,facing=north": { "model": "block/bed/green_foot" }, + "part=foot,facing=east": { "model": "block/bed/green_foot", "y": 90 }, + "part=foot,facing=south": { "model": "block/bed/green_foot", "y": 180 }, + "part=foot,facing=west": { "model": "block/bed/green_foot", "y": 270 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/green_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/green_shulker_box.json new file mode 100644 index 000000000..0aaa93799 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/green_shulker_box.json @@ -0,0 +1,10 @@ +{ + "variants": { + "facing=up": { "model": "minecraft:entity/dyed_shulker_box" }, + "facing=down": { "model": "minecraft:entity/dyed_shulker_box", "x": 180 }, + "facing=north": { "model": "minecraft:entity/dyed_shulker_box", "x": 90 }, + "facing=east": { "model": "minecraft:entity/dyed_shulker_box", "y": 90, "x": 90 }, + "facing=south": { "model": "minecraft:entity/dyed_shulker_box", "y": 180, "x": 90 }, + "facing=west": { "model": "minecraft:entity/dyed_shulker_box", "y": 270, "x": 90 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/green_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/green_wall_banner.json new file mode 100644 index 000000000..72dc27179 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/green_wall_banner.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/wall_banner", "y": 90 }, + "facing=south": { "model": "minecraft:entity/wall_banner", "y": 180 }, + "facing=west": { "model": "minecraft:entity/wall_banner", "y": 270 }, + "facing=north": { "model": "minecraft:entity/wall_banner" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/jungle_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/jungle_hanging_sign.json new file mode 100644 index 000000000..72c301a00 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/jungle_hanging_sign.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/jungle_hanging_sign", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/jungle_hanging_sign", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/jungle_hanging_sign", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/jungle_hanging_sign", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/jungle_hanging_sign", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/jungle_hanging_sign", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/jungle_hanging_sign", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/jungle_hanging_sign", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/jungle_hanging_sign" }, + "rotation=9": { "model": "minecraft:entity/jungle_hanging_sign", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/jungle_hanging_sign", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/jungle_hanging_sign", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/jungle_hanging_sign", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/jungle_hanging_sign", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/jungle_hanging_sign", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/jungle_hanging_sign", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/jungle_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/jungle_sign.json new file mode 100644 index 000000000..82f954d67 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/jungle_sign.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "block/sign/jungle" }, + "rotation=1": { "model": "block/sign/jungle", "y": 22.5 }, + "rotation=2": { "model": "block/sign/jungle", "y": 45 }, + "rotation=3": { "model": "block/sign/jungle", "y": 67.5 }, + "rotation=4": { "model": "block/sign/jungle", "y": 90 }, + "rotation=5": { "model": "block/sign/jungle", "y": 112.5 }, + "rotation=6": { "model": "block/sign/jungle", "y": 135 }, + "rotation=7": { "model": "block/sign/jungle", "y": 157.5 }, + "rotation=8": { "model": "block/sign/jungle", "y": 180 }, + "rotation=9": { "model": "block/sign/jungle", "y": 202.5 }, + "rotation=10": { "model": "block/sign/jungle", "y": 225 }, + "rotation=11": { "model": "block/sign/jungle", "y": 247.5 }, + "rotation=12": { "model": "block/sign/jungle", "y": 270 }, + "rotation=13": { "model": "block/sign/jungle", "y": 292.5 }, + "rotation=14": { "model": "block/sign/jungle", "y": 315 }, + "rotation=15": { "model": "block/sign/jungle", "y": 337.5 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/jungle_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/jungle_wall_hanging_sign.json new file mode 100644 index 000000000..e6f4f6e8e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/jungle_wall_hanging_sign.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/jungle_wall_hanging_sign", "y": 90 }, + "facing=south": { "model": "minecraft:entity/jungle_wall_hanging_sign", "y": 180 }, + "facing=west": { "model": "minecraft:entity/jungle_wall_hanging_sign", "y": 270 }, + "facing=north": { "model": "minecraft:entity/jungle_wall_hanging_sign" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/jungle_wall_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/jungle_wall_sign.json similarity index 100% rename from BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/jungle_wall_sign.json rename to BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/jungle_wall_sign.json diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/lava.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/lava.json new file mode 100644 index 000000000..0ca283840 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/lava.json @@ -0,0 +1,5 @@ +{ + "variants": { + "": { "model": "block/lava" } + } +} diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_blue_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_blue_banner.json new file mode 100644 index 000000000..e68d0f33e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_blue_banner.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/banner", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/banner", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/banner", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/banner", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/banner", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/banner", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/banner", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/banner", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/banner" }, + "rotation=9": { "model": "minecraft:entity/banner", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/banner", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/banner", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/banner", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/banner", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/banner", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/banner", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/light_blue_bed.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_blue_bed.json similarity index 100% rename from BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/light_blue_bed.json rename to BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_blue_bed.json diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_blue_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_blue_shulker_box.json new file mode 100644 index 000000000..0aaa93799 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_blue_shulker_box.json @@ -0,0 +1,10 @@ +{ + "variants": { + "facing=up": { "model": "minecraft:entity/dyed_shulker_box" }, + "facing=down": { "model": "minecraft:entity/dyed_shulker_box", "x": 180 }, + "facing=north": { "model": "minecraft:entity/dyed_shulker_box", "x": 90 }, + "facing=east": { "model": "minecraft:entity/dyed_shulker_box", "y": 90, "x": 90 }, + "facing=south": { "model": "minecraft:entity/dyed_shulker_box", "y": 180, "x": 90 }, + "facing=west": { "model": "minecraft:entity/dyed_shulker_box", "y": 270, "x": 90 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_blue_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_blue_wall_banner.json new file mode 100644 index 000000000..72dc27179 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_blue_wall_banner.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/wall_banner", "y": 90 }, + "facing=south": { "model": "minecraft:entity/wall_banner", "y": 180 }, + "facing=west": { "model": "minecraft:entity/wall_banner", "y": 270 }, + "facing=north": { "model": "minecraft:entity/wall_banner" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_gray_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_gray_banner.json new file mode 100644 index 000000000..e68d0f33e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_gray_banner.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/banner", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/banner", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/banner", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/banner", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/banner", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/banner", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/banner", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/banner", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/banner" }, + "rotation=9": { "model": "minecraft:entity/banner", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/banner", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/banner", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/banner", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/banner", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/banner", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/banner", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/light_gray_bed.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_gray_bed.json similarity index 100% rename from BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/light_gray_bed.json rename to BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_gray_bed.json diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_gray_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_gray_shulker_box.json new file mode 100644 index 000000000..0aaa93799 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_gray_shulker_box.json @@ -0,0 +1,10 @@ +{ + "variants": { + "facing=up": { "model": "minecraft:entity/dyed_shulker_box" }, + "facing=down": { "model": "minecraft:entity/dyed_shulker_box", "x": 180 }, + "facing=north": { "model": "minecraft:entity/dyed_shulker_box", "x": 90 }, + "facing=east": { "model": "minecraft:entity/dyed_shulker_box", "y": 90, "x": 90 }, + "facing=south": { "model": "minecraft:entity/dyed_shulker_box", "y": 180, "x": 90 }, + "facing=west": { "model": "minecraft:entity/dyed_shulker_box", "y": 270, "x": 90 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_gray_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_gray_wall_banner.json new file mode 100644 index 000000000..72dc27179 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/light_gray_wall_banner.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/wall_banner", "y": 90 }, + "facing=south": { "model": "minecraft:entity/wall_banner", "y": 180 }, + "facing=west": { "model": "minecraft:entity/wall_banner", "y": 270 }, + "facing=north": { "model": "minecraft:entity/wall_banner" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/lime_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/lime_banner.json new file mode 100644 index 000000000..e68d0f33e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/lime_banner.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/banner", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/banner", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/banner", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/banner", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/banner", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/banner", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/banner", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/banner", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/banner" }, + "rotation=9": { "model": "minecraft:entity/banner", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/banner", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/banner", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/banner", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/banner", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/banner", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/banner", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/lime_bed.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/lime_bed.json new file mode 100644 index 000000000..c7f6c93cc --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/lime_bed.json @@ -0,0 +1,12 @@ +{ + "variants": { + "part=head,facing=north": { "model": "block/bed/lime_head" }, + "part=head,facing=east": { "model": "block/bed/lime_head", "y": 90 }, + "part=head,facing=south": { "model": "block/bed/lime_head", "y": 180 }, + "part=head,facing=west": { "model": "block/bed/lime_head", "y": 270 }, + "part=foot,facing=north": { "model": "block/bed/lime_foot" }, + "part=foot,facing=east": { "model": "block/bed/lime_foot", "y": 90 }, + "part=foot,facing=south": { "model": "block/bed/lime_foot", "y": 180 }, + "part=foot,facing=west": { "model": "block/bed/lime_foot", "y": 270 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/lime_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/lime_shulker_box.json new file mode 100644 index 000000000..0aaa93799 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/lime_shulker_box.json @@ -0,0 +1,10 @@ +{ + "variants": { + "facing=up": { "model": "minecraft:entity/dyed_shulker_box" }, + "facing=down": { "model": "minecraft:entity/dyed_shulker_box", "x": 180 }, + "facing=north": { "model": "minecraft:entity/dyed_shulker_box", "x": 90 }, + "facing=east": { "model": "minecraft:entity/dyed_shulker_box", "y": 90, "x": 90 }, + "facing=south": { "model": "minecraft:entity/dyed_shulker_box", "y": 180, "x": 90 }, + "facing=west": { "model": "minecraft:entity/dyed_shulker_box", "y": 270, "x": 90 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/lime_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/lime_wall_banner.json new file mode 100644 index 000000000..72dc27179 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/lime_wall_banner.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/wall_banner", "y": 90 }, + "facing=south": { "model": "minecraft:entity/wall_banner", "y": 180 }, + "facing=west": { "model": "minecraft:entity/wall_banner", "y": 270 }, + "facing=north": { "model": "minecraft:entity/wall_banner" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/magenta_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/magenta_banner.json new file mode 100644 index 000000000..e68d0f33e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/magenta_banner.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/banner", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/banner", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/banner", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/banner", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/banner", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/banner", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/banner", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/banner", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/banner" }, + "rotation=9": { "model": "minecraft:entity/banner", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/banner", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/banner", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/banner", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/banner", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/banner", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/banner", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/magenta_bed.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/magenta_bed.json new file mode 100644 index 000000000..6feff92b7 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/magenta_bed.json @@ -0,0 +1,12 @@ +{ + "variants": { + "part=head,facing=north": { "model": "block/bed/magenta_head" }, + "part=head,facing=east": { "model": "block/bed/magenta_head", "y": 90 }, + "part=head,facing=south": { "model": "block/bed/magenta_head", "y": 180 }, + "part=head,facing=west": { "model": "block/bed/magenta_head", "y": 270 }, + "part=foot,facing=north": { "model": "block/bed/magenta_foot" }, + "part=foot,facing=east": { "model": "block/bed/magenta_foot", "y": 90 }, + "part=foot,facing=south": { "model": "block/bed/magenta_foot", "y": 180 }, + "part=foot,facing=west": { "model": "block/bed/magenta_foot", "y": 270 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/magenta_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/magenta_shulker_box.json new file mode 100644 index 000000000..0aaa93799 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/magenta_shulker_box.json @@ -0,0 +1,10 @@ +{ + "variants": { + "facing=up": { "model": "minecraft:entity/dyed_shulker_box" }, + "facing=down": { "model": "minecraft:entity/dyed_shulker_box", "x": 180 }, + "facing=north": { "model": "minecraft:entity/dyed_shulker_box", "x": 90 }, + "facing=east": { "model": "minecraft:entity/dyed_shulker_box", "y": 90, "x": 90 }, + "facing=south": { "model": "minecraft:entity/dyed_shulker_box", "y": 180, "x": 90 }, + "facing=west": { "model": "minecraft:entity/dyed_shulker_box", "y": 270, "x": 90 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/magenta_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/magenta_wall_banner.json new file mode 100644 index 000000000..72dc27179 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/magenta_wall_banner.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/wall_banner", "y": 90 }, + "facing=south": { "model": "minecraft:entity/wall_banner", "y": 180 }, + "facing=west": { "model": "minecraft:entity/wall_banner", "y": 270 }, + "facing=north": { "model": "minecraft:entity/wall_banner" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/mangrove_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/mangrove_hanging_sign.json new file mode 100644 index 000000000..4af847834 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/mangrove_hanging_sign.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/mangrove_hanging_sign", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/mangrove_hanging_sign", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/mangrove_hanging_sign", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/mangrove_hanging_sign", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/mangrove_hanging_sign", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/mangrove_hanging_sign", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/mangrove_hanging_sign", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/mangrove_hanging_sign", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/mangrove_hanging_sign" }, + "rotation=9": { "model": "minecraft:entity/mangrove_hanging_sign", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/mangrove_hanging_sign", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/mangrove_hanging_sign", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/mangrove_hanging_sign", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/mangrove_hanging_sign", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/mangrove_hanging_sign", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/mangrove_hanging_sign", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/mangrove_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/mangrove_sign.json similarity index 100% rename from BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/mangrove_sign.json rename to BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/mangrove_sign.json diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/mangrove_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/mangrove_wall_hanging_sign.json new file mode 100644 index 000000000..059b6546c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/mangrove_wall_hanging_sign.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/mangrove_wall_hanging_sign", "y": 90 }, + "facing=south": { "model": "minecraft:entity/mangrove_wall_hanging_sign", "y": 180 }, + "facing=west": { "model": "minecraft:entity/mangrove_wall_hanging_sign", "y": 270 }, + "facing=north": { "model": "minecraft:entity/mangrove_wall_hanging_sign" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/mangrove_wall_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/mangrove_wall_sign.json similarity index 100% rename from BlueMapCore/src/main/resourceExtensions/mc1_18/assets/minecraft/blockstates/mangrove_wall_sign.json rename to BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/mangrove_wall_sign.json diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/oak_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/oak_hanging_sign.json new file mode 100644 index 000000000..e1dac7392 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/oak_hanging_sign.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/oak_hanging_sign", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/oak_hanging_sign", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/oak_hanging_sign", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/oak_hanging_sign", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/oak_hanging_sign", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/oak_hanging_sign", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/oak_hanging_sign", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/oak_hanging_sign", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/oak_hanging_sign" }, + "rotation=9": { "model": "minecraft:entity/oak_hanging_sign", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/oak_hanging_sign", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/oak_hanging_sign", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/oak_hanging_sign", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/oak_hanging_sign", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/oak_hanging_sign", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/oak_hanging_sign", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/oak_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/oak_sign.json new file mode 100644 index 000000000..c22f0ca7c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/oak_sign.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "block/sign/oak" }, + "rotation=1": { "model": "block/sign/oak", "y": 22.5 }, + "rotation=2": { "model": "block/sign/oak", "y": 45 }, + "rotation=3": { "model": "block/sign/oak", "y": 67.5 }, + "rotation=4": { "model": "block/sign/oak", "y": 90 }, + "rotation=5": { "model": "block/sign/oak", "y": 112.5 }, + "rotation=6": { "model": "block/sign/oak", "y": 135 }, + "rotation=7": { "model": "block/sign/oak", "y": 157.5 }, + "rotation=8": { "model": "block/sign/oak", "y": 180 }, + "rotation=9": { "model": "block/sign/oak", "y": 202.5 }, + "rotation=10": { "model": "block/sign/oak", "y": 225 }, + "rotation=11": { "model": "block/sign/oak", "y": 247.5 }, + "rotation=12": { "model": "block/sign/oak", "y": 270 }, + "rotation=13": { "model": "block/sign/oak", "y": 292.5 }, + "rotation=14": { "model": "block/sign/oak", "y": 315 }, + "rotation=15": { "model": "block/sign/oak", "y": 337.5 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/oak_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/oak_wall_hanging_sign.json new file mode 100644 index 000000000..900e40f8d --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/oak_wall_hanging_sign.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/oak_wall_hanging_sign", "y": 90 }, + "facing=south": { "model": "minecraft:entity/oak_wall_hanging_sign", "y": 180 }, + "facing=west": { "model": "minecraft:entity/oak_wall_hanging_sign", "y": 270 }, + "facing=north": { "model": "minecraft:entity/oak_wall_hanging_sign" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/oak_wall_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/oak_wall_sign.json similarity index 100% rename from BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/oak_wall_sign.json rename to BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/oak_wall_sign.json diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/orange_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/orange_banner.json new file mode 100644 index 000000000..e68d0f33e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/orange_banner.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/banner", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/banner", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/banner", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/banner", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/banner", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/banner", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/banner", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/banner", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/banner" }, + "rotation=9": { "model": "minecraft:entity/banner", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/banner", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/banner", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/banner", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/banner", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/banner", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/banner", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/orange_bed.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/orange_bed.json new file mode 100644 index 000000000..bc91bcfc3 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/orange_bed.json @@ -0,0 +1,12 @@ +{ + "variants": { + "part=head,facing=north": { "model": "block/bed/orange_head" }, + "part=head,facing=east": { "model": "block/bed/orange_head", "y": 90 }, + "part=head,facing=south": { "model": "block/bed/orange_head", "y": 180 }, + "part=head,facing=west": { "model": "block/bed/orange_head", "y": 270 }, + "part=foot,facing=north": { "model": "block/bed/orange_foot" }, + "part=foot,facing=east": { "model": "block/bed/orange_foot", "y": 90 }, + "part=foot,facing=south": { "model": "block/bed/orange_foot", "y": 180 }, + "part=foot,facing=west": { "model": "block/bed/orange_foot", "y": 270 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/orange_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/orange_shulker_box.json new file mode 100644 index 000000000..0aaa93799 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/orange_shulker_box.json @@ -0,0 +1,10 @@ +{ + "variants": { + "facing=up": { "model": "minecraft:entity/dyed_shulker_box" }, + "facing=down": { "model": "minecraft:entity/dyed_shulker_box", "x": 180 }, + "facing=north": { "model": "minecraft:entity/dyed_shulker_box", "x": 90 }, + "facing=east": { "model": "minecraft:entity/dyed_shulker_box", "y": 90, "x": 90 }, + "facing=south": { "model": "minecraft:entity/dyed_shulker_box", "y": 180, "x": 90 }, + "facing=west": { "model": "minecraft:entity/dyed_shulker_box", "y": 270, "x": 90 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/orange_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/orange_wall_banner.json new file mode 100644 index 000000000..72dc27179 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/orange_wall_banner.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/wall_banner", "y": 90 }, + "facing=south": { "model": "minecraft:entity/wall_banner", "y": 180 }, + "facing=west": { "model": "minecraft:entity/wall_banner", "y": 270 }, + "facing=north": { "model": "minecraft:entity/wall_banner" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/piglin_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/piglin_head.json new file mode 100644 index 000000000..29331f6cf --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/piglin_head.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/piglin_head", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/piglin_head", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/piglin_head", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/piglin_head", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/piglin_head", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/piglin_head", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/piglin_head", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/piglin_head", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/piglin_head" }, + "rotation=9": { "model": "minecraft:entity/piglin_head", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/piglin_head", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/piglin_head", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/piglin_head", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/piglin_head", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/piglin_head", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/piglin_head", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/piglin_wall_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/piglin_wall_head.json new file mode 100644 index 000000000..bbd759700 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/piglin_wall_head.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/piglin_wall_head", "y": 90 }, + "facing=south": { "model": "minecraft:entity/piglin_wall_head", "y": 180 }, + "facing=west": { "model": "minecraft:entity/piglin_wall_head", "y": 270 }, + "facing=north": { "model": "minecraft:entity/piglin_wall_head" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/pink_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/pink_banner.json new file mode 100644 index 000000000..e68d0f33e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/pink_banner.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/banner", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/banner", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/banner", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/banner", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/banner", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/banner", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/banner", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/banner", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/banner" }, + "rotation=9": { "model": "minecraft:entity/banner", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/banner", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/banner", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/banner", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/banner", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/banner", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/banner", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/pink_bed.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/pink_bed.json new file mode 100644 index 000000000..ecc701623 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/pink_bed.json @@ -0,0 +1,12 @@ +{ + "variants": { + "part=head,facing=north": { "model": "block/bed/pink_head" }, + "part=head,facing=east": { "model": "block/bed/pink_head", "y": 90 }, + "part=head,facing=south": { "model": "block/bed/pink_head", "y": 180 }, + "part=head,facing=west": { "model": "block/bed/pink_head", "y": 270 }, + "part=foot,facing=north": { "model": "block/bed/pink_foot" }, + "part=foot,facing=east": { "model": "block/bed/pink_foot", "y": 90 }, + "part=foot,facing=south": { "model": "block/bed/pink_foot", "y": 180 }, + "part=foot,facing=west": { "model": "block/bed/pink_foot", "y": 270 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/pink_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/pink_shulker_box.json new file mode 100644 index 000000000..0aaa93799 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/pink_shulker_box.json @@ -0,0 +1,10 @@ +{ + "variants": { + "facing=up": { "model": "minecraft:entity/dyed_shulker_box" }, + "facing=down": { "model": "minecraft:entity/dyed_shulker_box", "x": 180 }, + "facing=north": { "model": "minecraft:entity/dyed_shulker_box", "x": 90 }, + "facing=east": { "model": "minecraft:entity/dyed_shulker_box", "y": 90, "x": 90 }, + "facing=south": { "model": "minecraft:entity/dyed_shulker_box", "y": 180, "x": 90 }, + "facing=west": { "model": "minecraft:entity/dyed_shulker_box", "y": 270, "x": 90 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/pink_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/pink_wall_banner.json new file mode 100644 index 000000000..72dc27179 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/pink_wall_banner.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/wall_banner", "y": 90 }, + "facing=south": { "model": "minecraft:entity/wall_banner", "y": 180 }, + "facing=west": { "model": "minecraft:entity/wall_banner", "y": 270 }, + "facing=north": { "model": "minecraft:entity/wall_banner" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/player_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/player_head.json new file mode 100644 index 000000000..a6fbaf2e0 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/player_head.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/player_head", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/player_head", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/player_head", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/player_head", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/player_head", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/player_head", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/player_head", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/player_head", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/player_head" }, + "rotation=9": { "model": "minecraft:entity/player_head", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/player_head", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/player_head", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/player_head", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/player_head", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/player_head", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/player_head", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/player_wall_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/player_wall_head.json new file mode 100644 index 000000000..22c2396d6 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/player_wall_head.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/player_wall_head", "y": 90 }, + "facing=south": { "model": "minecraft:entity/player_wall_head", "y": 180 }, + "facing=west": { "model": "minecraft:entity/player_wall_head", "y": 270 }, + "facing=north": { "model": "minecraft:entity/player_wall_head" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/purple_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/purple_banner.json new file mode 100644 index 000000000..e68d0f33e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/purple_banner.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/banner", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/banner", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/banner", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/banner", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/banner", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/banner", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/banner", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/banner", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/banner" }, + "rotation=9": { "model": "minecraft:entity/banner", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/banner", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/banner", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/banner", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/banner", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/banner", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/banner", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/purple_bed.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/purple_bed.json new file mode 100644 index 000000000..0d728b5ab --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/purple_bed.json @@ -0,0 +1,12 @@ +{ + "variants": { + "part=head,facing=north": { "model": "block/bed/purple_head" }, + "part=head,facing=east": { "model": "block/bed/purple_head", "y": 90 }, + "part=head,facing=south": { "model": "block/bed/purple_head", "y": 180 }, + "part=head,facing=west": { "model": "block/bed/purple_head", "y": 270 }, + "part=foot,facing=north": { "model": "block/bed/purple_foot" }, + "part=foot,facing=east": { "model": "block/bed/purple_foot", "y": 90 }, + "part=foot,facing=south": { "model": "block/bed/purple_foot", "y": 180 }, + "part=foot,facing=west": { "model": "block/bed/purple_foot", "y": 270 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/purple_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/purple_shulker_box.json new file mode 100644 index 000000000..0aaa93799 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/purple_shulker_box.json @@ -0,0 +1,10 @@ +{ + "variants": { + "facing=up": { "model": "minecraft:entity/dyed_shulker_box" }, + "facing=down": { "model": "minecraft:entity/dyed_shulker_box", "x": 180 }, + "facing=north": { "model": "minecraft:entity/dyed_shulker_box", "x": 90 }, + "facing=east": { "model": "minecraft:entity/dyed_shulker_box", "y": 90, "x": 90 }, + "facing=south": { "model": "minecraft:entity/dyed_shulker_box", "y": 180, "x": 90 }, + "facing=west": { "model": "minecraft:entity/dyed_shulker_box", "y": 270, "x": 90 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/purple_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/purple_wall_banner.json new file mode 100644 index 000000000..72dc27179 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/purple_wall_banner.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/wall_banner", "y": 90 }, + "facing=south": { "model": "minecraft:entity/wall_banner", "y": 180 }, + "facing=west": { "model": "minecraft:entity/wall_banner", "y": 270 }, + "facing=north": { "model": "minecraft:entity/wall_banner" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/red_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/red_banner.json new file mode 100644 index 000000000..e68d0f33e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/red_banner.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/banner", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/banner", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/banner", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/banner", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/banner", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/banner", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/banner", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/banner", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/banner" }, + "rotation=9": { "model": "minecraft:entity/banner", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/banner", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/banner", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/banner", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/banner", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/banner", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/banner", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/red_bed.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/red_bed.json new file mode 100644 index 000000000..b68b410f1 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/red_bed.json @@ -0,0 +1,12 @@ +{ + "variants": { + "part=head,facing=north": { "model": "block/bed/red_head" }, + "part=head,facing=east": { "model": "block/bed/red_head", "y": 90 }, + "part=head,facing=south": { "model": "block/bed/red_head", "y": 180 }, + "part=head,facing=west": { "model": "block/bed/red_head", "y": 270 }, + "part=foot,facing=north": { "model": "block/bed/red_foot" }, + "part=foot,facing=east": { "model": "block/bed/red_foot", "y": 90 }, + "part=foot,facing=south": { "model": "block/bed/red_foot", "y": 180 }, + "part=foot,facing=west": { "model": "block/bed/red_foot", "y": 270 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/red_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/red_shulker_box.json new file mode 100644 index 000000000..0aaa93799 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/red_shulker_box.json @@ -0,0 +1,10 @@ +{ + "variants": { + "facing=up": { "model": "minecraft:entity/dyed_shulker_box" }, + "facing=down": { "model": "minecraft:entity/dyed_shulker_box", "x": 180 }, + "facing=north": { "model": "minecraft:entity/dyed_shulker_box", "x": 90 }, + "facing=east": { "model": "minecraft:entity/dyed_shulker_box", "y": 90, "x": 90 }, + "facing=south": { "model": "minecraft:entity/dyed_shulker_box", "y": 180, "x": 90 }, + "facing=west": { "model": "minecraft:entity/dyed_shulker_box", "y": 270, "x": 90 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/red_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/red_wall_banner.json new file mode 100644 index 000000000..72dc27179 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/red_wall_banner.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/wall_banner", "y": 90 }, + "facing=south": { "model": "minecraft:entity/wall_banner", "y": 180 }, + "facing=west": { "model": "minecraft:entity/wall_banner", "y": 270 }, + "facing=north": { "model": "minecraft:entity/wall_banner" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/shulker_box.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/shulker_box.json new file mode 100644 index 000000000..2f7530241 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/shulker_box.json @@ -0,0 +1,10 @@ +{ + "variants": { + "facing=up": { "model": "minecraft:entity/shulker_box" }, + "facing=down": { "model": "minecraft:entity/shulker_box", "x": 180 }, + "facing=north": { "model": "minecraft:entity/shulker_box", "x": 90 }, + "facing=east": { "model": "minecraft:entity/shulker_box", "y": 90, "x": 90 }, + "facing=south": { "model": "minecraft:entity/shulker_box", "y": 180, "x": 90 }, + "facing=west": { "model": "minecraft:entity/shulker_box", "y": 270, "x": 90 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/skeleton_skull.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/skeleton_skull.json new file mode 100644 index 000000000..11fe10fe8 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/skeleton_skull.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/skeleton_skull", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/skeleton_skull", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/skeleton_skull", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/skeleton_skull", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/skeleton_skull", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/skeleton_skull", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/skeleton_skull", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/skeleton_skull", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/skeleton_skull" }, + "rotation=9": { "model": "minecraft:entity/skeleton_skull", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/skeleton_skull", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/skeleton_skull", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/skeleton_skull", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/skeleton_skull", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/skeleton_skull", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/skeleton_skull", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/skeleton_wall_skull.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/skeleton_wall_skull.json new file mode 100644 index 000000000..b6de41b02 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/skeleton_wall_skull.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/skeleton_wall_skull", "y": 90 }, + "facing=south": { "model": "minecraft:entity/skeleton_wall_skull", "y": 180 }, + "facing=west": { "model": "minecraft:entity/skeleton_wall_skull", "y": 270 }, + "facing=north": { "model": "minecraft:entity/skeleton_wall_skull" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/spruce_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/spruce_hanging_sign.json new file mode 100644 index 000000000..f6790367a --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/spruce_hanging_sign.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/spruce_hanging_sign", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/spruce_hanging_sign", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/spruce_hanging_sign", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/spruce_hanging_sign", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/spruce_hanging_sign", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/spruce_hanging_sign", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/spruce_hanging_sign", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/spruce_hanging_sign", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/spruce_hanging_sign" }, + "rotation=9": { "model": "minecraft:entity/spruce_hanging_sign", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/spruce_hanging_sign", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/spruce_hanging_sign", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/spruce_hanging_sign", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/spruce_hanging_sign", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/spruce_hanging_sign", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/spruce_hanging_sign", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/spruce_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/spruce_sign.json new file mode 100644 index 000000000..a3b63484c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/spruce_sign.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "block/sign/spruce" }, + "rotation=1": { "model": "block/sign/spruce", "y": 22.5 }, + "rotation=2": { "model": "block/sign/spruce", "y": 45 }, + "rotation=3": { "model": "block/sign/spruce", "y": 67.5 }, + "rotation=4": { "model": "block/sign/spruce", "y": 90 }, + "rotation=5": { "model": "block/sign/spruce", "y": 112.5 }, + "rotation=6": { "model": "block/sign/spruce", "y": 135 }, + "rotation=7": { "model": "block/sign/spruce", "y": 157.5 }, + "rotation=8": { "model": "block/sign/spruce", "y": 180 }, + "rotation=9": { "model": "block/sign/spruce", "y": 202.5 }, + "rotation=10": { "model": "block/sign/spruce", "y": 225 }, + "rotation=11": { "model": "block/sign/spruce", "y": 247.5 }, + "rotation=12": { "model": "block/sign/spruce", "y": 270 }, + "rotation=13": { "model": "block/sign/spruce", "y": 292.5 }, + "rotation=14": { "model": "block/sign/spruce", "y": 315 }, + "rotation=15": { "model": "block/sign/spruce", "y": 337.5 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/spruce_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/spruce_wall_hanging_sign.json new file mode 100644 index 000000000..f9ebeb95b --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/spruce_wall_hanging_sign.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/spruce_wall_hanging_sign", "y": 90 }, + "facing=south": { "model": "minecraft:entity/spruce_wall_hanging_sign", "y": 180 }, + "facing=west": { "model": "minecraft:entity/spruce_wall_hanging_sign", "y": 270 }, + "facing=north": { "model": "minecraft:entity/spruce_wall_hanging_sign" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/spruce_wall_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/spruce_wall_sign.json similarity index 100% rename from BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/spruce_wall_sign.json rename to BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/spruce_wall_sign.json diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/trapped_chest.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/trapped_chest.json similarity index 100% rename from BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/trapped_chest.json rename to BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/trapped_chest.json diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/warped_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/warped_hanging_sign.json new file mode 100644 index 000000000..c48e7820f --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/warped_hanging_sign.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/warped_hanging_sign", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/warped_hanging_sign", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/warped_hanging_sign", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/warped_hanging_sign", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/warped_hanging_sign", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/warped_hanging_sign", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/warped_hanging_sign", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/warped_hanging_sign", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/warped_hanging_sign" }, + "rotation=9": { "model": "minecraft:entity/warped_hanging_sign", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/warped_hanging_sign", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/warped_hanging_sign", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/warped_hanging_sign", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/warped_hanging_sign", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/warped_hanging_sign", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/warped_hanging_sign", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/warped_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/warped_sign.json new file mode 100644 index 000000000..59eabf864 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/warped_sign.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "block/sign/warped" }, + "rotation=1": { "model": "block/sign/warped", "y": 22.5 }, + "rotation=2": { "model": "block/sign/warped", "y": 45 }, + "rotation=3": { "model": "block/sign/warped", "y": 67.5 }, + "rotation=4": { "model": "block/sign/warped", "y": 90 }, + "rotation=5": { "model": "block/sign/warped", "y": 112.5 }, + "rotation=6": { "model": "block/sign/warped", "y": 135 }, + "rotation=7": { "model": "block/sign/warped", "y": 157.5 }, + "rotation=8": { "model": "block/sign/warped", "y": 180 }, + "rotation=9": { "model": "block/sign/warped", "y": 202.5 }, + "rotation=10": { "model": "block/sign/warped", "y": 225 }, + "rotation=11": { "model": "block/sign/warped", "y": 247.5 }, + "rotation=12": { "model": "block/sign/warped", "y": 270 }, + "rotation=13": { "model": "block/sign/warped", "y": 292.5 }, + "rotation=14": { "model": "block/sign/warped", "y": 315 }, + "rotation=15": { "model": "block/sign/warped", "y": 337.5 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/warped_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/warped_wall_hanging_sign.json new file mode 100644 index 000000000..6f7e19c6c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/warped_wall_hanging_sign.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/warped_wall_hanging_sign", "y": 90 }, + "facing=south": { "model": "minecraft:entity/warped_wall_hanging_sign", "y": 180 }, + "facing=west": { "model": "minecraft:entity/warped_wall_hanging_sign", "y": 270 }, + "facing=north": { "model": "minecraft:entity/warped_wall_hanging_sign" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/warped_wall_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/warped_wall_sign.json similarity index 100% rename from BlueMapCore/src/main/resourceExtensions/mc1_16/assets/minecraft/blockstates/warped_wall_sign.json rename to BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/warped_wall_sign.json diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/water.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/water.json new file mode 100644 index 000000000..358729bf5 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/water.json @@ -0,0 +1,5 @@ +{ + "variants": { + "": { "model": "block/water" } + } +} diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/white_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/white_banner.json new file mode 100644 index 000000000..e68d0f33e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/white_banner.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/banner", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/banner", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/banner", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/banner", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/banner", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/banner", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/banner", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/banner", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/banner" }, + "rotation=9": { "model": "minecraft:entity/banner", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/banner", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/banner", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/banner", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/banner", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/banner", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/banner", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/white_bed.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/white_bed.json new file mode 100644 index 000000000..9f4fd61b7 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/white_bed.json @@ -0,0 +1,12 @@ +{ + "variants": { + "part=head,facing=north": { "model": "block/bed/white_head" }, + "part=head,facing=east": { "model": "block/bed/white_head", "y": 90 }, + "part=head,facing=south": { "model": "block/bed/white_head", "y": 180 }, + "part=head,facing=west": { "model": "block/bed/white_head", "y": 270 }, + "part=foot,facing=north": { "model": "block/bed/white_foot" }, + "part=foot,facing=east": { "model": "block/bed/white_foot", "y": 90 }, + "part=foot,facing=south": { "model": "block/bed/white_foot", "y": 180 }, + "part=foot,facing=west": { "model": "block/bed/white_foot", "y": 270 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/white_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/white_shulker_box.json new file mode 100644 index 000000000..0aaa93799 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/white_shulker_box.json @@ -0,0 +1,10 @@ +{ + "variants": { + "facing=up": { "model": "minecraft:entity/dyed_shulker_box" }, + "facing=down": { "model": "minecraft:entity/dyed_shulker_box", "x": 180 }, + "facing=north": { "model": "minecraft:entity/dyed_shulker_box", "x": 90 }, + "facing=east": { "model": "minecraft:entity/dyed_shulker_box", "y": 90, "x": 90 }, + "facing=south": { "model": "minecraft:entity/dyed_shulker_box", "y": 180, "x": 90 }, + "facing=west": { "model": "minecraft:entity/dyed_shulker_box", "y": 270, "x": 90 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/white_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/white_wall_banner.json new file mode 100644 index 000000000..72dc27179 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/white_wall_banner.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/wall_banner", "y": 90 }, + "facing=south": { "model": "minecraft:entity/wall_banner", "y": 180 }, + "facing=west": { "model": "minecraft:entity/wall_banner", "y": 270 }, + "facing=north": { "model": "minecraft:entity/wall_banner" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/wither_skeleton_skull.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/wither_skeleton_skull.json new file mode 100644 index 000000000..af32c0253 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/wither_skeleton_skull.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/wither_skeleton_skull", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/wither_skeleton_skull", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/wither_skeleton_skull", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/wither_skeleton_skull", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/wither_skeleton_skull", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/wither_skeleton_skull", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/wither_skeleton_skull", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/wither_skeleton_skull", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/wither_skeleton_skull" }, + "rotation=9": { "model": "minecraft:entity/wither_skeleton_skull", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/wither_skeleton_skull", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/wither_skeleton_skull", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/wither_skeleton_skull", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/wither_skeleton_skull", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/wither_skeleton_skull", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/wither_skeleton_skull", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/wither_skeleton_wall_skull.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/wither_skeleton_wall_skull.json new file mode 100644 index 000000000..72fe4cc30 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/wither_skeleton_wall_skull.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/wither_skeleton_wall_skull", "y": 90 }, + "facing=south": { "model": "minecraft:entity/wither_skeleton_wall_skull", "y": 180 }, + "facing=west": { "model": "minecraft:entity/wither_skeleton_wall_skull", "y": 270 }, + "facing=north": { "model": "minecraft:entity/wither_skeleton_wall_skull" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/yellow_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/yellow_banner.json new file mode 100644 index 000000000..e68d0f33e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/yellow_banner.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/banner", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/banner", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/banner", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/banner", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/banner", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/banner", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/banner", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/banner", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/banner" }, + "rotation=9": { "model": "minecraft:entity/banner", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/banner", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/banner", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/banner", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/banner", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/banner", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/banner", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/yellow_bed.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/yellow_bed.json new file mode 100644 index 000000000..60bf04cd8 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/yellow_bed.json @@ -0,0 +1,12 @@ +{ + "variants": { + "part=head,facing=north": { "model": "block/bed/yellow_head" }, + "part=head,facing=east": { "model": "block/bed/yellow_head", "y": 90 }, + "part=head,facing=south": { "model": "block/bed/yellow_head", "y": 180 }, + "part=head,facing=west": { "model": "block/bed/yellow_head", "y": 270 }, + "part=foot,facing=north": { "model": "block/bed/yellow_foot" }, + "part=foot,facing=east": { "model": "block/bed/yellow_foot", "y": 90 }, + "part=foot,facing=south": { "model": "block/bed/yellow_foot", "y": 180 }, + "part=foot,facing=west": { "model": "block/bed/yellow_foot", "y": 270 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/yellow_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/yellow_shulker_box.json new file mode 100644 index 000000000..0aaa93799 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/yellow_shulker_box.json @@ -0,0 +1,10 @@ +{ + "variants": { + "facing=up": { "model": "minecraft:entity/dyed_shulker_box" }, + "facing=down": { "model": "minecraft:entity/dyed_shulker_box", "x": 180 }, + "facing=north": { "model": "minecraft:entity/dyed_shulker_box", "x": 90 }, + "facing=east": { "model": "minecraft:entity/dyed_shulker_box", "y": 90, "x": 90 }, + "facing=south": { "model": "minecraft:entity/dyed_shulker_box", "y": 180, "x": 90 }, + "facing=west": { "model": "minecraft:entity/dyed_shulker_box", "y": 270, "x": 90 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/yellow_wall_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/yellow_wall_banner.json new file mode 100644 index 000000000..72dc27179 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/yellow_wall_banner.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/wall_banner", "y": 90 }, + "facing=south": { "model": "minecraft:entity/wall_banner", "y": 180 }, + "facing=west": { "model": "minecraft:entity/wall_banner", "y": 270 }, + "facing=north": { "model": "minecraft:entity/wall_banner" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/zombie_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/zombie_head.json new file mode 100644 index 000000000..5e88dff48 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/zombie_head.json @@ -0,0 +1,20 @@ +{ + "variants": { + "rotation=0": { "model": "minecraft:entity/zombie_head", "y": 180 }, + "rotation=1": { "model": "minecraft:entity/zombie_head", "y": 202 }, + "rotation=2": { "model": "minecraft:entity/zombie_head", "y": 225 }, + "rotation=3": { "model": "minecraft:entity/zombie_head", "y": 247 }, + "rotation=4": { "model": "minecraft:entity/zombie_head", "y": 270 }, + "rotation=5": { "model": "minecraft:entity/zombie_head", "y": 292 }, + "rotation=6": { "model": "minecraft:entity/zombie_head", "y": 315 }, + "rotation=7": { "model": "minecraft:entity/zombie_head", "y": 337 }, + "rotation=8": { "model": "minecraft:entity/zombie_head" }, + "rotation=9": { "model": "minecraft:entity/zombie_head", "y": 22 }, + "rotation=10": { "model": "minecraft:entity/zombie_head", "y": 45 }, + "rotation=11": { "model": "minecraft:entity/zombie_head", "y": 67 }, + "rotation=12": { "model": "minecraft:entity/zombie_head", "y": 90 }, + "rotation=13": { "model": "minecraft:entity/zombie_head", "y": 112 }, + "rotation=14": { "model": "minecraft:entity/zombie_head", "y": 135 }, + "rotation=15": { "model": "minecraft:entity/zombie_head", "y": 157 } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/zombie_wall_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/zombie_wall_head.json new file mode 100644 index 000000000..57e257219 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/blockstates/zombie_wall_head.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=east": { "model": "minecraft:entity/zombie_wall_head", "y": 90 }, + "facing=south": { "model": "minecraft:entity/zombie_wall_head", "y": 180 }, + "facing=west": { "model": "minecraft:entity/zombie_wall_head", "y": 270 }, + "facing=north": { "model": "minecraft:entity/zombie_wall_head" } + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/bed_foot.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/bed_foot.json new file mode 100644 index 000000000..c71088505 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/bed_foot.json @@ -0,0 +1,39 @@ +{ + "elements": [ + { + "from": [0, 0, 13], + "to": [3, 3, 16], + "faces": { + "north": { "uv": [14.75, 0.75, 15.5, 1.5], "texture": "#bed" }, + "east": { "uv": [14, 0.75, 14.75, 1.5], "texture": "#bed" }, + "south": { "uv": [13.25, 0.75, 14, 1.5], "texture": "#bed" }, + "west": { "uv": [12.5, 0.75, 13.25, 1.5], "texture": "#bed" }, + "up": { "uv": [13.25, 0, 14, 0.75], "texture": "#bed" }, + "down": { "uv": [14, 0, 14.75, 0.75], "texture": "#bed" } + } + }, + { + "from": [13, 0, 13], + "to": [16, 3, 16], + "faces": { + "north": { "uv": [14, 3.75, 14.75, 4.5], "texture": "#bed" }, + "east": { "uv": [13.25, 3.75, 14, 4.5], "texture": "#bed" }, + "south": { "uv": [12.5, 3.75, 13.25, 4.5], "texture": "#bed" }, + "west": { "uv": [14.75, 3.75, 15.5, 4.5], "texture": "#bed" }, + "up": { "uv": [13.25, 3, 14, 3.75], "texture": "#bed" }, + "down": { "uv": [14, 3, 14.75, 3.75], "texture": "#bed" } + } + }, + { + "from": [0, 3, 0], + "to": [16, 9, 16], + "faces": { + "east": { "uv": [5.5, 7, 7, 11], "rotation": 90, "texture": "#bed" }, + "south": { "uv": [5.5, 7, 9.5, 5.5], "texture": "#bed" }, + "west": { "uv": [0, 7, 1.5, 11], "rotation": 270, "texture": "#bed" }, + "up": { "uv": [1.5, 7, 5.5, 11], "texture": "#bed" }, + "down": { "uv": [7, 7, 11, 11], "rotation": 180, "texture": "#bed" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/bed_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/bed_head.json new file mode 100644 index 000000000..bc9fa5f6b --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/bed_head.json @@ -0,0 +1,39 @@ +{ + "elements": [ + { + "from": [0, 0, 0], + "to": [3, 3, 3], + "faces": { + "north": { "uv": [12.5, 2.25, 13.25, 3], "texture": "#bed" }, + "east": { "uv": [14.75, 2.25, 15.5, 3], "texture": "#bed" }, + "south": { "uv": [14, 2.25, 14.75, 3], "texture": "#bed" }, + "west": { "uv": [13.25, 2.25, 14, 3], "texture": "#bed" }, + "up": { "uv": [13.25, 1.5, 14, 2.25], "texture": "#bed" }, + "down": { "uv": [14, 1.5, 14.75, 2.25], "texture": "#bed" } + } + }, + { + "from": [13, 0, 0], + "to": [16, 3, 3], + "faces": { + "north": { "uv": [13.25, 5.25, 14, 6], "texture": "#bed" }, + "east": { "uv": [12.5, 5.25, 13.25, 6], "texture": "#bed" }, + "south": { "uv": [14.75, 5.25, 15.5, 6], "texture": "#bed" }, + "west": { "uv": [14, 5.25, 14.75, 6], "texture": "#bed" }, + "up": { "uv": [13.25, 4.5, 14, 5.25], "texture": "#bed" }, + "down": { "uv": [14, 4.5, 14.75, 5.25], "texture": "#bed" } + } + }, + { + "from": [0, 3, 0], + "to": [16, 9, 16], + "faces": { + "north": { "uv": [1.5, 1.5, 5.5, 0], "texture": "#bed" }, + "east": { "uv": [5.5, 1.5, 7, 5.5], "rotation": 90, "texture": "#bed" }, + "west": { "uv": [0, 1.5, 1.5, 5.5], "rotation": 270, "texture": "#bed" }, + "up": { "uv": [1.5, 1.5, 5.5, 5.5], "texture": "#bed" }, + "down": { "uv": [7, 1.5, 11, 5.5], "rotation": 180, "texture": "#bed" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/black_foot.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/black_foot.json new file mode 100644 index 000000000..0a80336fd --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/black_foot.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_foot", + "textures": { + "bed": "entity/bed/black" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/black_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/black_head.json new file mode 100644 index 000000000..f1c7582c4 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/black_head.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_head", + "textures": { + "bed": "entity/bed/black" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/blue_foot.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/blue_foot.json new file mode 100644 index 000000000..92e90490b --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/blue_foot.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_foot", + "textures": { + "bed": "entity/bed/blue" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/blue_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/blue_head.json new file mode 100644 index 000000000..f1b29785e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/blue_head.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_head", + "textures": { + "bed": "entity/bed/blue" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/brown_foot.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/brown_foot.json new file mode 100644 index 000000000..cd2e6bbe4 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/brown_foot.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_foot", + "textures": { + "bed": "entity/bed/brown" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/brown_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/brown_head.json new file mode 100644 index 000000000..16747568f --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/brown_head.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_head", + "textures": { + "bed": "entity/bed/brown" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/cyan_foot.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/cyan_foot.json new file mode 100644 index 000000000..10b724927 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/cyan_foot.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_foot", + "textures": { + "bed": "entity/bed/cyan" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/cyan_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/cyan_head.json new file mode 100644 index 000000000..85b8be1f8 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/cyan_head.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_head", + "textures": { + "bed": "entity/bed/cyan" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/gray_foot.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/gray_foot.json new file mode 100644 index 000000000..c927a5833 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/gray_foot.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_foot", + "textures": { + "bed": "entity/bed/gray" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/gray_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/gray_head.json new file mode 100644 index 000000000..8384cb16a --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/gray_head.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_head", + "textures": { + "bed": "entity/bed/gray" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/green_foot.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/green_foot.json new file mode 100644 index 000000000..45a4a74f7 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/green_foot.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_foot", + "textures": { + "bed": "entity/bed/green" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/green_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/green_head.json new file mode 100644 index 000000000..147d64099 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/green_head.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_head", + "textures": { + "bed": "entity/bed/green" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/light_blue_foot.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/light_blue_foot.json new file mode 100644 index 000000000..e43b31f58 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/light_blue_foot.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_foot", + "textures": { + "bed": "entity/bed/light_blue" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/light_blue_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/light_blue_head.json new file mode 100644 index 000000000..5e9d5ed16 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/light_blue_head.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_head", + "textures": { + "bed": "entity/bed/light_blue" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/light_gray_foot.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/light_gray_foot.json new file mode 100644 index 000000000..6edd85964 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/light_gray_foot.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_foot", + "textures": { + "bed": "entity/bed/light_gray" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/light_gray_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/light_gray_head.json new file mode 100644 index 000000000..56e77cca9 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/light_gray_head.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_head", + "textures": { + "bed": "entity/bed/light_gray" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/lime_foot.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/lime_foot.json new file mode 100644 index 000000000..d44c5b1c4 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/lime_foot.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_foot", + "textures": { + "bed": "entity/bed/lime" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/lime_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/lime_head.json new file mode 100644 index 000000000..5850e0723 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/lime_head.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_head", + "textures": { + "bed": "entity/bed/lime" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/magenta_foot.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/magenta_foot.json new file mode 100644 index 000000000..063a8aafe --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/magenta_foot.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_foot", + "textures": { + "bed": "entity/bed/magenta" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/magenta_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/magenta_head.json new file mode 100644 index 000000000..316bc1301 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/magenta_head.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_head", + "textures": { + "bed": "entity/bed/magenta" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/orange_foot.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/orange_foot.json new file mode 100644 index 000000000..13c29d09d --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/orange_foot.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_foot", + "textures": { + "bed": "entity/bed/orange" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/orange_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/orange_head.json new file mode 100644 index 000000000..ee1666165 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/orange_head.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_head", + "textures": { + "bed": "entity/bed/orange" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/pink_foot.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/pink_foot.json new file mode 100644 index 000000000..09e82671b --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/pink_foot.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_foot", + "textures": { + "bed": "entity/bed/pink" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/pink_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/pink_head.json new file mode 100644 index 000000000..de3edc7de --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/pink_head.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_head", + "textures": { + "bed": "entity/bed/pink" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/purple_foot.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/purple_foot.json new file mode 100644 index 000000000..347f76ec6 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/purple_foot.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_foot", + "textures": { + "bed": "entity/bed/purple" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/purple_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/purple_head.json new file mode 100644 index 000000000..c3b688350 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/purple_head.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_head", + "textures": { + "bed": "entity/bed/purple" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/red_foot.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/red_foot.json new file mode 100644 index 000000000..4e9397f1b --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/red_foot.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_foot", + "textures": { + "bed": "entity/bed/red" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/red_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/red_head.json new file mode 100644 index 000000000..9fc8b3411 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/red_head.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_head", + "textures": { + "bed": "entity/bed/red" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/white_foot.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/white_foot.json new file mode 100644 index 000000000..89f9d5122 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/white_foot.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_foot", + "textures": { + "bed": "entity/bed/white" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/white_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/white_head.json new file mode 100644 index 000000000..31c82e761 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/white_head.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_head", + "textures": { + "bed": "entity/bed/white" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/yellow_foot.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/yellow_foot.json new file mode 100644 index 000000000..dfec84f22 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/yellow_foot.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_foot", + "textures": { + "bed": "entity/bed/yellow" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/yellow_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/yellow_head.json new file mode 100644 index 000000000..a1692647e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bed/yellow_head.json @@ -0,0 +1,6 @@ +{ + "parent": "block/bed/bed_head", + "textures": { + "bed": "entity/bed/yellow" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bell_between_walls.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bell_between_walls.json new file mode 100644 index 000000000..915a01ce0 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bell_between_walls.json @@ -0,0 +1,49 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "2": "block/bell_bottom", + "3": "block/bell_side", + "4": "block/bell_top", + "bar": "block/dark_oak_planks" + }, + "elements": [ + { + "from": [0, 13, 7], + "to": [16, 15, 9], + "faces": { + "north": { "uv": [2, 2, 14, 4], "texture": "#bar" }, + "east": { "uv": [5, 4, 7, 6], "texture": "#bar", "cullface": "east" }, + "south": { "uv": [2, 3, 14, 5], "texture": "#bar" }, + "west": { "uv": [5, 4, 7, 6], "texture": "#bar", "cullface": "west" }, + "up": { "uv": [2, 3, 14, 5], "texture": "#bar" }, + "down": { "uv": [2, 3, 14, 5], "texture": "#bar" } + } + }, + { + "name": "BellBase", + "from": [4, 4, 4], + "to": [12, 6, 12], + "faces": { + "north": { "uv": [0, 7, 8, 9], "texture": "#3" }, + "east": { "uv": [0, 7, 8, 9], "texture": "#3" }, + "south": { "uv": [0, 7, 8, 9], "texture": "#3" }, + "west": { "uv": [0, 7, 8, 9], "texture": "#3" }, + "up": { "uv": [0, 0, 8, 8], "texture": "#4" }, + "down": { "uv": [0, 0, 8, 8], "texture": "#2" } + } + }, + { + "name": "BellTop", + "from": [5, 6, 5], + "to": [11, 13, 11], + "faces": { + "north": { "uv": [1, 0, 7, 7], "texture": "#3" }, + "east": { "uv": [1, 0, 7, 7], "texture": "#3" }, + "south": { "uv": [1, 0, 7, 7], "texture": "#3" }, + "west": { "uv": [1, 0, 7, 7], "texture": "#3" }, + "up": { "uv": [1, 1, 7, 7], "texture": "#4" }, + "down": { "uv": [8, 1, 9, 2], "texture": "#2" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bell_ceiling.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bell_ceiling.json new file mode 100644 index 000000000..7261b0fbb --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bell_ceiling.json @@ -0,0 +1,48 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "2": "block/bell_side", + "3": "block/bell_top", + "4": "block/bell_bottom", + "bar": "block/dark_oak_planks" + }, + "elements": [ + { + "from": [7, 13, 7], + "to": [9, 16, 9], + "faces": { + "north": { "uv": [7, 2, 9, 5], "texture": "#bar" }, + "east": { "uv": [1, 2, 3, 5], "texture": "#bar" }, + "south": { "uv": [6, 2, 8, 5], "texture": "#bar" }, + "west": { "uv": [4, 2, 6, 5], "texture": "#bar" }, + "up": { "uv": [1, 3, 3, 5], "texture": "#bar", "cullface": "up" } + } + }, + { + "name": "BellBase", + "from": [4, 4, 4], + "to": [12, 6, 12], + "faces": { + "north": { "uv": [0, 7, 8, 9], "texture": "#2" }, + "east": { "uv": [0, 7, 8, 9], "texture": "#2" }, + "south": { "uv": [0, 7, 8, 9], "texture": "#2" }, + "west": { "uv": [0, 7, 8, 9], "texture": "#2" }, + "up": { "uv": [0, 0, 8, 8], "texture": "#3" }, + "down": { "uv": [0, 0, 8, 8], "texture": "#4" } + } + }, + { + "name": "BellTop", + "from": [5, 6, 5], + "to": [11, 13, 11], + "faces": { + "north": { "uv": [1, 0, 7, 7], "texture": "#2" }, + "east": { "uv": [1, 0, 7, 7], "texture": "#2" }, + "south": { "uv": [1, 0, 7, 7], "texture": "#2" }, + "west": { "uv": [1, 0, 7, 7], "texture": "#2" }, + "up": { "uv": [1, 1, 7, 7], "texture": "#2" }, + "down": { "uv": [8, 1, 9, 2], "texture": "#4" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bell_floor.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bell_floor.json new file mode 100644 index 000000000..767e9b725 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bell_floor.json @@ -0,0 +1,75 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "3": "block/bell_top", + "4": "block/bell_bottom", + "5": "block/bell_side", + "bar": "block/dark_oak_planks", + "post": "block/stone" + }, + "elements": [ + { + "name": "Topbar", + "from": [2, 13, 7], + "to": [14, 15, 9], + "faces": { + "north": { "uv": [2, 2, 14, 4], "texture": "#bar" }, + "south": { "uv": [2, 3, 14, 5], "texture": "#bar" }, + "up": { "uv": [2, 3, 14, 5], "texture": "#bar" }, + "down": { "uv": [2, 3, 14, 5], "texture": "#bar" } + } + }, + { + "name": "Eastpost", + "from": [14, 0, 6], + "to": [16, 16, 10], + "faces": { + "north": { "uv": [0, 1, 2, 16], "texture": "#post" }, + "east": { "uv": [0, 1, 4, 16], "texture": "#post" }, + "south": { "uv": [0, 1, 2, 16], "texture": "#post" }, + "west": { "uv": [0, 1, 4, 16], "texture": "#post" }, + "up": { "uv": [0, 0, 2, 4], "texture": "#post", "cullface": "up" }, + "down": { "uv": [0, 0, 2, 4], "texture": "#post", "cullface": "down" } + } + }, + { + "name": "Westpost", + "from": [0, 0, 6], + "to": [2, 16, 10], + "faces": { + "north": { "uv": [0, 1, 2, 16], "texture": "#post" }, + "east": { "uv": [0, 1, 4, 16], "texture": "#post" }, + "south": { "uv": [0, 1, 2, 16], "texture": "#post" }, + "west": { "uv": [0, 1, 4, 16], "texture": "#post" }, + "up": { "uv": [0, 0, 2, 4], "texture": "#post", "cullface": "up" }, + "down": { "uv": [0, 0, 2, 4], "texture": "#post", "cullface": "down" } + } + }, + { + "name": "BellBase", + "from": [4, 4, 4], + "to": [12, 6, 12], + "faces": { + "north": { "uv": [0, 7, 8, 9], "texture": "#5" }, + "east": { "uv": [0, 7, 8, 9], "texture": "#5" }, + "south": { "uv": [0, 7, 8, 9], "texture": "#5" }, + "west": { "uv": [0, 7, 8, 9], "texture": "#5" }, + "up": { "uv": [0, 0, 8, 8], "texture": "#3" }, + "down": { "uv": [0, 0, 8, 8], "texture": "#4" } + } + }, + { + "name": "BellTop", + "from": [5, 6, 5], + "to": [11, 13, 11], + "faces": { + "north": { "uv": [1, 0, 7, 7], "texture": "#5" }, + "east": { "uv": [1, 0, 7, 7], "texture": "#5" }, + "south": { "uv": [1, 0, 7, 7], "texture": "#5" }, + "west": { "uv": [1, 0, 7, 7], "texture": "#5" }, + "up": { "uv": [1, 1, 7, 7], "texture": "#3" }, + "down": { "uv": [8, 1, 9, 2], "texture": "#4" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bell_wall.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bell_wall.json new file mode 100644 index 000000000..b6846e30f --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bell_wall.json @@ -0,0 +1,49 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "2": "block/bell_side", + "3": "block/bell_top", + "4": "block/bell_bottom", + "bar": "block/dark_oak_planks" + }, + "elements": [ + { + "from": [3, 13, 7], + "to": [16, 15, 9], + "faces": { + "north": { "uv": [2, 2, 14, 4], "texture": "#bar" }, + "east": { "uv": [5, 4, 7, 6], "texture": "#bar", "cullface": "east" }, + "south": { "uv": [2, 3, 14, 5], "texture": "#bar" }, + "west": { "uv": [5, 4, 7, 6], "texture": "#bar" }, + "up": { "uv": [2, 3, 14, 5], "texture": "#bar" }, + "down": { "uv": [2, 3, 14, 5], "texture": "#bar" } + } + }, + { + "name": "BellBase", + "from": [4, 4, 4], + "to": [12, 6, 12], + "faces": { + "north": { "uv": [0, 7, 8, 9], "texture": "#2" }, + "east": { "uv": [0, 7, 8, 9], "texture": "#2" }, + "south": { "uv": [0, 7, 8, 9], "texture": "#2" }, + "west": { "uv": [0, 7, 8, 9], "texture": "#2" }, + "up": { "uv": [0, 0, 8, 8], "texture": "#3" }, + "down": { "uv": [0, 0, 8, 8], "texture": "#4" } + } + }, + { + "name": "BellTop", + "from": [5, 6, 5], + "to": [11, 13, 11], + "faces": { + "north": { "uv": [1, 0, 7, 7], "texture": "#2" }, + "east": { "uv": [1, 0, 7, 7], "texture": "#2" }, + "south": { "uv": [1, 0, 7, 7], "texture": "#2" }, + "west": { "uv": [1, 0, 7, 7], "texture": "#2" }, + "up": { "uv": [1, 1, 7, 7], "texture": "#3" }, + "down": { "uv": [8, 1, 9, 2], "texture": "#4" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/left.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bubble_column.json similarity index 100% rename from BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/left.json rename to BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/bubble_column.json diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake.json new file mode 100644 index 000000000..9edd0d91d --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake.json @@ -0,0 +1,21 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "textures": { + "top": "block/cake_top", + "side": "block/cake_side" + }, + "elements": [ + { + "from": [1, 0, 1], + "to": [15, 8, 15], + "faces": { + "north": { "uv": [1, 8, 15, 16], "texture": "#side" }, + "east": { "uv": [1, 8, 15, 16], "texture": "#side" }, + "south": { "uv": [1, 8, 15, 16], "texture": "#side" }, + "west": { "uv": [1, 8, 15, 16], "texture": "#side" }, + "up": { "uv": [1, 1, 15, 15], "texture": "#top" }, + "down": { "uv": [0, 0, 1, 1], "texture": "#top" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice1.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice1.json new file mode 100644 index 000000000..65b2e5664 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice1.json @@ -0,0 +1,24 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "ambientocclusion": false, + "textures": { + "3": "block/cake_inner", + "particle": "block/cake_inner", + "top": "block/cake_top", + "side": "block/cake_side" + }, + "elements": [ + { + "from": [3, 0, 1], + "to": [15, 8, 15], + "faces": { + "north": { "uv": [1, 8, 13, 16], "texture": "#side" }, + "east": { "uv": [1, 8, 15, 16], "texture": "#side" }, + "south": { "uv": [3, 8, 15, 16], "texture": "#side" }, + "west": { "uv": [1, 8, 15, 16], "texture": "#3" }, + "up": { "uv": [3, 1, 15, 15], "texture": "#top" }, + "down": { "uv": [0, 0, 1, 1], "texture": "#top" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice2.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice2.json new file mode 100644 index 000000000..044a6ab66 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice2.json @@ -0,0 +1,25 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "ambientocclusion": false, + "textures": { + "3": "block/cake_inner", + "bottom": "block/cake_bottom", + "top": "block/cake_top", + "side": "block/cake_side", + "particle": "block/cake_inner" + }, + "elements": [ + { + "from": [5, 0, 1], + "to": [15, 8, 15], + "faces": { + "north": { "uv": [1, 8, 11, 16], "texture": "#side" }, + "east": { "uv": [1, 8, 15, 16], "texture": "#side" }, + "south": { "uv": [5, 8, 15, 16], "texture": "#side" }, + "west": { "uv": [1, 8, 15, 16], "texture": "#3" }, + "up": { "uv": [5, 1, 15, 15], "texture": "#top" }, + "down": { "uv": [1, 1, 0, 15], "texture": "#bottom" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice3.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice3.json new file mode 100644 index 000000000..daf1030ee --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice3.json @@ -0,0 +1,25 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "ambientocclusion": false, + "textures": { + "3": "block/cake_inner", + "bottom": "block/cake_bottom", + "top": "block/cake_top", + "side": "block/cake_side", + "particle": "block/cake_inner" + }, + "elements": [ + { + "from": [7, 0, 1], + "to": [15, 8, 15], + "faces": { + "north": { "uv": [1, 8, 9, 16], "texture": "#side" }, + "east": { "uv": [1, 8, 15, 16], "texture": "#side" }, + "south": { "uv": [7, 8, 15, 16], "texture": "#side" }, + "west": { "uv": [1, 8, 15, 16], "texture": "#3" }, + "up": { "uv": [7, 1, 15, 15], "texture": "#top" }, + "down": { "uv": [1, 1, 0, 15], "texture": "#bottom" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice4.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice4.json new file mode 100644 index 000000000..164e862cd --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice4.json @@ -0,0 +1,25 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "ambientocclusion": false, + "textures": { + "3": "block/cake_inner", + "bottom": "block/cake_bottom", + "top": "block/cake_top", + "side": "block/cake_side", + "particle": "block/cake_inner" + }, + "elements": [ + { + "from": [9, 0, 1], + "to": [15, 8, 15], + "faces": { + "north": { "uv": [1, 8, 7, 16], "texture": "#side" }, + "east": { "uv": [1, 8, 15, 16], "texture": "#side" }, + "south": { "uv": [9, 8, 15, 16], "texture": "#side" }, + "west": { "uv": [1, 8, 15, 16], "texture": "#3" }, + "up": { "uv": [9, 1, 15, 15], "texture": "#top" }, + "down": { "uv": [1, 1, 0, 15], "texture": "#bottom" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice5.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice5.json new file mode 100644 index 000000000..3835aee29 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice5.json @@ -0,0 +1,25 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "ambientocclusion": false, + "textures": { + "3": "block/cake_inner", + "bottom": "block/cake_bottom", + "top": "block/cake_top", + "side": "block/cake_side", + "particle": "block/cake_inner" + }, + "elements": [ + { + "from": [11, 0, 1], + "to": [15, 8, 15], + "faces": { + "north": { "uv": [1, 8, 5, 16], "texture": "#side" }, + "east": { "uv": [1, 8, 15, 16], "texture": "#side" }, + "south": { "uv": [11, 8, 15, 16], "texture": "#side" }, + "west": { "uv": [1, 8, 15, 16], "texture": "#3" }, + "up": { "uv": [11, 1, 15, 15], "texture": "#top" }, + "down": { "uv": [1, 1, 0, 15], "texture": "#bottom" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice6.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice6.json new file mode 100644 index 000000000..a5011f60e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/cake_slice6.json @@ -0,0 +1,25 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "ambientocclusion": false, + "textures": { + "3": "block/cake_inner", + "bottom": "block/cake_bottom", + "top": "block/cake_top", + "side": "block/cake_side", + "particle": "block/cake_inner" + }, + "elements": [ + { + "from": [13, 0, 1], + "to": [15, 8, 15], + "faces": { + "north": { "uv": [1, 8, 3, 16], "texture": "#side" }, + "east": { "uv": [1, 8, 15, 16], "texture": "#side" }, + "south": { "uv": [13, 8, 15, 16], "texture": "#side" }, + "west": { "uv": [1, 8, 15, 16], "texture": "#3" }, + "up": { "uv": [13, 1, 15, 15], "texture": "#top" }, + "down": { "uv": [1, 1, 0, 15], "texture": "#bottom" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/chest.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/chest.json new file mode 100644 index 000000000..e7bf12fcb --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/chest.json @@ -0,0 +1,40 @@ +{ + "elements": [ + { + "from": [1, 0, 1], + "to": [15, 10, 15], + "faces": { + "north": { "uv": [10.5, 8.25, 14, 10.75], "texture": "#chest" }, + "east": { "uv": [7, 8.25, 10.5, 10.75], "texture": "#chest" }, + "south": { "uv": [3.5, 8.25, 7, 10.75], "texture": "#chest" }, + "west": { "uv": [0, 8.25, 3.5, 10.75], "texture": "#chest" }, + "up": { "uv": [3.5, 4.75, 7, 8.25], "texture": "#chest" }, + "down": { "uv": [7, 4.75, 10.5, 8.25], "texture": "#chest" } + } + }, + { + "from": [1, 9, 1], + "to": [15, 14, 15], + "faces": { + "north": { "uv": [10.5, 3.5, 14, 4.75], "texture": "#chest" }, + "east": { "uv": [7, 3.5, 10.5, 4.75], "texture": "#chest" }, + "south": { "uv": [3.5, 3.5, 7, 4.75], "texture": "#chest" }, + "west": { "uv": [0, 3.5, 3.5, 4.75], "texture": "#chest" }, + "up": { "uv": [3.5, 0, 7, 3.5], "texture": "#chest" }, + "down": { "uv": [7, 0, 10.5, 3.5], "texture": "#chest" } + } + }, + { + "from": [7, 7, 15], + "to": [9, 11, 16], + "faces": { + "north": { "uv": [0.25, 0.25, 0.75, 1.25], "texture": "#chest" }, + "east": { "uv": [0, 0.25, 0.25, 1.25], "texture": "#chest" }, + "south": { "uv": [1, 0.25, 1.5, 1.25], "texture": "#chest" }, + "west": { "uv": [0.75, 0.25, 1, 1.25], "texture": "#chest" }, + "up": { "uv": [0.25, 0, 0.75, 0.25], "texture": "#chest" }, + "down": { "uv": [0.75, 0, 1.25, 0.25], "texture": "#chest" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/chest_double.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/chest_double.json new file mode 100644 index 000000000..f14a8e2e9 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/chest_double.json @@ -0,0 +1,40 @@ +{ + "elements": [ + { + "from": [1, 0, 1], + "to": [31, 10, 15], + "faces": { + "north": { "uv": [7.25, 8.25, 11, 10.75], "texture": "#chest" }, + "east": { "uv": [5.5, 8.25, 7.25, 10.75], "texture": "#chest" }, + "south": { "uv": [1.75, 8.25, 5.5, 10.75], "texture": "#chest" }, + "west": { "uv": [0, 8.25, 1.75, 10.75], "texture": "#chest" }, + "up": { "uv": [1.75, 4.75, 5.5, 8.25], "texture": "#chest" }, + "down": { "uv": [5.5, 4.75, 9.25, 8.25], "texture": "#chest" } + } + }, + { + "from": [1, 9, 1], + "to": [31, 14, 15], + "faces": { + "north": { "uv": [7.25, 3.5, 11, 4.75], "texture": "#chest" }, + "east": { "uv": [5.5, 3.5, 7.25, 4.75], "texture": "#chest" }, + "south": { "uv": [1.75, 3.5, 5.5, 4.75], "texture": "#chest" }, + "west": { "uv": [0, 3.5, 1.75, 4.75], "texture": "#chest" }, + "up": { "uv": [1.75, 0, 5.5, 3.5], "texture": "#chest" }, + "down": { "uv": [5.5, 0, 9.25, 3.5], "texture": "#chest" } + } + }, + { + "from": [15, 7, 15], + "to": [17, 11, 16], + "faces": { + "north": { "uv": [0.5, 0.25, 0.75, 1.25], "texture": "#chest" }, + "east": { "uv": [0.375, 0.25, 0.5, 1.25], "texture": "#chest" }, + "south": { "uv": [0.125, 0.25, 0.375, 1.25], "texture": "#chest" }, + "west": { "uv": [0, 0.25, 0.125, 1.25], "texture": "#chest" }, + "up": { "uv": [0.125, 0, 0.375, 0.25], "texture": "#chest" }, + "down": { "uv": [0.375, 0, 0.625, 0.25], "texture": "#chest" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/ender.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/ender.json new file mode 100644 index 000000000..5fd48911d --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/ender.json @@ -0,0 +1,6 @@ +{ + "parent": "block/chest/chest", + "textures": { + "chest": "entity/chest/ender" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/left.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/left.json new file mode 100644 index 000000000..9e26dfeeb --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/left.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/normal.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/normal.json new file mode 100644 index 000000000..2d5afc2b9 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/normal.json @@ -0,0 +1,6 @@ +{ + "parent": "block/chest/chest", + "textures": { + "chest": "entity/chest/normal" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/normal_double.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/normal_double.json new file mode 100644 index 000000000..711a0022a --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/normal_double.json @@ -0,0 +1,6 @@ +{ + "parent": "block/chest/chest_double", + "textures": { + "chest": "entity/chest/normal_double" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/trapped.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/trapped.json new file mode 100644 index 000000000..9ab9df7a7 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/trapped.json @@ -0,0 +1,6 @@ +{ + "parent": "block/chest/chest", + "textures": { + "chest": "entity/chest/trapped" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/trapped_double.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/trapped_double.json new file mode 100644 index 000000000..8f55b9435 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/chest/trapped_double.json @@ -0,0 +1,6 @@ +{ + "parent": "block/chest/chest_double", + "textures": { + "chest": "entity/chest/trapped_double" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/lava.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/lava.json new file mode 100644 index 000000000..a514d057f --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/lava.json @@ -0,0 +1,8 @@ +{ + "parent": "bluemap:builtin/liquid", + "textures": { + "particle": "block/lava_still", + "still": "block/lava_still", + "flow": "block/lava_flow" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/acacia.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/acacia.json new file mode 100644 index 000000000..b0b67f8a5 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/acacia.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/sign", + "textures": { + "sign": "entity/signs/acacia" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/bamboo.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/bamboo.json new file mode 100644 index 000000000..ed9610a41 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/bamboo.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/sign", + "textures": { + "sign": "entity/signs/bamboo" + } +} diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/birch.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/birch.json new file mode 100644 index 000000000..cdf739219 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/birch.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/sign", + "textures": { + "sign": "entity/signs/birch" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/cherry.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/cherry.json new file mode 100644 index 000000000..e9ad375ca --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/cherry.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/sign", + "textures": { + "sign": "entity/signs/cherry" + } +} diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/crimson.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/crimson.json new file mode 100644 index 000000000..e4dd0574d --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/crimson.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/sign", + "textures": { + "sign": "entity/signs/crimson" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/dark_oak.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/dark_oak.json new file mode 100644 index 000000000..4f9c5d513 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/dark_oak.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/sign", + "textures": { + "sign": "entity/signs/dark_oak" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/jungle.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/jungle.json new file mode 100644 index 000000000..8814b6408 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/jungle.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/sign", + "textures": { + "sign": "entity/signs/jungle" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/mangrove.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/mangrove.json new file mode 100644 index 000000000..64afac8cd --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/mangrove.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/sign", + "textures": { + "sign": "entity/signs/mangrove" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/oak.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/oak.json new file mode 100644 index 000000000..08bccfb5e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/oak.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/sign", + "textures": { + "sign": "entity/signs/oak" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/sign.json new file mode 100644 index 000000000..26596ad6c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/sign.json @@ -0,0 +1,28 @@ +{ + "elements": [ + { + "from": [7.25, 0, 7.25], + "to": [8.75, 9.333, 8.75], + "faces": { + "north": { "uv": [1.5, 8, 2, 15], "texture": "#sign" }, + "east": { "uv": [1, 8, 1.5, 15], "texture": "#sign" }, + "south": { "uv": [0.5, 8, 1, 15], "texture": "#sign" }, + "west": { "uv": [0, 8, 0.5, 15], "texture": "#sign" }, + "up": { "uv": [0.5, 7, 1, 8], "texture": "#sign" }, + "down": { "uv": [1, 7, 1.5, 8], "texture": "#sign" } + } + }, + { + "from": [0, 9.333, 7.25], + "to": [16, 17.333, 8.75], + "faces": { + "north": { "uv": [7, 1, 13, 7], "texture": "#sign" }, + "east": { "uv": [6.5, 1, 7, 7], "texture": "#sign" }, + "south": { "uv": [0.5, 1, 6.5, 7], "texture": "#sign" }, + "west": { "uv": [0, 1, 0.5, 7], "texture": "#sign" }, + "up": { "uv": [0.5, 0, 6.5, 1], "texture": "#sign" }, + "down": { "uv": [6.5, 1, 12.5, 0], "texture": "#sign" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/spruce.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/spruce.json new file mode 100644 index 000000000..53435ceed --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/spruce.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/sign", + "textures": { + "sign": "entity/signs/spruce" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_acacia.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_acacia.json new file mode 100644 index 000000000..d2ed6e5c5 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_acacia.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/wall_sign", + "textures": { + "sign": "entity/signs/acacia" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_bamboo.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_bamboo.json new file mode 100644 index 000000000..f3201b2b1 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_bamboo.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/wall_sign", + "textures": { + "sign": "entity/signs/bamboo" + } +} diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_birch.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_birch.json new file mode 100644 index 000000000..42a55a8e5 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_birch.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/wall_sign", + "textures": { + "sign": "entity/signs/birch" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_cherry.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_cherry.json new file mode 100644 index 000000000..ae5c0976d --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_cherry.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/wall_sign", + "textures": { + "sign": "entity/signs/cherry" + } +} diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_crimson.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_crimson.json new file mode 100644 index 000000000..482966bb4 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_crimson.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/wall_sign", + "textures": { + "sign": "entity/signs/crimson" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_dark_oak.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_dark_oak.json new file mode 100644 index 000000000..185a30f2e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_dark_oak.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/wall_sign", + "textures": { + "sign": "entity/signs/dark_oak" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_jungle.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_jungle.json new file mode 100644 index 000000000..c0797f718 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_jungle.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/wall_sign", + "textures": { + "sign": "entity/signs/jungle" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_mangrove.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_mangrove.json new file mode 100644 index 000000000..178f6430c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_mangrove.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/wall_sign", + "textures": { + "sign": "entity/signs/mangrove" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_oak.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_oak.json new file mode 100644 index 000000000..9c2b8e77e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_oak.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/wall_sign", + "textures": { + "sign": "entity/signs/oak" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_sign.json new file mode 100644 index 000000000..3c4b16641 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_sign.json @@ -0,0 +1,16 @@ +{ + "elements": [ + { + "from": [0, 4.333, 0.25], + "to": [16, 12.333, 1.75], + "faces": { + "north": { "uv": [7, 1, 13, 7], "texture": "#sign" }, + "east": { "uv": [6.5, 1, 7, 7], "texture": "#sign" }, + "south": { "uv": [0.5, 1, 6.5, 7], "texture": "#sign" }, + "west": { "uv": [0, 1, 0.5, 7], "texture": "#sign" }, + "up": { "uv": [0.5, 0, 6.5, 1], "texture": "#sign" }, + "down": { "uv": [6.5, 1, 12.5, 0], "texture": "#sign" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_spruce.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_spruce.json new file mode 100644 index 000000000..20dd22689 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_spruce.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/wall_sign", + "textures": { + "sign": "entity/signs/spruce" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_warped.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_warped.json new file mode 100644 index 000000000..ac575fa17 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/wall_warped.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/wall_sign", + "textures": { + "sign": "entity/signs/warped" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/warped.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/warped.json new file mode 100644 index 000000000..8b5cd9ee8 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/sign/warped.json @@ -0,0 +1,6 @@ +{ + "parent": "block/sign/sign", + "textures": { + "sign": "entity/signs/warped" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/water.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/water.json new file mode 100644 index 000000000..0c0fc9a8f --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/block/water.json @@ -0,0 +1,8 @@ +{ + "parent": "bluemap:builtin/liquid", + "textures": { + "particle": "block/water_still", + "still": "block/water_still", + "flow": "block/water_flow" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/acacia_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/acacia_hanging_sign.json new file mode 100644 index 000000000..d3d2a6417 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/acacia_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/acacia" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/acacia_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/acacia_wall_hanging_sign.json new file mode 100644 index 000000000..8e39bd9cf --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/acacia_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/acacia" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/bamboo_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/bamboo_hanging_sign.json new file mode 100644 index 000000000..659906071 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/bamboo_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/bamboo" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/bamboo_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/bamboo_wall_hanging_sign.json new file mode 100644 index 000000000..7dbf04361 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/bamboo_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/bamboo" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/banner.json new file mode 100644 index 000000000..7597f5f8a --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/banner.json @@ -0,0 +1,48 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [64, 64], + "textures": { + "0": "entity/banner_base" + }, + "elements": [ + { + "name": "Handle", + "from": [1.2, 28.4, 7.5], + "to": [14.8, 29.4, 8.5], + "faces": { + "north": { "uv": [0.5, 11.5, 5.5, 12], "texture": "#0" }, + "east": { "uv": [0, 11, 0.5, 11.5], "texture": "#0" }, + "south": { "uv": [5.5, 10.5, 10.5, 11], "texture": "#0" }, + "west": { "uv": [5.5, 11, 6, 11.5], "texture": "#0" }, + "up": { "uv": [5.5, 11, 0.5, 10.5], "texture": "#0" }, + "down": { "uv": [5.5, 11, 0.5, 11.5], "texture": "#0" } + } + }, + { + "name": "Cloth", + "from": [1.2, 1.4, 7], + "to": [14.8, 29.4, 7.5], + "faces": { + "north": { "uv": [0.25, 0.25, 5.5, 10.25], "texture": "#0", "tintindex": 0 }, + "east": { "uv": [0, 0.25, 0.25, 10.25], "texture": "#0", "tintindex": 0 }, + "south": { "uv": [5.5, 0.25, 10.5, 10.25], "texture": "#0", "tintindex": 0 }, + "west": { "uv": [5.5, 0.25, 5.25, 10], "texture": "#0", "tintindex": 0 }, + "up": { "uv": [5.25, 0, 0.25, 0.25], "texture": "#0", "tintindex": 0 }, + "down": { "uv": [5, 0.25, 0.25, 0], "texture": "#0", "tintindex": 0 } + } + }, + { + "name": "Pole", + "from": [7.5, 0, 7.5], + "to": [8.5, 28.4, 8.5], + "faces": { + "north": { "uv": [11.5, 0.5, 12, 11], "texture": "#0" }, + "east": { "uv": [11, 0.5, 11.5, 11], "texture": "#0" }, + "south": { "uv": [12.5, 0.5, 13, 11], "texture": "#0" }, + "west": { "uv": [12, 0.5, 12.5, 11], "texture": "#0" }, + "up": { "uv": [11.5, 0.5, 11, 0], "texture": "#0" }, + "down": { "uv": [13, 0, 12.5, 0.5], "texture": "#0" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/birch_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/birch_hanging_sign.json new file mode 100644 index 000000000..27a93a85c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/birch_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/birch" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/birch_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/birch_wall_hanging_sign.json new file mode 100644 index 000000000..2cff5eb90 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/birch_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/birch" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/cherry_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/cherry_hanging_sign.json new file mode 100644 index 000000000..944534dd2 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/cherry_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/cherry" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/cherry_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/cherry_wall_hanging_sign.json new file mode 100644 index 000000000..8844a253a --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/cherry_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/cherry" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/creeper_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/creeper_head.json new file mode 100644 index 000000000..22108cc36 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/creeper_head.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/skull_32", + "textures": { + "entity": "entity/creeper/creeper" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/creeper_wall_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/creeper_wall_head.json new file mode 100644 index 000000000..9bd12be70 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/creeper_wall_head.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_skull_32", + "textures": { + "entity": "entity/creeper/creeper" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/crimson_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/crimson_hanging_sign.json new file mode 100644 index 000000000..c516894c9 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/crimson_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/crimson" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/crimson_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/crimson_wall_hanging_sign.json new file mode 100644 index 000000000..d89c0b57b --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/crimson_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/crimson" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/dark_oak_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/dark_oak_hanging_sign.json new file mode 100644 index 000000000..26d0ca517 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/dark_oak_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/dark_oak" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/dark_oak_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/dark_oak_wall_hanging_sign.json new file mode 100644 index 000000000..ec6d479ba --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/dark_oak_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/dark_oak" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/decorated_pot.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/decorated_pot.json new file mode 100644 index 000000000..6a8cc6284 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/decorated_pot.json @@ -0,0 +1,48 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [32, 32], + "textures": { + "0": "entity/decorated_pot/decorated_pot_base" + }, + "elements": [ + { + "name": "Body", + "from": [1, 0, 1], + "to": [15, 16, 15], + "faces": { + "north": { "uv": [0, 6.5, 7, 13.5], "texture": "#0" }, + "east": { "uv": [0, 6.5, 7, 13.5], "texture": "#0" }, + "south": { "uv": [0, 6.5, 7, 13.5], "texture": "#0" }, + "west": { "uv": [0, 6.5, 7, 13.5], "texture": "#0" }, + "up": { "uv": [7, 6.5, 14, 13.5], "texture": "#0" }, + "down": { "uv": [7, 6.5, 14, 13.5], "texture": "#0" } + } + }, + { + "name": "Neck", + "from": [5, 16, 5], + "to": [11, 17, 11], + "faces": { + "north": { "uv": [6, 5.5, 9, 6], "texture": "#0" }, + "east": { "uv": [9, 5.5, 12, 6], "texture": "#0" }, + "south": { "uv": [2.5, 5.5, 5.5, 6], "texture": "#0" }, + "west": { "uv": [0, 5.5, 3, 6], "texture": "#0" }, + "up": { "uv": [0, 0, 3, 3], "texture": "#0" }, + "down": { "uv": [0, 0, 3, 3], "texture": "#0" } + } + }, + { + "name": "Head", + "from": [4, 17, 4], + "to": [12, 20, 12], + "faces": { + "north": { "uv": [0, 4, 4, 5.5], "texture": "#0" }, + "east": { "uv": [4, 4, 8, 5.5], "texture": "#0" }, + "south": { "uv": [8, 4, 12, 5.5], "texture": "#0" }, + "west": { "uv": [12, 4, 16, 5.5], "texture": "#0" }, + "up": { "uv": [4, 0, 8, 4], "texture": "#0" }, + "down": { "uv": [8, 0, 12, 4], "texture": "#0" } + } + } + ] +} diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/dragon_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/dragon_head.json new file mode 100644 index 000000000..5ee1bb0c8 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/dragon_head.json @@ -0,0 +1,105 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [256, 256], + "textures": { + "0": "entity/enderdragon/dragon" + }, + "elements": [ + { + "name": "Skull", + "from": [2, 0, 3.5], + "to": [14, 12, 15.5], + "faces": { + "north": { "uv": [9.9375, 2.875, 10.9375, 3.875], "texture": "#0" }, + "east": { "uv": [9, 2.875, 10, 3.875], "texture": "#0" }, + "south": { "uv": [8, 2.875, 9, 3.875], "texture": "#0" }, + "west": { "uv": [7, 2.875, 8, 3.875], "texture": "#0" }, + "up": { "uv": [9, 1.875, 8, 2.875], "texture": "#0" }, + "down": { "uv": [11, 1.875, 10, 2.875], "texture": "#0" } + } + }, + { + "name": "Horn1", + "from": [4, 12, 6], + "to": [6, 16, 12], + "faces": { + "north": { "uv": [0.875, 0.375, 1, 0.625], "texture": "#0" }, + "east": { "uv": [0.5, 0.375, 0.875, 0.625], "texture": "#0" }, + "south": { "uv": [0.375, 0.375, 0.5, 0.625], "texture": "#0" }, + "west": { "uv": [0, 0.375, 0.375, 0.625], "texture": "#0" }, + "up": { "uv": [0.375, 0, 0.5, 0.375], "texture": "#0" }, + "down": { "uv": [0, 0, 0.125, 0.375], "texture": "#0" } + } + }, + { + "name": "Horn2", + "from": [10, 12, 6], + "to": [12, 16, 12], + "faces": { + "north": { "uv": [0.875, 0.375, 1, 0.625], "texture": "#0" }, + "east": { "uv": [0.5, 0.375, 0.875, 0.625], "texture": "#0" }, + "south": { "uv": [0.375, 0.375, 0.5, 0.625], "texture": "#0" }, + "west": { "uv": [0, 0.375, 0.375, 0.625], "texture": "#0" }, + "up": { "uv": [0.375, 0, 0.5, 0.375], "texture": "#0" }, + "down": { "uv": [0, 0, 0.125, 0.375], "texture": "#0" } + } + }, + { + "name": "TopJaw", + "from": [2.5, 3, 15.5], + "to": [13.5, 7, 26], + "faces": { + "north": { "uv": [0.375, 3.375, 1.0625, 3.625], "texture": "#0" }, + "east": { "uv": [11, 3.75, 12.00625, 4.0625], "texture": "#0" }, + "south": { "uv": [12, 3.75, 12.8125, 4.0625], "texture": "#0" }, + "west": { "uv": [13.5, 3.75, 14.46875, 4.0625], "texture": "#0" }, + "up": { "uv": [12, 2.75, 12.75, 3.71875], "texture": "#0" }, + "down": { "uv": [12.74375, 3.75, 13.49375, 2.75], "texture": "#0" } + } + }, + { + "name": "Bottom Jaw", + "from": [2.5, 0.5, 14.5], + "to": [13.5, 2.5, 26], + "rotation": { + "angle": 22.5, + "axis": "x", + "origin": [8, 2, 16] + }, + "faces": { + "north": { "uv": [8.1875, 4.8125, 8.875, 4.9375], "texture": "#0" }, + "east": { "uv": [11, 5.0625, 12, 5.3125], "texture": "#0" }, + "south": { "uv": [8.0625, 5.3125, 8.75, 5.4375], "texture": "#0" }, + "west": { "uv": [13.74375, 5.06875, 14.49375, 5.31875], "texture": "#0" }, + "up": { "uv": [12, 4.0625, 12.75, 5.0625], "texture": "#0" }, + "down": { "uv": [12.6875, 4.0625, 13.5, 5.0625], "texture": "#0" } + } + }, + { + "name": "Nostril1", + "from": [4, 7, 20], + "to": [6, 9, 24], + "faces": { + "north": { "uv": [7.25, 0.25, 7.375, 0.375], "texture": "#0" }, + "east": { "uv": [7, 0.25, 7.25, 0.375], "texture": "#0" }, + "south": { "uv": [7.625, 0.25, 7.75, 0.375], "texture": "#0" }, + "west": { "uv": [7.375, 0.25, 7.625, 0.375], "texture": "#0" }, + "up": { "uv": [7.25, 0, 7.375, 0.25], "texture": "#0" }, + "down": { "uv": [7.125, 0, 7.25, 0.25], "texture": "#0" } + } + }, + { + "name": "Nostril2", + "from": [10, 7, 20], + "to": [12, 9, 24], + "faces": { + "north": { "uv": [7.25, 0.25, 7.375, 0.375], "texture": "#0" }, + "east": { "uv": [7.375, 0.25, 7.625, 0.375], "texture": "#0" }, + "south": { "uv": [7.625, 0.25, 7.75, 0.375], "texture": "#0" }, + "west": { "uv": [7, 0.25, 7.25, 0.375], "texture": "#0" }, + "up": { "uv": [7.25, 0, 7.375, 0.25], "texture": "#0" }, + "down": { "uv": [7.125, 0, 7.25, 0.25], "texture": "#0" } + } + } + ] +} diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/dragon_wall_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/dragon_wall_head.json new file mode 100644 index 000000000..9c3f50699 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/dragon_wall_head.json @@ -0,0 +1,143 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [256, 256], + "textures": { + "0": "entity/enderdragon/dragon" + }, + "elements": [ + { + "name": "Skull", + "from": [2, 4, 4], + "to": [14, 16, 16], + "rotation": { + "angle": 0, + "axis": "y", + "origin": [8, 4, 7.5] + }, + "faces": { + "north": { "uv": [8, 2.875, 9, 3.875], "texture": "#0" }, + "east": { "uv": [7, 2.875, 8, 3.875], "texture": "#0" }, + "south": { "uv": [9.9375, 2.875, 10.9375, 3.875], "texture": "#0" }, + "west": { "uv": [9, 2.875, 10, 3.875], "texture": "#0" }, + "up": { "uv": [9, 1.875, 8, 2.875], "rotation": 180, "texture": "#0" }, + "down": { "uv": [10, 1.875, 9, 2.875], "rotation": 180, "texture": "#0" } + } + }, + { + "name": "Horn1", + "from": [10, 16, 7.5], + "to": [12, 20, 13.5], + "rotation": { + "angle": 0, + "axis": "y", + "origin": [8, 4, 7.5] + }, + "faces": { + "north": { "uv": [0.375, 0.375, 0.5, 0.625], "texture": "#0" }, + "east": { "uv": [0, 0.375, 0.375, 0.625], "texture": "#0" }, + "south": { "uv": [0.875, 0.375, 1, 0.625], "texture": "#0" }, + "west": { "uv": [0.5, 0.375, 0.875, 0.625], "texture": "#0" }, + "up": { "uv": [0.375, 0, 0.5, 0.375], "rotation": 180, "texture": "#0" }, + "down": { "uv": [0, 0, 0.125, 0.375], "rotation": 180, "texture": "#0" } + } + }, + { + "name": "Horn2", + "from": [4, 16, 7.5], + "to": [6, 20, 13.5], + "rotation": { + "angle": 0, + "axis": "y", + "origin": [8, 4, 7.5] + }, + "faces": { + "north": { "uv": [0.375, 0.375, 0.5, 0.625], "texture": "#0" }, + "east": { "uv": [0, 0.375, 0.375, 0.625], "texture": "#0" }, + "south": { "uv": [0.875, 0.375, 1, 0.625], "texture": "#0" }, + "west": { "uv": [0.5, 0.375, 0.875, 0.625], "texture": "#0" }, + "up": { "uv": [0.375, 0, 0.5, 0.375], "rotation": 180, "texture": "#0" }, + "down": { "uv": [0, 0, 0.125, 0.375], "rotation": 180, "texture": "#0" } + } + }, + { + "name": "TopJaw", + "from": [2.5, 7, -6.5], + "to": [13.5, 11, 4], + "rotation": { + "angle": 0, + "axis": "y", + "origin": [8, 4, 7.5] + }, + "faces": { + "north": { "uv": [12, 3.75, 12.8125, 4.0625], "texture": "#0" }, + "east": { "uv": [13.5, 3.75, 14.46875, 4.0625], "texture": "#0" }, + "south": { "uv": [0.375, 3.375, 1.0625, 3.625], "texture": "#0" }, + "west": { "uv": [11, 3.75, 12.00625, 4.0625], "texture": "#0" }, + "up": { "uv": [12, 2.75, 12.75, 3.71875], "rotation": 180, "texture": "#0" }, + "down": { "uv": [12.74375, 3.75, 13.49375, 2.75], "rotation": 180, "texture": "#0" } + } + }, + { + "name": "Bottom Jaw", + "from": [2.5, 4.5, -6.5], + "to": [13.5, 6.5, 5], + "rotation": { + "angle": -22.5, + "axis": "x", + "origin": [8, 6, 4.5] + }, + "faces": { + "north": { "uv": [8.0625, 5.3125, 8.75, 5.4375], "texture": "#0" }, + "east": { "uv": [13.74375, 5.06875, 14.49375, 5.31875], "texture": "#0" }, + "south": { "uv": [8.1875, 4.8125, 8.875, 4.9375], "texture": "#0" }, + "west": { "uv": [11, 5.0625, 12, 5.3125], "texture": "#0" }, + "up": { "uv": [12, 4.0625, 12.75, 5.0625], "rotation": 180, "texture": "#0" }, + "down": { "uv": [12.6875, 4.0625, 13.5, 5.0625], "rotation": 180, "texture": "#0" } + } + }, + { + "name": "Nostril1", + "from": [10, 11, -4.5], + "to": [12, 13, -0.5], + "rotation": { + "angle": 0, + "axis": "y", + "origin": [8, 4, 7.5] + }, + "faces": { + "north": { "uv": [7.625, 0.25, 7.75, 0.375], "texture": "#0" }, + "east": { "uv": [7.375, 0.25, 7.625, 0.375], "texture": "#0" }, + "south": { "uv": [7.25, 0.25, 7.375, 0.375], "texture": "#0" }, + "west": { "uv": [7, 0.25, 7.25, 0.375], "texture": "#0" }, + "up": { "uv": [7.25, 0, 7.375, 0.25], "rotation": 180, "texture": "#0" }, + "down": { "uv": [7.125, 0, 7.25, 0.25], "rotation": 180, "texture": "#0" } + } + }, + { + "name": "Nostril2", + "from": [4, 11, -4.5], + "to": [6, 13, -0.5], + "rotation": { + "angle": 0, + "axis": "y", + "origin": [8, 4, 7.5] + }, + "faces": { + "north": { "uv": [7.625, 0.25, 7.75, 0.375], "texture": "#0" }, + "east": { "uv": [7, 0.25, 7.25, 0.375], "texture": "#0" }, + "south": { "uv": [7.25, 0.25, 7.375, 0.375], "texture": "#0" }, + "west": { "uv": [7.375, 0.25, 7.625, 0.375], "texture": "#0" }, + "up": { "uv": [7.25, 0, 7.375, 0.25], "rotation": 180, "texture": "#0" }, + "down": { "uv": [7.125, 0, 7.25, 0.25], "rotation": 180, "texture": "#0" } + } + } + ], + "groups": [ + { + "name": "group", + "origin": [0, 4, -3.5], + "color": 0, + "children": [0, 1, 2, 3, 4, 5, 6] + } + ] +} diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/dyed_shulker_box.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/dyed_shulker_box.json new file mode 100644 index 000000000..b7984e544 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/dyed_shulker_box.json @@ -0,0 +1,33 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [64, 64], + "textures": { + "0": "entity/shulker/shulker_white" + }, + "elements": [ + { + "from": [0, 0, 0], + "to": [16, 8, 16], + "faces": { + "north": { "uv": [0, 11, 4, 13], "texture": "#0", "tintindex": 0 }, + "east": { "uv": [0, 11, 4, 13], "texture": "#0", "tintindex": 0 }, + "south": { "uv": [0, 11, 4, 13], "texture": "#0", "tintindex": 0 }, + "west": { "uv": [0, 11, 4, 13], "texture": "#0", "tintindex": 0 }, + "up": { "uv": [0, 0, 4, 4], "texture": "#0", "tintindex": 0 }, + "down": { "uv": [8.25, 7.25, 12, 11], "texture": "#0", "tintindex": 0 } + } + }, + { + "from": [0, 4, 0], + "to": [16, 16, 16], + "faces": { + "north": { "uv": [0, 4, 4, 7], "texture": "#0", "tintindex": 0 }, + "east": { "uv": [0, 4, 4, 7], "texture": "#0", "tintindex": 0 }, + "south": { "uv": [0, 4, 4, 7], "texture": "#0", "tintindex": 0 }, + "west": { "uv": [0, 4, 4, 7], "texture": "#0", "tintindex": 0 }, + "up": { "uv": [4, 0, 8, 4], "texture": "#0", "tintindex": 0 }, + "down": { "uv": [0, 0, 4, 4], "texture": "#0", "tintindex": 0 } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/hanging_sign.json new file mode 100644 index 000000000..b4492e6ed --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/hanging_sign.json @@ -0,0 +1,35 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "ambientocclusion": false, + "texture_size": [64, 32], + "textures": { + "wood": "entity/signs/hanging/oak" + }, + "elements": [ + { + "name": "Sign", + "from": [1, 0, 7], + "to": [15, 10, 9], + "faces": { + "north": { "uv": [4.5, 7, 8, 12], "texture": "#wood" }, + "east": { "uv": [4, 7, 4.5, 12], "texture": "#wood" }, + "south": { "uv": [0.5, 7, 4, 12], "texture": "#wood" }, + "west": { "uv": [0, 7, 0.5, 12], "texture": "#wood" }, + "up": { "uv": [4, 6, 0.5, 7], "rotation": 180, "texture": "#wood" }, + "down": { "uv": [4, 7, 7.5, 6], "texture": "#wood" } + } + }, + { + "from": [2, 10, 8], + "to": [14, 16, 8], + "faces": { + "north": { "uv": [3.5, 3, 6.5, 6], "texture": "#wood" }, + "east": { "uv": [0, 0, 0, 3], "texture": "#missing" }, + "south": { "uv": [3.5, 3, 6.5, 6], "texture": "#wood" }, + "west": { "uv": [0, 0, 0, 3], "texture": "#missing" }, + "up": { "uv": [0, 0, 0, 6], "rotation": 90, "texture": "#missing" }, + "down": { "uv": [0, 0, 0, 6], "rotation": 270, "texture": "#missing" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/jungle_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/jungle_hanging_sign.json new file mode 100644 index 000000000..021a9aef0 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/jungle_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/jungle" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/jungle_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/jungle_wall_hanging_sign.json new file mode 100644 index 000000000..ffc8d2e47 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/jungle_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/jungle" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/mangrove_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/mangrove_hanging_sign.json new file mode 100644 index 000000000..21bfdc043 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/mangrove_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/mangrove" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/mangrove_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/mangrove_wall_hanging_sign.json new file mode 100644 index 000000000..216124921 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/mangrove_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/mangrove" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/oak_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/oak_hanging_sign.json new file mode 100644 index 000000000..51e6cad6e --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/oak_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/oak" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/oak_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/oak_wall_hanging_sign.json new file mode 100644 index 000000000..30c430902 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/oak_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/oak" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/piglin_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/piglin_head.json new file mode 100644 index 000000000..c6e60fbd0 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/piglin_head.json @@ -0,0 +1,110 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [64, 64], + "textures": { + "0": "entity/piglin/piglin" + }, + "elements": [ + { + "name": "Skull", + "from": [3, 0, 4], + "to": [13, 8, 12], + "faces": { + "north": { "uv": [6.5, 2, 9, 4], "texture": "#0" }, + "east": { "uv": [4.5, 2, 6.5, 4], "texture": "#0" }, + "south": { "uv": [2, 2, 4.5, 4], "texture": "#0" }, + "west": { "uv": [0, 2, 2, 4], "texture": "#0" }, + "up": { "uv": [2, 0, 4.5, 2], "texture": "#0" }, + "down": { "uv": [11.25, 0, 13.75, 2], "texture": "#0" } + } + }, + { + "name": "SnoutBottom", + "from": [6, 0, 12], + "to": [10, 2, 13], + "faces": { + "north": { "uv": [3, 4, 4.5, 4.5], "texture": "#0" }, + "east": { "uv": [9, 1.5, 9.25, 2], "texture": "#0" }, + "south": { "uv": [8, 1, 9, 1.5], "texture": "#0" }, + "west": { "uv": [9, 1.5, 9.25, 2], "texture": "#0" }, + "up": { "uv": [8, 0, 9, 0.25], "texture": "#0" }, + "down": { "uv": [8, 1.5, 9, 1.75], "texture": "#0" } + } + }, + { + "name": "Snouttop", + "from": [6, 2, 12], + "to": [10, 4, 13], + "faces": { + "north": { "uv": [3, 4, 4, 4.5], "texture": "#0" }, + "east": { "uv": [7.75, 0.5, 8, 1], "texture": "#0" }, + "south": { "uv": [8, 0.5, 9, 1], "texture": "#0" }, + "west": { "uv": [9, 0.5, 9.25, 1], "texture": "#0" }, + "up": { "uv": [8, 0.25, 9, 0.5], "texture": "#0" }, + "down": { "uv": [10.25, 0.25, 11.25, 0.5], "texture": "#0" } + } + }, + { + "name": "Ear1", + "from": [3, 2, 6], + "to": [4, 7, 10], + "rotation": { + "angle": -22.5, + "axis": "z", + "origin": [3, 7, 8] + }, + "faces": { + "north": { "uv": [11, 2.5, 11.25, 3.75], "texture": "#0" }, + "east": { "uv": [11.25, 2.5, 12.25, 3.75], "texture": "#0" }, + "south": { "uv": [10.75, 2.5, 11, 3.75], "texture": "#0" }, + "west": { "uv": [9.75, 2.5, 10.75, 3.75], "texture": "#0" }, + "up": { "uv": [10.75, 1.5, 11, 2.5], "texture": "#0" }, + "down": { "uv": [11, 1.5, 11.25, 2.5], "texture": "#0" } + } + }, + { + "name": "Ear2", + "from": [12, 2, 6], + "to": [13, 7, 10], + "rotation": { + "angle": 22.5, + "axis": "z", + "origin": [13, 7, 8] + }, + "faces": { + "north": { "uv": [14, 2.5, 14.25, 3.75], "texture": "#0" }, + "east": { "uv": [14.25, 2.5, 15.25, 3.75], "texture": "#0" }, + "south": { "uv": [13.75, 2.5, 14, 3.75], "texture": "#0" }, + "west": { "uv": [12.75, 2.5, 13.75, 3.75], "texture": "#0" }, + "up": { "uv": [13.75, 1.5, 14, 2.5], "texture": "#0" }, + "down": { "uv": [14, 1.5, 14.25, 2.5], "texture": "#0" } + } + }, + { + "name": "Tusk1", + "from": [5, 0, 12], + "to": [6, 2, 13], + "faces": { + "north": { "uv": [0, 1.25, 0.25, 1.75], "texture": "#0" }, + "east": { "uv": [0.25, 0.25, 0.5, 0.75], "texture": "#0" }, + "south": { "uv": [0.75, 0.25, 1, 0.75], "texture": "#0" }, + "west": { "uv": [0.75, 0.25, 1, 0.75], "texture": "#0" }, + "up": { "uv": [0.75, 0, 1, 0.25], "texture": "#0" }, + "down": { "uv": [1.25, 0, 1.5, 0.25], "texture": "#0" } + } + }, + { + "name": "Tusk2", + "from": [10, 0, 12], + "to": [11, 2, 13], + "faces": { + "north": { "uv": [0, 1.25, 0.25, 1.75], "texture": "#0" }, + "east": { "uv": [1, 0.25, 1.25, 0.75], "texture": "#0" }, + "south": { "uv": [0.75, 0.25, 1, 0.75], "texture": "#0" }, + "west": { "uv": [0.25, 0.25, 0.5, 0.75], "texture": "#0" }, + "up": { "uv": [0.75, 0, 1, 0.25], "texture": "#0" }, + "down": { "uv": [1.25, 0, 1.5, 0.25], "texture": "#0" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/piglin_wall_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/piglin_wall_head.json new file mode 100644 index 000000000..5e37178f1 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/piglin_wall_head.json @@ -0,0 +1,135 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [64, 64], + "textures": { + "0": "entity/piglin/piglin" + }, + "elements": [ + { + "name": "Skull", + "from": [3, 4, 8], + "to": [13, 12, 16], + "rotation": { + "angle": 0, + "axis": "y", + "origin": [8, 7, 8] + }, + "faces": { + "north": { "uv": [2, 2, 4.5, 4], "texture": "#0" }, + "east": { "uv": [0, 2, 2, 4], "texture": "#0" }, + "south": { "uv": [6.5, 2, 9, 4], "texture": "#0" }, + "west": { "uv": [4.5, 2, 6.5, 4], "texture": "#0" }, + "up": { "uv": [2, 0, 4.5, 2], "rotation": 180, "texture": "#0" }, + "down": { "uv": [11.25, 0, 13.75, 2], "rotation": 180, "texture": "#0" } + } + }, + { + "name": "SnoutBottom", + "from": [6, 4, 7], + "to": [10, 6, 8], + "rotation": { + "angle": 0, + "axis": "y", + "origin": [8, 7, 8] + }, + "faces": { + "north": { "uv": [8, 1, 9, 1.5], "texture": "#0" }, + "east": { "uv": [9, 1.5, 9.25, 2], "texture": "#0" }, + "south": { "uv": [3, 4, 4.5, 4.5], "texture": "#0" }, + "west": { "uv": [9, 1.5, 9.25, 2], "texture": "#0" }, + "up": { "uv": [8, 0, 9, 0.25], "rotation": 180, "texture": "#0" }, + "down": { "uv": [8, 1.5, 9, 1.75], "rotation": 180, "texture": "#0" } + } + }, + { + "name": "Snouttop", + "from": [6, 6, 7], + "to": [10, 8, 8], + "rotation": { + "angle": 0, + "axis": "y", + "origin": [8, 7, 8] + }, + "faces": { + "north": { "uv": [8, 0.5, 9, 1], "texture": "#0" }, + "east": { "uv": [9, 0.5, 9.25, 1], "texture": "#0" }, + "south": { "uv": [3, 4, 4, 4.5], "texture": "#0" }, + "west": { "uv": [7.75, 0.5, 8, 1], "texture": "#0" }, + "up": { "uv": [8, 0.25, 9, 0.5], "rotation": 180, "texture": "#0" }, + "down": { "uv": [10.25, 0.25, 11.25, 0.5], "rotation": 180, "texture": "#0" } + } + }, + { + "name": "Ear1", + "from": [12, 6, 10], + "to": [13, 11, 14], + "rotation": { + "angle": 22.5, + "axis": "z", + "origin": [12, 11, 12] + }, + "faces": { + "north": { "uv": [10.75, 2.5, 11, 3.75], "texture": "#0" }, + "east": { "uv": [9.75, 2.5, 10.75, 3.75], "texture": "#0" }, + "south": { "uv": [11, 2.5, 11.25, 3.75], "texture": "#0" }, + "west": { "uv": [11.25, 2.5, 12.25, 3.75], "texture": "#0" }, + "up": { "uv": [10.75, 1.5, 11, 2.5], "rotation": 180, "texture": "#0" }, + "down": { "uv": [11, 1.5, 11.25, 2.5], "rotation": 180, "texture": "#0" } + } + }, + { + "name": "Ear2", + "from": [3, 6, 10], + "to": [4, 11, 14], + "rotation": { + "angle": -22.5, + "axis": "z", + "origin": [4, 11, 12] + }, + "faces": { + "north": { "uv": [13.75, 2.5, 14, 3.75], "texture": "#0" }, + "east": { "uv": [12.75, 2.5, 13.75, 3.75], "texture": "#0" }, + "south": { "uv": [14, 2.5, 14.25, 3.75], "texture": "#0" }, + "west": { "uv": [14.25, 2.5, 15.25, 3.75], "texture": "#0" }, + "up": { "uv": [13.75, 1.5, 14, 2.5], "rotation": 180, "texture": "#0" }, + "down": { "uv": [14, 1.5, 14.25, 2.5], "rotation": 180, "texture": "#0" } + } + }, + { + "name": "Tusk1", + "from": [10, 4, 7], + "to": [11, 6, 8], + "rotation": { + "angle": 0, + "axis": "y", + "origin": [8, 7, 8] + }, + "faces": { + "north": { "uv": [0.75, 0.25, 1, 0.75], "texture": "#0" }, + "east": { "uv": [0.75, 0.25, 1, 0.75], "texture": "#0" }, + "south": { "uv": [0, 1.25, 0.25, 1.75], "texture": "#0" }, + "west": { "uv": [0.25, 0.25, 0.5, 0.75], "texture": "#0" }, + "up": { "uv": [0.75, 0, 1, 0.25], "rotation": 180, "texture": "#0" }, + "down": { "uv": [1.25, 0, 1.5, 0.25], "rotation": 180, "texture": "#0" } + } + }, + { + "name": "Tusk2", + "from": [5, 4, 7], + "to": [6, 6, 8], + "rotation": { + "angle": 0, + "axis": "y", + "origin": [8, 7, 8] + }, + "faces": { + "north": { "uv": [0.75, 0.25, 1, 0.75], "texture": "#0" }, + "east": { "uv": [0.25, 0.25, 0.5, 0.75], "texture": "#0" }, + "south": { "uv": [0, 1.25, 0.25, 1.75], "texture": "#0" }, + "west": { "uv": [1, 0.25, 1.25, 0.75], "texture": "#0" }, + "up": { "uv": [0.75, 0, 1, 0.25], "rotation": 180, "texture": "#0" }, + "down": { "uv": [1.25, 0, 1.5, 0.25], "rotation": 180, "texture": "#0" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/player_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/player_head.json new file mode 100644 index 000000000..ef6ee81dc --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/player_head.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/skull_64", + "textures": { + "entity": "entity/player/slim/steve" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/player_wall_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/player_wall_head.json new file mode 100644 index 000000000..48f60c7bb --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/player_wall_head.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_skull_64", + "textures": { + "entity": "entity/player/slim/steve" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/shulker_box.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/shulker_box.json new file mode 100644 index 000000000..0cd6403ca --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/shulker_box.json @@ -0,0 +1,33 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [64, 64], + "textures": { + "0": "entity/shulker/shulker" + }, + "elements": [ + { + "from": [0, 0, 0], + "to": [16, 8, 16], + "faces": { + "north": { "uv": [0, 11, 4, 13], "texture": "#0" }, + "east": { "uv": [0, 11, 4, 13], "texture": "#0" }, + "south": { "uv": [0, 11, 4, 13], "texture": "#0" }, + "west": { "uv": [0, 11, 4, 13], "texture": "#0" }, + "up": { "uv": [0, 0, 4, 4], "texture": "#0" }, + "down": { "uv": [8.25, 7.25, 12, 11], "texture": "#0" } + } + }, + { + "from": [0, 4, 0], + "to": [16, 16, 16], + "faces": { + "north": { "uv": [0, 4, 4, 7], "texture": "#0" }, + "east": { "uv": [0, 4, 4, 7], "texture": "#0" }, + "south": { "uv": [0, 4, 4, 7], "texture": "#0" }, + "west": { "uv": [0, 4, 4, 7], "texture": "#0" }, + "up": { "uv": [4, 0, 8, 4], "texture": "#0" }, + "down": { "uv": [0, 0, 4, 4], "texture": "#0" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/skeleton_skull.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/skeleton_skull.json new file mode 100644 index 000000000..e37d250c9 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/skeleton_skull.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/skull_32", + "textures": { + "entity": "entity/skeleton/skeleton" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/skeleton_wall_skull.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/skeleton_wall_skull.json new file mode 100644 index 000000000..358e30f77 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/skeleton_wall_skull.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_skull_32", + "textures": { + "entity": "entity/skeleton/skeleton" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/skull_32.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/skull_32.json new file mode 100644 index 000000000..d1da88809 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/skull_32.json @@ -0,0 +1,32 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [64, 32], + "elements": [ + { + "name": "Skull", + "from": [4.1, 0, 4.1], + "to": [11.9, 7.9, 11.9], + "faces": { + "north": { "uv": [6, 4, 8, 8], "texture": "#entity" }, + "east": { "uv": [4, 4, 6, 8], "texture": "#entity" }, + "south": { "uv": [2, 4, 4, 8], "texture": "#entity" }, + "west": { "uv": [0, 4, 2, 8], "texture": "#entity" }, + "up": { "uv": [4, 4, 2, 0], "rotation": 180, "texture": "#entity" }, + "down": { "uv": [5.5, 0.5, 3.75, 4], "rotation": 180, "texture": "#entity" } + } + }, + { + "name": "Overlay", + "from": [4, 0, 4], + "to": [12, 8, 12], + "faces": { + "north": { "uv": [14, 4, 16, 8], "texture": "#entity" }, + "east": { "uv": [12, 4, 14, 8], "texture": "#entity" }, + "south": { "uv": [10, 4, 12, 8], "texture": "#entity" }, + "west": { "uv": [8, 4, 10, 8], "texture": "#entity" }, + "up": { "uv": [12, 4, 10, 0], "rotation": 180, "texture": "#entity" }, + "down": { "uv": [14, 0, 12, 4], "rotation": 180, "texture": "#entity" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/skull_64.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/skull_64.json new file mode 100644 index 000000000..a41e4d3cc --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/skull_64.json @@ -0,0 +1,32 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [64, 64], + "elements": [ + { + "name": "Skull", + "from": [4.1, 0, 4.1], + "to": [11.9, 7.9, 11.9], + "faces": { + "north": { "uv": [5.5, 2, 7.5, 4], "texture": "#entity" }, + "east": { "uv": [3.75, 2, 5.75, 4], "texture": "#entity" }, + "south": { "uv": [2, 2, 4, 4], "texture": "#entity" }, + "west": { "uv": [0, 2, 2, 4], "texture": "#entity" }, + "up": { "uv": [4, 2, 2, 0], "rotation": 180, "texture": "#entity" }, + "down": { "uv": [6, 0, 4, 2], "rotation": 180, "texture": "#entity" } + } + }, + { + "name": "Overlay", + "from": [4, 0, 4], + "to": [12, 8, 12], + "faces": { + "north": { "uv": [14, 2, 16, 4], "texture": "#entity" }, + "east": { "uv": [12, 2, 14, 4], "texture": "#entity" }, + "south": { "uv": [10, 2, 12, 4], "texture": "#entity" }, + "west": { "uv": [8, 2, 10, 4], "texture": "#entity" }, + "up": { "uv": [12, 2, 10, 0], "rotation": 180, "texture": "#entity" }, + "down": { "uv": [14, 0, 12, 2], "rotation": 180, "texture": "#entity" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/spruce_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/spruce_hanging_sign.json new file mode 100644 index 000000000..ce157113c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/spruce_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/spruce" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/spruce_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/spruce_wall_hanging_sign.json new file mode 100644 index 000000000..59dc872f1 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/spruce_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/spruce" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wall_banner.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wall_banner.json new file mode 100644 index 000000000..e5d120d6c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wall_banner.json @@ -0,0 +1,35 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [64, 64], + "textures": { + "0": "entity/banner_base" + }, + "elements": [ + { + "name": "Handle", + "from": [1.2, 12.4, 15], + "to": [14.8, 13.4, 16], + "faces": { + "north": { "uv": [0.5, 11.5, 5.5, 12], "texture": "#0" }, + "east": { "uv": [0, 11, 0.5, 11.5], "texture": "#0" }, + "south": { "uv": [5.5, 11.5, 10.5, 12], "texture": "#0" }, + "west": { "uv": [5.5, 11, 6, 11.5], "texture": "#0" }, + "up": { "uv": [5.5, 11, 0.5, 10.5], "texture": "#0" }, + "down": { "uv": [5.5, 11, 0.5, 11.5], "texture": "#0" } + } + }, + { + "name": "Cloth", + "from": [1.2, -14.6, 14.5], + "to": [14.8, 13.4, 15], + "faces": { + "north": { "uv": [0.25, 0.25, 5.5, 10.25], "texture": "#0", "tintindex": 0 }, + "east": { "uv": [0, 0.25, 0.25, 10.25], "texture": "#0", "tintindex": 0 }, + "south": { "uv": [5.5, 0.25, 10.5, 10.25], "texture": "#0", "tintindex": 0 }, + "west": { "uv": [5.5, 0.25, 5.25, 10], "texture": "#0", "tintindex": 0 }, + "up": { "uv": [5.25, 0, 0.25, 0.25], "texture": "#0", "tintindex": 0 }, + "down": { "uv": [5, 0.25, 0.25, 0], "texture": "#0", "tintindex": 0 } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wall_hanging_sign.json new file mode 100644 index 000000000..383762332 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wall_hanging_sign.json @@ -0,0 +1,110 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "ambientocclusion": false, + "texture_size": [64, 32], + "textures": { + "wood": "entity/signs/hanging/oak" + }, + "elements": [ + { + "name": "Sign", + "from": [1, 0, 7], + "to": [15, 10, 9], + "rotation": { + "angle": 0, + "axis": "y", + "origin": [8, 8, 8] + }, + "faces": { + "north": { "uv": [4.5, 7, 8, 12], "texture": "#wood" }, + "east": { "uv": [4, 7, 4.5, 12], "texture": "#wood" }, + "south": { "uv": [0.5, 7, 4, 12], "texture": "#wood" }, + "west": { "uv": [0, 7, 0.5, 12], "texture": "#wood" }, + "up": { "uv": [4, 6, 0.5, 7], "rotation": 180, "texture": "#wood" }, + "down": { "uv": [4, 7, 7.5, 6], "texture": "#wood" } + } + }, + { + "name": "Hanger", + "from": [0, 14, 6], + "to": [16, 16, 10], + "rotation": { + "angle": 0, + "axis": "y", + "origin": [8, 8, 8] + }, + "faces": { + "north": { "uv": [6, 2, 10, 3], "texture": "#wood" }, + "east": { "uv": [0, 2, 1, 3], "texture": "#wood" }, + "south": { "uv": [1, 2, 5, 3], "texture": "#wood" }, + "west": { "uv": [0, 2, 1, 3], "texture": "#wood" }, + "up": { "uv": [1, 0, 5, 2], "rotation": 180, "texture": "#wood" }, + "down": { "uv": [5, 0, 9, 2], "texture": "#wood" } + } + }, + { + "name": "ChainA1", + "from": [4.8, 10, 10.5], + "to": [6.2, 14, 10.5], + "shade": false, + "rotation": { + "angle": -45, + "axis": "y", + "origin": [8, 8, 8], + "rescale": true + }, + "faces": { + "north": { "uv": [1.5, 3, 2.25, 6], "texture": "#wood" }, + "south": { "uv": [1.5, 3, 2.25, 6], "texture": "#wood" } + } + }, + { + "name": "ChainB2", + "from": [10.5, 10, 4.8], + "to": [10.5, 14, 6.2], + "shade": false, + "rotation": { + "angle": -45, + "axis": "y", + "origin": [8, 8, 8], + "rescale": true + }, + "faces": { + "east": { "uv": [0, 3, 0.75, 6], "texture": "#wood" }, + "west": { "uv": [0, 3, 0.75, 6], "texture": "#wood" } + } + }, + { + "name": "ChainB1", + "from": [9.8, 10, 5.5], + "to": [11.2, 14, 5.5], + "shade": false, + "rotation": { + "angle": -45, + "axis": "y", + "origin": [8, 8, 8], + "rescale": true + }, + "faces": { + "north": { "uv": [1.5, 3, 2.25, 6], "texture": "#wood" }, + "south": { "uv": [1.5, 3, 2.25, 6], "texture": "#wood" } + } + }, + { + "name": "ChainA2", + "from": [5.5, 10, 9.8], + "to": [5.5, 14, 11.2], + "shade": false, + "rotation": { + "angle": -45, + "axis": "y", + "origin": [8, 8, 8], + "rescale": true + }, + "faces": { + "east": { "uv": [0, 3, 0.75, 6], "texture": "#wood" }, + "west": { "uv": [0, 3, 0.75, 6], "texture": "#wood" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wall_skull_32.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wall_skull_32.json new file mode 100644 index 000000000..a03aed70c --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wall_skull_32.json @@ -0,0 +1,32 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [64, 32], + "elements": [ + { + "name": "Skull", + "from": [4.1, 4.1, 8.1], + "to": [11.9, 11.9, 16], + "faces": { + "north": { "uv": [2, 4, 4, 8], "texture": "#entity" }, + "east": { "uv": [0, 4, 2, 8], "texture": "#entity" }, + "south": { "uv": [6, 4, 8, 8], "texture": "#entity" }, + "west": { "uv": [4, 4, 6, 8], "texture": "#entity" }, + "up": { "uv": [4, 4, 2, 0], "texture": "#entity" }, + "down": { "uv": [5.5, 0.5, 3.75, 4], "texture": "#entity" } + } + }, + { + "name": "Overlay", + "from": [4, 4, 8], + "to": [12, 12, 16], + "faces": { + "north": { "uv": [10, 4, 12, 8], "texture": "#entity" }, + "east": { "uv": [8.25, 4, 10.25, 8], "texture": "#entity" }, + "south": { "uv": [14, 4, 16, 8], "texture": "#entity" }, + "west": { "uv": [12, 4, 14, 8], "texture": "#entity" }, + "up": { "uv": [12, 4, 10, 0], "texture": "#entity" }, + "down": { "uv": [14, 0, 12, 4], "texture": "#entity" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wall_skull_64.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wall_skull_64.json new file mode 100644 index 000000000..37555d450 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wall_skull_64.json @@ -0,0 +1,32 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "texture_size": [64, 64], + "elements": [ + { + "name": "Skull", + "from": [4.1, 4.1, 8.2], + "to": [11.9, 11.9, 16], + "faces": { + "north": { "uv": [2, 2, 4, 4], "texture": "#entity" }, + "east": { "uv": [0, 2, 2, 4], "texture": "#entity" }, + "south": { "uv": [5.5, 2, 7.5, 4], "texture": "#entity" }, + "west": { "uv": [3.75, 2, 5.75, 4], "texture": "#entity" }, + "up": { "uv": [4, 2, 2, 0], "texture": "#entity" }, + "down": { "uv": [6, 0, 4, 2], "texture": "#entity" } + } + }, + { + "name": "Overlay", + "from": [4, 4, 8], + "to": [12, 12, 16], + "faces": { + "north": { "uv": [10, 2, 12, 4], "texture": "#entity" }, + "east": { "uv": [8, 2, 10, 4], "texture": "#entity" }, + "south": { "uv": [14, 2, 16, 4], "texture": "#entity" }, + "west": { "uv": [12, 2, 14, 4], "texture": "#entity" }, + "up": { "uv": [12, 2, 10, 0], "texture": "#entity" }, + "down": { "uv": [14, 0, 12, 2], "texture": "#entity" } + } + } + ] +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/warped_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/warped_hanging_sign.json new file mode 100644 index 000000000..f04b36cbd --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/warped_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/warped" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/warped_wall_hanging_sign.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/warped_wall_hanging_sign.json new file mode 100644 index 000000000..cd9301fd1 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/warped_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_hanging_sign", + "textures": { + "wood": "minecraft:entity/signs/hanging/warped" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wither_skeleton_skull.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wither_skeleton_skull.json new file mode 100644 index 000000000..8c6ca71a6 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wither_skeleton_skull.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/skull_32", + "textures": { + "entity": "entity/skeleton/wither_skeleton" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wither_skeleton_wall_skull.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wither_skeleton_wall_skull.json new file mode 100644 index 000000000..9e3e0160b --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/wither_skeleton_wall_skull.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_skull_32", + "textures": { + "entity": "entity/skeleton/wither_skeleton" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/zombie_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/zombie_head.json new file mode 100644 index 000000000..92936d890 --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/zombie_head.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/skull_64", + "textures": { + "entity": "entity/zombie/zombie" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/zombie_wall_head.json b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/zombie_wall_head.json new file mode 100644 index 000000000..bcde6703f --- /dev/null +++ b/BlueMapCore/src/main/resourceExtensions/assets/minecraft/models/entity/zombie_wall_head.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "minecraft:entity/wall_skull_64", + "textures": { + "entity": "entity/zombie/zombie" + } +} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/bluemap/blockstates/missing.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/bluemap/blockstates/missing.json deleted file mode 100644 index d917d257a..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/bluemap/blockstates/missing.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "variants": { - "": { "model": "bluemap:block/missing" } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/bluemap/models/block/missing.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/bluemap/models/block/missing.json deleted file mode 100644 index 5995c0c01..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/bluemap/models/block/missing.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "block/cube_all", - "textures": { - "all": "bluemap:block/missing" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/biomes.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/biomes.json deleted file mode 100644 index b14a8d348..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/biomes.json +++ /dev/null @@ -1,395 +0,0 @@ -{ - "minecraft:ocean": { - "humidity": 0.5, - "temperature": 0.5, - "watercolor": 4159204 - }, - "minecraft:plains": { - "humidity": 0.4, - "temperature": 0.8, - "watercolor": 4159204 - }, - "minecraft:desert": { - "humidity": 0.0, - "temperature": 2.0, - "watercolor": 4159204 - }, - "minecraft:mountains": { - "humidity": 0.3, - "temperature": 0.2, - "watercolor": 4159204 - }, - "minecraft:forest": { - "humidity": 0.8, - "temperature": 0.7, - "watercolor": 4159204 - }, - "minecraft:taiga": { - "humidity": 0.8, - "temperature": 0.25, - "watercolor": 4159204 - }, - "minecraft:swamp": { - "humidity": 0.9, - "temperature": 0.8, - "foliagecolor": "#6A7039", - "grasscolor": "#6A7039", - "watercolor": 6388580 - }, - "minecraft:river": { - "humidity": 0.5, - "temperature": 0.5, - "watercolor": 4159204 - }, - "minecraft:nether": { - "humidity": 0.0, - "temperature": 2.0, - "watercolor": 4159204 - }, - "minecraft:the_end": { - "humidity": 0.5, - "temperature": 0.5, - "watercolor": 4159204 - }, - "minecraft:frozen_ocean": { - "humidity": 0.5, - "temperature": 0.0, - "watercolor": 3750089 - }, - "minecraft:frozen_river": { - "humidity": 0.5, - "temperature": 0.0, - "watercolor": 3750089 - }, - "minecraft:snowy_tundra": { - "humidity": 0.5, - "temperature": 0.0, - "watercolor": 4159204 - }, - "minecraft:snowy_mountains": { - "humidity": 0.5, - "temperature": 0.0, - "watercolor": 4159204 - }, - "minecraft:mushroom_fields": { - "humidity": 1.0, - "temperature": 0.9, - "watercolor": 4159204 - }, - "minecraft:mushroom_field_shore": { - "humidity": 1.0, - "temperature": 0.9, - "watercolor": 4159204 - }, - "minecraft:beach": { - "humidity": 0.4, - "temperature": 0.8, - "watercolor": 4159204 - }, - "minecraft:desert_hills": { - "humidity": 0.0, - "temperature": 2.0, - "watercolor": 4159204 - }, - "minecraft:wooded_hills": { - "humidity": 0.8, - "temperature": 0.7, - "watercolor": 4159204 - }, - "minecraft:taiga_hills": { - "humidity": 0.8, - "temperature": 0.25, - "watercolor": 4159204 - }, - "minecraft:mountain_edge": { - "humidity": 0.3, - "temperature": 0.2, - "watercolor": 4159204 - }, - "minecraft:jungle": { - "humidity": 0.9, - "temperature": 0.95, - "watercolor": 4159204 - }, - "minecraft:jungle_hills": { - "humidity": 0.9, - "temperature": 0.95, - "watercolor": 4159204 - }, - "minecraft:jungle_edge": { - "humidity": 0.8, - "temperature": 0.95, - "watercolor": 4159204 - }, - "minecraft:deep_ocean": { - "humidity": 0.5, - "temperature": 0.5, - "watercolor": 4159204 - }, - "minecraft:stone_shore": { - "humidity": 0.3, - "temperature": 0.2, - "watercolor": 4159204 - }, - "minecraft:snowy_beach": { - "humidity": 0.3, - "temperature": 0.05, - "watercolor": 4020182 - }, - "minecraft:birch_forest": { - "humidity": 0.6, - "temperature": 0.6, - "watercolor": 4159204 - }, - "minecraft:birch_forest_hills": { - "humidity": 0.6, - "temperature": 0.6, - "watercolor": 4159204 - }, - "minecraft:dark_forest": { - "humidity": 0.8, - "temperature": 0.7, - "foliagecolor": "#28340a55", - "grasscolor": "#28340a88", - "watercolor": 4159204 - }, - "minecraft:snowy_taiga": { - "humidity": 0.4, - "temperature": -0.5, - "watercolor": 4020182 - }, - "minecraft:snowy_taiga_hills": { - "humidity": 0.4, - "temperature": -0.5, - "watercolor": 4020182 - }, - "minecraft:giant_tree_taiga": { - "humidity": 0.8, - "temperature": 0.3, - "watercolor": 4159204 - }, - "minecraft:giant_tree_taiga_hills": { - "humidity": 0.8, - "temperature": 0.3, - "watercolor": 4159204 - }, - "minecraft:wooded_mountains": { - "humidity": 0.3, - "temperature": 0.2, - "watercolor": 4159204 - }, - "minecraft:savanna": { - "humidity": 0.0, - "temperature": 1.2, - "watercolor": 4159204 - }, - "minecraft:savanna_plateau": { - "humidity": 0.0, - "temperature": 1.0, - "watercolor": 4159204 - }, - "minecraft:badlands": { - "humidity": 0.0, - "temperature": 2.0, - "foliagecolor": "#9e814d", - "grasscolor": "#90814d", - "watercolor": 4159204 - }, - "minecraft:wooded_badlands_plateau": { - "humidity": 0.0, - "temperature": 2.0, - "foliagecolor": "#9e814d", - "grasscolor": "#90814d", - "watercolor": 4159204 - }, - "minecraft:badlands_plateau": { - "humidity": 0.0, - "temperature": 2.0, - "foliagecolor": "#9e814d", - "grasscolor": "#90814d", - "watercolor": 4159204 - }, - "minecraft:small_end_islands": { - "humidity": 0.5, - "temperature": 0.5, - "watercolor": 4159204 - }, - "minecraft:end_midlands": { - "humidity": 0.5, - "temperature": 0.5, - "watercolor": 4159204 - }, - "minecraft:end_highlands": { - "humidity": 0.5, - "temperature": 0.5, - "watercolor": 4159204 - }, - "minecraft:end_barrens": { - "humidity": 0.5, - "temperature": 0.5, - "watercolor": 4159204 - }, - "minecraft:warm_ocean": { - "humidity": 0.5, - "temperature": 0.5, - "watercolor": 4445678 - }, - "minecraft:lukewarm_ocean": { - "humidity": 0.5, - "temperature": 0.5, - "watercolor": 4566514 - }, - "minecraft:cold_ocean": { - "humidity": 0.5, - "temperature": 0.5, - "watercolor": 4020182 - }, - "minecraft:deep_warm_ocean": { - "humidity": 0.5, - "temperature": 0.5, - "watercolor": 4445678 - }, - "minecraft:deep_lukewarm_ocean": { - "humidity": 0.5, - "temperature": 0.5, - "watercolor": 4566514 - }, - "minecraft:deep_cold_ocean": { - "humidity": 0.5, - "temperature": 0.5, - "watercolor": 4020182 - }, - "minecraft:deep_frozen_ocean": { - "humidity": 0.5, - "temperature": 0.5, - "watercolor": 3750089 - }, - "minecraft:the_void": { - "humidity": 0.5, - "temperature": 0.5, - "watercolor": 4159204 - }, - "minecraft:sunflower_plains": { - "humidity": 0.4, - "temperature": 0.8, - "watercolor": 4159204 - }, - "minecraft:desert_lakes": { - "humidity": 0.0, - "temperature": 2.0, - "watercolor": 4159204 - }, - "minecraft:gravelly_mountains": { - "humidity": 0.3, - "temperature": 0.2, - "watercolor": 4159204 - }, - "minecraft:flower_forest": { - "humidity": 0.8, - "temperature": 0.7, - "watercolor": 4159204 - }, - "minecraft:taiga_mountains": { - "humidity": 0.8, - "temperature": 0.25, - "watercolor": 4159204 - }, - "minecraft:swamp_hills": { - "humidity": 0.9, - "temperature": 0.8, - "foliagecolor": "#6A7039", - "grasscolor": "#6A7039", - "watercolor": 6388580 - }, - "minecraft:ice_spikes": { - "humidity": 0.5, - "temperature": 0.0, - "watercolor": 4159204 - }, - "minecraft:modified_jungle": { - "humidity": 0.9, - "temperature": 0.95, - "watercolor": 4159204 - }, - "minecraft:modified_jungle_edge": { - "humidity": 0.8, - "temperature": 0.95, - "watercolor": 4159204 - }, - "minecraft:tall_birch_forest": { - "humidity": 0.6, - "temperature": 0.6, - "watercolor": 4159204 - }, - "minecraft:tall_birch_hills": { - "humidity": 0.6, - "temperature": 0.6, - "watercolor": 4159204 - }, - "minecraft:dark_forest_hills": { - "humidity": 0.8, - "temperature": 0.7, - "foliagecolor": "#28340a55", - "grasscolor": "#28340a88", - "watercolor": 4159204 - }, - "minecraft:snowy_taiga_mountains": { - "humidity": 0.4, - "temperature": -0.5, - "watercolor": 4020182 - }, - "minecraft:giant_spruce_taiga": { - "humidity": 0.8, - "temperature": 0.25, - "watercolor": 4159204 - }, - "minecraft:giant_spruce_taiga_hills": { - "humidity": 0.8, - "temperature": 0.25, - "watercolor": 4159204 - }, - "minecraft:modified_gravelly_mountains": { - "humidity": 0.3, - "temperature": 0.2, - "watercolor": 4159204 - }, - "minecraft:shattered_savanna": { - "humidity": 0.0, - "temperature": 1.1, - "watercolor": 4159204 - }, - "minecraft:shattered_savanna_plateau": { - "humidity": 0.0, - "temperature": 1.0, - "watercolor": 4159204 - }, - "minecraft:eroded_badlands": { - "humidity": 0.0, - "temperature": 2.0, - "foliagecolor": "#9e814d", - "grasscolor": "#90814d", - "watercolor": 4159204 - }, - "minecraft:modified_wooded_badlands_plateau": { - "humidity": 0.0, - "temperature": 2.0, - "watercolor": 4159204 - }, - "minecraft:modified_badlands_plateau": { - "humidity": 0.0, - "temperature": 2.0, - "foliagecolor": "#9e814d", - "grasscolor": "#90814d", - "watercolor": 4159204 - }, - "minecraft:bamboo_jungle": { - "humidity": 0.9, - "temperature": 0.95, - "watercolor": 4159204 - }, - "minecraft:bamboo_jungle_hills": { - "humidity": 0.9, - "temperature": 0.95, - "watercolor": 4159204 - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockColors.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockColors.json deleted file mode 100644 index 6cf0cac39..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockColors.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "default": "@foliage", - "minecraft:water": "@water", - "minecraft:cauldron": "@water", - "minecraft:grass_block": "@grass", - "minecraft:grass": "@grass", - "minecraft:tall_grass": "@grass", - "minecraft:fern": "@grass", - "minecraft:large_fern": "@grass", - "minecraft:redstone_wire": "@redstone", - "minecraft:birch_leaves": 8431445, - "minecraft:spruce_leaves": 6396257, - "minecraft:stonecutter": "#ffffff", - "minecraft:snow": "#ffffff" -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockProperties.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockProperties.json deleted file mode 100644 index d319683a0..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockProperties.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "minecraft:seagrass": { "alwaysWaterlogged": true }, - "minecraft:tall_seagrass": { "alwaysWaterlogged": true }, - "minecraft:kelp": { "alwaysWaterlogged": true }, - "minecraft:kelp_plant": { "alwaysWaterlogged": true }, - "minecraft:bubble_column": { "alwaysWaterlogged": true }, - - "minecraft:grass": { "randomOffset": true }, - "minecraft:tall_grass": { "randomOffset": true }, - "minecraft:fern": { "randomOffset": true }, - "minecraft:dandelion": { "randomOffset": true }, - "minecraft:cornflower": { "randomOffset": true }, - "minecraft:poppy": { "randomOffset": true }, - "minecraft:blue_orchid": { "randomOffset": true }, - "minecraft:allium": { "randomOffset": true }, - "minecraft:azure_bluet": { "randomOffset": true }, - "minecraft:red_tulip": { "randomOffset": true }, - "minecraft:orange_tulip": { "randomOffset": true }, - "minecraft:white_tulip": { "randomOffset": true }, - "minecraft:pink_tulip": { "randomOffset": true }, - "minecraft:oxeye_daisy": { "randomOffset": true }, - "minecraft:lily_of_the_valley": { "randomOffset": true }, - "minecraft:wither_rose": { "randomOffset": true }, - "minecraft:crimson_roots": { "randomOffset": true }, - "minecraft:warped_roots": { "randomOffset": true }, - "minecraft:nether_sprouts": { "randomOffset": true }, - "minecraft:rose_bush": { "randomOffset": true }, - "minecraft:peony": { "randomOffset": true }, - "minecraft:lilac": { "randomOffset": true }, - "minecraft:sunflower": { "randomOffset": true }, - "minecraft:hanging_roots": { "randomOffset": true }, - "minecraft:small_dripleaf": { "randomOffset": true }, - - "minecraft:glass": { "occluding": false, "cullingIdentical": true }, - "minecraft:tinted_glass": { "occluding": false, "cullingIdentical": true }, - "minecraft:white_stained_glass": { "occluding": false, "cullingIdentical": true }, - "minecraft:orange_stained_glass": { "occluding": false, "cullingIdentical": true }, - "minecraft:magenta_stained_glass": { "occluding": false, "cullingIdentical": true }, - "minecraft:light_blue_stained_glass": { "occluding": false, "cullingIdentical": true }, - "minecraft:yellow_stained_glass": { "occluding": false, "cullingIdentical": true }, - "minecraft:lime_stained_glass": { "occluding": false, "cullingIdentical": true }, - "minecraft:pink_stained_glass": { "occluding": false, "cullingIdentical": true }, - "minecraft:gray_stained_glass": { "occluding": false, "cullingIdentical": true }, - "minecraft:light_gray_stained_glass": { "occluding": false, "cullingIdentical": true }, - "minecraft:cyan_stained_glass": { "occluding": false, "cullingIdentical": true }, - "minecraft:purple_stained_glass": { "occluding": false, "cullingIdentical": true }, - "minecraft:blue_stained_glass": { "occluding": false, "cullingIdentical": true }, - "minecraft:brown_stained_glass": { "occluding": false, "cullingIdentical": true }, - "minecraft:green_stained_glass": { "occluding": false, "cullingIdentical": true }, - "minecraft:red_stained_glass": { "occluding": false, "cullingIdentical": true }, - "minecraft:black_stained_glass": { "occluding": false, "cullingIdentical": true }, - - "minecraft:ice": { "cullingIdentical": true } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/acacia_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/acacia_sign.json deleted file mode 100644 index 7bde7036a..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/acacia_sign.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "variants": { - "rotation=0": { "model": "block/sign/acacia" }, - "rotation=1": { "model": "block/sign/acacia", "y": 22.5 }, - "rotation=2": { "model": "block/sign/acacia", "y": 45 }, - "rotation=3": { "model": "block/sign/acacia", "y": 67.5 }, - "rotation=4": { "model": "block/sign/acacia", "y": 90 }, - "rotation=5": { "model": "block/sign/acacia", "y": 112.5 }, - "rotation=6": { "model": "block/sign/acacia", "y": 135 }, - "rotation=7": { "model": "block/sign/acacia", "y": 157.5 }, - "rotation=8": { "model": "block/sign/acacia", "y": 180 }, - "rotation=9": { "model": "block/sign/acacia", "y": 202.5 }, - "rotation=10": { "model": "block/sign/acacia", "y": 225 }, - "rotation=11": { "model": "block/sign/acacia", "y": 247.5 }, - "rotation=12": { "model": "block/sign/acacia", "y": 270 }, - "rotation=13": { "model": "block/sign/acacia", "y": 292.5 }, - "rotation=14": { "model": "block/sign/acacia", "y": 315 }, - "rotation=15": { "model": "block/sign/acacia", "y": 337.5 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/birch_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/birch_sign.json deleted file mode 100644 index 3aff1cba2..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/birch_sign.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "variants": { - "rotation=0": { "model": "block/sign/birch" }, - "rotation=1": { "model": "block/sign/birch", "y": 22.5 }, - "rotation=2": { "model": "block/sign/birch", "y": 45 }, - "rotation=3": { "model": "block/sign/birch", "y": 67.5 }, - "rotation=4": { "model": "block/sign/birch", "y": 90 }, - "rotation=5": { "model": "block/sign/birch", "y": 112.5 }, - "rotation=6": { "model": "block/sign/birch", "y": 135 }, - "rotation=7": { "model": "block/sign/birch", "y": 157.5 }, - "rotation=8": { "model": "block/sign/birch", "y": 180 }, - "rotation=9": { "model": "block/sign/birch", "y": 202.5 }, - "rotation=10": { "model": "block/sign/birch", "y": 225 }, - "rotation=11": { "model": "block/sign/birch", "y": 247.5 }, - "rotation=12": { "model": "block/sign/birch", "y": 270 }, - "rotation=13": { "model": "block/sign/birch", "y": 292.5 }, - "rotation=14": { "model": "block/sign/birch", "y": 315 }, - "rotation=15": { "model": "block/sign/birch", "y": 337.5 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/black_bed.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/black_bed.json deleted file mode 100644 index c475b18ce..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/black_bed.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "variants": { - "part=head,facing=north": { "model": "block/bed/black_head" }, - "part=head,facing=east": { "model": "block/bed/black_head", "y": 90 }, - "part=head,facing=south": { "model": "block/bed/black_head", "y": 180 }, - "part=head,facing=west": { "model": "block/bed/black_head", "y": 270 }, - "part=foot,facing=north": { "model": "block/bed/black_foot" }, - "part=foot,facing=east": { "model": "block/bed/black_foot", "y": 90 }, - "part=foot,facing=south": { "model": "block/bed/black_foot", "y": 180 }, - "part=foot,facing=west": { "model": "block/bed/black_foot", "y": 270 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/blue_bed.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/blue_bed.json deleted file mode 100644 index e16bf1317..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/blue_bed.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "variants": { - "part=head,facing=north": { "model": "block/bed/blue_head" }, - "part=head,facing=east": { "model": "block/bed/blue_head", "y": 90 }, - "part=head,facing=south": { "model": "block/bed/blue_head", "y": 180 }, - "part=head,facing=west": { "model": "block/bed/blue_head", "y": 270 }, - "part=foot,facing=north": { "model": "block/bed/blue_foot" }, - "part=foot,facing=east": { "model": "block/bed/blue_foot", "y": 90 }, - "part=foot,facing=south": { "model": "block/bed/blue_foot", "y": 180 }, - "part=foot,facing=west": { "model": "block/bed/blue_foot", "y": 270 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/brown_bed.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/brown_bed.json deleted file mode 100644 index 44c1ab9c6..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/brown_bed.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "variants": { - "part=head,facing=north": { "model": "block/bed/brown_head" }, - "part=head,facing=east": { "model": "block/bed/brown_head", "y": 90 }, - "part=head,facing=south": { "model": "block/bed/brown_head", "y": 180 }, - "part=head,facing=west": { "model": "block/bed/brown_head", "y": 270 }, - "part=foot,facing=north": { "model": "block/bed/brown_foot" }, - "part=foot,facing=east": { "model": "block/bed/brown_foot", "y": 90 }, - "part=foot,facing=south": { "model": "block/bed/brown_foot", "y": 180 }, - "part=foot,facing=west": { "model": "block/bed/brown_foot", "y": 270 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/bubble_column.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/bubble_column.json deleted file mode 100644 index f047e558c..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/bubble_column.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "variants": { - "": { "model": "block/bubble_column" } - } -} diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/chest.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/chest.json deleted file mode 100644 index dd59d70ea..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/chest.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "variants": { - "type=single,facing=north": { "model": "block/chest/normal", "y": 180 }, - "type=single,facing=east": { "model": "block/chest/normal", "y": 270 }, - "type=single,facing=south": { "model": "block/chest/normal" }, - "type=single,facing=west": { "model": "block/chest/normal", "y":90 }, - "type=right,facing=north": { "model": "block/chest/normal_double", "y": 180 }, - "type=right,facing=east": { "model": "block/chest/normal_double", "y": 270 }, - "type=right,facing=south": { "model": "block/chest/normal_double" }, - "type=right,facing=west": { "model": "block/chest/normal_double", "y":90 }, - "type=left": { "model": "block/chest/left" } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/cyan_bed.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/cyan_bed.json deleted file mode 100644 index 2b1f6b7c7..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/cyan_bed.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "variants": { - "part=head,facing=north": { "model": "block/bed/cyan_head" }, - "part=head,facing=east": { "model": "block/bed/cyan_head", "y": 90 }, - "part=head,facing=south": { "model": "block/bed/cyan_head", "y": 180 }, - "part=head,facing=west": { "model": "block/bed/cyan_head", "y": 270 }, - "part=foot,facing=north": { "model": "block/bed/cyan_foot" }, - "part=foot,facing=east": { "model": "block/bed/cyan_foot", "y": 90 }, - "part=foot,facing=south": { "model": "block/bed/cyan_foot", "y": 180 }, - "part=foot,facing=west": { "model": "block/bed/cyan_foot", "y": 270 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/dark_oak_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/dark_oak_sign.json deleted file mode 100644 index 06e07f022..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/dark_oak_sign.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "variants": { - "rotation=0": { "model": "block/sign/dark_oak" }, - "rotation=1": { "model": "block/sign/dark_oak", "y": 22.5 }, - "rotation=2": { "model": "block/sign/dark_oak", "y": 45 }, - "rotation=3": { "model": "block/sign/dark_oak", "y": 67.5 }, - "rotation=4": { "model": "block/sign/dark_oak", "y": 90 }, - "rotation=5": { "model": "block/sign/dark_oak", "y": 112.5 }, - "rotation=6": { "model": "block/sign/dark_oak", "y": 135 }, - "rotation=7": { "model": "block/sign/dark_oak", "y": 157.5 }, - "rotation=8": { "model": "block/sign/dark_oak", "y": 180 }, - "rotation=9": { "model": "block/sign/dark_oak", "y": 202.5 }, - "rotation=10": { "model": "block/sign/dark_oak", "y": 225 }, - "rotation=11": { "model": "block/sign/dark_oak", "y": 247.5 }, - "rotation=12": { "model": "block/sign/dark_oak", "y": 270 }, - "rotation=13": { "model": "block/sign/dark_oak", "y": 292.5 }, - "rotation=14": { "model": "block/sign/dark_oak", "y": 315 }, - "rotation=15": { "model": "block/sign/dark_oak", "y": 337.5 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/ender_chest.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/ender_chest.json deleted file mode 100644 index 23d9dedc9..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/ender_chest.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "variants": { - "facing=north": { "model": "block/chest/ender", "y": 180 }, - "facing=east": { "model": "block/chest/ender", "y": 270 }, - "facing=south": { "model": "block/chest/ender" }, - "facing=west": { "model": "block/chest/ender", "y":90 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/gray_bed.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/gray_bed.json deleted file mode 100644 index a731191d0..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/gray_bed.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "variants": { - "part=head,facing=north": { "model": "block/bed/gray_head" }, - "part=head,facing=east": { "model": "block/bed/gray_head", "y": 90 }, - "part=head,facing=south": { "model": "block/bed/gray_head", "y": 180 }, - "part=head,facing=west": { "model": "block/bed/gray_head", "y": 270 }, - "part=foot,facing=north": { "model": "block/bed/gray_foot" }, - "part=foot,facing=east": { "model": "block/bed/gray_foot", "y": 90 }, - "part=foot,facing=south": { "model": "block/bed/gray_foot", "y": 180 }, - "part=foot,facing=west": { "model": "block/bed/gray_foot", "y": 270 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/green_bed.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/green_bed.json deleted file mode 100644 index 2c26704bc..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/green_bed.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "variants": { - "part=head,facing=north": { "model": "block/bed/green_head" }, - "part=head,facing=east": { "model": "block/bed/green_head", "y": 90 }, - "part=head,facing=south": { "model": "block/bed/green_head", "y": 180 }, - "part=head,facing=west": { "model": "block/bed/green_head", "y": 270 }, - "part=foot,facing=north": { "model": "block/bed/green_foot" }, - "part=foot,facing=east": { "model": "block/bed/green_foot", "y": 90 }, - "part=foot,facing=south": { "model": "block/bed/green_foot", "y": 180 }, - "part=foot,facing=west": { "model": "block/bed/green_foot", "y": 270 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/jungle_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/jungle_sign.json deleted file mode 100644 index a2f96d3e7..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/jungle_sign.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "variants": { - "rotation=0": { "model": "block/sign/jungle" }, - "rotation=1": { "model": "block/sign/jungle", "y": 22.5 }, - "rotation=2": { "model": "block/sign/jungle", "y": 45 }, - "rotation=3": { "model": "block/sign/jungle", "y": 67.5 }, - "rotation=4": { "model": "block/sign/jungle", "y": 90 }, - "rotation=5": { "model": "block/sign/jungle", "y": 112.5 }, - "rotation=6": { "model": "block/sign/jungle", "y": 135 }, - "rotation=7": { "model": "block/sign/jungle", "y": 157.5 }, - "rotation=8": { "model": "block/sign/jungle", "y": 180 }, - "rotation=9": { "model": "block/sign/jungle", "y": 202.5 }, - "rotation=10": { "model": "block/sign/jungle", "y": 225 }, - "rotation=11": { "model": "block/sign/jungle", "y": 247.5 }, - "rotation=12": { "model": "block/sign/jungle", "y": 270 }, - "rotation=13": { "model": "block/sign/jungle", "y": 292.5 }, - "rotation=14": { "model": "block/sign/jungle", "y": 315 }, - "rotation=15": { "model": "block/sign/jungle", "y": 337.5 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/lava.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/lava.json deleted file mode 100644 index d6adbba49..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/lava.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "variants": { - "": { "model": "block/lava" } - } -} diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/lime_bed.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/lime_bed.json deleted file mode 100644 index 77dd6cc63..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/lime_bed.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "variants": { - "part=head,facing=north": { "model": "block/bed/lime_head" }, - "part=head,facing=east": { "model": "block/bed/lime_head", "y": 90 }, - "part=head,facing=south": { "model": "block/bed/lime_head", "y": 180 }, - "part=head,facing=west": { "model": "block/bed/lime_head", "y": 270 }, - "part=foot,facing=north": { "model": "block/bed/lime_foot" }, - "part=foot,facing=east": { "model": "block/bed/lime_foot", "y": 90 }, - "part=foot,facing=south": { "model": "block/bed/lime_foot", "y": 180 }, - "part=foot,facing=west": { "model": "block/bed/lime_foot", "y": 270 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/magenta_bed.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/magenta_bed.json deleted file mode 100644 index 717f1183b..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/magenta_bed.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "variants": { - "part=head,facing=north": { "model": "block/bed/magenta_head" }, - "part=head,facing=east": { "model": "block/bed/magenta_head", "y": 90 }, - "part=head,facing=south": { "model": "block/bed/magenta_head", "y": 180 }, - "part=head,facing=west": { "model": "block/bed/magenta_head", "y": 270 }, - "part=foot,facing=north": { "model": "block/bed/magenta_foot" }, - "part=foot,facing=east": { "model": "block/bed/magenta_foot", "y": 90 }, - "part=foot,facing=south": { "model": "block/bed/magenta_foot", "y": 180 }, - "part=foot,facing=west": { "model": "block/bed/magenta_foot", "y": 270 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/oak_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/oak_sign.json deleted file mode 100644 index 567ec7783..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/oak_sign.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "variants": { - "rotation=0": { "model": "block/sign/oak" }, - "rotation=1": { "model": "block/sign/oak", "y": 22.5 }, - "rotation=2": { "model": "block/sign/oak", "y": 45 }, - "rotation=3": { "model": "block/sign/oak", "y": 67.5 }, - "rotation=4": { "model": "block/sign/oak", "y": 90 }, - "rotation=5": { "model": "block/sign/oak", "y": 112.5 }, - "rotation=6": { "model": "block/sign/oak", "y": 135 }, - "rotation=7": { "model": "block/sign/oak", "y": 157.5 }, - "rotation=8": { "model": "block/sign/oak", "y": 180 }, - "rotation=9": { "model": "block/sign/oak", "y": 202.5 }, - "rotation=10": { "model": "block/sign/oak", "y": 225 }, - "rotation=11": { "model": "block/sign/oak", "y": 247.5 }, - "rotation=12": { "model": "block/sign/oak", "y": 270 }, - "rotation=13": { "model": "block/sign/oak", "y": 292.5 }, - "rotation=14": { "model": "block/sign/oak", "y": 315 }, - "rotation=15": { "model": "block/sign/oak", "y": 337.5 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/orange_bed.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/orange_bed.json deleted file mode 100644 index 13bf33beb..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/orange_bed.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "variants": { - "part=head,facing=north": { "model": "block/bed/orange_head" }, - "part=head,facing=east": { "model": "block/bed/orange_head", "y": 90 }, - "part=head,facing=south": { "model": "block/bed/orange_head", "y": 180 }, - "part=head,facing=west": { "model": "block/bed/orange_head", "y": 270 }, - "part=foot,facing=north": { "model": "block/bed/orange_foot" }, - "part=foot,facing=east": { "model": "block/bed/orange_foot", "y": 90 }, - "part=foot,facing=south": { "model": "block/bed/orange_foot", "y": 180 }, - "part=foot,facing=west": { "model": "block/bed/orange_foot", "y": 270 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/pink_bed.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/pink_bed.json deleted file mode 100644 index 9237c82f0..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/pink_bed.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "variants": { - "part=head,facing=north": { "model": "block/bed/pink_head" }, - "part=head,facing=east": { "model": "block/bed/pink_head", "y": 90 }, - "part=head,facing=south": { "model": "block/bed/pink_head", "y": 180 }, - "part=head,facing=west": { "model": "block/bed/pink_head", "y": 270 }, - "part=foot,facing=north": { "model": "block/bed/pink_foot" }, - "part=foot,facing=east": { "model": "block/bed/pink_foot", "y": 90 }, - "part=foot,facing=south": { "model": "block/bed/pink_foot", "y": 180 }, - "part=foot,facing=west": { "model": "block/bed/pink_foot", "y": 270 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/purple_bed.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/purple_bed.json deleted file mode 100644 index 39bda4f01..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/purple_bed.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "variants": { - "part=head,facing=north": { "model": "block/bed/purple_head" }, - "part=head,facing=east": { "model": "block/bed/purple_head", "y": 90 }, - "part=head,facing=south": { "model": "block/bed/purple_head", "y": 180 }, - "part=head,facing=west": { "model": "block/bed/purple_head", "y": 270 }, - "part=foot,facing=north": { "model": "block/bed/purple_foot" }, - "part=foot,facing=east": { "model": "block/bed/purple_foot", "y": 90 }, - "part=foot,facing=south": { "model": "block/bed/purple_foot", "y": 180 }, - "part=foot,facing=west": { "model": "block/bed/purple_foot", "y": 270 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/red_bed.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/red_bed.json deleted file mode 100644 index ebb872d94..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/red_bed.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "variants": { - "part=head,facing=north": { "model": "block/bed/red_head" }, - "part=head,facing=east": { "model": "block/bed/red_head", "y": 90 }, - "part=head,facing=south": { "model": "block/bed/red_head", "y": 180 }, - "part=head,facing=west": { "model": "block/bed/red_head", "y": 270 }, - "part=foot,facing=north": { "model": "block/bed/red_foot" }, - "part=foot,facing=east": { "model": "block/bed/red_foot", "y": 90 }, - "part=foot,facing=south": { "model": "block/bed/red_foot", "y": 180 }, - "part=foot,facing=west": { "model": "block/bed/red_foot", "y": 270 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/spruce_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/spruce_sign.json deleted file mode 100644 index e592a6991..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/spruce_sign.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "variants": { - "rotation=0": { "model": "block/sign/spruce" }, - "rotation=1": { "model": "block/sign/spruce", "y": 22.5 }, - "rotation=2": { "model": "block/sign/spruce", "y": 45 }, - "rotation=3": { "model": "block/sign/spruce", "y": 67.5 }, - "rotation=4": { "model": "block/sign/spruce", "y": 90 }, - "rotation=5": { "model": "block/sign/spruce", "y": 112.5 }, - "rotation=6": { "model": "block/sign/spruce", "y": 135 }, - "rotation=7": { "model": "block/sign/spruce", "y": 157.5 }, - "rotation=8": { "model": "block/sign/spruce", "y": 180 }, - "rotation=9": { "model": "block/sign/spruce", "y": 202.5 }, - "rotation=10": { "model": "block/sign/spruce", "y": 225 }, - "rotation=11": { "model": "block/sign/spruce", "y": 247.5 }, - "rotation=12": { "model": "block/sign/spruce", "y": 270 }, - "rotation=13": { "model": "block/sign/spruce", "y": 292.5 }, - "rotation=14": { "model": "block/sign/spruce", "y": 315 }, - "rotation=15": { "model": "block/sign/spruce", "y": 337.5 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/water.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/water.json deleted file mode 100644 index 48ff0ea4e..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/water.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "variants": { - "": { "model": "block/water" } - } -} diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/white_bed.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/white_bed.json deleted file mode 100644 index 133bd10d3..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/white_bed.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "variants": { - "part=head,facing=north": { "model": "block/bed/white_head" }, - "part=head,facing=east": { "model": "block/bed/white_head", "y": 90 }, - "part=head,facing=south": { "model": "block/bed/white_head", "y": 180 }, - "part=head,facing=west": { "model": "block/bed/white_head", "y": 270 }, - "part=foot,facing=north": { "model": "block/bed/white_foot" }, - "part=foot,facing=east": { "model": "block/bed/white_foot", "y": 90 }, - "part=foot,facing=south": { "model": "block/bed/white_foot", "y": 180 }, - "part=foot,facing=west": { "model": "block/bed/white_foot", "y": 270 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/yellow_bed.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/yellow_bed.json deleted file mode 100644 index 48ef5c14e..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/blockstates/yellow_bed.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "variants": { - "part=head,facing=north": { "model": "block/bed/yellow_head" }, - "part=head,facing=east": { "model": "block/bed/yellow_head", "y": 90 }, - "part=head,facing=south": { "model": "block/bed/yellow_head", "y": 180 }, - "part=head,facing=west": { "model": "block/bed/yellow_head", "y": 270 }, - "part=foot,facing=north": { "model": "block/bed/yellow_foot" }, - "part=foot,facing=east": { "model": "block/bed/yellow_foot", "y": 90 }, - "part=foot,facing=south": { "model": "block/bed/yellow_foot", "y": 180 }, - "part=foot,facing=west": { "model": "block/bed/yellow_foot", "y": 270 } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/bed_foot.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/bed_foot.json deleted file mode 100644 index b40ef14ed..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/bed_foot.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "elements": [ - { - "from": [0, 0, 13], - "to": [3, 3, 16], - "faces": { - "north": {"uv": [14.75, 0.75, 15.5, 1.5], "texture": "#bed"}, - "east": {"uv": [14, 0.75, 14.75, 1.5], "texture": "#bed"}, - "south": {"uv": [13.25, 0.75, 14, 1.5], "texture": "#bed"}, - "west": {"uv": [12.5, 0.75, 13.25, 1.5], "texture": "#bed"}, - "up": {"uv": [13.25, 0, 14, 0.75], "texture": "#bed"}, - "down": {"uv": [14, 0, 14.75, 0.75], "texture": "#bed"} - } - }, - { - "from": [13, 0, 13], - "to": [16, 3, 16], - "faces": { - "north": {"uv": [14, 3.75, 14.75, 4.5], "texture": "#bed"}, - "east": {"uv": [13.25, 3.75, 14, 4.5], "texture": "#bed"}, - "south": {"uv": [12.5, 3.75, 13.25, 4.5], "texture": "#bed"}, - "west": {"uv": [14.75, 3.75, 15.5, 4.5], "texture": "#bed"}, - "up": {"uv": [13.25, 3, 14, 3.75], "texture": "#bed"}, - "down": {"uv": [14, 3, 14.75, 3.75], "texture": "#bed"} - } - }, - { - "from": [0, 3, 0], - "to": [16, 9, 16], - "faces": { - "east": {"uv": [5.5, 7, 7, 11], "rotation": 90, "texture": "#bed"}, - "south": {"uv": [5.5, 7, 9.5, 5.5], "texture": "#bed"}, - "west": {"uv": [0, 7, 1.5, 11], "rotation": 270, "texture": "#bed"}, - "up": {"uv": [1.5, 7, 5.5, 11], "texture": "#bed"}, - "down": {"uv": [7, 7, 11, 11], "rotation": 180, "texture": "#bed"} - } - } - ] -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/bed_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/bed_head.json deleted file mode 100644 index f762847d9..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/bed_head.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "elements": [ - { - "from": [0, 0, 0], - "to": [3, 3, 3], - "faces": { - "north": {"uv": [12.5, 2.25, 13.25, 3], "texture": "#bed"}, - "east": {"uv": [14.75, 2.25, 15.5, 3], "texture": "#bed"}, - "south": {"uv": [14, 2.25, 14.75, 3], "texture": "#bed"}, - "west": {"uv": [13.25, 2.25, 14, 3], "texture": "#bed"}, - "up": {"uv": [13.25, 1.5, 14, 2.25], "texture": "#bed"}, - "down": {"uv": [14, 1.5, 14.75, 2.25], "texture": "#bed"} - } - }, - { - "from": [13, 0, 0], - "to": [16, 3, 3], - "faces": { - "north": {"uv": [13.25, 5.25, 14, 6], "texture": "#bed"}, - "east": {"uv": [12.5, 5.25, 13.25, 6], "texture": "#bed"}, - "south": {"uv": [14.75, 5.25, 15.5, 6], "texture": "#bed"}, - "west": {"uv": [14, 5.25, 14.75, 6], "texture": "#bed"}, - "up": {"uv": [13.25, 4.5, 14, 5.25], "texture": "#bed"}, - "down": {"uv": [14, 4.5, 14.75, 5.25], "texture": "#bed"} - } - }, - { - "from": [0, 3, 0], - "to": [16, 9, 16], - "faces": { - "north": {"uv": [1.5, 1.5, 5.5, 0], "texture": "#bed"}, - "east": {"uv": [5.5, 1.5, 7, 5.5], "rotation": 90, "texture": "#bed"}, - "west": {"uv": [0, 1.5, 1.5, 5.5], "rotation": 270, "texture": "#bed"}, - "up": {"uv": [1.5, 1.5, 5.5, 5.5], "texture": "#bed"}, - "down": {"uv": [7, 1.5, 11, 5.5], "rotation": 180, "texture": "#bed"} - } - } - ] -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/black_foot.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/black_foot.json deleted file mode 100644 index 4d7685bd1..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/black_foot.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_foot", - "textures": { - "bed": "entity/bed/black" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/black_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/black_head.json deleted file mode 100644 index d34fc61c9..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/black_head.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_head", - "textures": { - "bed": "entity/bed/black" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/blue_foot.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/blue_foot.json deleted file mode 100644 index 045938396..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/blue_foot.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_foot", - "textures": { - "bed": "entity/bed/blue" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/blue_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/blue_head.json deleted file mode 100644 index d1b6cb8ae..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/blue_head.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_head", - "textures": { - "bed": "entity/bed/blue" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/brown_foot.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/brown_foot.json deleted file mode 100644 index cedb2e07f..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/brown_foot.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_foot", - "textures": { - "bed": "entity/bed/brown" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/brown_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/brown_head.json deleted file mode 100644 index b48bfdadd..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/brown_head.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_head", - "textures": { - "bed": "entity/bed/brown" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/cyan_foot.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/cyan_foot.json deleted file mode 100644 index 4000ca729..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/cyan_foot.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_foot", - "textures": { - "bed": "entity/bed/cyan" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/cyan_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/cyan_head.json deleted file mode 100644 index e290aee80..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/cyan_head.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_head", - "textures": { - "bed": "entity/bed/cyan" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/gray_foot.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/gray_foot.json deleted file mode 100644 index 57ad4f592..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/gray_foot.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_foot", - "textures": { - "bed": "entity/bed/gray" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/gray_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/gray_head.json deleted file mode 100644 index 500dac712..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/gray_head.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_head", - "textures": { - "bed": "entity/bed/gray" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/green_foot.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/green_foot.json deleted file mode 100644 index 97e07cada..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/green_foot.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_foot", - "textures": { - "bed": "entity/bed/green" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/green_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/green_head.json deleted file mode 100644 index 537512693..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/green_head.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_head", - "textures": { - "bed": "entity/bed/green" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/light_blue_foot.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/light_blue_foot.json deleted file mode 100644 index 80605904e..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/light_blue_foot.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_foot", - "textures": { - "bed": "entity/bed/light_blue" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/light_blue_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/light_blue_head.json deleted file mode 100644 index 6acc0f3b5..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/light_blue_head.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_head", - "textures": { - "bed": "entity/bed/light_blue" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/light_gray_foot.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/light_gray_foot.json deleted file mode 100644 index 573d74853..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/light_gray_foot.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_foot", - "textures": { - "bed": "entity/bed/light_gray" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/light_gray_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/light_gray_head.json deleted file mode 100644 index 9dafb5d96..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/light_gray_head.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_head", - "textures": { - "bed": "entity/bed/light_gray" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/lime_foot.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/lime_foot.json deleted file mode 100644 index 0b58242a7..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/lime_foot.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_foot", - "textures": { - "bed": "entity/bed/lime" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/lime_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/lime_head.json deleted file mode 100644 index de8bb79fa..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/lime_head.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_head", - "textures": { - "bed": "entity/bed/lime" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/magenta_foot.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/magenta_foot.json deleted file mode 100644 index c976ca69a..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/magenta_foot.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_foot", - "textures": { - "bed": "entity/bed/magenta" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/magenta_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/magenta_head.json deleted file mode 100644 index f86f337be..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/magenta_head.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_head", - "textures": { - "bed": "entity/bed/magenta" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/orange_foot.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/orange_foot.json deleted file mode 100644 index 8ab767d09..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/orange_foot.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_foot", - "textures": { - "bed": "entity/bed/orange" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/orange_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/orange_head.json deleted file mode 100644 index 74ebcb93d..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/orange_head.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_head", - "textures": { - "bed": "entity/bed/orange" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/pink_foot.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/pink_foot.json deleted file mode 100644 index 3993c20e6..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/pink_foot.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_foot", - "textures": { - "bed": "entity/bed/pink" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/pink_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/pink_head.json deleted file mode 100644 index af697548b..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/pink_head.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_head", - "textures": { - "bed": "entity/bed/pink" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/purple_foot.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/purple_foot.json deleted file mode 100644 index 96a0ec285..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/purple_foot.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_foot", - "textures": { - "bed": "entity/bed/purple" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/purple_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/purple_head.json deleted file mode 100644 index 3ddbd3403..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/purple_head.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_head", - "textures": { - "bed": "entity/bed/purple" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/red_foot.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/red_foot.json deleted file mode 100644 index 686d464e2..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/red_foot.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_foot", - "textures": { - "bed": "entity/bed/red" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/red_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/red_head.json deleted file mode 100644 index 21650b336..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/red_head.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_head", - "textures": { - "bed": "entity/bed/red" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/white_foot.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/white_foot.json deleted file mode 100644 index 1ca1b531a..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/white_foot.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_foot", - "textures": { - "bed": "entity/bed/white" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/white_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/white_head.json deleted file mode 100644 index 99894a58e..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/white_head.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_head", - "textures": { - "bed": "entity/bed/white" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/yellow_foot.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/yellow_foot.json deleted file mode 100644 index ecfb05952..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/yellow_foot.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_foot", - "textures": { - "bed": "entity/bed/yellow" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/yellow_head.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/yellow_head.json deleted file mode 100644 index 6b3023adf..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bed/yellow_head.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/bed/bed_head", - "textures": { - "bed": "entity/bed/yellow" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bubble_column.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bubble_column.json deleted file mode 100644 index 7a73a41bf..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/bubble_column.json +++ /dev/null @@ -1,2 +0,0 @@ -{ -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/chest.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/chest.json deleted file mode 100644 index 254558599..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/chest.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "elements": [ - { - "from": [1, 0, 1], - "to": [15, 10, 15], - "faces": { - "north": {"uv": [10.5, 8.25, 14, 10.75], "texture": "#chest"}, - "east": {"uv": [7, 8.25, 10.5, 10.75], "texture": "#chest"}, - "south": {"uv": [3.5, 8.25, 7, 10.75], "texture": "#chest"}, - "west": {"uv": [0, 8.25, 3.5, 10.75], "texture": "#chest"}, - "up": {"uv": [3.5, 4.75, 7, 8.25], "texture": "#chest"}, - "down": {"uv": [7, 4.75, 10.5, 8.25], "texture": "#chest"} - } - }, - { - "from": [1, 9, 1], - "to": [15, 14, 15], - "faces": { - "north": {"uv": [10.5, 3.5, 14, 4.75], "texture": "#chest"}, - "east": {"uv": [7, 3.5, 10.5, 4.75], "texture": "#chest"}, - "south": {"uv": [3.5, 3.5, 7, 4.75], "texture": "#chest"}, - "west": {"uv": [0, 3.5, 3.5, 4.75], "texture": "#chest"}, - "up": {"uv": [3.5, 0, 7, 3.5], "texture": "#chest"}, - "down": {"uv": [7, 0, 10.5, 3.5], "texture": "#chest"} - } - }, - { - "from": [7, 7, 15], - "to": [9, 11, 16], - "faces": { - "north": {"uv": [0.25, 0.25, 0.75, 1.25], "texture": "#chest"}, - "east": {"uv": [0, 0.25, 0.25, 1.25], "texture": "#chest"}, - "south": {"uv": [1, 0.25, 1.5, 1.25], "texture": "#chest"}, - "west": {"uv": [0.75, 0.25, 1, 1.25], "texture": "#chest"}, - "up": {"uv": [0.25, 0, 0.75, 0.25], "texture": "#chest"}, - "down": {"uv": [0.75, 0, 1.25, 0.25], "texture": "#chest"} - } - } - ] -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/chest_double.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/chest_double.json deleted file mode 100644 index 180cc1bc5..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/chest_double.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "elements": [ - { - "from": [1, 0, 1], - "to": [31, 10, 15], - "faces": { - "north": {"uv": [7.25, 8.25, 11, 10.75], "texture": "#chest"}, - "east": {"uv": [5.5, 8.25, 7.25, 10.75], "texture": "#chest"}, - "south": {"uv": [1.75, 8.25, 5.5, 10.75], "texture": "#chest"}, - "west": {"uv": [0, 8.25, 1.75, 10.75], "texture": "#chest"}, - "up": {"uv": [1.75, 4.75, 5.5, 8.25], "texture": "#chest"}, - "down": {"uv": [5.5, 4.75, 9.25, 8.25], "texture": "#chest"} - } - }, - { - "from": [1, 9, 1], - "to": [31, 14, 15], - "faces": { - "north": {"uv": [7.25, 3.5, 11, 4.75], "texture": "#chest"}, - "east": {"uv": [5.5, 3.5, 7.25, 4.75], "texture": "#chest"}, - "south": {"uv": [1.75, 3.5, 5.5, 4.75], "texture": "#chest"}, - "west": {"uv": [0, 3.5, 1.75, 4.75], "texture": "#chest"}, - "up": {"uv": [1.75, 0, 5.5, 3.5], "texture": "#chest"}, - "down": {"uv": [5.5, 0, 9.25, 3.5], "texture": "#chest"} - } - }, - { - "from": [15, 7, 15], - "to": [17, 11, 16], - "faces": { - "north": {"uv": [0.5, 0.25, 0.75, 1.25], "texture": "#chest"}, - "east": {"uv": [0.375, 0.25, 0.5, 1.25], "texture": "#chest"}, - "south": {"uv": [0.125, 0.25, 0.375, 1.25], "texture": "#chest"}, - "west": {"uv": [0, 0.25, 0.125, 1.25], "texture": "#chest"}, - "up": {"uv": [0.125, 0, 0.375, 0.25], "texture": "#chest"}, - "down": {"uv": [0.375, 0, 0.625, 0.25], "texture": "#chest"} - } - } - ] -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/ender.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/ender.json deleted file mode 100644 index e50bc420b..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/ender.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/chest/chest", - "textures": { - "chest": "entity/chest/ender" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/normal.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/normal.json deleted file mode 100644 index 87da674d8..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/normal.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/chest/chest", - "textures": { - "chest": "entity/chest/normal" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/normal_double.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/normal_double.json deleted file mode 100644 index 73bdbfba3..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/normal_double.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/chest/chest_double", - "textures": { - "chest": "entity/chest/normal_double" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/trapped.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/trapped.json deleted file mode 100644 index 9d10f500e..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/trapped.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/chest/chest", - "textures": { - "chest": "entity/chest/trapped" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/trapped_double.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/trapped_double.json deleted file mode 100644 index 1ae421e1d..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/chest/trapped_double.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/chest/chest_double", - "textures": { - "chest": "entity/chest/trapped_double" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/lava.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/lava.json deleted file mode 100644 index 0eea97aaa..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/lava.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "bluemap:builtin/liquid", - "textures": { - "particle": "block/lava_still", - "still": "block/lava_still", - "flow": "block/lava_flow" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/acacia.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/acacia.json deleted file mode 100644 index 791c9f041..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/acacia.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/sign/sign", - "textures": { - "sign": "entity/signs/acacia" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/birch.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/birch.json deleted file mode 100644 index 8fda49848..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/birch.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/sign/sign", - "textures": { - "sign": "entity/signs/birch" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/dark_oak.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/dark_oak.json deleted file mode 100644 index 25c324e1b..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/dark_oak.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/sign/sign", - "textures": { - "sign": "entity/signs/dark_oak" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/jungle.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/jungle.json deleted file mode 100644 index c1e44326c..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/jungle.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/sign/sign", - "textures": { - "sign": "entity/signs/jungle" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/oak.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/oak.json deleted file mode 100644 index 5fc2d9205..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/oak.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/sign/sign", - "textures": { - "sign": "entity/signs/oak" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/sign.json deleted file mode 100644 index 14bc9644c..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/sign.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "elements": [ - { - "from": [7.25, 0, 7.25], - "to": [8.75, 9.333, 8.75], - "faces": { - "north": {"uv": [1.5, 8, 2, 15], "texture": "#sign"}, - "east": {"uv": [1, 8, 1.5, 15], "texture": "#sign"}, - "south": {"uv": [0.5, 8, 1, 15], "texture": "#sign"}, - "west": {"uv": [0, 8, 0.5, 15], "texture": "#sign"}, - "up": {"uv": [0.5, 7, 1, 8], "texture": "#sign"}, - "down": {"uv": [1, 7, 1.5, 8], "texture": "#sign"} - } - }, - { - "from": [0, 9.333, 7.25], - "to": [16, 17.333, 8.75], - "faces": { - "north": {"uv": [7, 1, 13, 7], "texture": "#sign"}, - "east": {"uv": [6.5, 1, 7, 7], "texture": "#sign"}, - "south": {"uv": [0.5, 1, 6.5, 7], "texture": "#sign"}, - "west": {"uv": [0, 1, 0.5, 7], "texture": "#sign"}, - "up": {"uv": [0.5, 0, 6.5, 1], "texture": "#sign"}, - "down": {"uv": [6.5, 1, 12.5, 0], "texture": "#sign"} - } - } - ] -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/spruce.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/spruce.json deleted file mode 100644 index f30b6c48d..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/spruce.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/sign/sign", - "textures": { - "sign": "entity/signs/spruce" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_acacia.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_acacia.json deleted file mode 100644 index d2ba54c0e..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_acacia.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/sign/wall_sign", - "textures": { - "sign": "entity/signs/acacia" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_birch.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_birch.json deleted file mode 100644 index d40e75a65..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_birch.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/sign/wall_sign", - "textures": { - "sign": "entity/signs/birch" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_dark_oak.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_dark_oak.json deleted file mode 100644 index 9aa4dcf55..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_dark_oak.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/sign/wall_sign", - "textures": { - "sign": "entity/signs/dark_oak" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_jungle.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_jungle.json deleted file mode 100644 index c84ae16bf..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_jungle.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/sign/wall_sign", - "textures": { - "sign": "entity/signs/jungle" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_oak.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_oak.json deleted file mode 100644 index d83903c0c..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_oak.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/sign/wall_sign", - "textures": { - "sign": "entity/signs/oak" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_sign.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_sign.json deleted file mode 100644 index d083952bb..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_sign.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "elements": [ - { - "from": [0, 4.333, 0.25], - "to": [16, 12.333, 1.75], - "faces": { - "north": {"uv": [7, 1, 13, 7], "texture": "#sign"}, - "east": {"uv": [6.5, 1, 7, 7], "texture": "#sign"}, - "south": {"uv": [0.5, 1, 6.5, 7], "texture": "#sign"}, - "west": {"uv": [0, 1, 0.5, 7], "texture": "#sign"}, - "up": {"uv": [0.5, 0, 6.5, 1], "texture": "#sign"}, - "down": {"uv": [6.5, 1, 12.5, 0], "texture": "#sign"} - } - } - ] -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_spruce.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_spruce.json deleted file mode 100644 index 615772912..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/sign/wall_spruce.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent":"block/sign/wall_sign", - "textures": { - "sign": "entity/signs/spruce" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/water.json b/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/water.json deleted file mode 100644 index 2c092d905..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_13/assets/minecraft/models/block/water.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "bluemap:builtin/liquid", - "textures": { - "particle": "block/water_still", - "still": "block/water_still", - "flow": "block/water_flow" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_15/assets/bluemap/blockstates/missing.json b/BlueMapCore/src/main/resourceExtensions/mc1_15/assets/bluemap/blockstates/missing.json deleted file mode 100644 index d917d257a..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_15/assets/bluemap/blockstates/missing.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "variants": { - "": { "model": "bluemap:block/missing" } - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_15/assets/bluemap/models/block/missing.json b/BlueMapCore/src/main/resourceExtensions/mc1_15/assets/bluemap/models/block/missing.json deleted file mode 100644 index 5995c0c01..000000000 --- a/BlueMapCore/src/main/resourceExtensions/mc1_15/assets/bluemap/models/block/missing.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "block/cube_all", - "textures": { - "all": "bluemap:block/missing" - } -} \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_15/assets/bluemap/textures/block/missing.png b/BlueMapCore/src/main/resourceExtensions/mc1_15/assets/bluemap/textures/block/missing.png deleted file mode 100644 index bbfd3944cfa4f8ecf201c7fb575dab9b75b9b23c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2826 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 c0RR6305SRo8w1WgjsO4v07*qoM6N<$f Date: Wed, 8 May 2024 19:37:40 +0200 Subject: [PATCH 04/38] Fix some more resource formatting --- .../minecraft/blockstates/grass_path.json | 19 ++++--------------- .../assets/minecraft/blockstates/grass.json | 4 +--- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_17/assets/minecraft/blockstates/grass_path.json b/BlueMapCore/src/main/resourceExtensions/mc1_17/assets/minecraft/blockstates/grass_path.json index 3865928a3..97b241f8e 100644 --- a/BlueMapCore/src/main/resourceExtensions/mc1_17/assets/minecraft/blockstates/grass_path.json +++ b/BlueMapCore/src/main/resourceExtensions/mc1_17/assets/minecraft/blockstates/grass_path.json @@ -1,21 +1,10 @@ { "variants": { "": [ - { - "model": "minecraft:block/dirt_path" - }, - { - "model": "minecraft:block/dirt_path", - "y": 90 - }, - { - "model": "minecraft:block/dirt_path", - "y": 180 - }, - { - "model": "minecraft:block/dirt_path", - "y": 270 - } + { "model": "minecraft:block/dirt_path" }, + { "model": "minecraft:block/dirt_path", "y": 90 }, + { "model": "minecraft:block/dirt_path", "y": 180 }, + { "model": "minecraft:block/dirt_path", "y": 270 } ] } } \ No newline at end of file diff --git a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/grass.json b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/grass.json index d065ca080..d9fff6187 100644 --- a/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/grass.json +++ b/BlueMapCore/src/main/resourceExtensions/mc1_20_3/assets/minecraft/blockstates/grass.json @@ -1,7 +1,5 @@ { "variants": { - "": { - "model": "minecraft:block/short_grass" - } + "": { "model": "minecraft:block/short_grass" } } } \ No newline at end of file From 909642d4c3854ccc15d5475b7c07d908bd332494 Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Wed, 8 May 2024 19:51:59 +0200 Subject: [PATCH 05/38] apply spotless fixes --- .../core/map/renderstate/ChunkInfoRegion.java | 24 +++++++++++++++++++ .../map/renderstate/TileActionResolver.java | 24 +++++++++++++++++++ .../core/map/renderstate/TileInfoRegion.java | 24 +++++++++++++++++++ .../core/map/renderstate/TileState.java | 24 +++++++++++++++++++ .../core/resources/VersionManifest.java | 24 +++++++++++++++++++ .../adapter/LocalDateTimeAdapter.java | 24 +++++++++++++++++++ .../resources/adapter/RegistryAdapter.java | 24 +++++++++++++++++++ .../bluemap/core/resources/pack/Pack.java | 24 +++++++++++++++++++ .../bluemap/core/resources/pack/PackMeta.java | 24 +++++++++++++++++++ .../pack/datapack/biome/DatapackBiome.java | 24 +++++++++++++++++++ .../bluemap/core/storage/KeyedMapStorage.java | 24 +++++++++++++++++++ .../core/storage/file/FileItemStorage.java | 24 +++++++++++++++++++ .../bluemap/core/util/BiIntConsumer.java | 24 +++++++++++++++++++ .../core/util/PalettedArrayAdapter.java | 24 +++++++++++++++++++ .../bluemap/core/util/RegistryAdapter.java | 24 +++++++++++++++++++ .../core/world/biome/ColorModifier.java | 24 +++++++++++++++++++ .../core/world/biome/GrassColorModifier.java | 24 +++++++++++++++++++ 17 files changed, 408 insertions(+) diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/ChunkInfoRegion.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/ChunkInfoRegion.java index 29e7544dd..7d7e0427b 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/ChunkInfoRegion.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/ChunkInfoRegion.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.map.renderstate; import de.bluecolored.bluenbt.NBTName; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileActionResolver.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileActionResolver.java index 3816e3cb9..ab3f41c74 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileActionResolver.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileActionResolver.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.map.renderstate; import java.util.Objects; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileInfoRegion.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileInfoRegion.java index 600b6fb02..f5fe9dc6a 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileInfoRegion.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileInfoRegion.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.map.renderstate; import de.bluecolored.bluenbt.NBTName; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileState.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileState.java index e870016fa..1731279f0 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileState.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileState.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.map.renderstate; import de.bluecolored.bluemap.core.util.Key; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/VersionManifest.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/VersionManifest.java index 2c7adc7e7..6a6438e5b 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/VersionManifest.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/VersionManifest.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.resources; import com.google.gson.Gson; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/LocalDateTimeAdapter.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/LocalDateTimeAdapter.java index 76c87314e..c2aab2472 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/LocalDateTimeAdapter.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/LocalDateTimeAdapter.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.resources.adapter; import com.google.gson.TypeAdapter; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/RegistryAdapter.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/RegistryAdapter.java index fc0eb82c4..c0413a691 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/RegistryAdapter.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/adapter/RegistryAdapter.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.resources.adapter; import com.google.gson.TypeAdapter; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/Pack.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/Pack.java index 4e1006f26..da4c7ac6b 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/Pack.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/Pack.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.resources.pack; import com.google.gson.JsonElement; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/PackMeta.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/PackMeta.java index c7bb8afca..dcdc60a67 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/PackMeta.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/PackMeta.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.resources.pack; import com.google.gson.Gson; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/biome/DatapackBiome.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/biome/DatapackBiome.java index 3a3b1d613..bbebe5b84 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/biome/DatapackBiome.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/biome/DatapackBiome.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.resources.pack.datapack.biome; import de.bluecolored.bluemap.core.util.Key; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/KeyedMapStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/KeyedMapStorage.java index c0e565655..521e50c00 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/KeyedMapStorage.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/KeyedMapStorage.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.storage; import de.bluecolored.bluemap.core.storage.compression.Compression; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/FileItemStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/FileItemStorage.java index 1a51d76a2..1604b35a0 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/FileItemStorage.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/file/FileItemStorage.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.storage.file; import de.bluecolored.bluemap.core.storage.ItemStorage; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/BiIntConsumer.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/BiIntConsumer.java index 9ab4da271..6aa17ecb7 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/BiIntConsumer.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/BiIntConsumer.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.util; @FunctionalInterface diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/PalettedArrayAdapter.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/PalettedArrayAdapter.java index 7498d4a7d..fea7ae196 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/PalettedArrayAdapter.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/PalettedArrayAdapter.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.util; import com.google.gson.reflect.TypeToken; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/RegistryAdapter.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/RegistryAdapter.java index 23a8e059a..12f967f02 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/RegistryAdapter.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/RegistryAdapter.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.util; import de.bluecolored.bluemap.core.logger.Logger; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/ColorModifier.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/ColorModifier.java index 46b55dd03..d46a74509 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/ColorModifier.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/ColorModifier.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.biome; import de.bluecolored.bluemap.core.util.math.Color; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/GrassColorModifier.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/GrassColorModifier.java index f505b4ae3..f94a2ceba 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/GrassColorModifier.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/GrassColorModifier.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.biome; import de.bluecolored.bluemap.core.util.Key; From fe5c1fa785dddf2ba93a62c430db3de5951ee469 Mon Sep 17 00:00:00 2001 From: Salzian Date: Wed, 8 May 2024 23:47:50 +0200 Subject: [PATCH 06/38] Parallelized initial settings loading --- BlueMapCommon/webapp/src/js/BlueMapApp.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/BlueMapCommon/webapp/src/js/BlueMapApp.js b/BlueMapCommon/webapp/src/js/BlueMapApp.js index 853708742..dc0ba1aa8 100644 --- a/BlueMapCommon/webapp/src/js/BlueMapApp.js +++ b/BlueMapCommon/webapp/src/js/BlueMapApp.js @@ -299,15 +299,17 @@ export class BlueMapApp { // create maps if (settings.maps !== undefined){ - for (let mapId of settings.maps) { + let loadingPromises = settings.maps.map(mapId => { let map = new BlueMapMap(mapId, this.dataUrl + mapId + "/", this.loadBlocker, this.mapViewer.events); maps.push(map); - await map.loadSettings(this.mapViewer.tileCacheHash) + return map.loadSettings(this.mapViewer.tileCacheHash) .catch(error => { alert(this.events, `Failed to load settings for map '${map.data.id}':` + error, "warning"); }); - } + }) + + await Promise.all(loadingPromises); } // sort maps From 1b268035278f5247abcc226ac64e576d2ae7eb39 Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Sun, 12 May 2024 20:11:31 +0200 Subject: [PATCH 07/38] Update Caffeine, use soft values for chunk caches --- BlueMapCommon/build.gradle.kts | 4 ++-- BlueMapCore/build.gradle.kts | 10 +++++----- .../bluemap/core/map/lowres/LowresLayer.java | 16 +++++----------- .../bluemap/core/world/mca/MCAWorld.java | 9 ++++++++- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/BlueMapCommon/build.gradle.kts b/BlueMapCommon/build.gradle.kts index 51894011a..f092b0c28 100644 --- a/BlueMapCommon/build.gradle.kts +++ b/BlueMapCommon/build.gradle.kts @@ -30,9 +30,9 @@ dependencies { api ("de.bluecolored.bluemap:BlueMapCore") compileOnly ("org.jetbrains:annotations:16.0.2") - compileOnly ("org.projectlombok:lombok:1.18.30") + compileOnly ("org.projectlombok:lombok:1.18.32") - annotationProcessor ("org.projectlombok:lombok:1.18.30") + annotationProcessor ("org.projectlombok:lombok:1.18.32") testImplementation ("org.junit.jupiter:junit-jupiter:5.8.2") testRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.8.2") diff --git a/BlueMapCore/build.gradle.kts b/BlueMapCore/build.gradle.kts index 1d7587646..a9c7525b8 100644 --- a/BlueMapCore/build.gradle.kts +++ b/BlueMapCore/build.gradle.kts @@ -60,7 +60,7 @@ repositories { @Suppress("GradlePackageUpdate") dependencies { - api ("com.github.ben-manes.caffeine:caffeine:2.8.5") + api ("com.github.ben-manes.caffeine:caffeine:3.1.8") api ("org.apache.commons:commons-lang3:3.6") api ("commons-io:commons-io:2.5") api ("org.spongepowered:configurate-hocon:4.1.2") @@ -73,14 +73,14 @@ dependencies { api ("de.bluecolored.bluemap:BlueMapAPI") compileOnly ("org.jetbrains:annotations:23.0.0") - compileOnly ("org.projectlombok:lombok:1.18.30") + compileOnly ("org.projectlombok:lombok:1.18.32") - annotationProcessor ("org.projectlombok:lombok:1.18.30") + annotationProcessor ("org.projectlombok:lombok:1.18.32") testImplementation ("org.junit.jupiter:junit-jupiter:5.8.2") testRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.8.2") - testCompileOnly ("org.projectlombok:lombok:1.18.30") - testAnnotationProcessor ("org.projectlombok:lombok:1.18.30") + testCompileOnly ("org.projectlombok:lombok:1.18.32") + testAnnotationProcessor ("org.projectlombok:lombok:1.18.32") } spotless { diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/lowres/LowresLayer.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/lowres/LowresLayer.java index 7ef70c09b..cfdf3a01b 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/lowres/LowresLayer.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/lowres/LowresLayer.java @@ -25,14 +25,16 @@ package de.bluecolored.bluemap.core.map.lowres; import com.flowpowered.math.vector.Vector2i; -import com.github.benmanes.caffeine.cache.*; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; +import com.github.benmanes.caffeine.cache.RemovalCause; +import com.github.benmanes.caffeine.cache.Scheduler; import de.bluecolored.bluemap.core.BlueMap; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.storage.GridStorage; import de.bluecolored.bluemap.core.util.Grid; import de.bluecolored.bluemap.core.util.Vector2iCache; import de.bluecolored.bluemap.core.util.math.Color; -import org.checkerframework.checker.nullness.qual.NonNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; @@ -77,15 +79,7 @@ public LowresLayer( .scheduler(Scheduler.systemScheduler()) .expireAfterAccess(10, TimeUnit.SECONDS) .expireAfterWrite(5, TimeUnit.MINUTES) - .writer(new CacheWriter() { - @Override - public void write(@NonNull Vector2i key, @NonNull LowresTile value) {} - - @Override - public void delete(@NonNull Vector2i key, @Nullable LowresTile value, @NonNull RemovalCause cause) { - saveTile(key, value); - } - }) + .removalListener((Vector2i key, LowresTile value, RemovalCause cause) -> saveTile(key, value)) .build(tileWeakInstanceCache::get); } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java index 57eb3c542..356cecd31 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java @@ -48,7 +48,10 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; @@ -76,13 +79,17 @@ public class MCAWorld implements World { private final ChunkLoader chunkLoader = new ChunkLoader(this); private final LoadingCache regionCache = Caffeine.newBuilder() .executor(BlueMap.THREAD_POOL) + .softValues() .maximumSize(32) .expireAfterWrite(10, TimeUnit.MINUTES) + .expireAfterAccess(1, TimeUnit.MINUTES) .build(this::loadRegion); private final LoadingCache chunkCache = Caffeine.newBuilder() .executor(BlueMap.THREAD_POOL) + .softValues() .maximumSize(10240) // 10 regions worth of chunks .expireAfterWrite(10, TimeUnit.MINUTES) + .expireAfterAccess(1, TimeUnit.MINUTES) .build(this::loadChunk); private MCAWorld(Path worldFolder, Key dimension, DataPack dataPack, LevelData levelData) { From 2777846cf8d9ba8c9df080af56eac50a26dd4ddc Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Wed, 15 May 2024 00:01:54 +0200 Subject: [PATCH 08/38] Fix max-height calculation (#535) --- .../bluemap/core/map/hires/HiresModelRenderer.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/HiresModelRenderer.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/HiresModelRenderer.java index e88c114b1..d272b399c 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/HiresModelRenderer.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/hires/HiresModelRenderer.java @@ -68,7 +68,7 @@ public void render(World world, Vector3i modelMin, Vector3i modelMax, TileModel for (x = modelMin.getX(); x <= modelMax.getX(); x++){ for (z = modelMin.getZ(); z <= modelMax.getZ(); z++){ - maxHeight = 0; + maxHeight = Integer.MIN_VALUE; topBlockLight = 0; columnColor.set(0, 0, 0, 0, true); @@ -105,6 +105,9 @@ public void render(World world, Vector3i modelMin, Vector3i modelMax, TileModel } } + if (maxHeight == Integer.MIN_VALUE) + maxHeight = 0; + tileMetaConsumer.set(x, z, columnColor, maxHeight, (int) topBlockLight); } } From 2029fe0a87702990751aa1dab3fa52550ce69305 Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Wed, 15 May 2024 00:41:59 +0200 Subject: [PATCH 09/38] Add support for dimension-type directly stored in level.dat (#517) --- .../datapack/dimension/DimensionTypeData.java | 22 ++++++++- .../bluemap/core/world/mca/MCAUtil.java | 14 +++--- .../bluemap/core/world/mca/MCAWorld.java | 27 +++++------ .../mca/data/DimensionTypeDeserializer.java | 45 +++++++++++++++++++ .../core/world/mca/data/LevelData.java | 3 +- 5 files changed, 90 insertions(+), 21 deletions(-) create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/DimensionTypeDeserializer.java diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/dimension/DimensionTypeData.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/dimension/DimensionTypeData.java index 647b8f187..4fca54a96 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/dimension/DimensionTypeData.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/dimension/DimensionTypeData.java @@ -26,6 +26,7 @@ import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.world.DimensionType; +import de.bluecolored.bluenbt.NBTName; import lombok.*; import lombok.experimental.Accessors; @@ -33,13 +34,30 @@ @DebugDump public class DimensionTypeData implements DimensionType { + @NBTName("natural") private boolean natural; - @Accessors(fluent = true) private boolean hasSkylight; - @Accessors(fluent = true) private boolean hasCeiling; + + @NBTName("has_skylight") + @Accessors(fluent = true) + private boolean hasSkylight; + + @NBTName("has_ceiling") + @Accessors(fluent = true) + private boolean hasCeiling; + + @NBTName("ambient_light") private float ambientLight; + + @NBTName("min_y") private int minY; + + @NBTName("height") private int height; + + @NBTName("fixed_time") private Long fixedTime; + + @NBTName("coordinate_scale") private double coordinateScale; } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAUtil.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAUtil.java index 784a4a5e0..f9e19e2da 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAUtil.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAUtil.java @@ -31,14 +31,18 @@ import de.bluecolored.bluemap.core.world.mca.data.BlockStateDeserializer; import de.bluecolored.bluemap.core.world.mca.data.KeyDeserializer; import de.bluecolored.bluenbt.BlueNBT; +import org.jetbrains.annotations.Contract; public class MCAUtil { - public static final BlueNBT BLUENBT = new BlueNBT(); - static { - BLUENBT.register(TypeToken.get(BlockState.class), new BlockStateDeserializer()); - BLUENBT.register(TypeToken.get(Key.class), new KeyDeserializer()); - BLUENBT.register(TypeToken.get(BlockEntity.class), new BlockEntity.BlockEntityDeserializer()); + public static final BlueNBT BLUENBT = addCommonNbtAdapters(new BlueNBT()); + + @Contract(value = "_ -> param1", mutates = "param1") + public static BlueNBT addCommonNbtAdapters(BlueNBT nbt) { + nbt.register(TypeToken.get(BlockState.class), new BlockStateDeserializer()); + nbt.register(TypeToken.get(Key.class), new KeyDeserializer()); + nbt.register(TypeToken.get(BlockEntity.class), new BlockEntity.BlockEntityDeserializer()); + return nbt; } /** diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java index 356cecd31..42db41cf7 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java @@ -28,6 +28,7 @@ import com.flowpowered.math.vector.Vector3i; import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.LoadingCache; +import com.google.gson.reflect.TypeToken; import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.BlueMap; import de.bluecolored.bluemap.core.logger.Logger; @@ -38,8 +39,10 @@ import de.bluecolored.bluemap.core.util.Vector2iCache; import de.bluecolored.bluemap.core.world.*; import de.bluecolored.bluemap.core.world.mca.chunk.ChunkLoader; +import de.bluecolored.bluemap.core.world.mca.data.DimensionTypeDeserializer; import de.bluecolored.bluemap.core.world.mca.data.LevelData; import de.bluecolored.bluemap.core.world.mca.region.RegionType; +import de.bluecolored.bluenbt.BlueNBT; import lombok.Getter; import lombok.ToString; @@ -101,9 +104,9 @@ private MCAWorld(Path worldFolder, Key dimension, DataPack dataPack, LevelData l LevelData.Dimension dimensionData = levelData.getData().getWorldGenSettings().getDimensions().get(dimension.getFormatted()); if (dimensionData == null) { - if (DataPack.DIMENSION_OVERWORLD.equals(dimension)) dimensionData = new LevelData.Dimension(DataPack.DIMENSION_TYPE_OVERWORLD.getFormatted()); - else if (DataPack.DIMENSION_THE_NETHER.equals(dimension)) dimensionData = new LevelData.Dimension(DataPack.DIMENSION_TYPE_THE_NETHER.getFormatted()); - else if (DataPack.DIMENSION_THE_END.equals(dimension)) dimensionData = new LevelData.Dimension(DataPack.DIMENSION_TYPE_THE_END.getFormatted()); + if (DataPack.DIMENSION_OVERWORLD.equals(dimension)) dimensionData = new LevelData.Dimension(DimensionType.OVERWORLD); + else if (DataPack.DIMENSION_THE_NETHER.equals(dimension)) dimensionData = new LevelData.Dimension(DimensionType.NETHER); + else if (DataPack.DIMENSION_THE_END.equals(dimension)) dimensionData = new LevelData.Dimension(DimensionType.END); else { Logger.global.logWarning("The level-data does not contain any dimension with the id '" + dimension + "', using fallback."); @@ -111,14 +114,7 @@ private MCAWorld(Path worldFolder, Key dimension, DataPack dataPack, LevelData l } } - DimensionType dimensionType = dataPack.getDimensionType(new Key(dimensionData.getType())); - if (dimensionType == null) { - Logger.global.logWarning("The data-pack for world '" + worldFolder + - "' does not contain any dimension-type with the id '" + dimensionData.getType() + "', using fallback."); - dimensionType = DimensionType.OVERWORLD; - } - - this.dimensionType = dimensionType; + this.dimensionType = dimensionData.getType(); this.spawnPoint = new Vector3i( levelData.getData().getSpawnX(), levelData.getData().getSpawnY(), @@ -270,10 +266,15 @@ private Chunk loadChunk(int x, int z) { } public static MCAWorld load(Path worldFolder, Key dimension, DataPack dataPack) throws IOException, InterruptedException { + // load level.dat Path levelFile = worldFolder.resolve("level.dat"); - InputStream levelFileIn = Compression.GZIP.decompress(Files.newInputStream(levelFile)); - LevelData levelData = MCAUtil.BLUENBT.read(levelFileIn, LevelData.class); + BlueNBT blueNBT = MCAUtil.addCommonNbtAdapters(new BlueNBT()); + blueNBT.register(TypeToken.get(DimensionType.class), new DimensionTypeDeserializer(blueNBT, dataPack)); + LevelData levelData; + try (InputStream levelFileIn = Compression.GZIP.decompress(Files.newInputStream(levelFile))) { + levelData = blueNBT.read(levelFileIn, LevelData.class); + } // create world return new MCAWorld(worldFolder, dimension, dataPack, levelData); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/DimensionTypeDeserializer.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/DimensionTypeDeserializer.java new file mode 100644 index 000000000..40baa3bb3 --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/DimensionTypeDeserializer.java @@ -0,0 +1,45 @@ +package de.bluecolored.bluemap.core.world.mca.data; + +import com.google.gson.reflect.TypeToken; +import de.bluecolored.bluemap.core.logger.Logger; +import de.bluecolored.bluemap.core.resources.pack.datapack.DataPack; +import de.bluecolored.bluemap.core.resources.pack.datapack.dimension.DimensionTypeData; +import de.bluecolored.bluemap.core.util.Key; +import de.bluecolored.bluemap.core.world.DimensionType; +import de.bluecolored.bluenbt.BlueNBT; +import de.bluecolored.bluenbt.NBTReader; +import de.bluecolored.bluenbt.TagType; +import de.bluecolored.bluenbt.TypeDeserializer; + +import java.io.IOException; + +public class DimensionTypeDeserializer implements TypeDeserializer { + + private final TypeDeserializer defaultTypeDeserializer; + private final DataPack dataPack; + + public DimensionTypeDeserializer(BlueNBT blueNBT, DataPack dataPack) { + this.defaultTypeDeserializer = blueNBT.getTypeDeserializer(TypeToken.get(DimensionTypeData.class)); + this.dataPack = dataPack; + } + + @Override + public DimensionType read(NBTReader reader) throws IOException { + + // try load directly + if (reader.peek() == TagType.COMPOUND) + return defaultTypeDeserializer.read(reader); + + // load from datapack + Key key = Key.parse(reader.nextString(), Key.MINECRAFT_NAMESPACE); + + DimensionType dimensionType = dataPack.getDimensionType(key); + if (dimensionType == null) { + Logger.global.logWarning("No dimension-type found with the id '" + key.getFormatted() + "', using fallback."); + dimensionType = DimensionType.OVERWORLD; + } + + return dimensionType; + } + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/LevelData.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/LevelData.java index 25c532495..8130731cf 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/LevelData.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/LevelData.java @@ -25,6 +25,7 @@ package de.bluecolored.bluemap.core.world.mca.data; import de.bluecolored.bluemap.api.debug.DebugDump; +import de.bluecolored.bluemap.core.world.DimensionType; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -58,7 +59,7 @@ public static class WGSettings { @AllArgsConstructor @DebugDump public static class Dimension { - private String type = "minecraft:overworld"; + private DimensionType type = DimensionType.OVERWORLD; } } From b330c5d168b80a7ec587bbe81ccf6b444916d4bd Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Wed, 15 May 2024 00:45:34 +0200 Subject: [PATCH 10/38] Improve readabillity --- .../de/bluecolored/bluemap/core/world/mca/MCAWorld.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java index 42db41cf7..d4a0eb721 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java @@ -269,8 +269,7 @@ public static MCAWorld load(Path worldFolder, Key dimension, DataPack dataPack) // load level.dat Path levelFile = worldFolder.resolve("level.dat"); - BlueNBT blueNBT = MCAUtil.addCommonNbtAdapters(new BlueNBT()); - blueNBT.register(TypeToken.get(DimensionType.class), new DimensionTypeDeserializer(blueNBT, dataPack)); + BlueNBT blueNBT = createBlueNBTForDataPack(dataPack); LevelData levelData; try (InputStream levelFileIn = Compression.GZIP.decompress(Files.newInputStream(levelFile))) { levelData = blueNBT.read(levelFileIn, LevelData.class); @@ -297,4 +296,10 @@ public static Path resolveDimensionFolder(Path worldFolder, Key dimension) { return worldFolder.resolve("dimensions").resolve(dimension.getNamespace()).resolve(dimension.getValue()); } + private static BlueNBT createBlueNBTForDataPack(DataPack dataPack) { + BlueNBT blueNBT = MCAUtil.addCommonNbtAdapters(new BlueNBT()); + blueNBT.register(TypeToken.get(DimensionType.class), new DimensionTypeDeserializer(blueNBT, dataPack)); + return blueNBT; + } + } From 0b111463be5941c4f4be98ff4674f4ea147c4520 Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Wed, 15 May 2024 00:46:37 +0200 Subject: [PATCH 11/38] Apply spotless fixes --- .../mca/data/DimensionTypeDeserializer.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/DimensionTypeDeserializer.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/DimensionTypeDeserializer.java index 40baa3bb3..f41c44140 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/DimensionTypeDeserializer.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/DimensionTypeDeserializer.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.mca.data; import com.google.gson.reflect.TypeToken; From 3cd3f1d03274f487032b62e84b1eac426bd8f89b Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Wed, 15 May 2024 01:20:46 +0200 Subject: [PATCH 12/38] Switch to correct lz4 compression type --- .../bluemap/core/storage/compression/Compression.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/compression/Compression.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/compression/Compression.java index 4b9d589ac..905837c85 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/compression/Compression.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/storage/compression/Compression.java @@ -29,8 +29,8 @@ import de.bluecolored.bluemap.core.util.Registry; import io.airlift.compress.zstd.ZstdInputStream; import io.airlift.compress.zstd.ZstdOutputStream; -import net.jpountz.lz4.LZ4FrameInputStream; -import net.jpountz.lz4.LZ4FrameOutputStream; +import net.jpountz.lz4.LZ4BlockInputStream; +import net.jpountz.lz4.LZ4BlockOutputStream; import java.io.IOException; import java.io.InputStream; @@ -46,7 +46,7 @@ public interface Compression extends Keyed { Compression GZIP = new BufferedCompression(Key.bluemap("gzip"), "gzip", ".gz", GZIPOutputStream::new, GZIPInputStream::new); Compression DEFLATE = new BufferedCompression(Key.bluemap("deflate"), "deflate", ".deflate", DeflaterOutputStream::new, InflaterInputStream::new); Compression ZSTD = new BufferedCompression(Key.bluemap("zstd"), "zstd", ".zst", ZstdOutputStream::new, ZstdInputStream::new); - Compression LZ4 = new BufferedCompression(Key.bluemap("lz4"), "lz4", ".lz4", LZ4FrameOutputStream::new, LZ4FrameInputStream::new); + Compression LZ4 = new BufferedCompression(Key.bluemap("lz4"), "lz4", ".lz4", LZ4BlockOutputStream::new, LZ4BlockInputStream::new); Registry REGISTRY = new Registry<>( NONE, From 93d8876b20baee08afd678a2064abd3be8c899c6 Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Wed, 15 May 2024 23:47:25 +0200 Subject: [PATCH 13/38] Rework StateDumper --- BlueMapAPI | 2 +- BlueMapCommon/build.gradle.kts | 1 + .../bluemap/common/BlueMapService.java | 4 +- .../common/config/BlueMapConfigManager.java | 2 - .../bluemap/common/config/CoreConfig.java | 3 - .../bluemap/common/config/MapConfig.java | 2 - .../bluemap/common/config/PluginConfig.java | 2 - .../bluemap/common/config/WebappConfig.java | 2 - .../common/config/WebserverConfig.java | 3 - .../common/config/storage/FileConfig.java | 2 - .../common/config/storage/SQLConfig.java | 17 +- .../common/config/storage/StorageConfig.java | 2 - .../bluemap/common/debug/DebugDump.java | 44 +++ .../bluemap/common/debug/StateDumper.java | 328 ++++++++++++++++++ .../bluemap/common/plugin/Plugin.java | 4 +- .../common/plugin/RegionFileWatchService.java | 2 - .../common/plugin/commands/Commands.java | 4 +- .../plugin/skins/PlayerSkinUpdater.java | 2 - .../rendermanager/CombinedRenderTask.java | 3 - .../common/rendermanager/MapPurgeTask.java | 2 +- .../common/rendermanager/MapUpdateTask.java | 2 - .../common/rendermanager/RenderManager.java | 11 +- .../rendermanager/StorageDeleteTask.java | 2 +- .../rendermanager/WorldRegionRenderTask.java | 3 +- .../common/serverinterface/Server.java | 2 +- .../common/serverinterface/ServerWorld.java | 2 +- .../common/web/BlueMapResponseModifier.java | 2 - .../common/web/FileRequestHandler.java | 2 - .../common/web/LoggingRequestHandler.java | 2 - .../common/web/MapStorageRequestHandler.java | 2 - .../common/web/RoutingRequestHandler.java | 3 - .../bluemap/common/web/http/HttpServer.java | 2 - .../bluemap/core/debug/StateDumper.java | 277 --------------- .../bluecolored/bluemap/core/map/BmMap.java | 2 - .../bluemap/core/map/TextureGallery.java | 2 - .../core/map/renderstate/CellStorage.java | 2 - .../core/map/renderstate/MapChunkState.java | 2 - .../core/map/renderstate/MapTileState.java | 2 - .../BlockColorCalculatorFactory.java | 2 - .../core/resources/BlockPropertiesConfig.java | 2 - .../core/resources/BlockStateMapping.java | 2 - .../core/resources/MinecraftVersion.java | 2 - .../bluemap/core/resources/ResourcePath.java | 2 - .../datapack/dimension/DimensionTypeData.java | 2 - .../pack/resourcepack/ResourcePack.java | 2 - .../resourcepack/blockmodel/BlockModel.java | 2 - .../pack/resourcepack/blockmodel/Element.java | 2 - .../pack/resourcepack/blockmodel/Face.java | 2 - .../resourcepack/blockmodel/Rotation.java | 2 - .../blockmodel/TextureVariable.java | 2 - .../resourcepack/blockstate/BlockState.java | 2 - .../blockstate/BlockStateCondition.java | 6 - .../resourcepack/blockstate/Multipart.java | 2 - .../pack/resourcepack/blockstate/Variant.java | 2 - .../resourcepack/blockstate/VariantSet.java | 2 - .../resourcepack/blockstate/Variants.java | 2 - .../pack/resourcepack/texture/Texture.java | 2 - .../de/bluecolored/bluemap/core/util/Key.java | 3 - .../bluecolored/bluemap/core/util/Lazy.java | 3 - .../bluemap/core/util/math/Color.java | 3 - .../bluemap/core/world/BlockProperties.java | 2 - .../bluemap/core/world/BlockState.java | 2 - .../bluemap/core/world/biome/Biome.java | 2 - .../bluemap/core/world/mca/MCAWorld.java | 2 - .../core/world/mca/data/LevelData.java | 5 - 65 files changed, 398 insertions(+), 419 deletions(-) create mode 100644 BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/debug/DebugDump.java create mode 100644 BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/debug/StateDumper.java delete mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/debug/StateDumper.java diff --git a/BlueMapAPI b/BlueMapAPI index 6c84500df..8b179fb5e 160000 --- a/BlueMapAPI +++ b/BlueMapAPI @@ -1 +1 @@ -Subproject commit 6c84500dfc560ec9588c89f71cc4a2d7edef2b2d +Subproject commit 8b179fb5e011ef8ac7e550e2e9aa6c64b644eaee diff --git a/BlueMapCommon/build.gradle.kts b/BlueMapCommon/build.gradle.kts index f092b0c28..883f31f1c 100644 --- a/BlueMapCommon/build.gradle.kts +++ b/BlueMapCommon/build.gradle.kts @@ -27,6 +27,7 @@ repositories { dependencies { api ("com.mojang:brigadier:1.0.17") + api ("de.bluecolored.bluemap:BlueMapCore") compileOnly ("org.jetbrains:annotations:16.0.2") diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapService.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapService.java index 0ab90b724..ae00c4296 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapService.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapService.java @@ -29,14 +29,13 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; import com.google.gson.reflect.TypeToken; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.api.gson.MarkerGson; import de.bluecolored.bluemap.api.markers.MarkerSet; import de.bluecolored.bluemap.common.config.ConfigurationException; import de.bluecolored.bluemap.common.config.MapConfig; import de.bluecolored.bluemap.common.config.storage.StorageConfig; import de.bluecolored.bluemap.common.plugin.Plugin; -import de.bluecolored.bluemap.core.debug.StateDumper; +import de.bluecolored.bluemap.common.debug.StateDumper; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.map.BmMap; import de.bluecolored.bluemap.core.resources.MinecraftVersion; @@ -69,7 +68,6 @@ /** * This is the attempt to generalize as many actions as possible to have CLI and Plugins run on the same general setup-code. */ -@DebugDump public class BlueMapService implements Closeable { private final BlueMapConfiguration config; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigManager.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigManager.java index aec0deb7c..a005b10b4 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigManager.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigManager.java @@ -24,7 +24,6 @@ */ package de.bluecolored.bluemap.common.config; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.common.BlueMapConfiguration; import de.bluecolored.bluemap.common.config.storage.StorageConfig; import de.bluecolored.bluemap.common.serverinterface.ServerWorld; @@ -44,7 +43,6 @@ import java.util.*; import java.util.stream.Stream; -@DebugDump @Getter public class BlueMapConfigManager implements BlueMapConfiguration { diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/CoreConfig.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/CoreConfig.java index 810e27e48..c83d08631 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/CoreConfig.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/CoreConfig.java @@ -24,13 +24,11 @@ */ package de.bluecolored.bluemap.common.config; -import de.bluecolored.bluemap.api.debug.DebugDump; import org.spongepowered.configurate.objectmapping.ConfigSerializable; import java.nio.file.Path; @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"}) -@DebugDump @ConfigSerializable public class CoreConfig { @@ -75,7 +73,6 @@ public LogConfig getLog() { return log; } - @DebugDump @ConfigSerializable public static class LogConfig { diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/MapConfig.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/MapConfig.java index d986bc612..4463d4b22 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/MapConfig.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/MapConfig.java @@ -26,7 +26,6 @@ import com.flowpowered.math.vector.Vector2i; import com.flowpowered.math.vector.Vector3i; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.map.MapSettings; import de.bluecolored.bluemap.core.util.Key; import lombok.AccessLevel; @@ -38,7 +37,6 @@ import java.nio.file.Path; @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"}) -@DebugDump @ConfigSerializable @Getter public class MapConfig implements MapSettings { diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/PluginConfig.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/PluginConfig.java index 328b25fdb..f7cfd0b61 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/PluginConfig.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/PluginConfig.java @@ -24,14 +24,12 @@ */ package de.bluecolored.bluemap.common.config; -import de.bluecolored.bluemap.api.debug.DebugDump; import org.spongepowered.configurate.objectmapping.ConfigSerializable; import java.util.ArrayList; import java.util.List; @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"}) -@DebugDump @ConfigSerializable public class PluginConfig { diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/WebappConfig.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/WebappConfig.java index e366da11b..adde07d36 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/WebappConfig.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/WebappConfig.java @@ -24,7 +24,6 @@ */ package de.bluecolored.bluemap.common.config; -import de.bluecolored.bluemap.api.debug.DebugDump; import org.spongepowered.configurate.objectmapping.ConfigSerializable; import java.nio.file.Path; @@ -33,7 +32,6 @@ import java.util.Set; @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"}) -@DebugDump @ConfigSerializable public class WebappConfig { diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/WebserverConfig.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/WebserverConfig.java index 63a43d205..533f69514 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/WebserverConfig.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/WebserverConfig.java @@ -24,7 +24,6 @@ */ package de.bluecolored.bluemap.common.config; -import de.bluecolored.bluemap.api.debug.DebugDump; import org.spongepowered.configurate.objectmapping.ConfigSerializable; import java.net.InetAddress; @@ -33,7 +32,6 @@ import java.nio.file.Path; @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"}) -@DebugDump @ConfigSerializable public class WebserverConfig { @@ -75,7 +73,6 @@ public LogConfig getLog() { return log; } - @DebugDump @ConfigSerializable public static class LogConfig { diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/FileConfig.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/FileConfig.java index 5065504fa..b4714f97a 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/FileConfig.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/FileConfig.java @@ -24,7 +24,6 @@ */ package de.bluecolored.bluemap.common.config.storage; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.common.config.ConfigurationException; import de.bluecolored.bluemap.core.storage.compression.Compression; import de.bluecolored.bluemap.core.storage.file.FileStorage; @@ -34,7 +33,6 @@ import java.nio.file.Path; @SuppressWarnings("FieldMayBeFinal") -@DebugDump @ConfigSerializable @Getter public class FileConfig extends StorageConfig { diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLConfig.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLConfig.java index 68de7b2de..2a10f917a 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLConfig.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLConfig.java @@ -24,8 +24,8 @@ */ package de.bluecolored.bluemap.common.config.storage; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.common.config.ConfigurationException; +import de.bluecolored.bluemap.common.debug.DebugDump; import de.bluecolored.bluemap.core.storage.compression.Compression; import de.bluecolored.bluemap.core.storage.sql.Database; import de.bluecolored.bluemap.core.storage.sql.SQLStorage; @@ -51,17 +51,20 @@ @Getter public class SQLConfig extends StorageConfig { + @DebugDump(exclude = true) private String connectionUrl = "jdbc:mysql://localhost/bluemap?permitMysqlScheme"; + + @DebugDump(exclude = true) private Map connectionProperties = new HashMap<>(); - @DebugDump private String dialect = null; - @DebugDump private String driverJar = null; - @DebugDump private String driverClass = null; - @DebugDump private int maxConnections = -1; + private String dialect = null; + + private String driverJar = null; + private String driverClass = null; + private int maxConnections = -1; - @DebugDump private String compression = Compression.GZIP.getKey().getFormatted(); + private String compression = Compression.GZIP.getKey().getFormatted(); - @DebugDump @Getter(AccessLevel.NONE) private transient URL driverJarURL = null; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/StorageConfig.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/StorageConfig.java index 4c2705c26..0cb74b49b 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/StorageConfig.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/storage/StorageConfig.java @@ -24,7 +24,6 @@ */ package de.bluecolored.bluemap.common.config.storage; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.common.config.ConfigurationException; import de.bluecolored.bluemap.core.storage.Storage; import de.bluecolored.bluemap.core.util.Key; @@ -35,7 +34,6 @@ import java.util.Locale; @SuppressWarnings("FieldMayBeFinal") -@DebugDump @ConfigSerializable public abstract class StorageConfig { diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/debug/DebugDump.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/debug/DebugDump.java new file mode 100644 index 000000000..07f610058 --- /dev/null +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/debug/DebugDump.java @@ -0,0 +1,44 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.common.debug; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ + ElementType.METHOD, + ElementType.FIELD, + ElementType.TYPE +}) +public @interface DebugDump { + + String value() default ""; + + boolean exclude() default false; + +} \ No newline at end of file diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/debug/StateDumper.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/debug/StateDumper.java new file mode 100644 index 000000000..1fc1b7802 --- /dev/null +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/debug/StateDumper.java @@ -0,0 +1,328 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.common.debug; + +import com.google.gson.stream.JsonWriter; +import de.bluecolored.bluemap.core.BlueMap; +import de.bluecolored.bluemap.core.util.Key; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.time.LocalDateTime; +import java.util.*; + +public class StateDumper { + + private static final StateDumper GLOBAL = new StateDumper(); + + private final Set instances = Collections.newSetFromMap(new WeakHashMap<>()); + + public void dump(Path file) throws IOException { + JsonWriter writer = new JsonWriter(Files.newBufferedWriter( + file, + StandardCharsets.UTF_8, + StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING + )); + writer.setIndent(" "); + + writer.beginObject(); + + writer.name("system-info"); + collectSystemInfo(writer); + + Set alreadyDumped = Collections.newSetFromMap(new IdentityHashMap<>()); + + writer.name("threads").beginArray(); + for (Thread thread : Thread.getAllStackTraces().keySet()) { + dumpInstance(thread, writer, alreadyDumped); + } + writer.endArray(); + + writer.name("dump").beginObject(); + for (Object instance : instances) { + Class type = instance.getClass(); + writer.name(type.getName()); + dumpInstance(instance, writer, alreadyDumped); + } + writer.endObject(); + + writer.endObject(); + + writer.flush(); + writer.close(); + } + + private void dumpInstance(Object instance, JsonWriter writer, Set alreadyDumped) throws IOException { + + if (instance == null) { + writer.nullValue(); + return; + } + + if (instance instanceof String || + instance instanceof Path || + instance instanceof UUID || + instance instanceof Key + ) { + writer.value(instance.toString()); + return; + } + + if (instance instanceof Number val) { + writer.value(val); + return; + } + + if (instance instanceof Boolean val) { + writer.value(val); + return; + } + + if (!alreadyDumped.add(instance)) { + writer.value("<<" + Objects.toIdentityString(instance) + ">>"); + return; + } + + writer.beginObject(); + try { + String identityString = Objects.toIdentityString(instance); + writer.name("#identity").value(identityString); + + if (instance instanceof Map map) { + writer.name("entries").beginArray(); + + int count = 0; + for (Map.Entry entry : map.entrySet()) { + if (++count > 30) { + writer.value("<<" + (map.size() - 30) + " more elements>>"); + break; + } + + writer.beginObject(); + + writer.name("key"); + dumpInstance(entry.getKey(), writer, alreadyDumped); + + writer.name("value"); + dumpInstance(entry.getValue(), writer, alreadyDumped); + + writer.endObject(); + } + + writer.endArray(); + return; + } + + if (instance instanceof Collection collection) { + writer.name("entries").beginArray(); + + int count = 0; + for (Object entry : collection) { + if (++count > 30) { + writer.value("<<" + (collection.size() - 30) + " more elements>>"); + break; + } + + dumpInstance(entry, writer, alreadyDumped); + } + + writer.endArray(); + return; + } + + if (instance instanceof Object[] array) { + writer.name("entries").beginArray(); + + int count = 0; + for (Object entry : array) { + if (++count > 30) { + writer.value("<<" + (array.length - 30) + " more elements>>"); + break; + } + + dumpInstance(entry, writer, alreadyDumped); + } + + writer.endArray(); + return; + } + + String toString = instance.toString(); + if (!toString.equals(identityString)) + writer.name("#toString").value(instance.toString()); + + if (instance instanceof Thread thread) { + writer.name("name").value(thread.getName()); + writer.name("state").value(thread.getState().toString()); + writer.name("priority").value(thread.getPriority()); + writer.name("alive").value(thread.isAlive()); + writer.name("id").value(thread.getId()); + writer.name("deamon").value(thread.isDaemon()); + writer.name("interrupted").value(thread.isInterrupted()); + + try { + StackTraceElement[] trace = thread.getStackTrace(); + writer.name("stacktrace").beginArray(); + for (StackTraceElement element : trace) { + writer.value(element.toString()); + } + writer.endArray(); + } catch (SecurityException ignore) {} + + return; + } + + dumpAnnotatedInstance(instance.getClass(), instance, writer, alreadyDumped); + + } finally { + writer.endObject(); + } + } + + private void dumpAnnotatedInstance(Class type, Object instance, JsonWriter writer, Set alreadyDumped) throws IOException { + + DebugDump typedd = type.getAnnotation(DebugDump.class); + boolean exclude = typedd != null && typedd.exclude(); + boolean allFields = !exclude && ( + typedd != null || + type.getPackageName().startsWith("de.bluecolored.bluemap") + ); + + for (Field field : type.getDeclaredFields()) { + String key = field.getName(); + Object value; + + try { + DebugDump dd = field.getAnnotation(DebugDump.class); + if (dd == null) { + if (!allFields) continue; + if (Modifier.isStatic(field.getModifiers())) continue; + if (Modifier.isTransient(field.getModifiers())) continue; + } else { + if (dd.exclude()) continue; + } + + if (dd != null) { + key = dd.value(); + if (key.isEmpty()) key = field.getName(); + } + + field.setAccessible(true); + value = field.get(instance); + } catch (Exception ex) { + writer.name("!!" + key).value(ex.toString()); + continue; + } + + writer.name(key); + dumpInstance(value, writer, alreadyDumped); + } + + for (Method method : type.getDeclaredMethods()) { + String key = method.toGenericString(); + Object value; + + try { + DebugDump dd = method.getAnnotation(DebugDump.class); + if (dd == null || dd.exclude()) continue; + + key = dd.value(); + if (key.isEmpty()) key = method.toGenericString(); + + method.setAccessible(true); + value = method.invoke(instance); + } catch (Exception ex) { + writer.name("!!" + key).value(ex.toString()); + continue; + } + + writer.name(key); + dumpInstance(value, writer, alreadyDumped); + } + + for (Class iface : type.getInterfaces()) { + dumpAnnotatedInstance(iface, instance, writer, alreadyDumped); + } + + Class typeSuperclass = type.getSuperclass(); + if (typeSuperclass != null) { + dumpAnnotatedInstance(typeSuperclass, instance, writer, alreadyDumped); + } + + } + + private void collectSystemInfo(JsonWriter writer) throws IOException { + writer.beginObject(); + + writer.name("bluemap-version").value(BlueMap.VERSION); + writer.name("git-hash").value(BlueMap.GIT_HASH); + + String[] properties = new String[]{ + "java.runtime.name", + "java.runtime.version", + "java.vm.vendor", + "java.vm.name", + "os.name", + "os.version", + "user.dir", + "java.home", + "file.separator", + "sun.io.unicode.encoding", + "java.class.version" + }; + Map propMap = new HashMap<>(); + for (String key : properties) { + propMap.put(key, System.getProperty(key)); + } + writer.name("properties"); + dumpInstance(propMap, writer, new HashSet<>()); + + writer.name("cores").value(Runtime.getRuntime().availableProcessors()); + writer.name("max-memory").value(Runtime.getRuntime().maxMemory()); + writer.name("total-memory").value(Runtime.getRuntime().totalMemory()); + writer.name("free-memory").value(Runtime.getRuntime().freeMemory()); + + writer.name("timestamp").value(System.currentTimeMillis()); + writer.name("time").value(LocalDateTime.now().toString()); + + writer.endObject(); + } + + public static StateDumper global() { + return GLOBAL; + } + + public synchronized void register(Object instance) { + GLOBAL.instances.add(instance); + } + +} diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java index 822e8944b..17c30de21 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java @@ -24,7 +24,6 @@ */ package de.bluecolored.bluemap.common.plugin; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.common.BlueMapConfiguration; import de.bluecolored.bluemap.common.BlueMapService; import de.bluecolored.bluemap.common.InterruptableReentrantLock; @@ -40,7 +39,7 @@ import de.bluecolored.bluemap.common.serverinterface.ServerWorld; import de.bluecolored.bluemap.common.web.*; import de.bluecolored.bluemap.common.web.http.HttpServer; -import de.bluecolored.bluemap.core.debug.StateDumper; +import de.bluecolored.bluemap.common.debug.StateDumper; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.map.BmMap; import de.bluecolored.bluemap.core.metrics.Metrics; @@ -71,7 +70,6 @@ import java.util.function.Predicate; import java.util.regex.Pattern; -@DebugDump public class Plugin implements ServerEventListener { public static final String PLUGIN_ID = "bluemap"; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/RegionFileWatchService.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/RegionFileWatchService.java index 21a7324b2..a788bed40 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/RegionFileWatchService.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/RegionFileWatchService.java @@ -25,7 +25,6 @@ package de.bluecolored.bluemap.common.plugin; import com.flowpowered.math.vector.Vector2i; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.common.rendermanager.RenderManager; import de.bluecolored.bluemap.common.rendermanager.WorldRegionRenderTask; import de.bluecolored.bluemap.core.logger.Logger; @@ -52,7 +51,6 @@ public class RegionFileWatchService extends Thread { private Timer delayTimer; - @DebugDump private final Map scheduledUpdates; public RegionFileWatchService(RenderManager renderManager, BmMap map) throws IOException { diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java index 26a16017e..5d002fb83 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java @@ -48,7 +48,7 @@ import de.bluecolored.bluemap.common.rendermanager.*; import de.bluecolored.bluemap.common.serverinterface.CommandSource; import de.bluecolored.bluemap.core.BlueMap; -import de.bluecolored.bluemap.core.debug.StateDumper; +import de.bluecolored.bluemap.common.debug.StateDumper; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.map.BmMap; import de.bluecolored.bluemap.core.map.renderstate.TileInfoRegion; @@ -635,7 +635,7 @@ public int debugDumpCommand(CommandContext context) { final CommandSource source = commandSourceInterface.apply(context.getSource()); try { - Path file = plugin.getBlueMap().getConfig().getCoreConfig().getData().resolve("dump.json"); + Path file = plugin.getBlueMap().getConfig().getCoreConfig().getData().resolve("dump.json.gz"); StateDumper.global().dump(file); source.sendMessage(Text.of(TextColor.GREEN, "Dump created at: " + file)); diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/skins/PlayerSkinUpdater.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/skins/PlayerSkinUpdater.java index 2afe3ee21..3840a5bbb 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/skins/PlayerSkinUpdater.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/skins/PlayerSkinUpdater.java @@ -24,7 +24,6 @@ */ package de.bluecolored.bluemap.common.plugin.skins; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.api.plugin.PlayerIconFactory; import de.bluecolored.bluemap.api.plugin.SkinProvider; import de.bluecolored.bluemap.common.plugin.Plugin; @@ -45,7 +44,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; -@DebugDump public class PlayerSkinUpdater implements ServerEventListener { private final Plugin plugin; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/CombinedRenderTask.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/CombinedRenderTask.java index f239f60fa..b164b00ed 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/CombinedRenderTask.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/CombinedRenderTask.java @@ -24,11 +24,8 @@ */ package de.bluecolored.bluemap.common.rendermanager; -import de.bluecolored.bluemap.api.debug.DebugDump; - import java.util.*; -@DebugDump public class CombinedRenderTask implements RenderTask { private final String description; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapPurgeTask.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapPurgeTask.java index 20f6a6911..77d7d98b6 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapPurgeTask.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapPurgeTask.java @@ -24,7 +24,7 @@ */ package de.bluecolored.bluemap.common.rendermanager; -import de.bluecolored.bluemap.api.debug.DebugDump; +import de.bluecolored.bluemap.common.debug.DebugDump; import de.bluecolored.bluemap.core.map.BmMap; import java.util.Objects; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapUpdateTask.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapUpdateTask.java index d5224cddd..47a455ecb 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapUpdateTask.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapUpdateTask.java @@ -25,7 +25,6 @@ package de.bluecolored.bluemap.common.rendermanager; import com.flowpowered.math.vector.Vector2i; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.map.BmMap; import de.bluecolored.bluemap.core.map.renderstate.MapTileState; @@ -39,7 +38,6 @@ import java.util.function.Predicate; import java.util.stream.Stream; -@DebugDump public class MapUpdateTask extends CombinedRenderTask { private final BmMap map; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/RenderManager.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/RenderManager.java index d5d6112fc..b1b7a6963 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/RenderManager.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/RenderManager.java @@ -24,7 +24,6 @@ */ package de.bluecolored.bluemap.common.rendermanager; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.logger.Logger; import java.util.*; @@ -35,19 +34,19 @@ public class RenderManager { private static final AtomicInteger nextRenderManagerIndex = new AtomicInteger(0); - @DebugDump private final int id; - @DebugDump private volatile boolean running; + private final int id; + private volatile boolean running; - @DebugDump private long lastTimeBusy; + private long lastTimeBusy; private final AtomicInteger nextWorkerThreadIndex; - @DebugDump private final Collection workerThreads; + private final Collection workerThreads; private final AtomicInteger busyCount; private ProgressTracker progressTracker; private volatile boolean newTask; - @DebugDump private final LinkedList renderTasks; + private final LinkedList renderTasks; public RenderManager() { this.id = nextRenderManagerIndex.getAndIncrement(); diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/StorageDeleteTask.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/StorageDeleteTask.java index caff33d42..ecdf337ed 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/StorageDeleteTask.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/StorageDeleteTask.java @@ -24,7 +24,7 @@ */ package de.bluecolored.bluemap.common.rendermanager; -import de.bluecolored.bluemap.api.debug.DebugDump; +import de.bluecolored.bluemap.common.debug.DebugDump; import de.bluecolored.bluemap.core.storage.MapStorage; import java.util.Objects; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/WorldRegionRenderTask.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/WorldRegionRenderTask.java index 33f8862a8..ab728050c 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/WorldRegionRenderTask.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/WorldRegionRenderTask.java @@ -26,7 +26,7 @@ import com.flowpowered.math.vector.Vector2i; import com.flowpowered.math.vector.Vector2l; -import de.bluecolored.bluemap.api.debug.DebugDump; +import de.bluecolored.bluemap.common.debug.DebugDump; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.map.BmMap; import de.bluecolored.bluemap.core.map.renderstate.TileActionResolver.ActionAndNextState; @@ -47,7 +47,6 @@ import static de.bluecolored.bluemap.core.map.renderstate.TileActionResolver.Action.DELETE; import static de.bluecolored.bluemap.core.map.renderstate.TileActionResolver.Action.RENDER; -@DebugDump public class WorldRegionRenderTask implements RenderTask { @Getter private final BmMap map; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/serverinterface/Server.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/serverinterface/Server.java index 1b00db5b1..2430c39d5 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/serverinterface/Server.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/serverinterface/Server.java @@ -24,7 +24,7 @@ */ package de.bluecolored.bluemap.common.serverinterface; -import de.bluecolored.bluemap.api.debug.DebugDump; +import de.bluecolored.bluemap.common.debug.DebugDump; import de.bluecolored.bluemap.core.util.Tristate; import de.bluecolored.bluemap.core.world.World; import de.bluecolored.bluemap.core.world.mca.MCAWorld; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/serverinterface/ServerWorld.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/serverinterface/ServerWorld.java index 69216b8de..22f1785f6 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/serverinterface/ServerWorld.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/serverinterface/ServerWorld.java @@ -24,7 +24,7 @@ */ package de.bluecolored.bluemap.common.serverinterface; -import de.bluecolored.bluemap.api.debug.DebugDump; +import de.bluecolored.bluemap.common.debug.DebugDump; import de.bluecolored.bluemap.core.util.Key; import java.io.IOException; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/BlueMapResponseModifier.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/BlueMapResponseModifier.java index ce0c362ab..c11d07f52 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/BlueMapResponseModifier.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/BlueMapResponseModifier.java @@ -24,14 +24,12 @@ */ package de.bluecolored.bluemap.common.web; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.common.web.http.HttpRequest; import de.bluecolored.bluemap.common.web.http.HttpRequestHandler; import de.bluecolored.bluemap.common.web.http.HttpResponse; import de.bluecolored.bluemap.common.web.http.HttpStatusCode; import de.bluecolored.bluemap.core.BlueMap; -@DebugDump public class BlueMapResponseModifier implements HttpRequestHandler { private final HttpRequestHandler delegate; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java index af960e779..b3f427253 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java @@ -24,7 +24,6 @@ */ package de.bluecolored.bluemap.common.web; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.common.web.http.*; import org.apache.commons.lang3.time.DateFormatUtils; @@ -39,7 +38,6 @@ import java.util.TimeZone; import java.util.concurrent.TimeUnit; -@DebugDump public class FileRequestHandler implements HttpRequestHandler { private final Path webRoot; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/LoggingRequestHandler.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/LoggingRequestHandler.java index f54834579..62efe6427 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/LoggingRequestHandler.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/LoggingRequestHandler.java @@ -24,12 +24,10 @@ */ package de.bluecolored.bluemap.common.web; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.common.web.http.*; import de.bluecolored.bluemap.core.logger.Logger; import lombok.Getter; -@DebugDump @Getter public class LoggingRequestHandler implements HttpRequestHandler { diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/MapStorageRequestHandler.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/MapStorageRequestHandler.java index 0fdb38530..eaa8043ba 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/MapStorageRequestHandler.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/MapStorageRequestHandler.java @@ -25,7 +25,6 @@ package de.bluecolored.bluemap.common.web; import de.bluecolored.bluemap.api.ContentTypeRegistry; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.common.web.http.HttpRequest; import de.bluecolored.bluemap.common.web.http.HttpRequestHandler; import de.bluecolored.bluemap.common.web.http.HttpResponse; @@ -47,7 +46,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -@DebugDump @RequiredArgsConstructor public class MapStorageRequestHandler implements HttpRequestHandler { diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/RoutingRequestHandler.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/RoutingRequestHandler.java index 0f2f8cd4a..c68cb4eb9 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/RoutingRequestHandler.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/RoutingRequestHandler.java @@ -24,7 +24,6 @@ */ package de.bluecolored.bluemap.common.web; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.common.web.http.HttpRequest; import de.bluecolored.bluemap.common.web.http.HttpRequestHandler; import de.bluecolored.bluemap.common.web.http.HttpResponse; @@ -39,7 +38,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -@DebugDump public class RoutingRequestHandler implements HttpRequestHandler { public final LinkedList routes; @@ -83,7 +81,6 @@ public HttpResponse handle(HttpRequest request) { return new HttpResponse(HttpStatusCode.BAD_REQUEST); } - @DebugDump @AllArgsConstructor @Getter @Setter public static class Route { diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/http/HttpServer.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/http/HttpServer.java index e11e72248..d8e8c3546 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/http/HttpServer.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/http/HttpServer.java @@ -24,13 +24,11 @@ */ package de.bluecolored.bluemap.common.web.http; -import de.bluecolored.bluemap.api.debug.DebugDump; import lombok.Getter; import lombok.Setter; import java.io.IOException; -@DebugDump public class HttpServer extends Server { @Getter @Setter diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/debug/StateDumper.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/debug/StateDumper.java deleted file mode 100644 index 7551a0217..000000000 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/debug/StateDumper.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * This file is part of BlueMap, licensed under the MIT License (MIT). - * - * Copyright (c) Blue (Lukas Rieger) - * 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.debug; - -import de.bluecolored.bluemap.api.debug.DebugDump; -import de.bluecolored.bluemap.core.BlueMap; -import org.spongepowered.configurate.ConfigurationNode; -import org.spongepowered.configurate.ConfigurationOptions; -import org.spongepowered.configurate.gson.GsonConfigurationLoader; -import org.spongepowered.configurate.serialize.SerializationException; - -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.nio.file.Path; -import java.time.LocalDateTime; -import java.util.*; - -public class StateDumper { - - private static final StateDumper GLOBAL = new StateDumper(); - - private final Set instances = Collections.newSetFromMap(new WeakHashMap<>()); - - public void dump(Path file) throws IOException { - GsonConfigurationLoader loader = GsonConfigurationLoader.builder() - .path(file) - .build(); - ConfigurationNode node = loader.createNode(); - - collectSystemInfo(node.node("system-info")); - - Set alreadyDumped = Collections.newSetFromMap(new WeakHashMap<>()); - - try { - ConfigurationNode threadDump = node.node("threads"); - for (Thread thread : Thread.getAllStackTraces().keySet()) { - dumpInstance(thread, loader.defaultOptions(), threadDump.appendListNode(), alreadyDumped); - } - } catch (SecurityException ex){ - node.node("threads").set(ex.toString()); - } - - ConfigurationNode dump = node.node("dump"); - for (Object instance : instances) { - Class type = instance.getClass(); - ConfigurationNode instanceDump = dump.node(type.getName()).appendListNode(); - dumpInstance(instance, loader.defaultOptions(), instanceDump, alreadyDumped); - } - - loader.save(node); - - } - - private void dumpInstance(Object instance, ConfigurationOptions options, ConfigurationNode node, Set alreadyDumped) throws SerializationException { - - try { - if (instance == null){ - node.raw(null); - return; - } - - Class type = instance.getClass(); - - if (!alreadyDumped.add(instance)) { - node.set("<<" + instance + ">>"); - return; - } - - if (instance instanceof Map) { - int count = 0; - Map map = (Map) instance; - - if (map.isEmpty()){ - node.set(map.toString()); - return; - } - - for (Map.Entry entry : map.entrySet()) { - if (++count > 100) { - node.appendListNode().set("<<" + (map.size() - 100) + " more elements>>"); - break; - } - - ConfigurationNode entryNode = node.appendListNode(); - dumpInstance(entry.getKey(), options, entryNode.node("key"), alreadyDumped); - dumpInstance(entry.getValue(), options, entryNode.node("value"), alreadyDumped); - } - return; - } - - if (instance instanceof Collection) { - if (((Collection) instance).isEmpty()){ - node.set(instance.toString()); - return; - } - - int count = 0; - for (Object entry : (Collection) instance) { - if (++count > 100) { - node.appendListNode().set("<<" + (((Collection) instance).size() - 100) + " more elements>>"); - break; - } - - dumpInstance(entry, options, node.appendListNode(), alreadyDumped); - } - return; - } - - if (instance instanceof Object[]) { - if (((Object[]) instance).length == 0){ - node.set(instance.toString()); - return; - } - - int count = 0; - for (Object entry : (Object[]) instance) { - if (++count > 100) { - node.appendListNode().set("<<" + (((Object[]) instance).length - 100) + " more elements>>"); - break; - } - - dumpInstance(entry, options, node.appendListNode(), alreadyDumped); - } - return; - } - - if (instance instanceof Thread) { - Thread t = (Thread) instance; - node.node("name").set(t.getName()); - node.node("state").set(t.getState().toString()); - node.node("priority").set(t.getPriority()); - node.node("alive").set(t.isAlive()); - node.node("id").set(t.getId()); - node.node("deamon").set(t.isDaemon()); - node.node("interrupted").set(t.isInterrupted()); - - dumpInstance(t.getStackTrace(), options, node.node("stackTrace"), alreadyDumped); - return; - } - - boolean foundSomething = dumpAnnotatedInstance(type, instance, options, node, alreadyDumped); - if (!foundSomething) { - node.set(instance.toString()); - } - - } catch (Exception ex) { - StringWriter stringWriter = new StringWriter(); - ex.printStackTrace(new PrintWriter(stringWriter)); - node.set("Error: " + ex + " >> " + stringWriter); - } - } - - private boolean dumpAnnotatedInstance(Class type, Object instance, ConfigurationOptions options, ConfigurationNode node, Set alreadyDumped) throws Exception { - boolean foundSomething = false; - boolean allFields = type.isAnnotationPresent(DebugDump.class); - - for (Field field : type.getDeclaredFields()) { - DebugDump dd = field.getAnnotation(DebugDump.class); - if (dd == null) { - if (!allFields) continue; - if (Modifier.isStatic(field.getModifiers())) continue; - if (Modifier.isTransient(field.getModifiers())) continue; - } - foundSomething = true; - - String key = ""; - if (dd != null) key = dd.value(); - if (key.isEmpty()) key = field.getName(); - - field.setAccessible(true); - if (options.acceptsType(field.getType())) { - node.node(key).set(field.get(instance)); - } else { - dumpInstance(field.get(instance), options, node.node(key), alreadyDumped); - } - } - - for (Method method : type.getDeclaredMethods()) { - DebugDump dd = method.getAnnotation(DebugDump.class); - if (dd == null) continue; - foundSomething = true; - - String key = dd.value(); - if (key.isEmpty()) key = method.toGenericString().replace(' ', '_'); - - if (options.acceptsType(method.getReturnType())) { - method.setAccessible(true); - node.node(key).set(method.invoke(instance)); - } else { - method.setAccessible(true); - dumpInstance(method.invoke(instance), options, node.node(key), alreadyDumped); - } - } - - for (Class iface : type.getInterfaces()) { - foundSomething |= dumpAnnotatedInstance(iface, instance, options, node, alreadyDumped); - } - - Class typeSuperclass = type.getSuperclass(); - if (typeSuperclass != null) { - foundSomething |= dumpAnnotatedInstance(typeSuperclass, instance, options, node, alreadyDumped); - } - - return foundSomething; - } - - private void collectSystemInfo(ConfigurationNode node) throws SerializationException { - node.node("bluemap-version").set(BlueMap.VERSION); - node.node("git-hash").set(BlueMap.GIT_HASH); - - String[] properties = new String[]{ - "java.runtime.name", - "java.runtime.version", - "java.vm.vendor", - "java.vm.name", - "os.name", - "os.version", - "user.dir", - "java.home", - "file.separator", - "sun.io.unicode.encoding", - "java.class.version" - }; - Map propMap = new HashMap<>(); - for (String key : properties) { - propMap.put(key, System.getProperty(key)); - } - node.node("system-properties").set(propMap); - - node.node("cores").set(Runtime.getRuntime().availableProcessors()); - node.node("max-memory").set(Runtime.getRuntime().maxMemory()); - node.node("total-memory").set(Runtime.getRuntime().totalMemory()); - node.node("free-memory").set(Runtime.getRuntime().freeMemory()); - - node.node("timestamp").set(System.currentTimeMillis()); - node.node("time").set(LocalDateTime.now().toString()); - } - - public static StateDumper global() { - return GLOBAL; - } - - public synchronized void register(Object instance) { - GLOBAL.instances.add(instance); - } - - public synchronized void unregister(Object instance) { - GLOBAL.instances.remove(instance); - } - -} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/BmMap.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/BmMap.java index 01851a380..3b9120cee 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/BmMap.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/BmMap.java @@ -28,7 +28,6 @@ import com.google.gson.FieldNamingPolicy; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.api.gson.MarkerGson; import de.bluecolored.bluemap.api.markers.MarkerSet; import de.bluecolored.bluemap.core.logger.Logger; @@ -55,7 +54,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Predicate; -@DebugDump @Getter public class BmMap { diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/TextureGallery.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/TextureGallery.java index 2a5c89773..47d33bb4f 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/TextureGallery.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/TextureGallery.java @@ -29,7 +29,6 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonIOException; import com.google.gson.JsonParseException; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.resources.ResourcePath; import de.bluecolored.bluemap.core.resources.adapter.ResourcesGson; import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; @@ -43,7 +42,6 @@ import java.util.HashMap; import java.util.Map; -@DebugDump public class TextureGallery { private static final Gson GSON = ResourcesGson.addAdapter(new GsonBuilder()) diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/CellStorage.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/CellStorage.java index f133d88bf..0d9ee99bc 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/CellStorage.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/CellStorage.java @@ -26,7 +26,6 @@ import com.flowpowered.math.vector.Vector2i; import com.google.gson.reflect.TypeToken; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.storage.GridStorage; import de.bluecolored.bluemap.core.storage.compression.CompressedInputStream; @@ -41,7 +40,6 @@ import java.util.LinkedHashMap; import java.util.Map; -@DebugDump abstract class CellStorage { private static final BlueNBT BLUE_NBT = new BlueNBT(); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/MapChunkState.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/MapChunkState.java index 945a888c4..246146e3b 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/MapChunkState.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/MapChunkState.java @@ -24,10 +24,8 @@ */ package de.bluecolored.bluemap.core.map.renderstate; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.storage.GridStorage; -@DebugDump public class MapChunkState extends CellStorage { static final int SHIFT = 7; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/MapTileState.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/MapTileState.java index f3796698d..1dbc87a31 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/MapTileState.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/MapTileState.java @@ -24,7 +24,6 @@ */ package de.bluecolored.bluemap.core.map.renderstate; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.storage.GridStorage; import de.bluecolored.bluemap.core.util.Grid; @@ -36,7 +35,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; -@DebugDump public class MapTileState extends CellStorage { static final int SHIFT = 5; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/BlockColorCalculatorFactory.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/BlockColorCalculatorFactory.java index 913c08cdf..41282d944 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/BlockColorCalculatorFactory.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/BlockColorCalculatorFactory.java @@ -26,7 +26,6 @@ import com.flowpowered.math.GenericMath; import com.google.gson.stream.JsonReader; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.util.math.Color; import de.bluecolored.bluemap.core.world.biome.Biome; import de.bluecolored.bluemap.core.world.block.Block; @@ -40,7 +39,6 @@ import java.util.HashMap; import java.util.Map; -@DebugDump public class BlockColorCalculatorFactory { private static final int BLEND_RADIUS_H = 2; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/BlockPropertiesConfig.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/BlockPropertiesConfig.java index 59939d043..aa2d73efe 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/BlockPropertiesConfig.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/BlockPropertiesConfig.java @@ -25,7 +25,6 @@ package de.bluecolored.bluemap.core.resources; import com.google.gson.stream.JsonReader; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.world.BlockProperties; import de.bluecolored.bluemap.core.world.BlockState; @@ -39,7 +38,6 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -@DebugDump public class BlockPropertiesConfig { private final Map>> mappings; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/BlockStateMapping.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/BlockStateMapping.java index 090f9c620..e681d2f40 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/BlockStateMapping.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/BlockStateMapping.java @@ -24,12 +24,10 @@ */ package de.bluecolored.bluemap.core.resources; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.world.BlockState; import java.util.Map.Entry; -@DebugDump class BlockStateMapping { private final BlockState blockState; private final T mapping; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/MinecraftVersion.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/MinecraftVersion.java index 2b2067ff1..5c80eb372 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/MinecraftVersion.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/MinecraftVersion.java @@ -29,7 +29,6 @@ import com.google.gson.JsonObject; import com.google.gson.annotations.JsonAdapter; import com.google.gson.stream.JsonReader; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.util.FileHelper; import lombok.AccessLevel; @@ -48,7 +47,6 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; -@DebugDump @Getter @RequiredArgsConstructor(access = AccessLevel.PRIVATE) public class MinecraftVersion { diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/ResourcePath.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/ResourcePath.java index ef357ed9a..05f7fd15b 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/ResourcePath.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/ResourcePath.java @@ -31,7 +31,6 @@ import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.util.Key; import org.jetbrains.annotations.Nullable; @@ -40,7 +39,6 @@ import java.util.Locale; import java.util.function.Function; -@DebugDump @JsonAdapter(ResourcePath.Adapter.class) public class ResourcePath extends Key { diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/dimension/DimensionTypeData.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/dimension/DimensionTypeData.java index 4fca54a96..27694b37e 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/dimension/DimensionTypeData.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/datapack/dimension/DimensionTypeData.java @@ -24,14 +24,12 @@ */ package de.bluecolored.bluemap.core.resources.pack.datapack.dimension; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.world.DimensionType; import de.bluecolored.bluenbt.NBTName; import lombok.*; import lombok.experimental.Accessors; @Data -@DebugDump public class DimensionTypeData implements DimensionType { @NBTName("natural") diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/ResourcePack.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/ResourcePack.java index b85d111cd..28495dede 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/ResourcePack.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/ResourcePack.java @@ -26,7 +26,6 @@ import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.LoadingCache; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.BlueMap; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.resources.BlockColorCalculatorFactory; @@ -58,7 +57,6 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; -@DebugDump public class ResourcePack extends Pack { public static final ResourcePath MISSING_BLOCK_STATE = new ResourcePath<>("bluemap", "missing"); public static final ResourcePath MISSING_BLOCK_MODEL = new ResourcePath<>("bluemap", "block/missing"); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/BlockModel.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/BlockModel.java index 00dbae8d1..6c6f63c48 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/BlockModel.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/BlockModel.java @@ -24,7 +24,6 @@ */ package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.resources.ResourcePath; import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; import de.bluecolored.bluemap.core.resources.pack.resourcepack.texture.Texture; @@ -34,7 +33,6 @@ import java.util.*; @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"}) -@DebugDump public class BlockModel { private ResourcePath parent; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Element.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Element.java index a022d063c..950939353 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Element.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Element.java @@ -30,7 +30,6 @@ import com.google.gson.annotations.JsonAdapter; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.resources.AbstractTypeAdapterFactory; import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; import de.bluecolored.bluemap.core.util.Direction; @@ -39,7 +38,6 @@ import java.util.EnumMap; @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"}) -@DebugDump @JsonAdapter(Element.Adapter.class) public class Element { private static final Vector3f FULL_BLOCK_MIN = Vector3f.ZERO; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Face.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Face.java index 5c6ca23a5..2b9c42a30 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Face.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Face.java @@ -25,14 +25,12 @@ package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel; import com.flowpowered.math.vector.Vector4f; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; import de.bluecolored.bluemap.core.util.Direction; import java.util.function.Function; @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"}) -@DebugDump public class Face { private static final TextureVariable DEFAULT_TEXTURE = new TextureVariable(ResourcePack.MISSING_TEXTURE); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Rotation.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Rotation.java index 009d9993b..47f0af128 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Rotation.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/Rotation.java @@ -31,7 +31,6 @@ import com.google.gson.annotations.JsonAdapter; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.resources.AbstractTypeAdapterFactory; import de.bluecolored.bluemap.core.util.math.Axis; import de.bluecolored.bluemap.core.util.math.MatrixM4f; @@ -39,7 +38,6 @@ import java.io.IOException; @SuppressWarnings("FieldMayBeFinal") -@DebugDump @JsonAdapter(Rotation.Adapter.class) public class Rotation { private static final Vector3f DEFAULT_ORIGIN = new Vector3f(8, 8, 8); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/TextureVariable.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/TextureVariable.java index f29b59969..5d132186f 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/TextureVariable.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/TextureVariable.java @@ -28,7 +28,6 @@ import com.google.gson.annotations.JsonAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.resources.ResourcePath; import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; import de.bluecolored.bluemap.core.resources.pack.resourcepack.texture.Texture; @@ -38,7 +37,6 @@ import java.util.Objects; import java.util.function.Function; -@DebugDump @JsonAdapter(TextureVariable.Adapter.class) public class TextureVariable { diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/BlockState.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/BlockState.java index 26b01521a..c5ade4bce 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/BlockState.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/BlockState.java @@ -24,13 +24,11 @@ */ package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate; -import de.bluecolored.bluemap.api.debug.DebugDump; import org.jetbrains.annotations.Nullable; import java.util.function.Consumer; @SuppressWarnings("FieldMayBeFinal") -@DebugDump public class BlockState { private Variants variants = null; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/BlockStateCondition.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/BlockStateCondition.java index 858907495..4c071066e 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/BlockStateCondition.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/BlockStateCondition.java @@ -24,8 +24,6 @@ */ package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate; - -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.util.Preconditions; import de.bluecolored.bluemap.core.world.BlockState; @@ -41,7 +39,6 @@ public interface BlockStateCondition { boolean matches(BlockState state); - @DebugDump class Property implements BlockStateCondition { private final String key; @@ -61,7 +58,6 @@ public boolean matches(BlockState state) { } - @DebugDump class PropertySet implements BlockStateCondition { private final String key; @@ -82,7 +78,6 @@ public boolean matches(BlockState state) { } - @DebugDump class And implements BlockStateCondition { final BlockStateCondition[] conditions; @@ -117,7 +112,6 @@ public boolean matches(BlockState state) { } - @DebugDump class Or implements BlockStateCondition { private final BlockStateCondition[] conditions; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Multipart.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Multipart.java index 87223503c..ae3f542c7 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Multipart.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Multipart.java @@ -28,7 +28,6 @@ import com.google.gson.annotations.JsonAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.resources.AbstractTypeAdapterFactory; import de.bluecolored.bluemap.core.world.BlockState; import org.apache.commons.lang3.StringUtils; @@ -39,7 +38,6 @@ import java.util.function.Consumer; @SuppressWarnings("FieldMayBeFinal") -@DebugDump @JsonAdapter(Multipart.Adapter.class) public class Multipart { diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variant.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variant.java index ed491195b..aefb0bf88 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variant.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variant.java @@ -28,7 +28,6 @@ import com.google.gson.annotations.JsonAdapter; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.resources.AbstractTypeAdapterFactory; import de.bluecolored.bluemap.core.resources.ResourcePath; import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.BlockModel; @@ -38,7 +37,6 @@ import java.io.IOException; @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"}) -@DebugDump @JsonAdapter(Variant.Adapter.class) public class Variant { diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/VariantSet.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/VariantSet.java index b1e51482a..7cb5740a9 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/VariantSet.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/VariantSet.java @@ -28,7 +28,6 @@ import com.google.gson.annotations.JsonAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.resources.AbstractTypeAdapterFactory; import java.io.IOException; @@ -36,7 +35,6 @@ import java.util.function.Consumer; @SuppressWarnings("FieldMayBeFinal") -@DebugDump @JsonAdapter(VariantSet.Adapter.class) public class VariantSet { diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variants.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variants.java index 0630025b1..93edf381f 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variants.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variants.java @@ -27,7 +27,6 @@ import com.google.gson.Gson; import com.google.gson.annotations.JsonAdapter; import com.google.gson.stream.JsonReader; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.resources.AbstractTypeAdapterFactory; import de.bluecolored.bluemap.core.world.BlockState; @@ -40,7 +39,6 @@ import java.util.function.Consumer; @SuppressWarnings("FieldMayBeFinal") -@DebugDump @JsonAdapter(Variants.Adapter.class) public class Variants { diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/texture/Texture.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/texture/Texture.java index ea7fcb87f..b20cdbf6b 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/texture/Texture.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/texture/Texture.java @@ -24,7 +24,6 @@ */ package de.bluecolored.bluemap.core.resources.pack.resourcepack.texture; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.resources.ResourcePath; import de.bluecolored.bluemap.core.util.BufferedImageUtil; import de.bluecolored.bluemap.core.util.math.Color; @@ -36,7 +35,6 @@ import java.io.IOException; import java.util.Base64; -@DebugDump public class Texture { public static final Texture MISSING = new Texture( diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Key.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Key.java index 24c377ad4..e3f3fa471 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Key.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Key.java @@ -24,11 +24,8 @@ */ package de.bluecolored.bluemap.core.util; -import de.bluecolored.bluemap.api.debug.DebugDump; - import java.util.concurrent.ConcurrentHashMap; -@DebugDump public class Key implements Keyed { private static final ConcurrentHashMap STRING_INTERN_POOL = new ConcurrentHashMap<>(); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Lazy.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Lazy.java index 8d968ce35..71a0c275f 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Lazy.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/Lazy.java @@ -24,8 +24,6 @@ */ package de.bluecolored.bluemap.core.util; -import de.bluecolored.bluemap.api.debug.DebugDump; - import java.util.Objects; import java.util.function.Supplier; @@ -33,7 +31,6 @@ public class Lazy { private Supplier loader; - @DebugDump private volatile T value; public Lazy(Supplier loader) { diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/math/Color.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/math/Color.java index ef8f5ee31..fb666393f 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/math/Color.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/math/Color.java @@ -24,10 +24,7 @@ */ package de.bluecolored.bluemap.core.util.math; -import de.bluecolored.bluemap.api.debug.DebugDump; - @SuppressWarnings("UnusedReturnValue") -@DebugDump public class Color { public float r, g, b, a; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/BlockProperties.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/BlockProperties.java index f5a31effc..2c51d1acc 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/BlockProperties.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/BlockProperties.java @@ -24,10 +24,8 @@ */ package de.bluecolored.bluemap.core.world; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.util.Tristate; -@DebugDump public class BlockProperties { public static final BlockProperties DEFAULT = new BlockProperties(); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/BlockState.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/BlockState.java index 51164c8c6..fff30e892 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/BlockState.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/BlockState.java @@ -24,7 +24,6 @@ */ package de.bluecolored.bluemap.core.world; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.util.Key; import org.jetbrains.annotations.NotNull; @@ -39,7 +38,6 @@ *
* The implementation of this class has to be thread-save!
*/ -@DebugDump public class BlockState extends Key { private static final Pattern BLOCKSTATE_SERIALIZATION_PATTERN = Pattern.compile("^(.+?)(?:\\[(.*)])?$"); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/Biome.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/Biome.java index 799028be3..681c2605e 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/Biome.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/biome/Biome.java @@ -24,13 +24,11 @@ */ package de.bluecolored.bluemap.core.world.biome; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.util.Key; import de.bluecolored.bluemap.core.util.Keyed; import de.bluecolored.bluemap.core.util.math.Color; import lombok.Getter; -@DebugDump public interface Biome extends Keyed { Biome DEFAULT = new Default(); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java index d4a0eb721..0e75dfec5 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java @@ -29,7 +29,6 @@ import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.gson.reflect.TypeToken; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.BlueMap; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.resources.pack.datapack.DataPack; @@ -60,7 +59,6 @@ @Getter @ToString -@DebugDump public class MCAWorld implements World { private static final Grid CHUNK_GRID = new Grid(16); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/LevelData.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/LevelData.java index 8130731cf..8720e5844 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/LevelData.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/LevelData.java @@ -24,7 +24,6 @@ */ package de.bluecolored.bluemap.core.world.mca.data; -import de.bluecolored.bluemap.api.debug.DebugDump; import de.bluecolored.bluemap.core.world.DimensionType; import lombok.AllArgsConstructor; import lombok.Getter; @@ -35,13 +34,11 @@ @Getter @SuppressWarnings("FieldMayBeFinal") -@DebugDump public class LevelData { private Data data = new Data(); @Getter - @DebugDump public static class Data { private String levelName = "world"; private int spawnX = 0, spawnY = 0, spawnZ = 0; @@ -49,7 +46,6 @@ public static class Data { } @Getter - @DebugDump public static class WGSettings { private Map dimensions = new HashMap<>(); } @@ -57,7 +53,6 @@ public static class WGSettings { @Getter @NoArgsConstructor @AllArgsConstructor - @DebugDump public static class Dimension { private DimensionType type = DimensionType.OVERWORLD; } From ce25eb52e3a26b69a21f22175364e0b276b962bd Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Mon, 20 May 2024 21:43:50 +0200 Subject: [PATCH 14/38] Small improvements, make webserver more accessible for addons --- BlueMapAPI | 2 +- .../bluemap/common/api/BlueMapAPIImpl.java | 8 +++----- .../bluemap/common/api/RenderManagerImpl.java | 3 +-- .../common/web/BlueMapResponseModifier.java | 8 ++++++-- .../bluemap/common/web/FileRequestHandler.java | 6 +++++- .../common/web/JsonDataRequestHandler.java | 6 +++++- .../common/web/LoggingRequestHandler.java | 18 ++++++++---------- .../common/web/MapStorageRequestHandler.java | 6 +++++- .../common/web/RoutingRequestHandler.java | 8 +++++--- 9 files changed, 39 insertions(+), 26 deletions(-) diff --git a/BlueMapAPI b/BlueMapAPI index 8b179fb5e..ec9771134 160000 --- a/BlueMapAPI +++ b/BlueMapAPI @@ -1 +1 @@ -Subproject commit 8b179fb5e011ef8ac7e550e2e9aa6c64b644eaee +Subproject commit ec977113495dacd6f2e24239015f4b94b305fc52 diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/BlueMapAPIImpl.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/BlueMapAPIImpl.java index fbdbfdd29..b544d4c83 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/BlueMapAPIImpl.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/BlueMapAPIImpl.java @@ -39,7 +39,6 @@ import java.util.Collection; import java.util.Map; import java.util.Optional; -import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; public class BlueMapAPIImpl extends BlueMapAPI { @@ -107,8 +106,7 @@ public Optional getWorldUncached(Object world) { if (coreWorld != null) world = coreWorld; } - if (world instanceof World) { - var coreWorld = (World) world; + if (world instanceof World coreWorld) { return Optional.of(new BlueMapWorldImpl(plugin, coreWorld)); } @@ -146,7 +144,7 @@ public String getBlueMapVersion() { public void register() { try { BlueMapAPI.registerInstance(this); - } catch (ExecutionException ex) { + } catch (Exception ex) { Logger.global.logError("BlueMapAPI: A BlueMapAPI listener threw an exception (onEnable)!", ex.getCause()); } } @@ -154,7 +152,7 @@ public void register() { public void unregister() { try { BlueMapAPI.unregisterInstance(this); - } catch (ExecutionException ex) { + } catch (Exception ex) { Logger.global.logError("BlueMapAPI: A BlueMapAPI listener threw an exception (onDisable)!", ex.getCause()); } } diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/RenderManagerImpl.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/RenderManagerImpl.java index 69703f274..de203f28a 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/RenderManagerImpl.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/RenderManagerImpl.java @@ -31,7 +31,6 @@ import de.bluecolored.bluemap.common.rendermanager.MapPurgeTask; import de.bluecolored.bluemap.common.rendermanager.MapUpdateTask; -import java.io.IOException; import java.util.Collection; public class RenderManagerImpl implements RenderManager { @@ -59,7 +58,7 @@ public boolean scheduleMapUpdateTask(BlueMapMap map, Collection region } @Override - public boolean scheduleMapPurgeTask(BlueMapMap map) throws IOException { + public boolean scheduleMapPurgeTask(BlueMapMap map) { BlueMapMapImpl cmap = castMap(map); return renderManager.scheduleRenderTask(new MapPurgeTask(cmap.getBmMap())); } diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/BlueMapResponseModifier.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/BlueMapResponseModifier.java index c11d07f52..034da409a 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/BlueMapResponseModifier.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/BlueMapResponseModifier.java @@ -29,11 +29,15 @@ import de.bluecolored.bluemap.common.web.http.HttpResponse; import de.bluecolored.bluemap.common.web.http.HttpStatusCode; import de.bluecolored.bluemap.core.BlueMap; +import lombok.Getter; +import lombok.NonNull; +import lombok.Setter; +@Getter @Setter public class BlueMapResponseModifier implements HttpRequestHandler { - private final HttpRequestHandler delegate; - private final String serverName; + private @NonNull HttpRequestHandler delegate; + private @NonNull String serverName; public BlueMapResponseModifier(HttpRequestHandler delegate) { this.delegate = delegate; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java index b3f427253..2b0bd8250 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java @@ -25,6 +25,9 @@ package de.bluecolored.bluemap.common.web; import de.bluecolored.bluemap.common.web.http.*; +import lombok.Getter; +import lombok.NonNull; +import lombok.Setter; import org.apache.commons.lang3.time.DateFormatUtils; import java.io.File; @@ -38,9 +41,10 @@ import java.util.TimeZone; import java.util.concurrent.TimeUnit; +@Getter @Setter public class FileRequestHandler implements HttpRequestHandler { - private final Path webRoot; + private @NonNull Path webRoot; public FileRequestHandler(Path webRoot) { this.webRoot = webRoot.normalize(); diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/JsonDataRequestHandler.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/JsonDataRequestHandler.java index 41f734ef0..a4cc988b3 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/JsonDataRequestHandler.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/JsonDataRequestHandler.java @@ -28,12 +28,16 @@ import de.bluecolored.bluemap.common.web.http.HttpRequestHandler; import de.bluecolored.bluemap.common.web.http.HttpResponse; import de.bluecolored.bluemap.common.web.http.HttpStatusCode; +import lombok.Getter; +import lombok.NonNull; +import lombok.Setter; import java.util.function.Supplier; +@Getter @Setter public class JsonDataRequestHandler implements HttpRequestHandler { - private final Supplier dataSupplier; + private @NonNull Supplier dataSupplier; public JsonDataRequestHandler(Supplier dataSupplier) { this.dataSupplier = dataSupplier; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/LoggingRequestHandler.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/LoggingRequestHandler.java index 62efe6427..647af5d1f 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/LoggingRequestHandler.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/LoggingRequestHandler.java @@ -26,14 +26,18 @@ import de.bluecolored.bluemap.common.web.http.*; import de.bluecolored.bluemap.core.logger.Logger; +import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NonNull; +import lombok.Setter; -@Getter +@Getter @Setter +@AllArgsConstructor public class LoggingRequestHandler implements HttpRequestHandler { - private final HttpRequestHandler delegate; - private final Logger logger; - private final String format; + private @NonNull HttpRequestHandler delegate; + private @NonNull String format; + private @NonNull Logger logger; public LoggingRequestHandler(HttpRequestHandler delegate) { this(delegate, Logger.global); @@ -47,12 +51,6 @@ public LoggingRequestHandler(HttpRequestHandler delegate, String format) { this(delegate, format, Logger.global); } - public LoggingRequestHandler(HttpRequestHandler delegate, String format, Logger logger) { - this.delegate = delegate; - this.format = format; - this.logger = logger; - } - @Override public HttpResponse handle(HttpRequest request) { diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/MapStorageRequestHandler.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/MapStorageRequestHandler.java index eaa8043ba..726dbe1a7 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/MapStorageRequestHandler.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/MapStorageRequestHandler.java @@ -34,7 +34,10 @@ import de.bluecolored.bluemap.core.storage.MapStorage; import de.bluecolored.bluemap.core.storage.compression.CompressedInputStream; import de.bluecolored.bluemap.core.storage.compression.Compression; +import lombok.Getter; +import lombok.NonNull; import lombok.RequiredArgsConstructor; +import lombok.Setter; import org.apache.commons.io.IOUtils; import java.io.ByteArrayInputStream; @@ -47,11 +50,12 @@ import java.util.regex.Pattern; @RequiredArgsConstructor +@Getter @Setter public class MapStorageRequestHandler implements HttpRequestHandler { private static final Pattern TILE_PATTERN = Pattern.compile("tiles/([\\d/]+)/x(-?[\\d/]+)z(-?[\\d/]+).*"); - private final MapStorage mapStorage; + private @NonNull MapStorage mapStorage; @SuppressWarnings("resource") @Override diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/RoutingRequestHandler.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/RoutingRequestHandler.java index c68cb4eb9..72c0c0bfe 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/RoutingRequestHandler.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/RoutingRequestHandler.java @@ -34,16 +34,18 @@ import lombok.Setter; import org.intellij.lang.annotations.Language; -import java.util.LinkedList; +import java.util.Deque; +import java.util.concurrent.ConcurrentLinkedDeque; import java.util.regex.Matcher; import java.util.regex.Pattern; +@Getter public class RoutingRequestHandler implements HttpRequestHandler { - public final LinkedList routes; + private final Deque routes; public RoutingRequestHandler() { - this.routes = new LinkedList<>(); + this.routes = new ConcurrentLinkedDeque<>(); } public void register(@Language("RegExp") String pattern, HttpRequestHandler handler) { From d7dd8931a5bbc42605f476d3e27e7cae1e16c553 Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Tue, 21 May 2024 16:32:28 +0200 Subject: [PATCH 15/38] Remove all usages of java.io.File and bad usages of Path.of() --- .../bluemap/common/BlueMapService.java | 2 +- .../bluemap/common/WebFilesManager.java | 50 ++------ .../bluemap/common/api/WebAppImpl.java | 7 +- .../common/config/BlueMapConfigManager.java | 61 +++++---- .../bluemap/common/config/ConfigLoader.java | 45 +++++++ .../bluemap/common/config/ConfigManager.java | 115 ++++++++--------- .../bluemap/common/plugin/Plugin.java | 2 +- .../common/web/FileRequestHandler.java | 117 ++++++++---------- .../bluemap/core/util/CopyingPathVisitor.java | 78 ++++++++++++ .../bluemap/core/util/FileHelper.java | 41 +++++- .../bluemap/core/world/mca/MCAWorld.java | 49 ++++---- .../bluecolored/bluemap/cli/BlueMapCLI.java | 17 +-- 12 files changed, 349 insertions(+), 235 deletions(-) create mode 100644 BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/ConfigLoader.java create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/CopyingPathVisitor.java diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapService.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapService.java index ae00c4296..058931a0d 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapService.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapService.java @@ -200,7 +200,7 @@ private synchronized void loadMap(String id, MapConfig mapConfig) throws Configu dimension = DataPack.DIMENSION_THE_END; } else if ( worldFolder.getNameCount() > 3 && - worldFolder.getName(worldFolder.getNameCount() - 3).equals(Path.of("dimensions")) + worldFolder.getName(worldFolder.getNameCount() - 3).toString().equals("dimensions") ) { String namespace = worldFolder.getName(worldFolder.getNameCount() - 2).toString(); String value = worldFolder.getName(worldFolder.getNameCount() - 1).toString(); diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/WebFilesManager.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/WebFilesManager.java index 106378d5d..54051aee6 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/WebFilesManager.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/WebFilesManager.java @@ -32,21 +32,15 @@ import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.resources.adapter.ResourcesGson; import de.bluecolored.bluemap.core.util.FileHelper; -import org.apache.commons.io.FileUtils; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.IOException; +import java.io.*; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; -import java.util.Enumeration; import java.util.HashSet; import java.util.Set; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; public class WebFilesManager { @@ -114,39 +108,17 @@ public boolean filesNeedUpdate() { } public void updateFiles() throws IOException { - URL fileResource = getClass().getResource("/de/bluecolored/bluemap/webapp.zip"); - File tempFile = File.createTempFile("bluemap_webroot_extraction", null); - - if (fileResource == null) throw new IOException("Failed to open bundled webapp."); - - try { - FileUtils.copyURLToFile(fileResource, tempFile, 10000, 10000); - try (ZipFile zipFile = new ZipFile(tempFile)){ - Enumeration entries = zipFile.entries(); - while(entries.hasMoreElements()) { - ZipEntry zipEntry = entries.nextElement(); - if (zipEntry.isDirectory()) { - File dir = webRoot.resolve(zipEntry.getName()).toFile(); - FileUtils.forceMkdir(dir); - } else { - File target = webRoot.resolve(zipEntry.getName()).toFile(); - FileUtils.forceMkdirParent(target); - FileUtils.copyInputStreamToFile(zipFile.getInputStream(zipEntry), target); - } - } - } + URL zippedWebapp = getClass().getResource("/de/bluecolored/bluemap/webapp.zip"); + if (zippedWebapp == null) throw new IOException("Failed to open bundled webapp."); - // set version in index.html - Path indexFile = webRoot.resolve("index.html"); - String indexContent = Files.readString(indexFile); - indexContent = indexContent.replace("%version%", BlueMap.VERSION); - Files.writeString(indexFile, indexContent); + // extract zip to webroot + FileHelper.extractZipFile(zippedWebapp, webRoot, StandardCopyOption.REPLACE_EXISTING); - } finally { - if (!tempFile.delete()) { - Logger.global.logWarning("Failed to delete file: " + tempFile); - } - } + // set version in index.html + Path indexFile = webRoot.resolve("index.html"); + String indexContent = Files.readString(indexFile); + indexContent = indexContent.replace("%version%", BlueMap.VERSION); + Files.writeString(indexFile, indexContent); } @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "unused", "MismatchedQueryAndUpdateOfCollection"}) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/WebAppImpl.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/WebAppImpl.java index 6ead0849c..64af5bdac 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/WebAppImpl.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/WebAppImpl.java @@ -40,7 +40,6 @@ import java.util.stream.Stream; public class WebAppImpl implements WebApp { - private static final Path IMAGE_ROOT_PATH = Path.of("data", "images"); private final Plugin plugin; @@ -88,8 +87,8 @@ public String createImage(BufferedImage image, String path) throws IOException { Path webRoot = getWebRoot().toAbsolutePath(); String separator = webRoot.getFileSystem().getSeparator(); - Path imageRootFolder = webRoot.resolve(IMAGE_ROOT_PATH); - Path imagePath = imageRootFolder.resolve(Path.of(path.replace("/", separator) + ".png")).toAbsolutePath(); + Path imageRootFolder = webRoot.resolve("data").resolve("images"); + Path imagePath = imageRootFolder.resolve(path.replace("/", separator) + ".png").toAbsolutePath(); FileHelper.createDirectories(imagePath.getParent()); Files.deleteIfExists(imagePath); @@ -108,7 +107,7 @@ public Map availableImages() throws IOException { Path webRoot = getWebRoot().toAbsolutePath(); String separator = webRoot.getFileSystem().getSeparator(); - Path imageRootPath = webRoot.resolve("data").resolve(IMAGE_ROOT_PATH).toAbsolutePath(); + Path imageRootPath = webRoot.resolve("data").resolve("images").toAbsolutePath(); Map availableImagesMap = new HashMap<>(); diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigManager.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigManager.java index a005b10b4..0b60323e4 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigManager.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigManager.java @@ -46,6 +46,13 @@ @Getter public class BlueMapConfigManager implements BlueMapConfiguration { + public static final String CORE_CONFIG_NAME = "core"; + public static final String WEBSERVER_CONFIG_NAME = "webserver"; + public static final String WEBAPP_CONFIG_NAME = "webapp"; + public static final String PLUGIN_CONFIG_NAME = "plugin"; + public static final String MAPS_CONFIG_FOLDER_NAME = "maps"; + public static final String STORAGES_CONFIG_FOLDER_NAME = "storages"; + private final ConfigManager configManager; private final CoreConfig coreConfig; @@ -92,16 +99,15 @@ private BlueMapConfigManager( } private CoreConfig loadCoreConfig(Path defaultDataFolder, boolean useMetricsConfig) throws ConfigurationException { - Path configFileRaw = Path.of("core"); - Path configFile = configManager.findConfigPath(configFileRaw); + Path configFile = configManager.resolveConfigFile(CORE_CONFIG_NAME); Path configFolder = configFile.getParent(); if (!Files.exists(configFile)) { try { FileHelper.createDirectories(configFolder); Files.writeString( - configFolder.resolve("core.conf"), - configManager.loadConfigTemplate("/de/bluecolored/bluemap/config/core.conf") + configFile, + configManager.loadConfigTemplate(CORE_CONFIG_NAME) .setConditional("metrics", useMetricsConfig) .setVariable("timestamp", LocalDateTime.now().withNano(0).toString()) .setVariable("version", BlueMap.VERSION) @@ -118,7 +124,7 @@ private CoreConfig loadCoreConfig(Path defaultDataFolder, boolean useMetricsConf } } - return configManager.loadConfig(configFileRaw, CoreConfig.class); + return configManager.loadConfig(CORE_CONFIG_NAME, CoreConfig.class); } /** @@ -137,16 +143,15 @@ private int suggestRenderThreadCount() { } private WebserverConfig loadWebserverConfig(Path defaultWebroot, Path dataRoot) throws ConfigurationException { - Path configFileRaw = Path.of("webserver"); - Path configFile = configManager.findConfigPath(configFileRaw); + Path configFile = configManager.resolveConfigFile(WEBSERVER_CONFIG_NAME); Path configFolder = configFile.getParent(); if (!Files.exists(configFile)) { try { FileHelper.createDirectories(configFolder); Files.writeString( - configFolder.resolve("webserver.conf"), - configManager.loadConfigTemplate("/de/bluecolored/bluemap/config/webserver.conf") + configFile, + configManager.loadConfigTemplate(WEBSERVER_CONFIG_NAME) .setVariable("webroot", formatPath(defaultWebroot)) .setVariable("logfile", formatPath(dataRoot.resolve("logs").resolve("webserver.log"))) .setVariable("logfile-with-time", formatPath(dataRoot.resolve("logs").resolve("webserver_%1$tF_%1$tT.log"))) @@ -158,20 +163,19 @@ private WebserverConfig loadWebserverConfig(Path defaultWebroot, Path dataRoot) } } - return configManager.loadConfig(configFileRaw, WebserverConfig.class); + return configManager.loadConfig(WEBSERVER_CONFIG_NAME, WebserverConfig.class); } private WebappConfig loadWebappConfig(Path defaultWebroot) throws ConfigurationException { - Path configFileRaw = Path.of("webapp"); - Path configFile = configManager.findConfigPath(configFileRaw); + Path configFile = configManager.resolveConfigFile(WEBAPP_CONFIG_NAME); Path configFolder = configFile.getParent(); if (!Files.exists(configFile)) { try { FileHelper.createDirectories(configFolder); Files.writeString( - configFolder.resolve("webapp.conf"), - configManager.loadConfigTemplate("/de/bluecolored/bluemap/config/webapp.conf") + configFile, + configManager.loadConfigTemplate(WEBAPP_CONFIG_NAME) .setVariable("webroot", formatPath(defaultWebroot)) .build(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING @@ -181,20 +185,19 @@ private WebappConfig loadWebappConfig(Path defaultWebroot) throws ConfigurationE } } - return configManager.loadConfig(configFileRaw, WebappConfig.class); + return configManager.loadConfig(WEBAPP_CONFIG_NAME, WebappConfig.class); } private PluginConfig loadPluginConfig() throws ConfigurationException { - Path configFileRaw = Path.of("plugin"); - Path configFile = configManager.findConfigPath(configFileRaw); + Path configFile = configManager.resolveConfigFile(PLUGIN_CONFIG_NAME); Path configFolder = configFile.getParent(); if (!Files.exists(configFile)) { try { FileHelper.createDirectories(configFolder); Files.writeString( - configFolder.resolve("plugin.conf"), - configManager.loadConfigTemplate("/de/bluecolored/bluemap/config/plugin.conf") + configFile, + configManager.loadConfigTemplate(PLUGIN_CONFIG_NAME) .build(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING ); @@ -203,14 +206,13 @@ private PluginConfig loadPluginConfig() throws ConfigurationException { } } - return configManager.loadConfig(configFileRaw, PluginConfig.class); + return configManager.loadConfig(PLUGIN_CONFIG_NAME, PluginConfig.class); } private Map loadMapConfigs(Collection autoConfigWorlds) throws ConfigurationException { Map mapConfigs = new HashMap<>(); - Path mapFolder = Paths.get("maps"); - Path mapConfigFolder = configManager.getConfigRoot().resolve(mapFolder); + Path mapConfigFolder = configManager.getConfigRoot().resolve(MAPS_CONFIG_FOLDER_NAME); if (!Files.exists(mapConfigFolder)){ try { @@ -290,8 +292,7 @@ private Map loadMapConfigs(Collection autoConfig try (Stream configFiles = Files.list(mapConfigFolder)) { for (var configFile : configFiles.toArray(Path[]::new)) { if (!configManager.isConfigFile(configFile)) continue; - Path rawConfig = configManager.getRaw(configFile); - String id = sanitiseMapId(rawConfig.getFileName().toString()); + String id = sanitiseMapId(configManager.getConfigName(configFile)); if (mapConfigs.containsKey(id)) { throw new ConfigurationException("At least two of your map-config file-names result in ambiguous map-id's!\n" + @@ -299,7 +300,7 @@ private Map loadMapConfigs(Collection autoConfig "To resolve this issue, rename this file to something else."); } - MapConfig mapConfig = configManager.loadConfig(rawConfig, MapConfig.class); + MapConfig mapConfig = configManager.loadConfig(configFile, MapConfig.class); mapConfigs.put(id, mapConfig); } } catch (IOException ex) { @@ -315,8 +316,7 @@ private Map loadMapConfigs(Collection autoConfig private Map loadStorageConfigs(Path defaultWebroot) throws ConfigurationException { Map storageConfigs = new HashMap<>(); - Path storageFolder = Paths.get("storages"); - Path storageConfigFolder = configManager.getConfigRoot().resolve(storageFolder); + Path storageConfigFolder = configManager.getConfigRoot().resolve(STORAGES_CONFIG_FOLDER_NAME); if (!Files.exists(storageConfigFolder)){ try { @@ -345,11 +345,10 @@ private Map loadStorageConfigs(Path defaultWebroot) throw try (Stream configFiles = Files.list(storageConfigFolder)) { for (var configFile : configFiles.toArray(Path[]::new)) { if (!configManager.isConfigFile(configFile)) continue; - Path rawConfig = configManager.getRaw(configFile); - String id = rawConfig.getFileName().toString(); + String id = configManager.getConfigName(configFile); - StorageConfig storageConfig = configManager.loadConfig(rawConfig, StorageConfig.Base.class); // load superclass - storageConfig = configManager.loadConfig(rawConfig, storageConfig.getStorageType().getConfigType()); // load actual config type + StorageConfig storageConfig = configManager.loadConfig(configFile, StorageConfig.Base.class); // load superclass + storageConfig = configManager.loadConfig(configFile, storageConfig.getStorageType().getConfigType()); // load actual config type storageConfigs.put(id, storageConfig); } diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/ConfigLoader.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/ConfigLoader.java new file mode 100644 index 000000000..b10a10849 --- /dev/null +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/ConfigLoader.java @@ -0,0 +1,45 @@ +package de.bluecolored.bluemap.common.config; + +import de.bluecolored.bluemap.core.util.Key; +import de.bluecolored.bluemap.core.util.Keyed; +import de.bluecolored.bluemap.core.util.Registry; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.spongepowered.configurate.gson.GsonConfigurationLoader; +import org.spongepowered.configurate.hocon.HoconConfigurationLoader; +import org.spongepowered.configurate.loader.AbstractConfigurationLoader; + +import java.util.function.Supplier; + +public interface ConfigLoader extends Keyed { + + ConfigLoader HOCON = new Impl(Key.bluemap("hocon"), ".conf", HoconConfigurationLoader::builder); + ConfigLoader JSON = new Impl(Key.bluemap("json"), ".json", GsonConfigurationLoader::builder); + + ConfigLoader DEFAULT = HOCON; + + Registry REGISTRY = new Registry<>( + HOCON, + JSON + ); + + String getFileSuffix(); + + AbstractConfigurationLoader.Builder createLoaderBuilder(); + + @RequiredArgsConstructor + @Getter + class Impl implements ConfigLoader { + + private final Key key; + private final String fileSuffix; + private final Supplier> builderSupplier; + + @Override + public AbstractConfigurationLoader.Builder createLoaderBuilder() { + return builderSupplier.get(); + } + + } + +} diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/ConfigManager.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/ConfigManager.java index b9620e861..d26bed29d 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/ConfigManager.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/ConfigManager.java @@ -32,8 +32,6 @@ import org.apache.commons.io.IOUtils; import org.spongepowered.configurate.ConfigurateException; import org.spongepowered.configurate.ConfigurationNode; -import org.spongepowered.configurate.gson.GsonConfigurationLoader; -import org.spongepowered.configurate.hocon.HoconConfigurationLoader; import org.spongepowered.configurate.loader.AbstractConfigurationLoader; import org.spongepowered.configurate.loader.ConfigurationLoader; import org.spongepowered.configurate.serialize.SerializationException; @@ -43,14 +41,11 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.*; +import java.util.Objects; public class ConfigManager { - private static final String[] CONFIG_FILE_ENDINGS = new String[] { - ".conf", - ".json" - }; + private static final String CONFIG_TEMPLATE_RESOURCE_PATH = "/de/bluecolored/bluemap/config/"; private final Path configRoot; @@ -58,32 +53,63 @@ public ConfigManager(Path configRoot) { this.configRoot = configRoot; } - public T loadConfig(Path rawPath, Class type) throws ConfigurationException { - Path path = findConfigPath(rawPath); - ConfigurationNode configNode = loadConfigFile(path); + public T loadConfig(String name, Class type) throws ConfigurationException { + Path file = resolveConfigFile(name); + return loadConfig(file, type); + } + + public T loadConfig(Path file, Class type) throws ConfigurationException { + ConfigurationNode configNode = loadConfigFile(file); try { return Objects.requireNonNull(configNode.get(type)); } catch (SerializationException | NullPointerException ex) { throw new ConfigurationException( "BlueMap failed to parse this file:\n" + - path + "\n" + + file + "\n" + "Check if the file is correctly formatted and all values are correct!", ex); } } - public ConfigurationNode loadConfig(Path rawPath) throws ConfigurationException { - Path path = findConfigPath(rawPath); - return loadConfigFile(path); - } - - public ConfigTemplate loadConfigTemplate(String resource) throws IOException { + public ConfigTemplate loadConfigTemplate(String name) throws IOException { + String resource = CONFIG_TEMPLATE_RESOURCE_PATH + name + ConfigLoader.DEFAULT.getFileSuffix(); InputStream in = BlueMap.class.getResourceAsStream(resource); if (in == null) throw new IOException("Resource not found: " + resource); String configTemplate = IOUtils.toString(in, StandardCharsets.UTF_8); return new ConfigTemplate(configTemplate); } + public Path resolveConfigFile(String name) { + for (ConfigLoader configLoader : ConfigLoader.REGISTRY.values()) { + Path path = configRoot.resolve(name + configLoader.getFileSuffix()); + if (Files.isRegularFile(path)) return path; + } + + return configRoot.resolve(name + ConfigLoader.DEFAULT.getFileSuffix()); + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + public boolean isConfigFile(Path file) { + String fileName = file.getFileName().toString(); + for (ConfigLoader configLoader : ConfigLoader.REGISTRY.values()) + if (fileName.endsWith(configLoader.getFileSuffix())) return true; + return false; + } + + public String getConfigName(Path file) { + String fileName = file.getFileName().toString(); + for (ConfigLoader configLoader : ConfigLoader.REGISTRY.values()) { + String suffix = configLoader.getFileSuffix(); + if (fileName.endsWith(suffix)) + return fileName.substring(0, fileName.length() - suffix.length()); + } + return fileName; + } + + public Path getConfigRoot() { + return configRoot; + } + private ConfigurationNode loadConfigFile(Path path) throws ConfigurationException { if (!Files.exists(path)) { throw new ConfigurationException( @@ -110,58 +136,17 @@ private ConfigurationNode loadConfigFile(Path path) throws ConfigurationExceptio } } - public Path getConfigRoot() { - return configRoot; - } - - public Path findConfigPath(Path rawPath) { - if (!rawPath.startsWith(configRoot)) - rawPath = configRoot.resolve(rawPath); - - for (String fileEnding : CONFIG_FILE_ENDINGS) { - if (rawPath.getFileName().endsWith(fileEnding)) return rawPath; - } - - for (String fileEnding : CONFIG_FILE_ENDINGS) { - Path path = rawPath.getParent().resolve(rawPath.getFileName() + fileEnding); - if (Files.exists(path)) return path; - } - - return rawPath.getParent().resolve(rawPath.getFileName() + CONFIG_FILE_ENDINGS[0]); - } - - public boolean isConfigFile(Path path) { - if (!Files.isRegularFile(path)) return false; - - String fileName = path.getFileName().toString(); - for (String fileEnding : CONFIG_FILE_ENDINGS) { - if (fileName.endsWith(fileEnding)) return true; - } - - return false; - } - - public Path getRaw(Path path) { - String fileName = path.getFileName().toString(); - String rawName = null; - - for (String fileEnding : CONFIG_FILE_ENDINGS) { - if (fileName.endsWith(fileEnding)) { - rawName = fileName.substring(0, fileName.length() - fileEnding.length()); + private ConfigurationLoader getLoader(Path path){ + AbstractConfigurationLoader.Builder builder = null; + for (ConfigLoader loader : ConfigLoader.REGISTRY.values()) { + if (path.getFileName().endsWith(loader.getFileSuffix())) { + builder = loader.createLoaderBuilder(); break; } } - if (rawName == null) return path; - return path.getParent().resolve(rawName); - } - - private ConfigurationLoader getLoader(Path path){ - AbstractConfigurationLoader.Builder builder; - if (path.getFileName().endsWith(".json")) - builder = GsonConfigurationLoader.builder(); - else - builder = HoconConfigurationLoader.builder(); + if (builder == null) + builder = ConfigLoader.DEFAULT.createLoaderBuilder(); return builder .path(path) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java index 17c30de21..fcd09e07c 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java @@ -167,7 +167,7 @@ private void load(@Nullable ResourcePack preloadedResourcePack) throws IOExcepti BlueMapConfiguration configProvider = blueMap.getConfig(); if (configProvider instanceof BlueMapConfigManager) { - Logger.global.logWarning("Please check: " + ((BlueMapConfigManager) configProvider).getConfigManager().findConfigPath(Path.of("core")).toAbsolutePath().normalize()); + Logger.global.logWarning("Please check: " + ((BlueMapConfigManager) configProvider).getConfigManager().resolveConfigFile(BlueMapConfigManager.CORE_CONFIG_NAME).toAbsolutePath().normalize()); } Logger.global.logInfo("If you have changed the config you can simply reload the plugin using: /bluemap reload"); diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java index 2b0bd8250..f4438f117 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java @@ -25,14 +25,15 @@ package de.bluecolored.bluemap.common.web; import de.bluecolored.bluemap.common.web.http.*; +import de.bluecolored.bluemap.core.logger.Logger; import lombok.Getter; import lombok.NonNull; import lombok.Setter; import org.apache.commons.lang3.time.DateFormatUtils; -import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.util.Calendar; @@ -54,10 +55,16 @@ public FileRequestHandler(Path webRoot) { public HttpResponse handle(HttpRequest request) { if (!request.getMethod().equalsIgnoreCase("GET")) return new HttpResponse(HttpStatusCode.BAD_REQUEST); - return generateResponse(request); + + try { + return generateResponse(request); + } catch (IOException e) { + Logger.global.logError("Failed to serve file", e); + return new HttpResponse(HttpStatusCode.INTERNAL_SERVER_ERROR); + } } - private HttpResponse generateResponse(HttpRequest request) { + private HttpResponse generateResponse(HttpRequest request) throws IOException { String path = request.getPath(); // normalize path @@ -76,36 +83,34 @@ private HttpResponse generateResponse(HttpRequest request) { return new HttpResponse(HttpStatusCode.FORBIDDEN); } - File file = filePath.toFile(); - // redirect to have correct relative paths - if (file.isDirectory() && !request.getPath().endsWith("/")) { + if (Files.isDirectory(filePath) && !request.getPath().endsWith("/")) { HttpResponse response = new HttpResponse(HttpStatusCode.SEE_OTHER); response.addHeader("Location", "/" + path + "/" + (request.getGETParamString().isEmpty() ? "" : "?" + request.getGETParamString())); return response; } // default to index.html - if (!file.exists() || file.isDirectory()){ - file = new File(filePath + "/index.html"); + if (!Files.exists(filePath) || Files.isDirectory(filePath)){ + filePath = filePath.resolve("/index.html"); } - if (!file.exists() || file.isDirectory()) { + if (!Files.exists(filePath) || Files.isDirectory(filePath)){ return new HttpResponse(HttpStatusCode.NOT_FOUND); } // don't send php files - if (file.getName().endsWith(".php")) { + if (filePath.getFileName().toString().endsWith(".php")) { return new HttpResponse(HttpStatusCode.FORBIDDEN); } // check if file is still in web-root and is not a directory - if (!file.toPath().normalize().startsWith(webRoot) || file.isDirectory()){ + if (!filePath.normalize().startsWith(webRoot) || Files.isDirectory(filePath)){ return new HttpResponse(HttpStatusCode.FORBIDDEN); } // check modified - long lastModified = file.lastModified(); + long lastModified = Files.getLastModifiedTime(filePath).to(TimeUnit.MILLISECONDS); HttpHeader modHeader = request.getHeader("If-Modified-Since"); if (modHeader != null){ try { @@ -117,7 +122,10 @@ private HttpResponse generateResponse(HttpRequest request) { } //check ETag - String eTag = Long.toHexString(file.length()) + Integer.toHexString(file.hashCode()) + Long.toHexString(lastModified); + String eTag = + Long.toHexString(Files.size(filePath)) + + Integer.toHexString(filePath.hashCode()) + + Long.toHexString(lastModified); HttpHeader etagHeader = request.getHeader("If-None-Match"); if (etagHeader != null){ if(etagHeader.getValue().equals(eTag)) { @@ -133,7 +141,7 @@ private HttpResponse generateResponse(HttpRequest request) { response.addHeader("Cache-Control", "max-age=" + TimeUnit.DAYS.toSeconds(1)); //add content type header - String filetype = file.getName(); + String filetype = filePath.getFileName().toString(); int pointIndex = filetype.lastIndexOf('.'); if (pointIndex >= 0) filetype = filetype.substring(pointIndex + 1); String contentType = toContentType(filetype); @@ -141,7 +149,7 @@ private HttpResponse generateResponse(HttpRequest request) { //send response try { - response.setData(new FileInputStream(file)); + response.setData(Files.newInputStream(filePath)); return response; } catch (FileNotFoundException e) { return new HttpResponse(HttpStatusCode.NOT_FOUND); @@ -155,21 +163,21 @@ private static String timestampToString(long time){ private static long stringToTimestamp(String timeString) throws IllegalArgumentException { try { int day = Integer.parseInt(timeString.substring(5, 7)); - - int month = Calendar.JANUARY; - switch (timeString.substring(8, 11)){ - case "Feb" : month = Calendar.FEBRUARY; break; - case "Mar" : month = Calendar.MARCH; break; - case "Apr" : month = Calendar.APRIL; break; - case "May" : month = Calendar.MAY; break; - case "Jun" : month = Calendar.JUNE; break; - case "Jul" : month = Calendar.JULY; break; - case "Aug" : month = Calendar.AUGUST; break; - case "Sep" : month = Calendar.SEPTEMBER; break; - case "Oct" : month = Calendar.OCTOBER; break; - case "Nov" : month = Calendar.NOVEMBER; break; - case "Dec" : month = Calendar.DECEMBER; break; - } + int month = switch (timeString.substring(8, 11)) { + case "Jan" -> Calendar.JANUARY; + case "Feb" -> Calendar.FEBRUARY; + case "Mar" -> Calendar.MARCH; + case "Apr" -> Calendar.APRIL; + case "May" -> Calendar.MAY; + case "Jun" -> Calendar.JUNE; + case "Jul" -> Calendar.JULY; + case "Aug" -> Calendar.AUGUST; + case "Sep" -> Calendar.SEPTEMBER; + case "Oct" -> Calendar.OCTOBER; + case "Nov" -> Calendar.NOVEMBER; + case "Dec" -> Calendar.DECEMBER; + default -> throw new IllegalArgumentException("Invalid timestamp format"); + }; int year = Integer.parseInt(timeString.substring(12, 16)); int hour = Integer.parseInt(timeString.substring(17, 19)); int min = Integer.parseInt(timeString.substring(20, 22)); @@ -183,38 +191,21 @@ private static long stringToTimestamp(String timeString) throws IllegalArgumentE } private static String toContentType(String fileEnding) { - String contentType = "text/plain"; - switch (fileEnding) { - case "json" : - contentType = "application/json"; - break; - case "png" : - contentType = "image/png"; - break; - case "jpg" : - case "jpeg" : - case "jpe" : - contentType = "image/jpeg"; - break; - case "svg" : - contentType = "image/svg+xml"; - break; - case "css" : - contentType = "text/css"; - break; - case "js" : - contentType = "text/javascript"; - break; - case "html" : - case "htm" : - case "shtml" : - contentType = "text/html"; - break; - case "xml" : - contentType = "text/xml"; - break; - } - return contentType; + return switch (fileEnding) { + case "json" -> "application/json"; + case "png" -> "image/png"; + case "jpg", + "jpeg", + "jpe" -> "image/jpeg"; + case "svg" -> "image/svg+xml"; + case "css" -> "text/css"; + case "js" -> "text/javascript"; + case "html", + "htm", + "shtml" -> "text/html"; + case "xml" -> "text/xml"; + default -> "text/plain"; + }; } } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/CopyingPathVisitor.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/CopyingPathVisitor.java new file mode 100644 index 000000000..8d0a8cf69 --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/CopyingPathVisitor.java @@ -0,0 +1,78 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.util; + +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; + +public class CopyingPathVisitor extends SimpleFileVisitor { + + private final Path targetPath; + private final CopyOption[] options; + + @Nullable private Path sourcePath; + + public CopyingPathVisitor(Path target, CopyOption... options) { + this.targetPath = target; + this.options = options; + } + + public CopyingPathVisitor(@Nullable Path source, Path target, CopyOption... options) { + this.sourcePath = source; + this.targetPath = target; + this.options = options; + } + + @Override + public FileVisitResult preVisitDirectory(Path source, BasicFileAttributes attributes) throws IOException { + // the first directory we visit will be the sourcePath + if (sourcePath == null) sourcePath = source; + + Path target = resolveTarget(source); + if (Files.notExists(target)) Files.createDirectory(target); + + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path source, BasicFileAttributes attributes) throws IOException { + Path target = resolveTarget(source); + Files.copy(source, target, options); + + return FileVisitResult.CONTINUE; + } + + /** + * Resolves the target file or directory using Path#toString() to make it compatible across different file-systems + */ + private Path resolveTarget(Path source) { + if (sourcePath == null) return targetPath; + return targetPath.resolve(sourcePath.relativize(source).toString()); + } + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/FileHelper.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/FileHelper.java index 5fb271380..9f6696f63 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/FileHelper.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/FileHelper.java @@ -28,7 +28,9 @@ import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; +import java.net.URL; import java.nio.file.*; import java.nio.file.attribute.FileAttribute; @@ -46,14 +48,14 @@ public static OutputStream createFilepartOutputStream(final Path file) throws IO return new OnCloseOutputStream(os, () -> { if (!Files.exists(partFile)) return; FileHelper.createDirectories(folder); - FileHelper.move(partFile, file); + FileHelper.atomicMove(partFile, file); }); } /** * Tries to move the file atomically, but fallbacks to a normal move operation if moving atomically fails */ - public static void move(Path from, Path to) throws IOException { + public static void atomicMove(Path from, Path to) throws IOException { try { Files.move(from, to, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING); } catch (FileNotFoundException | NoSuchFileException ignore) { @@ -77,4 +79,39 @@ public static Path createDirectories(Path dir, FileAttribute... attrs) throws return Files.createDirectories(dir, attrs); } + + /** + * Extracts the entire zip-file into the given target directory + */ + public static void extractZipFile(URL zipFile, Path targetDirectory, CopyOption... options) throws IOException { + Path temp = Files.createTempFile(null, ".zip"); + FileHelper.copy(zipFile, temp); + FileHelper.extractZipFile(temp, targetDirectory, options); + Files.deleteIfExists(temp); + } + + /** + * Extracts the entire zip-file into the given target directory + */ + public static void extractZipFile(Path zipFile, Path targetDirectory, CopyOption... options) throws IOException { + try (FileSystem webappZipFs = FileSystems.newFileSystem(zipFile, (ClassLoader) null)) { + CopyingPathVisitor copyAction = new CopyingPathVisitor(targetDirectory, options); + for (Path root : webappZipFs.getRootDirectories()) { + Files.walkFileTree(root, copyAction); + } + } + } + + /** + * Copies from a URL to a target-path + */ + public static void copy(URL source, Path target) throws IOException { + try ( + InputStream in = source.openStream(); + OutputStream out = Files.newOutputStream(target) + ) { + in.transferTo(out); + } + } + } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java index 0e75dfec5..8cc24cc14 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java @@ -45,17 +45,16 @@ import lombok.Getter; import lombok.ToString; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; +import java.util.stream.Stream; @Getter @ToString @@ -162,25 +161,33 @@ private Region getRegion(Vector2i pos) { @Override public Collection listRegions() { - File[] regionFiles = getRegionFolder().toFile().listFiles(); - if (regionFiles == null) return Collections.emptyList(); - - List regions = new ArrayList<>(regionFiles.length); - - for (File file : regionFiles) { - if (RegionType.forFileName(file.getName()) == null) continue; - if (file.length() <= 0) continue; - - try { - String[] filenameParts = file.getName().split("\\."); - int rX = Integer.parseInt(filenameParts[1]); - int rZ = Integer.parseInt(filenameParts[2]); - - regions.add(new Vector2i(rX, rZ)); - } catch (NumberFormatException ignore) {} + try (Stream stream = Files.list(regionFolder)) { + return stream + .map(file -> { + try { + String fileName = file.getFileName().toString(); + + if (RegionType.forFileName(fileName) == null) return null; + if (Files.size(file) <= 0) return null; + + String[] filenameParts = fileName.split("\\."); + int rX = Integer.parseInt(filenameParts[1]); + int rZ = Integer.parseInt(filenameParts[2]); + + return new Vector2i(rX, rZ); + } catch (IOException ex) { + Logger.global.logError("Failed to read region-file: " + file, ex); + return null; + } catch (NumberFormatException ignore) { + return null; + } + }) + .filter(Objects::nonNull) + .toList(); + } catch (IOException ex) { + Logger.global.logError("Failed to list regions for world: '" + getId() + "'", ex); + return List.of(); } - - return regions; } @Override diff --git a/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java b/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java index c3e9714b2..026445a1a 100644 --- a/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java +++ b/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java @@ -48,11 +48,11 @@ import org.apache.commons.lang3.time.DurationFormatUtils; import org.checkerframework.checker.nullness.qual.Nullable; -import java.io.File; import java.io.IOException; import java.net.BindException; import java.net.InetSocketAddress; import java.net.UnknownHostException; +import java.nio.file.Files; import java.nio.file.Path; import java.time.Instant; import java.time.ZoneId; @@ -363,7 +363,7 @@ public static void main(String[] args) { if (blueMap != null) { BlueMapConfiguration configProvider = blueMap.getConfig(); if (configProvider instanceof BlueMapConfigManager) { - Logger.global.logWarning("Please check: " + ((BlueMapConfigManager) configProvider).getConfigManager().findConfigPath(Path.of("core")).toAbsolutePath().normalize()); + Logger.global.logWarning("Please check: " + ((BlueMapConfigManager) configProvider).getConfigManager().resolveConfigFile(BlueMapConfigManager.CORE_CONFIG_NAME).toAbsolutePath().normalize()); } } System.exit(2); @@ -461,19 +461,20 @@ private static void printHelp() { private static String getCliCommand() { String filename = "bluemap-cli.jar"; try { - File file = new File(BlueMapCLI.class.getProtectionDomain() + Path file = Path.of(BlueMapCLI.class.getProtectionDomain() .getCodeSource() .getLocation() - .getPath()); + .toURI()); - if (file.isFile()) { + if (Files.isRegularFile(file)) { try { - filename = "." + File.separator + new File("").getCanonicalFile().toPath().relativize(file.toPath()); + filename = "." + file.getFileSystem().getSeparator() + + Path.of("").toRealPath().relativize(file.toRealPath()); } catch (IllegalArgumentException ex) { - filename = file.getAbsolutePath(); + filename = file.toAbsolutePath().toString(); } } - } catch (IOException ignore) {} + } catch (Exception ignore) {} return "java -jar " + filename; } From d77d90c65828aa354b75e4b2fe30fb5e9559844c Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Tue, 21 May 2024 20:57:08 +0200 Subject: [PATCH 16/38] Fix some issues with the previous commit --- .../common/config/BlueMapConfigManager.java | 27 +++++++++++-------- .../common/web/FileRequestHandler.java | 2 +- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigManager.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigManager.java index 0b60323e4..cec0dfde8 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigManager.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigManager.java @@ -53,6 +53,11 @@ public class BlueMapConfigManager implements BlueMapConfiguration { public static final String MAPS_CONFIG_FOLDER_NAME = "maps"; public static final String STORAGES_CONFIG_FOLDER_NAME = "storages"; + public static final String MAP_STORAGE_CONFIG_NAME = MAPS_CONFIG_FOLDER_NAME + "/map"; + + public static final String FILE_STORAGE_CONFIG_NAME = STORAGES_CONFIG_FOLDER_NAME + "/file"; + public static final String SQL_STORAGE_CONFIG_NAME = STORAGES_CONFIG_FOLDER_NAME + "/sql"; + private final ConfigManager configManager; private final CoreConfig coreConfig; @@ -220,19 +225,19 @@ private Map loadMapConfigs(Collection autoConfig if (autoConfigWorlds.isEmpty()) { Path worldFolder = Path.of("world"); Files.writeString( - mapConfigFolder.resolve("overworld.conf"), + configManager.resolveConfigFile(MAPS_CONFIG_FOLDER_NAME + "/overworld"), createOverworldMapTemplate("Overworld", worldFolder, DataPack.DIMENSION_OVERWORLD, 0).build(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING ); Files.writeString( - mapConfigFolder.resolve("nether.conf"), + configManager.resolveConfigFile(MAPS_CONFIG_FOLDER_NAME + "/nether"), createNetherMapTemplate("Nether", worldFolder, DataPack.DIMENSION_THE_NETHER, 0).build(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING ); Files.writeString( - mapConfigFolder.resolve("end.conf"), + configManager.resolveConfigFile(MAPS_CONFIG_FOLDER_NAME + "/end"), createEndMapTemplate("End", worldFolder, DataPack.DIMENSION_THE_END, 0).build(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING @@ -264,7 +269,7 @@ private Map loadMapConfigs(Collection autoConfig uniqueId = id + "_" + (++i); mapIds.add(uniqueId); - Path configFile = mapConfigFolder.resolve(uniqueId + ".conf"); + Path configFile = configManager.resolveConfigFile(MAPS_CONFIG_FOLDER_NAME + "/" + uniqueId); String name = worldFolder.getFileName() + " (" + dimensionName + ")"; if (i > 1) name = name + " (" + i + ")"; @@ -322,15 +327,15 @@ private Map loadStorageConfigs(Path defaultWebroot) throw try { FileHelper.createDirectories(storageConfigFolder); Files.writeString( - storageConfigFolder.resolve("file.conf"), - configManager.loadConfigTemplate("/de/bluecolored/bluemap/config/storages/file.conf") + configManager.resolveConfigFile(FILE_STORAGE_CONFIG_NAME), + configManager.loadConfigTemplate(FILE_STORAGE_CONFIG_NAME) .setVariable("root", formatPath(defaultWebroot.resolve("maps"))) .build(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING ); Files.writeString( - storageConfigFolder.resolve("sql.conf"), - configManager.loadConfigTemplate("/de/bluecolored/bluemap/config/storages/sql.conf").build(), + configManager.resolveConfigFile(SQL_STORAGE_CONFIG_NAME), + configManager.loadConfigTemplate(SQL_STORAGE_CONFIG_NAME).build(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING ); } catch (IOException | NullPointerException ex) { @@ -367,7 +372,7 @@ private String sanitiseMapId(String id) { } private ConfigTemplate createOverworldMapTemplate(String name, Path worldFolder, Key dimension, int index) throws IOException { - return configManager.loadConfigTemplate("/de/bluecolored/bluemap/config/maps/map.conf") + return configManager.loadConfigTemplate(MAP_STORAGE_CONFIG_NAME) .setVariable("name", name) .setVariable("sorting", "" + index) .setVariable("world", formatPath(worldFolder)) @@ -381,7 +386,7 @@ private ConfigTemplate createOverworldMapTemplate(String name, Path worldFolder, } private ConfigTemplate createNetherMapTemplate(String name, Path worldFolder, Key dimension, int index) throws IOException { - return configManager.loadConfigTemplate("/de/bluecolored/bluemap/config/maps/map.conf") + return configManager.loadConfigTemplate(MAP_STORAGE_CONFIG_NAME) .setVariable("name", name) .setVariable("sorting", "" + (100 + index)) .setVariable("world", formatPath(worldFolder)) @@ -395,7 +400,7 @@ private ConfigTemplate createNetherMapTemplate(String name, Path worldFolder, Ke } private ConfigTemplate createEndMapTemplate(String name, Path worldFolder, Key dimension, int index) throws IOException { - return configManager.loadConfigTemplate("/de/bluecolored/bluemap/config/maps/map.conf") + return configManager.loadConfigTemplate(MAP_STORAGE_CONFIG_NAME) .setVariable("name", name) .setVariable("sorting", "" + (200 + index)) .setVariable("world", formatPath(worldFolder)) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java index f4438f117..f7e583c6c 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java @@ -92,7 +92,7 @@ private HttpResponse generateResponse(HttpRequest request) throws IOException { // default to index.html if (!Files.exists(filePath) || Files.isDirectory(filePath)){ - filePath = filePath.resolve("/index.html"); + filePath = filePath.resolve("index.html"); } if (!Files.exists(filePath) || Files.isDirectory(filePath)){ From 3faf2f0135efb0ecabd672e2a79ea2e2a97b1ace Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Tue, 21 May 2024 22:23:57 +0200 Subject: [PATCH 17/38] Only rebuild webapp if clean-build or there were changes --- BlueMapCommon/build.gradle.kts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/BlueMapCommon/build.gradle.kts b/BlueMapCommon/build.gradle.kts index 883f31f1c..389e4987b 100644 --- a/BlueMapCommon/build.gradle.kts +++ b/BlueMapCommon/build.gradle.kts @@ -70,12 +70,14 @@ tasks.test { useJUnitPlatform() } -tasks.register("buildWebapp", type = NpmTask::class) { +tasks.clean { doFirst { if (!file("webapp/dist/").deleteRecursively()) throw IOException("Failed to delete build directory!") } +} +tasks.register("buildWebapp", type = NpmTask::class) { dependsOn ("npmInstall") args.set(listOf("run", "build")) @@ -89,7 +91,6 @@ tasks.register("zipWebapp", type = Zip::class) { archiveFileName.set("webapp.zip") destinationDirectory.set(file("src/main/resources/de/bluecolored/bluemap/")) - //outputs.upToDateWhen { false } inputs.dir("webapp/dist/") outputs.file("src/main/resources/de/bluecolored/bluemap/webapp.zip") } From 20aa0a72f539c1998dd9f7a14d45c2267ea6d817 Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Tue, 21 May 2024 22:24:31 +0200 Subject: [PATCH 18/38] Apply spottless fixes --- .../bluemap/common/config/ConfigLoader.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/ConfigLoader.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/ConfigLoader.java index b10a10849..a5b241694 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/ConfigLoader.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/ConfigLoader.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.common.config; import de.bluecolored.bluemap.core.util.Key; From 3db6833fc6ceb602bc302668359642992d43b8ab Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Wed, 22 May 2024 15:45:06 +0200 Subject: [PATCH 19/38] Move region-file watch service into World interface --- ...atchService.java => MapUpdateService.java} | 95 +++++-------------- .../bluemap/common/plugin/Plugin.java | 28 +++--- .../bluemap/core/util/WatchService.java | 45 +++++++++ .../bluecolored/bluemap/core/world/World.java | 19 +++- .../bluemap/core/world/mca/MCAWorld.java | 23 ++--- .../world/mca/MCAWorldRegionWatchService.java | 95 +++++++++++++++++++ .../core/world/mca/region/LinearRegion.java | 2 + .../core/world/mca/region/MCARegion.java | 3 + .../core/world/mca/region/RegionType.java | 53 ++++++++--- .../bluecolored/bluemap/cli/BlueMapCLI.java | 17 ++-- 10 files changed, 258 insertions(+), 122 deletions(-) rename BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/{RegionFileWatchService.java => MapUpdateService.java} (50%) create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/WatchService.java create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorldRegionWatchService.java diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/RegionFileWatchService.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/MapUpdateService.java similarity index 50% rename from BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/RegionFileWatchService.java rename to BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/MapUpdateService.java index a788bed40..c75d0dc34 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/RegionFileWatchService.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/MapUpdateService.java @@ -29,23 +29,20 @@ import de.bluecolored.bluemap.common.rendermanager.WorldRegionRenderTask; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.map.BmMap; -import de.bluecolored.bluemap.core.util.FileHelper; -import de.bluecolored.bluemap.core.world.World; -import de.bluecolored.bluemap.core.world.mca.MCAWorld; -import de.bluecolored.bluemap.core.world.mca.region.RegionType; +import de.bluecolored.bluemap.core.util.WatchService; import java.io.IOException; -import java.nio.file.*; +import java.nio.file.ClosedWatchServiceException; import java.util.HashMap; import java.util.Map; import java.util.Timer; import java.util.TimerTask; -public class RegionFileWatchService extends Thread { +public class MapUpdateService extends Thread { private final BmMap map; private final RenderManager renderManager; - private final WatchService watchService; + private final WatchService watchService; private volatile boolean closed; @@ -53,25 +50,12 @@ public class RegionFileWatchService extends Thread { private final Map scheduledUpdates; - public RegionFileWatchService(RenderManager renderManager, BmMap map) throws IOException { + public MapUpdateService(RenderManager renderManager, BmMap map) throws IOException { this.renderManager = renderManager; this.map = map; this.closed = false; this.scheduledUpdates = new HashMap<>(); - - World world = map.getWorld(); - if (!(world instanceof MCAWorld)) throw new UnsupportedOperationException("world-type is not supported"); - Path folder = ((MCAWorld) world).getRegionFolder(); - FileHelper.createDirectories(folder); - - this.watchService = folder.getFileSystem().newWatchService(); - folder.register(this.watchService, - StandardWatchEventKinds.ENTRY_CREATE, - StandardWatchEventKinds.ENTRY_MODIFY, - StandardWatchEventKinds.ENTRY_DELETE - ); - - Logger.global.logDebug("Created region-file watch-service for map '" + map.getId() + "' at '" + folder + "'."); + this.watchService = map.getWorld().createRegionWatchService(); } @Override @@ -81,24 +65,8 @@ public void run() { Logger.global.logDebug("Started watching map '" + map.getId() + "' for updates..."); try { - while (!closed) { - WatchKey key = this.watchService.take(); - - for (WatchEvent event : key.pollEvents()) { - WatchEvent.Kind kind = event.kind(); - - if (kind == StandardWatchEventKinds.OVERFLOW) continue; - - Object fileObject = event.context(); - if (!(fileObject instanceof Path)) continue; - Path file = (Path) fileObject; - - String regionFileName = file.toFile().getName(); - updateRegion(regionFileName); - } - - if (!key.reset()) return; - } + while (!closed) + this.watchService.take().forEach(this::updateRegion); } catch (ClosedWatchServiceException ignore) { } catch (InterruptedException iex) { Thread.currentThread().interrupt(); @@ -111,36 +79,25 @@ public void run() { } } - private synchronized void updateRegion(String regionFileName) { - if (RegionType.forFileName(regionFileName) == null) return; + private synchronized void updateRegion(Vector2i regionPos) { + // we only want to start the render when there were no changes on a file for 5 seconds + TimerTask task = scheduledUpdates.remove(regionPos); + if (task != null) task.cancel(); - try { - String[] filenameParts = regionFileName.split("\\."); - if (filenameParts.length < 3) return; - - int rX = Integer.parseInt(filenameParts[1]); - int rZ = Integer.parseInt(filenameParts[2]); - Vector2i regionPos = new Vector2i(rX, rZ); - - // we only want to start the render when there were no changes on a file for 5 seconds - TimerTask task = scheduledUpdates.remove(regionPos); - if (task != null) task.cancel(); - - task = new TimerTask() { - @Override - public void run() { - synchronized (RegionFileWatchService.this) { - WorldRegionRenderTask task = new WorldRegionRenderTask(map, regionPos); - scheduledUpdates.remove(regionPos); - renderManager.scheduleRenderTask(task); - - Logger.global.logDebug("Scheduled update for region-file: " + regionPos + " (Map: " + map.getId() + ")"); - } + task = new TimerTask() { + @Override + public void run() { + synchronized (MapUpdateService.this) { + WorldRegionRenderTask task = new WorldRegionRenderTask(map, regionPos); + scheduledUpdates.remove(regionPos); + renderManager.scheduleRenderTask(task); + + Logger.global.logDebug("Scheduled update for region-file: " + regionPos + " (Map: " + map.getId() + ")"); } - }; - scheduledUpdates.put(regionPos, task); - delayTimer.schedule(task, 5000); - } catch (NumberFormatException ignore) {} + } + }; + scheduledUpdates.put(regionPos, task); + delayTimer.schedule(task, 5000); } public void close() { @@ -151,7 +108,7 @@ public void close() { try { this.watchService.close(); - } catch (IOException ex) { + } catch (Exception ex) { Logger.global.logError("Exception while trying to close WatchService!", ex); } } diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java index fcd09e07c..ba5aeb5ef 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java @@ -94,7 +94,7 @@ public class Plugin implements ServerEventListener { private Timer daemonTimer; - private Map regionFileWatchServices; + private Map mapUpdateServices; private PlayerSkinUpdater skinUpdater; @@ -316,8 +316,8 @@ public void run() { TimerTask fileWatcherRestartTask = new TimerTask() { @Override public void run() { - regionFileWatchServices.values().forEach(RegionFileWatchService::close); - regionFileWatchServices.clear(); + mapUpdateServices.values().forEach(MapUpdateService::close); + mapUpdateServices.clear(); initFileWatcherTasks(); } }; @@ -351,7 +351,7 @@ public void run() { daemonTimer.scheduleAtFixedRate(metricsTask, TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(30)); //watch map-changes - this.regionFileWatchServices = new HashMap<>(); + this.mapUpdateServices = new HashMap<>(); initFileWatcherTasks(); //register listener @@ -408,11 +408,11 @@ public void unload(boolean keepWebserver) { daemonTimer = null; //stop file-watchers - if (regionFileWatchServices != null) { - regionFileWatchServices.values().forEach(RegionFileWatchService::close); - regionFileWatchServices.clear(); + if (mapUpdateServices != null) { + mapUpdateServices.values().forEach(MapUpdateService::close); + mapUpdateServices.clear(); } - regionFileWatchServices = null; + mapUpdateServices = null; // stop render-manager if (renderManager != null){ @@ -567,16 +567,20 @@ public synchronized void startWatchingMap(BmMap map) { stopWatchingMap(map); try { - RegionFileWatchService watcher = new RegionFileWatchService(renderManager, map); + MapUpdateService watcher = new MapUpdateService(renderManager, map); watcher.start(); - regionFileWatchServices.put(map.getId(), watcher); + mapUpdateServices.put(map.getId(), watcher); } catch (IOException ex) { - Logger.global.logError("Failed to create file-watcher for map: " + map.getId() + " (This means the map might not automatically update)", ex); + Logger.global.logError("Failed to create update-watcher for map: " + map.getId() + + " (This means the map might not automatically update)", ex); + } catch (UnsupportedOperationException ex) { + Logger.global.logWarning("Update-watcher for map '" + map.getId() + "' is not supported for the world-type." + + " (This means the map might not automatically update)"); } } public synchronized void stopWatchingMap(BmMap map) { - RegionFileWatchService watcher = regionFileWatchServices.remove(map.getId()); + MapUpdateService watcher = mapUpdateServices.remove(map.getId()); if (watcher != null) { watcher.close(); } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/WatchService.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/WatchService.java new file mode 100644 index 000000000..48235b24e --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/WatchService.java @@ -0,0 +1,45 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.util; + +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * A watch service that watches for changes and events. + * @param The type of the events or changes this WatchService provides + */ +public interface WatchService extends AutoCloseable { + + @Nullable + List poll(); + + @Nullable List poll(long timeout, TimeUnit unit) throws InterruptedException; + + List take() throws InterruptedException; + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/World.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/World.java index 8015bd6f8..2f02e300c 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/World.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/World.java @@ -27,7 +27,9 @@ import com.flowpowered.math.vector.Vector2i; import com.flowpowered.math.vector.Vector3i; import de.bluecolored.bluemap.core.util.Grid; +import de.bluecolored.bluemap.core.util.WatchService; +import java.io.IOException; import java.util.Collection; import java.util.function.Predicate; @@ -72,6 +74,15 @@ public interface World { */ Collection listRegions(); + /** + * Creates and returns a new {@link WatchService} which watches for any changes in this worlds regions. + * @throws IOException if an IOException occurred while creating the watch-service + * @throws UnsupportedOperationException if watching this world is not supported + */ + default WatchService createRegionWatchService() throws IOException { + throw new UnsupportedOperationException(); + } + /** * Loads all chunks from the specified region into the chunk cache (if there is a cache) */ @@ -79,6 +90,9 @@ default void preloadRegionChunks(int x, int z) { preloadRegionChunks(x, z, pos -> true); } + /** + * Loads the filtered chunks from the specified region into the chunk cache (if there is a cache) + */ void preloadRegionChunks(int x, int z, Predicate chunkFilter); /** @@ -91,9 +105,4 @@ default void preloadRegionChunks(int x, int z) { */ void invalidateChunkCache(int x, int z); - /** - * Cleans up invalid cache-entries to free up memory - */ - void cleanUpChunkCache(); - } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java index 8cc24cc14..bc0ec6673 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java @@ -36,6 +36,7 @@ import de.bluecolored.bluemap.core.util.Grid; import de.bluecolored.bluemap.core.util.Key; import de.bluecolored.bluemap.core.util.Vector2iCache; +import de.bluecolored.bluemap.core.util.WatchService; import de.bluecolored.bluemap.core.world.*; import de.bluecolored.bluemap.core.world.mca.chunk.ChunkLoader; import de.bluecolored.bluemap.core.world.mca.data.DimensionTypeDeserializer; @@ -165,21 +166,11 @@ public Collection listRegions() { return stream .map(file -> { try { - String fileName = file.getFileName().toString(); - - if (RegionType.forFileName(fileName) == null) return null; if (Files.size(file) <= 0) return null; - - String[] filenameParts = fileName.split("\\."); - int rX = Integer.parseInt(filenameParts[1]); - int rZ = Integer.parseInt(filenameParts[2]); - - return new Vector2i(rX, rZ); + return RegionType.regionForFileName(file.getFileName().toString()); } catch (IOException ex) { Logger.global.logError("Failed to read region-file: " + file, ex); return null; - } catch (NumberFormatException ignore) { - return null; } }) .filter(Objects::nonNull) @@ -190,6 +181,11 @@ public Collection listRegions() { } } + @Override + public WatchService createRegionWatchService() throws IOException { + return new MCAWorldRegionWatchService(this.regionFolder); + } + @Override public void preloadRegionChunks(int x, int z, Predicate chunkFilter) { try { @@ -223,11 +219,6 @@ public void invalidateChunkCache(int x, int z) { chunkCache.invalidate(VECTOR_2_I_CACHE.get(x, z)); } - @Override - public void cleanUpChunkCache() { - chunkCache.cleanUp(); - } - private Region loadRegion(Vector2i regionPos) { return loadRegion(regionPos.getX(), regionPos.getY()); } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorldRegionWatchService.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorldRegionWatchService.java new file mode 100644 index 000000000..b01455df6 --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorldRegionWatchService.java @@ -0,0 +1,95 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.mca; + +import com.flowpowered.math.vector.Vector2i; +import de.bluecolored.bluemap.core.util.WatchService; +import de.bluecolored.bluemap.core.world.mca.region.RegionType; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.StandardWatchEventKinds; +import java.nio.file.WatchKey; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +public class MCAWorldRegionWatchService implements WatchService { + + private final java.nio.file.WatchService watchService; + + public MCAWorldRegionWatchService(Path regionFolder) throws IOException { + this.watchService = regionFolder.getFileSystem().newWatchService(); + regionFolder.register(this.watchService, + StandardWatchEventKinds.ENTRY_CREATE, + StandardWatchEventKinds.ENTRY_MODIFY, + StandardWatchEventKinds.ENTRY_DELETE + ); + } + + @Override + public @Nullable List poll() { + WatchKey key = watchService.poll(); + if (key == null) return null; + return processWatchKey(key); + } + + @Override + public @Nullable List poll(long timeout, TimeUnit unit) throws InterruptedException { + WatchKey key = watchService.poll(timeout, unit); + if (key == null) return null; + return processWatchKey(key); + } + + @Override + public List take() throws InterruptedException { + WatchKey key = watchService.take(); + return processWatchKey(key); + } + + @Override + public void close() throws IOException { + watchService.close(); + } + + private List processWatchKey(WatchKey key) { + try { + return key.pollEvents().stream() + .map(event -> { + if (event.context() instanceof Path path) { + return RegionType.regionForFileName(path.getFileName().toString()); + } else { + return null; + } + }) + .filter(Objects::nonNull) + .toList(); + } finally { + key.reset(); + } + } + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/LinearRegion.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/LinearRegion.java index d1294dc27..24cf5e98d 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/LinearRegion.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/LinearRegion.java @@ -36,6 +36,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; +import java.util.regex.Pattern; /* * LinearFormat: @@ -63,6 +64,7 @@ public class LinearRegion implements Region { public static final String FILE_SUFFIX = ".linear"; + public static final Pattern FILE_PATTERN = Pattern.compile("^r\\.(-?\\d+)\\.(-?\\d+)\\.linear$"); private static final long MAGIC = 0xc3ff13183cca9d9aL; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/MCARegion.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/MCARegion.java index d1e420bc6..69ec90f2b 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/MCARegion.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/MCARegion.java @@ -40,11 +40,14 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; +import java.util.regex.Pattern; @Getter public class MCARegion implements Region { public static final String FILE_SUFFIX = ".mca"; + public static final Pattern FILE_PATTERN = Pattern.compile("^r\\.(-?\\d+)\\.(-?\\d+)\\.mca$"); + public static final Compression[] CHUNK_COMPRESSION_MAP = new Compression[255]; static { CHUNK_COMPRESSION_MAP[0] = Compression.NONE; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/RegionType.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/RegionType.java index 85956eaf8..003943464 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/RegionType.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/region/RegionType.java @@ -24,6 +24,7 @@ */ package de.bluecolored.bluemap.core.world.mca.region; +import com.flowpowered.math.vector.Vector2i; import de.bluecolored.bluemap.core.util.Key; import de.bluecolored.bluemap.core.util.Keyed; import de.bluecolored.bluemap.core.util.Registry; @@ -31,16 +32,17 @@ import de.bluecolored.bluemap.core.world.mca.MCAWorld; import lombok.Getter; import lombok.RequiredArgsConstructor; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.nio.file.Files; import java.nio.file.Path; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public interface RegionType extends Keyed { - RegionType MCA = new Impl(Key.bluemap("mca"), MCARegion.FILE_SUFFIX, MCARegion::new, MCARegion::getRegionFileName); - RegionType LINEAR = new Impl(Key.bluemap("linear"), LinearRegion.FILE_SUFFIX, LinearRegion::new, LinearRegion::getRegionFileName); + RegionType MCA = new Impl(Key.bluemap("mca"), MCARegion::new, MCARegion::getRegionFileName, MCARegion.FILE_PATTERN); + RegionType LINEAR = new Impl(Key.bluemap("linear"), LinearRegion::new, LinearRegion::getRegionFileName, LinearRegion.FILE_PATTERN); RegionType DEFAULT = MCA; Registry REGISTRY = new Registry<>( @@ -48,36 +50,55 @@ public interface RegionType extends Keyed { LINEAR ); - String getFileSuffix(); - + /** + * Creates a new {@link Region} from the given world and region-file + */ Region createRegion(MCAWorld world, Path regionFile); - Path getRegionFile(Path regionFolder, int regionX, int regionZ); + /** + * Converts region coordinates into the region-file name. + */ + String getRegionFileName(int regionX, int regionZ); + + /** + * Converts the region-file name into region coordinates. + * Returns null if the name does not match the expected format. + */ + @Nullable Vector2i getRegionFromFileName(String fileName); static @Nullable RegionType forFileName(String fileName) { for (RegionType regionType : REGISTRY.values()) { - if (fileName.endsWith(regionType.getFileSuffix())) + if (regionType.getRegionFromFileName(fileName) != null) return regionType; } return null; } - static @NotNull Region loadRegion(MCAWorld world, Path regionFolder, int regionX, int regionZ) { + static @Nullable Vector2i regionForFileName(String fileName) { + for (RegionType regionType : REGISTRY.values()) { + Vector2i pos = regionType.getRegionFromFileName(fileName); + if (pos != null) return pos; + } + + return null; + } + + static Region loadRegion(MCAWorld world, Path regionFolder, int regionX, int regionZ) { for (RegionType regionType : REGISTRY.values()) { - Path regionFile = regionType.getRegionFile(regionFolder, regionX, regionZ); + Path regionFile = regionFolder.resolve(regionType.getRegionFileName(regionX, regionZ)); if (Files.exists(regionFile)) return regionType.createRegion(world, regionFile); } - return DEFAULT.createRegion(world, DEFAULT.getRegionFile(regionFolder, regionX, regionZ)); + return DEFAULT.createRegion(world, regionFolder.resolve(DEFAULT.getRegionFileName(regionX, regionZ))); } @RequiredArgsConstructor class Impl implements RegionType { @Getter private final Key key; - @Getter private final String fileSuffix; private final RegionFactory regionFactory; private final RegionFileNameFunction regionFileNameFunction; + private final Pattern regionFileNamePattern; public Region createRegion(MCAWorld world, Path regionFile) { return this.regionFactory.create(world, regionFile); @@ -87,8 +108,14 @@ public String getRegionFileName(int regionX, int regionZ) { return regionFileNameFunction.getRegionFileName(regionX, regionZ); } - public Path getRegionFile(Path regionFolder, int regionX, int regionZ) { - return regionFolder.resolve(getRegionFileName(regionX, regionZ)); + @Override + public @Nullable Vector2i getRegionFromFileName(String fileName) { + Matcher matcher = regionFileNamePattern.matcher(fileName); + if (!matcher.matches()) return null; + return new Vector2i( + Integer.parseInt(matcher.group(1)), + Integer.parseInt(matcher.group(2)) + ); } } diff --git a/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java b/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java index 026445a1a..7872b067f 100644 --- a/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java +++ b/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java @@ -31,7 +31,7 @@ import de.bluecolored.bluemap.common.config.ConfigurationException; import de.bluecolored.bluemap.common.config.CoreConfig; import de.bluecolored.bluemap.common.config.WebserverConfig; -import de.bluecolored.bluemap.common.plugin.RegionFileWatchService; +import de.bluecolored.bluemap.common.plugin.MapUpdateService; import de.bluecolored.bluemap.common.rendermanager.MapUpdateTask; import de.bluecolored.bluemap.common.rendermanager.RenderManager; import de.bluecolored.bluemap.common.rendermanager.RenderTask; @@ -88,16 +88,19 @@ public void renderMaps(BlueMapService blueMap, boolean watch, boolean forceRende Map maps = blueMap.getOrLoadMaps(mapFilter); //watcher - List regionFileWatchServices = new ArrayList<>(); + List mapUpdateServices = new ArrayList<>(); if (watch) { for (BmMap map : maps.values()) { try { - RegionFileWatchService watcher = new RegionFileWatchService(renderManager, map); + MapUpdateService watcher = new MapUpdateService(renderManager, map); watcher.start(); - regionFileWatchServices.add(watcher); + mapUpdateServices.add(watcher); } catch (IOException ex) { Logger.global.logError("Failed to create file-watcher for map: " + map.getId() + - " (This map might not automatically update)", ex); + " (This map might not automatically update)", ex); + } catch (UnsupportedOperationException ex) { + Logger.global.logWarning("Update-watcher for map '" + map.getId() + "' is not supported for the world-type." + + " (This means the map might not automatically update)"); } } } @@ -150,8 +153,8 @@ public void run() { updateInfoTask.cancel(); saveTask.cancel(); - regionFileWatchServices.forEach(RegionFileWatchService::close); - regionFileWatchServices.clear(); + mapUpdateServices.forEach(MapUpdateService::close); + mapUpdateServices.clear(); renderManager.removeAllRenderTasks(); try { From 8455b50fc390467ea0b0ecb65adb92153490dece Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Wed, 22 May 2024 16:00:54 +0200 Subject: [PATCH 20/38] Fix use of implementation-specific exception --- .../common/plugin/MapUpdateService.java | 3 +- .../bluemap/core/util/WatchService.java | 23 +++++++++++++++ .../world/mca/MCAWorldRegionWatchService.java | 29 ++++++++++++++----- 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/MapUpdateService.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/MapUpdateService.java index c75d0dc34..2db3ad438 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/MapUpdateService.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/MapUpdateService.java @@ -32,7 +32,6 @@ import de.bluecolored.bluemap.core.util.WatchService; import java.io.IOException; -import java.nio.file.ClosedWatchServiceException; import java.util.HashMap; import java.util.Map; import java.util.Timer; @@ -67,7 +66,7 @@ public void run() { try { while (!closed) this.watchService.take().forEach(this::updateRegion); - } catch (ClosedWatchServiceException ignore) { + } catch (WatchService.ClosedException ignore) { } catch (InterruptedException iex) { Thread.currentThread().interrupt(); } finally { diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/WatchService.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/WatchService.java index 48235b24e..e8954f7bd 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/WatchService.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/util/WatchService.java @@ -24,6 +24,7 @@ */ package de.bluecolored.bluemap.core.util; +import lombok.experimental.StandardException; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -35,11 +36,33 @@ */ public interface WatchService extends AutoCloseable { + /** + * Retrieves and consumes the next batch of events. + * @throws ClosedException If the watch-service is closed + */ @Nullable List poll(); + /** + * Retrieves and consumes the next batch of events, + * waiting if necessary up to the specified wait time if none are yet present. + * @throws ClosedException If the watch-service is closed, or it is closed while waiting for the next event + * @throws InterruptedException If interrupted while waiting + */ @Nullable List poll(long timeout, TimeUnit unit) throws InterruptedException; + /** + * Retrieves and consumes the next batch of events, + * waiting if necessary until an event becomes available. + * @throws ClosedException If the watch-service is closed, or it is closed while waiting for the next event + * @throws InterruptedException If interrupted while waiting + */ List take() throws InterruptedException; + /** + * Thrown when the WatchService is closed or gets closed when polling or while waiting for events + */ + @StandardException + class ClosedException extends RuntimeException {} + } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorldRegionWatchService.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorldRegionWatchService.java index b01455df6..91f585d16 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorldRegionWatchService.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorldRegionWatchService.java @@ -30,6 +30,7 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; +import java.nio.file.ClosedWatchServiceException; import java.nio.file.Path; import java.nio.file.StandardWatchEventKinds; import java.nio.file.WatchKey; @@ -52,22 +53,34 @@ public MCAWorldRegionWatchService(Path regionFolder) throws IOException { @Override public @Nullable List poll() { - WatchKey key = watchService.poll(); - if (key == null) return null; - return processWatchKey(key); + try { + WatchKey key = watchService.poll(); + if (key == null) return null; + return processWatchKey(key); + } catch (ClosedWatchServiceException e) { + throw new ClosedException(e); + } } @Override public @Nullable List poll(long timeout, TimeUnit unit) throws InterruptedException { - WatchKey key = watchService.poll(timeout, unit); - if (key == null) return null; - return processWatchKey(key); + try { + WatchKey key = watchService.poll(timeout, unit); + if (key == null) return null; + return processWatchKey(key); + } catch (ClosedWatchServiceException e) { + throw new ClosedException(e); + } } @Override public List take() throws InterruptedException { - WatchKey key = watchService.take(); - return processWatchKey(key); + try { + WatchKey key = watchService.take(); + return processWatchKey(key); + } catch (ClosedWatchServiceException e) { + throw new ClosedException(e); + } } @Override From 2c2d2f9227abb6e8895ba976aceb813a92d88354 Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Wed, 22 May 2024 16:03:58 +0200 Subject: [PATCH 21/38] Fix use of java-19 api --- .../de/bluecolored/bluemap/common/debug/StateDumper.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/debug/StateDumper.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/debug/StateDumper.java index 1fc1b7802..bd2c140e2 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/debug/StateDumper.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/debug/StateDumper.java @@ -108,13 +108,13 @@ private void dumpInstance(Object instance, JsonWriter writer, Set alread } if (!alreadyDumped.add(instance)) { - writer.value("<<" + Objects.toIdentityString(instance) + ">>"); + writer.value("<<" + toIdentityString(instance) + ">>"); return; } writer.beginObject(); try { - String identityString = Objects.toIdentityString(instance); + String identityString = toIdentityString(instance); writer.name("#identity").value(identityString); if (instance instanceof Map map) { @@ -208,6 +208,10 @@ private void dumpInstance(Object instance, JsonWriter writer, Set alread } } + private static String toIdentityString(Object instance) { + return instance.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(instance)); + } + private void dumpAnnotatedInstance(Class type, Object instance, JsonWriter writer, Set alreadyDumped) throws IOException { DebugDump typedd = type.getAnnotation(DebugDump.class); From a594a4bed315e7c9381d3ba01fdfe1afbfc28333 Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Wed, 22 May 2024 20:58:02 +0200 Subject: [PATCH 22/38] comment & formatting --- .../pack/resourcepack/blockmodel/TextureVariable.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/TextureVariable.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/TextureVariable.java index 5d132186f..8d2e397ed 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/TextureVariable.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockmodel/TextureVariable.java @@ -142,6 +142,9 @@ public TextureVariable read(JsonReader in) throws IOException { if (value.charAt(0) == '#') { return new TextureVariable(value.substring(1)); } else { + + // if the value contains neither a : nor a / it is safe to assume it was meant to be a reference + // as there is no texture at root-level in the implicit "minecraft" namespace if (!(value.contains(":") || value.contains("/"))) { return new TextureVariable(value); } @@ -149,5 +152,7 @@ public TextureVariable read(JsonReader in) throws IOException { return new TextureVariable(new ResourcePath<>(value)); } } + } + } From fc8377764c479ce956e9d8dccaa5df4b5562f02d Mon Sep 17 00:00:00 2001 From: TechnicJelle <22576047+TechnicJelle@users.noreply.github.com> Date: Sun, 26 May 2024 16:33:11 +0200 Subject: [PATCH 23/38] Show chunk borders (#542) * Show chunk borders * Change line width to width of two Minecraft pixels * Also fade out chunkborders on hires tiles The hires tiles just always had the chunkborders on them. But the "fade out" distance of those models was 1000. While the fade distance of the chunkborders on lowres tiles was between 200 and 600. This would cause an uneven fadeout between the lowres tiles and the hires tiles. * Added a toggle button for the chunk borders * Move variable to better place --- BlueMapCommon/webapp/public/lang/en.conf | 3 +++ BlueMapCommon/webapp/public/lang/nl.conf | 3 +++ .../src/components/Menu/SettingsMenu.vue | 7 +++++- BlueMapCommon/webapp/src/js/BlueMapApp.js | 6 +++++ BlueMapCommon/webapp/src/js/MapViewer.js | 1 + .../src/js/map/hires/HiresFragmentShader.js | 24 ++++++++++++++++++- .../src/js/map/hires/HiresVertexShader.js | 3 +++ .../src/js/map/lowres/LowresFragmentShader.js | 20 +++++++++++++++- 8 files changed, 64 insertions(+), 3 deletions(-) diff --git a/BlueMapCommon/webapp/public/lang/en.conf b/BlueMapCommon/webapp/public/lang/en.conf index 31107a957..b3fbdfd93 100644 --- a/BlueMapCommon/webapp/public/lang/en.conf +++ b/BlueMapCommon/webapp/public/lang/en.conf @@ -83,6 +83,9 @@ light: "Light" contrast: "Contrast" } + chunkBorders: { + button: "Show chunk borders" + } debug: { button: "Debug" } diff --git a/BlueMapCommon/webapp/public/lang/nl.conf b/BlueMapCommon/webapp/public/lang/nl.conf index b196b593e..f79eb64b5 100644 --- a/BlueMapCommon/webapp/public/lang/nl.conf +++ b/BlueMapCommon/webapp/public/lang/nl.conf @@ -83,6 +83,9 @@ light: "Licht" contrast: "Contrast" } + chunkBorders: { + button: "Laat chunk grenzen zien" + } debug: { button: "Debug" } diff --git a/BlueMapCommon/webapp/src/components/Menu/SettingsMenu.vue b/BlueMapCommon/webapp/src/components/Menu/SettingsMenu.vue index 155f2e61e..8cc6e45e5 100644 --- a/BlueMapCommon/webapp/src/components/Menu/SettingsMenu.vue +++ b/BlueMapCommon/webapp/src/components/Menu/SettingsMenu.vue @@ -56,6 +56,8 @@ >{{lang.name}} + {{ $t("chunkBorders.button") }} + {{ $t("debug.button") }} {{ $t("resetAllSettings.button") }} @@ -105,6 +107,9 @@ name: "SettingsMenu", } }, methods: { + switchChunkBorders() { + this.$bluemap.setChunkBorders(!this.mapViewer.uniforms.chunkBorders.value); + }, switchDebug() { this.$bluemap.setDebug(!this.appState.debug); }, @@ -121,4 +126,4 @@ name: "SettingsMenu", \ No newline at end of file + diff --git a/BlueMapCommon/webapp/src/js/BlueMapApp.js b/BlueMapCommon/webapp/src/js/BlueMapApp.js index dc0ba1aa8..27b707441 100644 --- a/BlueMapCommon/webapp/src/js/BlueMapApp.js +++ b/BlueMapCommon/webapp/src/js/BlueMapApp.js @@ -525,6 +525,10 @@ export class BlueMapApp { this.appState.controls.state = "free"; } + setChunkBorders(chunkBorders) { + this.mapViewer.data.uniforms.chunkBorders.value = chunkBorders; + } + setDebug(debug) { this.appState.debug = debug; @@ -608,6 +612,7 @@ export class BlueMapApp { this.setTheme(this.loadUserSetting("theme", this.appState.theme)); this.setScreenshotClipboard(this.loadUserSetting("screenshotClipboard", this.appState.screenshot.clipboard)); await setLanguage(this.loadUserSetting("lang", i18n.locale.value)); + this.setChunkBorders(this.loadUserSetting("chunkBorders", this.mapViewer.data.uniforms.chunkBorders.value)) this.setDebug(this.loadUserSetting("debug", this.appState.debug)); alert(this.events, "Settings loaded!", "info"); @@ -629,6 +634,7 @@ export class BlueMapApp { this.saveUserSetting("theme", this.appState.theme); this.saveUserSetting("screenshotClipboard", this.appState.screenshot.clipboard); this.saveUserSetting("lang", i18n.locale.value); + this.saveUserSetting("chunkBorders", this.mapViewer.data.uniforms.chunkBorders.value); this.saveUserSetting("debug", this.appState.debug); alert(this.events, "Settings saved!", "info"); diff --git a/BlueMapCommon/webapp/src/js/MapViewer.js b/BlueMapCommon/webapp/src/js/MapViewer.js index c29bd9bd4..868b45635 100644 --- a/BlueMapCommon/webapp/src/js/MapViewer.js +++ b/BlueMapCommon/webapp/src/js/MapViewer.js @@ -61,6 +61,7 @@ export class MapViewer { ambientLight: { value: 0 }, skyColor: { value: new Color(0.5, 0.5, 1) }, voidColor: { value: new Color(0, 0, 0) }, + chunkBorders: { value: false }, hiresTileMap: { value: { map: null, diff --git a/BlueMapCommon/webapp/src/js/map/hires/HiresFragmentShader.js b/BlueMapCommon/webapp/src/js/map/hires/HiresFragmentShader.js index 5fa5da161..e50c75d9a 100644 --- a/BlueMapCommon/webapp/src/js/map/hires/HiresFragmentShader.js +++ b/BlueMapCommon/webapp/src/js/map/hires/HiresFragmentShader.js @@ -24,6 +24,7 @@ */ import { ShaderChunk } from 'three'; +// language=GLSL export const HIRES_FRAGMENT_SHADER = ` ${ShaderChunk.logdepthbuf_pars_fragment} @@ -31,6 +32,7 @@ ${ShaderChunk.logdepthbuf_pars_fragment} #define texture texture2D #endif +uniform float distance; uniform sampler2D textureImage; uniform float sunlightStrength; uniform float ambientLight; @@ -38,9 +40,10 @@ uniform float animationFrameHeight; uniform float animationFrameIndex; uniform float animationInterpolationFrameIndex; uniform float animationInterpolation; +uniform bool chunkBorders; varying vec3 vPosition; -//varying vec3 vWorldPosition; +varying vec3 vWorldPosition; varying vec3 vNormal; varying vec2 vUv; varying vec3 vColor; @@ -68,6 +71,25 @@ void main() { float light = mix(vBlocklight, max(vSunlight, vBlocklight), sunlightStrength); color.rgb *= mix(ambientLight, 1.0, light / 15.0); + if (chunkBorders) { + vec4 lineColour = vec4(1.0, 0.0, 1.0, 0.4); + float lineInterval = 16.0; + float lineThickness = 0.125; //width of two Minecraft pixels + float offset = 0.5; + + vec2 worldPos = vWorldPosition.xz; + worldPos += offset; + float x = abs(mod(worldPos.x, lineInterval) - offset); + float y = abs(mod(worldPos.y, lineInterval) - offset); + bool isChunkBorder = x < lineThickness || y < lineThickness; + + //only show line on upwards facing surfaces + bool showChunkBorder = isChunkBorder && vNormal.y > 0.1; + + float distFac = smoothstep(200.0, 600.0, distance); + color.rgb = mix(mix(color.rgb, lineColour.rgb, float(showChunkBorder) * lineColour.a), color.rgb, distFac); + } + gl_FragColor = color; ${ShaderChunk.logdepthbuf_fragment} diff --git a/BlueMapCommon/webapp/src/js/map/hires/HiresVertexShader.js b/BlueMapCommon/webapp/src/js/map/hires/HiresVertexShader.js index d919f420e..ed15ccbfd 100644 --- a/BlueMapCommon/webapp/src/js/map/hires/HiresVertexShader.js +++ b/BlueMapCommon/webapp/src/js/map/hires/HiresVertexShader.js @@ -33,6 +33,7 @@ attribute float sunlight; attribute float blocklight; varying vec3 vPosition; +varying vec3 vWorldPosition; varying vec3 vNormal; varying vec2 vUv; varying vec3 vColor; @@ -42,6 +43,8 @@ varying float vBlocklight; void main() { vPosition = position; + vec4 worldPos = modelMatrix * vec4(vPosition, 1); + vWorldPosition = worldPos.xyz; vNormal = normal; vUv = uv; vColor = color; diff --git a/BlueMapCommon/webapp/src/js/map/lowres/LowresFragmentShader.js b/BlueMapCommon/webapp/src/js/map/lowres/LowresFragmentShader.js index 095d2b5a9..da702b8a4 100644 --- a/BlueMapCommon/webapp/src/js/map/lowres/LowresFragmentShader.js +++ b/BlueMapCommon/webapp/src/js/map/lowres/LowresFragmentShader.js @@ -24,6 +24,7 @@ */ import { ShaderChunk } from 'three'; +// language=GLSL export const LOWRES_FRAGMENT_SHADER = ` ${ShaderChunk.logdepthbuf_pars_fragment} @@ -51,6 +52,7 @@ uniform vec2 textureSize; uniform float lod; uniform float lodScale; uniform vec3 voidColor; +uniform bool chunkBorders; varying vec3 vPosition; varying vec3 vWorldPosition; @@ -98,9 +100,10 @@ void main() { float ao = 0.0; float aoStrength = 0.0; + float distFac = smoothstep(200.0, 600.0, distance); if(lod == 1.0) { aoStrength = smoothstep(PI - 0.8, PI - 0.2, acos(-clamp(viewMatrix[1][2], 0.0, 1.0))); - aoStrength *= 1.0 - smoothstep(200.0, 600.0, distance); + aoStrength *= 1.0 - distFac; if (aoStrength > 0.0) { const float r = 3.0; @@ -123,6 +126,21 @@ void main() { float light = mix(blockLight, 15.0, sunlightStrength); color.rgb *= mix(ambientLight, 1.0, light / 15.0); + if (chunkBorders) { + vec4 lineColour = vec4(1.0, 0.0, 1.0, 0.4); + float lineInterval = 16.0; + float lineThickness = 0.125; //width of two Minecraft pixels + float offset = 0.5; + + vec2 worldPos = vWorldPosition.xz; + worldPos += offset; + float x = abs(mod(worldPos.x, lineInterval) - offset); + float y = abs(mod(worldPos.y, lineInterval) - offset); + bool isChunkBorder = x < lineThickness || y < lineThickness; + + color.rgb = mix(mix(color.rgb, lineColour.rgb, float(isChunkBorder) * lineColour.a), color.rgb, distFac); + } + vec3 adjustedVoidColor = adjustColor(voidColor); //where there's transparency, there is void that needs to be coloured color.rgb = mix(adjustedVoidColor, color.rgb, color.a); From 6ad50a89cb300b9a758fc4f370ffb7f8fe5cd64b Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Mon, 27 May 2024 23:10:20 +0200 Subject: [PATCH 24/38] Implement native addon loader --- .../bluemap/common/addons/AddonException.java | 6 + .../bluemap/common/addons/AddonInfo.java | 12 ++ .../bluemap/common/addons/AddonManager.java | 139 ++++++++++++++++++ .../bluemap/common/addons/LoadedAddon.java | 7 + .../bluemap/common/api/BlueMapAPIImpl.java | 91 +++++++++--- .../bluemap/common/api/BlueMapMapImpl.java | 46 +++--- .../bluemap/common/api/BlueMapWorldImpl.java | 29 ++-- .../bluemap/common/api/RenderManagerImpl.java | 6 +- .../bluemap/common/api/WebAppImpl.java | 59 ++++++-- .../bluemap/common/plugin/Plugin.java | 65 +++----- .../bluecolored/bluemap/cli/BlueMapCLI.java | 14 ++ 11 files changed, 363 insertions(+), 111 deletions(-) create mode 100644 BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonException.java create mode 100644 BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonInfo.java create mode 100644 BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonManager.java create mode 100644 BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/LoadedAddon.java diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonException.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonException.java new file mode 100644 index 000000000..136c44555 --- /dev/null +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonException.java @@ -0,0 +1,6 @@ +package de.bluecolored.bluemap.common.addons; + +import lombok.experimental.StandardException; + +@StandardException +public class AddonException extends Exception {} diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonInfo.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonInfo.java new file mode 100644 index 000000000..b96f75107 --- /dev/null +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonInfo.java @@ -0,0 +1,12 @@ +package de.bluecolored.bluemap.common.addons; + +import lombok.Getter; + +@Getter +public class AddonInfo { + public static final String ADDON_INFO_FILE = "bluemap.addon.json"; + + private String id; + private String entrypoint; + +} diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonManager.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonManager.java new file mode 100644 index 000000000..0ff869f37 --- /dev/null +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonManager.java @@ -0,0 +1,139 @@ +package de.bluecolored.bluemap.common.addons; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import de.bluecolored.bluemap.core.BlueMap; +import de.bluecolored.bluemap.core.logger.Logger; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.io.Reader; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; + +import static de.bluecolored.bluemap.common.addons.AddonInfo.ADDON_INFO_FILE; + +public final class AddonManager { + + private static final Gson GSON = new GsonBuilder().create(); + private static final Map LOADED_ADDONS = new ConcurrentHashMap<>(); + + private AddonManager() { + throw new UnsupportedOperationException("Utility class"); + } + + public static void tryLoadAddons(Path root) { + tryLoadAddons(root, false); + } + + public static void tryLoadAddons(Path root, boolean expectOnlyAddons) { + try (Stream files = Files.list(root)) { + files + .filter(Files::isRegularFile) + .filter(f -> f.getFileName().toString().endsWith(".jar")) + .forEach(expectOnlyAddons ? AddonManager::tryLoadAddon : AddonManager::tryLoadJar); + } catch (IOException e) { + Logger.global.logError("Failed to load addons from '%s'".formatted(root), e); + } + } + + public static void tryLoadAddon(Path addonJarFile) { + try { + AddonInfo addonInfo = loadAddonInfo(addonJarFile); + if (addonInfo == null) throw new AddonException("No %s found in '%s'".formatted(ADDON_INFO_FILE, addonJarFile)); + + if (LOADED_ADDONS.containsKey(addonInfo.getId())) return; + + loadAddon(addonJarFile, addonInfo); + } catch (IOException | AddonException e) { + Logger.global.logError("Failed to load addon '%s'".formatted(addonJarFile), e); + } + } + + public static void tryLoadJar(Path addonJarFile) { + try { + AddonInfo addonInfo = loadAddonInfo(addonJarFile); + if (addonInfo == null) { + Logger.global.logDebug("No %s found in '%s', skipping...".formatted(ADDON_INFO_FILE, addonJarFile)); + return; + } + + if (LOADED_ADDONS.containsKey(addonInfo.getId())) return; + + loadAddon(addonJarFile, addonInfo); + } catch (IOException | AddonException e) { + Logger.global.logError("Failed to load addon '%s'".formatted(addonJarFile), e); + } + } + + public synchronized static void loadAddon(Path jarFile, AddonInfo addonInfo) throws AddonException { + Logger.global.logInfo("Loading BlueMap Addon: %s (%s)".formatted(addonInfo.getId(), jarFile)); + + if (LOADED_ADDONS.containsKey(addonInfo.getId())) + throw new AddonException("Addon with id '%s' is already loaded".formatted(addonInfo.getId())); + + try { + ClassLoader addonClassLoader = BlueMap.class.getClassLoader(); + Class entrypointClass; + + // try to find entrypoint class and load jar with new classloader if needed + try { + entrypointClass = BlueMap.class.getClassLoader().loadClass(addonInfo.getEntrypoint()); + } catch (ClassNotFoundException e) { + addonClassLoader = new URLClassLoader( + new URL[]{ jarFile.toUri().toURL() }, + BlueMap.class.getClassLoader() + ); + entrypointClass = addonClassLoader.loadClass(addonInfo.getEntrypoint()); + } + + // create addon instance + Object instance = entrypointClass.getConstructor().newInstance(); + LoadedAddon addon = new LoadedAddon( + addonInfo, + addonClassLoader, + instance + ); + LOADED_ADDONS.put(addonInfo.getId(), addon); + + // run addon + if (instance instanceof Runnable runnable) + runnable.run(); + + } catch (Exception e) { + throw new AddonException("Failed to load addon '%s'".formatted(jarFile), e); + } + } + + public static @Nullable AddonInfo loadAddonInfo(Path addonJarFile) throws IOException, AddonException { + try (FileSystem fileSystem = FileSystems.newFileSystem(addonJarFile, (ClassLoader) null)) { + for (Path root : fileSystem.getRootDirectories()) { + Path addonInfoFile = root.resolve(ADDON_INFO_FILE); + if (!Files.exists(addonInfoFile)) continue; + + try (Reader reader = Files.newBufferedReader(addonInfoFile, StandardCharsets.UTF_8)) { + AddonInfo addonInfo = GSON.fromJson(reader, AddonInfo.class); + + if (addonInfo.getId() == null) + throw new AddonException("'id' is missing"); + + if (addonInfo.getEntrypoint() == null) + throw new AddonException("'entrypoint' is missing"); + + return addonInfo; + } + } + } + + return null; + } + +} diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/LoadedAddon.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/LoadedAddon.java new file mode 100644 index 000000000..a3b6598a5 --- /dev/null +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/LoadedAddon.java @@ -0,0 +1,7 @@ +package de.bluecolored.bluemap.common.addons; + +public record LoadedAddon ( + AddonInfo addonInfo, + ClassLoader classLoader, + Object instance +) {} diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/BlueMapAPIImpl.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/BlueMapAPIImpl.java index b544d4c83..2652324a6 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/BlueMapAPIImpl.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/BlueMapAPIImpl.java @@ -29,12 +29,14 @@ import de.bluecolored.bluemap.api.BlueMapAPI; import de.bluecolored.bluemap.api.BlueMapMap; import de.bluecolored.bluemap.api.BlueMapWorld; +import de.bluecolored.bluemap.common.BlueMapService; import de.bluecolored.bluemap.common.plugin.Plugin; import de.bluecolored.bluemap.common.serverinterface.ServerWorld; import de.bluecolored.bluemap.core.BlueMap; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.map.BmMap; import de.bluecolored.bluemap.core.world.World; +import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Map; @@ -43,12 +45,28 @@ public class BlueMapAPIImpl extends BlueMapAPI { - private final Plugin plugin; + private final BlueMapService blueMapService; + private final @Nullable Plugin plugin; + + private final WebAppImpl webAppImpl; + private final @Nullable RenderManagerImpl renderManagerImpl; + private final @Nullable PluginImpl pluginImpl; + private final LoadingCache> worldCache; private final LoadingCache> mapCache; public BlueMapAPIImpl(Plugin plugin) { + this(plugin.getBlueMap(), plugin); + } + + public BlueMapAPIImpl(BlueMapService blueMapService, @Nullable Plugin plugin) { + this.blueMapService = blueMapService; this.plugin = plugin; + + this.renderManagerImpl = plugin != null ? new RenderManagerImpl(this, plugin) : null; + this.webAppImpl = new WebAppImpl(blueMapService, plugin); + this.pluginImpl = plugin != null ? new PluginImpl(plugin) : null; + this.worldCache = Caffeine.newBuilder() .executor(BlueMap.THREAD_POOL) .weakKeys() @@ -59,24 +77,9 @@ public BlueMapAPIImpl(Plugin plugin) { .build(this::getMapUncached); } - @Override - public RenderManagerImpl getRenderManager() { - return new RenderManagerImpl(this, plugin); - } - - @Override - public WebAppImpl getWebApp() { - return new WebAppImpl(plugin); - } - - @Override - public de.bluecolored.bluemap.api.plugin.Plugin getPlugin() { - return new PluginImpl(plugin); - } - @Override public Collection getMaps() { - Map maps = plugin.getBlueMap().getMaps(); + Map maps = blueMapService.getMaps(); return maps.keySet().stream() .map(this::getMap) .filter(Optional::isPresent) @@ -86,7 +89,7 @@ public Collection getMaps() { @Override public Collection getWorlds() { - Map worlds = plugin.getBlueMap().getWorlds(); + Map worlds = blueMapService.getWorlds(); return worlds.keySet().stream() .map(this::getWorld) .filter(Optional::isPresent) @@ -102,21 +105,24 @@ public Optional getWorld(Object world) { public Optional getWorldUncached(Object world) { if (world instanceof String) { - var coreWorld = plugin.getBlueMap().getWorlds().get(world); + var coreWorld = blueMapService.getWorlds().get(world); if (coreWorld != null) world = coreWorld; } if (world instanceof World coreWorld) { - return Optional.of(new BlueMapWorldImpl(plugin, coreWorld)); + return Optional.of(new BlueMapWorldImpl(coreWorld, blueMapService, plugin)); } + if (plugin == null) return Optional.empty(); + ServerWorld serverWorld = plugin.getServerInterface().getServerWorld(world).orElse(null); if (serverWorld == null) return Optional.empty(); World coreWorld = plugin.getWorld(serverWorld); if (coreWorld == null) return Optional.empty(); - return Optional.of(new BlueMapWorldImpl(plugin, coreWorld)); + return Optional.of(new BlueMapWorldImpl(coreWorld, blueMapService, plugin)); + } @Override @@ -125,7 +131,7 @@ public Optional getMap(String id) { } public Optional getMapUncached(String id) { - var maps = plugin.getBlueMap().getMaps(); + var maps = blueMapService.getMaps(); var map = maps.get(id); if (map == null) return Optional.empty(); @@ -133,7 +139,7 @@ public Optional getMapUncached(String id) { var world = getWorld(map.getWorld()).orElse(null); if (world == null) return Optional.empty(); - return Optional.of(new BlueMapMapImpl(plugin, map, (BlueMapWorldImpl) world)); + return Optional.of(new BlueMapMapImpl(map, (BlueMapWorldImpl) world, plugin)); } @Override @@ -141,6 +147,23 @@ public String getBlueMapVersion() { return BlueMap.VERSION; } + @Override + public WebAppImpl getWebApp() { + return webAppImpl; + } + + @Override + public RenderManagerImpl getRenderManager() { + if (renderManagerImpl == null) throw new UnsupportedOperationException("RenderManager API is not supported on this platform"); + return renderManagerImpl; + } + + @Override + public de.bluecolored.bluemap.api.plugin.Plugin getPlugin() { + if (pluginImpl == null) throw new UnsupportedOperationException("Plugin API is not supported on this platform"); + return pluginImpl; + } + public void register() { try { BlueMapAPI.registerInstance(this); @@ -157,4 +180,26 @@ public void unregister() { } } + /** + * Easy-access method for addons depending on BlueMapCommon:
+ *
+     *     BlueMapService bluemap = ((BlueMapAPIImpl) blueMapAPI).blueMapService();
+     * 
+ */ + @SuppressWarnings("unused") + public BlueMapService blueMapService() { + return blueMapService; + } + + /** + * Easy-access method for addons depending on BlueMapCommon:
+ *
+     *     Plugin plugin = ((BlueMapAPIImpl) blueMapAPI).plugin();
+     * 
+ */ + @SuppressWarnings("unused") + public @Nullable Plugin plugin() { + return plugin; + } + } diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/BlueMapMapImpl.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/BlueMapMapImpl.java index 027cfc8df..199a57f07 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/BlueMapMapImpl.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/BlueMapMapImpl.java @@ -25,16 +25,16 @@ package de.bluecolored.bluemap.common.api; import com.flowpowered.math.vector.Vector2i; +import de.bluecolored.bluemap.api.AssetStorage; import de.bluecolored.bluemap.api.BlueMapMap; import de.bluecolored.bluemap.api.BlueMapWorld; -import de.bluecolored.bluemap.api.AssetStorage; import de.bluecolored.bluemap.api.markers.MarkerSet; import de.bluecolored.bluemap.common.plugin.Plugin; import de.bluecolored.bluemap.common.rendermanager.MapUpdateTask; import de.bluecolored.bluemap.common.rendermanager.WorldRegionRenderTask; import de.bluecolored.bluemap.core.map.BmMap; +import org.jetbrains.annotations.Nullable; -import java.io.IOException; import java.lang.ref.WeakReference; import java.util.Map; import java.util.Objects; @@ -42,27 +42,16 @@ public class BlueMapMapImpl implements BlueMapMap { - private final WeakReference plugin; + private final String mapId; private final WeakReference map; private final BlueMapWorldImpl world; - private final String mapId; + private final WeakReference plugin; - public BlueMapMapImpl(Plugin plugin, BmMap map) throws IOException { - this.plugin = new WeakReference<>(plugin); - this.map = new WeakReference<>(map); - this.world = new BlueMapWorldImpl(plugin, map.getWorld()); + public BlueMapMapImpl(BmMap map, BlueMapWorldImpl world, @Nullable Plugin plugin) { this.mapId = map.getId(); - } - - public BlueMapMapImpl(Plugin plugin, BmMap map, BlueMapWorldImpl world) { - this.plugin = new WeakReference<>(plugin); this.map = new WeakReference<>(map); this.world = world; - this.mapId = map.getId(); - } - - public BmMap getBmMap() { - return unpack(map); + this.plugin = new WeakReference<>(plugin); } @Override @@ -122,7 +111,9 @@ public synchronized void setFrozen(boolean frozen) { } private synchronized void unfreeze() { - Plugin plugin = unpack(this.plugin); + Plugin plugin = this.plugin.get(); + if (plugin == null) return; // fail silently: not supported on non-plugin platforms + BmMap map = unpack(this.map); plugin.startWatchingMap(map); plugin.getPluginState().getMapState(map).setUpdateEnabled(true); @@ -130,7 +121,9 @@ private synchronized void unfreeze() { } private synchronized void freeze() { - Plugin plugin = unpack(this.plugin); + Plugin plugin = this.plugin.get(); + if (plugin == null) return; // fail silently: not supported on non-plugin platforms + BmMap map = unpack(this.map); plugin.stopWatchingMap(map); plugin.getPluginState().getMapState(map).setUpdateEnabled(false); @@ -147,7 +140,10 @@ private synchronized void freeze() { @Override public boolean isFrozen() { - return !unpack(plugin).getPluginState().getMapState(unpack(map)).isUpdateEnabled(); + Plugin plugin = this.plugin.get(); + if (plugin == null) return false; // fail silently: not supported on non-plugin platforms + + return !plugin.getPluginState().getMapState(unpack(map)).isUpdateEnabled(); } @Override @@ -169,4 +165,14 @@ private T unpack(WeakReference ref) { return Objects.requireNonNull(ref.get(), "Reference lost to delegate object. Most likely BlueMap got reloaded and this instance is no longer valid."); } + /** + * Easy-access method for addons depending on BlueMapCore:
+ *
+     *     BmMap map = ((BlueMapMapImpl) blueMapMap).map();
+     * 
+ */ + public BmMap map() { + return unpack(map); + } + } diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/BlueMapWorldImpl.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/BlueMapWorldImpl.java index 492936bc3..7186f8acc 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/BlueMapWorldImpl.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/BlueMapWorldImpl.java @@ -26,9 +26,11 @@ import de.bluecolored.bluemap.api.BlueMapMap; import de.bluecolored.bluemap.api.BlueMapWorld; +import de.bluecolored.bluemap.common.BlueMapService; import de.bluecolored.bluemap.common.plugin.Plugin; import de.bluecolored.bluemap.core.world.World; import de.bluecolored.bluemap.core.world.mca.MCAWorld; +import org.jetbrains.annotations.Nullable; import java.lang.ref.WeakReference; import java.nio.file.Path; @@ -39,17 +41,15 @@ public class BlueMapWorldImpl implements BlueMapWorld { private final String id; - private final WeakReference plugin; private final WeakReference world; + private final WeakReference blueMapService; + private final WeakReference plugin; - public BlueMapWorldImpl(Plugin plugin, World world) { + public BlueMapWorldImpl(World world, BlueMapService blueMapService, @Nullable Plugin plugin) { this.id = world.getId(); - this.plugin = new WeakReference<>(plugin); this.world = new WeakReference<>(world); - } - - public World getWorld() { - return unpack(world); + this.blueMapService = new WeakReference<>(blueMapService); + this.plugin = new WeakReference<>(plugin); } @Override @@ -70,11 +70,10 @@ public Path getSaveFolder() { @Override public Collection getMaps() { - Plugin plugin = unpack(this.plugin); World world = unpack(this.world); - return plugin.getBlueMap().getMaps().values().stream() + return unpack(blueMapService).getMaps().values().stream() .filter(map -> map.getWorld().equals(world)) - .map(map -> new BlueMapMapImpl(plugin, map, this)) + .map(map -> new BlueMapMapImpl(map, this, plugin.get())) .collect(Collectors.toUnmodifiableSet()); } @@ -97,4 +96,14 @@ private T unpack(WeakReference ref) { return Objects.requireNonNull(ref.get(), "Reference lost to delegate object. Most likely BlueMap got reloaded and this instance is no longer valid."); } + /** + * Easy-access method for addons depending on BlueMapCore:
+ *
+     *     World world = ((BlueMapWorldImpl) blueMapWorld).world();
+     * 
+ */ + public World world() { + return unpack(world); + } + } diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/RenderManagerImpl.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/RenderManagerImpl.java index de203f28a..bc104e626 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/RenderManagerImpl.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/RenderManagerImpl.java @@ -48,19 +48,19 @@ public RenderManagerImpl(BlueMapAPIImpl api, Plugin plugin) { @Override public boolean scheduleMapUpdateTask(BlueMapMap map, boolean force) { BlueMapMapImpl cmap = castMap(map); - return renderManager.scheduleRenderTask(new MapUpdateTask(cmap.getBmMap(), s -> force)); + return renderManager.scheduleRenderTask(new MapUpdateTask(cmap.map(), s -> force)); } @Override public boolean scheduleMapUpdateTask(BlueMapMap map, Collection regions, boolean force) { BlueMapMapImpl cmap = castMap(map); - return renderManager.scheduleRenderTask(new MapUpdateTask(cmap.getBmMap(), regions, s -> force)); + return renderManager.scheduleRenderTask(new MapUpdateTask(cmap.map(), regions, s -> force)); } @Override public boolean scheduleMapPurgeTask(BlueMapMap map) { BlueMapMapImpl cmap = castMap(map); - return renderManager.scheduleRenderTask(new MapPurgeTask(cmap.getBmMap())); + return renderManager.scheduleRenderTask(new MapPurgeTask(cmap.map())); } @Override diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/WebAppImpl.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/WebAppImpl.java index 64af5bdac..9e6bde030 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/WebAppImpl.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/WebAppImpl.java @@ -25,35 +25,47 @@ package de.bluecolored.bluemap.common.api; import de.bluecolored.bluemap.api.WebApp; +import de.bluecolored.bluemap.common.BlueMapService; import de.bluecolored.bluemap.common.plugin.Plugin; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.util.FileHelper; +import org.jetbrains.annotations.Nullable; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; +import java.util.*; import java.util.stream.Stream; public class WebAppImpl implements WebApp { - private final Plugin plugin; + private final BlueMapService blueMapService; + private final @Nullable Plugin plugin; + + private final Timer timer = new Timer(); + private @Nullable TimerTask scheduledWebAppSettingsUpdate; + + public WebAppImpl(BlueMapService blueMapService, @Nullable Plugin plugin) { + this.blueMapService = blueMapService; + this.plugin = plugin; + } public WebAppImpl(Plugin plugin) { + this.blueMapService = plugin.getBlueMap(); this.plugin = plugin; } @Override public Path getWebRoot() { - return plugin.getBlueMap().getConfig().getWebappConfig().getWebroot(); + return blueMapService.getConfig().getWebappConfig().getWebroot(); } @Override public void setPlayerVisibility(UUID player, boolean visible) { + if (plugin == null) return; // fail silently: not supported on non-plugin platforms + if (visible) { plugin.getPluginState().removeHiddenPlayer(player); } else { @@ -63,19 +75,48 @@ public void setPlayerVisibility(UUID player, boolean visible) { @Override public boolean getPlayerVisibility(UUID player) { + if (plugin == null) return false; // fail silently: not supported on non-plugin platforms + return !plugin.getPluginState().isPlayerHidden(player); } @Override - public void registerScript(String url) { + public synchronized void registerScript(String url) { Logger.global.logDebug("Registering script from API: " + url); - plugin.getBlueMap().getWebFilesManager().getScripts().add(url); + blueMapService.getWebFilesManager().getScripts().add(url); + scheduleUpdateWebAppSettings(); } @Override - public void registerStyle(String url) { + public synchronized void registerStyle(String url) { Logger.global.logDebug("Registering style from API: " + url); - plugin.getBlueMap().getWebFilesManager().getStyles().add(url); + blueMapService.getWebFilesManager().getStyles().add(url); + scheduleUpdateWebAppSettings(); + } + + /** + * Save webapp-settings after a short delay, if no other save is already scheduled. + * (to bulk-save changes in case there is a lot of scripts being registered at once) + */ + private synchronized void scheduleUpdateWebAppSettings() { + if (!blueMapService.getConfig().getWebappConfig().isEnabled()) return; + if (scheduledWebAppSettingsUpdate != null) return; + + timer.schedule(new TimerTask() { + @Override + public void run() { + synchronized (WebAppImpl.this) { + try { + if (blueMapService.getConfig().getWebappConfig().isEnabled()) + blueMapService.getWebFilesManager().saveSettings(); + } catch (IOException ex) { + Logger.global.logError("Failed to update webapp settings", ex); + } finally { + scheduledWebAppSettingsUpdate = null; + } + } + } + }, 1000); } @Override diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java index ba5aeb5ef..36178dd4c 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java @@ -28,6 +28,7 @@ import de.bluecolored.bluemap.common.BlueMapService; import de.bluecolored.bluemap.common.InterruptableReentrantLock; import de.bluecolored.bluemap.common.MissingResourcesException; +import de.bluecolored.bluemap.common.addons.AddonManager; import de.bluecolored.bluemap.common.api.BlueMapAPIImpl; import de.bluecolored.bluemap.common.config.*; import de.bluecolored.bluemap.common.live.LivePlayersDataSupplier; @@ -50,6 +51,8 @@ import de.bluecolored.bluemap.core.util.Tristate; import de.bluecolored.bluemap.core.world.World; import de.bluecolored.bluemap.core.world.mca.MCAWorld; +import lombok.AccessLevel; +import lombok.Getter; import org.jetbrains.annotations.Nullable; import org.spongepowered.configurate.gson.GsonConfigurationLoader; import org.spongepowered.configurate.serialize.SerializationException; @@ -61,6 +64,7 @@ import java.net.BindException; import java.net.InetSocketAddress; import java.net.UnknownHostException; +import java.nio.file.Files; import java.nio.file.Path; import java.time.Instant; import java.time.ZoneId; @@ -70,6 +74,7 @@ import java.util.function.Predicate; import java.util.regex.Pattern; +@Getter public class Plugin implements ServerEventListener { public static final String PLUGIN_ID = "bluemap"; @@ -77,25 +82,23 @@ public class Plugin implements ServerEventListener { private static final String DEBUG_FILE_LOG_NAME = "file-debug-log"; + @Getter(AccessLevel.NONE) private final InterruptableReentrantLock loadingLock = new InterruptableReentrantLock(); private final String implementationType; private final Server serverInterface; private BlueMapService blueMap; - private PluginState pluginState; - private RenderManager renderManager; + private BlueMapAPIImpl api; + private HttpServer webServer; + private RoutingRequestHandler webRequestHandler; private Logger webLogger; - private BlueMapAPIImpl api; - private Timer daemonTimer; - private Map mapUpdateServices; - private PlayerSkinUpdater skinUpdater; private boolean loaded = false; @@ -119,6 +122,12 @@ private void load(@Nullable ResourcePack preloadedResourcePack) throws IOExcepti if (loaded) return; unload(); //ensure nothing is left running (from a failed load or something) + //load addons + Path addonsFolder = serverInterface.getConfigFolder().resolve("addons"); + Files.createDirectories(addonsFolder); + AddonManager.tryLoadAddons(addonsFolder, true); + serverInterface.getModsFolder().ifPresent(AddonManager::tryLoadAddons); + //load configs BlueMapConfigManager configManager = BlueMapConfigManager.builder() .minecraftVersion(serverInterface.getMinecraftVersion()) @@ -184,10 +193,10 @@ private void load(@Nullable ResourcePack preloadedResourcePack) throws IOExcepti Path webroot = webserverConfig.getWebroot(); FileHelper.createDirectories(webroot); - RoutingRequestHandler routingRequestHandler = new RoutingRequestHandler(); + this.webRequestHandler = new RoutingRequestHandler(); // default route - routingRequestHandler.register(".*", new FileRequestHandler(webroot)); + webRequestHandler.register(".*", new FileRequestHandler(webroot)); // map route for (var mapConfigEntry : configManager.getMapConfigs().entrySet()) { @@ -203,7 +212,7 @@ private void load(@Nullable ResourcePack preloadedResourcePack) throws IOExcepti mapRequestHandler = new MapRequestHandler(storage.map(id)); } - routingRequestHandler.register( + webRequestHandler.register( "maps/" + Pattern.quote(id) + "/(.*)", "$1", new BlueMapResponseModifier(mapRequestHandler) @@ -223,7 +232,7 @@ private void load(@Nullable ResourcePack preloadedResourcePack) throws IOExcepti try { webServer = new HttpServer(new LoggingRequestHandler( - routingRequestHandler, + webRequestHandler, webserverConfig.getLog().getFormat(), webLogger )); @@ -361,10 +370,6 @@ public void run() { this.api = new BlueMapAPIImpl(this); this.api.register(); - //save webapp settings again (for api-registered scripts and styles) - if (webappConfig.isEnabled()) - this.getBlueMap().getWebFilesManager().saveSettings(); - //start render-manager if (pluginState.isRenderThreadsEnabled()) { checkPausedByPlayerCount(); // <- this also starts the render-manager if it should start @@ -638,38 +643,6 @@ public boolean checkPausedByPlayerCount() { return getBlueMap().getWorlds().get(id); } - public Server getServerInterface() { - return serverInterface; - } - - public BlueMapService getBlueMap() { - return blueMap; - } - - public PluginState getPluginState() { - return pluginState; - } - - public RenderManager getRenderManager() { - return renderManager; - } - - public HttpServer getWebServer() { - return webServer; - } - - public boolean isLoaded() { - return loaded; - } - - public String getImplementationType() { - return implementationType; - } - - public PlayerSkinUpdater getSkinUpdater() { - return skinUpdater; - } - private void initFileWatcherTasks() { var maps = blueMap.getMaps(); if (maps != null) { diff --git a/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java b/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java index 7872b067f..2fa38758d 100644 --- a/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java +++ b/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java @@ -27,6 +27,8 @@ import de.bluecolored.bluemap.common.BlueMapConfiguration; import de.bluecolored.bluemap.common.BlueMapService; import de.bluecolored.bluemap.common.MissingResourcesException; +import de.bluecolored.bluemap.common.addons.AddonManager; +import de.bluecolored.bluemap.common.api.BlueMapAPIImpl; import de.bluecolored.bluemap.common.config.BlueMapConfigManager; import de.bluecolored.bluemap.common.config.ConfigurationException; import de.bluecolored.bluemap.common.config.CoreConfig; @@ -113,6 +115,10 @@ public void renderMaps(BlueMapService blueMap, boolean watch, boolean forceRende totalRegions += updateTask.getRegions().size(); } + // enable api + BlueMapAPIImpl api = new BlueMapAPIImpl(blueMap, null); + api.register(); + Logger.global.logInfo("Start updating " + maps.size() + " maps (" + totalRegions + " regions, ~" + totalRegions * 1024L + " chunks)..."); // start rendering @@ -150,6 +156,8 @@ public void run() { Runnable shutdown = () -> { Logger.global.logInfo("Stopping..."); + api.unregister(); + updateInfoTask.cancel(); saveTask.cancel(); @@ -301,6 +309,12 @@ public static void main(String[] args) { cli.minecraftVersion = cmd.getOptionValue("v"); } + // load addons + Path addonsFolder = cli.configFolder.resolve("addons"); + Files.createDirectories(addonsFolder); + AddonManager.tryLoadAddons(cli.configFolder.resolve("addons"), true); + + // load configs BlueMapConfigManager configs = BlueMapConfigManager.builder() .minecraftVersion(cli.minecraftVersion) .configRoot(cli.configFolder) From 51185f5884cdb113a5bbbacdfb769dbdad788a73 Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Mon, 27 May 2024 23:11:02 +0200 Subject: [PATCH 25/38] Apply spotless fixes --- .../bluemap/common/addons/AddonException.java | 24 +++++++++++++++++++ .../bluemap/common/addons/AddonInfo.java | 24 +++++++++++++++++++ .../bluemap/common/addons/AddonManager.java | 24 +++++++++++++++++++ .../bluemap/common/addons/LoadedAddon.java | 24 +++++++++++++++++++ 4 files changed, 96 insertions(+) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonException.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonException.java index 136c44555..cbb84f4b6 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonException.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonException.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.common.addons; import lombok.experimental.StandardException; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonInfo.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonInfo.java index b96f75107..8ac0ffdf2 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonInfo.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonInfo.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.common.addons; import lombok.Getter; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonManager.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonManager.java index 0ff869f37..5a8488f38 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonManager.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonManager.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.common.addons; import com.google.gson.Gson; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/LoadedAddon.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/LoadedAddon.java index a3b6598a5..0d5db41b5 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/LoadedAddon.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/LoadedAddon.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.common.addons; public record LoadedAddon ( From 52d1e59108be24f0470cd807e2919f3edba8e4a3 Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Mon, 27 May 2024 23:46:32 +0200 Subject: [PATCH 26/38] Rename AddonManager to Addons --- .../common/addons/{AddonManager.java => Addons.java} | 6 +++--- .../java/de/bluecolored/bluemap/common/plugin/Plugin.java | 6 +++--- .../main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) rename BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/{AddonManager.java => Addons.java} (97%) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonManager.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/Addons.java similarity index 97% rename from BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonManager.java rename to BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/Addons.java index 5a8488f38..65f8decf9 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/AddonManager.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/Addons.java @@ -45,12 +45,12 @@ import static de.bluecolored.bluemap.common.addons.AddonInfo.ADDON_INFO_FILE; -public final class AddonManager { +public final class Addons { private static final Gson GSON = new GsonBuilder().create(); private static final Map LOADED_ADDONS = new ConcurrentHashMap<>(); - private AddonManager() { + private Addons() { throw new UnsupportedOperationException("Utility class"); } @@ -63,7 +63,7 @@ public static void tryLoadAddons(Path root, boolean expectOnlyAddons) { files .filter(Files::isRegularFile) .filter(f -> f.getFileName().toString().endsWith(".jar")) - .forEach(expectOnlyAddons ? AddonManager::tryLoadAddon : AddonManager::tryLoadJar); + .forEach(expectOnlyAddons ? Addons::tryLoadAddon : Addons::tryLoadJar); } catch (IOException e) { Logger.global.logError("Failed to load addons from '%s'".formatted(root), e); } diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java index 36178dd4c..4a7fba043 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java @@ -28,7 +28,7 @@ import de.bluecolored.bluemap.common.BlueMapService; import de.bluecolored.bluemap.common.InterruptableReentrantLock; import de.bluecolored.bluemap.common.MissingResourcesException; -import de.bluecolored.bluemap.common.addons.AddonManager; +import de.bluecolored.bluemap.common.addons.Addons; import de.bluecolored.bluemap.common.api.BlueMapAPIImpl; import de.bluecolored.bluemap.common.config.*; import de.bluecolored.bluemap.common.live.LivePlayersDataSupplier; @@ -125,8 +125,8 @@ private void load(@Nullable ResourcePack preloadedResourcePack) throws IOExcepti //load addons Path addonsFolder = serverInterface.getConfigFolder().resolve("addons"); Files.createDirectories(addonsFolder); - AddonManager.tryLoadAddons(addonsFolder, true); - serverInterface.getModsFolder().ifPresent(AddonManager::tryLoadAddons); + Addons.tryLoadAddons(addonsFolder, true); + serverInterface.getModsFolder().ifPresent(Addons::tryLoadAddons); //load configs BlueMapConfigManager configManager = BlueMapConfigManager.builder() diff --git a/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java b/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java index 2fa38758d..918c0909a 100644 --- a/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java +++ b/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java @@ -27,7 +27,7 @@ import de.bluecolored.bluemap.common.BlueMapConfiguration; import de.bluecolored.bluemap.common.BlueMapService; import de.bluecolored.bluemap.common.MissingResourcesException; -import de.bluecolored.bluemap.common.addons.AddonManager; +import de.bluecolored.bluemap.common.addons.Addons; import de.bluecolored.bluemap.common.api.BlueMapAPIImpl; import de.bluecolored.bluemap.common.config.BlueMapConfigManager; import de.bluecolored.bluemap.common.config.ConfigurationException; @@ -312,7 +312,7 @@ public static void main(String[] args) { // load addons Path addonsFolder = cli.configFolder.resolve("addons"); Files.createDirectories(addonsFolder); - AddonManager.tryLoadAddons(cli.configFolder.resolve("addons"), true); + Addons.tryLoadAddons(cli.configFolder.resolve("addons"), true); // load configs BlueMapConfigManager configs = BlueMapConfigManager.builder() From 02d9fc1405539833c2d446ac2af16c91450ce07d Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Mon, 27 May 2024 23:48:49 +0200 Subject: [PATCH 27/38] Use local variable --- .../main/java/de/bluecolored/bluemap/common/addons/Addons.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/Addons.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/Addons.java index 65f8decf9..6d537544b 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/Addons.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/Addons.java @@ -110,7 +110,7 @@ public synchronized static void loadAddon(Path jarFile, AddonInfo addonInfo) thr // try to find entrypoint class and load jar with new classloader if needed try { - entrypointClass = BlueMap.class.getClassLoader().loadClass(addonInfo.getEntrypoint()); + entrypointClass = addonClassLoader.loadClass(addonInfo.getEntrypoint()); } catch (ClassNotFoundException e) { addonClassLoader = new URLClassLoader( new URL[]{ jarFile.toUri().toURL() }, From b1c75aa44aa928701d29160a30c46483f3f94ab5 Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Tue, 28 May 2024 01:57:35 +0200 Subject: [PATCH 28/38] Implement a Registry for BlockEntities --- .../core/world/block/entity/BlockEntity.java | 115 +++++------------- .../world/block/entity/BlockEntityLoader.java | 9 ++ .../world/block/entity/BlockEntityType.java | 37 ++++++ .../bluemap/core/world/mca/MCAUtil.java | 2 +- .../core/world/mca/chunk/Chunk_1_13.java | 19 +-- .../core/world/mca/chunk/Chunk_1_16.java | 19 +-- .../core/world/mca/chunk/Chunk_1_18.java | 19 +-- .../core/world/mca/chunk/MCAChunk.java | 2 + 8 files changed, 115 insertions(+), 107 deletions(-) create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntityLoader.java create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntityType.java diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntity.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntity.java index 05757eb4c..de36da57f 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntity.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntity.java @@ -25,113 +25,58 @@ package de.bluecolored.bluemap.core.world.block.entity; import com.google.gson.reflect.TypeToken; -import de.bluecolored.bluemap.core.logger.Logger; +import de.bluecolored.bluemap.core.util.Key; import de.bluecolored.bluenbt.BlueNBT; import de.bluecolored.bluenbt.NBTDeserializer; import de.bluecolored.bluenbt.NBTReader; import de.bluecolored.bluenbt.TypeDeserializer; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; +import org.jetbrains.annotations.Nullable; import java.io.IOException; -import java.lang.reflect.Constructor; -import java.util.List; import java.util.Map; -import java.util.Objects; -import java.util.StringJoiner; -import java.util.function.Function; -import java.util.stream.Collectors; +@Getter +@EqualsAndHashCode +@ToString @NBTDeserializer(BlockEntity.BlockEntityDeserializer.class) -public class BlockEntity { - private static final BlueNBT BLUENBT = new BlueNBT(); - - @FunctionalInterface - private interface BlockEntityInitializer { - BlockEntity create(Map data); - } - - @SuppressWarnings("StaticInitializerReferencesSubClass") - private static final Map ID_MAPPING = Map.of( - "minecraft:sign", SignBlockEntity::new, - "minecraft:skull", SkullBlockEntity::new, - "minecraft:banner", BannerBlockEntity::new - ); +public abstract class BlockEntity { protected final String id; protected final int x, y, z; protected final boolean keepPacked; - protected BlockEntity(Map data) { - this.id = (String) data.get("id"); - this.x = (int) data.get("x"); - this.y = (int) data.get("y"); - this.z = (int) data.get("z"); - this.keepPacked = (byte) data.getOrDefault("keepPacked", (byte) 0) == 1; - } - - public String getId() { - return id; - } - - public int getX() { - return x; - } - - public int getY() { - return y; - } - - public int getZ() { - return z; + protected BlockEntity(Map raw) { + this.id = (String) raw.get("id"); + this.x = (int) raw.getOrDefault("x", 0); + this.y = (int) raw.getOrDefault("y", 0); + this.z = (int) raw.getOrDefault("z", 0); + this.keepPacked = (byte) raw.getOrDefault("keepPacked", (byte) 0) == 1; } - public boolean isKeepPacked() { - return keepPacked; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - BlockEntity that = (BlockEntity) o; - return x == that.x && y == that.y && z == that.z && keepPacked == that.keepPacked && Objects.equals(id, that.id); - } + @RequiredArgsConstructor + public static class BlockEntityDeserializer implements TypeDeserializer { - @Override - public int hashCode() { - return Objects.hash(id, x, y, z, keepPacked); - } + private final BlueNBT blueNBT; - @Override - public String toString() { - return "BlockEntity{" + - "id='" + id + '\'' + - ", x=" + x + - ", y=" + y + - ", z=" + z + - ", keepPacked=" + keepPacked + - '}'; - } - - public static class BlockEntityDeserializer implements TypeDeserializer { @Override - public BlockEntity read(NBTReader reader) throws IOException { - @SuppressWarnings("unchecked") Map data = - (Map) BLUENBT.read(reader, TypeToken.getParameterized(Map.class, String.class, Object.class)); - - String id = (String) data.get("id"); - if (id == null || id.isBlank()) { - return null; - } + @SuppressWarnings("unchecked") + public @Nullable BlockEntity read(NBTReader reader) throws IOException { + Map raw = (Map) blueNBT.read(reader, TypeToken.getParameterized(Map.class, String.class, Object.class)); - BlockEntityInitializer instance = ID_MAPPING.getOrDefault(id, BlockEntity::new); + String id = (String) raw.get("id"); + if (id == null) return null; - try { - return instance.create(data); - } catch (Exception e) { - Logger.global.logError("Failed to instantiate BlockEntity instance!", e); - } + Key typeKey = Key.parse(id, Key.MINECRAFT_NAMESPACE); + BlockEntityType type = BlockEntityType.REGISTRY.get(typeKey); + if (type == null) return null; - return null; + return type.load(raw); } + } + } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntityLoader.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntityLoader.java new file mode 100644 index 000000000..5ad10f22f --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntityLoader.java @@ -0,0 +1,9 @@ +package de.bluecolored.bluemap.core.world.block.entity; + +import java.util.Map; + +public interface BlockEntityLoader { + + BlockEntity load(Map raw); + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntityType.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntityType.java new file mode 100644 index 000000000..4ffbda625 --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntityType.java @@ -0,0 +1,37 @@ +package de.bluecolored.bluemap.core.world.block.entity; + +import de.bluecolored.bluemap.core.util.Key; +import de.bluecolored.bluemap.core.util.Keyed; +import de.bluecolored.bluemap.core.util.Registry; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Map; + +public interface BlockEntityType extends Keyed, BlockEntityLoader { + + BlockEntityType SIGN = new Impl(Key.minecraft("sign"), SignBlockEntity::new); + BlockEntityType SKULL = new Impl(Key.minecraft("skull"), SkullBlockEntity::new); + BlockEntityType BANNER = new Impl(Key.minecraft("banner"), BannerBlockEntity::new); + + Registry REGISTRY = new Registry<>( + SIGN, + SKULL, + BANNER + ); + + @RequiredArgsConstructor + class Impl implements BlockEntityType { + + @Getter + private final Key key; + private final BlockEntityLoader loader; + + @Override + public BlockEntity load(Map raw) { + return loader.load(raw); + } + + } + +} diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAUtil.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAUtil.java index f9e19e2da..8772f2e14 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAUtil.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAUtil.java @@ -41,7 +41,7 @@ public class MCAUtil { public static BlueNBT addCommonNbtAdapters(BlueNBT nbt) { nbt.register(TypeToken.get(BlockState.class), new BlockStateDeserializer()); nbt.register(TypeToken.get(Key.class), new KeyDeserializer()); - nbt.register(TypeToken.get(BlockEntity.class), new BlockEntity.BlockEntityDeserializer()); + nbt.register(TypeToken.get(BlockEntity.class), new BlockEntity.BlockEntityDeserializer(nbt)); return nbt; } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_13.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_13.java index 976952276..d0f5b6dc9 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_13.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_13.java @@ -26,10 +26,10 @@ import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.util.Key; -import de.bluecolored.bluemap.core.world.biome.Biome; import de.bluecolored.bluemap.core.world.BlockState; import de.bluecolored.bluemap.core.world.DimensionType; import de.bluecolored.bluemap.core.world.LightData; +import de.bluecolored.bluemap.core.world.biome.Biome; import de.bluecolored.bluemap.core.world.block.entity.BlockEntity; import de.bluecolored.bluemap.core.world.mca.MCAUtil; import de.bluecolored.bluemap.core.world.mca.MCAWorld; @@ -37,9 +37,8 @@ import lombok.Getter; import org.jetbrains.annotations.Nullable; -import java.util.List; +import java.util.HashMap; import java.util.Map; -import java.util.stream.Collectors; public class Chunk_1_13 extends MCAChunk { @@ -120,9 +119,15 @@ public Chunk_1_13(MCAWorld world, Data data) { this.sectionMax = 0; } - this.blockEntities = level.blockEntities.stream().collect(Collectors.toMap( - it -> (long) it.getY() << 8 | (it.getX() & 0xF) << 4 | it.getZ() & 0xF, it -> it - )); + // load block-entities + this.blockEntities = new HashMap<>(); + for (int i = 0; i < level.blockEntities.length; i++) { + BlockEntity be = level.blockEntities[i]; + if (be == null) continue; + + long hash = (long) be.getY() << 8 | (be.getX() & 0xF) << 4 | be.getZ() & 0xF; + blockEntities.put(hash, be); + } } @Override @@ -290,7 +295,7 @@ public static class Level { private HeightmapsData heightmaps = new HeightmapsData(); private SectionData @Nullable [] sections = null; private int[] biomes = EMPTY_INT_ARRAY; - @NBTName("TileEntities") private List blockEntities = List.of(); + @NBTName("TileEntities") private @Nullable BlockEntity [] blockEntities = EMPTY_BLOCK_ENTITIES_ARRAY; } @Getter diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_16.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_16.java index 6481d440d..afca54c07 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_16.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_16.java @@ -26,10 +26,10 @@ import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.util.Key; -import de.bluecolored.bluemap.core.world.biome.Biome; import de.bluecolored.bluemap.core.world.BlockState; import de.bluecolored.bluemap.core.world.DimensionType; import de.bluecolored.bluemap.core.world.LightData; +import de.bluecolored.bluemap.core.world.biome.Biome; import de.bluecolored.bluemap.core.world.block.entity.BlockEntity; import de.bluecolored.bluemap.core.world.mca.MCAUtil; import de.bluecolored.bluemap.core.world.mca.MCAWorld; @@ -38,9 +38,8 @@ import lombok.Getter; import org.jetbrains.annotations.Nullable; -import java.util.List; +import java.util.HashMap; import java.util.Map; -import java.util.stream.Collectors; public class Chunk_1_16 extends MCAChunk { @@ -119,9 +118,15 @@ public Chunk_1_16(MCAWorld world, Data data) { this.sectionMax = 0; } - this.blockEntities = level.blockEntities.stream().collect(Collectors.toMap( - it -> (long) it.getY() << 8 | (it.getX() & 0xF) << 4 | it.getZ() & 0xF, it -> it - )); + // load block-entities + this.blockEntities = new HashMap<>(); + for (int i = 0; i < level.blockEntities.length; i++) { + BlockEntity be = level.blockEntities[i]; + if (be == null) continue; + + long hash = (long) be.getY() << 8 | (be.getX() & 0xF) << 4 | be.getZ() & 0xF; + blockEntities.put(hash, be); + } } @Override @@ -277,7 +282,7 @@ public static class Level { private HeightmapsData heightmaps = new HeightmapsData(); private SectionData @Nullable [] sections = null; private int[] biomes = EMPTY_INT_ARRAY; - @NBTName("TileEntities") private List blockEntities = List.of(); + @NBTName("TileEntities") private @Nullable BlockEntity [] blockEntities = EMPTY_BLOCK_ENTITIES_ARRAY; } @Getter diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_18.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_18.java index 91c035ce9..de3e1bd56 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_18.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_18.java @@ -26,10 +26,10 @@ import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.util.Key; -import de.bluecolored.bluemap.core.world.biome.Biome; import de.bluecolored.bluemap.core.world.BlockState; import de.bluecolored.bluemap.core.world.DimensionType; import de.bluecolored.bluemap.core.world.LightData; +import de.bluecolored.bluemap.core.world.biome.Biome; import de.bluecolored.bluemap.core.world.block.entity.BlockEntity; import de.bluecolored.bluemap.core.world.mca.MCAUtil; import de.bluecolored.bluemap.core.world.mca.MCAWorld; @@ -38,9 +38,8 @@ import lombok.Getter; import org.jetbrains.annotations.Nullable; -import java.util.List; +import java.util.HashMap; import java.util.Map; -import java.util.stream.Collectors; public class Chunk_1_18 extends MCAChunk { @@ -116,9 +115,15 @@ public Chunk_1_18(MCAWorld world, Data data) { this.sectionMax = 0; } - this.blockEntities = data.blockEntities.stream().collect(Collectors.toMap( - it -> (long) it.getY() << 8 | (it.getX() & 0xF) << 4 | it.getZ() & 0xF, it -> it - )); + // load block-entities + this.blockEntities = new HashMap<>(); + for (int i = 0; i < data.blockEntities.length; i++) { + BlockEntity be = data.blockEntities[i]; + if (be == null) continue; + + long hash = (long) be.getY() << 8 | (be.getX() & 0xF) << 4 | be.getZ() & 0xF; + blockEntities.put(hash, be); + } } @Override @@ -285,7 +290,7 @@ public static class Data extends MCAChunk.Data { private long inhabitedTime = 0; private HeightmapsData heightmaps = new HeightmapsData(); private SectionData @Nullable [] sections = null; - @NBTName("block_entities") private List blockEntities = List.of(); + @NBTName("block_entities") private @Nullable BlockEntity [] blockEntities = EMPTY_BLOCK_ENTITIES_ARRAY; } @Getter diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/MCAChunk.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/MCAChunk.java index e3be9503a..627b0b4c0 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/MCAChunk.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/MCAChunk.java @@ -27,6 +27,7 @@ import de.bluecolored.bluemap.core.util.Key; import de.bluecolored.bluemap.core.world.BlockState; import de.bluecolored.bluemap.core.world.Chunk; +import de.bluecolored.bluemap.core.world.block.entity.BlockEntity; import de.bluecolored.bluemap.core.world.mca.MCAWorld; import lombok.Getter; import lombok.ToString; @@ -44,6 +45,7 @@ public abstract class MCAChunk implements Chunk { protected static final long[] EMPTY_LONG_ARRAY = new long[0]; protected static final Key[] EMPTY_KEY_ARRAY = new Key[0]; protected static final BlockState[] EMPTY_BLOCKSTATE_ARRAY = new BlockState[0]; + protected static final BlockEntity[] EMPTY_BLOCK_ENTITIES_ARRAY = new BlockEntity[0]; private final MCAWorld world; private final int dataVersion; From e04e46fa5fd175eac2e1cc52037c67acf9ab997c Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Tue, 28 May 2024 01:58:18 +0200 Subject: [PATCH 29/38] Spotless --- .../world/block/entity/BlockEntityLoader.java | 24 +++++++++++++++++++ .../world/block/entity/BlockEntityType.java | 24 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntityLoader.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntityLoader.java index 5ad10f22f..bf76ab4fe 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntityLoader.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntityLoader.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.block.entity; import java.util.Map; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntityType.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntityType.java index 4ffbda625..9ed9391b4 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntityType.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/block/entity/BlockEntityType.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.block.entity; import de.bluecolored.bluemap.core.util.Key; From 0cc0247930b4427e59e84882baae85e8d4232279 Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Tue, 28 May 2024 21:54:14 +0200 Subject: [PATCH 30/38] Remove apache.commons.io and apache.commons.lang libraries --- .../bluemap/common/BlueMapService.java | 3 +- .../bluemap/common/config/ConfigManager.java | 16 ++++-- .../common/plugin/commands/CommandHelper.java | 11 +++- .../common/web/FileRequestHandler.java | 48 ++-------------- .../common/web/MapStorageRequestHandler.java | 3 +- BlueMapCore/build.gradle.kts | 2 - .../resourcepack/blockstate/Multipart.java | 55 +++++++++---------- .../resourcepack/blockstate/Variants.java | 5 +- implementations/cli/build.gradle.kts | 18 ------ .../bluecolored/bluemap/cli/BlueMapCLI.java | 11 +++- implementations/fabric-1.18/build.gradle.kts | 2 - .../fabric-1.19.4/build.gradle.kts | 2 - implementations/fabric-1.20/build.gradle.kts | 2 - implementations/forge-1.18.1/build.gradle | 2 - implementations/forge-1.19.4/build.gradle | 2 - implementations/forge-1.20/build.gradle | 2 - implementations/neoforge-1.20.2/build.gradle | 2 - implementations/paper/build.gradle.kts | 2 - .../bluemap/bukkit/BukkitCommands.java | 3 +- implementations/spigot/build.gradle.kts | 2 - .../bluemap/bukkit/BukkitCommands.java | 3 +- implementations/sponge/build.gradle.kts | 2 - 22 files changed, 66 insertions(+), 132 deletions(-) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapService.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapService.java index 058931a0d..86aa3d4be 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapService.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapService.java @@ -47,7 +47,6 @@ import de.bluecolored.bluemap.core.util.Key; import de.bluecolored.bluemap.core.world.World; import de.bluecolored.bluemap.core.world.mca.MCAWorld; -import org.apache.commons.io.FileUtils; import org.jetbrains.annotations.Nullable; import org.spongepowered.configurate.ConfigurateException; import org.spongepowered.configurate.ConfigurationNode; @@ -399,7 +398,7 @@ private synchronized Deque getPackRoots(Iterable additionalRoots) th URL resourceExtensionsUrl = Objects.requireNonNull( Plugin.class.getResource("/de/bluecolored/bluemap/resourceExtensions.zip") ); - FileUtils.copyURLToFile(resourceExtensionsUrl, resourceExtensionsFile.toFile(), 10000, 10000); + FileHelper.copy(resourceExtensionsUrl, resourceExtensionsFile); } catch (IOException ex) { throw new ConfigurationException( "Failed to create resourceExtensions.zip!\n" + diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/ConfigManager.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/ConfigManager.java index d26bed29d..f3603dd75 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/ConfigManager.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/config/ConfigManager.java @@ -29,7 +29,6 @@ import de.bluecolored.bluemap.common.config.typeserializer.Vector2iTypeSerializer; import de.bluecolored.bluemap.core.BlueMap; import de.bluecolored.bluemap.core.util.Key; -import org.apache.commons.io.IOUtils; import org.spongepowered.configurate.ConfigurateException; import org.spongepowered.configurate.ConfigurationNode; import org.spongepowered.configurate.loader.AbstractConfigurationLoader; @@ -38,6 +37,8 @@ import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringWriter; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -73,10 +74,15 @@ public T loadConfig(Path file, Class type) throws ConfigurationException public ConfigTemplate loadConfigTemplate(String name) throws IOException { String resource = CONFIG_TEMPLATE_RESOURCE_PATH + name + ConfigLoader.DEFAULT.getFileSuffix(); - InputStream in = BlueMap.class.getResourceAsStream(resource); - if (in == null) throw new IOException("Resource not found: " + resource); - String configTemplate = IOUtils.toString(in, StandardCharsets.UTF_8); - return new ConfigTemplate(configTemplate); + try (InputStream in = BlueMap.class.getResourceAsStream(resource)) { + if (in == null) throw new IOException("Resource not found: " + resource); + + StringWriter writer = new StringWriter(); + InputStreamReader reader = new InputStreamReader(in, StandardCharsets.UTF_8); + reader.transferTo(writer); + + return new ConfigTemplate(writer.toString()); + } } public Path resolveConfigFile(String name) { diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/CommandHelper.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/CommandHelper.java index 27f4e50a5..f96521ed8 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/CommandHelper.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/CommandHelper.java @@ -30,12 +30,13 @@ import de.bluecolored.bluemap.common.plugin.text.TextFormat; import de.bluecolored.bluemap.common.rendermanager.RenderManager; import de.bluecolored.bluemap.common.rendermanager.RenderTask; -import org.apache.commons.lang3.time.DurationFormatUtils; import java.lang.ref.WeakReference; +import java.time.Duration; import java.time.Instant; import java.time.ZoneId; import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; import java.util.*; public class CommandHelper { @@ -96,7 +97,13 @@ public List createStatusMessage(){ long etaMs = renderer.estimateCurrentRenderTaskTimeRemaining(); if (etaMs > 0) { - lines.add(Text.of(TextColor.GRAY, "\u00A0\u00A0\u00A0ETA: ", TextColor.WHITE, DurationFormatUtils.formatDuration(etaMs, "HH:mm:ss"))); + Duration eta = Duration.of(etaMs, ChronoUnit.MILLIS); + String etaString = "%d:%02d:%02d".formatted( + eta.toHours(), + eta.toMinutesPart(), + eta.toSecondsPart() + ); + lines.add(Text.of(TextColor.GRAY, "\u00A0\u00A0\u00A0ETA: ", TextColor.WHITE, etaString)); } } } diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java index f7e583c6c..b8c3a9ddc 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java @@ -29,17 +29,15 @@ import lombok.Getter; import lombok.NonNull; import lombok.Setter; -import org.apache.commons.lang3.time.DateFormatUtils; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.Locale; -import java.util.TimeZone; +import java.time.Instant; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.util.concurrent.TimeUnit; @Getter @Setter @@ -114,11 +112,11 @@ private HttpResponse generateResponse(HttpRequest request) throws IOException { HttpHeader modHeader = request.getHeader("If-Modified-Since"); if (modHeader != null){ try { - long since = stringToTimestamp(modHeader.getValue()); + long since = Instant.from(DateTimeFormatter.RFC_1123_DATE_TIME.parse(modHeader.getValue())).toEpochMilli(); if (since + 1000 >= lastModified){ return new HttpResponse(HttpStatusCode.NOT_MODIFIED); } - } catch (IllegalArgumentException ignored){} + } catch (DateTimeParseException ignored){} } //check ETag @@ -136,7 +134,7 @@ private HttpResponse generateResponse(HttpRequest request) throws IOException { //create response HttpResponse response = new HttpResponse(HttpStatusCode.OK); response.addHeader("ETag", eTag); - if (lastModified > 0) response.addHeader("Last-Modified", timestampToString(lastModified)); + if (lastModified > 0) response.addHeader("Last-Modified", DateTimeFormatter.RFC_1123_DATE_TIME.format(Instant.ofEpochMilli(lastModified))); response.addHeader("Cache-Control", "public"); response.addHeader("Cache-Control", "max-age=" + TimeUnit.DAYS.toSeconds(1)); @@ -156,40 +154,6 @@ private HttpResponse generateResponse(HttpRequest request) throws IOException { } } - private static String timestampToString(long time){ - return DateFormatUtils.format(time, "EEE, dd MMM yyy HH:mm:ss 'GMT'", TimeZone.getTimeZone("GMT"), Locale.ENGLISH); - } - - private static long stringToTimestamp(String timeString) throws IllegalArgumentException { - try { - int day = Integer.parseInt(timeString.substring(5, 7)); - int month = switch (timeString.substring(8, 11)) { - case "Jan" -> Calendar.JANUARY; - case "Feb" -> Calendar.FEBRUARY; - case "Mar" -> Calendar.MARCH; - case "Apr" -> Calendar.APRIL; - case "May" -> Calendar.MAY; - case "Jun" -> Calendar.JUNE; - case "Jul" -> Calendar.JULY; - case "Aug" -> Calendar.AUGUST; - case "Sep" -> Calendar.SEPTEMBER; - case "Oct" -> Calendar.OCTOBER; - case "Nov" -> Calendar.NOVEMBER; - case "Dec" -> Calendar.DECEMBER; - default -> throw new IllegalArgumentException("Invalid timestamp format"); - }; - int year = Integer.parseInt(timeString.substring(12, 16)); - int hour = Integer.parseInt(timeString.substring(17, 19)); - int min = Integer.parseInt(timeString.substring(20, 22)); - int sec = Integer.parseInt(timeString.substring(23, 25)); - GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT")); - cal.set(year, month, day, hour, min, sec); - return cal.getTimeInMillis(); - } catch (NumberFormatException | IndexOutOfBoundsException e){ - throw new IllegalArgumentException(e); - } - } - private static String toContentType(String fileEnding) { return switch (fileEnding) { case "json" -> "application/json"; diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/MapStorageRequestHandler.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/MapStorageRequestHandler.java index 726dbe1a7..05b8870a0 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/MapStorageRequestHandler.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/MapStorageRequestHandler.java @@ -38,7 +38,6 @@ import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.Setter; -import org.apache.commons.io.IOUtils; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -132,7 +131,7 @@ private void writeToResponse(CompressedInputStream data, HttpResponse response, response.addHeader("Content-Encoding", Compression.GZIP.getId()); ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); try (OutputStream os = Compression.GZIP.compress(byteOut)) { - IOUtils.copyLarge(data.decompress(), os); + data.decompress().transferTo(os); } byte[] compressedData = byteOut.toByteArray(); response.setData(new ByteArrayInputStream(compressedData)); diff --git a/BlueMapCore/build.gradle.kts b/BlueMapCore/build.gradle.kts index a9c7525b8..45525a018 100644 --- a/BlueMapCore/build.gradle.kts +++ b/BlueMapCore/build.gradle.kts @@ -61,8 +61,6 @@ repositories { @Suppress("GradlePackageUpdate") dependencies { api ("com.github.ben-manes.caffeine:caffeine:3.1.8") - api ("org.apache.commons:commons-lang3:3.6") - api ("commons-io:commons-io:2.5") api ("org.spongepowered:configurate-hocon:4.1.2") api ("org.spongepowered:configurate-gson:4.1.2") api ("de.bluecolored.bluenbt:BlueNBT:2.3.0") diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Multipart.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Multipart.java index ae3f542c7..15595f165 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Multipart.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Multipart.java @@ -30,7 +30,7 @@ import com.google.gson.stream.JsonToken; import de.bluecolored.bluemap.core.resources.AbstractTypeAdapterFactory; import de.bluecolored.bluemap.core.world.BlockState; -import org.apache.commons.lang3.StringUtils; +import lombok.Getter; import java.io.IOException; import java.util.ArrayList; @@ -41,14 +41,11 @@ @JsonAdapter(Multipart.Adapter.class) public class Multipart { + @Getter private VariantSet[] parts = new VariantSet[0]; private Multipart(){} - public VariantSet[] getParts() { - return parts; - } - public void forEach(BlockState blockState, int x, int y, int z, Consumer consumer) { for (VariantSet part : parts) { if (part.getCondition().matches(blockState)) { @@ -99,32 +96,32 @@ public BlockStateCondition readCondition(JsonReader in) throws IOException { in.beginObject(); while (in.hasNext()) { String name = in.nextName(); - if (name.equals(JSON_COMMENT)) { - in.skipValue(); - continue; - } - - if (name.equals("OR")) { - List orConditions = new ArrayList<>(); - in.beginArray(); - while (in.hasNext()) { - orConditions.add(readCondition(in)); + switch (name) { + case JSON_COMMENT -> in.skipValue(); + case "OR" -> { + List orConditions = new ArrayList<>(); + in.beginArray(); + while (in.hasNext()) { + orConditions.add(readCondition(in)); + } + in.endArray(); + andConditions.add( + BlockStateCondition.or(orConditions.toArray(new BlockStateCondition[0]))); + } + case "AND" -> { + List andArray = new ArrayList<>(); + in.beginArray(); + while (in.hasNext()) { + andArray.add(readCondition(in)); + } + in.endArray(); + andConditions.add( + BlockStateCondition.and(andArray.toArray(new BlockStateCondition[0]))); } - in.endArray(); - andConditions.add( - BlockStateCondition.or(orConditions.toArray(new BlockStateCondition[0]))); - } else if (name.equals("AND")) { - List andArray = new ArrayList<>(); - in.beginArray(); - while (in.hasNext()) { - andArray.add(readCondition(in)); + default -> { + String[] values = nextStringOrBoolean(in).split("\\|"); + andConditions.add(BlockStateCondition.property(name, values)); } - in.endArray(); - andConditions.add( - BlockStateCondition.and(andArray.toArray(new BlockStateCondition[0]))); - } else { - String[] values = StringUtils.split(nextStringOrBoolean(in), '|'); - andConditions.add(BlockStateCondition.property(name, values)); } } in.endObject(); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variants.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variants.java index 93edf381f..d414a7985 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variants.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resources/pack/resourcepack/blockstate/Variants.java @@ -30,7 +30,6 @@ import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.resources.AbstractTypeAdapterFactory; import de.bluecolored.bluemap.core.world.BlockState; -import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.Nullable; import java.io.IOException; @@ -111,9 +110,9 @@ private BlockStateCondition parseConditionString(String conditionString) { List conditions = new ArrayList<>(); boolean invalid = false; if (!conditionString.isEmpty() && !conditionString.equals("default") && !conditionString.equals("normal")) { - String[] conditionSplit = StringUtils.split(conditionString, ','); + String[] conditionSplit = conditionString.split(","); for (String element : conditionSplit) { - String[] keyval = StringUtils.split(element, "=", 2); + String[] keyval = element.split("=", 2); if (keyval.length < 2) { Logger.global.logDebug("Failed to parse condition: Condition-String '" + conditionString + "' is invalid!"); invalid = true; diff --git a/implementations/cli/build.gradle.kts b/implementations/cli/build.gradle.kts index 5a17f4b40..eb74f6093 100644 --- a/implementations/cli/build.gradle.kts +++ b/implementations/cli/build.gradle.kts @@ -24,7 +24,6 @@ repositories { dependencies { api ("de.bluecolored.bluemap:BlueMapCommon") - @Suppress("GradlePackageUpdate") implementation ("commons-cli:commons-cli:1.5.0") testImplementation ("org.junit.jupiter:junit-jupiter:5.8.2") @@ -68,23 +67,6 @@ tasks.jar { tasks.shadowJar { destinationDirectory.set(file("../../build/release")) archiveFileName.set("BlueMap-${project.version}-${project.name}.jar") - - //relocate ("com.flowpowered.math", "de.bluecolored.shadow.flowpowered.math") //DON"T relocate this, because the API depends on it - relocate ("com.google", "de.bluecolored.shadow.google") - relocate ("com.typesafe", "de.bluecolored.shadow.typesafe") - relocate ("de.bluecolored.bluenbt", "de.bluecolored.shadow.bluenbt") - relocate ("org.spongepowered.configurate", "de.bluecolored.shadow.configurate") - relocate ("com.github.benmanes.caffeine", "de.bluecolored.shadow.benmanes.caffeine") - relocate ("org.aopalliance", "de.bluecolored.shadow.aopalliance") - relocate ("javax.inject", "de.bluecolored.shadow.javax.inject") - relocate ("javax.annotation", "de.bluecolored.shadow.javax.annotation") - relocate ("com.mojang.brigadier", "de.bluecolored.shadow.mojang.brigadier") - relocate ("org.checkerframework", "de.bluecolored.shadow.checkerframework") - relocate ("org.codehaus", "de.bluecolored.shadow.codehaus") - relocate ("io.leangen.geantyref", "de.bluecolored.shadow.geantyref") - relocate ("io.airlift", "de.bluecolored.shadow.airlift") - relocate ("org.apache.commons", "de.bluecolored.shadow.apache.commons") - relocate ("net.jpountz", "de.bluecolored.shadow.jpountz") } tasks.register("release") { diff --git a/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java b/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java index 918c0909a..a1b983a21 100644 --- a/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java +++ b/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java @@ -47,7 +47,6 @@ import de.bluecolored.bluemap.core.storage.MapStorage; import de.bluecolored.bluemap.core.util.FileHelper; import org.apache.commons.cli.*; -import org.apache.commons.lang3.time.DurationFormatUtils; import org.checkerframework.checker.nullness.qual.Nullable; import java.io.IOException; @@ -56,9 +55,11 @@ import java.net.UnknownHostException; import java.nio.file.Files; import java.nio.file.Path; +import java.time.Duration; import java.time.Instant; import java.time.ZoneId; import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; @@ -136,8 +137,12 @@ public void run() { String eta = ""; if (etaMs > 0) { - String etrDurationString = DurationFormatUtils.formatDuration(etaMs, "HH:mm:ss"); - eta = " (ETA: " + etrDurationString + ")"; + Duration duration = Duration.of(etaMs, ChronoUnit.MILLIS); + eta = " (ETA: %d:%02d:%02d)".formatted( + duration.toHours(), + duration.toMinutesPart(), + duration.toSecondsPart() + ); } Logger.global.logInfo(task.getDescription() + ": " + (Math.round(progress * 100000) / 1000.0) + "%" + eta); } diff --git a/implementations/fabric-1.18/build.gradle.kts b/implementations/fabric-1.18/build.gradle.kts index 607916310..94d1de490 100644 --- a/implementations/fabric-1.18/build.gradle.kts +++ b/implementations/fabric-1.18/build.gradle.kts @@ -45,8 +45,6 @@ dependencies { //exclude dependencies provided by fabric exclude (group = "com.google.guava", module = "guava") exclude (group = "com.google.code.gson", module = "gson") - exclude (group = "org.apache.commons", module = "commons-lang3") - exclude (group = "commons-io", module = "commons-io") exclude (group = "com.mojang", module = "brigadier") } diff --git a/implementations/fabric-1.19.4/build.gradle.kts b/implementations/fabric-1.19.4/build.gradle.kts index 6189749cc..9da979c62 100644 --- a/implementations/fabric-1.19.4/build.gradle.kts +++ b/implementations/fabric-1.19.4/build.gradle.kts @@ -45,8 +45,6 @@ dependencies { //exclude dependencies provided by fabric exclude (group = "com.google.guava", module = "guava") exclude (group = "com.google.code.gson", module = "gson") - exclude (group = "org.apache.commons", module = "commons-lang3") - exclude (group = "commons-io", module = "commons-io") exclude (group = "com.mojang", module = "brigadier") } diff --git a/implementations/fabric-1.20/build.gradle.kts b/implementations/fabric-1.20/build.gradle.kts index cd5cf7171..0008f475b 100644 --- a/implementations/fabric-1.20/build.gradle.kts +++ b/implementations/fabric-1.20/build.gradle.kts @@ -45,8 +45,6 @@ dependencies { //exclude dependencies provided by fabric exclude (group = "com.google.guava", module = "guava") exclude (group = "com.google.code.gson", module = "gson") - exclude (group = "org.apache.commons", module = "commons-lang3") - exclude (group = "commons-io", module = "commons-io") exclude (group = "com.mojang", module = "brigadier") } diff --git a/implementations/forge-1.18.1/build.gradle b/implementations/forge-1.18.1/build.gradle index d5c611416..cca34b340 100644 --- a/implementations/forge-1.18.1/build.gradle +++ b/implementations/forge-1.18.1/build.gradle @@ -68,8 +68,6 @@ dependencies { //exclude dependencies provided by forge exclude (group: "com.google.guava", module: "guava") exclude (group: "com.google.code.gson", module: "gson") - exclude (group: "org.apache.commons", module: "commons-lang3") - exclude (group: "commons-io", module: "commons-io") exclude (group: "com.mojang", module: "brigadier") } diff --git a/implementations/forge-1.19.4/build.gradle b/implementations/forge-1.19.4/build.gradle index 8721de2d7..876f41bad 100644 --- a/implementations/forge-1.19.4/build.gradle +++ b/implementations/forge-1.19.4/build.gradle @@ -67,8 +67,6 @@ dependencies { //exclude dependencies provided by forge exclude (group: "com.google.guava", module: "guava") exclude (group: "com.google.code.gson", module: "gson") - exclude (group: "org.apache.commons", module: "commons-lang3") - exclude (group: "commons-io", module: "commons-io") exclude (group: "com.mojang", module: "brigadier") } diff --git a/implementations/forge-1.20/build.gradle b/implementations/forge-1.20/build.gradle index afef14d15..79a7a431b 100644 --- a/implementations/forge-1.20/build.gradle +++ b/implementations/forge-1.20/build.gradle @@ -67,8 +67,6 @@ dependencies { //exclude dependencies provided by forge exclude (group: "com.google.guava", module: "guava") exclude (group: "com.google.code.gson", module: "gson") - exclude (group: "org.apache.commons", module: "commons-lang3") - exclude (group: "commons-io", module: "commons-io") exclude (group: "com.mojang", module: "brigadier") } diff --git a/implementations/neoforge-1.20.2/build.gradle b/implementations/neoforge-1.20.2/build.gradle index 790b981fc..bfe68b5af 100644 --- a/implementations/neoforge-1.20.2/build.gradle +++ b/implementations/neoforge-1.20.2/build.gradle @@ -36,8 +36,6 @@ dependencies { //exclude dependencies provided by forge exclude (group: "com.google.guava", module: "guava") exclude (group: "com.google.code.gson", module: "gson") - exclude (group: "org.apache.commons", module: "commons-lang3") - exclude (group: "commons-io", module: "commons-io") exclude (group: "com.mojang", module: "brigadier") } diff --git a/implementations/paper/build.gradle.kts b/implementations/paper/build.gradle.kts index 5dab3bb22..a909b97af 100644 --- a/implementations/paper/build.gradle.kts +++ b/implementations/paper/build.gradle.kts @@ -98,8 +98,6 @@ tasks.shadowJar { relocate ("com.google.inject", "de.bluecolored.shadow.google.inject") relocate ("org.apache.commons.dbcp2", "de.bluecolored.shadow.apache.commons.dbcp2") - relocate ("org.apache.commons.io", "de.bluecolored.shadow.apache.commons.io") - relocate ("org.apache.commons.lang3", "de.bluecolored.shadow.apache.commons.lang3") relocate ("org.apache.commons.logging", "de.bluecolored.shadow.apache.commons.logging") relocate ("org.apache.commons.pool2", "de.bluecolored.shadow.apache.commons.pool2") } diff --git a/implementations/paper/src/main/java/de/bluecolored/bluemap/bukkit/BukkitCommands.java b/implementations/paper/src/main/java/de/bluecolored/bluemap/bukkit/BukkitCommands.java index d3ef75602..5aa36f557 100644 --- a/implementations/paper/src/main/java/de/bluecolored/bluemap/bukkit/BukkitCommands.java +++ b/implementations/paper/src/main/java/de/bluecolored/bluemap/bukkit/BukkitCommands.java @@ -33,7 +33,6 @@ import de.bluecolored.bluemap.common.plugin.commands.Commands; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; -import org.apache.commons.lang3.StringUtils; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.command.RemoteConsoleCommandSender; @@ -123,7 +122,7 @@ protected CommandProxy(String name) { public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, String[] args) { String command = commandLabel; if (args.length > 0) { - command += " " + StringUtils.join(args, ' '); + command += " " + String.join(" ", args); } try { diff --git a/implementations/spigot/build.gradle.kts b/implementations/spigot/build.gradle.kts index 9077079ab..6e42bf4e2 100644 --- a/implementations/spigot/build.gradle.kts +++ b/implementations/spigot/build.gradle.kts @@ -101,8 +101,6 @@ tasks.shadowJar { relocate ("com.google.inject", "de.bluecolored.shadow.google.inject") relocate ("org.apache.commons.dbcp2", "de.bluecolored.shadow.apache.commons.dbcp2") - relocate ("org.apache.commons.io", "de.bluecolored.shadow.apache.commons.io") - relocate ("org.apache.commons.lang3", "de.bluecolored.shadow.apache.commons.lang3") relocate ("org.apache.commons.logging", "de.bluecolored.shadow.apache.commons.logging") relocate ("org.apache.commons.pool2", "de.bluecolored.shadow.apache.commons.pool2") } diff --git a/implementations/spigot/src/main/java/de/bluecolored/bluemap/bukkit/BukkitCommands.java b/implementations/spigot/src/main/java/de/bluecolored/bluemap/bukkit/BukkitCommands.java index 2ff4450a1..7c2da104c 100644 --- a/implementations/spigot/src/main/java/de/bluecolored/bluemap/bukkit/BukkitCommands.java +++ b/implementations/spigot/src/main/java/de/bluecolored/bluemap/bukkit/BukkitCommands.java @@ -31,7 +31,6 @@ import com.mojang.brigadier.tree.CommandNode; import de.bluecolored.bluemap.common.plugin.Plugin; import de.bluecolored.bluemap.common.plugin.commands.Commands; -import org.apache.commons.lang.StringUtils; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; @@ -121,7 +120,7 @@ protected CommandProxy(String name) { public boolean execute(CommandSender sender, String commandLabel, String[] args) { String command = commandLabel; if (args.length > 0) { - command += " " + StringUtils.join(args, ' '); + command += " " + String.join(" ", args); } try { diff --git a/implementations/sponge/build.gradle.kts b/implementations/sponge/build.gradle.kts index 2fc11308f..90fa82327 100644 --- a/implementations/sponge/build.gradle.kts +++ b/implementations/sponge/build.gradle.kts @@ -31,7 +31,6 @@ dependencies { //exclude dependencies provided by sponge exclude( group = "com.google.guava", module = "guava" ) exclude( group = "com.google.code.gson", module = "gson" ) - exclude( group = "org.apache.commons", module = "commons-lang3" ) exclude( group = "javax.inject" ) exclude( group = "com.google.inject" ) } @@ -119,7 +118,6 @@ tasks.shadowJar { relocate ("net.jpountz", "de.bluecolored.shadow.jpountz") relocate ("org.apache.commons.dbcp2", "de.bluecolored.shadow.apache.commons.dbcp2") - relocate ("org.apache.commons.io", "de.bluecolored.shadow.apache.commons.io") relocate ("org.apache.commons.logging", "de.bluecolored.shadow.apache.commons.logging") relocate ("org.apache.commons.pool2", "de.bluecolored.shadow.apache.commons.pool2") } From 7afcbeefd703b8e02a657ecd0a7fe4b3bc88a1a4 Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Tue, 28 May 2024 21:56:53 +0200 Subject: [PATCH 31/38] Fix addon loading issue --- .../main/java/de/bluecolored/bluemap/common/addons/Addons.java | 1 + .../main/java/de/bluecolored/bluemap/common/plugin/Plugin.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/Addons.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/Addons.java index 6d537544b..298e087c8 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/Addons.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/addons/Addons.java @@ -59,6 +59,7 @@ public static void tryLoadAddons(Path root) { } public static void tryLoadAddons(Path root, boolean expectOnlyAddons) { + if (!Files.exists(root)) return; try (Stream files = Files.list(root)) { files .filter(Files::isRegularFile) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java index 4a7fba043..3ba6bcfa5 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java @@ -126,7 +126,7 @@ private void load(@Nullable ResourcePack preloadedResourcePack) throws IOExcepti Path addonsFolder = serverInterface.getConfigFolder().resolve("addons"); Files.createDirectories(addonsFolder); Addons.tryLoadAddons(addonsFolder, true); - serverInterface.getModsFolder().ifPresent(Addons::tryLoadAddons); + //serverInterface.getModsFolder().ifPresent(Addons::tryLoadAddons); //load configs BlueMapConfigManager configManager = BlueMapConfigManager.builder() From b5e8bf42aebb007001e751f75a133837f80d67db Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Mon, 3 Jun 2024 10:17:53 +0200 Subject: [PATCH 32/38] Fix update-region expanding with force-updates & chunks with broken tile-entity data can now be loaded --- .../bluemap/common/api/WebAppImpl.java | 2 +- .../common/rendermanager/MapUpdateTask.java | 17 ++++++++++ .../core/map/renderstate/TileInfoRegion.java | 31 +++++++++++++++++ .../bluemap/core/world/mca/MCAWorld.java | 4 +-- .../core/world/mca/chunk/ChunkLoader.java | 8 +++-- .../core/world/mca/chunk/Chunk_1_13.java | 7 +++- .../core/world/mca/chunk/Chunk_1_16.java | 7 +++- .../core/world/mca/chunk/Chunk_1_18.java | 7 +++- .../LenientBlockEntityArrayDeserializer.java | 34 +++++++++++++++++++ .../bluecolored/bluemap/cli/BlueMapCLI.java | 3 ++ 10 files changed, 112 insertions(+), 8 deletions(-) create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/LenientBlockEntityArrayDeserializer.java diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/WebAppImpl.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/WebAppImpl.java index 9e6bde030..bfef8825f 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/WebAppImpl.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/api/WebAppImpl.java @@ -44,7 +44,7 @@ public class WebAppImpl implements WebApp { private final BlueMapService blueMapService; private final @Nullable Plugin plugin; - private final Timer timer = new Timer(); + private final Timer timer = new Timer("BlueMap-WebbAppImpl-Timer", true); private @Nullable TimerTask scheduledWebAppSettingsUpdate; public WebAppImpl(BlueMapService blueMapService, @Nullable Plugin plugin) { diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapUpdateTask.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapUpdateTask.java index 47a455ecb..eb4d99059 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapUpdateTask.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapUpdateTask.java @@ -28,8 +28,10 @@ import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.map.BmMap; import de.bluecolored.bluemap.core.map.renderstate.MapTileState; +import de.bluecolored.bluemap.core.map.renderstate.TileInfoRegion; import de.bluecolored.bluemap.core.map.renderstate.TileState; import de.bluecolored.bluemap.core.storage.GridStorage; +import de.bluecolored.bluemap.core.storage.compression.CompressedInputStream; import de.bluecolored.bluemap.core.util.Grid; import de.bluecolored.bluemap.core.world.World; @@ -134,6 +136,21 @@ private static Collection getRegions(BmMap map, Vector2i center, int r Grid cellGrid = MapTileState.GRID.multiply(tileGrid); try (Stream stream = map.getStorage().tileState().stream()) { stream + .filter(c -> { // filter out files that are fully UNKNOWN + try (CompressedInputStream in = c.read()) { + if (in == null) return false; + TileState[] states = TileInfoRegion.loadPalette(in.decompress()); + for (TileState state : states) { + if ( + state != TileState.UNKNOWN && + state != TileState.NOT_GENERATED + ) return true; + } + return false; + } catch (IOException ignore) { + return true; + } + }) .map(c -> new Vector2i(c.getX(), c.getZ())) .flatMap(v -> cellGrid.getIntersecting(v, regionGrid).stream()) .filter(regionRadiusFilter) diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileInfoRegion.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileInfoRegion.java index f5fe9dc6a..9c41178dd 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileInfoRegion.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/map/renderstate/TileInfoRegion.java @@ -24,12 +24,18 @@ */ package de.bluecolored.bluemap.core.map.renderstate; +import com.google.gson.reflect.TypeToken; +import de.bluecolored.bluemap.core.util.Key; +import de.bluecolored.bluemap.core.util.RegistryAdapter; +import de.bluecolored.bluenbt.BlueNBT; import de.bluecolored.bluenbt.NBTName; import de.bluecolored.bluenbt.NBTPostDeserialize; import lombok.AllArgsConstructor; import lombok.Data; import lombok.Getter; +import java.io.IOException; +import java.io.InputStream; import java.util.Arrays; import java.util.Map; import java.util.Objects; @@ -122,4 +128,29 @@ public static TileInfoRegion create() { return region; } + /** + * Only loads the palette-part from a TileState-file + */ + public static TileState[] loadPalette(InputStream in) throws IOException { + return PaletteOnly.BLUE_NBT.read(in, PaletteOnly.class).tileStates.palette; + } + + @Getter + private static class PaletteOnly { + + private final static BlueNBT BLUE_NBT = new BlueNBT(); + static { + BLUE_NBT.register(TypeToken.get(TileState.class), new RegistryAdapter<>(TileState.REGISTRY, Key.BLUEMAP_NAMESPACE, TileState.UNKNOWN)); + } + + @NBTName("tile-states") + private TileStates tileStates; + + @Getter + private static class TileStates { + private TileState[] palette; + } + + } + } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java index bc0ec6673..367e700da 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java @@ -203,7 +203,7 @@ public void accept(int chunkX, int chunkZ, Chunk chunk) { } }); } catch (IOException ex) { - Logger.global.logDebug("Unexpected exception trying to load preload region (x:" + x + ", z:" + z + "):" + ex); + Logger.global.logDebug("Unexpected exception trying to load preload region (x:" + x + ", z:" + z + "): " + ex); } } @@ -257,7 +257,7 @@ private Chunk loadChunk(int x, int z) { } } - Logger.global.logDebug("Unexpected exception trying to load chunk (x:" + x + ", z:" + z + "):" + loadException); + Logger.global.logDebug("Unexpected exception trying to load chunk (x:" + x + ", z:" + z + "): " + loadException); return Chunk.ERRORED_CHUNK; } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/ChunkLoader.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/ChunkLoader.java index fcd211349..450832c24 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/ChunkLoader.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/ChunkLoader.java @@ -95,8 +95,12 @@ private static class ChunkVersionLoader { private final int dataVersion; public MCAChunk load(MCAWorld world, InputStream in) throws IOException { - D data = MCAUtil.BLUENBT.read(in, dataType); - return mightSupport(data.getDataVersion()) ? constructor.apply(world, data) : new MCAChunk(world, data) {}; + try { + D data = MCAUtil.BLUENBT.read(in, dataType); + return mightSupport(data.getDataVersion()) ? constructor.apply(world, data) : new MCAChunk(world, data) {}; + } catch (Exception e) { + throw new IOException("Failed to parse chunk-data: " + e, e); + } } public boolean mightSupport(int dataVersion) { diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_13.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_13.java index d0f5b6dc9..26a5206db 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_13.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_13.java @@ -33,6 +33,8 @@ import de.bluecolored.bluemap.core.world.block.entity.BlockEntity; import de.bluecolored.bluemap.core.world.mca.MCAUtil; import de.bluecolored.bluemap.core.world.mca.MCAWorld; +import de.bluecolored.bluemap.core.world.mca.data.LenientBlockEntityArrayDeserializer; +import de.bluecolored.bluenbt.NBTDeserializer; import de.bluecolored.bluenbt.NBTName; import lombok.Getter; import org.jetbrains.annotations.Nullable; @@ -295,7 +297,10 @@ public static class Level { private HeightmapsData heightmaps = new HeightmapsData(); private SectionData @Nullable [] sections = null; private int[] biomes = EMPTY_INT_ARRAY; - @NBTName("TileEntities") private @Nullable BlockEntity [] blockEntities = EMPTY_BLOCK_ENTITIES_ARRAY; + + @NBTName("TileEntities") + @NBTDeserializer(LenientBlockEntityArrayDeserializer.class) + private @Nullable BlockEntity [] blockEntities = EMPTY_BLOCK_ENTITIES_ARRAY; } @Getter diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_16.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_16.java index afca54c07..a482888d1 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_16.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_16.java @@ -34,6 +34,8 @@ import de.bluecolored.bluemap.core.world.mca.MCAUtil; import de.bluecolored.bluemap.core.world.mca.MCAWorld; import de.bluecolored.bluemap.core.world.mca.PackedIntArrayAccess; +import de.bluecolored.bluemap.core.world.mca.data.LenientBlockEntityArrayDeserializer; +import de.bluecolored.bluenbt.NBTDeserializer; import de.bluecolored.bluenbt.NBTName; import lombok.Getter; import org.jetbrains.annotations.Nullable; @@ -282,7 +284,10 @@ public static class Level { private HeightmapsData heightmaps = new HeightmapsData(); private SectionData @Nullable [] sections = null; private int[] biomes = EMPTY_INT_ARRAY; - @NBTName("TileEntities") private @Nullable BlockEntity [] blockEntities = EMPTY_BLOCK_ENTITIES_ARRAY; + + @NBTName("TileEntities") + @NBTDeserializer(LenientBlockEntityArrayDeserializer.class) + private @Nullable BlockEntity [] blockEntities = EMPTY_BLOCK_ENTITIES_ARRAY; } @Getter diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_18.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_18.java index de3e1bd56..d6e81a7a4 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_18.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/chunk/Chunk_1_18.java @@ -34,6 +34,8 @@ import de.bluecolored.bluemap.core.world.mca.MCAUtil; import de.bluecolored.bluemap.core.world.mca.MCAWorld; import de.bluecolored.bluemap.core.world.mca.PackedIntArrayAccess; +import de.bluecolored.bluemap.core.world.mca.data.LenientBlockEntityArrayDeserializer; +import de.bluecolored.bluenbt.NBTDeserializer; import de.bluecolored.bluenbt.NBTName; import lombok.Getter; import org.jetbrains.annotations.Nullable; @@ -290,7 +292,10 @@ public static class Data extends MCAChunk.Data { private long inhabitedTime = 0; private HeightmapsData heightmaps = new HeightmapsData(); private SectionData @Nullable [] sections = null; - @NBTName("block_entities") private @Nullable BlockEntity [] blockEntities = EMPTY_BLOCK_ENTITIES_ARRAY; + + @NBTName("block_entities") + @NBTDeserializer(LenientBlockEntityArrayDeserializer.class) + private @Nullable BlockEntity [] blockEntities = EMPTY_BLOCK_ENTITIES_ARRAY; } @Getter diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/LenientBlockEntityArrayDeserializer.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/LenientBlockEntityArrayDeserializer.java new file mode 100644 index 000000000..0f8ccaa8c --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/LenientBlockEntityArrayDeserializer.java @@ -0,0 +1,34 @@ +package de.bluecolored.bluemap.core.world.mca.data; + +import com.google.gson.reflect.TypeToken; +import de.bluecolored.bluemap.core.world.block.entity.BlockEntity; +import de.bluecolored.bluenbt.BlueNBT; +import de.bluecolored.bluenbt.NBTReader; +import de.bluecolored.bluenbt.TagType; +import de.bluecolored.bluenbt.TypeDeserializer; + +import java.io.IOException; + +/** + * TypeSerializer that returns a default value instead of failing when the serialized field is of the wrong type + */ +public class LenientBlockEntityArrayDeserializer implements TypeDeserializer { + + private static final BlockEntity[] EMPTY_BLOCK_ENTITIES_ARRAY = new BlockEntity[0]; + + private final TypeDeserializer delegate; + + public LenientBlockEntityArrayDeserializer(BlueNBT blueNBT) { + delegate = blueNBT.getTypeDeserializer(new TypeToken<>(){}); + } + + @Override + public BlockEntity[] read(NBTReader reader) throws IOException { + if (reader.peek() != TagType.LIST) { + reader.skip(); + return EMPTY_BLOCK_ENTITIES_ARRAY; + } + return delegate.read(reader); + } + +} diff --git a/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java b/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java index a1b983a21..a718ebf93 100644 --- a/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java +++ b/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java @@ -33,6 +33,7 @@ import de.bluecolored.bluemap.common.config.ConfigurationException; import de.bluecolored.bluemap.common.config.CoreConfig; import de.bluecolored.bluemap.common.config.WebserverConfig; +import de.bluecolored.bluemap.common.debug.StateDumper; import de.bluecolored.bluemap.common.plugin.MapUpdateService; import de.bluecolored.bluemap.common.rendermanager.MapUpdateTask; import de.bluecolored.bluemap.common.rendermanager.RenderManager; @@ -209,6 +210,8 @@ public void run() { Runtime.getRuntime().removeShutdownHook(shutdownHook); shutdown.run(); } + + StateDumper.global().dump(Path.of("teststate.json")); } public void startWebserver(BlueMapService blueMap, boolean verbose) throws IOException, ConfigurationException, InterruptedException { From 4b8245d19deddf18cd5d87269282ee1008120c6c Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Mon, 3 Jun 2024 10:52:14 +0200 Subject: [PATCH 33/38] Fix webserver stalling --- .../bluemap/common/web/FileRequestHandler.java | 6 +++++- .../bluemap/common/web/http/HttpConnection.java | 9 ++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java index b8c3a9ddc..491f65c5c 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/FileRequestHandler.java @@ -36,6 +36,7 @@ import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.time.Instant; +import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.util.concurrent.TimeUnit; @@ -134,7 +135,10 @@ private HttpResponse generateResponse(HttpRequest request) throws IOException { //create response HttpResponse response = new HttpResponse(HttpStatusCode.OK); response.addHeader("ETag", eTag); - if (lastModified > 0) response.addHeader("Last-Modified", DateTimeFormatter.RFC_1123_DATE_TIME.format(Instant.ofEpochMilli(lastModified))); + if (lastModified > 0) response.addHeader("Last-Modified", DateTimeFormatter.RFC_1123_DATE_TIME.format(Instant + .ofEpochMilli(lastModified) + .atOffset(ZoneOffset.UTC) + )); response.addHeader("Cache-Control", "public"); response.addHeader("Cache-Control", "max-age=" + TimeUnit.DAYS.toSeconds(1)); diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/http/HttpConnection.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/http/HttpConnection.java index 06e1213e3..567d3e4ae 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/http/HttpConnection.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/web/http/HttpConnection.java @@ -87,13 +87,20 @@ public void accept(SelectionKey selectionKey) { () -> requestHandler.handle(request), responseHandlerExecutor ); - futureResponse.thenAccept(response -> { + futureResponse.handle((response, error) -> { + if (error != null) { + Logger.global.logError("Unexpected error handling request", error); + response = new HttpResponse(HttpStatusCode.INTERNAL_SERVER_ERROR); + } + try { response.read(channel); // do an initial read to trigger response sending intent this.response = response; } catch (IOException e) { handleIOException(channel, e); } + + return null; }); } From d43c7c474f91bb35ba072d43f3ef1cd945a1803d Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Mon, 3 Jun 2024 12:26:37 +0200 Subject: [PATCH 34/38] Apply spotless foxes and a comment --- .../common/rendermanager/MapUpdateTask.java | 5 +++- .../LenientBlockEntityArrayDeserializer.java | 24 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapUpdateTask.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapUpdateTask.java index eb4d99059..53378e410 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapUpdateTask.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/rendermanager/MapUpdateTask.java @@ -132,11 +132,14 @@ private static Collection getRegions(BmMap map, Vector2i center, int r .forEach(regions::add); // also update regions that are present as map-tile-state files (they might have been rendered before but deleted now) + // (a little hacky as we are operating on raw tile-state files -> maybe find a better way?) Grid tileGrid = map.getHiresModelManager().getTileGrid(); Grid cellGrid = MapTileState.GRID.multiply(tileGrid); try (Stream stream = map.getStorage().tileState().stream()) { stream - .filter(c -> { // filter out files that are fully UNKNOWN + .filter(c -> { + // filter out files that are fully UNKNOWN/NOT_GENERATED + // this avoids unnecessarily converting UNKNOWN tiles into NOT_GENERATED tiles on force-updates try (CompressedInputStream in = c.read()) { if (in == null) return false; TileState[] states = TileInfoRegion.loadPalette(in.decompress()); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/LenientBlockEntityArrayDeserializer.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/LenientBlockEntityArrayDeserializer.java index 0f8ccaa8c..485c5ce68 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/LenientBlockEntityArrayDeserializer.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/data/LenientBlockEntityArrayDeserializer.java @@ -1,3 +1,27 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.mca.data; import com.google.gson.reflect.TypeToken; From 474c5e27c4929b231d0e9d8ed1926def0f527493 Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Mon, 3 Jun 2024 15:24:55 +0200 Subject: [PATCH 35/38] Add fix-edges command and cli-option --- .../common/plugin/commands/Commands.java | 27 +++++++++++++------ .../bluecolored/bluemap/cli/BlueMapCLI.java | 10 ++++--- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java index 5d002fb83..953a022b6 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java @@ -52,6 +52,7 @@ import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.map.BmMap; import de.bluecolored.bluemap.core.map.renderstate.TileInfoRegion; +import de.bluecolored.bluemap.core.map.renderstate.TileState; import de.bluecolored.bluemap.core.storage.MapStorage; import de.bluecolored.bluemap.core.storage.Storage; import de.bluecolored.bluemap.core.util.Grid; @@ -180,6 +181,13 @@ public void init() { this::forceUpdateCommand ).build(); + LiteralCommandNode fixEdgesCommand = + addRenderArguments( + literal("fix-edges") + .requires(requirements("bluemap.update.force")), + this::fixEdgesCommand + ).build(); + LiteralCommandNode updateCommand = addRenderArguments( literal("update") @@ -235,6 +243,7 @@ public void init() { baseCommand.addChild(freezeCommand); baseCommand.addChild(unfreezeCommand); baseCommand.addChild(forceUpdateCommand); + baseCommand.addChild(fixEdgesCommand); baseCommand.addChild(updateCommand); baseCommand.addChild(cancelCommand); baseCommand.addChild(purgeCommand); @@ -761,14 +770,18 @@ public int unfreezeCommand(CommandContext context) { } public int forceUpdateCommand(CommandContext context) { - return updateCommand(context, true); + return updateCommand(context, s -> true); + } + + public int fixEdgesCommand(CommandContext context) { + return updateCommand(context, s -> s == TileState.RENDERED_EDGE); } public int updateCommand(CommandContext context) { - return updateCommand(context, false); + return updateCommand(context, s -> false); } - public int updateCommand(CommandContext context, boolean force) { + public int updateCommand(CommandContext context, Predicate force) { final CommandSource source = commandSourceInterface.apply(context.getSource()); // parse world/map argument @@ -795,8 +808,7 @@ public int updateCommand(CommandContext context, boolean force) { mapToRender = null; if (worldToRender == null) { - source.sendMessage(Text.of(TextColor.RED, "Can't detect a world from this command-source, you'll have to define a world or a map to update!") - .setHoverText(Text.of(TextColor.GRAY, "/bluemap " + (force ? "force-update" : "update") + " "))); + source.sendMessage(Text.of(TextColor.RED, "Can't detect a world from this command-source, you'll have to define a world or a map to update!")); return 0; } } @@ -813,8 +825,7 @@ public int updateCommand(CommandContext context, boolean force) { } else { Vector3d position = source.getPosition().orElse(null); if (position == null) { - source.sendMessage(Text.of(TextColor.RED, "Can't detect a position from this command-source, you'll have to define x,z coordinates to update with a radius!") - .setHoverText(Text.of(TextColor.GRAY, "/bluemap " + (force ? "force-update" : "update") + " " + radius))); + source.sendMessage(Text.of(TextColor.RED, "Can't detect a position from this command-source, you'll have to define x,z coordinates to update with a radius!")); return 0; } @@ -844,7 +855,7 @@ public int updateCommand(CommandContext context, boolean force) { } for (BmMap map : maps) { - MapUpdateTask updateTask = new MapUpdateTask(map, center, radius, s -> force); + MapUpdateTask updateTask = new MapUpdateTask(map, center, radius, force); plugin.getRenderManager().scheduleRenderTask(updateTask); source.sendMessage(Text.of(TextColor.GREEN, "Created new Update-Task for map '" + map.getId() + "' ", diff --git a/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java b/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java index a718ebf93..73e7c6b60 100644 --- a/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java +++ b/implementations/cli/src/main/java/de/bluecolored/bluemap/cli/BlueMapCLI.java @@ -44,6 +44,7 @@ import de.bluecolored.bluemap.core.BlueMap; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.map.BmMap; +import de.bluecolored.bluemap.core.map.renderstate.TileState; import de.bluecolored.bluemap.core.metrics.Metrics; import de.bluecolored.bluemap.core.storage.MapStorage; import de.bluecolored.bluemap.core.util.FileHelper; @@ -71,7 +72,7 @@ public class BlueMapCLI { private String minecraftVersion = null; private Path configFolder = Path.of("config"); - public void renderMaps(BlueMapService blueMap, boolean watch, boolean forceRender, boolean forceGenerateWebapp, + public void renderMaps(BlueMapService blueMap, boolean watch, Predicate force, boolean forceGenerateWebapp, @Nullable String mapsToRender) throws ConfigurationException, IOException, InterruptedException { if (blueMap.getConfig().getWebappConfig().isEnabled()) @@ -112,7 +113,7 @@ public void renderMaps(BlueMapService blueMap, boolean watch, boolean forceRende //update all maps int totalRegions = 0; for (BmMap map : maps.values()) { - MapUpdateTask updateTask = new MapUpdateTask(map, s -> forceRender); + MapUpdateTask updateTask = new MapUpdateTask(map, force); renderManager.scheduleRenderTask(updateTask); totalRegions += updateTask.getRegions().size(); } @@ -355,7 +356,9 @@ public static void main(String[] args) { noActions = false; boolean watch = cmd.hasOption("u"); - boolean force = cmd.hasOption("f"); + Predicate force = t -> false; + if (cmd.hasOption("f")) force = t -> true; + else if (cmd.hasOption("e")) force = t -> t == TileState.RENDERED_EDGE; boolean generateWebappFiles = cmd.hasOption("g"); String mapsToRender = cmd.getOptionValue("m", null); cli.renderMaps(blueMap, watch, force, generateWebappFiles, mapsToRender); @@ -453,6 +456,7 @@ private static Options createOptions() { options.addOption("s", "generate-websettings", false, "Updates the settings.json for the web-app"); options.addOption("r", "render", false, "Renders the maps configured in the 'render.conf' file"); + options.addOption("e", "fix-edges", false, "Forces rendering the map-edges, instead of only rendering chunks that have been modified since the last render"); options.addOption("f", "force-render", false, "Forces rendering everything, instead of only rendering chunks that have been modified since the last render"); options.addOption("m", "maps", true, "A comma-separated list of map-id's that should be rendered. Example: 'world,nether'"); From 75b562eeb1898ca52711830b07970e607f122108 Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Mon, 3 Jun 2024 15:40:45 +0200 Subject: [PATCH 36/38] Generalize world-ids --- .../bluemap/common/BlueMapService.java | 2 +- .../bluecolored/bluemap/common/plugin/Plugin.java | 5 ++--- .../de/bluecolored/bluemap/core/world/World.java | 15 +++++++++++++++ .../bluemap/core/world/mca/MCAWorld.java | 12 +----------- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapService.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapService.java index 86aa3d4be..779adb3a4 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapService.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/BlueMapService.java @@ -219,7 +219,7 @@ private synchronized void loadMap(String id, MapConfig mapConfig) throws Configu "Check if the 'world' setting in the config-file for that map is correct, or remove the entire config-file if you don't want that map."); } - String worldId = MCAWorld.id(worldFolder, dimension); + String worldId = World.id(worldFolder, dimension); World world = worlds.get(worldId); if (world == null) { try { diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java index 3ba6bcfa5..5cb347b86 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java @@ -31,6 +31,7 @@ import de.bluecolored.bluemap.common.addons.Addons; import de.bluecolored.bluemap.common.api.BlueMapAPIImpl; import de.bluecolored.bluemap.common.config.*; +import de.bluecolored.bluemap.common.debug.StateDumper; import de.bluecolored.bluemap.common.live.LivePlayersDataSupplier; import de.bluecolored.bluemap.common.plugin.skins.PlayerSkinUpdater; import de.bluecolored.bluemap.common.rendermanager.MapUpdateTask; @@ -40,7 +41,6 @@ import de.bluecolored.bluemap.common.serverinterface.ServerWorld; import de.bluecolored.bluemap.common.web.*; import de.bluecolored.bluemap.common.web.http.HttpServer; -import de.bluecolored.bluemap.common.debug.StateDumper; import de.bluecolored.bluemap.core.logger.Logger; import de.bluecolored.bluemap.core.map.BmMap; import de.bluecolored.bluemap.core.metrics.Metrics; @@ -50,7 +50,6 @@ import de.bluecolored.bluemap.core.util.FileHelper; import de.bluecolored.bluemap.core.util.Tristate; import de.bluecolored.bluemap.core.world.World; -import de.bluecolored.bluemap.core.world.mca.MCAWorld; import lombok.AccessLevel; import lombok.Getter; import org.jetbrains.annotations.Nullable; @@ -639,7 +638,7 @@ public boolean checkPausedByPlayerCount() { } public @Nullable World getWorld(ServerWorld serverWorld) { - String id = MCAWorld.id(serverWorld.getWorldFolder(), serverWorld.getDimension()); + String id = World.id(serverWorld.getWorldFolder(), serverWorld.getDimension()); return getBlueMap().getWorlds().get(id); } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/World.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/World.java index 2f02e300c..7d86e638c 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/World.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/World.java @@ -27,9 +27,11 @@ import com.flowpowered.math.vector.Vector2i; import com.flowpowered.math.vector.Vector3i; import de.bluecolored.bluemap.core.util.Grid; +import de.bluecolored.bluemap.core.util.Key; import de.bluecolored.bluemap.core.util.WatchService; import java.io.IOException; +import java.nio.file.Path; import java.util.Collection; import java.util.function.Predicate; @@ -105,4 +107,17 @@ default void preloadRegionChunks(int x, int z) { */ void invalidateChunkCache(int x, int z); + /** + * Generates a unique world-id based on a world-folder and a dimension + */ + static String id(Path worldFolder, Key dimension) { + worldFolder = worldFolder.toAbsolutePath().normalize(); + + Path workingDir = Path.of("").toAbsolutePath().normalize(); + if (worldFolder.startsWith(workingDir)) + worldFolder = workingDir.relativize(worldFolder); + + return worldFolder + "#" + dimension.getFormatted(); + } + } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java index 367e700da..3acf9381a 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/mca/MCAWorld.java @@ -94,7 +94,7 @@ public class MCAWorld implements World { .build(this::loadChunk); private MCAWorld(Path worldFolder, Key dimension, DataPack dataPack, LevelData levelData) { - this.id = id(worldFolder, dimension); + this.id = World.id(worldFolder, dimension); this.worldFolder = worldFolder; this.dimension = dimension; this.dataPack = dataPack; @@ -275,16 +275,6 @@ public static MCAWorld load(Path worldFolder, Key dimension, DataPack dataPack) return new MCAWorld(worldFolder, dimension, dataPack, levelData); } - public static String id(Path worldFolder, Key dimension) { - worldFolder = worldFolder.toAbsolutePath().normalize(); - - Path workingDir = Path.of("").toAbsolutePath().normalize(); - if (worldFolder.startsWith(workingDir)) - worldFolder = workingDir.relativize(worldFolder); - - return "MCA#" + worldFolder + "#" + dimension.getFormatted(); - } - public static Path resolveDimensionFolder(Path worldFolder, Key dimension) { if (DataPack.DIMENSION_OVERWORLD.equals(dimension)) return worldFolder; if (DataPack.DIMENSION_THE_NETHER.equals(dimension)) return worldFolder.resolve("DIM-1"); From 2dfd9feb21dafc6e9d15756dd9782f6c7d29d34a Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Mon, 3 Jun 2024 21:50:52 +0200 Subject: [PATCH 37/38] Add implementations for the newest fabric/forge/neoforge versions --- .github/workflows/build.yml | 1 + .github/workflows/publish.yml | 1 + implementations/cli/build.gradle.kts | 2 +- implementations/fabric-1.18/build.gradle.kts | 2 +- .../fabric-1.19.4/build.gradle.kts | 2 +- implementations/fabric-1.20/build.gradle.kts | 2 +- implementations/fabric/build.gradle.kts | 177 ++++++++++++ implementations/fabric/settings.gradle.kts | 13 + .../bluemap/fabric/FabricCommandSource.java | 90 ++++++ .../bluemap/fabric/FabricEventForwarder.java | 76 +++++ .../bluecolored/bluemap/fabric/FabricMod.java | 241 ++++++++++++++++ .../bluemap/fabric/FabricPlayer.java | 153 ++++++++++ .../bluemap/fabric/FabricWorld.java | 110 ++++++++ .../bluemap/fabric/Log4jLogger.java | 69 +++++ .../main/resources/assets/bluemap/icon.png | Bin 0 -> 10593 bytes .../fabric/src/main/resources/fabric.mod.json | 33 +++ implementations/forge-1.18.1/build.gradle | 2 +- implementations/forge-1.19.4/build.gradle | 2 +- implementations/forge-1.20/build.gradle | 2 +- implementations/forge/build.gradle | 195 +++++++++++++ implementations/forge/settings.gradle.kts | 3 + .../bluemap/forge/ForgeCommandSource.java | 6 +- .../bluemap/forge/ForgeEventForwarder.java | 67 +++++ .../bluecolored/bluemap/forge/ForgeMod.java | 262 ++++++++++++++++++ .../bluemap/forge/ForgePlayer.java | 0 .../bluecolored/bluemap/forge/ForgeWorld.java | 0 .../bluemap/forge/Log4jLogger.java | 69 +++++ .../src/main/resources/META-INF/mods.toml | 26 ++ .../forge/src/main/resources/pack.mcmeta | 6 + .../neoforge-1.20.2/gradle.properties | 16 -- .../build.gradle | 19 +- implementations/neoforge/gradle.properties | 17 ++ .../settings.gradle | 2 +- .../bluemap/forge/ForgeCommandSource.java | 78 ++++++ .../bluemap/forge/ForgeEventForwarder.java | 0 .../bluecolored/bluemap/forge/ForgeMod.java | 12 +- .../bluemap/forge/ForgePlayer.java | 154 ++++++++++ .../bluecolored/bluemap/forge/ForgeWorld.java | 111 ++++++++ .../bluemap/forge/Log4jLogger.java | 0 .../resources/META-INF/neoforge.mods.toml} | 1 + .../src/main/resources/pack.mcmeta | 0 implementations/paper/build.gradle.kts | 2 +- implementations/spigot/build.gradle.kts | 2 +- implementations/sponge/build.gradle.kts | 2 +- settings.gradle.kts | 20 +- 45 files changed, 1990 insertions(+), 58 deletions(-) create mode 100644 implementations/fabric/build.gradle.kts create mode 100644 implementations/fabric/settings.gradle.kts create mode 100644 implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/FabricCommandSource.java create mode 100644 implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/FabricEventForwarder.java create mode 100644 implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/FabricMod.java create mode 100644 implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/FabricPlayer.java create mode 100644 implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/FabricWorld.java create mode 100644 implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/Log4jLogger.java create mode 100644 implementations/fabric/src/main/resources/assets/bluemap/icon.png create mode 100644 implementations/fabric/src/main/resources/fabric.mod.json create mode 100644 implementations/forge/build.gradle create mode 100644 implementations/forge/settings.gradle.kts rename implementations/{neoforge-1.20.2 => forge}/src/main/java/de/bluecolored/bluemap/forge/ForgeCommandSource.java (92%) create mode 100644 implementations/forge/src/main/java/de/bluecolored/bluemap/forge/ForgeEventForwarder.java create mode 100644 implementations/forge/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java rename implementations/{neoforge-1.20.2 => forge}/src/main/java/de/bluecolored/bluemap/forge/ForgePlayer.java (100%) rename implementations/{neoforge-1.20.2 => forge}/src/main/java/de/bluecolored/bluemap/forge/ForgeWorld.java (100%) create mode 100644 implementations/forge/src/main/java/de/bluecolored/bluemap/forge/Log4jLogger.java create mode 100644 implementations/forge/src/main/resources/META-INF/mods.toml create mode 100644 implementations/forge/src/main/resources/pack.mcmeta delete mode 100644 implementations/neoforge-1.20.2/gradle.properties rename implementations/{neoforge-1.20.2 => neoforge}/build.gradle (90%) create mode 100644 implementations/neoforge/gradle.properties rename implementations/{neoforge-1.20.2 => neoforge}/settings.gradle (88%) create mode 100644 implementations/neoforge/src/main/java/de/bluecolored/bluemap/forge/ForgeCommandSource.java rename implementations/{neoforge-1.20.2 => neoforge}/src/main/java/de/bluecolored/bluemap/forge/ForgeEventForwarder.java (100%) rename implementations/{neoforge-1.20.2 => neoforge}/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java (93%) create mode 100644 implementations/neoforge/src/main/java/de/bluecolored/bluemap/forge/ForgePlayer.java create mode 100644 implementations/neoforge/src/main/java/de/bluecolored/bluemap/forge/ForgeWorld.java rename implementations/{neoforge-1.20.2 => neoforge}/src/main/java/de/bluecolored/bluemap/forge/Log4jLogger.java (100%) rename implementations/{neoforge-1.20.2/src/main/resources/META-INF/mods.toml => neoforge/src/main/resources/META-INF/neoforge.mods.toml} (93%) rename implementations/{neoforge-1.20.2 => neoforge}/src/main/resources/pack.mcmeta (100%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ee1aacf33..af5c99a3d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,6 +26,7 @@ jobs: java-version: | 16 17 + 21 cache: 'gradle' - name: Build with Gradle run: ./gradlew clean spotlessCheck test build diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b41f20a2f..9a392a969 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -21,6 +21,7 @@ jobs: java-version: | 16 17 + 21 cache: 'gradle' - name: Build with Gradle run: ./gradlew clean :BlueMapCore:publish :BlueMapCommon:publish diff --git a/implementations/cli/build.gradle.kts b/implementations/cli/build.gradle.kts index eb74f6093..9be58278b 100644 --- a/implementations/cli/build.gradle.kts +++ b/implementations/cli/build.gradle.kts @@ -3,7 +3,7 @@ plugins { `java-library` id("com.diffplug.spotless") version "6.1.2" id ("com.github.node-gradle.node") version "3.0.1" - id ("com.github.johnrengelman.shadow") version "7.1.2" + id ("com.github.johnrengelman.shadow") version "8.1.1" } group = "de.bluecolored.bluemap" diff --git a/implementations/fabric-1.18/build.gradle.kts b/implementations/fabric-1.18/build.gradle.kts index 94d1de490..0b14a8a58 100644 --- a/implementations/fabric-1.18/build.gradle.kts +++ b/implementations/fabric-1.18/build.gradle.kts @@ -9,7 +9,7 @@ plugins { `java-library` id("com.diffplug.spotless") version "6.1.2" id ("com.github.node-gradle.node") version "3.0.1" - id ("com.github.johnrengelman.shadow") version "7.1.2" + id ("com.github.johnrengelman.shadow") version "8.1.1" id ("fabric-loom") version "1.3-SNAPSHOT" id ("com.modrinth.minotaur") version "2.+" id ("com.matthewprenger.cursegradle") version "1.4.0" diff --git a/implementations/fabric-1.19.4/build.gradle.kts b/implementations/fabric-1.19.4/build.gradle.kts index 9da979c62..79b049e18 100644 --- a/implementations/fabric-1.19.4/build.gradle.kts +++ b/implementations/fabric-1.19.4/build.gradle.kts @@ -9,7 +9,7 @@ plugins { `java-library` id("com.diffplug.spotless") version "6.1.2" id ("com.github.node-gradle.node") version "3.0.1" - id ("com.github.johnrengelman.shadow") version "7.1.2" + id ("com.github.johnrengelman.shadow") version "8.1.1" id ("fabric-loom") version "1.3-SNAPSHOT" id ("com.modrinth.minotaur") version "2.+" id ("com.matthewprenger.cursegradle") version "1.4.0" diff --git a/implementations/fabric-1.20/build.gradle.kts b/implementations/fabric-1.20/build.gradle.kts index 0008f475b..c02a7e352 100644 --- a/implementations/fabric-1.20/build.gradle.kts +++ b/implementations/fabric-1.20/build.gradle.kts @@ -9,7 +9,7 @@ plugins { `java-library` id("com.diffplug.spotless") version "6.1.2" id ("com.github.node-gradle.node") version "3.0.1" - id ("com.github.johnrengelman.shadow") version "7.1.2" + id ("com.github.johnrengelman.shadow") version "8.1.1" id ("fabric-loom") version "1.5-SNAPSHOT" id ("com.modrinth.minotaur") version "2.+" id ("com.matthewprenger.cursegradle") version "1.4.0" diff --git a/implementations/fabric/build.gradle.kts b/implementations/fabric/build.gradle.kts new file mode 100644 index 000000000..27517b4ea --- /dev/null +++ b/implementations/fabric/build.gradle.kts @@ -0,0 +1,177 @@ +import com.matthewprenger.cursegradle.CurseArtifact +import com.matthewprenger.cursegradle.CurseProject +import com.matthewprenger.cursegradle.CurseRelation +import com.matthewprenger.cursegradle.Options +import net.fabricmc.loom.task.RemapJarTask + +plugins { + java + `java-library` + id("com.diffplug.spotless") version "6.1.2" + id ("com.github.node-gradle.node") version "3.0.1" + id ("com.github.johnrengelman.shadow") version "8.1.1" + id ("fabric-loom") version "1.6-SNAPSHOT" + id ("com.modrinth.minotaur") version "2.+" + id ("com.matthewprenger.cursegradle") version "1.4.0" +} + +group = "de.bluecolored.bluemap" +version = System.getProperty("bluemap.version") ?: "?" // set by BlueMapCore + +val javaTarget = 21 +java { + sourceCompatibility = JavaVersion.toVersion(javaTarget) + targetCompatibility = JavaVersion.toVersion(javaTarget) + + withSourcesJar() +} + +repositories { + mavenCentral() + maven ("https://libraries.minecraft.net") + maven ("https://maven.fabricmc.net/") + maven ("https://oss.sonatype.org/content/repositories/snapshots") + maven ("https://repo.bluecolored.de/releases") +} + +val shadowInclude: Configuration by configurations.creating + +configurations { + implementation.get().extendsFrom(shadowInclude) +} + +dependencies { + shadowInclude ("de.bluecolored.bluemap:BlueMapCommon") { + //exclude dependencies provided by fabric + exclude (group = "com.google.guava", module = "guava") + exclude (group = "com.google.code.gson", module = "gson") + exclude (group = "com.mojang", module = "brigadier") + } + + minecraft ("com.mojang:minecraft:1.20.5") + mappings ("net.fabricmc:yarn:1.20.5+build.1") + modImplementation ("net.fabricmc:fabric-loader:0.15.10") + modImplementation ("net.fabricmc.fabric-api:fabric-api:0.97.8+1.20.5") + modImplementation("me.lucko:fabric-permissions-api:0.1-SNAPSHOT") + + testImplementation ("org.junit.jupiter:junit-jupiter:5.9.0") + testRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.9.0") +} + +spotless { + java { + target ("src/*/java/**/*.java") + + licenseHeaderFile("../../HEADER") + indentWithSpaces() + trimTrailingWhitespace() + } +} + +tasks.withType(JavaCompile::class).configureEach { + options.apply { + encoding = "utf-8" + } +} + +tasks.withType(AbstractArchiveTask::class).configureEach { + isReproducibleFileOrder = true + isPreserveFileTimestamps = false +} + +tasks.test { + useJUnitPlatform() +} + +tasks.processResources { + inputs.property ("version", project.version) + + filesMatching("fabric.mod.json") { + expand ("version" to project.version) + } +} + +tasks.shadowJar { + configurations = listOf(shadowInclude) + + //relocate ("com.flowpowered.math", "de.bluecolored.shadow.flowpowered.math") //DON"T relocate this, because the API depends on it + relocate ("com.typesafe.config", "de.bluecolored.shadow.typesafe.config") + relocate ("de.bluecolored.bluenbt", "de.bluecolored.shadow.bluenbt") + relocate ("org.spongepowered.configurate", "de.bluecolored.shadow.configurate") + relocate ("com.github.benmanes.caffeine", "de.bluecolored.shadow.benmanes.caffeine") + relocate ("org.aopalliance", "de.bluecolored.shadow.aopalliance") + relocate ("javax.inject", "de.bluecolored.shadow.javax.inject") + relocate ("org.checkerframework", "de.bluecolored.shadow.checkerframework") + relocate ("org.codehaus", "de.bluecolored.shadow.codehaus") + relocate ("io.leangen.geantyref", "de.bluecolored.shadow.geantyref") + relocate ("io.airlift", "de.bluecolored.shadow.airlift") + relocate ("net.jpountz", "de.bluecolored.shadow.jpountz") + + relocate ("com.google.errorprone", "de.bluecolored.shadow.google.errorprone") + relocate ("com.google.inject", "de.bluecolored.shadow.google.inject") + + relocate ("org.apache.commons.dbcp2", "de.bluecolored.shadow.apache.commons.dbcp2") + relocate ("org.apache.commons.logging", "de.bluecolored.shadow.apache.commons.logging") + relocate ("org.apache.commons.pool2", "de.bluecolored.shadow.apache.commons.pool2") +} + +tasks.register("remappedShadowJar", type = RemapJarTask::class) { + destinationDirectory.set(file("../../build/release")) + archiveFileName.set("BlueMap-${project.version}-${project.name}.jar") + dependsOn (tasks.shadowJar) + inputFile.set(tasks.shadowJar.get().archiveFile) + addNestedDependencies.set(true) +} + +tasks.register("release") { + dependsOn("remappedShadowJar") +} + +modrinth { + token.set(System.getenv("MODRINTH_TOKEN")) + projectId.set("swbUV1cr") + versionNumber.set("${project.version}-${project.name}") + changelog.set(file("../../release.md") + .readText() + .replace("{version}", project.version.toString())) + uploadFile.set(tasks.findByName("remappedShadowJar")) + gameVersions.addAll("1.20.5", "1.20.6") + dependencies { + required.project("P7dR8mSH") // Fabric API + } +} + +curseforge { + apiKey = System.getenv("CURSEFORGE_TOKEN") ?: "" + project(closureOf { + id = "406463" + changelogType = "markdown" + changelog = file("../../release.md") + .readText() + .replace("{version}", project.version.toString()) + releaseType = "release" + + addGameVersion("Fabric") + + addGameVersion("Java 21") + + addGameVersion("1.20.5") + addGameVersion("1.20.6") + + mainArtifact(tasks.findByName("remappedShadowJar"), closureOf { + relations(closureOf { + requiredDependency("fabric-api") + }) + }) + }) + options(closureOf { + javaVersionAutoDetect = false + javaIntegration = false + forgeGradleIntegration = false + }) +} + +tasks.register("publish") { + dependsOn("modrinth") + dependsOn("curseforge") +} diff --git a/implementations/fabric/settings.gradle.kts b/implementations/fabric/settings.gradle.kts new file mode 100644 index 000000000..9eb20cab5 --- /dev/null +++ b/implementations/fabric/settings.gradle.kts @@ -0,0 +1,13 @@ +pluginManagement { + repositories { + maven { + name = "Fabric" + url = uri("https://maven.fabricmc.net/") + } + gradlePluginPortal() + } +} + +rootProject.name = "fabric" + +includeBuild("../../BlueMapCommon") diff --git a/implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/FabricCommandSource.java b/implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/FabricCommandSource.java new file mode 100644 index 000000000..85b0f2e6b --- /dev/null +++ b/implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/FabricCommandSource.java @@ -0,0 +1,90 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.fabric; + +import com.flowpowered.math.vector.Vector3d; +import de.bluecolored.bluemap.common.plugin.Plugin; +import de.bluecolored.bluemap.common.plugin.text.Text; +import de.bluecolored.bluemap.common.serverinterface.CommandSource; +import de.bluecolored.bluemap.common.serverinterface.ServerWorld; +import de.bluecolored.bluemap.core.world.World; +import me.lucko.fabric.api.permissions.v0.Permissions; +import net.minecraft.registry.BuiltinRegistries; +import net.minecraft.registry.RegistryWrapper; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.util.math.Vec3d; + +import java.util.Optional; + +public class FabricCommandSource implements CommandSource { + + private static final RegistryWrapper.WrapperLookup lookup = BuiltinRegistries.createWrapperLookup(); + + private final FabricMod mod; + private final Plugin plugin; + private final ServerCommandSource delegate; + + public FabricCommandSource(FabricMod mod, Plugin plugin, ServerCommandSource delegate) { + this.mod = mod; + this.plugin = plugin; + this.delegate = delegate; + } + + @Override + public void sendMessage(Text text) { + delegate.sendFeedback( + () -> net.minecraft.text.Text.Serialization + .fromJson(text.toJSONString(), lookup), + false + ); + } + + @Override + public boolean hasPermission(String permission) { + try { + Class.forName("me.lucko.fabric.api.permissions.v0.Permissions"); + return Permissions.check(delegate, permission, 1); + } catch (ClassNotFoundException ex) { + return delegate.hasPermissionLevel(1); + } + } + + @Override + public Optional getPosition() { + Vec3d pos = delegate.getPosition(); + if (pos != null) { + return Optional.of(new Vector3d(pos.x, pos.y, pos.z)); + } + + return Optional.empty(); + } + + @Override + public Optional getWorld() { + ServerWorld serverWorld = mod.getServerWorld(delegate.getWorld()); + return Optional.ofNullable(plugin.getWorld(serverWorld)); + } + +} diff --git a/implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/FabricEventForwarder.java b/implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/FabricEventForwarder.java new file mode 100644 index 000000000..411e1c344 --- /dev/null +++ b/implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/FabricEventForwarder.java @@ -0,0 +1,76 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.fabric; + +import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.UUID; + +public class FabricEventForwarder { + + private final FabricMod mod; + private final Collection eventListeners; + + public FabricEventForwarder(FabricMod mod) { + this.mod = mod; + this.eventListeners = new ArrayList<>(1); + + ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { + this.onPlayerJoin(server, handler.getPlayer()); + }); + + ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> { + this.onPlayerLeave(server, handler.getPlayer()); + }); + } + + public synchronized void addEventListener(ServerEventListener listener) { + this.eventListeners.add(listener); + } + + public synchronized void removeAllListeners() { + this.eventListeners.clear(); + } + + public synchronized void onPlayerJoin(MinecraftServer server, ServerPlayerEntity player) { + if (this.mod.getServer() != server) return; + + UUID uuid = player.getUuid(); + for (ServerEventListener listener : eventListeners) listener.onPlayerJoin(uuid); + } + + public synchronized void onPlayerLeave(MinecraftServer server, ServerPlayerEntity player) { + if (this.mod.getServer() != server) return; + + UUID uuid = player.getUuid(); + for (ServerEventListener listener : eventListeners) listener.onPlayerLeave(uuid); + } + +} diff --git a/implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/FabricMod.java b/implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/FabricMod.java new file mode 100644 index 000000000..ada6b842b --- /dev/null +++ b/implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/FabricMod.java @@ -0,0 +1,241 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.fabric; + +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; +import de.bluecolored.bluemap.common.plugin.Plugin; +import de.bluecolored.bluemap.common.plugin.commands.Commands; +import de.bluecolored.bluemap.common.serverinterface.Player; +import de.bluecolored.bluemap.common.serverinterface.Server; +import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; +import de.bluecolored.bluemap.common.serverinterface.ServerWorld; +import de.bluecolored.bluemap.core.BlueMap; +import de.bluecolored.bluemap.core.logger.Logger; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; +import net.minecraft.SharedConstants; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Identifier; +import net.minecraft.world.World; +import org.apache.logging.log4j.LogManager; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public class FabricMod implements ModInitializer, Server { + + private final Plugin pluginInstance; + private MinecraftServer serverInstance = null; + + private final FabricEventForwarder eventForwarder; + + private final LoadingCache worlds; + + private int playerUpdateIndex = 0; + private final Map onlinePlayerMap; + private final List onlinePlayerList; + + public FabricMod() { + Logger.global.clear(); + Logger.global.put(new Log4jLogger(LogManager.getLogger(Plugin.PLUGIN_NAME))); + + this.onlinePlayerMap = new ConcurrentHashMap<>(); + this.onlinePlayerList = Collections.synchronizedList(new ArrayList<>()); + + pluginInstance = new Plugin("fabric", this); + + this.eventForwarder = new FabricEventForwarder(this); + this.worlds = Caffeine.newBuilder() + .executor(BlueMap.THREAD_POOL) + .weakKeys() + .maximumSize(1000) + .build(FabricWorld::new); + } + + @Override + public void onInitialize() { + + //register commands + CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> + new Commands<>(pluginInstance, dispatcher, fabricSource -> + new FabricCommandSource(this, pluginInstance, fabricSource) + ) + ); + + ServerLifecycleEvents.SERVER_STARTED.register((MinecraftServer server) -> { + this.serverInstance = server; + + new Thread(()->{ + Logger.global.logInfo("Loading BlueMap..."); + + try { + pluginInstance.load(); + if (pluginInstance.isLoaded()) Logger.global.logInfo("BlueMap loaded!"); + } catch (IOException e) { + Logger.global.logError("Failed to load bluemap!", e); + pluginInstance.unload(); + } + }, "BlueMap-Plugin-Loading").start(); + }); + + ServerLifecycleEvents.SERVER_STOPPING.register((MinecraftServer server) -> { + pluginInstance.unload(); + Logger.global.logInfo("BlueMap unloaded!"); + }); + + ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { + this.onPlayerJoin(server, handler.getPlayer()); + }); + + ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> { + this.onPlayerLeave(server, handler.getPlayer()); + }); + + ServerTickEvents.END_SERVER_TICK.register((MinecraftServer server) -> { + if (server == this.serverInstance) this.updateSomePlayers(); + }); + } + + @Override + public String getMinecraftVersion() { + return SharedConstants.getGameVersion().getId(); + } + + @Override + public void registerListener(ServerEventListener listener) { + eventForwarder.addEventListener(listener); + } + + @Override + public void unregisterAllListeners() { + eventForwarder.removeAllListeners(); + } + + @Override + public Collection getLoadedServerWorlds() { + Collection loadedWorlds = new ArrayList<>(3); + for (net.minecraft.server.world.ServerWorld serverWorld : serverInstance.getWorlds()) { + loadedWorlds.add(worlds.get(serverWorld)); + } + return loadedWorlds; + } + + @SuppressWarnings("unchecked") + @Override + public Optional getServerWorld(Object world) { + + if (world instanceof String) { + Identifier identifier = Identifier.tryParse((String) world); + if (identifier != null) world = serverInstance.getWorld(RegistryKey.of(RegistryKeys.WORLD, identifier)); + } + + if (world instanceof RegistryKey) { + try { + world = serverInstance.getWorld((RegistryKey) world); + } catch (ClassCastException ignored) {} + } + + if (world instanceof net.minecraft.server.world.ServerWorld) + return Optional.of(getServerWorld((net.minecraft.server.world.ServerWorld) world)); + + return Optional.empty(); + } + + public ServerWorld getServerWorld(net.minecraft.server.world.ServerWorld serverWorld) { + return worlds.get(serverWorld); + } + + @Override + public Path getConfigFolder() { + return Path.of("config", "bluemap"); + } + + @Override + public Optional getModsFolder() { + return Optional.of(Path.of("mods")); + } + + public void onPlayerJoin(MinecraftServer server, ServerPlayerEntity playerInstance) { + if (this.serverInstance != server) return; + + FabricPlayer player = new FabricPlayer(playerInstance.getUuid(), this); + onlinePlayerMap.put(player.getUuid(), player); + onlinePlayerList.add(player); + } + + public void onPlayerLeave(MinecraftServer server, ServerPlayerEntity player) { + if (this.serverInstance != server) return; + + UUID playerUUID = player.getUuid(); + onlinePlayerMap.remove(playerUUID); + synchronized (onlinePlayerList) { + onlinePlayerList.removeIf(p -> p.getUuid().equals(playerUUID)); + } + } + + public MinecraftServer getServer() { + return this.serverInstance; + } + + public Plugin getPluginInstance() { + return pluginInstance; + } + + @Override + public Collection getOnlinePlayers() { + return onlinePlayerMap.values(); + } + + /** + * Only update some of the online players each tick to minimize performance impact on the server-thread. + * Only call this method on the server-thread. + */ + private void updateSomePlayers() { + int onlinePlayerCount = onlinePlayerList.size(); + if (onlinePlayerCount == 0) return; + + int playersToBeUpdated = onlinePlayerCount / 20; //with 20 tps, each player is updated once a second + if (playersToBeUpdated == 0) playersToBeUpdated = 1; + + for (int i = 0; i < playersToBeUpdated; i++) { + playerUpdateIndex++; + if (playerUpdateIndex >= 20 && playerUpdateIndex >= onlinePlayerCount) playerUpdateIndex = 0; + + if (playerUpdateIndex < onlinePlayerCount) { + onlinePlayerList.get(playerUpdateIndex).update(); + } + } + } + +} diff --git a/implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/FabricPlayer.java b/implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/FabricPlayer.java new file mode 100644 index 000000000..6dcf2428f --- /dev/null +++ b/implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/FabricPlayer.java @@ -0,0 +1,153 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.fabric; + +import com.flowpowered.math.vector.Vector3d; +import de.bluecolored.bluemap.common.plugin.text.Text; +import de.bluecolored.bluemap.common.serverinterface.Gamemode; +import de.bluecolored.bluemap.common.serverinterface.Player; +import de.bluecolored.bluemap.common.serverinterface.ServerWorld; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.GameMode; +import net.minecraft.world.LightType; + +import java.util.EnumMap; +import java.util.Map; +import java.util.UUID; + +public class FabricPlayer implements Player { + + private static final Map GAMEMODE_MAP = new EnumMap<>(GameMode.class); + static { + GAMEMODE_MAP.put(GameMode.ADVENTURE, Gamemode.ADVENTURE); + GAMEMODE_MAP.put(GameMode.SURVIVAL, Gamemode.SURVIVAL); + GAMEMODE_MAP.put(GameMode.CREATIVE, Gamemode.CREATIVE); + GAMEMODE_MAP.put(GameMode.SPECTATOR, Gamemode.SPECTATOR); + } + + private final UUID uuid; + private Text name; + private ServerWorld world; + private Vector3d position; + private Vector3d rotation; + private int skyLight; + private int blockLight; + private boolean sneaking; + private boolean invisible; + private Gamemode gamemode; + + private final FabricMod mod; + + public FabricPlayer(UUID playerUuid, FabricMod mod) { + this.uuid = playerUuid; + this.mod = mod; + + update(); + } + + @Override + public UUID getUuid() { + return this.uuid; + } + + @Override + public Text getName() { + return this.name; + } + + @Override + public ServerWorld getWorld() { + return this.world; + } + + @Override + public Vector3d getPosition() { + return this.position; + } + + @Override + public Vector3d getRotation() { + return rotation; + } + + @Override + public int getSkyLight() { + return skyLight; + } + + @Override + public int getBlockLight() { + return blockLight; + } + + @Override + public boolean isSneaking() { + return this.sneaking; + } + + @Override + public boolean isInvisible() { + return this.invisible; + } + + @Override + public Gamemode getGamemode() { + return this.gamemode; + } + + /** + * Only call on server thread! + */ + public void update() { + MinecraftServer server = mod.getServer(); + if (server == null) return; + + ServerPlayerEntity player = server.getPlayerManager().getPlayer(uuid); + if (player == null) return; + + this.gamemode = GAMEMODE_MAP.get(player.interactionManager.getGameMode()); + if (this.gamemode == null) this.gamemode = Gamemode.SURVIVAL; + + StatusEffectInstance invis = player.getStatusEffect(StatusEffects.INVISIBILITY); + this.invisible = invis != null && invis.getDuration() > 0; + + this.name = Text.of(player.getName().getString()); + + Vec3d pos = player.getPos(); + this.position = new Vector3d(pos.getX(), pos.getY(), pos.getZ()); + this.rotation = new Vector3d(player.getPitch(), player.getHeadYaw(), 0); + this.sneaking = player.isSneaking(); + + this.skyLight = player.getWorld().getLightingProvider().get(LightType.SKY).getLightLevel(player.getBlockPos()); + this.blockLight = player.getWorld().getLightingProvider().get(LightType.BLOCK).getLightLevel(player.getBlockPos()); + + this.world = mod.getServerWorld(player.getServerWorld()); + } + +} diff --git a/implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/FabricWorld.java b/implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/FabricWorld.java new file mode 100644 index 000000000..ff4468d90 --- /dev/null +++ b/implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/FabricWorld.java @@ -0,0 +1,110 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.fabric; + +import de.bluecolored.bluemap.common.serverinterface.ServerWorld; +import de.bluecolored.bluemap.core.util.Key; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.Identifier; +import net.minecraft.util.WorldSavePath; + +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.nio.file.Path; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; + +public class FabricWorld implements ServerWorld { + + private final WeakReference delegate; + private final Path worldFolder; + private final Key dimension; + + public FabricWorld(net.minecraft.server.world.ServerWorld delegate) { + this.delegate = new WeakReference<>(delegate); + + MinecraftServer server = delegate.getServer(); + this.worldFolder = delegate.getServer().getRunDirectory().toPath() + .resolve(server.getSavePath(WorldSavePath.ROOT)); + + Identifier id = delegate.getRegistryKey().getValue(); + this.dimension = new Key(id.getNamespace(), id.getPath()); + } + + @Override + public boolean persistWorldChanges() throws IOException { + net.minecraft.server.world.ServerWorld world = delegate.get(); + if (world == null) return false; + + var taskResult = CompletableFuture.supplyAsync(() -> { + try { + world.save(null, true, false); + return true; + } catch (Exception e) { + throw new CompletionException(e); + } + }, world.getServer()); + + try { + return taskResult.get(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException(e); + } catch (ExecutionException e) { + Throwable t = e.getCause(); + if (t instanceof IOException) throw (IOException) t; + if (t instanceof IllegalArgumentException) throw (IllegalArgumentException) t; + throw new IOException(t); + } + } + + @Override + public Path getWorldFolder() { + return worldFolder; + } + + @Override + public Key getDimension() { + return dimension; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + FabricWorld that = (FabricWorld) o; + Object world = delegate.get(); + return world != null && world.equals(that.delegate.get()); + } + + @Override + public int hashCode() { + Object world = delegate.get(); + return world != null ? world.hashCode() : 0; + } + +} diff --git a/implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/Log4jLogger.java b/implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/Log4jLogger.java new file mode 100644 index 000000000..9e60f395d --- /dev/null +++ b/implementations/fabric/src/main/java/de/bluecolored/bluemap/fabric/Log4jLogger.java @@ -0,0 +1,69 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.fabric; + +import org.apache.logging.log4j.Logger; + +import de.bluecolored.bluemap.core.logger.AbstractLogger; + +public class Log4jLogger extends AbstractLogger { + + private final Logger out; + + public Log4jLogger(Logger out) { + this.out = out; + } + + @Override + public void logError(String message, Throwable throwable) { + out.error(message, throwable); + } + + @Override + public void logWarning(String message) { + out.warn(message); + } + + @Override + public void logInfo(String message) { + out.info(message); + } + + @Override + public void logDebug(String message) { + if (out.isDebugEnabled()) out.debug(message); + } + + @Override + public void noFloodDebug(String message) { + if (out.isDebugEnabled()) super.noFloodDebug(message); + } + + @Override + public void noFloodDebug(String key, String message) { + if (out.isDebugEnabled()) super.noFloodDebug(key, message); + } + +} diff --git a/implementations/fabric/src/main/resources/assets/bluemap/icon.png b/implementations/fabric/src/main/resources/assets/bluemap/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..65d56d7a88fd8adb9003df6e0c10424b0ec8e375 GIT binary patch literal 10593 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 vi6!A+?}%zq>>?r?=0.15.10", + "fabric": "*", + "fabric-api-base": "*", + "minecraft": "*" + }, + "suggests": {} +} diff --git a/implementations/forge-1.18.1/build.gradle b/implementations/forge-1.18.1/build.gradle index cca34b340..02a5b7a5e 100644 --- a/implementations/forge-1.18.1/build.gradle +++ b/implementations/forge-1.18.1/build.gradle @@ -14,7 +14,7 @@ plugins { id "java-library" id "com.diffplug.spotless" version "6.1.2" id "com.github.node-gradle.node" version "3.0.1" - id "com.github.johnrengelman.shadow" version "7.1.2" + id "com.github.johnrengelman.shadow" version "8.1.1" id "com.modrinth.minotaur" version "2.+" id "com.matthewprenger.cursegradle" version "1.4.0" } diff --git a/implementations/forge-1.19.4/build.gradle b/implementations/forge-1.19.4/build.gradle index 876f41bad..1b8278385 100644 --- a/implementations/forge-1.19.4/build.gradle +++ b/implementations/forge-1.19.4/build.gradle @@ -14,7 +14,7 @@ plugins { id "java-library" id "com.diffplug.spotless" version "6.1.2" id "com.github.node-gradle.node" version "3.0.1" - id "com.github.johnrengelman.shadow" version "7.1.2" + id "com.github.johnrengelman.shadow" version "8.1.1" id "com.modrinth.minotaur" version "2.+" id "com.matthewprenger.cursegradle" version "1.4.0" } diff --git a/implementations/forge-1.20/build.gradle b/implementations/forge-1.20/build.gradle index 79a7a431b..d538fcbd5 100644 --- a/implementations/forge-1.20/build.gradle +++ b/implementations/forge-1.20/build.gradle @@ -14,7 +14,7 @@ plugins { id "java-library" id "com.diffplug.spotless" version "6.1.2" id "com.github.node-gradle.node" version "3.0.1" - id "com.github.johnrengelman.shadow" version "7.1.2" + id "com.github.johnrengelman.shadow" version "8.1.1" id "com.modrinth.minotaur" version "2.+" id "com.matthewprenger.cursegradle" version "1.4.0" } diff --git a/implementations/forge/build.gradle b/implementations/forge/build.gradle new file mode 100644 index 000000000..bfb6604c5 --- /dev/null +++ b/implementations/forge/build.gradle @@ -0,0 +1,195 @@ +buildscript { + repositories { + // These repositories are only for Gradle plugins, put any other repositories in the repository block further below + maven { url = 'https://maven.minecraftforge.net' } + mavenCentral() + } + dependencies { + classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '[6.0.24,6.2)', changing: true + } +} + +plugins { + id "java" + id "java-library" + id "com.diffplug.spotless" version "6.1.2" + id "com.github.node-gradle.node" version "3.0.1" + id "com.github.johnrengelman.shadow" version "8.1.1" + id "com.modrinth.minotaur" version "2.+" + id "com.matthewprenger.cursegradle" version "1.4.0" +} + +apply plugin: "net.minecraftforge.gradle" + +group = "de.bluecolored.bluemap" +version = System.getProperty("bluemap.version") ?: "?" // set by BlueMapCore +archivesBaseName = 'bluemap' + +java.toolchain.languageVersion = JavaLanguageVersion.of(21) + +minecraft { + mappings channel: 'official', version: '1.20.6' + + reobf = false + + runs { + server { + workingDirectory project.file('run') + property 'forge.logging.markers', 'REGISTRIES' + property 'forge.logging.console.level', 'debug' + + mods { + bluemap { + source sourceSets.main + } + } + } + } +} + +sourceSets.main.resources { srcDir 'src/generated/resources' } + +repositories { + mavenCentral() + maven { url = "https://libraries.minecraft.net" } + maven { url = "https://repo.bluecolored.de/releases" } +} + +configurations { + implementation.extendsFrom(shadowInclude) +} + +dependencies { + minecraft 'net.minecraftforge:forge:1.20.6-50.0.13' + + shadowInclude ("de.bluecolored.bluemap:BlueMapCommon") { + //exclude dependencies provided by forge + exclude (group: "com.google.guava", module: "guava") + exclude (group: "com.google.code.gson", module: "gson") + exclude (group: "com.mojang", module: "brigadier") + } + + testImplementation ("org.junit.jupiter:junit-jupiter:5.8.2") + testRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.8.2") +} + +spotless { + java { + target ("src/*/java/**/*.java") + + licenseHeaderFile("../../HEADER") + indentWithSpaces() + trimTrailingWhitespace() + } +} + +jar { + manifest { + attributes([ + "Specification-Title" : "bluemap", + "Specification-Vendor" : "bluemap", + "Specification-Version" : "1", // We are version 1 of ourselves + "Implementation-Title" : project.name, + "Implementation-Version" : project.jar.archiveVersion, + "Implementation-Vendor" : "bluemap", + "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") + ]) + } +} + +tasks.withType(JavaCompile).configureEach { + options.encoding = "utf-8" +} + +tasks.withType(AbstractArchiveTask).configureEach { + setReproducibleFileOrder(true) + setPreserveFileTimestamps(false) +} + +test { + useJUnitPlatform() +} + +shadowJar { + def version = System.getProperty("bluemap.version") ?: "" // set by BlueMapCore + destinationDirectory.set(file("../../build/release")) + archiveFileName.set("BlueMap-${project.version}-${project.name}.jar") + + configurations = [project.configurations.shadowInclude] + + //relocate ("com.flowpowered.math", "de.bluecolored.shadow.flowpowered.math") //DON"T relocate this, because the API depends on it + relocate ("com.typesafe.config", "de.bluecolored.shadow.typesafe.config") + relocate ("de.bluecolored.bluenbt", "de.bluecolored.shadow.bluenbt") + relocate ("org.spongepowered.configurate", "de.bluecolored.shadow.configurate") + relocate ("com.github.benmanes.caffeine", "de.bluecolored.shadow.benmanes.caffeine") + relocate ("org.aopalliance", "de.bluecolored.shadow.aopalliance") + relocate ("javax.inject", "de.bluecolored.shadow.javax.inject") + relocate ("org.checkerframework", "de.bluecolored.shadow.checkerframework") + relocate ("org.codehaus", "de.bluecolored.shadow.codehaus") + relocate ("io.leangen.geantyref", "de.bluecolored.shadow.geantyref") + relocate ("io.airlift", "de.bluecolored.shadow.airlift") + relocate ("net.jpountz", "de.bluecolored.shadow.jpountz") + + relocate ("com.google.errorprone", "de.bluecolored.shadow.google.errorprone") + relocate ("com.google.inject", "de.bluecolored.shadow.google.inject") + + relocate ("org.apache.commons.dbcp2", "de.bluecolored.shadow.apache.commons.dbcp2") + relocate ("org.apache.commons.logging", "de.bluecolored.shadow.apache.commons.logging") + relocate ("org.apache.commons.pool2", "de.bluecolored.shadow.apache.commons.pool2") +} + +processResources { + from(sourceSets.main.resources.srcDirs) { + include 'mcmod.info','META-INF/mods.toml' + duplicatesStrategy = DuplicatesStrategy.WARN + + expand ( + version: project.version + ) + } +} + +task release { + dependsOn(shadowJar) +} + +modrinth { + token = System.getenv("MODRINTH_TOKEN") + projectId = "swbUV1cr" + versionNumber = "${project.version}-${project.name}" + changelog = file("../../release.md") + .getText() + .replace("{version}", project.version.toString()) + uploadFile = shadowJar + gameVersions = ["1.20.6"] +} + +curseforge { + apiKey = System.getenv("CURSEFORGE_TOKEN") ?: "" + project { + id = "406463" + changelogType = "markdown" + changelog = file("../../release.md") + .getText() + .replace("{version}", project.version.toString()) + releaseType = "release" + + addGameVersion "Forge" + + addGameVersion "Java 21" + + addGameVersion "1.20.6" + + mainArtifact shadowJar + } + options { + javaVersionAutoDetect = false + javaIntegration = false + forgeGradleIntegration = false + } +} + +task publish { + dependsOn(tasks.findByName("modrinth")) + dependsOn(tasks.findByName("curseforge")) +} diff --git a/implementations/forge/settings.gradle.kts b/implementations/forge/settings.gradle.kts new file mode 100644 index 000000000..768bb0580 --- /dev/null +++ b/implementations/forge/settings.gradle.kts @@ -0,0 +1,3 @@ +rootProject.name = "forge" + +includeBuild("../../BlueMapCommon") diff --git a/implementations/neoforge-1.20.2/src/main/java/de/bluecolored/bluemap/forge/ForgeCommandSource.java b/implementations/forge/src/main/java/de/bluecolored/bluemap/forge/ForgeCommandSource.java similarity index 92% rename from implementations/neoforge-1.20.2/src/main/java/de/bluecolored/bluemap/forge/ForgeCommandSource.java rename to implementations/forge/src/main/java/de/bluecolored/bluemap/forge/ForgeCommandSource.java index 64428e6f7..564b7b256 100644 --- a/implementations/neoforge-1.20.2/src/main/java/de/bluecolored/bluemap/forge/ForgeCommandSource.java +++ b/implementations/forge/src/main/java/de/bluecolored/bluemap/forge/ForgeCommandSource.java @@ -31,12 +31,16 @@ import de.bluecolored.bluemap.common.serverinterface.ServerWorld; import de.bluecolored.bluemap.core.world.World; import net.minecraft.commands.CommandSourceStack; +import net.minecraft.core.HolderLookup; +import net.minecraft.data.registries.VanillaRegistries; import net.minecraft.network.chat.Component; import java.util.Optional; public class ForgeCommandSource implements CommandSource { + private static final HolderLookup.Provider lookup = VanillaRegistries.createLookup(); + private final ForgeMod mod; private final Plugin plugin; private final CommandSourceStack delegate; @@ -49,7 +53,7 @@ public ForgeCommandSource(ForgeMod mod, Plugin plugin, CommandSourceStack delega @Override public void sendMessage(Text text) { - var component = Component.Serializer.fromJsonLenient(text.toJSONString()); + var component = Component.Serializer.fromJsonLenient(text.toJSONString(), lookup); if (component != null) delegate.sendSuccess(() -> component, false); } diff --git a/implementations/forge/src/main/java/de/bluecolored/bluemap/forge/ForgeEventForwarder.java b/implementations/forge/src/main/java/de/bluecolored/bluemap/forge/ForgeEventForwarder.java new file mode 100644 index 000000000..f4311881b --- /dev/null +++ b/implementations/forge/src/main/java/de/bluecolored/bluemap/forge/ForgeEventForwarder.java @@ -0,0 +1,67 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.forge; + +import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.player.PlayerEvent.PlayerLoggedInEvent; +import net.minecraftforge.event.entity.player.PlayerEvent.PlayerLoggedOutEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.UUID; + +public class ForgeEventForwarder { + + private final Collection eventListeners; + + public ForgeEventForwarder() { + this.eventListeners = new ArrayList<>(1); + + MinecraftForge.EVENT_BUS.register(this); + } + + public synchronized void addEventListener(ServerEventListener listener) { + this.eventListeners.add(listener); + } + + public synchronized void removeAllListeners() { + this.eventListeners.clear(); + } + + @SubscribeEvent + public synchronized void onPlayerJoin(PlayerLoggedInEvent evt) { + UUID uuid = evt.getEntity().getUUID(); + for (ServerEventListener listener : eventListeners) listener.onPlayerJoin(uuid); + } + + @SubscribeEvent + public synchronized void onPlayerLeave(PlayerLoggedOutEvent evt) { + UUID uuid = evt.getEntity().getUUID(); + for (ServerEventListener listener : eventListeners) listener.onPlayerLeave(uuid); + } + +} diff --git a/implementations/forge/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java b/implementations/forge/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java new file mode 100644 index 000000000..2a3277f1c --- /dev/null +++ b/implementations/forge/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java @@ -0,0 +1,262 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.forge; + +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; +import de.bluecolored.bluemap.common.plugin.Plugin; +import de.bluecolored.bluemap.common.plugin.commands.Commands; +import de.bluecolored.bluemap.common.serverinterface.Player; +import de.bluecolored.bluemap.common.serverinterface.Server; +import de.bluecolored.bluemap.common.serverinterface.ServerEventListener; +import de.bluecolored.bluemap.common.serverinterface.ServerWorld; +import de.bluecolored.bluemap.core.BlueMap; +import de.bluecolored.bluemap.core.logger.Logger; +import net.minecraft.SharedConstants; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.RegisterCommandsEvent; +import net.minecraftforge.event.TickEvent.ServerTickEvent; +import net.minecraftforge.event.entity.player.PlayerEvent.PlayerLoggedInEvent; +import net.minecraftforge.event.entity.player.PlayerEvent.PlayerLoggedOutEvent; +import net.minecraftforge.event.server.ServerStartedEvent; +import net.minecraftforge.event.server.ServerStartingEvent; +import net.minecraftforge.event.server.ServerStoppingEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.IExtensionPoint; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.common.Mod; +import org.apache.logging.log4j.LogManager; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +@Mod(Plugin.PLUGIN_ID) +public class ForgeMod implements Server { + + private final Plugin pluginInstance; + private MinecraftServer serverInstance = null; + + private final ForgeEventForwarder eventForwarder; + private final LoadingCache worlds; + + private int playerUpdateIndex = 0; + private final Map onlinePlayerMap; + private final List onlinePlayerList; + + public ForgeMod() { + Logger.global.clear(); + Logger.global.put(new Log4jLogger(LogManager.getLogger(Plugin.PLUGIN_NAME))); + + this.onlinePlayerMap = new ConcurrentHashMap<>(); + this.onlinePlayerList = Collections.synchronizedList(new ArrayList<>()); + + this.pluginInstance = new Plugin("forge", this); + + this.eventForwarder = new ForgeEventForwarder(); + this.worlds = Caffeine.newBuilder() + .executor(BlueMap.THREAD_POOL) + .weakKeys() + .maximumSize(1000) + .build(ForgeWorld::new); + + MinecraftForge.EVENT_BUS.register(this); + + //Make sure the mod being absent on the other network side does not cause the client to display the server as incompatible + ModLoadingContext.get().registerExtensionPoint( + IExtensionPoint.DisplayTest.class, + () -> new IExtensionPoint.DisplayTest( + () -> IExtensionPoint.DisplayTest.IGNORESERVERONLY, + (a, b) -> true + ) + ); + } + + @SubscribeEvent + public void onServerStarting(ServerStartingEvent event) { + this.serverInstance = event.getServer(); + } + + @SubscribeEvent + public void onRegisterCommands(RegisterCommandsEvent event) { + //register commands + new Commands<>(pluginInstance, event.getDispatcher(), forgeSource -> + new ForgeCommandSource(this, pluginInstance, forgeSource) + ); + } + + @SubscribeEvent + public void onServerStarted(ServerStartedEvent event) { + //save worlds to generate level.dat files + serverInstance.saveAllChunks(false, true, true); + + new Thread(() -> { + Logger.global.logInfo("Loading..."); + + try { + pluginInstance.load(); + if (pluginInstance.isLoaded()) Logger.global.logInfo("Loaded!"); + } catch (IOException e) { + Logger.global.logError("Failed to load bluemap!", e); + pluginInstance.unload(); + } + }, "BlueMap-Plugin-Loading").start(); + } + + @SubscribeEvent + public void onServerStopping(ServerStoppingEvent event) { + pluginInstance.unload(); + Logger.global.logInfo("BlueMap unloaded!"); + } + + @SubscribeEvent + public void onTick(ServerTickEvent evt) { + updateSomePlayers(); + } + + @Override + public String getMinecraftVersion() { + return SharedConstants.getCurrentVersion().getId(); + } + + @Override + public void registerListener(ServerEventListener listener) { + eventForwarder.addEventListener(listener); + } + + @Override + public void unregisterAllListeners() { + eventForwarder.removeAllListeners(); + } + + @Override + public Collection getLoadedServerWorlds() { + Collection loadedWorlds = new ArrayList<>(3); + for (ServerLevel serverWorld : serverInstance.getAllLevels()) { + loadedWorlds.add(worlds.get(serverWorld)); + } + return loadedWorlds; + } + + @SuppressWarnings("unchecked") + @Override + public Optional getServerWorld(Object world) { + + if (world instanceof String) { + ResourceLocation resourceLocation = ResourceLocation.tryParse((String) world); + if (resourceLocation != null) world = serverInstance.getLevel(ResourceKey.create(Registries.DIMENSION, resourceLocation)); + } + + if (world instanceof ResourceKey) { + try { + world = serverInstance.getLevel((ResourceKey) world); + } catch (ClassCastException ignored) {} + } + + if (world instanceof ServerLevel) + return Optional.of(getServerWorld((ServerLevel) world)); + + return Optional.empty(); + } + + public ServerWorld getServerWorld(ServerLevel world) { + return worlds.get(world); + } + + @Override + public Path getConfigFolder() { + return Path.of("config", "bluemap"); + } + + @Override + public Optional getModsFolder() { + return Optional.of(Path.of("mods")); + } + + @SubscribeEvent + public void onPlayerJoin(PlayerLoggedInEvent evt) { + var playerInstance = evt.getEntity(); + if (!(playerInstance instanceof ServerPlayer)) return; + + ForgePlayer player = new ForgePlayer(playerInstance.getUUID(), this); + onlinePlayerMap.put(player.getUuid(), player); + onlinePlayerList.add(player); + } + + @SubscribeEvent + public void onPlayerLeave(PlayerLoggedOutEvent evt) { + var player = evt.getEntity(); + if (!(player instanceof ServerPlayer)) return; + + UUID playerUUID = player.getUUID(); + onlinePlayerMap.remove(playerUUID); + synchronized (onlinePlayerList) { + onlinePlayerList.removeIf(p -> p.getUuid().equals(playerUUID)); + } + } + + public MinecraftServer getServer() { + return this.serverInstance; + } + + public Plugin getPlugin() { + return this.pluginInstance; + } + + @Override + public Collection getOnlinePlayers() { + return onlinePlayerMap.values(); + } + + /** + * Only update some of the online players each tick to minimize performance impact on the server-thread. + * Only call this method on the server-thread. + */ + private void updateSomePlayers() { + int onlinePlayerCount = onlinePlayerList.size(); + if (onlinePlayerCount == 0) return; + + int playersToBeUpdated = onlinePlayerCount / 20; //with 20 tps, each player is updated once a second + if (playersToBeUpdated == 0) playersToBeUpdated = 1; + + for (int i = 0; i < playersToBeUpdated; i++) { + playerUpdateIndex++; + if (playerUpdateIndex >= 20 && playerUpdateIndex >= onlinePlayerCount) playerUpdateIndex = 0; + + if (playerUpdateIndex < onlinePlayerCount) { + onlinePlayerList.get(playerUpdateIndex).update(); + } + } + } + +} diff --git a/implementations/neoforge-1.20.2/src/main/java/de/bluecolored/bluemap/forge/ForgePlayer.java b/implementations/forge/src/main/java/de/bluecolored/bluemap/forge/ForgePlayer.java similarity index 100% rename from implementations/neoforge-1.20.2/src/main/java/de/bluecolored/bluemap/forge/ForgePlayer.java rename to implementations/forge/src/main/java/de/bluecolored/bluemap/forge/ForgePlayer.java diff --git a/implementations/neoforge-1.20.2/src/main/java/de/bluecolored/bluemap/forge/ForgeWorld.java b/implementations/forge/src/main/java/de/bluecolored/bluemap/forge/ForgeWorld.java similarity index 100% rename from implementations/neoforge-1.20.2/src/main/java/de/bluecolored/bluemap/forge/ForgeWorld.java rename to implementations/forge/src/main/java/de/bluecolored/bluemap/forge/ForgeWorld.java diff --git a/implementations/forge/src/main/java/de/bluecolored/bluemap/forge/Log4jLogger.java b/implementations/forge/src/main/java/de/bluecolored/bluemap/forge/Log4jLogger.java new file mode 100644 index 000000000..a77265e0e --- /dev/null +++ b/implementations/forge/src/main/java/de/bluecolored/bluemap/forge/Log4jLogger.java @@ -0,0 +1,69 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.forge; + +import org.apache.logging.log4j.Logger; + +import de.bluecolored.bluemap.core.logger.AbstractLogger; + +public class Log4jLogger extends AbstractLogger { + + private final Logger out; + + public Log4jLogger(Logger out) { + this.out = out; + } + + @Override + public void logError(String message, Throwable throwable) { + out.error(message, throwable); + } + + @Override + public void logWarning(String message) { + out.warn(message); + } + + @Override + public void logInfo(String message) { + out.info(message); + } + + @Override + public void logDebug(String message) { + if (out.isDebugEnabled()) out.debug(message); + } + + @Override + public void noFloodDebug(String message) { + if (out.isDebugEnabled()) super.noFloodDebug(message); + } + + @Override + public void noFloodDebug(String key, String message) { + if (out.isDebugEnabled()) super.noFloodDebug(key, message); + } + +} diff --git a/implementations/forge/src/main/resources/META-INF/mods.toml b/implementations/forge/src/main/resources/META-INF/mods.toml new file mode 100644 index 000000000..e5f5a4cb4 --- /dev/null +++ b/implementations/forge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,26 @@ +modLoader="javafml" +loaderVersion="[44,)" +license="MIT" +issueTrackerURL="https://github.com/BlueMap-Minecraft/BlueMap/issues" +[[mods]] +modId="bluemap" +version="${version}" +displayName="BlueMap" +displayURL="https://github.com/BlueMap-Minecraft/BlueMap" +authors="Blue (TBlueF, Lukas Rieger)" +description=''' +A 3d-map of your Minecraft worlds view-able in your browser using three.js (WebGL) +''' + +[[dependencies.bluemap]] + modId="forge" + mandatory=true + versionRange="[50,)" + ordering="NONE" + side="SERVER" +[[dependencies.bluemap]] + modId="minecraft" + mandatory=true + versionRange="[1.20.6,)" + ordering="NONE" + side="SERVER" diff --git a/implementations/forge/src/main/resources/pack.mcmeta b/implementations/forge/src/main/resources/pack.mcmeta new file mode 100644 index 000000000..0f95ce1ce --- /dev/null +++ b/implementations/forge/src/main/resources/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "description": "BlueMap - A 3d-map of your Minecraft worlds view-able in your browser using three.js (WebGL)", + "pack_format": 8 + } +} diff --git a/implementations/neoforge-1.20.2/gradle.properties b/implementations/neoforge-1.20.2/gradle.properties deleted file mode 100644 index cfb744f0d..000000000 --- a/implementations/neoforge-1.20.2/gradle.properties +++ /dev/null @@ -1,16 +0,0 @@ -org.gradle.daemon=false -org.gradle.debug=false - -minecraft_version=1.20.2 -minecraft_version_range=[1.20.2,1.21) -neo_version=20.2.86 -neo_version_range=[20.2,) -loader_version_range=[1,) -mapping_channel=official -mapping_version=1.20.2 - -mod_id=bluemap -mod_name=BlueMap -mod_description=A 3d-map of your Minecraft worlds view-able in your browser using three.js (WebGL) -mod_license=MIT -pack_format_number=18 diff --git a/implementations/neoforge-1.20.2/build.gradle b/implementations/neoforge/build.gradle similarity index 90% rename from implementations/neoforge-1.20.2/build.gradle rename to implementations/neoforge/build.gradle index bfe68b5af..700e8bc4e 100644 --- a/implementations/neoforge-1.20.2/build.gradle +++ b/implementations/neoforge/build.gradle @@ -1,12 +1,12 @@ plugins { id "java" id "java-library" - id "net.neoforged.gradle.userdev" version '7.0.57' + id "net.neoforged.gradle.userdev" version '7.0.120' id "com.diffplug.spotless" version "6.1.2" id "com.github.node-gradle.node" version "3.0.1" id "com.modrinth.minotaur" version "2.+" id "com.matthewprenger.cursegradle" version "1.4.0" - id "com.github.johnrengelman.shadow" version "7.1.2" + id "com.github.johnrengelman.shadow" version "8.1.1" } group = "de.bluecolored.bluemap" @@ -22,7 +22,7 @@ base { archivesName = "bluemap" } -java.toolchain.languageVersion = JavaLanguageVersion.of(17) +java.toolchain.languageVersion = JavaLanguageVersion.of(21) sourceSets.main.resources { srcDir 'src/generated/resources' } configurations { @@ -30,7 +30,7 @@ configurations { } dependencies { - implementation "net.neoforged:neoforge:20.2.86" + implementation "net.neoforged:neoforge:${neo_version}" shadowInclude ("de.bluecolored.bluemap:BlueMapCommon") { //exclude dependencies provided by forge @@ -59,7 +59,7 @@ tasks.withType(ProcessResources).configureEach { ] inputs.properties replaceProperties - filesMatching(['META-INF/mods.toml', 'pack.mcmeta']) { + filesMatching(['META-INF/neoforge.mods.toml', 'pack.mcmeta']) { expand replaceProperties + [project: project] } } @@ -127,7 +127,7 @@ modrinth { .replace("{version}", project.version.toString()) uploadFile = shadowJar loaders = ["neoforge"] - gameVersions = ["1.20.2", "1.20.3", "1.20.4"] + gameVersions = ["1.20.6"] } curseforge { @@ -142,12 +142,9 @@ curseforge { addGameVersion "NeoForge" - addGameVersion "Java 18" - addGameVersion "Java 17" + addGameVersion "Java 21" - addGameVersion "1.20.2" - addGameVersion "1.20.3" - addGameVersion "1.20.4" + addGameVersion "1.20.6" mainArtifact shadowJar } diff --git a/implementations/neoforge/gradle.properties b/implementations/neoforge/gradle.properties new file mode 100644 index 000000000..5f51b4da7 --- /dev/null +++ b/implementations/neoforge/gradle.properties @@ -0,0 +1,17 @@ +org.gradle.daemon=false +org.gradle.debug=false + +neogradle.subsystems.parchment.minecraftVersion=1.20.6 +neogradle.subsystems.parchment.mappingsVersion=2024.05.01 + +minecraft_version=1.20.6 +minecraft_version_range=[1.20.6,1.21) +neo_version=20.6.43-beta +neo_version_range=[20.5,) +loader_version_range=[2,) + +mod_id=bluemap +mod_name=BlueMap +mod_description=A 3d-map of your Minecraft worlds view-able in your browser using three.js (WebGL) +mod_license=MIT +pack_format_number=18 diff --git a/implementations/neoforge-1.20.2/settings.gradle b/implementations/neoforge/settings.gradle similarity index 88% rename from implementations/neoforge-1.20.2/settings.gradle rename to implementations/neoforge/settings.gradle index 948bd4cc4..8a6688614 100644 --- a/implementations/neoforge-1.20.2/settings.gradle +++ b/implementations/neoforge/settings.gradle @@ -10,6 +10,6 @@ plugins { id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0' } -rootProject.name = "neoforge-1.20.2" +rootProject.name = "neoforge" includeBuild("../../BlueMapCommon") \ No newline at end of file diff --git a/implementations/neoforge/src/main/java/de/bluecolored/bluemap/forge/ForgeCommandSource.java b/implementations/neoforge/src/main/java/de/bluecolored/bluemap/forge/ForgeCommandSource.java new file mode 100644 index 000000000..564b7b256 --- /dev/null +++ b/implementations/neoforge/src/main/java/de/bluecolored/bluemap/forge/ForgeCommandSource.java @@ -0,0 +1,78 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.forge; + +import com.flowpowered.math.vector.Vector3d; +import de.bluecolored.bluemap.common.plugin.Plugin; +import de.bluecolored.bluemap.common.plugin.text.Text; +import de.bluecolored.bluemap.common.serverinterface.CommandSource; +import de.bluecolored.bluemap.common.serverinterface.ServerWorld; +import de.bluecolored.bluemap.core.world.World; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.core.HolderLookup; +import net.minecraft.data.registries.VanillaRegistries; +import net.minecraft.network.chat.Component; + +import java.util.Optional; + +public class ForgeCommandSource implements CommandSource { + + private static final HolderLookup.Provider lookup = VanillaRegistries.createLookup(); + + private final ForgeMod mod; + private final Plugin plugin; + private final CommandSourceStack delegate; + + public ForgeCommandSource(ForgeMod mod, Plugin plugin, CommandSourceStack delegate) { + this.mod = mod; + this.plugin = plugin; + this.delegate = delegate; + } + + @Override + public void sendMessage(Text text) { + var component = Component.Serializer.fromJsonLenient(text.toJSONString(), lookup); + if (component != null) + delegate.sendSuccess(() -> component, false); + } + + @Override + public boolean hasPermission(String permission) { + return delegate.hasPermission(1); + } + + @Override + public Optional getPosition() { + var pos = delegate.getPosition(); + return Optional.of(new Vector3d(pos.x, pos.y, pos.z)); + } + + @Override + public Optional getWorld() { + ServerWorld serverWorld = mod.getServerWorld(delegate.getLevel()); + return Optional.ofNullable(plugin.getWorld(serverWorld)); + } + +} diff --git a/implementations/neoforge-1.20.2/src/main/java/de/bluecolored/bluemap/forge/ForgeEventForwarder.java b/implementations/neoforge/src/main/java/de/bluecolored/bluemap/forge/ForgeEventForwarder.java similarity index 100% rename from implementations/neoforge-1.20.2/src/main/java/de/bluecolored/bluemap/forge/ForgeEventForwarder.java rename to implementations/neoforge/src/main/java/de/bluecolored/bluemap/forge/ForgeEventForwarder.java diff --git a/implementations/neoforge-1.20.2/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java b/implementations/neoforge/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java similarity index 93% rename from implementations/neoforge-1.20.2/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java rename to implementations/neoforge/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java index 6f8d4da3b..60726dd3f 100644 --- a/implementations/neoforge-1.20.2/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java +++ b/implementations/neoforge/src/main/java/de/bluecolored/bluemap/forge/ForgeMod.java @@ -43,17 +43,14 @@ import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.level.Level; import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.IExtensionPoint; -import net.neoforged.fml.ModLoadingContext; import net.neoforged.fml.common.Mod; import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.event.RegisterCommandsEvent; -import net.neoforged.neoforge.event.TickEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; import net.neoforged.neoforge.event.server.ServerStartedEvent; import net.neoforged.neoforge.event.server.ServerStartingEvent; import net.neoforged.neoforge.event.server.ServerStoppingEvent; -import net.neoforged.neoforge.network.NetworkConstants; +import net.neoforged.neoforge.event.tick.ServerTickEvent; import org.apache.logging.log4j.LogManager; import java.io.IOException; @@ -81,7 +78,7 @@ public ForgeMod() { this.onlinePlayerMap = new ConcurrentHashMap<>(); this.onlinePlayerList = Collections.synchronizedList(new ArrayList<>()); - this.pluginInstance = new Plugin("neoforge-1.20.2", this); + this.pluginInstance = new Plugin("neoforge", this); this.eventForwarder = new ForgeEventForwarder(); this.worlds = Caffeine.newBuilder() @@ -91,9 +88,6 @@ public ForgeMod() { .build(ForgeWorld::new); NeoForge.EVENT_BUS.register(this); - - //Make sure the mod being absent on the other network side does not cause the client to display the server as incompatible - ModLoadingContext.get().registerExtensionPoint(IExtensionPoint.DisplayTest.class, () -> new IExtensionPoint.DisplayTest(() -> NetworkConstants.IGNORESERVERONLY, (a, b) -> true)); } @SubscribeEvent @@ -134,7 +128,7 @@ public void onServerStopping(ServerStoppingEvent event) { } @SubscribeEvent - public void onTick(TickEvent.ServerTickEvent evt) { + public void onTick(ServerTickEvent.Post evt) { updateSomePlayers(); } diff --git a/implementations/neoforge/src/main/java/de/bluecolored/bluemap/forge/ForgePlayer.java b/implementations/neoforge/src/main/java/de/bluecolored/bluemap/forge/ForgePlayer.java new file mode 100644 index 000000000..e90501b36 --- /dev/null +++ b/implementations/neoforge/src/main/java/de/bluecolored/bluemap/forge/ForgePlayer.java @@ -0,0 +1,154 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.forge; + +import com.flowpowered.math.vector.Vector3d; +import de.bluecolored.bluemap.common.plugin.text.Text; +import de.bluecolored.bluemap.common.serverinterface.Gamemode; +import de.bluecolored.bluemap.common.serverinterface.Player; +import de.bluecolored.bluemap.common.serverinterface.ServerWorld; +import net.minecraft.core.BlockPos; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.phys.Vec3; + +import java.util.EnumMap; +import java.util.Map; +import java.util.UUID; + +public class ForgePlayer implements Player { + + private static final Map GAMEMODE_MAP = new EnumMap<>(GameType.class); + static { + GAMEMODE_MAP.put(GameType.ADVENTURE, Gamemode.ADVENTURE); + GAMEMODE_MAP.put(GameType.SURVIVAL, Gamemode.SURVIVAL); + GAMEMODE_MAP.put(GameType.CREATIVE, Gamemode.CREATIVE); + GAMEMODE_MAP.put(GameType.SPECTATOR, Gamemode.SPECTATOR); + } + + private final UUID uuid; + private Text name; + private ServerWorld world; + private Vector3d position; + private Vector3d rotation; + private int skyLight; + private int blockLight; + private boolean sneaking; + private boolean invisible; + private Gamemode gamemode; + + private final ForgeMod mod; + + public ForgePlayer(UUID playerUuid, ForgeMod mod) { + this.uuid = playerUuid; + this.mod = mod; + + update(); + } + + @Override + public UUID getUuid() { + return this.uuid; + } + + @Override + public Text getName() { + return this.name; + } + + @Override + public ServerWorld getWorld() { + return this.world; + } + + @Override + public Vector3d getPosition() { + return this.position; + } + + @Override + public Vector3d getRotation() { + return rotation; + } + + @Override + public int getSkyLight() { + return skyLight; + } + + @Override + public int getBlockLight() { + return blockLight; + } + + @Override + public boolean isSneaking() { + return this.sneaking; + } + + @Override + public boolean isInvisible() { + return this.invisible; + } + + @Override + public Gamemode getGamemode() { + return this.gamemode; + } + + /** + * Only call on server thread! + */ + public void update() { + MinecraftServer server = mod.getServer(); + if (server == null) return; + + ServerPlayer player = server.getPlayerList().getPlayer(uuid); + if (player == null) return; + + this.gamemode = GAMEMODE_MAP.getOrDefault(player.gameMode.getGameModeForPlayer(), Gamemode.SURVIVAL); + if (this.gamemode == null) this.gamemode = Gamemode.SURVIVAL; + + MobEffectInstance invis = player.getEffect(MobEffects.INVISIBILITY); + this.invisible = invis != null && invis.getDuration() > 0; + + this.name = Text.of(player.getName().getString()); + + Vec3 pos = player.getPosition(1f); + this.position = new Vector3d(pos.x(), pos.y(), pos.z()); + this.rotation = new Vector3d(player.getXRot(), player.getYHeadRot(), 0); + this.sneaking = player.isCrouching(); + + this.skyLight = player.level().getChunkSource().getLightEngine().getLayerListener(LightLayer.SKY).getLightValue(new BlockPos(player.getBlockX(), player.getBlockY(), player.getBlockZ())); + this.blockLight = player.level().getChunkSource().getLightEngine().getLayerListener(LightLayer.BLOCK).getLightValue(new BlockPos(player.getBlockX(), player.getBlockY(), player.getBlockZ())); + + this.world = mod.getServerWorld(player.serverLevel()); + } + +} diff --git a/implementations/neoforge/src/main/java/de/bluecolored/bluemap/forge/ForgeWorld.java b/implementations/neoforge/src/main/java/de/bluecolored/bluemap/forge/ForgeWorld.java new file mode 100644 index 000000000..dc2284be2 --- /dev/null +++ b/implementations/neoforge/src/main/java/de/bluecolored/bluemap/forge/ForgeWorld.java @@ -0,0 +1,111 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * 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.forge; + +import de.bluecolored.bluemap.common.serverinterface.ServerWorld; +import de.bluecolored.bluemap.core.util.Key; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.storage.LevelResource; + +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.nio.file.Path; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; + +public class ForgeWorld implements ServerWorld { + + private final WeakReference delegate; + private final Path worldFolder; + private final Key dimension; + + public ForgeWorld(ServerLevel delegate) { + this.delegate = new WeakReference<>(delegate); + + MinecraftServer server = delegate.getServer(); + this.worldFolder = delegate.getServer().getServerDirectory().toPath() + .resolve(server.getWorldPath(LevelResource.ROOT)); + + ResourceLocation id = delegate.dimension().location(); + this.dimension = new Key(id.getNamespace(), id.getPath()); + } + + @Override + public boolean persistWorldChanges() throws IOException { + ServerLevel world = delegate.get(); + if (world == null) return false; + + var taskResult = CompletableFuture.supplyAsync(() -> { + try { + world.save(null, true, false); + return true; + } catch (Exception e) { + throw new CompletionException(e); + } + }, world.getServer()); + + try { + return taskResult.get(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException(e); + } catch (ExecutionException e) { + Throwable t = e.getCause(); + if (t instanceof IOException) throw (IOException) t; + if (t instanceof IllegalArgumentException) throw (IllegalArgumentException) t; + throw new IOException(t); + } + } + + @Override + public Path getWorldFolder() { + return worldFolder; + } + + @Override + public Key getDimension() { + return dimension; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ForgeWorld that = (ForgeWorld) o; + Object world = delegate.get(); + return world != null && world.equals(that.delegate.get()); + } + + @Override + public int hashCode() { + Object world = delegate.get(); + return world != null ? world.hashCode() : 0; + } + +} diff --git a/implementations/neoforge-1.20.2/src/main/java/de/bluecolored/bluemap/forge/Log4jLogger.java b/implementations/neoforge/src/main/java/de/bluecolored/bluemap/forge/Log4jLogger.java similarity index 100% rename from implementations/neoforge-1.20.2/src/main/java/de/bluecolored/bluemap/forge/Log4jLogger.java rename to implementations/neoforge/src/main/java/de/bluecolored/bluemap/forge/Log4jLogger.java diff --git a/implementations/neoforge-1.20.2/src/main/resources/META-INF/mods.toml b/implementations/neoforge/src/main/resources/META-INF/neoforge.mods.toml similarity index 93% rename from implementations/neoforge-1.20.2/src/main/resources/META-INF/mods.toml rename to implementations/neoforge/src/main/resources/META-INF/neoforge.mods.toml index 1d6a5d73e..f8f61f84a 100644 --- a/implementations/neoforge-1.20.2/src/main/resources/META-INF/mods.toml +++ b/implementations/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -7,6 +7,7 @@ modId="${mod_id}" version="${mod_version}" displayName="${mod_name}" description='''${mod_description}''' +displayTest="IGNORE_SERVER_VERSION" [[dependencies.${mod_id}]] #optional modId="neoforge" diff --git a/implementations/neoforge-1.20.2/src/main/resources/pack.mcmeta b/implementations/neoforge/src/main/resources/pack.mcmeta similarity index 100% rename from implementations/neoforge-1.20.2/src/main/resources/pack.mcmeta rename to implementations/neoforge/src/main/resources/pack.mcmeta diff --git a/implementations/paper/build.gradle.kts b/implementations/paper/build.gradle.kts index a909b97af..82e4bd18f 100644 --- a/implementations/paper/build.gradle.kts +++ b/implementations/paper/build.gradle.kts @@ -3,7 +3,7 @@ plugins { `java-library` id("com.diffplug.spotless") version "6.1.2" id ("com.github.node-gradle.node") version "3.0.1" - id ("com.github.johnrengelman.shadow") version "7.1.2" + id ("com.github.johnrengelman.shadow") version "8.1.1" id ("com.modrinth.minotaur") version "2.+" id ("io.papermc.hangar-publish-plugin") version "0.1.2" } diff --git a/implementations/spigot/build.gradle.kts b/implementations/spigot/build.gradle.kts index 6e42bf4e2..e81c29908 100644 --- a/implementations/spigot/build.gradle.kts +++ b/implementations/spigot/build.gradle.kts @@ -3,7 +3,7 @@ plugins { `java-library` id("com.diffplug.spotless") version "6.1.2" id ("com.github.node-gradle.node") version "3.0.1" - id ("com.github.johnrengelman.shadow") version "7.1.2" + id ("com.github.johnrengelman.shadow") version "8.1.1" id ("com.modrinth.minotaur") version "2.+" } diff --git a/implementations/sponge/build.gradle.kts b/implementations/sponge/build.gradle.kts index 90fa82327..7c8ff1e44 100644 --- a/implementations/sponge/build.gradle.kts +++ b/implementations/sponge/build.gradle.kts @@ -5,7 +5,7 @@ plugins { `java-library` id("com.diffplug.spotless") version "6.1.2" id ("com.github.node-gradle.node") version "3.0.1" - id ("com.github.johnrengelman.shadow") version "7.1.2" + id ("com.github.johnrengelman.shadow") version "8.1.1" id ("org.spongepowered.gradle.plugin") version "2.0.0" id ("com.modrinth.minotaur") version "2.+" id("org.spongepowered.gradle.ore") version "2.2.0" diff --git a/settings.gradle.kts b/settings.gradle.kts index 496dfa4ff..b7e50cbb0 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -10,18 +10,18 @@ includeBuild("BlueMapCommon") // implementations includeBuild("implementations/cli") +includeBuild("implementations/fabric") +includeBuild("implementations/forge") +includeBuild("implementations/neoforge") +includeBuild("implementations/spigot") +includeBuild("implementations/paper") +includeBuild("implementations/sponge") -includeBuild("implementations/fabric-1.18") -includeBuild("implementations/fabric-1.19.4") -includeBuild("implementations/fabric-1.20") - +// legacy support includeBuild("implementations/forge-1.18.1") includeBuild("implementations/forge-1.19.4") includeBuild("implementations/forge-1.20") -includeBuild("implementations/neoforge-1.20.2") - -includeBuild("implementations/spigot") -includeBuild("implementations/paper") - -includeBuild("implementations/sponge") +includeBuild("implementations/fabric-1.18") +includeBuild("implementations/fabric-1.19.4") +includeBuild("implementations/fabric-1.20") From 4a38a7491b695d5e8d51dfd659617876cb831cfe Mon Sep 17 00:00:00 2001 From: "Lukas Rieger (Blue)" Date: Mon, 3 Jun 2024 21:59:27 +0200 Subject: [PATCH 38/38] Remove unneeded gradle wrappers --- .../gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - BlueMapCommon/gradlew | 234 ------------------ BlueMapCommon/gradlew.bat | 89 ------- BlueMapCore/gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - BlueMapCore/gradlew | 234 ------------------ BlueMapCore/gradlew.bat | 89 ------- .../cli/gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - implementations/cli/gradlew | 234 ------------------ implementations/cli/gradlew.bat | 89 ------- .../gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - implementations/fabric-1.19.4/gradlew | 234 ------------------ implementations/fabric-1.19.4/gradlew.bat | 89 ------- .../gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - implementations/fabric-1.20/gradlew | 234 ------------------ implementations/fabric-1.20/gradlew.bat | 89 ------- .../gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - implementations/forge-1.18.1/gradlew | 234 ------------------ implementations/forge-1.18.1/gradlew.bat | 89 ------- .../gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - implementations/forge-1.19.4/gradlew | 234 ------------------ implementations/forge-1.19.4/gradlew.bat | 89 ------- .../gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - implementations/forge-1.20/gradlew | 234 ------------------ implementations/forge-1.20/gradlew.bat | 89 ------- .../paper/gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - implementations/paper/gradlew | 234 ------------------ implementations/paper/gradlew.bat | 89 ------- .../spigot/gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - implementations/spigot/gradlew | 234 ------------------ implementations/spigot/gradlew.bat | 89 ------- .../sponge/gradle/wrapper/gradle-wrapper.jar | Bin 59536 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - implementations/sponge/gradlew | 185 -------------- implementations/sponge/gradlew.bat | 89 ------- 44 files changed, 3559 deletions(-) delete mode 100644 BlueMapCommon/gradle/wrapper/gradle-wrapper.jar delete mode 100644 BlueMapCommon/gradle/wrapper/gradle-wrapper.properties delete mode 100644 BlueMapCommon/gradlew delete mode 100644 BlueMapCommon/gradlew.bat delete mode 100644 BlueMapCore/gradle/wrapper/gradle-wrapper.jar delete mode 100644 BlueMapCore/gradle/wrapper/gradle-wrapper.properties delete mode 100644 BlueMapCore/gradlew delete mode 100644 BlueMapCore/gradlew.bat delete mode 100644 implementations/cli/gradle/wrapper/gradle-wrapper.jar delete mode 100644 implementations/cli/gradle/wrapper/gradle-wrapper.properties delete mode 100644 implementations/cli/gradlew delete mode 100644 implementations/cli/gradlew.bat delete mode 100644 implementations/fabric-1.19.4/gradle/wrapper/gradle-wrapper.jar delete mode 100644 implementations/fabric-1.19.4/gradle/wrapper/gradle-wrapper.properties delete mode 100644 implementations/fabric-1.19.4/gradlew delete mode 100644 implementations/fabric-1.19.4/gradlew.bat delete mode 100644 implementations/fabric-1.20/gradle/wrapper/gradle-wrapper.jar delete mode 100644 implementations/fabric-1.20/gradle/wrapper/gradle-wrapper.properties delete mode 100644 implementations/fabric-1.20/gradlew delete mode 100644 implementations/fabric-1.20/gradlew.bat delete mode 100644 implementations/forge-1.18.1/gradle/wrapper/gradle-wrapper.jar delete mode 100644 implementations/forge-1.18.1/gradle/wrapper/gradle-wrapper.properties delete mode 100644 implementations/forge-1.18.1/gradlew delete mode 100644 implementations/forge-1.18.1/gradlew.bat delete mode 100644 implementations/forge-1.19.4/gradle/wrapper/gradle-wrapper.jar delete mode 100644 implementations/forge-1.19.4/gradle/wrapper/gradle-wrapper.properties delete mode 100644 implementations/forge-1.19.4/gradlew delete mode 100644 implementations/forge-1.19.4/gradlew.bat delete mode 100644 implementations/forge-1.20/gradle/wrapper/gradle-wrapper.jar delete mode 100644 implementations/forge-1.20/gradle/wrapper/gradle-wrapper.properties delete mode 100644 implementations/forge-1.20/gradlew delete mode 100644 implementations/forge-1.20/gradlew.bat delete mode 100644 implementations/paper/gradle/wrapper/gradle-wrapper.jar delete mode 100644 implementations/paper/gradle/wrapper/gradle-wrapper.properties delete mode 100644 implementations/paper/gradlew delete mode 100644 implementations/paper/gradlew.bat delete mode 100644 implementations/spigot/gradle/wrapper/gradle-wrapper.jar delete mode 100644 implementations/spigot/gradle/wrapper/gradle-wrapper.properties delete mode 100644 implementations/spigot/gradlew delete mode 100644 implementations/spigot/gradlew.bat delete mode 100644 implementations/sponge/gradle/wrapper/gradle-wrapper.jar delete mode 100644 implementations/sponge/gradle/wrapper/gradle-wrapper.properties delete mode 100644 implementations/sponge/gradlew delete mode 100644 implementations/sponge/gradlew.bat diff --git a/BlueMapCommon/gradle/wrapper/gradle-wrapper.jar b/BlueMapCommon/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 41d9927a4d4fb3f96a785543079b8df6723c946b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59821 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 diff --git a/BlueMapCommon/gradle/wrapper/gradle-wrapper.properties b/BlueMapCommon/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 48c0a02ca..000000000 --- a/BlueMapCommon/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/BlueMapCommon/gradlew b/BlueMapCommon/gradlew deleted file mode 100644 index 1b6c78733..000000000 --- a/BlueMapCommon/gradlew +++ /dev/null @@ -1,234 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" -APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/BlueMapCommon/gradlew.bat b/BlueMapCommon/gradlew.bat deleted file mode 100644 index 107acd32c..000000000 --- a/BlueMapCommon/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/BlueMapCore/gradle/wrapper/gradle-wrapper.jar b/BlueMapCore/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 41d9927a4d4fb3f96a785543079b8df6723c946b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59821 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 diff --git a/BlueMapCore/gradle/wrapper/gradle-wrapper.properties b/BlueMapCore/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 48c0a02ca..000000000 --- a/BlueMapCore/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/BlueMapCore/gradlew b/BlueMapCore/gradlew deleted file mode 100644 index 1b6c78733..000000000 --- a/BlueMapCore/gradlew +++ /dev/null @@ -1,234 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" -APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/BlueMapCore/gradlew.bat b/BlueMapCore/gradlew.bat deleted file mode 100644 index 107acd32c..000000000 --- a/BlueMapCore/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/implementations/cli/gradle/wrapper/gradle-wrapper.jar b/implementations/cli/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 41d9927a4d4fb3f96a785543079b8df6723c946b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59821 zcma&NV|1p`(k7gaZQHhOJ9%QKV?D8LCmq{1JGRYE(y=?XJw0>InKkE~^UnAEs2gk5 zUVGPCwX3dOb!}xiFmPB95NK!+5D<~S0s;d1zn&lrfAn7 zC?Nb-LFlib|DTEqB8oDS5&$(u1<5;wsY!V`2F7^=IR@I9so5q~=3i_(hqqG<9SbL8Q(LqDrz+aNtGYWGJ2;p*{a-^;C>BfGzkz_@fPsK8{pTT~_VzB$E`P@> z7+V1WF2+tSW=`ZRj3&0m&d#x_lfXq`bb-Y-SC-O{dkN2EVM7@!n|{s+2=xSEMtW7( zz~A!cBpDMpQu{FP=y;sO4Le}Z)I$wuFwpugEY3vEGfVAHGqZ-<{vaMv-5_^uO%a{n zE_Zw46^M|0*dZ`;t%^3C19hr=8FvVdDp1>SY>KvG!UfD`O_@weQH~;~W=fXK_!Yc> z`EY^PDJ&C&7LC;CgQJeXH2 zjfM}2(1i5Syj)Jj4EaRyiIl#@&lC5xD{8hS4Wko7>J)6AYPC-(ROpVE-;|Z&u(o=X z2j!*>XJ|>Lo+8T?PQm;SH_St1wxQPz)b)Z^C(KDEN$|-6{A>P7r4J1R-=R7|FX*@! zmA{Ja?XE;AvisJy6;cr9Q5ovphdXR{gE_7EF`ji;n|RokAJ30Zo5;|v!xtJr+}qbW zY!NI6_Wk#6pWFX~t$rAUWi?bAOv-oL6N#1>C~S|7_e4 zF}b9(&a*gHk+4@J26&xpiWYf2HN>P;4p|TD4f586umA2t@cO1=Fx+qd@1Ae#Le>{-?m!PnbuF->g3u)7(n^llJfVI%Q2rMvetfV5 z6g|sGf}pV)3_`$QiKQnqQ<&ghOWz4_{`rA1+7*M0X{y(+?$|{n zs;FEW>YzUWg{sO*+D2l6&qd+$JJP_1Tm;To<@ZE%5iug8vCN3yH{!6u5Hm=#3HJ6J zmS(4nG@PI^7l6AW+cWAo9sFmE`VRcM`sP7X$^vQY(NBqBYU8B|n-PrZdNv8?K?kUTT3|IE`-A8V*eEM2=u*kDhhKsmVPWGns z8QvBk=BPjvu!QLtlF0qW(k+4i+?H&L*qf262G#fks9}D5-L{yiaD10~a;-j!p!>5K zl@Lh+(9D{ePo_S4F&QXv|q_yT`GIPEWNHDD8KEcF*2DdZD;=J6u z|8ICSoT~5Wd!>g%2ovFh`!lTZhAwpIbtchDc{$N%<~e$E<7GWsD42UdJh1fD($89f2on`W`9XZJmr*7lRjAA8K0!(t8-u>2H*xn5cy1EG{J;w;Q-H8Yyx+WW(qoZZM7p(KQx^2-yI6Sw?k<=lVOVwYn zY*eDm%~=|`c{tUupZ^oNwIr!o9T;H3Fr|>NE#By8SvHb&#;cyBmY1LwdXqZwi;qn8 zK+&z{{95(SOPXAl%EdJ3jC5yV^|^}nOT@M0)|$iOcq8G{#*OH7=DlfOb; z#tRO#tcrc*yQB5!{l5AF3(U4>e}nEvkoE_XCX=a3&A6Atwnr&`r&f2d%lDr8f?hBB zr1dKNypE$CFbT9I?n){q<1zHmY>C=5>9_phi79pLJG)f=#dKdQ7We8emMjwR*qIMF zE_P-T*$hX#FUa%bjv4Vm=;oxxv`B*`weqUn}K=^TXjJG=UxdFMSj-QV6fu~;- z|IsUq`#|73M%Yn;VHJUbt<0UHRzbaF{X@76=8*-IRx~bYgSf*H(t?KH=?D@wk*E{| z2@U%jKlmf~C^YxD=|&H?(g~R9-jzEb^y|N5d`p#2-@?BUcHys({pUz4Zto7XwKq2X zSB~|KQGgv_Mh@M!*{nl~2~VV_te&E7K39|WYH zCxfd|v_4!h$Ps2@atm+gj14Ru)DhivY&(e_`eA)!O1>nkGq|F-#-6oo5|XKEfF4hR z%{U%ar7Z8~B!foCd_VRHr;Z1c0Et~y8>ZyVVo9>LLi(qb^bxVkbq-Jq9IF7!FT`(- zTMrf6I*|SIznJLRtlP)_7tQ>J`Um>@pP=TSfaPB(bto$G1C zx#z0$=zNpP-~R);kM4O)9Mqn@5Myv5MmmXOJln312kq#_94)bpSd%fcEo7cD#&|<` zrcal$(1Xv(nDEquG#`{&9Ci~W)-zd_HbH-@2F6+|a4v}P!w!Q*h$#Zu+EcZeY>u&?hn#DCfC zVuye5@Ygr+T)0O2R1*Hvlt>%rez)P2wS}N-i{~IQItGZkp&aeY^;>^m7JT|O^{`78 z$KaK0quwcajja;LU%N|{`2o&QH@u%jtH+j!haGj;*ZCR*`UgOXWE>qpXqHc?g&vA& zt-?_g8k%ZS|D;()0Lf!>7KzTSo-8hUh%OA~i76HKRLudaNiwo*E9HxmzN4y>YpZNO zUE%Q|H_R_UmX=*f=2g=xyP)l-DP}kB@PX|(Ye$NOGN{h+fI6HVw`~Cd0cKqO;s6aiYLy7sl~%gs`~XaL z^KrZ9QeRA{O*#iNmB7_P!=*^pZiJ5O@iE&X2UmUCPz!)`2G3)5;H?d~3#P|)O(OQ_ zua+ZzwWGkWflk4j^Lb=x56M75_p9M*Q50#(+!aT01y80x#rs9##!;b-BH?2Fu&vx} za%4!~GAEDsB54X9wCF~juV@aU}fp_(a<`Ig0Pip8IjpRe#BR?-niYcz@jI+QY zBU9!8dAfq@%p;FX)X=E7?B=qJJNXlJ&7FBsz;4&|*z{^kEE!XbA)(G_O6I9GVzMAF z8)+Un(6od`W7O!!M=0Z)AJuNyN8q>jNaOdC-zAZ31$Iq%{c_SYZe+(~_R`a@ zOFiE*&*o5XG;~UjsuW*ja-0}}rJdd@^VnQD!z2O~+k-OSF%?hqcFPa4e{mV1UOY#J zTf!PM=KMNAzbf(+|AL%K~$ahX0Ol zbAxKu3;v#P{Qia{_WzHl`!@!8c#62XSegM{tW1nu?Ee{sQq(t{0TSq67YfG;KrZ$n z*$S-+R2G?aa*6kRiTvVxqgUhJ{ASSgtepG3hb<3hlM|r>Hr~v_DQ>|Nc%&)r0A9go z&F3Ao!PWKVq~aWOzLQIy&R*xo>}{UTr}?`)KS&2$3NR@a+>+hqK*6r6Uu-H};ZG^| zfq_Vl%YE1*uGwtJ>H*Y(Q9E6kOfLJRlrDNv`N;jnag&f<4#UErM0ECf$8DASxMFF& zK=mZgu)xBz6lXJ~WZR7OYw;4&?v3Kk-QTs;v1r%XhgzSWVf|`Sre2XGdJb}l1!a~z zP92YjnfI7OnF@4~g*LF>G9IZ5c+tifpcm6#m)+BmnZ1kz+pM8iUhwag`_gqr(bnpy zl-noA2L@2+?*7`ZO{P7&UL~ahldjl`r3=HIdo~Hq#d+&Q;)LHZ4&5zuDNug@9-uk; z<2&m#0Um`s=B}_}9s&70Tv_~Va@WJ$n~s`7tVxi^s&_nPI0`QX=JnItlOu*Tn;T@> zXsVNAHd&K?*u~a@u8MWX17VaWuE0=6B93P2IQ{S$-WmT+Yp!9eA>@n~=s>?uDQ4*X zC(SxlKap@0R^z1p9C(VKM>nX8-|84nvIQJ-;9ei0qs{}X>?f%&E#%-)Bpv_p;s4R+ z;PMpG5*rvN&l;i{^~&wKnEhT!S!LQ>udPzta#Hc9)S8EUHK=%x+z@iq!O{)*XM}aI zBJE)vokFFXTeG<2Pq}5Na+kKnu?Ch|YoxdPb&Z{07nq!yzj0=xjzZj@3XvwLF0}Pa zn;x^HW504NNfLY~w!}5>`z=e{nzGB>t4ntE>R}r7*hJF3OoEx}&6LvZz4``m{AZxC zz6V+^73YbuY>6i9ulu)2`ozP(XBY5n$!kiAE_Vf4}Ih)tlOjgF3HW|DF+q-jI_0p%6Voc^e;g28* z;Sr4X{n(X7eEnACWRGNsHqQ_OfWhAHwnSQ87@PvPcpa!xr9`9+{QRn;bh^jgO8q@v zLekO@-cdc&eOKsvXs-eMCH8Y{*~3Iy!+CANy+(WXYS&6XB$&1+tB?!qcL@@) zS7XQ|5=o1fr8yM7r1AyAD~c@Mo`^i~hjx{N17%pDX?j@2bdBEbxY}YZxz!h#)q^1x zpc_RnoC3`V?L|G2R1QbR6pI{Am?yW?4Gy`G-xBYfebXvZ=(nTD7u?OEw>;vQICdPJBmi~;xhVV zisVvnE!bxI5|@IIlDRolo_^tc1{m)XTbIX^<{TQfsUA1Wv(KjJED^nj`r!JjEA%MaEGqPB z9YVt~ol3%e`PaqjZt&-)Fl^NeGmZ)nbL;92cOeLM2H*r-zA@d->H5T_8_;Jut0Q_G zBM2((-VHy2&eNkztIpHk&1H3M3@&wvvU9+$RO%fSEa_d5-qZ!<`-5?L9lQ1@AEpo* z3}Zz~R6&^i9KfRM8WGc6fTFD%PGdruE}`X$tP_*A)_7(uI5{k|LYc-WY*%GJ6JMmw zNBT%^E#IhekpA(i zcB$!EB}#>{^=G%rQ~2;gbObT9PQ{~aVx_W6?(j@)S$&Ja1s}aLT%A*mP}NiG5G93- z_DaRGP77PzLv0s32{UFm##C2LsU!w{vHdKTM1X)}W%OyZ&{3d^2Zu-zw?fT=+zi*q z^fu6CXQ!i?=ljsqSUzw>g#PMk>(^#ejrYp(C)7+@Z1=Mw$Rw!l8c9}+$Uz;9NUO(kCd#A1DX4Lbis0k; z?~pO(;@I6Ajp}PL;&`3+;OVkr3A^dQ(j?`by@A!qQam@_5(w6fG>PvhO`#P(y~2ue zW1BH_GqUY&>PggMhhi@8kAY;XWmj>y1M@c`0v+l~l0&~Kd8ZSg5#46wTLPo*Aom-5 z>qRXyWl}Yda=e@hJ%`x=?I42(B0lRiR~w>n6p8SHN~B6Y>W(MOxLpv>aB)E<1oEcw z%X;#DJpeDaD;CJRLX%u!t23F|cv0ZaE183LXxMq*uWn)cD_ zp!@i5zsmcxb!5uhp^@>U;K>$B|8U@3$65CmhuLlZ2(lF#hHq-<<+7ZN9m3-hFAPgA zKi;jMBa*59ficc#TRbH_l`2r>z(Bm_XEY}rAwyp~c8L>{A<0@Q)j*uXns^q5z~>KI z)43=nMhcU1ZaF;CaBo>hl6;@(2#9yXZ7_BwS4u>gN%SBS<;j{{+p}tbD8y_DFu1#0 zx)h&?`_`=ti_6L>VDH3>PPAc@?wg=Omdoip5j-2{$T;E9m)o2noyFW$5dXb{9CZ?c z);zf3U526r3Fl+{82!z)aHkZV6GM@%OKJB5mS~JcDjieFaVn}}M5rtPnHQVw0Stn- zEHs_gqfT8(0b-5ZCk1%1{QQaY3%b>wU z7lyE?lYGuPmB6jnMI6s$1uxN{Tf_n7H~nKu+h7=%60WK-C&kEIq_d4`wU(*~rJsW< zo^D$-(b0~uNVgC+$J3MUK)(>6*k?92mLgpod{Pd?{os+yHr&t+9ZgM*9;dCQBzE!V zk6e6)9U6Bq$^_`E1xd}d;5O8^6?@bK>QB&7l{vAy^P6FOEO^l7wK4K=lLA45gQ3$X z=$N{GR1{cxO)j;ZxKI*1kZIT9p>%FhoFbRK;M(m&bL?SaN zzkZS9xMf={o@gpG%wE857u@9dq>UKvbaM1SNtMA9EFOp7$BjJQVkIm$wU?-yOOs{i z1^(E(WwZZG{_#aIzfpGc@g5-AtK^?Q&vY#CtVpfLbW?g0{BEX4Vlk(`AO1{-D@31J zce}#=$?Gq+FZG-SD^z)-;wQg9`qEO}Dvo+S9*PUB*JcU)@S;UVIpN7rOqXmEIerWo zP_lk!@RQvyds&zF$Rt>N#_=!?5{XI`Dbo0<@>fIVgcU*9Y+ z)}K(Y&fdgve3ruT{WCNs$XtParmvV;rjr&R(V&_#?ob1LzO0RW3?8_kSw)bjom#0; zeNllfz(HlOJw012B}rgCUF5o|Xp#HLC~of%lg+!pr(g^n;wCX@Yk~SQOss!j9f(KL zDiI1h#k{po=Irl)8N*KU*6*n)A8&i9Wf#7;HUR^5*6+Bzh;I*1cICa|`&`e{pgrdc zs}ita0AXb$c6{tu&hxmT0faMG0GFc)unG8tssRJd%&?^62!_h_kn^HU_kBgp$bSew zqu)M3jTn;)tipv9Wt4Ll#1bmO2n?^)t^ZPxjveoOuK89$oy4(8Ujw{nd*Rs*<+xFi z{k*9v%sl?wS{aBSMMWdazhs0#gX9Has=pi?DhG&_0|cIyRG7c`OBiVG6W#JjYf7-n zIQU*Jc+SYnI8oG^Q8So9SP_-w;Y00$p5+LZ{l+81>v7|qa#Cn->312n=YQd$PaVz8 zL*s?ZU*t-RxoR~4I7e^c!8TA4g>w@R5F4JnEWJpy>|m5la2b#F4d*uoz!m=i1;`L` zB(f>1fAd~;*wf%GEbE8`EA>IO9o6TdgbIC%+en!}(C5PGYqS0{pa?PD)5?ds=j9{w za9^@WBXMZ|D&(yfc~)tnrDd#*;u;0?8=lh4%b-lFPR3ItwVJp};HMdEw#SXg>f-zU zEiaj5H=jzRSy(sWVd%hnLZE{SUj~$xk&TfheSch#23)YTcjrB+IVe0jJqsdz__n{- zC~7L`DG}-Dgrinzf7Jr)e&^tdQ}8v7F+~eF*<`~Vph=MIB|YxNEtLo1jXt#9#UG5` zQ$OSk`u!US+Z!=>dGL>%i#uV<5*F?pivBH@@1idFrzVAzttp5~>Y?D0LV;8Yv`wAa{hewVjlhhBM z_mJhU9yWz9Jexg@G~dq6EW5^nDXe(sU^5{}qbd0*yW2Xq6G37f8{{X&Z>G~dUGDFu zgmsDDZZ5ZmtiBw58CERFPrEG>*)*`_B75!MDsOoK`T1aJ4GZ1avI?Z3OX|Hg?P(xy zSPgO$alKZuXd=pHP6UZy0G>#BFm(np+dekv0l6gd=36FijlT8^kI5; zw?Z*FPsibF2d9T$_L@uX9iw*>y_w9HSh8c=Rm}f>%W+8OS=Hj_wsH-^actull3c@!z@R4NQ4qpytnwMaY z)>!;FUeY?h2N9tD(othc7Q=(dF zZAX&Y1ac1~0n(z}!9{J2kPPnru1?qteJPvA2m!@3Zh%+f1VQt~@leK^$&ZudOpS!+ zw#L0usf!?Df1tB?9=zPZ@q2sG!A#9 zKZL`2cs%|Jf}wG=_rJkwh|5Idb;&}z)JQuMVCZSH9kkG%zvQO01wBN)c4Q`*xnto3 zi7TscilQ>t_SLij{@Fepen*a(`upw#RJAx|JYYXvP1v8f)dTHv9pc3ZUwx!0tOH?c z^Hn=gfjUyo!;+3vZhxNE?LJgP`qYJ`J)umMXT@b z{nU(a^xFfofcxfHN-!Jn*{Dp5NZ&i9#9r{)s^lUFCzs5LQL9~HgxvmU#W|iNs0<3O z%Y2FEgvts4t({%lfX1uJ$w{JwfpV|HsO{ZDl2|Q$-Q?UJd`@SLBsMKGjFFrJ(s?t^ z2Llf`deAe@YaGJf)k2e&ryg*m8R|pcjct@rOXa=64#V9!sp=6tC#~QvYh&M~zmJ;% zr*A}V)Ka^3JE!1pcF5G}b&jdrt;bM^+J;G^#R08x@{|ZWy|547&L|k6)HLG|sN<~o z?y`%kbfRN_vc}pwS!Zr}*q6DG7;be0qmxn)eOcD%s3Wk`=@GM>U3ojhAW&WRppi0e zudTj{ufwO~H7izZJmLJD3uPHtjAJvo6H=)&SJ_2%qRRECN#HEU_RGa(Pefk*HIvOH zW7{=Tt(Q(LZ6&WX_Z9vpen}jqge|wCCaLYpiw@f_%9+-!l{kYi&gT@Cj#D*&rz1%e z@*b1W13bN8^j7IpAi$>`_0c!aVzLe*01DY-AcvwE;kW}=Z{3RJLR|O~^iOS(dNEnL zJJ?Dv^ab++s2v!4Oa_WFDLc4fMspglkh;+vzg)4;LS{%CR*>VwyP4>1Tly+!fA-k? z6$bg!*>wKtg!qGO6GQ=cAmM_RC&hKg$~(m2LdP{{*M+*OVf07P$OHp*4SSj9H;)1p z^b1_4p4@C;8G7cBCB6XC{i@vTB3#55iRBZiml^jc4sYnepCKUD+~k}TiuA;HWC6V3 zV{L5uUAU9CdoU+qsFszEwp;@d^!6XnX~KI|!o|=r?qhs`(-Y{GfO4^d6?8BC0xonf zKtZc1C@dNu$~+p#m%JW*J7alfz^$x`U~)1{c7svkIgQ3~RK2LZ5;2TAx=H<4AjC8{ z;)}8OfkZy7pSzVsdX|wzLe=SLg$W1+`Isf=o&}npxWdVR(i8Rr{uzE516a@28VhVr zVgZ3L&X(Q}J0R2{V(}bbNwCDD5K)<5h9CLM*~!xmGTl{Mq$@;~+|U*O#nc^oHnFOy z9Kz%AS*=iTBY_bSZAAY6wXCI?EaE>8^}WF@|}O@I#i69ljjWQPBJVk zQ_rt#J56_wGXiyItvAShJpLEMtW_)V5JZAuK#BAp6bV3K;IkS zK0AL(3ia99!vUPL#j>?<>mA~Q!mC@F-9I$9Z!96ZCSJO8FDz1SP3gF~m`1c#y!efq8QN}eHd+BHwtm%M5586jlU8&e!CmOC z^N_{YV$1`II$~cTxt*dV{-yp61nUuX5z?N8GNBuZZR}Uy_Y3_~@Y3db#~-&0TX644OuG^D3w_`?Yci{gTaPWST8`LdE)HK5OYv>a=6B%R zw|}>ngvSTE1rh`#1Rey0?LXTq;bCIy>TKm^CTV4BCSqdpx1pzC3^ca*S3fUBbKMzF z6X%OSdtt50)yJw*V_HE`hnBA)1yVN3Ruq3l@lY;%Bu+Q&hYLf_Z@fCUVQY-h4M3)- zE_G|moU)Ne0TMjhg?tscN7#ME6!Rb+y#Kd&-`!9gZ06o3I-VX1d4b1O=bpRG-tDK0 zSEa9y46s7QI%LmhbU3P`RO?w#FDM(}k8T`&>OCU3xD=s5N7}w$GntXF;?jdVfg5w9OR8VPxp5{uw zD+_;Gb}@7Vo_d3UV7PS65%_pBUeEwX_Hwfe2e6Qmyq$%0i8Ewn%F7i%=CNEV)Qg`r|&+$ zP6^Vl(MmgvFq`Zb715wYD>a#si;o+b4j^VuhuN>+sNOq6Qc~Y;Y=T&!Q4>(&^>Z6* zwliz!_16EDLTT;v$@W(s7s0s zi*%p>q#t)`S4j=Ox_IcjcllyT38C4hr&mlr6qX-c;qVa~k$MG;UqdnzKX0wo0Xe-_)b zrHu1&21O$y5828UIHI@N;}J@-9cpxob}zqO#!U%Q*ybZ?BH#~^fOT_|8&xAs_rX24 z^nqn{UWqR?MlY~klh)#Rz-*%&e~9agOg*fIN`P&v!@gcO25Mec23}PhzImkdwVT|@ zFR9dYYmf&HiUF4xO9@t#u=uTBS@k*97Z!&hu@|xQnQDkLd!*N`!0JN7{EUoH%OD85 z@aQ2(w-N)1_M{;FV)C#(a4p!ofIA3XG(XZ2E#%j_(=`IWlJAHWkYM2&(+yY|^2TB0 z>wfC-+I}`)LFOJ%KeBb1?eNxGKeq?AI_eBE!M~$wYR~bB)J3=WvVlT8ZlF2EzIFZt zkaeyj#vmBTGkIL9mM3cEz@Yf>j=82+KgvJ-u_{bBOxE5zoRNQW3+Ahx+eMGem|8xo zL3ORKxY_R{k=f~M5oi-Z>5fgqjEtzC&xJEDQ@`<)*Gh3UsftBJno-y5Je^!D?Im{j za*I>RQ=IvU@5WKsIr?kC$DT+2bgR>8rOf3mtXeMVB~sm%X7W5`s=Tp>FR544tuQ>9qLt|aUSv^io&z93luW$_OYE^sf8DB?gx z4&k;dHMWph>Z{iuhhFJr+PCZ#SiZ9e5xM$A#0yPtVC>yk&_b9I676n|oAH?VeTe*1 z@tDK}QM-%J^3Ns6=_vh*I8hE?+=6n9nUU`}EX|;Mkr?6@NXy8&B0i6h?7%D=%M*Er zivG61Wk7e=v;<%t*G+HKBqz{;0Biv7F+WxGirONRxJij zon5~(a`UR%uUzfEma99QGbIxD(d}~oa|exU5Y27#4k@N|=hE%Y?Y3H%rcT zHmNO#ZJ7nPHRG#y-(-FSzaZ2S{`itkdYY^ZUvyw<7yMBkNG+>$Rfm{iN!gz7eASN9-B3g%LIEyRev|3)kSl;JL zX7MaUL_@~4ot3$woD0UA49)wUeu7#lj77M4ar8+myvO$B5LZS$!-ZXw3w;l#0anYz zDc_RQ0Ome}_i+o~H=CkzEa&r~M$1GC!-~WBiHiDq9Sdg{m|G?o7g`R%f(Zvby5q4; z=cvn`M>RFO%i_S@h3^#3wImmWI4}2x4skPNL9Am{c!WxR_spQX3+;fo!y(&~Palyjt~Xo0uy6d%sX&I`e>zv6CRSm)rc^w!;Y6iVBb3x@Y=`hl9jft zXm5vilB4IhImY5b->x{!MIdCermpyLbsalx8;hIUia%*+WEo4<2yZ6`OyG1Wp%1s$ zh<|KrHMv~XJ9dC8&EXJ`t3ETz>a|zLMx|MyJE54RU(@?K&p2d#x?eJC*WKO9^d17# zdTTKx-Os3k%^=58Sz|J28aCJ}X2-?YV3T7ee?*FoDLOC214J4|^*EX`?cy%+7Kb3(@0@!Q?p zk>>6dWjF~y(eyRPqjXqDOT`4^Qv-%G#Zb2G?&LS-EmO|ixxt79JZlMgd^~j)7XYQ; z62rGGXA=gLfgy{M-%1gR87hbhxq-fL)GSfEAm{yLQP!~m-{4i_jG*JsvUdqAkoc#q6Yd&>=;4udAh#?xa2L z7mFvCjz(hN7eV&cyFb%(U*30H@bQ8-b7mkm!=wh2|;+_4vo=tyHPQ0hL=NR`jbsSiBWtG ztMPPBgHj(JTK#0VcP36Z`?P|AN~ybm=jNbU=^3dK=|rLE+40>w+MWQW%4gJ`>K!^- zx4kM*XZLd(E4WsolMCRsdvTGC=37FofIyCZCj{v3{wqy4OXX-dZl@g`Dv>p2`l|H^ zS_@(8)7gA62{Qfft>vx71stILMuyV4uKb7BbCstG@|e*KWl{P1$=1xg(7E8MRRCWQ1g)>|QPAZot~|FYz_J0T+r zTWTB3AatKyUsTXR7{Uu) z$1J5SSqoJWt(@@L5a)#Q6bj$KvuC->J-q1!nYS6K5&e7vNdtj- zj9;qwbODLgIcObqNRGs1l{8>&7W?BbDd!87=@YD75B2ep?IY|gE~t)$`?XJ45MG@2 zz|H}f?qtEb_p^Xs$4{?nA=Qko3Lc~WrAS`M%9N60FKqL7XI+v_5H-UDiCbRm`fEmv z$pMVH*#@wQqml~MZe+)e4Ts3Gl^!Z0W3y$;|9hI?9(iw29b7en0>Kt2pjFXk@!@-g zTb4}Kw!@u|V!wzk0|qM*zj$*-*}e*ZXs#Y<6E_!BR}3^YtjI_byo{F+w9H9?f%mnBh(uE~!Um7)tgp2Ye;XYdVD95qt1I-fc@X zXHM)BfJ?^g(s3K|{N8B^hamrWAW|zis$`6|iA>M-`0f+vq(FLWgC&KnBDsM)_ez1# zPCTfN8{s^K`_bum2i5SWOn)B7JB0tzH5blC?|x;N{|@ch(8Uy-O{B2)OsfB$q0@FR z27m3YkcVi$KL;;4I*S;Z#6VfZcZFn!D2Npv5pio)sz-`_H*#}ROd7*y4i(y(YlH<4 zh4MmqBe^QV_$)VvzWgMXFy`M(vzyR2u!xx&%&{^*AcVLrGa8J9ycbynjKR~G6zC0e zlEU>zt7yQtMhz>XMnz>ewXS#{Bulz$6HETn?qD5v3td>`qGD;Y8&RmkvN=24=^6Q@DYY zxMt}uh2cSToMkkIWo1_Lp^FOn$+47JXJ*#q=JaeiIBUHEw#IiXz8cStEsw{UYCA5v_%cF@#m^Y!=+qttuH4u}r6gMvO4EAvjBURtLf& z6k!C|OU@hv_!*qear3KJ?VzVXDKqvKRtugefa7^^MSWl0fXXZR$Xb!b6`eY4A1#pk zAVoZvb_4dZ{f~M8fk3o?{xno^znH1t;;E6K#9?erW~7cs%EV|h^K>@&3Im}c7nm%Y zbLozFrwM&tSNp|46)OhP%MJ(5PydzR>8)X%i3!^L%3HCoCF#Y0#9vPI5l&MK*_ z6G8Y>$`~c)VvQle_4L_AewDGh@!bKkJeEs_NTz(yilnM!t}7jz>fmJb89jQo6~)%% z@GNIJ@AShd&K%UdQ5vR#yT<-goR+D@Tg;PuvcZ*2AzSWN&wW$Xc+~vW)pww~O|6hL zBxX?hOyA~S;3rAEfI&jmMT4f!-eVm%n^KF_QT=>!A<5tgXgi~VNBXqsFI(iI$Tu3x0L{<_-%|HMG4Cn?Xs zq~fvBhu;SDOCD7K5(l&i7Py-;Czx5byV*3y%#-Of9rtz?M_owXc2}$OIY~)EZ&2?r zLQ(onz~I7U!w?B%LtfDz)*X=CscqH!UE=mO?d&oYvtj|(u)^yomS;Cd>Men|#2yuD zg&tf(*iSHyo;^A03p&_j*QXay9d}qZ0CgU@rnFNDIT5xLhC5_tlugv()+w%`7;ICf z>;<#L4m@{1}Og76*e zHWFm~;n@B1GqO8s%=qu)+^MR|jp(ULUOi~v;wE8SB6^mK@adSb=o+A_>Itjn13AF& zDZe+wUF9G!JFv|dpj1#d+}BO~s*QTe3381TxA%Q>P*J#z%( z5*8N^QWxgF73^cTKkkvgvIzf*cLEyyKw)Wf{#$n{uS#(rAA~>TS#!asqQ2m_izXe3 z7$Oh=rR;sdmVx3G)s}eImsb<@r2~5?vcw*Q4LU~FFh!y4r*>~S7slAE6)W3Up2OHr z2R)+O<0kKo<3+5vB}v!lB*`%}gFldc+79iahqEx#&Im@NCQU$@PyCZbcTt?K{;o@4 z312O9GB)?X&wAB}*-NEU zn@6`)G`FhT8O^=Cz3y+XtbwO{5+{4-&?z!esFts-C zypwgI^4#tZ74KC+_IW|E@kMI=1pSJkvg$9G3Va(!reMnJ$kcMiZ=30dTJ%(Ws>eUf z;|l--TFDqL!PZbLc_O(XP0QornpP;!)hdT#Ts7tZ9fcQeH&rhP_1L|Z_ha#JOroe^qcsLi`+AoBWHPM7}gD z+mHuPXd14M?nkp|nu9G8hPk;3=JXE-a204Fg!BK|$MX`k-qPeD$2OOqvF;C(l8wm13?>i(pz7kRyYm zM$IEzf`$}B%ezr!$(UO#uWExn%nTCTIZzq&8@i8sP#6r8 z*QMUzZV(LEWZb)wbmf|Li;UpiP;PlTQ(X4zreD`|`RG!7_wc6J^MFD!A=#K*ze>Jg z?9v?p(M=fg_VB0+c?!M$L>5FIfD(KD5ku*djwCp+5GVIs9^=}kM2RFsxx0_5DE%BF zykxwjWvs=rbi4xKIt!z$&v(`msFrl4n>a%NO_4`iSyb!UiAE&mDa+apc zPe)#!ToRW~rqi2e1bdO1RLN5*uUM@{S`KLJhhY-@TvC&5D(c?a(2$mW-&N%h5IfEM zdFI6`6KJiJQIHvFiG-34^BtO3%*$(-Ht_JU*(KddiUYoM{coadlG&LVvke&*p>Cac z^BPy2Zteiq1@ulw0e)e*ot7@A$RJui0$l^{lsCt%R;$){>zuRv9#w@;m=#d%%TJmm zC#%eFOoy$V)|3*d<OC1iP+4R7D z8FE$E8l2Y?(o-i6wG=BKBh0-I?i3WF%hqdD7VCd;vpk|LFP!Et8$@voH>l>U8BY`Q zC*G;&y6|!p=7`G$*+hxCv!@^#+QD3m>^azyZoLS^;o_|plQaj-wx^ zRV&$HcY~p)2|Zqp0SYU?W3zV87s6JP-@D~$t0 zvd;-YL~JWc*8mtHz_s(cXus#XYJc5zdC=&!4MeZ;N3TQ>^I|Pd=HPjVP*j^45rs(n zzB{U4-44=oQ4rNN6@>qYVMH4|GmMIz#z@3UW-1_y#eNa+Q%(41oJ5i(DzvMO^%|?L z^r_+MZtw0DZ0=BT-@?hUtA)Ijk~Kh-N8?~X5%KnRH7cb!?Yrd8gtiEo!v{sGrQk{X zvV>h{8-DqTyuAxIE(hb}jMVtga$;FIrrKm>ye5t%M;p!jcH1(Bbux>4D#MVhgZGd> z=c=nVb%^9T?iDgM&9G(mV5xShc-lBLi*6RShenDqB%`-2;I*;IHg6>#ovKQ$M}dDb z<$USN%LMqa5_5DR7g7@(oAoQ%!~<1KSQr$rmS{UFQJs5&qBhgTEM_Y7|0Wv?fbP`z z)`8~=v;B)+>Jh`V*|$dTxKe`HTBkho^-!!K#@i{9FLn-XqX&fQcGsEAXp)BV7(`Lk zC{4&+Pe-0&<)C0kAa(MTnb|L;ZB5i|b#L1o;J)+?SV8T*U9$Vxhy}dm3%!A}SK9l_6(#5(e*>8|;4gNKk7o_%m_ zEaS=Z(ewk}hBJ>v`jtR=$pm_Wq3d&DU+6`BACU4%qdhH1o^m8hT2&j<4Z8!v=rMCk z-I*?48{2H*&+r<{2?wp$kh@L@=rj8c`EaS~J>W?)trc?zP&4bsNagS4yafuDoXpi5`!{BVqJ1$ZC3`pf$`LIZ(`0&Ik+!_Xa=NJW`R2 zd#Ntgwz`JVwC4A61$FZ&kP)-{T|rGO59`h#1enAa`cWxRR8bKVvvN6jBzAYePrc&5 z+*zr3en|LYB2>qJp479rEALk5d*X-dfKn6|kuNm;2-U2+P3_rma!nWjZQ-y*q3JS? zBE}zE-!1ZBR~G%v!$l#dZ*$UV4$7q}xct}=on+Ba8{b>Y9h*f-GW0D0o#vJ0%ALg( ztG2+AjWlG#d;myA(i&dh8Gp?y9HD@`CTaDAy?c&0unZ%*LbLIg4;m{Kc?)ws3^>M+ zt5>R)%KIJV*MRUg{0$#nW=Lj{#8?dD$yhjBOrAeR#4$H_Dc(eyA4dNjZEz1Xk+Bqt zB&pPl+?R{w8GPv%VI`x`IFOj320F1=cV4aq0(*()Tx!VVxCjua;)t}gTr=b?zY+U! zkb}xjXZ?hMJN{Hjw?w&?gz8Ow`htX z@}WG*_4<%ff8(!S6bf3)p+8h2!Rory>@aob$gY#fYJ=LiW0`+~l7GI%EX_=8 z{(;0&lJ%9)M9{;wty=XvHbIx|-$g4HFij`J$-z~`mW)*IK^MWVN+*>uTNqaDmi!M8 zurj6DGd)g1g(f`A-K^v)3KSOEoZXImXT06apJum-dO_%oR)z6Bam-QC&CNWh7kLOE zcxLdVjYLNO2V?IXWa-ys30Jbxw(Xm?U1{4kDs9`gZQHh8X{*w9=H&Zz&-6RL?uq#R zxN+k~JaL|gdsdvY_u6}}MHC?a@ElFeipA1Lud#M~)pp2SnG#K{a@tSpvXM;A8gz9> zRVDV5T1%%!LsNRDOw~LIuiAiKcj<%7WpgjP7G6mMU1#pFo6a-1>0I5ZdhxnkMX&#L z=Vm}?SDlb_LArobqpnU!WLQE*yVGWgs^4RRy4rrJwoUUWoA~ZJUx$mK>J6}7{CyC4 zv=8W)kKl7TmAnM%m;anEDPv5tzT{A{ON9#FPYF6c=QIc*OrPp96tiY&^Qs+#A1H>Y z<{XtWt2eDwuqM zQ_BI#UIP;2-olOL4LsZ`vTPv-eILtuB7oWosoSefWdM}BcP>iH^HmimR`G`|+9waCO z&M375o@;_My(qYvPNz;N8FBZaoaw3$b#x`yTBJLc8iIP z--la{bzK>YPP|@Mke!{Km{vT8Z4|#An*f=EmL34?!GJfHaDS#41j~8c5KGKmj!GTh&QIH+DjEI*BdbSS2~6VTt}t zhAwNQNT6%c{G`If3?|~Fp7iwee(LaUS)X9@I29cIb61} z$@YBq4hSplr&liE@ye!y&7+7n$fb+8nS~co#^n@oCjCwuKD61x$5|0ShDxhQES5MP z(gH|FO-s6#$++AxnkQR!3YMgKcF)!&aqr^a3^{gAVT`(tY9@tqgY7@ z>>ul3LYy`R({OY7*^Mf}UgJl(N7yyo$ag;RIpYHa_^HKx?DD`%Vf1D0s^ zjk#OCM5oSzuEz(7X`5u~C-Y~n4B}_3*`5B&8tEdND@&h;H{R`o%IFpIJ4~Kw!kUjehGT8W!CD7?d8sg_$KKp%@*dW)#fI1#R<}kvzBVpaog_2&W%c_jJfP` z6)wE+$3+Hdn^4G}(ymPyasc1<*a7s2yL%=3LgtZLXGuA^jdM^{`KDb%%}lr|ONDsl zy~~jEuK|XJ2y<`R{^F)Gx7DJVMvpT>gF<4O%$cbsJqK1;v@GKXm*9l3*~8^_xj*Gs z=Z#2VQ6`H@^~#5Pv##@CddHfm;lbxiQnqy7AYEH(35pTg^;u&J2xs-F#jGLuDw2%z z`a>=0sVMM+oKx4%OnC9zWdbpq*#5^yM;og*EQKpv`^n~-mO_vj=EgFxYnga(7jO?G z`^C87B4-jfB_RgN2FP|IrjOi;W9AM1qS}9W@&1a9Us>PKFQ9~YE!I~wTbl!m3$Th? z)~GjFxmhyyGxN}t*G#1^KGVXm#o(K0xJyverPe}mS=QgJ$#D}emQDw+dHyPu^&Uv> z4O=3gK*HLFZPBY|!VGq60Of6QrAdj`nj1h!$?&a;Hgaj{oo{l0P3TzpJK_q_eW8Ng zP6QF}1{V;xlolCs?pGegPoCSxx@bshb#3ng4Fkp4!7B0=&+1%187izf@}tvsjZ6{m z4;K>sR5rm97HJrJ`w}Y`-MZN$Wv2N%X4KW(N$v2@R1RkRJH2q1Ozs0H`@ zd5)X-{!{<+4Nyd=hQ8Wm3CCd}ujm*a?L79ztfT7@&(?B|!pU5&%9Rl!`i;suAg0+A zxb&UYpo-z}u6CLIndtH~C|yz&!OV_I*L;H#C7ie_5uB1fNRyH*<^d=ww=gxvE%P$p zRHKI{^{nQlB9nLhp9yj-so1is{4^`{Xd>Jl&;dX;J)#- z=fmE5GiV?-&3kcjM1+XG7&tSq;q9Oi4NUuRrIpoyp*Fn&nVNFdUuGQ_g)g>VzXGdneB7`;!aTUE$t* z5iH+8XPxrYl)vFo~+vmcU-2) zq!6R(T0SsoDnB>Mmvr^k*{34_BAK+I=DAGu){p)(ndZqOFT%%^_y;X(w3q-L``N<6 zw9=M zoQ8Lyp>L_j$T20UUUCzYn2-xdN}{e@$8-3vLDN?GbfJ>7*qky{n!wC#1NcYQr~d51 zy;H!am=EI#*S&TCuP{FA3CO)b0AAiN*tLnDbvKwxtMw-l;G2T@EGH)YU?-B`+Y=!$ zypvDn@5V1Tr~y~U0s$ee2+CL3xm_BmxD3w}d_Pd@S%ft#v~_j;6sC6cy%E|dJy@wj z`+(YSh2CrXMxI;yVy*=O@DE2~i5$>nuzZ$wYHs$y`TAtB-ck4fQ!B8a;M=CxY^Nf{ z+UQhn0jopOzvbl(uZZ1R-(IFaprC$9hYK~b=57@ zAJ8*pH%|Tjotzu5(oxZyCQ{5MAw+6L4)NI!9H&XM$Eui-DIoDa@GpNI=I4}m>Hr^r zZjT?xDOea}7cq+TP#wK1p3}sbMK{BV%(h`?R#zNGIP+7u@dV5#zyMau+w}VC1uQ@p zrFUjrJAx6+9%pMhv(IOT52}Dq{B9njh_R`>&j&5Sbub&r*hf4es)_^FTYdDX$8NRk zMi=%I`)hN@N9>X&Gu2RmjKVsUbU>TRUM`gwd?CrL*0zxu-g#uNNnnicYw=kZ{7Vz3 zULaFQ)H=7%Lm5|Z#k?<{ux{o4T{v-e zTLj?F(_qp{FXUzOfJxEyKO15Nr!LQYHF&^jMMBs z`P-}WCyUYIv>K`~)oP$Z85zZr4gw>%aug1V1A)1H(r!8l&5J?ia1x_}Wh)FXTxZUE zs=kI}Ix2cK%Bi_Hc4?mF^m`sr6m8M(n?E+k7Tm^Gn}Kf= zfnqoyVU^*yLypz?s+-XV5(*oOBwn-uhwco5b(@B(hD|vtT8y7#W{>RomA_KchB&Cd zcFNAD9mmqR<341sq+j+2Ra}N5-3wx5IZqg6Wmi6CNO#pLvYPGNER}Q8+PjvIJ42|n zc5r@T*p)R^U=d{cT2AszQcC6SkWiE|hdK)m{7ul^mU+ED1R8G#)#X}A9JSP_ubF5p z8Xxcl;jlGjPwow^p+-f_-a~S;$lztguPE6SceeUCfmRo=Qg zKHTY*O_ z;pXl@z&7hniVYVbGgp+Nj#XP^Aln2T!D*{(Td8h{8Dc?C)KFfjPybiC`Va?Rf)X>y z;5?B{bAhPtbmOMUsAy2Y0RNDQ3K`v`gq)#ns_C&ec-)6cq)d^{5938T`Sr@|7nLl; zcyewuiSUh7Z}q8iIJ@$)L3)m)(D|MbJm_h&tj^;iNk%7K-YR}+J|S?KR|29K?z-$c z<+C4uA43yfSWBv*%z=-0lI{ev`C6JxJ};A5N;lmoR(g{4cjCEn33 z-ef#x^uc%cM-f^_+*dzE?U;5EtEe;&8EOK^K}xITa?GH`tz2F9N$O5;)`Uof4~l+t z#n_M(KkcVP*yMYlk_~5h89o zlf#^qjYG8Wovx+f%x7M7_>@r7xaXa2uXb?_*=QOEe_>ErS(v5-i)mrT3&^`Oqr4c9 zDjP_6T&NQMD`{l#K&sHTm@;}ed_sQ88X3y`ON<=$<8Qq{dOPA&WAc2>EQ+U8%>yWR zK%(whl8tB;{C)yRw|@Gn4%RhT=bbpgMZ6erACc>l5^p)9tR`(2W-D*?Ph6;2=Fr|G- zdF^R&aCqyxqWy#P7#G8>+aUG`pP*ow93N=A?pA=aW0^^+?~#zRWcf_zlKL8q8-80n zqGUm=S8+%4_LA7qrV4Eq{FHm9#9X15%ld`@UKyR7uc1X*>Ebr0+2yCye6b?i=r{MPoqnTnYnq z^?HWgl+G&@OcVx4$(y;{m^TkB5Tnhx2O%yPI=r*4H2f_6Gfyasq&PN^W{#)_Gu7e= zVHBQ8R5W6j;N6P3O(jsRU;hkmLG(Xs_8=F&xh@`*|l{~0OjUVlgm z7opltSHg7Mb%mYamGs*v1-#iW^QMT**f+Nq*AzIvFT~Ur3KTD26OhIw1WQsL(6nGg znHUo-4e15cXBIiyqN};5ydNYJ6zznECVVR44%(P0oW!yQ!YH)FPY?^k{IrtrLo7Zo`?sg%%oMP9E^+H@JLXicr zi?eoI?LODRPcMLl90MH32rf8btf69)ZE~&4d%(&D{C45egC6bF-XQ;6QKkbmqW>_H z{86XDZvjiN2wr&ZPfi;^SM6W+IP0);50m>qBhzx+docpBkkiY@2bSvtPVj~E`CfEu zhQG5G>~J@dni5M5Jmv7GD&@%UR`k3ru-W$$onI259jM&nZ)*d3QFF?Mu?{`+nVzkx z=R*_VH=;yeU?9TzQ3dP)q;P)4sAo&k;{*Eky1+Z!10J<(cJC3zY9>bP=znA=<-0RR zMnt#<9^X7BQ0wKVBV{}oaV=?JA=>R0$az^XE%4WZcA^Em>`m_obQyKbmf-GA;!S-z zK5+y5{xbkdA?2NgZ0MQYF-cfOwV0?3Tzh8tcBE{u%Uy?Ky4^tn^>X}p>4&S(L7amF zpWEio8VBNeZ=l!%RY>oVGOtZh7<>v3?`NcHlYDPUBRzgg z0OXEivCkw<>F(>1x@Zk=IbSOn+frQ^+jI*&qdtf4bbydk-jgVmLAd?5ImK+Sigh?X zgaGUlbf^b-MH2@QbqCawa$H1Vb+uhu{zUG9268pa{5>O&Vq8__Xk5LXDaR1z$g;s~;+Ae82wq#l;wo08tX(9uUX6NJWq1vZLh3QbP$# zL`udY|Qp*4ER`_;$%)2 zmcJLj|FD`(;ts0bD{}Ghq6UAVpEm#>j`S$wHi0-D_|)bEZ}#6) zIiqH7Co;TB`<6KrZi1SF9=lO+>-_3=Hm%Rr7|Zu-EzWLSF{9d(H1v*|UZDWiiqX3} zmx~oQ6%9~$=KjPV_ejzz7aPSvTo+3@-a(OCCoF_u#2dHY&I?`nk zQ@t8#epxAv@t=RUM09u?qnPr6=Y5Pj;^4=7GJ`2)Oq~H)2V)M1sC^S;w?hOB|0zXT zQdf8$)jslO>Q}(4RQ$DPUF#QUJm-k9ysZFEGi9xN*_KqCs9Ng(&<;XONBDe1Joku? z*W!lx(i&gvfXZ4U(AE@)c0FI2UqrFLOO$&Yic|`L;Vyy-kcm49hJ^Mj^H9uY8Fdm2 z?=U1U_5GE_JT;Tx$2#I3rAAs(q@oebIK=19a$N?HNQ4jw0ljtyGJ#D}z3^^Y=hf^Bb--297h6LQxi0-`TB|QY2QPg92TAq$cEQdWE ze)ltSTVMYe0K4wte6;^tE+^>|a>Hit_3QDlFo!3Jd`GQYTwlR#{<^MzG zK!vW&))~RTKq4u29bc<+VOcg7fdorq-kwHaaCQe6tLB{|gW1_W_KtgOD0^$^|`V4C# z*D_S9Dt_DIxpjk3my5cBFdiYaq||#0&0&%_LEN}BOxkb3v*d$4L|S|z z!cZZmfe~_Y`46v=zul=aixZTQCOzb(jx>8&a%S%!(;x{M2!*$od2!Pwfs>RZ-a%GOZdO88rS)ZW~{$656GgW)$Q=@!x;&Nn~!K)lr4gF*%qVO=hlodHA@2)keS2 zC}7O=_64#g&=zY?(zhzFO3)f5=+`dpuyM!Q)zS&otpYB@hhn$lm*iK2DRt+#1n|L%zjM}nB*$uAY^2JIw zV_P)*HCVq%F))^)iaZD#R9n^{sAxBZ?Yvi1SVc*`;8|F2X%bz^+s=yS&AXjysDny)YaU5RMotF-tt~FndTK ziRve_5b!``^ZRLG_ks}y_ye0PKyKQSsQCJuK5()b2ThnKPFU?An4;dK>)T^4J+XjD zEUsW~H?Q&l%K4<1f5^?|?lyCQe(O3?!~OU{_Wxs#|Ff8?a_WPQUKvP7?>1()Cy6oLeA zjEF^d#$6Wb${opCc^%%DjOjll%N2=GeS6D-w=Ap$Ux2+0v#s#Z&s6K*)_h{KFfgKjzO17@p1nKcC4NIgt+3t}&}F z@cV; zZ1r#~?R@ZdSwbFNV(fFl2lWI(Zf#nxa<6f!nBZD>*K)nI&Fun@ngq@Ge!N$O< zySt*mY&0moUXNPe~Fg=%gIu)tJ;asscQ!-AujR@VJBRoNZNk;z4hs4T>Ud!y=1NwGs-k zlTNeBOe}=)Epw=}+dfX;kZ32h$t&7q%Xqdt-&tlYEWc>>c3(hVylsG{Ybh_M8>Cz0ZT_6B|3!_(RwEJus9{;u-mq zW|!`{BCtnao4;kCT8cr@yeV~#rf76=%QQs(J{>Mj?>aISwp3{^BjBO zLV>XSRK+o=oVDBnbv?Y@iK)MiFSl{5HLN@k%SQZ}yhPiu_2jrnI?Kk?HtCv>wN$OM zSe#}2@He9bDZ27hX_fZey=64#SNU#1~=icK`D>a;V-&Km>V6ZdVNj7d2 z-NmAoOQm_aIZ2lXpJhlUeJ95eZt~4_S zIfrDs)S$4UjyxKSaTi#9KGs2P zfSD>(y~r+bU4*#|r`q+be_dopJzKK5JNJ#rR978ikHyJKD>SD@^Bk$~D0*U38Y*IpYcH>aaMdZq|YzQ-Ixd(_KZK!+VL@MWGl zG!k=<%Y-KeqK%``uhx}0#X^@wS+mX@6Ul@90#nmYaKh}?uw>U;GS4fn3|X%AcV@iY z8v+ePk)HxSQ7ZYDtlYj#zJ?5uJ8CeCg3efmc#|a%2=u>+vrGGRg$S@^mk~0f;mIu! zWMA13H1<@hSOVE*o0S5D8y=}RiL#jQpUq42D}vW$z*)VB*FB%C?wl%(3>ANaY)bO@ zW$VFutemwy5Q*&*9HJ603;mJJkB$qp6yxNOY0o_4*y?2`qbN{m&*l{)YMG_QHXXa2 z+hTmlA;=mYwg{Bfusl zyF&}ib2J;#q5tN^e)D62fWW*Lv;Rnb3GO-JVtYG0CgR4jGujFo$Waw zSNLhc{>P~>{KVZE1Vl1!z)|HFuN@J7{`xIp_)6>*5Z27BHg6QIgqLqDJTmKDM+ON* zK0Fh=EG`q13l z+m--9UH0{ZGQ%j=OLO8G2WM*tgfY}bV~>3Grcrpehjj z6Xe<$gNJyD8td3EhkHjpKk}7?k55Tu7?#;5`Qcm~ki;BeOlNr+#PK{kjV>qfE?1No zMA07}b>}Dv!uaS8Hym0TgzxBxh$*RX+Fab6Gm02!mr6u}f$_G4C|^GSXJMniy^b`G z74OC=83m0G7L_dS99qv3a0BU({t$zHQsB-RI_jn1^uK9ka_%aQuE2+~J2o!7`735Z zb?+sTe}Gd??VEkz|KAPMfj(1b{om89p5GIJ^#Aics_6DD%WnNGWAW`I<7jT|Af|8g zZA0^)`p8i#oBvX2|I&`HC8Pn&0>jRuMF4i0s=}2NYLmgkZb=0w9tvpnGiU-gTUQhJ zR6o4W6ZWONuBZAiN77#7;TR1^RKE(>>OL>YU`Yy_;5oj<*}ac99DI(qGCtn6`949f ziMpY4k>$aVfffm{dNH=-=rMg|u?&GIToq-u;@1-W&B2(UOhC-O2N5_px&cF-C^tWp zXvChm9@GXEcxd;+Q6}u;TKy}$JF$B`Ty?|Y3tP$N@Rtoy(*05Wj-Ks32|2y2ZM>bM zi8v8E1os!yorR!FSeP)QxtjIKh=F1ElfR8U7StE#Ika;h{q?b?Q+>%78z^>gTU5+> zxQ$a^rECmETF@Jl8fg>MApu>btHGJ*Q99(tMqsZcG+dZ6Yikx7@V09jWCiQH&nnAv zY)4iR$Ro223F+c3Q%KPyP9^iyzZsP%R%-i^MKxmXQHnW6#6n7%VD{gG$E;7*g86G< zu$h=RN_L2(YHO3@`B<^L(q@^W_0#U%mLC9Q^XEo3LTp*~(I%?P_klu-c~WJxY1zTI z^PqntLIEmdtK~E-v8yc&%U+jVxW5VuA{VMA4Ru1sk#*Srj0Pk#tZuXxkS=5H9?8eb z)t38?JNdP@#xb*yn=<*_pK9^lx%;&yH6XkD6-JXgdddZty8@Mfr9UpGE!I<37ZHUe z_Rd+LKsNH^O)+NW8Ni-V%`@J_QGKA9ZCAMSnsN>Ych9VW zCE7R_1FVy}r@MlkbxZ*TRIGXu`ema##OkqCM9{wkWQJg^%3H${!vUT&vv2250jAWN zw=h)C!b2s`QbWhBMSIYmWqZ_~ReRW;)U#@C&ThctSd_V!=HA=kdGO-Hl57an|M1XC?~3f0{7pyjWY}0mChU z2Fj2(B*r(UpCKm-#(2(ZJD#Y|Or*Vc5VyLpJ8gO1;fCm@EM~{DqpJS5FaZ5%|ALw) zyumBl!i@T57I4ITCFmdbxhaOYud}i!0YkdiNRaQ%5$T5>*HRBhyB~<%-5nj*b8=i= z(8g(LA50%0Zi_eQe}Xypk|bt5e6X{aI^jU2*c?!p*$bGk=?t z+17R){lx~Z{!B34Zip~|A;8l@%*Gc}kT|kC0*Ny$&fI3@%M! zqk_zvN}7bM`x@jqFOtaxI?*^Im5ix@=`QEv;__i;Tek-&7kGm6yP17QANVL>*d0B=4>i^;HKb$k8?DYFMr38IX4azK zBbwjF%$>PqXhJh=*7{zH5=+gi$!nc%SqFZlwRm zmpctOjZh3bwt!Oc>qVJhWQf>`HTwMH2ibK^eE*j!&Z`-bs8=A`Yvnb^?p;5+U=Fb8 z@h>j_3hhazd$y^Z-bt%3%E3vica%nYnLxW+4+?w{%|M_=w^04U{a6^22>M_?{@mXP zS|Qjcn4&F%WN7Z?u&I3fU(UQVw4msFehxR*80dSb=a&UG4zDQp&?r2UGPy@G?0FbY zVUQ?uU9-c;f9z06$O5FO1TOn|P{pLcDGP?rfdt`&uw|(Pm@$n+A?)8 zP$nG(VG&aRU*(_5z#{+yVnntu`6tEq>%9~n^*ao}`F6ph_@6_8|AfAXtFfWee_14` zKKURYV}4}=UJmxv7{RSz5QlwZtzbYQs0;t3?kx*7S%nf-aY&lJ@h?-BAn%~0&&@j) zQd_6TUOLXErJ`A3vE?DJIbLE;s~s%eVt(%fMzUq^UfZV9c?YuhO&6pwKt>j(=2CkgTNEq7&c zfeGN+%5DS@b9HO>zsoRXv@}(EiA|t5LPi}*R3?(-=iASADny<{D0WiQG>*-BSROk4vI6%$R>q64J&v-T+(D<_(b!LD z9GL;DV;;N3!pZYg23mcg81tx>7)=e%f|i{6Mx0GczVpc}{}Mg(W_^=Wh0Rp+xXgX` z@hw|5=Je&nz^Xa>>vclstYt;8c2PY)87Ap;z&S&`yRN>yQVV#K{4&diVR7Rm;S{6m z6<+;jwbm`==`JuC6--u6W7A@o4&ZpJV%5+H)}toy0afF*!)AaG5=pz_i9}@OG%?$O z2cec6#@=%xE3K8;^ps<2{t4SnqH+#607gAHP-G4^+PBiC1s>MXf&bQ|Pa;WBIiErV z?3VFpR9JFl9(W$7p3#xe(Bd?Z93Uu~jHJFo7U3K_x4Ej-=N#=a@f;kPV$>;hiN9i9 z<6elJl?bLI$o=|d6jlihA4~bG;Fm2eEnlGxZL`#H%Cdes>uJfMJ4>@1SGGeQ81DwxGxy7L5 zm05Ik*WpSgZvHh@Wpv|2i|Y#FG?Y$hbRM5ZF0Z7FB3cY0+ei#km9mDSPI}^!<<`vr zuv$SPg2vU{wa)6&QMY)h1hbbxvR2cc_6WcWR`SH& z&KuUQcgu}!iW2Wqvp~|&&LSec9>t(UR_|f$;f-fC&tSO-^-eE0B~Frttnf+XN(#T) z^PsuFV#(pE#6ztaI8(;ywN%CtZh?w&;_)w_s@{JiA-SMjf&pQk+Bw<}f@Q8-xCQMwfaf zMgHsAPU=>>Kw~uDFS(IVRN{$ak(SV(hrO!UqhJ?l{lNnA1>U24!=>|q_p404Xd>M# z7?lh^C&-IfeIr`Dri9If+bc%oU0?|Rh8)%BND5;_9@9tuM)h5Kcw6}$Ca7H_n)nOf0pd`boCXItb`o11 zb`)@}l6I_h>n+;`g+b^RkYs7;voBz&Gv6FLmyvY|2pS)z#P;t8k;lS>49a$XeVDc4 z(tx2Pe3N%Gd(!wM`E7WRBZy)~vh_vRGt&esDa0NCua)rH#_39*H0!gIXpd>~{rGx+ zJKAeXAZ-z5n=mMVqlM5Km;b;B&KSJlScD8n?2t}kS4Wf9@MjIZSJ2R?&=zQn zs_`=+5J$47&mP4s{Y{TU=~O_LzSrXvEP6W?^pz<#Y*6Fxg@$yUGp31d(h+4x>xpb< zH+R639oDST6F*0iH<9NHC^Ep*8D4-%p2^n-kD6YEI<6GYta6-I;V^ZH3n5}syTD=P z3b6z=jBsdP=FlXcUe@I|%=tY4J_2j!EVNEzph_42iO3yfir|Dh>nFl&Lu9!;`!zJB zCis9?_(%DI?$CA(00pkzw^Up`O;>AnPc(uE$C^a9868t$m?5Q)CR%!crI$YZpiYK6m= z!jv}82He`QKF;10{9@roL2Q7CF)OeY{~dBp>J~X#c-Z~{YLAxNmn~kWQW|2u!Yq00 zl5LKbzl39sVCTpm9eDW_T>Z{x@s6#RH|P zA~_lYas7B@SqI`N=>x50Vj@S)QxouKC(f6Aj zz}7e5e*5n?j@GO;mCYEo^Jp_*BmLt3!N)(T>f#L$XHQWzZEVlJo(>qH@7;c%fy zS-jm^Adju9Sm8rOKTxfTU^!&bg2R!7C_-t+#mKb_K?0R72%26ASF;JWA_prJ8_SVW zOSC7C&CpSrgfXRp8r)QK34g<~!1|poTS7F;)NseFsbwO$YfzEeG3oo!qe#iSxQ2S# z1=Fxc9J;2)pCab-9o-m8%BLjf(*mk#JJX3k9}S7Oq)dV0jG)SOMbw7V^Z<5Q0Cy$< z^U0QUVd4(96W03OA1j|x%{sd&BRqIERDb6W{u1p1{J(a;fd6lnWzjeS`d?L3-0#o7 z{Qv&L7!Tm`9|}u=|IbwS_jgH(_V@o`S*R(-XC$O)DVwF~B&5c~m!zl14ydT6sK+Ly zn+}2hQ4RTC^8YvrQ~vk$f9u=pTN{5H_yTOcza9SVE&nt_{`ZC8zkmFji=UyD`G4~f zUfSTR=Kju>6u+y&|Bylb*W&^P|8fvEbQH3+w*DrKq|9xMzq2OiZyM=;(?>~4+O|jn zC_Et05oc>e%}w4ye2Fm%RIR??VvofwZS-}BL@X=_4jdHp}FlMhW_IW?Zh`4$z*Wr!IzQHa3^?1|);~VaWmsIcmc6 zJs{k0YW}OpkfdoTtr4?9F6IX6$!>hhA+^y_y@vvA_Gr7u8T+i-< zDX(~W5W{8mfbbM-en&U%{mINU#Q8GA`byo)iLF7rMVU#wXXY`a3ji3m{4;x53216i z`zA8ap?>_}`tQj7-%$K78uR}R$|@C2)qgop$}o=g(jOv0ishl!E(R73N=i0~%S)6+ z1xFP7|H0yt3Z_Re*_#C2m3_X{=zi1C&3CM7e?9-Y5lCtAlA%RFG9PDD=Quw1dfYnZ zdUL)#+m`hKx@PT`r;mIx_RQ6Txbti+&;xQorP;$H=R2r)gPMO9>l+!p*Mt04VH$$M zSLwJ81IFjQ5N!S#;MyBD^IS`2n04kuYbZ2~4%3%tp0jn^**BZQ05ELp zY%yntZ=52s6U5Y93Aao)v~M3y?6h7mZcVGp63pK*d&!TRjW99rUU;@s#3kYB76Bs$|LRwkH>L!0Xe zE=dz1o}phhnOVYZFsajQsRA^}IYZnk9Wehvo>gHPA=TPI?2A`plIm8=F1%QiHx*Zn zi)*Y@)$aXW0v1J|#+R2=$ysooHZ&NoA|Wa}htd`=Eud!(HD7JlT8ug|yeBZmpry(W z)pS>^1$N#nuo3PnK*>Thmaxz4pLcY?PP2r3AlhJ7jw(TI8V#c}>Ym;$iPaw+83L+* z!_QWpYs{UWYcl0u z(&(bT0Q*S_uUX9$jC;Vk%oUXw=A-1I+!c18ij1CiUlP@pfP9}CHAVm{!P6AEJ(7Dn z?}u#}g`Q?`*|*_0Rrnu8{l4PP?yCI28qC~&zlwgLH2AkfQt1?B#3AOQjW&10%@@)Q zDG?`6$8?Nz(-sChL8mRs#3z^uOA>~G=ZIG*mgUibWmgd{a|Tn4nkRK9O^37E(()Q% zPR0#M4e2Q-)>}RSt1^UOCGuv?dn|IT3#oW_$S(YR+jxAzxCD_L25p_dt|^>g+6Kgj zJhC8n)@wY;Y7JI6?wjU$MQU|_Gw*FIC)x~^Eq1k41BjLmr}U>6#_wxP0-2Ka?uK14u5M-lAFSX$K1K{WH!M1&q}((MWWUp#Uhl#n_yT5dFs4X`>vmM& z*1!p0lACUVqp&sZG1GWATvZEENs^0_7Ymwem~PlFN3hTHVBv(sDuP;+8iH07a)s(# z%a7+p1QM)YkS7>kbo${k2N1&*%jFP*7UABJ2d||c!eSXWM*<4(_uD7;1XFDod@cT$ zP>IC%^fbC${^QrUXy$f)yBwY^g@}}kngZKa1US!lAa+D=G4wklukaY8AEW%GL zh40pnuv*6D>9`_e14@wWD^o#JvxYVG-~P)+<)0fW zP()DuJN?O*3+Ab!CP-tGr8S4;JN-Ye^9D%(%8d{vb_pK#S1z)nZzE^ezD&%L6nYbZ z*62>?u)xQe(Akd=e?vZbyb5)MMNS?RheZDHU?HK<9;PBHdC~r{MvF__%T)-9ifM#cR#2~BjVJYbA>xbPyl9yNX zX)iFVvv-lfm`d?tbfh^j*A|nw)RszyD<#e>llO8X zou=q3$1|M@Ob;F|o4H0554`&y9T&QTa3{yn=w0BLN~l;XhoslF-$4KGNUdRe?-lcV zS4_WmftU*XpP}*wFM^oKT!D%_$HMT#V*j;9weoOq0mjbl1271$F)`Q(C z76*PAw3_TE{vntIkd=|(zw)j^!@j ^tV@s0U~V+mu)vv`xgL$Z9NQLnuRdZ;95D|1)!0Aybwv}XCE#xz1k?ZC zxAU)v@!$Sm*?)t2mWrkevNFbILU9&znoek=d7jn*k+~ptQ)6z`h6e4B&g?Q;IK+aH z)X(BH`n2DOS1#{AJD-a?uL)@Vl+`B=6X3gF(BCm>Q(9+?IMX%?CqgpsvK+b_de%Q> zj-GtHKf!t@p2;Gu*~#}kF@Q2HMevg~?0{^cPxCRh!gdg7MXsS}BLtG_a0IY0G1DVm z2F&O-$Dzzc#M~iN`!j38gAn`6*~h~AP=s_gy2-#LMFoNZ0<3q+=q)a|4}ur7F#><%j1lnr=F42Mbti zi-LYs85K{%NP8wE1*r4Mm+ZuZ8qjovmB;f##!E*M{*A(4^~vg!bblYi1M@7tq^L8- zH7tf_70iWXqcSQgENGdEjvLiSLicUi3l0H*sx=K!!HLxDg^K|s1G}6Tam|KBV>%YeU)Q>zxQe;ddnDTWJZ~^g-kNeycQ?u242mZs`i8cP)9qW`cwqk)Jf?Re0=SD=2z;Gafh(^X-=WJ$i7Z9$Pao56bTwb+?p>L3bi9 zP|qi@;H^1iT+qnNHBp~X>dd=Us6v#FPDTQLb9KTk%z{&OWmkx3uY(c6JYyK3w|z#Q zMY%FPv%ZNg#w^NaW6lZBU+}Znwc|KF(+X0RO~Q6*O{T-P*fi@5cPGLnzWMSyoOPe3 z(J;R#q}3?z5Ve%crTPZQFLTW81cNY-finw!LH9wr$(C)p_@v?(y#b-R^Pv!}_#7t+A?pHEUMY zoQZIwSETTKeS!W{H$lyB1^!jn4gTD{_mgG?#l1Hx2h^HrpCXo95f3utP-b&%w80F} zXFs@Jp$lbIL64@gc?k*gJ;OForPaapOH7zNMB60FdNP<*9<@hEXJk9Rt=XhHR-5_$Ck-R?+1py&J3Y9^sBBZuj?GwSzua;C@9)@JZpaI zE?x6{H8@j9P06%K_m%9#nnp0Li;QAt{jf-7X%Pd2jHoI4As-9!UR=h6Rjc z!3{UPWiSeLG&>1V5RlM@;5HhQW_&-wL2?%k@dvRS<+@B6Yaj*NG>qE5L*w~1ATP$D zmWu6(OE=*EHqy{($~U4zjxAwpPn42_%bdH9dMphiUU|) z*+V@lHaf%*GcXP079>vy5na3h^>X=n;xc;VFx)`AJEk zYZFlS#Nc-GIHc}j06;cOU@ zAD7Egkw<2a8TOcfO9jCp4U4oI*`|jpbqMWo(={gG3BjuM3QTGDG`%y|xithFck}0J zG}N#LyhCr$IYP`#;}tdm-7^9=72+CBfBsOZ0lI=LC_a%U@(t3J_I1t(UdiJ^@NubM zvvA0mGvTC%{fj53M^|Ywv$KbW;n8B-x{9}Z!K6v-tw&Xe_D2{7tX?eVk$sA*0826( zuGz!K7$O#;K;1w<38Tjegl)PmRso`fc&>fAT5s z7hzQe-_`lx`}2=c)jz6;yn(~F6#M@z_7@Z(@GWbIAo6A2&;aFf&>CVHpqoPh5#~=G zav`rZ3mSL2qwNL+Pg>aQv;%V&41e|YU$!fQ9Ksle!XZERpjAowHtX zi#0lnw{(zmk&}t`iFEMmx-y7FWaE*vA{Hh&>ieZg{5u0-3@a8BY)Z47E`j-H$dadu zIP|PXw1gjO@%aSz*O{GqZs_{ke|&S6hV{-dPkl*V|3U4LpqhG0eVdqfeNX28hrafI zE13WOsRE|o?24#`gQJs@v*EwL{@3>Ffa;knvI4@VEG2I>t-L(KRS0ShZ9N!bwXa}e zI0}@2#PwFA&Y9o}>6(ZaSaz>kw{U=@;d{|dYJ~lyjh~@bBL>n}#@KjvXUOhrZ`DbnAtf5bz3LD@0RpmAyC-4cgu<7rZo&C3~A_jA*0)v|Ctcdu} zt@c7nQ6hSDC@76c4hI&*v|5A0Mj4eQ4kVb0$5j^*$@psB zdouR@B?l6E%a-9%i(*YWUAhxTQ(b@z&Z#jmIb9`8bZ3Um3UW!@w4%t0#nxsc;*YrG z@x$D9Yj3EiA(-@|IIzi@!E$N)j?gedGJpW!7wr*7zKZwIFa>j|cy<(1`VV_GzWN=1 zc%OO)o*RRobvTZE<9n1s$#V+~5u8ZwmDaysD^&^cxynksn!_ypmx)Mg^8$jXu5lMo zK3K_8GJh#+7HA1rO2AM8cK(#sXd2e?%3h2D9GD7!hxOEKJZK&T`ZS0e*c9c36Y-6yz2D0>Kvqy(EuiQtUQH^~M*HY!$e z20PGLb2Xq{3Ceg^sn+99K6w)TkprP)YyNU(+^PGU8}4&Vdw*u;(`Bw!Um76gL_aMT z>*82nmA8Tp;~hwi0d3S{vCwD};P(%AVaBr=yJ zqB?DktZ#)_VFh_X69lAHQw(ZNE~ZRo2fZOIP;N6fD)J*3u^YGdgwO(HnI4pb$H#9) zizJ<>qI*a6{+z=j+SibowDLKYI*Je2Y>~=*fL@i*f&8**s~4l&B&}$~nwhtbOTr=G zFx>{y6)dpJPqv={_@*!q0=jgw3^j`qi@!wiWiT_$1`SPUgaG&9z9u9=m5C8`GpMaM zyMRSv2llS4F}L?233!)f?mvcYIZ~U z7mPng^=p)@Z*Fp9owSYA`Fe4OjLiJ`rdM`-U(&z1B1`S`ufK_#T@_BvenxDQU`deH$X5eMVO=;I4EJjh6?kkG2oc6AYF6|(t)L0$ukG}Zn=c+R`Oq;nC)W^ z{ek!A?!nCsfd_5>d&ozG%OJmhmnCOtARwOq&p!FzWl7M))YjqK8|;6sOAc$w2%k|E z`^~kpT!j+Y1lvE0B)mc$Ez_4Rq~df#vC-FmW;n#7E)>@kMA6K30!MdiC19qYFnxQ* z?BKegU_6T37%s`~Gi2^ewVbciy-m5%1P3$88r^`xN-+VdhhyUj4Kzg2 zlKZ|FLUHiJCZL8&<=e=F2A!j@3D@_VN%z?J;uw9MquL`V*f^kYTrpoWZ6iFq00uO+ zD~Zwrs!e4cqGedAtYxZ76Bq3Ur>-h(m1~@{x@^*YExmS*vw9!Suxjlaxyk9P#xaZK z)|opA2v#h=O*T42z>Mub2O3Okd3GL86KZM2zlfbS z{Vps`OO&3efvt->OOSpMx~i7J@GsRtoOfQ%vo&jZ6^?7VhBMbPUo-V^Znt%-4k{I# z8&X)=KY{3lXlQg4^FH^{jw0%t#2%skLNMJ}hvvyd>?_AO#MtdvH;M^Y?OUWU6BdMX zJ(h;PM9mlo@i)lWX&#E@d4h zj4Z0Czj{+ipPeW$Qtz_A52HA<4$F9Qe4CiNQSNE2Q-d1OPObk4?7-&`={{yod5Iy3kB=PK3%0oYSr`Gca120>CHbC#SqE*ivL2R(YmI1A|nAT?JmK*2qj_3p#?0h)$#ixdmP?UejCg9%AS2 z8I(=_QP(a(s)re5bu-kcNQc-&2{QZ%KE*`NBx|v%K2?bK@Ihz_e<5Y(o(gQ-h+s&+ zjpV>uj~?rfJ!UW5Mop~ro^|FP3Z`@B6A=@f{Wn78cm`)3&VJ!QE+P9&$;3SDNH>hI z_88;?|LHr%1kTX0t*xzG-6BU=LRpJFZucRBQ<^zy?O5iH$t>o}C}Fc+kM1EZu$hm% zTTFKrJkXmCylFgrA;QAA(fX5Sia5TNo z?=Ujz7$Q?P%kM$RKqRQisOexvV&L+bolR%`u`k;~!o(HqgzV9I6w9|g*5SVZN6+kT9H$-3@%h%k7BBnB zPn+wmPYNG)V2Jv`&$LoI*6d0EO^&Nh`E* z&1V^!!Szd`8_uf%OK?fuj~! z%p9QLJ?V*T^)72<6p1ONqpmD?Wm((40>W?rhjCDOz?#Ei^sXRt|GM3ULLnoa8cABQ zA)gCqJ%Q5J%D&nJqypG-OX1`JLT+d`R^|0KtfGQU+jw79la&$GHTjKF>*8BI z0}l6TC@XB6`>7<&{6WX2kX4k+0SaI`$I8{{mMHB}tVo*(&H2SmZLmW* z+P8N>(r}tR?f!O)?)df>HIu>$U~e~tflVmwk*+B1;TuqJ+q_^`jwGwCbCgSevBqj$ z<`Fj*izeO)_~fq%wZ0Jfvi6<3v{Afz;l5C^C7!i^(W>%5!R=Ic7nm(0gJ~9NOvHyA zqWH2-6w^YmOy(DY{VrN6ErvZREuUMko@lVbdLDq*{A+_%F>!@6Z)X9kR1VI1+Ler+ zLUPtth=u~23=CqZoAbQ`uGE_91kR(8Ie$mq1p`q|ilkJ`Y-ob_=Nl(RF=o7k{47*I)F%_XMBz9uwRH8q1o$TkV@8Pwl zzi`^7i;K6Ak7o58a_D-V0AWp;H8pSjbEs$4BxoJkkC6UF@QNL)0$NU;Wv0*5 z0Ld;6tm7eR%u=`hnUb)gjHbE2cP?qpo3f4w%5qM0J*W_Kl6&z4YKX?iD@=McR!gTyhpGGYj!ljQm@2GL^J70`q~4CzPv@sz`s80FgiuxjAZ zLq61rHv1O>>w1qOEbVBwGu4%LGS!!muKHJ#JjfT>g`aSn>83Af<9gM3XBdY)Yql|{ zUds}u*;5wuus)D>HmexkC?;R&*Z`yB4;k;4T*(823M&52{pOd1yXvPJ3PPK{Zs>6w zztXy*HSH0scZHn7qIsZ8y-zftJ*uIW;%&-Ka0ExdpijI&xInDg-Bv-Q#Islcbz+R! zq|xz?3}G5W@*7jSd`Hv9q^5N*yN=4?Lh=LXS^5KJC=j|AJ5Y(f_fC-c4YQNtvAvn|(uP9@5Co{dL z?7|=jqTzD8>(6Wr&(XYUEzT~-VVErf@|KeFpKjh=v51iDYN_`Kg&XLOIG;ZI8*U$@ zKig{dy?1H}UbW%3jp@7EVSD>6c%#abQ^YfcO(`)*HuvNc|j( zyUbYozBR15$nNU$0ZAE%ivo4viW?@EprUZr6oX=4Sc!-WvrpJdF`3SwopKPyX~F>L zJ>N>v=_plttTSUq6bYu({&rkq)d94m5n~Sk_MO*gY*tlkPFd2m=Pi>MK)ObVV@Sgs zmXMNMvvcAuz+<$GLR2!j4w&;{)HEkxl{$B^*)lUKIn&p5_huD6+%WDoH4`p}9mkw$ zXCPw6Y7tc%rn$o_vy>%UNBC`0@+Ih-#T05AT)ooKt?94^ROI5;6m2pIM@@tdT=&WP z{u09xEVdD}{(3v}8AYUyT82;LV%P%TaJa%f)c36?=90z>Dzk5mF2}Gs0jYCmufihid8(VFcZWs8#59;JCn{!tHu5kSBbm zL`F{COgE01gg-qcP2Lt~M9}mALg@i?TZp&i9ZM^G<3`WSDh}+Ceb3Q!QecJ|N;Xrs z{wH{D8wQ2+mEfBX#M8)-32+~q4MRVr1UaSPtw}`iwx@x=1Xv-?UT{t}w}W(J&WKAC zrZ%hssvf*T!rs}}#atryn?LB=>0U%PLwA9IQZt$$UYrSw`7++}WR7tfE~*Qg)vRrM zT;(1>Zzka?wIIz8vfrG86oc^rjM@P7^i8D~b(S23AoKYj9HBC(6kq9g`1gN@|9^xO z{~h zbxGMHqGZ@eJ17bgES?HQnwp|G#7I>@p~o2zxWkgZUYSUeB*KT{1Q z*J3xZdWt`eBsA}7(bAHNcMPZf_BZC(WUR5B8wUQa=UV^e21>|yp+uop;$+#JwXD!> zunhJVCIKgaol0AM_AwJNl}_k&q|uD?aTE@{Q*&hxZ=k_>jcwp}KwG6mb5J*pV@K+- zj*`r0WuEU_8O=m&1!|rj9FG7ad<2px63;Gl z9lJrXx$~mPnuiqIH&n$jSt*ReG}1_?r4x&iV#3e_z+B4QbhHwdjiGu^J3vcazPi`| zaty}NFSWe=TDry*a*4XB)F;KDI$5i9!!(5p@5ra4*iW;FlGFV0P;OZXF!HCQ!oLm1 zsK+rY-FnJ?+yTBd0}{*Y6su|hul)wJ>RNQ{eau*;wWM{vWM`d0dTC-}Vwx6@cd#P? zx$Qyk^2*+_ZnMC}q0)+hE-q)PKoox#;pc%DNJ&D5+if6X4j~p$A7-s&AjDkSEV)aM z(<3UOw*&f)+^5F0Mpzw3zB1ZHl*B?C~Cx) zuNg*>5RM9F5{EpU@a2E7hAE`m<89wbQ2Lz&?Egu-^sglNXG5Q;{9n(%&*kEb0vApd zRHrY@22=pkFN81%x)~acZeu`yvK zovAVJNykgxqkEr^hZksHkpxm>2I8FTu2%+XLs@?ym0n;;A~X>i32{g6NOB@o4lk8{ zB}7Z2MNAJi>9u=y%s4QUXaNdt@SlAZr54!S6^ETWoik6gw=k-itu_}Yl_M9!l+Rbv z(S&WD`{_|SE@@(|Wp7bq1Zq}mc4JAG?mr2WN~6}~u`7M_F@J9`sr0frzxfuqSF~mA z$m$(TWAuCIE99yLSwi%R)8geQhs;6VBlRhJb(4Cx zu)QIF%_W9+21xI45U>JknBRaZ9nYkgAcK6~E|Zxo!B&z9zQhjsi^fgwZI%K@rYbMq znWBXg1uCZ+ljGJrsW7@x3h2 z;kn!J!bwCeOrBx;oPkZ}FeP%wExyf4=XMp)N8*lct~SyfK~4^-75EZFpHYO5AnuRM z!>u?>Vj3+j=uiHc<=cD~JWRphDSwxFaINB42-{@ZJTWe85>-RcQ&U%?wK)vjz z5u5fJYkck##j(bP7W0*RdW#BmAIK`D3=(U~?b`cJ&U2jHj}?w6 z_4BM)#EoJ6)2?pcR4AqBd)qAUn@RtNQq})FIQoBK4ie+GB(Vih2D|Ds>RJo2zE~C- z7mI)7p)5(-O6JRh6a@VZ5~piVC+Xv=O-)=0eTMSJsRE^c1@bPQWlr}E31VqO-%739 zdcmE{`1m;5LH8w|7euK>>>U#Iod8l1yivC>;YWsg=z#07E%cU9x1yw#3l6AcIm%79 zGi^zH6rM#CZMow(S(8dcOq#5$kbHnQV6s?MRsU3et!!YK5H?OV9vf2qy-UHCn>}2d zTwI(A_fzmmCtE@10yAGgU7R&|Fl$unZJ_^0BgCEDE6(B*SzfkapE9#0N6adc>}dtH zJ#nt^F~@JMJg4=Pv}OdUHyPt-<<9Z&c0@H@^4U?KwZM&6q0XjXc$>K3c&3iXLD9_%(?)?2kmZ=Ykb;)M`Tw=%_d=e@9eheGG zk0<`4so}r={C{zr|6+_1mA_=a56(XyJq||g6Es1E6%fPg#l{r+vk9;)r6VB7D84nu zE0Z1EIxH{Y@}hT+|#$0xn+CdMy6Uhh80eK~nfMEIpM z`|G1v!USmx81nY8XkhEOSWto}pc#{Ut#`Pqb}9j$FpzkQ7`0<-@5D_!mrLah98Mpr zz(R7;ZcaR-$aKqUaO!j z=7QT;Bu0cvYBi+LDfE_WZ`e@YaE_8CCxoRc?Y_!Xjnz~Gl|aYjN2&NtT5v4#q3od2 zkCQZHe#bn(5P#J**Fj4Py%SaaAKJsmV6}F_6Z7V&n6QAu8UQ#9{gkq+tB=VF_Q6~^ zf(hXvhJ#tC(eYm6g|I>;55Lq-;yY*COpTp4?J}hGQ42MIVI9CgEC{3hYw#CZfFKVG zgD(steIg8veyqX%pYMoulq zMUmbj8I`t>mC`!kZ@A>@PYXy*@NprM@e}W2Q+s?XIRM-U1FHVLM~c60(yz1<46-*j zW*FjTnBh$EzI|B|MRU11^McTPIGVJrzozlv$1nah_|t4~u}Ht^S1@V8r@IXAkN;lH z_s|WHlN90k4X}*#neR5bX%}?;G`X!1#U~@X6bbhgDYKJK17~oFF0&-UB#()c$&V<0 z7o~Pfye$P@$)Lj%T;axz+G1L_YQ*#(qO zQND$QTz(~8EF1c3<%;>dAiD$>8j@7WS$G_+ktE|Z?Cx<}HJb=!aChR&4z ziD&FwsiZ)wxS4k6KTLn>d~!DJ^78yb>?Trmx;GLHrbCBy|Bip<@sWdAfP0I~;(Ybr zoc-@j?wA!$ zIP0m3;LZy+>dl#&Ymws@7|{i1+OFLYf@+8+)w}n?mHUBCqg2=-Hb_sBb?=q))N7Ej zDIL9%@xQFOA!(EQmchHiDN%Omrr;WvlPIN5gW;u#ByV)x2aiOd2smy&;vA2+V!u|D zc~K(OVI8} z0t|e0OQ7h23e01O;%SJ}Q#yeDh`|jZR7j-mL(T4E;{w^}2hzmf_6PF|`gWVj{I?^2T3MBK>{?nMXed4kgNox2DP!jvP9v`;pa6AV)OD zDt*Vd-x7s{-;E?E5}3p-V;Y#dB-@c5vTWfS7<=>E+tN$ME`Z7K$px@!%{5{uV`cH80|IzU! zDs9=$%75P^QKCRQ`mW7$q9U?mU@vrFMvx)NNDrI(uk>xwO;^($EUvqVev#{W&GdtR z0ew;Iwa}(-5D28zABlC{WnN{heSY5Eq5Fc=TN^9X#R}0z53!xP85#@;2E=&oNYHyo z46~#Sf!1M1X!rh}ioe`>G2SkPH{5nCoP`GT@}rH;-LP1Q7U_ypw4+lwsqiBql80aA zJE<(88yw$`xzNiSnU(hsyJqHGac<}{Av)x9lQ=&py9djsh0uc}6QkmKN3{P!TEy;P zzLDVQj4>+0r<9B0owxBt5Uz`!M_VSS|{(?`_e+qD9b=vZHoo6>?u;!IP zM7sqoyP>kWY|=v06gkhaGRUrO8n@zE?Yh8$om@8%=1}*!2wdIWsbrCg@;6HfF?TEN z+B_xtSvT6H3in#8e~jvD7eE|LTQhO_>3b823&O_l$R$CFvP@3~)L7;_A}JpgN@ax{ z2d9Ra)~Yh%75wsmHK8e87yAn-ZMiLo6#=<&PgdFsJw1bby-j&3%&4=9dQFltFR(VB z@=6XmyNN4yr^^o$ON8d{PQ=!OX17^CrdM~7D-;ZrC!||<+FEOxI_WI3 zCA<35va%4v>gcEX-@h8esj=a4szW7x z{0g$hwoWRQG$yK{@3mqd-jYiVofJE!Wok1*nV7Gm&Ssq#hFuvj1sRyHg(6PFA5U*Q z8Rx>-blOs=lb`qa{zFy&n4xY;sd$fE+<3EI##W$P9M{B3c3Si9gw^jlPU-JqD~Cye z;wr=XkV7BSv#6}DrsXWFJ3eUNrc%7{=^sP>rp)BWKA9<}^R9g!0q7yWlh;gr_TEOD|#BmGq<@IV;ue zg+D2}cjpp+dPf&Q(36sFU&K8}hA85U61faW&{lB`9HUl-WWCG|<1XANN3JVAkRYvr5U z4q6;!G*MTdSUt*Mi=z_y3B1A9j-@aK{lNvxK%p23>M&=KTCgR!Ee8c?DAO2_R?Bkaqr6^BSP!8dHXxj%N1l+V$_%vzHjq zvu7p@%Nl6;>y*S}M!B=pz=aqUV#`;h%M0rUHfcog>kv3UZAEB*g7Er@t6CF8kHDmK zTjO@rejA^ULqn!`LwrEwOVmHx^;g|5PHm#B6~YD=gjJ!043F+&#_;D*mz%Q60=L9O zve|$gU&~As5^uz@2-BfQ!bW)Khn}G+Wyjw-19qI#oB(RSNydn0t~;tAmK!P-d{b-@ z@E5|cdgOS#!>%#Rj6ynkMvaW@37E>@hJP^82zk8VXx|3mR^JCcWdA|t{0nPmYFOxN z55#^-rlqobcr==<)bi?E?SPymF*a5oDDeSdO0gx?#KMoOd&G(2O@*W)HgX6y_aa6i zMCl^~`{@UR`nMQE`>n_{_aY5nA}vqU8mt8H`oa=g0SyiLd~BxAj2~l$zRSDHxvDs; zI4>+M$W`HbJ|g&P+$!U7-PHX4RAcR0szJ*(e-417=bO2q{492SWrqDK+L3#ChUHtz z*@MP)e^%@>_&#Yk^1|tv@j4%3T)diEXATx4K*hcO`sY$jk#jN5WD<=C3nvuVs zRh||qDHnc~;Kf59zr0;c7VkVSUPD%NnnJC_l3F^#f_rDu8l}l8qcAz0FFa)EAt32I zUy_JLIhU_J^l~FRH&6-iv zSpG2PRqzDdMWft>Zc(c)#tb%wgmWN%>IOPmZi-noqS!^Ft zb81pRcQi`X#UhWK70hy4tGW1mz|+vI8c*h@fFGJtW3r>qV>1Z0r|L>7I3un^gcep$ zAAWfZHRvB|E*kktY$qQP_$YG60C z@X~tTQjB3%@`uz!qxtxF+LE!+=nrS^07hn`EgAp!h|r03h7B!$#OZW#ACD+M;-5J!W+{h z|6I;5cNnE(Y863%1(oH}_FTW})8zYb$7czPg~Szk1+_NTm6SJ0MS_|oSz%e(S~P-& zSFp;!k?uFayytV$8HPwuyELSXOs^27XvK-DOx-Dl!P|28DK6iX>p#Yb%3`A&CG0X2 zS43FjN%IB}q(!hC$fG}yl1y9W&W&I@KTg6@K^kpH8=yFuP+vI^+59|3%Zqnb5lTDAykf9S#X`3N(X^SpdMyWQGOQRjhiwlj!0W-yD<3aEj^ z&X%=?`6lCy~?`&WSWt?U~EKFcCG_RJ(Qp7j=$I%H8t)Z@6Vj zA#>1f@EYiS8MRHZphpMA_5`znM=pzUpBPO)pXGYpQ6gkine{ z6u_o!P@Q+NKJ}k!_X7u|qfpAyIJb$_#3@wJ<1SE2Edkfk9C!0t%}8Yio09^F`YGzp zaJHGk*-ffsn85@)%4@`;Fv^8q(-Wk7r=Q8pT&hD`5(f?M{gfzGbbwh8(}G#|#fDuk z7v1W)5H9wkorE0ZZjL0Q1=NRGY>zwgfm81DdoaVwNH;or{{e zSyybt)m<=zXoA^RALYG-2touH|L*BLvmm9cdMmn+KGopyR@4*=&0 z&4g|FLoreZOhRmh=)R0bg~T2(8V_q7~42-zvb)+y959OAv!V$u(O z3)%Es0M@CRFmG{5sovIq4%8Ahjk#*5w{+)+MWQoJI_r$HxL5km1#6(e@{lK3Udc~n z0@g`g$s?VrnQJ$!oPnb?IHh-1qA`Rz$)Ai<6w$-MJW-gKNvOhL+XMbE7&mFt`x1KY z>k4(!KbbpZ`>`K@1J<(#vVbjx@Z@(6Q}MF#Mnbr-f55)vXj=^j+#)=s+ThMaV~E`B z8V=|W_fZWDwiso8tNMTNse)RNBGi=gVwgg%bOg8>mbRN%7^Um-7oj4=6`$|(K7!+t^90a{$1 z8Z>}<#!bm%ZEFQ{X(yBZMc>lCz0f1I2w9SquGh<9<=AO&g6BZte6hn>Qmvv;Rt)*c zJfTr2=~EnGD8P$v3R|&1RCl&7)b+`=QGapiPbLg_pxm`+HZurtFZ;wZ=`Vk*do~$wBxoW&=j0OTbQ=Q%S8XJ%~qoa3Ea|au5 zo}_(P;=!y z-AjFrERh%8la!z6Fn@lR?^E~H12D? z8#ht=1F;7@o4$Q8GDj;sSC%Jfn01xgL&%F2wG1|5ikb^qHv&9hT8w83+yv&BQXOQy zMVJSBL(Ky~p)gU3#%|blG?I zR9rP^zUbs7rOA0X52Ao=GRt@C&zlyjNLv-}9?*x{y(`509qhCV*B47f2hLrGl^<@S zuRGR!KwHei?!CM10pBKpDIoBNyRuO*>3FU?HjipIE#B~y3FSfOsMfj~F9PNr*H?0o zHyYB^G(YyNh{SxcE(Y-`x5jFMKb~HO*m+R%rq|ic4fzJ#USpTm;X7K+E%xsT_3VHK ze?*uc4-FsILUH;kL>_okY(w`VU*8+l>o>JmiU#?2^`>arnsl#)*R&nf_%>A+qwl%o z{l(u)M?DK1^mf260_oteV3#E_>6Y4!_hhVDM8AI6MM2V*^_M^sQ0dmHu11fy^kOqX zqzps-c5efIKWG`=Es(9&S@K@)ZjA{lj3ea7_MBPk(|hBFRjHVMN!sNUkrB;(cTP)T97M$ z0Dtc&UXSec<+q?y>5=)}S~{Z@ua;1xt@=T5I7{`Z=z_X*no8s>mY;>BvEXK%b`a6(DTS6t&b!vf_z#HM{Uoy z_5fiB(zpkF{})ruka$iX*~pq1ZxD?q68dIoIZSVls9kFGsTwvr4{T_LidcWtt$u{k zJlW7moRaH6+A5hW&;;2O#$oKyEN8kx z`LmG)Wfq4ykh+q{I3|RfVpkR&QH_x;t41UwxzRFXt^E2B$domKT@|nNW`EHwyj>&< zJatrLQ=_3X%vd%nHh^z@vIk(<5%IRAa&Hjzw`TSyVMLV^L$N5Kk_i3ey6byDt)F^U zuM+Ub4*8+XZpnnPUSBgu^ijLtQD>}K;eDpe1bNOh=fvIfk`&B61+S8ND<(KC%>y&? z>opCnY*r5M+!UrWKxv0_QvTlJc>X#AaI^xoaRXL}t5Ej_Z$y*|w*$6D+A?Lw-CO-$ zitm^{2Ct82-<0IW)0KMNvJHgBrdsIR0v~=H?n6^}l{D``Me90`^o|q!olsF?UX3YS zq^6Vu>Ijm>>PaZI8G@<^NGw{Cx&%|PwYrfwR!gX_%AR=L3BFsf8LxI|K^J}deh0Zd zV?$3r--FEX`#INxsOG6_=!v)DI>0q|BxT)z-G6kzA01M?rba+G_mwNMQD1mbVbNTW zmBi*{s_v_Ft9m2Avg!^78(QFu&n6mbRJ2bAv!b;%yo{g*9l2)>tsZJOOp}U~8VUH`}$8p_}t*XIOehezolNa-a2x0BS})Y9}& z*TPgua{Ewn-=wVrmJUeU39EKx+%w%=ixQWKDLpwaNJs65#6o7Ln7~~X+p_o2BR1g~ zVCfxLzxA{HlWAI6^H;`juI=&r1jQrUv_q0Z1Ja-tjdktrrP>GOC*#p?*xfQU5MqjM zsBe!9lh(u8)w$e@Z|>aUHI5o;MGw*|Myiz3-f0;pHg~Q#%*Kx8MxH%AluVXjG2C$) zWL-K63@Q`#y9_k_+}eR(x4~dp7oV-ek0H>Igy8p#i4GN{>#v=pFYUQT(g&b$OeTy- zX_#FDgNF8XyfGY6R!>inYn8IR2RDa&O!(6NIHrC0H+Qpam1bNa=(`SRKjixBTtm&e z`j9porEci!zdlg1RI0Jw#b(_Tb@RQK1Zxr_%7SUeH6=TrXt3J@js`4iDD0=I zoHhK~I7^W8^Rcp~Yaf>2wVe|Hh1bXa_A{oZ9eG$he;_xYvTbTD#moBy zY57-f2Ef1TP^lBi&p5_s7WGG9|0T}dlfxOxXvScJO1Cnq`c`~{Dp;{;l<-KkCDE+p zmexJkd}zCgE{eF=)K``-qC~IT6GcRog_)!X?fK^F8UDz$(zFUrwuR$qro5>qqn>+Z z%<5>;_*3pZ8QM|yv9CAtrAx;($>4l^_$_-L*&?(77!-=zvnCVW&kUcZMb6;2!83si z518Y%R*A3JZ8Is|kUCMu`!vxDgaWjs7^0j(iTaS4HhQ)ldR=r)_7vYFUr%THE}cPF z{0H45FJ5MQW^+W>P+eEX2kLp3zzFe*-pFVAdDZRybv?H|>`9f$AKVjFWJ=wegO7hO zOIYCtd?Vj{EYLT*^gl35|HbMX|NAEUf2ra9dy1=O;figB>La=~eA^#>O6n4?EMugV zbbt{Dbfef5l^(;}5kZ@!XaWwF8z0vUr6r|+QN*|WpF z^*osUHzOnE$lHuWYO$G7>}Y)bY0^9UY4eDV`E{s+{}Z$O$2*lMEYl zTA`ki(<0(Yrm~}15V-E^e2W6`*`%ydED-3G@$UFm6$ZtLx z+av`BhsHcAWqdxPWfu2*%{}|Sptax4_=NpDMeWy$* zZM6__s`enB$~0aT1BU^2k`J9F%+n+lL_|8JklWOCVYt*0%o*j4w1CsB_H^tVpYT_LLyKuyk=CV6~1M<7~^FylL*+AIFf3h>J=x$ygY-BG}4LJ z8XxYPY!v7dO3PVwEoY=`)6krokmR^|Mg5ztX_^#QR}ibr^X-|_St#rtv3gukh0(#A=};NPlNz57ZDFJ9hf#NP50zS)+Fo=StX)i@ zWS?W}i6LjB>kAB~lupAPyIjFb)izFgRq*iS*(Jt509jNr3r72{Gj`5DGoj;J&k5G@Rm!dJ($ox>SbxR)fc zz|Phug;~A7!p@?|mMva@rWuf2fSDK_ZxN3vVmlYz>rrf?LpiNs)^z!y{As@`55JC~ zS*GD3#N-ptY!2<613UelAJ;M4EEI$dm)`8#n$|o{ce^dlyoUY3bsy2hgnj-;ovubb zg2h1rZA6Ot}K_cpYBpIuF&CyK~5R0Wv;kG|3A^8K3nk{rw$Be8u@aos#qvKQKJyVU$cX6biw&Ep#+q7upFX z%qo&`WZ){<%zh@BTl{MO@v9#;t+cb7so0Uz49Fmo1e4>y!vUyIHadguZS0T7-x#_drMXz*16*c zymR0u^`ZQpXN}2ofegbpSedL%F9aypdQcrzjzPlBW0j zMlPzC&ePZ@Cq!?d%9oQNEg0`rHALm8l#lUdXMVEqDvb(AID~H(?H9z!e9G98fG@IzhajKr)3{L_Clu1(Bwg`RM!-(MOuZi zbeDsj9I3(~EITsE=3Z)a|l_rn8W92U0DB70gF7YYfO0j!)h?QobY1lSR>0 z_TVw@$eP~3k8r9;%g%RlZzCJ2%f}DvY`rsZ$;ak&^~-`i%B%+O!pnADeVyV!dHj|} zzOj#q4eRx9Q8c2Z7vy9L&fGLj+3_?fp}+8o`Xpwyi(81H|7P8#65%FIS*lOi={o&v z4NV$xu7az4Nb50dRGZv<tdZCx4Ek<_o3!mAT} zL5l*|K3Qr-)W8paaG z&R6{ped_4e2cy}ejD0!dt{*PaC*^L@eB%(1Fmc%Y#4)~!jF#lCGfj#E??4LG-T;!M z>Uha}f;W>ib_ZL-I7-v9KZQls^G!-JmL^w;=^}?!RXK;m4$#MwI2AH-l7M2-0 zVMK8k^+4+>2S0k^N_40EDa#`7c;2!&3-o6MHsnBfRnq@>E@)=hDulVq-g5SQWDWbt zj6H5?QS2gRZ^Zvbs~cW|8jagJV|;^zqC0e=D1oUsQPJ3MCb+eRGw(XgIY9y8v_tXq z9$(xWntWpx_Uronmvho{JfyYdV{L1N$^s^|-Nj`Ll`lUsiWTjm&8fadUGMXreJGw$ zQ**m+Tj|(XG}DyUKY~2?&9&n6SJ@9VKa9Hcayv{ar^pNr0WHy zP$bQv&8O!vd;GoT!pLwod-42qB^`m!b7nP@YTX}^+1hzA$}LSLh}Ln|?`%8xGMazw z8WT!LoYJ-Aq3=2p6ZSP~uMgSSWv3f`&-I06tU}WhZsA^6nr&r17hjQIZE>^pk=yZ% z06}dfR$85MjWJPq)T?OO(RxoaF+E#4{Z7)i9}Xsb;Nf+dzig61HO;@JX1Lf9)R5j9)Oi6vPL{H z&UQ9ln=$Q8jnh6-t;`hKM6pHftdd?$=1Aq16jty4-TF~`Gx=C&R242uxP{Y@Q~%O3 z*(16@x+vJsbW@^3tzY=-5MHi#(kB};CU%Ep`mVY1j$MAPpYJBB3x$ue`%t}wZ-@CG z(lBv36{2HMjxT)2$n%(UtHo{iW9>4HX4>)%k8QNnzIQYXrm-^M%#Qk%9odbUrZDz1YPdY`2Z4w~p!5tb^m(mUfk}kZ9+EsmenQ)5iwiaulcy zCJ#2o4Dz?@%)aAKfVXYMF;3t@aqNh2tBBlBkCdj`F31b=h93y(46zQ-YK@+zX5qM9 z&=KkN&3@Ptp*>UD$^q-WpG|9O)HBXz{D>p!`a36aPKkgz7uxEo0J>-o+4HHVD9!Hn z${LD0d{tuGsW*wvZoHc8mJroAs(3!FK@~<}Pz1+vY|Gw}Lwfxp{4DhgiQ_SSlV)E| zZWZxYZLu2EB1=g_y@(ieCQC_1?WNA0J0*}eMZfxCCs>oL;?kHdfMcKB+A)Qull$v( z2x6(38utR^-(?DG>d1GyU()8>ih3ud0@r&I$`ZSS<*1n6(76=OmP>r_JuNCdS|-8U zxGKXL1)Lc2kWY@`_kVBt^%7t9FyLVYX(g%a6>j=yURS1!V<9ieT$$5R+yT!I>}jI5 z?fem|T=Jq;BfZmsvqz_Ud*m5;&xE66*o*S22vf-L+MosmUPPA}~wy`kntf8rIeP-m;;{`xe}9E~G7J!PYoVH_$q~NzQab?F8vWUja5BJ!T5%5IpyqI#Dkps0B;gQ*z?c#N>spFw|wRE$gY?y4wQbJ zku2sVLh({KQz6e0yo+X!rV#8n8<;bHWd{ZLL_(*9Oi)&*`LBdGWz>h zx+p`Wi00u#V$f=CcMmEmgFjw+KnbK3`mbaKfoCsB{;Q^oJgj*LWnd_(dk9Kcssbj` z?*g8l`%{*LuY!Ls*|Tm`1Gv-tRparW8q4AK(5pfJFY5>@qO( zcY>pt*na>LlB^&O@YBDnWLE$x7>pMdSmb-?qMh79eB+Wa{)$%}^kX@Z3g>fytppz! zl%>pMD(Yw+5=!UgYHLD69JiJ;YhiGeEyZM$Au{ff;i zCBbNQfO{d!b7z^F732XX&qhEsJA1UZtJjJEIPyDq+F`LeAUU_4`%2aTX#3NG3%W8u zC!7OvlB?QJ4s2#Ok^_8SKcu&pBd}L?vLRT8Kow#xARt`5&Cg=ygYuz>>c z4)+Vv$;<$l=is&E{k&4Lf-Lzq#BHuWc;wDfm4Fbd5Sr!40s{UpKT$kzmUi{V0t1yp zPOf%H8ynE$x@dQ_!+ISaI}#%72UcYm7~|D*(Fp8xiFAj$CmQ4oH3C+Q8W=Y_9Sp|B z+k<%5=y{eW=YvTivV(*KvC?qxo)xqcEU9(Te=?ITts~;xA0Jph-vpd4@Zw#?r2!`? zB3#XtIY^wxrpjJv&(7Xjvm>$TIg2ZC&+^j(gT0R|&4cb)=92-2Hti1`& z=+M;*O%_j3>9zW|3h{0Tfh5i)Fa;clGNJpPRcUmgErzC{B+zACiPHbff3SmsCZ&X; zp=tgI=zW-t(5sXFL8;ITHw0?5FL3+*z5F-KcLN130l=jAU6%F=DClRPrzO|zY+HD`zlZ-)JT}X?2g!o zxg4Ld-mx6&*-N0-MQ(z+zJo8c`B39gf{-h2vqH<=^T&o1Dgd>4BnVht+JwLcrjJl1 zsP!8`>3-rSls07q2i1hScM&x0lQyBbk(U=#3hI7Bkh*kj6H*&^p+J?OMiT_3*vw5R zEl&p|QQHZq6f~TlAeDGy(^BC0vUK?V&#ezC0*#R-h}_8Cw8-*${mVfHssathC8%VA zUE^Qd!;Rvym%|f@?-!sEj|73Vg8!$$zj_QBZAOraF5HCFKl=(Ac|_p%-P;6z<2WSf zz(9jF2x7ZR{w+p)ETCW06PVt0YnZ>gW9^sr&~`%a_7j-Ful~*4=o|&TM@k@Px2z>^ t{*Ed16F~3V5p+(suF-++X8+nHtT~NSfJ>UC3v)>lEpV}<+rIR_{{yMcG_L>v diff --git a/implementations/cli/gradle/wrapper/gradle-wrapper.properties b/implementations/cli/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 48c0a02ca..000000000 --- a/implementations/cli/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/implementations/cli/gradlew b/implementations/cli/gradlew deleted file mode 100644 index 1b6c78733..000000000 --- a/implementations/cli/gradlew +++ /dev/null @@ -1,234 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" -APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/implementations/cli/gradlew.bat b/implementations/cli/gradlew.bat deleted file mode 100644 index 107acd32c..000000000 --- a/implementations/cli/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/implementations/fabric-1.19.4/gradle/wrapper/gradle-wrapper.jar b/implementations/fabric-1.19.4/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 41d9927a4d4fb3f96a785543079b8df6723c946b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59821 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 diff --git a/implementations/fabric-1.19.4/gradle/wrapper/gradle-wrapper.properties b/implementations/fabric-1.19.4/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 48c0a02ca..000000000 --- a/implementations/fabric-1.19.4/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/implementations/fabric-1.19.4/gradlew b/implementations/fabric-1.19.4/gradlew deleted file mode 100644 index 1b6c78733..000000000 --- a/implementations/fabric-1.19.4/gradlew +++ /dev/null @@ -1,234 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" -APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/implementations/fabric-1.19.4/gradlew.bat b/implementations/fabric-1.19.4/gradlew.bat deleted file mode 100644 index 107acd32c..000000000 --- a/implementations/fabric-1.19.4/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/implementations/fabric-1.20/gradle/wrapper/gradle-wrapper.jar b/implementations/fabric-1.20/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 41d9927a4d4fb3f96a785543079b8df6723c946b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59821 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 diff --git a/implementations/fabric-1.20/gradle/wrapper/gradle-wrapper.properties b/implementations/fabric-1.20/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 48c0a02ca..000000000 --- a/implementations/fabric-1.20/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/implementations/fabric-1.20/gradlew b/implementations/fabric-1.20/gradlew deleted file mode 100644 index 1b6c78733..000000000 --- a/implementations/fabric-1.20/gradlew +++ /dev/null @@ -1,234 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" -APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/implementations/fabric-1.20/gradlew.bat b/implementations/fabric-1.20/gradlew.bat deleted file mode 100644 index 107acd32c..000000000 --- a/implementations/fabric-1.20/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/implementations/forge-1.18.1/gradle/wrapper/gradle-wrapper.jar b/implementations/forge-1.18.1/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 41d9927a4d4fb3f96a785543079b8df6723c946b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59821 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 diff --git a/implementations/forge-1.18.1/gradle/wrapper/gradle-wrapper.properties b/implementations/forge-1.18.1/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 48c0a02ca..000000000 --- a/implementations/forge-1.18.1/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/implementations/forge-1.18.1/gradlew b/implementations/forge-1.18.1/gradlew deleted file mode 100644 index 1b6c78733..000000000 --- a/implementations/forge-1.18.1/gradlew +++ /dev/null @@ -1,234 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" -APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/implementations/forge-1.18.1/gradlew.bat b/implementations/forge-1.18.1/gradlew.bat deleted file mode 100644 index 107acd32c..000000000 --- a/implementations/forge-1.18.1/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/implementations/forge-1.19.4/gradle/wrapper/gradle-wrapper.jar b/implementations/forge-1.19.4/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 41d9927a4d4fb3f96a785543079b8df6723c946b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59821 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 diff --git a/implementations/forge-1.19.4/gradle/wrapper/gradle-wrapper.properties b/implementations/forge-1.19.4/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 48c0a02ca..000000000 --- a/implementations/forge-1.19.4/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/implementations/forge-1.19.4/gradlew b/implementations/forge-1.19.4/gradlew deleted file mode 100644 index 1b6c78733..000000000 --- a/implementations/forge-1.19.4/gradlew +++ /dev/null @@ -1,234 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" -APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/implementations/forge-1.19.4/gradlew.bat b/implementations/forge-1.19.4/gradlew.bat deleted file mode 100644 index 107acd32c..000000000 --- a/implementations/forge-1.19.4/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/implementations/forge-1.20/gradle/wrapper/gradle-wrapper.jar b/implementations/forge-1.20/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 41d9927a4d4fb3f96a785543079b8df6723c946b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59821 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 diff --git a/implementations/forge-1.20/gradle/wrapper/gradle-wrapper.properties b/implementations/forge-1.20/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 48c0a02ca..000000000 --- a/implementations/forge-1.20/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/implementations/forge-1.20/gradlew b/implementations/forge-1.20/gradlew deleted file mode 100644 index 1b6c78733..000000000 --- a/implementations/forge-1.20/gradlew +++ /dev/null @@ -1,234 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" -APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/implementations/forge-1.20/gradlew.bat b/implementations/forge-1.20/gradlew.bat deleted file mode 100644 index 107acd32c..000000000 --- a/implementations/forge-1.20/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/implementations/paper/gradle/wrapper/gradle-wrapper.jar b/implementations/paper/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 41d9927a4d4fb3f96a785543079b8df6723c946b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59821 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 diff --git a/implementations/paper/gradle/wrapper/gradle-wrapper.properties b/implementations/paper/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 48c0a02ca..000000000 --- a/implementations/paper/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/implementations/paper/gradlew b/implementations/paper/gradlew deleted file mode 100644 index 1b6c78733..000000000 --- a/implementations/paper/gradlew +++ /dev/null @@ -1,234 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" -APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/implementations/paper/gradlew.bat b/implementations/paper/gradlew.bat deleted file mode 100644 index 107acd32c..000000000 --- a/implementations/paper/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/implementations/spigot/gradle/wrapper/gradle-wrapper.jar b/implementations/spigot/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 41d9927a4d4fb3f96a785543079b8df6723c946b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59821 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 diff --git a/implementations/spigot/gradle/wrapper/gradle-wrapper.properties b/implementations/spigot/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 48c0a02ca..000000000 --- a/implementations/spigot/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/implementations/spigot/gradlew b/implementations/spigot/gradlew deleted file mode 100644 index 1b6c78733..000000000 --- a/implementations/spigot/gradlew +++ /dev/null @@ -1,234 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" -APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/implementations/spigot/gradlew.bat b/implementations/spigot/gradlew.bat deleted file mode 100644 index 107acd32c..000000000 --- a/implementations/spigot/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/implementations/sponge/gradle/wrapper/gradle-wrapper.jar b/implementations/sponge/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 7454180f2ae8848c63b8b4dea2cb829da983f2fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59536 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 QuEJmfE|#`Dqx|px0L@K;Y5)KL diff --git a/implementations/sponge/gradle/wrapper/gradle-wrapper.properties b/implementations/sponge/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 48c0a02ca..000000000 --- a/implementations/sponge/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/implementations/sponge/gradlew b/implementations/sponge/gradlew deleted file mode 100644 index 744e882ed..000000000 --- a/implementations/sponge/gradlew +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/env sh - -# -# Copyright 2015 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MSYS* | MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -exec "$JAVACMD" "$@" diff --git a/implementations/sponge/gradlew.bat b/implementations/sponge/gradlew.bat deleted file mode 100644 index 107acd32c..000000000 --- a/implementations/sponge/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega