├── .github └── workflows │ └── gradle.yml ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src └── main ├── java └── io │ └── github │ └── nuclearfarts │ └── cbt │ ├── ColorCacheHack.java │ ├── ConnectedBlockTextures.java │ ├── ConnectionConditions.java │ ├── config │ ├── BaseCTMConfig.java │ ├── CTMConfig.java │ ├── ConnectingCTMConfig.java │ ├── MainTextureConnectingCTMConfig.java │ ├── RandomCTMConfig.java │ └── RepeatingCTMConfig.java │ ├── mixin │ ├── ClientWorldMixin.java │ ├── IdentifierMixin.java │ ├── ModelLoaderMixin.java │ ├── NativeImageAccessor.java │ └── ReloadableResourceManagerImplMixin.java │ ├── model │ ├── CBTBakedModel.java │ └── CBTUnbakedModel.java │ ├── resource │ └── CBTResourcePack.java │ ├── sprite │ ├── BaseSpriteProvider.java │ ├── ConnectingSpriteProvider.java │ ├── FullCTMSpriteProvider.java │ ├── HorizontalCTMSpriteProvider.java │ ├── HorizontalVerticalCTMSpriteProvider.java │ ├── RandomSpriteProvider.java │ ├── RepeatingCTMSpriteProvider.java │ ├── SpriteProvider.java │ ├── TopCTMSpriteProvider.java │ ├── VerticalCTMSpriteProvider.java │ └── VerticalHorizontalCTMSpriteProvider.java │ ├── tile │ ├── ImageBackedTile.java │ ├── ResourceBackedTile.java │ ├── Tile.java │ ├── loader │ │ ├── BasicTileLoader.java │ │ ├── DynamicBookshelfTileLoader.java │ │ ├── DynamicGlassTileLoader.java │ │ ├── DynamicSandstoneTileLoader.java │ │ └── TileLoader.java │ └── provider │ │ ├── BasicTileProvider.java │ │ ├── CompactTileProvider.java │ │ └── TileProvider.java │ └── util │ ├── CBTUtil.java │ ├── CursedBiomeThing.java │ ├── SimplePool.java │ ├── VoidSet.java │ └── function │ ├── MutableCachingSupplier.java │ └── ThrowingPredicate.java └── resources ├── assets ├── connected_block_textures │ └── icon.png └── minecraft │ ├── models │ └── block │ │ ├── template_glass_pane_post.json │ │ ├── template_glass_pane_side.json │ │ └── template_glass_pane_side_alt.json │ └── optifine │ └── ctm │ ├── bookshelf │ └── bookshelf.properties │ ├── glass │ ├── black_stained_glass.properties │ ├── black_stained_glass_pane.properties │ ├── blue_stained_glass.properties │ ├── blue_stained_glass_pane.properties │ ├── brown_stained_glass.properties │ ├── brown_stained_glass_pane.properties │ ├── cyan_stained_glass.properties │ ├── cyan_stained_glass_pane.properties │ ├── glass.properties │ ├── glass_pane.properties │ ├── gray_stained_glass.properties │ ├── gray_stained_glass_pane.properties │ ├── green_stained_glass.properties │ ├── green_stained_glass_pane.properties │ ├── light_blue_stained_glass.properties │ ├── light_blue_stained_glass_pane.properties │ ├── light_gray_stained_glass.properties │ ├── light_gray_stained_glass_pane.properties │ ├── lime_stained_glass.properties │ ├── lime_stained_glass_pane.properties │ ├── magenta_stained_glass.properties │ ├── magenta_stained_glass_pane.properties │ ├── orange_stained_glass.properties │ ├── orange_stained_glass_pane.properties │ ├── pink_stained_glass.properties │ ├── pink_stained_glass_pane.properties │ ├── purple_stained_glass.properties │ ├── purple_stained_glass_pane.properties │ ├── red_stained_glass.properties │ ├── red_stained_glass_pane.properties │ ├── tinted_glass.properties │ ├── white_stained_glass.properties │ ├── white_stained_glass_pane.properties │ ├── yellow_stained_glass.properties │ └── yellow_stained_glass_pane.properties │ └── sandstone │ ├── red_sandstone.properties │ └── sandstone.properties ├── connected_block_textures.mixins.json ├── fabric.mod.json └── programmer_art └── assets └── minecraft └── optifine └── ctm └── glass ├── red_stained_glass_pane_programmer.properties └── red_stained_glass_programmer.properties /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | name: Java CI with Gradle 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v2 11 | - name: Set up JDK 8 12 | uses: actions/setup-java@v1 13 | with: 14 | java-version: 16 15 | - name: Grant execute permission for gradlew 16 | run: chmod +x gradlew 17 | - name: Build with Gradle 18 | run: ./gradlew build 19 | - name: Upload build artifacts 20 | uses: actions/upload-artifact@v1 21 | with: 22 | name: build-artifacts 23 | path: build/libs 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # gradle 2 | 3 | .gradle/ 4 | build/ 5 | out/ 6 | classes/ 7 | 8 | # idea 9 | 10 | .idea/ 11 | *.iml 12 | *.ipr 13 | *.iws 14 | 15 | # vscode 16 | 17 | .settings/ 18 | .vscode/ 19 | bin/ 20 | .classpath 21 | .project 22 | *.launch 23 | # fabric 24 | 25 | run/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # connected-block-textures 2 | An implementation of the MCPatcher/Optifine connected textures format on the Fabric modloader. 3 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'fabric-loom' version '0.8-SNAPSHOT' 3 | id 'maven-publish' 4 | } 5 | 6 | sourceCompatibility = JavaVersion.VERSION_1_8 7 | targetCompatibility = JavaVersion.VERSION_1_8 8 | 9 | archivesBaseName = project.archives_base_name 10 | version = project.mod_version 11 | group = project.maven_group 12 | 13 | minecraft { 14 | } 15 | 16 | dependencies { 17 | //to change the versions see the gradle.properties file 18 | minecraft "com.mojang:minecraft:${project.minecraft_version}" 19 | mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" 20 | modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" 21 | 22 | modImplementation ("net.fabricmc.fabric-api:fabric-api:${project.fabric_version}") { 23 | exclude module: "fabric-loader" 24 | exclude group: "net.fabricmc" 25 | } 26 | } 27 | 28 | processResources { 29 | inputs.property "version", project.version 30 | 31 | filesMatching("fabric.mod.json") { 32 | expand "version": project.version 33 | } 34 | } 35 | 36 | tasks.withType(JavaCompile).configureEach { 37 | // ensure that the encoding is set to UTF-8, no matter what the system default is 38 | // this fixes some edge cases with special characters not displaying correctly 39 | // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html 40 | // If Javadoc is generated, this must be specified in that task too. 41 | it.options.encoding = "UTF-8" 42 | 43 | // The Minecraft launcher currently installs Java 8 for users, so your mod probably wants to target Java 8 too 44 | // JDK 9 introduced a new way of specifying this that will make sure no newer classes or methods are used. 45 | // We'll use that if it's available, but otherwise we'll use the older option. 46 | def targetVersion = 8 47 | if (JavaVersion.current().isJava9Compatible()) { 48 | it.options.release = targetVersion 49 | } 50 | } 51 | 52 | java { 53 | // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task 54 | // if it is present. 55 | // If you remove this line, sources will not be generated. 56 | withSourcesJar() 57 | } 58 | 59 | jar { 60 | from("LICENSE") { 61 | rename { "${it}_${project.archivesBaseName}"} 62 | } 63 | } 64 | 65 | // configure the maven publication 66 | publishing { 67 | publications { 68 | mavenJava(MavenPublication) { 69 | // add all the jars that should be included when publishing to maven 70 | artifact(jar) { 71 | builtBy remapJar 72 | } 73 | artifact(sourcesJar) { 74 | builtBy remapSourcesJar 75 | } 76 | } 77 | } 78 | 79 | // select the repositories you want to publish to 80 | repositories { 81 | // uncomment to publish to the local maven 82 | // mavenLocal() 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx1G 3 | 4 | # Fabric Properties 5 | # check these on https://fabricmc.net/use 6 | minecraft_version=1.17 7 | yarn_mappings=1.17+build.11 8 | loader_version=0.11.6 9 | 10 | #Fabric api 11 | fabric_version=0.35.2+1.17 12 | 13 | # Mod Properties 14 | mod_version = 0.1.5+1.17 15 | maven_group = io.github.nuclearfarts 16 | archives_base_name = connected-block-textures 17 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HyperCubeMC/connected-block-textures/5e06943fdf444456b54056bc197aef54f4863f30/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { 4 | name = 'Fabric' 5 | url = 'https://maven.fabricmc.net/' 6 | } 7 | gradlePluginPortal() 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/ColorCacheHack.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt; 2 | 3 | import java.util.function.IntSupplier; 4 | 5 | import net.minecraft.client.world.BiomeColorCache; 6 | import net.minecraft.util.math.BlockPos; 7 | 8 | public class ColorCacheHack extends BiomeColorCache { 9 | public int getBiomeColor(BlockPos pos, IntSupplier colorFactory) { 10 | return colorFactory.getAsInt(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/ConnectedBlockTextures.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt; 2 | 3 | import org.apache.logging.log4j.LogManager; 4 | import org.apache.logging.log4j.Logger; 5 | 6 | import net.minecraft.util.Identifier; 7 | 8 | import net.fabricmc.api.ModInitializer; 9 | import io.github.nuclearfarts.cbt.config.CTMConfig; 10 | import io.github.nuclearfarts.cbt.config.MainTextureConnectingCTMConfig; 11 | import io.github.nuclearfarts.cbt.config.RandomCTMConfig; 12 | import io.github.nuclearfarts.cbt.config.RepeatingCTMConfig; 13 | import io.github.nuclearfarts.cbt.resource.CBTResourcePack; 14 | import io.github.nuclearfarts.cbt.sprite.FullCTMSpriteProvider; 15 | import io.github.nuclearfarts.cbt.sprite.HorizontalCTMSpriteProvider; 16 | import io.github.nuclearfarts.cbt.sprite.HorizontalVerticalCTMSpriteProvider; 17 | import io.github.nuclearfarts.cbt.sprite.RandomSpriteProvider; 18 | import io.github.nuclearfarts.cbt.sprite.RepeatingCTMSpriteProvider; 19 | import io.github.nuclearfarts.cbt.sprite.TopCTMSpriteProvider; 20 | import io.github.nuclearfarts.cbt.sprite.VerticalCTMSpriteProvider; 21 | import io.github.nuclearfarts.cbt.sprite.VerticalHorizontalCTMSpriteProvider; 22 | import io.github.nuclearfarts.cbt.tile.loader.DynamicBookshelfTileLoader; 23 | import io.github.nuclearfarts.cbt.tile.loader.DynamicGlassTileLoader; 24 | import io.github.nuclearfarts.cbt.tile.loader.DynamicSandstoneTileLoader; 25 | import io.github.nuclearfarts.cbt.tile.loader.TileLoader; 26 | import io.github.nuclearfarts.cbt.tile.provider.CompactTileProvider; 27 | import io.github.nuclearfarts.cbt.tile.provider.TileProvider; 28 | import it.unimi.dsi.fastutil.objects.Object2IntMap; 29 | import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; 30 | 31 | public class ConnectedBlockTextures implements ModInitializer { 32 | 33 | public static final Logger LOGGER = LogManager.getLogger("ConnectedBlockTextures"); 34 | 35 | public static CBTResourcePack resourcePack; 36 | public static boolean overrideIdentifierCharRestriction = false; 37 | public static Thread identifierOverrideThread = null; 38 | public static final Object2IntMap RESOURCE_PACK_PRIORITY_MAP = new Object2IntOpenHashMap<>(); 39 | 40 | public static final short[] CTM_TO_IDEALIZED_BITHACK = {165, 173, 189, 181, 174, 179, 206, 186, 122, 91, 222, 250, 167, 175, 191, 183, 205, 117, 93, 115, 218, 94, 95, 123, 231, 239, 255, 247, 207, 190, 238, 187, 254, 251, 126, 219, 229, 237, 253, 245, 125, 243, 221, 119, 223, 127, 90}; 41 | 42 | @Override 43 | public void onInitialize() { 44 | //connection modes 45 | CTMConfig.registerConfigLoader("ctm", MainTextureConnectingCTMConfig.loaderForFactory(FullCTMSpriteProvider::new)); 46 | CTMConfig.registerConfigLoader("top", MainTextureConnectingCTMConfig.loaderForFactory(TopCTMSpriteProvider::new)); 47 | CTMConfig.registerConfigLoader("horizontal", MainTextureConnectingCTMConfig.loaderForFactory(HorizontalCTMSpriteProvider::new)); 48 | CTMConfig.registerConfigLoader("ctm_compact", MainTextureConnectingCTMConfig.loaderForFactory(FullCTMSpriteProvider::new)); 49 | CTMConfig.registerConfigLoader("vertical", MainTextureConnectingCTMConfig.loaderForFactory(VerticalCTMSpriteProvider::new)); 50 | CTMConfig.registerConfigLoader("horizontal+vertical", MainTextureConnectingCTMConfig.loaderForFactory(HorizontalVerticalCTMSpriteProvider::new)); 51 | CTMConfig.registerConfigLoader("vertical+horizontal", MainTextureConnectingCTMConfig.loaderForFactory(VerticalHorizontalCTMSpriteProvider::new)); 52 | //legacy random textures/texture replacement modes 53 | CTMConfig.registerConfigLoader("fixed", RandomCTMConfig.loaderForFactory(RandomSpriteProvider::new)); 54 | CTMConfig.registerConfigLoader("random", RandomCTMConfig.loaderForFactory(RandomSpriteProvider::new)); 55 | //repeating pattern 56 | CTMConfig.registerConfigLoader("repeat", RepeatingCTMConfig.loaderForFactory(RepeatingCTMSpriteProvider::new)); 57 | 58 | TileProvider.registerTileProviderFactory("ctm_compact", CompactTileProvider::new); 59 | 60 | TileLoader.registerSpecialTileLoader("$CBT_SPECIAL_DYNAMIC_GLASS", DynamicGlassTileLoader::new); 61 | TileLoader.registerSpecialTileLoader("$CBT_SPECIAL_DYNAMIC_SANDSTONE", DynamicSandstoneTileLoader::new); 62 | TileLoader.registerSpecialTileLoader("$CBT_SPECIAL_DYNAMIC_BOOKSHELF", DynamicBookshelfTileLoader::new); 63 | } 64 | 65 | public static Identifier id(String string) { 66 | return new Identifier("connected_block_textures", string); 67 | } 68 | 69 | public static void breakpointHack() { 70 | System.out.println("bp"); 71 | } 72 | 73 | static { 74 | RESOURCE_PACK_PRIORITY_MAP.defaultReturnValue(-1); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/ConnectionConditions.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt; 2 | 3 | import java.util.function.BiPredicate; 4 | 5 | import net.minecraft.block.BlockState; 6 | import net.minecraft.client.MinecraftClient; 7 | import net.minecraft.client.render.block.BlockModels; 8 | 9 | public enum ConnectionConditions implements BiPredicate { 10 | BLOCK((t, o) -> t.getBlock() == o.getBlock()), 11 | BLOCKS((t, o) -> t.getBlock() == o.getBlock()), 12 | STATE((t, o) -> t == o), 13 | MATERIAL((t, o) -> t.getMaterial() == o.getMaterial()), 14 | TILE((t, o) -> { 15 | BlockModels models = MinecraftClient.getInstance().getBakedModelManager().getBlockModels(); 16 | return models.getSprite(t) == models.getSprite(o); 17 | }); 18 | 19 | private final BiPredicate func; 20 | 21 | private ConnectionConditions(BiPredicate func) { 22 | this.func = func; 23 | } 24 | 25 | @Override 26 | public boolean test(BlockState myState, BlockState otherState) { 27 | return func.test(myState, otherState); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/config/BaseCTMConfig.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.config; 2 | 3 | import io.github.nuclearfarts.cbt.ConnectedBlockTextures; 4 | import io.github.nuclearfarts.cbt.sprite.SpriteProvider; 5 | import io.github.nuclearfarts.cbt.tile.provider.TileProvider; 6 | import io.github.nuclearfarts.cbt.util.CBTUtil; 7 | import io.github.nuclearfarts.cbt.util.CursedBiomeThing; 8 | import net.minecraft.client.MinecraftClient; 9 | import net.minecraft.client.texture.Sprite; 10 | import net.minecraft.client.util.ModelIdentifier; 11 | import net.minecraft.client.util.SpriteIdentifier; 12 | import net.minecraft.resource.ResourceManager; 13 | import net.minecraft.util.Identifier; 14 | import net.minecraft.util.math.BlockPos; 15 | import net.minecraft.util.math.Direction; 16 | import net.minecraft.util.registry.Registry; 17 | import net.minecraft.world.BlockRenderView; 18 | import net.minecraft.world.biome.Biome; 19 | 20 | import java.io.IOException; 21 | import java.util.*; 22 | import java.util.function.BiPredicate; 23 | import java.util.function.IntPredicate; 24 | import java.util.function.Predicate; 25 | import java.util.function.Supplier; 26 | import java.util.stream.Collectors; 27 | 28 | //Java generics are awful. 29 | public abstract class BaseCTMConfig> implements CTMConfig { 30 | 31 | protected final TileProvider tileProvider; 32 | protected final Predicate tileMatcher; 33 | protected final Predicate blockMatcher; 34 | protected final Predicate faceMatcher; 35 | protected final BiPredicate worldConditions; 36 | protected final int packPriority; 37 | protected final int weight; 38 | protected final String fileName; 39 | protected final SpriteProviderFactory spriteProviderFactory; 40 | 41 | public BaseCTMConfig(Properties properties, Identifier location, ResourceManager manager, SpriteProviderFactory bakedModelFactory, String packName) throws IOException { 42 | if(properties.containsKey("matchTiles")) { 43 | tileMatcher = Arrays.stream(properties.getProperty("matchTiles").split(" ")).map(s -> CBTUtil.prependId(new Identifier(s), "block/")).collect(Collectors.toCollection(HashSet::new))::contains; 44 | } else { 45 | tileMatcher = null; 46 | } 47 | 48 | if(properties.containsKey("matchBlocks")) { 49 | blockMatcher = Arrays.stream(properties.getProperty("matchBlocks").split(" ")).map(Identifier::new).collect(Collectors.toCollection(HashSet::new))::contains; 50 | } else { 51 | blockMatcher = identifier -> true; 52 | } 53 | 54 | Predicate biomeMatcher; 55 | if(properties.containsKey("biomes") && MinecraftClient.getInstance().world != null) { 56 | Registry biomes = MinecraftClient.getInstance().world.getRegistryManager().get(Registry.BIOME_KEY); 57 | biomeMatcher = Arrays.stream(properties.getProperty("biomes").split(" ")).map(Identifier::new).map(biomes::get).collect(Collectors.toCollection(HashSet::new))::contains; 58 | } else { 59 | biomeMatcher = null; 60 | } 61 | 62 | IntPredicate heightMatcher; 63 | if(properties.containsKey("heights")) { 64 | List heightTests = new ArrayList<>(); 65 | for(String range : properties.getProperty("heights").split(" ")) { 66 | String[] split = range.split("-"); 67 | int min = Integer.parseInt(split[0]); 68 | int max = Integer.parseInt(split[1]); 69 | heightTests.add(i -> min <= i && i <= max); 70 | } 71 | if(heightTests.size() == 1) { 72 | heightMatcher = heightTests.get(0); 73 | } else { 74 | heightMatcher = i -> CBTUtil.satisfiesAny(heightTests, i); 75 | } 76 | } else { 77 | heightMatcher = i -> true; 78 | } 79 | 80 | if(biomeMatcher != null) { 81 | worldConditions = (w, p) -> biomeMatcher.test(CursedBiomeThing.getBiome(w, p)) && heightMatcher.test(p.getY()); 82 | } else { 83 | worldConditions = (w, p) -> heightMatcher.test(p.getY()); 84 | } 85 | 86 | if(properties.containsKey("faces")) { 87 | Set faces = EnumSet.noneOf(Direction.class); 88 | for(String face : properties.getProperty("faces").split(" ")) { 89 | switch(face) { 90 | case "sides": 91 | faces.add(Direction.NORTH); 92 | faces.add(Direction.EAST); 93 | faces.add(Direction.SOUTH); 94 | faces.add(Direction.WEST); 95 | break; 96 | case "top": 97 | faces.add(Direction.UP); 98 | break; 99 | case "bottom": 100 | faces.add(Direction.DOWN); 101 | break; 102 | case "all": 103 | Collections.addAll(faces, Direction.values()); 104 | break; 105 | default: 106 | faces.add(Direction.valueOf(face.toUpperCase(Locale.ENGLISH))); //avoid the turkish bug 107 | break; 108 | } 109 | } 110 | faceMatcher = faces::contains; 111 | } else { 112 | faceMatcher = direction -> true; 113 | } 114 | 115 | weight = Integer.parseInt(properties.getProperty("weight", "0")); 116 | 117 | if(properties.containsKey("cbt_special_change_pack_if_loaded")) { 118 | String packOverride = properties.getProperty("cbt_special_change_pack_if_loaded"); 119 | if(ConnectedBlockTextures.RESOURCE_PACK_PRIORITY_MAP.containsKey(packOverride)) { 120 | packName = packOverride; 121 | } 122 | } 123 | 124 | this.packPriority = ConnectedBlockTextures.RESOURCE_PACK_PRIORITY_MAP.getInt(packName); 125 | this.spriteProviderFactory = bakedModelFactory; 126 | this.tileProvider = TileProvider.load(properties, CBTUtil.directoryOf(location), manager); 127 | this.fileName = CBTUtil.fileNameOf(location); 128 | } 129 | 130 | public int compareTo(CTMConfig other) { 131 | if(getResourcePackPriority() != other.getResourcePackPriority()) { 132 | return getResourcePackPriority() - other.getResourcePackPriority(); 133 | } 134 | 135 | if(getWeight() != other.getWeight()) { 136 | return getWeight() - other.getWeight(); 137 | } 138 | 139 | if(!getFileName().equals(other.getFileName())) { 140 | return getFileName().compareTo(other.getFileName()); 141 | } 142 | 143 | return 0; 144 | } 145 | 146 | @Override 147 | public TileProvider getTileProvider() { 148 | return tileProvider; 149 | } 150 | 151 | @Override 152 | public Predicate getTileMatcher() { 153 | return tileMatcher; 154 | } 155 | 156 | @Override 157 | public Predicate getFaceMatcher() { 158 | return faceMatcher; 159 | } 160 | 161 | @Override 162 | public BiPredicate getWorldConditions() { 163 | return worldConditions; 164 | } 165 | 166 | @Override 167 | public SpriteProvider createSpriteProvider(Sprite[] sprites) { 168 | return spriteProviderFactory.create(sprites, getSelf()); 169 | } 170 | 171 | @Override 172 | public boolean affectsModel(ModelIdentifier id, Supplier> textureDeps) { 173 | return (blockMatcher.test(id) || blockMatcher.test(CBTUtil.stripVariants(id))) && (tileMatcher == null || CBTUtil.mapAnyMatch(textureDeps.get(), SpriteIdentifier::getTextureId, tileMatcher)); 174 | } 175 | 176 | @Override 177 | public int getResourcePackPriority() { 178 | return packPriority; 179 | } 180 | 181 | @Override 182 | public int getWeight() { 183 | return weight; 184 | } 185 | 186 | @Override 187 | public String getFileName() { 188 | return fileName; 189 | } 190 | 191 | @FunctionalInterface 192 | public interface SpriteProviderFactory> { 193 | SpriteProvider create(Sprite[] sprites, C config); 194 | } 195 | 196 | protected abstract Self getSelf(); //java pls 197 | } 198 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/config/CTMConfig.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.config; 2 | 3 | import java.io.IOException; 4 | import java.util.Collection; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | import java.util.Properties; 8 | import java.util.function.BiPredicate; 9 | import java.util.function.Predicate; 10 | import java.util.function.Supplier; 11 | 12 | import net.minecraft.client.texture.Sprite; 13 | import net.minecraft.client.util.ModelIdentifier; 14 | import net.minecraft.client.util.SpriteIdentifier; 15 | import net.minecraft.resource.Resource; 16 | import net.minecraft.resource.ResourceManager; 17 | import net.minecraft.util.Identifier; 18 | import net.minecraft.util.math.BlockPos; 19 | import net.minecraft.util.math.Direction; 20 | import net.minecraft.world.BlockRenderView; 21 | 22 | import io.github.nuclearfarts.cbt.sprite.SpriteProvider; 23 | import io.github.nuclearfarts.cbt.tile.provider.TileProvider; 24 | 25 | public interface CTMConfig extends Comparable { 26 | TileProvider getTileProvider(); 27 | Predicate getTileMatcher(); 28 | Predicate getFaceMatcher(); 29 | BiPredicate getWorldConditions(); 30 | SpriteProvider createSpriteProvider(Sprite[] sprites); 31 | boolean affectsModel(ModelIdentifier id, Supplier> textureDeps); 32 | int getResourcePackPriority(); 33 | int getWeight(); 34 | String getFileName(); 35 | 36 | static void registerConfigLoader(String formatName, Loader loader) { 37 | PrivateConstants.CTM_CONFIG_LOADERS.put(formatName, loader); 38 | } 39 | 40 | static CTMConfig load(Properties properties, Identifier location, ResourceManager manager, String packName) throws IOException { 41 | Loader loader; 42 | if((loader = PrivateConstants.CTM_CONFIG_LOADERS.get(properties.getProperty("method"))) != null) { 43 | return loader.load(properties, location, manager, packName); 44 | } 45 | throw new IllegalArgumentException("Invalid or unsupported CTM method " + properties.getProperty("method")); 46 | } 47 | 48 | static CTMConfig load(Identifier propertiesLocation, ResourceManager manager) throws IOException { 49 | Properties properties = new Properties(); 50 | Resource resource = manager.getResource(propertiesLocation); 51 | properties.load(resource.getInputStream()); 52 | return CTMConfig.load(properties, propertiesLocation, manager, resource.getResourcePackName()); 53 | } 54 | 55 | @FunctionalInterface 56 | public interface Loader { 57 | T load(Properties properties, Identifier location, ResourceManager manager, String packName) throws IOException; 58 | } 59 | 60 | public static final class PrivateConstants { 61 | private PrivateConstants() { } 62 | private static final Map> CTM_CONFIG_LOADERS = new HashMap<>(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/config/ConnectingCTMConfig.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.config; 2 | 3 | import java.io.IOException; 4 | import java.util.Properties; 5 | import java.util.function.BiPredicate; 6 | import net.minecraft.block.BlockState; 7 | import net.minecraft.resource.ResourceManager; 8 | import net.minecraft.util.Identifier; 9 | 10 | public abstract class ConnectingCTMConfig> extends BaseCTMConfig { 11 | public ConnectingCTMConfig(Properties properties, Identifier location, ResourceManager manager, SpriteProviderFactory bakedModelFactory, String packName) throws IOException { 12 | super(properties, location, manager, bakedModelFactory, packName); 13 | } 14 | 15 | public abstract BiPredicate getConnectionMatcher(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/config/MainTextureConnectingCTMConfig.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.config; 2 | 3 | import java.io.IOException; 4 | import java.util.Locale; 5 | import java.util.Properties; 6 | import java.util.function.BiPredicate; 7 | import net.minecraft.block.BlockState; 8 | import net.minecraft.resource.ResourceManager; 9 | import net.minecraft.util.Identifier; 10 | import io.github.nuclearfarts.cbt.ConnectionConditions; 11 | 12 | public class MainTextureConnectingCTMConfig extends ConnectingCTMConfig { 13 | private final BiPredicate connectionMatcher; 14 | 15 | public static CTMConfig.Loader loaderForFactory(SpriteProviderFactory factory) { 16 | return (p, l, m, n) -> new MainTextureConnectingCTMConfig(p, l, m, factory, n); 17 | } 18 | 19 | public MainTextureConnectingCTMConfig(Properties properties, Identifier location, ResourceManager manager, SpriteProviderFactory bakedModelFactory, String packName) throws IOException { 20 | super(properties, location, manager, bakedModelFactory, packName); 21 | String connect = properties.getProperty("connect", properties.containsKey("matchBlocks") ? "blocks" : "tiles"); 22 | connectionMatcher = ConnectionConditions.valueOf(connect.toUpperCase(Locale.ENGLISH)); 23 | } 24 | 25 | @Override 26 | public BiPredicate getConnectionMatcher() { 27 | return connectionMatcher; 28 | } 29 | 30 | @Override 31 | protected MainTextureConnectingCTMConfig getSelf() { 32 | return this; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/config/RandomCTMConfig.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.config; 2 | 3 | import java.io.IOException; 4 | import java.util.Properties; 5 | import net.minecraft.resource.ResourceManager; 6 | import net.minecraft.util.Identifier; 7 | 8 | public class RandomCTMConfig extends BaseCTMConfig { 9 | 10 | public static CTMConfig.Loader loaderForFactory(SpriteProviderFactory factory) { 11 | return (p, l, m, n) -> new RandomCTMConfig(p, l, m, factory, n); 12 | } 13 | 14 | public RandomCTMConfig(Properties properties, Identifier location, ResourceManager manager, SpriteProviderFactory bakedModelFactory, String packName) throws IOException { 15 | super(properties, location, manager, bakedModelFactory, packName); 16 | } 17 | 18 | @Override 19 | protected RandomCTMConfig getSelf() { 20 | return this; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/config/RepeatingCTMConfig.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.config; 2 | 3 | import java.io.IOException; 4 | import java.util.Properties; 5 | import net.minecraft.resource.ResourceManager; 6 | import net.minecraft.util.Identifier; 7 | 8 | public class RepeatingCTMConfig extends BaseCTMConfig { 9 | private final int width; 10 | private final int height; 11 | 12 | public static CTMConfig.Loader loaderForFactory(SpriteProviderFactory factory) { 13 | return (p, l, m, n) -> new RepeatingCTMConfig(p, l, m, factory, n); 14 | } 15 | 16 | public RepeatingCTMConfig(Properties properties, Identifier location, ResourceManager manager, SpriteProviderFactory bakedModelFactory, String packName) throws IOException { 17 | super(properties, location, manager, bakedModelFactory, packName); 18 | width = Integer.parseInt(properties.getProperty("width")); 19 | height = Integer.parseInt(properties.getProperty("height")); 20 | } 21 | 22 | @Override 23 | protected RepeatingCTMConfig getSelf() { 24 | return this; 25 | } 26 | 27 | public int getWidth() { 28 | return width; 29 | } 30 | 31 | public int getHeight() { 32 | return height; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/mixin/ClientWorldMixin.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.mixin; 2 | 3 | import org.spongepowered.asm.mixin.Final; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Shadow; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 9 | 10 | import net.minecraft.client.world.BiomeColorCache; 11 | import net.minecraft.client.world.ClientWorld; 12 | import net.minecraft.world.level.ColorResolver; 13 | 14 | import io.github.nuclearfarts.cbt.ColorCacheHack; 15 | import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; 16 | 17 | @Mixin(ClientWorld.class) 18 | public class ClientWorldMixin { 19 | @Shadow 20 | private @Final Object2ObjectArrayMap colorCache; 21 | 22 | @Inject(method = "", at = @At("RETURN")) 23 | private void cachePls(CallbackInfo callback) { 24 | colorCache.defaultReturnValue(new ColorCacheHack()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/mixin/IdentifierMixin.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.mixin; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.At; 5 | import org.spongepowered.asm.mixin.injection.Inject; 6 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 7 | 8 | import net.minecraft.util.Identifier; 9 | 10 | import io.github.nuclearfarts.cbt.ConnectedBlockTextures; 11 | 12 | @Mixin(Identifier.class) 13 | public class IdentifierMixin { 14 | @Inject(method = "isPathValid(Ljava/lang/String;)Z", at = @At("HEAD"), cancellable = true) 15 | private static void overrideIdentifierRestrictions(CallbackInfoReturnable callback) { 16 | if(ConnectedBlockTextures.overrideIdentifierCharRestriction && Thread.currentThread() == ConnectedBlockTextures.identifierOverrideThread) { 17 | callback.setReturnValue(true); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/mixin/ModelLoaderMixin.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.mixin; 2 | 3 | import net.minecraft.client.render.model.ModelLoader; 4 | import net.minecraft.client.render.model.UnbakedModel; 5 | import net.minecraft.client.util.ModelIdentifier; 6 | import net.minecraft.client.util.SpriteIdentifier; 7 | import net.minecraft.resource.ResourceManager; 8 | import net.minecraft.util.Identifier; 9 | import net.minecraft.util.profiler.Profiler; 10 | 11 | import io.github.nuclearfarts.cbt.ConnectedBlockTextures; 12 | import io.github.nuclearfarts.cbt.config.CTMConfig; 13 | import io.github.nuclearfarts.cbt.model.CBTUnbakedModel; 14 | import io.github.nuclearfarts.cbt.util.CBTUtil; 15 | import io.github.nuclearfarts.cbt.util.VoidSet; 16 | import io.github.nuclearfarts.cbt.util.function.MutableCachingSupplier; 17 | 18 | import java.io.IOException; 19 | import java.util.ArrayList; 20 | import java.util.Collection; 21 | import java.util.HashSet; 22 | import java.util.List; 23 | import java.util.Map; 24 | import java.util.Set; 25 | import java.util.SortedSet; 26 | import java.util.TreeSet; 27 | import org.spongepowered.asm.mixin.Final; 28 | import org.spongepowered.asm.mixin.Mixin; 29 | import org.spongepowered.asm.mixin.Shadow; 30 | import org.spongepowered.asm.mixin.Unique; 31 | import org.spongepowered.asm.mixin.injection.At; 32 | import org.spongepowered.asm.mixin.injection.Redirect; 33 | 34 | @Mixin(ModelLoader.class) 35 | public abstract class ModelLoaderMixin { 36 | @Shadow 37 | private @Final Map unbakedModels; 38 | @Shadow 39 | private @Final Map modelsToBake; 40 | @Shadow 41 | private @Final ResourceManager resourceManager; 42 | 43 | @Redirect(method = "", at = @At(value = "INVOKE_STRING", target = "net/minecraft/util/profiler/Profiler.swap(Ljava/lang/String;)V", args = "ldc=textures")) 44 | private void injectCbtModels(Profiler on, String str) { 45 | on.swap("ctm"); 46 | ConnectedBlockTextures.overrideIdentifierCharRestriction = true; 47 | ConnectedBlockTextures.identifierOverrideThread = Thread.currentThread(); 48 | List data = new ArrayList<>(); 49 | Collection propertiesIds = resourceManager.findResources("optifine/ctm", s -> s.endsWith(".properties")); 50 | for(Identifier id : propertiesIds) { 51 | try { 52 | data.add(CTMConfig.load(id, resourceManager)); 53 | } catch(Exception e) { 54 | ConnectedBlockTextures.LOGGER.error("Error loading connected textures config at " + id, e); 55 | } 56 | } 57 | 58 | Set priorityFails = new HashSet<>(); 59 | MutableCachingSupplier> textureCached = new MutableCachingSupplier<>(); 60 | unbakedModels.forEach((id, model) -> { 61 | if(id instanceof ModelIdentifier) { 62 | ModelIdentifier modelId = (ModelIdentifier) id; 63 | if(!modelId.getVariant().equals("inventory")) { 64 | UnbakedModel newModel = checkCtmConfigs(modelId, model, textureCached, data, priorityFails); 65 | if(newModel != model) { 66 | unbakedModels.put(id, newModel); 67 | modelsToBake.put(id, newModel); 68 | } 69 | } 70 | } 71 | }); 72 | ConnectedBlockTextures.overrideIdentifierCharRestriction = false; 73 | on.swap(str); 74 | } 75 | 76 | @Unique 77 | private UnbakedModel checkCtmConfigs(ModelIdentifier id, UnbakedModel model, MutableCachingSupplier> textureCached, List data, Set priorityFails) { 78 | Set configs = new TreeSet<>(); 79 | boolean foundNewConfigs = false; 80 | do { 81 | SortedSet newConfigs = new TreeSet<>(); 82 | UnbakedModel javaPls = model; 83 | textureCached.set(() -> javaPls.getTextureDependencies(((ModelLoader) (Object) this)::getOrLoadModel, VoidSet.get())); 84 | for(CTMConfig c : data) { 85 | if(c.affectsModel(id, textureCached) && CBTUtil.allMatchThrowable(textureCached.get(), s -> checkPack(s, c.getResourcePackPriority(), priorityFails))) { 86 | if(configs.add(c)) { 87 | newConfigs.add(c); 88 | } 89 | } 90 | } 91 | foundNewConfigs = !newConfigs.isEmpty(); 92 | if(foundNewConfigs) { 93 | model = new CBTUnbakedModel(model, newConfigs.toArray(new CTMConfig[newConfigs.size()])); 94 | } 95 | } while(foundNewConfigs); 96 | return model; 97 | } 98 | 99 | @Unique 100 | private boolean checkPack(SpriteIdentifier spriteId, int ctmPackPriority, Set fails) { 101 | Identifier texId = spriteId.getTextureId(); 102 | String spritePack; 103 | try { 104 | spritePack = resourceManager.getResource(new Identifier(texId.getNamespace(), "textures/" + texId.getPath() + ".png")).getResourcePackName(); 105 | } catch(IOException e) { 106 | if(fails.add(texId)) { 107 | ConnectedBlockTextures.LOGGER.error("Error checking resource pack priority", e); 108 | } 109 | return true; 110 | } 111 | return ConnectedBlockTextures.RESOURCE_PACK_PRIORITY_MAP.getInt(spritePack) <= ctmPackPriority; 112 | } 113 | } -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/mixin/NativeImageAccessor.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.mixin; 2 | 3 | import java.nio.channels.WritableByteChannel; 4 | 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Invoker; 7 | 8 | import net.minecraft.client.texture.NativeImage; 9 | 10 | @Mixin(NativeImage.class) 11 | public interface NativeImageAccessor { 12 | @Invoker 13 | boolean invokeWrite(WritableByteChannel channel); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/mixin/ReloadableResourceManagerImplMixin.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.mixin; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.CompletableFuture; 5 | import java.util.concurrent.Executor; 6 | 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 12 | 13 | import net.minecraft.resource.ReloadableResourceManager; 14 | import net.minecraft.resource.ReloadableResourceManagerImpl; 15 | import net.minecraft.resource.ResourcePack; 16 | import net.minecraft.resource.ResourceReload; 17 | import net.minecraft.util.Unit; 18 | 19 | import io.github.nuclearfarts.cbt.ConnectedBlockTextures; 20 | import io.github.nuclearfarts.cbt.resource.CBTResourcePack; 21 | 22 | @Mixin(ReloadableResourceManagerImpl.class) 23 | public abstract class ReloadableResourceManagerImplMixin implements ReloadableResourceManager { 24 | @Shadow 25 | public abstract void addPack(ResourcePack resourcePack); 26 | 27 | @Inject(method = "reload", at = @At(value = "RETURN", shift = At.Shift.BEFORE)) 28 | private void injectCBTPack(Executor prepareExecutor, Executor applyExecutor, CompletableFuture initialStage, List packs, CallbackInfoReturnable cir) { 29 | ConnectedBlockTextures.RESOURCE_PACK_PRIORITY_MAP.clear(); 30 | for(int i = 0; i < packs.size(); i++) { 31 | ConnectedBlockTextures.RESOURCE_PACK_PRIORITY_MAP.put(packs.get(i).getName(), i); 32 | } 33 | this.addPack(ConnectedBlockTextures.resourcePack = new CBTResourcePack(this)); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/model/CBTBakedModel.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.model; 2 | 3 | import java.util.Random; 4 | import java.util.function.Supplier; 5 | 6 | import net.minecraft.block.BlockState; 7 | import net.minecraft.client.MinecraftClient; 8 | import net.minecraft.client.render.model.BakedModel; 9 | import net.minecraft.client.texture.Sprite; 10 | import net.minecraft.client.texture.SpriteAtlasTexture; 11 | import net.minecraft.util.math.Vec3f; 12 | import net.minecraft.item.ItemStack; 13 | import net.minecraft.util.math.BlockPos; 14 | import net.minecraft.util.math.Direction; 15 | import net.minecraft.world.BlockRenderView; 16 | 17 | import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView; 18 | import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel; 19 | import net.fabricmc.fabric.api.renderer.v1.model.SpriteFinder; 20 | import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; 21 | 22 | import io.github.nuclearfarts.cbt.sprite.SpriteProvider; 23 | 24 | public class CBTBakedModel extends ForwardingBakedModel { 25 | protected final SpriteProvider[] spriteProviders; 26 | 27 | public CBTBakedModel(BakedModel baseModel, SpriteProvider[] spriteProviders) { 28 | wrapped = baseModel; 29 | this.spriteProviders = spriteProviders; 30 | } 31 | 32 | @Override 33 | public boolean isVanillaAdapter() { 34 | return false; 35 | } 36 | 37 | @Override 38 | public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { 39 | SpriteFinder spriteFinder = SpriteFinder.get(MinecraftClient.getInstance().getBakedModelManager().getAtlas(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE)); 40 | context.pushTransform(quad -> { 41 | for(SpriteProvider provider : spriteProviders) { 42 | //use short-circuiting to our advantage to save the more expensive ones for last 43 | if(provider.affectsDirection(quad.nominalFace()) && provider.affectsBlock(blockView, state, pos) && provider.affectsSprite(quad, spriteFinder)) { 44 | //which way is up relative to the texture? 45 | Vec3f lowV1 = new Vec3f(); 46 | int lowV1I = -1; 47 | Vec3f lowV2 = new Vec3f(); 48 | Vec3f lowU1 = new Vec3f(); 49 | int lowU1I = -1; 50 | Vec3f lowU2 = new Vec3f(); 51 | 52 | Vec3f current = new Vec3f(); 53 | Vec3f center = new Vec3f(); 54 | 55 | float lastLowV = Float.MAX_VALUE; 56 | float lastLowU = Float.MAX_VALUE; 57 | for(int i = 0; i < 4; i++) { 58 | float v = quad.spriteV(i, 0); 59 | float u = quad.spriteU(i, 0); 60 | quad.copyPos(i, current); 61 | center.add(current); 62 | if(v < lastLowV) { 63 | lowV1I = i; 64 | lastLowV = v; 65 | quad.copyPos(i, lowV1); 66 | } 67 | if(u < lastLowU) { 68 | lowU1I = i; 69 | lastLowU = u; 70 | quad.copyPos(i, lowU1); 71 | } 72 | } 73 | // find center 74 | center.scale(1f/4f); 75 | // 2nd lowest 76 | lastLowV = Float.MAX_VALUE; 77 | lastLowU = Float.MAX_VALUE; 78 | for(int i = 0; i < 4; i++) { 79 | float v = quad.spriteV(i, 0); 80 | float u = quad.spriteU(i, 0); 81 | if(lowV1I != i && v < lastLowV) { 82 | lastLowV = v; 83 | quad.copyPos(i, lowV2); 84 | } 85 | if(lowU1I != i && u < lastLowU) { 86 | lastLowU = u; 87 | quad.copyPos(i, lowU2); 88 | } 89 | } 90 | 91 | // find center of low-v edge 92 | lowV1.add(lowV2); 93 | lowV1.scale(0.5f); 94 | // find center of low-u edge 95 | lowU1.add(lowU2); 96 | lowU1.scale(0.5f); 97 | // find vector between center of quad and center of edge 98 | lowV1.subtract(center); 99 | lowU1.subtract(center); 100 | 101 | Direction upDir = Direction.getFacing(lowV1.getX(), lowV1.getY(), lowV1.getZ()); 102 | Direction leftDir = Direction.getFacing(lowU1.getX(), lowU1.getY(), lowU1.getZ()); 103 | 104 | Sprite newSpr; 105 | if((newSpr = provider.getSpriteForSide(quad.nominalFace(), upDir, leftDir, blockView, state, pos, randomSupplier.get())) != null) { 106 | quad.spriteBake(0, newSpr, MutableQuadView.BAKE_LOCK_UV); 107 | } 108 | } 109 | } 110 | return true; 111 | }); 112 | super.emitBlockQuads(blockView, state, pos, randomSupplier, context); 113 | context.popTransform(); 114 | } 115 | 116 | @Override 117 | public void emitItemQuads(ItemStack stack, Supplier randomSupplier, RenderContext context) { 118 | throw new UnsupportedOperationException("CBT models should never try to render as an item! THIS IS A PROBLEM!"); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/model/CBTUnbakedModel.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.Collections; 6 | import java.util.List; 7 | import java.util.Set; 8 | import java.util.function.Function; 9 | import com.mojang.datafixers.util.Pair; 10 | 11 | import net.minecraft.client.render.model.BakedModel; 12 | import net.minecraft.client.render.model.ModelBakeSettings; 13 | import net.minecraft.client.render.model.ModelLoader; 14 | import net.minecraft.client.render.model.UnbakedModel; 15 | import net.minecraft.client.texture.Sprite; 16 | import net.minecraft.client.util.SpriteIdentifier; 17 | import net.minecraft.util.Identifier; 18 | 19 | import io.github.nuclearfarts.cbt.config.CTMConfig; 20 | import io.github.nuclearfarts.cbt.sprite.SpriteProvider; 21 | 22 | public class CBTUnbakedModel implements UnbakedModel { 23 | 24 | private final UnbakedModel baseModel; 25 | private final CTMConfig[] configs; 26 | 27 | public CBTUnbakedModel(UnbakedModel baseModel, CTMConfig[] configs) { 28 | this.baseModel = baseModel; 29 | this.configs = configs; 30 | } 31 | 32 | @Override 33 | public Collection getModelDependencies() { 34 | return Collections.emptySet(); 35 | } 36 | 37 | @Override 38 | public Collection getTextureDependencies(Function unbakedModelGetter, Set> unresolvedTextureReferences) { 39 | Collection baseDeps = baseModel.getTextureDependencies(unbakedModelGetter, unresolvedTextureReferences); 40 | Collection allDeps = new ArrayList(baseDeps); 41 | for(CTMConfig config : configs) { 42 | allDeps.addAll(config.getTileProvider().getIdsToLoad()); 43 | } 44 | return allDeps; 45 | } 46 | 47 | @Override 48 | public BakedModel bake(ModelLoader loader, Function textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) { 49 | try { 50 | List spriteProviders = new ArrayList<>(); 51 | for(CTMConfig config : configs) { 52 | spriteProviders.add(config.createSpriteProvider(config.getTileProvider().load(textureGetter))); 53 | } 54 | return new CBTBakedModel(baseModel.bake(loader, textureGetter, rotationContainer, modelId), spriteProviders.toArray(new SpriteProvider[spriteProviders.size()])); 55 | } catch (Exception e) { 56 | e.printStackTrace(); 57 | return null; 58 | } 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/resource/CBTResourcePack.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.resource; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.nio.channels.Channels; 8 | import java.util.Collection; 9 | import java.util.Collections; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | import java.util.Set; 13 | import java.util.function.Predicate; 14 | import java.util.stream.Collectors; 15 | 16 | import com.google.common.collect.ImmutableSet; 17 | 18 | import net.minecraft.client.texture.NativeImage; 19 | import net.minecraft.resource.ResourceManager; 20 | import net.minecraft.resource.ResourcePack; 21 | import net.minecraft.resource.ResourceType; 22 | import net.minecraft.resource.metadata.ResourceMetadataReader; 23 | import net.minecraft.util.Identifier; 24 | 25 | import io.github.nuclearfarts.cbt.mixin.NativeImageAccessor; 26 | import io.github.nuclearfarts.cbt.tile.Tile; 27 | 28 | public class CBTResourcePack implements ResourcePack { 29 | 30 | private static final Set NAMESPACES = ImmutableSet.of("connectedblocktextures"); 31 | 32 | private final Map aliases = new HashMap<>(); 33 | private final Map resources = new HashMap<>(); 34 | private final ResourceManager manager; 35 | 36 | private int genCounter = 0; 37 | 38 | public CBTResourcePack(ResourceManager manager) { 39 | this.manager = manager; 40 | } 41 | 42 | public void putResource(String resource, byte[] data) { 43 | resources.put(resource, data); 44 | } 45 | 46 | public void alias(String location, Identifier to) { 47 | aliases.put(location, to); 48 | } 49 | 50 | public void putImage(String location, NativeImage image) { 51 | ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); 52 | ((NativeImageAccessor) (Object) image).invokeWrite(Channels.newChannel(byteOut)); 53 | image.close(); 54 | putResource(location, byteOut.toByteArray()); 55 | } 56 | 57 | public Identifier dynamicallyPutImage(NativeImage image) { 58 | String texPath = "gen/" + genCounter++; 59 | putImage("assets/connectedblocktextures/textures/" + texPath + ".png", image); 60 | return new Identifier("connectedblocktextures", texPath); 61 | } 62 | 63 | public Identifier dynamicallyPutTile(Tile tile) { 64 | String texPath = "gen/" + genCounter++; 65 | putTile("assets/connectedblocktextures/textures/" + texPath + ".png", tile); 66 | return new Identifier("connectedblocktextures", texPath); 67 | } 68 | 69 | public void putTile(String location, Tile tile) { 70 | if(tile.hasResource()) { 71 | alias(location, tile.getResource()); 72 | } else { 73 | try { 74 | putImage(location, tile.getImage()); 75 | } catch (IOException e) { 76 | //should be unreachable 77 | e.printStackTrace(); 78 | } 79 | } 80 | } 81 | 82 | @Override 83 | public void close() {} 84 | 85 | @Override 86 | public InputStream openRoot(String fileName) throws IOException { 87 | byte[] data; 88 | Identifier aliasOf; 89 | if((data = resources.get(fileName)) != null) { 90 | return new ByteArrayInputStream(data); 91 | } else if((aliasOf = aliases.get(fileName)) != null) { 92 | return manager.getResource(aliasOf).getInputStream(); 93 | } 94 | throw new IOException("generated resources pack has no data or alias for " + fileName); 95 | } 96 | 97 | @Override 98 | public InputStream open(ResourceType type, Identifier id) throws IOException { 99 | if(type == ResourceType.SERVER_DATA) throw new IOException("reading server data from connectedblocktextures client resource pack"); 100 | return openRoot(type.getDirectory() + "/" + id.getNamespace() + "/" + id.getPath()); 101 | } 102 | 103 | @Override 104 | public Collection findResources(ResourceType type, String namespace, String prefix, int maxDepth, Predicate pathFilter) { 105 | //maxdepth not implemented. 106 | if(type == ResourceType.SERVER_DATA) return Collections.emptyList(); 107 | String start = "assets/" + namespace + "/" + prefix; 108 | return resources.keySet().stream().filter(s -> s.startsWith(start) && pathFilter.test(s)).map(CBTResourcePack::fromPath).collect(Collectors.toList()); 109 | } 110 | 111 | @Override 112 | public boolean contains(ResourceType type, Identifier id) { 113 | String path = type.getDirectory() + "/" + id.getNamespace() + "/" + id.getPath(); 114 | return resources.containsKey(path) || aliases.containsKey(path); 115 | } 116 | 117 | @Override 118 | public Set getNamespaces(ResourceType type) { 119 | return NAMESPACES; 120 | } 121 | 122 | @Override 123 | public T parseMetadata(ResourceMetadataReader metaReader) throws IOException { 124 | return null; 125 | } 126 | 127 | @Override 128 | public String getName() { 129 | return "Connected Block Textures generated resources"; 130 | } 131 | 132 | private static Identifier fromPath(String path) { 133 | String[] split = path.split("/", 2); 134 | return new Identifier(split[0], split[1]); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/sprite/BaseSpriteProvider.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.sprite; 2 | 3 | import java.util.function.BiPredicate; 4 | import java.util.function.Predicate; 5 | 6 | import net.minecraft.block.BlockState; 7 | import net.minecraft.client.texture.Sprite; 8 | import net.minecraft.util.Identifier; 9 | import net.minecraft.util.math.BlockPos; 10 | import net.minecraft.util.math.Direction; 11 | import net.minecraft.world.BlockRenderView; 12 | 13 | import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView; 14 | import net.fabricmc.fabric.api.renderer.v1.model.SpriteFinder; 15 | 16 | import io.github.nuclearfarts.cbt.config.CTMConfig; 17 | 18 | public abstract class BaseSpriteProvider implements SpriteProvider { 19 | protected final Sprite[] connects; //different subclasses use this different ways 20 | protected final Predicate tileMatcher; 21 | protected final Predicate faceMatcher; 22 | protected final BiPredicate worldConditions; 23 | 24 | public BaseSpriteProvider(Sprite[] connects, CTMConfig config) { 25 | this.connects = connects; 26 | Predicate tileMatcher = config.getTileMatcher(); 27 | this.tileMatcher = tileMatcher == null ? null : s -> tileMatcher.test(s.getId()); 28 | faceMatcher = config.getFaceMatcher(); 29 | worldConditions = config.getWorldConditions(); 30 | } 31 | 32 | @Override 33 | public boolean affectsBlock(BlockRenderView view, BlockState state, BlockPos pos) { 34 | return worldConditions.test(view, pos); 35 | } 36 | 37 | @Override 38 | public boolean affectsDirection(Direction side) { 39 | return faceMatcher.test(side); 40 | } 41 | 42 | @Override 43 | public boolean affectsSprite(QuadView quad, SpriteFinder finder) { 44 | return tileMatcher == null ? true : tileMatcher.test(finder.find(quad, 0)); 45 | } 46 | 47 | protected BlockState[][] getAll(BlockRenderView view, Direction upD, Direction leftD, BlockPos pos) { 48 | BlockState[][] result = new BlockState[3][3]; 49 | BlockPos left = pos.offset(leftD); 50 | BlockPos right = pos.offset(leftD.getOpposite()); 51 | result[0][0] = view.getBlockState(left.offset(upD)); 52 | result[0][1] = view.getBlockState(left); 53 | result[0][2] = view.getBlockState(left.offset(upD.getOpposite())); 54 | result[1][0] = view.getBlockState(pos.offset(upD)); 55 | result[1][1] = null; 56 | result[1][2] = view.getBlockState(pos.offset(upD.getOpposite())); 57 | result[2][0] = view.getBlockState(right.offset(upD)); 58 | result[2][1] = view.getBlockState(right); 59 | result[2][2] = view.getBlockState(right.offset(upD.getOpposite())); 60 | return result; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/sprite/ConnectingSpriteProvider.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.sprite; 2 | 3 | import java.util.function.BiPredicate; 4 | 5 | import net.minecraft.block.BlockState; 6 | import net.minecraft.client.texture.Sprite; 7 | import net.minecraft.util.math.BlockPos; 8 | import net.minecraft.util.math.Direction; 9 | import net.minecraft.world.BlockRenderView; 10 | 11 | import io.github.nuclearfarts.cbt.config.ConnectingCTMConfig; 12 | 13 | public abstract class ConnectingSpriteProvider extends BaseSpriteProvider { 14 | protected final BiPredicate connectionMatcher; 15 | 16 | public ConnectingSpriteProvider(Sprite[] connects, ConnectingCTMConfig config) { 17 | super(connects, config); 18 | this.connectionMatcher = config.getConnectionMatcher(); 19 | } 20 | 21 | protected boolean testUp(BlockRenderView view, Direction upD, BlockPos pos, BlockState thisState) { 22 | return connectionMatcher.test(thisState, view.getBlockState(pos.offset(upD))); 23 | } 24 | 25 | protected boolean testLeft(BlockRenderView view, Direction leftD, BlockPos pos, BlockState thisState) { 26 | return connectionMatcher.test(thisState, view.getBlockState(pos.offset(leftD))); 27 | } 28 | 29 | protected boolean testRight(BlockRenderView view, Direction leftD, BlockPos pos, BlockState thisState) { 30 | return connectionMatcher.test(thisState, view.getBlockState(pos.offset(leftD.getOpposite()))); 31 | } 32 | 33 | protected boolean testDown(BlockRenderView view, Direction upD, BlockPos pos, BlockState thisState) { 34 | return connectionMatcher.test(thisState, view.getBlockState(pos.offset(upD.getOpposite()))); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/sprite/FullCTMSpriteProvider.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.sprite; 2 | 3 | import java.util.Random; 4 | import net.minecraft.block.BlockState; 5 | import net.minecraft.client.texture.Sprite; 6 | import net.minecraft.util.math.BlockPos; 7 | import net.minecraft.util.math.Direction; 8 | import net.minecraft.world.BlockRenderView; 9 | 10 | import io.github.nuclearfarts.cbt.config.ConnectingCTMConfig; 11 | 12 | public class FullCTMSpriteProvider extends ConnectingSpriteProvider { 13 | 14 | //i did not write this manually, i generated it. do not ask how. it's evil and involved Swing. 15 | public static final byte[] BITHACK_TO_CTM = {0, 0, 12, 12, 0, 0, 12, 12, 1, 1, 4, 13, 1, 1, 4, 13, 3, 3, 5, 5, 3, 3, 15, 15, 2, 2, 7, 31, 2, 2, 29, 14, 0, 0, 12, 12, 0, 0, 12, 12, 1, 1, 4, 13, 1, 1, 4, 13, 3, 3, 5, 5, 3, 3, 15, 15, 2, 2, 7, 31, 2, 2, 29, 14, 36, 36, 24, 24, 36, 36, 24, 24, 16, 16, 6, 28, 16, 16, 6, 28, 17, 17, 19, 19, 17, 17, 43, 43, 18, 18, 46, 9, 18, 18, 21, 22, 36, 36, 24, 24, 36, 36, 24, 24, 37, 37, 30, 25, 37, 37, 30, 25, 17, 17, 19, 19, 17, 17, 43, 43, 40, 40, 8, 23, 40, 40, 34, 45, 0, 0, 12, 12, 0, 0, 12, 12, 1, 1, 4, 13, 1, 1, 4, 13, 3, 3, 5, 5, 3, 3, 15, 15, 2, 2, 7, 31, 2, 2, 29, 14, 0, 0, 12, 12, 0, 0, 12, 12, 1, 1, 4, 13, 1, 1, 4, 13, 3, 3, 5, 5, 3, 3, 15, 15, 2, 2, 7, 31, 2, 2, 29, 14, 36, 36, 24, 24, 36, 36, 24, 24, 16, 16, 6, 28, 16, 16, 6, 28, 39, 39, 41, 41, 39, 39, 27, 27, 42, 42, 20, 35, 42, 42, 10, 44, 36, 36, 24, 24, 36, 36, 24, 24, 37, 37, 30, 25, 37, 37, 30, 25, 39, 39, 41, 41, 39, 39, 27, 27, 38, 38, 11, 33, 38, 38, 32, 26}; 16 | 17 | public FullCTMSpriteProvider(Sprite[] connects, ConnectingCTMConfig config) { 18 | super(connects, config); 19 | } 20 | 21 | @Override 22 | public Sprite getSpriteForSide(Direction side, Direction upD, Direction leftD, BlockRenderView view, BlockState state, BlockPos pos, Random random) { 23 | BlockState[][] blocks = getAll(view, upD, leftD, pos); 24 | return this.connects[BITHACK_TO_CTM[awfulBitHack(blocks, state)]]; 25 | } 26 | 27 | private int awfulBitHack(BlockState[][] blocks, BlockState state) { 28 | blocks[1][1] = state; 29 | //System.out.println(Arrays.deepToString(blocks)); 30 | int result = 0; 31 | int i = 0; 32 | for(int j = 0; j < blocks.length; j++) { 33 | for(int k = 0; k < blocks.length; k++) { 34 | if(j == 1 && k == 1) { 35 | continue; 36 | } 37 | if(connectionMatcher.test(state, blocks[blocks.length - (k + 1)][blocks.length - (j + 1)])) { 38 | result |= (1 << i); 39 | } 40 | i++; 41 | } 42 | } 43 | return result; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/sprite/HorizontalCTMSpriteProvider.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.sprite; 2 | 3 | import java.util.Random; 4 | import net.minecraft.block.BlockState; 5 | import net.minecraft.client.texture.Sprite; 6 | import net.minecraft.util.math.BlockPos; 7 | import net.minecraft.util.math.Direction; 8 | import net.minecraft.world.BlockRenderView; 9 | 10 | import io.github.nuclearfarts.cbt.config.ConnectingCTMConfig; 11 | 12 | public class HorizontalCTMSpriteProvider extends ConnectingSpriteProvider { 13 | 14 | public HorizontalCTMSpriteProvider(Sprite[] connects, ConnectingCTMConfig config) { 15 | super(connects, config); 16 | } 17 | 18 | @Override 19 | public Sprite getSpriteForSide(Direction side, Direction upD, Direction leftD, BlockRenderView view, BlockState state, BlockPos pos, Random random) { 20 | boolean left = testLeft(view, leftD, pos, state); 21 | boolean right = testRight(view, leftD, pos, state); 22 | if(left && right) { 23 | return connects[1]; 24 | } else if(left && !right) { 25 | return connects[2]; 26 | } else if(!left && right) { 27 | return connects[0]; 28 | } else { 29 | return connects[3]; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/sprite/HorizontalVerticalCTMSpriteProvider.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.sprite; 2 | 3 | import java.util.Random; 4 | import net.minecraft.block.BlockState; 5 | import net.minecraft.client.texture.Sprite; 6 | import net.minecraft.util.math.BlockPos; 7 | import net.minecraft.util.math.Direction; 8 | import net.minecraft.world.BlockRenderView; 9 | 10 | import io.github.nuclearfarts.cbt.config.ConnectingCTMConfig; 11 | 12 | public class HorizontalVerticalCTMSpriteProvider extends ConnectingSpriteProvider { 13 | 14 | public HorizontalVerticalCTMSpriteProvider(Sprite[] connects, ConnectingCTMConfig config) { 15 | super(connects, config); 16 | } 17 | 18 | @Override 19 | public Sprite getSpriteForSide(Direction side, Direction upD, Direction leftD, BlockRenderView view, BlockState state, BlockPos pos, Random random) { 20 | boolean left = testLeft(view, leftD, pos, state); 21 | boolean right = testRight(view, leftD, pos, state); 22 | boolean down = testDown(view, upD, pos, state); 23 | boolean up = testUp(view, upD, pos, state); 24 | if(left && right) { 25 | return connects[1]; 26 | } else if(left && !right) { 27 | return connects[2]; 28 | } else if(!left && right) { 29 | return connects[0]; 30 | } else if(down && up) { 31 | return connects[5]; 32 | } else if(down && !up) { 33 | return connects[6]; 34 | } else if(!down && up) { 35 | return connects[4]; 36 | } else { 37 | return connects[3]; 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/sprite/RandomSpriteProvider.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.sprite; 2 | 3 | import java.util.Random; 4 | import net.minecraft.block.BlockState; 5 | import net.minecraft.client.texture.Sprite; 6 | import net.minecraft.util.math.BlockPos; 7 | import net.minecraft.util.math.Direction; 8 | import net.minecraft.world.BlockRenderView; 9 | 10 | import io.github.nuclearfarts.cbt.config.RandomCTMConfig; 11 | 12 | public class RandomSpriteProvider extends BaseSpriteProvider { 13 | 14 | public RandomSpriteProvider(Sprite[] connects, RandomCTMConfig config) { 15 | super(connects, config); 16 | } 17 | 18 | @Override 19 | public Sprite getSpriteForSide(Direction side, Direction upD, Direction leftD, BlockRenderView view, BlockState state, BlockPos pos, Random random) { 20 | return connects[random.nextInt(connects.length)]; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/sprite/RepeatingCTMSpriteProvider.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.sprite; 2 | 3 | import java.util.Random; 4 | 5 | import net.minecraft.block.BlockState; 6 | import net.minecraft.client.texture.Sprite; 7 | import net.minecraft.util.math.BlockPos; 8 | import net.minecraft.util.math.Direction; 9 | import net.minecraft.world.BlockRenderView; 10 | 11 | import io.github.nuclearfarts.cbt.config.RepeatingCTMConfig; 12 | import io.github.nuclearfarts.cbt.util.CBTUtil; 13 | 14 | public class RepeatingCTMSpriteProvider extends BaseSpriteProvider { 15 | private final int width; 16 | private final int height; 17 | 18 | public RepeatingCTMSpriteProvider(Sprite[] connects, RepeatingCTMConfig config) { 19 | super(connects, config); 20 | width = config.getWidth(); 21 | height = config.getHeight(); 22 | } 23 | 24 | @Override 25 | public Sprite getSpriteForSide(Direction side, Direction upD, Direction leftD, BlockRenderView view, BlockState state, BlockPos pos, Random random) { 26 | int wPos = 0; 27 | int hPos = 0; 28 | switch(side.getAxis()) { 29 | case X: 30 | if(side.getOffsetX() < 0) { 31 | wPos = CBTUtil.actualMod(pos.getZ(), width); 32 | } else { 33 | wPos = CBTUtil.actualMod(pos.getZ() - 1, width); 34 | } 35 | hPos = CBTUtil.actualMod(-pos.getY(), height); 36 | break; 37 | case Z: 38 | if(side.getOffsetZ() < 0) { 39 | wPos = CBTUtil.actualMod(pos.getX() - 1, width); 40 | } else { 41 | wPos = CBTUtil.actualMod(pos.getX(), width); 42 | } 43 | hPos = CBTUtil.actualMod(-pos.getY(), height); 44 | break; 45 | case Y: 46 | wPos = CBTUtil.actualMod(pos.getX(), width); 47 | if(side.getOffsetY() < 0) { 48 | hPos = CBTUtil.actualMod(-pos.getZ() - 1, height); 49 | } else { 50 | hPos = CBTUtil.actualMod(pos.getZ(), height); 51 | } 52 | } 53 | return connects[wPos + hPos * width]; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/sprite/SpriteProvider.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.sprite; 2 | 3 | import java.util.Random; 4 | 5 | import net.minecraft.block.BlockState; 6 | import net.minecraft.client.texture.Sprite; 7 | import net.minecraft.util.math.BlockPos; 8 | import net.minecraft.util.math.Direction; 9 | import net.minecraft.world.BlockRenderView; 10 | 11 | import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView; 12 | import net.fabricmc.fabric.api.renderer.v1.model.SpriteFinder; 13 | 14 | public interface SpriteProvider { 15 | boolean affectsBlock(BlockRenderView view, BlockState state, BlockPos pos); 16 | boolean affectsDirection(Direction side); 17 | boolean affectsSprite(QuadView quad, SpriteFinder finder); 18 | Sprite getSpriteForSide(Direction side, Direction up, Direction left, BlockRenderView view, BlockState state, BlockPos pos, Random random); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/sprite/TopCTMSpriteProvider.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.sprite; 2 | 3 | import java.util.Random; 4 | import net.minecraft.block.BlockState; 5 | import net.minecraft.client.texture.Sprite; 6 | import net.minecraft.util.math.BlockPos; 7 | import net.minecraft.util.math.Direction; 8 | import net.minecraft.world.BlockRenderView; 9 | 10 | import io.github.nuclearfarts.cbt.config.ConnectingCTMConfig; 11 | 12 | public class TopCTMSpriteProvider extends ConnectingSpriteProvider { 13 | 14 | public TopCTMSpriteProvider(Sprite[] connects, ConnectingCTMConfig config) { 15 | super(connects, config); 16 | } 17 | 18 | @Override 19 | public Sprite getSpriteForSide(Direction side, Direction upD, Direction leftD, BlockRenderView view, BlockState state, BlockPos pos, Random random) { 20 | return testUp(view, upD, pos, state) ? connects[0] : null; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/sprite/VerticalCTMSpriteProvider.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.sprite; 2 | 3 | import java.util.Random; 4 | import net.minecraft.block.BlockState; 5 | import net.minecraft.client.texture.Sprite; 6 | import net.minecraft.util.math.BlockPos; 7 | import net.minecraft.util.math.Direction; 8 | import net.minecraft.world.BlockRenderView; 9 | 10 | import io.github.nuclearfarts.cbt.config.ConnectingCTMConfig; 11 | 12 | public class VerticalCTMSpriteProvider extends ConnectingSpriteProvider { 13 | 14 | public VerticalCTMSpriteProvider(Sprite[] connects, ConnectingCTMConfig config) { 15 | super(connects, config); 16 | } 17 | 18 | @Override 19 | public Sprite getSpriteForSide(Direction side, Direction upD, Direction leftD, BlockRenderView view, BlockState state, BlockPos pos, Random random) { 20 | boolean down = testDown(view, upD, pos, state); 21 | boolean up = testUp(view, upD, pos, state); 22 | if(down && up) { 23 | return connects[1]; 24 | } else if(down && !up) { 25 | return connects[2]; 26 | } else if(!down && up) { 27 | return connects[0]; 28 | } else { 29 | return connects[3]; 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/sprite/VerticalHorizontalCTMSpriteProvider.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.sprite; 2 | 3 | import java.util.Random; 4 | import net.minecraft.block.BlockState; 5 | import net.minecraft.client.texture.Sprite; 6 | import net.minecraft.util.math.BlockPos; 7 | import net.minecraft.util.math.Direction; 8 | import net.minecraft.world.BlockRenderView; 9 | 10 | import io.github.nuclearfarts.cbt.config.ConnectingCTMConfig; 11 | 12 | public class VerticalHorizontalCTMSpriteProvider extends ConnectingSpriteProvider { 13 | 14 | public VerticalHorizontalCTMSpriteProvider(Sprite[] connects, ConnectingCTMConfig config) { 15 | super(connects, config); 16 | } 17 | 18 | @Override 19 | public Sprite getSpriteForSide(Direction side, Direction upD, Direction leftD, BlockRenderView view, BlockState state, BlockPos pos, Random random) { 20 | boolean left = testLeft(view, leftD, pos, state); 21 | boolean right = testRight(view, leftD, pos, state); 22 | boolean down = testDown(view, upD, pos, state); 23 | boolean up = testUp(view, upD, pos, state); 24 | if(down && up) { 25 | return connects[1]; 26 | } else if(down && !up) { 27 | return connects[2]; 28 | } else if(!down && up) { 29 | return connects[0]; 30 | } else if(left && right) { 31 | return connects[5]; 32 | } else if(left && !right) { 33 | return connects[6]; 34 | } else if(!left && right) { 35 | return connects[4]; 36 | } else { 37 | return connects[3]; 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/tile/ImageBackedTile.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.tile; 2 | 3 | import net.minecraft.client.texture.NativeImage; 4 | import net.minecraft.util.Identifier; 5 | 6 | public class ImageBackedTile implements Tile { 7 | private final NativeImage image; 8 | 9 | public ImageBackedTile(NativeImage image) { 10 | this.image = image; 11 | } 12 | 13 | @Override 14 | public boolean hasResource() { 15 | return false; 16 | } 17 | 18 | @Override 19 | public Identifier getResource() { 20 | throw new UnsupportedOperationException("Tile has no underlying resource!"); 21 | } 22 | 23 | @Override 24 | public NativeImage getImage() { 25 | return image; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/tile/ResourceBackedTile.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.tile; 2 | 3 | import java.io.IOException; 4 | 5 | import net.minecraft.client.texture.NativeImage; 6 | import net.minecraft.resource.ResourceManager; 7 | import net.minecraft.util.Identifier; 8 | 9 | public class ResourceBackedTile implements Tile { 10 | private final Identifier resource; 11 | private final ResourceManager resourceManager; 12 | 13 | public ResourceBackedTile(Identifier resource, ResourceManager resourceManager) { 14 | this.resource = resource; 15 | this.resourceManager = resourceManager; 16 | } 17 | 18 | @Override 19 | public boolean hasResource() { 20 | return true; 21 | } 22 | 23 | @Override 24 | public Identifier getResource() { 25 | return resource; 26 | } 27 | 28 | @Override 29 | public NativeImage getImage() throws IOException { 30 | return NativeImage.read(resourceManager.getResource(resource).getInputStream()); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/tile/Tile.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.tile; 2 | 3 | import java.io.IOException; 4 | 5 | import net.minecraft.client.texture.NativeImage; 6 | import net.minecraft.util.Identifier; 7 | 8 | public interface Tile { 9 | boolean hasResource(); 10 | /** 11 | * @throws UnsupportedOperationException if this is a dynamically generated tile. 12 | * */ 13 | Identifier getResource(); 14 | NativeImage getImage() throws IOException; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/tile/loader/BasicTileLoader.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.tile.loader; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Properties; 6 | import java.util.regex.Pattern; 7 | 8 | import net.minecraft.resource.ResourceManager; 9 | import net.minecraft.util.Identifier; 10 | 11 | import io.github.nuclearfarts.cbt.tile.ResourceBackedTile; 12 | import io.github.nuclearfarts.cbt.tile.Tile; 13 | import io.github.nuclearfarts.cbt.util.CBTUtil; 14 | 15 | public class BasicTileLoader implements TileLoader { 16 | private static final Pattern RANGE_PATTERN = Pattern.compile("^\\d+-\\d+$"); 17 | 18 | private final Tile[] tiles; 19 | 20 | public BasicTileLoader(Properties properties, Identifier location, ResourceManager manager) { 21 | this(properties.getProperty("tiles").split(" "), location, manager); 22 | } 23 | 24 | public BasicTileLoader(String[] tileDefs, Identifier location, ResourceManager manager) { 25 | List loadedTiles = new ArrayList<>(); 26 | for(String tileDef : tileDefs) { 27 | if(RANGE_PATTERN.matcher(tileDef).find()) { 28 | String[] defSplit = tileDef.split("-"); 29 | int min = Integer.parseInt(defSplit[0]); 30 | int max = Integer.parseInt(defSplit[1]); 31 | for(int i = min; i <= max; i++) { 32 | loadedTiles.add(new ResourceBackedTile(CBTUtil.appendId(location, "/" + i + ".png"), manager)); 33 | } 34 | } else { 35 | if(tileDef.contains("/")) { 36 | if(tileDef.startsWith("~")) { 37 | tileDef = "optifine" + tileDef.substring(1); 38 | } 39 | loadedTiles.add(new ResourceBackedTile(new Identifier(CBTUtil.ensurePngExtension(tileDef)), manager)); 40 | } else { 41 | loadedTiles.add(new ResourceBackedTile(CBTUtil.appendId(location, "/" + CBTUtil.ensurePngExtension(tileDef)), manager)); 42 | } 43 | } 44 | } 45 | this.tiles = loadedTiles.toArray(new Tile[loadedTiles.size()]); 46 | } 47 | 48 | @Override 49 | public Tile[] getTiles() { 50 | return tiles; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/tile/loader/DynamicBookshelfTileLoader.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.tile.loader; 2 | 3 | import java.io.IOException; 4 | import java.util.Properties; 5 | 6 | import net.minecraft.client.texture.NativeImage; 7 | import net.minecraft.resource.ResourceManager; 8 | import net.minecraft.util.Identifier; 9 | 10 | import io.github.nuclearfarts.cbt.tile.ImageBackedTile; 11 | import io.github.nuclearfarts.cbt.tile.ResourceBackedTile; 12 | import io.github.nuclearfarts.cbt.tile.Tile; 13 | import io.github.nuclearfarts.cbt.util.CBTUtil; 14 | 15 | public class DynamicBookshelfTileLoader implements TileLoader { 16 | Tile[] tiles = new Tile[4]; 17 | 18 | public DynamicBookshelfTileLoader(Properties properties, Identifier location, ResourceManager manager) throws IOException { 19 | Identifier textureLocation = new Identifier(properties.getProperty("cbt_special_bookshelf_texture")); 20 | try(NativeImage bookshelf = NativeImage.read(manager.getResource(textureLocation).getInputStream())) { 21 | tiles[3] = new ResourceBackedTile(textureLocation, manager); 22 | NativeImage work; 23 | work = CBTUtil.copy(bookshelf); 24 | copyVLine(work, 4, 1, 6, 15, 9); 25 | copyVLine(work, 8, 9, 6, 15, 1); 26 | tiles[0] = new ImageBackedTile(work); 27 | work = CBTUtil.copy(work); 28 | copyVLine(work, 5, 1, 6, 0, 9); 29 | copyVLine(work, 9, 9, 6, 0, 1); 30 | tiles[1] = new ImageBackedTile(work); 31 | work = CBTUtil.copy(bookshelf); 32 | copyVLine(work, 5, 1, 6, 0, 9); 33 | copyVLine(work, 9, 9, 6, 0, 1); 34 | tiles[2] = new ImageBackedTile(work); 35 | } 36 | } 37 | 38 | @Override 39 | public Tile[] getTiles() { 40 | return tiles; 41 | } 42 | 43 | private void copyVLine(NativeImage on, int srcX, int srcY, int height, int dstX, int dstY) { 44 | for(int i = 0; i < height; i++) { 45 | on.setPixelColor(dstX, dstY + i, on.getPixelColor(srcX, srcY + i)); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/tile/loader/DynamicGlassTileLoader.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.tile.loader; 2 | 3 | import java.io.IOException; 4 | import java.util.Properties; 5 | 6 | import net.minecraft.client.texture.NativeImage; 7 | import net.minecraft.resource.ResourceManager; 8 | import net.minecraft.util.Identifier; 9 | 10 | import io.github.nuclearfarts.cbt.tile.ImageBackedTile; 11 | import io.github.nuclearfarts.cbt.tile.Tile; 12 | import io.github.nuclearfarts.cbt.util.CBTUtil; 13 | 14 | public class DynamicGlassTileLoader implements TileLoader { 15 | private final Tile[] tiles = new Tile[5]; 16 | 17 | public DynamicGlassTileLoader(Properties properties, Identifier location, ResourceManager manager) throws IOException { 18 | NativeImage glass = NativeImage.read(manager.getResource(new Identifier(properties.getProperty("cbt_special_glass_texture"))).getInputStream()); 19 | int background = CBTUtil.toABGR(Integer.parseUnsignedInt(properties.getProperty("cbt_special_glass_background"), 16)); 20 | tiles[0] = new ImageBackedTile(glass); //all-borders 21 | 22 | NativeImage work; 23 | work = CBTUtil.copy(glass); 24 | hLine(work, 0, 0, 16, background); 25 | hLine(work, 0, 15, 16, background); 26 | vLine(work, 0, 1, 14, background); 27 | vLine(work, 15, 1, 14, background); 28 | tiles[1] = new ImageBackedTile(work); 29 | 30 | work = CBTUtil.copy(glass); 31 | hLine(work, 1, 0, 14, background); 32 | hLine(work, 1, 15, 14, background); 33 | tiles[2] = new ImageBackedTile(work); 34 | 35 | work = CBTUtil.copy(glass); 36 | vLine(work, 0, 1, 14, background); 37 | vLine(work, 15, 1, 14, background); 38 | tiles[3] = new ImageBackedTile(work); 39 | 40 | work = CBTUtil.copy(glass); 41 | hLine(work, 1, 0, 14, background); 42 | hLine(work, 1, 15, 14, background); 43 | vLine(work, 0, 1, 14, background); 44 | vLine(work, 15, 1, 14, background); 45 | tiles[4] = new ImageBackedTile(work); 46 | } 47 | 48 | @Override 49 | public Tile[] getTiles() { 50 | return tiles; 51 | } 52 | 53 | private static void hLine(NativeImage image, int xStart, int y, int length, int color) { 54 | for(int x = 0; x < length; x++) { 55 | image.setPixelColor(x + xStart, y, color); 56 | } 57 | } 58 | 59 | private static void vLine(NativeImage image, int x, int yStart, int length, int color) { 60 | for(int y = 0; y < length; y++) { 61 | image.setPixelColor(x, y + yStart, color); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/tile/loader/DynamicSandstoneTileLoader.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.tile.loader; 2 | 3 | import java.io.IOException; 4 | import java.util.Properties; 5 | 6 | import net.minecraft.client.texture.NativeImage; 7 | import net.minecraft.resource.ResourceManager; 8 | import net.minecraft.util.Identifier; 9 | 10 | import io.github.nuclearfarts.cbt.tile.ImageBackedTile; 11 | import io.github.nuclearfarts.cbt.tile.Tile; 12 | 13 | public class DynamicSandstoneTileLoader implements TileLoader { 14 | private Tile[] tiles = new Tile[1]; 15 | 16 | public DynamicSandstoneTileLoader(Properties properties, Identifier location, ResourceManager manager) throws IOException { 17 | NativeImage sandstone = NativeImage.read(manager.getResource(new Identifier(properties.getProperty("cbt_special_sandstone_texture"))).getInputStream()); 18 | for(int x = 0; x < 16; x++) { 19 | for(int y = 0; y < 3; y++) { 20 | sandstone.setPixelColor(15 - x, y, sandstone.getPixelColor(x, y + 12)); 21 | } 22 | } 23 | tiles[0] = new ImageBackedTile(sandstone); 24 | } 25 | 26 | @Override 27 | public Tile[] getTiles() { 28 | return tiles; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/tile/loader/TileLoader.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.tile.loader; 2 | 3 | import java.io.IOException; 4 | import java.util.Properties; 5 | 6 | import net.minecraft.resource.ResourceManager; 7 | import net.minecraft.util.Identifier; 8 | 9 | import io.github.nuclearfarts.cbt.tile.Tile; 10 | import it.unimi.dsi.fastutil.objects.Object2ObjectMap; 11 | import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; 12 | 13 | public interface TileLoader { 14 | Tile[] getTiles(); 15 | 16 | static void registerSpecialTileLoader(String name, Loader loader) { 17 | PrivateConstants.SPECIAL_TILE_LOADERS.put(name, loader); 18 | } 19 | 20 | static TileLoader load(Properties properties, Identifier location, ResourceManager manager) throws IOException { 21 | return PrivateConstants.SPECIAL_TILE_LOADERS.get(properties.getProperty("tiles")).load(properties, location, manager); 22 | } 23 | 24 | public interface Loader { 25 | T load(Properties properties, Identifier location, ResourceManager manager) throws IOException; 26 | } 27 | 28 | public static final class PrivateConstants { 29 | private PrivateConstants() { } 30 | private static final Object2ObjectMap> SPECIAL_TILE_LOADERS = new Object2ObjectOpenHashMap<>(); 31 | 32 | static { 33 | SPECIAL_TILE_LOADERS.defaultReturnValue(BasicTileLoader::new); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/tile/provider/BasicTileProvider.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.tile.provider; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.function.Function; 6 | 7 | import net.minecraft.client.texture.Sprite; 8 | import net.minecraft.client.texture.SpriteAtlasTexture; 9 | import net.minecraft.client.util.SpriteIdentifier; 10 | 11 | import io.github.nuclearfarts.cbt.ConnectedBlockTextures; 12 | import io.github.nuclearfarts.cbt.tile.Tile; 13 | 14 | public class BasicTileProvider implements TileProvider { 15 | private final List ids = new ArrayList<>(); 16 | 17 | public BasicTileProvider(Tile[] tiles) { 18 | for(Tile tile : tiles) { 19 | ids.add(new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, ConnectedBlockTextures.resourcePack.dynamicallyPutTile(tile))); 20 | } 21 | } 22 | 23 | @Override 24 | public List getIdsToLoad() { 25 | //System.out.println(ids); 26 | return ids; 27 | } 28 | 29 | @Override 30 | public Sprite[] load(Function textureGetter) { 31 | Sprite[] sprites = new Sprite[ids.size()]; 32 | for(int i = 0; i < ids.size(); i++) { 33 | sprites[i] = textureGetter.apply(ids.get(i)); 34 | } 35 | return sprites; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/tile/provider/CompactTileProvider.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.tile.provider; 2 | 3 | import java.io.IOException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.function.Function; 7 | 8 | import net.minecraft.client.texture.NativeImage; 9 | import net.minecraft.client.texture.Sprite; 10 | import net.minecraft.client.texture.SpriteAtlasTexture; 11 | import net.minecraft.client.util.SpriteIdentifier; 12 | import io.github.nuclearfarts.cbt.ConnectedBlockTextures; 13 | import io.github.nuclearfarts.cbt.tile.Tile; 14 | 15 | public class CompactTileProvider implements TileProvider { 16 | private final List spriteIds = new ArrayList<>(); 17 | 18 | public CompactTileProvider(Tile[] origTiles) throws IOException { 19 | NativeImage[] origImages = new NativeImage[5]; 20 | for(int i = 0; i < 5; i++) { 21 | origImages[i] = origTiles[i].getImage(); 22 | } 23 | for(int i = 0; i <= 46; i++) { 24 | NativeImage tile = new NativeImage(origImages[0].getWidth(), origImages[0].getHeight(), true); 25 | short bithack = ConnectedBlockTextures.CTM_TO_IDEALIZED_BITHACK[i]; 26 | //Up-left. up-left-upleft 27 | 28 | if((bithack & 0b1010000) == 0) { 29 | //draw both. 30 | blitQuarter(0, 0, origImages[0], tile); 31 | } else if((bithack & 0b10000) == 0) { 32 | //draw left 33 | blitQuarter(0, 0, origImages[2], tile); 34 | } else if((bithack & 0b1000000) == 0) { 35 | //draw up 36 | blitQuarter(0, 0, origImages[3], tile); 37 | } else if((bithack & 0b10000000) == 0) { 38 | //draw corner 39 | blitQuarter(0, 0, origImages[4], tile); 40 | } else { 41 | //empty 42 | blitQuarter(0, 0, origImages[1], tile); 43 | } 44 | 45 | //up-right. 46 | if((bithack & 0b1001000) == 0) { 47 | //draw both. 48 | blitQuarter(1, 0, origImages[0], tile); 49 | } else if((bithack & 0b1000) == 0) { 50 | //draw right 51 | blitQuarter(1, 0, origImages[2], tile); 52 | } else if((bithack & 0b1000000) == 0) { 53 | //draw up 54 | blitQuarter(1, 0, origImages[3], tile); 55 | } else if((bithack & 0b100000) == 0) { 56 | //draw corner 57 | blitQuarter(1, 0, origImages[4], tile); 58 | } else { 59 | //empty 60 | blitQuarter(1, 0, origImages[1], tile); 61 | } 62 | 63 | //down-left 64 | if((bithack & 0b10010) == 0) { 65 | //draw both. 66 | blitQuarter(0, 1, origImages[0], tile); 67 | } else if((bithack & 0b10000) == 0) { 68 | //draw left 69 | blitQuarter(0, 1, origImages[2], tile); 70 | } else if((bithack & 0b10) == 0) { 71 | //draw down 72 | blitQuarter(0, 1, origImages[3], tile); 73 | } else if((bithack & 0b100) == 0) { 74 | //draw corner 75 | blitQuarter(0, 1, origImages[4], tile); 76 | } else { 77 | //empty 78 | blitQuarter(0, 1, origImages[1], tile); 79 | } 80 | 81 | //down-right 82 | if((bithack & 0b1010) == 0) { 83 | //draw both. 84 | blitQuarter(1, 1, origImages[0], tile); 85 | } else if((bithack & 0b1000) == 0) { 86 | //draw right 87 | blitQuarter(1, 1, origImages[2], tile); 88 | } else if((bithack & 0b10) == 0) { 89 | //draw down 90 | blitQuarter(1, 1, origImages[3], tile); 91 | } else if((bithack & 0b1) == 0) { 92 | //draw corner 93 | blitQuarter(1, 1, origImages[4], tile); 94 | } else { 95 | //empty 96 | blitQuarter(1, 1, origImages[1], tile); 97 | } 98 | 99 | spriteIds.add(new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, ConnectedBlockTextures.resourcePack.dynamicallyPutImage(tile))); 100 | } 101 | } 102 | 103 | private static void blitQuarter(int offsetX, int offsetY, NativeImage src, NativeImage dst) { 104 | int w = src.getWidth() / 2; 105 | int h = src.getHeight() / 2; 106 | int x = w * offsetX; 107 | int y = h * offsetY; 108 | for(int i = x; i < w + x; i++) { 109 | for(int j = y; j < h + y; j++) { 110 | dst.setPixelColor(i, j, src.getPixelColor(i, j)); 111 | } 112 | } 113 | } 114 | 115 | @Override 116 | public List getIdsToLoad() { 117 | return spriteIds; 118 | } 119 | 120 | @Override 121 | public Sprite[] load(Function textureGetter) { 122 | Sprite[] sprites = new Sprite[spriteIds.size()]; 123 | for(int i = 0; i < sprites.length; i++) { 124 | sprites[i] = textureGetter.apply(spriteIds.get(i)); 125 | } 126 | return sprites; 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/tile/provider/TileProvider.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.tile.provider; 2 | 3 | import java.io.IOException; 4 | import java.util.List; 5 | import java.util.Properties; 6 | import java.util.function.Function; 7 | 8 | import net.minecraft.client.texture.Sprite; 9 | import net.minecraft.client.util.SpriteIdentifier; 10 | import net.minecraft.resource.ResourceManager; 11 | import net.minecraft.util.Identifier; 12 | 13 | import io.github.nuclearfarts.cbt.tile.Tile; 14 | import io.github.nuclearfarts.cbt.tile.loader.TileLoader; 15 | import io.github.nuclearfarts.cbt.util.CBTUtil; 16 | import it.unimi.dsi.fastutil.objects.Object2ObjectMap; 17 | import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; 18 | 19 | public interface TileProvider { 20 | List getIdsToLoad(); 21 | Sprite[] load(Function textureGetter); 22 | 23 | static TileProvider load(Properties properties, Identifier location, ResourceManager manager) throws IOException { 24 | return PrivateConstants.TILE_PROVIDERS.get(properties.getProperty("method")).create(TileLoader.load(properties, location, manager).getTiles()); 25 | } 26 | 27 | static TileProvider load(Identifier propertiesLocation, ResourceManager manager) throws IOException { 28 | Properties properties = new Properties(); 29 | properties.load(manager.getResource(propertiesLocation).getInputStream()); 30 | return load(properties, CBTUtil.directoryOf(propertiesLocation), manager); 31 | } 32 | 33 | static void registerTileProviderFactory(String method, Factory loader) { 34 | PrivateConstants.TILE_PROVIDERS.put(method, loader); 35 | } 36 | 37 | @FunctionalInterface 38 | public interface Factory { 39 | T create(Tile[] tiles) throws IOException; 40 | } 41 | 42 | public static final class PrivateConstants { 43 | private PrivateConstants() { } 44 | private static final Object2ObjectMap> TILE_PROVIDERS = new Object2ObjectOpenHashMap<>(); 45 | 46 | static { 47 | TILE_PROVIDERS.defaultReturnValue(BasicTileProvider::new); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/util/CBTUtil.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.util; 2 | 3 | import java.util.Collection; 4 | import java.util.function.Function; 5 | import java.util.function.IntPredicate; 6 | import java.util.function.Predicate; 7 | 8 | import net.minecraft.client.texture.NativeImage; 9 | import net.minecraft.client.util.ModelIdentifier; 10 | import net.minecraft.util.Identifier; 11 | 12 | import io.github.nuclearfarts.cbt.util.function.ThrowingPredicate; 13 | 14 | public class CBTUtil { 15 | 16 | public static Identifier appendId(Identifier path, String str) { 17 | return new Identifier(path.getNamespace(), path.getPath() + str); 18 | } 19 | 20 | public static Identifier prependId(Identifier path, String str) { 21 | return new Identifier(path.getNamespace(), str + path.getPath()); 22 | } 23 | 24 | public static String ensurePngExtension(String string) { 25 | if(!string.endsWith(".png")) { 26 | return string + ".png"; 27 | } 28 | return string; 29 | } 30 | 31 | //time to avoid streams! 32 | public static boolean mapAnyMatch(Collection collection, Function mapper, Predicate predicate) { 33 | for(T t : collection) { 34 | if(predicate.test(mapper.apply(t))) { 35 | return true; 36 | } 37 | } 38 | return false; 39 | } 40 | 41 | public static boolean allMatchThrowable(Collection collection, ThrowingPredicate predicate) throws U { 42 | for(T t : collection) { 43 | if(!predicate.test(t)) { 44 | return false; 45 | } 46 | } 47 | return true; 48 | } 49 | 50 | public static boolean satisfiesAny(Collection predicates, int i) { 51 | for(IntPredicate p : predicates) { 52 | if(p.test(i)) { 53 | return true; 54 | } 55 | } 56 | return false; 57 | } 58 | 59 | public static Identifier directoryOf(Identifier id) { 60 | String path = id.getPath(); 61 | return new Identifier(id.getNamespace(), path.substring(0, path.lastIndexOf('/'))); 62 | } 63 | 64 | public static String fileNameOf(Identifier id) { 65 | String path = id.getPath(); 66 | return path.substring(path.lastIndexOf('/'), path.length()); 67 | } 68 | 69 | public static Identifier stripBlankVariants(ModelIdentifier modelId) { 70 | if(modelId.getVariant().equals("")) { 71 | return new Identifier(modelId.getNamespace(), modelId.getPath()); 72 | } 73 | return modelId; 74 | } 75 | 76 | public static Identifier stripVariants(ModelIdentifier modelId) { 77 | return new Identifier(modelId.getNamespace(), modelId.getPath()); 78 | } 79 | 80 | public static NativeImage copy(NativeImage image) { 81 | NativeImage newImage = new NativeImage(image.getFormat(), image.getWidth(), image.getHeight(), true); 82 | newImage.copyFrom(image); 83 | return newImage; 84 | } 85 | 86 | public static int actualMod(int in, int modulo) { 87 | int mod = in % modulo; 88 | if(mod < 0) { 89 | mod += modulo; 90 | } 91 | return mod; 92 | } 93 | 94 | public static int toABGR(int argb) { 95 | return ((argb >> 24) << 24) | // Alpha 96 | ((argb >> 16) & 0xFF) | // Red -> Blue 97 | ((argb >> 8) & 0xFF) << 8 | // Green 98 | ((argb) & 0xFF) << 16; // Blue -> Red 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/util/CursedBiomeThing.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.util; 2 | 3 | import net.minecraft.util.math.BlockPos; 4 | import net.minecraft.world.BlockRenderView; 5 | import net.minecraft.world.biome.Biome; 6 | import net.minecraft.world.level.ColorResolver; 7 | 8 | public class CursedBiomeThing implements ColorResolver { 9 | private static final SimplePool POOL = new SimplePool(CursedBiomeThing::new); 10 | 11 | Biome result; 12 | 13 | private CursedBiomeThing() { } 14 | 15 | public static Biome getBiome(BlockRenderView view, BlockPos pos) { 16 | CursedBiomeThing cursed = POOL.get(); 17 | view.getColor(pos, cursed); 18 | Biome result = cursed.result; 19 | POOL.readd(cursed); 20 | return result; 21 | } 22 | 23 | @Override 24 | public int getColor(Biome biome, double d, double e) { 25 | result = biome; 26 | return 0; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/util/SimplePool.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.util; 2 | 3 | import java.util.Queue; 4 | import java.util.concurrent.ConcurrentLinkedQueue; 5 | import java.util.function.Consumer; 6 | import java.util.function.Supplier; 7 | 8 | public class SimplePool { 9 | private final Queue queue = new ConcurrentLinkedQueue<>(); 10 | private final Supplier supplier; 11 | private final Consumer resetter; 12 | 13 | public SimplePool(Supplier supplier, Consumer resetter) { 14 | this.supplier = supplier; 15 | this.resetter = resetter; 16 | } 17 | 18 | public SimplePool(Supplier supplier) { 19 | this(supplier, t -> {}); 20 | } 21 | 22 | public T get() { 23 | T obj; 24 | if((obj = queue.poll()) == null) { 25 | return supplier.get(); 26 | } else { 27 | resetter.accept(obj); 28 | return obj; 29 | } 30 | } 31 | 32 | public void readd(T t) { 33 | queue.add(t); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/util/VoidSet.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.util; 2 | 3 | import java.util.Collection; 4 | import java.util.Iterator; 5 | import java.util.Set; 6 | 7 | public class VoidSet implements Set { 8 | private static final VoidSet INSTANCE = new VoidSet<>(); 9 | 10 | @SuppressWarnings("unchecked") 11 | public static VoidSet get() { 12 | return (VoidSet) INSTANCE; 13 | } 14 | 15 | private VoidSet() { } 16 | 17 | @Override 18 | public int size() { 19 | return 0; 20 | } 21 | 22 | @Override 23 | public boolean isEmpty() { 24 | return true; 25 | } 26 | 27 | @Override 28 | public boolean contains(Object o) { 29 | return false; 30 | } 31 | 32 | @Override 33 | public Iterator iterator() { 34 | return VoidIterator.get(); 35 | } 36 | 37 | @Override 38 | public Object[] toArray() { 39 | return new Object[0]; 40 | } 41 | 42 | @Override 43 | public T[] toArray(T[] a) { 44 | return a; 45 | } 46 | 47 | @Override 48 | public boolean add(E e) { 49 | return false; 50 | } 51 | 52 | @Override 53 | public boolean remove(Object o) { 54 | return false; 55 | } 56 | 57 | @Override 58 | public boolean containsAll(Collection c) { 59 | return false; 60 | } 61 | 62 | @Override 63 | public boolean addAll(Collection c) { 64 | return false; 65 | } 66 | 67 | @Override 68 | public boolean retainAll(Collection c) { 69 | return false; 70 | } 71 | 72 | @Override 73 | public boolean removeAll(Collection c) { 74 | return false; 75 | } 76 | 77 | @Override 78 | public void clear() { } 79 | 80 | private static class VoidIterator implements Iterator { 81 | private static final VoidIterator INSTANCE = new VoidIterator<>(); 82 | 83 | @SuppressWarnings("unchecked") 84 | public static VoidIterator get() { 85 | return (VoidIterator) INSTANCE; 86 | } 87 | 88 | @Override 89 | public boolean hasNext() { 90 | return false; 91 | } 92 | 93 | @Override 94 | public E next() { 95 | return null; 96 | } 97 | 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/util/function/MutableCachingSupplier.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.util.function; 2 | 3 | import java.util.function.Supplier; 4 | 5 | public class MutableCachingSupplier implements Supplier { 6 | private Supplier supplier; 7 | private T cache; 8 | 9 | public void set(Supplier newSupplier) { 10 | supplier = newSupplier; 11 | cache = null; 12 | } 13 | 14 | @Override 15 | public T get() { 16 | return cache == null ? cache = supplier.get() : cache; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/io/github/nuclearfarts/cbt/util/function/ThrowingPredicate.java: -------------------------------------------------------------------------------- 1 | package io.github.nuclearfarts.cbt.util.function; 2 | 3 | public interface ThrowingPredicate { 4 | boolean test(T t) throws U; 5 | } 6 | -------------------------------------------------------------------------------- /src/main/resources/assets/connected_block_textures/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HyperCubeMC/connected-block-textures/5e06943fdf444456b54056bc197aef54f4863f30/src/main/resources/assets/connected_block_textures/icon.png -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/models/block/template_glass_pane_post.json: -------------------------------------------------------------------------------- 1 | { 2 | "ambientocclusion": false, 3 | "textures": { 4 | "particle": "#pane" 5 | }, 6 | "elements": [ 7 | { "from": [ 7, 0, 7 ], 8 | "to": [ 9, 16, 9 ], 9 | "faces": { 10 | "down": { "uv": [ 7, 7, 9, 9 ], "texture": "#edge", "cullface": "down" }, 11 | "up": { "uv": [ 7, 7, 9, 9 ], "texture": "#edge", "cullface": "up" } 12 | } 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/models/block/template_glass_pane_side.json: -------------------------------------------------------------------------------- 1 | { 2 | "ambientocclusion": false, 3 | "textures": { 4 | "particle": "#pane" 5 | }, 6 | "elements": [ 7 | { "from": [ 7, 0, 0 ], 8 | "to": [ 9, 16, 7 ], 9 | "faces": { 10 | "down": { "uv": [ 7, 0, 9, 7 ], "texture": "#edge", "cullface": "down" }, 11 | "up": { "uv": [ 7, 0, 9, 7 ], "texture": "#edge", "cullface": "up" }, 12 | "north": { "uv": [ 7, 0, 9, 16 ], "texture": "#edge", "cullface": "north" }, 13 | "west": { "uv": [ 0, 0, 7, 16 ], "texture": "#pane" }, 14 | "east": { "uv": [ 9, 0, 16, 16 ], "texture": "#pane" } 15 | } 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/models/block/template_glass_pane_side_alt.json: -------------------------------------------------------------------------------- 1 | { 2 | "ambientocclusion": false, 3 | "textures": { 4 | "particle": "#pane" 5 | }, 6 | "elements": [ 7 | { "from": [ 7, 0, 9 ], 8 | "to": [ 9, 16, 16 ], 9 | "faces": { 10 | "down": { "uv": [ 7, 0, 9, 7 ], "texture": "#edge", "cullface": "down" }, 11 | "up": { "uv": [ 7, 0, 9, 7 ], "texture": "#edge", "cullface": "up" }, 12 | "south": { "uv": [ 7, 0, 9, 16 ], "texture": "#edge", "cullface": "south" }, 13 | "west": { "uv": [ 9, 0, 16, 16 ], "texture": "#pane" }, 14 | "east": { "uv": [ 0, 0, 7, 16 ], "texture": "#pane" } 15 | } 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/bookshelf/bookshelf.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=bookshelf 2 | connect=block 3 | faces=sides 4 | method=horizontal 5 | tiles=$CBT_SPECIAL_DYNAMIC_BOOKSHELF 6 | cbt_special_bookshelf_texture=minecraft:textures/block/bookshelf.png 7 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/black_stained_glass.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=black_stained_glass 2 | connect=block 3 | method=ctm_compact 4 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 5 | cbt_special_glass_background=66191919 6 | cbt_special_glass_texture=minecraft:textures/block/black_stained_glass.png 7 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/black_stained_glass_pane.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=black_stained_glass_pane 2 | faces=sides 3 | connect=block 4 | method=ctm_compact 5 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 6 | cbt_special_glass_background=66191919 7 | cbt_special_glass_texture=minecraft:textures/block/black_stained_glass.png 8 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/blue_stained_glass.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=blue_stained_glass 2 | connect=block 3 | method=ctm_compact 4 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 5 | cbt_special_glass_background=66334CB2 6 | cbt_special_glass_texture=minecraft:textures/block/blue_stained_glass.png 7 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/blue_stained_glass_pane.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=blue_stained_glass_pane 2 | faces=sides 3 | connect=block 4 | method=ctm_compact 5 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 6 | cbt_special_glass_background=66334CB2 7 | cbt_special_glass_texture=minecraft:textures/block/blue_stained_glass.png 8 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/brown_stained_glass.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=brown_stained_glass 2 | connect=block 3 | method=ctm_compact 4 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 5 | cbt_special_glass_background=66664C33 6 | cbt_special_glass_texture=minecraft:textures/block/brown_stained_glass.png 7 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/brown_stained_glass_pane.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=brown_stained_glass_pane 2 | faces=sides 3 | connect=block 4 | method=ctm_compact 5 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 6 | cbt_special_glass_background=66664C33 7 | cbt_special_glass_texture=minecraft:textures/block/brown_stained_glass.png 8 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/cyan_stained_glass.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=cyan_stained_glass 2 | connect=block 3 | method=ctm_compact 4 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 5 | cbt_special_glass_background=664C7F99 6 | cbt_special_glass_texture=minecraft:textures/block/cyan_stained_glass.png 7 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/cyan_stained_glass_pane.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=cyan_stained_glass_pane 2 | faces=sides 3 | connect=block 4 | method=ctm_compact 5 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 6 | cbt_special_glass_background=664C7F99 7 | cbt_special_glass_texture=minecraft:textures/block/cyan_stained_glass.png 8 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/glass.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=glass 2 | connect=block 3 | method=ctm_compact 4 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 5 | cbt_special_glass_background=00000000 6 | cbt_special_glass_texture=minecraft:textures/block/glass.png 7 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/glass_pane.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=glass_pane 2 | faces=sides 3 | connect=block 4 | method=ctm_compact 5 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 6 | cbt_special_glass_background=00000000 7 | cbt_special_glass_texture=minecraft:textures/block/glass.png 8 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/gray_stained_glass.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=gray_stained_glass 2 | connect=block 3 | method=ctm_compact 4 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 5 | cbt_special_glass_background=664C4C4C 6 | cbt_special_glass_texture=minecraft:textures/block/gray_stained_glass.png 7 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/gray_stained_glass_pane.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=gray_stained_glass_pane 2 | faces=sides 3 | connect=block 4 | method=ctm_compact 5 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 6 | cbt_special_glass_background=664C4C4C 7 | cbt_special_glass_texture=minecraft:textures/block/gray_stained_glass.png 8 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/green_stained_glass.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=green_stained_glass 2 | connect=block 3 | method=ctm_compact 4 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 5 | cbt_special_glass_background=66667F33 6 | cbt_special_glass_texture=minecraft:textures/block/green_stained_glass.png 7 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/green_stained_glass_pane.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=green_stained_glass_pane 2 | faces=sides 3 | connect=block 4 | method=ctm_compact 5 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 6 | cbt_special_glass_background=66667F33 7 | cbt_special_glass_texture=minecraft:textures/block/green_stained_glass.png 8 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/light_blue_stained_glass.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=light_blue_stained_glass 2 | connect=block 3 | method=ctm_compact 4 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 5 | cbt_special_glass_background=666699D8 6 | cbt_special_glass_texture=minecraft:textures/block/light_blue_stained_glass.png 7 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/light_blue_stained_glass_pane.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=light_blue_stained_glass_pane 2 | faces=sides 3 | connect=block 4 | method=ctm_compact 5 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 6 | cbt_special_glass_background=666699D8 7 | cbt_special_glass_texture=minecraft:textures/block/light_blue_stained_glass.png 8 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/light_gray_stained_glass.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=light_gray_stained_glass 2 | connect=block 3 | method=ctm_compact 4 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 5 | cbt_special_glass_background=66999999 6 | cbt_special_glass_texture=minecraft:textures/block/light_gray_stained_glass.png 7 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/light_gray_stained_glass_pane.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=light_gray_stained_glass_pane 2 | faces=sides 3 | connect=block 4 | method=ctm_compact 5 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 6 | cbt_special_glass_background=66999999 7 | cbt_special_glass_texture=minecraft:textures/block/light_gray_stained_glass.png 8 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/lime_stained_glass.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=lime_stained_glass 2 | connect=block 3 | method=ctm_compact 4 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 5 | cbt_special_glass_background=667FCC19 6 | cbt_special_glass_texture=minecraft:textures/block/lime_stained_glass.png 7 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/lime_stained_glass_pane.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=lime_stained_glass_pane 2 | faces=sides 3 | connect=block 4 | method=ctm_compact 5 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 6 | cbt_special_glass_background=667FCC19 7 | cbt_special_glass_texture=minecraft:textures/block/lime_stained_glass.png 8 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/magenta_stained_glass.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=magenta_stained_glass 2 | connect=block 3 | method=ctm_compact 4 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 5 | cbt_special_glass_background=66B24CD8 6 | cbt_special_glass_texture=minecraft:textures/block/magenta_stained_glass.png 7 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/magenta_stained_glass_pane.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=magenta_stained_glass_pane 2 | faces=sides 3 | connect=block 4 | method=ctm_compact 5 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 6 | cbt_special_glass_background=66B24CD8 7 | cbt_special_glass_texture=minecraft:textures/block/magenta_stained_glass.png 8 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/orange_stained_glass.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=orange_stained_glass 2 | connect=block 3 | method=ctm_compact 4 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 5 | cbt_special_glass_background=66D87F33 6 | cbt_special_glass_texture=minecraft:textures/block/orange_stained_glass.png 7 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/orange_stained_glass_pane.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=orange_stained_glass_pane 2 | faces=sides 3 | connect=block 4 | method=ctm_compact 5 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 6 | cbt_special_glass_background=66D87F33 7 | cbt_special_glass_texture=minecraft:textures/block/orange_stained_glass.png 8 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/pink_stained_glass.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=pink_stained_glass 2 | connect=block 3 | method=ctm_compact 4 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 5 | cbt_special_glass_background=66F27FA5 6 | cbt_special_glass_texture=minecraft:textures/block/pink_stained_glass.png 7 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/pink_stained_glass_pane.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=pink_stained_glass_pane 2 | faces=sides 3 | connect=block 4 | method=ctm_compact 5 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 6 | cbt_special_glass_background=66F27FA5 7 | cbt_special_glass_texture=minecraft:textures/block/pink_stained_glass.png 8 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/purple_stained_glass.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=purple_stained_glass 2 | connect=block 3 | method=ctm_compact 4 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 5 | cbt_special_glass_background=667F3FB2 6 | cbt_special_glass_texture=minecraft:textures/block/purple_stained_glass.png 7 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/purple_stained_glass_pane.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=purple_stained_glass_pane 2 | faces=sides 3 | connect=block 4 | method=ctm_compact 5 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 6 | cbt_special_glass_background=667F3FB2 7 | cbt_special_glass_texture=minecraft:textures/block/purple_stained_glass.png 8 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/red_stained_glass.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=red_stained_glass 2 | connect=block 3 | method=ctm_compact 4 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 5 | cbt_special_glass_background=80993333 6 | cbt_special_glass_texture=minecraft:textures/block/red_stained_glass.png 7 | cbt_special_change_pack_if_loaded=Default -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/red_stained_glass_pane.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=red_stained_glass_pane 2 | faces=sides 3 | connect=block 4 | method=ctm_compact 5 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 6 | cbt_special_glass_background=80993333 7 | cbt_special_glass_texture=minecraft:textures/block/red_stained_glass.png 8 | cbt_special_change_pack_if_loaded=Default -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/tinted_glass.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=tinted_glass 2 | connect=block 3 | method=ctm_compact 4 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 5 | cbt_special_glass_background=6E272527 6 | cbt_special_glass_texture=minecraft:textures/block/tinted_glass.png 7 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/white_stained_glass.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=white_stained_glass 2 | connect=block 3 | method=ctm_compact 4 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 5 | cbt_special_glass_background=66FFFFFF 6 | cbt_special_glass_texture=minecraft:textures/block/white_stained_glass.png 7 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/white_stained_glass_pane.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=white_stained_glass_pane 2 | faces=sides 3 | connect=block 4 | method=ctm_compact 5 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 6 | cbt_special_glass_background=66FFFFFF 7 | cbt_special_glass_texture=minecraft:textures/block/white_stained_glass.png 8 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/yellow_stained_glass.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=yellow_stained_glass 2 | connect=block 3 | method=ctm_compact 4 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 5 | cbt_special_glass_background=66E5E533 6 | cbt_special_glass_texture=minecraft:textures/block/yellow_stained_glass.png 7 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/glass/yellow_stained_glass_pane.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=yellow_stained_glass_pane 2 | faces=sides 3 | connect=block 4 | method=ctm_compact 5 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 6 | cbt_special_glass_background=66E5E533 7 | cbt_special_glass_texture=minecraft:textures/block/yellow_stained_glass.png 8 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/sandstone/red_sandstone.properties: -------------------------------------------------------------------------------- 1 | matchTiles=red_sandstone 2 | connect=tile 3 | method=top 4 | faces=sides 5 | tiles=$CBT_SPECIAL_DYNAMIC_SANDSTONE 6 | cbt_special_sandstone_texture=minecraft:textures/block/red_sandstone.png 7 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/optifine/ctm/sandstone/sandstone.properties: -------------------------------------------------------------------------------- 1 | matchTiles=sandstone 2 | connect=tile 3 | method=top 4 | faces=sides 5 | tiles=$CBT_SPECIAL_DYNAMIC_SANDSTONE 6 | cbt_special_sandstone_texture=minecraft:textures/block/sandstone.png 7 | cbt_special_change_pack_if_loaded=Programmer Art -------------------------------------------------------------------------------- /src/main/resources/connected_block_textures.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "package": "io.github.nuclearfarts.cbt.mixin", 4 | "compatibilityLevel": "JAVA_8", 5 | "client": [ 6 | "ModelLoaderMixin", 7 | "ReloadableResourceManagerImplMixin", 8 | "ClientWorldMixin", 9 | "IdentifierMixin", 10 | "NativeImageAccessor" 11 | ], 12 | "injectors": { 13 | "defaultRequire": 1 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "connected_block_textures", 4 | "version": "${version}", 5 | 6 | "name": "Connected Block Textures", 7 | "description": "Support for MCPatcher/Optifine-format connected textures.", 8 | "authors": [ 9 | "NuclearFarts" 10 | ], 11 | "contact": { 12 | "sources": "https://github.com/Nuclearfarts/connected-block-textures" 13 | }, 14 | 15 | "license": "LGPLv3", 16 | "icon": "assets/connected_block_textures/icon.png", 17 | "environment": "client", 18 | "entrypoints": { 19 | "main": [ 20 | "io.github.nuclearfarts.cbt.ConnectedBlockTextures" 21 | ] 22 | }, 23 | "mixins": [ 24 | "connected_block_textures.mixins.json" 25 | ], 26 | 27 | "depends": { 28 | "fabricloader": ">=0.4.0", 29 | "fabric": "*" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/resources/programmer_art/assets/minecraft/optifine/ctm/glass/red_stained_glass_pane_programmer.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=red_stained_glass_pane 2 | faces=sides 3 | connect=block 4 | method=ctm_compact 5 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 6 | cbt_special_glass_background=66993333 7 | cbt_special_glass_texture=minecraft:textures/block/red_stained_glass.png -------------------------------------------------------------------------------- /src/main/resources/programmer_art/assets/minecraft/optifine/ctm/glass/red_stained_glass_programmer.properties: -------------------------------------------------------------------------------- 1 | matchBlocks=red_stained_glass 2 | connect=block 3 | method=ctm_compact 4 | tiles=$CBT_SPECIAL_DYNAMIC_GLASS 5 | cbt_special_glass_background=66993333 6 | cbt_special_glass_texture=minecraft:textures/block/red_stained_glass.png --------------------------------------------------------------------------------