├── .gitignore ├── LICENSE ├── build.gradle ├── common.gradle ├── fabricWrapper ├── build.gradle └── src │ └── main │ └── resources │ └── fabric.mod.json ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── icon.png ├── settings.gradle ├── src └── main │ ├── java │ └── com │ │ └── zxy │ │ └── wuhuclient │ │ ├── MyThreadManager.java │ │ ├── Utils │ │ ├── BlockFilters.java │ │ ├── HighlightBlockRenderer.java │ │ ├── InventoryUtils.java │ │ ├── MyBox.java │ │ ├── PinYinSearch.java │ │ ├── ScreenManagement.java │ │ ├── SwitchItem.java │ │ └── ZxyUtils.java │ │ ├── WuHuClientMod.java │ │ ├── config │ │ ├── ConfigUi.java │ │ ├── Configs.java │ │ ├── HotkeysCallback.java │ │ ├── InputHandler.java │ │ └── ModMenu.java │ │ ├── features_list │ │ ├── AutoMending.java │ │ ├── CloseTheContainerAfterOpening.java │ │ ├── EasyPlaceFix.java │ │ ├── QuickClickSlot.java │ │ ├── QuickFirework.java │ │ ├── SyncInventory.java │ │ ├── Synthesis.java │ │ ├── Test.java │ │ └── litematica_helper │ │ │ ├── Condition.java │ │ │ ├── LitematicaHelper.java │ │ │ └── Restriction.java │ │ └── mixin │ │ ├── BlockMixin.java │ │ ├── ClientPlayNetworkHandlerMixin.java │ │ ├── ClientPlayerEMixin.java │ │ ├── ClientPlayerInteractionManagerMixin.java │ │ ├── CraftingScreenHandlerMixin.java │ │ ├── MinecraftClientMixin.java │ │ ├── MixinExperienceOrbEntity.java │ │ ├── SuffixArrayMixin.java │ │ ├── jackf │ │ └── fix │ │ │ └── InteractionTrackerImplMixin.java │ │ ├── masa │ │ ├── Litematica_InventoryUtilsMixin.java │ │ ├── MixinInventoryUtils.java │ │ ├── WorldUtilsAccessor.java │ │ ├── litematica_easy_place_fix │ │ │ ├── ClientPlayerInteractionManagerMixin_EasyPlaceFix.java │ │ │ └── WorldUtilsMixin.java │ │ ├── litematicahelper │ │ │ ├── MaterialListHudRendererAccessor.java │ │ │ ├── ScreenHandlerMixin.java │ │ │ ├── SelectionManagerMixin.java │ │ │ ├── TaskCountBlocksAreaMixin.java │ │ │ └── TaskCountBlocksPlacementMixin.java │ │ └── pinyin │ │ │ ├── WidgetListBaseMixin.java │ │ │ └── WidgetListConfigOptionsMixin.java │ │ └── pointless │ │ └── Pointless.java │ └── resources │ ├── assets │ └── wuhuclient │ │ └── lang │ │ ├── en_us.json │ │ └── zh_cn.json │ ├── fabric.mod.json │ └── wuhuclient.mixins.json └── versions ├── 1.18.2 └── gradle.properties ├── 1.19.4 ├── gradle.properties └── src │ └── main │ └── java │ └── com │ └── zxy │ └── wuhuclient │ └── mixin │ └── jackf │ └── fix │ └── InteractionTrackerImplMixin.java ├── 1.20.1 └── gradle.properties ├── 1.20.2 └── gradle.properties ├── 1.20.4 └── gradle.properties ├── 1.20.6 └── gradle.properties ├── 1.21.1 └── gradle.properties ├── 1.21.4 └── gradle.properties ├── 1.21.5 └── gradle.properties ├── 1.21.6 └── gradle.properties ├── mainProject ├── mapping-1.18.2-1.19.4.txt ├── mapping-1.19.4-1.20.1.txt ├── mapping-1.20.1-1.20.2.txt ├── mapping-1.20.2-1.20.4.txt ├── mapping-1.20.4-1.20.6.txt ├── mapping-1.20.6-1.21.0.txt ├── mapping-1.21.0-1.21.4.txt ├── mapping-1.21.4-1.21.5.txt └── mapping-1.21.5-1.21.6.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # gradle 2 | 3 | .gradle/ 4 | build/ 5 | out/ 6 | classes/ 7 | 8 | # eclipse 9 | 10 | *.launch 11 | 12 | # idea 13 | 14 | .idea/ 15 | *.iml 16 | *.ipr 17 | *.iws 18 | 19 | # vscode 20 | 21 | .settings/ 22 | .vscode/ 23 | bin/ 24 | .classpath 25 | .project 26 | 27 | # macos 28 | 29 | *.DS_Store 30 | 31 | # fabric 32 | 33 | run/ 34 | 35 | # java 36 | 37 | hs_err_*.log 38 | replay_*.log 39 | *.hprof 40 | *.jfr 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("maven-publish") 3 | id("fabric-loom").version("1.10-SNAPSHOT").apply(false) 4 | id("org.ajoberstar.grgit").version("5.2.0") 5 | id("com.replaymod.preprocess").version("9d21b334a7") 6 | 7 | } 8 | 9 | preprocess { 10 | // def mc11404 = createNode("1.14.4", 1_14_04, "mojang") 11 | // def mc11502 = createNode("1.15.2", 1_15_02, "mojang") 12 | // def mc11605 = createNode("1.16.5", 1_16_05, "mojang") 13 | // def mc11701 = createNode("1.17.1", 1_17_01, "mojang") 14 | def mc11802 = createNode("1.18.2", 1_18_02, "mojang") 15 | // def mc11902 = createNode("1.19.2", 1_19_02, "mojang") 16 | // def mc11903 = createNode("1.19.3", 1_19_03, "mojang") 17 | def mc11904 = createNode("1.19.4", 1_19_04, "mojang") 18 | def mc12001 = createNode("1.20.1", 1_20_01, "mojang") 19 | def mc12002 = createNode("1.20.2", 1_20_02, "mojang") 20 | def mc12004 = createNode("1.20.4", 1_20_04, "mojang") 21 | def mc12006 = createNode("1.20.6", 1_20_06, "mojang") 22 | def mc12101 = createNode("1.21.1", 1_21_01, "mojang") 23 | def mc12104 = createNode("1.21.4", 1_21_04, "mojang") 24 | def mc12105 = createNode("1.21.5", 1_21_05, "mojang") 25 | def mc12106 = createNode("1.21.6", 1_21_06, "mojang") 26 | 27 | // mc11404.link(mc11502, null) 28 | // mc11502.link(mc11605, null) 29 | // mc11605.link(mc11701, null) 30 | // mc11701.link(mc11802, null) 31 | mc11802.link(mc11904,file("versions/mapping-1.18.2-1.19.4.txt")) 32 | // mc11902.link(mc11903, null) 33 | // mc11903.link(mc11904, null) 34 | mc11904.link(mc12001, file("versions/mapping-1.19.4-1.20.1.txt")) 35 | mc12001.link(mc12002, file("versions/mapping-1.20.1-1.20.2.txt")) 36 | mc12002.link(mc12004, file("versions/mapping-1.20.2-1.20.4.txt")) 37 | mc12004.link(mc12006, file("versions/mapping-1.20.4-1.20.6.txt")) 38 | mc12006.link(mc12101, file("versions/mapping-1.20.6-1.21.0.txt")) 39 | mc12001.link(mc12104, file("versions/mapping-1.21.0-1.21.4.txt")) 40 | mc12004.link(mc12105, file("versions/mapping-1.21.4-1.21.5.txt")) 41 | mc12105.link(mc12106, file("versions/mapping-1.21.5-1.21.6.txt")) 42 | } 43 | 44 | ext { 45 | env = System.getenv() 46 | 47 | getVersionGit = { List paths -> 48 | if (grgit == null) { 49 | return "nogit" 50 | } 51 | 52 | List latestCommits = paths.isEmpty() ? grgit.log(maxCommits: 1) : grgit.log(paths: paths, maxCommits: 1) 53 | return latestCommits.isEmpty() ? "uncommited" : "${latestCommits.get(0).id.substring(0, 7)}" 54 | } 55 | 56 | getBuildNumber = { 57 | return ext.env.GITHUB_RUN_NUMBER ? ext.env.GITHUB_RUN_NUMBER : Integer.MAX_VALUE 58 | } 59 | 60 | getVersionType = { 61 | switch (ext.env.BUILD_TYPE) { 62 | case "RELEASE": 63 | return "stable" 64 | case "BETA": 65 | return "beta" 66 | default: 67 | return "dev" 68 | } 69 | } 70 | 71 | getVersionPatch = { List paths -> 72 | if (grgit == null) { 73 | return 0 74 | } 75 | 76 | List latestCommits = paths.isEmpty() ? grgit.log() : grgit.log(paths: paths) 77 | return latestCommits.size() 78 | } 79 | 80 | getMavenArtifactVersion = { 81 | return ext.getVersionType() == "stable" ? "${project.mod_version}.${ext.getVersionPatch([])}" : project.version 82 | } 83 | 84 | getModVersion = { 85 | return "${project.mod_version}.${getVersionPatch([])}+${getVersionGit([])}-${getVersionType()}" 86 | } 87 | } 88 | 89 | setVersion(project.getModVersion()) 90 | 91 | tasks.register("cleanPreprocessSources") { 92 | it.group("${project.mod_id}") 93 | 94 | doFirst { 95 | subprojects { 96 | def path = project.projectDir.toPath().resolve("build/preprocessed") 97 | path.toFile().deleteDir() 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /fabricWrapper/build.gradle: -------------------------------------------------------------------------------- 1 | import groovy.json.JsonBuilder 2 | import groovy.json.JsonSlurper 3 | 4 | plugins { 5 | id("java-library") 6 | id("maven-publish") 7 | } 8 | def time = new Date().format("yyyyMMdd", TimeZone.getTimeZone("GMT+08:00")) 9 | 10 | group(project.mod_maven_group) 11 | version(project.mod_version+"+"+time) 12 | 13 | base { 14 | archivesName.set("${project.mod_archives_base_name}-all") 15 | } 16 | 17 | def fabric_subprojects = project.parent.subprojects.findAll({ 18 | it.name != "fabricWrapper" 19 | }) 20 | 21 | fabric_subprojects.collect { 22 | evaluationDependsOn(":${it.name}") 23 | } 24 | 25 | jar { 26 | // disable cache 27 | outputs.upToDateWhen { false } 28 | 29 | dependsOn(fabric_subprojects.collect { 30 | it.tasks.remapJar 31 | }) 32 | 33 | doFirst { 34 | delete fileTree("build/tmp/submods/META-INF/jars") 35 | 36 | copy { 37 | from { 38 | fabric_subprojects.collect { 39 | it.remapJar.outputs.files 40 | } 41 | } 42 | 43 | into("build/tmp/submods/META-INF/jars") 44 | } 45 | } 46 | 47 | from("${rootDir}/LICENSE") 48 | from("build/tmp/submods") 49 | } 50 | 51 | processResources { 52 | // disable cache 53 | outputs.upToDateWhen { false } 54 | 55 | from("${rootDir}/icon.png") { 56 | into("assets/${project.mod_id}") 57 | } 58 | 59 | filesMatching("fabric.mod.json") { 60 | expand([ 61 | "mod_description" : project.mod_description, 62 | "mod_homepage" : project.mod_homepage, 63 | "mod_id" : project.mod_id, 64 | "mod_license" : project.mod_license, 65 | "mod_name" : project.mod_name, 66 | "mod_version" : project.version, 67 | "mod_sources" : project.mod_sources 68 | ]) 69 | } 70 | 71 | doLast { 72 | ArrayList mc_condition = [] 73 | ArrayList jars = [] 74 | 75 | fabric_subprojects.each({ 76 | mc_condition.add("${it.minecraft_dependency}") 77 | jars.add(["file": "META-INF/jars/${project.mod_archives_base_name}-${it.minecraft_version}-${project.version}.jar"]) 78 | }) 79 | 80 | File file = file("build/resources/main/fabric.mod.json") 81 | JsonSlurper slurper = new JsonSlurper() 82 | JsonBuilder builder = new JsonBuilder(slurper.parse(file)) 83 | builder.content.depends.minecraft = mc_condition 84 | builder.content.jars = jars 85 | BufferedWriter writer = file.newWriter() 86 | writer.append(builder.toPrettyString()) 87 | writer.flush() 88 | writer.close() 89 | } 90 | } 91 | 92 | java { 93 | sourceCompatibility(JavaVersion.VERSION_1_8) 94 | targetCompatibility(JavaVersion.VERSION_1_8) 95 | } 96 | 97 | publishing { 98 | publications { 99 | register("mavenJava", MavenPublication) { 100 | artifactId("${project.mod_id}") 101 | version("${rootProject.getMavenArtifactVersion()}") 102 | from(components.java) 103 | } 104 | } 105 | 106 | repositories { 107 | mavenLocal() 108 | 109 | maven { 110 | url("$rootDir/publish") 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /fabricWrapper/src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "${mod_id}", 4 | "version": "${mod_version}", 5 | "name": "${mod_name}", 6 | "description": "${mod_description}", 7 | "authors": [ 8 | { 9 | "name": "zhaixianyu", 10 | "contact": { 11 | "homepage": "https://github.com/zhaixianyu" 12 | } 13 | } 14 | ], 15 | "contact": { 16 | "homepage": "${mod_homepage}", 17 | "issues": "${mod_sources}/issues", 18 | "sources": "${mod_sources}" 19 | }, 20 | "license": "${mod_license}", 21 | "environment": "*", 22 | "entrypoints": { 23 | }, 24 | "depends": { 25 | "malilib": "*" 26 | }, 27 | "custom": { 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.cache.cleanup=false 3 | org.gradle.jvmargs=-Xmx4G 4 | org.gradle.parallel=true 5 | #org.gradle.offline=true 6 | 7 | mod_archives_base_name=WuHuClient 8 | mod_description=Add something interesting <3 9 | mod_homepage=https://space.bilibili.com/31545812 10 | mod_id=wuhuclient 11 | mod_license=LGPLv3 12 | mod_maven_group=com.zxy.wuhu-client 13 | mod_name=WuHu Client 14 | mod_sources=https://github.com/zhaixianyu/wuhu-client 15 | mod_version=1.0.5 16 | 17 | loader_version=0.17.2 18 | #pinyin_verson = 2.5.0 19 | 20 | 21 | #org.gradle.dependency_verification=true 22 | #org.gradle.caching=true 23 | 24 | #minecraft_version=1.20.4 25 | #yarn_mappings=1.20.4+build.3 26 | #loader_version=0.15.3 27 | # 28 | ##Fabric api 29 | #fabric_version=0.92.0+1.20.4 30 | # 31 | ## Mod Properties 32 | #mod_version=1.0.3 33 | #maven_group=com.zxy 34 | #archives_base_name=wuhu-client 35 | # 36 | #malilib_version = 1.20.2:0.17.0 37 | # 38 | #item_scroller_fileid=4788435 39 | #item_scroller_projectid=242064 40 | #litematica_fileid=4789765 41 | #litematica_projectid=308892 42 | #quickshulker_fileid=4592296 43 | #quickshulker_projectid=362669 44 | #mod_menu=8.0.1 45 | #carpet=1.4.121 46 | #jei=16.0.0.28 47 | #carpet_tis_addition=mc1.18.2-v1.55.0 48 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaixianyu/wuhu-client/a8a021944e8c1f907c2cccaf819fb1ac3a44a5fb/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-8.8-bin.zip 4 | distributionUrl=https://mirrors.cloud.tencent.com/gradle/gradle-8.12-bin.zip 5 | networkTimeout=10000 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original 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 POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Use the maximum available, or set MAX_FD != -1 to use that value. 89 | MAX_FD=maximum 90 | 91 | warn () { 92 | echo "$*" 93 | } >&2 94 | 95 | die () { 96 | echo 97 | echo "$*" 98 | echo 99 | exit 1 100 | } >&2 101 | 102 | # OS specific support (must be 'true' or 'false'). 103 | cygwin=false 104 | msys=false 105 | darwin=false 106 | nonstop=false 107 | case "$( uname )" in #( 108 | CYGWIN* ) cygwin=true ;; #( 109 | Darwin* ) darwin=true ;; #( 110 | MSYS* | MINGW* ) msys=true ;; #( 111 | NONSTOP* ) nonstop=true ;; 112 | esac 113 | 114 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 115 | 116 | 117 | # Determine the Java command to use to start the JVM. 118 | if [ -n "$JAVA_HOME" ] ; then 119 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 120 | # IBM's JDK on AIX uses strange locations for the executables 121 | JAVACMD=$JAVA_HOME/jre/sh/java 122 | else 123 | JAVACMD=$JAVA_HOME/bin/java 124 | fi 125 | if [ ! -x "$JAVACMD" ] ; then 126 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 127 | 128 | Please set the JAVA_HOME variable in your environment to match the 129 | location of your Java installation." 130 | fi 131 | else 132 | JAVACMD=java 133 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 134 | 135 | Please set the JAVA_HOME variable in your environment to match the 136 | location of your Java installation." 137 | fi 138 | 139 | # Increase the maximum file descriptors if we can. 140 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 141 | case $MAX_FD in #( 142 | max*) 143 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 144 | # shellcheck disable=SC3045 145 | MAX_FD=$( ulimit -H -n ) || 146 | warn "Could not query maximum file descriptor limit" 147 | esac 148 | case $MAX_FD in #( 149 | '' | soft) :;; #( 150 | *) 151 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 152 | # shellcheck disable=SC3045 153 | ulimit -n "$MAX_FD" || 154 | warn "Could not set maximum file descriptor limit to $MAX_FD" 155 | esac 156 | fi 157 | 158 | # Collect all arguments for the java command, stacking in reverse order: 159 | # * args from the command line 160 | # * the main class name 161 | # * -classpath 162 | # * -D...appname settings 163 | # * --module-path (only if needed) 164 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 165 | 166 | # For Cygwin or MSYS, switch paths to Windows format before running java 167 | if "$cygwin" || "$msys" ; then 168 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 169 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 170 | 171 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 172 | 173 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 174 | for arg do 175 | if 176 | case $arg in #( 177 | -*) false ;; # don't mess with options #( 178 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 179 | [ -e "$t" ] ;; #( 180 | *) false ;; 181 | esac 182 | then 183 | arg=$( cygpath --path --ignore --mixed "$arg" ) 184 | fi 185 | # Roll the args list around exactly as many times as the number of 186 | # args, so each arg winds up back in the position where it started, but 187 | # possibly modified. 188 | # 189 | # NB: a `for` loop captures its iteration list before it begins, so 190 | # changing the positional parameters here affects neither the number of 191 | # iterations, nor the values presented in `arg`. 192 | shift # remove old arg 193 | set -- "$@" "$arg" # push replacement arg 194 | done 195 | fi 196 | 197 | 198 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 199 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 200 | 201 | # Collect all arguments for the java command; 202 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 203 | # shell script including quotes and variable substitutions, so put them in 204 | # double quotes to make sure that they get re-expanded; and 205 | # * put everything else in single quotes, so that it's not re-expanded. 206 | 207 | set -- \ 208 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 209 | -classpath "$CLASSPATH" \ 210 | org.gradle.wrapper.GradleWrapperMain \ 211 | "$@" 212 | 213 | # Stop when "xargs" is not available. 214 | if ! command -v xargs >/dev/null 2>&1 215 | then 216 | die "xargs is not available" 217 | fi 218 | 219 | # Use "xargs" to parse quoted args. 220 | # 221 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 222 | # 223 | # In Bash we could simply go: 224 | # 225 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 226 | # set -- "${ARGS[@]}" "$@" 227 | # 228 | # but POSIX shell has neither arrays nor command substitution, so instead we 229 | # post-process each arg (as a line of input to sed) to backslash-escape any 230 | # character that might be a shell metacharacter, then use eval to reverse 231 | # that process (while maintaining the separation between arguments), and wrap 232 | # the whole thing up as a single "set" statement. 233 | # 234 | # This will of course break if any of these variables contains a newline or 235 | # an unmatched quote. 236 | # 237 | 238 | eval "set -- $( 239 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 240 | xargs -n1 | 241 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 242 | tr '\n' ' ' 243 | )" '"$@"' 244 | 245 | exec "$JAVACMD" "$@" 246 | -------------------------------------------------------------------------------- /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 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaixianyu/wuhu-client/a8a021944e8c1f907c2cccaf819fb1ac3a44a5fb/icon.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | mavenLocal() 4 | mavenCentral() 5 | gradlePluginPortal() 6 | 7 | maven { 8 | name("Fabric") 9 | url("https://maven.fabricmc.net") 10 | } 11 | 12 | maven { 13 | name("Jitpack") 14 | url("https://jitpack.io") 15 | } 16 | 17 | maven { 18 | name("Nyan Maven") 19 | url("https://maven.hendrixshen.top") 20 | } 21 | 22 | maven { 23 | name("Cotton") 24 | url("https://server.bbkr.space/artifactory/libs-release") 25 | } 26 | 27 | resolutionStrategy { 28 | eachPlugin { 29 | switch (requested.id.id) { 30 | case "com.replaymod.preprocess": { 31 | useModule("com.github.Fallen-Breath:preprocessor:${requested.version}") 32 | break 33 | } 34 | } 35 | } 36 | } 37 | } 38 | } 39 | 40 | def versions = Arrays.asList( 41 | // "1.14.4", 42 | // "1.15.2", 43 | // "1.16.5", 44 | // "1.17.1", 45 | "1.18.2", 46 | // "1.19.2", 47 | // "1.19.3", 48 | "1.19.4", 49 | "1.20.1", 50 | "1.20.2", 51 | "1.20.4", 52 | "1.20.6", 53 | "1.21.1", 54 | "1.21.4", 55 | "1.21.5", 56 | "1.21.6", 57 | ) 58 | 59 | 60 | for (String version : versions) { 61 | include(":$version") 62 | def proj = project(":$version") 63 | proj.projectDir = file("versions/$version") 64 | proj.buildFileName = "../../common.gradle" 65 | } 66 | 67 | include(":fabricWrapper") 68 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/MyThreadManager.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class MyThreadManager { 6 | public static final ArrayList myThread = new ArrayList<>(); 7 | 8 | public static void createThread(String threadName,Thread thread1){ 9 | if (myThread.stream().noneMatch(thread2 -> threadName.equals(thread2.getName()))) { 10 | myThread.add(thread1); 11 | thread1.setName(threadName); 12 | thread1.start(); 13 | } 14 | } 15 | public static void stopThread(String threadName){ 16 | for (Thread thread : myThread) { 17 | if (threadName.equals(thread.getName())) { 18 | thread.interrupt(); 19 | } 20 | } 21 | } 22 | public static void stopThreadAll(){ 23 | myThread.forEach(Thread::interrupt); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/Utils/BlockFilters.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.Utils; 2 | 3 | import net.minecraft.block.BlockState; 4 | import net.minecraft.registry.Registries; 5 | import net.minecraft.util.math.BlockPos; 6 | 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.concurrent.atomic.AtomicBoolean; 10 | import java.util.stream.Stream; 11 | 12 | public class BlockFilters { 13 | 14 | //包含/比较 15 | public static boolean filters(String str1,String str2,String[] argument){ 16 | ArrayList strArr = new ArrayList<>(Arrays.asList(argument)); 17 | AtomicBoolean b = new AtomicBoolean(false); 18 | strArr.forEach(str -> { 19 | switch (str){ 20 | case "c" -> { 21 | b.set(str1.contains(str2)); 22 | } 23 | } 24 | }); 25 | return b.get() || str1.equals(str2); 26 | } 27 | 28 | // public static boolean equalsBlockName(String blockName, BlockState blockState, BlockPos pos){ 29 | // return equalsBlockName(blockName,blockState); 30 | // } 31 | 32 | public static boolean equalsBlockName(String blockName, BlockState blockState,BlockPos pos){ 33 | String string = Registries.BLOCK.getId(blockState.getBlock()).toString(); 34 | String[] strs = blockName.split(","); 35 | String blockName1 = strs[0]; 36 | if(strs.length > 1){ 37 | strs = Arrays.copyOfRange(strs,1,strs.length); 38 | }else strs = new String[]{}; 39 | 40 | if (Arrays.stream(strs).toList().contains("inv")) { 41 | return InventoryUtils.isInventory(pos); 42 | } 43 | 44 | //标签 45 | if (blockName1.length() > 1 && blockName1.charAt(0) == '#') { 46 | AtomicBoolean theLabelIsTheSame = new AtomicBoolean(false); 47 | String fix1 = blockName1.split("#")[1]; 48 | String[] finalStrs = strs; 49 | blockState.streamTags().forEach(tag -> { 50 | String tagName = tag.id().toString(); 51 | if (BlockFilters.filters(tagName,fix1, finalStrs)) { 52 | theLabelIsTheSame.set(true); 53 | } 54 | }); 55 | return theLabelIsTheSame.get(); 56 | } 57 | 58 | //中文 、 拼音 59 | String block = blockState.getBlock().getName().getString(); 60 | ArrayList pinYin = PinYinSearch.getPinYin(block); 61 | String[] finalStrs1 = strs; 62 | boolean py = pinYin.stream().anyMatch(p -> BlockFilters.filters(p,blockName1, finalStrs1)); 63 | return BlockFilters.filters(block,blockName1,strs) || py || BlockFilters.filters(string,blockName1,strs); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/Utils/HighlightBlockRenderer.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.Utils; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | import com.zxy.wuhuclient.MyThreadManager; 5 | import com.zxy.wuhuclient.features_list.litematica_helper.LitematicaHelper; 6 | import fi.dy.masa.litematica.Litematica; 7 | import fi.dy.masa.litematica.data.DataManager; 8 | import fi.dy.masa.malilib.config.options.ConfigColor; 9 | import fi.dy.masa.malilib.event.RenderEventHandler; 10 | import fi.dy.masa.malilib.interfaces.IRenderer; 11 | import fi.dy.masa.malilib.render.RenderUtils; 12 | import fi.dy.masa.malilib.util.data.Color4f; 13 | import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; 14 | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; 15 | import net.minecraft.block.BlockState; 16 | import net.minecraft.block.ShapeContext; 17 | import net.minecraft.client.MinecraftClient; 18 | import net.minecraft.client.gl.ShaderProgram; 19 | import net.minecraft.client.util.math.MatrixStack; 20 | import net.minecraft.client.render.*; 21 | import net.minecraft.client.util.math.MatrixStack; 22 | import net.minecraft.entity.Entity; 23 | import net.minecraft.util.math.BlockPos; 24 | import net.minecraft.util.math.Vec3d; 25 | import net.minecraft.util.shape.VoxelShape; 26 | import net.minecraft.util.shape.VoxelShapes; 27 | import org.joml.Matrix4f; 28 | //#if MC > 11802 29 | import org.joml.Matrix4fStack; 30 | //#endif 31 | 32 | //#if MC > 12104 33 | //#if MC < 12106 34 | //$$ import com.mojang.blaze3d.buffers.BufferUsage; 35 | //#endif 36 | import com.mojang.blaze3d.vertex.VertexFormat; 37 | import fi.dy.masa.malilib.render.MaLiLibPipelines; 38 | import fi.dy.masa.malilib.render.RenderContext; 39 | //#endif 40 | 41 | import org.lwjgl.opengl.GL11; 42 | 43 | import java.lang.reflect.Method; 44 | import java.util.*; 45 | import java.util.concurrent.ConcurrentHashMap; 46 | import java.util.concurrent.CopyOnWriteArrayList; 47 | import java.util.concurrent.CopyOnWriteArraySet; 48 | 49 | import static com.zxy.wuhuclient.Utils.ZxyUtils.searchBlockId; 50 | import static com.zxy.wuhuclient.Utils.ZxyUtils.searchBlockThread; 51 | import static com.zxy.wuhuclient.WuHuClientMod.client; 52 | import static com.zxy.wuhuclient.config.Configs.LITEMATICA_HELPER; 53 | import static com.zxy.wuhuclient.config.Configs.SEARCH_BLOCK_LIMIT; 54 | import static fi.dy.masa.malilib.render.RenderUtils.*; 55 | import static net.minecraft.client.render.VertexFormats.POSITION_COLOR; 56 | 57 | public class HighlightBlockRenderer implements IRenderer { 58 | public static HighlightBlockRenderer instance = new HighlightBlockRenderer(); 59 | public record HighlightTheProject(ConfigColor color4f, Set pos){} 60 | public static Map highlightTheProjectMap = new ConcurrentHashMap<>(); 61 | public static String threadName = "wuhuRenderThread"; 62 | public static boolean shaderIng = false; 63 | public static void createHighlightBlockList(String id,ConfigColor color4f){ 64 | if (highlightTheProjectMap.get(id) == null) { 65 | highlightTheProjectMap.put(id,new HighlightTheProject(color4f,new LinkedHashSet <>())); 66 | } 67 | } 68 | public static Set getHighlightBlockPosList(String id){ 69 | if(highlightTheProjectMap.get(id) != null){ 70 | return highlightTheProjectMap.get(id).pos(); 71 | } 72 | return null; 73 | } 74 | public static List clearList = new CopyOnWriteArrayList<>(); 75 | public static void clear(String id){ 76 | if (!clearList.contains(id)) clearList.add(id); 77 | } 78 | public static Map> setMap = new HashMap<>(); 79 | // public static Map> setMap = new HashMap<>(); 80 | public static void setPos(String id,Set posSet){ 81 | HighlightTheProject highlightTheProject = highlightTheProjectMap.get(id); 82 | if (highlightTheProject != null && posSet != null) { 83 | setMap.put(id,posSet); 84 | } 85 | } 86 | public static Method method; 87 | 88 | 89 | 90 | //#if MC > 12004 91 | public void highlightBlock(Matrix4f matrices, Color4f color4f, Set posSet){ 92 | //#else 93 | //$$ public void highlightBlock(MatrixStack matrices ,Color4f color4f, Set posSet){ 94 | //#endif 95 | 96 | // for (BlockPos pos : posSet) { 97 | // renderAreaSides(pos,pos,color4f,matrices,client); 98 | // } 99 | //#if MC <= 12104 100 | //$$ RenderSystem.disableDepthTest(); 101 | //#endif 102 | 103 | //#if MC > 12104 104 | //#if MC > 12105 105 | RenderSystem.setShaderFog(RenderSystem.getShaderFog()); 106 | //#else 107 | //$$ RenderSystem.setShaderFog(Fog.DUMMY); 108 | //#endif 109 | //#else 110 | //$$ RenderSystem.enableBlend(); 111 | //$$ RenderSystem.disableCull(); 112 | //#endif 113 | 114 | 115 | //#if MC >= 12101 116 | //#else 117 | //$$ RenderSystem.setShader(GameRenderer::getPositionColorProgram); 118 | //#endif 119 | 120 | Tessellator tessellator = Tessellator.getInstance(); 121 | 122 | //#if MC > 12006 123 | //#if MC > 12104 124 | //#if MC == 12105 125 | //$$ RenderContext ctx = new RenderContext(MaLiLibPipelines.POSITION_COLOR_TRANSLUCENT_DEPTH_MASK, BufferUsage.STATIC_WRITE); 126 | //#else 127 | RenderContext ctx = new RenderContext(() -> threadName ,MaLiLibPipelines.POSITION_COLOR_TRANSLUCENT_DEPTH_MASK); 128 | //#endif 129 | BufferBuilder buffer = ctx.getBuilder(); 130 | //#else 131 | //$$ BufferBuilder buffer = tessellator.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR); 132 | //#endif 133 | BuiltBuffer meshData; 134 | //#else 135 | //$$ BufferBuilder buffer = tessellator.getBuffer(); 136 | //$$ buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR); 137 | //#endif 138 | for (BlockPos pos : posSet) { 139 | //#if MC >= 12105 140 | RenderUtils.renderAreaSidesBatched(pos, pos, color4f, 0.002, buffer); 141 | //#else 142 | //$$ fi.dy.masa.litematica.render.RenderUtils.renderAreaSidesBatched(pos, pos, color4f, 0.002, buffer, client); 143 | //#endif 144 | } 145 | 146 | try 147 | { 148 | if(buffer != null){ 149 | //#if MC > 12006 150 | meshData = buffer.end(); 151 | //#if MC > 12104 152 | ctx.upload(meshData, true); 153 | ctx.startResorting(meshData, ctx.createVertexSorter(fi.dy.masa.malilib.render.RenderUtils.camPos())); 154 | meshData.close(); 155 | ctx.drawPost(); 156 | //#else 157 | //$$ BufferRenderer.drawWithGlobalProgram(meshData); 158 | //$$ meshData.close(); 159 | //#endif 160 | //#else 161 | //$$ tessellator.draw(); 162 | //#endif 163 | } 164 | } 165 | catch (Exception e) 166 | { 167 | // Litematica.logger.error("renderAreaSides: Failed to draw Area Selection box (Error: {})", e.getLocalizedMessage()); 168 | } 169 | 170 | //#if MC > 12104 171 | RenderSystem.setShaderFog(RenderSystem.getShaderFog()); 172 | //#else 173 | //$$ RenderSystem.enableCull(); 174 | //$$ RenderSystem.disableBlend(); 175 | //#endif 176 | 177 | //#if MC <= 12104 178 | //$$ RenderSystem.enableDepthTest(); 179 | //#endif 180 | 181 | // fi.dy.masa.litematica.render.RenderUtils.renderAreaSides(pos, pos, color4f, matrices, client); 182 | } 183 | 184 | public static void init(){ 185 | //如果不注册无法渲染, 186 | RenderEventHandler.getInstance().registerWorldLastRenderer(instance); 187 | MyThreadManager.createThread(threadName,new Thread(() -> { 188 | while (!Thread.currentThread().isInterrupted()){ 189 | try { 190 | Thread.sleep(80); 191 | } catch (InterruptedException ignored) { 192 | Thread.currentThread().interrupt(); 193 | } 194 | //投影材料助手、搜索方块渲染 195 | searchBlockThread(); 196 | 197 | } 198 | })); 199 | 200 | ClientPlayConnectionEvents.DISCONNECT.register((handler, client1) -> { 201 | for (Map.Entry stringHighlightTheProjectEntry : highlightTheProjectMap.entrySet()) { 202 | stringHighlightTheProjectEntry.getValue().pos.clear(); 203 | } 204 | }); 205 | } 206 | 207 | @Override 208 | //#if MC > 12004 209 | public void onRenderWorldLast(Matrix4f matrices, Matrix4f projMatrix){ 210 | //#else 211 | //$$ public void onRenderWorldLast(MatrixStack matrices, Matrix4f projMatrix){ 212 | //#endif 213 | //更改渲染 214 | setMap.forEach((k,v) -> { 215 | HighlightTheProject highlightTheProject = highlightTheProjectMap.get(k); 216 | if(highlightTheProject != null){ 217 | highlightTheProject.pos.clear(); 218 | highlightTheProject.pos.addAll(v); 219 | } 220 | }); 221 | setMap.clear(); 222 | 223 | for (String string : clearList) { 224 | HighlightTheProject highlightTheProject = highlightTheProjectMap.get(string); 225 | if (highlightTheProject != null) { 226 | highlightTheProject.pos.clear(); 227 | } 228 | } 229 | clearList.clear(); 230 | 231 | shaderIng = true; 232 | highlightTheProjectMap.forEach((key, value) -> { 233 | if (!LITEMATICA_HELPER.getBooleanValue() && LitematicaHelper.instance.litematicaHelper.equals(key)) return; 234 | Color4f color = value.color4f.getColor(); 235 | highlightBlock(matrices, color, value.pos); 236 | 237 | }); 238 | shaderIng = false; 239 | } 240 | } -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/Utils/InventoryUtils.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.Utils; 2 | 3 | import com.zxy.wuhuclient.mixin.masa.Litematica_InventoryUtilsMixin; 4 | import fi.dy.masa.litematica.config.Configs; 5 | import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; 6 | import net.minecraft.block.BlockState; 7 | import net.minecraft.block.entity.BlockEntity; 8 | import net.minecraft.block.entity.ShulkerBoxBlockEntity; 9 | import net.minecraft.client.MinecraftClient; 10 | import net.minecraft.client.network.ClientPlayNetworkHandler; 11 | import net.minecraft.client.network.ClientPlayerEntity; 12 | 13 | import net.minecraft.enchantment.Enchantment; 14 | import net.minecraft.entity.mob.ShulkerEntity; 15 | import net.minecraft.entity.player.PlayerInventory; 16 | import net.minecraft.inventory.Inventory; 17 | import net.minecraft.item.Item; 18 | import net.minecraft.item.ItemStack; 19 | import net.minecraft.item.Items; 20 | import net.minecraft.nbt.NbtCompound; 21 | import net.minecraft.network.packet.c2s.play.ClickSlotC2SPacket; 22 | import net.minecraft.registry.Registries; 23 | import net.minecraft.registry.RegistryKey; 24 | import net.minecraft.registry.entry.RegistryEntry; 25 | import net.minecraft.screen.ScreenHandler; 26 | import net.minecraft.screen.slot.Slot; 27 | import net.minecraft.screen.slot.SlotActionType; 28 | import net.minecraft.text.Text; 29 | import net.minecraft.util.collection.DefaultedList; 30 | import net.minecraft.util.math.BlockPos; 31 | import org.jetbrains.annotations.NotNull; 32 | 33 | import java.lang.reflect.Method; 34 | import java.util.HashSet; 35 | import java.util.Set; 36 | //#if MC >= 12006 37 | import net.minecraft.component.type.ItemEnchantmentsComponent; 38 | import net.minecraft.component.DataComponentTypes; 39 | import net.minecraft.component.type.NbtComponent; 40 | //#else 41 | //$$ 42 | //#endif 43 | import net.minecraft.enchantment.EnchantmentHelper; 44 | import net.minecraft.enchantment.Enchantments; 45 | 46 | //#if MC > 12104 47 | import net.minecraft.screen.sync.ItemStackHash; 48 | //#endif 49 | 50 | import static com.zxy.wuhuclient.Utils.SwitchItem.reSwitchItem; 51 | import static com.zxy.wuhuclient.Utils.ZxyUtils.getPlayer; 52 | import static com.zxy.wuhuclient.config.Configs.QUICK_SHULKER; 53 | import static net.minecraft.block.ShulkerBoxBlock.FACING; 54 | 55 | public class InventoryUtils { 56 | public static HashSet items2 = new HashSet<>(); 57 | @NotNull 58 | public static MinecraftClient client = MinecraftClient.getInstance(); 59 | public static boolean openIng = false; 60 | public static boolean switchItem = false; 61 | public static void switchInv(){ 62 | ClientPlayerEntity player = MinecraftClient.getInstance().player; 63 | ScreenHandler sc = player.currentScreenHandler; 64 | if(sc.equals(player.playerScreenHandler)){ 65 | return; 66 | } 67 | DefaultedList slots = sc.slots; 68 | for(Item item : items2) { 69 | for (int y = 0; y < slots.get(0).inventory.size(); y++) { 70 | if (slots.get(y).getStack().getItem().equals(item)) { 71 | 72 | String[] str = Configs.Generic.PICK_BLOCKABLE_SLOTS.getStringValue().split(","); 73 | if(str.length==0) return; 74 | for (String s : str) { 75 | if (s == null) break; 76 | try { 77 | int c = Integer.parseInt(s) - 1; 78 | if (Registries.ITEM.getId(player.getInventory().getStack(c).getItem()).toString().contains("shulker_box") && 79 | QUICK_SHULKER.getBooleanValue()) { 80 | MinecraftClient.getInstance().inGameHud.setOverlayMessage(Text.of("没有可替换的槽位,请将预选位的濳影盒换个位置"),false); 81 | continue; 82 | } 83 | SwitchItem.newItem(slots.get(y).getStack(), null,null,y, shulkerBoxSlot); 84 | shulkerBoxSlot = -1; 85 | int a = Litematica_InventoryUtilsMixin.getEmptyPickBlockableHotbarSlot(player.getInventory()) == -1 ? 86 | Litematica_InventoryUtilsMixin.getPickBlockTargetSlot(player) : 87 | Litematica_InventoryUtilsMixin.getEmptyPickBlockableHotbarSlot(player.getInventory()); 88 | c = a == -1 ? c : a; 89 | switchPlayerInvToHotbarAir(c); 90 | fi.dy.masa.malilib.util.InventoryUtils.swapSlots(sc, y, c); 91 | //#if MC > 12104 92 | player.getInventory().setSelectedSlot(c); 93 | //#else 94 | //$$ player.getInventory().selectedSlot = c; 95 | //#endif 96 | player.closeHandledScreen(); 97 | items2 = new HashSet<>(); 98 | return; 99 | } catch (Exception e) { 100 | System.out.println("切换物品异常"); 101 | } 102 | } 103 | } 104 | } 105 | } 106 | shulkerBoxSlot = -1; 107 | items2 = new HashSet<>(); 108 | player.closeHandledScreen(); 109 | } 110 | public static boolean switchItem(){ 111 | if(items2.isEmpty()) return false; 112 | ClientPlayerEntity player = client.player; 113 | ScreenHandler sc = player.currentScreenHandler; 114 | if(!switchItem){ 115 | if(!player.currentScreenHandler.equals(player.playerScreenHandler)) player.closeHandledScreen(); 116 | if (sc.slots.stream().skip(9).limit(sc.slots.size()-10).noneMatch(slot -> slot.getStack().isEmpty())) { 117 | SwitchItem.checkItems(); 118 | return true; 119 | } 120 | if(QUICK_SHULKER.getBooleanValue() && openShulker(items2)) return true; 121 | } 122 | return false; 123 | } 124 | static int shulkerBoxSlot = 0; 125 | static boolean openShulker(HashSet items){ 126 | for (Item item : items) { 127 | ScreenHandler sc = MinecraftClient.getInstance().player.playerScreenHandler; 128 | for (int i = 9; i < sc.slots.size(); i++) { 129 | ItemStack stack = sc.slots.get(i).getStack(); 130 | String itemid = Registries.ITEM.getId(stack.getItem()).toString(); 131 | if(itemid.contains("shulker_box")){ 132 | DefaultedList items1 = fi.dy.masa.malilib.util.InventoryUtils.getStoredItems(stack, -1); 133 | if(items1.stream().anyMatch(s1 -> s1.getItem().equals(item))){ 134 | try { 135 | if(reSwitchItem == null) shulkerBoxSlot = i; 136 | Class quickShulker = Class.forName("net.kyrptonaught.quickshulker.client.ClientUtil"); 137 | Method checkAndSend = quickShulker.getDeclaredMethod("CheckAndSend",ItemStack.class,int.class); 138 | checkAndSend.invoke(checkAndSend,stack,i); 139 | ScreenManagement.closeScreen++; 140 | switchItem = true; 141 | return true; 142 | } catch (Exception e) { 143 | } 144 | } 145 | } 146 | } 147 | } 148 | return false; 149 | } 150 | public static void switchPlayerInvToHotbarAir(int slot){ 151 | if(client.player == null )return; 152 | ClientPlayerEntity player = client.player; 153 | ScreenHandler sc = player.currentScreenHandler; 154 | DefaultedList slots = sc.slots; 155 | int i = sc.equals(player.playerScreenHandler) ? 9 : 0; 156 | for (; i < slots.size(); i++) { 157 | if (slots.get(i).getStack().isEmpty() && slots.get(i).inventory instanceof PlayerInventory) { 158 | fi.dy.masa.malilib.util.InventoryUtils.swapSlots(sc, i, slot); 159 | return; 160 | } 161 | } 162 | } 163 | 164 | public static boolean equalsItem(ItemStack itemStack1,ItemStack itemStack2){ 165 | //#if MC > 12004 166 | return ItemStack.areItemsAndComponentsEqual(itemStack1, itemStack2); 167 | //#else 168 | //$$ return ItemStack.canCombine(itemStack1, itemStack2); 169 | //#endif 170 | } 171 | 172 | public static int getEnchantmentLevel(ItemStack itemStack, 173 | //#if MC > 12006 174 | RegistryKey enchantment 175 | //#else 176 | //$$ Enchantment enchantment 177 | //#endif 178 | ){ 179 | //#if MC > 12006 180 | ItemEnchantmentsComponent enchantments = itemStack.getEnchantments(); 181 | if (enchantments.equals(ItemEnchantmentsComponent.DEFAULT)) return -1; 182 | Set> enchantmentsEnchantments = enchantments.getEnchantments(); 183 | for (RegistryEntry entry : enchantmentsEnchantments) { 184 | if (entry.matchesKey(enchantment)) { 185 | return enchantments.getLevel(entry); 186 | } 187 | } 188 | return -1; 189 | //#else 190 | //$$ return EnchantmentHelper.getLevel(Enchantments.MENDING,itemStack); 191 | //#endif 192 | } 193 | public static void refreshPlayerInventory(){ 194 | ClientPlayNetworkHandler networkHandler = client.getNetworkHandler(); 195 | if (getPlayer().isEmpty()) return; 196 | ClientPlayerEntity player = getPlayer().get(); 197 | if(networkHandler == null) return; 198 | ItemStack uniqueItem = new ItemStack(Items.STONE); 199 | 200 | // Tags with NaN are not equal, so the server will find an inventory desync and send an inventory refresh to the client 201 | //#if MC >= 12006 202 | var nbt = new NbtCompound(); 203 | nbt.putDouble("force_sync", Double.NaN); 204 | NbtComponent.set(DataComponentTypes.CUSTOM_DATA, uniqueItem, nbt); 205 | //#else 206 | //$$ uniqueItem.getOrCreateNbt().putDouble("force_resync", Double.NaN); 207 | //#endif 208 | 209 | //#if MC >= 12105 210 | ItemStackHash itemStackHash = ItemStackHash.fromItemStack(uniqueItem, networkHandler.getComponentHasher()); 211 | //#endif 212 | 213 | networkHandler.sendPacket(new ClickSlotC2SPacket( 214 | player.currentScreenHandler.syncId, 215 | player.currentScreenHandler.getRevision(), 216 | (short) -999,(byte) 2, 217 | SlotActionType.QUICK_CRAFT, 218 | //#if MC < 12105 219 | //$$ uniqueItem, 220 | //$$ new Int2ObjectOpenHashMap<>() 221 | //#else 222 | new Int2ObjectOpenHashMap<>(), 223 | itemStackHash 224 | //#endif 225 | 226 | )); 227 | } 228 | 229 | public static boolean isInventory(BlockPos pos) { 230 | // if (client.crosshairTarget != null && client.crosshairTarget.getType() == HitResult.Type.BLOCK) { 231 | // BlockPos pos = ((BlockHitResult) client.crosshairTarget).getBlockPos(); 232 | if (client.world == null) return false; 233 | Inventory inventory = fi.dy.masa.malilib.util.InventoryUtils.getInventory(client.world, pos); 234 | 235 | return inventory != null; 236 | // BlockState blockState = client.world.getBlockState(pos); 237 | // BlockEntity blockEntity = client.world.getBlockEntity(pos); 238 | // try { 239 | // if (((BlockWithEntityMixin) blockState.getBlock()).createScreenHandlerFactory(blockState, client.world, pos) == null || 240 | // (blockEntity instanceof ShulkerBoxBlockEntity entity && 241 | // //#if MC > 12004 242 | // !client.world.isSpaceEmpty(ShulkerEntity.calculateBoundingBox(0.0f,blockState.get(FACING), 0.5f).offset(pos).contract(1.0E-6)) && 243 | // //#else 244 | // //$$ !client.world.isSpaceEmpty(ShulkerEntity.calculateBoundingBox(blockState.get(FACING), 0.0f, 0.5f).offset(pos).contract(1.0E-6)) && 245 | // //#endif 246 | // entity.getAnimationStage() == ShulkerBoxBlockEntity.AnimationStage.CLOSED)) { 247 | // client.inGameHud.setOverlayMessage(Text.of("目标无法打开"), false); 248 | // return false; 249 | // } 250 | // } catch (Exception e) { 251 | // return false; 252 | // } 253 | // return true; 254 | } 255 | 256 | public static boolean canOpenInv(BlockPos pos){ 257 | if (client.world != null) { 258 | BlockState blockState = client.world.getBlockState(pos); 259 | BlockEntity blockEntity = client.world.getBlockEntity(pos); 260 | boolean isInventory = InventoryUtils.isInventory(pos); 261 | try { 262 | if ((isInventory && blockState.createScreenHandlerFactory(client.world,pos) == null) || 263 | (blockEntity instanceof ShulkerBoxBlockEntity entity && 264 | //#if MC > 12101 265 | !client.world.isSpaceEmpty(ShulkerEntity.calculateBoundingBox(1.0F, blockState.get(FACING), 0.0F, 0.5F, pos.toBottomCenterPos()).offset(pos).contract(1.0E-6)) && 266 | //#elseif MC <= 12101 && MC > 12004 267 | //$$ !client.world.isSpaceEmpty(ShulkerEntity.calculateBoundingBox(1.0F, blockState.get(FACING), 0.0F, 0.5F).offset(pos).contract(1.0E-6)) && 268 | //#elseif MC <= 12004 269 | //$$ !client.world.isSpaceEmpty(ShulkerEntity.calculateBoundingBox(blockState.get(FACING), 0.0f, 0.5f).offset(pos).contract(1.0E-6)) && 270 | //#endif 271 | entity.getAnimationStage() == ShulkerBoxBlockEntity.AnimationStage.CLOSED)) { 272 | return false; 273 | }else if(!isInventory){ 274 | return false; 275 | } 276 | } catch (Exception e) { 277 | return false; 278 | } 279 | return true; 280 | }else { 281 | return false; 282 | } 283 | } 284 | } -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/Utils/MyBox.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.Utils; 2 | 3 | import net.minecraft.util.math.BlockPos; 4 | import net.minecraft.util.math.Box; 5 | import net.minecraft.util.math.Vec3d; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | import java.util.Iterator; 9 | 10 | public class MyBox extends Box implements Iterable { 11 | public boolean yIncrement = true; 12 | public Iterator iterator; 13 | public MyBox(double x1, double y1, double z1, double x2, double y2, double z2) { 14 | super(x1, y1, z1, x2, y2, z2); 15 | } 16 | 17 | public MyBox(fi.dy.masa.litematica.selection.Box box) { 18 | this(Vec3d.of(box.getPos1()), Vec3d.of(box.getPos2())); 19 | } 20 | public MyBox(Box box) { 21 | this(box.minX,box.minY,box.minZ,box.maxX,box.maxY,box.maxZ); 22 | } 23 | 24 | public MyBox(BlockPos pos) { 25 | this((double) pos.getX(), (double) pos.getY(), (double) pos.getZ(), (double) (pos.getX()), (double) (pos.getY()), (double) (pos.getZ())); 26 | } 27 | 28 | public MyBox(Vec3d pos1, Vec3d pos2) { 29 | this(pos1.x, pos1.y, pos1.z, pos2.x, pos2.y, pos2.z); 30 | } 31 | 32 | //因原方法最大值比较时使用的是 < 而不是 <= 因此 最小边界能被覆盖 而最大边界不能 33 | @Override 34 | public boolean contains(double x, double y, double z) { 35 | return x >= this.minX && x <= this.maxX && y >= this.minY && y <= this.maxY && z >= this.minZ && z <= this.maxZ; 36 | } 37 | @Override 38 | public MyBox expand(double x, double y, double z) { 39 | double d = this.minX - x; 40 | double e = this.minY - y; 41 | double f = this.minZ - z; 42 | double g = this.maxX + x; 43 | double h = this.maxY + y; 44 | double i = this.maxZ + z; 45 | return new MyBox(d, e, f, g, h, i); 46 | } 47 | @Override 48 | public MyBox expand(double value) { 49 | return this.expand(value, value, value); 50 | } 51 | public void initIterator(){ 52 | if (this.iterator == null) this.iterator = iterator(); 53 | } 54 | public void resetIterator(){ 55 | this.iterator = iterator(); 56 | } 57 | @Override 58 | public @NotNull Iterator iterator() { 59 | return new Iterator() { 60 | public BlockPos currPos; 61 | @Override 62 | public boolean hasNext() { 63 | if (currPos == null) return true; 64 | int x = currPos.getX(); 65 | int y = currPos.getY(); 66 | int z = currPos.getZ(); 67 | boolean b = !(x == maxX && (yIncrement ? y == maxY : y == minY) && z == maxZ); 68 | if (!b) currPos = null; 69 | return b; 70 | } 71 | 72 | @Override 73 | public BlockPos next() { 74 | if (currPos == null) { 75 | currPos = new BlockPos((int) minX, (int) (yIncrement ? minY : maxY), (int) minZ); 76 | return currPos; 77 | } 78 | int x = currPos.getX(); 79 | int y = currPos.getY(); 80 | int z = currPos.getZ(); 81 | x++; 82 | if (x > maxX) { 83 | x = (int) minX; 84 | z++; 85 | if (z > maxZ) { 86 | z = (int) minZ; 87 | y = yIncrement ? y + 1 : y - 1; 88 | if (yIncrement ? y > maxY : y < minY) { 89 | y = (int) (yIncrement ? minY : maxY); 90 | } 91 | } 92 | } 93 | currPos = new BlockPos(x, y, z); 94 | return currPos; 95 | } 96 | }; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/Utils/PinYinSearch.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.Utils; 2 | 3 | import net.minecraft.component.type.FoodComponent; 4 | import net.sourceforge.pinyin4j.PinyinHelper; 5 | import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType; 6 | import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; 7 | import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; 8 | import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType; 9 | import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | public class PinYinSearch { 16 | public static void main(String[] args) { 17 | getPinYin("曾0长0"); 18 | } 19 | 20 | public static ArrayList getPinYin(String str) { 21 | 22 | char[] ch = str.toCharArray(); 23 | HanyuPinyinOutputFormat gs = new HanyuPinyinOutputFormat(); 24 | gs.setCaseType(HanyuPinyinCaseType.LOWERCASE); 25 | gs.setToneType(HanyuPinyinToneType.WITHOUT_TONE); 26 | gs.setVCharType(HanyuPinyinVCharType.WITH_V); 27 | 28 | ArrayList pinyin = new ArrayList<>(); 29 | try { 30 | for (char c : ch) { 31 | if (c <= 128) pinyin.add(new String[]{"" + c}); 32 | else pinyin.add(PinyinHelper.toHanyuPinyinStringArray(c, gs)); 33 | } 34 | } catch (BadHanyuPinyinOutputFormatCombination e) { 35 | throw new RuntimeException(e); 36 | } 37 | return getStrings(pinyin); 38 | } 39 | 40 | public static boolean hasPinYin(String zh, String py) { 41 | return getPinYin(zh).stream().anyMatch(s -> s.contains(py)); 42 | } 43 | 44 | @NotNull 45 | private static ArrayList getStrings(ArrayList pinyin) { 46 | if(pinyin == null || pinyin.isEmpty()) return new ArrayList<>(); 47 | //全拼 48 | ArrayList quanPin = new ArrayList<>(); 49 | //首字母简拼 50 | ArrayList jianPin = new ArrayList<>(); 51 | //如果输入的是 曾长 那么pinyin中的内容为 ["zeng","ceng"],["chang","zhang"] 52 | //处理第一个字 不要信idea的用getFirst方法 旧版jdk不支持 53 | for (String py : pinyin.get(0)) { 54 | quanPin.add(py); 55 | jianPin.add("" + py.charAt(0)); 56 | } 57 | 58 | //从第二个字开始遍历 59 | for (int i = 1; i < pinyin.size(); i++) { 60 | ArrayList tempQuanPin = new ArrayList<>(); 61 | ArrayList tempJianPin = new ArrayList<>(); 62 | //遍历当前字的全部读音 63 | for (String currPinYin : pinyin.get(i)) { 64 | for (int i1 = 0; i1 < quanPin.size(); i1++) { 65 | tempQuanPin.add(quanPin.get(i1) + currPinYin); 66 | tempJianPin.add(jianPin.get(i1) + currPinYin.charAt(0)); 67 | } 68 | } 69 | quanPin = tempQuanPin; 70 | jianPin = tempJianPin; 71 | } 72 | quanPin.addAll(jianPin); 73 | return quanPin; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/Utils/ScreenManagement.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.Utils; 2 | 3 | import net.minecraft.client.gui.screen.Screen; 4 | 5 | public class ScreenManagement { 6 | //阻止UI显示 如果此时已经在UI中 请设置为2因为关闭UI也会调用一次 7 | public static int closeScreen = 0; 8 | public static Screen screen = null; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/Utils/SwitchItem.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.Utils; 2 | 3 | import fi.dy.masa.malilib.util.InventoryUtils; 4 | import net.minecraft.client.network.ClientPlayerEntity; 5 | import net.minecraft.entity.player.PlayerInventory; 6 | import net.minecraft.item.ItemStack; 7 | import net.minecraft.registry.RegistryKey; 8 | import net.minecraft.screen.ScreenHandler; 9 | import net.minecraft.screen.slot.Slot; 10 | import net.minecraft.screen.slot.SlotActionType; 11 | import net.minecraft.text.Text; 12 | import net.minecraft.util.math.BlockPos; 13 | import net.minecraft.world.World; 14 | 15 | import java.lang.reflect.Method; 16 | import java.util.ArrayList; 17 | import java.util.HashMap; 18 | import java.util.List; 19 | import java.util.Map; 20 | import java.util.concurrent.atomic.AtomicReference; 21 | 22 | import static com.zxy.wuhuclient.Utils.ScreenManagement.closeScreen; 23 | import static com.zxy.wuhuclient.features_list.Synthesis.client; 24 | 25 | public class SwitchItem { 26 | // public static boolean switchIng = false; 27 | public static ItemStack reSwitchItem = null; 28 | public static Map itemStacks = new HashMap<>(); 29 | public static void removeItem(ItemStack itemStack){ 30 | itemStacks.remove(itemStack); 31 | } 32 | public static void syncUseTime(ItemStack itemStack){ 33 | ItemStatistics itemStatistics = itemStacks.get(itemStack); 34 | if(itemStatistics !=null) itemStatistics.syncUseTime(); 35 | } 36 | public static void newItem(ItemStack itemStack, BlockPos pos, RegistryKey key, int slot, int shulkerBox){ 37 | itemStacks.put(itemStack,new ItemStatistics(key,pos,slot,shulkerBox)); 38 | } 39 | public static void openInv(ItemStack itemStack){ 40 | if(!client.player.currentScreenHandler.equals(client.player.playerScreenHandler) || closeScreen > 0){ 41 | return; 42 | } 43 | ScreenHandler sc1 = client.player.currentScreenHandler; 44 | if (sc1.slots.stream().skip(9).limit(sc1.slots.size()-10) 45 | .noneMatch(slot -> InventoryUtils.areStacksEqual(slot.getStack(),reSwitchItem))) { 46 | itemStacks.remove(reSwitchItem); 47 | reSwitchItem = null; 48 | return; 49 | } 50 | ItemStatistics itemStatistics = itemStacks.get(itemStack); 51 | if(itemStatistics != null){ 52 | ScreenHandler sc = client.player.currentScreenHandler; 53 | for (int i = 9; i < sc.slots.size() && itemStatistics.shulkerBoxSlot != -1; i++) { 54 | ItemStack stack = sc.slots.get(i).getStack(); 55 | if (InventoryUtils.getStoredItems(stack,-1).stream().anyMatch(stack1 -> stack1.isEmpty() || 56 | (InventoryUtils.areStacksEqual(stack1,reSwitchItem) && stack1.getCount() < stack1.getMaxCount())) 57 | ) { 58 | try { 59 | Class quickShulker = Class.forName("net.kyrptonaught.quickshulker.client.ClientUtil"); 60 | Method checkAndSend = quickShulker.getDeclaredMethod("CheckAndSend",ItemStack.class,int.class); 61 | checkAndSend.invoke(checkAndSend,sc.slots.get(itemStatistics.shulkerBoxSlot).getStack(),i); 62 | closeScreen++; 63 | return; 64 | } catch (Exception ignored){} 65 | } 66 | } 67 | removeItem(reSwitchItem); 68 | reSwitchItem = null; 69 | } 70 | } 71 | public static void checkItems(){ 72 | final long[] min = {System.currentTimeMillis()}; 73 | AtomicReference key = new AtomicReference<>(); 74 | itemStacks.keySet().forEach(k ->{ 75 | long useTime = itemStacks.get(k).useTime; 76 | if(useTime < min[0]){ 77 | min[0] = useTime; 78 | key.set(k); 79 | } 80 | }); 81 | ItemStack itemStack = key.get(); 82 | if(itemStack != null) { 83 | reSwitchItem = itemStack; 84 | openInv(itemStack); 85 | }else client.inGameHud.setOverlayMessage(Text.of("背包已满,请先清理"),false); 86 | } 87 | public static void reSwitchItem(){ 88 | if(client.player == null || reSwitchItem == null) return; 89 | ClientPlayerEntity player = client.player; 90 | ScreenHandler sc = player.currentScreenHandler; 91 | if (sc.equals(player.playerScreenHandler)) return; 92 | List sameItem = new ArrayList<>(); 93 | for (int i = 0; i < sc.slots.size(); i++) { 94 | Slot slot = sc.slots.get(i); 95 | if(!(slot.inventory instanceof PlayerInventory) && 96 | InventoryUtils.areStacksEqual(reSwitchItem,slot.getStack()) && 97 | slot.getStack().getCount() < slot.getStack().getMaxCount() 98 | ) sameItem.add(i); 99 | if(slot.inventory instanceof PlayerInventory && client.interactionManager != null && InventoryUtils.areStacksEqual(slot.getStack(),reSwitchItem)){ 100 | int slot1 = itemStacks.get(reSwitchItem).slot; 101 | boolean reInv = false; 102 | //检查记录的槽位是否有物品 103 | if(sc.slots.get(slot1).getStack().isEmpty()){ 104 | client.interactionManager.clickSlot(sc.syncId, i, 0, SlotActionType.PICKUP, client.player); 105 | client.interactionManager.clickSlot(sc.syncId, slot1, 0, SlotActionType.PICKUP, client.player); 106 | reInv = true; 107 | } else { 108 | int count = reSwitchItem.getCount(); 109 | client.interactionManager.clickSlot(sc.syncId, i, 0, SlotActionType.PICKUP, client.player); 110 | for (Integer integer : sameItem) { 111 | int count1 = sc.slots.get(integer).getStack().getCount(); 112 | int maxCount = sc.slots.get(integer).getStack().getMaxCount(); 113 | int i1 = maxCount - count1; 114 | count -= i1; 115 | client.interactionManager.clickSlot(sc.syncId, integer, 0, SlotActionType.PICKUP, client.player); 116 | if (count<=0) reInv = true; 117 | } 118 | } 119 | removeItem(reSwitchItem); 120 | reSwitchItem = null; 121 | player.closeHandledScreen(); 122 | if(!reInv) client.inGameHud.setOverlayMessage(Text.of("复原库存物品失败"),false); 123 | client.interactionManager.clickSlot(sc.syncId, i, 0, SlotActionType.PICKUP, client.player); 124 | return; 125 | } 126 | } 127 | } 128 | public static void reSet(){ 129 | reSwitchItem = null; 130 | itemStacks = new HashMap<>(); 131 | } 132 | public static class ItemStatistics { 133 | public RegistryKey key; 134 | public BlockPos pos; 135 | public int slot; 136 | public int shulkerBoxSlot; 137 | public long useTime = System.currentTimeMillis(); 138 | public ItemStatistics(RegistryKey key, BlockPos pos, int slot, int shulkerBox) { 139 | this.key = key; 140 | this.pos = pos; 141 | this.slot = slot; 142 | this.shulkerBoxSlot = shulkerBox; 143 | } 144 | public void syncUseTime(){ 145 | this.useTime = System.currentTimeMillis(); 146 | } 147 | } 148 | } -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/Utils/ZxyUtils.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.Utils; 2 | 3 | import com.zxy.wuhuclient.features_list.SyncInventory; 4 | import com.zxy.wuhuclient.features_list.Synthesis; 5 | import com.zxy.wuhuclient.features_list.Test; 6 | import com.zxy.wuhuclient.features_list.litematica_helper.LitematicaHelper; 7 | import fi.dy.masa.litematica.data.DataManager; 8 | import fi.dy.masa.litematica.selection.AreaSelection; 9 | import fi.dy.masa.litematica.selection.Box; 10 | import fi.dy.masa.litematica.world.WorldSchematic; 11 | import net.fabricmc.loader.api.FabricLoader; 12 | import net.minecraft.block.Block; 13 | import net.minecraft.block.BlockState; 14 | import net.minecraft.client.MinecraftClient; 15 | import net.minecraft.client.network.ClientPlayerEntity; 16 | import net.minecraft.client.world.ClientWorld; 17 | import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket; 18 | import net.minecraft.network.packet.c2s.play.PlayerInputC2SPacket; 19 | import net.minecraft.util.math.Vec3d; 20 | import net.minecraft.registry.Registries; 21 | import net.minecraft.util.math.BlockPos; 22 | 23 | 24 | import java.util.*; 25 | import java.util.concurrent.CopyOnWriteArrayList; 26 | import java.util.concurrent.CopyOnWriteArraySet; 27 | 28 | import net.minecraft.text.Text; 29 | 30 | 31 | //#if MC > 11802 32 | import net.minecraft.text.MutableText; 33 | //#else 34 | //$$ import net.minecraft.text.TranslatableText; 35 | //#endif 36 | 37 | //#if MC > 12105 38 | import net.minecraft.util.PlayerInput; 39 | //#endif 40 | 41 | import static com.zxy.wuhuclient.Utils.BlockFilters.equalsBlockName; 42 | import static com.zxy.wuhuclient.Utils.ZxyUtils.TempData.max; 43 | import static com.zxy.wuhuclient.Utils.ZxyUtils.TempData.min; 44 | import static com.zxy.wuhuclient.WuHuClientMod.client; 45 | import static com.zxy.wuhuclient.config.Configs.*; 46 | import static com.zxy.wuhuclient.features_list.CloseTheContainerAfterOpening.step; 47 | import static fi.dy.masa.litematica.selection.SelectionMode.NORMAL; 48 | 49 | public class ZxyUtils { 50 | public static boolean isLoadQuiShulker = isLoadMod("quickshulker"); 51 | public static boolean isLoadChestTracker = isLoadMod("chesttracker"); 52 | public static boolean isLoadPrinter = isLoadMod("litematica-printer"); 53 | public static boolean isLoadMod(String modId){ 54 | return FabricLoader.getInstance().isModLoaded(modId); 55 | } 56 | public static void tick(){ 57 | // searchBlockThread(); 58 | Synthesis.tick(); 59 | Test.tick(); 60 | step(); 61 | if (SyncInventory.num==2) SyncInventory.syncInv(); 62 | } 63 | 64 | public static void setShift(boolean shift){ 65 | ClientPlayerEntity player = client.player; 66 | //#if MC > 12105 67 | PlayerInput input = new PlayerInput(player.input.playerInput.forward(), player.input.playerInput.backward(), player.input.playerInput.left(), player.input.playerInput.right(), player.input.playerInput.jump(), shift, player.input.playerInput.sprint()); 68 | PlayerInputC2SPacket packet = new PlayerInputC2SPacket(input); 69 | //#else 70 | //$$ ClientCommandC2SPacket packet = new ClientCommandC2SPacket(player, shift ? ClientCommandC2SPacket.Mode.PRESS_SHIFT_KEY : ClientCommandC2SPacket.Mode.RELEASE_SHIFT_KEY); 71 | //#endif 72 | 73 | player.networkHandler.sendPacket(packet); 74 | 75 | } 76 | public static class TempData { 77 | public static int[] min; 78 | public static int[] max; 79 | 80 | public static boolean xuanQuFanWeiNei_p(BlockPos pos) { 81 | AreaSelection i = DataManager.getSelectionManager().getCurrentSelection(); 82 | if (i == null) return false; 83 | if (DataManager.getSelectionManager().getSelectionMode() == NORMAL) { 84 | boolean fw = false; 85 | List arr = i.getAllSubRegionBoxes(); 86 | for (int j = 0; j < arr.size(); j++) { 87 | if (comparePos(arr.get(j), pos)) { 88 | return true; 89 | } else { 90 | fw = false; 91 | } 92 | } 93 | return fw; 94 | } else { 95 | Box box = i.getSubRegionBox(DataManager.getSimpleArea().getName()); 96 | return comparePos(box, pos); 97 | } 98 | } 99 | 100 | static boolean comparePos(Box box, BlockPos pos) { 101 | if (box == null || pos == null) return false; 102 | MyBox myBox = new MyBox(box); 103 | return myBox.contains(Vec3d.of(pos)); 104 | } 105 | 106 | public ClientPlayerEntity player; 107 | public ClientWorld world; 108 | public WorldSchematic worldSchematic; 109 | 110 | public TempData(ClientPlayerEntity player, ClientWorld world, WorldSchematic worldSchematic) { 111 | this.player = player; 112 | this.world = world; 113 | this.worldSchematic = worldSchematic; 114 | } 115 | } 116 | 117 | public static LinkedList siftBlock(String blockName) { 118 | LinkedList blocks = new LinkedList<>(); 119 | AreaSelection i = DataManager.getSelectionManager().getCurrentSelection(); 120 | List box; 121 | if (i == null) return blocks; 122 | box = i.getAllSubRegionBoxes(); 123 | for (Box value : box) { 124 | MyBox myBox = new MyBox(value); 125 | for (BlockPos pos : myBox) { 126 | BlockState state = null; 127 | if (client.world != null) { 128 | state = client.world.getBlockState(pos); 129 | } 130 | 131 | if (state != null && equalsBlockName(blockName, state, pos)) { 132 | blocks.add(pos); 133 | } 134 | } 135 | } 136 | return blocks; 137 | } 138 | 139 | public static String searchBlockId = "searchBlock"; 140 | public static boolean searchBlockIng = false; 141 | 142 | public synchronized static void searchBlock() { 143 | boolean searchBlockSwitch = SEARCH_BLOCK.getBooleanValue(); 144 | 145 | if (!searchBlockSwitch) { 146 | Set highlightBlockPosList = HighlightBlockRenderer.getHighlightBlockPosList(searchBlockId); 147 | if (highlightBlockPosList != null) { 148 | HighlightBlockRenderer.clear(searchBlockId); 149 | return; 150 | } 151 | } 152 | 153 | HighlightBlockRenderer.createHighlightBlockList(searchBlockId, SEARCH_BLOCK_COLOR); 154 | 155 | if (!searchBlockSwitch) return; 156 | LinkedHashSet blockPos = new LinkedHashSet<>(); 157 | List strings = SEARCH_BLOCK_LIST.getStrings(); 158 | 159 | for (String blockName : strings) { 160 | LinkedList blockPosLinkedList = siftBlock(blockName); 161 | List list = blockPosLinkedList.stream().distinct().toList(); 162 | boolean booleanValue = SEARCH_BLOCK_LIMIT.getBooleanValue(); 163 | blockPos.addAll(list.stream().filter(pos -> !booleanValue || DataManager.getRenderLayerRange().isPositionWithinRange(pos)).toList()); 164 | } 165 | HighlightBlockRenderer.setPos(searchBlockId, blockPos); 166 | } 167 | public static void searchBlockThread() { 168 | if (!searchBlockIng) { 169 | try { 170 | searchBlockIng = true; 171 | searchBlock(); 172 | if (isLoadChestTracker) LitematicaHelper.instance.highlightInventoryBlock(); 173 | } finally { 174 | searchBlockIng = false; 175 | } 176 | } 177 | } 178 | public static Optional getPlayer(){ 179 | return Optional.ofNullable(client.player); 180 | } 181 | 182 | public static void actionBar(String message){ 183 | MinecraftClient minecraftClient = MinecraftClient.getInstance(); 184 | //#if MC > 11802 185 | MutableText translatable = Text.translatable(message); 186 | //#else 187 | //$$ TranslatableText translatable = new TranslatableText(message); 188 | //#endif 189 | minecraftClient.inGameHud.setOverlayMessage(translatable,false); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/WuHuClientMod.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient; 2 | 3 | 4 | import com.zxy.wuhuclient.Utils.HighlightBlockRenderer; 5 | import com.zxy.wuhuclient.config.Configs; 6 | import com.zxy.wuhuclient.config.HotkeysCallback; 7 | import com.zxy.wuhuclient.config.InputHandler; 8 | import fi.dy.masa.malilib.config.ConfigManager; 9 | import fi.dy.masa.malilib.event.InputEventHandler; 10 | import net.fabricmc.api.ClientModInitializer; 11 | import net.fabricmc.api.ModInitializer; 12 | import net.minecraft.client.MinecraftClient; 13 | import org.apache.logging.log4j.LogManager; 14 | import org.apache.logging.log4j.Logger; 15 | 16 | public class WuHuClientMod implements ClientModInitializer, ModInitializer { 17 | 18 | public static MinecraftClient client = MinecraftClient.getInstance(); 19 | public static final String MOD_ID = "wuhuclient"; 20 | public static final String MOD_NAME = "wuhuclient"; 21 | public static final Logger LOGGER = LogManager.getLogger(); 22 | @Override 23 | public void onInitialize() { 24 | register(); 25 | } 26 | void register(){ 27 | Configs.INSTANCE.load(); 28 | ConfigManager.getInstance().registerConfigHandler(MOD_ID, Configs.INSTANCE); 29 | 30 | InputEventHandler.getKeybindManager().registerKeybindProvider(InputHandler.getInstance()); 31 | InputEventHandler.getInputManager().registerKeyboardInputHandler(InputHandler.getInstance()); 32 | HighlightBlockRenderer.init(); 33 | HotkeysCallback.init(); 34 | } 35 | @Override 36 | public void onInitializeClient() { 37 | register(); 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/config/ConfigUi.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.config; 2 | 3 | import fi.dy.masa.malilib.config.IConfigBase; 4 | import fi.dy.masa.malilib.gui.GuiConfigsBase; 5 | import fi.dy.masa.malilib.gui.button.ButtonBase; 6 | import fi.dy.masa.malilib.gui.button.ButtonGeneric; 7 | import fi.dy.masa.malilib.gui.button.IButtonActionListener; 8 | 9 | import java.util.List; 10 | 11 | import static com.zxy.wuhuclient.WuHuClientMod.MOD_ID; 12 | import static com.zxy.wuhuclient.config.ConfigUi.Tab.*; 13 | 14 | public class ConfigUi extends GuiConfigsBase { 15 | private static Tab tab = Tab.ALL; 16 | 17 | public ConfigUi() { 18 | super(10, 50, MOD_ID, null, "wuhu-client"); 19 | } 20 | 21 | @Override 22 | public void initGui() { 23 | super.initGui(); 24 | this.clearOptions(); 25 | 26 | int x = 10; 27 | int y = 26; 28 | for (Tab tab : Tab.values()) { 29 | x += this.createButton(x, y, -1, tab); 30 | } 31 | 32 | } 33 | 34 | private int createButton(int x, int y, int width, Tab tab) { 35 | ButtonGeneric button = new ButtonGeneric(x, y, width, 20, tab.name); 36 | button.setEnabled(ConfigUi.tab != tab); 37 | this.addButton(button, new ButtonListener(tab, this)); 38 | 39 | return button.getWidth() + 2; 40 | } 41 | 42 | //按钮宽度 43 | // @Override 44 | // protected int getConfigWidth() 45 | // { 46 | // Tab tab = ConfigUi.tab; 47 | // 48 | // if (tab == Tab.ALL) 49 | // { 50 | // return 120; 51 | // } 52 | // else if (tab == Tab.GENERAL) 53 | // { 54 | // return 60; 55 | // } 56 | // return 260; 57 | // } 58 | 59 | @Override 60 | public List getConfigs() { 61 | List configs; 62 | Tab tab = ConfigUi.tab; 63 | if (tab == Tab.ALL) { 64 | configs = Configs.ALL_CONFIGS; 65 | } else if(tab == COMPATIBILITY) { 66 | configs = Configs.COMPATIBILITY; 67 | } else if (tab == FUNCTION) { 68 | configs = Configs.FUNCTION; 69 | } else if (tab == COLOR) { 70 | configs = Configs.COLOR; 71 | } else if(tab == null){ 72 | return null; 73 | } else { 74 | configs = Configs.ALL_CONFIGS; 75 | } 76 | return ConfigOptionWrapper.createFor(configs); 77 | } 78 | 79 | private static class ButtonListener implements IButtonActionListener { 80 | private final ConfigUi parent; 81 | private final Tab tab; 82 | 83 | public ButtonListener(Tab tab, ConfigUi parent) { 84 | this.tab = tab; 85 | this.parent = parent; 86 | } 87 | 88 | @Override 89 | public void actionPerformedWithButton(ButtonBase button, int mouseButton) { 90 | ConfigUi.tab = this.tab; 91 | this.parent.reCreateListWidget(); 92 | this.parent.getListWidget().resetScrollbarPosition(); 93 | this.parent.initGui(); 94 | } 95 | } 96 | 97 | public enum Tab { 98 | ALL("全部"), 99 | COMPATIBILITY("兼容"), 100 | FUNCTION("功能"), 101 | COLOR("颜色"), 102 | ; 103 | 104 | public final String name; 105 | 106 | Tab(String str) { 107 | name = str; 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/config/Configs.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.config; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.google.gson.JsonElement; 5 | import com.google.gson.JsonObject; 6 | import fi.dy.masa.malilib.config.ConfigUtils; 7 | import fi.dy.masa.malilib.config.IConfigBase; 8 | import fi.dy.masa.malilib.config.IConfigHandler; 9 | import fi.dy.masa.malilib.config.IHotkeyTogglable; 10 | import fi.dy.masa.malilib.config.options.*; 11 | import fi.dy.masa.malilib.hotkeys.KeyAction; 12 | import fi.dy.masa.malilib.hotkeys.KeybindSettings; 13 | import fi.dy.masa.malilib.util.JsonUtils; 14 | 15 | import java.io.File; 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | import static com.zxy.wuhuclient.Utils.ZxyUtils.isLoadChestTracker; 20 | import static com.zxy.wuhuclient.Utils.ZxyUtils.isLoadQuiShulker; 21 | import static com.zxy.wuhuclient.WuHuClientMod.MOD_ID; 22 | import static fi.dy.masa.malilib.hotkeys.KeybindSettings.*; 23 | 24 | public class Configs implements IConfigHandler { 25 | public static Configs INSTANCE = new Configs(); 26 | private static final String FILE_PATH = "./config/" + MOD_ID + ".json"; 27 | private static final File CONFIG_DIR = new File("./config"); 28 | 29 | //mod 30 | public static final ConfigHotkey WUHU_CLIENT = new ConfigHotkey( "打开设置菜单", "Z,X",""); 31 | public static final ConfigBooleanHotkeyed TEST = new ConfigBooleanHotkeyed( "test",false,"",""); 32 | //功能 33 | public static final ConfigBooleanHotkeyed SYNTHESIS = new ConfigBooleanHotkeyed( "合成助手", false, "Z,C",""); 34 | public static final ConfigHotkey SYNC_INVENTORY = new ConfigHotkey( "容器同步","","按下热键后会记录看向容器的物品。\n将投影选区内的同类型容器中的物品,同步至记录的容器。"); 35 | public static final ConfigBooleanHotkeyed SYNC_INVENTORY_CHECK = new ConfigBooleanHotkeyed( "容器同步是否检查背包",true,"","开启时会检测背包中的物品是否满足填充条件,物品不足时不会打开容器。"); 36 | public static final ConfigBooleanHotkeyed AUTO_MENDING = new ConfigBooleanHotkeyed( "自动经验修补", false, "","在获取经验的时候可以将背包中带有经验修补且未满耐久的物品放到副手,"+"\n" + "修补完成后或一段时间未获得经验后放回原位。如果经验不是持续获得 可能不稳定"); 37 | public static final ConfigHotkey QUICK_FIREWORK = new ConfigHotkey( "快捷烟花", "",PRESS_ALLOWEXTRA,"在飞行状态时,按下热键会将背包内的烟花放到副手,使用烟花后再放回原位\n不会使用会爆炸的烟花"); 38 | public static final ConfigHotkey TAKE_OUT_THE_LAST_ITEM = new ConfigHotkey( "取出最后一格物品", "",GUI,"在ui中按下热键后可以视为按住shift点击了打开容器的最后一个格子\n在铁砧,工作台,砂轮等ui中可以帮助你更便捷的取出输出栏物品"); 39 | public static final ConfigBooleanHotkeyed SEARCH_BLOCK = new ConfigBooleanHotkeyed( "搜索选取内指定方块", false,"","按下后将选区内列表中的方块高亮,再次按下取消高亮"); 40 | public static final ConfigBoolean SEARCH_BLOCK_LIMIT = new ConfigBoolean( "搜索方块渲染层数限制", false,"是否受到投影渲染层数限制影响"); 41 | public static final ConfigStringList SEARCH_BLOCK_LIST = new ConfigStringList( "搜索方块列表",ImmutableList.of() ,""); 42 | public static final ConfigBooleanHotkeyed LITEMATICA_HELPER = new ConfigBooleanHotkeyed("投影材料助手",false,"","开启后将允许选区选中投影方块,会根据框选的投影更新材料列表。打开容器自动拿取对应材料\n安装箱子追踪后可高亮箱子\n"+"取物品功能来自 Fallen_Breath的TweakerMore"); 43 | public static final ConfigBoolean LITEMATICA_HELPER_TIPS = new ConfigBoolean("投影材料助手提示",true,"","交互容器后的存放提示"); 44 | public static final ConfigHotkey REFRESH_MATERIALS = new ConfigHotkey("刷新材料列表","","相当于点击了材料列表的刷新按钮"); 45 | public static final ConfigHotkey ADD_INVENTORY = new ConfigHotkey( "打开容器后关闭", "","按下后将打开选区内的容器然后关闭,再次按下取消高亮"); 46 | 47 | //兼容 48 | public static final ConfigBoolean PINYIN = new ConfigBoolean( "拼音搜索",true,"拼音/首字母简拼搜索 支持masa系列和创造搜索栏"); 49 | public static final ConfigBoolean EASY_PLACED_FIX = new ConfigBoolean( "轻松放置修复",true,"修复轻松放置多放置方块的bug\n此功能来自 Earthcomputer"); 50 | public static final ConfigBooleanHotkeyed QUICK_SHULKER = new ConfigBooleanHotkeyed( "快捷盒子支持", false, "","需要服务端有快捷盒子mod,否则会出现无法打开UI的情况\n" + 51 | "中键投影或轻松放置可以从濳影盒中直接取出物品(需要背包中有空位)"); 52 | // public static final ConfigBooleanHotkeyed REMOTE_INVENTORY = new ConfigBooleanHotkeyed( "远程库存", false, "","需要服务端有远程库存mod,否则会出现无法打开UI的情况\n"); 53 | 54 | //color 55 | public static final ConfigColor SYNC_INVENTORY_COLOR = new ConfigColor("容器同步高亮颜色","#4CFF4CE6",""); 56 | public static final ConfigColor SEARCH_BLOCK_COLOR = new ConfigColor("搜索方块高亮颜色","#4CFFB912",""); 57 | public static final ConfigColor LITEMATICA_HELPER_COLOR = new ConfigColor("投影材料助手高亮颜色","#4C6272E9","需要安装箱子追踪后才会高亮"); 58 | 59 | public static final ImmutableList COMPATIBILITY = addCompatibility(); 60 | public static ImmutableList addCompatibility(){ 61 | List list = new ArrayList<>(); 62 | list.add(WUHU_CLIENT); 63 | if(isLoadQuiShulker) list.add(QUICK_SHULKER); 64 | // list.add(REMOTE_INVENTORY); 65 | list.add(PINYIN); 66 | list.add(EASY_PLACED_FIX); 67 | 68 | return ImmutableList.copyOf(list); 69 | } 70 | public static final ImmutableList FUNCTION = addFunction(); 71 | public static ImmutableList addFunction(){ 72 | List list = new ArrayList<>(); 73 | list.add(SYNTHESIS); 74 | list.add(AUTO_MENDING); 75 | list.add(SYNC_INVENTORY); 76 | list.add(SYNC_INVENTORY_CHECK); 77 | list.add(SEARCH_BLOCK); 78 | list.add(SEARCH_BLOCK_LIMIT); 79 | list.add(SEARCH_BLOCK_LIST); 80 | list.add(LITEMATICA_HELPER); 81 | list.add(LITEMATICA_HELPER_TIPS); 82 | list.add(REFRESH_MATERIALS); 83 | list.add(ADD_INVENTORY); 84 | list.add(QUICK_FIREWORK); 85 | list.add(TAKE_OUT_THE_LAST_ITEM); 86 | // list.add(TEST); 87 | 88 | return ImmutableList.copyOf(list); 89 | } 90 | 91 | public static final ImmutableList COLOR = addColor(); 92 | public static ImmutableList addColor(){ 93 | List list = new ArrayList<>(); 94 | list.add(SYNC_INVENTORY_COLOR); 95 | list.add(SEARCH_BLOCK_COLOR); 96 | if(isLoadChestTracker) list.add(LITEMATICA_HELPER_COLOR); 97 | return ImmutableList.copyOf(list); 98 | } 99 | 100 | //按下时激活一次 101 | public static final ImmutableList KEY_LIST = ImmutableList.of( 102 | WUHU_CLIENT, 103 | SYNC_INVENTORY, 104 | QUICK_FIREWORK, 105 | TAKE_OUT_THE_LAST_ITEM, 106 | ADD_INVENTORY, 107 | REFRESH_MATERIALS 108 | ); 109 | //切换型开关 110 | public static final ImmutableList SWITCH_KEY = ImmutableList.of( 111 | SYNTHESIS, 112 | QUICK_SHULKER, 113 | SYNC_INVENTORY_CHECK, 114 | LITEMATICA_HELPER, 115 | AUTO_MENDING, 116 | SEARCH_BLOCK, 117 | // AUTO_STORAGE, 118 | TEST 119 | ); 120 | 121 | 122 | public static final ImmutableList ALL_CONFIGS = addAllConfigs(); 123 | public static ImmutableList addAllConfigs(){ 124 | List list = new ArrayList<>(); 125 | list.addAll(COMPATIBILITY); 126 | list.addAll(FUNCTION); 127 | list.addAll(COLOR); 128 | 129 | return ImmutableList.copyOf(list); 130 | } 131 | @Override 132 | public void load() { 133 | File settingFile = new File(FILE_PATH); 134 | if (settingFile.isFile() && settingFile.exists()) { 135 | JsonElement jsonElement = JsonUtils.parseJsonFile(settingFile); 136 | if (jsonElement != null && jsonElement.isJsonObject()) { 137 | JsonObject obj = jsonElement.getAsJsonObject(); 138 | ConfigUtils.readConfigBase(obj, MOD_ID, ALL_CONFIGS); 139 | } 140 | } 141 | } 142 | 143 | @Override 144 | public void save() { 145 | if ((CONFIG_DIR.exists() && CONFIG_DIR.isDirectory()) || CONFIG_DIR.mkdirs()) { 146 | JsonObject configRoot = new JsonObject(); 147 | ConfigUtils.writeConfigBase(configRoot, MOD_ID, ALL_CONFIGS); 148 | JsonUtils.writeJsonToFile(configRoot, new File(FILE_PATH)); 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/config/HotkeysCallback.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.config; 2 | 3 | import com.zxy.wuhuclient.features_list.CloseTheContainerAfterOpening; 4 | import com.zxy.wuhuclient.features_list.QuickFirework; 5 | import com.zxy.wuhuclient.features_list.SyncInventory; 6 | import fi.dy.masa.litematica.data.DataManager; 7 | import fi.dy.masa.litematica.materials.MaterialListBase; 8 | import fi.dy.masa.malilib.config.IHotkeyTogglable; 9 | import fi.dy.masa.malilib.config.options.ConfigHotkey; 10 | import fi.dy.masa.malilib.hotkeys.IHotkeyCallback; 11 | import fi.dy.masa.malilib.hotkeys.IKeybind; 12 | import fi.dy.masa.malilib.hotkeys.KeyAction; 13 | import net.minecraft.client.MinecraftClient; 14 | 15 | import static com.zxy.wuhuclient.config.Configs.*; 16 | import static com.zxy.wuhuclient.features_list.QuickClickSlot.clickLastSlot; 17 | 18 | //监听按键 19 | public class HotkeysCallback implements IHotkeyCallback { 20 | MinecraftClient client = MinecraftClient.getInstance(); 21 | 22 | //激活的热键会被key记录 23 | @Override 24 | public boolean onKeyAction(KeyAction action, IKeybind key) { 25 | if(key == WUHU_CLIENT.getKeybind()){ 26 | client.setScreen(new ConfigUi()); 27 | return true; 28 | }else if(key == SYNC_INVENTORY.getKeybind()){ 29 | SyncInventory.startOrOffSyncInventory(); 30 | }else if(key == TAKE_OUT_THE_LAST_ITEM.getKeybind()){ 31 | clickLastSlot(); 32 | }else if(key == QUICK_FIREWORK.getKeybind()){ 33 | QuickFirework.accelerated(); 34 | }else if(key == ADD_INVENTORY.getKeybind()){ 35 | CloseTheContainerAfterOpening.start(); 36 | }else if(key == REFRESH_MATERIALS.getKeybind() && DataManager.getMaterialList() != null){ 37 | DataManager.getMaterialList().reCreateMaterialList(); 38 | } 39 | return false; 40 | } 41 | 42 | //设置反馈到onKeyAction()方法的快捷键 43 | public static void init(){ 44 | HotkeysCallback hotkeysCallback = new HotkeysCallback(); 45 | 46 | for (ConfigHotkey configHotkey : Configs.KEY_LIST) { 47 | configHotkey.getKeybind().setCallback(hotkeysCallback); 48 | } 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/config/InputHandler.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.config; 2 | 3 | import com.zxy.wuhuclient.WuHuClientMod; 4 | import fi.dy.masa.malilib.hotkeys.IHotkey; 5 | import fi.dy.masa.malilib.hotkeys.IKeybindManager; 6 | import fi.dy.masa.malilib.hotkeys.IKeybindProvider; 7 | import fi.dy.masa.malilib.hotkeys.IKeyboardInputHandler; 8 | 9 | 10 | 11 | //注册按键 12 | public class InputHandler implements IKeybindProvider, IKeyboardInputHandler { 13 | private static final InputHandler INSTANCE = new InputHandler(); 14 | 15 | @Override 16 | public void addKeysToMap(IKeybindManager manager) { 17 | //没被添加到的,按下按键时不会被识别 18 | for (IHotkey hotkey : Configs.KEY_LIST) { 19 | manager.addKeybindToMap(hotkey.getKeybind()); 20 | } 21 | for (IHotkey hotkey : Configs.SWITCH_KEY) { 22 | manager.addKeybindToMap(hotkey.getKeybind()); 23 | } 24 | } 25 | 26 | @Override 27 | public void addHotkeys(IKeybindManager manager) { 28 | manager.addHotkeysForCategory(WuHuClientMod.MOD_ID, "按下式",Configs.KEY_LIST ); 29 | manager.addHotkeysForCategory(WuHuClientMod.MOD_ID, "切换式",Configs.SWITCH_KEY); 30 | } 31 | 32 | public static InputHandler getInstance(){ 33 | return INSTANCE; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/config/ModMenu.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.config; 2 | 3 | import com.terraformersmc.modmenu.api.ConfigScreenFactory; 4 | import com.terraformersmc.modmenu.api.ModMenuApi; 5 | 6 | public class ModMenu implements ModMenuApi { 7 | @Override 8 | public ConfigScreenFactory getModConfigScreenFactory() { 9 | return (screen)->{ 10 | ConfigUi ui = new ConfigUi(); 11 | ui.setParent(screen); 12 | return ui; 13 | }; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/features_list/AutoMending.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.features_list; 2 | 3 | import com.zxy.wuhuclient.Utils.InventoryUtils; 4 | import com.zxy.wuhuclient.config.Configs; 5 | import net.minecraft.client.network.ClientPlayerEntity; 6 | import net.minecraft.enchantment.Enchantments; 7 | import net.minecraft.item.ItemStack; 8 | import net.minecraft.screen.ScreenHandler; 9 | import net.minecraft.screen.slot.SlotActionType; 10 | 11 | import static com.zxy.wuhuclient.Utils.InventoryUtils.client; 12 | 13 | 14 | public class AutoMending { 15 | public static final AutoMending AUTO_MENDING = new AutoMending(); 16 | private boolean patching = false; 17 | private int tempSlot = -1; 18 | public int tick = 1; 19 | 20 | public void mending(){ 21 | ClientPlayerEntity player = client.player; 22 | if(player == null) return; 23 | 24 | ScreenHandler sc = player.currentScreenHandler; 25 | ItemStack offHandStack = player.getOffHandStack(); 26 | if(patching){ 27 | if(!offHandStack.isDamaged() && InventoryUtils.getEnchantmentLevel(offHandStack,Enchantments.MENDING) > 0) restoresSlot(); 28 | else return; 29 | } 30 | for (int i = 0; i < sc.slots.size(); i++) { 31 | if (sc.slots.get(i).getStack() == player.getMainHandStack()) continue; 32 | ItemStack copy = sc.slots.get(i).getStack().copy(); 33 | if ( 34 | i <= 8 || 35 | copy.isEmpty() || 36 | sc.slots.get(i).getStack() == player.getOffHandStack() || 37 | InventoryUtils.getEnchantmentLevel(copy, Enchantments.MENDING) <= 0 || 38 | !copy.isDamaged()) 39 | continue; 40 | switchSlot(sc,i); 41 | patching = true; 42 | tempSlot = i; 43 | break; 44 | } 45 | } 46 | public void tick(){ 47 | if(!Configs.AUTO_MENDING.getBooleanValue() || !isPlayerScreenHandler()) return; 48 | if(tick == 0) mending(); 49 | 50 | if (patching) { 51 | tick++; 52 | if(tick % 30 == 0 ) { 53 | restoresSlot(); 54 | patching = false; 55 | } 56 | } 57 | 58 | } 59 | private void restoresSlot(){ 60 | if(tempSlot != -1 && client.player != null){ 61 | switchSlot(client.player.currentScreenHandler,tempSlot); 62 | tempSlot = -1; 63 | } 64 | } 65 | private void switchSlot(ScreenHandler sc,int i){ 66 | client.interactionManager.clickSlot(sc.syncId, i, 40, SlotActionType.SWAP, client.player); 67 | } 68 | 69 | public boolean isPlayerScreenHandler(){ 70 | return client.player.currentScreenHandler.equals(client.player.playerScreenHandler); 71 | } 72 | 73 | private AutoMending(){} 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/features_list/CloseTheContainerAfterOpening.java: -------------------------------------------------------------------------------- 1 | // 2 | // Source code recreated from a .class file by IntelliJ IDEA 3 | // (powered by FernFlower decompiler) 4 | // 5 | 6 | package com.zxy.wuhuclient.features_list; 7 | 8 | import com.zxy.wuhuclient.Utils.InventoryUtils; 9 | import com.zxy.wuhuclient.Utils.ZxyUtils; 10 | import java.util.LinkedList; 11 | import java.util.List; 12 | import java.util.Objects; 13 | import java.util.Set; 14 | 15 | import net.minecraft.client.network.ClientPlayerEntity; 16 | import net.minecraft.util.math.BlockPos; 17 | 18 | import static com.zxy.wuhuclient.Utils.InventoryUtils.canOpenInv; 19 | 20 | public class CloseTheContainerAfterOpening { 21 | static LinkedList pos = new LinkedList(); 22 | public static int step = 0; 23 | 24 | public CloseTheContainerAfterOpening() { 25 | } 26 | 27 | private static void addPos() { 28 | List blockPos = ZxyUtils.siftBlock(",inv").stream().filter(InventoryUtils::canOpenInv).toList(); 29 | pos.addAll(blockPos); 30 | } 31 | 32 | public static void start() { 33 | if (step == 0) { 34 | SyncInventory.getReadyColor(); 35 | addPos(); 36 | if (pos.isEmpty()) return; 37 | SyncInventory.highlightPosList.addAll(pos); 38 | step = 1; 39 | } else { 40 | step = 0; 41 | LinkedList var10000 = pos; 42 | Set var10001 = SyncInventory.highlightPosList; 43 | Objects.requireNonNull(var10001); 44 | var10000.forEach(var10001::remove); 45 | pos.clear(); 46 | } 47 | 48 | } 49 | 50 | public static void step() { 51 | if (pos != null) { 52 | switch (step) { 53 | case 1: 54 | for(BlockPos po : pos) { 55 | if (SyncInventory.openInv(po, false)) { 56 | SyncInventory.highlightPosList.remove(po); 57 | pos.remove(po); 58 | step = 2; 59 | break; 60 | } 61 | } 62 | 63 | ZxyUtils.actionBar("剩余 " + pos.size() + " 个需要打开的容器,再次按下快捷键取消"); 64 | break; 65 | case 2: 66 | ClientPlayerEntity player = Synthesis.client.player; 67 | if (player != null) { 68 | player.closeHandledScreen(); 69 | } 70 | 71 | step = 1; 72 | if (pos.isEmpty()) { 73 | step = 0; 74 | } 75 | } 76 | 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/features_list/EasyPlaceFix.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.features_list; 2 | 3 | import com.zxy.wuhuclient.mixin.masa.WorldUtilsAccessor; 4 | import fi.dy.masa.litematica.config.Configs; 5 | import fi.dy.masa.malilib.gui.Message; 6 | import fi.dy.masa.malilib.util.InfoUtils; 7 | import fi.dy.masa.malilib.util.MessageOutputType; 8 | import net.minecraft.client.MinecraftClient; 9 | 10 | public final class EasyPlaceFix { 11 | public static boolean isPlacingWithEasyPlace = false; 12 | 13 | private EasyPlaceFix() { 14 | } 15 | 16 | public static boolean handleEasyPlaceRestriction(MinecraftClient mc) { 17 | boolean cancel = WorldUtilsAccessor.invokePlacementRestrictionInEffect(mc); 18 | 19 | if (cancel) { 20 | MessageOutputType type = (MessageOutputType) Configs.Generic.PLACEMENT_RESTRICTION_WARN.getOptionListValue(); 21 | 22 | if (type == MessageOutputType.MESSAGE) { 23 | InfoUtils.showGuiOrInGameMessage(Message.MessageType.WARNING, "litematica.message.easy_place_fail"); 24 | } else if (type == MessageOutputType.ACTIONBAR) { 25 | InfoUtils.printActionbarMessage("litematica.message.easy_place_fail"); 26 | } 27 | } 28 | 29 | return cancel; 30 | } 31 | } -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/features_list/QuickClickSlot.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.features_list; 2 | 3 | 4 | import net.minecraft.entity.player.PlayerInventory; 5 | import net.minecraft.screen.CraftingScreenHandler; 6 | import net.minecraft.screen.ScreenHandler; 7 | import net.minecraft.screen.slot.SlotActionType; 8 | 9 | 10 | import static com.zxy.wuhuclient.Utils.ZxyUtils.getPlayer; 11 | import static com.zxy.wuhuclient.WuHuClientMod.*; 12 | 13 | public class QuickClickSlot { 14 | 15 | public static void clickLastSlot() { 16 | getPlayer().ifPresent(clientPlayer -> { 17 | ScreenHandler sc = clientPlayer.currentScreenHandler; 18 | if (clientPlayer.currentScreenHandler.equals(clientPlayer.playerScreenHandler)) return; 19 | for (int i = 0; i < sc.slots.size(); i++) { 20 | if (sc.slots.get(i).inventory instanceof PlayerInventory && i > 0) { 21 | if (sc instanceof CraftingScreenHandler) i = 1; 22 | client.interactionManager.clickSlot(sc.syncId, i-1, 0, SlotActionType.QUICK_MOVE, client.player); 23 | return; 24 | } 25 | } 26 | 27 | //下面的代码在砂轮下不行 28 | // int size = sc.slots.get(0).inventory.size(); 29 | // client.interactionManager.clickSlot(sc.syncId, size-1, 0, SlotActionType.QUICK_MOVE, client.player); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/features_list/QuickFirework.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.features_list; 2 | 3 | import com.zxy.wuhuclient.Utils.ZxyUtils; 4 | import com.zxy.wuhuclient.WuHuClientMod; 5 | import net.minecraft.client.network.ClientPlayerEntity; 6 | 7 | import net.minecraft.item.FireworkRocketItem; 8 | import net.minecraft.item.ItemStack; 9 | import net.minecraft.nbt.NbtCompound; 10 | import net.minecraft.screen.ScreenHandler; 11 | import net.minecraft.screen.slot.Slot; 12 | import net.minecraft.screen.slot.SlotActionType; 13 | import net.minecraft.util.Hand; 14 | import net.minecraft.util.collection.DefaultedList; 15 | import java.util.List; 16 | //#if MC > 12004 17 | import net.minecraft.component.DataComponentTypes; 18 | import net.minecraft.component.type.FireworksComponent; 19 | import net.minecraft.component.type.FireworkExplosionComponent; 20 | //#else 21 | //$$ 22 | //#endif 23 | 24 | import static com.zxy.wuhuclient.WuHuClientMod.*; 25 | //快捷烟花 在飞行时按下快捷键可以从背包中拿出烟花并使用,然后还原副手物品 26 | //TODO 从盒子中取出烟花 27 | public class QuickFirework { 28 | 29 | public static void accelerated(){ 30 | ClientPlayerEntity player = client.player; 31 | if (player == null || !player.isGliding()) return; 32 | ScreenHandler sc = player.currentScreenHandler; 33 | DefaultedList slots = sc.slots; 34 | for (int i = 0; i < slots.size(); i++) { 35 | ItemStack stack = slots.get(i).getStack(); 36 | //#if MC > 12004 37 | FireworksComponent fireworksComponent = stack.get(DataComponentTypes.FIREWORKS); 38 | if (fireworksComponent != null && fireworksComponent.explosions().isEmpty()) { 39 | interactItem(sc,i); 40 | return; 41 | } 42 | //#else 43 | //$$ NbtCompound nbtCompound = stack.getSubNbt("Fireworks"); 44 | //$$ if(nbtCompound != null && nbtCompound.getList("Explosions", 10).isEmpty()){ 45 | //$$ interactItem(sc,i); 46 | //$$ return; 47 | //$$ } 48 | //#endif 49 | } 50 | } 51 | public static void interactItem(ScreenHandler sc , int i) { 52 | client.interactionManager.clickSlot(sc.syncId, i, 40, SlotActionType.SWAP, client.player); 53 | //#if MC > 11802 54 | client.interactionManager.interactItem(client.player, Hand.OFF_HAND); 55 | //#else 56 | //$$ client.interactionManager.interactItem(client.player,client.world, Hand.OFF_HAND); 57 | //#endif 58 | client.interactionManager.clickSlot(sc.syncId, i, 40, SlotActionType.SWAP, client.player); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/features_list/SyncInventory.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.features_list; 2 | 3 | import com.zxy.wuhuclient.Utils.HighlightBlockRenderer; 4 | import com.zxy.wuhuclient.Utils.InventoryUtils; 5 | import com.zxy.wuhuclient.Utils.ScreenManagement; 6 | import net.minecraft.block.*; 7 | import net.minecraft.block.entity.BlockEntity; 8 | import net.minecraft.block.entity.ShulkerBoxBlockEntity; 9 | import net.minecraft.entity.mob.ShulkerEntity; 10 | import net.minecraft.item.ItemStack; 11 | import net.minecraft.registry.Registries; 12 | import net.minecraft.screen.ScreenHandler; 13 | import net.minecraft.screen.slot.Slot; 14 | import net.minecraft.screen.slot.SlotActionType; 15 | import net.minecraft.text.Text; 16 | import net.minecraft.util.Hand; 17 | import net.minecraft.util.collection.DefaultedList; 18 | import net.minecraft.util.hit.BlockHitResult; 19 | import net.minecraft.util.hit.HitResult; 20 | import net.minecraft.util.math.BlockPos; 21 | import net.minecraft.util.math.Direction; 22 | import net.minecraft.util.math.Vec3d; 23 | import java.util.*; 24 | 25 | import static com.zxy.wuhuclient.Utils.InventoryUtils.equalsItem; 26 | import static com.zxy.wuhuclient.Utils.ZxyUtils.siftBlock; 27 | import static com.zxy.wuhuclient.WuHuClientMod.client; 28 | import static com.zxy.wuhuclient.config.Configs.*; 29 | import static net.minecraft.block.ShulkerBoxBlock.FACING; 30 | 31 | public class SyncInventory { 32 | public static LinkedList syncPosList = new LinkedList<>(); 33 | public static ArrayList targetBlockInv; 34 | public static int num = 0; 35 | static BlockPos blockPos = null; 36 | static String syncInventoryId = "syncInventory"; 37 | static Set highlightPosList = new LinkedHashSet<>(); 38 | static Map targetItemsCount = new HashMap<>(); 39 | static Map playerItemsCount = new HashMap<>(); 40 | 41 | public static void getReadyColor() { 42 | HighlightBlockRenderer.createHighlightBlockList(syncInventoryId,SYNC_INVENTORY_COLOR); 43 | highlightPosList = HighlightBlockRenderer.getHighlightBlockPosList(syncInventoryId); 44 | } 45 | 46 | public static void startOrOffSyncInventory() { 47 | getReadyColor(); 48 | if (client.crosshairTarget != null && client.crosshairTarget.getType() == HitResult.Type.BLOCK && syncPosList.isEmpty()) { 49 | BlockPos pos = ((BlockHitResult) client.crosshairTarget).getBlockPos(); 50 | BlockState blockState = client.world.getBlockState(pos); 51 | Block block = null; 52 | if (client.world != null) { 53 | block = client.world.getBlockState(pos).getBlock(); 54 | BlockEntity blockEntity = client.world.getBlockEntity(pos); 55 | boolean inventory = InventoryUtils.isInventory(pos); 56 | try { 57 | if ((inventory && blockState.createScreenHandlerFactory(client.world,pos) == null) || 58 | (blockEntity instanceof ShulkerBoxBlockEntity entity && 59 | //#if MC > 12004 && MC < 12104 60 | //$$ !client.world.isSpaceEmpty(ShulkerEntity.calculateBoundingBox(1.0F, blockState.get(FACING), 0.0F, 0.5F).offset(pos).contract(1.0E-6)) && 61 | //#elseif MC >= 12104 62 | !client.world.isSpaceEmpty(ShulkerEntity.calculateBoundingBox(1.0F, blockState.get(FACING), 0.0F, 0.5F, pos.toBottomCenterPos()).offset(pos).contract(1.0E-6)) && 63 | //#else 64 | //$$ !client.world.isSpaceEmpty(ShulkerEntity.calculateBoundingBox(blockState.get(FACING), 0.0f, 0.5f).offset(pos).contract(1.0E-6)) && 65 | //#endif 66 | entity.getAnimationStage() == ShulkerBoxBlockEntity.AnimationStage.CLOSED)) { 67 | client.inGameHud.setOverlayMessage(Text.of("容器无法打开"), false); 68 | return; 69 | }else if(!inventory) { 70 | client.inGameHud.setOverlayMessage(Text.of("这不是容器 无法同步"), false); 71 | return; 72 | } 73 | } catch (Exception e) { 74 | client.inGameHud.setOverlayMessage(Text.of("这不是容器 无法同步"), false); 75 | return; 76 | } 77 | } 78 | String blockName = Registries.BLOCK.getId(block).toString(); 79 | syncPosList.addAll(siftBlock(blockName)); 80 | if (!syncPosList.isEmpty()) { 81 | if (client.player == null) return; 82 | client.player.closeHandledScreen(); 83 | if (!openInv(pos, false)) { 84 | syncPosList = new LinkedList<>(); 85 | return; 86 | } 87 | highlightPosList.addAll(syncPosList); 88 | ScreenManagement.closeScreen++; 89 | num = 1; 90 | } 91 | } else if(!syncPosList.isEmpty()){ 92 | highlightPosList.removeAll(syncPosList); 93 | syncPosList = new LinkedList<>(); 94 | if (client.player != null) client.player.closeScreen(); 95 | num = 0; 96 | client.inGameHud.setOverlayMessage(Text.of("已取消同步"), false); 97 | } 98 | } 99 | 100 | public static boolean openInv(BlockPos pos, boolean ignoreThePrompt) { 101 | if (client.player != null && client.player.getEyePos().squaredDistanceTo(Vec3d.ofCenter(pos)) > 25D) { 102 | if (!ignoreThePrompt) client.inGameHud.setOverlayMessage(Text.of("距离过远无法打开容器"), false); 103 | return false; 104 | } 105 | if (client.interactionManager != null) { 106 | //#if MC > 11802 107 | client.interactionManager.interactBlock(client.player, Hand.MAIN_HAND, new BlockHitResult(Vec3d.ofCenter(pos), Direction.DOWN, pos, false)); 108 | //#else 109 | //$$ client.interactionManager.interactBlock(client.player,client.world, Hand.MAIN_HAND,new BlockHitResult(Vec3d.ofCenter(pos), Direction.DOWN,pos,false)); 110 | //#endif 111 | return true; 112 | } else return false; 113 | } 114 | 115 | public static void itemsCount(Map itemsCount, ItemStack itemStack) { 116 | // 判断是否存在可合并的键 117 | Optional> entry = itemsCount.entrySet().stream() 118 | //#if MC > 12004 119 | .filter(e -> ItemStack.areItemsAndComponentsEqual(e.getKey(), itemStack)) 120 | //#else 121 | //$$ .filter(e -> ItemStack.canCombine(e.getKey(), itemStack)) 122 | //#endif 123 | .findFirst(); 124 | 125 | if (entry.isPresent()) { 126 | // 更新已有键对应的值 127 | Integer count = entry.get().getValue(); 128 | count += itemStack.getCount(); 129 | itemsCount.put(entry.get().getKey(), count); 130 | } else { 131 | // 添加新键值对 132 | itemsCount.put(itemStack, itemStack.getCount()); 133 | } 134 | } 135 | 136 | public static void syncInv() { 137 | switch (num) { 138 | case 1 -> { 139 | //按下热键后记录看向的容器 开始同步容器 只会触发一次 140 | targetBlockInv = new ArrayList<>(); 141 | targetItemsCount = new HashMap<>(); 142 | if (client.player != null && !client.player.currentScreenHandler.equals(client.player.playerScreenHandler)) { 143 | for (int i = 0; i < client.player.currentScreenHandler.slots.get(0).inventory.size(); i++) { 144 | ItemStack copy = client.player.currentScreenHandler.slots.get(i).getStack().copy(); 145 | itemsCount(targetItemsCount, copy); 146 | targetBlockInv.add(copy); 147 | } 148 | //上面如果不使用copy()在关闭容器后会使第一个元素号变该物品成总数 非常有趣... 149 | // System.out.println("???1 "+targetBlockInv.get(0).getCount()); 150 | client.player.closeHandledScreen(); 151 | // System.out.println("!!!1 "+targetBlockInv.get(0).getCount()); 152 | num = 2; 153 | } 154 | } 155 | case 2 -> { 156 | //打开列表中的容器 只要容器同步列表不为空 就会一直执行此处 157 | if (client.player == null) return; 158 | playerItemsCount = new HashMap<>(); 159 | client.inGameHud.setOverlayMessage(Text.of("剩余 " + syncPosList.size() + " 个容器. 再次按下快捷键取消同步"), false); 160 | if (!client.player.currentScreenHandler.equals(client.player.playerScreenHandler)) return; 161 | DefaultedList slots = client.player.playerScreenHandler.slots; 162 | slots.forEach(slot -> itemsCount(playerItemsCount, slot.getStack())); 163 | 164 | if (SYNC_INVENTORY_CHECK.getBooleanValue() && !targetItemsCount.entrySet().stream() 165 | .allMatch(target -> playerItemsCount.entrySet().stream() 166 | .anyMatch(player -> 167 | equalsItem(player.getKey(), target.getKey()) && target.getValue() <= player.getValue()))) 168 | 169 | return; 170 | 171 | 172 | for (BlockPos pos : syncPosList) { 173 | if (!openInv(pos, true)) continue; 174 | ScreenManagement.closeScreen++; 175 | blockPos = pos; 176 | num = 3; 177 | break; 178 | } 179 | if (syncPosList.isEmpty()) { 180 | num = 0; 181 | client.inGameHud.setOverlayMessage(Text.of("同步完成"), false); 182 | } 183 | } 184 | case 3 -> { 185 | //开始同步 在打开容器后触发 186 | ScreenHandler sc = client.player.currentScreenHandler; 187 | if (sc.equals(client.player.playerScreenHandler)) return; 188 | int size = Math.min(targetBlockInv.size(), sc.slots.get(0).inventory.size()); 189 | 190 | int times = 0; 191 | for (int i = 0; i < size; i++) { 192 | ItemStack item1 = sc.slots.get(i).getStack(); 193 | ItemStack item2 = targetBlockInv.get(i).copy(); 194 | int currNum = item1.getCount(); 195 | int tarNum = item2.getCount(); 196 | boolean same = equalsItem(item1, item2.copy()) && !item1.isEmpty(); 197 | if (equalsItem(item1, item2) && currNum == tarNum) continue; 198 | //不和背包交互 199 | if (same) { 200 | //有多 201 | while (currNum > tarNum) { 202 | client.interactionManager.clickSlot(sc.syncId, i, 0, SlotActionType.THROW, client.player); 203 | currNum--; 204 | } 205 | } else { 206 | //不同直接扔出 207 | client.interactionManager.clickSlot(sc.syncId, i, 1, SlotActionType.THROW, client.player); 208 | times++; 209 | } 210 | boolean thereAreItems = false; 211 | //背包交互 212 | for (int i1 = size; i1 < sc.slots.size(); i1++) { 213 | ItemStack stack = sc.slots.get(i1).getStack(); 214 | ItemStack currStack = sc.slots.get(i).getStack(); 215 | currNum = currStack.getCount(); 216 | boolean same2 = thereAreItems = equalsItem(item2, stack); 217 | if (same2 && !stack.isEmpty()) { 218 | int i2 = stack.getCount(); 219 | client.interactionManager.clickSlot(sc.syncId, i1, 0, SlotActionType.PICKUP, client.player); 220 | for (; currNum < tarNum && i2 > 0; i2--) { 221 | client.interactionManager.clickSlot(sc.syncId, i, 1, SlotActionType.PICKUP, client.player); 222 | currNum++; 223 | } 224 | client.interactionManager.clickSlot(sc.syncId, i1, 0, SlotActionType.PICKUP, client.player); 225 | } 226 | //这里判断没啥用,因为一个游戏刻操作背包太多次.getStack().getCount()获取的数量不准确 下次一定优化, 227 | if (currNum != tarNum) times++; 228 | } 229 | if (!thereAreItems) times++; 230 | } 231 | if (times == 0) { 232 | syncPosList.remove(blockPos); 233 | highlightPosList.remove(blockPos); 234 | blockPos = null; 235 | } 236 | client.player.closeHandledScreen(); 237 | num = 2; 238 | } 239 | } 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/features_list/Synthesis.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.features_list; 2 | 3 | 4 | import com.zxy.wuhuclient.Utils.ScreenManagement; 5 | import com.zxy.wuhuclient.Utils.ZxyUtils; 6 | import com.zxy.wuhuclient.config.Configs; 7 | import com.zxy.wuhuclient.mixin.CraftingScreenHandlerMixin; 8 | import fi.dy.masa.itemscroller.recipes.CraftingHandler; 9 | import fi.dy.masa.itemscroller.recipes.RecipePattern; 10 | import fi.dy.masa.itemscroller.recipes.RecipeStorage; 11 | import fi.dy.masa.malilib.util.GuiUtils; 12 | import fi.dy.masa.malilib.util.InventoryUtils; 13 | import net.fabricmc.loader.api.FabricLoader; 14 | import net.minecraft.block.BlockState; 15 | import net.minecraft.block.Blocks; 16 | import net.minecraft.client.MinecraftClient; 17 | import net.minecraft.client.gui.screen.ingame.HandledScreen; 18 | import net.minecraft.client.network.ClientPlayerEntity; 19 | import net.minecraft.client.world.ClientWorld; 20 | 21 | import net.minecraft.item.Item; 22 | import net.minecraft.item.ItemStack; 23 | import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket; 24 | import net.minecraft.recipe.*; 25 | 26 | 27 | import net.minecraft.screen.CraftingScreenHandler; 28 | import net.minecraft.screen.PlayerScreenHandler; 29 | import net.minecraft.screen.ScreenHandler; 30 | 31 | import net.minecraft.screen.slot.Slot; 32 | import net.minecraft.screen.slot.SlotActionType; 33 | import net.minecraft.server.world.ServerWorld; 34 | import net.minecraft.text.Text; 35 | import net.minecraft.util.Hand; 36 | import net.minecraft.util.collection.DefaultedList; 37 | import net.minecraft.util.hit.BlockHitResult; 38 | import net.minecraft.util.math.BlockPos; 39 | import net.minecraft.util.math.Direction; 40 | import net.minecraft.util.math.Vec3d; 41 | import net.minecraft.world.GameRules; 42 | 43 | //#if MC < 12001 44 | //$$ import net.minecraft.inventory.CraftingInventory; 45 | //#elseif MC == 12001 46 | //$$ import net.minecraft.inventory.RecipeInputInventory; 47 | //#else 48 | import net.minecraft.inventory.RecipeInputInventory; 49 | //#endif 50 | 51 | import java.util.*; 52 | import java.util.concurrent.atomic.AtomicReference; 53 | 54 | import static com.zxy.wuhuclient.Utils.InventoryUtils.isInventory; 55 | import static com.zxy.wuhuclient.Utils.InventoryUtils.refreshPlayerInventory; 56 | import static com.zxy.wuhuclient.Utils.ScreenManagement.closeScreen; 57 | 58 | 59 | public class Synthesis { 60 | public static boolean isLoadMod = FabricLoader.getInstance().isModLoaded("itemscroller"); 61 | public static MinecraftClient client = MinecraftClient.getInstance(); 62 | public static RecipePattern recipe = null; 63 | //1 丢出容器物品 2 合成 3 装箱 64 | public static int step = 0; 65 | //记录合成点击的方块位置 66 | public static BlockPos pos; 67 | // public static Set updatedSlot = new HashSet<>(); 68 | public static boolean invUpdated = false; 69 | public static int tick = 0; 70 | public static void tick() { 71 | // tick++; 72 | // tick %= Integer.MAX_VALUE; 73 | // if(step != 0) System.out.println(step); 74 | if(!Configs.SYNTHESIS.getBooleanValue()) return; 75 | if(invUpdated){ 76 | switch (step) { 77 | case 1 -> { 78 | dropInventory(); 79 | step = 0; 80 | } 81 | case 3 -> { 82 | storage(); 83 | step = 0; 84 | } 85 | } 86 | } 87 | if (storagePos != null && autoStorage && step != 1) { 88 | autoStorage(); 89 | if(step == 3) return; 90 | } 91 | if(step == 0 || step == 2) continueSynthesis(); 92 | } 93 | 94 | public static void onInventory() { 95 | if(!Configs.SYNTHESIS.getBooleanValue()) return; 96 | invUpdated = true; 97 | } 98 | 99 | public static void start(BlockPos pos) { 100 | tick = 0; 101 | if (!updateRecipe()) { 102 | client.inGameHud.setOverlayMessage(Text.of("当前快捷合成配方为空"), false); 103 | return; 104 | } 105 | // if (mc.crosshairTarget != null && mc.crosshairTarget.getType() == HitResult.Type.BLOCK) { 106 | // BlockPos pos = ((BlockHitResult) mc.crosshairTarget).getBlockPos(); 107 | if (client.world != null) { 108 | BlockState blockState = client.world.getBlockState(pos); 109 | if (blockState.isOf(Blocks.CRAFTING_TABLE)) { 110 | //工作台合成 111 | // step = 2; 112 | Synthesis.pos = pos; 113 | return; 114 | } 115 | if (!isInventory(pos)) { 116 | //背包合成 117 | if (recipe.getRecipeItems().length == 4) { 118 | // step = 2; 119 | Synthesis.pos = pos; 120 | } 121 | return; 122 | } 123 | if (client.player.isSneaking()) { 124 | client.inGameHud.setOverlayMessage(Text.of("合成取物已标记"), false); 125 | autoDrop = true; 126 | }else{ 127 | autoDrop = false; 128 | } 129 | if(closeScreen != 0) return; 130 | dropPos = pos; 131 | dropStart(); 132 | } 133 | // } 134 | } 135 | 136 | public static BlockPos dropPos; 137 | static boolean autoDrop; 138 | static void dropStart(){ 139 | if(closeScreen != 0 || !isInventory(dropPos) || !updateRecipe()) return; 140 | step = 1; 141 | closeScreen = 1; 142 | invUpdated = false; 143 | if(!dropPos.isWithinDistance(client.player.getPos(),5)){ 144 | dropPos = null; 145 | return; 146 | } 147 | ZxyUtils.setShift(false); 148 | useBlock(dropPos); 149 | } 150 | public static void useBlock(BlockPos pos){ 151 | //#if MC > 11802 152 | client.interactionManager.interactBlock(client.player, Hand.MAIN_HAND, new BlockHitResult(new Vec3d(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5), Direction.UP, pos, false)); 153 | //#else 154 | //$$ client.interactionManager.interactBlock(client.player,client.world, Hand.MAIN_HAND, new BlockHitResult(new Vec3d(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5), Direction.UP, pos, false)); 155 | //#endif 156 | } 157 | private static Map must = new HashMap<>(); 158 | public static boolean isSynthesis(){ 159 | if (!updateRecipe()) return false; 160 | ItemStack[] recipeItems = recipe.getRecipeItems(); 161 | 162 | Map recipeMap = new HashMap<>(); 163 | must = new HashMap<>(); 164 | for (ItemStack recipeItem : recipeItems) { 165 | if (recipeItem.isEmpty()) continue; 166 | Item item = recipeItem.getItem(); 167 | if (must.containsKey(item)) { 168 | must.put(item, must.get(item) + recipeItem.getCount()); 169 | } else { 170 | must.put(item, recipeItem.getCount()); 171 | } 172 | 173 | recipeMap.put(item, 0); 174 | } 175 | for (Slot slot : client.player.currentScreenHandler.slots) { 176 | ItemStack stack = slot.getStack(); 177 | //#if MC > 12004 178 | 179 | if (stack.isEmpty() || stack.getComponents().isEmpty()) continue; 180 | //#else 181 | //$$ if (stack.isEmpty() || stack.hasNbt()) continue; 182 | //#endif 183 | recipeMap.forEach((k, v) -> { 184 | int num = stack.getMaxCount() == 1 ? 0 : 1; 185 | if (stack.getItem().equals(k)) recipeMap.put(k, v + (stack.getCount() - num)); 186 | }); 187 | } 188 | AtomicReference result = new AtomicReference<>(true); 189 | recipeMap.forEach((k, v) -> { 190 | // System.out.println(k + "\t" + v); 191 | // System.out.println(must.get(k)); 192 | if (v < must.get(k)) { 193 | result.set(false); 194 | // System.out.println("000"); 195 | return; 196 | } 197 | }); 198 | // if(!result.get() && dropPos != null && Configs.AUTO_DROP.getBooleanValue()) { 199 | if(!result.get() && dropPos != null && autoDrop && closeScreen <= 0) { 200 | // client.player.closeHandledScreen(); 201 | dropStart(); 202 | } 203 | return result.get(); 204 | } 205 | 206 | public static boolean satisfyCraft(){ 207 | if (ScreenManagement.screen instanceof HandledScreen gui) { 208 | Slot slot = CraftingHandler.getFirstCraftingOutputSlotForGui(gui); 209 | fi.dy.masa.itemscroller.util.InventoryUtils.updateCraftingOutputSlot(slot); 210 | ItemStack stack = slot.getStack(); 211 | return !stack.isEmpty() && stack.getItem().equals(Synthesis.recipe.getResult().getItem()); 212 | } 213 | return false; 214 | } 215 | 216 | public static void synthesis2(){ 217 | client.inGameHud.setOverlayMessage(Text.of("合成中..."), false); 218 | if(!pos.isWithinDistance(client.player.getPos(),5)){ 219 | client.inGameHud.setOverlayMessage(Text.of("工作台或标记的方块超出范围,已重置。请再次点击开始合成"), false); 220 | pos = null; 221 | return; 222 | } 223 | if(!isSynthesis()) return; 224 | 225 | ClientPlayerEntity player = client.player; 226 | ScreenHandler sc = player.currentScreenHandler; 227 | if (sc.equals(player.playerScreenHandler)) return; 228 | 229 | ItemStack[] recipeItems = recipe.getRecipeItems(); 230 | // int[] playerInv = new int[sc.slots.size()]; 231 | 232 | int[] recInv = new int[recipeItems.length]; 233 | // for (int i = 0; i < recInv.length; i++) { 234 | // recInv[i] = sc.slots.get(i+1).getStack().getCount(); 235 | // } 236 | 237 | for (int i = recipeItems.length+1; i < sc.slots.size(); i++) { 238 | ItemStack stack = sc.slots.get(i).getStack().copy(); 239 | if (stack.isEmpty() || (stack.getMaxCount() != 1 && stack.getCount() == 1)) continue; 240 | if (Arrays.stream(recipeItems).noneMatch(rec -> InventoryUtils.areStacksEqual(rec,stack))) continue; 241 | 242 | int stackCount = stack.getCount()-1; 243 | int cursorStackCount = stack.getCount()-1; 244 | client.interactionManager.clickSlot(sc.syncId, -999, 0, SlotActionType.PICKUP, player); 245 | client.interactionManager.clickSlot(sc.syncId, i, 0, SlotActionType.PICKUP, player); 246 | client.interactionManager.clickSlot(sc.syncId, i, 1, SlotActionType.PICKUP, player); 247 | client.interactionManager.clickSlot(sc.syncId, -999, 0, SlotActionType.QUICK_CRAFT, client.player); 248 | 249 | int skip = 0; 250 | int craft = 0; 251 | ArrayList numArr = new ArrayList<>(); 252 | for (int i1 = 1; i1 <= recipeItems.length; i1++) { 253 | ItemStack stack1 = sc.slots.get(i1).getStack(); 254 | if (craft >= stackCount) break; 255 | if(!InventoryUtils.areStacksEqual(stack,recipeItems[i1-1])) continue; 256 | 257 | if (recInv[i1-1] >= stack.getMaxCount()){ 258 | skip++; 259 | continue; 260 | } 261 | numArr.add(i1-1); 262 | craft++; 263 | client.interactionManager.clickSlot(sc.syncId, i1, 1, SlotActionType.QUICK_CRAFT, client.player); 264 | } 265 | client.interactionManager.clickSlot(sc.syncId, -999, 2, SlotActionType.QUICK_CRAFT, client.player); 266 | 267 | if(craft== 0){ 268 | client.interactionManager.clickSlot(sc.syncId, i, 0, SlotActionType.PICKUP, player); 269 | continue; 270 | } 271 | if(craft > cursorStackCount){ 272 | int craftCopy = craft; 273 | for (Integer integer : numArr) { 274 | recInv[integer] += 1; 275 | if(--craftCopy <= 0) break; 276 | } 277 | }else { 278 | for (Integer integer : numArr) { 279 | 280 | if(recInv[integer] + stackCount/craft >= stack.getMaxCount()){ 281 | int num = stack.getMaxCount() - recInv[integer]; 282 | cursorStackCount -= num; 283 | recInv[integer] += num; 284 | }else { 285 | cursorStackCount -= stackCount/craft; 286 | recInv[integer] += stackCount/craft; 287 | } 288 | } 289 | } 290 | if(cursorStackCount > 0){ 291 | client.interactionManager.clickSlot(sc.syncId, i, 0, SlotActionType.PICKUP, player); 292 | } 293 | 294 | if(skip == recipeItems.length) break; 295 | } 296 | // for (int i2 = 0; InventoryUtils.areStacksEqual(sc.slots.get(0).getStack(), recipe.getResult()) && i2 < 64; i2++) { 297 | for (int i2 = 1; satisfyCraft() && i2 < 64; i2++) { 298 | client.interactionManager.clickSlot(sc.syncId, 0, 1, SlotActionType.THROW, player); 299 | } 300 | ScreenManagement.screen = null; 301 | player.closeHandledScreen(); 302 | refreshPlayerInventory(); 303 | } 304 | 305 | public static void dropItem(ItemStack itemStack, boolean isPlayerInventory) { 306 | ClientPlayerEntity player = client.player; 307 | if (player == null) return; 308 | ScreenHandler sc = player.currentScreenHandler; 309 | int size = 0; 310 | if (isPlayerInventory && sc.equals(client.player.playerScreenHandler)) { 311 | size = sc.slots.size(); 312 | } else if (!isPlayerInventory && !sc.equals(player.playerScreenHandler)) { 313 | size = sc.slots.get(0).inventory.size(); 314 | } 315 | if (size == 0) return; 316 | for (int i = 0; i < size; i++) { 317 | if (InventoryUtils.areStacksEqual(sc.slots.get(i).getStack(), itemStack)) { 318 | client.interactionManager.clickSlot(sc.syncId, i, 1, SlotActionType.THROW, player); 319 | } 320 | } 321 | } 322 | 323 | public static void dropInventory() { 324 | if (!updateRecipe()) return; 325 | client = MinecraftClient.getInstance(); 326 | ClientPlayerEntity player; 327 | if (client.player == null) return; 328 | player = client.player; 329 | if (player.currentScreenHandler.equals(player.playerScreenHandler)) return; 330 | for (ItemStack recipeItem : recipe.getRecipeItems()) { 331 | dropItem(recipeItem, false); 332 | } 333 | player.closeHandledScreen(); 334 | } 335 | public static BlockPos storagePos = null; 336 | public static boolean autoStorage = false; 337 | 338 | public static void autoStorage() { 339 | if (client.player == null || !updateRecipe() || !isInventory(storagePos)) return; 340 | ClientPlayerEntity player = client.player; 341 | DefaultedList slots = player.currentScreenHandler.slots; 342 | if (storagePos != null && storagePos.isWithinDistance(player.getPos(), 5) && step != 3 && closeScreen <= 0) { 343 | if (slots.stream() 344 | .anyMatch(slot -> InventoryUtils.areStacksEqual(slot.getStack(), recipe.getResult()) && slot.getStack().getCount() > 1)) 345 | { 346 | // System.out.println("autoStorage"); 347 | closeScreen = 1; 348 | step = 3; 349 | invUpdated = false; 350 | ZxyUtils.setShift(false); 351 | useBlock(storagePos); 352 | } 353 | } 354 | } 355 | public static void storage() { 356 | if (!updateRecipe()) return; 357 | ClientPlayerEntity player = client.player; 358 | if (player == null) return; 359 | ScreenHandler sc = player.currentScreenHandler; 360 | if(sc.equals(player.playerScreenHandler)) return; 361 | DefaultedList slots = sc.slots; 362 | if (slots.stream() 363 | .limit(slots.get(0).inventory.size()) 364 | .allMatch(slot -> InventoryUtils.areStacksEqual(slot.getStack(), recipe.getResult()) 365 | && slot.getStack().getCount() >= slot.getStack().getMaxCount())) { 366 | client.inGameHud.setOverlayMessage(Text.of("合成助手: 该容器已满"), false); 367 | player.closeHandledScreen(); 368 | return; 369 | } 370 | //从玩家背包寻找合成物 371 | for (int i = slots.get(0).inventory.size(); i < slots.size(); i++) { 372 | ItemStack stack = slots.get(i).getStack(); 373 | if (InventoryUtils.areStacksEqual(stack, recipe.getResult()) && stack.getCount() > 1) { 374 | client.interactionManager.clickSlot(sc.syncId, i, 0, SlotActionType.PICKUP, player); 375 | client.interactionManager.clickSlot(sc.syncId, i, 1, SlotActionType.PICKUP, player); 376 | //检测容器中能放下的空位 377 | for (int i2 = 0; i2 < slots.get(0).inventory.size(); i2++) { 378 | if ((InventoryUtils.areStacksEqual(slots.get(i2).getStack(), recipe.getResult()) 379 | && slots.get(i2).getStack().getCount() <= slots.get(i2).getStack().getMaxCount()) 380 | || slots.get(i2).getStack().isEmpty() 381 | ) client.interactionManager.clickSlot(sc.syncId, i2, 0, SlotActionType.PICKUP, player); 382 | } 383 | if(!sc.getCursorStack().isEmpty()){ 384 | client.interactionManager.clickSlot(sc.syncId, i, 0, SlotActionType.PICKUP, player); 385 | client.interactionManager.clickSlot(sc.syncId, -999, 0, SlotActionType.PICKUP, player); 386 | } 387 | } 388 | } 389 | player.closeHandledScreen(); 390 | } 391 | 392 | private static boolean updateRecipe() { 393 | recipe = RecipeStorage.getInstance().getSelectedRecipe(); 394 | return !recipe.getResult().isEmpty(); 395 | } 396 | 397 | public static void continueSynthesis() { 398 | if (pos != null ) { 399 | ScreenHandler sc = client.player.currentScreenHandler; 400 | ItemStack[] recipeItems = recipe.getRecipeItems(); 401 | if (((recipeItems.length == 9 && !(sc instanceof CraftingScreenHandler)) || (recipeItems.length == 4 && !(sc instanceof PlayerScreenHandler)))) { 402 | if (recipeItems.length == 9 && sc instanceof PlayerScreenHandler && closeScreen <= 0) { 403 | if (client.world.getBlockState(pos).isAir()) return; 404 | // System.out.println("............."); 405 | closeScreen = 1; 406 | // tick = 0; 407 | step = 2; 408 | invUpdated = false; 409 | ZxyUtils.setShift(false); 410 | useBlock(pos); 411 | } else if (recipeItems.length == 4) { 412 | client.player.closeHandledScreen(); 413 | } 414 | }else if(invUpdated && step == 2) { 415 | synthesis2(); 416 | }else{ 417 | client.player.closeScreen(); 418 | } 419 | } 420 | } 421 | } 422 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/features_list/Test.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.features_list; 2 | 3 | import com.zxy.wuhuclient.config.Configs; 4 | import net.minecraft.client.MinecraftClient; 5 | 6 | public class Test { 7 | public static void tick(){ 8 | if(!Configs.TEST.getBooleanValue())return; 9 | MinecraftClient.getInstance().player.setVelocity(0,0,0); 10 | // mezz.jei.core.search.CombinedSearchables 11 | // ZombieVillagerEntity. 12 | // System.out.println(Items.STONE.asItem().getTranslationKey()); 13 | // System.out.println(Items.STONE.asItem().getName().getString().toLowerCase()); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/features_list/litematica_helper/Condition.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.features_list.litematica_helper; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | @Retention(RetentionPolicy.RUNTIME) 7 | public @interface Condition 8 | { 9 | /** 10 | * Define when the type of this condition. See {@link Type} for more information 11 | */ 12 | Type type() default Type.MOD; 13 | 14 | /** 15 | *
    16 | *
  • (type MOD): A mod id, e.g. "lithium" or "carpet" 17 | *
  • (type MIXIN): A full qualified mixin class name, e.g. "com.example.mod.mixins.FooBarMixin", 18 | *
  • (type TESTER): Unused
  • 19 | *
