diff --git a/README.md b/README.md index 8237601..4739176 100644 --- a/README.md +++ b/README.md @@ -23,9 +23,8 @@ Download: [GeyserOptionalPack.mcpack](https://download.geysermc.org/v2/projects/ ### Manually compiling the pack 1. Clone the repo to your computer -2. Run `gradlew build`. -3. Run the pack compiler using `java -jar build/libs/GeyserOptionalPackCompiler.jar` -4. When it finishes compiling, it will output the `GeyserOptionalPack.mcpack`. +2. Run `gradlew run`. +3. When it finishes compiling, it will output the `GeyserOptionalPack.mcpack`. ### Legal diff --git a/developer_documentation.md b/developer_documentation.md index b1a38c4..35c9adf 100644 --- a/developer_documentation.md +++ b/developer_documentation.md @@ -26,6 +26,11 @@ The GeyserOptionalPack is compiled using a program written in Java. It contains Entity data and entity flags (known as queries in Molang) are pieces of metadata that store various pieces of information about an entity on the Bedrock Edition of Minecraft. You can query for an entity's health, for example (a number query or an entity data), and can query for if an entity is angry (an entity flag, which is either 1.0 or 0.0 in Molang). Not all entities use every query, but every entity has access to most queries, though Bedrock by default ignores these. These queries can be sent by Geyser and change how an entity looks. We use this to our advantage in this resource pack. +### Patches +There is a system within the compiler to apply patches to the vanilla Bedrock json files. This is done by placing a `.patch.json` in the `patches` resource folder, with the same path as the file you want to patch. The patch file will be merged with the original file, replacing any existing keys. This is useful for small changes to vanilla files, such as adding an extra texture to an entity. + +The source for these files is https://github.com/Mojang/bedrock-samples/tree/main/resource_pack with each patch being the same name and path as the original file but with `.json` replaced with `.patch.json`. + ### Armor stands #### Part visibility and rotation encoding diff --git a/src/main/java/org/geysermc/optionalpack/BedrockResourcesWrapper.java b/src/main/java/org/geysermc/optionalpack/BedrockResourcesWrapper.java index 164a73f..4b361bf 100644 --- a/src/main/java/org/geysermc/optionalpack/BedrockResourcesWrapper.java +++ b/src/main/java/org/geysermc/optionalpack/BedrockResourcesWrapper.java @@ -6,10 +6,10 @@ public class BedrockResourcesWrapper { private static final String BEDROCK_RESOURCES_URL = "https://raw.githubusercontent.com/Mojang/bedrock-samples/refs/tags/v" + Constants.BEDROCK_TARGET_VERSION + "/resource_pack/%s"; public static String getResourceAsString(String path) { - return HTTP.getAsString(BEDROCK_RESOURCES_URL.formatted(path)); + return WebUtils.getAsString(BEDROCK_RESOURCES_URL.formatted(path)); } public static InputStream getResource(String path) { - return HTTP.request(BEDROCK_RESOURCES_URL.formatted(path)); + return WebUtils.request(BEDROCK_RESOURCES_URL.formatted(path)); } } diff --git a/src/main/java/org/geysermc/optionalpack/FileUtils.java b/src/main/java/org/geysermc/optionalpack/FileUtils.java new file mode 100644 index 0000000..b67be90 --- /dev/null +++ b/src/main/java/org/geysermc/optionalpack/FileUtils.java @@ -0,0 +1,62 @@ +package org.geysermc.optionalpack; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +public class FileUtils { + /** + * Delete a directory and all files within it + * From: https://www.geeksforgeeks.org/java/java-program-to-delete-a-directory/ + * + * @param directory The directory to remove + */ + public static void deleteDirectory(File directory) { + File[] files = directory.listFiles(); + if (files != null) { + for (File subfile : directory.listFiles()) { + if (subfile.isDirectory()) { + deleteDirectory(subfile); + } + subfile.delete(); + } + } + + directory.delete(); + } + + /** + * @see #deleteDirectory(File) + */ + public static void deleteDirectory(Path directory) { + deleteDirectory(directory.toFile()); + } + + /** + * Zip a folder + * From: https://stackoverflow.com/a/57997601 + * + * @param sourceFolderPath Folder to zip + * @param zipPath Output path for the zip + */ + public static void zipFolder(Path sourceFolderPath, Path zipPath) throws Exception { + ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipPath.toFile())); + Files.walkFileTree(sourceFolderPath, new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + zos.putNextEntry(new ZipEntry(sourceFolderPath.relativize(file).toString())); + Files.copy(file, zos); + zos.closeEntry(); + return FileVisitResult.CONTINUE; + } + }); + zos.close(); + } +} diff --git a/src/main/java/org/geysermc/optionalpack/JavaResources.java b/src/main/java/org/geysermc/optionalpack/JavaResources.java index ae0ca13..e5787d8 100644 --- a/src/main/java/org/geysermc/optionalpack/JavaResources.java +++ b/src/main/java/org/geysermc/optionalpack/JavaResources.java @@ -27,6 +27,7 @@ package org.geysermc.optionalpack; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; @@ -60,12 +61,15 @@ public class JavaResources { String assetFileName = Path.of(jarAssetPath).toFile().getName(); Path destination = OptionalPack.WORKING_PATH.resolve(destinationPath).resolve(assetFileName); - if (destination.toFile().mkdirs()) { - Files.copy(asset, destination, StandardCopyOption.REPLACE_EXISTING); - } - else { - OptionalPack.log("Could not make directories for copying " + jarAssetPath + " to " + destinationPath + "!"); + File destinationFolder = OptionalPack.WORKING_PATH.resolve(destinationPath).toFile(); + if (!destinationFolder.exists()) { + if (!destinationFolder.mkdirs()) { + OptionalPack.log("Could not make directories for copying " + jarAssetPath + " to " + destinationPath + "!"); + continue; + } } + + Files.copy(asset, destination, StandardCopyOption.REPLACE_EXISTING); } } catch (IOException e) { diff --git a/src/main/java/org/geysermc/optionalpack/LauncherMetaWrapper.java b/src/main/java/org/geysermc/optionalpack/LauncherMetaWrapper.java index b22c87d..4ce601a 100644 --- a/src/main/java/org/geysermc/optionalpack/LauncherMetaWrapper.java +++ b/src/main/java/org/geysermc/optionalpack/LauncherMetaWrapper.java @@ -1,7 +1,5 @@ package org.geysermc.optionalpack; -import com.google.gson.Gson; - import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; @@ -16,15 +14,15 @@ public class LauncherMetaWrapper { public static Path getLatest() { OptionalPack.log("Downloading " + Constants.JAVA_TARGET_VERSION + " client.jar from Mojang..."); - VersionManifest versionManifest = Constants.GSON.fromJson(HTTP.getAsString(LAUNCHER_META_URL), VersionManifest.class); + VersionManifest versionManifest = Constants.GSON.fromJson(WebUtils.getAsString(LAUNCHER_META_URL), VersionManifest.class); for (Version version : versionManifest.versions()) { if (version.id().equals(Constants.JAVA_TARGET_VERSION)) { - VersionInfo versionInfo = Constants.GSON.fromJson(HTTP.getAsString(version.url()), VersionInfo.class); + VersionInfo versionInfo = Constants.GSON.fromJson(WebUtils.getAsString(version.url()), VersionInfo.class); VersionDownload client = versionInfo.downloads().get("client"); if (!Files.exists(CLIENT_JAR) || !client.sha1.equals(getSha1(CLIENT_JAR))) { // Download the client jar - try (InputStream in = HTTP.request(client.url())) { + try (InputStream in = WebUtils.request(client.url())) { Files.copy(in, CLIENT_JAR); } catch (Exception e) { throw new RuntimeException("Could not download client jar", e); diff --git a/src/main/java/org/geysermc/optionalpack/OptionalPack.java b/src/main/java/org/geysermc/optionalpack/OptionalPack.java index f510afa..20a5c02 100644 --- a/src/main/java/org/geysermc/optionalpack/OptionalPack.java +++ b/src/main/java/org/geysermc/optionalpack/OptionalPack.java @@ -74,7 +74,7 @@ public class OptionalPack { log("Extracting pre-made optional pack data to folder..."); // there are probably better ways to do this, but this is the way im doing it - unzipPack(Resources.get("optionalpack"), WORKING_PATH); + Resources.extractFolder("optionalpack", WORKING_PATH); // Step 2: Download the 1.21.8 client.jar and copy all files needed to working folder File jarFile = LauncherMetaWrapper.getLatest().toFile(); @@ -96,12 +96,12 @@ public class OptionalPack { // Step 4: Compile pack folder into a mcpack. log("Zipping as GeyserOptionalPack.mcpack..."); - zipFolder(WORKING_PATH, Path.of("GeyserOptionalPack.mcpack")); + FileUtils.zipFolder(WORKING_PATH, Path.of("GeyserOptionalPack.mcpack")); // Step 5: Cleanup temporary folders and files log("Clearing temporary files..."); clientJar.close(); - deleteDirectory(WORKING_PATH.toFile()); + FileUtils.deleteDirectory(WORKING_PATH); // Step 6: Finish!! DecimalFormat r3 = new DecimalFormat("0.000"); @@ -113,106 +113,6 @@ public class OptionalPack { } } - /** - * Delete a directory and all files within it - * From: https://www.geeksforgeeks.org/java/java-program-to-delete-a-directory/ - * - * @param directory The directory to remove - */ - public static void deleteDirectory(File directory) { - File[] files = directory.listFiles(); - if (files != null) { - for (File subfile : directory.listFiles()) { - if (subfile.isDirectory()) { - deleteDirectory(subfile); - } - subfile.delete(); - } - } - - directory.delete(); - } - - /** - * Zip a folder - * From: https://stackoverflow.com/a/57997601 - * - * @param sourceFolderPath Folder to zip - * @param zipPath Output path for the zip - */ - private static void zipFolder(Path sourceFolderPath, Path zipPath) throws Exception { - ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipPath.toFile())); - Files.walkFileTree(sourceFolderPath, new SimpleFileVisitor<>() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - zos.putNextEntry(new ZipEntry(sourceFolderPath.relativize(file).toString())); - Files.copy(file, zos); - zos.closeEntry(); - return FileVisitResult.CONTINUE; - } - }); - zos.close(); - } - - /** - * Extract a zip to a given directory - * - * @param file The zip to extract - * @param destDir THe destination to put all the files - */ - private static void unzipPack(URL file, Path destDir) { - File dir = destDir.toFile(); - // create output directory if it doesn't exist - if (!dir.exists()) dir.mkdirs(); - - try { - if (file.getProtocol().equals("file")) { - Path resourceDir = Paths.get(file.toURI()); - Files.walk(resourceDir) - .filter(Files::isRegularFile) - .forEach(source -> { - try { - Path relative = resourceDir.relativize(source); - Path target = destDir.resolve(relative); - Files.createDirectories(target.getParent()); - Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - }); - } else { - byte[] buffer = new byte[1024]; - FileInputStream fileStream = new FileInputStream(new File(file.toURI())); - ZipInputStream zipStream = new ZipInputStream(fileStream); - ZipEntry entry = zipStream.getNextEntry(); - while (entry != null) { - if (!entry.isDirectory()) { - String fileName = entry.getName(); - File newFile = new File(destDir + File.separator + fileName); - // create directories for subdirectories in zip - new File(newFile.getParent()).mkdirs(); - FileOutputStream extractedFile = new FileOutputStream(newFile); - int len; - while ((len = zipStream.read(buffer)) > 0) { - extractedFile.write(buffer, 0, len); - } - extractedFile.close(); - } - // close this ZipEntry - - zipStream.closeEntry(); - entry = zipStream.getNextEntry(); - } - // close the last ZipEntry - zipStream.closeEntry(); - zipStream.close(); - fileStream.close(); - } - } catch (IOException | URISyntaxException e) { - throw new RuntimeException("Unable to unzip pack!", e); - } - } - /** * Prints a message to the console. * diff --git a/src/main/java/org/geysermc/optionalpack/Resources.java b/src/main/java/org/geysermc/optionalpack/Resources.java index f364e4c..d5c99f4 100644 --- a/src/main/java/org/geysermc/optionalpack/Resources.java +++ b/src/main/java/org/geysermc/optionalpack/Resources.java @@ -27,10 +27,21 @@ package org.geysermc.optionalpack; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.UncheckedIOException; +import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; public class Resources { /** @@ -89,4 +100,64 @@ public class Resources { is.close(); return image; } + + /** + * Extract a resource folder to a given directory + * + * @param folder The resource folder to extract + * @param destDir The destination to put all the files + */ + public static void extractFolder(String folder, Path destDir) { + URL file = get(folder); + File dir = destDir.toFile(); + // create output directory if it doesn't exist + if (!dir.exists()) dir.mkdirs(); + + try { + if (file.getProtocol().equals("file")) { + Path resourceDir = Paths.get(file.toURI()); + Files.walk(resourceDir) + .filter(Files::isRegularFile) + .forEach(source -> { + try { + Path relative = resourceDir.relativize(source); + Path target = destDir.resolve(relative); + Files.createDirectories(target.getParent()); + Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + } else { + byte[] buffer = new byte[1024]; + FileInputStream fileStream = new FileInputStream(new File(file.toURI())); + ZipInputStream zipStream = new ZipInputStream(fileStream); + ZipEntry entry = zipStream.getNextEntry(); + while (entry != null) { + if (!entry.isDirectory()) { + String fileName = entry.getName(); + File newFile = new File(destDir + File.separator + fileName); + // create directories for subdirectories in zip + new File(newFile.getParent()).mkdirs(); + FileOutputStream extractedFile = new FileOutputStream(newFile); + int len; + while ((len = zipStream.read(buffer)) > 0) { + extractedFile.write(buffer, 0, len); + } + extractedFile.close(); + } + // close this ZipEntry + + zipStream.closeEntry(); + entry = zipStream.getNextEntry(); + } + // close the last ZipEntry + zipStream.closeEntry(); + zipStream.close(); + fileStream.close(); + } + } catch (IOException | URISyntaxException e) { + throw new RuntimeException("Unable to unzip pack!", e); + } + } } diff --git a/src/main/java/org/geysermc/optionalpack/HTTP.java b/src/main/java/org/geysermc/optionalpack/WebUtils.java similarity index 99% rename from src/main/java/org/geysermc/optionalpack/HTTP.java rename to src/main/java/org/geysermc/optionalpack/WebUtils.java index 62d5138..1d6065e 100644 --- a/src/main/java/org/geysermc/optionalpack/HTTP.java +++ b/src/main/java/org/geysermc/optionalpack/WebUtils.java @@ -30,7 +30,7 @@ import java.io.InputStream; import java.net.*; import java.nio.charset.StandardCharsets; -public class HTTP { +public class WebUtils { /** * Requests a URL and returns the InputStream. diff --git a/src/main/java/org/geysermc/optionalpack/renderers/JsonPatchRenderer.java b/src/main/java/org/geysermc/optionalpack/renderers/JsonPatchRenderer.java index e6b65c7..fa47e66 100644 --- a/src/main/java/org/geysermc/optionalpack/renderers/JsonPatchRenderer.java +++ b/src/main/java/org/geysermc/optionalpack/renderers/JsonPatchRenderer.java @@ -5,39 +5,57 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import org.geysermc.optionalpack.BedrockResourcesWrapper; import org.geysermc.optionalpack.Constants; +import org.geysermc.optionalpack.FileUtils; +import org.geysermc.optionalpack.OptionalPack; +import org.geysermc.optionalpack.Resources; import java.io.FileWriter; import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; public class JsonPatchRenderer implements Renderer { - private final String name; - private final String file; - private final String patch; - - public JsonPatchRenderer(String name, String file, String patch) { - this.name = name; - this.file = file; - this.patch = patch; - } + private static final Path PATCHES_PATH = OptionalPack.TEMP_PATH.resolve("patches"); @Override public String getName() { - return name; + return "Json Patcher"; } @Override public String getDestination() { - return file; + return ""; } @Override public void render() throws IOException { - JsonObject sourceJson = JsonParser.parseString(BedrockResourcesWrapper.getResourceAsString(getDestination())).getAsJsonObject(); - JsonObject patchJson = JsonParser.parseString(patch).getAsJsonObject(); + log("Extracting JSON patches..."); + Resources.extractFolder("patches", PATCHES_PATH); + + log("Patching JSON files..."); + try (var stream = Files.walk(PATCHES_PATH)) { + for (var path : stream.filter(Files::isRegularFile).toList()) { + String patchFile = PATCHES_PATH.relativize(path).toString().replace("\\", "/"); + + log("Applying patch: " + patchFile); + patchJsonFile(patchFile); + } + } + + // Clean up patches folder + FileUtils.deleteDirectory(PATCHES_PATH); + } + + private void patchJsonFile(String patchFile) throws IOException { + String realPath = patchFile.replace(".patch.json", ".json"); + + JsonObject sourceJson = JsonParser.parseString(BedrockResourcesWrapper.getResourceAsString(realPath)).getAsJsonObject(); + JsonObject patchJson = JsonParser.parseString(Files.readString(PATCHES_PATH.resolve(patchFile), StandardCharsets.UTF_8)).getAsJsonObject(); JsonObject merged = mergeJsonObjects(sourceJson, patchJson); - try (FileWriter writer = new FileWriter(getDestinationPath().toFile())) { + try (FileWriter writer = new FileWriter(OptionalPack.WORKING_PATH.resolve(realPath).toFile())) { writer.write(Constants.GSON.toJson(merged)); } } diff --git a/src/main/java/org/geysermc/optionalpack/renderers/Renderer.java b/src/main/java/org/geysermc/optionalpack/renderers/Renderer.java index 6191c7a..c430fd4 100644 --- a/src/main/java/org/geysermc/optionalpack/renderers/Renderer.java +++ b/src/main/java/org/geysermc/optionalpack/renderers/Renderer.java @@ -55,9 +55,6 @@ public interface Renderer { */ default Path getDestinationPath() { String destination = getDestination(); - if (destination.isEmpty()) { - return null; - } return OptionalPack.WORKING_PATH.resolve(destination); } @@ -67,4 +64,8 @@ public interface Renderer { * @throws IOException If an error occurs during rendering. */ void render() throws IOException; + + default void log(String message) { + OptionalPack.log(message); + } } diff --git a/src/main/java/org/geysermc/optionalpack/renderers/entities/ArrowEntityRenderer.java b/src/main/java/org/geysermc/optionalpack/renderers/entities/ArrowEntityRenderer.java deleted file mode 100644 index 1adf4c5..0000000 --- a/src/main/java/org/geysermc/optionalpack/renderers/entities/ArrowEntityRenderer.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.geysermc.optionalpack.renderers.entities; - -import org.geysermc.optionalpack.renderers.JsonPatchRenderer; - -public class ArrowEntityRenderer extends JsonPatchRenderer { - public ArrowEntityRenderer() { - super("Arrow Entity", "entity/arrow.entity.json", "{\"minecraft:client_entity\": {\"description\": {\"textures\": {\"spectral\": \"textures/geyser/entity/arrow/spectral_arrow\"}}}}"); - } -} diff --git a/src/main/java/org/geysermc/optionalpack/renderers/entities/EvocationIllagerEntityRenderer.java b/src/main/java/org/geysermc/optionalpack/renderers/entities/EvocationIllagerEntityRenderer.java deleted file mode 100644 index 4b0a529..0000000 --- a/src/main/java/org/geysermc/optionalpack/renderers/entities/EvocationIllagerEntityRenderer.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.geysermc.optionalpack.renderers.entities; - -import org.geysermc.optionalpack.renderers.JsonPatchRenderer; - -public class EvocationIllagerEntityRenderer extends JsonPatchRenderer { - public EvocationIllagerEntityRenderer() { - super("Evocation Illager Entity", "entity/evocation_illager.entity.json", "{\"minecraft:client_entity\": {\"description\": {\"textures\": {\"illusioner\": \"textures/geyser/entity/illager/illusioner\"}}}}"); - } -} diff --git a/src/main/java/org/geysermc/optionalpack/renderers/entities/RabbitEntityRenderer.java b/src/main/java/org/geysermc/optionalpack/renderers/entities/RabbitEntityRenderer.java deleted file mode 100644 index c41ccd8..0000000 --- a/src/main/java/org/geysermc/optionalpack/renderers/entities/RabbitEntityRenderer.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.geysermc.optionalpack.renderers.entities; - -import org.geysermc.optionalpack.renderers.JsonPatchRenderer; - -public class RabbitEntityRenderer extends JsonPatchRenderer { - public RabbitEntityRenderer() { - super("Rabbit Entity", "entity/rabbit.entity.json", "{\"minecraft:client_entity\": {\"description\": {\"textures\": {\"caerbannog\": \"textures/geyser/entity/rabbit/caerbannog\"}}}}"); - } -} diff --git a/src/main/java/org/geysermc/optionalpack/renderers/particles/BasicBubbleParticleRenderer.java b/src/main/java/org/geysermc/optionalpack/renderers/particles/BasicBubbleParticleRenderer.java deleted file mode 100644 index dbd51bc..0000000 --- a/src/main/java/org/geysermc/optionalpack/renderers/particles/BasicBubbleParticleRenderer.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.geysermc.optionalpack.renderers.particles; - -import org.geysermc.optionalpack.renderers.JsonPatchRenderer; - -public class BasicBubbleParticleRenderer extends JsonPatchRenderer { - public BasicBubbleParticleRenderer() { - super("Basic Bubble Particle", "particles/basic_bubble_manual.json", "{\"particle_effect\": {\"components\": {\"minecraft:particle_expire_if_not_in_blocks\": []}}}"); - } -} diff --git a/src/main/java/org/geysermc/optionalpack/renderers/particles/TrialSpawnerDetectionParticleRenderer.java b/src/main/java/org/geysermc/optionalpack/renderers/particles/TrialSpawnerDetectionParticleRenderer.java deleted file mode 100644 index 70452db..0000000 --- a/src/main/java/org/geysermc/optionalpack/renderers/particles/TrialSpawnerDetectionParticleRenderer.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.geysermc.optionalpack.renderers.particles; - -import org.geysermc.optionalpack.renderers.JsonPatchRenderer; - -public class TrialSpawnerDetectionParticleRenderer extends JsonPatchRenderer { - public TrialSpawnerDetectionParticleRenderer() { - super("Trial spawner detection Particle", "particles/trial_spawner_detection.particle.json", "{\"particle_effect\": {\"components\": {\"minecraft:emitter_rate_instant\": {\"num_particles\": \"1\"}, \"minecraft:emitter_shape_box\": {\"offset\": [0, 0, 0]}}}}"); - } -} diff --git a/src/main/resources/optionalpack/render_controllers/arrow.render_controllers.json b/src/main/resources/optionalpack/render_controllers/arrow.render_controllers.json deleted file mode 100644 index a8c2e44..0000000 --- a/src/main/resources/optionalpack/render_controllers/arrow.render_controllers.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "format_version": "1.10.0", - "render_controllers": { - "controller.render.arrow": { - "geometry": "geometry.default", - "materials": [ { "*": "Material.default" } ], - "textures": [ - "q.is_bribed ? texture.spectral : texture.default" - ], - "filter_lighting": true - } - } -} diff --git a/src/main/resources/patches/entity/arrow.entity.patch.json b/src/main/resources/patches/entity/arrow.entity.patch.json new file mode 100644 index 0000000..ae1398d --- /dev/null +++ b/src/main/resources/patches/entity/arrow.entity.patch.json @@ -0,0 +1,9 @@ +{ + "minecraft:client_entity": { + "description": { + "textures": { + "spectral": "textures/geyser/entity/arrow/spectral_arrow" + } + } + } +} diff --git a/src/main/resources/patches/entity/evocation_illager.entity.patch.json b/src/main/resources/patches/entity/evocation_illager.entity.patch.json new file mode 100644 index 0000000..00ff613 --- /dev/null +++ b/src/main/resources/patches/entity/evocation_illager.entity.patch.json @@ -0,0 +1 @@ +{"minecraft:client_entity": {"description": {"textures": {"illusioner": "textures/geyser/entity/illager/illusioner"}}}} \ No newline at end of file diff --git a/src/main/resources/patches/entity/rabbit.entity.patch.json b/src/main/resources/patches/entity/rabbit.entity.patch.json new file mode 100644 index 0000000..c71542e --- /dev/null +++ b/src/main/resources/patches/entity/rabbit.entity.patch.json @@ -0,0 +1 @@ +{"minecraft:client_entity": {"description": {"textures": {"caerbannog": "textures/geyser/entity/rabbit/caerbannog"}}}} \ No newline at end of file diff --git a/src/main/resources/patches/particles/basic_bubble_manual.patch.json b/src/main/resources/patches/particles/basic_bubble_manual.patch.json new file mode 100644 index 0000000..1f60770 --- /dev/null +++ b/src/main/resources/patches/particles/basic_bubble_manual.patch.json @@ -0,0 +1 @@ +{"particle_effect": {"components": {"minecraft:particle_expire_if_not_in_blocks": []}}} \ No newline at end of file diff --git a/src/main/resources/patches/particles/trial_spawner_detection.particle.patch.json b/src/main/resources/patches/particles/trial_spawner_detection.particle.patch.json new file mode 100644 index 0000000..a25ab87 --- /dev/null +++ b/src/main/resources/patches/particles/trial_spawner_detection.particle.patch.json @@ -0,0 +1 @@ +{"particle_effect": {"components": {"minecraft:emitter_rate_instant": {"num_particles": "1"}, "minecraft:emitter_shape_box": {"offset": [0, 0, 0]}}}} \ No newline at end of file diff --git a/src/main/resources/patches/render_controllers/arrow.render_controllers.patch.json b/src/main/resources/patches/render_controllers/arrow.render_controllers.patch.json new file mode 100644 index 0000000..00c6778 --- /dev/null +++ b/src/main/resources/patches/render_controllers/arrow.render_controllers.patch.json @@ -0,0 +1 @@ +{"render_controllers": {"controller.render.arrow": {"textures": ["q.is_bribed ? texture.spectral : texture.default"]}}} \ No newline at end of file