├── .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 |
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 | [](https://www.curseforge.com/minecraft/mc-mods/auto-clicker-fabric)
6 | [](https://www.curseforge.com/minecraft/mc-mods/auto-clicker-fabric)
7 | [](https://github.com/AdvancedXRay/Auto-Clicker-Fabric/blob/main/LICENSE)
8 | [](https://github.com/AdvancedXRay/Auto-Clicker-Fabric/stargazers)
9 | [](https://github.com/AdvancedXRay/Auto-Clicker-Fabric/issues)
10 | 
11 | 
12 | 
13 | 
14 | [](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 | 
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