20 | */ 21 | String value() default ""; 22 | 23 | /** 24 | * The value is used only when type == MOD 25 | *

26 | * All possible version range requirements. The predicate syntax depends on the current mod loader platform 27 | *

28 | * The condition is satisfied when the testing version matches any versionPredicate, or no versionPredicate is given 29 | *

30 | * Examples (using fabric-like platforms syntax): 31 | *

    32 | *
  • ">=1.2.3": version >= 1.2.3
  • 33 | *
  • ">=1.2.3 <1.3": version in [1.2.3, 1.3)
  • 34 | *
  • [">=1.2.3 <1.3", ">=2.0"]: version in [1.2.3, 1.3), or version >= 2.0
  • 35 | *
36 | * Examples (using forge-like platforms syntax): 37 | *
    38 | *
  • "[1.2.3,)": version >= 1.2.3
  • 39 | *
  • "[1.2.3, 1.3)": version in [1.2.3, 1.3)
  • 40 | *
  • ["[1.2.3, 1.3)", "[2.0,)"]: version in [1.2.3, 1.3), or version >= 2.0
  • 41 | *
42 | */ 43 | String[] versionPredicates() default {}; 44 | 45 | 46 | enum Type 47 | { 48 | /** 49 | * Satisfies when the given mod presents, and its version satisfied the given {@link #versionPredicates} 50 | */ 51 | MOD, 52 | 53 | /** 54 | * Satisfies when the specified mixin class exists, and (if it has {@link Restriction}) its {@link Restriction} is satisfied 55 | *

56 | * Notes: Please make sure the class name you provide in {@link #value} is a valid mixin class from your mod, or the behavior might be undefined 57 | */ 58 | MIXIN, 59 | 60 | TESTER, 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/features_list/litematica_helper/LitematicaHelper.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.features_list.litematica_helper; 2 | 3 | import com.zxy.wuhuclient.Utils.HighlightBlockRenderer; 4 | import com.zxy.wuhuclient.config.Configs; 5 | import com.zxy.wuhuclient.mixin.masa.litematicahelper.MaterialListHudRendererAccessor; 6 | import fi.dy.masa.itemscroller.util.AccessorUtils; 7 | import fi.dy.masa.itemscroller.util.InventoryUtils; 8 | import fi.dy.masa.litematica.data.DataManager; 9 | import fi.dy.masa.litematica.materials.MaterialListBase; 10 | import fi.dy.masa.litematica.materials.MaterialListEntry; 11 | import fi.dy.masa.litematica.materials.MaterialListHudRenderer; 12 | import fi.dy.masa.litematica.materials.MaterialListUtils; 13 | import fi.dy.masa.malilib.gui.GuiBase; 14 | import fi.dy.masa.malilib.gui.Message; 15 | import fi.dy.masa.malilib.util.GuiUtils; 16 | import fi.dy.masa.malilib.util.InfoUtils; 17 | import net.minecraft.block.Block; 18 | import net.minecraft.block.ShulkerBoxBlock; 19 | import net.minecraft.client.gui.screen.ingame.HandledScreen; 20 | import net.minecraft.client.network.ClientPlayerEntity; 21 | import net.minecraft.client.world.ClientWorld; 22 | import net.minecraft.entity.player.PlayerInventory; 23 | import net.minecraft.item.ItemStack; 24 | import net.minecraft.screen.ScreenHandler; 25 | import net.minecraft.screen.slot.Slot; 26 | import net.minecraft.util.Identifier; 27 | import net.minecraft.util.math.BlockPos; 28 | 29 | //#if MC > 11904 30 | import red.jackf.chesttracker.api.memory.CommonKeys; 31 | import red.jackf.chesttracker.api.memory.Memory; 32 | import red.jackf.chesttracker.impl.memory.MemoryBankAccessImpl; 33 | import red.jackf.chesttracker.impl.memory.MemoryBankImpl; 34 | import red.jackf.whereisit.api.SearchRequest; 35 | import red.jackf.whereisit.client.api.events.SearchRequestPopulator; 36 | //#else 37 | //$$ import red.jackf.chesttracker.memory.Memory; 38 | //$$ import red.jackf.chesttracker.memory.MemoryDatabase; 39 | //#endif 40 | 41 | import java.util.*; 42 | import java.util.stream.Collectors; 43 | 44 | import static com.zxy.wuhuclient.WuHuClientMod.client; 45 | import static com.zxy.wuhuclient.config.Configs.LITEMATICA_HELPER_TIPS; 46 | 47 | public class LitematicaHelper { 48 | //投影施工助手 49 | //开启后选区预施工范围 可以以投影为目标 50 | //统计材料 读取箱子追踪库存 51 | //高亮箱子 52 | //点击高亮的箱子后拿出对应物品 53 | 54 | 55 | //待施工 56 | //按住shift点击箱子放回选区内已完成的多余物品 57 | // 58 | // 59 | public String litematicaHelper = "litematicaHelper"; 60 | public static LitematicaHelper instance = new LitematicaHelper(); 61 | public LitematicaHelper(){ 62 | HighlightBlockRenderer.createHighlightBlockList(litematicaHelper, Configs.LITEMATICA_HELPER_COLOR); 63 | } 64 | public Map> inventoryList = new HashMap<>(); 65 | 66 | public static void process(ScreenHandler container) { 67 | ClientPlayerEntity player = client.player; 68 | if (player == null) return; 69 | HandledScreen containerScreen; 70 | if(client.currentScreen instanceof HandledScreen){ 71 | containerScreen = (HandledScreen)client.currentScreen; 72 | }else return; 73 | List playerInvSlots = container.slots.stream().filter(slot -> slot.inventory instanceof PlayerInventory).collect(Collectors.toList()); 74 | List containerInvSlots = container.slots.stream().filter(slot -> areSlotsInSameInventory(slot, container.slots.get(0),false)).collect(Collectors.toList()); 75 | 76 | MaterialListBase materialList = DataManager.getMaterialList(); 77 | if (materialList != null) { 78 | MaterialListHudRendererAccessor hudRendererAccessor = (MaterialListHudRendererAccessor) materialList.getHudRenderer(); 79 | String guiTitle = containerScreen.getTitle().getString(); 80 | 81 | // refresh before operation starts to make sure it's up-to-date 82 | MaterialListUtils.updateAvailableCounts(materialList.getMaterialsAll(), player); 83 | List missingOnly = materialList.getMaterialsMissingOnly(true); 84 | 85 | boolean takenSomething = false; 86 | for (MaterialListEntry entry : missingOnly) { 87 | int missing = entry.getCountMissing() * materialList.getMultiplier() - entry.getCountAvailable(); 88 | ItemStack stack = entry.getStack(); 89 | if (missing <= 0) { 90 | continue; 91 | } 92 | int totalTaken = 0; 93 | for (Slot slot : containerInvSlots) { 94 | if (InventoryUtils.areStacksEqual(stack, slot.getStack())) { 95 | int stackAmount = slot.getStack().getCount(); 96 | moveToPlayerInventory(containerScreen, playerInvSlots, slot, Math.min(missing, stackAmount)); 97 | int moved = stackAmount - slot.getStack().getCount(); 98 | missing -= moved; 99 | totalTaken += moved; 100 | if (moved == 0) { 101 | break; 102 | } 103 | } 104 | } 105 | if (totalTaken > 0) { 106 | 107 | takenSomething = true; 108 | log(Message.MessageType.INFO, "从%1$s中收集了:", guiTitle); 109 | 110 | String missingColor = missing == 0 ? GuiBase.TXT_GREEN : GuiBase.TXT_GOLD; 111 | String stackName = stack.getRarity(). 112 | //#if MC > 12004 113 | getFormatting() 114 | //#else 115 | //$$ formatting 116 | //#endif 117 | + stack.getName().getString() + GuiBase.TXT_RST; 118 | 119 | log( 120 | Message.MessageType.INFO, 121 | "- %1$s 个%2$s,仍需 %3$s", 122 | GuiBase.TXT_GOLD + totalTaken + GuiBase.TXT_RST, 123 | stackName, 124 | missingColor + hudRendererAccessor.invokeGetFormattedCountString(missing, stack.getMaxCount()) + GuiBase.TXT_RST 125 | ); 126 | 127 | } 128 | } 129 | if (!takenSomething) log(Message.MessageType.INFO, "未在%1$s中收集任何材料列表中需要的物品", guiTitle); 130 | 131 | // refresh after operation ends 132 | hudRendererAccessor.setLastUpdateTime(-1); 133 | } else { 134 | log(Message.MessageType.WARNING, "没有生效的材料列表"); 135 | } 136 | player.closeHandledScreen(); 137 | } 138 | 139 | private static void moveToPlayerInventory(HandledScreen containerScreen, List playerInvSlots, Slot fromSlot, int amount) { 140 | ItemStack stack = fromSlot.getStack().copy(); 141 | if (amount == stack.getCount()) { 142 | InventoryUtils.shiftClickSlot(containerScreen, fromSlot.id); 143 | return; 144 | } else if (amount > stack.getCount()) { 145 | return; 146 | } 147 | // ensure amount <= stack.getCount() 148 | 149 | InventoryUtils.leftClickSlot(containerScreen, fromSlot.id); 150 | // reversed iterating to match vanilla shift-click item putting order 151 | for (int idx = playerInvSlots.size() - 1; idx >= 0; idx--) { 152 | Slot slot = playerInvSlots.get(idx); 153 | int clickAmount = 0; 154 | if (slot.hasStack() && InventoryUtils.areStacksEqual(slot.getStack(), stack)) { 155 | ItemStack invStack = slot.getStack(); 156 | clickAmount = Math.min(invStack.getMaxCount() - invStack.getCount(), amount); 157 | } else if (!slot.hasStack()) { 158 | clickAmount = amount; 159 | } 160 | for (int i = 0; i < clickAmount; i++) InventoryUtils.rightClickSlot(containerScreen, slot.id); 161 | amount -= clickAmount; 162 | if (amount == 0) { 163 | break; 164 | } 165 | } 166 | InventoryUtils.leftClickSlot(containerScreen, fromSlot.id); 167 | 168 | } 169 | 170 | private static void log(Message.MessageType type, String translationKey, Object... args) { 171 | if (!LITEMATICA_HELPER_TIPS.getBooleanValue()) return; 172 | InfoUtils.showGuiOrInGameMessage(type, translationKey, args); 173 | } 174 | 175 | private static boolean areSlotsInSameInventory(Slot slot1, Slot slot2, boolean treatHotbarAsDifferent) { 176 | if (slot1.inventory != slot2.inventory) { 177 | return false; 178 | } else if (treatHotbarAsDifferent && slot1.inventory instanceof PlayerInventory) { 179 | int index1 = AccessorUtils.getSlotIndex(slot1); 180 | int index2 = AccessorUtils.getSlotIndex(slot2); 181 | return index1 == 40 || index2 == 40 || index1 < 9 == index2 < 9; 182 | } else { 183 | return true; 184 | } 185 | } 186 | 187 | public void highlightInventoryBlock(){ 188 | ClientPlayerEntity player = client.player; 189 | if (!Configs.LITEMATICA_HELPER.getBooleanValue() || player == null) return; 190 | MaterialListBase materialList = DataManager.getMaterialList(); 191 | if (materialList == null) return; 192 | MaterialListUtils.updateAvailableCounts(materialList.getMaterialsAll(), player); 193 | MaterialListHudRenderer hudRenderer = materialList.getHudRenderer(); 194 | boolean b = hudRenderer.getShouldRenderCustom() && hudRenderer.shouldRenderInGuis(); 195 | List materialsMissingOnly = materialList.getMaterialsMissingOnly(!b); 196 | List list = new ArrayList<>(); 197 | for (MaterialListEntry materialListEntry : materialsMissingOnly) { 198 | ItemStack stack = materialListEntry.getStack(); 199 | list.addAll(searchChestTrackerMemory(stack)); 200 | } 201 | if (list.isEmpty()){ 202 | HighlightBlockRenderer.clear(litematicaHelper); 203 | return; 204 | } 205 | HighlightBlockRenderer.setPos(litematicaHelper,new HashSet<>(list.stream().distinct().toList())); 206 | } 207 | 208 | public List searchChestTrackerMemory(ItemStack itemStack){ 209 | List blockPos = new ArrayList<>(); 210 | ClientWorld world = client.world; 211 | if (world == null) return blockPos; 212 | Identifier registry = world.getRegistryKey().getValue(); 213 | //#if MC > 11904 214 | Map blockPosMemoryMap = memoriesSearch(registry, itemStack, MemoryBankAccessImpl.INSTANCE.getLoadedInternal().orElse(null)); 215 | if (blockPosMemoryMap == null) return blockPos; 216 | blockPos.addAll(blockPosMemoryMap.keySet()); 217 | 218 | //#else 219 | //$$ MemoryDatabase database = MemoryDatabase.getCurrent(); 220 | //$$ if (database == null) return blockPos; 221 | //$$ List list = database.findItems(itemStack, registry).stream().map(Memory::getPosition).distinct().toList(); 222 | //$$ blockPos.addAll(list); 223 | //#endif 224 | return blockPos; 225 | } 226 | 227 | //#if MC > 11904 228 | public Map memoriesSearch(Identifier key, ItemStack itemStack, MemoryBankImpl memoryBank) { 229 | if (key == null || itemStack == null) return null; 230 | ClientPlayerEntity player = client.player; 231 | if (player == null) return null; 232 | if (memoryBank != null && memoryBank.getMemories() != null && 233 | memoryBank.getMemories().get(key) != null && 234 | !CommonKeys.ENDER_CHEST_KEY.equals(key)) { 235 | SearchRequest searchRequest = new SearchRequest(); 236 | SearchRequestPopulator.addItemStack(searchRequest, itemStack, SearchRequestPopulator.Context.FAVOURITE); 237 | int range = memoryBank.getMetadata().getSearchSettings().searchRange; 238 | double rangeSquared = range == Integer.MAX_VALUE ? Integer.MAX_VALUE : range * range; 239 | 240 | Map itemsMap = new LinkedHashMap<>(); 241 | for (Map.Entry entry : memoryBank.getMemories().get(key).getMemories().entrySet()) { 242 | if (entry.getKey().getSquaredDistance(player.getPos()) > rangeSquared && range != Integer.MAX_VALUE) continue; 243 | if (entry.getValue().items().stream() 244 | .filter(item -> SearchRequest.check(item, searchRequest)) 245 | .anyMatch(item -> !((Block.getBlockFromItem(item.getItem())) instanceof ShulkerBoxBlock))) { 246 | itemsMap.put(entry.getKey(),entry.getValue()); 247 | } 248 | } 249 | return itemsMap; 250 | } 251 | return null; 252 | } 253 | //#else 254 | //$$ 255 | //#endif 256 | } 257 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/features_list/litematica_helper/Restriction.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.features_list.litematica_helper; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | /** 7 | * The restrictions to be satisfied in order to apply the annotated mixin 8 | */ 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface Restriction 11 | { 12 | /** 13 | * Enable only when all given conditions are satisfied, like the "depends" entry in "fabric.mod.json" 14 | */ 15 | Condition[] require() default {}; 16 | 17 | /** 18 | * Disable if any given condition is satisfied, like the "breaks" entry in "fabric.mod.json" 19 | * Has higher priority than field "require" 20 | */ 21 | Condition[] conflict() default {}; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/BlockMixin.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin; 2 | 3 | import net.minecraft.block.Block; 4 | import net.minecraft.block.BlockState; 5 | import net.minecraft.block.entity.BlockEntity; 6 | import net.minecraft.util.math.BlockPos; 7 | import net.minecraft.world.WorldAccess; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 12 | 13 | import static com.zxy.wuhuclient.Utils.ScreenManagement.closeScreen; 14 | import static com.zxy.wuhuclient.features_list.Synthesis.*; 15 | 16 | @Mixin(Block.class) 17 | public class BlockMixin { 18 | @Inject(at = @At("TAIL"),method = "dropStacks(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/WorldAccess;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/entity/BlockEntity;)V") 19 | private static void dropStacks(BlockState state, WorldAccess world, BlockPos pos, BlockEntity blockEntity, CallbackInfo ci){ 20 | if(!world.isClient()) return; 21 | if((step == 1 && pos.equals(dropPos)) || (step == 3 && (pos.equals(storagePos)))){ 22 | // System.out.println("onBreak " + step); 23 | closeScreen = 0; 24 | //加了这一行单机会崩溃!!!??? 25 | // if (client.player != null && !client.player.currentScreenHandler.equals(client.player.playerScreenHandler)) client.player.closeHandledScreen(); 26 | step = 0; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/ClientPlayNetworkHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin; 2 | 3 | import com.zxy.wuhuclient.Utils.InventoryUtils; 4 | import com.zxy.wuhuclient.config.Configs; 5 | import com.zxy.wuhuclient.features_list.AutoMending; 6 | import com.zxy.wuhuclient.features_list.CloseTheContainerAfterOpening; 7 | import com.zxy.wuhuclient.features_list.Synthesis; 8 | import net.fabricmc.api.EnvType; 9 | import net.fabricmc.api.Environment; 10 | import net.minecraft.client.network.ClientPlayNetworkHandler; 11 | import net.minecraft.client.network.ClientPlayerEntity; 12 | import net.minecraft.entity.ExperienceOrbEntity; 13 | import net.minecraft.network.packet.s2c.play.*; 14 | import org.spongepowered.asm.mixin.Mixin; 15 | import org.spongepowered.asm.mixin.injection.At; 16 | import org.spongepowered.asm.mixin.injection.Inject; 17 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 18 | 19 | import static com.zxy.wuhuclient.Utils.InventoryUtils.client; 20 | import static com.zxy.wuhuclient.Utils.InventoryUtils.switchInv; 21 | import static com.zxy.wuhuclient.features_list.SyncInventory.num; 22 | import static com.zxy.wuhuclient.features_list.SyncInventory.syncInv; 23 | 24 | @Mixin(value = ClientPlayNetworkHandler.class) 25 | @Environment(EnvType.CLIENT) 26 | public class ClientPlayNetworkHandlerMixin { 27 | @Inject(at = @At("TAIL"),method = "onInventory") 28 | public void onInventory(InventoryS2CPacket packet, CallbackInfo ci){ 29 | if(Synthesis.step!=0)Synthesis.onInventory(); 30 | if(InventoryUtils.switchItem)switchInv(); 31 | if(num == 3 || num == 1)syncInv(); 32 | if (CloseTheContainerAfterOpening.step == 2) { 33 | CloseTheContainerAfterOpening.step(); 34 | } 35 | } 36 | @Inject(at = @At("TAIL"),method = "onPlayerPositionLook") 37 | public void onPlayerPositionLook(PlayerPositionLookS2CPacket packet, CallbackInfo ci){ 38 | // System.out.println("speed"); 39 | } 40 | @Inject(at = @At("TAIL"),method = "onItemPickupAnimation") 41 | public void onItemPickupAnimation(ItemPickupAnimationS2CPacket packet, CallbackInfo ci){ 42 | } 43 | @Inject(at = @At("HEAD"),method = "onExperienceBarUpdate") 44 | public void onExperienceBarUpdate(ExperienceBarUpdateS2CPacket packet, CallbackInfo ci){ 45 | // int experience = packet.getExperience(); 46 | // float barProgress = packet.getBarProgress(); 47 | // int experienceLevel = packet.getExperienceLevel(); 48 | // if(Configs.AUTO_MENDING.getBooleanValue()) { 49 | // AutoMending.AUTO_MENDING.tick = 0; 50 | // } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/ClientPlayerEMixin.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin; 2 | 3 | import com.zxy.wuhuclient.Utils.InventoryUtils; 4 | import com.zxy.wuhuclient.Utils.ZxyUtils; 5 | import com.zxy.wuhuclient.config.Configs; 6 | import com.zxy.wuhuclient.features_list.AutoMending; 7 | import net.minecraft.client.MinecraftClient; 8 | import net.minecraft.client.network.ClientPlayNetworkHandler; 9 | import net.minecraft.client.network.ClientPlayerEntity; 10 | import net.minecraft.client.recipebook.ClientRecipeBook; 11 | import net.minecraft.client.world.ClientWorld; 12 | import net.minecraft.stat.StatHandler; 13 | import org.spongepowered.asm.mixin.Final; 14 | import org.spongepowered.asm.mixin.Mixin; 15 | import org.spongepowered.asm.mixin.Mutable; 16 | import org.spongepowered.asm.mixin.Shadow; 17 | import org.spongepowered.asm.mixin.injection.At; 18 | import org.spongepowered.asm.mixin.injection.Inject; 19 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 20 | 21 | @Mixin(ClientPlayerEntity.class) 22 | public abstract class ClientPlayerEMixin { 23 | @Mutable 24 | @Final 25 | @Shadow 26 | protected final MinecraftClient client; 27 | 28 | public ClientPlayerEMixin(MinecraftClient client) { 29 | this.client = client; 30 | } 31 | 32 | @Inject(at = @At("TAIL"),method = "tick") 33 | public void tick(CallbackInfo ci){ 34 | ZxyUtils.tick(); 35 | 36 | AutoMending.AUTO_MENDING.tick(); 37 | } 38 | 39 | @Inject(at = @At("TAIL"),method = "closeHandledScreen") 40 | public void closeScreen(CallbackInfo ci){ 41 | InventoryUtils.openIng = false; 42 | InventoryUtils.switchItem = false; 43 | } 44 | 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/ClientPlayerInteractionManagerMixin.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin; 2 | 3 | 4 | import com.zxy.wuhuclient.Utils.InventoryUtils; 5 | import com.zxy.wuhuclient.Utils.ScreenManagement; 6 | import com.zxy.wuhuclient.features_list.Synthesis; 7 | import com.zxy.wuhuclient.config.Configs; 8 | import net.minecraft.client.MinecraftClient; 9 | import net.minecraft.client.network.ClientPlayerEntity; 10 | import net.minecraft.client.network.ClientPlayerInteractionManager; 11 | import net.minecraft.client.world.ClientWorld; 12 | import net.minecraft.text.Text; 13 | import net.minecraft.util.ActionResult; 14 | import net.minecraft.util.Hand; 15 | import net.minecraft.util.hit.BlockHitResult; 16 | import net.minecraft.util.math.BlockPos; 17 | import net.minecraft.util.math.Direction; 18 | import org.spongepowered.asm.mixin.Final; 19 | import org.spongepowered.asm.mixin.Mixin; 20 | import org.spongepowered.asm.mixin.Shadow; 21 | import org.spongepowered.asm.mixin.injection.At; 22 | import org.spongepowered.asm.mixin.injection.Inject; 23 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 24 | 25 | import static com.zxy.wuhuclient.features_list.Synthesis.*; 26 | 27 | 28 | @Mixin(ClientPlayerInteractionManager.class) 29 | public class ClientPlayerInteractionManagerMixin { 30 | @Shadow @Final private MinecraftClient client; 31 | 32 | @Inject(at = @At("HEAD"),method = "interactBlock") 33 | public void interactBlock(ClientPlayerEntity player, 34 | //#if MC > 11802 35 | 36 | //#else 37 | //$$ ClientWorld world, 38 | //#endif 39 | Hand hand, BlockHitResult hitResult, CallbackInfoReturnable cir){ 40 | // System.out.println("interactBlock"); 41 | if(isLoadMod && Configs.SYNTHESIS.getBooleanValue() && step != 1){ 42 | if (InventoryUtils.isInventory(hitResult.getBlockPos())) { 43 | if(autoStorage){ 44 | storagePos = hitResult.getBlockPos(); 45 | }else { 46 | invUpdated = false; 47 | step = 3; 48 | ScreenManagement.closeScreen = 1; 49 | } 50 | } 51 | } 52 | } 53 | @Inject(at = @At("TAIL"),method = "attackBlock") 54 | public void attackBlock(BlockPos pos, Direction direction, CallbackInfoReturnable cir){ 55 | if(isLoadMod && Configs.SYNTHESIS.getBooleanValue()){ 56 | if(pos.equals(Synthesis.pos)){ 57 | Synthesis.pos = null; 58 | step = 0; 59 | client.inGameHud.setOverlayMessage(Text.of("合成停止"),false); 60 | client.player.closeHandledScreen(); 61 | return; 62 | } 63 | Synthesis.start(pos); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/CraftingScreenHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin; 2 | 3 | 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.gen.Accessor; 6 | 7 | //#if MC < 12001 8 | //$$ import net.minecraft.inventory.CraftingInventory; 9 | //#else 10 | import net.minecraft.inventory.RecipeInputInventory; 11 | //#endif 12 | 13 | //#if MC < 12104 14 | //$$ import net.minecraft.screen.CraftingScreenHandler; 15 | //#else 16 | import net.minecraft.screen.AbstractCraftingScreenHandler; 17 | //#endif 18 | 19 | @Mixin( 20 | //#if MC < 12104 21 | //$$ CraftingScreenHandler.class 22 | //#else 23 | AbstractCraftingScreenHandler.class 24 | //#endif 25 | ) 26 | public interface CraftingScreenHandlerMixin { 27 | //#if MC < 12104 28 | //$$ @Accessor("input") 29 | //#else 30 | @Accessor("craftingInventory") 31 | //#endif 32 | 33 | //#if MC < 12001 34 | //$$ CraftingInventory 35 | //#else 36 | RecipeInputInventory 37 | //#endif 38 | getInput(); 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/MinecraftClientMixin.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin; 2 | 3 | import com.zxy.wuhuclient.Utils.ScreenManagement; 4 | import com.zxy.wuhuclient.config.Configs; 5 | import com.zxy.wuhuclient.features_list.Synthesis; 6 | import net.minecraft.client.MinecraftClient; 7 | import net.minecraft.client.gui.screen.Screen; 8 | import net.minecraft.client.gui.screen.ingame.HandledScreen; 9 | import net.minecraft.client.network.ClientPlayerEntity; 10 | import net.minecraft.network.packet.s2c.play.OpenScreenS2CPacket; 11 | import net.minecraft.text.Text; 12 | import org.jetbrains.annotations.Nullable; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.Shadow; 15 | import org.spongepowered.asm.mixin.injection.At; 16 | import org.spongepowered.asm.mixin.injection.Inject; 17 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 18 | import static com.zxy.wuhuclient.Utils.ScreenManagement.closeScreen; 19 | import static com.zxy.wuhuclient.features_list.Synthesis.*; 20 | 21 | @Mixin(MinecraftClient.class) 22 | public class MinecraftClientMixin { 23 | @Shadow @Nullable public ClientPlayerEntity player; 24 | 25 | @Inject(at = @At(value = "HEAD"),method = "setScreen", cancellable = true) 26 | public void setScreen(Screen screen, CallbackInfo ci){ 27 | if(closeScreen > 0 && screen instanceof HandledScreen){ 28 | closeScreen--; 29 | ScreenManagement.screen = screen; 30 | ci.cancel(); 31 | } 32 | } 33 | @Inject(at = @At("HEAD"),method = "doItemUse") 34 | public void doItemUse(CallbackInfo ci){ 35 | if ((Synthesis.autoStorage = Configs.SYNTHESIS.getBooleanValue()) && player != null && player.isSneaking()) { 36 | client.inGameHud.setOverlayMessage(Text.of("合成装容已标记"), false); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/MixinExperienceOrbEntity.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin; 2 | 3 | 4 | import com.zxy.wuhuclient.config.Configs; 5 | import com.zxy.wuhuclient.features_list.AutoMending; 6 | import net.minecraft.client.network.ClientPlayerEntity; 7 | import net.minecraft.entity.ExperienceOrbEntity; 8 | import net.minecraft.entity.player.PlayerEntity; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | 14 | @Mixin (ExperienceOrbEntity.class) 15 | public class MixinExperienceOrbEntity { 16 | @Inject(at = @At("HEAD"),method = "onPlayerCollision") 17 | public void onPlayerCollision(PlayerEntity player, CallbackInfo ci){ 18 | if(player instanceof ClientPlayerEntity && Configs.AUTO_MENDING.getBooleanValue()) { 19 | AutoMending.AUTO_MENDING.tick = 0; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/SuffixArrayMixin.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin; 2 | 3 | import com.zxy.wuhuclient.Utils.PinYinSearch; 4 | import com.zxy.wuhuclient.config.Configs; 5 | import net.minecraft.client.MinecraftClient; 6 | import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen; 7 | import net.minecraft.client.network.ClientPlayerEntity; 8 | import net.minecraft.client.search.SuffixArray; 9 | import net.minecraft.item.ItemStack; 10 | import net.minecraft.registry.Registries; 11 | 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.Inject; 15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 16 | 17 | import java.util.List; 18 | 19 | @Mixin(SuffixArray.class) 20 | public class SuffixArrayMixin { 21 | @Inject(at = @At("TAIL"),method = "findAll") 22 | public void findAll1(String text, CallbackInfoReturnable> cir){ 23 | if (!Configs.PINYIN.getBooleanValue()) return; 24 | ClientPlayerEntity player = MinecraftClient.getInstance().player; 25 | if (player != null && player.currentScreenHandler instanceof CreativeInventoryScreen.CreativeScreenHandler) { 26 | Registries.ITEM.stream().forEach(item -> { 27 | if (PinYinSearch.hasPinYin(item.getName().getString().toLowerCase(),text) || item.toString().contains(text)) { 28 | ((CreativeInventoryScreen.CreativeScreenHandler) player.currentScreenHandler).itemList.add(new ItemStack(item)); 29 | } 30 | }); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/jackf/fix/InteractionTrackerImplMixin.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin.jackf.fix; 2 | 3 | import com.zxy.wuhuclient.Utils.InventoryUtils; 4 | import org.jetbrains.annotations.Nullable; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.Shadow; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 10 | import red.jackf.chesttracker.api.ClientBlockSource; 11 | import red.jackf.chesttracker.impl.providers.InteractionTrackerImpl; 12 | 13 | import static com.zxy.wuhuclient.Utils.ZxyUtils.isLoadPrinter; 14 | 15 | 16 | //通过快捷盒子等方式非右键打开ui的情况会导致记录错误 17 | @Mixin(InteractionTrackerImpl.class) 18 | public class InteractionTrackerImplMixin { 19 | @Shadow(remap = false) 20 | private @Nullable ClientBlockSource lastSource = null; 21 | 22 | @Inject(at = @At("TAIL"),method = "setLastBlockSource",remap = false) 23 | public void setLastBlockSource(ClientBlockSource source, CallbackInfo ci) { 24 | if (!isLoadPrinter && !InventoryUtils.isInventory(source.pos())) { 25 | this.lastSource = null; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/masa/Litematica_InventoryUtilsMixin.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin.masa; 2 | 3 | import fi.dy.masa.litematica.util.InventoryUtils; 4 | import net.minecraft.entity.player.PlayerEntity; 5 | import net.minecraft.entity.player.PlayerInventory; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.gen.Invoker; 8 | 9 | @Mixin(InventoryUtils.class) 10 | public interface Litematica_InventoryUtilsMixin { 11 | @Invoker("getPickBlockTargetSlot") 12 | public static int getPickBlockTargetSlot(PlayerEntity player){ 13 | return -1; 14 | }; 15 | @Invoker("getEmptyPickBlockableHotbarSlot") 16 | 17 | public static int getEmptyPickBlockableHotbarSlot(PlayerInventory inventory){ 18 | return -1; 19 | }; 20 | } -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/masa/MixinInventoryUtils.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin.masa; 2 | 3 | 4 | import fi.dy.masa.litematica.util.InventoryUtils; 5 | import net.minecraft.client.MinecraftClient; 6 | import net.minecraft.item.ItemStack; 7 | import net.minecraft.util.math.BlockPos; 8 | import net.minecraft.world.World; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | 14 | import static com.zxy.wuhuclient.Utils.InventoryUtils.equalsItem; 15 | import static com.zxy.wuhuclient.Utils.InventoryUtils.items2; 16 | import static com.zxy.wuhuclient.config.Configs.QUICK_SHULKER; 17 | 18 | @Mixin(InventoryUtils.class) 19 | public class MixinInventoryUtils { 20 | @Inject(at = @At("TAIL"),method = "schematicWorldPickBlock") 21 | private static void schematicWorldPickBlock(ItemStack stack, BlockPos pos, World schematicWorld, MinecraftClient mc, CallbackInfo ci){ 22 | // System.out.println(cir.getReturnValue().booleanValue()); 23 | if (mc.player != null && !equalsItem(mc.player.getMainHandStack(),stack) && (QUICK_SHULKER.getBooleanValue())) { 24 | items2.add(stack.getItem()); 25 | com.zxy.wuhuclient.Utils.InventoryUtils.switchItem(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/masa/WorldUtilsAccessor.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin.masa; 2 | 3 | import fi.dy.masa.litematica.util.WorldUtils; 4 | import net.minecraft.client.MinecraftClient; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Invoker; 7 | 8 | @Mixin(WorldUtils.class) 9 | public interface WorldUtilsAccessor { 10 | @Invoker 11 | static boolean invokePlacementRestrictionInEffect(MinecraftClient mc) { 12 | throw new UnsupportedOperationException(); 13 | } 14 | } -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/masa/litematica_easy_place_fix/ClientPlayerInteractionManagerMixin_EasyPlaceFix.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin.masa.litematica_easy_place_fix; 2 | 3 | import com.zxy.wuhuclient.features_list.EasyPlaceFix; 4 | import fi.dy.masa.litematica.config.Configs; 5 | import net.minecraft.client.MinecraftClient; 6 | import net.minecraft.client.network.ClientPlayerEntity; 7 | import net.minecraft.client.network.ClientPlayerInteractionManager; 8 | import net.minecraft.client.world.ClientWorld; 9 | import net.minecraft.util.ActionResult; 10 | import net.minecraft.util.Hand; 11 | import net.minecraft.util.hit.BlockHitResult; 12 | import org.spongepowered.asm.mixin.Final; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.Shadow; 15 | import org.spongepowered.asm.mixin.injection.At; 16 | import org.spongepowered.asm.mixin.injection.Inject; 17 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 18 | 19 | import static com.zxy.wuhuclient.config.Configs.EASY_PLACED_FIX; 20 | 21 | @Mixin(ClientPlayerInteractionManager.class) 22 | public class ClientPlayerInteractionManagerMixin_EasyPlaceFix { 23 | @Shadow @Final private MinecraftClient client; 24 | 25 | @Inject(method = "interactBlock", at = @At("HEAD"), cancellable = true) 26 | //#if MC > 11802 27 | private void onInteractBlock(ClientPlayerEntity player, Hand hand, BlockHitResult hitResult, CallbackInfoReturnable cir) { 28 | //#else 29 | //$$ private void onInteractBlock(ClientPlayerEntity player, ClientWorld world , Hand hand, BlockHitResult hitResult, CallbackInfoReturnable cir) { 30 | //#endif 31 | if (EASY_PLACED_FIX.getBooleanValue() && Configs.Generic.EASY_PLACE_MODE.getBooleanValue() && !EasyPlaceFix.isPlacingWithEasyPlace) { 32 | if (EasyPlaceFix.handleEasyPlaceRestriction(client)) { 33 | cir.setReturnValue(ActionResult.FAIL); 34 | } 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/masa/litematica_easy_place_fix/WorldUtilsMixin.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin.masa.litematica_easy_place_fix; 2 | 3 | import com.zxy.wuhuclient.features_list.EasyPlaceFix; 4 | import fi.dy.masa.litematica.util.WorldUtils; 5 | import fi.dy.masa.malilib.util.LayerRange; 6 | import net.minecraft.block.BlockState; 7 | import net.minecraft.client.MinecraftClient; 8 | import net.minecraft.item.ItemPlacementContext; 9 | import net.minecraft.item.ItemStack; 10 | import net.minecraft.util.ActionResult; 11 | import net.minecraft.util.hit.BlockHitResult; 12 | import net.minecraft.util.hit.HitResult; 13 | import net.minecraft.util.math.BlockPos; 14 | import net.minecraft.world.World; 15 | import org.spongepowered.asm.mixin.Mixin; 16 | import org.spongepowered.asm.mixin.injection.At; 17 | import org.spongepowered.asm.mixin.injection.Inject; 18 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 19 | import org.spongepowered.asm.mixin.injection.callback.LocalCapture; 20 | 21 | import static com.zxy.wuhuclient.config.Configs.EASY_PLACED_FIX; 22 | 23 | @Mixin(WorldUtils.class) 24 | public class WorldUtilsMixin { 25 | //#if MC > 11802 26 | @Inject(method = "doEasyPlaceAction", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;interactBlock(Lnet/minecraft/client/network/ClientPlayerEntity;Lnet/minecraft/util/Hand;Lnet/minecraft/util/hit/BlockHitResult;)Lnet/minecraft/util/ActionResult;", remap = true), require = 2) 27 | //#else 28 | //$$ @Inject(method = "doEasyPlaceAction", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;interactBlock(Lnet/minecraft/client/network/ClientPlayerEntity;Lnet/minecraft/client/world/ClientWorld;Lnet/minecraft/util/Hand;Lnet/minecraft/util/hit/BlockHitResult;)Lnet/minecraft/util/ActionResult;", remap = true), require = 2) 29 | //#endif 30 | private static void preInteractBlock(CallbackInfoReturnable cir) { 31 | EasyPlaceFix.isPlacingWithEasyPlace = true; 32 | } 33 | //#if MC > 11802 34 | @Inject(method = "doEasyPlaceAction", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;interactBlock(Lnet/minecraft/client/network/ClientPlayerEntity;Lnet/minecraft/util/Hand;Lnet/minecraft/util/hit/BlockHitResult;)Lnet/minecraft/util/ActionResult;", shift = At.Shift.AFTER, remap = true), require = 2) 35 | //#else 36 | //$$ @Inject(method = "doEasyPlaceAction", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;interactBlock(Lnet/minecraft/client/network/ClientPlayerEntity;Lnet/minecraft/client/world/ClientWorld;Lnet/minecraft/util/Hand;Lnet/minecraft/util/hit/BlockHitResult;)Lnet/minecraft/util/ActionResult;", shift = At.Shift.AFTER, remap = true), require = 2) 37 | //#endif 38 | private static void postInteractBlock(CallbackInfoReturnable cir) { 39 | EasyPlaceFix.isPlacingWithEasyPlace = false; 40 | } 41 | 42 | @Inject(method = "placementRestrictionInEffect", at = @At(value = "INVOKE", target = "Lfi/dy/masa/litematica/materials/MaterialCache;getInstance()Lfi/dy/masa/litematica/materials/MaterialCache;"), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD,remap = false) 43 | private static void stopEasyPlaceWhenBlockAlreadyCorrect(MinecraftClient mc, CallbackInfoReturnable cir, HitResult trace, ItemStack stack, BlockHitResult blockHitResult, ItemPlacementContext ctx, BlockPos pos, BlockState stateClient, World worldSchematic, LayerRange range, boolean schematicHasAir, BlockState stateSchematic) { 44 | if (EASY_PLACED_FIX.getBooleanValue() && stateClient == stateSchematic) { 45 | cir.setReturnValue(Boolean.TRUE); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/masa/litematicahelper/MaterialListHudRendererAccessor.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin.masa.litematicahelper; 2 | 3 | import com.zxy.wuhuclient.features_list.litematica_helper.Condition; 4 | import com.zxy.wuhuclient.features_list.litematica_helper.Restriction; 5 | import fi.dy.masa.litematica.materials.MaterialListHudRenderer; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.gen.Accessor; 8 | import org.spongepowered.asm.mixin.gen.Invoker; 9 | 10 | @Restriction(require = @Condition("litematica")) 11 | @Mixin(MaterialListHudRenderer.class) 12 | public interface MaterialListHudRendererAccessor 13 | { 14 | @Accessor(remap = false) 15 | void setLastUpdateTime(long value); 16 | 17 | @Invoker(remap = false) 18 | String invokeGetFormattedCountString(int count, int maxStackSize); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/masa/litematicahelper/ScreenHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin.masa.litematicahelper; 2 | 3 | 4 | import com.zxy.wuhuclient.config.Configs; 5 | import net.minecraft.screen.ScreenHandler; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 10 | 11 | import static com.zxy.wuhuclient.features_list.litematica_helper.LitematicaHelper.process; 12 | 13 | @Mixin(ScreenHandler.class) 14 | public class ScreenHandlerMixin { 15 | @Inject(method = "updateSlotStacks", at = @At("TAIL")) 16 | private void tweakerMoreAutoContainerProcessorProcess(CallbackInfo ci) 17 | { 18 | if(Configs.LITEMATICA_HELPER.getBooleanValue()) process((ScreenHandler)(Object)this); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/masa/litematicahelper/SelectionManagerMixin.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin.masa.litematicahelper; 2 | 3 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 4 | import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; 5 | import com.zxy.wuhuclient.config.Configs; 6 | import fi.dy.masa.litematica.selection.SelectionManager; 7 | import fi.dy.masa.litematica.world.SchematicWorldHandler; 8 | import fi.dy.masa.litematica.world.WorldSchematic; 9 | import net.minecraft.block.BlockState; 10 | import net.minecraft.entity.Entity; 11 | import net.minecraft.util.hit.BlockHitResult; 12 | import net.minecraft.util.hit.HitResult; 13 | import net.minecraft.util.math.BlockPos; 14 | import net.minecraft.util.math.Vec3d; 15 | import net.minecraft.world.RaycastContext; 16 | import net.minecraft.world.World; 17 | import org.spongepowered.asm.mixin.Mixin; 18 | import org.spongepowered.asm.mixin.Unique; 19 | import org.spongepowered.asm.mixin.injection.At; 20 | 21 | import static fi.dy.masa.litematica.util.RayTraceUtils.*; 22 | 23 | @Mixin(SelectionManager.class) 24 | public class SelectionManagerMixin { 25 | @WrapOperation(at = @At(value = "INVOKE", target = "Lfi/dy/masa/litematica/util/RayTraceUtils;getTargetedPosition(Lnet/minecraft/world/World;Lnet/minecraft/entity/Entity;DZ)Lnet/minecraft/util/math/BlockPos;"),method = "resetSelectionToClickedPosition") 26 | public BlockPos resetSelectionToClickedPosition(World world, Entity player, double maxDistance, boolean sneakToOffset, Operation original){ 27 | return getPos(world,player,maxDistance,sneakToOffset,original); 28 | } 29 | @WrapOperation(at = @At(value = "INVOKE", target = "Lfi/dy/masa/litematica/util/RayTraceUtils;getTargetedPosition(Lnet/minecraft/world/World;Lnet/minecraft/entity/Entity;DZ)Lnet/minecraft/util/math/BlockPos;"),method = "growSelectionToContainClickedPosition") 30 | public BlockPos growSelectionToContainClickedPosition(World world, Entity player, double maxDistance, boolean sneakToOffset, Operation original){ 31 | return getPos(world,player,maxDistance,sneakToOffset,original); 32 | } 33 | @WrapOperation(at = @At(value = "INVOKE", target = "Lfi/dy/masa/litematica/util/RayTraceUtils;getTargetedPosition(Lnet/minecraft/world/World;Lnet/minecraft/entity/Entity;DZ)Lnet/minecraft/util/math/BlockPos;"),method = "setPositionOfCurrentSelectionToRayTrace") 34 | public BlockPos setPositionOfCurrentSelectionToRayTrace(World world, Entity player, double maxDistance, boolean sneakToOffset, Operation original){ 35 | return getPos(world,player,maxDistance,sneakToOffset,original); 36 | } 37 | 38 | @Unique 39 | private BlockPos getPos(World world, Entity player, double maxDistance, boolean sneakToOffset, Operation original){ 40 | WorldSchematic schematicWorld = SchematicWorldHandler.getSchematicWorld(); 41 | if (schematicWorld == null || !Configs.LITEMATICA_HELPER.getBooleanValue()) return original.call(world,player,maxDistance,sneakToOffset); 42 | 43 | BlockHitResult blockHitResult = traceToSchematicWorld(player, 200, true, true); 44 | if(blockHitResult == null || schematicWorld.getBlockState(blockHitResult.getBlockPos()).isAir()){ 45 | return original.call(world, player, maxDistance, sneakToOffset); 46 | } 47 | BlockPos pos = blockHitResult.getBlockPos(); 48 | if (sneakToOffset == player.isSneaking()) 49 | { 50 | pos = pos.offset(blockHitResult.getSide()); 51 | } 52 | return pos; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/masa/litematicahelper/TaskCountBlocksAreaMixin.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin.masa.litematicahelper; 2 | 3 | import com.zxy.wuhuclient.Utils.ZxyUtils; 4 | import com.zxy.wuhuclient.config.Configs; 5 | import fi.dy.masa.litematica.scheduler.tasks.TaskCountBlocksArea; 6 | import fi.dy.masa.litematica.scheduler.tasks.TaskCountBlocksPlacement; 7 | import net.minecraft.util.math.BlockPos; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 12 | 13 | @Mixin(value = {TaskCountBlocksArea.class, TaskCountBlocksPlacement.class}) 14 | public class TaskCountBlocksAreaMixin { 15 | @Inject(at = @At(value = "HEAD"), method = "countAtPosition", cancellable = true) 16 | private void countAtPosition(BlockPos pos, CallbackInfo ci) { 17 | if(Configs.LITEMATICA_HELPER.getBooleanValue() && !ZxyUtils.TempData.xuanQuFanWeiNei_p(pos)) ci.cancel(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/masa/litematicahelper/TaskCountBlocksPlacementMixin.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin.masa.litematicahelper; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 5 | import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; 6 | import com.zxy.wuhuclient.config.Configs; 7 | import fi.dy.masa.litematica.data.DataManager; 8 | import fi.dy.masa.litematica.scheduler.tasks.TaskCountBlocksPlacement; 9 | import fi.dy.masa.litematica.schematic.placement.SchematicPlacement; 10 | import fi.dy.masa.litematica.schematic.placement.SubRegionPlacement; 11 | import fi.dy.masa.litematica.selection.Box; 12 | import net.fabricmc.loader.api.FabricLoader; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.injection.At; 15 | 16 | @Mixin(TaskCountBlocksPlacement.class) 17 | public class TaskCountBlocksPlacementMixin { 18 | //获取投影框 修改为选区 19 | 20 | //#if MC >= 12001 && MC != 12002 21 | @WrapOperation(method = "(Lfi/dy/masa/litematica/schematic/placement/SchematicPlacement;Lfi/dy/masa/litematica/materials/IMaterialList;Z)V",at = @At(value = "INVOKE", target = "Lfi/dy/masa/litematica/schematic/placement/SchematicPlacement;getSubRegionBoxes(Lfi/dy/masa/litematica/schematic/placement/SubRegionPlacement$RequiredEnabled;)Lcom/google/common/collect/ImmutableMap;"),remap = false) 22 | //#else 23 | //$$ @WrapOperation(method = "",at = @At(value = "INVOKE", target = "Lfi/dy/masa/litematica/schematic/placement/SchematicPlacement;getSubRegionBoxes(Lfi/dy/masa/litematica/schematic/placement/SubRegionPlacement$RequiredEnabled;)Lcom/google/common/collect/ImmutableMap;"),remap = false) 24 | //#endif 25 | private ImmutableMap getSubRegionBoxes(SchematicPlacement instance, SubRegionPlacement.RequiredEnabled boxOriginAbsolute, Operation> original){ 26 | if(Configs.LITEMATICA_HELPER.getBooleanValue() && DataManager.getSelectionManager().getCurrentSelection() != null){ 27 | return DataManager.getSelectionManager().getCurrentSelection().getAllSubRegions(); 28 | }else return original.call(instance, boxOriginAbsolute); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/masa/pinyin/WidgetListBaseMixin.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin.masa.pinyin; 2 | 3 | import com.zxy.wuhuclient.Utils.PinYinSearch; 4 | import com.zxy.wuhuclient.config.Configs; 5 | import fi.dy.masa.malilib.gui.widgets.WidgetListBase; 6 | import fi.dy.masa.malilib.util.StringUtils; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 11 | 12 | @Mixin(WidgetListBase.class) 13 | public class WidgetListBaseMixin{ 14 | @Inject(at = @At(value = "INVOKE",target = "Ljava/lang/String;contains(Ljava/lang/CharSequence;)Z"),method = "matchesFilter(Ljava/lang/String;Ljava/lang/String;)Z",remap = false, cancellable = true) 15 | public void matchesFilter(String entryString, String filterText, CallbackInfoReturnable cir){ 16 | if (!Configs.PINYIN.getBooleanValue()) return; 17 | String translate = StringUtils.translate(entryString); 18 | if (PinYinSearch.hasPinYin(translate,filterText) || translate.contains(filterText)) { 19 | cir.setReturnValue(true); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/masa/pinyin/WidgetListConfigOptionsMixin.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin.masa.pinyin; 2 | 3 | import com.zxy.wuhuclient.config.Configs; 4 | import fi.dy.masa.malilib.config.IConfigBase; 5 | import fi.dy.masa.malilib.gui.GuiConfigsBase; 6 | import fi.dy.masa.malilib.gui.widgets.WidgetListConfigOptions; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 11 | 12 | import java.util.List; 13 | 14 | @Mixin(value = WidgetListConfigOptions.class) 15 | public class WidgetListConfigOptionsMixin { 16 | @Inject(at = @At("RETURN"),method = "getEntryStringsForFilter(Lfi/dy/masa/malilib/gui/GuiConfigsBase$ConfigOptionWrapper;)Ljava/util/List;",remap = false) 17 | public void getEntryString(GuiConfigsBase.ConfigOptionWrapper entry, CallbackInfoReturnable> cir){ 18 | IConfigBase config = entry.getConfig(); 19 | if(config == null || !Configs.PINYIN.getBooleanValue()) return; 20 | List list = cir.getReturnValue(); 21 | list.add(config.getName()); 22 | if(config.getPrettyName() != null)list.add(config.getPrettyName()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/zxy/wuhuclient/mixin/pointless/Pointless.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin.pointless; 2 | 3 | public class Pointless { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/resources/assets/wuhuclient/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } -------------------------------------------------------------------------------- /src/main/resources/assets/wuhuclient/lang/zh_cn.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } -------------------------------------------------------------------------------- /src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "${mod_id}-${minecraft_version_id}", 4 | "version": "${mod_version}", 5 | "icon": "assets/${mod_id}/icon.png", 6 | "name": "${mod_name} for ${minecraft_version}", 7 | "description": "阿巴阿巴", 8 | "authors": [ 9 | "zhaixianyu" 10 | ], 11 | "contact": { 12 | "website": "${mod_homepage}", 13 | "homepage": "${mod_sources}", 14 | "sources": "${mod_sources}" 15 | }, 16 | "license": "${mod_license}", 17 | "environment": "*", 18 | "entrypoints": { 19 | "main": [ 20 | "com.zxy.wuhuclient.WuHuClientMod" 21 | ], 22 | "modmenu": [ 23 | "com.zxy.wuhuclient.config.ModMenu" 24 | ] 25 | }, 26 | "mixins": [ 27 | "wuhuclient.mixins.json" 28 | ], 29 | "depends": { 30 | "minecraft": "${minecraft_dependency}" 31 | }, 32 | "custom": { 33 | "modmenu": { 34 | "parent": "${mod_id}" 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/resources/wuhuclient.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "com.zxy.wuhuclient.mixin", 5 | "compatibilityLevel": "{{COMPATIBILITY_LEVEL}}", 6 | "mixins": [ 7 | "masa.WorldUtilsAccessor", 8 | "masa.litematicahelper.MaterialListHudRendererAccessor", 9 | "masa.litematicahelper.ScreenHandlerMixin", 10 | "masa.litematicahelper.TaskCountBlocksPlacementMixin" 11 | ], 12 | "injectors": { 13 | "defaultRequire": 1 14 | }, 15 | "client": [ 16 | "BlockMixin", 17 | "ClientPlayerEMixin", 18 | "ClientPlayerInteractionManagerMixin", 19 | "ClientPlayNetworkHandlerMixin", 20 | "CraftingScreenHandlerMixin", 21 | "MinecraftClientMixin", 22 | "MixinExperienceOrbEntity", 23 | "SuffixArrayMixin", 24 | "jackf.fix.InteractionTrackerImplMixin", 25 | "masa.Litematica_InventoryUtilsMixin", 26 | "masa.MixinInventoryUtils", 27 | "masa.litematica_easy_place_fix.ClientPlayerInteractionManagerMixin_EasyPlaceFix", 28 | "masa.litematica_easy_place_fix.WorldUtilsMixin", 29 | "masa.litematicahelper.SelectionManagerMixin", 30 | "masa.litematicahelper.TaskCountBlocksAreaMixin", 31 | "masa.pinyin.WidgetListBaseMixin", 32 | "masa.pinyin.WidgetListConfigOptionsMixin" 33 | ] 34 | } -------------------------------------------------------------------------------- /versions/1.18.2/gradle.properties: -------------------------------------------------------------------------------- 1 | 2 | minecraft_dependency=1.18.x 3 | 4 | #https://fabricmc.net/develop/ 5 | minecraft_version=1.18.2 6 | yarn_mappings=1.18.2+build.4 7 | 8 | #Fabric api 9 | fabric_version=0.77.0+1.18.2 10 | #https://www.curseforge.com/minecraft/mc-mods/malilib/files/all 11 | malilib_version = malilib-fabric-1.18.2:0.12.0 12 | #https://www.curseforge.com/minecraft/mc-mods/item-scroller/files/all 13 | item_scrolle_version =3879911 14 | #https://www.curseforge.com/minecraft/mc-mods/litematica/files/all 15 | #https://modrinth.com/mod/litematica/versions?g=1.18.2 16 | litematica_version =0.11.6 17 | #https://www.curseforge.com/minecraft/mc-mods/quick-shulker/files/all 18 | quick_shulker_version =4008786 19 | kyrptconfig_version = 1.4.6-1.18 20 | shulkerutils_version = 1.0.4-1.18 21 | #https://www.modrinth.com/mod/modmenu/versions 22 | modmenu_version =3.2.5 23 | #https://modrinth.com/mod/carpet/versions 24 | carpet_version =1.4.69 25 | 26 | #https://modrinth.com/mod/chest-tracker/versions 27 | chesttracker=1.1.16 28 | #https://modrinth.com/mod/where-is-it/versions?l=fabric 29 | whereisit=1.14.10 30 | #https://modrinth.com/mod/cloth-config/versions?l=fabric 31 | cloth_config=6.5.102 32 | #https://www.curseforge.com/minecraft/mc-mods/cloth-api/files/all 33 | cloth_api=3.2.64 34 | #https://github.com/CottonMC/LibGui/releases 35 | LibGui=5.4.1+1.18.2 36 | 37 | jackfredlib=6 38 | searchables=6 39 | yacl=6 -------------------------------------------------------------------------------- /versions/1.19.4/gradle.properties: -------------------------------------------------------------------------------- 1 | 2 | minecraft_dependency=1.19.4 3 | 4 | #https://fabricmc.net/develop/ 5 | minecraft_version=1.19.4 6 | yarn_mappings=1.19.4+build.2 7 | 8 | #Fabric api 9 | fabric_version=0.87.2+1.19.4 10 | 11 | #https://www.curseforge.com/minecraft/mc-mods/malilib/files/all 12 | malilib_version = malilib-fabric-1.19.4:0.15.2 13 | #https://www.curseforge.com/minecraft/mc-mods/item-scroller/files/all 14 | item_scrolle_version =4946332 15 | #https://www.curseforge.com/minecraft/mc-mods/litematica/files/all 16 | #https://modrinth.com/mod/litematica/versions?g=1.19.4 17 | litematica_version =0.14.7 18 | #https://www.curseforge.com/minecraft/mc-mods/quick-shulker/files/all 19 | quick_shulker_version =4592290 20 | kyrptconfig_version = 1.4.6-1.18 21 | shulkerutils_version = 1.0.4-1.18 22 | #https://www.modrinth.com/mod/modmenu/versions 23 | modmenu_version =6.3.1 24 | #https://modrinth.com/mod/carpet/versions 25 | carpet_version =1.4.101 26 | 27 | #https://modrinth.com/mod/chest-tracker/versions 28 | chesttracker=1.1.21 29 | #https://modrinth.com/mod/where-is-it/versions?l=fabric 30 | whereisit=1.14.16 31 | #https://modrinth.com/mod/cloth-config/versions?l=fabric 32 | cloth_config=10.1.117+fabric 33 | #https://github.com/CottonMC/LibGui/releases 34 | LibGui=7.1.1+1.19.4 35 | 36 | jackfredlib=6 37 | searchables=6 38 | yacl=6 39 | cloth_api=6 40 | -------------------------------------------------------------------------------- /versions/1.19.4/src/main/java/com/zxy/wuhuclient/mixin/jackf/fix/InteractionTrackerImplMixin.java: -------------------------------------------------------------------------------- 1 | package com.zxy.wuhuclient.mixin.jackf.fix; 2 | 3 | 4 | 5 | import com.zxy.wuhuclient.mixin.pointless.Pointless; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | 8 | 9 | //通过快捷盒子等方式非右键打开ui的情况会导致记录错误 10 | @Mixin(Pointless.class) 11 | public class InteractionTrackerImplMixin { 12 | } 13 | -------------------------------------------------------------------------------- /versions/1.20.1/gradle.properties: -------------------------------------------------------------------------------- 1 | 2 | minecraft_dependency=1.20.1 3 | 4 | #https://fabricmc.net/develop/ 5 | minecraft_version=1.20.1 6 | yarn_mappings=1.20.1+build.10 7 | 8 | #Fabric api 9 | fabric_version=0.92.0+1.20.1 10 | #https://www.curseforge.com/minecraft/mc-mods/malilib/files/all 11 | malilib_version = malilib-fabric-1.20.1:0.16.2 12 | #https://www.curseforge.com/minecraft/mc-mods/item-scroller/files/all 13 | item_scrolle_version =4593079 14 | #https://www.curseforge.com/minecraft/mc-mods/litematica/files/all 15 | #https://modrinth.com/mod/litematica/versions?g=1.20.1 16 | litematica_version =0.15.4 17 | #https://www.curseforge.com/minecraft/mc-mods/quick-shulker/files/all 18 | quick_shulker_version =4592296 19 | kyrptconfig_version = 1.4.6-1.18 20 | shulkerutils_version = 1.0.4-1.18 21 | #https://www.modrinth.com/mod/modmenu/versions 22 | modmenu_version =7.2.2 23 | #https://modrinth.com/mod/carpet/versions 24 | carpet_version =1.4.112 25 | 26 | #https://maven.jackf.red/#/releases/red/jackf/jackfredlib/jackfredlib 27 | jackfredlib=0.10.2+1.20.1 28 | #https://modrinth.com/mod/chest-tracker/versions 29 | chesttracker=2.6.4+1.20.1 30 | #https://modrinth.com/mod/where-is-it/versions?l=fabric 31 | whereisit=2.6.3+1.20.1 32 | 33 | searchables=Searchables-fabric-1.20.1:1.0.2 34 | #https://maven.isxander.dev/#/releases/dev/isxander/yacl/yet-another-config-lib-fabric 35 | yacl=3.5.0+1.20.1-fabric 36 | 37 | 38 | 39 | cloth_config=6 40 | cloth_api=6 41 | LibGui=6 -------------------------------------------------------------------------------- /versions/1.20.2/gradle.properties: -------------------------------------------------------------------------------- 1 | 2 | minecraft_dependency=1.20.2 3 | 4 | #https://fabricmc.net/develop/ 5 | minecraft_version=1.20.2 6 | yarn_mappings=1.20.2+build.4 7 | 8 | #Fabric api 9 | fabric_version=0.91.6+1.20.2 10 | #https://www.curseforge.com/minecraft/mc-mods/malilib/files/all 11 | malilib_version = malilib-fabric-1.20.2:0.17.0 12 | #https://www.curseforge.com/minecraft/mc-mods/item-scroller/files/all 13 | item_scrolle_version =4788435 14 | #https://www.curseforge.com/minecraft/mc-mods/litematica/files/all 15 | #https://modrinth.com/mod/litematica/versions?g=1.20.2 16 | litematica_version =0.16.1 17 | #https://www.curseforge.com/minecraft/mc-mods/quick-shulker/files/all 18 | quick_shulker_version =4592296 19 | kyrptconfig_version = 1.4.6-1.18 20 | shulkerutils_version = 1.0.4-1.18 21 | #https://www.modrinth.com/mod/modmenu/versions 22 | modmenu_version =8.0.1 23 | #https://modrinth.com/mod/carpet/versions 24 | carpet_version =1.4.121 25 | 26 | #https://maven.jackf.red/#/releases/red/jackf/jackfredlib/jackfredlib 27 | jackfredlib=0.10.2+1.20.2 28 | #https://modrinth.com/mod/chest-tracker/versions 29 | chesttracker=2.4.12+1.20.2 30 | #https://modrinth.com/mod/where-is-it/versions?l=fabric 31 | whereisit=2.4.3+1.20.2 32 | #https://modrinth.com/mod/searchables/versions?l=fabric 33 | searchables=Searchables-fabric-1.20.2:1.0.16 34 | #https://maven.isxander.dev/#/snapshots/dev/isxander/yet-another-config-lib 35 | yacl=3.3.0-beta.1+1.20.2-fabric 36 | #https://modrinth.com/mod/modmenu/versions 37 | 38 | cloth_config=6 39 | cloth_api=6 40 | LibGui=6 41 | -------------------------------------------------------------------------------- /versions/1.20.4/gradle.properties: -------------------------------------------------------------------------------- 1 | minecraft_dependency=1.20.4 2 | 3 | #https://fabricmc.net/develop/ 4 | minecraft_version=1.20.4 5 | yarn_mappings=1.20.4+build.3 6 | 7 | #Fabric api 8 | fabric_version=0.97.2+1.20.4 9 | #https://www.curseforge.com/minecraft/mc-mods/malilib/files/all 10 | malilib_version = malilib-fabric-1.20.4:0.18.0 11 | #https://www.curseforge.com/minecraft/mc-mods/item-scroller/files/all 12 | item_scrolle_version =4946332 13 | #https://www.curseforge.com/minecraft/mc-mods/litematica/files/all 14 | #https://modrinth.com/mod/litematica/versions?g=1.20.4 15 | litematica_version =0.17.4 16 | #https://www.curseforge.com/minecraft/mc-mods/quick-shulker/files/all 17 | quick_shulker_version =4592296 18 | kyrptconfig_version = 1.4.6-1.18 19 | shulkerutils_version = 1.0.4-1.18 20 | #https://www.modrinth.com/mod/modmenu/versions 21 | modmenu_version =9.0.0 22 | #https://modrinth.com/mod/carpet/versions 23 | carpet_version =1.4.128 24 | 25 | #https://maven.jackf.red/#/releases/red/jackf/jackfredlib/jackfredlib 26 | jackfredlib=0.10.2+1.20.4 27 | #https://modrinth.com/mod/chest-tracker/versions 28 | #https://maven.jackf.red/#/releases/red/jackf/chesttracker 29 | chesttracker=2.4.12+1.20.4 30 | #https://modrinth.com/mod/where-is-it/versions?l=fabric 31 | whereisit=2.4.3+1.20.4 32 | #https://modrinth.com/mod/searchables/versions?l=fabric 33 | searchables=Searchables-fabric-1.20.4:1.0.6 34 | #https://modrinth.com/mod/yacl/versions?l=fabric 35 | #https://maven.isxander.dev/#/releases/dev/isxander/yet-another-config-lib 36 | yacl=3.5.0+1.20.4-fabric 37 | #https://modrinth.com/mod/modmenu/versions 38 | 39 | 40 | cloth_config=6 41 | cloth_api=6 42 | LibGui=6 -------------------------------------------------------------------------------- /versions/1.20.6/gradle.properties: -------------------------------------------------------------------------------- 1 | minecraft_dependency=1.20.6 2 | 3 | #https://fabricmc.net/develop/ 4 | 5 | minecraft_version=1.20.6 6 | yarn_mappings=1.20.6+build.3 7 | #Fabric api 8 | 9 | fabric_version=0.100.4+1.20.6 10 | 11 | #https://www.curseforge.com/minecraft/mc-mods/malilib/files/all 12 | #https://jitpack.io/#sakura-ryoko/malilib 13 | malilib_version=malilib-fabric-1.20.6:0.19.0 14 | #https://www.curseforge.com/minecraft/mc-mods/item-scroller/files/all 15 | #https://jitpack.io/#sakura-ryoko/itemscroller 16 | item_scrolle_version=5450180 17 | #https://www.curseforge.com/minecraft/mc-mods/litematica/files/all 18 | #https://jitpack.io/#sakura-ryoko/litematica 19 | #https://modrinth.com/mod/litematica/versions?g=1.20.6 20 | litematica_version=0.18.1 21 | #https://www.curseforge.com/minecraft/mc-mods/quick-shulker/files/all 22 | quick_shulker_version=4592296 23 | kyrptconfig_version=1.4.6-1.18 24 | shulkerutils_version=1.0.4-1.18 25 | #https://www.modrinth.com/mod/modmenu/versions 26 | modmenu_version=10.0.0 27 | #https://modrinth.com/mod/carpet/versions 28 | carpet_version=5301955 29 | 30 | #https://maven.jackf.red/#/releases/red/jackf/jackfredlib/jackfredlib 31 | jackfredlib=0.10.2+1.20.6 32 | #https://modrinth.com/mod/chest-tracker/versions 33 | chesttracker=2.4.12+1.20.6 34 | #https://modrinth.com/mod/where-is-it/versions?l=fabric 35 | whereisit=2.4.3+1.20.6 36 | #https://modrinth.com/mod/searchables/versions?l=fabric 37 | searchables=Searchables-fabric-1.20.6:1.0.1 38 | #https://modrinth.com/mod/yacl/versions?l=fabric 39 | yacl=3.4.4+1.20.6-fabric 40 | #https://modrinth.com/mod/modmenu/versions 41 | 42 | cloth_config=6 43 | cloth_api=6 44 | LibGui=6 45 | -------------------------------------------------------------------------------- /versions/1.21.1/gradle.properties: -------------------------------------------------------------------------------- 1 | minecraft_dependency=>=1.21 <=1.21.1 2 | 3 | #https://fabricmc.net/develop/ 4 | 5 | minecraft_version=1.21.1 6 | yarn_mappings=1.21.1+build.3 7 | # Fabric API 8 | fabric_version=0.110.0+1.21.1 9 | 10 | #https://www.curseforge.com/minecraft/mc-mods/malilib/files/all 11 | #https://jitpack.io/#sakura-ryoko/malilib 12 | malilib_version=1.21-021.1-sakura.2 13 | #https://www.curseforge.com/minecraft/mc-mods/item-scroller/files/all 14 | #https://jitpack.io/#sakura-ryoko/itemscroller 15 | item_scrolle_version=1.21-sakura.7 16 | #https://www.curseforge.com/minecraft/mc-mods/litematica/files/all 17 | #https://jitpack.io/#sakura-ryoko/litematica 18 | litematica_version=1.21-0.19.3-sakura.3 19 | #https://www.curseforge.com/minecraft/mc-mods/quick-shulker/files/all 20 | quick_shulker_version=4592296 21 | kyrptconfig_version=1.4.6-1.18 22 | shulkerutils_version=1.0.4-1.18 23 | #https://www.modrinth.com/mod/modmenu/versions 24 | modmenu_version=11.0.1 25 | #https://modrinth.com/mod/carpet/versions 26 | #https://www.curseforge.com/minecraft/mc-mods/carpet/files/all 27 | carpet_version=5425253 28 | 29 | #https://maven.jackf.red/#/releases/red/jackf/jackfredlib/jackfredlib 30 | jackfredlib=0.10.2+1.21.1 31 | #https://modrinth.com/mod/chest-tracker/versions 32 | chesttracker=2.6.5+1.21.1 33 | #https://modrinth.com/mod/where-is-it/versions?l=fabric 34 | whereisit=2.6.3+1.21.1 35 | #https://modrinth.com/mod/searchables/versions?l=fabric 36 | searchables=Searchables-fabric-1.21.1:1.0.2 37 | #https://modrinth.com/mod/yacl/versions?l=fabric 38 | yacl=3.5.0+1.21-fabric 39 | #https://modrinth.com/mod/modmenu/versions 40 | 41 | cloth_config=6 42 | cloth_api=6 43 | LibGui=6 44 | -------------------------------------------------------------------------------- /versions/1.21.4/gradle.properties: -------------------------------------------------------------------------------- 1 | minecraft_dependency=1.21.4 2 | 3 | #https://fabricmc.net/develop/ 4 | minecraft_version=1.21.4 5 | yarn_mappings=1.21.4+build.8 6 | 7 | # Fabric API 8 | fabric_version=0.118.0+1.21.4 9 | 10 | #https://www.curseforge.com/minecraft/mc-mods/malilib/files/all 11 | #https://jitpack.io/#sakura-ryoko/malilib 12 | malilib_version=1.21.4-0.23.2-sakura.6 13 | #https://www.curseforge.com/minecraft/mc-mods/item-scroller/files/all 14 | #https://jitpack.io/#sakura-ryoko/itemscroller 15 | item_scrolle_version=1.21.4-0.26.2-sakura.4 16 | #https://www.curseforge.com/minecraft/mc-mods/litematica/files/all 17 | #https://jitpack.io/#sakura-ryoko/litematica 18 | litematica_version=1.21.4-0.21.2-sakura.8 19 | #https://www.curseforge.com/minecraft/mc-mods/quick-shulker/files/all 20 | quick_shulker_version=4592296 21 | kyrptconfig_version=1.4.6-1.18 22 | shulkerutils_version=1.0.4-1.18 23 | #https://www.modrinth.com/mod/modmenu/versions 24 | modmenu_version=13.0.2 25 | #https://modrinth.com/mod/carpet/versions 26 | #https://www.curseforge.com/minecraft/mc-mods/carpet/files/all 27 | carpet_version=5960519 28 | 29 | #https://maven.jackf.red/#/releases/red/jackf/jackfredlib/jackfredlib 30 | jackfredlib=0.10.6+1.21.4 31 | #https://modrinth.com/mod/chest-tracker/versions 32 | chesttracker=2.6.7+1.21.4 33 | #https://modrinth.com/mod/where-is-it/versions?l=fabric 34 | whereisit=2.6.4+1.21.2 35 | #https://modrinth.com/mod/searchables/versions?l=fabric 36 | searchables=Searchables-fabric-1.21.4:1.0.3 37 | #https://modrinth.com/mod/yacl/versions?l=fabric 38 | yacl=3.6.2+1.21.4-fabric 39 | #https://modrinth.com/mod/modmenu/versions 40 | 41 | cloth_config=6 42 | cloth_api=6 43 | LibGui=6 44 | -------------------------------------------------------------------------------- /versions/1.21.5/gradle.properties: -------------------------------------------------------------------------------- 1 | minecraft_dependency=1.21.5 2 | 3 | #https://fabricmc.net/develop/ 4 | minecraft_version=1.21.5 5 | yarn_mappings=1.21.5+build.1 6 | 7 | # Fabric API 8 | fabric_version=0.121.0+1.21.5 9 | 10 | #https://www.curseforge.com/minecraft/mc-mods/malilib/files/all 11 | #https://jitpack.io/#sakura-ryoko/malilib 12 | malilib_version=1.21.5-0.24.1-sakura.1 13 | #https://www.curseforge.com/minecraft/mc-mods/item-scroller/files/all 14 | #https://jitpack.io/#sakura-ryoko/itemscroller 15 | item_scrolle_version=1.21.5-0.27.0-sakura.5 16 | #https://www.curseforge.com/minecraft/mc-mods/litematica/files/all 17 | #https://jitpack.io/#sakura-ryoko/litematica 18 | litematica_version=1.21.5-0.22.0 19 | #https://www.curseforge.com/minecraft/mc-mods/quick-shulker/files/all 20 | quick_shulker_version=4592296 21 | kyrptconfig_version=1.4.6-1.18 22 | shulkerutils_version=1.0.4-1.18 23 | #https://www.modrinth.com/mod/modmenu/versions 24 | modmenu_version=13.0.2 25 | #https://modrinth.com/mod/carpet/versions 26 | #https://www.curseforge.com/minecraft/mc-mods/carpet/files/all 27 | carpet_version=6347645 28 | 29 | #https://maven.jackf.red/#/releases/red/jackf/jackfredlib/jackfredlib 30 | jackfredlib=0.10.6+1.21.4 31 | #https://modrinth.com/mod/chest-tracker/versions 32 | chesttracker=2.6.7+1.21.4 33 | #https://modrinth.com/mod/where-is-it/versions?l=fabric 34 | whereisit=2.6.4+1.21.2 35 | #https://modrinth.com/mod/searchables/versions?l=fabric 36 | searchables=Searchables-fabric-1.21.5:1.0.2 37 | #https://modrinth.com/mod/yacl/versions?l=fabric 38 | yacl=3.7.1+1.21.5-fabric 39 | #https://modrinth.com/mod/modmenu/versions 40 | 41 | cloth_config=6 42 | cloth_api=6 43 | LibGui=6 44 | -------------------------------------------------------------------------------- /versions/1.21.6/gradle.properties: -------------------------------------------------------------------------------- 1 | minecraft_dependency= >=1.21.6 2 | 3 | #https://fabricmc.net/develop/ 4 | minecraft_version=1.21.6 5 | yarn_mappings=1.21.6+build.1 6 | 7 | # Fabric API 8 | fabric_version=0.128.2+1.21.6 9 | 10 | #https://www.curseforge.com/minecraft/mc-mods/malilib/files/all 11 | #https://jitpack.io/#sakura-ryoko/malilib 12 | malilib_version=1.21.6-0.25.0-sakura.1 13 | #https://www.curseforge.com/minecraft/mc-mods/item-scroller/files/all 14 | #https://jitpack.io/#sakura-ryoko/itemscroller 15 | item_scrolle_version=1.21.6-0.28.0-sakura.1 16 | #https://www.curseforge.com/minecraft/mc-mods/litematica/files/all 17 | #https://jitpack.io/#sakura-ryoko/litematica 18 | litematica_version=1.21.6-0.23.0-sakura.2 19 | #https://www.curseforge.com/minecraft/mc-mods/quick-shulker/files/all 20 | quick_shulker_version=4592296 21 | kyrptconfig_version=1.4.6-1.18 22 | shulkerutils_version=1.0.4-1.18 23 | #https://www.modrinth.com/mod/modmenu/versions 24 | modmenu_version=15.0.0-beta.3 25 | #https://modrinth.com/mod/carpet/versions 26 | #https://www.curseforge.com/minecraft/mc-mods/carpet/files/all 27 | carpet_version=6662589 28 | 29 | #https://maven.jackf.red/#/releases/red/jackf/jackfredlib/jackfredlib 30 | jackfredlib=0.10.6+1.21.4 31 | #https://modrinth.com/mod/chest-tracker/versions 32 | chesttracker=2.6.7+1.21.4 33 | #https://modrinth.com/mod/where-is-it/versions?l=fabric 34 | whereisit=2.6.4+1.21.2 35 | #https://modrinth.com/mod/searchables/versions?l=fabric 36 | searchables=Searchables-fabric-1.21.6:1.0.2 37 | #https://modrinth.com/mod/yacl/versions?l=fabric 38 | yacl=3.7.1+1.21.6-fabric 39 | #https://modrinth.com/mod/modmenu/versions 40 | 41 | cloth_config=6 42 | cloth_api=6 43 | LibGui=6 44 | -------------------------------------------------------------------------------- /versions/mainProject: -------------------------------------------------------------------------------- 1 | 1.21.6 -------------------------------------------------------------------------------- /versions/mapping-1.18.2-1.19.4.txt: -------------------------------------------------------------------------------- 1 | net.minecraft.util.registry.Registry net.minecraft.registry.Registries 2 | net.minecraft.util.math.Matrix4f org.joml.Matrix4f -------------------------------------------------------------------------------- /versions/mapping-1.19.4-1.20.1.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaixianyu/wuhu-client/a8a021944e8c1f907c2cccaf819fb1ac3a44a5fb/versions/mapping-1.19.4-1.20.1.txt -------------------------------------------------------------------------------- /versions/mapping-1.20.1-1.20.2.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaixianyu/wuhu-client/a8a021944e8c1f907c2cccaf819fb1ac3a44a5fb/versions/mapping-1.20.1-1.20.2.txt -------------------------------------------------------------------------------- /versions/mapping-1.20.2-1.20.4.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaixianyu/wuhu-client/a8a021944e8c1f907c2cccaf819fb1ac3a44a5fb/versions/mapping-1.20.2-1.20.4.txt -------------------------------------------------------------------------------- /versions/mapping-1.20.4-1.20.6.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaixianyu/wuhu-client/a8a021944e8c1f907c2cccaf819fb1ac3a44a5fb/versions/mapping-1.20.4-1.20.6.txt -------------------------------------------------------------------------------- /versions/mapping-1.20.6-1.21.0.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaixianyu/wuhu-client/a8a021944e8c1f907c2cccaf819fb1ac3a44a5fb/versions/mapping-1.20.6-1.21.0.txt -------------------------------------------------------------------------------- /versions/mapping-1.21.0-1.21.4.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaixianyu/wuhu-client/a8a021944e8c1f907c2cccaf819fb1ac3a44a5fb/versions/mapping-1.21.0-1.21.4.txt -------------------------------------------------------------------------------- /versions/mapping-1.21.4-1.21.5.txt: -------------------------------------------------------------------------------- 1 | fi.dy.masa.malilib.util.Color4f fi.dy.masa.malilib.util.data.Color4f 2 | fi.dy.masa.litematica.render.RenderUtils fi.dy.masa.malilib.render.RenderUtils 3 | net.minecraft.entity.player.PlayerInventory selectedSlot net.minecraft.entity.player.PlayerInventory getSelectedSlot() 4 | net.minecraft.server.world.ServerWorld shouldTick() shouldTickBlockPos() 5 | net.minecraft.util.math.Direction getId() getIndex() -------------------------------------------------------------------------------- /versions/mapping-1.21.5-1.21.6.txt: -------------------------------------------------------------------------------- 1 | net.minecraft.client.network.ClientPlayNetworkHandler method_68823() getComponentHasher() --------------------------------------------------------------------------------