├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ └── feature_request.md ├── assets │ └── discord-join-badge.svg └── workflows │ └── build-and-release.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── build.gradle ├── common ├── build.gradle └── src │ └── main │ ├── java │ └── pro │ │ └── mikey │ │ └── autoclicker │ │ ├── AutoClicker.java │ │ ├── Config.java │ │ ├── Holding.java │ │ ├── Language.java │ │ ├── OptionsScreen.java │ │ └── OptionsSliderWidget.java │ └── resources │ ├── assets │ └── autoclicker │ │ ├── icon.png │ │ └── lang │ │ ├── en_us.json │ │ └── es_es.json │ └── autoclicker.mixins.json ├── fabric ├── build.gradle └── src │ └── main │ ├── java │ └── pro │ │ └── mikey │ │ └── autoclicker │ │ └── fabric │ │ └── client │ │ ├── AutoClickerFabricClient.java │ │ └── ModMenuAPIImpl.java │ └── resources │ └── fabric.mod.json ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── neoforge ├── build.gradle ├── gradle.properties └── src │ └── main │ ├── java │ └── pro │ │ └── mikey │ │ └── autoclicker │ │ └── neoforge │ │ └── AutoClickerNeoForge.java │ └── resources │ └── META-INF │ └── neoforge.mods.toml └── settings.gradle /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: If you've found a bug that you think needs to be fixed then use this template. Be sure to fill out the form as shown and don't leave any sections off. 4 | --- 5 | 6 | **Describe the bug** 7 | A clear and concise description of what the bug is. 8 | 9 | **To Reproduce** 10 | Steps to reproduce the behavior: 11 | 1. step one 12 | 13 | **Expected behavior** 14 | A clear and concise description of what you expected to happen. 15 | 16 | **Screenshots** 17 | If applicable (delete if not), add screenshots to help explain your problem. 18 | 19 | **Minecraft Enviorment** 20 | - Minecraft Version: [eg: 1.12.2] 21 | - XRay Mod Version: [eg: 1.5.0] 22 | - Mod Pack & Version if applicable 23 | - Forge Version if applicable 24 | 25 | **Additional context** 26 | Add any other context about the problem here. 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/assets/discord-join-badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /.github/workflows/build-and-release.yml: -------------------------------------------------------------------------------- 1 | name: CI Build & Release 2 | 3 | on: 4 | push: 5 | tags: [ "v*" ] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | if: | 11 | !contains(github.event.head_commit.message, '[ciskip]') 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: Set up JDK 21 & Cache 15 | uses: actions/setup-java@v4 16 | with: 17 | distribution: 'microsoft' 18 | java-version: '21' 19 | cache: 'gradle' 20 | - name: Release 21 | if: | 22 | !contains(github.event.head_commit.message, '[norelease]') 23 | env: 24 | GIT_COMMIT: ${{ github.event.after }} 25 | GIT_PREVIOUS_COMMIT: ${{ github.event.before }} 26 | CURSE_DEPLOY_TOKEN: ${{ secrets.CURSE_DEPLOY_TOKEN }} 27 | SAPS_TOKEN: ${{ secrets.SAPS_TOKEN }} 28 | MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }} 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | run: | 31 | chmod +x ./gradlew 32 | ./gradlew clean build publish publishMods --stacktrace --no-daemon 33 | -------------------------------------------------------------------------------- /.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 | remappedSrc/ 34 | run/ 35 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [21.5.0] 2 | 3 | ### Changed 4 | 5 | - Updated to 1.21.5 6 | 7 | ## [21.1.0] 8 | 9 | ### Changed 10 | 11 | - Auto clicker is now available for Neoforge as well as Fabric! Thanks to [@AdyTech99](https://github.com/AdyTech99) 12 | 13 | ## [21.0.3] 14 | 15 | ### Changed 16 | 17 | - You can now set the 'spamming' delay to any value using an input instead of a slider thanks to [@AdyTech99](https://github.com/AdyTech99) 18 | 19 | ### Fixed 20 | 21 | - Auto clicker would fail to work if 'spamming' was set to `1` on the delay. Thanks to [@AdyTech99](https://github.com/AdyTech99) 22 | 23 | ## [21.0.2] 24 | 25 | ### Added 26 | 27 | - Option to move the hud around on the screen [#26](https://github.com/AdvancedXRay/Auto-Clicker/issues/26) thanks to [@AdyTech99](https://github.com/AdyTech99) ([#61](https://github.com/AdvancedXRay/Auto-Clicker/pull/61)) 28 | - Mod menu support for opening the config screen via Mod Menu [#59](https://github.com/AdvancedXRay/Auto-Clicker/issues/59) thanks to [@AdyTech99](https://github.com/AdyTech99) ([#61](https://github.com/AdvancedXRay/Auto-Clicker/pull/61)) 29 | 30 | ### Changed 31 | 32 | - Better support invalid config values [#60](https://github.com/AdvancedXRay/Auto-Clicker/issues/60) thanks to [@AdyTech99](https://github.com/AdyTech99) ([#61](https://github.com/AdvancedXRay/Auto-Clicker/pull/61)) 33 | 34 | ## [21.0.1] 35 | 36 | ### Fixed 37 | 38 | - Correctly unpress buttons we were holding [#54](https://github.com/AdvancedXray/Auto-clicker/issues/54) thanks to [@AdyTech99](https://github.com/AdyTech99) 39 | - Auto clicker attackas entities that are in the dying stage [#55](https://github.com/AdvancedXray/Auto-clicker/issues/55) thanks to [@AdyTech99](https://github.com/AdyTech99) 40 | - Auto clicker will continue to attack entities that have died [#56](https://github.com/AdvancedXray/Auto-clicker/issues/56) thanks to [@AdyTech99](https://github.com/AdyTech99) 41 | - Disable autoclicker on death [#57](https://github.com/AdvancedXray/Auto-clicker/issues/57) thanks to [@AdyTech99](https://github.com/AdyTech99) 42 | 43 | ## [21.0.0] 44 | 45 | ### Changes 46 | 47 | - Ported to 1.21 48 | 49 | ## [20.6.1] 50 | 51 | ### Added 52 | 53 | - Added a new config option to respect your shield being held and active (Thanks to [#53](https://github.com/AdvancedXRay/Auto-Clicker/pull/53) [@AdyTech99](https://github.com/AdyTech99)) 54 | 55 | ### Changed 56 | 57 | - Messed with the version number, we're now using Neoforges versioning system 58 | 59 | ## [86.0.0] 60 | 61 | ### Changed 62 | 63 | - Updated to 1.20.6 64 | 65 | ## [84.0.1] 66 | 67 | ### Fixed 68 | 69 | - Actually trigger the arm swing animation 70 | 71 | ## [84.0.0] 72 | 73 | ### Changed 74 | 75 | - Updated to 1.20.4 76 | 77 | ## [83.0.0] 78 | 79 | ### Changed 80 | 81 | - Updated to 1.20.3 82 | 83 | ## [1.8.0] 84 | 85 | ### Changed 86 | 87 | - Ported to 1.20.1 88 | 89 | ## [1.7.0] 90 | 91 | ### Changed 92 | 93 | - Ported to 1.20.0 94 | 95 | ## [1.8.0] 96 | 97 | ### Changed 98 | 99 | - Ported to 1.20.1 100 | 101 | ## [1.9.0] 102 | 103 | ### Changed 104 | 105 | - Ported to 1.20.2 106 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Michael Hillcox 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Auto Clicker (Fabric) 2 | 3 | Quick and dirty Auto Clicker mod for Fabric(mc) 4 | 5 | [![Downloads](http://cf.way2muchnoise.eu/full_445095_downloads.svg)](https://www.curseforge.com/minecraft/mc-mods/auto-clicker-fabric) 6 | [![Versions Supported](http://cf.way2muchnoise.eu/versions/445095.svg)](https://www.curseforge.com/minecraft/mc-mods/auto-clicker-fabric) 7 | [![GitHub license](https://img.shields.io/github/license/AdvancedXRay/Auto-Clicker-Fabric)](https://github.com/AdvancedXRay/Auto-Clicker-Fabric/blob/main/LICENSE) 8 | [![GitHub stars](https://img.shields.io/github/stars/AdvancedXRay/Auto-Clicker-Fabric)](https://github.com/AdvancedXRay/Auto-Clicker-Fabric/stargazers) 9 | [![GitHub issues](https://img.shields.io/github/issues/AdvancedXRay/Auto-Clicker-Fabric)](https://github.com/AdvancedXRay/Auto-Clicker-Fabric/issues) 10 | ![GitHub all releases](https://img.shields.io/github/downloads/AdvancedXRay/Auto-Clicker-Fabric/total) 11 | ![GitHub release (latest by date)](https://img.shields.io/github/v/release/AdvancedXRay/Auto-Clicker-Fabric) 12 | ![GitHub Release Date](https://img.shields.io/github/release-date/AdvancedXRay/Auto-Clicker-Fabric) 13 | ![GitHub last commit](https://img.shields.io/github/last-commit/AdvancedXRay/Auto-Clicker-Fabric) 14 | [![Build Status](https://ci.mikey.pro/buildStatus/icon?job=Auto-Clicker-Fabric%2Fmain)](https://ci.mikey.pro/job/Auto-Clicker-Fabric/job/main/) 15 | 16 | ## Features 17 | - Auto click (hold & spam) for Right and Left click 18 | - Support for AFK farms when respecting cool down 19 | - Configurable spam timeout (speed) 20 | - (almost) No janky key press logic, all native Minecraft key button handling. 21 | 22 | ## How to use (Subject to change) 23 | - Open GUI with `O` (default key) to enable and edit the settings of each button being clicked 24 | - Use `I` (default key) to enable auto clicker 25 | 26 | ### Option descriptions 27 | - `Active`: Enables that key to be held when `Auto Clicker` is active (holding) 28 | - `Spamming`: Enables per tick spamming meaning every tick the button is quickly pressed and un-pressed 29 | - `Speed`: Speed controls how fast (per tick) the spamming will happen, 0 being the quickest, 10 being the fastest 30 | - `Respect cooldown`: Will Attack only once the cooldown has cooled down :tada: 31 | 32 | ## Previews 33 | 34 | The [Imgur Album](https://imgur.com/a/ASZXIiO) 35 | ![Auto Clicker](https://i.imgur.com/CgQk5uE.png) 36 | 37 | ## Use on public servers 38 | 39 | I **DO NOT** support the use of this mod on any public servers which do not allow this kind of mod. The mod **does** work on servers but I do not approve of, and will not, support anyone that attempts to use this mod on servers. I **do not** have the time to review each issue; I will simply close any issue with server connections in the crash log. 40 | 41 | If you wish to use this mod on private servers then that's on you. If you use this on public servers and are banned then that's on you and I will **not** support your use of this mod in that way. 42 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'dev.architectury.loom' version '1.10-SNAPSHOT' apply false 3 | id 'architectury-plugin' version '3.4-SNAPSHOT' 4 | id 'com.github.johnrengelman.shadow' version '8.1.1' apply false 5 | id 'maven-publish' 6 | id 'pro.mikey.plugins.insaniam' version "0.1-SNAPSHOT" 7 | id "me.modmuss50.mod-publish-plugin" version "0.7.4" 8 | } 9 | 10 | architectury { 11 | minecraft = project.minecraft_version 12 | } 13 | 14 | allprojects { 15 | group = rootProject.maven_group 16 | version = rootProject.mod_version 17 | } 18 | 19 | subprojects { 20 | version = project.mod_version 21 | group = project.maven_group 22 | 23 | apply plugin: 'dev.architectury.loom' 24 | apply plugin: 'architectury-plugin' 25 | apply plugin: 'maven-publish' 26 | 27 | base { 28 | // Set up a suffixed format for the mod jar names, e.g. `example-fabric`. 29 | archivesName = "$rootProject.archives_name-$project.name" 30 | } 31 | 32 | repositories { 33 | maven { url "https://maven.terraformersmc.com/releases/"} 34 | maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } 35 | } 36 | 37 | dependencies { 38 | minecraft "net.minecraft:minecraft:$rootProject.minecraft_version" 39 | mappings loom.officialMojangMappings() 40 | } 41 | 42 | java { 43 | withSourcesJar() 44 | 45 | sourceCompatibility = JavaVersion.VERSION_21 46 | targetCompatibility = JavaVersion.VERSION_21 47 | } 48 | 49 | tasks.withType(JavaCompile).configureEach { 50 | it.options.release = 21 51 | it.options.encoding = "UTF-8" 52 | } 53 | 54 | jar { 55 | from("LICENSE") { 56 | rename { "${it}_${project.archivesBaseName}" } 57 | } 58 | } 59 | 60 | // Configure Maven publishing. 61 | publishing { 62 | publications { 63 | mavenJava(MavenPublication) { 64 | groupId project.group 65 | artifactId project.archivesBaseName 66 | version project.version 67 | from components.java 68 | } 69 | } 70 | 71 | repositories { 72 | def token = providers.environmentVariable("SAPS_TOKEN") 73 | if (token.isPresent()) { 74 | maven { 75 | url "https://maven.saps.dev/releases" 76 | credentials { 77 | username = "mikeymods" 78 | password = token.get() 79 | } 80 | } 81 | } 82 | } 83 | } 84 | } 85 | 86 | def changelogData = insaniamUtils.createChangelog { 87 | file = file('CHANGELOG.md') 88 | versionPattern = ~/## \[[^]]+]/ 89 | fallbackValue = "No changelog provided" 90 | version = project.mod_version 91 | } 92 | 93 | publishMods { 94 | def curseToken = providers.environmentVariable("CURSE_DEPLOY_TOKEN") 95 | 96 | dryRun = !curseToken.isPresent() 97 | changelog = changelogData 98 | version = project.mod_version 99 | type = STABLE 100 | 101 | def createOptions = (String name) -> { 102 | publishOptions { 103 | file = project.provider { project(":$name").tasks.remapJar }.flatMap { it.archiveFile } 104 | displayName = "[${name.toUpperCase()}][${minecraft_version}] Auto Clicker ${mod_version}" 105 | modLoaders.add(name.toLowerCase()) 106 | } 107 | } 108 | 109 | def curseForgeOptions = curseforgeOptions { 110 | projectId = project.curseforge_id 111 | accessToken = providers.environmentVariable("CURSE_DEPLOY_TOKEN") 112 | minecraftVersions.add("${minecraft_version}") 113 | javaVersions.add(JavaVersion.VERSION_21) 114 | } 115 | 116 | def modrinthOptions = modrinthOptions { 117 | accessToken = providers.environmentVariable("MODRINTH_TOKEN") 118 | projectId = project.modrinth_id 119 | minecraftVersions.add("${minecraft_version}") 120 | } 121 | 122 | def fabricOptions = createOptions("fabric") 123 | def neoforgeOptions = createOptions("neoforge") 124 | 125 | curseforge("curseforgeFabric") { 126 | from(curseForgeOptions, fabricOptions) 127 | requires("fabric-api") 128 | } 129 | 130 | curseforge("curseforgeNeoforge") { 131 | from(curseForgeOptions, neoforgeOptions) 132 | } 133 | 134 | modrinth("modrinthFabric") { 135 | from(modrinthOptions, fabricOptions) 136 | requires("fabric-api") 137 | } 138 | 139 | modrinth("modrinthNeoforge") { 140 | from(modrinthOptions, neoforgeOptions) 141 | } 142 | 143 | github { 144 | file = project.provider { project(":neoforge").tasks.remapJar }.flatMap { it.archiveFile } 145 | additionalFiles.from project.provider { project(":fabric").tasks.remapJar }.flatMap { it.archiveFile } 146 | additionalFiles.from project.provider { project(":common").tasks.remapJar }.flatMap { it.archiveFile } 147 | 148 | repository = "AdvancedXRay/Auto-Clicker" 149 | accessToken = providers.environmentVariable("GITHUB_TOKEN") 150 | commitish = providers.environmentVariable("GITHUB_SHA").orElse("main") 151 | tagName = providers.environmentVariable("GITHUB_REF_NAME").orElse("v${mod_version}") 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /common/build.gradle: -------------------------------------------------------------------------------- 1 | architectury { 2 | common rootProject.enabled_platforms.split(',') 3 | } 4 | 5 | dependencies { 6 | // We depend on Fabric Loader here to use the Fabric @Environment annotations, 7 | // which get remapped to the correct annotations on each platform. 8 | // Do NOT use other classes from Fabric Loader. 9 | modImplementation "net.fabricmc:fabric-loader:$rootProject.fabric_loader_version" 10 | } 11 | -------------------------------------------------------------------------------- /common/src/main/java/pro/mikey/autoclicker/AutoClicker.java: -------------------------------------------------------------------------------- 1 | package pro.mikey.autoclicker; 2 | 3 | import com.google.common.base.Suppliers; 4 | import com.google.gson.Gson; 5 | import it.unimi.dsi.fastutil.Pair; 6 | import net.minecraft.ChatFormatting; 7 | import net.minecraft.client.DeltaTracker; 8 | import net.minecraft.client.KeyMapping; 9 | import net.minecraft.client.Minecraft; 10 | import net.minecraft.client.gui.GuiGraphics; 11 | import net.minecraft.client.player.LocalPlayer; 12 | import net.minecraft.client.resources.language.I18n; 13 | import net.minecraft.network.chat.Component; 14 | import net.minecraft.util.LazyLoadedValue; 15 | import net.minecraft.world.InteractionHand; 16 | import net.minecraft.world.entity.LivingEntity; 17 | import net.minecraft.world.item.ShieldItem; 18 | import net.minecraft.world.phys.EntityHitResult; 19 | import net.minecraft.world.phys.HitResult; 20 | import org.apache.commons.lang3.concurrent.LazyInitializer; 21 | import org.apache.logging.log4j.LogManager; 22 | import org.apache.logging.log4j.Logger; 23 | import org.lwjgl.glfw.GLFW; 24 | 25 | import java.io.FileReader; 26 | import java.io.FileWriter; 27 | import java.io.IOException; 28 | import java.nio.file.Files; 29 | import java.nio.file.Path; 30 | import java.nio.file.Paths; 31 | import java.util.function.Supplier; 32 | 33 | public class AutoClicker { 34 | public static final String MOD_ID = "autoclicker"; 35 | public static final Logger LOGGER = LogManager.getLogger(MOD_ID); 36 | public static final KeyMapping openConfig = 37 | new KeyMapping("keybinding.open-gui", GLFW.GLFW_KEY_O, "category.autoclicker-fabric"); 38 | public static final KeyMapping toggleHolding = 39 | new KeyMapping("keybinding.toggle-hold", GLFW.GLFW_KEY_I, "category.autoclicker-fabric"); 40 | 41 | private static final Supplier> CONFIG_PATHS = Suppliers.memoize(() -> { 42 | Path configDir = Paths.get(Minecraft.getInstance().gameDirectory.getPath() + "/config"); 43 | Path configFile = Paths.get(configDir + "/auto-clicker-fabric.json"); 44 | return Pair.of(configDir, configFile); 45 | }); 46 | 47 | public static Holding.AttackHolding leftHolding; 48 | public static Holding rightHolding; 49 | public static Holding jumpHolding; 50 | public static Config.HudConfig hudConfig; 51 | private static AutoClicker INSTANCE; 52 | private boolean isActive = false; 53 | private Config config = new Config( 54 | new Config.LeftMouseConfig(false, false, 0, false, false, false), 55 | new Config.RightMouseConfig(false, false, 0), 56 | new Config.JumpConfig(false, false, 0), 57 | new Config.HudConfig(true, "top-left") 58 | ); 59 | 60 | public AutoClicker() { 61 | INSTANCE = this; 62 | } 63 | 64 | public static AutoClicker getInstance() { 65 | return INSTANCE; 66 | } 67 | 68 | public void onInitialize() { 69 | LOGGER.info("Auto Clicker Initialised"); 70 | } 71 | 72 | public void clientReady(Minecraft client) { 73 | var configPaths = CONFIG_PATHS.get(); 74 | if (!Files.exists(configPaths.value())) { 75 | try { 76 | Files.createDirectories(configPaths.key()); 77 | Files.createFile(configPaths.value()); 78 | } catch (IOException e) { 79 | e.printStackTrace(); 80 | } 81 | 82 | this.saveConfig(); 83 | } else { 84 | try { 85 | FileReader json = new FileReader(configPaths.value().toFile()); 86 | Config config = new Gson().fromJson(json, Config.class); 87 | json.close(); 88 | if (config != null && config.getHudConfig() != null) { 89 | this.config = config; 90 | } 91 | } catch (Exception e){ 92 | e.printStackTrace(); 93 | this.saveConfig(); 94 | } 95 | } 96 | 97 | leftHolding = new Holding.AttackHolding(client.options.keyAttack, this.config.getLeftClick()); 98 | rightHolding = new Holding(client.options.keyUse, this.config.getRightClick()); 99 | jumpHolding = new Holding(client.options.keyJump, this.config.getJump()); 100 | hudConfig = this.config.getHudConfig(); 101 | } 102 | 103 | public void saveConfig() { 104 | var configPaths = CONFIG_PATHS.get(); 105 | try { 106 | FileWriter writer = new FileWriter(configPaths.value().toFile()); 107 | 108 | new Gson().toJson(this.config, writer); 109 | writer.flush(); 110 | writer.close(); 111 | } catch (IOException e) { 112 | e.printStackTrace(); 113 | } 114 | } 115 | 116 | public void renderGameOverlayEvent(GuiGraphics context, DeltaTracker delta) { 117 | 118 | if ((!leftHolding.isActive() && !rightHolding.isActive() && !jumpHolding.isActive()) || !this.isActive || !config.getHudConfig().isEnabled()) { 119 | return; 120 | } 121 | 122 | Minecraft client = Minecraft.getInstance(); 123 | 124 | if (leftHolding.isActive()) { 125 | Component text = Language.HUD_HOLDING.getText(I18n.get(leftHolding.getKey().getName())); 126 | int y = getHudY() + (15 * 0); 127 | int x = getHudX(text); 128 | context.drawString(client.font, text.getVisualOrderText(), x, y, 0xffffff); 129 | } 130 | 131 | if (rightHolding.isActive()) { 132 | Component text = Language.HUD_HOLDING.getText(I18n.get(rightHolding.getKey().getName())); 133 | int y = getHudY() + (15 * 1); 134 | int x = getHudX(text); 135 | context.drawString(client.font, text.getVisualOrderText(), x, y, 0xffffff); 136 | } 137 | 138 | if (jumpHolding.isActive()) { 139 | Component text = Language.HUD_HOLDING.getText(I18n.get(jumpHolding.getKey().getName())); 140 | int y = getHudY() + (15 * 2); 141 | int x = getHudX(text); 142 | context.drawString(client.font, text.getVisualOrderText(), x, y, 0xffffff); 143 | } 144 | } 145 | 146 | public int getHudX(Component text){ 147 | Minecraft client = Minecraft.getInstance(); 148 | 149 | String location = this.config.getHudConfig().getLocation(); 150 | return switch (location) { 151 | case "top-left", "bottom-left" -> 10; 152 | case "top-right", "bottom-right" -> (Minecraft.getInstance().getWindow().getGuiScaledWidth()) - 10 - client.font.width(text); 153 | default -> 10; 154 | }; 155 | } 156 | public int getHudY(){ 157 | String location = this.config.getHudConfig().getLocation(); 158 | return switch (location) { 159 | case "top-left", "top-right" -> 10; 160 | case "bottom-left", "bottom-right" -> (Minecraft.getInstance().getWindow().getGuiScaledHeight()) - 50; 161 | default -> 10; 162 | }; 163 | } 164 | 165 | public void clientTickEvent(Minecraft mc) { 166 | if (mc.player == null || mc.level == null) { 167 | return; 168 | } 169 | if(!mc.player.isAlive()) this.isActive = false; 170 | 171 | if (this.isActive) { 172 | if (leftHolding.isActive()) { 173 | this.handleActiveHolding(mc, leftHolding); 174 | } 175 | 176 | if (rightHolding.isActive()) { 177 | this.handleActiveHolding(mc, rightHolding); 178 | } 179 | 180 | if (jumpHolding.isActive()) { 181 | this.handleActiveHolding(mc, jumpHolding); 182 | } 183 | } 184 | 185 | this.keyInputEvent(mc); 186 | } 187 | 188 | private void handleActiveHolding(Minecraft mc, Holding key) { 189 | assert mc.player != null; 190 | if (!key.isActive()) { 191 | return; 192 | } 193 | 194 | if (key.isSpamming()) { 195 | // How to handle the click if it's done by spamming 196 | if (key.getSpeed() > 0) { 197 | if (key.getTimeout() <= 1) { 198 | if (key.getTimeout() <= 0) { 199 | key.resetTimeout(); 200 | } 201 | 202 | // Press the button twice by toggling 1 and 0 203 | key.getKey().setDown(key.getTimeout() == 1); 204 | 205 | if (key.getKey().isDown()) { 206 | this.attemptMobAttack(mc, key); 207 | } 208 | } 209 | key.decreaseTimeout(); 210 | } else { 211 | // Handle the click if it's done normally 212 | key.getKey().setDown(!key.getKey().isDown()); 213 | if (key.getKey().isDown()) { 214 | this.attemptMobAttack(mc, key); 215 | } 216 | } 217 | 218 | return; 219 | } 220 | 221 | // Normal holding or cool down behaviour 222 | // respect cool down 223 | if (key.isRespectCooldown()) { 224 | // Don't do anything if they're not looking at something 225 | if (key instanceof Holding.AttackHolding && ((Holding.AttackHolding) key).isMobMode() && !this.isPlayerLookingAtMob(mc)) { 226 | if (key.getKey().isDown()) { 227 | key.getKey().setDown(false); 228 | } 229 | return; 230 | } 231 | 232 | if (mc.player.getAttackStrengthScale(0) == 1.0F) { 233 | key.getKey().setDown(true); 234 | this.attemptMobAttack(mc, key); 235 | } else { 236 | key.getKey().setDown(false); 237 | } 238 | } else { 239 | // Hold the click 240 | key.getKey().setDown(true); 241 | } 242 | } 243 | 244 | private void attemptMobAttack(Minecraft mc, Holding key) { 245 | // Don't attack on a right click 246 | if (key.getKey() != leftHolding.getKey()) { 247 | return; 248 | } 249 | 250 | HitResult rayTrace = mc.hitResult; 251 | if (rayTrace instanceof EntityHitResult && mc.gameMode != null) { 252 | if(!(config.getLeftClick().isRespectShield() && isShielding(mc.player))) { 253 | mc.gameMode.attack(mc.player, ((EntityHitResult) rayTrace).getEntity()); 254 | if (mc.player != null) { 255 | mc.player.swing(InteractionHand.MAIN_HAND); 256 | } 257 | } 258 | } 259 | } 260 | 261 | private boolean isShielding(LocalPlayer player) { 262 | if (player.isUsingItem()) { 263 | return player.getUseItem().getItem() instanceof ShieldItem; 264 | } 265 | return false; 266 | } 267 | 268 | private boolean isPlayerLookingAtMob(Minecraft mc) { 269 | HitResult rayTrace = mc.hitResult; 270 | return rayTrace instanceof EntityHitResult && ((EntityHitResult) rayTrace).getEntity() instanceof LivingEntity livingEntity && livingEntity.isAlive() && livingEntity.isAttackable(); 271 | } 272 | 273 | private void keyInputEvent(Minecraft mc) { 274 | assert mc.player != null; 275 | while (toggleHolding.consumeClick()) { 276 | this.isActive = !this.isActive; 277 | mc.player.displayClientMessage( 278 | (this.isActive ? Language.MSG_HOLDING_KEYS : Language.MSG_RELEASED_KEYS) 279 | .getText() 280 | .withStyle(this.isActive ? ChatFormatting.GREEN : ChatFormatting.RED), 281 | true 282 | ); 283 | 284 | if (!this.isActive) { 285 | if(leftHolding.isActive()) leftHolding.getKey().setDown(false); 286 | if(rightHolding.isActive()) rightHolding.getKey().setDown(false); 287 | if(jumpHolding.isActive()) jumpHolding.getKey().setDown(false); 288 | } 289 | } 290 | 291 | while (openConfig.consumeClick()) { 292 | mc.setScreen(getConfigScreen()); 293 | } 294 | } 295 | 296 | public OptionsScreen getConfigScreen(){ 297 | return new OptionsScreen(); 298 | } 299 | } 300 | -------------------------------------------------------------------------------- /common/src/main/java/pro/mikey/autoclicker/Config.java: -------------------------------------------------------------------------------- 1 | package pro.mikey.autoclicker; 2 | 3 | public class Config { 4 | 5 | private final LeftMouseConfig leftClick; 6 | private final RightMouseConfig rightClick; 7 | private final JumpConfig jump; 8 | private final HudConfig hudConfig; 9 | 10 | public Config(LeftMouseConfig leftClick, RightMouseConfig rightClick, JumpConfig jump, HudConfig hudConfig) { 11 | this.leftClick = leftClick; 12 | this.rightClick = rightClick; 13 | this.jump = jump; 14 | this.hudConfig = hudConfig; 15 | } 16 | 17 | public LeftMouseConfig getLeftClick() { 18 | return this.leftClick; 19 | } 20 | 21 | public RightMouseConfig getRightClick() { 22 | return this.rightClick; 23 | } 24 | 25 | public JumpConfig getJump() { 26 | return this.jump; 27 | } 28 | 29 | public HudConfig getHudConfig(){return this.hudConfig;} 30 | 31 | @Override 32 | public String toString() { 33 | return "Config{" + 34 | "leftClick=" + this.leftClick + 35 | ", rightClick=" + this.rightClick + 36 | ", jump=" + this.jump + 37 | '}'; 38 | } 39 | 40 | public static class HudConfig { 41 | private boolean enabled; 42 | private String location; 43 | 44 | public HudConfig(Boolean enabled, String location){ 45 | this.enabled = enabled; 46 | this.location = location; 47 | } 48 | 49 | public boolean isEnabled() { 50 | return this.enabled; 51 | } 52 | 53 | public void setEnabled(boolean enabled) { 54 | this.enabled = enabled; 55 | } 56 | 57 | public String getLocation(){ 58 | return this.location; 59 | } 60 | 61 | public void setLocation(String location) { 62 | this.location = location; 63 | } 64 | 65 | public String toString(){ 66 | return "Config{" + 67 | "hudEnabled=" + this.enabled + 68 | ", hudLocation=" + this.location + 69 | '}'; 70 | } 71 | } 72 | 73 | public static class LeftMouseConfig extends SharedConfig { 74 | private boolean respectCooldown; 75 | private boolean respectShield; 76 | private boolean mobMode; 77 | 78 | public LeftMouseConfig(boolean active, boolean spamming, int cpt, boolean respectCooldown, boolean respectShield, boolean mobMode) { 79 | super(active, spamming, cpt); 80 | 81 | this.respectCooldown = respectCooldown; 82 | this.mobMode = mobMode; 83 | } 84 | 85 | public boolean isRespectCooldown() { 86 | return this.respectCooldown; 87 | } 88 | 89 | public void setRespectCooldown(boolean respectCooldown) { 90 | this.respectCooldown = respectCooldown; 91 | } 92 | 93 | public boolean isRespectShield() { 94 | return this.respectShield; 95 | } 96 | 97 | public void setRespectShield(boolean respectShield) { 98 | this.respectShield = respectShield; 99 | } 100 | 101 | public boolean isMobMode() { 102 | return this.mobMode; 103 | } 104 | 105 | public void setMobMode(boolean mobMode) { 106 | this.mobMode = mobMode; 107 | } 108 | } 109 | 110 | public static class RightMouseConfig extends SharedConfig { 111 | public RightMouseConfig(boolean active, boolean spamming, int cpt) { 112 | super(active, spamming, cpt); 113 | } 114 | } 115 | 116 | public static class JumpConfig extends SharedConfig { 117 | public JumpConfig(boolean active, boolean spamming, int cpt) { 118 | super(active, spamming, cpt); 119 | } 120 | } 121 | 122 | public static class SharedConfig { 123 | private boolean active; 124 | private boolean spamming; 125 | private int cpt; 126 | 127 | public SharedConfig(boolean active, boolean spamming, int cpt) { 128 | this.active = active; 129 | this.spamming = spamming; 130 | this.cpt = cpt; 131 | } 132 | 133 | public boolean isActive() { 134 | return this.active; 135 | } 136 | 137 | public void setActive(boolean active) { 138 | this.active = active; 139 | } 140 | 141 | public boolean isSpamming() { 142 | return this.spamming; 143 | } 144 | 145 | public void setSpamming(boolean spamming) { 146 | this.spamming = spamming; 147 | } 148 | 149 | public int getCpt() { 150 | return this.cpt; 151 | } 152 | 153 | public void setCpt(int cpt) { 154 | this.cpt = cpt; 155 | } 156 | 157 | @Override 158 | public String toString() { 159 | return "SharedConfig{" + 160 | "active=" + this.active + 161 | ", spamming=" + this.spamming + 162 | ", cpt=" + this.cpt + 163 | '}'; 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /common/src/main/java/pro/mikey/autoclicker/Holding.java: -------------------------------------------------------------------------------- 1 | package pro.mikey.autoclicker; 2 | 3 | import net.minecraft.client.KeyMapping; 4 | 5 | public class Holding { 6 | private final KeyMapping key; 7 | Config.SharedConfig config; 8 | private int timeout; 9 | 10 | public Holding(KeyMapping key, Config.SharedConfig config) { 11 | this.config = config; 12 | this.key = key; 13 | this.timeout = config.getCpt(); 14 | } 15 | 16 | public boolean isRespectCooldown() { 17 | return this.config instanceof Config.LeftMouseConfig && ((Config.LeftMouseConfig) this.config).isRespectCooldown(); 18 | } 19 | 20 | public void setRespectCooldown(boolean respectCooldown) { 21 | if (!(this.config instanceof Config.LeftMouseConfig)) { 22 | return; 23 | } 24 | 25 | ((Config.LeftMouseConfig) this.config).setRespectCooldown(respectCooldown); 26 | } 27 | 28 | public boolean isRespectShield() { 29 | return this.config instanceof Config.LeftMouseConfig && ((Config.LeftMouseConfig) this.config).isRespectShield(); 30 | } 31 | 32 | public void setRespectShield(boolean respectShield) { 33 | if (!(this.config instanceof Config.LeftMouseConfig)) { 34 | return; 35 | } 36 | 37 | ((Config.LeftMouseConfig) this.config).setRespectShield(respectShield); 38 | } 39 | 40 | public KeyMapping getKey() { 41 | return this.key; 42 | } 43 | 44 | public boolean isActive() { 45 | return this.config.isActive(); 46 | } 47 | 48 | public void setActive(boolean active) { 49 | this.config.setActive(active); 50 | } 51 | 52 | public boolean isSpamming() { 53 | return this.config.isSpamming(); 54 | } 55 | 56 | public void setSpamming(boolean spamming) { 57 | this.config.setSpamming(spamming); 58 | } 59 | 60 | public int getSpeed() { 61 | return this.config.getCpt(); 62 | } 63 | 64 | public void setSpeed(int speed) { 65 | this.config.setCpt(speed); 66 | } 67 | 68 | public int getTimeout() { 69 | return this.timeout; 70 | } 71 | 72 | public void resetTimeout() { 73 | this.timeout = this.config.getCpt(); 74 | } 75 | 76 | public void decreaseTimeout() { 77 | if ((this.timeout - 1) < 0) { 78 | return; 79 | } 80 | 81 | this.timeout -= 1; 82 | } 83 | 84 | public static class AttackHolding extends Holding { 85 | 86 | public AttackHolding(KeyMapping key, Config.LeftMouseConfig config) { 87 | super(key, config); 88 | } 89 | 90 | public boolean isMobMode() { 91 | return ((Config.LeftMouseConfig) this.config).isMobMode(); 92 | } 93 | 94 | public void setMobMode(boolean mobMode) { 95 | ((Config.LeftMouseConfig) this.config).setMobMode(mobMode); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /common/src/main/java/pro/mikey/autoclicker/Language.java: -------------------------------------------------------------------------------- 1 | package pro.mikey.autoclicker; 2 | 3 | import net.minecraft.network.chat.Component; 4 | import net.minecraft.network.chat.MutableComponent; 5 | 6 | public enum Language { 7 | HUD_HOLDING("autoclicker-fabric.hud.holding"), 8 | MSG_HOLDING_KEYS("autoclicker-fabric.msg.holding-keys"), 9 | MSG_RELEASED_KEYS("autoclicker-fabric.msg.released-keys"), 10 | GUI_SPEED("autoclicker-fabric.gui.speed"), 11 | GUI_ACTIVE("autoclicker-fabric.gui.active"), 12 | GUI_SPAMMING("autoclicker-fabric.gui.spamming"), 13 | GUI_ATTACK("autoclicker-fabric.gui.attack"), 14 | GUI_USE("autoclicker-fabric.gui.use"), 15 | GUI_JUMP("autoclicker-fabric.gui.jump"), 16 | GUI_RESPECT_COOLDOWN("autoclicker-fabric.gui.respect"), 17 | GUI_RESPECT_SHIELD("autoclicker-fabric.gui.shield"), 18 | GUI_MOB_MODE("autoclicker-fabric.gui.mob-mode"), 19 | GUI_HUD_ENABLED("autoclicker-fabric.gui.hud-enabled"), 20 | GUI_HUD_LOCATION("autoclicker-fabric.gui.hud-location"); 21 | 22 | private final String key; 23 | MutableComponent text; 24 | 25 | Language(String langKey) { 26 | this.text = Component.translatable(langKey); 27 | this.key = langKey; 28 | } 29 | 30 | public MutableComponent getText() { 31 | return this.text; 32 | } 33 | 34 | public Component getText(Object... args) { 35 | return Component.translatable(this.key, args); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /common/src/main/java/pro/mikey/autoclicker/OptionsScreen.java: -------------------------------------------------------------------------------- 1 | package pro.mikey.autoclicker; 2 | 3 | 4 | import net.minecraft.client.gui.GuiGraphics; 5 | import net.minecraft.client.gui.components.Button; 6 | import net.minecraft.client.gui.components.EditBox; 7 | import net.minecraft.client.gui.screens.Screen; 8 | import net.minecraft.client.gui.screens.inventory.tooltip.DefaultTooltipPositioner; 9 | import net.minecraft.network.chat.Component; 10 | import net.minecraft.network.chat.FormattedText; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | import java.util.HashMap; 14 | 15 | public class OptionsScreen extends Screen { 16 | private final HashMap buttonTooltips = new HashMap<>(); 17 | private final HashMap sliderTooltips = new HashMap<>(); 18 | private EditBox leftHoldingSpamSpeed; 19 | private EditBox rightHoldingSpamSpeed; 20 | private EditBox jumpHoldingSpamSpeed; 21 | 22 | protected OptionsScreen() { 23 | super(Component.empty()); 24 | } 25 | 26 | public static Screen createScreen(@Nullable Screen parent) { 27 | return new OptionsScreen(); 28 | } 29 | 30 | @Override 31 | protected void init() { 32 | int x = (this.width / 2), y = (this.height / 2); 33 | 34 | leftHoldingSpamSpeed = new EditBox(minecraft.font, x - 200, y-50, 130, 20, Component.literal(String.valueOf(AutoClicker.leftHolding.getSpeed()))); 35 | rightHoldingSpamSpeed = new EditBox(minecraft.font, x - 65, y-50, 130, 20, Component.literal(String.valueOf(AutoClicker.rightHolding.getSpeed()))); 36 | jumpHoldingSpamSpeed = new EditBox(minecraft.font, x + 70, y-50, 130, 20, Component.literal(String.valueOf(AutoClicker.jumpHolding.getSpeed()))); 37 | 38 | leftHoldingSpamSpeed.setValue(String.valueOf(AutoClicker.leftHolding.getSpeed())); 39 | rightHoldingSpamSpeed.setValue(String.valueOf(AutoClicker.rightHolding.getSpeed())); 40 | jumpHoldingSpamSpeed.setValue(String.valueOf(AutoClicker.jumpHolding.getSpeed())); 41 | 42 | leftHoldingSpamSpeed.setResponder(s -> { 43 | if(s.startsWith("0") && s.length() > 1){ 44 | s = s.substring(1); 45 | leftHoldingSpamSpeed.setValue(s); 46 | } 47 | 48 | try { 49 | AutoClicker.leftHolding.setSpeed(Integer.parseInt(s)); 50 | } 51 | catch (NumberFormatException e){ 52 | AutoClicker.leftHolding.setSpeed(0); 53 | leftHoldingSpamSpeed.setValue(String.valueOf(AutoClicker.leftHolding.getSpeed())); 54 | } 55 | 56 | AutoClicker.getInstance().saveConfig(); 57 | }); 58 | 59 | 60 | rightHoldingSpamSpeed.setResponder(s -> { 61 | if(s.startsWith("0") && s.length() > 1){ 62 | s = s.substring(1); 63 | rightHoldingSpamSpeed.setValue(s); 64 | } 65 | 66 | try { 67 | AutoClicker.rightHolding.setSpeed(Integer.parseInt(s)); 68 | } 69 | catch (NumberFormatException e){ 70 | AutoClicker.rightHolding.setSpeed(0); 71 | rightHoldingSpamSpeed.setValue(String.valueOf(AutoClicker.rightHolding.getSpeed())); 72 | } 73 | 74 | AutoClicker.getInstance().saveConfig(); 75 | }); 76 | 77 | jumpHoldingSpamSpeed.setResponder(s -> { 78 | if(s.startsWith("0") && s.length() > 1){ 79 | s = s.substring(1); 80 | jumpHoldingSpamSpeed.setValue(s); 81 | } 82 | 83 | try { 84 | AutoClicker.jumpHolding.setSpeed(Integer.parseInt(s)); 85 | } 86 | catch (NumberFormatException e){ 87 | AutoClicker.jumpHolding.setSpeed(0); 88 | jumpHoldingSpamSpeed.setValue(String.valueOf(AutoClicker.jumpHolding.getSpeed())); 89 | } 90 | 91 | AutoClicker.getInstance().saveConfig(); 92 | }); 93 | 94 | // Button Tooltips 95 | 96 | this.buttonTooltips.put(this.addRenderableWidget( 97 | Button.builder( 98 | Language.GUI_ACTIVE.getText(AutoClicker.leftHolding.isActive()), (button) -> { 99 | AutoClicker.leftHolding.setActive(!AutoClicker.leftHolding.isActive()); 100 | button.setMessage(Language.GUI_ACTIVE.getText(AutoClicker.leftHolding.isActive())); 101 | AutoClicker.getInstance().saveConfig(); 102 | }) 103 | .bounds(x - 200, y - 94, 130, 20) 104 | .build() 105 | ), "autoclicker-fabric.gui.help.active"); 106 | 107 | this.buttonTooltips.put(this.addRenderableWidget( 108 | Button.builder( 109 | Language.GUI_ACTIVE.getText(AutoClicker.rightHolding.isActive()), (button) -> { 110 | AutoClicker.rightHolding.setActive(!AutoClicker.rightHolding.isActive()); 111 | button.setMessage(Language.GUI_ACTIVE.getText(AutoClicker.rightHolding.isActive())); 112 | AutoClicker.getInstance().saveConfig(); 113 | }) 114 | .bounds(x - 65, y - 94, 130, 20) 115 | .build() 116 | ), "autoclicker-fabric.gui.help.active"); 117 | 118 | this.buttonTooltips.put(this.addRenderableWidget( 119 | Button.builder( 120 | Language.GUI_ACTIVE.getText(AutoClicker.jumpHolding.isActive()), (button) -> { 121 | AutoClicker.jumpHolding.setActive(!AutoClicker.jumpHolding.isActive()); 122 | button.setMessage(Language.GUI_ACTIVE.getText(AutoClicker.jumpHolding.isActive())); 123 | AutoClicker.getInstance().saveConfig(); 124 | }) 125 | .bounds(x + 70 , y - 94, 130, 20) 126 | .build() 127 | ), "autoclicker-fabric.gui.help.active"); 128 | 129 | this.buttonTooltips.put(this.addRenderableWidget( 130 | Button.builder( 131 | Language.GUI_SPAMMING.getText(AutoClicker.leftHolding.isSpamming()), (button) -> { 132 | AutoClicker.leftHolding.setSpamming(!AutoClicker.leftHolding.isSpamming()); 133 | button.setMessage(Language.GUI_SPAMMING.getText(AutoClicker.leftHolding.isSpamming())); 134 | AutoClicker.getInstance().saveConfig(); 135 | }) 136 | .bounds(x - 200, y - 72, 130, 20) 137 | .build() 138 | ), "autoclicker-fabric.gui.help.spamming"); 139 | 140 | this.buttonTooltips.put(this.addRenderableWidget( 141 | Button.builder( 142 | Language.GUI_SPAMMING.getText(AutoClicker.rightHolding.isSpamming()), (button) -> { 143 | AutoClicker.rightHolding.setSpamming(!AutoClicker.rightHolding.isSpamming()); 144 | button.setMessage(Language.GUI_SPAMMING.getText(AutoClicker.rightHolding.isSpamming())); 145 | AutoClicker.getInstance().saveConfig(); 146 | }) 147 | .bounds(x - 65, y - 72, 130, 20) 148 | .build() 149 | ), "autoclicker-fabric.gui.help.spamming"); 150 | 151 | this.buttonTooltips.put(this.addRenderableWidget( 152 | Button.builder( 153 | Language.GUI_SPAMMING.getText(AutoClicker.jumpHolding.isSpamming()), (button) -> { 154 | AutoClicker.jumpHolding.setSpamming(!AutoClicker.jumpHolding.isSpamming()); 155 | button.setMessage(Language.GUI_SPAMMING.getText(AutoClicker.jumpHolding.isSpamming())); 156 | AutoClicker.getInstance().saveConfig(); 157 | }) 158 | .bounds(x + 70, y - 72, 130, 20) 159 | .build() 160 | ), "autoclicker-fabric.gui.help.spamming"); 161 | 162 | this.sliderTooltips.put(this.addRenderableWidget(leftHoldingSpamSpeed), "autoclicker-fabric.gui.help.spam-speed"); 163 | 164 | this.sliderTooltips.put(this.addRenderableWidget(rightHoldingSpamSpeed), "autoclicker-fabric.gui.help.spam-speed"); 165 | 166 | this.sliderTooltips.put(this.addRenderableWidget(jumpHoldingSpamSpeed), "autoclicker-fabric.gui.help.spam-speed"); 167 | 168 | this.buttonTooltips.put(this.addRenderableWidget( 169 | Button.builder( 170 | Language.GUI_RESPECT_COOLDOWN.getText(AutoClicker.leftHolding.isRespectCooldown()), (button) -> { 171 | AutoClicker.leftHolding.setRespectCooldown(!AutoClicker.leftHolding.isRespectCooldown()); 172 | button.setMessage(Language.GUI_RESPECT_COOLDOWN.getText(AutoClicker.leftHolding.isRespectCooldown())); 173 | AutoClicker.getInstance().saveConfig(); 174 | }) 175 | .bounds(x - 200, y - 28, 130, 20) 176 | .build() 177 | ), "autoclicker-fabric.gui.help.cooldown"); 178 | 179 | this.buttonTooltips.put(this.addRenderableWidget( 180 | Button.builder( 181 | Language.GUI_RESPECT_SHIELD.getText(AutoClicker.leftHolding.isRespectShield()), (button) -> { 182 | AutoClicker.leftHolding.setRespectShield(!AutoClicker.leftHolding.isRespectShield()); 183 | button.setMessage(Language.GUI_RESPECT_SHIELD.getText(AutoClicker.leftHolding.isRespectShield())); 184 | AutoClicker.getInstance().saveConfig(); 185 | }) 186 | .bounds(x - 200, y - 6, 130, 20) 187 | .build() 188 | ), "autoclicker-fabric.gui.help.shield"); 189 | 190 | this.buttonTooltips.put(this.addRenderableWidget( 191 | Button.builder( 192 | Language.GUI_MOB_MODE.getText(AutoClicker.leftHolding.isMobMode()), (button) -> { 193 | AutoClicker.leftHolding.setMobMode(!AutoClicker.leftHolding.isMobMode()); 194 | button.setMessage(Language.GUI_MOB_MODE.getText(AutoClicker.leftHolding.isMobMode())); 195 | AutoClicker.getInstance().saveConfig(); 196 | }) 197 | .bounds(x - 200, y + 16, 130, 20) 198 | .build() 199 | ), "autoclicker-fabric.gui.help.mob-mode"); 200 | 201 | this.buttonTooltips.put(this.addRenderableWidget( 202 | Button.builder( 203 | Language.GUI_HUD_ENABLED.getText(AutoClicker.hudConfig.isEnabled()), (button) -> { 204 | AutoClicker.hudConfig.setEnabled(!AutoClicker.hudConfig.isEnabled()); 205 | button.setMessage(Language.GUI_HUD_ENABLED.getText(AutoClicker.hudConfig.isEnabled())); 206 | AutoClicker.getInstance().saveConfig(); 207 | }) 208 | .bounds(x - 65, y + 38, 130, 20) 209 | .build() 210 | ), "autoclicker-fabric.gui.help.hud-enabled"); 211 | 212 | this.buttonTooltips.put(this.addRenderableWidget( 213 | Button.builder( 214 | Language.GUI_HUD_LOCATION.getText(AutoClicker.hudConfig.getLocation()), (button) -> { 215 | AutoClicker.hudConfig.setLocation(getNextLocation(AutoClicker.hudConfig.getLocation())); 216 | button.setMessage(Language.GUI_HUD_LOCATION.getText(AutoClicker.hudConfig.getLocation())); 217 | AutoClicker.getInstance().saveConfig(); 218 | }) 219 | .bounds(x - 65, y + 60, 130, 20) 220 | .build() 221 | ), "autoclicker-fabric.gui.help.hud-location"); 222 | } 223 | 224 | private String getNextLocation(String currentLocation){ 225 | switch (currentLocation){ 226 | case "top-left": 227 | return "top-right"; 228 | case "top-right": 229 | return "bottom-left"; 230 | case "bottom-left": 231 | return "bottom-right"; 232 | case "bottom-right": 233 | return "top-left"; 234 | } 235 | return "top-left"; 236 | } 237 | 238 | private void renderHelpingTip(GuiGraphics context, Component text, int mouseX, int mouseY) { 239 | context.renderTooltip( 240 | this.font, this.font.split(FormattedText.of(text.getString()), 250), DefaultTooltipPositioner.INSTANCE, mouseX, mouseY); 241 | } 242 | 243 | @Override 244 | public void render(GuiGraphics context, int mouseX, int mouseY, float delta) { 245 | this.renderBackground(context, mouseX, mouseY, delta); 246 | super.render(context, mouseX, mouseY, delta); 247 | 248 | context.drawString( 249 | this.font,Language.GUI_ATTACK.getText().getVisualOrderText(), this.width / 2 - 200, this.height / 2 - 116, 0xFFFFFF); 250 | 251 | context.drawString( 252 | this.font, Language.GUI_USE.getText().getVisualOrderText(), this.width / 2 - 65, this.height / 2 - 116, 0xFFFFFF); 253 | 254 | context.drawString( 255 | this.font, Language.GUI_JUMP.getText().getVisualOrderText(), this.width / 2 + 70, this.height / 2 - 116, 0xFFFFFF); 256 | 257 | for (Button button : buttonTooltips.keySet()) { 258 | if (button.isHovered()) { 259 | this.renderHelpingTip(context, Component.translatable(this.buttonTooltips.get(button)), mouseX, mouseY); 260 | } 261 | } 262 | 263 | for (EditBox widget : sliderTooltips.keySet()) { 264 | if (widget.isHovered()) { 265 | this.renderHelpingTip(context, Component.translatable(this.sliderTooltips.get(widget)), mouseX, mouseY); 266 | } 267 | } 268 | } 269 | 270 | @Override 271 | public boolean keyPressed(int keyCode, int scanCode, int modifiers) { 272 | if (keyCode == AutoClicker.openConfig.getDefaultKey().getValue()) { 273 | this.onClose(); 274 | return true; 275 | } 276 | 277 | return super.keyPressed(keyCode, scanCode, modifiers); 278 | } 279 | 280 | @Override 281 | public boolean isPauseScreen() { 282 | return false; 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /common/src/main/java/pro/mikey/autoclicker/OptionsSliderWidget.java: -------------------------------------------------------------------------------- 1 | package pro.mikey.autoclicker; 2 | 3 | import net.minecraft.client.gui.components.AbstractSliderButton; 4 | import net.minecraft.network.chat.Component; 5 | 6 | import java.util.function.Consumer; 7 | 8 | @Deprecated 9 | public class OptionsSliderWidget extends AbstractSliderButton { 10 | public Consumer onUpdate; 11 | 12 | public OptionsSliderWidget(int x, int y, int width, int height, Component text, double value, Consumer onUpdate) { 13 | super(x, y, width, height, text, value); 14 | this.onUpdate = onUpdate; 15 | this.updateMessage(); 16 | } 17 | 18 | @Override 19 | protected void updateMessage() { 20 | this.setMessage(Language.GUI_SPEED.getText((int) Math.round(this.value * 1200))); 21 | } 22 | 23 | @Override 24 | protected void applyValue() { 25 | this.onUpdate.accept((int) Math.round(this.value * 1200)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /common/src/main/resources/assets/autoclicker/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdvancedXRay/Auto-Clicker/22272aa71e53ed0a797901bba58e679f8982671f/common/src/main/resources/assets/autoclicker/icon.png -------------------------------------------------------------------------------- /common/src/main/resources/assets/autoclicker/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "category.autoclicker-fabric": "Auto clicker", 3 | "keybinding.toggle-hold": "Toggle Holding keys", 4 | "keybinding.toggle-jump": "Toggle Holding jump", 5 | "keybinding.open-gui": "Open auto clicker GUI", 6 | "autoclicker-fabric.hud.holding": "Holding %s", 7 | "autoclicker-fabric.msg.holding-keys": "Holding keys!", 8 | "autoclicker-fabric.msg.released-keys": "Released keys!", 9 | "autoclicker-fabric.gui.speed": "Speed: %f ticks", 10 | "autoclicker-fabric.gui.active": "Active: %s", 11 | "autoclicker-fabric.gui.spamming": "Spamming: %s", 12 | "autoclicker-fabric.gui.attack": "Attack (left click)", 13 | "autoclicker-fabric.gui.use": "Use (right click)", 14 | "autoclicker-fabric.gui.jump": "Use (jump)", 15 | "autoclicker-fabric.gui.respect": "Respect cooldown: %s", 16 | "autoclicker-fabric.gui.shield": "Respect shield: %s", 17 | "autoclicker-fabric.gui.mob-mode": "Mob mode: %s", 18 | "autoclicker-fabric.gui.hud-enabled": "Hud enabled: %s", 19 | "autoclicker-fabric.gui.hud-location": "Hud location: %s", 20 | "autoclicker-fabric.gui.help.active": "If enabled, it will use the options below to determine how to auto click", 21 | "autoclicker-fabric.gui.help.spamming": "When enabled, the key will be pressed then unpressed, you can control how quickly this happens below.", 22 | "autoclicker-fabric.gui.help.cooldown": "When enabled, if a mob is detected, the button will be tapped in respect to the cooldown of the attack.", 23 | "autoclicker-fabric.gui.help.shield": "When enabled, the button will not be tapped if your shield is up.", 24 | "autoclicker-fabric.gui.help.mob-mode": "(Must have 'Respect Cooldown' enabled). When enabled, the button will only be clicked when a mob is in direct light of sight.", 25 | "autoclicker-fabric.gui.help.spam-speed": "When 'spamming' is enabled, this setting will determine how many ticks are between each click, 0 = off, 1+ = 1 tick of delay.", 26 | "autoclicker-fabric.gui.help.hud-enabled": "Whether to enable the mod HUD", 27 | "autoclicker-fabric.gui.help.hud-location": "The location of the mod HUD." 28 | } 29 | -------------------------------------------------------------------------------- /common/src/main/resources/assets/autoclicker/lang/es_es.json: -------------------------------------------------------------------------------- 1 | { 2 | "category.autoclicker-fabric": "Auto clicker", 3 | "keybinding.toggle-hold": "Alternar Mantener teclas", 4 | "keybinding.toggle-jump": "Alternar Mantener salto", 5 | "keybinding.open-gui": "Abrir GUI de auto clicker", 6 | "autoclicker-fabric.hud.holding": "Manteniendo %s", 7 | "autoclicker-fabric.msg.holding-keys": "¡Manteniendo teclas!", 8 | "autoclicker-fabric.msg.released-keys": "¡Teclas liberadas!", 9 | "autoclicker-fabric.gui.speed": "Velocidad: %f ticks", 10 | "autoclicker-fabric.gui.active": "Activo: %s", 11 | "autoclicker-fabric.gui.spamming": "Spameando: %s", 12 | "autoclicker-fabric.gui.attack": "Ataque (clic izquierdo)", 13 | "autoclicker-fabric.gui.use": "Usar (clic derecho)", 14 | "autoclicker-fabric.gui.jump": "Usar (saltar)", 15 | "autoclicker-fabric.gui.respect": "Respetar tiempo de reutilización: %s", 16 | "autoclicker-fabric.gui.shield": "Respetar escudo: %s", 17 | "autoclicker-fabric.gui.mob-mode": "Modo Mob: %s", 18 | "autoclicker-fabric.gui.hud-enabled": "HUD habilitado: %s", 19 | "autoclicker-fabric.gui.hud-location": "Ubicación del HUD: %s", 20 | "autoclicker-fabric.gui.help.active": "Si está habilitado, utilizará las opciones a continuación para determinar cómo auto clicar", 21 | "autoclicker-fabric.gui.help.spamming": "Cuando está habilitado, la tecla será presionada y luego liberada. Puedes controlar la velocidad con la configuración a continuación.", 22 | "autoclicker-fabric.gui.help.cooldown": "Cuando está habilitado, si se detecta un mob, el botón se presionará respetando el tiempo de reutilización del ataque.", 23 | "autoclicker-fabric.gui.help.shield": "Cuando está habilitado, el botón no se presionará si tienes el escudo levantado.", 24 | "autoclicker-fabric.gui.help.mob-mode": "(Debe tener 'Respetar tiempo de reutilización' habilitado). Cuando está habilitado, el botón solo se presionará cuando un mob esté en la línea de visión directa.", 25 | "autoclicker-fabric.gui.help.spam-speed": "Cuando 'spamear' está habilitado, esta configuración determinará cuántos ticks hay entre cada clic, 0 = apagado, 1+ = 1 tick de demora.", 26 | "autoclicker-fabric.gui.help.hud-enabled": "Si habilitar el HUD del mod", 27 | "autoclicker-fabric.gui.help.hud-location": "La ubicación del HUD del mod." 28 | } 29 | -------------------------------------------------------------------------------- /common/src/main/resources/autoclicker.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "package": "pro.mikey.autoclicker.mixin", 4 | "compatibilityLevel": "JAVA_21", 5 | "minVersion": "0.8", 6 | "client": [ 7 | ], 8 | "mixins": [ 9 | ], 10 | "injectors": { 11 | "defaultRequire": 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /fabric/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.github.johnrengelman.shadow' 3 | } 4 | 5 | architectury { 6 | platformSetupLoomIde() 7 | fabric() 8 | } 9 | 10 | configurations { 11 | common { 12 | canBeResolved = true 13 | canBeConsumed = false 14 | } 15 | compileClasspath.extendsFrom common 16 | runtimeClasspath.extendsFrom common 17 | developmentFabric.extendsFrom common 18 | 19 | // Files in this configuration will be bundled into your mod using the Shadow plugin. 20 | // Don't use the `shadow` configuration from the plugin itself as it's meant for excluding files. 21 | shadowBundle { 22 | canBeResolved = true 23 | canBeConsumed = false 24 | } 25 | } 26 | 27 | dependencies { 28 | modImplementation "net.fabricmc:fabric-loader:$rootProject.fabric_loader_version" 29 | 30 | // Fabric API. This is technically optional, but you probably want it anyway. 31 | modImplementation "net.fabricmc.fabric-api:fabric-api:$rootProject.fabric_api_version" 32 | 33 | modApi "com.terraformersmc:modmenu:${project.modmenu}" 34 | common(project(path: ':common', configuration: 'namedElements')) { transitive false } 35 | shadowBundle project(path: ':common', configuration: 'transformProductionFabric') 36 | } 37 | 38 | processResources { 39 | inputs.property 'version', project.version 40 | 41 | filesMatching('fabric.mod.json') { 42 | expand version: project.version 43 | } 44 | } 45 | 46 | shadowJar { 47 | configurations = [project.configurations.shadowBundle] 48 | archiveClassifier = 'dev-shadow' 49 | } 50 | 51 | remapJar { 52 | input.set shadowJar.archiveFile 53 | } 54 | -------------------------------------------------------------------------------- /fabric/src/main/java/pro/mikey/autoclicker/fabric/client/AutoClickerFabricClient.java: -------------------------------------------------------------------------------- 1 | package pro.mikey.autoclicker.fabric.client; 2 | 3 | import net.fabricmc.api.ClientModInitializer; 4 | import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; 5 | import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; 6 | import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; 7 | import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; 8 | import pro.mikey.autoclicker.AutoClicker; 9 | 10 | public final class AutoClickerFabricClient implements ClientModInitializer { 11 | AutoClicker autoClicker = new AutoClicker(); 12 | @Override 13 | public void onInitializeClient() { 14 | ClientTickEvents.END_CLIENT_TICK.register(autoClicker::clientTickEvent); 15 | 16 | KeyBindingHelper.registerKeyBinding(AutoClicker.toggleHolding); 17 | KeyBindingHelper.registerKeyBinding(AutoClicker.openConfig); 18 | 19 | ClientLifecycleEvents.CLIENT_STARTED.register(autoClicker::clientReady); 20 | HudRenderCallback.EVENT.register(autoClicker::renderGameOverlayEvent); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /fabric/src/main/java/pro/mikey/autoclicker/fabric/client/ModMenuAPIImpl.java: -------------------------------------------------------------------------------- 1 | package pro.mikey.autoclicker.fabric.client; 2 | 3 | import com.terraformersmc.modmenu.api.ConfigScreenFactory; 4 | import com.terraformersmc.modmenu.api.ModMenuApi; 5 | import pro.mikey.autoclicker.OptionsScreen; 6 | 7 | 8 | public class ModMenuAPIImpl implements ModMenuApi { 9 | @Override 10 | public ConfigScreenFactory getModConfigScreenFactory() { 11 | return OptionsScreen::createScreen; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /fabric/src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "autoclicker", 4 | "version": "${version}", 5 | "name": "Auto Clicker", 6 | "description": "Automatically left and right clicks for you, how kind!", 7 | "authors": [ 8 | "ErrorMikey", 9 | "Advanced XRay team" 10 | ], 11 | "contact": { 12 | "homepage": "https://mikey.pro/", 13 | "sources": "https://github.com/advancedxray/auto-clicker", 14 | "issues": "https://github.com/advancedxray/auto-clicker/issues" 15 | }, 16 | "license": "MIT", 17 | "icon": "assets/autoclicker/icon.png", 18 | "environment": "client", 19 | "entrypoints": { 20 | "client": [ 21 | "pro.mikey.autoclicker.fabric.client.AutoClickerFabricClient" 22 | ], 23 | "modmenu" : ["pro.mikey.autoclicker.fabric.client.ModMenuAPIImpl"] 24 | }, 25 | "depends": { 26 | "fabricloader": ">=0.16.0", 27 | "fabric": "*", 28 | "minecraft": ">=1.21", 29 | "java": ">=21" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to Gradle. 2 | org.gradle.jvmargs=-Xmx2G 3 | org.gradle.parallel=true 4 | 5 | # Mod properties 6 | mod_version = 21.5.0 7 | maven_group = pro.mikey.autoclicker 8 | archives_name = autoclicker 9 | enabled_platforms = fabric,neoforge 10 | 11 | # Minecraft properties 12 | minecraft_version = 1.21.5 13 | 14 | # Dependencies 15 | fabric_loader_version=0.16.14 16 | fabric_api_version=0.124.0+1.21.5 17 | neoforge_version = 21.5.35-beta 18 | 19 | modmenu = 14.0.0-rc.2 20 | 21 | curseforge_id=445095 22 | modrinth_id=r8axuw4u 23 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdvancedXRay/Auto-Clicker/22272aa71e53ed0a797901bba58e679f8982671f/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.12-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /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 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 87 | APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit 88 | 89 | # Use the maximum available, or set MAX_FD != -1 to use that value. 90 | MAX_FD=maximum 91 | 92 | warn () { 93 | echo "$*" 94 | } >&2 95 | 96 | die () { 97 | echo 98 | echo "$*" 99 | echo 100 | exit 1 101 | } >&2 102 | 103 | # OS specific support (must be 'true' or 'false'). 104 | cygwin=false 105 | msys=false 106 | darwin=false 107 | nonstop=false 108 | case "$( uname )" in #( 109 | CYGWIN* ) cygwin=true ;; #( 110 | Darwin* ) darwin=true ;; #( 111 | MSYS* | MINGW* ) msys=true ;; #( 112 | NONSTOP* ) nonstop=true ;; 113 | esac 114 | 115 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 116 | 117 | 118 | # Determine the Java command to use to start the JVM. 119 | if [ -n "$JAVA_HOME" ] ; then 120 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 121 | # IBM's JDK on AIX uses strange locations for the executables 122 | JAVACMD=$JAVA_HOME/jre/sh/java 123 | else 124 | JAVACMD=$JAVA_HOME/bin/java 125 | fi 126 | if [ ! -x "$JAVACMD" ] ; then 127 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 128 | 129 | Please set the JAVA_HOME variable in your environment to match the 130 | location of your Java installation." 131 | fi 132 | else 133 | JAVACMD=java 134 | if ! command -v java >/dev/null 2>&1 135 | then 136 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | fi 142 | 143 | # Increase the maximum file descriptors if we can. 144 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 145 | case $MAX_FD in #( 146 | max*) 147 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 148 | # shellcheck disable=SC2039,SC3045 149 | MAX_FD=$( ulimit -H -n ) || 150 | warn "Could not query maximum file descriptor limit" 151 | esac 152 | case $MAX_FD in #( 153 | '' | soft) :;; #( 154 | *) 155 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 156 | # shellcheck disable=SC2039,SC3045 157 | ulimit -n "$MAX_FD" || 158 | warn "Could not set maximum file descriptor limit to $MAX_FD" 159 | esac 160 | fi 161 | 162 | # Collect all arguments for the java command, stacking in reverse order: 163 | # * args from the command line 164 | # * the main class name 165 | # * -classpath 166 | # * -D...appname settings 167 | # * --module-path (only if needed) 168 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 169 | 170 | # For Cygwin or MSYS, switch paths to Windows format before running java 171 | if "$cygwin" || "$msys" ; then 172 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 173 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 174 | 175 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 176 | 177 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 178 | for arg do 179 | if 180 | case $arg in #( 181 | -*) false ;; # don't mess with options #( 182 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 183 | [ -e "$t" ] ;; #( 184 | *) false ;; 185 | esac 186 | then 187 | arg=$( cygpath --path --ignore --mixed "$arg" ) 188 | fi 189 | # Roll the args list around exactly as many times as the number of 190 | # args, so each arg winds up back in the position where it started, but 191 | # possibly modified. 192 | # 193 | # NB: a `for` loop captures its iteration list before it begins, so 194 | # changing the positional parameters here affects neither the number of 195 | # iterations, nor the values presented in `arg`. 196 | shift # remove old arg 197 | set -- "$@" "$arg" # push replacement arg 198 | done 199 | fi 200 | 201 | 202 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 203 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 204 | 205 | # Collect all arguments for the java command: 206 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 207 | # and any embedded shellness will be escaped. 208 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 209 | # treated as '${Hostname}' itself on the command line. 210 | 211 | set -- \ 212 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 213 | -classpath "$CLASSPATH" \ 214 | org.gradle.wrapper.GradleWrapperMain \ 215 | "$@" 216 | 217 | # Stop when "xargs" is not available. 218 | if ! command -v xargs >/dev/null 2>&1 219 | then 220 | die "xargs is not available" 221 | fi 222 | 223 | # Use "xargs" to parse quoted args. 224 | # 225 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 226 | # 227 | # In Bash we could simply go: 228 | # 229 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 230 | # set -- "${ARGS[@]}" "$@" 231 | # 232 | # but POSIX shell has neither arrays nor command substitution, so instead we 233 | # post-process each arg (as a line of input to sed) to backslash-escape any 234 | # character that might be a shell metacharacter, then use eval to reverse 235 | # that process (while maintaining the separation between arguments), and wrap 236 | # the whole thing up as a single "set" statement. 237 | # 238 | # This will of course break if any of these variables contains a newline or 239 | # an unmatched quote. 240 | # 241 | 242 | eval "set -- $( 243 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 244 | xargs -n1 | 245 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 246 | tr '\n' ' ' 247 | )" '"$@"' 248 | 249 | exec "$JAVACMD" "$@" 250 | -------------------------------------------------------------------------------- /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. 1>&2 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 48 | echo. 1>&2 49 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 50 | echo location of your Java installation. 1>&2 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. 1>&2 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 62 | echo. 1>&2 63 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 64 | echo location of your Java installation. 1>&2 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 | -------------------------------------------------------------------------------- /neoforge/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.github.johnrengelman.shadow' 3 | } 4 | 5 | architectury { 6 | platformSetupLoomIde() 7 | neoForge() 8 | } 9 | 10 | configurations { 11 | common { 12 | canBeResolved = true 13 | canBeConsumed = false 14 | } 15 | compileClasspath.extendsFrom common 16 | runtimeClasspath.extendsFrom common 17 | developmentNeoForge.extendsFrom common 18 | 19 | // Files in this configuration will be bundled into your mod using the Shadow plugin. 20 | // Don't use the `shadow` configuration from the plugin itself as it's meant for excluding files. 21 | shadowBundle { 22 | canBeResolved = true 23 | canBeConsumed = false 24 | } 25 | } 26 | 27 | repositories { 28 | maven { 29 | name = 'NeoForged' 30 | url = 'https://maven.neoforged.net/releases' 31 | } 32 | } 33 | 34 | dependencies { 35 | neoForge "net.neoforged:neoforge:$rootProject.neoforge_version" 36 | 37 | common(project(path: ':common', configuration: 'namedElements')) { transitive false } 38 | shadowBundle project(path: ':common', configuration: 'transformProductionNeoForge') 39 | } 40 | 41 | processResources { 42 | inputs.property 'version', project.version 43 | 44 | filesMatching('META-INF/neoforge.mods.toml') { 45 | expand version: project.version 46 | } 47 | } 48 | 49 | shadowJar { 50 | configurations = [project.configurations.shadowBundle] 51 | archiveClassifier = 'dev-shadow' 52 | } 53 | 54 | remapJar { 55 | input.set shadowJar.archiveFile 56 | } 57 | -------------------------------------------------------------------------------- /neoforge/gradle.properties: -------------------------------------------------------------------------------- 1 | loom.platform = neoforge 2 | -------------------------------------------------------------------------------- /neoforge/src/main/java/pro/mikey/autoclicker/neoforge/AutoClickerNeoForge.java: -------------------------------------------------------------------------------- 1 | package pro.mikey.autoclicker.neoforge; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraft.client.gui.screens.Screen; 5 | import net.neoforged.api.distmarker.Dist; 6 | import net.neoforged.bus.api.SubscribeEvent; 7 | import net.neoforged.fml.ModContainer; 8 | import net.neoforged.fml.ModLoadingContext; 9 | import net.neoforged.fml.common.EventBusSubscriber; 10 | import net.neoforged.fml.common.Mod; 11 | 12 | import net.neoforged.fml.event.lifecycle.FMLConstructModEvent; 13 | import net.neoforged.fml.event.lifecycle.FMLLoadCompleteEvent; 14 | import net.neoforged.neoforge.client.event.ClientTickEvent; 15 | import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent; 16 | import net.neoforged.neoforge.client.event.RenderGuiEvent; 17 | import net.neoforged.neoforge.client.gui.IConfigScreenFactory; 18 | import net.neoforged.neoforge.common.NeoForge; 19 | import org.jetbrains.annotations.NotNull; 20 | import pro.mikey.autoclicker.AutoClicker; 21 | 22 | @Mod(AutoClicker.MOD_ID) 23 | @EventBusSubscriber(value = Dist.CLIENT, modid = AutoClicker.MOD_ID, bus = EventBusSubscriber.Bus.MOD) 24 | public final class AutoClickerNeoForge { 25 | private static final AutoClicker autoClicker = new AutoClicker(); 26 | public AutoClickerNeoForge() { 27 | autoClicker.onInitialize(); 28 | NeoForge.EVENT_BUS.addListener(this::onClientTick); 29 | NeoForge.EVENT_BUS.addListener(this::onHudRender); 30 | } 31 | 32 | @SubscribeEvent 33 | public static void onClientStarted(FMLLoadCompleteEvent event){ 34 | autoClicker.clientReady(Minecraft.getInstance()); 35 | } 36 | 37 | @SubscribeEvent 38 | public static void registerBindings(RegisterKeyMappingsEvent event){ 39 | event.register(AutoClicker.toggleHolding); 40 | event.register(AutoClicker.openConfig); 41 | } 42 | 43 | public void onClientTick(ClientTickEvent.Post event){ 44 | autoClicker.clientTickEvent(Minecraft.getInstance()); 45 | } 46 | 47 | public void onHudRender(RenderGuiEvent.Pre event){ 48 | autoClicker.renderGameOverlayEvent(event.getGuiGraphics(), event.getPartialTick()); 49 | } 50 | 51 | @SubscribeEvent 52 | public static void constructMod(FMLConstructModEvent event){ 53 | ModLoadingContext.get().registerExtensionPoint(IConfigScreenFactory.class, () -> new IConfigScreenFactory() { 54 | @Override 55 | public @NotNull Screen createScreen(@NotNull ModContainer arg, @NotNull Screen arg2) { 56 | return (autoClicker.getConfigScreen()); 57 | } 58 | }); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /neoforge/src/main/resources/META-INF/neoforge.mods.toml: -------------------------------------------------------------------------------- 1 | modLoader = "javafml" 2 | loaderVersion = "[4,)" 3 | issueTrackerURL = "https://github.com/advancedxray/auto-clicker/issues" 4 | license = "MIT" 5 | 6 | [[mods]] 7 | modId = "autoclicker" 8 | version = "${version}" 9 | displayName = "Auto Clicker" 10 | authors = "ErrorMikey" 11 | description = ''' 12 | Automatically left and right clicks for you, how kind! 13 | ''' 14 | logoFile = "assets/autoclicker-fabric/icon.png" 15 | 16 | [[dependencies.autoclicker]] 17 | modId = "neoforge" 18 | type = "required" 19 | versionRange = "[21.1,)" 20 | ordering = "NONE" 21 | side = "BOTH" 22 | 23 | [[dependencies.autoclicker]] 24 | modId = "minecraft" 25 | type = "required" 26 | versionRange = "[1.21.1,)" 27 | ordering = "NONE" 28 | side = "BOTH" 29 | 30 | [[mixins]] 31 | config = "autoclicker.mixins.json" 32 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { url "https://maven.fabricmc.net/" } 4 | maven { url "https://maven.architectury.dev/" } 5 | maven { url "https://files.minecraftforge.net/maven/" } 6 | gradlePluginPortal() 7 | maven { url "https://maven.saps.dev/mirror" } 8 | maven { url "https://maven.saps.dev/releases" } 9 | maven { url "https://maven.saps.dev/snapshots" } 10 | } 11 | } 12 | 13 | rootProject.name = 'autoclicker' 14 | 15 | include 'common' 16 | include 'fabric' 17 | include 'neoforge' 18 | --------------------------------------------------------------------------------