├── .github └── workflows │ └── build.yml ├── gradlew ├── README.md ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src └── main │ ├── resources │ ├── assets │ │ └── chestboatdupe │ │ │ └── icon.png │ ├── chestboatdupe.mixins.json │ └── fabric.mod.json │ └── java │ └── com │ └── mikarific │ └── chestboatdupe │ ├── SharedVariables.java │ ├── mixin │ ├── ClientPlayerEntityMixin.java │ └── GenericContainerScreenMixin.java │ ├── Util.java │ └── Main.java ├── settings.gradle ├── .gitignore ├── gradle.properties ├── gradlew.bat └── LICENSE /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mikarific/chest-boat-dupe/HEAD/gradlew -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mikarific/chest-boat-dupe/HEAD/README.md -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mikarific/chest-boat-dupe/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/assets/chestboatdupe/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mikarific/chest-boat-dupe/HEAD/src/main/resources/assets/chestboatdupe/icon.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { 4 | name = 'Fabric' 5 | url = 'https://maven.fabricmc.net/' 6 | } 7 | mavenCentral() 8 | gradlePluginPortal() 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/mikarific/chestboatdupe/SharedVariables.java: -------------------------------------------------------------------------------- 1 | package com.mikarific.chestboatdupe; 2 | 3 | public class SharedVariables { 4 | public static boolean ready = false; 5 | public static boolean shouldDupe = false; 6 | public static boolean shouldDupeAll = false; 7 | } -------------------------------------------------------------------------------- /.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/ -------------------------------------------------------------------------------- /src/main/resources/chestboatdupe.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "com.mikarific.chestboatdupe.mixin", 5 | "compatibilityLevel": "JAVA_17", 6 | "mixins": [ 7 | ], 8 | "client": [ 9 | "GenericContainerScreenMixin", 10 | "ClientPlayerEntityMixin" 11 | ], 12 | "injectors": { 13 | "defaultRequire": 1 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx1G 3 | 4 | # Fabric Properties 5 | # check these on https://fabricmc.net/develop 6 | minecraft_version=1.19 7 | yarn_mappings=1.19+build.1 8 | loader_version=0.14.6 9 | 10 | # Mod Properties 11 | mod_version = 1.0.0 12 | maven_group = com.mikarific.chestboatdupe 13 | archives_base_name = chest-boat-dupe 14 | 15 | # Dependencies 16 | fabric_version=0.55.1+1.19 17 | -------------------------------------------------------------------------------- /src/main/java/com/mikarific/chestboatdupe/mixin/ClientPlayerEntityMixin.java: -------------------------------------------------------------------------------- 1 | package com.mikarific.chestboatdupe.mixin; 2 | 3 | import com.mikarific.chestboatdupe.Main; 4 | import net.minecraft.client.world.ClientWorld; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 9 | 10 | @Mixin(ClientWorld.class) 11 | public class ClientPlayerEntityMixin { 12 | @Inject(at = @At("TAIL"), method = "tick") 13 | public void tick(CallbackInfo ci) { 14 | Main.tick(); 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "chest-boat-dupe", 4 | "version": "1.0.0", 5 | 6 | "name": "Chest Boat Dupe", 7 | "description": "A mod to perform the 1.19 Chest Boat Dupe.", 8 | "authors": [ 9 | "Mikarific" 10 | ], 11 | "contact": {}, 12 | 13 | "license": "CC0-1.0", 14 | "icon": "assets/chestboatdupe/icon.png", 15 | 16 | "environment": "*", 17 | "entrypoints": { 18 | "main": [ 19 | "com.mikarific.chestboatdupe.Main" 20 | ] 21 | }, 22 | "mixins": [ 23 | "chestboatdupe.mixins.json" 24 | ], 25 | 26 | "depends": { 27 | "fabricloader": ">=0.14.6", 28 | "fabric": "*", 29 | "minecraft": "~1.19", 30 | "java": ">=17" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/mikarific/chestboatdupe/Util.java: -------------------------------------------------------------------------------- 1 | package com.mikarific.chestboatdupe; 2 | 3 | import net.minecraft.client.MinecraftClient; 4 | import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; 5 | import net.minecraft.item.ItemStack; 6 | import net.minecraft.network.packet.c2s.play.ClickSlotC2SPacket; 7 | import net.minecraft.screen.GenericContainerScreenHandler; 8 | import net.minecraft.screen.slot.SlotActionType; 9 | 10 | import java.util.Objects; 11 | 12 | public class Util { 13 | public static final MinecraftClient CLIENT = MinecraftClient.getInstance(); 14 | 15 | public static void quickMoveAllItems() { 16 | for (int i = 0; i < 27; i++) { 17 | quickMoveItem(i); 18 | } 19 | } 20 | 21 | public static void quickMoveItem(int slot) { 22 | assert CLIENT.player != null; 23 | if (CLIENT.player.currentScreenHandler instanceof GenericContainerScreenHandler screenHandler) { 24 | Int2ObjectArrayMap stack = new Int2ObjectArrayMap<>(); 25 | stack.put(slot, screenHandler.getSlot(slot).getStack()); 26 | Objects.requireNonNull(CLIENT.getNetworkHandler()).sendPacket(new ClickSlotC2SPacket(screenHandler.syncId, 0, slot, 0, SlotActionType.QUICK_MOVE, screenHandler.getSlot(0).getStack(), stack)); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/mikarific/chestboatdupe/Main.java: -------------------------------------------------------------------------------- 1 | package com.mikarific.chestboatdupe; 2 | 3 | import net.fabricmc.api.ModInitializer; 4 | import net.minecraft.client.gui.screen.TitleScreen; 5 | import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen; 6 | import net.minecraft.screen.GenericContainerScreenHandler; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import static com.mikarific.chestboatdupe.SharedVariables.*; 11 | import static com.mikarific.chestboatdupe.Util.*; 12 | 13 | public class Main implements ModInitializer { 14 | @Override 15 | public void onInitialize() { 16 | } 17 | 18 | public static void tick() { 19 | if (String.valueOf(CLIENT.world != null ? CLIENT.world.getTime() : 0).endsWith("00")) { 20 | assert CLIENT.player != null; 21 | boolean b1 = (CLIENT.player.currentScreenHandler instanceof GenericContainerScreenHandler); 22 | if (!b1) { 23 | ready = false; 24 | shouldDupe = false; 25 | shouldDupeAll = false; 26 | } 27 | if (shouldDupe) { 28 | quickMoveItem(0); 29 | shouldDupe = false; 30 | } 31 | if (shouldDupeAll) { 32 | quickMoveAllItems(); 33 | shouldDupeAll = false; 34 | } 35 | if (ready) { 36 | CLIENT.world.disconnect(); 37 | CLIENT.disconnect(); 38 | CLIENT.setScreen(new MultiplayerScreen(new TitleScreen())); 39 | ready = false; 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /src/main/java/com/mikarific/chestboatdupe/mixin/GenericContainerScreenMixin.java: -------------------------------------------------------------------------------- 1 | package com.mikarific.chestboatdupe.mixin; 2 | 3 | import net.minecraft.client.MinecraftClient; 4 | import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; 5 | import net.minecraft.client.gui.screen.ingame.HandledScreen; 6 | import net.minecraft.client.gui.widget.ButtonWidget; 7 | import net.minecraft.client.util.math.MatrixStack; 8 | import net.minecraft.entity.player.PlayerInventory; 9 | import net.minecraft.entity.vehicle.ChestBoatEntity; 10 | import net.minecraft.screen.GenericContainerScreenHandler; 11 | import net.minecraft.text.Text; 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.CallbackInfo; 16 | 17 | import static com.mikarific.chestboatdupe.SharedVariables.*; 18 | 19 | @Mixin(GenericContainerScreen.class) 20 | public abstract class GenericContainerScreenMixin extends HandledScreen { 21 | public GenericContainerScreenMixin(GenericContainerScreenHandler handler, PlayerInventory inventory, Text title) { 22 | super(handler, inventory, title); 23 | } 24 | 25 | @Inject(at = @At("TAIL"), method = "render(Lnet/minecraft/client/util/math/MatrixStack;IIF)V") 26 | public void render(MatrixStack matrices, int mouseX, int mouseY, float delta, CallbackInfo ci) { 27 | assert MinecraftClient.getInstance().player != null; 28 | if (this.getTitle().getString().equals(Text.translatable("entity.minecraft.chest_boat").getString())) { 29 | this.textRenderer.drawWithShadow(matrices, "Chest Boat Dupe Mod by Mikarific.", (float) this.width/2-90, (float) this.height/2+90, 16777215); 30 | if (MinecraftClient.getInstance().player.getVehicle() instanceof ChestBoatEntity) { 31 | if (!ready) { 32 | this.addDrawableChild(new ButtonWidget(this.width/2-90, this.height/2+35-145, 50, 20, Text.of("Ready!"), (button) -> { 33 | if (shouldDupe) shouldDupe = false; 34 | if (shouldDupeAll) shouldDupeAll = false; 35 | ready = true; 36 | })); 37 | } else { 38 | this.textRenderer.drawWithShadow(matrices, "Duping on the next opportunity...", (float) this.width/2-90, (float) this.height/2+35-160, 16777215); 39 | } 40 | } else { 41 | if (!shouldDupe) { 42 | this.addDrawableChild(new ButtonWidget(this.width/2-90, this.height/2+35-145, 50, 20, Text.of("Dupe"), (button) -> { 43 | if (ready) ready = false; 44 | if (shouldDupeAll) shouldDupeAll = false; 45 | shouldDupe = true; 46 | })); 47 | } else { 48 | this.textRenderer.drawWithShadow(matrices, "Duping on the next opportunity...", (float) this.width/2-90, (float) this.height/2+35-160, 16777215); 49 | } 50 | if (!shouldDupeAll) { 51 | this.addDrawableChild(new ButtonWidget(this.width/2+40, this.height/2+35-145, 50, 20, Text.of("Dupe All"), (button) -> { 52 | if (ready) ready = false; 53 | if (shouldDupe) shouldDupe = false; 54 | shouldDupeAll = true; 55 | })); 56 | } else { 57 | this.textRenderer.drawWithShadow(matrices, "Duping on the next opportunity...", (float) this.width/2-90, (float) this.height/2+35-160, 16777215); 58 | } 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /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. 122 | --------------------------------------------------------------------------------