[
  {
    "path": ".github/workflows/build.yml",
    "content": "name: build\non: [pull_request, push]\n\njobs:\n  build:\n    strategy:\n      matrix:\n        java: [21]\n    runs-on: ubuntu-22.04\n    steps:\n      - name: checkout repository\n        uses: actions/checkout@v4\n      - name: validate gradle wrapper\n        uses: gradle/wrapper-validation-action@v2\n      - name: setup jdk ${{ matrix.java }}\n        uses: actions/setup-java@v4\n        with:\n          java-version: ${{ matrix.java }}\n          distribution: 'temurin'\n      - name: make gradle wrapper executable\n        run: chmod +x ./gradlew\n      - name: build\n        run: ./gradlew build\n      - name: capture build artifacts\n        if: ${{ matrix.java == '21' }}\n        uses: actions/upload-artifact@v4\n        with:\n          name: Artifacts\n          path: build/libs/\n"
  },
  {
    "path": ".gitignore",
    "content": "# gradle\n\n.gradle/\nbuild/\nout/\nclasses/\n\n# eclipse\n\n*.launch\n\n# idea\n\n.idea/\n*.iml\n*.ipr\n*.iws\n\n# vscode\n\n.settings/\n.vscode/\nbin/\n.classpath\n.project\n\n# macos\n\n*.DS_Store\n\n# fabric\n\nrun/\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "                   GNU LESSER GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\n  This version of the GNU Lesser General Public License incorporates\nthe terms and conditions of version 3 of the GNU General Public\nLicense, supplemented by the additional permissions listed below.\n\n  0. Additional Definitions.\n\n  As used herein, \"this License\" refers to version 3 of the GNU Lesser\nGeneral Public License, and the \"GNU GPL\" refers to version 3 of the GNU\nGeneral Public License.\n\n  \"The Library\" refers to a covered work governed by this License,\nother than an Application or a Combined Work as defined below.\n\n  An \"Application\" is any work that makes use of an interface provided\nby the Library, but which is not otherwise based on the Library.\nDefining a subclass of a class defined by the Library is deemed a mode\nof using an interface provided by the Library.\n\n  A \"Combined Work\" is a work produced by combining or linking an\nApplication with the Library.  The particular version of the Library\nwith which the Combined Work was made is also called the \"Linked\nVersion\".\n\n  The \"Minimal Corresponding Source\" for a Combined Work means the\nCorresponding Source for the Combined Work, excluding any source code\nfor portions of the Combined Work that, considered in isolation, are\nbased on the Application, and not on the Linked Version.\n\n  The \"Corresponding Application Code\" for a Combined Work means the\nobject code and/or source code for the Application, including any data\nand utility programs needed for reproducing the Combined Work from the\nApplication, but excluding the System Libraries of the Combined Work.\n\n  1. Exception to Section 3 of the GNU GPL.\n\n  You may convey a covered work under sections 3 and 4 of this License\nwithout being bound by section 3 of the GNU GPL.\n\n  2. Conveying Modified Versions.\n\n  If you modify a copy of the Library, and, in your modifications, a\nfacility refers to a function or data to be supplied by an Application\nthat uses the facility (other than as an argument passed when the\nfacility is invoked), then you may convey a copy of the modified\nversion:\n\n   a) under this License, provided that you make a good faith effort to\n   ensure that, in the event an Application does not supply the\n   function or data, the facility still operates, and performs\n   whatever part of its purpose remains meaningful, or\n\n   b) under the GNU GPL, with none of the additional permissions of\n   this License applicable to that copy.\n\n  3. Object Code Incorporating Material from Library Header Files.\n\n  The object code form of an Application may incorporate material from\na header file that is part of the Library.  You may convey such object\ncode under terms of your choice, provided that, if the incorporated\nmaterial is not limited to numerical parameters, data structure\nlayouts and accessors, or small macros, inline functions and templates\n(ten or fewer lines in length), you do both of the following:\n\n   a) Give prominent notice with each copy of the object code that the\n   Library is used in it and that the Library and its use are\n   covered by this License.\n\n   b) Accompany the object code with a copy of the GNU GPL and this license\n   document.\n\n  4. Combined Works.\n\n  You may convey a Combined Work under terms of your choice that,\ntaken together, effectively do not restrict modification of the\nportions of the Library contained in the Combined Work and reverse\nengineering for debugging such modifications, if you also do each of\nthe following:\n\n   a) Give prominent notice with each copy of the Combined Work that\n   the Library is used in it and that the Library and its use are\n   covered by this License.\n\n   b) Accompany the Combined Work with a copy of the GNU GPL and this license\n   document.\n\n   c) For a Combined Work that displays copyright notices during\n   execution, include the copyright notice for the Library among\n   these notices, as well as a reference directing the user to the\n   copies of the GNU GPL and this license document.\n\n   d) Do one of the following:\n\n       0) Convey the Minimal Corresponding Source under the terms of this\n       License, and the Corresponding Application Code in a form\n       suitable for, and under terms that permit, the user to\n       recombine or relink the Application with a modified version of\n       the Linked Version to produce a modified Combined Work, in the\n       manner specified by section 6 of the GNU GPL for conveying\n       Corresponding Source.\n\n       1) Use a suitable shared library mechanism for linking with the\n       Library.  A suitable mechanism is one that (a) uses at run time\n       a copy of the Library already present on the user's computer\n       system, and (b) will operate properly with a modified version\n       of the Library that is interface-compatible with the Linked\n       Version.\n\n   e) Provide Installation Information, but only if you would otherwise\n   be required to provide such information under section 6 of the\n   GNU GPL, and only to the extent that such information is\n   necessary to install and execute a modified version of the\n   Combined Work produced by recombining or relinking the\n   Application with a modified version of the Linked Version. (If\n   you use option 4d0, the Installation Information must accompany\n   the Minimal Corresponding Source and Corresponding Application\n   Code. If you use option 4d1, you must provide the Installation\n   Information in the manner specified by section 6 of the GNU GPL\n   for conveying Corresponding Source.)\n\n  5. Combined Libraries.\n\n  You may place library facilities that are a work based on the\nLibrary side by side in a single library together with other library\nfacilities that are not Applications and are not covered by this\nLicense, and convey such a combined library under terms of your\nchoice, if you do both of the following:\n\n   a) Accompany the combined library with a copy of the same work based\n   on the Library, uncombined with any other library facilities,\n   conveyed under the terms of this License.\n\n   b) Give prominent notice with the combined library that part of it\n   is a work based on the Library, and explaining where to find the\n   accompanying uncombined form of the same work.\n\n  6. Revised Versions of the GNU Lesser General Public License.\n\n  The Free Software Foundation may publish revised and/or new versions\nof the GNU Lesser General Public License from time to time. Such new\nversions will be similar in spirit to the present version, but may\ndiffer in detail to address new problems or concerns.\n\n  Each version is given a distinguishing version number. If the\nLibrary as you received it specifies that a certain numbered version\nof the GNU Lesser General Public License \"or any later version\"\napplies to it, you have the option of following the terms and\nconditions either of that published version or of any later version\npublished by the Free Software Foundation. If the Library as you\nreceived it does not specify a version number of the GNU Lesser\nGeneral Public License, you may choose any version of the GNU Lesser\nGeneral Public License ever published by the Free Software Foundation.\n\n  If the Library as you received it specifies that a proxy can decide\nwhether future versions of the GNU Lesser General Public License shall\napply, that proxy's public statement of acceptance of any version is\npermanent authorization for you to choose that version for the\nLibrary.\n\nCopyright 2021 FoundationGames, LGPLv3"
  },
  {
    "path": "README.md",
    "content": "## Enhanced Block Entities\n\nEBE is a **100% client side** Minecraft mod for the **[Fabric](https://fabricmc.net/use/)** mod loader which aims to increase the performance of block entity rendering, as well as offer customizability via resource packs. <br/><br/>\n**How does it work?** EBE Makes some block entities use baked block models rather than laggy entity models. <br/><br/>\n**Is it just an optimization mod?** EBE isn't *just* an optimization mod, some side effects of its optimizations are many visual improvements. <br/>\nThese may include:\n- Smooth lighting on block entities\n- Being able to remodel block entities with block models\n- Toggling features like christmas chests\n- Being able to see block entities from as far away as possible\n<br/><br/>\n\n**What about animations?** The best part about EBE is that you still get to keep animations, while gaining the performance boost of baked models! Most animated block entity models will only render when absolutely necessary. <br/><br/>\n**Can I use it with Sodium?** Yes.<br/><br/> \n- EBE 0.10.2 and above are **fully compatible with Sodium 0.6+**\n- Earlier EBE versions require installing [Indium](https://modrinth.com/mod/indium) along with Sodium 0.5.11 or below.\n\n## Downloading the mod\n\nFor stable releases, you can check out the [CurseForge](https://www.curseforge.com/minecraft/mc-mods/enhanced-block-entities) or [Modrinth](https://modrinth.com/mod/OVuFYfre) page. If you want the newest bleeding edge build, you can use GitHub Actions (or alternatively, you can build yourself). This mod requires [Fabric API](https://modrinth.com/mod/fabric-api) <br/><br/>\n\n## FAQ and Help\n\n**Q: I need help with the mod/need to report a bug!** <br/>\n**A:** If you're having trouble setting up the mod or using it alongside other mods, I'd recommend you join our [Discord Server](https://discord.gg/7Aw3y4RtY9) and ask for help there. *If the issue is a BUG* please report it on our issue tracker (\"Issues\" tab at the top of the page)<br/><br/>\n\n**Q: Does this mod glitch the chest animation or turn chests invisible?**\n**A:** This bug has been completely eradicated in EBE versions 0.5 and above. If the issue still persists (it shouldn't), leave an issue on GitHub or join the [Discord Server](https://discord.gg/7Aw3y4RtY9). The chest lid may flash when using with Sodium. <br/><br/>\n\n**Q: My chests are still invisible!** <br/>\n**A:** You're likely using a Sodium version lower than 0.4, which doesn't support certain Fabric Rendering features by default. If you need to use a Sodium version lower than 0.4 with EBE, you should install [Indium](https://modrinth.com/mod/indium). <br/><br/>\n<br/><br/>\n\n## FPS Boost\nRendering 1700 chests:\n### Vanilla\n![Before](https://github.com/FoundationGames/EnhancedBlockEntities/raw/116_indev/img/before.png)\n### With EBE\n![After](https://github.com/FoundationGames/EnhancedBlockEntities/raw/116_indev/img/after.png) <br/>\nA 155% frame rate increase!\n\n## Is your mod incompatible with EBE?\nIf you are the developer of a mod that makes changes to block entity rendering, your mod will be broken by EBE. Fortunately, EBE provides an API that allows you to force-disable its features, allowing your mod to function instead.\n<br/>\n**You don't need to add EBE as a dependency in your development environment either!**\n\n### Add the Entrypoint\n`fabric.mod.json`:\n```json\n{\n    \"entrypoints\": {\n        \"main\": [...],\n        \"client\": [...],\n        \"ebe_v1\": [\n            \"my.mod.compat.EBECompatibility\"\n        ]\n    }\n}\n```\n\n### Need to modify config values? Implement `BiConsumer<Properties, Map<String, Text>>`\n`my.mod.compat.EBECompatibility`:\n```java\npublic class EBECompatibility implements BiConsumer<Properties, Map<String, Text>>, ... {\n    @Override\n    public void accept(Properties overrideConfigValues, Map<String, Text> overrideReasons) {\n        overrideConfigValues.setProperty(\"render_enhanced_chests\", \"false\");\n\n        overrideReasons.put(\"render_enhanced_chests\",\n                Text.literal(\"EBE Enhanced Chests are not compatible with my mod!\")\n                        .formatted(Formatting.YELLOW));\n    }\n    \n    ...\n}\n```\nThe `accept(Properties, Map<String, Text>)` function is called when EBE loads config values. You can override a desired config value by setting the corresponding property of `overrideConfigValues`. This will also gray out the option in the config menu.\n<br/>\nTo explain to users why your mod made that change, you can add a text component to the `overrideReasons` map corresponding to the key of the option you changed.\n<br/>\n`Text` is `net.minecraft.text.Text` when using Yarn mappings.\n\n### Need to manually reload EBE? Implement `Consumer<Runnable>`\n`my.mod.compat.EBECompatibility`:\n```java\npublic class EBECompatibility implements Consumer<Runnable>, ... {\n    private static Runnable ebeReloader = () -> {};\n    \n    ...\n\n    @Override\n    public void accept(Runnable ebeConfigReloader) {\n        ebeReloader = ebeConfigReloader;\n    }\n}\n```\nIf your mod needs to modify EBE's config values depending on loaded resources, it may encounter load order problems. This can be somewhat fixed by manually reloading EBE.\n<br/>\nThe `accept(Runnable)` function is called when EBE is first loaded. The `Runnable` executes `EnhancedBlockEntities.load()`. Store this in a field so you can execute it whenever necessary.\n```java\nvoid onMyModResourceReload() {\n    EBECompatibility.someParameter = true;\n    EBECompatibility.ebeReloader.run();\n    // Your config modification handler in EBECompatibility can change \n    // its behavior based on EBECompatibility.someParameter.\n}\n```"
  },
  {
    "path": "build.gradle",
    "content": "plugins {\n\tid 'fabric-loom' version '1.8-SNAPSHOT'\n\tid 'maven-publish'\n}\n\nsourceCompatibility = JavaVersion.VERSION_21\ntargetCompatibility = JavaVersion.VERSION_21\n\narchivesBaseName = project.archives_base_name\nversion = project.mod_version\ngroup = project.maven_group\n\nrepositories {\n\tmaven { url = 'https://maven.terraformersmc.com/' }\n\tmaven { url = 'https://api.modrinth.com/maven/' }\n}\n\ndependencies {\n\t// To change the versions see the gradle.properties file\n\tminecraft \"com.mojang:minecraft:${project.minecraft_version}\"\n\tmappings \"net.fabricmc:yarn:${project.yarn_mappings}:v2\"\n\tmodImplementation \"net.fabricmc:fabric-loader:${project.loader_version}\"\n\n\t// Fabric API. This is technically optional, but you probably want it anyway.\n\tmodImplementation \"net.fabricmc.fabric-api:fabric-api:${project.fabric_version}\"\n\n\t// Mod Menu because config screen access from another place\n\tmodApi \"com.terraformersmc:modmenu:${project.modmenu_version}\"\n\n\t// Sodium for compatibility\n\tmodCompileOnlyApi \"maven.modrinth:sodium:${project.sodium_version}\"\n}\n\nprocessResources {\n\tinputs.property \"version\", project.version\n\n\tfilesMatching(\"fabric.mod.json\") {\n\t\texpand \"version\": project.version\n\t}\n}\n\ntasks.withType(JavaCompile).configureEach {\n\t// ensure that the encoding is set to UTF-8, no matter what the system default is\n\t// this fixes some edge cases with special characters not displaying correctly\n\t// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html\n\t// If Javadoc is generated, this must be specified in that task too.\n\tit.options.encoding = \"UTF-8\"\n}\n\njava {\n\t// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the \"build\" task\n\t// if it is present.\n\t// If you remove this line, sources will not be generated.\n\twithSourcesJar()\n}\n\njar {\n\tfrom(\"LICENSE\") {\n\t\trename { \"${it}_${project.archivesBaseName}\"}\n\t}\n}\n\nloom {\n\taccessWidenerPath = file(\"src/main/resources/enhancedblockentities.accesswidener\")\n}\n\n// configure the maven publication\npublishing {\n\tpublications {\n\t\tmavenJava(MavenPublication) {\n\t\t\tfrom components.java\n\t\t}\n\t}\n\n\t// Select the repositories you want to publish to\n\t// To publish to maven local, no extra repositories are necessary. Just use the task `publishToMavenLocal`.\n\trepositories {\n\t\t// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.\n\t}\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.10-bin.zip\nnetworkTimeout=10000\nvalidateDistributionUrl=true\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradle.properties",
    "content": "org.gradle.jvmargs=-Xmx2G\n\nminecraft_version=1.21.4\nyarn_mappings=1.21.4+build.8\nloader_version=0.16.10\n\nfabric_version=0.114.3+1.21.4\n\nmod_version = 0.11.4+1.21.4\nmaven_group = foundationgames\narchives_base_name = enhancedblockentities\n\nmodmenu_version=13.0.0\nsodium_version=mc1.21.4-0.6.6-fabric\n"
  },
  {
    "path": "gradlew",
    "content": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n#\n#   Gradle start up script for POSIX generated by Gradle.\n#\n#   Important for running:\n#\n#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is\n#       noncompliant, but you have some other compliant shell such as ksh or\n#       bash, then to run this script, type that shell name before the whole\n#       command line, like:\n#\n#           ksh Gradle\n#\n#       Busybox and similar reduced shells will NOT work, because this script\n#       requires all of these POSIX shell features:\n#         * functions;\n#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,\n#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;\n#         * compound commands having a testable exit status, especially «case»;\n#         * various built-in commands including «command», «set», and «ulimit».\n#\n#   Important for patching:\n#\n#   (2) This script targets any POSIX shell, so it avoids extensions provided\n#       by Bash, Ksh, etc; in particular arrays are avoided.\n#\n#       The \"traditional\" practice of packing multiple parameters into a\n#       space-separated string is a well documented source of bugs and security\n#       problems, so this is (mostly) avoided, by progressively accumulating\n#       options in \"$@\", and eventually passing that to Java.\n#\n#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,\n#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;\n#       see the in-line comments for details.\n#\n#       There are tweaks for specific operating systems such as AIX, CygWin,\n#       Darwin, MinGW, and NonStop.\n#\n#   (3) This script is generated from the Groovy template\n#       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt\n#       within the Gradle project.\n#\n#       You can find Gradle at https://github.com/gradle/gradle/.\n#\n##############################################################################\n\n# Attempt to set APP_HOME\n\n# Resolve links: $0 may be a link\napp_path=$0\n\n# Need this for daisy-chained symlinks.\nwhile\n    APP_HOME=${app_path%\"${app_path##*/}\"}  # leaves a trailing /; empty if no leading path\n    [ -h \"$app_path\" ]\ndo\n    ls=$( ls -ld \"$app_path\" )\n    link=${ls#*' -> '}\n    case $link in             #(\n      /*)   app_path=$link ;; #(\n      *)    app_path=$APP_HOME$link ;;\n    esac\ndone\n\n# This is normally unused\n# shellcheck disable=SC2034\nAPP_BASE_NAME=${0##*/}\n# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)\nAPP_HOME=$( cd \"${APP_HOME:-./}\" > /dev/null && pwd -P ) || exit\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=maximum\n\nwarn () {\n    echo \"$*\"\n} >&2\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n} >&2\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"$( uname )\" in                #(\n  CYGWIN* )         cygwin=true  ;; #(\n  Darwin* )         darwin=true  ;; #(\n  MSYS* | MINGW* )  msys=true    ;; #(\n  NONSTOP* )        nonstop=true ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=$JAVA_HOME/jre/sh/java\n    else\n        JAVACMD=$JAVA_HOME/bin/java\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=java\n    if ! command -v java >/dev/null 2>&1\n    then\n        die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nfi\n\n# Increase the maximum file descriptors if we can.\nif ! \"$cygwin\" && ! \"$darwin\" && ! \"$nonstop\" ; then\n    case $MAX_FD in #(\n      max*)\n        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        MAX_FD=$( ulimit -H -n ) ||\n            warn \"Could not query maximum file descriptor limit\"\n    esac\n    case $MAX_FD in  #(\n      '' | soft) :;; #(\n      *)\n        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        ulimit -n \"$MAX_FD\" ||\n            warn \"Could not set maximum file descriptor limit to $MAX_FD\"\n    esac\nfi\n\n# Collect all arguments for the java command, stacking in reverse order:\n#   * args from the command line\n#   * the main class name\n#   * -classpath\n#   * -D...appname settings\n#   * --module-path (only if needed)\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif \"$cygwin\" || \"$msys\" ; then\n    APP_HOME=$( cygpath --path --mixed \"$APP_HOME\" )\n    CLASSPATH=$( cygpath --path --mixed \"$CLASSPATH\" )\n\n    JAVACMD=$( cygpath --unix \"$JAVACMD\" )\n\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    for arg do\n        if\n            case $arg in                                #(\n              -*)   false ;;                            # don't mess with options #(\n              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath\n                    [ -e \"$t\" ] ;;                      #(\n              *)    false ;;\n            esac\n        then\n            arg=$( cygpath --path --ignore --mixed \"$arg\" )\n        fi\n        # Roll the args list around exactly as many times as the number of\n        # args, so each arg winds up back in the position where it started, but\n        # possibly modified.\n        #\n        # NB: a `for` loop captures its iteration list before it begins, so\n        # changing the positional parameters here affects neither the number of\n        # iterations, nor the values presented in `arg`.\n        shift                   # remove old arg\n        set -- \"$@\" \"$arg\"      # push replacement arg\n    done\nfi\n\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Collect all arguments for the java command:\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,\n#     and any embedded shellness will be escaped.\n#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be\n#     treated as '${Hostname}' itself on the command line.\n\nset -- \\\n        \"-Dorg.gradle.appname=$APP_BASE_NAME\" \\\n        -classpath \"$CLASSPATH\" \\\n        org.gradle.wrapper.GradleWrapperMain \\\n        \"$@\"\n\n# Stop when \"xargs\" is not available.\nif ! command -v xargs >/dev/null 2>&1\nthen\n    die \"xargs is not available\"\nfi\n\n# Use \"xargs\" to parse quoted args.\n#\n# With -n1 it outputs one arg per line, with the quotes and backslashes removed.\n#\n# In Bash we could simply go:\n#\n#   readarray ARGS < <( xargs -n1 <<<\"$var\" ) &&\n#   set -- \"${ARGS[@]}\" \"$@\"\n#\n# but POSIX shell has neither arrays nor command substitution, so instead we\n# post-process each arg (as a line of input to sed) to backslash-escape any\n# character that might be a shell metacharacter, then use eval to reverse\n# that process (while maintaining the separation between arguments), and wrap\n# the whole thing up as a single \"set\" statement.\n#\n# This will of course break if any of these variables contains a newline or\n# an unmatched quote.\n#\n\neval \"set -- $(\n        printf '%s\\n' \"$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\" |\n        xargs -n1 |\n        sed ' s~[^-[:alnum:]+,./:=@_]~\\\\&~g; ' |\n        tr '\\n' ' '\n    )\" '\"$@\"'\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n\r\n@if \"%DEBUG%\"==\"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\"==\"\" set DIRNAME=.\r\n@rem This is normally unused\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif %ERRORLEVEL% equ 0 goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif %ERRORLEVEL% equ 0 goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nset EXIT_CODE=%ERRORLEVEL%\r\nif %EXIT_CODE% equ 0 set EXIT_CODE=1\r\nif not \"\"==\"%GRADLE_EXIT_CONSOLE%\" exit %EXIT_CODE%\r\nexit /b %EXIT_CODE%\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "settings.gradle",
    "content": "pluginManagement {\n    repositories {\n        maven {\n            name = 'Fabric'\n            url = 'https://maven.fabricmc.net/'\n        }\n        gradlePluginPortal()\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/EBESetup.java",
    "content": "package foundationgames.enhancedblockentities;\n\nimport foundationgames.enhancedblockentities.client.model.DynamicModelEffects;\nimport foundationgames.enhancedblockentities.client.model.DynamicModelProvidingPlugin;\nimport foundationgames.enhancedblockentities.client.model.DynamicUnbakedModel;\nimport foundationgames.enhancedblockentities.client.model.ModelIdentifiers;\nimport foundationgames.enhancedblockentities.client.model.ModelSelector;\nimport foundationgames.enhancedblockentities.client.model.misc.DecoratedPotModelSelector;\nimport foundationgames.enhancedblockentities.client.render.BlockEntityRenderCondition;\nimport foundationgames.enhancedblockentities.client.render.BlockEntityRendererOverride;\nimport foundationgames.enhancedblockentities.client.render.entity.BellBlockEntityRendererOverride;\nimport foundationgames.enhancedblockentities.client.render.entity.ChestBlockEntityRendererOverride;\nimport foundationgames.enhancedblockentities.client.render.entity.DecoratedPotBlockEntityRendererOverride;\nimport foundationgames.enhancedblockentities.client.render.entity.ShulkerBoxBlockEntityRendererOverride;\nimport foundationgames.enhancedblockentities.client.render.entity.SignBlockEntityRendererOverride;\nimport foundationgames.enhancedblockentities.client.resource.EBEPack;\nimport foundationgames.enhancedblockentities.util.DateUtil;\nimport foundationgames.enhancedblockentities.util.EBEUtil;\nimport foundationgames.enhancedblockentities.util.ResourceUtil;\nimport net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;\nimport net.fabricmc.fabric.api.client.model.loading.v1.FabricBakedModelManager;\nimport net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;\nimport net.minecraft.block.Block;\nimport net.minecraft.block.Blocks;\nimport net.minecraft.block.ShulkerBoxBlock;\nimport net.minecraft.block.entity.BlockEntity;\nimport net.minecraft.block.entity.BlockEntityType;\nimport net.minecraft.block.enums.ChestType;\nimport net.minecraft.client.MinecraftClient;\nimport net.minecraft.client.render.RenderLayer;\nimport net.minecraft.client.render.model.BakedModel;\nimport net.minecraft.registry.Registries;\nimport net.minecraft.state.property.Properties;\nimport net.minecraft.util.DyeColor;\nimport net.minecraft.util.Identifier;\n\nimport java.util.function.Function;\n\npublic enum EBESetup {;\n    public static void setupRRPChests() {\n        EBEPack p = ResourceUtil.getPackForCompat();\n\n        ResourceUtil.addChestBlockStates(\"chest\", p);\n        ResourceUtil.addChestBlockStates(\"trapped_chest\", p);\n        ResourceUtil.addChestBlockStates(\"christmas_chest\", p);\n        ResourceUtil.addSingleChestOnlyBlockStates(\"ender_chest\", p);\n\n        p = ResourceUtil.getBasePack();\n\n        ResourceUtil.addSingleChestModels(\"normal\", \"chest\", p);\n        ResourceUtil.addDoubleChestModels(\"normal_left\", \"normal_right\",\"chest\", p);\n        ResourceUtil.addSingleChestModels(\"trapped\", \"trapped_chest\", p);\n        ResourceUtil.addDoubleChestModels(\"trapped_left\", \"trapped_right\",\"trapped_chest\", p);\n        ResourceUtil.addSingleChestModels(\"christmas\", \"christmas_chest\", p);\n        ResourceUtil.addDoubleChestModels(\"christmas_left\", \"christmas_right\",\"christmas_chest\", p);\n        ResourceUtil.addSingleChestModels(\"ender\", \"ender_chest\", p);\n\n        ResourceUtil.addChestItemDefinition(\"chest\", \"chest_center\", true, p);\n        ResourceUtil.addChestItemDefinition(\"trapped_chest\", \"trapped_chest_center\", true, p);\n        ResourceUtil.addChestItemDefinition(\"ender_chest\", \"ender_chest_center\", false, p);\n\n        p.addDirBlockSprites(\"entity/chest\", \"entity/chest/\");\n    }\n\n    public static void setupRRPSigns() {\n        EBEPack p = ResourceUtil.getPackForCompat();\n\n        ResourceUtil.addSignBlockStates(\"oak_sign\", \"oak_wall_sign\", p);\n        ResourceUtil.addSignBlockStates(\"birch_sign\", \"birch_wall_sign\", p);\n        ResourceUtil.addSignBlockStates(\"spruce_sign\", \"spruce_wall_sign\", p);\n        ResourceUtil.addSignBlockStates(\"jungle_sign\", \"jungle_wall_sign\", p);\n        ResourceUtil.addSignBlockStates(\"acacia_sign\", \"acacia_wall_sign\", p);\n        ResourceUtil.addSignBlockStates(\"dark_oak_sign\", \"dark_oak_wall_sign\", p);\n        ResourceUtil.addSignBlockStates(\"mangrove_sign\", \"mangrove_wall_sign\", p);\n        ResourceUtil.addSignBlockStates(\"cherry_sign\", \"cherry_wall_sign\", p);\n        ResourceUtil.addSignBlockStates(\"crimson_sign\", \"crimson_wall_sign\", p);\n        ResourceUtil.addSignBlockStates(\"warped_sign\", \"warped_wall_sign\", p);\n        ResourceUtil.addSignBlockStates(\"bamboo_sign\", \"bamboo_wall_sign\", p);\n        ResourceUtil.addSignBlockStates(\"pale_oak_sign\", \"pale_oak_wall_sign\", p);\n\n        ResourceUtil.addHangingSignBlockStates(\"oak_hanging_sign\", \"oak_wall_hanging_sign\", p);\n        ResourceUtil.addHangingSignBlockStates(\"birch_hanging_sign\", \"birch_wall_hanging_sign\", p);\n        ResourceUtil.addHangingSignBlockStates(\"spruce_hanging_sign\", \"spruce_wall_hanging_sign\", p);\n        ResourceUtil.addHangingSignBlockStates(\"jungle_hanging_sign\", \"jungle_wall_hanging_sign\", p);\n        ResourceUtil.addHangingSignBlockStates(\"acacia_hanging_sign\", \"acacia_wall_hanging_sign\", p);\n        ResourceUtil.addHangingSignBlockStates(\"dark_oak_hanging_sign\", \"dark_oak_wall_hanging_sign\", p);\n        ResourceUtil.addHangingSignBlockStates(\"mangrove_hanging_sign\", \"mangrove_wall_hanging_sign\", p);\n        ResourceUtil.addHangingSignBlockStates(\"cherry_hanging_sign\", \"cherry_wall_hanging_sign\", p);\n        ResourceUtil.addHangingSignBlockStates(\"crimson_hanging_sign\", \"crimson_wall_hanging_sign\", p);\n        ResourceUtil.addHangingSignBlockStates(\"warped_hanging_sign\", \"warped_wall_hanging_sign\", p);\n        ResourceUtil.addHangingSignBlockStates(\"bamboo_hanging_sign\", \"bamboo_wall_hanging_sign\", p);\n        ResourceUtil.addHangingSignBlockStates(\"pale_oak_hanging_sign\", \"pale_oak_wall_hanging_sign\", p);\n\n        p = ResourceUtil.getBasePack();\n\n        ResourceUtil.addSignTypeModels(\"oak\", p);\n        ResourceUtil.addSignTypeModels(\"birch\", p);\n        ResourceUtil.addSignTypeModels(\"spruce\", p);\n        ResourceUtil.addSignTypeModels(\"jungle\", p);\n        ResourceUtil.addSignTypeModels(\"acacia\", p);\n        ResourceUtil.addSignTypeModels(\"dark_oak\", p);\n        ResourceUtil.addSignTypeModels(\"mangrove\", p);\n        ResourceUtil.addSignTypeModels(\"cherry\", p);\n        ResourceUtil.addSignTypeModels(\"crimson\", p);\n        ResourceUtil.addSignTypeModels(\"warped\", p);\n        ResourceUtil.addSignTypeModels(\"bamboo\", p);\n        ResourceUtil.addSignTypeModels(\"pale_oak\", p);\n\n        p.addDirBlockSprites(\"entity/signs\", \"entity/signs/\");\n        p.addDirBlockSprites(\"entity/signs/hanging\", \"entity/signs/hanging/\");\n        p.addDirBlockSprites(\"gui/hanging_signs\", \"block/particle_hanging_sign_\");\n    }\n\n    public static void setupRRPBells() {\n        ResourceUtil.addBellBlockState(ResourceUtil.getPackForCompat());\n\n        ResourceUtil.getBasePack().addSingleBlockSprite(Identifier.of(\"entity/bell/bell_body\"));\n    }\n\n    public static void setupRRPBeds() {\n        EBEPack p = ResourceUtil.getBasePack();\n        EBEPack pCompat = ResourceUtil.getPackForCompat();\n\n        for (DyeColor color : DyeColor.values()) {\n            ResourceUtil.addBedBlockState(color, pCompat);\n            ResourceUtil.addBedModels(color, p);\n        }\n\n        p.addDirBlockSprites(\"entity/bed\", \"entity/bed/\");\n    }\n\n    public static void setupRRPShulkerBoxes() {\n        EBEPack p = ResourceUtil.getBasePack();\n        EBEPack pCompat = ResourceUtil.getPackForCompat();\n\n        for (DyeColor color : EBEUtil.DEFAULTED_DYE_COLORS) {\n            var id = color != null ? color.getName()+\"_shulker_box\" : \"shulker_box\";\n            ResourceUtil.addShulkerBoxBlockStates(color, pCompat);\n            ResourceUtil.addShulkerBoxModels(color, p);\n            ResourceUtil.addParentModel(\"block/\"+id, Identifier.of(\"item/\"+id), p);\n        }\n\n        p.addDirBlockSprites(\"entity/shulker\", \"entity/shulker/\");\n    }\n\n    public static void setupRRPDecoratedPots() {\n        EBEPack p = ResourceUtil.getBasePack();\n        EBEPack pCompat = ResourceUtil.getPackForCompat();\n\n        ResourceUtil.addDecoratedPotBlockState(pCompat);\n        for (var patternKey : Registries.DECORATED_POT_PATTERN.getKeys()) {\n            ResourceUtil.addDecoratedPotPatternModels(patternKey, p);\n        }\n\n        p.addDirBlockSprites(\"entity/decorated_pot\", \"entity/decorated_pot/\");\n    }\n\n    public static void setupResourceProviders() {\n        ModelLoadingPlugin.register(new DynamicModelProvidingPlugin(\n                Identifier.of(\"builtin\", \"chest_center\"),\n                () -> new DynamicUnbakedModel(\n                        new Identifier[] {\n                                ModelIdentifiers.CHEST_CENTER,\n                                ModelIdentifiers.CHEST_CENTER_TRUNK,\n                                ModelIdentifiers.CHRISTMAS_CHEST_CENTER,\n                                ModelIdentifiers.CHRISTMAS_CHEST_CENTER_TRUNK\n                        },\n                        ModelSelector.CHEST_WITH_CHRISTMAS,\n                        DynamicModelEffects.CHEST\n                )\n        ));\n        ModelLoadingPlugin.register(new DynamicModelProvidingPlugin(\n                Identifier.of(\"builtin\", \"chest_left\"),\n                () -> new DynamicUnbakedModel(\n                        new Identifier[] {\n                                ModelIdentifiers.CHEST_LEFT,\n                                ModelIdentifiers.CHEST_LEFT_TRUNK,\n                                ModelIdentifiers.CHRISTMAS_CHEST_LEFT,\n                                ModelIdentifiers.CHRISTMAS_CHEST_LEFT_TRUNK\n                        },\n                        ModelSelector.CHEST_WITH_CHRISTMAS,\n                        DynamicModelEffects.CHEST\n                )\n        ));\n\n        ModelLoadingPlugin.register(new DynamicModelProvidingPlugin(\n                Identifier.of(\"builtin\", \"chest_right\"),\n                () -> new DynamicUnbakedModel(\n                        new Identifier[] {\n                                ModelIdentifiers.CHEST_RIGHT,\n                                ModelIdentifiers.CHEST_RIGHT_TRUNK,\n                                ModelIdentifiers.CHRISTMAS_CHEST_RIGHT,\n                                ModelIdentifiers.CHRISTMAS_CHEST_RIGHT_TRUNK\n                        },\n                        ModelSelector.CHEST_WITH_CHRISTMAS,\n                        DynamicModelEffects.CHEST\n                )\n        ));\n        ModelLoadingPlugin.register(new DynamicModelProvidingPlugin(\n                Identifier.of(\"builtin\", \"trapped_chest_center\"),\n                () -> new DynamicUnbakedModel(\n                        new Identifier[] {\n                                ModelIdentifiers.TRAPPED_CHEST_CENTER,\n                                ModelIdentifiers.TRAPPED_CHEST_CENTER_TRUNK,\n                                ModelIdentifiers.CHRISTMAS_CHEST_CENTER,\n                                ModelIdentifiers.CHRISTMAS_CHEST_CENTER_TRUNK\n                        },\n                        ModelSelector.CHEST_WITH_CHRISTMAS,\n                        DynamicModelEffects.CHEST\n                )\n        ));\n        ModelLoadingPlugin.register(new DynamicModelProvidingPlugin(\n                Identifier.of(\"builtin\", \"trapped_chest_left\"),\n                () -> new DynamicUnbakedModel(\n                        new Identifier[] {\n                                ModelIdentifiers.TRAPPED_CHEST_LEFT,\n                                ModelIdentifiers.TRAPPED_CHEST_LEFT_TRUNK,\n                                ModelIdentifiers.CHRISTMAS_CHEST_LEFT,\n                                ModelIdentifiers.CHRISTMAS_CHEST_LEFT_TRUNK\n                        },\n                        ModelSelector.CHEST_WITH_CHRISTMAS,\n                        DynamicModelEffects.CHEST\n                )\n        ));\n        ModelLoadingPlugin.register(new DynamicModelProvidingPlugin(\n                Identifier.of(\"builtin\", \"trapped_chest_right\"),\n                () -> new DynamicUnbakedModel(\n                        new Identifier[] {\n                                ModelIdentifiers.TRAPPED_CHEST_RIGHT,\n                                ModelIdentifiers.TRAPPED_CHEST_RIGHT_TRUNK,\n                                ModelIdentifiers.CHRISTMAS_CHEST_RIGHT,\n                                ModelIdentifiers.CHRISTMAS_CHEST_RIGHT_TRUNK\n                        },\n                        ModelSelector.CHEST_WITH_CHRISTMAS,\n                        DynamicModelEffects.CHEST\n                )\n        ));\n        ModelLoadingPlugin.register(new DynamicModelProvidingPlugin(\n                Identifier.of(\"builtin\", \"ender_chest_center\"),\n                () -> new DynamicUnbakedModel(\n                        new Identifier[] {\n                                ModelIdentifiers.ENDER_CHEST_CENTER,\n                                ModelIdentifiers.ENDER_CHEST_CENTER_TRUNK\n                        },\n                        ModelSelector.CHEST,\n                        DynamicModelEffects.CHEST\n                )\n        ));\n\n        ModelLoadingPlugin.register(new DynamicModelProvidingPlugin(\n                Identifier.of(\"builtin\", \"bell_between_walls\"),\n                () -> new DynamicUnbakedModel(\n                        new Identifier[] {\n                                ModelIdentifiers.BELL_BETWEEN_WALLS_WITH_BELL,\n                                ModelIdentifiers.BELL_BETWEEN_WALLS\n                        },\n                        ModelSelector.BELL,\n                        DynamicModelEffects.BELL\n                )\n        ));\n        ModelLoadingPlugin.register(new DynamicModelProvidingPlugin(\n                Identifier.of(\"builtin\", \"bell_ceiling\"),\n                () -> new DynamicUnbakedModel(\n                        new Identifier[] {\n                                ModelIdentifiers.BELL_CEILING_WITH_BELL,\n                                ModelIdentifiers.BELL_CEILING\n                        },\n                        ModelSelector.BELL,\n                        DynamicModelEffects.BELL\n                )\n        ));\n        ModelLoadingPlugin.register(new DynamicModelProvidingPlugin(\n                Identifier.of(\"builtin\", \"bell_floor\"),\n                () -> new DynamicUnbakedModel(\n                        new Identifier[] {\n                                ModelIdentifiers.BELL_FLOOR_WITH_BELL,\n                                ModelIdentifiers.BELL_FLOOR\n                        },\n                        ModelSelector.BELL,\n                        DynamicModelEffects.BELL\n                )\n        ));\n        ModelLoadingPlugin.register(new DynamicModelProvidingPlugin(\n                Identifier.of(\"builtin\", \"bell_wall\"),\n                () -> new DynamicUnbakedModel(\n                        new Identifier[] {\n                                ModelIdentifiers.BELL_WALL_WITH_BELL,\n                                ModelIdentifiers.BELL_WALL\n                        },\n                        ModelSelector.BELL,\n                        DynamicModelEffects.BELL\n                )\n        ));\n        for (DyeColor color : EBEUtil.DEFAULTED_DYE_COLORS) {\n            ModelLoadingPlugin.register(new DynamicModelProvidingPlugin(\n                    Identifier.of(\"builtin\", color != null ? color.getName()+\"_shulker_box\" : \"shulker_box\"),\n                    () -> new DynamicUnbakedModel(\n                            new Identifier[] {\n                                    ModelIdentifiers.SHULKER_BOXES.get(color),\n                                    ModelIdentifiers.SHULKER_BOX_BOTTOMS.get(color)\n                            },\n                            ModelSelector.SHULKER_BOX,\n                            DynamicModelEffects.SHULKER_BOX\n                    )\n            ));\n        }\n\n        DecoratedPotModelSelector decoratedPotSelector = new DecoratedPotModelSelector();\n        ModelLoadingPlugin.register(new DynamicModelProvidingPlugin(\n                Identifier.of(\"builtin\", \"decorated_pot\"),\n                () -> new DynamicUnbakedModel(\n                        decoratedPotSelector.createModelIDs(),\n                        decoratedPotSelector,\n                        DynamicModelEffects.DECORATED_POT\n                )\n        ));\n    }\n\n    public static void setupChests() {\n        BlockRenderLayerMap.INSTANCE.putBlock(Blocks.CHEST, RenderLayer.getCutoutMipped());\n        BlockRenderLayerMap.INSTANCE.putBlock(Blocks.TRAPPED_CHEST, RenderLayer.getCutoutMipped());\n        BlockRenderLayerMap.INSTANCE.putBlock(Blocks.ENDER_CHEST, RenderLayer.getCutoutMipped());\n\n        Function<BlockEntity, Integer> christmasChestSelector = entity -> {\n            int os = DateUtil.isChristmas() ? 3 : 0;\n            ChestType type = entity.getCachedState().get(Properties.CHEST_TYPE);\n            return type == ChestType.RIGHT ? 2 + os : type == ChestType.LEFT ? 1 + os : os;\n        };\n        EnhancedBlockEntityRegistry.register(Blocks.CHEST, BlockEntityType.CHEST, BlockEntityRenderCondition.CHEST,\n                new ChestBlockEntityRendererOverride(() -> {\n                    FabricBakedModelManager manager =  MinecraftClient.getInstance().getBakedModelManager();\n                    return new BakedModel[] {\n                            manager.getModel(ModelIdentifiers.CHEST_CENTER_LID),\n                            manager.getModel(ModelIdentifiers.CHEST_LEFT_LID),\n                            manager.getModel(ModelIdentifiers.CHEST_RIGHT_LID),\n                            manager.getModel(ModelIdentifiers.CHRISTMAS_CHEST_CENTER_LID),\n                            manager.getModel(ModelIdentifiers.CHRISTMAS_CHEST_LEFT_LID),\n                            manager.getModel(ModelIdentifiers.CHRISTMAS_CHEST_RIGHT_LID)\n                    };\n                }, christmasChestSelector)\n        );\n        EnhancedBlockEntityRegistry.register(Blocks.TRAPPED_CHEST, BlockEntityType.TRAPPED_CHEST, BlockEntityRenderCondition.CHEST,\n                new ChestBlockEntityRendererOverride(() -> {\n                    FabricBakedModelManager manager = MinecraftClient.getInstance().getBakedModelManager();\n                    return new BakedModel[] {\n                            manager.getModel(ModelIdentifiers.TRAPPED_CHEST_CENTER_LID),\n                            manager.getModel(ModelIdentifiers.TRAPPED_CHEST_LEFT_LID),\n                            manager.getModel(ModelIdentifiers.TRAPPED_CHEST_RIGHT_LID),\n                            manager.getModel(ModelIdentifiers.CHRISTMAS_CHEST_CENTER_LID),\n                            manager.getModel(ModelIdentifiers.CHRISTMAS_CHEST_LEFT_LID),\n                            manager.getModel(ModelIdentifiers.CHRISTMAS_CHEST_RIGHT_LID)\n                    };\n                }, christmasChestSelector)\n        );\n        EnhancedBlockEntityRegistry.register(Blocks.ENDER_CHEST, BlockEntityType.ENDER_CHEST, BlockEntityRenderCondition.CHEST,\n                new ChestBlockEntityRendererOverride(() -> {\n                    FabricBakedModelManager manager = MinecraftClient.getInstance().getBakedModelManager();\n                    return new BakedModel[] { manager.getModel(ModelIdentifiers.ENDER_CHEST_CENTER_LID) };\n                }, entity -> 0)\n        );\n    }\n\n    public static void setupSigns() {\n        for (var sign : new Block[] {\n                Blocks.OAK_SIGN, Blocks.OAK_WALL_SIGN,\n                Blocks.BIRCH_SIGN, Blocks.BIRCH_WALL_SIGN,\n                Blocks.SPRUCE_SIGN, Blocks.SPRUCE_WALL_SIGN,\n                Blocks.JUNGLE_SIGN, Blocks.JUNGLE_WALL_SIGN,\n                Blocks.ACACIA_SIGN, Blocks.ACACIA_WALL_SIGN,\n                Blocks.DARK_OAK_SIGN, Blocks.DARK_OAK_WALL_SIGN,\n                Blocks.MANGROVE_SIGN, Blocks.MANGROVE_WALL_SIGN,\n                Blocks.CHERRY_SIGN, Blocks.CHERRY_WALL_SIGN,\n                Blocks.CRIMSON_SIGN, Blocks.CRIMSON_WALL_SIGN,\n                Blocks.WARPED_SIGN, Blocks.WARPED_WALL_SIGN,\n                Blocks.BAMBOO_SIGN, Blocks.BAMBOO_WALL_SIGN,\n                Blocks.PALE_OAK_SIGN, Blocks.PALE_OAK_WALL_SIGN\n        }) {\n            EnhancedBlockEntityRegistry.register(sign, BlockEntityType.SIGN, BlockEntityRenderCondition.SIGN,\n                    new SignBlockEntityRendererOverride()\n            );\n        }\n\n        for (var sign : new Block[] {\n                Blocks.OAK_HANGING_SIGN, Blocks.OAK_WALL_HANGING_SIGN,\n                Blocks.BIRCH_HANGING_SIGN, Blocks.BIRCH_WALL_HANGING_SIGN,\n                Blocks.SPRUCE_HANGING_SIGN, Blocks.SPRUCE_WALL_HANGING_SIGN,\n                Blocks.JUNGLE_HANGING_SIGN, Blocks.JUNGLE_WALL_HANGING_SIGN,\n                Blocks.ACACIA_HANGING_SIGN, Blocks.ACACIA_WALL_HANGING_SIGN,\n                Blocks.DARK_OAK_HANGING_SIGN, Blocks.DARK_OAK_WALL_HANGING_SIGN,\n                Blocks.MANGROVE_HANGING_SIGN, Blocks.MANGROVE_WALL_HANGING_SIGN,\n                Blocks.CHERRY_HANGING_SIGN, Blocks.CHERRY_WALL_HANGING_SIGN,\n                Blocks.CRIMSON_HANGING_SIGN, Blocks.CRIMSON_WALL_HANGING_SIGN,\n                Blocks.WARPED_HANGING_SIGN, Blocks.WARPED_WALL_HANGING_SIGN,\n                Blocks.BAMBOO_HANGING_SIGN, Blocks.BAMBOO_WALL_HANGING_SIGN,\n                Blocks.PALE_OAK_HANGING_SIGN, Blocks.PALE_OAK_WALL_HANGING_SIGN\n        }) {\n            EnhancedBlockEntityRegistry.register(sign, BlockEntityType.HANGING_SIGN, BlockEntityRenderCondition.SIGN,\n                    new SignBlockEntityRendererOverride()\n            );\n            BlockRenderLayerMap.INSTANCE.putBlock(sign, RenderLayer.getCutout());\n        }\n    }\n\n    public static void setupBells() {\n        EnhancedBlockEntityRegistry.register(Blocks.BELL, BlockEntityType.BELL, BlockEntityRenderCondition.BELL,\n                new BellBlockEntityRendererOverride()\n        );\n    }\n\n    public static void setupBeds() {\n        EnhancedBlockEntityRegistry.register(Blocks.BLACK_BED, BlockEntityType.BED, BlockEntityRenderCondition.NEVER, BlockEntityRendererOverride.NO_OP);\n        EnhancedBlockEntityRegistry.register(Blocks.BLUE_BED, BlockEntityType.BED, BlockEntityRenderCondition.NEVER, BlockEntityRendererOverride.NO_OP);\n        EnhancedBlockEntityRegistry.register(Blocks.BROWN_BED, BlockEntityType.BED, BlockEntityRenderCondition.NEVER, BlockEntityRendererOverride.NO_OP);\n        EnhancedBlockEntityRegistry.register(Blocks.CYAN_BED, BlockEntityType.BED, BlockEntityRenderCondition.NEVER, BlockEntityRendererOverride.NO_OP);\n        EnhancedBlockEntityRegistry.register(Blocks.GRAY_BED, BlockEntityType.BED, BlockEntityRenderCondition.NEVER, BlockEntityRendererOverride.NO_OP);\n        EnhancedBlockEntityRegistry.register(Blocks.GREEN_BED, BlockEntityType.BED, BlockEntityRenderCondition.NEVER, BlockEntityRendererOverride.NO_OP);\n        EnhancedBlockEntityRegistry.register(Blocks.LIGHT_BLUE_BED, BlockEntityType.BED, BlockEntityRenderCondition.NEVER, BlockEntityRendererOverride.NO_OP);\n        EnhancedBlockEntityRegistry.register(Blocks.LIGHT_GRAY_BED, BlockEntityType.BED, BlockEntityRenderCondition.NEVER, BlockEntityRendererOverride.NO_OP);\n        EnhancedBlockEntityRegistry.register(Blocks.LIME_BED, BlockEntityType.BED, BlockEntityRenderCondition.NEVER, BlockEntityRendererOverride.NO_OP);\n        EnhancedBlockEntityRegistry.register(Blocks.MAGENTA_BED, BlockEntityType.BED, BlockEntityRenderCondition.NEVER, BlockEntityRendererOverride.NO_OP);\n        EnhancedBlockEntityRegistry.register(Blocks.ORANGE_BED, BlockEntityType.BED, BlockEntityRenderCondition.NEVER, BlockEntityRendererOverride.NO_OP);\n        EnhancedBlockEntityRegistry.register(Blocks.PINK_BED, BlockEntityType.BED, BlockEntityRenderCondition.NEVER, BlockEntityRendererOverride.NO_OP);\n        EnhancedBlockEntityRegistry.register(Blocks.PURPLE_BED, BlockEntityType.BED, BlockEntityRenderCondition.NEVER, BlockEntityRendererOverride.NO_OP);\n        EnhancedBlockEntityRegistry.register(Blocks.RED_BED, BlockEntityType.BED, BlockEntityRenderCondition.NEVER, BlockEntityRendererOverride.NO_OP);\n        EnhancedBlockEntityRegistry.register(Blocks.WHITE_BED, BlockEntityType.BED, BlockEntityRenderCondition.NEVER, BlockEntityRendererOverride.NO_OP);\n        EnhancedBlockEntityRegistry.register(Blocks.YELLOW_BED, BlockEntityType.BED, BlockEntityRenderCondition.NEVER, BlockEntityRendererOverride.NO_OP);\n    }\n\n    public static void setupShulkerBoxes() {\n        for (DyeColor color : EBEUtil.DEFAULTED_DYE_COLORS) {\n            var block = ShulkerBoxBlock.get(color);\n            BlockRenderLayerMap.INSTANCE.putBlock(block, RenderLayer.getCutoutMipped());\n            EnhancedBlockEntityRegistry.register(block, BlockEntityType.SHULKER_BOX, BlockEntityRenderCondition.SHULKER_BOX,\n                    new ShulkerBoxBlockEntityRendererOverride((map) -> {\n                        var models =  MinecraftClient.getInstance().getBakedModelManager();\n                        for (DyeColor dc : EBEUtil.DEFAULTED_DYE_COLORS) {\n                            map.put(dc, models.getModel(ModelIdentifiers.SHULKER_BOX_LIDS.get(dc)));\n                        }\n                    })\n            );\n        }\n    }\n\n    public static void setupDecoratedPots() {\n        EnhancedBlockEntityRegistry.register(Blocks.DECORATED_POT, BlockEntityType.DECORATED_POT,\n                BlockEntityRenderCondition.DECORATED_POT, new DecoratedPotBlockEntityRendererOverride());\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/EnhancedBlockEntities.java",
    "content": "package foundationgames.enhancedblockentities;\n\nimport foundationgames.enhancedblockentities.client.model.ModelIdentifiers;\nimport foundationgames.enhancedblockentities.client.model.item.EBEIsChristmasProperty;\nimport foundationgames.enhancedblockentities.client.render.SignRenderManager;\nimport foundationgames.enhancedblockentities.client.resource.template.TemplateLoader;\nimport foundationgames.enhancedblockentities.config.EBEConfig;\nimport foundationgames.enhancedblockentities.util.EBEUtil;\nimport foundationgames.enhancedblockentities.util.ResourceUtil;\nimport foundationgames.enhancedblockentities.util.WorldUtil;\nimport net.fabricmc.api.ClientModInitializer;\nimport net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;\nimport net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;\nimport net.fabricmc.loader.api.FabricLoader;\nimport net.minecraft.client.MinecraftClient;\nimport net.minecraft.client.render.item.property.bool.BooleanProperties;\nimport org.apache.logging.log4j.LogManager;\nimport org.apache.logging.log4j.Logger;\n\nimport java.util.function.Consumer;\n\npublic final class EnhancedBlockEntities implements ClientModInitializer {\n    public static final String ID = \"enhancedblockentities\";\n    public static final String NAMESPACE = \"ebe\";\n    public static final Logger LOG = LogManager.getLogger(\"Enhanced Block Entities\");\n    public static final EBEConfig CONFIG = new EBEConfig();\n\n    public static final TemplateLoader TEMPLATE_LOADER = new TemplateLoader();\n\n    public static final String API_V1 = \"ebe_v1\";\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public void onInitializeClient() {\n        FabricLoader.getInstance().getModContainer(ID).ifPresent(mod -> {\n            var roots = mod.getRootPaths();\n\n            if (!roots.isEmpty()) {\n                TEMPLATE_LOADER.setRoot(roots.getFirst().resolve(\"templates\"));\n            }\n        });\n\n        var ebeCompatInitializers = FabricLoader.getInstance().getEntrypointContainers(API_V1, Consumer.class);\n        for (var init : ebeCompatInitializers) {\n            init.getEntrypoint().accept((Runnable) EnhancedBlockEntities::load);\n        }\n\n        BooleanProperties.ID_MAPPER.put(EBEUtil.id(\"ebe_is_christmas\"), EBEIsChristmasProperty.CODEC);\n\n        WorldRenderEvents.END.register(SignRenderManager::endFrame);\n        ClientTickEvents.END_WORLD_TICK.register(WorldUtil.EVENT_LISTENER);\n\n        ModelIdentifiers.init();\n        EBESetup.setupResourceProviders();\n\n        load();\n    }\n\n    public static void reload(ReloadType type) {\n        load();\n        if (type == ReloadType.WORLD) {\n            MinecraftClient.getInstance().worldRenderer.reload();\n        } else if (type == ReloadType.RESOURCES) {\n            MinecraftClient.getInstance().reloadResources();\n        }\n    }\n\n    public static void load() {\n        CONFIG.load();\n\n        EnhancedBlockEntityRegistry.clear();\n        ResourceUtil.resetBasePack();\n        ResourceUtil.resetTopLevelPack();\n\n        if (CONFIG.renderEnhancedChests) {\n            EBESetup.setupChests();\n            EBESetup.setupRRPChests();\n        }\n\n        if (CONFIG.renderEnhancedSigns) {\n            EBESetup.setupSigns();\n            EBESetup.setupRRPSigns();\n        }\n\n        if (CONFIG.renderEnhancedBells) {\n            EBESetup.setupBells();\n            EBESetup.setupRRPBells();\n        }\n\n        if (CONFIG.renderEnhancedBeds) {\n            EBESetup.setupBeds();\n            EBESetup.setupRRPBeds();\n        }\n\n        if (CONFIG.renderEnhancedShulkerBoxes) {\n            EBESetup.setupShulkerBoxes();\n            EBESetup.setupRRPShulkerBoxes();\n        }\n\n        if (CONFIG.renderEnhancedDecoratedPots) {\n            EBESetup.setupDecoratedPots();\n            EBESetup.setupRRPDecoratedPots();\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/EnhancedBlockEntityRegistry.java",
    "content": "package foundationgames.enhancedblockentities;\n\nimport foundationgames.enhancedblockentities.client.render.BlockEntityRenderCondition;\nimport foundationgames.enhancedblockentities.client.render.BlockEntityRendererOverride;\nimport net.minecraft.block.Block;\nimport net.minecraft.block.entity.BlockEntityType;\nimport net.minecraft.util.Pair;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\npublic final class EnhancedBlockEntityRegistry {\n    public static final Map<BlockEntityType<?>, Pair<BlockEntityRenderCondition, BlockEntityRendererOverride>> ENTITIES = new HashMap<>();\n    public static final Set<Block> BLOCKS = new HashSet<>();\n\n    private EnhancedBlockEntityRegistry() {}\n\n    public static void register(Block block, BlockEntityType<?> type, BlockEntityRenderCondition condition, BlockEntityRendererOverride renderer) {\n        ENTITIES.put(type, new Pair<>(condition, renderer));\n        BLOCKS.add(block);\n    }\n\n    public static void clear() {\n        ENTITIES.clear();\n        BLOCKS.clear();\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/ReloadType.java",
    "content": "package foundationgames.enhancedblockentities;\n\npublic enum ReloadType {\n    NONE(0),\n    WORLD(1),\n    RESOURCES(2);\n\n    private final int pertinence;\n\n    ReloadType(int pertinence) {\n        this.pertinence = pertinence;\n    }\n\n    public ReloadType or(ReloadType type) {\n        return type.pertinence > this.pertinence ? type : this;\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/model/DynamicBakedModel.java",
    "content": "package foundationgames.enhancedblockentities.client.model;\n\nimport net.fabricmc.fabric.api.renderer.v1.Renderer;\nimport net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;\nimport net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;\nimport net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;\nimport net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;\nimport net.minecraft.block.BlockState;\nimport net.minecraft.client.render.model.BakedModel;\nimport net.minecraft.client.render.model.BakedQuad;\nimport net.minecraft.client.render.model.json.ModelTransformation;\nimport net.minecraft.client.texture.Sprite;\nimport net.minecraft.util.math.BlockPos;\nimport net.minecraft.util.math.Direction;\nimport net.minecraft.util.math.random.Random;\nimport net.minecraft.world.BlockRenderView;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.List;\nimport java.util.function.Predicate;\nimport java.util.function.Supplier;\n\npublic class DynamicBakedModel implements BakedModel, FabricBakedModel {\n    private final BakedModel[] models;\n    private final ModelSelector selector;\n    private final DynamicModelEffects effects;\n\n    private final ThreadLocal<int[]> activeModelIndices;\n    private final ThreadLocal<BakedModel[]> displayedModels;\n\n    public DynamicBakedModel(BakedModel[] models, ModelSelector selector, DynamicModelEffects effects) {\n        this.models = models;\n        this.selector = selector;\n        this.effects = effects;\n\n        this.activeModelIndices = ThreadLocal.withInitial(() -> new int[selector.displayedModelCount]);\n        this.displayedModels = ThreadLocal.withInitial(() -> new BakedModel[selector.displayedModelCount]);\n    }\n\n    @Override\n    public boolean isVanillaAdapter() {\n        return false;\n    }\n\n    @Override\n    public void emitBlockQuads(QuadEmitter emitter, BlockRenderView view, BlockState state, BlockPos pos, Supplier<Random> rng, Predicate<@Nullable Direction> cullTest) {\n        RenderMaterial mat = null;\n\n        var indices = this.activeModelIndices.get();\n        var models = this.displayedModels.get();\n\n        getSelector().writeModelIndices(view, state, pos, rng, indices);\n        for (int i = 0; i < indices.length; i++) {\n            int modelIndex = indices[i];\n\n            if (modelIndex >= 0) {\n                models[i] = this.models[modelIndex];\n            } else {\n                models[i] = null;\n            }\n        }\n\n        var renderer = Renderer.get();\n        if (renderer != null) {\n            mat = renderer.materialById(RenderMaterial.STANDARD_ID);\n        }\n\n        for (int i = 0; i <= 6; i++) {\n            Direction dir = ModelHelper.faceFromIndex(i);\n            for (BakedModel model : models) if (model != null) {\n                for (BakedQuad quad : model.getQuads(state, dir, rng.get())) {\n                    emitter.fromVanilla(quad, mat, dir);\n                    emitter.emit();\n                }\n            }\n        }\n    }\n\n    @Override\n    public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) {\n        return models[0].getQuads(state, face, random);\n    }\n\n    @Override\n    public boolean useAmbientOcclusion() {\n        return getEffects().ambientOcclusion();\n    }\n\n    @Override\n    public boolean hasDepth() {\n        return false;\n    }\n\n    @Override\n    public boolean isSideLit() {\n        return false;\n    }\n\n    @Override\n    public Sprite getParticleSprite() {\n        return models[getSelector().getParticleModelIndex()].getParticleSprite();\n    }\n\n    @Override\n    public ModelTransformation getTransformation() {\n        return null;\n    }\n\n    public BakedModel[] getModels() {\n        return models;\n    }\n\n    public ModelSelector getSelector() {\n        return selector;\n    }\n\n    public DynamicModelEffects getEffects() {\n        return effects;\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/model/DynamicModelEffects.java",
    "content": "package foundationgames.enhancedblockentities.client.model;\n\nimport foundationgames.enhancedblockentities.EnhancedBlockEntities;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic abstract class DynamicModelEffects {\n    private static final List<DynamicModelEffects> REGISTRY = new ArrayList<>();\n\n    public static final DynamicModelEffects DEFAULT = new DynamicModelEffects() {};\n\n    public static final DynamicModelEffects CHEST = new DynamicModelEffects() {\n        @Override\n        public boolean ambientOcclusion() {\n            return EnhancedBlockEntities.CONFIG.chestAO;\n        }\n    };\n\n    public static final DynamicModelEffects BELL = new DynamicModelEffects() {\n        @Override\n        public boolean ambientOcclusion() {\n            return EnhancedBlockEntities.CONFIG.bellAO;\n        }\n    };\n\n    public static final DynamicModelEffects SHULKER_BOX = new DynamicModelEffects() {\n        @Override\n        public boolean ambientOcclusion() {\n            return EnhancedBlockEntities.CONFIG.shulkerBoxAO;\n        }\n    };\n\n    public static final DynamicModelEffects DECORATED_POT = new DynamicModelEffects() {\n        @Override\n        public boolean ambientOcclusion() {\n            return EnhancedBlockEntities.CONFIG.decoratedPotAO;\n        }\n    };\n\n    public final int id;\n\n    public DynamicModelEffects() {\n        this.id = REGISTRY.size();\n        REGISTRY.add(this);\n    }\n\n    public boolean ambientOcclusion() {\n        return true;\n    }\n\n    public static DynamicModelEffects fromId(int id) {\n        return REGISTRY.get(id);\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/model/DynamicModelProvidingPlugin.java",
    "content": "package foundationgames.enhancedblockentities.client.model;\n\nimport net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;\nimport net.fabricmc.fabric.api.client.model.loading.v1.ModelModifier;\nimport net.minecraft.client.render.model.UnbakedModel;\nimport net.minecraft.util.Identifier;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.function.Supplier;\n\npublic class DynamicModelProvidingPlugin implements ModelLoadingPlugin, ModelModifier.OnLoad {\n    private final Supplier<DynamicUnbakedModel> model;\n    private final Identifier id;\n\n    public DynamicModelProvidingPlugin(Identifier id, Supplier<DynamicUnbakedModel> model) {\n        this.model = model;\n        this.id = id;\n    }\n\n    @Override\n    public void initialize(ModelLoadingPlugin.Context ctx) {\n        ctx.modifyModelOnLoad().register(this);\n    }\n\n    @Override\n    public @Nullable UnbakedModel modifyModelOnLoad(@Nullable UnbakedModel model, ModelModifier.OnLoad.Context context) {\n        if (context.id().equals(this.id)) return this.model.get();\n        return model;\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/model/DynamicUnbakedModel.java",
    "content": "package foundationgames.enhancedblockentities.client.model;\n\nimport net.minecraft.client.render.model.BakedModel;\nimport net.minecraft.client.render.model.Baker;\nimport net.minecraft.client.render.model.ModelBakeSettings;\nimport net.minecraft.client.render.model.ModelTextures;\nimport net.minecraft.client.render.model.UnbakedModel;\nimport net.minecraft.client.render.model.json.ModelTransformation;\nimport net.minecraft.util.Identifier;\nimport org.jetbrains.annotations.Nullable;\n\npublic class DynamicUnbakedModel implements UnbakedModel {\n    private final Identifier[] models;\n    private final ModelSelector selector;\n    private final DynamicModelEffects effects;\n\n    public DynamicUnbakedModel(Identifier[] models, ModelSelector selector, DynamicModelEffects effects) {\n        this.models = models;\n        this.selector = selector;\n        this.effects = effects;\n    }\n\n    @Override\n    public void resolve(Resolver resolver) {\n        for (Identifier modelId : models) {\n            if(modelId == null) continue;\n            resolver.resolve(modelId);\n        }\n    }\n\n    @Override\n    public @Nullable BakedModel bake(ModelTextures textures, Baker baker, ModelBakeSettings settings, boolean ambientOcclusion, boolean isSideLit, ModelTransformation transformation) {\n        BakedModel[] baked = new BakedModel[models.length];\n        for (int i = 0; i < models.length; i++) {\n            baked[i] = baker.bake(models[i], settings);\n        }\n        return new DynamicBakedModel(baked, selector, effects);\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/model/ModelIdentifiers.java",
    "content": "package foundationgames.enhancedblockentities.client.model;\n\nimport foundationgames.enhancedblockentities.EnhancedBlockEntities;\nimport foundationgames.enhancedblockentities.config.EBEConfig;\nimport foundationgames.enhancedblockentities.util.EBEUtil;\nimport net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;\nimport net.minecraft.block.DecoratedPotPattern;\nimport net.minecraft.registry.Registries;\nimport net.minecraft.registry.RegistryKey;\nimport net.minecraft.util.DyeColor;\nimport net.minecraft.util.Identifier;\nimport net.minecraft.util.math.Direction;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Predicate;\n\npublic final class ModelIdentifiers implements ModelLoadingPlugin {\n    private static final Map<Predicate<EBEConfig>, Set<Identifier>> modelLoaders = new HashMap<>();\n\n    public static final Predicate<EBEConfig> CHEST_PREDICATE = c -> c.renderEnhancedChests;\n    public static final Predicate<EBEConfig> BELL_PREDICATE = c -> c.renderEnhancedBells;\n    public static final Predicate<EBEConfig> SHULKER_BOX_PREDICATE = c -> c.renderEnhancedShulkerBoxes;\n    public static final Predicate<EBEConfig> DECORATED_POT_PREDICATE = c -> c.renderEnhancedDecoratedPots;\n\n    public static final Identifier CHEST_CENTER = of(\"block/chest_center\", CHEST_PREDICATE);\n    public static final Identifier CHEST_CENTER_TRUNK = of(\"block/chest_center_trunk\", CHEST_PREDICATE);\n    public static final Identifier CHEST_CENTER_LID = of(\"block/chest_center_lid\", CHEST_PREDICATE);\n    public static final Identifier CHEST_LEFT = of(\"block/chest_left\", CHEST_PREDICATE);\n    public static final Identifier CHEST_LEFT_TRUNK = of(\"block/chest_left_trunk\", CHEST_PREDICATE);\n    public static final Identifier CHEST_LEFT_LID = of(\"block/chest_left_lid\", CHEST_PREDICATE);\n    public static final Identifier CHEST_RIGHT = of(\"block/chest_right\", CHEST_PREDICATE);\n    public static final Identifier CHEST_RIGHT_TRUNK = of(\"block/chest_right_trunk\", CHEST_PREDICATE);\n    public static final Identifier CHEST_RIGHT_LID = of(\"block/chest_right_lid\", CHEST_PREDICATE);\n\n    public static final Identifier TRAPPED_CHEST_CENTER = of(\"block/trapped_chest_center\", CHEST_PREDICATE);\n    public static final Identifier TRAPPED_CHEST_CENTER_TRUNK = of(\"block/trapped_chest_center_trunk\", CHEST_PREDICATE);\n    public static final Identifier TRAPPED_CHEST_CENTER_LID = of(\"block/trapped_chest_center_lid\", CHEST_PREDICATE);\n    public static final Identifier TRAPPED_CHEST_LEFT = of(\"block/trapped_chest_left\", CHEST_PREDICATE);\n    public static final Identifier TRAPPED_CHEST_LEFT_TRUNK = of(\"block/trapped_chest_left_trunk\", CHEST_PREDICATE);\n    public static final Identifier TRAPPED_CHEST_LEFT_LID = of(\"block/trapped_chest_left_lid\", CHEST_PREDICATE);\n    public static final Identifier TRAPPED_CHEST_RIGHT = of(\"block/trapped_chest_right\", CHEST_PREDICATE);\n    public static final Identifier TRAPPED_CHEST_RIGHT_TRUNK = of(\"block/trapped_chest_right_trunk\", CHEST_PREDICATE);\n    public static final Identifier TRAPPED_CHEST_RIGHT_LID = of(\"block/trapped_chest_right_lid\", CHEST_PREDICATE);\n\n    public static final Identifier CHRISTMAS_CHEST_CENTER = of(\"block/christmas_chest_center\", CHEST_PREDICATE);\n    public static final Identifier CHRISTMAS_CHEST_CENTER_TRUNK = of(\"block/christmas_chest_center_trunk\", CHEST_PREDICATE);\n    public static final Identifier CHRISTMAS_CHEST_CENTER_LID = of(\"block/christmas_chest_center_lid\", CHEST_PREDICATE);\n    public static final Identifier CHRISTMAS_CHEST_LEFT = of(\"block/christmas_chest_left\", CHEST_PREDICATE);\n    public static final Identifier CHRISTMAS_CHEST_LEFT_TRUNK = of(\"block/christmas_chest_left_trunk\", CHEST_PREDICATE);\n    public static final Identifier CHRISTMAS_CHEST_LEFT_LID = of(\"block/christmas_chest_left_lid\", CHEST_PREDICATE);\n    public static final Identifier CHRISTMAS_CHEST_RIGHT = of(\"block/christmas_chest_right\", CHEST_PREDICATE);\n    public static final Identifier CHRISTMAS_CHEST_RIGHT_TRUNK = of(\"block/christmas_chest_right_trunk\", CHEST_PREDICATE);\n    public static final Identifier CHRISTMAS_CHEST_RIGHT_LID = of(\"block/christmas_chest_right_lid\", CHEST_PREDICATE);\n\n    public static final Identifier ENDER_CHEST_CENTER = of(\"block/ender_chest_center\", CHEST_PREDICATE);\n    public static final Identifier ENDER_CHEST_CENTER_TRUNK = of(\"block/ender_chest_center_trunk\", CHEST_PREDICATE);\n    public static final Identifier ENDER_CHEST_CENTER_LID = of(\"block/ender_chest_center_lid\", CHEST_PREDICATE);\n\n    public static final Identifier BELL_BETWEEN_WALLS = of(\"block/bell_between_walls\", BELL_PREDICATE);\n    public static final Identifier BELL_CEILING = of(\"block/bell_ceiling\", BELL_PREDICATE);\n    public static final Identifier BELL_FLOOR = of(\"block/bell_floor\", BELL_PREDICATE);\n    public static final Identifier BELL_WALL = of(\"block/bell_wall\", BELL_PREDICATE);\n    public static final Identifier BELL_BETWEEN_WALLS_WITH_BELL = of(\"block/bell_between_walls_with_bell\", BELL_PREDICATE);\n    public static final Identifier BELL_CEILING_WITH_BELL = of(\"block/bell_ceiling_with_bell\", BELL_PREDICATE);\n    public static final Identifier BELL_FLOOR_WITH_BELL = of(\"block/bell_floor_with_bell\", BELL_PREDICATE);\n    public static final Identifier BELL_WALL_WITH_BELL = of(\"block/bell_wall_with_bell\", BELL_PREDICATE);\n    public static final Identifier BELL_BODY = of(\"block/bell_body\", BELL_PREDICATE);\n\n    public static final Identifier DECORATED_POT_BASE = of(\"block/decorated_pot_base\", DECORATED_POT_PREDICATE);\n    public static final Identifier DECORATED_POT_SHAKING = of(\"block/decorated_pot_shaking\", DECORATED_POT_PREDICATE);\n\n    public static final Map<DyeColor, Identifier> SHULKER_BOXES = new HashMap<>();\n    public static final Map<DyeColor, Identifier> SHULKER_BOX_BOTTOMS = new HashMap<>();\n    public static final Map<DyeColor, Identifier> SHULKER_BOX_LIDS = new HashMap<>();\n\n    public static final Map<RegistryKey<DecoratedPotPattern>, Identifier[]> POTTERY_PATTERNS = new HashMap<>();\n\n    static {\n        for (DyeColor color : EBEUtil.DEFAULTED_DYE_COLORS) {\n            var id = color != null ? \"block/\"+color.getName()+\"_shulker_box\" : \"block/shulker_box\";\n            SHULKER_BOXES.put(color, of(id, SHULKER_BOX_PREDICATE));\n            SHULKER_BOX_BOTTOMS.put(color, of(id+\"_bottom\", SHULKER_BOX_PREDICATE));\n            SHULKER_BOX_LIDS.put(color, of(id+\"_lid\", SHULKER_BOX_PREDICATE));\n        }\n\n        refreshPotteryPatterns();\n    }\n\n    public static void init() {\n        ModelLoadingPlugin.register(new ModelIdentifiers());\n    }\n\n    public static void refreshPotteryPatterns() {\n        POTTERY_PATTERNS.clear();\n\n        // The order decorated pots store patterns per face\n        Direction[] orderedHorizontalDirs = new Direction[] {Direction.NORTH, Direction.WEST, Direction.EAST, Direction.SOUTH};\n\n        for (var patternKey : Registries.DECORATED_POT_PATTERN.getKeys()) {\n            var pattern = patternKey.getValue().getPath();\n            var ids = new Identifier[orderedHorizontalDirs.length];;\n\n            for (int i = 0; i < 4; i++) {\n                ids[i] = of(\"block/\" + pattern + \"_\" + orderedHorizontalDirs[i].getName(),\n                        DECORATED_POT_PREDICATE);\n            }\n\n            POTTERY_PATTERNS.put(patternKey, ids);\n        }\n    }\n\n    private static Identifier of(String id, Predicate<EBEConfig> condition) {\n        Identifier idf = Identifier.of(id);\n        modelLoaders.computeIfAbsent(condition, k -> new HashSet<>()).add(idf);\n        return idf;\n    }\n\n    @Override\n    public void initialize(Context ctx) {\n        var config = EnhancedBlockEntities.CONFIG;\n\n        for (var entry : modelLoaders.entrySet()) {\n            if (entry.getKey().test(config)) {\n                ctx.addModels(entry.getValue());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/model/ModelSelector.java",
    "content": "package foundationgames.enhancedblockentities.client.model;\n\nimport foundationgames.enhancedblockentities.util.DateUtil;\nimport foundationgames.enhancedblockentities.util.duck.AppearanceStateHolder;\nimport net.minecraft.block.BlockState;\nimport net.minecraft.util.math.BlockPos;\nimport net.minecraft.util.math.random.Random;\nimport net.minecraft.world.BlockRenderView;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.Supplier;\n\npublic abstract class ModelSelector {\n    private static final List<ModelSelector> REGISTRY = new ArrayList<>();\n\n    public static final ModelSelector STATE_HOLDER_SELECTOR = new ModelSelector() {\n        @Override\n        public void writeModelIndices(BlockRenderView view, BlockState state, BlockPos pos, Supplier<Random> rand, int[] indices) {\n            if (view.getBlockEntity(pos) instanceof AppearanceStateHolder stateHolder) {\n                indices[0] = stateHolder.getModelState();\n                return;\n            }\n            indices[0] = 0;\n        }\n    };\n\n    public static final ModelSelector CHEST = STATE_HOLDER_SELECTOR;\n\n    public static final ModelSelector CHEST_WITH_CHRISTMAS = new ModelSelector() {\n        @Override\n        public int getParticleModelIndex() {\n            return DateUtil.isChristmas() ? 2 : 0;\n        }\n\n        @Override\n        public void writeModelIndices(BlockRenderView view, BlockState state, BlockPos pos, Supplier<Random> rand, int[] indices) {\n            if (view.getBlockEntity(pos) instanceof AppearanceStateHolder stateHolder) {\n                indices[0] = stateHolder.getModelState() + this.getParticleModelIndex();\n                return;\n            }\n            indices[0] = this.getParticleModelIndex();\n        }\n    };\n\n    public static final ModelSelector BELL = STATE_HOLDER_SELECTOR;\n\n    public static final ModelSelector SHULKER_BOX = STATE_HOLDER_SELECTOR;\n\n    public int getParticleModelIndex() {\n        return 0;\n    }\n\n    public abstract void writeModelIndices(BlockRenderView view, BlockState state, BlockPos pos, Supplier<Random> rand, int[] indices);\n\n    public final int id;\n    public final int displayedModelCount;\n\n    public ModelSelector(int displayedModelCount) {\n        this.id = REGISTRY.size();\n        this.displayedModelCount = displayedModelCount;\n        REGISTRY.add(this);\n    }\n\n    public ModelSelector() {\n        this(1);\n    }\n\n    public static ModelSelector fromId(int id) {\n        return REGISTRY.get(id);\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/model/item/EBEIsChristmasProperty.java",
    "content": "package foundationgames.enhancedblockentities.client.model.item;\n\nimport com.mojang.serialization.MapCodec;\nimport foundationgames.enhancedblockentities.util.DateUtil;\nimport net.minecraft.client.render.item.property.bool.BooleanProperty;\nimport net.minecraft.client.world.ClientWorld;\nimport net.minecraft.entity.LivingEntity;\nimport net.minecraft.item.ItemStack;\nimport net.minecraft.item.ModelTransformationMode;\nimport org.jetbrains.annotations.Nullable;\n\npublic record EBEIsChristmasProperty() implements BooleanProperty {\n    public static final MapCodec<EBEIsChristmasProperty> CODEC = MapCodec.unit(new EBEIsChristmasProperty());\n\n    @Override\n    public boolean getValue(ItemStack stack, @Nullable ClientWorld world, @Nullable LivingEntity user, int seed, ModelTransformationMode modelTransformationMode) {\n        return DateUtil.isChristmas();\n    }\n\n    @Override\n    public MapCodec<EBEIsChristmasProperty> getCodec() {\n        return CODEC;\n    }\n}"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/model/misc/DecoratedPotModelSelector.java",
    "content": "package foundationgames.enhancedblockentities.client.model.misc;\n\nimport foundationgames.enhancedblockentities.client.model.ModelIdentifiers;\nimport foundationgames.enhancedblockentities.client.model.ModelSelector;\nimport foundationgames.enhancedblockentities.util.duck.AppearanceStateHolder;\nimport net.minecraft.block.BlockState;\nimport net.minecraft.block.DecoratedPotPattern;\nimport net.minecraft.block.DecoratedPotPatterns;\nimport net.minecraft.block.entity.DecoratedPotBlockEntity;\nimport net.minecraft.item.Item;\nimport net.minecraft.registry.Registries;\nimport net.minecraft.registry.RegistryKey;\nimport net.minecraft.util.Identifier;\nimport net.minecraft.util.math.BlockPos;\nimport net.minecraft.util.math.MathHelper;\nimport net.minecraft.util.math.random.Random;\nimport net.minecraft.world.BlockRenderView;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.function.Supplier;\n\npublic class DecoratedPotModelSelector extends ModelSelector {\n    public static final int BUILTIN_MODEL_COUNT = 2;\n\n    public static final int IDX_EMPTY = 0;\n    public static final int IDX_BASE_POT = 1;\n\n    private final List<RegistryKey<DecoratedPotPattern>> potteryPatterns;\n\n    public DecoratedPotModelSelector() {\n        super(5);\n\n        this.potteryPatterns = new ArrayList<>(Registries.DECORATED_POT_PATTERN.getKeys());\n    }\n\n    public Identifier[] createModelIDs() {\n        ModelIdentifiers.refreshPotteryPatterns();\n\n        var ids = new Identifier[BUILTIN_MODEL_COUNT + potteryPatterns.size() * 4];\n        ids[IDX_EMPTY] = ModelIdentifiers.DECORATED_POT_SHAKING;\n        ids[IDX_BASE_POT] = ModelIdentifiers.DECORATED_POT_BASE;\n\n        int idIndex = BUILTIN_MODEL_COUNT;\n        for (int dirIndex = 0; dirIndex < 4; dirIndex++) {\n            for (var pattern : this.potteryPatterns) {\n                ids[idIndex] = ModelIdentifiers.POTTERY_PATTERNS.get(pattern)[dirIndex];\n\n                idIndex++;\n            }\n        }\n\n        return ids;\n    }\n\n    @Override\n    public void writeModelIndices(BlockRenderView view, BlockState state, BlockPos pos, Supplier<Random> rand, int[] indices) {\n        final int patternCount = potteryPatterns.size();\n\n        indices[0] = IDX_BASE_POT;\n        if (view.getBlockEntity(pos) instanceof DecoratedPotBlockEntity pot) {\n            if (pot instanceof AppearanceStateHolder ms && ms.getModelState() > 0) {\n                Arrays.fill(indices, IDX_EMPTY);\n                return;\n            }\n\n            var sherds = pot.getSherds();\n\n            indices[1] = BUILTIN_MODEL_COUNT + getPatternIndex(sherds.back(), patternCount);\n            indices[2] = BUILTIN_MODEL_COUNT + getPatternIndex(sherds.left(), patternCount) + patternCount;\n            indices[3] = BUILTIN_MODEL_COUNT + getPatternIndex(sherds.right(), patternCount) + patternCount * 2;\n            indices[4] = BUILTIN_MODEL_COUNT + getPatternIndex(sherds.front(), patternCount) + patternCount * 3;\n\n            return;\n        }\n\n        for (int i = 0; i < 4; i++) {\n            indices[1 + i] = BUILTIN_MODEL_COUNT + patternCount * i;\n        }\n    }\n\n    private int getPatternIndex(Optional<Item> sherd, int max) {\n        return MathHelper.clamp(this.potteryPatterns.indexOf(sherd.map(DecoratedPotPatterns::fromSherd).orElse(DecoratedPotPatterns.BLANK)), 0, max - 1);\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/render/BlockEntityRenderCondition.java",
    "content": "package foundationgames.enhancedblockentities.client.render;\n\nimport foundationgames.enhancedblockentities.EnhancedBlockEntities;\nimport foundationgames.enhancedblockentities.config.EBEConfig;\nimport foundationgames.enhancedblockentities.mixin.AbstractSignBlockEntityRenderAccessor;\nimport foundationgames.enhancedblockentities.util.duck.AppearanceStateHolder;\nimport net.minecraft.block.entity.BlockEntity;\nimport net.minecraft.client.MinecraftClient;\nimport net.minecraft.util.math.Vec3d;\n\n@FunctionalInterface\npublic interface BlockEntityRenderCondition {\n    BlockEntityRenderCondition NON_ZERO_STATE = entity -> {\n        if (entity instanceof AppearanceStateHolder stateHolder) {\n            return stateHolder.getRenderState() > 0;\n        }\n        return false;\n    };\n\n    BlockEntityRenderCondition CHEST = NON_ZERO_STATE;\n\n    BlockEntityRenderCondition BELL = NON_ZERO_STATE;\n\n    BlockEntityRenderCondition SHULKER_BOX = NON_ZERO_STATE;\n\n    BlockEntityRenderCondition SIGN = entity -> {\n        EBEConfig config = EnhancedBlockEntities.CONFIG;\n        if (config.signTextRendering.equals(\"all\")) {\n            return true;\n        }\n        double playerDistance = MinecraftClient.getInstance().player.getBlockPos().getSquaredDistance(entity.getPos());\n        if (config.signTextRendering.equals(\"smart\")) {\n            SignRenderManager.renderedSigns++;\n            return playerDistance < 80 + Math.max(0, 580 - (SignRenderManager.getRenderedSignAmount() * 0.7));\n        }\n        double dist = AbstractSignBlockEntityRenderAccessor.enhanced_bes$getRenderDistance();\n        Vec3d blockPos = Vec3d.ofCenter(entity.getPos());\n        Vec3d playerPos = MinecraftClient.getInstance().player.getPos();\n        if (config.signTextRendering.equals(\"most\")) {\n            return blockPos.isInRange(playerPos, dist * 0.6);\n        }\n        if (config.signTextRendering.equals(\"some\")) {\n            return blockPos.isInRange(playerPos, dist * 0.3);\n        }\n        if (config.signTextRendering.equals(\"few\")) {\n            return blockPos.isInRange(playerPos, dist * 0.15);\n        }\n        return false;\n    };\n\n    BlockEntityRenderCondition DECORATED_POT = NON_ZERO_STATE;\n\n    BlockEntityRenderCondition NEVER = entity -> false;\n\n    BlockEntityRenderCondition ALWAYS = entity -> true;\n\n    boolean shouldRender(BlockEntity entity);\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/render/BlockEntityRendererOverride.java",
    "content": "package foundationgames.enhancedblockentities.client.render;\n\nimport foundationgames.enhancedblockentities.event.EBEEvents;\nimport net.minecraft.block.entity.BlockEntity;\nimport net.minecraft.client.render.VertexConsumerProvider;\nimport net.minecraft.client.render.block.entity.BlockEntityRenderer;\nimport net.minecraft.client.util.math.MatrixStack;\n\npublic abstract class BlockEntityRendererOverride {\n    public static final BlockEntityRendererOverride NO_OP = new BlockEntityRendererOverride() {\n        @Override\n        public void render(BlockEntityRenderer<BlockEntity> renderer, BlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {}\n    };\n\n    public BlockEntityRendererOverride() {\n        EBEEvents.RESOURCE_RELOAD.register(this::onModelsReload);\n    }\n\n    public abstract void render(BlockEntityRenderer<BlockEntity> renderer, BlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay);\n\n    public void onModelsReload() {}\n\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/render/SignRenderManager.java",
    "content": "package foundationgames.enhancedblockentities.client.render;\n\nimport net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;\n\npublic class SignRenderManager {\n    private static int lastRenderedSigns = 0;\n    public static int renderedSigns = 0;\n\n    public static int getRenderedSignAmount() {\n        return lastRenderedSigns;\n    }\n\n    public static void endFrame(WorldRenderContext ctx) {\n        lastRenderedSigns = renderedSigns;\n        renderedSigns = 0;\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/render/entity/BellBlockEntityRendererOverride.java",
    "content": "package foundationgames.enhancedblockentities.client.render.entity;\n\nimport foundationgames.enhancedblockentities.client.model.ModelIdentifiers;\nimport foundationgames.enhancedblockentities.client.render.BlockEntityRendererOverride;\nimport foundationgames.enhancedblockentities.util.EBEUtil;\nimport net.minecraft.block.entity.BellBlockEntity;\nimport net.minecraft.block.entity.BlockEntity;\nimport net.minecraft.client.MinecraftClient;\nimport net.minecraft.client.render.VertexConsumerProvider;\nimport net.minecraft.client.render.block.entity.BlockEntityRenderer;\nimport net.minecraft.client.render.model.BakedModel;\nimport net.minecraft.client.util.math.MatrixStack;\nimport net.minecraft.util.math.Direction;\nimport net.minecraft.util.math.MathHelper;\nimport net.minecraft.util.math.RotationAxis;\n\npublic class BellBlockEntityRendererOverride extends BlockEntityRendererOverride {\n    private BakedModel bellModel = null;\n\n    @Override\n    public void render(BlockEntityRenderer<BlockEntity> renderer, BlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {\n        if (bellModel == null) bellModel = getBellModel();\n        if (bellModel != null && blockEntity instanceof BellBlockEntity self) {\n            float ringTicks = (float)self.ringTicks + tickDelta;\n            float bellPitch = 0.0F;\n            float bellRoll = 0.0F;\n            if (self.ringing) {\n                float swingAngle = MathHelper.sin(ringTicks / (float)Math.PI) / (4.0F + ringTicks / 3.0F);\n                if (self.lastSideHit == Direction.NORTH) {\n                    bellPitch = -swingAngle;\n                } else if (self.lastSideHit == Direction.SOUTH) {\n                    bellPitch = swingAngle;\n                } else if (self.lastSideHit == Direction.EAST) {\n                    bellRoll = -swingAngle;\n                } else if (self.lastSideHit == Direction.WEST) {\n                    bellRoll = swingAngle;\n                }\n            }\n            matrices.push();\n            matrices.translate(8f/16, 12f/16, 8f/16);\n            matrices.multiply(RotationAxis.POSITIVE_X.rotation(bellPitch));\n            matrices.multiply(RotationAxis.POSITIVE_Z.rotation(bellRoll));\n            matrices.translate(-8f/16, -12f/16, -8f/16);\n            EBEUtil.renderBakedModel(vertexConsumers, blockEntity.getCachedState(), matrices, bellModel, light, overlay);\n\n            matrices.pop();\n        }\n    }\n\n    private BakedModel getBellModel() {\n        return MinecraftClient.getInstance().getBakedModelManager().getModel(ModelIdentifiers.BELL_BODY);\n    }\n\n    @Override\n    public void onModelsReload() {\n        bellModel = null;\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/render/entity/ChestBlockEntityRendererOverride.java",
    "content": "package foundationgames.enhancedblockentities.client.render.entity;\n\nimport foundationgames.enhancedblockentities.client.render.BlockEntityRendererOverride;\nimport foundationgames.enhancedblockentities.util.EBEUtil;\nimport net.minecraft.block.BlockState;\nimport net.minecraft.block.ChestBlock;\nimport net.minecraft.block.entity.BlockEntity;\nimport net.minecraft.block.entity.LidOpenable;\nimport net.minecraft.block.enums.ChestType;\nimport net.minecraft.client.render.VertexConsumerProvider;\nimport net.minecraft.client.render.block.entity.BlockEntityRenderer;\nimport net.minecraft.client.render.model.BakedModel;\nimport net.minecraft.client.util.math.MatrixStack;\nimport net.minecraft.util.math.BlockPos;\nimport net.minecraft.util.math.Direction;\nimport net.minecraft.util.math.RotationAxis;\n\nimport java.util.function.Function;\nimport java.util.function.Supplier;\n\npublic class ChestBlockEntityRendererOverride extends BlockEntityRendererOverride {\n    private BakedModel[] models = null;\n    private final Supplier<BakedModel[]> modelGetter;\n    private final Function<BlockEntity, Integer> modelSelector;\n\n    public ChestBlockEntityRendererOverride(Supplier<BakedModel[]> modelGetter, Function<BlockEntity, Integer> modelSelector) {\n        this.modelGetter = modelGetter;\n        this.modelSelector = modelSelector;\n    }\n\n    @Override\n    public void render(BlockEntityRenderer<BlockEntity> renderer, BlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {\n        if (models == null) models = modelGetter.get();\n        if (blockEntity instanceof LidOpenable) {\n            matrices.push();\n\n            LidOpenable chest = getLidAnimationHolder(blockEntity, tickDelta);\n            matrices.translate(0.5f, 0, 0.5f);\n            Direction dir = blockEntity.getCachedState().get(ChestBlock.FACING);\n            matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180 - EBEUtil.angle(dir)));\n            matrices.translate(-0.5f, 0, -0.5f);\n            float yPiv = 9f / 16;\n            float zPiv = 15f / 16;\n            matrices.translate(0, yPiv, zPiv);\n            float rot = chest.getAnimationProgress(tickDelta);\n            rot = 1f - rot;\n            rot = 1f - (rot * rot * rot);\n            matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(rot * 90));\n            matrices.translate(0, -yPiv, -zPiv);\n            EBEUtil.renderBakedModel(vertexConsumers, blockEntity.getCachedState(), matrices, models[modelSelector.apply(blockEntity)], light, overlay);\n\n            matrices.pop();\n        }\n    }\n\n    public static LidOpenable getLidAnimationHolder(BlockEntity blockEntity, float tickDelta) {\n        LidOpenable chest = (LidOpenable)blockEntity;\n\n        BlockState state = blockEntity.getCachedState();\n        if (state.contains(ChestBlock.CHEST_TYPE) && state.get(ChestBlock.CHEST_TYPE) != ChestType.SINGLE) {\n            BlockEntity neighbor = null;\n            BlockPos pos = blockEntity.getPos();\n            Direction facing = state.get(ChestBlock.FACING);\n            switch (state.get(ChestBlock.CHEST_TYPE)) {\n                case LEFT -> neighbor = blockEntity.getWorld().getBlockEntity(pos.offset(facing.rotateYClockwise()));\n                case RIGHT -> neighbor = blockEntity.getWorld().getBlockEntity(pos.offset(facing.rotateYCounterclockwise()));\n            }\n            if (neighbor instanceof LidOpenable) {\n                float nAnim = ((LidOpenable)neighbor).getAnimationProgress(tickDelta);\n                if (nAnim > chest.getAnimationProgress(tickDelta)) {\n                    chest = ((LidOpenable)neighbor);\n                }\n            }\n        }\n\n        return chest;\n    }\n\n    @Override\n    public void onModelsReload() {\n        this.models = null;\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/render/entity/DecoratedPotBlockEntityRendererOverride.java",
    "content": "package foundationgames.enhancedblockentities.client.render.entity;\n\nimport com.google.common.collect.ImmutableMap;\nimport foundationgames.enhancedblockentities.client.model.ModelIdentifiers;\nimport foundationgames.enhancedblockentities.client.render.BlockEntityRendererOverride;\nimport foundationgames.enhancedblockentities.util.EBEUtil;\nimport net.minecraft.block.DecoratedPotPattern;\nimport net.minecraft.block.DecoratedPotPatterns;\nimport net.minecraft.block.entity.BlockEntity;\nimport net.minecraft.block.entity.DecoratedPotBlockEntity;\nimport net.minecraft.client.MinecraftClient;\nimport net.minecraft.client.render.VertexConsumerProvider;\nimport net.minecraft.client.render.block.entity.BlockEntityRenderer;\nimport net.minecraft.client.render.model.BakedModel;\nimport net.minecraft.client.util.math.MatrixStack;\nimport net.minecraft.registry.Registries;\nimport net.minecraft.registry.RegistryKey;\nimport net.minecraft.util.math.MathHelper;\nimport net.minecraft.util.math.RotationAxis;\n\nimport java.util.Map;\n\npublic class DecoratedPotBlockEntityRendererOverride extends BlockEntityRendererOverride {\n    public static final float WOBBLE_STRENGTH = 1f / 64;\n\n    private BakedModel baseModel = null;\n    private Map<RegistryKey<DecoratedPotPattern>, BakedModel[]> potPatternModels = null;\n\n    private void tryGetModels() {\n        var models = MinecraftClient.getInstance().getBakedModelManager();\n\n        if (this.baseModel == null) {\n            this.baseModel = models.getModel(ModelIdentifiers.DECORATED_POT_BASE);\n        }\n\n        if (this.potPatternModels == null) {\n            var builder = ImmutableMap.<RegistryKey<DecoratedPotPattern>, BakedModel[]>builder();\n\n            Registries.DECORATED_POT_PATTERN.getKeys().forEach(k -> {\n                var patternModelIDs = ModelIdentifiers.POTTERY_PATTERNS.get(k);\n                BakedModel[] patternPerFaceModels = new BakedModel[patternModelIDs.length];\n\n                for (int i = 0; i < patternModelIDs.length; i++) {\n                    patternPerFaceModels[i] = models.getModel(patternModelIDs[i]);\n                }\n\n                builder.put(k, patternPerFaceModels);\n            });\n\n            this.potPatternModels = builder.build();\n        }\n    }\n\n    @Override\n    public void render(BlockEntityRenderer<BlockEntity> renderer, BlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {\n        tryGetModels();\n\n        if (blockEntity instanceof DecoratedPotBlockEntity pot) {\n            matrices.push();\n\n            var dir = pot.getHorizontalFacing();\n\n            matrices.translate(0.5f, 0, 0.5f);\n            matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180 - EBEUtil.angle(dir)));\n            matrices.translate(-0.5f, 0, -0.5f);\n\n            var wobbleType = pot.lastWobbleType;\n            if (wobbleType != null && pot.getWorld() != null) {\n                float tilt = ((float)(pot.getWorld().getTime() - pot.lastWobbleTime) + tickDelta) / (float)wobbleType.lengthInTicks;\n                if (tilt >= 0.0F && tilt <= 1.0F) {\n                    if (wobbleType == DecoratedPotBlockEntity.WobbleType.POSITIVE) {\n                        float animPeriod = tilt * MathHelper.TAU;\n\n                        float tiltX = -1.5f * (MathHelper.cos(animPeriod) + 0.5f) * MathHelper.sin(animPeriod * 0.5f);\n                        matrices.multiply(RotationAxis.POSITIVE_X.rotation(tiltX * WOBBLE_STRENGTH), 0.5f, 0f, 0.5f);\n\n                        float tiltZ = MathHelper.sin(animPeriod);\n                        matrices.multiply(RotationAxis.POSITIVE_Z.rotation(tiltZ * WOBBLE_STRENGTH), 0.5f, 0f, 0.5f);\n                    } else {\n                        float yaw = (1f - tilt) * MathHelper.sin(-tilt * 3 * MathHelper.PI) * 0.125f;\n                        matrices.multiply(RotationAxis.POSITIVE_Y.rotation(yaw), 0.5f, 0f, 0.5f);\n                    }\n                }\n            }\n\n            var sherds = pot.getSherds();\n            EBEUtil.renderBakedModel(vertexConsumers, blockEntity.getCachedState(), matrices, this.baseModel, light, overlay);\n\n            EBEUtil.renderBakedModel(vertexConsumers, blockEntity.getCachedState(), matrices,\n                    this.potPatternModels.get(\n                            sherds.back().map(DecoratedPotPatterns::fromSherd).orElse(DecoratedPotPatterns.BLANK)\n                    )[0], light, overlay);\n            EBEUtil.renderBakedModel(vertexConsumers, blockEntity.getCachedState(), matrices,\n                    this.potPatternModels.get(\n                            sherds.left().map(DecoratedPotPatterns::fromSherd).orElse(DecoratedPotPatterns.BLANK)\n                    )[1], light, overlay);\n            EBEUtil.renderBakedModel(vertexConsumers, blockEntity.getCachedState(), matrices,\n                    this.potPatternModels.get(\n                            sherds.right().map(DecoratedPotPatterns::fromSherd).orElse(DecoratedPotPatterns.BLANK)\n                    )[2], light, overlay);\n            EBEUtil.renderBakedModel(vertexConsumers, blockEntity.getCachedState(), matrices,\n                    this.potPatternModels.get(\n                            sherds.front().map(DecoratedPotPatterns::fromSherd).orElse(DecoratedPotPatterns.BLANK)\n                    )[3], light, overlay);\n\n            matrices.pop();\n        }\n    }\n\n    @Override\n    public void onModelsReload() {\n        this.baseModel = null;\n        this.potPatternModels = null;\n    }\n}"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/render/entity/ShulkerBoxBlockEntityRendererOverride.java",
    "content": "package foundationgames.enhancedblockentities.client.render.entity;\n\nimport foundationgames.enhancedblockentities.client.render.BlockEntityRendererOverride;\nimport foundationgames.enhancedblockentities.util.EBEUtil;\nimport net.minecraft.block.BlockState;\nimport net.minecraft.block.ShulkerBoxBlock;\nimport net.minecraft.block.entity.BlockEntity;\nimport net.minecraft.block.entity.ShulkerBoxBlockEntity;\nimport net.minecraft.client.render.VertexConsumerProvider;\nimport net.minecraft.client.render.block.entity.BlockEntityRenderer;\nimport net.minecraft.client.render.model.BakedModel;\nimport net.minecraft.client.util.math.MatrixStack;\nimport net.minecraft.util.DyeColor;\nimport net.minecraft.util.math.Direction;\nimport net.minecraft.util.math.RotationAxis;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\npublic class ShulkerBoxBlockEntityRendererOverride extends BlockEntityRendererOverride {\n    private final Map<DyeColor, BakedModel> models = new HashMap<>();\n    private final Consumer<Map<DyeColor, BakedModel>> modelMapFiller;\n\n    public ShulkerBoxBlockEntityRendererOverride(Consumer<Map<DyeColor, BakedModel>> modelMapFiller) {\n        this.modelMapFiller = modelMapFiller;\n    }\n\n    @Override\n    public void render(BlockEntityRenderer<BlockEntity> renderer, BlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {\n        if (models.isEmpty()) modelMapFiller.accept(models);\n        if (blockEntity instanceof ShulkerBoxBlockEntity entity) {\n            Direction dir = Direction.UP;\n            BlockState state = entity.getWorld().getBlockState(entity.getPos());\n            if (state.getBlock() instanceof ShulkerBoxBlock) {\n                dir = state.get(ShulkerBoxBlock.FACING);\n            }\n            matrices.push();\n\n            float animation = entity.getAnimationProgress(tickDelta);\n\n            matrices.translate(0.5, 0.5, 0.5);\n            matrices.multiply(dir.getRotationQuaternion());\n            matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(270 * animation));\n            matrices.translate(-0.5, -0.5, -0.5);\n\n            matrices.translate(0, animation * 0.5f, 0);\n\n            var lidModel = models.get(entity.getColor());\n            if (lidModel != null) {\n                EBEUtil.renderBakedModel(vertexConsumers, blockEntity.getCachedState(), matrices, lidModel, light, overlay);\n            }\n\n            matrices.pop();\n        }\n    }\n\n    @Override\n    public void onModelsReload() {\n        this.models.clear();\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/render/entity/SignBlockEntityRendererOverride.java",
    "content": "package foundationgames.enhancedblockentities.client.render.entity;\n\nimport foundationgames.enhancedblockentities.client.render.BlockEntityRendererOverride;\nimport foundationgames.enhancedblockentities.mixin.AbstractSignBlockEntityRenderAccessor;\nimport net.minecraft.block.AbstractSignBlock;\nimport net.minecraft.block.entity.BlockEntity;\nimport net.minecraft.block.entity.SignBlockEntity;\nimport net.minecraft.client.render.VertexConsumerProvider;\nimport net.minecraft.client.render.block.entity.BlockEntityRenderer;\nimport net.minecraft.client.util.math.MatrixStack;\n\npublic class SignBlockEntityRendererOverride extends BlockEntityRendererOverride {\n    public SignBlockEntityRendererOverride() {}\n\n    @Override\n    public void render(BlockEntityRenderer<BlockEntity> renderer, BlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {\n        if (blockEntity instanceof SignBlockEntity entity) {\n            var state = entity.getCachedState();\n            AbstractSignBlock block = (AbstractSignBlock) state.getBlock();\n            var sign = (AbstractSignBlockEntityRenderAccessor) renderer;\n            sign.enhanced_bes$applyTransforms(matrices, -block.getRotationDegrees(state), state);\n            sign.enhanced_bes$renderText(entity.getPos(), entity.getFrontText(), matrices, vertexConsumers, light, entity.getTextLineHeight(), entity.getMaxTextWidth(), true);\n            sign.enhanced_bes$renderText(entity.getPos(), entity.getBackText(), matrices, vertexConsumers, light, entity.getTextLineHeight(), entity.getMaxTextWidth(), false);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/resource/AtlasResourceBuilder.java",
    "content": "package foundationgames.enhancedblockentities.client.resource;\n\nimport com.google.gson.Gson;\nimport com.google.gson.JsonObject;\nimport com.mojang.serialization.JsonOps;\nimport net.minecraft.client.texture.atlas.AtlasSource;\nimport net.minecraft.client.texture.atlas.AtlasSourceManager;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class AtlasResourceBuilder {\n    private static final Gson GSON = new Gson();\n    private final List<AtlasSource> sources = new ArrayList<>();\n\n    public void put(AtlasSource source) {\n        sources.add(source);\n    }\n\n    public byte[] toBytes() {\n        return GSON.toJson(AtlasSourceManager.LIST_CODEC.encode(this.sources, JsonOps.INSTANCE, new JsonObject())\n                .getOrThrow())\n                .getBytes(StandardCharsets.UTF_8);\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/resource/EBEPack.java",
    "content": "package foundationgames.enhancedblockentities.client.resource;\n\nimport foundationgames.enhancedblockentities.client.resource.template.TemplateLoader;\nimport foundationgames.enhancedblockentities.client.resource.template.TemplateProvider;\nimport net.minecraft.SharedConstants;\nimport net.minecraft.client.texture.atlas.AtlasSource;\nimport net.minecraft.client.texture.atlas.DirectoryAtlasSource;\nimport net.minecraft.client.texture.atlas.SingleAtlasSource;\nimport net.minecraft.resource.InputSupplier;\nimport net.minecraft.resource.ResourcePack;\nimport net.minecraft.resource.ResourcePackInfo;\nimport net.minecraft.resource.ResourcePackSource;\nimport net.minecraft.resource.ResourceType;\nimport net.minecraft.resource.metadata.PackResourceMetadata;\nimport net.minecraft.resource.metadata.ResourceMetadataMap;\nimport net.minecraft.resource.metadata.ResourceMetadataSerializer;\nimport net.minecraft.text.Text;\nimport net.minecraft.util.Identifier;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Properties;\nimport java.util.Set;\n\npublic class EBEPack implements ResourcePack {\n    public static final Identifier BLOCK_ATLAS = Identifier.of(\"blocks\");\n\n    private final Map<Identifier, AtlasResourceBuilder> atlases = new HashMap<>();\n    private final Map<Identifier, InputSupplier<InputStream>> resources = new HashMap<>();\n    private final Set<String> namespaces = new HashSet<>();\n\n    private final TemplateLoader templates;\n\n    private final PackResourceMetadata packMeta;\n    private final ResourcePackInfo packInfo;\n\n    public EBEPack(Identifier id, TemplateLoader templates) {\n        this.templates = templates;\n\n        this.packMeta = new PackResourceMetadata(\n                Text.literal(\"Enhanced Block Entities Resources\"),\n                SharedConstants.getGameVersion().getResourceVersion(ResourceType.CLIENT_RESOURCES),\n                Optional.empty());\n\n        this.packInfo = new ResourcePackInfo(id.toString(), Text.literal(id.toString()), ResourcePackSource.BUILTIN, Optional.empty());\n    }\n\n    public void addAtlasSprite(Identifier atlas, AtlasSource source) {\n        var resource = this.atlases.computeIfAbsent(atlas, id -> new AtlasResourceBuilder());\n        resource.put(source);\n\n        this.addResource(Identifier.of(atlas.getNamespace(), \"atlases/\" + atlas.getPath() + \".json\"), resource::toBytes);\n    }\n\n    public void addSingleBlockSprite(Identifier path) {\n        this.addAtlasSprite(BLOCK_ATLAS, new SingleAtlasSource(path, Optional.empty()));\n    }\n\n    public void addDirBlockSprites(String dir, String prefix) {\n        this.addAtlasSprite(BLOCK_ATLAS, new DirectoryAtlasSource(dir, prefix));\n    }\n\n    public void addResource(Identifier id, InputSupplier<byte[]> resource) {\n        this.namespaces.add(id.getNamespace());\n        this.resources.put(id, new LazyBufferedResource(resource));\n    }\n\n    public void addResource(Identifier id, byte[] resource) {\n        this.namespaces.add(id.getNamespace());\n        this.resources.put(id, () -> new ByteArrayInputStream(resource));\n    }\n\n    public void addPlainTextResource(Identifier id, String plainText) {\n        this.addResource(id, plainText.getBytes(StandardCharsets.UTF_8));\n    }\n\n    public void addTemplateResource(Identifier id, TemplateProvider.TemplateApplyingFunction template) {\n        this.addResource(id, () -> template.getAndApplyTemplate(new TemplateProvider(this.templates)).getBytes(StandardCharsets.UTF_8));\n    }\n\n    public void addTemplateResource(Identifier id, String templatePath) {\n        this.addTemplateResource(id, t -> t.load(templatePath, d -> {}));\n    }\n\n    @Nullable\n    @Override\n    public InputSupplier<InputStream> openRoot(String... segments) {\n        return null; // Provide no root resources\n    }\n\n    @Nullable\n    @Override\n    public InputSupplier<InputStream> open(ResourceType type, Identifier id) {\n        if (type != ResourceType.CLIENT_RESOURCES) return null;\n\n        return this.resources.get(id);\n    }\n\n    @Override\n    public void findResources(ResourceType type, String namespace, String prefix, ResultConsumer consumer) {\n        if (type != ResourceType.CLIENT_RESOURCES) return;\n\n        for (var entry : this.resources.entrySet()) {\n            var id = entry.getKey();\n\n            if (id.getNamespace().startsWith(namespace) && id.getPath().startsWith(prefix)) {\n                consumer.accept(id, entry.getValue());\n            }\n        }\n    }\n\n    @Override\n    public Set<String> getNamespaces(ResourceType type) {\n        if (type != ResourceType.CLIENT_RESOURCES) return Set.of();\n\n        return this.namespaces;\n    }\n\n    @Nullable\n    @Override\n    public <T> T parseMetadata(ResourceMetadataSerializer<T> meta) {\n        return ResourceMetadataMap.of(PackResourceMetadata.SERIALIZER, this.packMeta).get(meta);\n    }\n\n    @Override\n    public ResourcePackInfo getInfo() {\n        return this.packInfo;\n    }\n\n    @Override\n    public void close() {\n    }\n\n    public void dump(Path dir) throws IOException {\n        dir = dir.resolve(\"assets\");\n\n        for (var entry : this.resources.entrySet()) {\n            var id = entry.getKey();\n            var file = dir.resolve(id.getNamespace()).resolve(id.getPath());\n\n            Files.createDirectories(file.getParent());\n\n            try (var out = Files.newOutputStream(file)) {\n                var in = entry.getValue().get();\n\n                int i;\n                while ((i = in.read()) >= 0) {\n                    out.write(i);\n                }\n            }\n        }\n    }\n\n    public static class PropertyBuilder {\n        private Properties properties = new Properties();\n\n        private PropertyBuilder() {}\n\n        public PropertyBuilder def(String k, String v) {\n            if (this.properties != null) {\n                this.properties.setProperty(k, v);\n            }\n\n            return this;\n        }\n\n        private Properties build() {\n            var properties = this.properties;\n            this.properties = null;\n\n            return properties;\n        }\n    }\n\n    public static class LazyBufferedResource implements InputSupplier<InputStream> {\n        private final InputSupplier<byte[]> backing;\n        private byte[] buffer = null;\n\n        public LazyBufferedResource(InputSupplier<byte[]> backing) {\n            this.backing = backing;\n        }\n\n        @Override\n        public InputStream get() throws IOException {\n            if (buffer == null) {\n                buffer = backing.get();\n            }\n\n            return new ByteArrayInputStream(buffer);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/resource/template/TemplateDefinitions.java",
    "content": "package foundationgames.enhancedblockentities.client.resource.template;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.ArrayDeque;\nimport java.util.Deque;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\n\npublic interface TemplateDefinitions {\n    default TemplateDefinitions def(String k, Object v) {\n        return this.def(k, templates -> String.valueOf(v));\n    }\n\n    TemplateDefinitions def(String k, TemplateProvider.TemplateApplyingFunction v);\n\n    class Impl implements TemplateDefinitions, Iterable<Map.Entry<String, TemplateProvider.TemplateApplyingFunction>> {\n        private final Deque<HashMap<String, TemplateProvider.TemplateApplyingFunction>> stack = new ArrayDeque<>();\n\n        public void push() {\n            this.stack.addLast(new HashMap<>());\n        }\n\n        public void pop() {\n            this.stack.removeLast();\n        }\n\n        public TemplateDefinitions def(String k, String v) {\n            return this.def(k, templates -> v);\n        }\n\n        public TemplateDefinitions def(String k, TemplateProvider.TemplateApplyingFunction v) {\n            this.stack.getLast().put(k, v);\n\n            return this;\n        }\n\n        @NotNull\n        @Override\n        public Iterator<Map.Entry<String, TemplateProvider.TemplateApplyingFunction>> iterator() {\n            return this.stack.getLast().entrySet().iterator();\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/resource/template/TemplateLoader.java",
    "content": "package foundationgames.enhancedblockentities.client.resource.template;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class TemplateLoader {\n    private Path rootPath;\n\n    private final Map<String, String> loadedTemplates = new HashMap<>();\n\n    public TemplateLoader() {\n    }\n\n    public void setRoot(Path path) {\n        this.rootPath = path;\n    }\n\n    public String getOrLoadRaw(String path) throws IOException {\n        if (this.rootPath == null) {\n            return \"\";\n        }\n\n        if (this.loadedTemplates.containsKey(path)) {\n            return this.loadedTemplates.get(path);\n        }\n\n        var file = rootPath.resolve(path);\n        try (var in = Files.newInputStream(file)) {\n            var templateRaw = new String(in.readAllBytes(), StandardCharsets.UTF_8);\n            this.loadedTemplates.put(path, templateRaw);\n\n            return templateRaw;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/client/resource/template/TemplateProvider.java",
    "content": "package foundationgames.enhancedblockentities.client.resource.template;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.function.Consumer;\nimport java.util.regex.Pattern;\n\npublic class TemplateProvider {\n    private final TemplateLoader loader;\n    private final TemplateDefinitions.Impl definitions = new TemplateDefinitions.Impl();\n\n    public TemplateProvider(TemplateLoader loader) {\n        this.loader = loader;\n    }\n\n    public String load(String templatePath, Consumer<TemplateDefinitions> definitions) throws IOException {\n        this.definitions.push();\n        definitions.accept(this.definitions);\n\n        try {\n            var substitutions = new HashMap<String, String>();\n            for (var entry : this.definitions) {\n                substitutions.put(entry.getKey(), entry.getValue().getAndApplyTemplate(this));\n            }\n\n            var templateRaw = this.loader.getOrLoadRaw(templatePath);\n            var matcher = Pattern.compile(\"!\\\\[(\" + String.join(\"|\", substitutions.keySet()) + \")]\")\n                    .matcher(templateRaw);\n\n            var result = new StringBuilder();\n            while (matcher.find()) {\n                matcher.appendReplacement(result, substitutions.get(matcher.group(1)));\n            }\n            matcher.appendTail(result);\n\n            this.definitions.pop();\n            return result.toString();\n        } catch (IOException ex) {\n            this.definitions.pop();\n            throw ex;\n        }\n    }\n\n    @FunctionalInterface\n    public interface TemplateApplyingFunction {\n        String getAndApplyTemplate(TemplateProvider templates) throws IOException;\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/config/EBEConfig.java",
    "content": "package foundationgames.enhancedblockentities.config;\n\nimport foundationgames.enhancedblockentities.EnhancedBlockEntities;\nimport foundationgames.enhancedblockentities.util.ConvUtil;\nimport net.fabricmc.loader.api.FabricLoader;\nimport net.fabricmc.loader.api.ModContainer;\nimport net.minecraft.text.Text;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.function.BiConsumer;\n\npublic class EBEConfig {\n    public static final String RENDER_ENHANCED_CHESTS_KEY = \"render_enhanced_chests\";\n    public static final String RENDER_ENHANCED_SIGNS_KEY = \"render_enhanced_signs\";\n    public static final String RENDER_ENHANCED_BELLS_KEY = \"render_enhanced_bells\";\n    public static final String RENDER_ENHANCED_BEDS_KEY = \"render_enhanced_beds\";\n    public static final String RENDER_ENHANCED_SHULKER_BOXES_KEY = \"render_enhanced_shulker_boxes\";\n    public static final String RENDER_ENHANCED_DECORATED_POTS_KEY = \"render_enhanced_decorated_pots\";\n    public static final String CHEST_AO_KEY = \"chest_ao\";\n    public static final String SIGN_AO_KEY = \"sign_ao\";\n    public static final String BELL_AO_KEY = \"bell_ao\";\n    public static final String BED_AO_KEY = \"bed_ao\";\n    public static final String SHULKER_BOX_AO_KEY = \"shulker_box_ao\";\n    public static final String DECORATED_POT_AO_KEY = \"decorated_pot_ao\";\n    public static final String CHRISTMAS_CHESTS_KEY = \"christmas_chests\";\n    public static final String SIGN_TEXT_RENDERING_KEY = \"sign_text_rendering\";\n    public static final String EXPERIMENTAL_CHESTS_KEY = \"experimental_chests\";\n    public static final String EXPERIMENTAL_BEDS_KEY = \"experimental_beds\";\n    public static final String EXPERIMENTAL_SIGNS_KEY = \"experimental_signs\";\n    public static final String FORCE_RESOURCE_PACK_COMPAT_KEY = \"force_resource_pack_compat\";\n\n    public boolean renderEnhancedChests = true;\n    public boolean renderEnhancedSigns = true;\n    public boolean renderEnhancedBells = true;\n    public boolean renderEnhancedBeds = true;\n    public boolean renderEnhancedShulkerBoxes = true;\n    public boolean renderEnhancedDecoratedPots = true;\n    public boolean chestAO = false;\n    public boolean signAO = false;\n    public boolean bellAO = true;\n    public boolean bedAO = false;\n    public boolean shulkerBoxAO = false;\n    public boolean decoratedPotAO = false;\n    public String christmasChests = \"allowed\";\n    public String signTextRendering = \"smart\";\n    public boolean experimentalChests = true;\n    public boolean experimentalBeds = true;\n    public boolean experimentalSigns = true;\n    public boolean forceResourcePackCompat = false;\n\n    public final Map<String, Override> overrides = new HashMap<>();\n\n    public void writeTo(Properties properties) {\n        properties.setProperty(RENDER_ENHANCED_CHESTS_KEY, Boolean.toString(renderEnhancedChests));\n        properties.setProperty(RENDER_ENHANCED_SIGNS_KEY, Boolean.toString(renderEnhancedSigns));\n        properties.setProperty(RENDER_ENHANCED_BELLS_KEY, Boolean.toString(renderEnhancedBells));\n        properties.setProperty(RENDER_ENHANCED_BEDS_KEY, Boolean.toString(renderEnhancedBeds));\n        properties.setProperty(RENDER_ENHANCED_SHULKER_BOXES_KEY, Boolean.toString(renderEnhancedShulkerBoxes));\n        properties.setProperty(RENDER_ENHANCED_DECORATED_POTS_KEY, Boolean.toString(renderEnhancedDecoratedPots));\n        properties.setProperty(CHEST_AO_KEY, Boolean.toString(chestAO));\n        properties.setProperty(SIGN_AO_KEY, Boolean.toString(signAO));\n        properties.setProperty(BELL_AO_KEY, Boolean.toString(bellAO));\n        properties.setProperty(BED_AO_KEY, Boolean.toString(bedAO));\n        properties.setProperty(SHULKER_BOX_AO_KEY, Boolean.toString(shulkerBoxAO));\n        properties.setProperty(DECORATED_POT_AO_KEY, Boolean.toString(decoratedPotAO));\n        properties.setProperty(CHRISTMAS_CHESTS_KEY, christmasChests);\n        properties.setProperty(SIGN_TEXT_RENDERING_KEY, signTextRendering);\n        properties.setProperty(EXPERIMENTAL_CHESTS_KEY, Boolean.toString(experimentalChests));\n        properties.setProperty(EXPERIMENTAL_BEDS_KEY, Boolean.toString(experimentalBeds));\n        properties.setProperty(EXPERIMENTAL_SIGNS_KEY, Boolean.toString(experimentalSigns));\n        properties.setProperty(FORCE_RESOURCE_PACK_COMPAT_KEY, Boolean.toString(forceResourcePackCompat));\n    }\n\n    public void readFrom(Properties properties) {\n        this.renderEnhancedChests = ConvUtil.defaultedBool(properties.getProperty(RENDER_ENHANCED_CHESTS_KEY), true);\n        this.renderEnhancedSigns = ConvUtil.defaultedBool(properties.getProperty(RENDER_ENHANCED_SIGNS_KEY), true);\n        this.renderEnhancedBells = ConvUtil.defaultedBool(properties.getProperty(RENDER_ENHANCED_BELLS_KEY), true);\n        this.renderEnhancedBeds = ConvUtil.defaultedBool(properties.getProperty(RENDER_ENHANCED_BEDS_KEY), true);\n        this.renderEnhancedShulkerBoxes = ConvUtil.defaultedBool(properties.getProperty(RENDER_ENHANCED_SHULKER_BOXES_KEY), true);\n        this.renderEnhancedDecoratedPots = ConvUtil.defaultedBool(properties.getProperty(RENDER_ENHANCED_DECORATED_POTS_KEY), true);\n        String pCC = properties.getProperty(CHRISTMAS_CHESTS_KEY);\n        if (pCC != null && (pCC.equals(\"allowed\") || pCC.equals(\"forced\") || pCC.equals(\"disabled\"))) {\n            this.christmasChests = pCC;\n        } else {\n            EnhancedBlockEntities.LOG.warn(\"Configuration option 'christmas_chests' must be one of: 'allowed', 'forced', 'disabled'\");\n            this.christmasChests = \"allowed\";\n        }\n        String sST = properties.getProperty(SIGN_TEXT_RENDERING_KEY);\n        if (sST != null && (sST.equals(\"smart\") || sST.equals(\"all\") || sST.equals(\"most\") || sST.equals(\"some\") || sST.equals(\"few\"))) {\n            this.signTextRendering = sST;\n        } else {\n            EnhancedBlockEntities.LOG.warn(\"Configuration option 'sign_text_rendering' must be one of: 'smart', 'all', 'most', 'some', 'few'\");\n            this.signTextRendering = \"smart\";\n        }\n        this.chestAO = ConvUtil.defaultedBool(properties.getProperty(CHEST_AO_KEY), false);\n        this.signAO = ConvUtil.defaultedBool(properties.getProperty(SIGN_AO_KEY), false);\n        this.bellAO = ConvUtil.defaultedBool(properties.getProperty(BELL_AO_KEY), true);\n        this.bedAO = ConvUtil.defaultedBool(properties.getProperty(BED_AO_KEY), false);\n        this.shulkerBoxAO = ConvUtil.defaultedBool(properties.getProperty(SHULKER_BOX_AO_KEY), false);\n        this.decoratedPotAO = ConvUtil.defaultedBool(properties.getProperty(DECORATED_POT_AO_KEY), false);\n        this.experimentalChests = ConvUtil.defaultedBool(properties.getProperty(EXPERIMENTAL_CHESTS_KEY), true);\n        this.experimentalBeds = ConvUtil.defaultedBool(properties.getProperty(EXPERIMENTAL_BEDS_KEY), true);\n        this.experimentalSigns = ConvUtil.defaultedBool(properties.getProperty(EXPERIMENTAL_SIGNS_KEY), true);\n        this.forceResourcePackCompat = ConvUtil.defaultedBool(properties.getProperty(FORCE_RESOURCE_PACK_COMPAT_KEY), false);\n    }\n\n    public void save() {\n        Properties properties = new Properties();\n        writeTo(properties);\n        Path configPath = FabricLoader.getInstance().getConfigDir().resolve(\"enhanced_bes.properties\");\n        if (!Files.exists(configPath)) {\n            try {\n                Files.createFile(configPath);\n            } catch (IOException e) {\n                EnhancedBlockEntities.LOG.error(\"Failed to create configuration file!\", e);\n                return;\n            }\n        }\n        try {\n            properties.store(Files.newOutputStream(configPath), \"Configuration file for Enhanced Block Entities\");\n        } catch (IOException e) {\n            EnhancedBlockEntities.LOG.error(\"Failed to write to configuration file!\", e);\n        }\n    }\n\n    public void load() {\n        Properties properties = new Properties();\n        Path configPath = FabricLoader.getInstance().getConfigDir().resolve(\"enhanced_bes.properties\");\n        if (!Files.exists(configPath)) {\n            try {\n                Files.createFile(configPath);\n                save();\n            } catch (IOException e) {\n                EnhancedBlockEntities.LOG.error(\"Failed to create configuration file!\", e);\n                return;\n            }\n        }\n        try {\n            properties.load(Files.newInputStream(configPath));\n        } catch (IOException e) {\n            EnhancedBlockEntities.LOG.error(\"Failed to read configuration file!\", e);\n            return;\n        }\n\n        applyCompatConfigModifiers(properties);\n\n        readFrom(properties);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private void applyCompatConfigModifiers(Properties properties) {\n        this.overrides.clear();\n\n        var ebeCompatCfgModifiers = FabricLoader.getInstance()\n                .getEntrypointContainers(EnhancedBlockEntities.API_V1, BiConsumer.class);\n        for (var modifier : ebeCompatCfgModifiers) {\n            var mod = modifier.getProvider();\n            var overrides = new Properties();\n            var reasons = new HashMap<String, Text>();\n            modifier.getEntrypoint().accept(overrides, reasons);\n\n            for (var key : overrides.stringPropertyNames()) {\n                @Nullable Text reason = reasons.get(key);\n                this.overrides.put(key, new Override(mod, reason));\n            }\n\n            properties.putAll(overrides);\n        }\n    }\n\n    public record Override(ModContainer modResponsible, @Nullable Text reason) {}\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/config/gui/EBEModMenuPlugin.java",
    "content": "package foundationgames.enhancedblockentities.config.gui;\n\nimport com.terraformersmc.modmenu.api.ConfigScreenFactory;\nimport com.terraformersmc.modmenu.api.ModMenuApi;\nimport foundationgames.enhancedblockentities.config.gui.screen.EBEConfigScreen;\n\npublic class EBEModMenuPlugin implements ModMenuApi {\n    @Override\n    public ConfigScreenFactory<?> getModConfigScreenFactory() {\n        return EBEConfigScreen::new;\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/config/gui/option/ConfigButtonOption.java",
    "content": "package foundationgames.enhancedblockentities.config.gui.option;\n\nimport com.mojang.serialization.Codec;\nimport foundationgames.enhancedblockentities.config.gui.screen.EBEConfigScreen;\nimport net.minecraft.client.MinecraftClient;\nimport net.minecraft.client.gui.screen.Screen;\nimport net.minecraft.client.gui.widget.ButtonWidget;\nimport net.minecraft.client.gui.widget.ClickableWidget;\nimport net.minecraft.client.option.GameOptions;\nimport net.minecraft.client.option.SimpleOption;\nimport net.minecraft.text.Text;\n\nimport java.util.Optional;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\npublic class ConfigButtonOption {\n    public static SimpleOption<?> getOption(Screen parent) {\n        return new SimpleOption<>(\n            \"option.ebe.config\",\n            SimpleOption.emptyTooltip(),\n            (title, object) -> title,\n            new ConfigButtonCallbacks<>(parent),\n            Optional.empty(),\n            value -> {\n            }\n        );\n    }\n\n    private record ConfigButtonCallbacks<T>(Screen parent) implements SimpleOption.Callbacks<T> {\n        @Override\n        public Function<SimpleOption<T>, ClickableWidget> getWidgetCreator(SimpleOption.TooltipFactory<T> tooltipFactory, GameOptions gameOptions, int x, int y, int width, Consumer<T> changed) {\n            return (option) -> ButtonWidget.builder(Text.translatable(\"option.ebe.config\"), b -> {\n                MinecraftClient.getInstance().setScreen(new EBEConfigScreen(parent));\n            }).dimensions(x, y, width, 20).build();\n        }\n\n        @Override\n        public Optional<T> validate(T value) {\n            return Optional.empty();\n        }\n\n        @Override\n        public Codec<T> codec() {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/config/gui/option/EBEOption.java",
    "content": "package foundationgames.enhancedblockentities.config.gui.option;\n\nimport foundationgames.enhancedblockentities.ReloadType;\nimport foundationgames.enhancedblockentities.config.EBEConfig;\nimport foundationgames.enhancedblockentities.util.GuiUtil;\nimport net.minecraft.client.gui.tooltip.Tooltip;\nimport net.minecraft.client.resource.language.I18n;\nimport net.minecraft.text.Text;\nimport net.minecraft.util.Formatting;\nimport net.minecraft.util.math.MathHelper;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\npublic final class EBEOption {\n    private static final Text NEWLINE = Text.of(\"\\n\");\n    private static final String OPTION_VALUE = \"options.generic_value\";\n    private static final String DIVIDER = \"text.ebe.option_value_division\";\n    private static final String OVERRIDDEN = \"warning.ebe.overridden\";\n\n    public final String key;\n    public final boolean hasValueComments;\n    public final Text comment;\n    public final ReloadType reloadType;\n    public final TextPalette palette;\n    public final @Nullable EBEConfig.Override override;\n\n    private final List<String> values;\n    private final int defaultValue;\n\n    private int selected;\n    private Tooltip tooltip = null;\n    private Text text = null;\n\n    public EBEOption(String key, List<String> values, ConfigView config, boolean hasValueComments, TextPalette palette, ReloadType reloadType) {\n        this.key = key;\n        this.values = values;\n        this.defaultValue = MathHelper.clamp(values.indexOf(config.configValues.getProperty(key)), 0, values.size());\n        this.override = config.overrides.get(key);\n        this.selected = this.defaultValue;\n        this.hasValueComments = hasValueComments;\n        this.palette = palette;\n        this.reloadType = reloadType;\n\n        String commentKey = I18n.translate(String.format(\"option.ebe.%s.comment\", key));\n        comment = GuiUtil.shorten(commentKey, 20);\n    }\n\n    public String getValue() {\n        return values.get(selected);\n    }\n\n    public String getOptionKey() {\n        return String.format(\"option.ebe.%s\", key);\n    }\n\n    public String getValueKey() {\n        return String.format(\"value.ebe.%s\", getValue());\n    }\n\n    public Text getText() {\n        var option = Text.translatable(this.getOptionKey()).styled(style -> style.withColor(isDefault() ? 0xFFFFFF : 0xFFDA5E));\n        var value = Text.translatable(this.getValueKey()).styled(style -> style.withColor(this.palette.getColor((float)this.selected / this.values.size())));\n\n        if (text == null) text = option.append(Text.translatable(DIVIDER).append(value));\n        return text;\n    }\n\n    public Tooltip getTooltip() {\n        if (tooltip == null) {\n            if (override != null) {\n                var text = Text.translatable(OVERRIDDEN, override.modResponsible().getMetadata().getId())\n                        .formatted(Formatting.RED, Formatting.UNDERLINE);\n                if (override.reason() != null) {\n                    text.append(NEWLINE).append(override.reason());\n                }\n\n                tooltip = Tooltip.of(text);\n            }\n            else if (hasValueComments) tooltip = Tooltip.of(Text.translatable(String.format(\"option.ebe.%s.valueComment.%s\", key, getValue())).append(NEWLINE).append(comment.copyContentOnly()));\n            else tooltip = Tooltip.of(comment.copyContentOnly());\n        }\n        return tooltip;\n    }\n\n    public void next() {\n        selected++;\n        if (selected >= values.size()) selected = 0;\n        tooltip = null;\n        text = null;\n    }\n\n    public boolean isDefault() {\n        return selected == defaultValue;\n    }\n\n    public record ConfigView(Properties configValues, Map<String, EBEConfig.Override> overrides) {}\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/config/gui/option/TextPalette.java",
    "content": "package foundationgames.enhancedblockentities.config.gui.option;\n\npublic interface TextPalette {\n    TextPalette ON_OFF = opt -> (opt < 0.5f) ? 0x74ff45 : 0xff6745;\n\n    /**\n     * Return a color based on the amount the option has been cycled through\n     *\n     * @param cycle a value 0-1 representing the progress cycling this palette\n     * @return a RGB color integer\n     */\n    int getColor(float cycle);\n\n    static TextPalette rainbow(float start) {\n        return opt -> {\n            opt += start;\n\n            float r = 0.5f * (float)Math.cos(2 * Math.PI * opt) + 0.5f;\n            float g = 0.5f * (float)Math.cos(2 * Math.PI * (opt - 0.333333333f)) + 0.5f;\n            float b = 0.5f * (float)Math.cos(2 * Math.PI * (opt - 0.666666666f)) + 0.5f;\n\n            return ((int)(r * 255) << 16) | ((int)(g * 255) << 8) | (int)(b * 255);\n        };\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/config/gui/screen/EBEConfigScreen.java",
    "content": "package foundationgames.enhancedblockentities.config.gui.screen;\n\nimport com.google.common.collect.ImmutableList;\nimport foundationgames.enhancedblockentities.EnhancedBlockEntities;\nimport foundationgames.enhancedblockentities.ReloadType;\nimport foundationgames.enhancedblockentities.config.EBEConfig;\nimport foundationgames.enhancedblockentities.config.gui.option.EBEOption;\nimport foundationgames.enhancedblockentities.config.gui.option.TextPalette;\nimport foundationgames.enhancedblockentities.config.gui.widget.SectionTextWidget;\nimport foundationgames.enhancedblockentities.config.gui.widget.WidgetRowListWidget;\nimport foundationgames.enhancedblockentities.util.EBEUtil;\nimport foundationgames.enhancedblockentities.util.GuiUtil;\nimport net.minecraft.client.gui.DrawContext;\nimport net.minecraft.client.gui.screen.Screen;\nimport net.minecraft.client.gui.tooltip.Tooltip;\nimport net.minecraft.client.gui.widget.ButtonWidget;\nimport net.minecraft.client.gui.widget.GridWidget;\nimport net.minecraft.client.resource.language.I18n;\nimport net.minecraft.screen.ScreenTexts;\nimport net.minecraft.text.Text;\nimport net.minecraft.util.Formatting;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.concurrent.atomic.AtomicReference;\n\npublic class EBEConfigScreen extends Screen {\n    private WidgetRowListWidget optionsWidget;\n    private final List<EBEOption> options = new ArrayList<>();\n    private final Screen parent;\n\n    private static final ImmutableList<String> BOOLEAN_OPTIONS = ImmutableList.of(\"true\", \"false\");\n    private static final ImmutableList<String> ALLOWED_FORCED_DISABLED = ImmutableList.of(\"allowed\", \"forced\", \"disabled\");\n    private static final ImmutableList<String> SIGN_TEXT_OPTIONS = ImmutableList.of(\"smart\", \"all\", \"most\", \"some\", \"few\");\n\n    private static final Text HOLD_SHIFT = Text.translatable(\"text.ebe.descriptions\").formatted(Formatting.GRAY, Formatting.ITALIC);\n    private static final Text CHEST_OPTIONS_TITLE = Text.translatable(\"text.ebe.chest_options\");\n    private static final Text SIGN_OPTIONS_TITLE = Text.translatable(\"text.ebe.sign_options\");\n    private static final Text BELL_OPTIONS_TITLE = Text.translatable(\"text.ebe.bell_options\");\n    private static final Text BED_OPTIONS_TITLE = Text.translatable(\"text.ebe.bed_options\");\n    private static final Text SHULKER_BOX_OPTIONS_TITLE = Text.translatable(\"text.ebe.shulker_box_options\");\n    private static final Text DECORATED_POT_OPTIONS_TITLE = Text.translatable(\"text.ebe.decorated_pot_options\");\n    private static final Text ADVANCED_TITLE = Text.translatable(\"text.ebe.advanced\");\n\n    private static final Text DUMP_LABEL = Text.translatable(\"option.ebe.dump\");\n\n    private final Text dumpTooltip = GuiUtil.shorten(I18n.translate(\"option.ebe.dump.comment\"), 20);\n\n    public EBEConfigScreen(Screen screen) {\n        super(Text.translatable(\"screen.ebe.config\"));\n        parent = screen;\n    }\n\n    @Override\n    protected void init() {\n        super.init();\n\n        this.optionsWidget = new WidgetRowListWidget(this.client, this.width, this.height - 69, 34, 316, 20);\n        this.options.clear();\n\n        addOptions();\n        this.addDrawableChild(optionsWidget);\n\n        var menuButtons = new GridWidget();\n        menuButtons.setColumnSpacing(4);\n\n        var menuButtonAdder = menuButtons.createAdder(3);\n\n        menuButtonAdder.add(ButtonWidget.builder(ScreenTexts.CANCEL, button -> this.close())\n                .size(100, 20).build());\n        menuButtonAdder.add(ButtonWidget.builder(Text.translatable(\"text.ebe.apply\"), button -> this.applyChanges())\n                .size(100, 20).build());\n        menuButtonAdder.add(ButtonWidget.builder(ScreenTexts.DONE,\n                button -> {\n                    applyChanges();\n                    close();\n                })\n                .size(100, 20).build());\n\n        menuButtons.refreshPositions();\n        menuButtons.setPosition((this.width - menuButtons.getWidth()) / 2, this.height - 27);\n        menuButtons.forEachChild((child) -> {\n            child.setNavigationOrder(1);\n            this.addDrawableChild(child);\n        });\n    }\n\n    @Override\n    protected void renderDarkening(DrawContext context) {\n        renderDarkening(context, 0, 0, this.width, 34);\n        renderDarkening(context, 0, this.height - 35, this.width, 35);\n    }\n\n    @Override\n    public void render(DrawContext context, int mouseX, int mouseY, float delta) {\n        super.render(context, mouseX, mouseY, delta);\n\n        context.drawCenteredTextWithShadow(this.textRenderer, this.title, (int)(this.width * 0.5), 8, 0xFFFFFF);\n        context.drawCenteredTextWithShadow(this.textRenderer, HOLD_SHIFT, (int)(this.width * 0.5), 21, 0xFFFFFF);\n    }\n\n    @Override\n    public void close() {\n        this.client.setScreen(parent);\n    }\n\n    public void applyChanges() {\n        EBEConfig config = EnhancedBlockEntities.CONFIG;\n        Properties properties = new Properties();\n        AtomicReference<ReloadType> type = new AtomicReference<>(ReloadType.NONE);\n        options.forEach(option -> {\n            if (!option.isDefault()) {\n                type.set(type.get().or(option.reloadType));\n            }\n            properties.setProperty(option.key, option.getValue());\n        });\n        config.readFrom(properties);\n        config.save();\n        EnhancedBlockEntities.reload(type.get());\n    }\n\n    public void addOptions() {\n        Properties config = new Properties();\n        EnhancedBlockEntities.CONFIG.writeTo(config);\n\n        final var configView = new EBEOption.ConfigView(config, EnhancedBlockEntities.CONFIG.overrides);\n        final var textRenderer = this.client.textRenderer;\n\n        optionsWidget.add(new SectionTextWidget(CHEST_OPTIONS_TITLE, textRenderer));\n        optionsWidget.add(option(\n                new EBEOption(EBEConfig.RENDER_ENHANCED_CHESTS_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES)\n        ));\n        optionsWidget.add(option(\n                new EBEOption(EBEConfig.CHEST_AO_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES)\n        ));\n        optionsWidget.add(option(\n                new EBEOption(EBEConfig.EXPERIMENTAL_CHESTS_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES)\n        ), option(\n                new EBEOption(EBEConfig.CHRISTMAS_CHESTS_KEY, ALLOWED_FORCED_DISABLED, configView, true, TextPalette.rainbow(0.35f), ReloadType.WORLD)\n        ));\n\n        optionsWidget.add(new SectionTextWidget(SIGN_OPTIONS_TITLE, textRenderer));\n        optionsWidget.add(option(\n                new EBEOption(EBEConfig.RENDER_ENHANCED_SIGNS_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES)\n        ));\n        optionsWidget.add(option(\n                new EBEOption(EBEConfig.SIGN_TEXT_RENDERING_KEY, SIGN_TEXT_OPTIONS, configView, true, TextPalette.rainbow(0.45f), ReloadType.NONE)\n        ));\n        optionsWidget.add(option(\n                new EBEOption(EBEConfig.EXPERIMENTAL_SIGNS_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES)\n        ), option(\n                new EBEOption(EBEConfig.SIGN_AO_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES)\n        ));\n\n        optionsWidget.add(new SectionTextWidget(BELL_OPTIONS_TITLE, textRenderer));\n        optionsWidget.add(option(\n                new EBEOption(EBEConfig.RENDER_ENHANCED_BELLS_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES)\n        ));\n        optionsWidget.add(option(\n                new EBEOption(EBEConfig.BELL_AO_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES)\n        ));\n\n        optionsWidget.add(new SectionTextWidget(BED_OPTIONS_TITLE, textRenderer));\n        optionsWidget.add(option(\n                new EBEOption(EBEConfig.RENDER_ENHANCED_BEDS_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES)\n        ));\n        optionsWidget.add(option(\n                new EBEOption(EBEConfig.EXPERIMENTAL_BEDS_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES)\n        ), option(\n                new EBEOption(EBEConfig.BED_AO_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES)\n        ));\n\n        optionsWidget.add(new SectionTextWidget(SHULKER_BOX_OPTIONS_TITLE, textRenderer));\n        optionsWidget.add(option(\n                new EBEOption(EBEConfig.RENDER_ENHANCED_SHULKER_BOXES_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES)\n        ));\n        optionsWidget.add(option(\n                new EBEOption(EBEConfig.SHULKER_BOX_AO_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES)\n        ));\n\n        optionsWidget.add(new SectionTextWidget(DECORATED_POT_OPTIONS_TITLE, textRenderer));\n        optionsWidget.add(option(\n                new EBEOption(EBEConfig.RENDER_ENHANCED_DECORATED_POTS_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES)\n        ));\n        optionsWidget.add(option(\n                new EBEOption(EBEConfig.DECORATED_POT_AO_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES)\n        ));\n\n        optionsWidget.add(new SectionTextWidget(ADVANCED_TITLE, textRenderer));\n        optionsWidget.add(option(\n                new EBEOption(EBEConfig.FORCE_RESOURCE_PACK_COMPAT_KEY, BOOLEAN_OPTIONS, configView, false, TextPalette.ON_OFF, ReloadType.RESOURCES)\n        ));\n        optionsWidget.add(ButtonWidget.builder(DUMP_LABEL, b -> {\n            try {\n                EBEUtil.dumpResources();\n            } catch (IOException e) {\n                EnhancedBlockEntities.LOG.error(e);\n            }\n        }).tooltip(Tooltip.of(dumpTooltip)).build());\n    }\n\n    private ButtonWidget option(EBEOption option) {\n        options.add(option);\n\n        var button = ButtonWidget.builder(option.getText(), b -> {\n            option.next();\n            b.setMessage(option.getText());\n            b.setTooltip(option.getTooltip());\n        }).tooltip(option.getTooltip()).build();\n\n        if (option.override != null) {\n            button.active = false;\n        }\n\n        return button;\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/config/gui/widget/SectionTextWidget.java",
    "content": "package foundationgames.enhancedblockentities.config.gui.widget;\n\nimport net.minecraft.client.font.TextRenderer;\nimport net.minecraft.client.gui.DrawContext;\nimport net.minecraft.client.gui.widget.AbstractTextWidget;\nimport net.minecraft.text.Text;\n\npublic class SectionTextWidget extends AbstractTextWidget {\n    public SectionTextWidget(Text message, TextRenderer textRenderer) {\n        this(0, 0, 200, 20, message, textRenderer);\n    }\n\n    public SectionTextWidget(int x, int y, int width, int height, Text message, TextRenderer textRenderer) {\n        super(x, y, width, height, message, textRenderer);\n        this.active = false;\n    }\n\n    @Override\n    public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) {\n        final int white = 0xFFFFFFFF;\n        var font = this.getTextRenderer();\n        var msg = this.getMessage();\n\n        int l = this.getX();\n        int w = this.getWidth();\n        int r = l + w;\n        int y = (this.getY() + this.getHeight()) - 6;\n\n        int tx = l + (w / 2);\n        int ty = y - (font.fontHeight / 2);\n        int tw = font.getWidth(msg);\n\n        int ml = l + ((w - tw) / 2) - 5;\n        int mr = ml + tw + 10;\n\n        l += 1;\n        r -= 1;\n\n        context.fill(l, y, ml, y + 2, white);\n        context.fill(mr, y, r, y + 2, white);\n\n        context.drawCenteredTextWithShadow(font, msg, tx, ty, 0xFFFFFF);\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/config/gui/widget/WidgetRowListWidget.java",
    "content": "package foundationgames.enhancedblockentities.config.gui.widget;\n\nimport net.minecraft.client.MinecraftClient;\nimport net.minecraft.client.gui.DrawContext;\nimport net.minecraft.client.gui.Element;\nimport net.minecraft.client.gui.Selectable;\nimport net.minecraft.client.gui.widget.ClickableWidget;\nimport net.minecraft.client.gui.widget.ElementListWidget;\nimport net.minecraft.client.gui.widget.GridWidget;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class WidgetRowListWidget extends ElementListWidget<WidgetRowListWidget.Entry> {\n    public static final int SPACING = 3;\n\n    public final int rowWidth;\n    public final int rowHeight;\n\n    public WidgetRowListWidget(MinecraftClient mc, int w, int h, int y, int rowWidth, int rowHeight) {\n        super(mc, w, h, y, rowHeight + SPACING);\n        this.rowWidth = rowWidth;\n        this.rowHeight = rowHeight;\n    }\n\n    public void add(ClickableWidget ... widgets) {\n        if (widgets.length == 0) return;\n\n        var grid = new GridWidget();\n        grid.setColumnSpacing(SPACING);\n        var adder = grid.createAdder(widgets.length);\n\n        int width = (this.rowWidth - ((widgets.length - 1) * SPACING)) / widgets.length;\n\n        for (var widget : widgets) {\n            widget.setDimensions(width, this.rowHeight);\n            adder.add(widget);\n        }\n\n        grid.refreshPositions();\n\n        this.addEntry(new Entry(grid));\n    }\n\n    @Override\n    public int getRowWidth() {\n        return rowWidth;\n    }\n\n    @Override\n    protected int getScrollbarX() {\n        return this.width - 6;\n    }\n\n    @Override\n    protected void drawMenuListBackground(DrawContext context) {\n    }\n\n    public static class Entry extends ElementListWidget.Entry<Entry> {\n        private final GridWidget widget;\n        private final List<ClickableWidget> children = new ArrayList<>();\n\n        public Entry(GridWidget widget) {\n            this.widget = widget;\n            widget.forEachChild(children::add);\n        }\n\n        @Override\n        public List<? extends Element> children() {\n            return this.children;\n        }\n\n        @Override\n        public List<? extends Selectable> selectableChildren() {\n            return this.children;\n        }\n\n        @Override\n        public void render(DrawContext context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {\n            this.widget.setPosition(x - 3, y);\n            this.widget.refreshPositions();\n\n            this.widget.forEachChild(c -> c.render(context, mouseX, mouseY, tickDelta));\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/event/EBEEvents.java",
    "content": "package foundationgames.enhancedblockentities.event;\n\nimport net.fabricmc.fabric.api.event.Event;\nimport net.fabricmc.fabric.api.event.EventFactory;\n\npublic enum EBEEvents {;\n    public static final Event<Runnable> RESOURCE_RELOAD = EventFactory.createArrayBacked(Runnable.class, (callbacks) -> () -> {\n        for (var event : callbacks) {\n            event.run();\n        }\n    });\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/mixin/AbstractBlockStateMixin.java",
    "content": "package foundationgames.enhancedblockentities.mixin;\n\nimport foundationgames.enhancedblockentities.EnhancedBlockEntityRegistry;\nimport net.minecraft.block.AbstractBlock;\nimport net.minecraft.block.Block;\nimport net.minecraft.block.BlockRenderType;\nimport org.spongepowered.asm.mixin.Mixin;\nimport org.spongepowered.asm.mixin.Shadow;\nimport org.spongepowered.asm.mixin.injection.At;\nimport org.spongepowered.asm.mixin.injection.Inject;\nimport org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;\n\n@Mixin(AbstractBlock.AbstractBlockState.class)\npublic abstract class AbstractBlockStateMixin {\n    @Shadow public abstract Block getBlock();\n\n    @Inject(method = \"getRenderType\", at = @At(\"HEAD\"), cancellable = true)\n    public void enhanced_bes$overrideRenderType(CallbackInfoReturnable<BlockRenderType> cir) {\n        Block block = this.getBlock();\n        if (EnhancedBlockEntityRegistry.BLOCKS.contains(block)) {\n            cir.setReturnValue(BlockRenderType.MODEL);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/mixin/AbstractSignBlockEntityRenderAccessor.java",
    "content": "package foundationgames.enhancedblockentities.mixin;\n\nimport net.minecraft.block.BlockState;\nimport net.minecraft.block.entity.SignText;\nimport net.minecraft.client.render.VertexConsumerProvider;\nimport net.minecraft.client.render.block.entity.AbstractSignBlockEntityRenderer;\nimport net.minecraft.client.util.math.MatrixStack;\nimport net.minecraft.util.math.BlockPos;\nimport org.spongepowered.asm.mixin.Mixin;\nimport org.spongepowered.asm.mixin.gen.Accessor;\nimport org.spongepowered.asm.mixin.gen.Invoker;\n\n@Mixin(AbstractSignBlockEntityRenderer.class)\npublic interface AbstractSignBlockEntityRenderAccessor {\n    @Invoker(\"applyTransforms\")\n    void enhanced_bes$applyTransforms(MatrixStack matrices, float rotationDegrees, BlockState state);\n\n    @Invoker(\"renderText\")\n    void enhanced_bes$renderText(BlockPos pos, SignText signText, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int lineHeight, int lineWidth, boolean front);\n\n    @Accessor(\"MAX_COLORED_TEXT_OUTLINE_RENDER_DISTANCE\")\n    static int enhanced_bes$getRenderDistance() {\n        throw new AssertionError();\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/mixin/BellBlockEntityMixin.java",
    "content": "package foundationgames.enhancedblockentities.mixin;\n\nimport foundationgames.enhancedblockentities.EnhancedBlockEntities;\nimport foundationgames.enhancedblockentities.util.duck.AppearanceStateHolder;\nimport net.minecraft.block.BlockState;\nimport net.minecraft.block.entity.BellBlockEntity;\nimport net.minecraft.block.entity.BlockEntity;\nimport net.minecraft.block.entity.BlockEntityType;\nimport net.minecraft.util.math.BlockPos;\nimport org.objectweb.asm.Opcodes;\nimport org.spongepowered.asm.mixin.Mixin;\nimport org.spongepowered.asm.mixin.Unique;\nimport org.spongepowered.asm.mixin.injection.At;\nimport org.spongepowered.asm.mixin.injection.ModifyVariable;\n\n@Mixin(BellBlockEntity.class)\npublic class BellBlockEntityMixin extends BlockEntity implements AppearanceStateHolder {\n    @Unique private int enhanced_bes$modelState = 0;\n    @Unique private int enhanced_bes$renderState = 0;\n\n    public BellBlockEntityMixin(BlockEntityType<?> type, BlockPos pos, BlockState state) {\n        super(type, pos, state);\n    }\n\n    // Can't inject because one of the args' type is private (BellBlockEntity$Effect) and I don't feel like AW\n    // So now you get to suffer through this\n    @ModifyVariable(method = \"tick\", at = @At(\n            value = \"JUMP\", opcode = Opcodes.IF_ICMPLT, ordinal = 0, shift = At.Shift.BEFORE\n    ), index = 3)\n    private static BellBlockEntity enhanced_bes$listenForStopRinging(BellBlockEntity blockEntity) {\n        int mState = blockEntity.ringTicks > 0 ? 1 : 0;\n        if (EnhancedBlockEntities.CONFIG.renderEnhancedBells && ((AppearanceStateHolder)blockEntity).getModelState() != mState) {\n            ((AppearanceStateHolder)blockEntity).updateAppearanceState(mState, blockEntity.getWorld(), blockEntity.getPos());\n        }\n        return blockEntity;\n    }\n\n    @Override\n    public int getModelState() {\n        return enhanced_bes$modelState;\n    }\n\n    @Override\n    public void setModelState(int state) {\n        this.enhanced_bes$modelState = state;\n    }\n\n    @Override\n    public int getRenderState() {\n        return enhanced_bes$renderState;\n    }\n\n    @Override\n    public void setRenderState(int state) {\n        this.enhanced_bes$renderState = state;\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/mixin/BlockEntityRenderDispatcherMixin.java",
    "content": "package foundationgames.enhancedblockentities.mixin;\n\nimport foundationgames.enhancedblockentities.EnhancedBlockEntityRegistry;\nimport foundationgames.enhancedblockentities.client.render.BlockEntityRenderCondition;\nimport foundationgames.enhancedblockentities.client.render.BlockEntityRendererOverride;\nimport net.minecraft.block.entity.BlockEntity;\nimport net.minecraft.client.render.OverlayTexture;\nimport net.minecraft.client.render.VertexConsumerProvider;\nimport net.minecraft.client.render.WorldRenderer;\nimport net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher;\nimport net.minecraft.client.render.block.entity.BlockEntityRenderer;\nimport net.minecraft.client.util.math.MatrixStack;\nimport net.minecraft.util.Pair;\nimport org.spongepowered.asm.mixin.Mixin;\nimport org.spongepowered.asm.mixin.injection.At;\nimport org.spongepowered.asm.mixin.injection.Inject;\nimport org.spongepowered.asm.mixin.injection.callback.CallbackInfo;\n\n@Mixin(BlockEntityRenderDispatcher.class)\npublic class BlockEntityRenderDispatcherMixin {\n    @Inject(\n            method = \"render(Lnet/minecraft/client/render/block/entity/BlockEntityRenderer;Lnet/minecraft/block/entity/BlockEntity;FLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;)V\",\n            at = @At(\"HEAD\"),\n            cancellable = true\n    )\n    private static void enhanced_bes$renderOverrides(BlockEntityRenderer<BlockEntity> renderer, BlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, CallbackInfo ci) {\n        if (EnhancedBlockEntityRegistry.ENTITIES.containsKey(blockEntity.getType()) && EnhancedBlockEntityRegistry.BLOCKS.contains(blockEntity.getCachedState().getBlock())) {\n            Pair<BlockEntityRenderCondition, BlockEntityRendererOverride> entry = EnhancedBlockEntityRegistry.ENTITIES.get(blockEntity.getType());\n            if (entry.getLeft().shouldRender(blockEntity)) {\n                entry.getRight().render(renderer, blockEntity, tickDelta, matrices, vertexConsumers, WorldRenderer.getLightmapCoordinates(blockEntity.getWorld(), blockEntity.getPos()), OverlayTexture.DEFAULT_UV);\n            }\n            ci.cancel();\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/mixin/BuiltChunkMixin.java",
    "content": "package foundationgames.enhancedblockentities.mixin;\n\nimport foundationgames.enhancedblockentities.util.duck.ChunkRebuildTaskAccess;\nimport net.minecraft.client.render.chunk.ChunkBuilder;\nimport org.jetbrains.annotations.Nullable;\nimport org.spongepowered.asm.mixin.Mixin;\nimport org.spongepowered.asm.mixin.Unique;\n\n@Mixin(ChunkBuilder.BuiltChunk.class)\npublic class BuiltChunkMixin implements ChunkRebuildTaskAccess {\n    private @Unique\n    @Nullable Runnable enhanced_bes$taskAfterRebuild = null;\n\n    @Override\n    public Runnable enhanced_bes$getTaskAfterRebuild() {\n        return enhanced_bes$taskAfterRebuild;\n    }\n\n    @Override\n    public void enhanced_bes$setTaskAfterRebuild(Runnable task) {\n        enhanced_bes$taskAfterRebuild = task;\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/mixin/ChestBlockEntityMixin.java",
    "content": "package foundationgames.enhancedblockentities.mixin;\n\nimport foundationgames.enhancedblockentities.EnhancedBlockEntities;\nimport foundationgames.enhancedblockentities.client.render.entity.ChestBlockEntityRendererOverride;\nimport foundationgames.enhancedblockentities.util.duck.AppearanceStateHolder;\nimport net.minecraft.block.BlockState;\nimport net.minecraft.block.entity.BlockEntity;\nimport net.minecraft.block.entity.BlockEntityType;\nimport net.minecraft.block.entity.ChestBlockEntity;\nimport net.minecraft.util.math.BlockPos;\nimport net.minecraft.world.World;\nimport org.spongepowered.asm.mixin.Mixin;\nimport org.spongepowered.asm.mixin.Unique;\nimport org.spongepowered.asm.mixin.injection.At;\nimport org.spongepowered.asm.mixin.injection.Inject;\nimport org.spongepowered.asm.mixin.injection.callback.CallbackInfo;\n\n@Mixin(ChestBlockEntity.class)\npublic abstract class ChestBlockEntityMixin extends BlockEntity implements AppearanceStateHolder {\n    @Unique private int enhanced_bes$modelState = 0;\n    @Unique private int enhanced_bes$renderState = 0;\n\n    private ChestBlockEntityMixin(BlockEntityType<?> type, BlockPos pos, BlockState state) {\n        super(type, pos, state);\n    }\n\n    @Inject(method = \"clientTick\", at = @At(value = \"TAIL\"))\n    private static void enhanced_bes$listenForOpenClose(World world, BlockPos pos, BlockState state, ChestBlockEntity blockEntity, CallbackInfo ci) {\n        var lid = ChestBlockEntityRendererOverride.getLidAnimationHolder(blockEntity, 0.5f);\n        int mState = lid.getAnimationProgress(0.5f) > 0 ? 1 : 0;\n\n        if (EnhancedBlockEntities.CONFIG.renderEnhancedChests && ((AppearanceStateHolder)blockEntity).getModelState() != mState) {\n            ((AppearanceStateHolder)blockEntity).updateAppearanceState(mState, world, pos);\n        }\n    }\n\n    @Override\n    public int getModelState() {\n        return enhanced_bes$modelState;\n    }\n\n    @Override\n    public void setModelState(int state) {\n        this.enhanced_bes$modelState = state;\n    }\n\n    @Override\n    public int getRenderState() {\n        return enhanced_bes$renderState;\n    }\n\n    @Override\n    public void setRenderState(int state) {\n        this.enhanced_bes$renderState = state;\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/mixin/DecoratedPotBlockEntityMixin.java",
    "content": "package foundationgames.enhancedblockentities.mixin;\n\nimport foundationgames.enhancedblockentities.util.WorldUtil;\nimport foundationgames.enhancedblockentities.util.duck.AppearanceStateHolder;\nimport net.minecraft.block.entity.DecoratedPotBlockEntity;\nimport net.minecraft.nbt.NbtCompound;\nimport net.minecraft.registry.RegistryWrapper;\nimport org.spongepowered.asm.mixin.Mixin;\nimport org.spongepowered.asm.mixin.Unique;\nimport org.spongepowered.asm.mixin.injection.At;\nimport org.spongepowered.asm.mixin.injection.Inject;\nimport org.spongepowered.asm.mixin.injection.callback.CallbackInfo;\nimport org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;\n\n@Mixin(DecoratedPotBlockEntity.class)\npublic class DecoratedPotBlockEntityMixin implements AppearanceStateHolder {\n    @Unique private int enhanced_bes$modelState = 0;\n    @Unique private int enhanced_bes$renderState = 0;\n\n    @Inject(method = \"readNbt\", at = @At(\"TAIL\"))\n    private void enhanced_bes$updateChunkOnPatternsLoaded(NbtCompound nbt, RegistryWrapper.WrapperLookup rwl, CallbackInfo ci) {\n        var self = (DecoratedPotBlockEntity)(Object)this;\n\n        if (self.getWorld() != null && self.getWorld().isClient()) {\n            WorldUtil.rebuildChunk(self.getWorld(), self.getPos());\n        }\n    }\n\n    @Inject(method = \"onSyncedBlockEvent\", at = @At(value = \"RETURN\", shift = At.Shift.BEFORE, ordinal = 0))\n    private void enhanced_bes$updateOnWobble(int type, int data, CallbackInfoReturnable<Boolean> cir) {\n        var self = (DecoratedPotBlockEntity)(Object)this;\n        var world = self.getWorld();\n\n        if (self.lastWobbleType == null) {\n            return;\n        }\n\n        this.updateAppearanceState(1, world, self.getPos());\n\n        WorldUtil.scheduleTimed(world, self.lastWobbleTime + self.lastWobbleType.lengthInTicks,\n                () -> {\n                    if (self.getWorld().getTime() >= self.lastWobbleTime + self.lastWobbleType.lengthInTicks) {\n                        this.updateAppearanceState(0, world, self.getPos());\n                    }\n                });\n    }\n\n    @Override\n    public int getModelState() {\n        return enhanced_bes$modelState;\n    }\n\n    @Override\n    public void setModelState(int state) {\n        this.enhanced_bes$modelState = state;\n    }\n\n    @Override\n    public int getRenderState() {\n        return enhanced_bes$renderState;\n    }\n\n    @Override\n    public void setRenderState(int state) {\n        this.enhanced_bes$renderState = state;\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/mixin/EnderChestBlockEntityMixin.java",
    "content": "package foundationgames.enhancedblockentities.mixin;\n\nimport foundationgames.enhancedblockentities.EnhancedBlockEntities;\nimport foundationgames.enhancedblockentities.client.render.entity.ChestBlockEntityRendererOverride;\nimport foundationgames.enhancedblockentities.util.duck.AppearanceStateHolder;\nimport net.minecraft.block.BlockState;\nimport net.minecraft.block.entity.BlockEntity;\nimport net.minecraft.block.entity.BlockEntityType;\nimport net.minecraft.block.entity.EnderChestBlockEntity;\nimport net.minecraft.util.math.BlockPos;\nimport net.minecraft.world.World;\nimport org.spongepowered.asm.mixin.Mixin;\nimport org.spongepowered.asm.mixin.Unique;\nimport org.spongepowered.asm.mixin.injection.At;\nimport org.spongepowered.asm.mixin.injection.Inject;\nimport org.spongepowered.asm.mixin.injection.callback.CallbackInfo;\n\n@Mixin(EnderChestBlockEntity.class)\npublic abstract class EnderChestBlockEntityMixin extends BlockEntity implements AppearanceStateHolder {\n    @Unique private int enhanced_bes$modelState = 0;\n    @Unique private int enhanced_bes$renderState = 0;\n\n    private EnderChestBlockEntityMixin(BlockEntityType<?> type, BlockPos pos, BlockState state) {\n        super(type, pos, state);\n    }\n\n    @Inject(method = \"clientTick\", at = @At(value = \"TAIL\"))\n    private static void enhanced_bes$listenForOpenClose(World world, BlockPos pos, BlockState state, EnderChestBlockEntity blockEntity, CallbackInfo ci) {\n        var lid = ChestBlockEntityRendererOverride.getLidAnimationHolder(blockEntity, 0.5f);\n        int mState = lid.getAnimationProgress(0.5f) > 0 ? 1 : 0;\n\n        if (EnhancedBlockEntities.CONFIG.renderEnhancedChests && ((AppearanceStateHolder)blockEntity).getModelState() != mState) {\n            ((AppearanceStateHolder)blockEntity).updateAppearanceState(mState, world, pos);\n        }\n    }\n\n    @Override\n    public int getModelState() {\n        return enhanced_bes$modelState;\n    }\n\n    @Override\n    public void setModelState(int state) {\n        this.enhanced_bes$modelState = state;\n    }\n\n    @Override\n    public int getRenderState() {\n        return enhanced_bes$renderState;\n    }\n\n    @Override\n    public void setRenderState(int state) {\n        this.enhanced_bes$renderState = state;\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/mixin/LifecycledResourceManagerImplMixin.java",
    "content": "package foundationgames.enhancedblockentities.mixin;\n\nimport foundationgames.enhancedblockentities.util.EBEUtil;\nimport foundationgames.enhancedblockentities.util.ResourceUtil;\nimport foundationgames.enhancedblockentities.util.hacks.ExperimentalSetup;\nimport net.minecraft.resource.LifecycledResourceManagerImpl;\nimport net.minecraft.resource.NamespaceResourceManager;\nimport net.minecraft.resource.ResourceManager;\nimport net.minecraft.resource.ResourcePack;\nimport net.minecraft.resource.ResourceType;\nimport org.spongepowered.asm.mixin.Final;\nimport org.spongepowered.asm.mixin.Mixin;\nimport org.spongepowered.asm.mixin.Shadow;\nimport org.spongepowered.asm.mixin.injection.At;\nimport org.spongepowered.asm.mixin.injection.Inject;\nimport org.spongepowered.asm.mixin.injection.ModifyVariable;\nimport org.spongepowered.asm.mixin.injection.callback.CallbackInfo;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n@Mixin(LifecycledResourceManagerImpl.class)\npublic abstract class LifecycledResourceManagerImplMixin {\n    @Shadow @Final          private Map<String, NamespaceResourceManager> subManagers;\n\n    @ModifyVariable(method = \"<init>\", at = @At(value = \"INVOKE\", target = \"Ljava/util/List;copyOf(Ljava/util/Collection;)Ljava/util/List;\", shift = At.Shift.BEFORE), ordinal = 0)\n    private List<ResourcePack> enhanced_bes$injectBasePack(List<ResourcePack> old) {\n        var packs = new ArrayList<>(old);\n\n        int idx = 0;\n        if (packs.size() > 0) do {\n            idx++;\n        } while (idx < packs.size() && !EBEUtil.isVanillaResourcePack(packs.get(idx - 1)));\n        packs.add(idx, ResourceUtil.getBasePack());\n\n        return packs;\n    }\n\n    @Inject(method = \"<init>\", at = @At(value = \"TAIL\"))\n    private void enhanced_bes$injectTopLevelPack(ResourceType type, List<ResourcePack> packs, CallbackInfo ci) {\n        ExperimentalSetup.cacheResources((ResourceManager) this);\n        ExperimentalSetup.setup();\n\n        addPack(type, ResourceUtil.getTopLevelPack());\n    }\n\n    private void addPack(ResourceType type, ResourcePack pack) {\n        for (var namespace : pack.getNamespaces(type)) {\n            this.subManagers.computeIfAbsent(namespace, n -> new NamespaceResourceManager(type, n)).addPack(pack);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/mixin/MinecraftClientMixin.java",
    "content": "package foundationgames.enhancedblockentities.mixin;\n\nimport foundationgames.enhancedblockentities.event.EBEEvents;\nimport net.minecraft.client.MinecraftClient;\nimport org.spongepowered.asm.mixin.Mixin;\nimport org.spongepowered.asm.mixin.injection.At;\nimport org.spongepowered.asm.mixin.injection.Inject;\nimport org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;\n\nimport java.util.concurrent.CompletableFuture;\n\n@Mixin(MinecraftClient.class)\npublic class MinecraftClientMixin {\n    @Inject(method = \"reloadResources()Ljava/util/concurrent/CompletableFuture;\",\n            at = @At(\"RETURN\"))\n    private void enhanced_bes$fireReloadEvent(CallbackInfoReturnable<CompletableFuture<Void>> cir) {\n        cir.getReturnValue().thenAccept(v -> EBEEvents.RESOURCE_RELOAD.invoker().run());\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/mixin/ShulkerBoxBlockEntityMixin.java",
    "content": "package foundationgames.enhancedblockentities.mixin;\n\nimport foundationgames.enhancedblockentities.util.duck.AppearanceStateHolder;\nimport net.minecraft.block.BlockState;\nimport net.minecraft.block.entity.BlockEntity;\nimport net.minecraft.block.entity.BlockEntityType;\nimport net.minecraft.block.entity.ShulkerBoxBlockEntity;\nimport net.minecraft.util.math.BlockPos;\nimport net.minecraft.world.World;\nimport org.spongepowered.asm.mixin.Mixin;\nimport org.spongepowered.asm.mixin.Shadow;\nimport org.spongepowered.asm.mixin.Unique;\nimport org.spongepowered.asm.mixin.injection.At;\nimport org.spongepowered.asm.mixin.injection.Inject;\nimport org.spongepowered.asm.mixin.injection.callback.CallbackInfo;\n\n@Mixin(ShulkerBoxBlockEntity.class)\npublic abstract class ShulkerBoxBlockEntityMixin extends BlockEntity implements AppearanceStateHolder {\n    @Shadow public abstract float getAnimationProgress(float delta);\n\n    @Unique private int enhanced_bes$modelState = 0;\n    @Unique private int enhanced_bes$renderState = 0;\n\n    public ShulkerBoxBlockEntityMixin(BlockEntityType<?> type, BlockPos pos, BlockState state) {\n        super(type, pos, state);\n    }\n\n    @Inject(method = \"updateAnimation\", at = @At(\"TAIL\"))\n    private void enhanced_bes$updateModelState(World world, BlockPos pos, BlockState state, CallbackInfo ci) {\n        int mState = this.getAnimationProgress(0) > 0 ? 1 : 0;\n        if (mState != enhanced_bes$modelState) updateAppearanceState(mState, world, pos);\n    }\n\n    @Override\n    public int getModelState() {\n        return enhanced_bes$modelState;\n    }\n\n    @Override\n    public void setModelState(int state) {\n        this.enhanced_bes$modelState = state;\n    }\n\n    @Override\n    public int getRenderState() {\n        return enhanced_bes$renderState;\n    }\n\n    @Override\n    public void setRenderState(int state) {\n        this.enhanced_bes$renderState = state;\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/mixin/SignEditScreenMixin.java",
    "content": "package foundationgames.enhancedblockentities.mixin;\n\nimport foundationgames.enhancedblockentities.EnhancedBlockEntities;\nimport foundationgames.enhancedblockentities.EnhancedBlockEntityRegistry;\nimport foundationgames.enhancedblockentities.util.EBEUtil;\nimport net.minecraft.block.BlockState;\nimport net.minecraft.client.MinecraftClient;\nimport net.minecraft.client.gui.DrawContext;\nimport net.minecraft.client.gui.screen.ingame.SignEditScreen;\nimport net.minecraft.client.render.OverlayTexture;\nimport net.minecraft.state.property.Properties;\nimport net.minecraft.util.math.Direction;\nimport org.spongepowered.asm.mixin.Mixin;\nimport org.spongepowered.asm.mixin.injection.At;\nimport org.spongepowered.asm.mixin.injection.Inject;\nimport org.spongepowered.asm.mixin.injection.callback.CallbackInfo;\n\n@Mixin(SignEditScreen.class)\npublic class SignEditScreenMixin {\n    @Inject(method = \"renderSignBackground\", at = @At(\"HEAD\"), cancellable = true)\n    private void enhanced_bes$renderBakedModelSign(DrawContext context, CallbackInfo ci) {\n        BlockState state = ((SignEditScreen) (Object) this).blockEntity.getCachedState();\n\n        boolean enhanceSigns = EnhancedBlockEntities.CONFIG.renderEnhancedSigns;\n\n        if (!EnhancedBlockEntityRegistry.BLOCKS.contains(state.getBlock())) return;\n\n        if (enhanceSigns) {\n            var models = MinecraftClient.getInstance().getBakedModelManager().getBlockModels();\n            var buffers = MinecraftClient.getInstance().getBufferBuilders().getEntityVertexConsumers();\n            float up = 0;\n            if (state.contains(Properties.HORIZONTAL_FACING)) {\n                state = state.with(Properties.HORIZONTAL_FACING, Direction.SOUTH);\n                up += 5f/16;\n            } else if (state.contains(Properties.ROTATION)) {\n                state = state.with(Properties.ROTATION, 0);\n            }\n\n            var signModel = models.getModel(state);\n            var matrices = context.getMatrices();\n\n            matrices.push();\n            matrices.translate(0, 31, -50);\n            matrices.scale(93.75f, -93.75f, 93.75f);\n            matrices.translate(-0.5, up - 0.5, 0);\n\n            EBEUtil.renderBakedModel(buffers, state, matrices, signModel, 15728880, OverlayTexture.DEFAULT_UV);\n\n            matrices.pop();\n\n            ci.cancel();\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/mixin/VideoOptionsScreenMixin.java",
    "content": "package foundationgames.enhancedblockentities.mixin;\n\nimport foundationgames.enhancedblockentities.config.gui.option.ConfigButtonOption;\nimport net.minecraft.client.gui.screen.Screen;\nimport net.minecraft.client.gui.screen.option.VideoOptionsScreen;\nimport net.minecraft.client.option.SimpleOption;\nimport net.minecraft.text.Text;\nimport org.spongepowered.asm.mixin.Mixin;\nimport org.spongepowered.asm.mixin.injection.At;\nimport org.spongepowered.asm.mixin.injection.ModifyArg;\n\n@Mixin(VideoOptionsScreen.class)\npublic abstract class VideoOptionsScreenMixin extends Screen {\n    protected VideoOptionsScreenMixin(Text title) {\n        super(title);\n    }\n\n    @ModifyArg(\n            method = \"addOptions\",\n            at = @At(\n                    value = \"INVOKE\",\n                    target = \"Lnet/minecraft/client/gui/widget/OptionListWidget;addAll([Lnet/minecraft/client/option/SimpleOption;)V\"\n            ),\n            index = 0\n    )\n    private SimpleOption<?>[] enhanced_bes$addEBEOptionButton(SimpleOption<?>[] old) {\n        var options = new SimpleOption<?>[old.length + 1];\n        System.arraycopy(old, 0, options, 0, old.length);\n        options[options.length - 1] = ConfigButtonOption.getOption(this);\n        return options;\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/mixin/WorldRendererMixin.java",
    "content": "package foundationgames.enhancedblockentities.mixin;\n\nimport foundationgames.enhancedblockentities.util.WorldUtil;\nimport foundationgames.enhancedblockentities.util.duck.ChunkRebuildTaskAccess;\nimport net.minecraft.client.render.WorldRenderer;\nimport net.minecraft.client.render.chunk.ChunkBuilder;\nimport net.minecraft.util.math.ChunkSectionPos;\nimport org.spongepowered.asm.mixin.Mixin;\nimport org.spongepowered.asm.mixin.injection.At;\nimport org.spongepowered.asm.mixin.injection.Inject;\nimport org.spongepowered.asm.mixin.injection.ModifyVariable;\nimport org.spongepowered.asm.mixin.injection.callback.CallbackInfo;\n\n@Mixin(WorldRenderer.class)\npublic class WorldRendererMixin {\n\n    @ModifyVariable(method = \"updateChunks\",\n            at = @At(value = \"INVOKE\", shift = At.Shift.BEFORE, ordinal = 0, target = \"Lnet/minecraft/client/option/SimpleOption;getValue()Ljava/lang/Object;\"),\n            index = 7)\n    private ChunkBuilder.BuiltChunk enhanced_bes$addPostRebuildTask(ChunkBuilder.BuiltChunk chunk) {\n        if (WorldUtil.CHUNK_UPDATE_TASKS.size() > 0) {\n            var pos = ChunkSectionPos.from(chunk.getOrigin());\n\n            if (WorldUtil.CHUNK_UPDATE_TASKS.containsKey(pos)) {\n                var task = WorldUtil.CHUNK_UPDATE_TASKS.remove(pos);\n                ((ChunkRebuildTaskAccess) chunk).enhanced_bes$setTaskAfterRebuild(task);\n            }\n        }\n\n        return chunk;\n    }\n\n    @Inject(method = \"addBuiltChunk\", at = @At(\"HEAD\"))\n    private void enhanced_bes$runPostRebuildTask(ChunkBuilder.BuiltChunk chunk, CallbackInfo ci) {\n        ((ChunkRebuildTaskAccess) chunk).enhanced_bes$runAfterRebuildTask();\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/mixin/compat/sodium/RenderSectionManagerMixin.java",
    "content": "package foundationgames.enhancedblockentities.mixin.compat.sodium;\n\nimport foundationgames.enhancedblockentities.util.WorldUtil;\nimport foundationgames.enhancedblockentities.util.duck.ChunkRebuildTaskAccess;\nimport net.caffeinemc.mods.sodium.client.render.chunk.RenderSection;\nimport net.caffeinemc.mods.sodium.client.render.chunk.RenderSectionManager;\nimport net.caffeinemc.mods.sodium.client.render.chunk.compile.BuilderTaskOutput;\nimport net.minecraft.util.math.ChunkSectionPos;\nimport org.spongepowered.asm.mixin.Mixin;\nimport org.spongepowered.asm.mixin.Pseudo;\nimport org.spongepowered.asm.mixin.injection.At;\nimport org.spongepowered.asm.mixin.injection.ModifyVariable;\n\n/**\n * <p>Adapted from {@link foundationgames.enhancedblockentities.mixin.WorldRendererMixin}</p>\n */\n@Pseudo\n@Mixin(value = RenderSectionManager.class, remap = false)\npublic class RenderSectionManagerMixin {\n    @ModifyVariable(method = \"submitSectionTasks(Lnet/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector;Lnet/caffeinemc/mods/sodium/client/render/chunk/ChunkUpdateType;Z)V\",\n            at = @At(value = \"INVOKE\", shift = At.Shift.BEFORE, ordinal = 0, target = \"Lnet/caffeinemc/mods/sodium/client/render/chunk/RenderSection;isDisposed()Z\"),\n            index = 5, require = 0\n    )\n    private RenderSection enhanced_bes$compat_sodium$cacheUpdatingChunk(RenderSection section) {\n        if (WorldUtil.CHUNK_UPDATE_TASKS.size() > 0) {\n            var pos = ChunkSectionPos.from(section.getChunkX(), section.getChunkY(), section.getChunkZ());\n\n            if (WorldUtil.CHUNK_UPDATE_TASKS.containsKey(pos)) {\n                var task = WorldUtil.CHUNK_UPDATE_TASKS.remove(pos);\n                ((ChunkRebuildTaskAccess) section).enhanced_bes$setTaskAfterRebuild(task);\n            }\n        }\n\n        return section;\n    }\n\n    @ModifyVariable(method = \"processChunkBuildResults\",\n            at = @At(value = \"INVOKE_ASSIGN\", shift = At.Shift.BEFORE, ordinal = 0, target = \"Lnet/caffeinemc/mods/sodium/client/render/chunk/RenderSection;getTaskCancellationToken()Lnet/caffeinemc/mods/sodium/client/util/task/CancellationToken;\"),\n            index = 5, require = 0\n    )\n    private BuilderTaskOutput enhanced_bes$runPostRebuildTask(BuilderTaskOutput output) {\n        ((ChunkRebuildTaskAccess) output.render).enhanced_bes$runAfterRebuildTask();\n\n        return output;\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/mixin/compat/sodium/RenderSectionMixin.java",
    "content": "package foundationgames.enhancedblockentities.mixin.compat.sodium;\n\nimport foundationgames.enhancedblockentities.util.duck.ChunkRebuildTaskAccess;\nimport net.caffeinemc.mods.sodium.client.render.chunk.RenderSection;\nimport org.jetbrains.annotations.Nullable;\nimport org.spongepowered.asm.mixin.Mixin;\nimport org.spongepowered.asm.mixin.Pseudo;\nimport org.spongepowered.asm.mixin.Unique;\n\n\n/**\n * <p>Adapted from {@link foundationgames.enhancedblockentities.mixin.BuiltChunkMixin}</p>\n */\n@Pseudo\n@Mixin(value = RenderSection.class, remap = false)\npublic class RenderSectionMixin implements ChunkRebuildTaskAccess {\n    private @Unique @Nullable Runnable enhanced_bes$taskAfterRebuild = null;\n\n    @Override\n    public Runnable enhanced_bes$getTaskAfterRebuild() {\n        return enhanced_bes$taskAfterRebuild;\n    }\n\n    @Override\n    public void enhanced_bes$setTaskAfterRebuild(Runnable task) {\n        enhanced_bes$taskAfterRebuild = task;\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/util/ConvUtil.java",
    "content": "package foundationgames.enhancedblockentities.util;\n\npublic enum ConvUtil {;\n    public static boolean bool(String bool) {\n        return bool != null && bool.equalsIgnoreCase(\"true\");\n    }\n\n    public static boolean defaultedBool(String bool, boolean defaultVal) {\n        return bool == null ? defaultVal : bool(bool);\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/util/DateUtil.java",
    "content": "package foundationgames.enhancedblockentities.util;\n\nimport foundationgames.enhancedblockentities.EnhancedBlockEntities;\nimport net.minecraft.client.render.block.entity.ChestBlockEntityRenderer;\n\npublic enum DateUtil {;\n    public static boolean isChristmas() {\n        String config = EnhancedBlockEntities.CONFIG.christmasChests;\n        if (config.equals(\"disabled\")) return false;\n        if (config.equals(\"forced\")) return true;\n        return ChestBlockEntityRenderer.isAroundChristmas();\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/util/EBEUtil.java",
    "content": "package foundationgames.enhancedblockentities.util;\n\nimport foundationgames.enhancedblockentities.EnhancedBlockEntities;\nimport net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;\nimport net.fabricmc.loader.api.FabricLoader;\nimport net.minecraft.block.BlockState;\nimport net.minecraft.client.render.RenderLayers;\nimport net.minecraft.client.render.VertexConsumer;\nimport net.minecraft.client.render.VertexConsumerProvider;\nimport net.minecraft.client.render.model.BakedModel;\nimport net.minecraft.client.render.model.BakedQuad;\nimport net.minecraft.client.util.math.MatrixStack;\nimport net.minecraft.resource.DefaultResourcePack;\nimport net.minecraft.resource.ResourcePack;\nimport net.minecraft.util.DyeColor;\nimport net.minecraft.util.Identifier;\nimport net.minecraft.util.math.Direction;\nimport net.minecraft.util.math.random.Random;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\n\npublic enum EBEUtil {;\n    private static final Random dummy = Random.create();\n\n    // Contains all dye colors, and null\n    public static final DyeColor[] DEFAULTED_DYE_COLORS;\n    // All directions except up and down\n    public static final Direction[] HORIZONTAL_DIRECTIONS;\n\n    static {\n        var dColors = DyeColor.values();\n        DEFAULTED_DYE_COLORS = new DyeColor[dColors.length + 1];\n        System.arraycopy(dColors, 0, DEFAULTED_DYE_COLORS, 0, dColors.length);\n\n        HORIZONTAL_DIRECTIONS = new Direction[] {Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST};\n    }\n\n    public static int angle(Direction dir) {\n        int h = dir.getHorizontalQuarterTurns();\n        return h >= 0 ? h * 90 : 0;\n    }\n\n    public static void renderBakedModel(VertexConsumerProvider vertexConsumers, BlockState state, MatrixStack matrices, BakedModel model, int light, int overlay) {\n        VertexConsumer vertices = vertexConsumers.getBuffer(RenderLayers.getEntityBlockLayer(state));\n        for (int i = 0; i <= 6; i++) {\n            for (BakedQuad q : model.getQuads(null, ModelHelper.faceFromIndex(i), dummy)) {\n                vertices.quad(matrices.peek(), q, 1, 1, 1, 1, light, overlay);\n            }\n        }\n    }\n\n    public static boolean isVanillaResourcePack(ResourcePack pack) {\n        return (pack instanceof DefaultResourcePack) ||\n                // Terrible quilt compat hack\n                (\"org.quiltmc.qsl.resource.loader.api.GroupResourcePack$Wrapped\".equals(pack.getClass().getName()));\n    }\n\n    public static Identifier id(String path) {\n        return Identifier.of(EnhancedBlockEntities.NAMESPACE, path);\n    }\n\n    public static final String DUMP_FOLDER_NAME = \"enhanced_bes_dump\";\n\n    public static void dumpResources() throws IOException {\n        var path = FabricLoader.getInstance().getGameDir().resolve(DUMP_FOLDER_NAME);\n\n        if (!Files.exists(path)) {\n            Files.createDirectory(path);\n        }\n\n        ResourceUtil.dumpAllPacks(path);\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/util/ExecutableRunnableHashSet.java",
    "content": "package foundationgames.enhancedblockentities.util;\n\nimport java.util.HashSet;\n\npublic class ExecutableRunnableHashSet extends HashSet<Runnable> implements Runnable {\n    @Override\n    public void run() {\n        this.forEach(Runnable::run);\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/util/GuiUtil.java",
    "content": "package foundationgames.enhancedblockentities.util;\n\nimport net.minecraft.text.Text;\nimport net.minecraft.util.Formatting;\n\npublic enum GuiUtil {;\n    public static Text shorten(String text, final int maxLength, Formatting ... formats) {\n        String[] words = text.split(\" \");\n        StringBuilder line = new StringBuilder();\n        StringBuilder result = new StringBuilder();\n        for (int i = 0; i < words.length; i++) {\n            var word = words[i];\n            line.append(word).append(\" \");\n            if (line.length() > maxLength) {\n                if (i < words.length - 1) {\n                    line.append(\"\\n\");\n                }\n                result.append(line);\n                line = new StringBuilder();\n            }\n        }\n        if (line.length() > 0) result.append(line);\n        return Text.literal(result.toString()).formatted(formats);\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/util/ResourceUtil.java",
    "content": "package foundationgames.enhancedblockentities.util;\n\nimport foundationgames.enhancedblockentities.EnhancedBlockEntities;\nimport foundationgames.enhancedblockentities.client.resource.EBEPack;\nimport foundationgames.enhancedblockentities.client.resource.template.TemplateProvider;\nimport net.fabricmc.loader.api.FabricLoader;\nimport net.fabricmc.loader.api.ModContainer;\nimport net.minecraft.block.DecoratedPotPattern;\nimport net.minecraft.client.render.TexturedRenderLayers;\nimport net.minecraft.registry.RegistryKey;\nimport net.minecraft.util.DyeColor;\nimport net.minecraft.util.Identifier;\nimport net.minecraft.util.math.Direction;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.io.IOException;\nimport java.nio.file.CopyOption;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardCopyOption;\nimport java.util.List;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\npublic enum ResourceUtil {;\n    private static EBEPack BASE_PACK;\n    private static EBEPack TOP_LEVEL_PACK;\n\n    public static void addChestItemDefinition(String chestName, String centerChest, boolean hasChristmas, EBEPack pack) {\n        pack.addTemplateResource(Identifier.of(\"items/\"+chestName+\".json\"),\n                t -> t.load(hasChristmas ? \"item/chest_item.json\" : \"item/chest_item_no_christmas.json\",\n                        d -> d.def(\"chest\", centerChest)));\n    }\n\n    public static void addBedItemDefinition(String bedColor, EBEPack pack) {\n        pack.addTemplateResource(Identifier.of(\"items/\"+bedColor+\"_bed.json\"),\n                t -> t.load(\"item/bed.json\",\n                        d -> d.def(\"head\", bedColor + \"_bed_head\").def(\"foot\", bedColor + \"_bed_foot\")));\n\n        pack.addTemplateResource(Identifier.of(\"models/item/\"+bedColor+\"_bed_head.json\"),\n                t -> t.load(\"model/bed_head_item.json\", d -> d.def(\"bed\", bedColor)));\n        pack.addTemplateResource(Identifier.of(\"models/item/\"+bedColor+\"_bed_foot.json\"),\n                t -> t.load(\"model/bed_foot_item.json\", d -> d.def(\"bed\", bedColor)));\n    }\n\n    private static String list(String ... els) {\n        return String.join(\",\", els);\n    }\n\n    private static String kv(String k, String v) {\n        return String.format(\"\\\"\"+k+\"\\\":\\\"\"+v+\"\\\"\");\n    }\n\n    private static String kv(String k, int v) {\n        return String.format(\"\\\"\"+k+\"\\\":\"+v+\"\");\n    }\n\n    private static String variant(TemplateProvider t, String state, String model) throws IOException {\n        return t.load(\"blockstate/var.json\", d -> d\n                .def(\"state\", state)\n                .def(\"model\", model)\n                .def(\"extra\", \"\"));\n    }\n\n    private static String variantY(TemplateProvider t, String state, String model, int y) throws IOException {\n        return t.load(\"blockstate/var.json\", d -> d\n                .def(\"state\", state)\n                .def(\"model\", model)\n                .def(\"extra\", kv(\"y\", y) + \",\"));\n    }\n\n    private static String variantXY(TemplateProvider t, String state, String model, int x, int y) throws IOException {\n        return t.load(\"blockstate/var.json\", d -> d\n                .def(\"state\", state)\n                .def(\"model\", model)\n                .def(\"extra\", list(\n                        kv(\"x\", x),\n                        kv(\"y\", y)\n                ) + \",\"));\n    }\n\n    private static String variantRotation16(TemplateProvider t, String keyPrefix, String modelPrefix) throws IOException {\n        return list(\n                variantY(t, keyPrefix+\"0\", modelPrefix+\"_0\", 180),\n                variantY(t, keyPrefix+\"1\", modelPrefix+\"_67_5\", 270),\n                variantY(t, keyPrefix+\"2\", modelPrefix+\"_45\", 270),\n                variantY(t, keyPrefix+\"3\", modelPrefix+\"_22_5\", 270),\n                variantY(t, keyPrefix+\"4\", modelPrefix+\"_0\", 270),\n                variant(t, keyPrefix+\"5\", modelPrefix+\"_67_5\"),\n                variant(t, keyPrefix+\"6\", modelPrefix+\"_45\"),\n                variant(t, keyPrefix+\"7\", modelPrefix+\"_22_5\"),\n                variant(t, keyPrefix+\"8\", modelPrefix+\"_0\"),\n                variantY(t, keyPrefix+\"9\", modelPrefix+\"_67_5\", 90),\n                variantY(t, keyPrefix+\"10\", modelPrefix+\"_45\", 90),\n                variantY(t, keyPrefix+\"11\", modelPrefix+\"_22_5\", 90),\n                variantY(t, keyPrefix+\"12\", modelPrefix+\"_0\", 90),\n                variantY(t, keyPrefix+\"13\", modelPrefix+\"_67_5\", 180),\n                variantY(t, keyPrefix+\"14\", modelPrefix+\"_45\", 180),\n                variantY(t, keyPrefix+\"15\", modelPrefix+\"_22_5\", 180)\n        );\n    }\n\n    private static String variantHFacing(TemplateProvider t, String keyPrefix, String model) throws IOException {\n        return list(\n                variant(t, keyPrefix+\"north\", model),\n                variantY(t, keyPrefix+\"west\", model, 270),\n                variantY(t, keyPrefix+\"south\", model, 180),\n                variantY(t, keyPrefix+\"east\", model, 90)\n        );\n    }\n\n    private static void addChestLikeModel(String parent, String chestTex, String chestName, Identifier id, EBEPack pack) {\n        pack.addTemplateResource(Identifier.of(id.getNamespace(), \"models/\" + id.getPath() + \".json\"),\n                t -> t.load(\"model/chest_like.json\", d -> d\n                        .def(\"parent\", parent)\n                        .def(\"chest_tex\", chestTex)\n                        .def(\"particle\", chestParticle(chestName))\n                )\n        );\n    }\n\n    public static void addSingleChestModels(String chestTex, String chestName, EBEPack pack) {\n        addChestLikeModel(\"template_chest_center\", chestTex, chestName, Identifier.of(\"block/\" + chestName + \"_center\"), pack);\n        addChestLikeModel(\"template_chest_center_lid\", chestTex, chestName, Identifier.of(\"block/\" + chestName + \"_center_lid\"), pack);\n        addChestLikeModel(\"template_chest_center_trunk\", chestTex, chestName, Identifier.of(\"block/\" + chestName + \"_center_trunk\"), pack);\n    }\n\n    public static void addDoubleChestModels(String leftTex, String rightTex, String chestName, EBEPack pack) {\n        addChestLikeModel(\"template_chest_left\", leftTex, chestName, Identifier.of(\"block/\" + chestName + \"_left\"), pack);\n        addChestLikeModel(\"template_chest_left_lid\", leftTex, chestName, Identifier.of(\"block/\" + chestName + \"_left_lid\"), pack);\n        addChestLikeModel(\"template_chest_left_trunk\", leftTex, chestName, Identifier.of(\"block/\" + chestName + \"_left_trunk\"), pack);\n        addChestLikeModel(\"template_chest_right\", rightTex, chestName, Identifier.of(\"block/\" + chestName + \"_right\"), pack);\n        addChestLikeModel(\"template_chest_right_lid\", rightTex, chestName, Identifier.of(\"block/\" + chestName + \"_right_lid\"), pack);\n        addChestLikeModel(\"template_chest_right_trunk\", rightTex, chestName, Identifier.of(\"block/\" + chestName + \"_right_trunk\"), pack);\n    }\n\n    private static String chestParticle(String chestName) {\n        if (EnhancedBlockEntities.CONFIG.experimentalChests) return kv(\"particle\", \"block/\"+chestName+\"_particle\") + \",\";\n        return \"\";\n    }\n\n    private static String bedParticle(String bedColor) {\n        if (EnhancedBlockEntities.CONFIG.experimentalBeds) return kv(\"particle\", \"block/\"+bedColor+\"_bed_particle\") + \",\";\n        return \"\";\n    }\n\n    private static String signParticle(String signName) {\n        if (EnhancedBlockEntities.CONFIG.experimentalSigns) return kv(\"particle\", \"block/\"+signName+\"_particle\") + \",\";\n        return \"\";\n    }\n\n    private static void addBlockState(Identifier id, TemplateProvider.TemplateApplyingFunction vars, EBEPack pack) {\n        pack.addTemplateResource(Identifier.of(id.getNamespace(), \"blockstates/\" + id.getPath() + \".json\"),\n                t -> t.load(\"blockstate/base.json\", d -> d.def(\"vars\", vars)));\n    }\n\n    public static void addChestBlockStates(String chestName, EBEPack pack) {\n        addBlockState(Identifier.of(chestName),\n                t0 -> list(\n                        variantHFacing(t0, \"type=single,facing=\", \"builtin:\"+chestName+\"_center\"),\n                        variantHFacing(t0, \"type=left,facing=\", \"builtin:\"+chestName+\"_left\"),\n                        variantHFacing(t0, \"type=right,facing=\", \"builtin:\"+chestName+\"_right\")\n                ), pack);\n    }\n\n    public static void addSingleChestOnlyBlockStates(String chestName, EBEPack pack) {\n        addBlockState(Identifier.of(chestName),\n                t0 -> list(\n                        variantHFacing(t0, \"facing=\", \"builtin:\"+chestName+\"_center\")\n                ), pack);\n    }\n\n    public static void addParentModel(String parent, Identifier id, EBEPack pack) {\n        pack.addTemplateResource(Identifier.of(id.getNamespace(), \"models/\" + id.getPath() + \".json\"), t ->\n                \"{\" + kv(\"parent\", parent) + \"}\");\n    }\n\n    public static void addParentTexModel(String parent, String textures, Identifier id, EBEPack pack) {\n        pack.addTemplateResource(Identifier.of(id.getNamespace(), \"models/\" + id.getPath() + \".json\"), t ->\n                t.load(\"model/parent_and_tex.json\", d -> d.def(\"parent\", parent).def(\"textures\", textures)));\n    }\n\n    public static void addSignTypeModels(String signType, EBEPack pack) {\n        var signName = signType+\"_sign\";\n        var signTex = \"entity/signs/\"+signType;\n        addRotation16Models(\n                signParticle(signName) + kv(\"sign\", signTex),\n                \"block/template_sign\", \"block/\"+signName, ResourceUtil::signAOSuffix, pack);\n\n        var hangingTexDef = list(\n                kv(\"sign\", \"entity/signs/hanging/\"+signType),\n                kv(\"particle\", \"block/particle_hanging_sign_\"+signType)\n        );\n        addRotation16Models(hangingTexDef, \"block/template_hanging_sign\", \"block/\"+signType+\"_hanging_sign\",\n                ResourceUtil::signAOSuffix, pack);\n        addRotation16Models(hangingTexDef, \"block/template_hanging_sign_attached\", \"block/\"+signType+\"_hanging_sign_attached\",\n                ResourceUtil::signAOSuffix, pack);\n\n        addParentTexModel(signAOSuffix(\"block/template_wall_sign\"),\n                signParticle(signName) + kv(\"sign\", signTex), Identifier.of(\"block/\"+signType+\"_wall_sign\"), pack);\n        addParentTexModel(signAOSuffix(\"block/template_wall_hanging_sign\"),\n                hangingTexDef, Identifier.of(\"block/\"+signType+\"_wall_hanging_sign\"), pack);\n    }\n\n    public static void addRotation16Models(String textures, String templatePrefix, String modelPrefix, Function<String, String> suffix, EBEPack pack) {\n        addParentTexModel(suffix.apply(templatePrefix+\"_0\"), textures, Identifier.of(modelPrefix + \"_0\"), pack);\n        addParentTexModel(suffix.apply(templatePrefix+\"_22_5\"), textures, Identifier.of(modelPrefix + \"_22_5\"), pack);\n        addParentTexModel(suffix.apply(templatePrefix+\"_45\"), textures, Identifier.of(modelPrefix + \"_45\"), pack);\n        addParentTexModel(suffix.apply(templatePrefix+\"_67_5\"), textures, Identifier.of(modelPrefix + \"_67_5\"), pack);\n    }\n\n    private static String signAOSuffix(String model) {\n        if (EnhancedBlockEntities.CONFIG.signAO) model += \"_ao\";\n        return model;\n    }\n\n    public static void addSignBlockStates(String signName, String wallSignName, EBEPack pack) {\n        addBlockState(Identifier.of(signName),\n                t -> variantRotation16(t, \"rotation=\", \"block/\"+signName), pack);\n        addBlockState(Identifier.of(wallSignName),\n                t -> variantHFacing(t, \"facing=\", \"block/\"+wallSignName), pack);\n    }\n\n    public static void addHangingSignBlockStates(String signName, String wallSignName, EBEPack pack) {\n        addBlockState(Identifier.of(signName),\n                t -> list(\n                        variantRotation16(t, \"attached=false,rotation=\", \"block/\"+signName),\n                        variantRotation16(t, \"attached=true,rotation=\", \"block/\"+signName+\"_attached\")\n                ), pack);\n\n        addBlockState(Identifier.of(wallSignName),\n                t -> variantHFacing(t, \"facing=\", \"block/\"+wallSignName), pack);\n    }\n\n    public static void addBellBlockState(EBEPack pack) {\n        addBlockState(Identifier.of(\"bell\"),\n                t -> {\n                    var vars = new DelimitedAppender(\",\");\n                    for (Direction dir : EBEUtil.HORIZONTAL_DIRECTIONS) {\n                        int rot = EBEUtil.angle(dir) + 90;\n                        vars\n                                .append(variantY(t, \"attachment=double_wall,facing=\"+dir.getName(), \"builtin:bell_between_walls\", rot))\n                                .append(variantY(t, \"attachment=ceiling,facing=\"+dir.getName(), \"builtin:bell_ceiling\", rot + 90)) // adding 90 here and below to maintain Parity with vanilla's weird choice of rotations\n                                .append(variantY(t, \"attachment=floor,facing=\"+dir.getName(), \"builtin:bell_floor\", rot + 90))\n                                .append(variantY(t, \"attachment=single_wall,facing=\"+dir.getName(), \"builtin:bell_wall\", rot));\n                    }\n                    return vars.get();\n                }, pack);\n    }\n\n    public static void addBedModels(DyeColor bedColor, EBEPack pack) {\n        String color = bedColor.getName();\n\n        addParentTexModel(bedAOSuffix(\"block/template_bed_head\"),\n                bedParticle(color) + kv(\"bed\", \"entity/bed/\" + color),\n                Identifier.of(\"block/\" + color + \"_bed_head\"), pack);\n        addParentTexModel(bedAOSuffix(\"block/template_bed_foot\"),\n                bedParticle(color) + kv(\"bed\", \"entity/bed/\" + color),\n                Identifier.of(\"block/\" + color + \"_bed_foot\"), pack);\n\n        addBedItemDefinition(color, pack);\n    }\n\n    public static void addBedBlockState(DyeColor bedColor, EBEPack pack) {\n        String color = bedColor.getName();\n        addBlockState(Identifier.of(color + \"_bed\"),\n                t -> {\n                    var vars = new DelimitedAppender(\",\");\n                    for (Direction dir : EBEUtil.HORIZONTAL_DIRECTIONS) {\n                        int rot = EBEUtil.angle(dir) + 180;\n                        vars\n                                .append(variantY(t, \"part=head,facing=\"+dir.getName(), \"block/\" + bedColor + \"_bed_head\", rot))\n                                .append(variantY(t, \"part=foot,facing=\"+dir.getName(), \"block/\" + bedColor + \"_bed_foot\", rot));\n                    }\n                    return vars.get();\n                }, pack);\n    }\n\n    private static String bedAOSuffix(String model) {\n        if (EnhancedBlockEntities.CONFIG.bedAO) model += \"_ao\";\n        return model;\n    }\n\n    public static void addShulkerBoxModels(@Nullable DyeColor color, EBEPack pack) {\n        var texture = color != null ? \"entity/shulker/shulker_\"+color.getName() : \"entity/shulker/shulker\";\n        var shulkerBoxStr = color != null ? color.getName()+\"_shulker_box\" : \"shulker_box\";\n        var particle = \"block/\"+shulkerBoxStr;\n        addParentTexModel(\"block/template_shulker_box\",\n                list(kv(\"shulker\", texture), kv(\"particle\", particle)),\n                Identifier.of(\"block/\"+shulkerBoxStr), pack);\n        addParentTexModel(\"block/template_shulker_box_bottom\",\n                list(kv(\"shulker\", texture), kv(\"particle\", particle)),\n                Identifier.of(\"block/\"+shulkerBoxStr+\"_bottom\"), pack);\n        addParentTexModel(\"block/template_shulker_box_lid\",\n                list(kv(\"shulker\", texture), kv(\"particle\", particle)),\n                Identifier.of(\"block/\"+shulkerBoxStr+\"_lid\"), pack);\n    }\n\n    public static void addShulkerBoxBlockStates(@Nullable DyeColor color, EBEPack pack) {\n        var shulkerBoxStr = color != null ? color.getName()+\"_shulker_box\" : \"shulker_box\";\n        addBlockState(Identifier.of(shulkerBoxStr),\n                t -> {\n                    var vars = new DelimitedAppender(\",\");\n                    vars\n                            .append(variant(t, \"facing=up\", \"builtin:\"+shulkerBoxStr))\n                            .append(variantXY(t, \"facing=down\", \"builtin:\"+shulkerBoxStr, 180, 0));\n                    for (Direction dir : EBEUtil.HORIZONTAL_DIRECTIONS) {\n                        int rot = EBEUtil.angle(dir) + 180;\n                        vars.append(variantXY(t, \"facing=\"+dir.getName(), \"builtin:\"+shulkerBoxStr, 90, rot));\n                    }\n                    return vars.get();\n                }, pack);\n    }\n\n    public static void addDecoratedPotBlockState(EBEPack pack) {\n        addBlockState(Identifier.of(\"decorated_pot\"),\n                t -> variantHFacing(t, \"facing=\", \"builtin:decorated_pot\"), pack);\n    }\n\n    public static void addDecoratedPotPatternModels(RegistryKey<DecoratedPotPattern> patternKey, EBEPack pack) {\n        for (Direction dir : EBEUtil.HORIZONTAL_DIRECTIONS) {\n            addParentTexModel(\"block/template_pottery_pattern_\" + dir.getName(),\n                    kv(\"pattern\", TexturedRenderLayers.getDecoratedPotPatternTextureId(patternKey).getTextureId().toString()),\n                    Identifier.of(\"block/\" + patternKey.getValue().getPath() + \"_\" + dir.getName()),\n                    pack);\n        }\n    }\n\n    public static void resetBasePack() {\n        BASE_PACK = new EBEPack(EBEUtil.id(\"base_resources\"), EnhancedBlockEntities.TEMPLATE_LOADER);\n    }\n\n    public static void resetTopLevelPack() {\n        TOP_LEVEL_PACK = new EBEPack(EBEUtil.id(\"top_level_resources\"), EnhancedBlockEntities.TEMPLATE_LOADER);\n    }\n\n    public static EBEPack getBasePack() {\n        return BASE_PACK;\n    }\n\n    public static EBEPack getTopLevelPack() {\n        return TOP_LEVEL_PACK;\n    }\n\n    /**\n     * @return the pack most appropriate for resources that might be accidentally overwritten by resource packs\n     */\n    public static EBEPack getPackForCompat() {\n        if (EnhancedBlockEntities.CONFIG.forceResourcePackCompat) {\n            return getTopLevelPack();\n        }\n\n        return getBasePack();\n    }\n\n    public static void dumpModAssets(Path dest) throws IOException {\n        var roots = FabricLoader.getInstance().getModContainer(EnhancedBlockEntities.ID)\n                .map(ModContainer::getRootPaths).orElse(List.of());\n\n        for (var root : roots) {\n            var sourceAssets = Files.walk(root.resolve(\"assets\"));\n            for (var asset : sourceAssets.collect(Collectors.toSet())) {\n                if (!Files.isDirectory(asset)) {\n                    var out = dest.resolve(root.relativize(asset));\n                    if (!Files.exists(out.getParent())) {\n                        Files.createDirectories(out.getParent());\n                    }\n                    Files.copy(asset, out, Files.exists(out) ? new CopyOption[] {StandardCopyOption.REPLACE_EXISTING} : new CopyOption[] {});\n                }\n            }\n        }\n    }\n\n    public static void dumpAllPacks(Path dest) throws IOException {\n        getBasePack().dump(dest);\n        getTopLevelPack().dump(dest);\n        dumpModAssets(dest);\n    }\n\n    private static class DelimitedAppender {\n        private final StringBuilder builder = new StringBuilder();\n        private final CharSequence delimiter;\n\n        private DelimitedAppender(CharSequence delimiter) {\n            this.delimiter = delimiter;\n        }\n\n        public DelimitedAppender append(CharSequence seq) {\n            if (!this.builder.isEmpty()) this.builder.append(this.delimiter);\n\n            this.builder.append(seq);\n            return this;\n        }\n\n        public String get() {\n            return this.builder.toString();\n        }\n    }\n\n    static {\n        resetBasePack();\n        resetTopLevelPack();\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/util/WorldUtil.java",
    "content": "package foundationgames.enhancedblockentities.util;\n\nimport it.unimi.dsi.fastutil.longs.Long2ObjectMap;\nimport it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;\nimport net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;\nimport net.minecraft.client.MinecraftClient;\nimport net.minecraft.client.world.ClientWorld;\nimport net.minecraft.registry.RegistryKey;\nimport net.minecraft.util.math.BlockPos;\nimport net.minecraft.util.math.ChunkSectionPos;\nimport net.minecraft.world.World;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic enum WorldUtil implements ClientTickEvents.EndWorldTick {\n    EVENT_LISTENER;\n\n    public static final Map<ChunkSectionPos, ExecutableRunnableHashSet> CHUNK_UPDATE_TASKS = new HashMap<>();\n    private static final Map<RegistryKey<World>, Long2ObjectMap<Runnable>> TIMED_TASKS = new HashMap<>();\n\n    public static void rebuildChunk(World world, BlockPos pos) {\n        var state = world.getBlockState(pos);\n        MinecraftClient.getInstance().worldRenderer.updateBlock(world, pos, state, state, 8);\n    }\n\n    public static void rebuildChunkAndThen(World world, BlockPos pos, Runnable action) {\n        CHUNK_UPDATE_TASKS.computeIfAbsent(ChunkSectionPos.from(pos), k -> new ExecutableRunnableHashSet()).add(action);\n        rebuildChunk(world, pos);\n    }\n\n    public static void scheduleTimed(World world, long time, Runnable action) {\n        TIMED_TASKS.computeIfAbsent(world.getRegistryKey(), k -> new Long2ObjectOpenHashMap<>()).put(time, action);\n    }\n\n    @Override\n    public void onEndTick(ClientWorld world) {\n        var key = world.getRegistryKey();\n\n        if (TIMED_TASKS.containsKey(key)) {\n            TIMED_TASKS.get(key).long2ObjectEntrySet().removeIf(entry -> {\n                if (world.getTime() >= entry.getLongKey()) {\n                    entry.getValue().run();\n                    return true;\n                }\n\n                return false;\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/util/duck/AppearanceStateHolder.java",
    "content": "package foundationgames.enhancedblockentities.util.duck;\n\nimport foundationgames.enhancedblockentities.util.WorldUtil;\nimport net.minecraft.util.math.BlockPos;\nimport net.minecraft.world.World;\n\npublic interface AppearanceStateHolder {\n    int getModelState();\n\n    void setModelState(int state);\n\n    int getRenderState();\n\n    void setRenderState(int state);\n\n    default void updateAppearanceState(int state, World world, BlockPos pos) {\n        if (!world.isClient()) {\n            return;\n        }\n\n        this.setModelState(state);\n        WorldUtil.rebuildChunkAndThen(world, pos, () -> this.setRenderState(state));\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/util/duck/ChunkRebuildTaskAccess.java",
    "content": "package foundationgames.enhancedblockentities.util.duck;\n\npublic interface ChunkRebuildTaskAccess {\n    Runnable enhanced_bes$getTaskAfterRebuild();\n\n    void enhanced_bes$setTaskAfterRebuild(Runnable task);\n\n    default void enhanced_bes$runAfterRebuildTask() {\n        var task = this.enhanced_bes$getTaskAfterRebuild();\n\n        if (task != null) {\n            task.run();\n\n            this.enhanced_bes$setTaskAfterRebuild(null);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/util/hacks/ExperimentalSetup.java",
    "content": "package foundationgames.enhancedblockentities.util.hacks;\n\nimport foundationgames.enhancedblockentities.EnhancedBlockEntities;\nimport foundationgames.enhancedblockentities.client.resource.EBEPack;\nimport foundationgames.enhancedblockentities.config.EBEConfig;\nimport foundationgames.enhancedblockentities.util.ResourceUtil;\nimport net.minecraft.resource.ResourceManager;\nimport net.minecraft.util.DyeColor;\n\nimport java.io.IOException;\n\npublic enum ExperimentalSetup {;\n    private static ResourceManager RESOURCES;\n\n    public static void setup() {\n        EBEConfig config = EnhancedBlockEntities.CONFIG;\n\n        if (config.renderEnhancedChests && config.experimentalChests) {\n            try {\n                if (RESOURCES != null) setupChests(RESOURCES);\n            } catch (IOException e) {\n                EnhancedBlockEntities.LOG.error(\"Error loading experimental chests!\", e);\n                config.experimentalChests = false;\n                config.save();\n            }\n        }\n        if (config.renderEnhancedBeds && config.experimentalBeds) {\n            try {\n                if (RESOURCES != null) setupBeds(RESOURCES);\n            } catch (IOException e) {\n                EnhancedBlockEntities.LOG.error(\"Error loading experimental beds!\", e);\n                config.experimentalBeds = false;\n                config.save();\n            }\n        }\n        if (config.renderEnhancedSigns && config.experimentalSigns) {\n            try {\n                if (RESOURCES != null) setupSigns(RESOURCES);\n            } catch (IOException e) {\n                EnhancedBlockEntities.LOG.error(\"Error loading experimental signs!\", e);\n                config.experimentalSigns = false;\n                config.save();\n            }\n        }\n    }\n\n    public static void setupChests(ResourceManager manager) throws IOException {\n        EBEPack p = ResourceUtil.getTopLevelPack();\n\n        ResourceHacks.addChestParticleTexture(\"chest\", \"entity/chest/normal\", manager, p);\n        ResourceHacks.addChestParticleTexture(\"trapped_chest\", \"entity/chest/trapped\", manager, p);\n        ResourceHacks.addChestParticleTexture(\"ender_chest\", \"entity/chest/ender\", manager, p);\n        ResourceHacks.addChestParticleTexture(\"christmas_chest\", \"entity/chest/christmas\", manager, p);\n    }\n\n    public static void setupBeds(ResourceManager manager) throws IOException {\n        EBEPack p = ResourceUtil.getTopLevelPack();\n\n        for (var color : DyeColor.values()) {\n            ResourceHacks.addBedParticleTexture(color.getName(), \"entity/bed/\"+color.getName(), manager, p);\n        }\n    }\n\n    public static void setupSigns(ResourceManager manager) throws IOException {\n        EBEPack p = ResourceUtil.getTopLevelPack();\n\n        ResourceHacks.addSignParticleTexture(\"oak\", \"entity/signs/oak\", manager, p);\n        ResourceHacks.addSignParticleTexture(\"birch\", \"entity/signs/birch\", manager, p);\n        ResourceHacks.addSignParticleTexture(\"spruce\", \"entity/signs/spruce\", manager, p);\n        ResourceHacks.addSignParticleTexture(\"jungle\", \"entity/signs/jungle\", manager, p);\n        ResourceHacks.addSignParticleTexture(\"acacia\", \"entity/signs/acacia\", manager, p);\n        ResourceHacks.addSignParticleTexture(\"dark_oak\", \"entity/signs/dark_oak\", manager, p);\n        ResourceHacks.addSignParticleTexture(\"mangrove\", \"entity/signs/mangrove\", manager, p);\n        ResourceHacks.addSignParticleTexture(\"cherry\", \"entity/signs/cherry\", manager, p);\n        ResourceHacks.addSignParticleTexture(\"crimson\", \"entity/signs/crimson\", manager, p);\n        ResourceHacks.addSignParticleTexture(\"warped\", \"entity/signs/warped\", manager, p);\n        ResourceHacks.addSignParticleTexture(\"bamboo\", \"entity/signs/bamboo\", manager, p);\n    }\n\n    public static void cacheResources(ResourceManager resources) {\n        RESOURCES = resources;\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/util/hacks/ResourceHacks.java",
    "content": "package foundationgames.enhancedblockentities.util.hacks;\n\nimport foundationgames.enhancedblockentities.client.resource.EBEPack;\nimport net.minecraft.resource.ResourceManager;\nimport net.minecraft.util.Identifier;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.NoSuchElementException;\n\npublic enum ResourceHacks {;\n    private static void cropAndPutTexture(Identifier source, Identifier result, ResourceManager manager, EBEPack pack, float u0, float v0, float u1, float v1) throws IOException {\n        InputStream image;\n        try {\n            image = manager.getResource(source).orElseThrow().getInputStream();\n        } catch (IOException | NoSuchElementException e) {\n            return;\n        }\n        if (image == null) return;\n\n        TextureHacks.cropImage(image, u0, v0, u1, v1).ifPresent(imgBytes -> pack.addResource(result, imgBytes));\n        image.close();\n    }\n\n    public static void addChestParticleTexture(String chestName, String chestTexture, ResourceManager manager, EBEPack pack) throws IOException {\n        cropAndPutTexture(\n                Identifier.of(\"textures/\"+chestTexture+\".png\"), Identifier.of(\"textures/block/\"+chestName+\"_particle.png\"),\n                manager, pack,\n                42f/64, 33f/64, 58f/64, 49f/64\n        );\n    }\n\n    public static void addBedParticleTexture(String bedColor, String bedTexture, ResourceManager manager, EBEPack pack) throws IOException {\n        cropAndPutTexture(\n                Identifier.of(\"textures/\"+bedTexture+\".png\"), Identifier.of(\"textures/block/\"+bedColor+\"_bed_particle.png\"),\n                manager, pack,\n                18f/64, 6f/64, 34f/64, 22f/64\n        );\n    }\n\n    public static void addSignParticleTexture(String signType, String signTexture, ResourceManager manager, EBEPack pack) throws IOException {\n        cropAndPutTexture(\n                Identifier.of(\"textures/\"+signTexture+\".png\"), Identifier.of(\"textures/block/\"+signType+\"_sign_particle.png\"),\n                manager, pack,\n                0, 3f/32, 16f/64, 19f/32\n        );\n    }\n}\n"
  },
  {
    "path": "src/main/java/foundationgames/enhancedblockentities/util/hacks/TextureHacks.java",
    "content": "package foundationgames.enhancedblockentities.util.hacks;\n\nimport net.minecraft.client.texture.NativeImage;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.channels.Channels;\nimport java.nio.channels.WritableByteChannel;\nimport java.util.Optional;\n\npublic enum TextureHacks {;\n    public static Optional<byte[]> cropImage(@Nullable InputStream image, float u0, float v0, float u1, float v1) throws IOException {\n        byte[] r = new byte[0];\n        if (image != null) {\n            try {\n                NativeImage src = NativeImage.read(NativeImage.Format.RGBA, image);\n\n                int w = src.getWidth();\n                int h = src.getHeight();\n                int x = (int)Math.floor(u0 * w);\n                int y = (int)Math.floor(v0 * h);\n                int sw = (int)Math.floor((u1 - u0) * w);\n                int sh = (int)Math.floor((v1 - v0) * h);\n                NativeImage prod = new NativeImage(src.getFormat(), sw, sh, false);\n                for (int u = 0; u < sw; u++) {\n                    for (int v = 0; v < sh; v++) {\n                        prod.setColorArgb(u, v, src.getColorArgb(x + u, y + v));\n                    }\n                }\n                src.close();\n                try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();\n                     WritableByteChannel writableByteChannel = Channels.newChannel(byteArrayOutputStream)) {\n\n                    if (!prod.write(writableByteChannel)) {\n                        throw new IOException(\"Could not write cropped image to byte array\");\n                    }\n\n                    r = byteArrayOutputStream.toByteArray();\n                }\n                prod.close();\n            } catch (IllegalArgumentException e) {\n                return Optional.empty();\n            }\n        }\n        return Optional.of(r);\n    }\n}\n"
  },
  {
    "path": "src/main/resources/assets/enhancedblockentities/lang/en_us.json",
    "content": "{\n    \"option.ebe.config\": \"Block Entities...\",\n\n    \"value.ebe.true\": \"On\",\n    \"value.ebe.false\": \"Off\",\n    \"value.ebe.allowed\": \"Allowed\",\n    \"value.ebe.forced\": \"Forced\",\n    \"value.ebe.disabled\": \"Disabled\",\n    \"value.ebe.smart\": \"Smart\",\n    \"value.ebe.all\": \"All\",\n    \"value.ebe.most\": \"Most\",\n    \"value.ebe.some\": \"Some\",\n    \"value.ebe.few\": \"Few\",\n\n    \"option.ebe.render_enhanced_chests\": \"Enhanced Chests\",\n    \"option.ebe.render_enhanced_chests.comment\": \"Enables baked chest models, greatly improving performance in areas with lots of chests. Also allows for seeing chests from far distances. Disable if chests appear invisible due to another mod.\",\n    \"option.ebe.render_enhanced_signs\": \"Enhanced Signs\",\n    \"option.ebe.render_enhanced_signs.comment\": \"Enables baked sign models and smart sign text rendering, greatly improving performance in areas with lots of signs. Also allows for seeing signs from far distances. Disable if signs appear invisible due to another mod.\",\n    \"option.ebe.render_enhanced_bells\": \"Enhanced Bells\",\n    \"option.ebe.render_enhanced_bells.comment\": \"Enables fully baked bell models, greatly improving performance in areas with lots of bells. Also allows for seeing bells from far distances. Disable if bells appear invisible due to another mod.\",\n    \"option.ebe.render_enhanced_beds\": \"Enhanced Beds\",\n    \"option.ebe.render_enhanced_beds.comment\": \"Enables baked bed models, greatly improving performance in areas with lots of beds. Also allows for seeing beds from far distances. Disable if beds appear invisible due to another mod.\",\n    \"option.ebe.render_enhanced_shulker_boxes\": \"Enhanced Shulker Boxes\",\n    \"option.ebe.render_enhanced_shulker_boxes.comment\": \"Enables baked shulker box models, greatly improving performance in areas with lots of shulker boxes. Also allows for seeing shulker boxes from far distances. Disable if shulker boxes appear invisible due to another mod.\",\n    \"option.ebe.render_enhanced_decorated_pots\": \"Enhanced Decorated Pots\",\n    \"option.ebe.render_enhanced_decorated_pots.comment\": \"Enables baked decorated pot models, greatly improving performance in areas with lots of decorated pots. Also allows for seeing decorated pots from far distances. Disable if decorated pots appear invisible, or if modded pottery patterns are not working properly.\",\n    \"option.ebe.chest_ao\": \"Smooth Chest Lighting\",\n    \"option.ebe.chest_ao.comment\": \"Allows for chests to use smooth lighting and ambient occlusion. Requires Enhanced Chests to be enabled.\",\n    \"option.ebe.sign_ao\": \"Smooth Sign Lighting\",\n    \"option.ebe.sign_ao.comment\": \"Allows for signs to use smooth lighting and ambient occlusion. Requires Enhanced Signs to be enabled.\",\n    \"option.ebe.bell_ao\": \"Smooth Bell Lighting\",\n    \"option.ebe.bell_ao.comment\": \"Allows for bells to use smooth lighting and ambient occlusion. Requires Enhanced Bells to be enabled.\",\n    \"option.ebe.bed_ao\": \"Smooth Bed Lighting\",\n    \"option.ebe.bed_ao.comment\": \"Allows for beds to use smooth lighting and ambient occlusion. Requires Enhanced Beds to be enabled.\",\n    \"option.ebe.shulker_box_ao\": \"Smooth Shulker Box Lighting\",\n    \"option.ebe.shulker_box_ao.comment\": \"Allows for shulker boxes to use smooth lighting and ambient occlusion. Requires Enhanced Shulker Boxes to be enabled.\",\n    \"option.ebe.decorated_pot_ao\": \"Smooth Decorated Pot Lighting\",\n    \"option.ebe.decorated_pot_ao.comment\": \"Allows for decorated pots to use smooth lighting and ambient occlusion. Requires Enhanced Decorated Pots to be enabled.\",\n    \"option.ebe.christmas_chests\": \"Christmas Chests\",\n    \"option.ebe.christmas_chests.valueComment.allowed\": \"Allowed - Christmas texture will be applied from December 24th to 26th.\",\n    \"option.ebe.christmas_chests.valueComment.forced\": \"Forced - Christmas texture will always be applied.\",\n    \"option.ebe.christmas_chests.valueComment.disabled\": \"Disabled - Christmas texture will never be applied.\",\n    \"option.ebe.christmas_chests.comment\": \"Either allows, forces, or disables the Christmas chest texture. Requires Enhanced Chests to be enabled.\",\n    \"option.ebe.sign_text_rendering\": \"Sign Text Rendering\",\n    \"option.ebe.sign_text_rendering.valueComment.smart\": \"Smart - The maximum render distance will be automatically determined based on how many signs are rendering at once.\",\n    \"option.ebe.sign_text_rendering.valueComment.all\": \"All - All signs within block entity render distance will try to render text. Very performance heavy.\",\n    \"option.ebe.sign_text_rendering.valueComment.most\": \"Most - All signs within 50%% of block entity render distance will try to render text.\",\n    \"option.ebe.sign_text_rendering.valueComment.some\": \"Some - All signs within 30%% of block entity render distance will try to render text. \",\n    \"option.ebe.sign_text_rendering.valueComment.few\": \"Few - All signs within 20%% of block entity render distance will try to render text. Highest performance.\",\n    \"option.ebe.sign_text_rendering.comment\": \"Determines the maximum distance from the player that sign text will render. Requires Enhanced Signs to be enabled.\",\n    \"option.ebe.experimental_chests\": \"Experimental Chests\",\n    \"option.ebe.experimental_chests.comment\": \"Enables very experimental rendering features for chests, such as specially generated particle textures which work with resource packs.\",\n    \"option.ebe.experimental_beds\": \"Experimental Beds\",\n    \"option.ebe.experimental_beds.comment\": \"Enables very experimental rendering features for beds, such as specially generated particle textures which work with resource packs.\",\n    \"option.ebe.experimental_signs\": \"Experimental Signs\",\n    \"option.ebe.experimental_signs.comment\": \"Enables very experimental rendering features for signs, such as specially generated particle textures which work with resource packs.\",\n    \"option.ebe.force_resource_pack_compat\": \"Force Resource Pack Compatibility\",\n    \"option.ebe.force_resource_pack_compat.comment\": \"Enable this if blocks are invisible when using resource packs. Do not use with resource packs designed for this mod. If issues continue, report them.\",\n    \"option.ebe.dump\": \"Dump Example Resources\",\n    \"option.ebe.dump.comment\": \"Dumps the mod's default resources to .minecraft/enhanced_bes_dump/ to be used as an example by resource pack makers.\",\n\n    \"warning.ebe.overridden\": \"Overwritten by '%s'\",\n\n    \"screen.ebe.config\": \"Block Entity Settings\",\n\n    \"text.ebe.apply\": \"Apply\",\n    \"text.ebe.descriptions\": \"Hover over options for descriptions\",\n    \"text.ebe.chest_options\": \"Chest Options\",\n    \"text.ebe.sign_options\": \"Sign Options\",\n    \"text.ebe.bell_options\": \"Bell Options\",\n    \"text.ebe.bed_options\": \"Bed Options\",\n    \"text.ebe.shulker_box_options\": \"Shulker Box Options\",\n    \"text.ebe.decorated_pot_options\": \"Decorated Pot Options\",\n    \"text.ebe.advanced\": \"Advanced\",\n    \"text.ebe.option_value_division\": \": \"\n}"
  },
  {
    "path": "src/main/resources/assets/enhancedblockentities/lang/ru_ru.json",
    "content": "{\n    \"option.ebe.config\": \"Блоки-сущности...\",\n\n    \"value.ebe.true\": \"Вкл\",\n    \"value.ebe.false\": \"Выкл\",\n    \"value.ebe.allowed\": \"Разрешены\",\n    \"value.ebe.forced\": \"Включены\",\n    \"value.ebe.disabled\": \"Отключены\",\n    \"value.ebe.smart\": \"Умно\",\n    \"value.ebe.all\": \"Все\",\n    \"value.ebe.most\": \"Половина\",\n    \"value.ebe.some\": \"Меньше\",\n    \"value.ebe.few\": \"Минимум\",\n\n    \"option.ebe.render_enhanced_chests\": \"Улучшенные сундуки\",\n    \"option.ebe.render_enhanced_chests.comment\": \"Позволяет использовать запечённые модели сундуков, что значительно повышает производительность в областях с большим количеством сундуков. Также позволяет видеть сундуки издалека. Отключите, если из-за других модов сундуки становятся невидимыми.\",\n    \"option.ebe.render_enhanced_signs\": \"Улучшенные таблички\",\n    \"option.ebe.render_enhanced_signs.comment\": \"Позволяет использовать запечённые модели табличек и умный рендеринг текста, что значительно повышает производительность в областях с большим количеством табличек. Также позволяет видеть таблички издалека. Отключите, если из-за других модов таблички становятся невидимыми.\",\n    \"option.ebe.render_enhanced_bells\": \"Улучшенные колокола\",\n    \"option.ebe.render_enhanced_bells.comment\": \"Позволяет использовать запечённые модели колоколов, что значительно повышает производительность в областях с большим количеством колоколов. Также позволяет видеть колокола издалека. Отключите, если из-за других модов колокола становятся невидимыми.\",\n    \"option.ebe.render_enhanced_beds\": \"Улучшенные кровати\",\n    \"option.ebe.render_enhanced_beds.comment\": \"Позволяет использовать запечённые модели кроватей, что значительно повышает производительность в областях с большим количеством кроватей. Также позволяет видеть кровати издалека. Отключите, если из-за других модов кровати становятся невидимыми.\",\n    \"option.ebe.render_enhanced_shulker_boxes\": \"Улучшенные шалкеровые ящики\",\n    \"option.ebe.render_enhanced_shulker_boxes.comment\": \"Позволяет использовать запечённые модели шалкеровых ящиков, что значительно повышает производительность в областях с большим количеством шалкеровых ящиков. Также позволяет видеть шалкеровые ящики издалека. Отключите, если из-за других модов шалкеровые ящики становятся невидимыми.\",\n    \"option.ebe.chest_ao\": \"Мягкое освещение сундуков\",\n    \"option.ebe.chest_ao.comment\": \"Позволяет использовать мягкое и объёмное освещение для сундуков. Требует настройки «Улучшенные сундуки».\",\n    \"option.ebe.sign_ao\": \"Мягкое освещение\",\n    \"option.ebe.sign_ao.comment\": \"Позволяет использовать мягкое и объёмное освещение для табличек. Требует настройки «Улучшенные таблички».\",\n    \"option.ebe.bell_ao\": \"Мягкое освещение колоколов\",\n    \"option.ebe.bell_ao.comment\": \"Позволяет использовать мягкое и объёмное освещение для колоколов. Требует настройки «Улучшенные колокола».\",\n    \"option.ebe.bed_ao\": \"Мягкое освещение\",\n    \"option.ebe.bed_ao.comment\": \"Позволяет использовать мягкое и объёмное освещение для кроватей. Требует настройки «Улучшенные кровати».\",\n    \"option.ebe.shulker_box_ao\": \"Мягкое освещение шалкеровых ящиков\",\n    \"option.ebe.shulker_box_ao.comment\": \"Позволяет использовать мягкое и объёмное освещение для сундуков. Требует настройки «Улучшенные шалкеровые ящики».\",\n    \"option.ebe.christmas_chests\": \"Рождественские\",\n    \"option.ebe.christmas_chests.valueComment.allowed\": \"Разрешены - Рождественские текстуры будут отображаться с 24 по 26 декабря.\",\n    \"option.ebe.christmas_chests.valueComment.forced\": \"Включены - Рождественские текстуры будут включены всегда.\",\n    \"option.ebe.christmas_chests.valueComment.disabled\": \"Отключены - Рождественские текстуры будут всегда отключены.\",\n    \"option.ebe.christmas_chests.comment\": \"Разрешает, включает или отключает текстуры рождественских сундуков. Требуется включить улучшенные сундуки.\",\n    \"option.ebe.sign_text_rendering\": \"Отображение текста на табличках\",\n    \"option.ebe.sign_text_rendering.valueComment.smart\": \"Умно - Максимальное расстояние видимости будет определяться автоматически в зависимости от того, сколько символов отображается одновременно.\",\n    \"option.ebe.sign_text_rendering.valueComment.all\": \"Все - Все таблички в пределах расстояния видимости блоков-сущностей будут пытаться отобразить текст. Сильно снижает производительность.\",\n    \"option.ebe.sign_text_rendering.valueComment.most\": \"Половина - Все таблички в пределах 50%% расстояния видимости блоков-сущностей будут пытаться отобразить текст.\",\n    \"option.ebe.sign_text_rendering.valueComment.some\": \"Меньше - Все таблички в пределах 30%% расстояния видимости блоков-сущностей будут пытаться отобразить текст.\",\n    \"option.ebe.sign_text_rendering.valueComment.few\": \"Минимум - Все таблички в пределах 20%% расстояния рендеринга блоков-сущностей будут пытаться отобразить текст, наилучшая производительность.\",\n    \"option.ebe.sign_text_rendering.comment\": \"Определяет максимальное расстояние от игрока, на котором будет отображаться текст табличек. Необходимо включить «Улучшенные таблички».\",\n    \"option.ebe.experimental_chests\": \"Экспериментальные\",\n    \"option.ebe.experimental_chests.comment\": \"Активирует крайне экспериментальные функции рендеринга для сундуков, такие как специально сгенерированные текстуры частиц, работающие с пакетами ресурсов.\",\n    \"option.ebe.experimental_beds\": \"Экспериментальные\",\n    \"option.ebe.experimental_beds.comment\": \"Активирует крайне экспериментальные функции рендеринга для кроватей, такие как специально сгенерированные текстуры частиц, работающие с пакетами ресурсов.\",\n    \"option.ebe.experimental_signs\": \"Экспериментальные\",\n    \"option.ebe.experimental_signs.comment\": \"Активирует крайне экспериментальные функции рендеринга для табличек, такие как специально сгенерированные текстуры частиц, работающие с пакетами ресурсов.\",\n    \"option.ebe.dump\": \"Выгрузить пример ресурсов\",\n    \"option.ebe.dump.comment\": \"Выгружает базовые ресурсы мода в .minecraft/enhanced_bes_dump для их использования создателями наборов ресурсов в качестве образца.\",\n\n    \"screen.ebe.config\": \"Настройки блоков-сущностей\",\n\n    \"text.ebe.apply\": \"Применить\",\n    \"text.ebe.descriptions\": \"Наведите мышь для отображения описания\",\n    \"text.ebe.chest_options\": \"Настройки сундуков\",\n    \"text.ebe.sign_options\": \"Настройки табличек\",\n    \"text.ebe.bell_options\": \"Настройки колоколов\",\n    \"text.ebe.bed_options\": \"Настройки кроватей\",\n    \"text.ebe.shulker_box_options\": \"Настройки шалкеровых ящиков\",\n    \"text.ebe.advanced\": \"Расширенные\",\n    \"text.ebe.option_value_division\": \": \",\n\n    \"modmenu.summaryTranslation.enhancedblockentities\": \"Современный подход к оптимизации и персонализации блоков-сущностей.\",\n    \"modmenu.descriptionTranslation.enhancedblockentities\": \"Клиентский мод для Fabric, предназначенный для повышения производительности при отрисовке блоков-сущностей и расширения возможностей их персонализации при помощи наборов ресурсов.\"\n}\n"
  },
  {
    "path": "src/main/resources/assets/enhancedblockentities/lang/zh_cn.json",
    "content": "{\n    \"option.ebe.config\": \"方块实体...\",\n\n    \"value.ebe.true\": \"开\",\n    \"value.ebe.false\": \"关\",\n    \"value.ebe.allowed\": \"允许\",\n    \"value.ebe.forced\": \"一直\",\n    \"value.ebe.disabled\": \"禁用\",\n    \"value.ebe.smart\": \"智能\",\n    \"value.ebe.all\": \"全部\",\n    \"value.ebe.most\": \"多数\",\n    \"value.ebe.some\": \"部分\",\n    \"value.ebe.few\": \"少量\",\n\n    \"option.ebe.render_enhanced_chests\": \"优化箱子\",\n    \"option.ebe.render_enhanced_chests.comment\": \"启用烘焙箱子模型，极大地提高了多箱子区域的性能。还能在远处看见箱子。如果箱子不可见，可能是由其他mod引起的，尝试禁用解决。\",\n    \"option.ebe.render_enhanced_signs\": \"优化告示牌\",\n    \"option.ebe.render_enhanced_signs.comment\": \"启用烘焙告示牌模型和智能告示牌文本渲染，极大地提高了多告示牌区域的性能。还能从远处看见告示牌。如果告示牌不可见，可能是由其他mod引起的，尝试禁用解决。\",\n    \"option.ebe.render_enhanced_bells\": \"优化钟\",\n    \"option.ebe.render_enhanced_bells.comment\": \"启用完整的烘焙钟模型，极大地提高了多钟区域的性能。还能在远处看见钟。如果钟不可见，可能是由其他mod引起的，尝试禁用解决。\",\n    \"option.ebe.render_enhanced_beds\": \"优化床\",\n    \"option.ebe.render_enhanced_beds.comment\": \"启用烘焙床模型，极大地提高了多床区域的性能。还能在远程看见床。如果床不可见，可能是由其他mod引起的，尝试禁用解决。\",\n    \"option.ebe.render_enhanced_shulker_boxes\": \"优化潜影盒\",\n    \"option.ebe.render_enhanced_shulker_boxes.comment\": \"启用烘焙潜影盒模型，极大地提高了多潜影盒区域的性能。还能在远处看见潜影盒。如果潜影盒不可见，可能是由其他mod引起的，尝试禁用解决。\",\n    \"option.ebe.chest_ao\": \"平滑箱子光照\",\n    \"option.ebe.chest_ao.comment\": \"允许箱子使用平滑光照和环境光遮蔽。需要启用优化箱子。\",\n    \"option.ebe.sign_ao\": \"平滑告示牌光照\",\n    \"option.ebe.sign_ao.comment\": \"允许告示牌使用平滑光照和环境光遮蔽。需要启用优化告示牌。\",\n    \"option.ebe.bell_ao\": \"平滑钟光照\",\n    \"option.ebe.bell_ao.comment\": \"允许钟使用平滑光照和环境光遮蔽。需要启用优化钟。\",\n    \"option.ebe.bed_ao\": \"平滑床光照\",\n    \"option.ebe.bed_ao.comment\": \"允许床使用平滑光照和环境光遮蔽。需要启用优化床。\",\n    \"option.ebe.shulker_box_ao\": \"平滑潜影盒光照\",\n    \"option.ebe.shulker_box_ao.comment\": \"允许潜影盒使用平滑光照和环境光遮蔽。需要启用优化潜影盒\",\n    \"option.ebe.christmas_chests\": \"圣诞箱子\",\n    \"option.ebe.christmas_chests.valueComment.allowed\": \"允许 - 圣诞节纹理将于12月24日至26日应用。\",\n    \"option.ebe.christmas_chests.valueComment.forced\": \"一直 - 圣诞节纹理将永远应用。\",\n    \"option.ebe.christmas_chests.valueComment.disabled\": \"禁用 - 圣诞节纹理将永远不会应用。\",\n    \"option.ebe.christmas_chests.comment\": \"允许、一直或禁用圣诞节箱子纹理。需要启用优化箱子。\",\n    \"option.ebe.sign_text_rendering\": \"告示牌文本渲染\",\n    \"option.ebe.sign_text_rendering.valueComment.smart\": \"智能 - 最大渲染距离将根据一次渲染多少个告示牌来自动确定。\",\n    \"option.ebe.sign_text_rendering.valueComment.all\": \"全部 - 方块实体渲染距离内的所有告示牌都会尝试渲染文本。非常注重性能。\",\n    \"option.ebe.sign_text_rendering.valueComment.most\": \"多数 - 方块实体渲染距离50%%以内的所有告示牌都会尝试渲染文本。\",\n    \"option.ebe.sign_text_rendering.valueComment.some\": \"部分 - 方块实体渲染距离30%%以内的所有告示牌都会尝试渲染文本。\",\n    \"option.ebe.sign_text_rendering.valueComment.few\": \"少量 - 方块实体渲染距离20%%以内的所有告示牌都会尝试渲染文本。最佳性能。\",\n    \"option.ebe.sign_text_rendering.comment\": \"确定玩家渲染告示牌文本的最大距离。需要启用优化告示牌。\",\n    \"option.ebe.experimental_chests\": \"实验性箱子\",\n    \"option.ebe.experimental_chests.comment\": \"为箱子启用非常实验性的渲染功能，例如与资源包一起使用时特殊生成的粒子纹理。\",\n    \"option.ebe.experimental_beds\": \"实验性床\",\n    \"option.ebe.experimental_beds.comment\": \"为床启用非常实验性的渲染功能，例如与资源包一起使用时特殊生成的粒子纹理。\",\n    \"option.ebe.experimental_signs\": \"实验性告示牌\",\n    \"option.ebe.experimental_signs.comment\": \"为告示牌启用非常实验性的渲染功能，例如与资源包一起使用时特殊生成的粒子纹理。\",\n    \"option.ebe.dump\": \"导出示例资源\",\n    \"option.ebe.dump.comment\": \"导出本模组的默认资源到.minecraft/enhanced_bes_dump/用于资源包制作者当做一个示例。\",\n\n    \"screen.ebe.config\": \"方块实体设置\",\n\n    \"text.ebe.apply\": \"应用\",\n    \"text.ebe.descriptions\": \"将鼠标悬停在选项上查看描述\",\n    \"text.ebe.chest_options\": \"箱子\",\n    \"text.ebe.sign_options\": \"告示牌\",\n    \"text.ebe.bell_options\": \"钟\",\n    \"text.ebe.bed_options\": \"床\",\n    \"text.ebe.shulker_box_options\": \"潜影盒\",\n    \"text.ebe.option_value_division\": \"：\"\n}\n"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/bell_between_walls_with_bell.json",
    "content": "{\n\t\"textures\": {\n\t\t\"bell\": \"entity/bell/bell_body\",\n\t\t\"bar\": \"block/dark_oak_planks\",\n\t\t\"particle\": \"entity/bell/bell_body\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [0, 13, 7],\n\t\t\t\"to\": [16, 15, 9],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [2, 2, 14, 4], \"texture\": \"#bar\"},\n\t\t\t\t\"east\": {\"uv\": [5, 4, 7, 6], \"texture\": \"#bar\", \"cullface\": \"east\"},\n\t\t\t\t\"south\": {\"uv\": [2, 3, 14, 5], \"texture\": \"#bar\"},\n\t\t\t\t\"west\": {\"uv\": [5, 4, 7, 6], \"texture\": \"#bar\", \"cullface\": \"west\"},\n\t\t\t\t\"up\": {\"uv\": [2, 3, 14, 5], \"texture\": \"#bar\"},\n\t\t\t\t\"down\": {\"uv\": [2, 3, 14, 5], \"texture\": \"#bar\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [5, 6, 5],\n\t\t\t\"to\": [11, 13, 11],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [3, 3, 6, 6.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3, 3, 6.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"south\": {\"uv\": [9, 3, 12, 6.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"west\": {\"uv\": [6, 3, 9, 6.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"up\": {\"uv\": [3, 0, 6, 3], \"rotation\": 180, \"texture\": \"#bell\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [4, 4, 4],\n\t\t\t\"to\": [12, 6, 12],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [4, 10.5, 8, 11.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"east\": {\"uv\": [0, 10.5, 4, 11.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"south\": {\"uv\": [4, 10.5, 8, 11.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"west\": {\"uv\": [8, 10.5, 12, 11.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"up\": {\"uv\": [4, 6.5, 8, 10.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"down\": {\"uv\": [8, 6.5, 12, 10.5], \"rotation\": 180, \"texture\": \"#bell\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/bell_body.json",
    "content": "{\n\t\"texture_size\": [32, 32],\n\t\"textures\": {\n\t\t\"bell\": \"entity/bell/bell_body\",\n\t\t\"particle\": \"entity/bell/bell_body\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [5, 6, 5],\n\t\t\t\"to\": [11, 13, 11],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [3, 3, 6, 6.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3, 3, 6.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"south\": {\"uv\": [9, 3, 12, 6.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"west\": {\"uv\": [6, 3, 9, 6.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"up\": {\"uv\": [3, 0, 6, 3], \"rotation\": 180, \"texture\": \"#bell\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [4, 4, 4],\n\t\t\t\"to\": [12, 6, 12],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [4, 10.5, 8, 11.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"east\": {\"uv\": [0, 10.5, 4, 11.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"south\": {\"uv\": [4, 10.5, 8, 11.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"west\": {\"uv\": [8, 10.5, 12, 11.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"up\": {\"uv\": [4, 6.5, 8, 10.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"down\": {\"uv\": [8, 6.5, 12, 10.5], \"rotation\": 180, \"texture\": \"#bell\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/bell_ceiling_with_bell.json",
    "content": "{\n\t\"textures\": {\n\t\t\"bell\": \"entity/bell/bell_body\",\n\t\t\"bar\": \"block/dark_oak_planks\",\n\t\t\"particle\": \"entity/bell/bell_body\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [7, 13, 7],\n\t\t\t\"to\": [9, 16, 9],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [7, 2, 9, 5], \"texture\": \"#bar\"},\n\t\t\t\t\"east\": {\"uv\": [1, 2, 3, 5], \"texture\": \"#bar\"},\n\t\t\t\t\"south\": {\"uv\": [6, 2, 8, 5], \"texture\": \"#bar\"},\n\t\t\t\t\"west\": {\"uv\": [4, 2, 6, 5], \"texture\": \"#bar\"},\n\t\t\t\t\"up\": {\"uv\": [1, 3, 3, 5], \"texture\": \"#bar\", \"cullface\": \"up\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [5, 6, 5],\n\t\t\t\"to\": [11, 13, 11],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [3, 3, 6, 6.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3, 3, 6.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"south\": {\"uv\": [9, 3, 12, 6.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"west\": {\"uv\": [6, 3, 9, 6.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"up\": {\"uv\": [3, 0, 6, 3], \"rotation\": 180, \"texture\": \"#bell\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [4, 4, 4],\n\t\t\t\"to\": [12, 6, 12],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [4, 10.5, 8, 11.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"east\": {\"uv\": [0, 10.5, 4, 11.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"south\": {\"uv\": [4, 10.5, 8, 11.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"west\": {\"uv\": [8, 10.5, 12, 11.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"up\": {\"uv\": [4, 6.5, 8, 10.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"down\": {\"uv\": [8, 6.5, 12, 10.5], \"rotation\": 180, \"texture\": \"#bell\"}\n\t\t\t}\n\t\t}\n\t],\n\t\"groups\": [0,\n\t\t{\n\t\t\t\"name\": \"bell_base_DELETETHIS\",\n\t\t\t\"origin\": [8, 8, 8],\n\t\t\t\"children\": [1, 2]\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/bell_floor_with_bell.json",
    "content": "{\n\t\"textures\": {\n\t\t\"bell\": \"entity/bell/bell_body\",\n\t\t\"bar\": \"block/dark_oak_planks\",\n\t\t\"post\": \"block/stone\",\n\t\t\"particle\": \"entity/bell/bell_body\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [2, 13, 7],\n\t\t\t\"to\": [14, 15, 9],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [2, 2, 14, 4], \"texture\": \"#bar\"},\n\t\t\t\t\"south\": {\"uv\": [2, 3, 14, 5], \"texture\": \"#bar\"},\n\t\t\t\t\"up\": {\"uv\": [2, 3, 14, 5], \"texture\": \"#bar\"},\n\t\t\t\t\"down\": {\"uv\": [2, 3, 14, 5], \"texture\": \"#bar\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [14, 0, 6],\n\t\t\t\"to\": [16, 16, 10],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 1, 2, 16], \"texture\": \"#post\"},\n\t\t\t\t\"east\": {\"uv\": [0, 1, 4, 16], \"texture\": \"#post\", \"cullface\": \"east\"},\n\t\t\t\t\"south\": {\"uv\": [0, 1, 2, 16], \"texture\": \"#post\"},\n\t\t\t\t\"west\": {\"uv\": [0, 1, 4, 16], \"texture\": \"#post\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 2, 4], \"texture\": \"#post\", \"cullface\": \"up\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 2, 4], \"texture\": \"#post\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [0, 0, 6],\n\t\t\t\"to\": [2, 16, 10],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 1, 2, 16], \"texture\": \"#post\"},\n\t\t\t\t\"east\": {\"uv\": [0, 1, 4, 16], \"texture\": \"#post\"},\n\t\t\t\t\"south\": {\"uv\": [0, 1, 2, 16], \"texture\": \"#post\"},\n\t\t\t\t\"west\": {\"uv\": [0, 1, 4, 16], \"texture\": \"#post\", \"cullface\": \"west\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 2, 4], \"texture\": \"#post\", \"cullface\": \"up\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 2, 4], \"texture\": \"#post\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [5, 6, 5],\n\t\t\t\"to\": [11, 13, 11],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [3, 3, 6, 6.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3, 3, 6.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"south\": {\"uv\": [9, 3, 12, 6.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"west\": {\"uv\": [6, 3, 9, 6.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"up\": {\"uv\": [3, 0, 6, 3], \"rotation\": 180, \"texture\": \"#bell\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [4, 4, 4],\n\t\t\t\"to\": [12, 6, 12],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [4, 10.5, 8, 11.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"east\": {\"uv\": [0, 10.5, 4, 11.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"south\": {\"uv\": [4, 10.5, 8, 11.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"west\": {\"uv\": [8, 10.5, 12, 11.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"up\": {\"uv\": [4, 6.5, 8, 10.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"down\": {\"uv\": [8, 6.5, 12, 10.5], \"rotation\": 180, \"texture\": \"#bell\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/bell_wall_with_bell.json",
    "content": "{\n\t\"textures\": {\n\t\t\"bell\": \"entity/bell/bell_body\",\n\t\t\"bar\": \"block/dark_oak_planks\",\n\t\t\"particle\": \"entity/bell/bell_body\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [3, 13, 7],\n\t\t\t\"to\": [16, 15, 9],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [2, 2, 14, 4], \"texture\": \"#bar\"},\n\t\t\t\t\"east\": {\"uv\": [5, 4, 7, 6], \"texture\": \"#bar\", \"cullface\": \"east\"},\n\t\t\t\t\"south\": {\"uv\": [2, 3, 14, 5], \"texture\": \"#bar\"},\n\t\t\t\t\"west\": {\"uv\": [5, 4, 7, 6], \"texture\": \"#bar\"},\n\t\t\t\t\"up\": {\"uv\": [2, 3, 14, 5], \"texture\": \"#bar\"},\n\t\t\t\t\"down\": {\"uv\": [2, 3, 14, 5], \"texture\": \"#bar\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [5, 6, 5],\n\t\t\t\"to\": [11, 13, 11],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [3, 3, 6, 6.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3, 3, 6.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"south\": {\"uv\": [9, 3, 12, 6.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"west\": {\"uv\": [6, 3, 9, 6.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"up\": {\"uv\": [3, 0, 6, 3], \"rotation\": 180, \"texture\": \"#bell\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [4, 4, 4],\n\t\t\t\"to\": [12, 6, 12],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [4, 10.5, 8, 11.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"east\": {\"uv\": [0, 10.5, 4, 11.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"south\": {\"uv\": [4, 10.5, 8, 11.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"west\": {\"uv\": [8, 10.5, 12, 11.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"up\": {\"uv\": [4, 6.5, 8, 10.5], \"rotation\": 180, \"texture\": \"#bell\"},\n\t\t\t\t\"down\": {\"uv\": [8, 6.5, 12, 10.5], \"rotation\": 180, \"texture\": \"#bell\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/decorated_pot_base.json",
    "content": "{\n\t\"parent\": \"block/block\",\n\t\"texture_size\": [32, 32],\n\t\"textures\": {\n\t\t\"0\": \"entity/decorated_pot/decorated_pot_base\",\n\t\t\"particle\": \"minecraft:block/terracotta\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 1],\n\t\t\t\"to\": [15, 16, 15],\n\t\t\t\"faces\": {\n\t\t\t\t\"up\": {\"uv\": [7, 6.5, 14, 13.5], \"texture\": \"#0\", \"cullface\": \"up\"},\n\t\t\t\t\"down\": {\"uv\": [0, 6.5, 7, 13.5], \"texture\": \"#0\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [4.8, 15.8, 4.8],\n\t\t\t\"to\": [11.2, 17.2, 11.2],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [3, 5.5, 6, 6], \"texture\": \"#0\"},\n\t\t\t\t\"east\": {\"uv\": [0, 5.5, 3, 6], \"texture\": \"#0\"},\n\t\t\t\t\"south\": {\"uv\": [9, 5.5, 12, 6], \"texture\": \"#0\"},\n\t\t\t\t\"west\": {\"uv\": [6, 5.5, 9, 6], \"texture\": \"#0\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [4.1, 17.1, 4.1],\n\t\t\t\"to\": [11.9, 19.9, 11.9],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [4, 4, 8, 5.5], \"texture\": \"#0\"},\n\t\t\t\t\"east\": {\"uv\": [0, 4, 4, 5.5], \"texture\": \"#0\"},\n\t\t\t\t\"south\": {\"uv\": [12, 4, 16, 5.5], \"texture\": \"#0\"},\n\t\t\t\t\"west\": {\"uv\": [8, 4, 12, 5.5], \"texture\": \"#0\"},\n\t\t\t\t\"up\": {\"uv\": [4, 0, 8, 4], \"texture\": \"#0\"},\n\t\t\t\t\"down\": {\"uv\": [8, 0, 12, 4], \"texture\": \"#0\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/decorated_pot_shaking.json",
    "content": "{\n  \"textures\": {\n    \"particle\": \"minecraft:block/terracotta\"\n  }\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_bed_foot.json",
    "content": "{\n\t\"ambientocclusion\": false,\n\t\"texture_size\": [64, 64],\n\t\"textures\": {\n\t\t\"particle\": \"#bed\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [0, 0, 13],\n\t\t\t\"to\": [3, 3, 16],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [1.5, 0, 14.5]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [14.75, 0.75, 15.5, 1.5], \"texture\": \"#bed\"},\n\t\t\t\t\"east\": {\"uv\": [14, 0.75, 14.75, 1.5], \"texture\": \"#bed\"},\n\t\t\t\t\"south\": {\"uv\": [13.25, 0.75, 14, 1.5], \"texture\": \"#bed\", \"cullface\": \"south\"},\n\t\t\t\t\"west\": {\"uv\": [12.5, 0.75, 13.25, 1.5], \"texture\": \"#bed\", \"cullface\": \"west\"},\n\t\t\t\t\"down\": {\"uv\": [14, 0, 14.75, 0.75], \"texture\": \"#bed\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [13, 0, 13],\n\t\t\t\"to\": [16, 3, 16],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [14.5, 0, 14.5]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [14, 3.75, 14.75, 4.5], \"texture\": \"#bed\"},\n\t\t\t\t\"east\": {\"uv\": [13.25, 3.75, 14, 4.5], \"texture\": \"#bed\", \"cullface\": \"east\"},\n\t\t\t\t\"south\": {\"uv\": [12.5, 3.75, 13.25, 4.5], \"texture\": \"#bed\", \"cullface\": \"south\"},\n\t\t\t\t\"west\": {\"uv\": [14.75, 3.75, 15.5, 4.5], \"texture\": \"#bed\"},\n\t\t\t\t\"down\": {\"uv\": [14, 3, 14.75, 3.75], \"rotation\": 90, \"texture\": \"#bed\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [0, 3, 0],\n\t\t\t\"to\": [16, 9, 16],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"x\", \"origin\": [0, 3, 16]},\n\t\t\t\"faces\": {\n\t\t\t\t\"east\": {\"uv\": [5.5, 7, 7, 11], \"rotation\": 90, \"texture\": \"#bed\", \"cullface\": \"east\"},\n\t\t\t\t\"south\": {\"uv\": [5.5, 5.5, 9.5, 7], \"rotation\": 180, \"texture\": \"#bed\", \"cullface\": \"south\"},\n\t\t\t\t\"west\": {\"uv\": [0, 7, 1.5, 11], \"rotation\": 270, \"texture\": \"#bed\", \"cullface\": \"west\"},\n\t\t\t\t\"up\": {\"uv\": [1.5, 7, 5.5, 11], \"texture\": \"#bed\"},\n\t\t\t\t\"down\": {\"uv\": [7, 7, 11, 11], \"rotation\": 180, \"texture\": \"#bed\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_bed_foot_ao.json",
    "content": "{\n\t\"ambientocclusion\": true,\n\t\"texture_size\": [64, 64],\n\t\"textures\": {\n\t\t\"particle\": \"#bed\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [0, 0, 13],\n\t\t\t\"to\": [3, 3, 16],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [1.5, 0, 14.5]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [14.75, 0.75, 15.5, 1.5], \"texture\": \"#bed\"},\n\t\t\t\t\"east\": {\"uv\": [14, 0.75, 14.75, 1.5], \"texture\": \"#bed\"},\n\t\t\t\t\"south\": {\"uv\": [13.25, 0.75, 14, 1.5], \"texture\": \"#bed\", \"cullface\": \"south\"},\n\t\t\t\t\"west\": {\"uv\": [12.5, 0.75, 13.25, 1.5], \"texture\": \"#bed\", \"cullface\": \"west\"},\n\t\t\t\t\"down\": {\"uv\": [14, 0, 14.75, 0.75], \"texture\": \"#bed\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [13, 0, 13],\n\t\t\t\"to\": [16, 3, 16],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [14.5, 0, 14.5]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [14, 3.75, 14.75, 4.5], \"texture\": \"#bed\"},\n\t\t\t\t\"east\": {\"uv\": [13.25, 3.75, 14, 4.5], \"texture\": \"#bed\", \"cullface\": \"east\"},\n\t\t\t\t\"south\": {\"uv\": [12.5, 3.75, 13.25, 4.5], \"texture\": \"#bed\", \"cullface\": \"south\"},\n\t\t\t\t\"west\": {\"uv\": [14.75, 3.75, 15.5, 4.5], \"texture\": \"#bed\"},\n\t\t\t\t\"down\": {\"uv\": [14, 3, 14.75, 3.75], \"rotation\": 90, \"texture\": \"#bed\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [0, 3, 0],\n\t\t\t\"to\": [16, 9, 16],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"x\", \"origin\": [0, 3, 16]},\n\t\t\t\"faces\": {\n\t\t\t\t\"east\": {\"uv\": [5.5, 7, 7, 11], \"rotation\": 90, \"texture\": \"#bed\", \"cullface\": \"east\"},\n\t\t\t\t\"south\": {\"uv\": [5.5, 5.5, 9.5, 7], \"rotation\": 180, \"texture\": \"#bed\", \"cullface\": \"south\"},\n\t\t\t\t\"west\": {\"uv\": [0, 7, 1.5, 11], \"rotation\": 270, \"texture\": \"#bed\", \"cullface\": \"west\"},\n\t\t\t\t\"up\": {\"uv\": [1.5, 7, 5.5, 11], \"texture\": \"#bed\"},\n\t\t\t\t\"down\": {\"uv\": [7, 7, 11, 11], \"rotation\": 180, \"texture\": \"#bed\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_bed_foot_offset.json",
    "content": "{\n\t\"ambientocclusion\": false,\n\t\"texture_size\": [64, 64],\n\t\"textures\": {\n\t\t\"particle\": \"#bed\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [0, 0, 29],\n\t\t\t\"to\": [3, 3, 32],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [1.5, 0, 14.5]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [14.75, 0.75, 15.5, 1.5], \"texture\": \"#bed\"},\n\t\t\t\t\"east\": {\"uv\": [14, 0.75, 14.75, 1.5], \"texture\": \"#bed\"},\n\t\t\t\t\"south\": {\"uv\": [13.25, 0.75, 14, 1.5], \"texture\": \"#bed\", \"cullface\": \"south\"},\n\t\t\t\t\"west\": {\"uv\": [12.5, 0.75, 13.25, 1.5], \"texture\": \"#bed\", \"cullface\": \"west\"},\n\t\t\t\t\"down\": {\"uv\": [14, 0, 14.75, 0.75], \"texture\": \"#bed\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [13, 0, 29],\n\t\t\t\"to\": [16, 3, 32],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [14.5, 0, 14.5]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [14, 3.75, 14.75, 4.5], \"texture\": \"#bed\"},\n\t\t\t\t\"east\": {\"uv\": [13.25, 3.75, 14, 4.5], \"texture\": \"#bed\", \"cullface\": \"east\"},\n\t\t\t\t\"south\": {\"uv\": [12.5, 3.75, 13.25, 4.5], \"texture\": \"#bed\", \"cullface\": \"south\"},\n\t\t\t\t\"west\": {\"uv\": [14.75, 3.75, 15.5, 4.5], \"texture\": \"#bed\"},\n\t\t\t\t\"down\": {\"uv\": [14, 3, 14.75, 3.75], \"rotation\": 90, \"texture\": \"#bed\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [0, 3, 16],\n\t\t\t\"to\": [16, 9, 32],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"x\", \"origin\": [0, 3, 16]},\n\t\t\t\"faces\": {\n\t\t\t\t\"east\": {\"uv\": [5.5, 7, 7, 11], \"rotation\": 90, \"texture\": \"#bed\", \"cullface\": \"east\"},\n\t\t\t\t\"south\": {\"uv\": [5.5, 5.5, 9.5, 7], \"rotation\": 180, \"texture\": \"#bed\", \"cullface\": \"south\"},\n\t\t\t\t\"west\": {\"uv\": [0, 7, 1.5, 11], \"rotation\": 270, \"texture\": \"#bed\", \"cullface\": \"west\"},\n\t\t\t\t\"up\": {\"uv\": [1.5, 7, 5.5, 11], \"texture\": \"#bed\"},\n\t\t\t\t\"down\": {\"uv\": [7, 7, 11, 11], \"rotation\": 180, \"texture\": \"#bed\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_bed_head.json",
    "content": "{\n\t\"ambientocclusion\": false,\n\t\"texture_size\": [64, 64],\n\t\"textures\": {\n\t\t\"particle\": \"#bed\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [0, 0, 0],\n\t\t\t\"to\": [3, 3, 3],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [1.5, 0, 1.5]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [12.5, 2.25, 13.25, 3], \"texture\": \"#bed\", \"cullface\": \"north\"},\n\t\t\t\t\"east\": {\"uv\": [14.75, 2.25, 15.5, 3], \"texture\": \"#bed\"},\n\t\t\t\t\"south\": {\"uv\": [14, 2.25, 14.75, 3], \"texture\": \"#bed\"},\n\t\t\t\t\"west\": {\"uv\": [13.25, 2.25, 14, 3], \"texture\": \"#bed\", \"cullface\": \"west\"},\n\t\t\t\t\"down\": {\"uv\": [14, 1.5, 14.75, 2.25], \"rotation\": 270, \"texture\": \"#bed\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [13, 0, 0],\n\t\t\t\"to\": [16, 3, 3],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [13.25, 5.25, 14, 6], \"texture\": \"#bed\", \"cullface\": \"north\"},\n\t\t\t\t\"east\": {\"uv\": [12.5, 5.25, 13.25, 6], \"texture\": \"#bed\", \"cullface\": \"east\"},\n\t\t\t\t\"south\": {\"uv\": [14.75, 5.25, 15.5, 6], \"texture\": \"#bed\"},\n\t\t\t\t\"west\": {\"uv\": [14, 5.25, 14.75, 6], \"texture\": \"#bed\"},\n\t\t\t\t\"down\": {\"uv\": [14, 4.5, 14.75, 5.25], \"rotation\": 180, \"texture\": \"#bed\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [0, 3, 0],\n\t\t\t\"to\": [16, 9, 16],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"x\", \"origin\": [0, 3, 16]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 0, 5.5, 1.5], \"rotation\": 180, \"texture\": \"#bed\", \"cullface\": \"north\"},\n\t\t\t\t\"east\": {\"uv\": [5.5, 1.5, 7, 5.5], \"rotation\": 90, \"texture\": \"#bed\", \"cullface\": \"east\"},\n\t\t\t\t\"west\": {\"uv\": [0, 1.5, 1.5, 5.5], \"rotation\": 270, \"texture\": \"#bed\", \"cullface\": \"west\"},\n\t\t\t\t\"up\": {\"uv\": [1.5, 1.5, 5.5, 5.5], \"texture\": \"#bed\"},\n\t\t\t\t\"down\": {\"uv\": [7, 1.5, 11, 5.5], \"rotation\": 180, \"texture\": \"#bed\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_bed_head_ao.json",
    "content": "{\n\t\"ambientocclusion\": true,\n\t\"texture_size\": [64, 64],\n\t\"textures\": {\n\t\t\"particle\": \"#bed\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [0, 0, 0],\n\t\t\t\"to\": [3, 3, 3],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [1.5, 0, 1.5]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [12.5, 2.25, 13.25, 3], \"texture\": \"#bed\", \"cullface\": \"north\"},\n\t\t\t\t\"east\": {\"uv\": [14.75, 2.25, 15.5, 3], \"texture\": \"#bed\"},\n\t\t\t\t\"south\": {\"uv\": [14, 2.25, 14.75, 3], \"texture\": \"#bed\"},\n\t\t\t\t\"west\": {\"uv\": [13.25, 2.25, 14, 3], \"texture\": \"#bed\", \"cullface\": \"west\"},\n\t\t\t\t\"down\": {\"uv\": [14, 1.5, 14.75, 2.25], \"rotation\": 270, \"texture\": \"#bed\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [13, 0, 0],\n\t\t\t\"to\": [16, 3, 3],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [13.25, 5.25, 14, 6], \"texture\": \"#bed\", \"cullface\": \"north\"},\n\t\t\t\t\"east\": {\"uv\": [12.5, 5.25, 13.25, 6], \"texture\": \"#bed\", \"cullface\": \"east\"},\n\t\t\t\t\"south\": {\"uv\": [14.75, 5.25, 15.5, 6], \"texture\": \"#bed\"},\n\t\t\t\t\"west\": {\"uv\": [14, 5.25, 14.75, 6], \"texture\": \"#bed\"},\n\t\t\t\t\"down\": {\"uv\": [14, 4.5, 14.75, 5.25], \"rotation\": 180, \"texture\": \"#bed\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [0, 3, 0],\n\t\t\t\"to\": [16, 9, 16],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"x\", \"origin\": [0, 3, 16]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 0, 5.5, 1.5], \"rotation\": 180, \"texture\": \"#bed\", \"cullface\": \"north\"},\n\t\t\t\t\"east\": {\"uv\": [5.5, 1.5, 7, 5.5], \"rotation\": 90, \"texture\": \"#bed\", \"cullface\": \"east\"},\n\t\t\t\t\"west\": {\"uv\": [0, 1.5, 1.5, 5.5], \"rotation\": 270, \"texture\": \"#bed\", \"cullface\": \"west\"},\n\t\t\t\t\"up\": {\"uv\": [1.5, 1.5, 5.5, 5.5], \"texture\": \"#bed\"},\n\t\t\t\t\"down\": {\"uv\": [7, 1.5, 11, 5.5], \"rotation\": 180, \"texture\": \"#bed\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_chest_center.json",
    "content": "{\n\t\"parent\": \"block/block\",\n\t\"texture_size\": [64, 64],\n\t\"textures\": {\n\t\t\"particle\": \"#chest\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 1],\n\t\t\t\"to\": [15, 10, 15],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [9, 8, 9]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [10.5, 8.25, 14, 10.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"east\": {\"uv\": [0, 8.25, 3.5, 10.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"south\": {\"uv\": [3.5, 8.25, 7, 10.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"west\": {\"uv\": [7, 8.25, 10.5, 10.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"down\": {\"uv\": [3.5, 4.75, 7, 8.25], \"texture\": \"#chest\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [1, 9, 1],\n\t\t\t\"to\": [15, 14, 15],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [9, 18, 9]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [10.5, 3.5, 14, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3.5, 3.5, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"south\": {\"uv\": [3.5, 3.5, 7, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"west\": {\"uv\": [7, 3.5, 10.5, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"up\": {\"uv\": [10.5, 0, 7, 3.5], \"texture\": \"#chest\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [7, 7, 0],\n\t\t\t\"to\": [9, 11, 1],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [15, 15, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1, 0.25, 1.5, 1.25], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0.25, 0.25, 1.25], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"west\": {\"uv\": [0.75, 0.25, 1, 1.25], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"up\": {\"uv\": [1.25, 0, 0.75, 0.25], \"texture\": \"#chest\"},\n\t\t\t\t\"down\": {\"uv\": [0.25, 0, 0.75, 0.25], \"rotation\": 180, \"texture\": \"#chest\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_chest_center_lid.json",
    "content": "{\n\t\"parent\": \"block/block\",\n\t\"texture_size\": [64, 64],\n\t\"textures\": {\n\t\t\"particle\": \"#chest\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 9, 1],\n\t\t\t\"to\": [15, 14, 15],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [9, 18, 9]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [10.5, 3.5, 14, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3.5, 3.5, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"south\": {\"uv\": [3.5, 3.5, 7, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"west\": {\"uv\": [7, 3.5, 10.5, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"up\": {\"uv\": [10.5, 0, 7, 3.5], \"texture\": \"#chest\"},\n\t\t\t\t\"down\": {\"uv\": [3.5, 0, 7, 3.5], \"texture\": \"#chest\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [7, 7, 0],\n\t\t\t\"to\": [9, 11, 1],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [15, 15, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1, 0.25, 1.5, 1.25], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0.25, 0.25, 1.25], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"south\": {\"uv\": [0.25, 0.25, 0.75, 1.25], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"west\": {\"uv\": [0.75, 0.25, 1, 1.25], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"up\": {\"uv\": [1.25, 0, 0.75, 0.25], \"texture\": \"#chest\"},\n\t\t\t\t\"down\": {\"uv\": [0.25, 0, 0.75, 0.25], \"rotation\": 180, \"texture\": \"#chest\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_chest_center_trunk.json",
    "content": "{\n\t\"parent\": \"block/block\",\n\t\"texture_size\": [64, 64],\n\t\"textures\": {\n\t\t\"particle\": \"#chest\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 1],\n\t\t\t\"to\": [15, 10, 15],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [9, 8, 9]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [10.5, 8.25, 14, 10.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"east\": {\"uv\": [0, 8.25, 3.5, 10.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"south\": {\"uv\": [3.5, 8.25, 7, 10.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"west\": {\"uv\": [7, 8.25, 10.5, 10.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"up\": {\"uv\": [7, 4.75, 10.5, 8.25], \"texture\": \"#chest\"},\n\t\t\t\t\"down\": {\"uv\": [3.5, 4.75, 7, 8.25], \"texture\": \"#chest\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_chest_left.json",
    "content": "{\n\t\"parent\": \"block/block\",\n\t\"texture_size\": [64, 64],\n\t\"textures\": {\n\t\t\"particle\": \"#chest\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 1],\n\t\t\t\"to\": [16, 10, 15],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [9, 8, 9]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [10.75, 8.25, 14.5, 10.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"south\": {\"uv\": [3.5, 8.25, 7.25, 10.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"west\": {\"uv\": [7.25, 8.25, 10.75, 10.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"down\": {\"uv\": [7.25, 4.75, 3.5, 8.25], \"texture\": \"#chest\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [1, 9, 1],\n\t\t\t\"to\": [16, 14, 15],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [9, 17, 9]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [10.75, 3.5, 14.5, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3.5, 3.5, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"south\": {\"uv\": [3.5, 3.5, 7.25, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"west\": {\"uv\": [7.25, 3.5, 10.75, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"up\": {\"uv\": [11, 0, 7.25, 3.5], \"texture\": \"#chest\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [15, 7, 0],\n\t\t\t\"to\": [16, 11, 1],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [23, 15, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.75, 0.25, 1, 1.25], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"west\": {\"uv\": [0.5, 0.25, 0.75, 1.25], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 0, 0.75, 0.25], \"texture\": \"#chest\"},\n\t\t\t\t\"down\": {\"uv\": [0.25, 0, 0.5, 0.25], \"texture\": \"#chest\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_chest_left_lid.json",
    "content": "{\n\t\"parent\": \"block/block\",\n\t\"texture_size\": [64, 64],\n\t\"textures\": {\n\t\t\"particle\": \"#chest\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 9, 1],\n\t\t\t\"to\": [16, 14, 15],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [9, 17, 9]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [10.75, 3.5, 14.5, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"south\": {\"uv\": [3.5, 3.5, 7.25, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"west\": {\"uv\": [7.25, 3.5, 10.75, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"up\": {\"uv\": [11, 0, 7.25, 3.5], \"texture\": \"#chest\"},\n\t\t\t\t\"down\": {\"uv\": [7.25, 0, 3.5, 3.5], \"texture\": \"#chest\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [15, 7, 0],\n\t\t\t\"to\": [16, 11, 1],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [23, 15, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.75, 0.25, 1, 1.25], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"south\": {\"uv\": [0.25, 0.25, 0.5, 1.25], \"texture\": \"#chest\"},\n\t\t\t\t\"west\": {\"uv\": [0.5, 0.25, 0.75, 1.25], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 0, 0.75, 0.25], \"texture\": \"#chest\"},\n\t\t\t\t\"down\": {\"uv\": [0.25, 0, 0.5, 0.25], \"texture\": \"#chest\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_chest_left_trunk.json",
    "content": "{\n\t\"parent\": \"block/block\",\n\t\"texture_size\": [64, 64],\n\t\"textures\": {\n\t\t\"particle\": \"#chest\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 1],\n\t\t\t\"to\": [16, 10, 15],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [9, 8, 9]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [10.75, 8.25, 14.5, 10.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"south\": {\"uv\": [3.5, 8.25, 7.25, 10.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"west\": {\"uv\": [7.25, 8.25, 10.75, 10.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"up\": {\"uv\": [11, 4.75, 7.25, 8.25], \"texture\": \"#chest\"},\n\t\t\t\t\"down\": {\"uv\": [7.25, 4.75, 3.5, 8.25], \"texture\": \"#chest\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_chest_right.json",
    "content": "{\n\t\"parent\": \"block/block\",\n\t\"texture_size\": [64, 64],\n\t\"textures\": {\n\t\t\"particle\": \"#chest\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [0, 0, 1],\n\t\t\t\"to\": [15, 10, 15],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 8, 9]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [10.75, 8.25, 14.5, 10.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"east\": {\"uv\": [0, 8.25, 3.5, 10.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"south\": {\"uv\": [3.5, 8.25, 7.25, 10.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"down\": {\"uv\": [7.25, 4.75, 3.5, 8.25], \"texture\": \"#chest\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [0, 9, 1],\n\t\t\t\"to\": [15, 14, 15],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 17, 9]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [10.75, 3.5, 14.5, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3.5, 3.5, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"south\": {\"uv\": [3.5, 3.5, 7.25, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"up\": {\"uv\": [11, 0, 7.25, 3.5], \"texture\": \"#chest\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [0, 7, 0],\n\t\t\t\"to\": [1, 11, 1],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 15, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.75, 0.25, 1, 1.25], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0.25, 0.25, 1.25], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 0, 0.75, 0.25], \"texture\": \"#chest\"},\n\t\t\t\t\"down\": {\"uv\": [0.25, 0, 0.5, 0.25], \"texture\": \"#chest\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_chest_right_lid.json",
    "content": "{\n\t\"parent\": \"block/block\",\n\t\"texture_size\": [64, 64],\n\t\"textures\": {\n\t\t\"particle\": \"#chest\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [0, 9, 1],\n\t\t\t\"to\": [15, 14, 15],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 17, 9]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [10.75, 3.5, 14.5, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3.5, 3.5, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"south\": {\"uv\": [3.5, 3.5, 7.25, 4.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"up\": {\"uv\": [11, 0, 7.25, 3.5], \"texture\": \"#chest\"},\n\t\t\t\t\"down\": {\"uv\": [7.25, 0, 3.5, 3.5], \"texture\": \"#chest\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [0, 7, 0],\n\t\t\t\"to\": [1, 11, 1],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 15, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.75, 0.25, 1, 1.25], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0.25, 0.25, 1.25], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"south\": {\"uv\": [0.25, 0.25, 0.5, 1.25], \"texture\": \"#chest\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 0, 0.75, 0.25], \"texture\": \"#chest\"},\n\t\t\t\t\"down\": {\"uv\": [0.25, 0, 0.5, 0.25], \"texture\": \"#chest\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_chest_right_trunk.json",
    "content": "{\n\t\"parent\": \"block/block\",\n\t\"texture_size\": [64, 64],\n\t\"textures\": {\n\t\t\"particle\": \"#chest\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [0, 0, 1],\n\t\t\t\"to\": [15, 10, 15],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 8, 9]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [10.75, 8.25, 14.5, 10.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"east\": {\"uv\": [0, 8.25, 3.5, 10.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"south\": {\"uv\": [3.5, 8.25, 7.25, 10.75], \"rotation\": 180, \"texture\": \"#chest\"},\n\t\t\t\t\"up\": {\"uv\": [11, 4.75, 7.25, 8.25], \"texture\": \"#chest\"},\n\t\t\t\t\"down\": {\"uv\": [7.25, 4.75, 3.5, 8.25], \"texture\": \"#chest\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_hanging_sign_0.json",
    "content": "{\n\t\"ambientocclusion\": false,\n\t\"texture_size\": [64, 32],\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 7],\n\t\t\t\"to\": [15, 10, 9],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 7, 4, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 7, 0.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [4.5, 7, 8, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [4, 7, 4.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 7, 4, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [4, 6, 7.5, 7], \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [10.03553, 10, 11.53553],\n\t\t\t\"to\": [13.03553, 16, 11.53553],\n\t\t\t\"rotation\": {\"angle\": 45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [10.03553, 10, 4.46447],\n\t\t\t\"to\": [13.03553, 16, 4.46447],\n\t\t\t\"rotation\": {\"angle\": -45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [2.96447, 10, 4.46447],\n\t\t\t\"to\": [5.96447, 16, 4.46447],\n\t\t\t\"rotation\": {\"angle\": 45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [2.96447, 10, 11.53553],\n\t\t\t\"to\": [5.96447, 16, 11.53553],\n\t\t\t\"rotation\": {\"angle\": -45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_hanging_sign_0_ao.json",
    "content": "{\n\t\"ambientocclusion\": true,\n\t\"texture_size\": [64, 32],\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 7],\n\t\t\t\"to\": [15, 10, 9],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 7, 4, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 7, 0.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [4.5, 7, 8, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [4, 7, 4.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 7, 4, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [4, 6, 7.5, 7], \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [10.03553, 10, 11.53553],\n\t\t\t\"to\": [13.03553, 16, 11.53553],\n\t\t\t\"rotation\": {\"angle\": 45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [10.03553, 10, 4.46447],\n\t\t\t\"to\": [13.03553, 16, 4.46447],\n\t\t\t\"rotation\": {\"angle\": -45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [2.96447, 10, 4.46447],\n\t\t\t\"to\": [5.96447, 16, 4.46447],\n\t\t\t\"rotation\": {\"angle\": 45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [2.96447, 10, 11.53553],\n\t\t\t\"to\": [5.96447, 16, 11.53553],\n\t\t\t\"rotation\": {\"angle\": -45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_hanging_sign_22_5.json",
    "content": "{\n\t\"ambientocclusion\": false,\n\t\"texture_size\": [64, 32],\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 7],\n\t\t\t\"to\": [15, 10, 9],\n\t\t\t\"rotation\": {\"angle\": 22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 7, 4, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 7, 0.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [4.5, 7, 8, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [4, 7, 4.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 7, 4, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [4, 6, 7.5, 7], \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [11.53553, 10, 2.96447],\n\t\t\t\"to\": [11.53553, 16, 5.96447],\n\t\t\t\"rotation\": {\"angle\": -22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 270, \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 90, \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [10.03553, 10, 4.46447],\n\t\t\t\"to\": [13.03553, 16, 4.46447],\n\t\t\t\"rotation\": {\"angle\": -22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [4.46447, 10, 10.03553],\n\t\t\t\"to\": [4.46447, 16, 13.03553],\n\t\t\t\"rotation\": {\"angle\": -22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 270, \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 90, \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [2.96447, 10, 11.53553],\n\t\t\t\"to\": [5.96447, 16, 11.53553],\n\t\t\t\"rotation\": {\"angle\": -22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_hanging_sign_22_5_ao.json",
    "content": "{\n\t\"ambientocclusion\": true,\n\t\"texture_size\": [64, 32],\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 7],\n\t\t\t\"to\": [15, 10, 9],\n\t\t\t\"rotation\": {\"angle\": 22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 7, 4, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 7, 0.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [4.5, 7, 8, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [4, 7, 4.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 7, 4, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [4, 6, 7.5, 7], \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [11.53553, 10, 2.96447],\n\t\t\t\"to\": [11.53553, 16, 5.96447],\n\t\t\t\"rotation\": {\"angle\": -22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 270, \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 90, \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [10.03553, 10, 4.46447],\n\t\t\t\"to\": [13.03553, 16, 4.46447],\n\t\t\t\"rotation\": {\"angle\": -22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [4.46447, 10, 10.03553],\n\t\t\t\"to\": [4.46447, 16, 13.03553],\n\t\t\t\"rotation\": {\"angle\": -22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 270, \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 90, \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [2.96447, 10, 11.53553],\n\t\t\t\"to\": [5.96447, 16, 11.53553],\n\t\t\t\"rotation\": {\"angle\": -22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_hanging_sign_45.json",
    "content": "{\n\t\"ambientocclusion\": false,\n\t\"texture_size\": [64, 32],\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 7],\n\t\t\t\"to\": [15, 10, 9],\n\t\t\t\"rotation\": {\"angle\": 45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 7, 4, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 7, 0.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [4.5, 7, 8, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [4, 7, 4.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 7, 4, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [4, 6, 7.5, 7], \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [11.53553, 10, 2.96447],\n\t\t\t\"to\": [11.53553, 16, 5.96447],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 270, \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 90, \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [10.03553, 10, 4.46447],\n\t\t\t\"to\": [13.03553, 16, 4.46447],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [4.46447, 10, 10.03553],\n\t\t\t\"to\": [4.46447, 16, 13.03553],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 270, \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 90, \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [2.96447, 10, 11.53553],\n\t\t\t\"to\": [5.96447, 16, 11.53553],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_hanging_sign_45_ao.json",
    "content": "{\n\t\"ambientocclusion\": true,\n\t\"texture_size\": [64, 32],\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 7],\n\t\t\t\"to\": [15, 10, 9],\n\t\t\t\"rotation\": {\"angle\": 45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 7, 4, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 7, 0.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [4.5, 7, 8, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [4, 7, 4.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 7, 4, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [4, 6, 7.5, 7], \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [11.53553, 10, 2.96447],\n\t\t\t\"to\": [11.53553, 16, 5.96447],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 270, \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 90, \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [10.03553, 10, 4.46447],\n\t\t\t\"to\": [13.03553, 16, 4.46447],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [4.46447, 10, 10.03553],\n\t\t\t\"to\": [4.46447, 16, 13.03553],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 270, \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 90, \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [2.96447, 10, 11.53553],\n\t\t\t\"to\": [5.96447, 16, 11.53553],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_hanging_sign_67_5.json",
    "content": "{\n\t\"ambientocclusion\": false,\n\t\"texture_size\": [64, 32],\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [7, 0, 1],\n\t\t\t\"to\": [9, 10, 15],\n\t\t\t\"rotation\": {\"angle\": -22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 7, 0.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [4.5, 7, 8, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [4, 7, 4.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0.5, 7, 4, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 7, 4, 6], \"rotation\": 270, \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [4, 6, 7.5, 7], \"rotation\": 90, \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [11.53553, 10, 2.96447],\n\t\t\t\"to\": [11.53553, 16, 5.96447],\n\t\t\t\"rotation\": {\"angle\": 22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 270, \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 90, \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [10.03553, 10, 4.46447],\n\t\t\t\"to\": [13.03553, 16, 4.46447],\n\t\t\t\"rotation\": {\"angle\": 22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [4.46447, 10, 10.03553],\n\t\t\t\"to\": [4.46447, 16, 13.03553],\n\t\t\t\"rotation\": {\"angle\": 22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 270, \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 90, \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [2.96447, 10, 11.53553],\n\t\t\t\"to\": [5.96447, 16, 11.53553],\n\t\t\t\"rotation\": {\"angle\": 22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_hanging_sign_67_5_ao.json",
    "content": "{\n\t\"ambientocclusion\": true,\n\t\"texture_size\": [64, 32],\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [7, 0, 1],\n\t\t\t\"to\": [9, 10, 15],\n\t\t\t\"rotation\": {\"angle\": -22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 7, 0.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [4.5, 7, 8, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [4, 7, 4.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0.5, 7, 4, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 7, 4, 6], \"rotation\": 270, \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [4, 6, 7.5, 7], \"rotation\": 90, \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [11.53553, 10, 2.96447],\n\t\t\t\"to\": [11.53553, 16, 5.96447],\n\t\t\t\"rotation\": {\"angle\": 22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 270, \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 90, \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [10.03553, 10, 4.46447],\n\t\t\t\"to\": [13.03553, 16, 4.46447],\n\t\t\t\"rotation\": {\"angle\": 22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [4.46447, 10, 10.03553],\n\t\t\t\"to\": [4.46447, 16, 13.03553],\n\t\t\t\"rotation\": {\"angle\": 22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 270, \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"rotation\": 90, \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [2.96447, 10, 11.53553],\n\t\t\t\"to\": [5.96447, 16, 11.53553],\n\t\t\t\"rotation\": {\"angle\": 22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_hanging_sign_attached_0.json",
    "content": "{\n\t\"ambientocclusion\": false,\n\t\"texture_size\": [64, 32],\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 7],\n\t\t\t\"to\": [15, 10, 9],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 7, 4, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 7, 0.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [4.5, 7, 8, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [4, 7, 4.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 7, 4, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [4, 6, 7.5, 7], \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [2, 10, 8],\n\t\t\t\"to\": [14, 16, 8],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [3.5, 3, 6.5, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [3.5, 3, 6.5, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 3, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 3, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_hanging_sign_attached_0_ao.json",
    "content": "{\n\t\"ambientocclusion\": true,\n\t\"texture_size\": [64, 32],\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 7],\n\t\t\t\"to\": [15, 10, 9],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 7, 4, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 7, 0.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [4.5, 7, 8, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [4, 7, 4.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 7, 4, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [4, 6, 7.5, 7], \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [2, 10, 8],\n\t\t\t\"to\": [14, 16, 8],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [3.5, 3, 6.5, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [3.5, 3, 6.5, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 3, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 3, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_hanging_sign_attached_22_5.json",
    "content": "{\n\t\"ambientocclusion\": false,\n\t\"texture_size\": [64, 32],\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 7],\n\t\t\t\"to\": [15, 10, 9],\n\t\t\t\"rotation\": {\"angle\": 22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 7, 4, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 7, 0.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [4.5, 7, 8, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [4, 7, 4.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 7, 4, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [4, 6, 7.5, 7], \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [2, 10, 8],\n\t\t\t\"to\": [14, 16, 8],\n\t\t\t\"rotation\": {\"angle\": 22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [3.5, 3, 6.5, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [3.5, 3, 6.5, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 3, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 3, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_hanging_sign_attached_22_5_ao.json",
    "content": "{\n\t\"ambientocclusion\": true,\n\t\"texture_size\": [64, 32],\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 7],\n\t\t\t\"to\": [15, 10, 9],\n\t\t\t\"rotation\": {\"angle\": 22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 7, 4, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 7, 0.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [4.5, 7, 8, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [4, 7, 4.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 7, 4, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [4, 6, 7.5, 7], \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [2, 10, 8],\n\t\t\t\"to\": [14, 16, 8],\n\t\t\t\"rotation\": {\"angle\": 22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [3.5, 3, 6.5, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [3.5, 3, 6.5, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 3, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 3, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_hanging_sign_attached_45.json",
    "content": "{\n\t\"ambientocclusion\": false,\n\t\"texture_size\": [64, 32],\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 7],\n\t\t\t\"to\": [15, 10, 9],\n\t\t\t\"rotation\": {\"angle\": 45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 7, 4, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 7, 0.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [4.5, 7, 8, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [4, 7, 4.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 7, 4, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [4, 6, 7.5, 7], \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [2, 10, 8],\n\t\t\t\"to\": [14, 16, 8],\n\t\t\t\"rotation\": {\"angle\": 45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [3.5, 3, 6.5, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [3.5, 3, 6.5, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 3, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 3, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_hanging_sign_attached_45_ao.json",
    "content": "{\n\t\"ambientocclusion\": true,\n\t\"texture_size\": [64, 32],\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 7],\n\t\t\t\"to\": [15, 10, 9],\n\t\t\t\"rotation\": {\"angle\": 45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 7, 4, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 7, 0.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [4.5, 7, 8, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [4, 7, 4.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 7, 4, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [4, 6, 7.5, 7], \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [2, 10, 8],\n\t\t\t\"to\": [14, 16, 8],\n\t\t\t\"rotation\": {\"angle\": 45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [3.5, 3, 6.5, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [3.5, 3, 6.5, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 3, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 3, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_hanging_sign_attached_67_5.json",
    "content": "{\n\t\"ambientocclusion\": false,\n\t\"texture_size\": [64, 32],\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [7, 0, 1],\n\t\t\t\"to\": [9, 10, 15],\n\t\t\t\"rotation\": {\"angle\": -22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 7, 0.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [4.5, 7, 8, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [4, 7, 4.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0.5, 7, 4, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 7, 4, 6], \"rotation\": 270, \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [4, 6, 7.5, 7], \"rotation\": 90, \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [8, 10, 2],\n\t\t\t\"to\": [8, 16, 14],\n\t\t\t\"rotation\": {\"angle\": -22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [3.5, 3, 6.5, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [3.5, 3, 6.5, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 3, 0], \"rotation\": 270, \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 3, 0], \"rotation\": 90, \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_hanging_sign_attached_67_5_ao.json",
    "content": "{\n\t\"ambientocclusion\": true,\n\t\"texture_size\": [64, 32],\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [7, 0, 1],\n\t\t\t\"to\": [9, 10, 15],\n\t\t\t\"rotation\": {\"angle\": -22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 7, 0.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [4.5, 7, 8, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [4, 7, 4.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0.5, 7, 4, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 7, 4, 6], \"rotation\": 270, \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [4, 6, 7.5, 7], \"rotation\": 90, \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [8, 10, 2],\n\t\t\t\"to\": [8, 16, 14],\n\t\t\t\"rotation\": {\"angle\": -22.5, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [3.5, 3, 6.5, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [3.5, 3, 6.5, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 3, 0], \"rotation\": 270, \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 3, 0], \"rotation\": 90, \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_pottery_pattern_east.json",
    "content": "{\n\t\"parent\": \"block/block\",\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 1],\n\t\t\t\"to\": [15, 16, 15],\n\t\t\t\"faces\": {\n\t\t\t\t\"east\": {\"uv\": [1, 0, 15, 16], \"texture\": \"#pattern\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_pottery_pattern_north.json",
    "content": "{\n\t\"parent\": \"block/block\",\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 1],\n\t\t\t\"to\": [15, 16, 15],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1, 0, 15, 16], \"texture\": \"#pattern\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_pottery_pattern_south.json",
    "content": "{\n\t\"parent\": \"block/block\",\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 1],\n\t\t\t\"to\": [15, 16, 15],\n\t\t\t\"faces\": {\n\t\t\t\t\"south\": {\"uv\": [1, 0, 15, 16], \"texture\": \"#pattern\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_pottery_pattern_west.json",
    "content": "{\n\t\"parent\": \"block/block\",\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 1],\n\t\t\t\"to\": [15, 16, 15],\n\t\t\t\"faces\": {\n\t\t\t\t\"west\": {\"uv\": [1, 0, 15, 16], \"texture\": \"#pattern\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_shulker_box.json",
    "content": "{\n\t\"parent\": \"block/block\",\n\t\"texture_size\": [64, 64],\n\t\"textures\": {\n\t\t\"particle\": \"#shulker\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [0, 0, 0],\n\t\t\t\"to\": [16, 8, 16],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [4, 11, 8, 13], \"texture\": \"#shulker\", \"cullface\": \"north\"},\n\t\t\t\t\"east\": {\"uv\": [0, 11, 4, 13], \"texture\": \"#shulker\", \"cullface\": \"east\"},\n\t\t\t\t\"south\": {\"uv\": [12, 11, 16, 13], \"texture\": \"#shulker\", \"cullface\": \"south\"},\n\t\t\t\t\"west\": {\"uv\": [8, 11, 12, 13], \"texture\": \"#shulker\", \"cullface\": \"west\"},\n\t\t\t\t\"down\": {\"uv\": [8, 7, 12, 11], \"texture\": \"#shulker\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [0, 4, 0],\n\t\t\t\"to\": [16, 16, 16],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [4, 4, 8, 7], \"texture\": \"#shulker\", \"cullface\": \"north\"},\n\t\t\t\t\"east\": {\"uv\": [0, 4, 4, 7], \"texture\": \"#shulker\", \"cullface\": \"east\"},\n\t\t\t\t\"south\": {\"uv\": [12, 4, 16, 7], \"texture\": \"#shulker\", \"cullface\": \"south\"},\n\t\t\t\t\"west\": {\"uv\": [8, 4, 12, 7], \"texture\": \"#shulker\", \"cullface\": \"west\"},\n\t\t\t\t\"up\": {\"uv\": [4, 0, 8, 4], \"texture\": \"#shulker\", \"cullface\": \"up\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_shulker_box_bottom.json",
    "content": "{\n\t\"parent\": \"block/block\",\n\t\"texture_size\": [64, 64],\n\t\"textures\": {\n\t\t\"particle\": \"#shulker\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [0, 0, 0],\n\t\t\t\"to\": [16, 8, 16],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [4, 11, 8, 13], \"texture\": \"#shulker\", \"cullface\": \"north\"},\n\t\t\t\t\"east\": {\"uv\": [0, 11, 4, 13], \"texture\": \"#shulker\", \"cullface\": \"east\"},\n\t\t\t\t\"south\": {\"uv\": [12, 11, 16, 13], \"texture\": \"#shulker\", \"cullface\": \"south\"},\n\t\t\t\t\"west\": {\"uv\": [8, 11, 12, 13], \"texture\": \"#shulker\", \"cullface\": \"west\"},\n\t\t\t\t\"down\": {\"uv\": [8, 7, 12, 11], \"texture\": \"#shulker\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [15.95, 0.05, 0.05],\n\t\t\t\"to\": [0.05, 8, 15.95],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [8, 11, 4, 13], \"texture\": \"#shulker\"},\n\t\t\t\t\"east\": {\"uv\": [4, 11, 0, 13], \"texture\": \"#shulker\"},\n\t\t\t\t\"south\": {\"uv\": [16, 11, 12, 13], \"texture\": \"#shulker\"},\n\t\t\t\t\"west\": {\"uv\": [12, 11, 8, 13], \"texture\": \"#shulker\"},\n\t\t\t\t\"down\": {\"uv\": [8, 7, 12, 11], \"texture\": \"#shulker\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_shulker_box_lid.json",
    "content": "{\n\t\"parent\": \"block/block\",\n\t\"texture_size\": [64, 64],\n\t\"textures\": {\n\t\t\"particle\": \"#shulker\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [0, 4, 0],\n\t\t\t\"to\": [16, 16, 16],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [4, 4, 8, 7], \"texture\": \"#shulker\", \"cullface\": \"north\"},\n\t\t\t\t\"east\": {\"uv\": [0, 4, 4, 7], \"texture\": \"#shulker\", \"cullface\": \"east\"},\n\t\t\t\t\"south\": {\"uv\": [12, 4, 16, 7], \"texture\": \"#shulker\", \"cullface\": \"south\"},\n\t\t\t\t\"west\": {\"uv\": [8, 4, 12, 7], \"texture\": \"#shulker\", \"cullface\": \"west\"},\n\t\t\t\t\"up\": {\"uv\": [4, 0, 8, 4], \"texture\": \"#shulker\", \"cullface\": \"up\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [15.95, 4, 0.05],\n\t\t\t\"to\": [0.05, 15.95, 15.95],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [8, 4, 4, 7], \"texture\": \"#shulker\"},\n\t\t\t\t\"east\": {\"uv\": [4, 4, 0, 7], \"texture\": \"#shulker\"},\n\t\t\t\t\"south\": {\"uv\": [16, 4, 12, 7], \"texture\": \"#shulker\"},\n\t\t\t\t\"west\": {\"uv\": [12, 4, 8, 7], \"texture\": \"#shulker\"},\n\t\t\t\t\"up\": {\"uv\": [4, 0, 8, 4], \"texture\": \"#shulker\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_sign_0.json",
    "content": "{\n    \"ambientocclusion\": false,\n\t\"texture_size\": [64, 32],\n\t\"textures\": {\n\t\t\"particle\": \"#sign\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [7.3333, 0, 7.3333],\n\t\t\t\"to\": [8.66663, 9.33333, 8.66663],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 8, 1, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 8, 0.5, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 8, 2, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [1, 8, 1.5, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [1, 7, 1.5, 8], \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [0, 9.3333, 7.3333],\n\t\t\t\"to\": [16, 17.3333, 8.66663],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 1, 6.5, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 1, 0.5, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [7, 1, 13, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [6.5, 1, 7, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 0, 6.5, 1], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [6.5, 0, 12.5, 1], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_sign_0_ao.json",
    "content": "{\n    \"ambientocclusion\": true,\n\t\"texture_size\": [64, 32],\n\t\"textures\": {\n\t\t\"particle\": \"#sign\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [7.3333, 0, 7.3333],\n\t\t\t\"to\": [8.66663, 9.33333, 8.66663],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 8, 1, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 8, 0.5, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 8, 2, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [1, 8, 1.5, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [1, 7, 1.5, 8], \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [0, 9.3333, 7.3333],\n\t\t\t\"to\": [16, 17.3333, 8.66663],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 1, 6.5, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 1, 0.5, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [7, 1, 13, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [6.5, 1, 7, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 0, 6.5, 1], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [6.5, 0, 12.5, 1], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_sign_22_5.json",
    "content": "{\n\t\"ambientocclusion\": false,\n\t\"texture_size\": [64, 32],\n\t\"textures\": {\n\t\t\"particle\": \"#sign\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [7.3333, 0, 7.3333],\n\t\t\t\"to\": [8.66663, 9.33333, 8.66663],\n\t\t\t\"rotation\": {\"angle\": 22.5, \"axis\": \"y\", \"origin\": [8, 8, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 8, 1, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 8, 0.5, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 8, 2, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [1, 8, 1.5, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [1, 7, 1.5, 8], \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [0, 9.3333, 7.3333],\n\t\t\t\"to\": [16, 17.3333, 8.66663],\n\t\t\t\"rotation\": {\"angle\": 22.5, \"axis\": \"y\", \"origin\": [8, 8, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 1, 6.5, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 1, 0.5, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [7, 1, 13, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [6.5, 1, 7, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 0, 6.5, 1], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [6.5, 0, 12.5, 1], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_sign_22_5_ao.json",
    "content": "{\n    \"ambientocclusion\": true,\n\t\"texture_size\": [64, 32],\n\t\"textures\": {\n\t\t\"particle\": \"#sign\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [7.3333, 0, 7.3333],\n\t\t\t\"to\": [8.66663, 9.33333, 8.66663],\n\t\t\t\"rotation\": {\"angle\": 22.5, \"axis\": \"y\", \"origin\": [8, 8, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 8, 1, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 8, 0.5, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 8, 2, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [1, 8, 1.5, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [1, 7, 1.5, 8], \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [0, 9.3333, 7.3333],\n\t\t\t\"to\": [16, 17.3333, 8.66663],\n\t\t\t\"rotation\": {\"angle\": 22.5, \"axis\": \"y\", \"origin\": [8, 8, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 1, 6.5, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 1, 0.5, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [7, 1, 13, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [6.5, 1, 7, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 0, 6.5, 1], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [6.5, 0, 12.5, 1], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_sign_45.json",
    "content": "{\n\t\"ambientocclusion\": false,\n\t\"texture_size\": [64, 32],\n\t\"textures\": {\n\t\t\"particle\": \"#sign\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [7.3333, 0, 7.3333],\n\t\t\t\"to\": [8.66663, 9.33333, 8.66663],\n\t\t\t\"rotation\": {\"angle\": 45, \"axis\": \"y\", \"origin\": [8, 8, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 8, 1, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 8, 0.5, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 8, 2, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [1, 8, 1.5, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [1, 7, 1.5, 8], \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [0, 9.3333, 7.3333],\n\t\t\t\"to\": [16, 17.3333, 8.66663],\n\t\t\t\"rotation\": {\"angle\": 45, \"axis\": \"y\", \"origin\": [8, 8, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 1, 6.5, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 1, 0.5, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [7, 1, 13, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [6.5, 1, 7, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 0, 6.5, 1], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [6.5, 0, 12.5, 1], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_sign_45_ao.json",
    "content": "{\n    \"ambientocclusion\": true,\n\t\"texture_size\": [64, 32],\n\t\"textures\": {\n\t\t\"particle\": \"#sign\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [7.3333, 0, 7.3333],\n\t\t\t\"to\": [8.66663, 9.33333, 8.66663],\n\t\t\t\"rotation\": {\"angle\": 45, \"axis\": \"y\", \"origin\": [8, 8, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 8, 1, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 8, 0.5, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 8, 2, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [1, 8, 1.5, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [1, 7, 1.5, 8], \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [0, 9.3333, 7.3333],\n\t\t\t\"to\": [16, 17.3333, 8.66663],\n\t\t\t\"rotation\": {\"angle\": 45, \"axis\": \"y\", \"origin\": [8, 8, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 1, 6.5, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 1, 0.5, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [7, 1, 13, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [6.5, 1, 7, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 0, 6.5, 1], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [6.5, 0, 12.5, 1], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_sign_67_5.json",
    "content": "{\n\t\"ambientocclusion\": false,\n\t\"texture_size\": [64, 32],\n\t\"textures\": {\n\t\t\"particle\": \"#sign\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [7.3333, 0, 7.33337],\n\t\t\t\"to\": [8.66663, 9.33333, 8.6667],\n\t\t\t\"rotation\": {\"angle\": -22.5, \"axis\": \"y\", \"origin\": [8, 8, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 8, 0.5, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [1.5, 8, 2, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1, 8, 1.5, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0.5, 8, 1, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [1, 7, 1.5, 8], \"rotation\": 90, \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [7.3333, 9.3333, 0],\n\t\t\t\"to\": [8.66663, 17.3333, 16],\n\t\t\t\"rotation\": {\"angle\": -22.5, \"axis\": \"y\", \"origin\": [8, 8, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 1, 0.5, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [7, 1, 13, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [6.5, 1, 7, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0.5, 1, 6.5, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 0, 6.5, 1], \"rotation\": 270, \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [6.5, 0, 12.5, 1], \"rotation\": 90, \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_sign_67_5_ao.json",
    "content": "{\n    \"ambientocclusion\": true,\n\t\"texture_size\": [64, 32],\n\t\"textures\": {\n\t\t\"particle\": \"#sign\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [7.3333, 0, 7.33337],\n\t\t\t\"to\": [8.66663, 9.33333, 8.6667],\n\t\t\t\"rotation\": {\"angle\": -22.5, \"axis\": \"y\", \"origin\": [8, 8, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 8, 0.5, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [1.5, 8, 2, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1, 8, 1.5, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0.5, 8, 1, 15], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [1, 7, 1.5, 8], \"rotation\": 90, \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [7.3333, 9.3333, 0],\n\t\t\t\"to\": [8.66663, 17.3333, 16],\n\t\t\t\"rotation\": {\"angle\": -22.5, \"axis\": \"y\", \"origin\": [8, 8, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 1, 0.5, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [7, 1, 13, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [6.5, 1, 7, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0.5, 1, 6.5, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 0, 6.5, 1], \"rotation\": 270, \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [6.5, 0, 12.5, 1], \"rotation\": 90, \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_wall_hanging_sign.json",
    "content": "{\n\t\"ambientocclusion\": false,\n\t\"texture_size\": [64, 32],\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 7],\n\t\t\t\"to\": [15, 10, 9],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 7, 4, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 7, 0.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [4.5, 7, 8, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [4, 7, 4.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 7, 4, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [4, 6, 7.5, 7], \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [10.03553, 10, 11.53553],\n\t\t\t\"to\": [13.03553, 16, 11.53553],\n\t\t\t\"rotation\": {\"angle\": 45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [10.03553, 10, 4.46447],\n\t\t\t\"to\": [13.03553, 16, 4.46447],\n\t\t\t\"rotation\": {\"angle\": -45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [2.96447, 10, 4.46447],\n\t\t\t\"to\": [5.96447, 16, 4.46447],\n\t\t\t\"rotation\": {\"angle\": 45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [2.96447, 10, 11.53553],\n\t\t\t\"to\": [5.96447, 16, 11.53553],\n\t\t\t\"rotation\": {\"angle\": -45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [0, 14, 6],\n\t\t\t\"to\": [16, 16, 10],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1, 2, 5, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 2, 1, 3], \"texture\": \"#sign\", \"cullface\": \"west\"},\n\t\t\t\t\"south\": {\"uv\": [6, 2, 10, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [5, 2, 6, 3], \"texture\": \"#sign\", \"cullface\": \"west\"},\n\t\t\t\t\"up\": {\"uv\": [1, 2, 5, 0], \"texture\": \"#sign\", \"cullface\": \"up\"},\n\t\t\t\t\"down\": {\"uv\": [5, 0, 9, 2], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_wall_hanging_sign_ao.json",
    "content": "{\n\t\"ambientocclusion\": true,\n\t\"texture_size\": [64, 32],\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [1, 0, 7],\n\t\t\t\"to\": [15, 10, 9],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 7, 4, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 7, 0.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [4.5, 7, 8, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [4, 7, 4.5, 12], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 7, 4, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [4, 6, 7.5, 7], \"texture\": \"#sign\", \"cullface\": \"down\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [10.03553, 10, 11.53553],\n\t\t\t\"to\": [13.03553, 16, 11.53553],\n\t\t\t\"rotation\": {\"angle\": 45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [10.03553, 10, 4.46447],\n\t\t\t\"to\": [13.03553, 16, 4.46447],\n\t\t\t\"rotation\": {\"angle\": -45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [2.96447, 10, 4.46447],\n\t\t\t\"to\": [5.96447, 16, 4.46447],\n\t\t\t\"rotation\": {\"angle\": 45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [0, 3, 0.75, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [2.96447, 10, 11.53553],\n\t\t\t\"to\": [5.96447, 16, 11.53553],\n\t\t\t\"rotation\": {\"angle\": -45, \"axis\": \"y\", \"origin\": [8, 0, 8]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [1.5, 3, 2.25, 6], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [0, 0, 0, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [0, 0, 0.75, 0], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"from\": [0, 14, 6],\n\t\t\t\"to\": [16, 16, 10],\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [1, 2, 5, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 2, 1, 3], \"texture\": \"#sign\", \"cullface\": \"east\"},\n\t\t\t\t\"south\": {\"uv\": [6, 2, 10, 3], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [5, 2, 6, 3], \"texture\": \"#sign\", \"cullface\": \"west\"},\n\t\t\t\t\"up\": {\"uv\": [1, 2, 5, 0], \"texture\": \"#sign\", \"cullface\": \"up\"},\n\t\t\t\t\"down\": {\"uv\": [5, 0, 9, 2], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_wall_sign.json",
    "content": "{\n\t\"ambientocclusion\": false,\n\t\"texture_size\": [64, 32],\n\t\"textures\": {\n\t\t\"particle\": \"#sign\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [0, 4.3333, 14.3333],\n\t\t\t\"to\": [16, 12.3333, 15.66663],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 3, 15]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 1, 6.5, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 1, 0.5, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [7, 1, 13, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [6.5, 1, 7, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 0, 6.5, 1], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [6.5, 0, 12.5, 1], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/block/template_wall_sign_ao.json",
    "content": "{\n\t\"ambientocclusion\": true,\n\t\"texture_size\": [64, 32],\n\t\"textures\": {\n\t\t\"particle\": \"#sign\"\n\t},\n\t\"elements\": [\n\t\t{\n\t\t\t\"from\": [0, 4.3333, 14.3333],\n\t\t\t\"to\": [16, 12.3333, 15.66663],\n\t\t\t\"rotation\": {\"angle\": 0, \"axis\": \"y\", \"origin\": [8, 3, 15]},\n\t\t\t\"faces\": {\n\t\t\t\t\"north\": {\"uv\": [0.5, 1, 6.5, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"east\": {\"uv\": [0, 1, 0.5, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"south\": {\"uv\": [7, 1, 13, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"west\": {\"uv\": [6.5, 1, 7, 7], \"texture\": \"#sign\"},\n\t\t\t\t\"up\": {\"uv\": [0.5, 0, 6.5, 1], \"texture\": \"#sign\"},\n\t\t\t\t\"down\": {\"uv\": [6.5, 0, 12.5, 1], \"texture\": \"#sign\"}\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "src/main/resources/assets/minecraft/models/item/christmas_chest.json",
    "content": "{\n\t\"parent\": \"block/christmas_chest_center\"\n}"
  },
  {
    "path": "src/main/resources/enhancedblockentities.accesswidener",
    "content": "accessWidener   v2      named\n\naccessible      class   net/minecraft/client/option/SimpleOption$Callbacks\naccessible      class   net/minecraft/client/render/model/BakedModelManager$BakingResult\naccessible      field   net/minecraft/client/gui/screen/ingame/AbstractSignEditScreen blockEntity Lnet/minecraft/block/entity/SignBlockEntity;\naccessible      method  net/minecraft/client/texture/NativeImage write (Ljava/nio/channels/WritableByteChannel;)Z"
  },
  {
    "path": "src/main/resources/enhancedblockentities.mixins.json",
    "content": "{\n  \"required\": true,\n  \"minVersion\": \"0.8\",\n  \"package\": \"foundationgames.enhancedblockentities.mixin\",\n  \"compatibilityLevel\": \"JAVA_17\",\n  \"client\": [\n    \"AbstractBlockStateMixin\",\n    \"AbstractSignBlockEntityRenderAccessor\",\n    \"BellBlockEntityMixin\",\n    \"BlockEntityRenderDispatcherMixin\",\n    \"BuiltChunkMixin\",\n    \"ChestBlockEntityMixin\",\n    \"DecoratedPotBlockEntityMixin\",\n    \"EnderChestBlockEntityMixin\",\n    \"LifecycledResourceManagerImplMixin\",\n    \"MinecraftClientMixin\",\n    \"ShulkerBoxBlockEntityMixin\",\n    \"SignEditScreenMixin\",\n    \"VideoOptionsScreenMixin\",\n    \"WorldRendererMixin\",\n    \"compat.sodium.RenderSectionManagerMixin\",\n    \"compat.sodium.RenderSectionMixin\"\n  ],\n  \"injectors\": {\n    \"defaultRequire\": 1\n  }\n}\n"
  },
  {
    "path": "src/main/resources/fabric.mod.json",
    "content": "{\n  \"schemaVersion\": 1,\n  \"id\": \"enhancedblockentities\",\n  \"version\": \"${version}\",\n\n  \"name\": \"Enhanced Block Entities\",\n  \"description\": \"Optimize and customize block entity rendering with a more modern approach.\",\n  \"authors\": [\n    \"FoundationGames\"\n  ],\n  \"contact\": {\n    \"homepage\": \"https://github.com/FoundationGames/EnhancedBlockEntities\",\n    \"issues\": \"https://github.com/FoundationGames/EnhancedBlockEntities/issues\",\n    \"sources\": \"https://github.com/FoundationGames/EnhancedBlockEntities\"\n  },\n\n  \"license\": \"LGPLv3\",\n  \"icon\": \"assets/enhancedblockentities/icon.png\",\n\n  \"environment\": \"client\",\n  \"entrypoints\": {\n    \"client\": [\n      \"foundationgames.enhancedblockentities.EnhancedBlockEntities\"\n    ],\n    \"modmenu\": [\n      \"foundationgames.enhancedblockentities.config.gui.EBEModMenuPlugin\"\n    ]\n  },\n  \"mixins\": [\n    \"enhancedblockentities.mixins.json\"\n  ],\n\n  \"depends\": {\n    \"fabricloader\": \">=0.16.7\",\n    \"fabric-api\": \">=0.114.1\",\n    \"minecraft\": \">=1.21.3\"\n  },\n  \"breaks\": {\n    \"optifabric\": \"*\"\n  },\n\n  \"accessWidener\": \"enhancedblockentities.accesswidener\",\n\n  \"custom\": {\n    \"modmenu\": {\n      \"links\": {\n        \"modmenu.discord\": \"https://discord.gg/7Aw3y4RtY9\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/main/resources/templates/blockstate/base.json",
    "content": "{\n  \"variants\": {\n    ![vars]\n  }\n}"
  },
  {
    "path": "src/main/resources/templates/blockstate/var.json",
    "content": "\"![state]\": {![extra]\"model\": \"![model]\"}"
  },
  {
    "path": "src/main/resources/templates/item/bed.json",
    "content": "{\n  \"model\": {\n    \"type\": \"minecraft:composite\",\n    \"models\": [\n      {\n        \"type\": \"minecraft:model\",\n        \"model\": \"minecraft:item/![foot]\"\n      },\n      {\n        \"type\": \"minecraft:model\",\n        \"model\": \"minecraft:item/![head]\"\n      }\n    ]\n  }\n}"
  },
  {
    "path": "src/main/resources/templates/item/chest_item.json",
    "content": "{\n  \"model\": {\n    \"type\": \"minecraft:condition\",\n    \"on_false\": {\n      \"type\": \"minecraft:model\",\n      \"model\": \"minecraft:block/![chest]\"\n    },\n    \"on_true\": {\n      \"type\": \"minecraft:model\",\n      \"model\": \"minecraft:block/christmas_chest_center\"\n    },\n    \"property\": \"ebe:ebe_is_christmas\"\n  }\n}"
  },
  {
    "path": "src/main/resources/templates/item/chest_item_no_christmas.json",
    "content": "{\n  \"model\": {\n    \"type\": \"minecraft:model\",\n    \"model\": \"minecraft:block/![chest]\"\n  }\n}"
  },
  {
    "path": "src/main/resources/templates/model/bed_foot_item.json",
    "content": "{\n  \"parent\": \"minecraft:block/template_bed_foot_offset\",\n  \"textures\": {\n    \"bed\": \"minecraft:entity/bed/![bed]\"\n  },\n  \"display\": {\n    \"thirdperson_righthand\": {\n      \"rotation\": [ 30, 340, 0 ],\n      \"translation\": [ 0, 3, -2],\n      \"scale\":[ 0.23, 0.23, 0.23]\n    },\n    \"firstperson_righthand\": {\n      \"rotation\": [ 30, 340, 0 ],\n      \"translation\": [ 0, 3, 0],\n      \"scale\":[ 0.375, 0.375, 0.375]\n    },\n    \"gui\": {\n      \"rotation\": [ 30, 340, 0 ],\n      \"translation\": [ 2, 3, 0],\n      \"scale\":[ 0.5325, 0.5325, 0.5325]\n    },\n    \"ground\": {\n      \"rotation\": [ 0, 180, 0 ],\n      \"translation\": [ 0, 1, 2],\n      \"scale\":[ 0.25, 0.25, 0.25]\n    },\n    \"head\": {\n      \"rotation\": [ 0, 0, 0 ],\n      \"translation\": [ 0, 10, -8],\n      \"scale\":[ 1,1,1 ]\n    },\n    \"fixed\": {\n      \"rotation\": [ 270, 180, 0 ],\n      \"translation\": [ 0, 4, -2],\n      \"scale\":[ 0.5, 0.5, 0.5]\n    }\n  }\n}"
  },
  {
    "path": "src/main/resources/templates/model/bed_head_item.json",
    "content": "{\n  \"parent\": \"minecraft:block/![bed]_bed_head\",\n  \"display\": {\n    \"thirdperson_righthand\": {\n      \"rotation\": [ 30, 340, 0 ],\n      \"translation\": [ 0, 3, -2],\n      \"scale\":[ 0.23, 0.23, 0.23]\n    },\n    \"firstperson_righthand\": {\n      \"rotation\": [ 30, 340, 0 ],\n      \"translation\": [ 0, 3, 0],\n      \"scale\":[ 0.375, 0.375, 0.375]\n    },\n    \"gui\": {\n      \"rotation\": [ 30, 340, 0 ],\n      \"translation\": [ 2, 3, 0],\n      \"scale\":[ 0.5325, 0.5325, 0.5325]\n    },\n    \"ground\": {\n      \"rotation\": [ 0, 180, 0 ],\n      \"translation\": [ 0, 1, 2],\n      \"scale\":[ 0.25, 0.25, 0.25]\n    },\n    \"head\": {\n      \"rotation\": [ 0, 0, 0 ],\n      \"translation\": [ 0, 10, -8],\n      \"scale\":[ 1,1,1 ]\n    },\n    \"fixed\": {\n      \"rotation\": [ 270, 180, 0 ],\n      \"translation\": [ 0, 4, -2],\n      \"scale\":[ 0.5, 0.5, 0.5]\n    }\n  }\n}"
  },
  {
    "path": "src/main/resources/templates/model/chest_like.json",
    "content": "{\n  \"parent\": \"block/![parent]\",\n  \"textures\": {\n    ![particle]\n    \"chest\": \"entity/chest/![chest_tex]\"\n  }\n}"
  },
  {
    "path": "src/main/resources/templates/model/parent_and_tex.json",
    "content": "{\n  \"parent\": \"![parent]\",\n  \"textures\": {\n    ![textures]\n  }\n}"
  }
]