diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..f63fa18 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,15 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry +polar: # Replace with a single Polar username +buy_me_a_coffee: kaddicus +thanks_dev: # Replace with a single thanks.dev username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..38befbd --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,40 @@ +# Automatically build the project and run any configured tests for every push +# and submitted pull request. This can help catch issues that only occur on +# certain platforms or Java versions, and provides a first line of defence +# against bad commits. + +name: build +on: [pull_request, push] + +jobs: + build: + strategy: + matrix: + # Use these Java versions + java: [ + 21, # Current Java LTS + ] + # and run on both Linux and Windows + os: [ubuntu-22.04, windows-2022] + runs-on: ${{ matrix.os }} + steps: + - name: checkout repository + uses: actions/checkout@v4 + - name: validate gradle wrapper + uses: gradle/actions/wrapper-validation@v3 + - name: setup jdk ${{ matrix.java }} + uses: actions/setup-java@v4 + with: + java-version: ${{ matrix.java }} + distribution: 'microsoft' + - name: make gradle wrapper executable + if: ${{ runner.os != 'Windows' }} + run: chmod +x ./gradlew + - name: build + run: ./gradlew build + - name: capture build artifacts + if: ${{ runner.os == 'Linux' && matrix.java == '21' }} # Only upload artifacts built from latest java on one OS + uses: actions/upload-artifact@v4 + with: + name: Artifacts + path: build/libs/ \ No newline at end of file diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml deleted file mode 100644 index a954bd9..0000000 --- a/.github/workflows/gradle.yml +++ /dev/null @@ -1,94 +0,0 @@ -name: 'Build mod' -on: - push: - paths-ignore: - - 'README.md' - - 'LICENSE' - - 'src/main/resources/assets/**' -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: 'Checkout repository' - uses: actions/checkout@v3 - - name: 'Validate gradle wrapper' - uses: gradle/wrapper-validation-action@v1 - - name: 'Setup JDK 17' - uses: actions/setup-java@v3 - with: - distribution: 'adopt' - java-version: '17' - - name: 'Make gradle wrapper executable' - run: chmod +x ./gradlew - - name: 'Build mod' - run: ./gradlew build - - name: 'Get tag' - if: startsWith(github.ref, 'refs/tags/') - id: git_tag - run: echo ::set-output name=TAG::${GITHUB_REF/refs\/tags\//} - - name: Build changelog - if: startsWith(github.ref, 'refs/tags/') - id: changelog_release - uses: mikepenz/release-changelog-builder-action@v3 - with: - commitMode: true - configurationJson: | - { - "categories": [ - { - "title": "### New Features", - "labels": ["feat"] - }, - { - "title": "### Changes", - "labels": ["change", "impr"] - }, - { - "title": "### Fixes", - "labels": ["fix"] - }, - { - "title": "### Localization", - "labels": ["loc"] - }, - { - "title": "### Other", - "labels": [] - } - ], - "ignore_labels": [ - "build", - "refactor", - "docs" - ], - "sort": { - "order": "DESC", - "on_property": "mergedAt" - }, - "label_extractor": [ - { - "pattern": "(.*): (.*)", - "target": "$1", - "on_property": "title" - } - ], - "transformers": [ - { - "pattern": "(.*): (.*)", - "target": "* $2" - } - ], - "template": "## Changelog\n\n#{{CHANGELOG}}", - "pr_template": "#{{TITLE}}", - "empty_template": "CHANGEME" - } - env: - GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} - - name: 'Draft a new release' - if: startsWith(github.ref, 'refs/tags/') - uses: softprops/action-gh-release@v1 - with: - draft: true - name: 'Accurate Block Placement v${{steps.git_tag.outputs.TAG}}' - body: ${{steps.changelog_release.outputs.changelog}} - files: 'build/libs/accurate-block-placement-${{steps.git_tag.outputs.TAG}}.jar' diff --git a/LICENSE b/LICENSE index 588edd9..bbbfd95 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,9 @@ MIT License +Copyright (c) 2023 schwar + +Copyright (c) 2023 KadTheHunter + Copyright (c) 2022 Flourick Copyright (c) 2019 Clayborn diff --git a/README.md b/README.md index 2e192ad..e19290c 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,52 @@ -# Accurate Block Placement +

Accurate Block Placement: Reborn

-A simple fabric mod for Minecraft which causes players to place blocks based on what they are looking at rather than a timer. +

+ +Current Modrinth Release + + +Current CurseForge Release + + +Current GitHub Release + +

+ +Modrinth Downloads + + +CurseForge Downloads + +

+ +Buy Me A Coffee + +

-## Installation +AccurateBlockPlacement: Reborn is a client-side mod for [Fabric](https://fabricmc.net). -1. Download fabric loader from [here](https://fabricmc.net/use/) (**REQUIRES** Fabric-API! Get it [here](https://www.curseforge.com/minecraft/mc-mods/fabric-api) (Make sure you get the right one for your version!)) +[Fabric API](https://modrinth.com/mod/fabric-api) is required, [Mod Menu](https://modrinth.com/mod/modmenu) and [Cloth Config API](https://modrinth.com/mod/cloth-config) are optional, but strongly recommended. -2. Download AccurateBlockPlacement jar release from [here](https://github.com/Flourick/AccurateBlockPlacement/releases). +--- -3. Once you run fabric loader a mods folder will be created in your *.minecraft* directory. Move the `accurate-block-placement-*.jar` and `fabric-api-*.jar` there. +*Although many experienced minecraft players know exactly how to time their clicks in order to rapidly place blocks with no mistakes, why should it be that difficult? In this mod, if you hold your 'use key' (usually RMB) and look at a new block it will automatically place it no matter how fast you move. No more need to time when you click or look in order to accurately place blocks quickly!* + +## Features +**WARNING:** This mod may be considered a "cheat" on some servers (and detected as such)! Please check the server's rules before using this mod. _Use this at your own risk._ + +### Accurate Block Placement +Accurate Block Placement makes placing blocks a smooth and reliable process when holding right click. The best way to explain it is the following GIF: + +Mod Showcase + +Enabled by default, can be toggled on or off through the config or by way of a configurable keybind (default: Not Bound). + +### Fast Block Breaking (v1.3.0+ for 1.21.3+) +Fast Block Breaking makes breaking blocks much easier and more consistent, by removing the Mining Cooldown when breaking blocks. + +No GIF for this one yet :(, _essentially haste insta-mining but for creative mode_ + +Disabled by default, can be toggled on or off through the config or by way of a configurable keybind (default: Not Bound). + +## License +Accurate Block Placement: Reborn is provided under the [MIT License](https://github.com/hschwar/AccurateBlockPlacement-Reborn/blob/main/LICENSE). diff --git a/build.gradle b/build.gradle index eb2f327..191b140 100644 --- a/build.gradle +++ b/build.gradle @@ -1,44 +1,47 @@ plugins { - id 'fabric-loom' version '1.0-SNAPSHOT' + id 'fabric-loom' version '1.14-SNAPSHOT' id 'maven-publish' } -sourceCompatibility = JavaVersion.VERSION_17 -targetCompatibility = JavaVersion.VERSION_17 - -archivesBaseName = project.archives_base_name version = project.mod_version group = project.maven_group +base { + archivesName = project.archives_base_name +} + repositories { - // Add repositories to retrieve artifacts from in here. - // You should only use this when depending on other mods because - // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. - // See https://docs.gradle.org/current/userguide/declaring_repositories.html - // for more information about repositories. + maven { url "https://maven.shedaniel.me/" } + maven { url "https://maven.terraformersmc.com/releases/" } } dependencies { //to change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + mappings loom.officialMojangMappings() modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" // Fabric API. This is technically optional, but you probably want it anyway. modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + + modCompileOnly "com.terraformersmc:modmenu:${project.mod_menu_version}" + + modApi("me.shedaniel.cloth:cloth-config-fabric:${project.cloth_config_version}") { + exclude(group: "net.fabricmc.fabric-api") + } } processResources { inputs.property "version", project.version filesMatching("fabric.mod.json") { - expand "version": project.version + expand "version": inputs.properties.version } } tasks.withType(JavaCompile).configureEach { // since 1.18, Minecraft requires Java 17 - it.options.release = 17 + it.options.release = 21 } java { @@ -46,27 +49,32 @@ java { // if it is present. // If you remove this line, sources will not be generated. withSourcesJar() + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 } jar { + inputs.property "archivesName", project.base.archivesName + from("LICENSE") { - rename { "${it}_${project.archivesBaseName}"} + rename { "${it}_${inputs.properties.archivesName}"} } } // configure the maven publication publishing { publications { - mavenJava(MavenPublication) { + create("mavenJava", MavenPublication) { + artifactId = project.archives_base_name from components.java } } - // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. - repositories { - // Add repositories to publish to here. - // Notice: This block does NOT have the same function as the block in the top level. - // The repositories here will be used for publishing your artifact, not for - // retrieving dependencies. - } + // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. + repositories { + // Add repositories to publish to here. + // Notice: This block does NOT have the same function as the block in the top level. + // The repositories here will be used for publishing your artifact, not for + // retrieving dependencies. + } } diff --git a/gradle.properties b/gradle.properties index 32c9f5c..c2d4938 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,14 +2,15 @@ org.gradle.jvmargs=-Xmx4G # Fabric Properties (https://fabricmc.net/versions.html) -minecraft_version=1.19.3 -yarn_mappings=1.19.3+build.3 -loader_version=0.14.11 +minecraft_version=1.21.11 +loader_version=0.17.3 # Mod Properties (to automatically tag on linux: 'git tag $(grep -oP '^mod_version = \K.*' gradle.properties)') -mod_version = 1.0.16 +mod_version = 1.3.11+mc-1.21.9-1.21.11 maven_group = net.clayborn -archives_base_name = accurate-block-placement +archives_base_name = AccurateBlockPlacement-Reborn # Dependencies -fabric_version=0.69.0+1.19.3 +fabric_version=0.140.2+1.21.11 +mod_menu_version=16.0.0-rc.1 +cloth_config_version=20.0.148 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f398c33..cd4b7aa 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/net/clayborn/accurateblockplacement/AccurateBlockPlacementMod.java b/src/main/java/net/clayborn/accurateblockplacement/AccurateBlockPlacementMod.java index 3170fcb..b9c26ed 100644 --- a/src/main/java/net/clayborn/accurateblockplacement/AccurateBlockPlacementMod.java +++ b/src/main/java/net/clayborn/accurateblockplacement/AccurateBlockPlacementMod.java @@ -1,35 +1,56 @@ package net.clayborn.accurateblockplacement; +import net.clayborn.accurateblockplacement.config.AccurateBlockPlacementConfig; + import org.lwjgl.glfw.GLFW; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.option.KeyBinding; -import net.minecraft.client.util.InputUtil; -import net.minecraft.text.Text; +import net.minecraft.client.Minecraft; +import net.minecraft.client.KeyMapping; +import net.minecraft.client.KeyMapping.Category; +import com.mojang.blaze3d.platform.InputConstants; +import net.minecraft.resources.Identifier; +import net.minecraft.network.chat.Component; public class AccurateBlockPlacementMod implements ClientModInitializer { public static Boolean disableNormalItemUse = false; - public static boolean isAccurateBlockPlacementEnabled = true; - public static MinecraftClient MC; + public static boolean isAccurateBlockPlacementEnabled; + public static boolean isFastBlockBreakingEnabled; + + public static Minecraft MC; @Override public void onInitializeClient() { - MC = MinecraftClient.getInstance(); + AccurateBlockPlacementConfig.load(); + + MC = Minecraft.getInstance(); - KeyBinding keybind = KeyBindingHelper.registerKeyBinding(new KeyBinding("net.clayborn.accurateblockplacement.togglevanillaplacement", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_UNKNOWN, "Accurate Block Placement")); + Category keybindCategory = KeyMapping.Category.register(Identifier.fromNamespaceAndPath("accurateblockplacement", "category")); + + KeyMapping place_keybind = KeyBindingHelper.registerKeyBinding(new KeyMapping("net.clayborn.accurateblockplacement.togglevanillaplacement", InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_UNKNOWN, keybindCategory)); + + KeyMapping break_keybind = KeyBindingHelper.registerKeyBinding(new KeyMapping("net.clayborn.accurateblockplacement.togglefastbreaking", InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_UNKNOWN, keybindCategory)); ClientTickEvents.END_CLIENT_TICK.register(e -> { - while(keybind.wasPressed()) { + while(place_keybind.consumeClick()) { isAccurateBlockPlacementEnabled = !isAccurateBlockPlacementEnabled; - - MC.inGameHud.getChatHud().addMessage(isAccurateBlockPlacementEnabled ? Text.translatable("net.clayborn.accurateblockplacement.modplacementmodemessage") : Text.translatable("net.clayborn.accurateblockplacement.vanillaplacementmodemessage")); + AccurateBlockPlacementConfig.save(); + if (MC.player != null && AccurateBlockPlacementConfig.confirmation) { + MC.player.displayClientMessage(isAccurateBlockPlacementEnabled ? Component.translatable("net.clayborn.accurateblockplacement.modplacementmodemessage") : Component.translatable("net.clayborn.accurateblockplacement.vanillaplacementmodemessage"), AccurateBlockPlacementConfig.confirmationType); + } + } + while(break_keybind.consumeClick()) { + isFastBlockBreakingEnabled = !isFastBlockBreakingEnabled; + AccurateBlockPlacementConfig.save(); + if (MC.player != null && AccurateBlockPlacementConfig.confirmation) { + MC.player.displayClientMessage(isFastBlockBreakingEnabled ? Component.translatable("net.clayborn.accurateblockplacement.fastbreakingenabled") : Component.translatable("net.clayborn.accurateblockplacement.fastbreakingdisabled"), AccurateBlockPlacementConfig.confirmationType); + } } }); } diff --git a/src/main/java/net/clayborn/accurateblockplacement/config/AccurateBlockPlacementConfig.java b/src/main/java/net/clayborn/accurateblockplacement/config/AccurateBlockPlacementConfig.java new file mode 100644 index 0000000..fe8b4a2 --- /dev/null +++ b/src/main/java/net/clayborn/accurateblockplacement/config/AccurateBlockPlacementConfig.java @@ -0,0 +1,74 @@ +package net.clayborn.accurateblockplacement.config; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.util.Properties; + +import static net.clayborn.accurateblockplacement.AccurateBlockPlacementMod.*; + +import net.fabricmc.loader.api.FabricLoader; + +public class AccurateBlockPlacementConfig { + + private static final String PLACEMENT_KEY = "accurateplace-enabled"; + private static final String BREAKING_KEY = "fastbreak-enabled"; + + final public static boolean DEFAULT_ACCURATE_PLACEMENT_ENABLED = true; + final public static boolean DEFAULT_FAST_BREAKING_ENABLED = false; + + private static final String CONFIRMATION_KEY = "confirmation"; + final public static boolean DEFAULT_CONFIRMATION = true; + public static boolean confirmation; + + private static final String CONFIRMATION_TYPE_KEY = "confirmationType"; + final public static boolean DEFAULT_CONFIRMATION_TYPE = true; + public static boolean confirmationType; + + public static void save() { + File configFile = FabricLoader.getInstance().getConfigDir().resolve("accurateblockplacement.properties").toFile(); + + try (Writer writer = new FileWriter(configFile)) { + Properties properties = new Properties(); + properties.setProperty(PLACEMENT_KEY, Boolean.toString(isAccurateBlockPlacementEnabled)); + properties.setProperty(BREAKING_KEY, Boolean.toString(isFastBlockBreakingEnabled)); + properties.setProperty(CONFIRMATION_KEY, String.valueOf(confirmation)); + properties.setProperty(CONFIRMATION_TYPE_KEY, String.valueOf(confirmationType)); + properties.store(writer, null); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static void load() { + File configFile = FabricLoader.getInstance().getConfigDir().resolve("accurateblockplacement.properties").toFile(); + if (!configFile.exists()) { + try (Writer writer = new FileWriter(configFile)) { + Properties properties = new Properties(); + properties.setProperty(PLACEMENT_KEY, Boolean.toString(DEFAULT_ACCURATE_PLACEMENT_ENABLED)); + properties.setProperty(BREAKING_KEY, Boolean.toString(DEFAULT_FAST_BREAKING_ENABLED)); + properties.setProperty(CONFIRMATION_KEY, String.valueOf(DEFAULT_CONFIRMATION)); + properties.setProperty(CONFIRMATION_TYPE_KEY, String.valueOf(DEFAULT_CONFIRMATION_TYPE)); + properties.store(writer, null); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + try (Reader reader = new FileReader(configFile)) { + Properties properties = new Properties(); + properties.load(reader); + isAccurateBlockPlacementEnabled = Boolean.parseBoolean(properties.getProperty(PLACEMENT_KEY, String.valueOf(DEFAULT_ACCURATE_PLACEMENT_ENABLED))); + isFastBlockBreakingEnabled = Boolean.parseBoolean(properties.getProperty(BREAKING_KEY, String.valueOf(DEFAULT_FAST_BREAKING_ENABLED))); + confirmation = Boolean.parseBoolean(properties.getProperty(CONFIRMATION_KEY, String.valueOf(DEFAULT_CONFIRMATION))); + confirmationType = Boolean.parseBoolean(properties.getProperty(CONFIRMATION_TYPE_KEY, String.valueOf(DEFAULT_CONFIRMATION_TYPE))); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (IllegalStateException e) { + save(); + } + } +} diff --git a/src/main/java/net/clayborn/accurateblockplacement/config/AccurateBlockPlacementConfigScreen.java b/src/main/java/net/clayborn/accurateblockplacement/config/AccurateBlockPlacementConfigScreen.java new file mode 100644 index 0000000..cbfd242 --- /dev/null +++ b/src/main/java/net/clayborn/accurateblockplacement/config/AccurateBlockPlacementConfigScreen.java @@ -0,0 +1,58 @@ +package net.clayborn.accurateblockplacement.config; + +import static net.clayborn.accurateblockplacement.AccurateBlockPlacementMod.*; + +import net.clayborn.accurateblockplacement.config.AccurateBlockPlacementConfig; +import me.shedaniel.clothconfig2.api.ConfigBuilder; +import me.shedaniel.clothconfig2.api.ConfigCategory; +import me.shedaniel.clothconfig2.api.ConfigEntryBuilder; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; + +public class AccurateBlockPlacementConfigScreen { + public static Screen createConfigScreen(Screen parent) { + ConfigBuilder builder = ConfigBuilder.create() + .setParentScreen(parent) + .setTitle(Component.translatable("text.autoconfig.accurateblockplacement.title")); + builder.setSavingRunnable(AccurateBlockPlacementConfig::save); + ConfigCategory general = builder + .getOrCreateCategory(Component.translatable("text.autoconfig.accurateblockplacement.title")); + ConfigEntryBuilder entryBuilder = builder.entryBuilder(); + // Accurate placement + general.addEntry(entryBuilder + .startBooleanToggle( + Component.translatable("text.autoconfig.accurateblockplacement.option.accuratePlacementEnabled"), + isAccurateBlockPlacementEnabled) + .setDefaultValue(AccurateBlockPlacementConfig.DEFAULT_ACCURATE_PLACEMENT_ENABLED) + .setSaveConsumer((replace) -> isAccurateBlockPlacementEnabled = replace).build()); + // Fast breaking + general.addEntry(entryBuilder + .startBooleanToggle( + Component.translatable("text.autoconfig.accurateblockplacement.option.fastBreakingEnabled"), + isFastBlockBreakingEnabled) + .setDefaultValue(AccurateBlockPlacementConfig.DEFAULT_FAST_BREAKING_ENABLED) + .setSaveConsumer((replace) -> isFastBlockBreakingEnabled = replace) + .build()); + // Confirmation + general.addEntry(entryBuilder + .startBooleanToggle( + Component.translatable("text.autoconfig.accurateblockplacement.option.confirmation"), + AccurateBlockPlacementConfig.confirmation) + .setDefaultValue(AccurateBlockPlacementConfig.DEFAULT_CONFIRMATION) + .setSaveConsumer((replace) -> AccurateBlockPlacementConfig.confirmation = replace) + .build()); + // Confirmation Type + enum ConfirmTypeLabel { + CHAT, + HUD + } + general.addEntry(entryBuilder + .startEnumSelector(Component.translatable("text.autoconfig.accurateblockplacement.option.confirmationType"), + ConfirmTypeLabel.class, + !AccurateBlockPlacementConfig.confirmationType ? ConfirmTypeLabel.CHAT : ConfirmTypeLabel.HUD) + .setDefaultValue(ConfirmTypeLabel.HUD) + .setSaveConsumer((replace) -> AccurateBlockPlacementConfig.confirmationType = replace == ConfirmTypeLabel.HUD) + .build()); + return builder.build(); + } +} diff --git a/src/main/java/net/clayborn/accurateblockplacement/config/ModMenuPlugin.java b/src/main/java/net/clayborn/accurateblockplacement/config/ModMenuPlugin.java new file mode 100644 index 0000000..9c04400 --- /dev/null +++ b/src/main/java/net/clayborn/accurateblockplacement/config/ModMenuPlugin.java @@ -0,0 +1,18 @@ +package net.clayborn.accurateblockplacement.config; + +import com.terraformersmc.modmenu.api.ConfigScreenFactory; +import com.terraformersmc.modmenu.api.ModMenuApi; + +import net.clayborn.accurateblockplacement.config.AccurateBlockPlacementConfigScreen; +import net.fabricmc.loader.api.FabricLoader; + +public class ModMenuPlugin implements ModMenuApi { + @Override + public ConfigScreenFactory getModConfigScreenFactory() { + if (FabricLoader.getInstance().isModLoaded("cloth-config")) { + return AccurateBlockPlacementConfigScreen::createConfigScreen; + } else { + return null; + } + } +} diff --git a/src/main/java/net/clayborn/accurateblockplacement/mixin/GameRendererMixin.java b/src/main/java/net/clayborn/accurateblockplacement/mixin/GameRendererMixin.java index d31ff59..2b3dea4 100644 --- a/src/main/java/net/clayborn/accurateblockplacement/mixin/GameRendererMixin.java +++ b/src/main/java/net/clayborn/accurateblockplacement/mixin/GameRendererMixin.java @@ -1,69 +1,77 @@ package net.clayborn.accurateblockplacement.mixin; -import java.lang.reflect.Method; -import java.util.ArrayList; - +import net.clayborn.accurateblockplacement.AccurateBlockPlacementMod; +import net.clayborn.accurateblockplacement.IKeyBindingAccessor; +import net.clayborn.accurateblockplacement.IMinecraftClientAccessor; +import net.minecraft.world.level.block.*; +import net.minecraft.world.level.block.state.*; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; +// TODO: Can this actually be removed? +import net.minecraft.core.component.DataComponents; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.*; +import net.minecraft.world.item.context.*; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction.Axis; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.level.Level; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import net.clayborn.accurateblockplacement.AccurateBlockPlacementMod; -import net.clayborn.accurateblockplacement.IKeyBindingAccessor; -import net.clayborn.accurateblockplacement.IMinecraftClientAccessor; -import net.minecraft.block.AbstractBlock; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.StairsBlock; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.GameRenderer; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.AliasedBlockItem; -import net.minecraft.item.BlockItem; -import net.minecraft.item.Item; -import net.minecraft.item.ItemPlacementContext; -import net.minecraft.item.ItemStack; -import net.minecraft.item.ItemUsageContext; -import net.minecraft.item.MiningToolItem; -import net.minecraft.util.Hand; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.hit.HitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; -import net.minecraft.util.math.Direction.Axis; -import net.minecraft.world.World; +import java.lang.reflect.Method; +import java.util.ArrayList; @Mixin(GameRenderer.class) public abstract class GameRendererMixin { + @Unique private static final String blockActivateMethodName = getBlockActivateMethodName(); + @Unique private static final String itemUseMethodName = getItemUseMethodName(); - + @Unique private BlockPos lastSeenBlockPos = null; + @Unique private BlockPos lastPlacedBlockPos = null; - private Vec3d lastPlayerPlacedBlockPos = null; + @Unique + private Vec3 lastPlayerPlacedBlockPos = null; + @Unique private Boolean autoRepeatWaitingOnCooldown = true; - private Vec3d lastFreshPressMouseRatio = null; - private ArrayList backFillList = new ArrayList(); + @Unique + private Vec3 lastFreshPressMouseRatio = null; + @Unique + private ArrayList backFillList = new ArrayList<>(); + @Unique private Item lastItemInUse = null; - Hand handOfCurrentItemInUse; + @Unique + InteractionHand handOfCurrentItemInUse; - private Item getItemInUse(MinecraftClient client) + @Unique + private Item getItemInUse(Minecraft client) { // have to check each hand - Hand[] hands = Hand.values(); + InteractionHand[] hands = InteractionHand.values(); int numHands = hands.length; for(int i = 0; i < numHands; ++i) { - Hand thisHand = hands[i]; - ItemStack itemInHand = client.player.getStackInHand(thisHand); + InteractionHand thisHand = hands[i]; + assert client.player!= null; + ItemStack itemInHand = client.player.getItemInHand(thisHand); if(itemInHand.isEmpty()) { // hand is empty try the next one continue; } - else { + else if(itemInHand instanceof ItemStack && (itemInHand.getItem() instanceof BlockItem || itemInHand.getItem() instanceof ShovelItem || itemInHand.getItem() instanceof HoeItem || itemInHand.getItem() instanceof AxeItem)) { + // found a block + // or found an item that can be placed, used or interacted with a block handOfCurrentItemInUse = thisHand; return itemInHand.getItem(); } @@ -72,6 +80,7 @@ private Item getItemInUse(MinecraftClient client) return null; } + @Unique private static String getBlockActivateMethodName() { Method[] methods = Block.class.getMethods(); @@ -85,89 +94,73 @@ private static String getBlockActivateMethodName() if(types[0] != BlockState.class) { continue; } - if(types[1] != World.class) { + if(types[1] != Level.class) { continue; } if(types[2] != BlockPos.class) { continue; } - if(types[3] != PlayerEntity.class) { + if(types[3] != Player.class) { continue; } - if(types[4] != Hand.class) { + if(types[4] != InteractionHand.class) { continue; } if(types[5] != BlockHitResult.class) { continue; } - return method.getName(); } - return null; } - private Boolean doesBlockHaveOverriddenActivateMethod(Block block) + @Unique + private static String getItemUseMethodName() { - if(blockActivateMethodName == null) { - System.out.println("[ERROR] blockActivateMethodName is null!"); - } - - // TODO: consider cache of results - try { - return !block.getClass().getMethod(blockActivateMethodName, BlockState.class, World.class, BlockPos.class, PlayerEntity.class, Hand.class, BlockHitResult.class).getDeclaringClass().equals(AbstractBlock.class); + Method useMethod = Item.class.getDeclaredMethod("use", Level.class, Player.class, InteractionHand.class); + return useMethod.getName(); } - catch(Exception e) { - System.out.println("[ERROR] Unable to find block " + block.getClass().getName() + " activate method!"); - return false; + catch (NoSuchMethodException e) { + return null; } } - private static String getItemUseMethodName() + @Unique + private static boolean doesBlockHaveOverriddenActivateMethod(Block block) { - Method[] methods = Item.class.getMethods(); - - for(Method method : methods) { - Class[] types = method.getParameterTypes(); - - if(types.length != 3) { - continue; - } - if(types[0] != World.class) { - continue; - } - if(types[1] != PlayerEntity.class) { - continue; - } - if(types[2] != Hand.class) { - continue; - } + if(blockActivateMethodName == null) { + return false; + } - return method.getName(); + try { + Method activateMethod = block.getClass().getDeclaredMethod(blockActivateMethodName, BlockState.class, Level.class, BlockPos.class, Player.class, InteractionHand.class, BlockHitResult.class); + return activateMethod.getDeclaringClass()!= Block.class; + } + catch (NoSuchMethodException e) { + return false; } - return null; } - private Boolean doesItemHaveOverriddenUseMethod(Item item) + @Unique + private static boolean doesItemHaveOverriddenUseMethod(Item item) { - if(itemUseMethodName == null) { - System.out.println("[ERROR] itemUseMethodName is null!"); + // have to mark other Item types because they have vanilla usages that would get flagged, despite being usable in/by ABP:R + if(itemUseMethodName == null || item instanceof ShovelItem || item instanceof HoeItem || item instanceof AxeItem) { + return false; } - // TODO: consider cache of results - try { - return !item.getClass().getMethod(itemUseMethodName, World.class, PlayerEntity.class, Hand.class).getDeclaringClass().equals(Item.class); + Method useMethod = item.getClass().getDeclaredMethod(itemUseMethodName, ItemStack.class, Level.class, Player.class, InteractionHand.class, BlockHitResult.class); + return useMethod.getDeclaringClass()!= Item.class; } - catch (Exception e) { - System.out.println("[ERROR] Unable to find item " + item.getClass().getName() + " use method!"); + catch (NoSuchMethodException e) { return false; } } - @Inject(method = "updateTargetedEntity", at = @At("RETURN")) + @Inject(method = "pick", at = @At("RETURN")) private void onUpdateTargetedEntityComplete(CallbackInfo info) { if(!AccurateBlockPlacementMod.isAccurateBlockPlacementEnabled) { @@ -183,22 +176,20 @@ private void onUpdateTargetedEntityComplete(CallbackInfo info) lastFreshPressMouseRatio = null; - lastItemInUse = null; - return; } - MinecraftClient client = MinecraftClient.getInstance(); + Minecraft client = Minecraft.getInstance(); // safety checks - if(client == null || client.options == null || client.options.useKey == null || client.crosshairTarget == null || client.player == null || client.world == null || client.mouse == null || client.getWindow() == null) { + if(client == null || client.options == null || client.options.keyUse == null || client.hitResult == null || client.player == null || client.level == null || client.mouseHandler == null || client.getWindow() == null) { return; } // will be set to true only if needed AccurateBlockPlacementMod.disableNormalItemUse = false; - IKeyBindingAccessor keyUseAccessor = (IKeyBindingAccessor) (Object) client.options.useKey; - Boolean freshKeyPress = keyUseAccessor.accurateblockplacement_GetTimesPressed() > 0; + IKeyBindingAccessor keyUseAccessor = (IKeyBindingAccessor) client.options.keyUse; + boolean freshKeyPress = keyUseAccessor.accurateblockplacement_GetTimesPressed() > 0; Item currentItem = getItemInUse(client); @@ -214,15 +205,12 @@ private void onUpdateTargetedEntityComplete(CallbackInfo info) autoRepeatWaitingOnCooldown = true; backFillList.clear(); - if(client.getWindow().getWidth() > 0 && client.getWindow().getHeight() > 0) { - lastFreshPressMouseRatio = new Vec3d(client.mouse.getX() / client.getWindow().getWidth(), client.mouse.getY() / client.getWindow().getHeight(), 0); + if(client.getWindow().getScreenWidth() > 0 && client.getWindow().getScreenHeight() > 0) { + lastFreshPressMouseRatio = new Vec3(client.mouseHandler.xpos() / client.getWindow().getScreenWidth(), client.mouseHandler.ypos() / client.getWindow().getScreenHeight(), 0); } else { lastFreshPressMouseRatio = null; } - - // a fresh keypress is required each time the item being used changes - lastItemInUse = currentItem; } // if nothing in hand, let vanilla take over @@ -230,73 +218,95 @@ private void onUpdateTargetedEntityComplete(CallbackInfo info) return; } - // if the item isn't a block or a mining tool (axe, hoe, pickaxe, shovel), let vanilla take over - if(!(currentItem instanceof BlockItem) && !(currentItem instanceof MiningToolItem)) { + // if player is actively using an item (i.e. a shield), let vanilla take over + if(client.player.isUsingItem()) { + return; + } + + // if the item isn't a block, shovel, hoe or axe, let vanilla take over + if(!(currentItem instanceof BlockItem || currentItem instanceof ShovelItem || currentItem instanceof HoeItem || currentItem instanceof AxeItem)) { return; } // if the item we are holding is activatable, let vanilla take over - if((currentItem.isFood() && !(currentItem instanceof AliasedBlockItem)) || doesItemHaveOverriddenUseMethod(currentItem)) { + // important to note that this will NOT catch Hoes, Shovels or Axes, as they're exempted in the method called + if(doesItemHaveOverriddenUseMethod(currentItem)) { return; } - // if we aren't looking at a block (so we can place), let vanilla take over - if(client.crosshairTarget.getType() != HitResult.Type.BLOCK) { + // if we aren't looking at a block, let vanilla take over + if(client.hitResult.getType() != HitResult.Type.BLOCK) { return; } // check the other hand if it has something in use and if so let vanilla take over - Hand otherHand = handOfCurrentItemInUse == Hand.MAIN_HAND ? Hand.OFF_HAND : Hand.MAIN_HAND; - ItemStack otherHandItemStack = client.player.getStackInHand(otherHand); - if(!otherHandItemStack.isEmpty() && (otherHandItemStack.getItem().isFood() || doesItemHaveOverriddenUseMethod(otherHandItemStack.getItem())) && client.player.isUsingItem()) { + InteractionHand otherHand = handOfCurrentItemInUse == InteractionHand.MAIN_HAND ? InteractionHand.OFF_HAND : InteractionHand.MAIN_HAND; + ItemStack otherHandItemStack = client.player.getItemInHand(otherHand); + if(!otherHandItemStack.isEmpty() && (doesItemHaveOverriddenUseMethod(otherHandItemStack.getItem())) && client.player.isUsingItem()) { return; } - BlockHitResult blockHitResult = (BlockHitResult) client.crosshairTarget; + BlockHitResult blockHitResult = (BlockHitResult) client.hitResult; BlockPos blockHitPos = blockHitResult.getBlockPos(); - Block targetBlock = client.world.getBlockState(blockHitPos).getBlock(); - Boolean isTargetBlockActivatable = doesBlockHaveOverriddenActivateMethod(targetBlock); + Block targetBlock = client.level.getBlockState(blockHitPos).getBlock(); + boolean isTargetBlockActivatable = doesBlockHaveOverriddenActivateMethod(targetBlock); // don't override behavior of clicking activatable blocks (and stairs) unless holding SNEAKING to replicate vanilla behaviors - if(isTargetBlockActivatable && !(targetBlock instanceof StairsBlock) && !client.player.isSneaking()) { + if(isTargetBlockActivatable && !(targetBlock instanceof StairBlock) && !client.player.isShiftKeyDown()) { + return; + } + + // if the target block is a BlockWithEntity (i.e. storage container) and the player has moved less than 0.6 blocks, let vanilla take over + // TODO: Investigate the secondary check, it doesn't seem to be working as intended + if((targetBlock instanceof BaseEntityBlock) && (lastPlayerPlacedBlockPos != null && lastPlayerPlacedBlockPos.distanceTo(client.player.position()) <= 0.6)) { + return; + } + + // if the hand item and target block are both scaffolding, let vanilla take over + if ((currentItem instanceof ScaffoldingBlockItem) && (targetBlock instanceof ScaffoldingBlock)) { + return; + } + + // if the target block is a composter and the held item is compostable, let vanilla take over + if((targetBlock instanceof ComposterBlock) && (ComposterBlock.COMPOSTABLES.containsKey(currentItem))) { return; } // are they holding the use key and is the item to use a block? - // also is the the SAME item we started with if we are in repeat mode? + // also is the SAME item we started with if we are in repeat mode? // note: check both freshKey and current state in cause of shitty frame rates - if((freshKeyPress || client.options.useKey.isPressed())) { + if((freshKeyPress || client.options.keyUse.isDown())) { // it's a block!! it's go time! AccurateBlockPlacementMod.disableNormalItemUse = true; - ItemPlacementContext targetPlacement = new ItemPlacementContext(new ItemUsageContext(client.player, handOfCurrentItemInUse, blockHitResult)); + BlockPlaceContext targetPlacement = new BlockPlaceContext(new UseOnContext(client.player, handOfCurrentItemInUse, blockHitResult)); // remember what was there before - Block oldBlock = client.world.getBlockState(targetPlacement.getBlockPos()).getBlock(); + Block oldBlock = client.level.getBlockState(targetPlacement.getClickedPos()).getBlock(); double facingAxisPlayerPos = 0.0d; double facingAxisPlayerLastPos = 0.0d; double facingAxisLastPlacedPos = 0.0d; if(lastPlacedBlockPos != null && lastPlayerPlacedBlockPos != null) { - Axis axis = targetPlacement.getSide().getAxis(); + Axis axis = targetPlacement.getClickedFace().getAxis(); - facingAxisPlayerPos = client.player.getPos().getComponentAlongAxis(axis); - facingAxisPlayerLastPos = lastPlayerPlacedBlockPos.getComponentAlongAxis(axis); - facingAxisLastPlacedPos = new Vec3d(lastPlacedBlockPos.getX(), lastPlacedBlockPos.getY(), lastPlacedBlockPos.getZ()).getComponentAlongAxis(axis); + facingAxisPlayerPos = client.player.position().get(axis); + facingAxisPlayerLastPos = lastPlayerPlacedBlockPos.get(axis); + facingAxisLastPlacedPos = new Vec3(lastPlacedBlockPos.getX(), lastPlacedBlockPos.getY(), lastPlacedBlockPos.getZ()).get(axis); // fixes placement being directional because getting the correct side pos is apparently too hard - if(targetPlacement.getSide().getName().equals("west") || targetPlacement.getSide().getName().equals("north")) { + if(targetPlacement.getClickedFace().toString().equals("west") || targetPlacement.getClickedFace().toString().equals("north")) { facingAxisLastPlacedPos += 1.0d; } } IMinecraftClientAccessor clientAccessor = (IMinecraftClientAccessor) client; - Vec3d currentMouseRatio = null; + Vec3 currentMouseRatio = null; - if(client.getWindow().getWidth() > 0 && client.getWindow().getHeight() > 0) { - currentMouseRatio = new Vec3d(client.mouse.getX() / client.getWindow().getWidth(), client.mouse.getY() / client.getWindow().getHeight(), 0); + if(client.getWindow().getScreenWidth() > 0 && client.getWindow().getScreenHeight() > 0) { + currentMouseRatio = new Vec3(client.mouseHandler.xpos() / client.getWindow().getScreenWidth(), client.mouseHandler.ypos() / client.getWindow().getScreenHeight(), 0); } // Condition: @@ -305,78 +315,71 @@ private void onUpdateTargetedEntityComplete(CallbackInfo info) // [ we have no 'place' history or the 'place' history isn't a match ] ] OR // [ we have 'place' history, it is a match, the player is building toward // themselves and has moved one block backwards] ] - Boolean isPlacementTargetFresh = ((lastSeenBlockPos == null || !lastSeenBlockPos.equals(blockHitPos)) - && (lastPlacedBlockPos == null || !lastPlacedBlockPos.equals(blockHitPos))) - || (lastPlacedBlockPos != null && lastPlayerPlacedBlockPos != null + boolean isPlacementTargetFresh = ((lastSeenBlockPos == null || !lastSeenBlockPos.equals(blockHitPos)) + && (lastPlacedBlockPos == null || !lastPlacedBlockPos.equals(blockHitPos))) + || (lastPlacedBlockPos != null && lastPlayerPlacedBlockPos != null && lastPlacedBlockPos.equals(blockHitPos) && Math.abs(facingAxisPlayerLastPos - facingAxisPlayerPos) >= 0.99d // because precision && Math.abs(facingAxisPlayerLastPos - facingAxisLastPlacedPos) < Math.abs(facingAxisPlayerPos - facingAxisLastPlacedPos)); - Boolean hasMouseMoved = (currentMouseRatio != null && lastFreshPressMouseRatio != null && lastFreshPressMouseRatio.distanceTo(currentMouseRatio) >= 0.1); + boolean hasMouseMoved = (currentMouseRatio != null && lastFreshPressMouseRatio != null && lastFreshPressMouseRatio.distanceTo(currentMouseRatio) >= 0.1); - Boolean isOnCooldown = autoRepeatWaitingOnCooldown && clientAccessor.accurateblockplacement_GetItemUseCooldown() > 0 && !hasMouseMoved; + boolean isOnCooldown = autoRepeatWaitingOnCooldown && clientAccessor.accurateblockplacement_GetItemUseCooldown() > 0 && !hasMouseMoved; - // if [ we are still holding the same block we starting pressing 'use' with] AND - // [ [ this is a fresh keypress ] OR + // if [ [ this is a fresh keypress ] OR // [ [ we have a fresh place to put a block ] AND - // [ auto repeat isn't on cooldown OR the mouse has moved enough ] ] + // [ auto-repeat isn't on cooldown OR the mouse has moved enough ] ] // we can try to place a block // note: this is always true on a fresh keypress - if(lastItemInUse == currentItem) { if(freshKeyPress || (isPlacementTargetFresh && !isOnCooldown)) { // update if we are repeating if(autoRepeatWaitingOnCooldown && !freshKeyPress) { autoRepeatWaitingOnCooldown = false; - HitResult currentHitResult = client.crosshairTarget; + HitResult currentHitResult = client.hitResult; // try to place the backlog for(HitResult prevHitResult : backFillList) { - client.crosshairTarget = prevHitResult; + client.hitResult = prevHitResult; // use item clientAccessor.accurateblockplacement_DoItemUseBypassDisable(); } backFillList.clear(); - client.crosshairTarget = currentHitResult; + client.hitResult = currentHitResult; } // always run at least once if we reach here // if this isn't a fresh key press, turn on the run once flag - Boolean runOnceFlag = !freshKeyPress; + boolean runOnceFlag = !freshKeyPress; // in case they manage to push the button multiple times per frame // note: we already subtracted one from the press count earlier so the total // should be the same - while(runOnceFlag || client.options.useKey.wasPressed()) { + while(runOnceFlag || client.options.keyUse.consumeClick()) { // use item clientAccessor.accurateblockplacement_DoItemUseBypassDisable(); // update last placed - if(!oldBlock.equals(client.world.getBlockState(targetPlacement.getBlockPos()).getBlock())) { - lastPlacedBlockPos = targetPlacement.getBlockPos(); + if(!oldBlock.equals(client.level.getBlockState(targetPlacement.getClickedPos()).getBlock())) { + lastPlacedBlockPos = targetPlacement.getClickedPos(); if(lastPlayerPlacedBlockPos == null) { - lastPlayerPlacedBlockPos = client.player.getPos(); + lastPlayerPlacedBlockPos = client.player.position(); } else { // prevent slow rounding error from eventually moving the player out of range - Vec3d summedLastPlayerPos = lastPlayerPlacedBlockPos.add(new Vec3d(targetPlacement.getSide().getVector().getX(), targetPlacement.getSide().getVector().getY(), targetPlacement.getSide().getVector().getZ())); - - Vec3d newLastPlayerPlacedPos = null; - - switch(targetPlacement.getSide().getAxis()) { - case X: - newLastPlayerPlacedPos = new Vec3d(summedLastPlayerPos.x, client.player.getPos().y, client.player.getPos().z); - break; - case Y: - newLastPlayerPlacedPos = new Vec3d(client.player.getPos().x, summedLastPlayerPos.y, client.player.getPos().z); - break; - case Z: - newLastPlayerPlacedPos = new Vec3d(client.player.getPos().x, client.player.getPos().y, summedLastPlayerPos.z); - break; - } + Vec3 summedLastPlayerPos = lastPlayerPlacedBlockPos.add(new Vec3(targetPlacement.getClickedFace().getUnitVec3i().getX(), targetPlacement.getClickedFace().getUnitVec3i().getY(), targetPlacement.getClickedFace().getUnitVec3i().getZ())); + + Vec3 newLastPlayerPlacedPos = switch (targetPlacement.getClickedFace().getAxis()) { + case X -> + new Vec3(summedLastPlayerPos.x, client.player.position().y, client.player.position().z); + case Y -> + new Vec3(client.player.position().x, summedLastPlayerPos.y, client.player.position().z); + case Z -> + new Vec3(client.player.position().x, client.player.position().y, summedLastPlayerPos.z); + }; lastPlayerPlacedBlockPos = newLastPlayerPlacedPos; } @@ -387,12 +390,11 @@ private void onUpdateTargetedEntityComplete(CallbackInfo info) } else if(isPlacementTargetFresh) { // populate the backfill list just in case - backFillList.add(client.crosshairTarget); + backFillList.add(client.hitResult); } - } // update the last block we looked at lastSeenBlockPos = blockHitResult.getBlockPos(); } } -} +} \ No newline at end of file diff --git a/src/main/java/net/clayborn/accurateblockplacement/mixin/KeyBindingMixin.java b/src/main/java/net/clayborn/accurateblockplacement/mixin/KeyMappingMixin.java similarity index 60% rename from src/main/java/net/clayborn/accurateblockplacement/mixin/KeyBindingMixin.java rename to src/main/java/net/clayborn/accurateblockplacement/mixin/KeyMappingMixin.java index 2f8835e..78fdb09 100644 --- a/src/main/java/net/clayborn/accurateblockplacement/mixin/KeyBindingMixin.java +++ b/src/main/java/net/clayborn/accurateblockplacement/mixin/KeyMappingMixin.java @@ -4,17 +4,17 @@ import org.spongepowered.asm.mixin.Shadow; import net.clayborn.accurateblockplacement.IKeyBindingAccessor; -import net.minecraft.client.option.KeyBinding; +import net.minecraft.client.KeyMapping; -@Mixin(KeyBinding.class) -public abstract class KeyBindingMixin implements IKeyBindingAccessor +@Mixin(KeyMapping.class) +public abstract class KeyMappingMixin implements IKeyBindingAccessor { @Shadow - private int timesPressed; + private int clickCount; @Override public int accurateblockplacement_GetTimesPressed() { - return timesPressed; + return clickCount; } } diff --git a/src/main/java/net/clayborn/accurateblockplacement/mixin/MinecraftClientMixin.java b/src/main/java/net/clayborn/accurateblockplacement/mixin/MinecraftMixin.java similarity index 73% rename from src/main/java/net/clayborn/accurateblockplacement/mixin/MinecraftClientMixin.java rename to src/main/java/net/clayborn/accurateblockplacement/mixin/MinecraftMixin.java index a5dc37f..f216360 100644 --- a/src/main/java/net/clayborn/accurateblockplacement/mixin/MinecraftClientMixin.java +++ b/src/main/java/net/clayborn/accurateblockplacement/mixin/MinecraftMixin.java @@ -8,27 +8,27 @@ import net.clayborn.accurateblockplacement.AccurateBlockPlacementMod; import net.clayborn.accurateblockplacement.IMinecraftClientAccessor; -import net.minecraft.client.MinecraftClient; +import net.minecraft.client.Minecraft; -@Mixin(MinecraftClient.class) -public abstract class MinecraftClientMixin implements IMinecraftClientAccessor +@Mixin(Minecraft.class) +public abstract class MinecraftMixin implements IMinecraftClientAccessor { @Shadow - protected abstract void doItemUse(); + protected abstract void startUseItem(); @Shadow - private int itemUseCooldown; + private int rightClickDelay; @Override public void accurateblockplacement_DoItemUseBypassDisable() { Boolean oldValue = AccurateBlockPlacementMod.disableNormalItemUse; AccurateBlockPlacementMod.disableNormalItemUse = false; - doItemUse(); + startUseItem(); AccurateBlockPlacementMod.disableNormalItemUse = oldValue; } - @Inject(method = "doItemUse", at = @At("HEAD"), cancellable = true) + @Inject(method = "startUseItem", at = @At("HEAD"), cancellable = true) void OnDoItemUse(CallbackInfo info) { if(AccurateBlockPlacementMod.disableNormalItemUse) { @@ -39,12 +39,12 @@ void OnDoItemUse(CallbackInfo info) @Override public void accurateblockplacement_SetItemUseCooldown(int cooldown) { - itemUseCooldown = cooldown; + rightClickDelay = cooldown; } @Override public int accurateblockplacement_GetItemUseCooldown() { - return itemUseCooldown; + return rightClickDelay; } } diff --git a/src/main/java/net/clayborn/accurateblockplacement/mixin/MultiPlayerGameModeMixin.java b/src/main/java/net/clayborn/accurateblockplacement/mixin/MultiPlayerGameModeMixin.java new file mode 100644 index 0000000..7156847 --- /dev/null +++ b/src/main/java/net/clayborn/accurateblockplacement/mixin/MultiPlayerGameModeMixin.java @@ -0,0 +1,15 @@ +package net.clayborn.accurateblockplacement.mixin; + +import net.clayborn.accurateblockplacement.AccurateBlockPlacementMod; +import net.minecraft.client.multiplayer.MultiPlayerGameMode; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +@Mixin(MultiPlayerGameMode.class) +public class MultiPlayerGameModeMixin { + @ModifyConstant(method = "continueDestroyBlock", constant = @Constant(intValue = 5)) + private int FastBlockBreaking(int value) { + return AccurateBlockPlacementMod.isFastBlockBreakingEnabled ? 0 : value; + } +} \ No newline at end of file diff --git a/src/main/resources/accurateblockplacement.mixins.json b/src/main/resources/accurateblockplacement.mixins.json index 3bd32ba..4a8d765 100644 --- a/src/main/resources/accurateblockplacement.mixins.json +++ b/src/main/resources/accurateblockplacement.mixins.json @@ -1,14 +1,15 @@ { - "required": true, - "minVersion": "0.8", - "package": "net.clayborn.accurateblockplacement.mixin", - "compatibilityLevel": "JAVA_17", - "client": [ - "GameRendererMixin", - "MinecraftClientMixin", - "KeyBindingMixin" - ], - "injectors": { - "defaultRequire": 1 - } + "required": true, + "minVersion": "0.8", + "package": "net.clayborn.accurateblockplacement.mixin", + "compatibilityLevel": "JAVA_17", + "client": [ + "MultiPlayerGameModeMixin", + "GameRendererMixin", + "KeyMappingMixin", + "MinecraftMixin" + ], + "injectors": { + "defaultRequire": 1 + } } diff --git a/src/main/resources/assets/accurateblockplacement/icon.png b/src/main/resources/assets/accurateblockplacement/icon.png index 6560e61..8ad582c 100644 Binary files a/src/main/resources/assets/accurateblockplacement/icon.png and b/src/main/resources/assets/accurateblockplacement/icon.png differ diff --git a/src/main/resources/assets/accurateblockplacement/lang/cs_cz.json b/src/main/resources/assets/accurateblockplacement/lang/cs_cz.json index 282b7fb..b102fcd 100644 --- a/src/main/resources/assets/accurateblockplacement/lang/cs_cz.json +++ b/src/main/resources/assets/accurateblockplacement/lang/cs_cz.json @@ -1,5 +1,16 @@ { + "key.category.accurateblockplacement.category": "Accurate Block Placement", "net.clayborn.accurateblockplacement.togglevanillaplacement": "Přepínání vylepšeného/vanilla pokládání", "net.clayborn.accurateblockplacement.modplacementmodemessage": "Vylepšené pokládání bloků je nyní zaplé!", - "net.clayborn.accurateblockplacement.vanillaplacementmodemessage": "Vanilla pokládání bloků je nyní zaplé!" + "net.clayborn.accurateblockplacement.vanillaplacementmodemessage": "Vanilla pokládání bloků je nyní zaplé!", + "net.clayborn.accurateblockplacement.togglefastbreaking": "Toggle Breaking Mode", + "net.clayborn.accurateblockplacement.fastbreakingenabled": "Fast block breaking mode is now enabled!", + "net.clayborn.accurateblockplacement.fastbreakingdisabled": "Vanilla block breaking mode is now enabled!", + "text.autoconfig.accurateblockplacement.title": "Accurate Block Placement", + "text.autoconfig.accurateblockplacement.option.accuratePlacementEnabled": "Accurate block placement enabled", + "text.autoconfig.accurateblockplacement.option.fastBreakingEnabled": "Fast block breaking enabled", + "text.autoconfig.accurateblockplacement.option.confirmation": "Confirmation on Toggle", + "text.autoconfig.accurateblockplacement.option.confirmationType": "Confirmation Type", + "text.autoconfig.accurateblockplacement.option.confirmationType.CHAT": "Chat", + "text.autoconfig.accurateblockplacement.option.confirmationType.HUD": "HUD" } diff --git a/src/main/resources/assets/accurateblockplacement/lang/en_us.json b/src/main/resources/assets/accurateblockplacement/lang/en_us.json index 8d7bdfe..d76c620 100644 --- a/src/main/resources/assets/accurateblockplacement/lang/en_us.json +++ b/src/main/resources/assets/accurateblockplacement/lang/en_us.json @@ -1,5 +1,16 @@ { - "net.clayborn.accurateblockplacement.togglevanillaplacement": "Toggle Vanilla Placement", - "net.clayborn.accurateblockplacement.modplacementmodemessage": "Accurate block placement mode is now enabled!", - "net.clayborn.accurateblockplacement.vanillaplacementmodemessage": "Vanilla block placement mode is now enabled!" + "key.category.accurateblockplacement.category": "Accurate Block Placement", + "net.clayborn.accurateblockplacement.togglevanillaplacement": "Toggle Placement Mode", + "net.clayborn.accurateblockplacement.modplacementmodemessage": "§7Accurate Block Placement: §aEnabled", + "net.clayborn.accurateblockplacement.vanillaplacementmodemessage": "§7Accurate Block Placement: §cDisabled", + "net.clayborn.accurateblockplacement.togglefastbreaking": "Toggle Breaking Mode", + "net.clayborn.accurateblockplacement.fastbreakingenabled": "§7Fast Block Breaking: §aEnabled", + "net.clayborn.accurateblockplacement.fastbreakingdisabled": "§7Fast Block Breaking: §cDisabled", + "text.autoconfig.accurateblockplacement.title": "Accurate Block Placement", + "text.autoconfig.accurateblockplacement.option.accuratePlacementEnabled": "Accurate Block Placement enabled", + "text.autoconfig.accurateblockplacement.option.fastBreakingEnabled": "Fast Block Breaking enabled", + "text.autoconfig.accurateblockplacement.option.confirmation": "Confirmation on Toggle", + "text.autoconfig.accurateblockplacement.option.confirmationType": "Confirmation Type", + "text.autoconfig.accurateblockplacement.option.confirmationType.CHAT": "Chat", + "text.autoconfig.accurateblockplacement.option.confirmationType.HUD": "HUD" } diff --git a/src/main/resources/assets/accurateblockplacement/lang/it_it.json b/src/main/resources/assets/accurateblockplacement/lang/it_it.json new file mode 100644 index 0000000..e9761a2 --- /dev/null +++ b/src/main/resources/assets/accurateblockplacement/lang/it_it.json @@ -0,0 +1,16 @@ +{ + "key.category.accurateblockplacement.category": "Accurate Block Placement", + "net.clayborn.accurateblockplacement.togglevanillaplacement": "Alterna Modalità Posizionamento", + "net.clayborn.accurateblockplacement.modplacementmodemessage": "La modalità di posizionamento accurato dei blocchi è ora abilitata!", + "net.clayborn.accurateblockplacement.vanillaplacementmodemessage": "La modalità di posizionamento dei blocchi Vanilla è ora abilitata!", + "net.clayborn.accurateblockplacement.togglefastbreaking": "Toggle Breaking Mode", + "net.clayborn.accurateblockplacement.fastbreakingenabled": "Fast block breaking mode is now enabled!", + "net.clayborn.accurateblockplacement.fastbreakingdisabled": "Vanilla block breaking mode is now enabled!", + "text.autoconfig.accurateblockplacement.title": "Accurate Block Placement", + "text.autoconfig.accurateblockplacement.option.accuratePlacementEnabled": "Accurate block placement enabled", + "text.autoconfig.accurateblockplacement.option.fastBreakingEnabled": "Fast block breaking enabled", + "text.autoconfig.accurateblockplacement.option.confirmation": "Confirmation on Toggle", + "text.autoconfig.accurateblockplacement.option.confirmationType": "Confirmation Type", + "text.autoconfig.accurateblockplacement.option.confirmationType.CHAT": "Chat", + "text.autoconfig.accurateblockplacement.option.confirmationType.HUD": "HUD" +} diff --git a/src/main/resources/assets/accurateblockplacement/lang/pt_br.json b/src/main/resources/assets/accurateblockplacement/lang/pt_br.json new file mode 100644 index 0000000..3c8067e --- /dev/null +++ b/src/main/resources/assets/accurateblockplacement/lang/pt_br.json @@ -0,0 +1,16 @@ +{ + "key.category.accurateblockplacement.category": "Posicionamento Preciso de Blocos", + "net.clayborn.accurateblockplacement.togglevanillaplacement": "Alternar o Modo de Posicionamento", + "net.clayborn.accurateblockplacement.modplacementmodemessage": "§7Posicionamento Preciso de Blocos: §aAtivado", + "net.clayborn.accurateblockplacement.vanillaplacementmodemessage": "§7Posicionamento Preciso de Blocos: §cDesativado", + "net.clayborn.accurateblockplacement.togglefastbreaking": "Alternar Modo de Quebra", + "net.clayborn.accurateblockplacement.fastbreakingenabled": "§7Quebra Rápida de Blocos: §aAtivado", + "net.clayborn.accurateblockplacement.fastbreakingdisabled": "§7Quebra Rápida de Blocos: §cDesativado", + "text.autoconfig.accurateblockplacement.title": "Posicionamento Preciso dos Blocos", + "text.autoconfig.accurateblockplacement.option.accuratePlacementEnabled": "Posicionamento Preciso dos Blocos ativado", + "text.autoconfig.accurateblockplacement.option.fastBreakingEnabled": "Quebra Rápida de Blocos ativada", + "text.autoconfig.accurateblockplacement.option.confirmation": "Confirmação na Alternância", + "text.autoconfig.accurateblockplacement.option.confirmationType": "Tipo de Confirmação", + "text.autoconfig.accurateblockplacement.option.confirmationType.CHAT": "Chat", + "text.autoconfig.accurateblockplacement.option.confirmationType.HUD": "HUD" +} \ No newline at end of file diff --git a/src/main/resources/assets/accurateblockplacement/lang/ru_ru.json b/src/main/resources/assets/accurateblockplacement/lang/ru_ru.json index f8327b5..f6d8106 100644 --- a/src/main/resources/assets/accurateblockplacement/lang/ru_ru.json +++ b/src/main/resources/assets/accurateblockplacement/lang/ru_ru.json @@ -1,5 +1,16 @@ { - "net.clayborn.accurateblockplacement.togglevanillaplacement": "Переключить режим размещения", - "net.clayborn.accurateblockplacement.modplacementmodemessage": "Режим аккуратного размещения блоков включён.", - "net.clayborn.accurateblockplacement.vanillaplacementmodemessage": "Режим аккуратного размещения блоков выключен." + "key.category.accurateblockplacement.category": "Режим аккуратного размещения", + "net.clayborn.accurateblockplacement.togglevanillaplacement": "Переключение режима размещения блоков", + "net.clayborn.accurateblockplacement.modplacementmodemessage": "§7Режим аккуратного размещения блоков: §aВключено", + "net.clayborn.accurateblockplacement.vanillaplacementmodemessage": "§7Режим аккуратного размещения блоков: §cВыключен", + "net.clayborn.accurateblockplacement.togglefastbreaking": "Переключение режима ломания блоков", + "net.clayborn.accurateblockplacement.fastbreakingenabled": "§7Быстрое ломание блоков: §aВключено", + "net.clayborn.accurateblockplacement.fastbreakingdisabled": "§7Быстрое ломание блоков: §cВыключено", + "text.autoconfig.accurateblockplacement.title": "Accurate Block Placement", + "text.autoconfig.accurateblockplacement.option.accuratePlacementEnabled": "Режим аккуратного размещения блоков", + "text.autoconfig.accurateblockplacement.option.fastBreakingEnabled": "Быстрое ломание блоков", + "text.autoconfig.accurateblockplacement.option.confirmation": "Информировать о переключении режима", + "text.autoconfig.accurateblockplacement.option.confirmationType": "Вывод информации", + "text.autoconfig.accurateblockplacement.option.confirmationType.CHAT": "Чат", + "text.autoconfig.accurateblockplacement.option.confirmationType.HUD": "HUD" } diff --git a/src/main/resources/assets/accurateblockplacement/lang/tr_tr.json b/src/main/resources/assets/accurateblockplacement/lang/tr_tr.json new file mode 100644 index 0000000..b4a65f1 --- /dev/null +++ b/src/main/resources/assets/accurateblockplacement/lang/tr_tr.json @@ -0,0 +1,16 @@ +{ + "key.category.accurateblockplacement.category": "Accurate Block Placement", + "net.clayborn.accurateblockplacement.togglevanillaplacement": "Blok yerleştirme modunu değiştir", + "net.clayborn.accurateblockplacement.modplacementmodemessage": "Doğru blok yerleştirme modu etkin!", + "net.clayborn.accurateblockplacement.vanillaplacementmodemessage": "Vanilla blok yerleştirme modu etkin!", + "net.clayborn.accurateblockplacement.togglefastbreaking": "Toggle Breaking Mode", + "net.clayborn.accurateblockplacement.fastbreakingenabled": "Fast block breaking mode is now enabled!", + "net.clayborn.accurateblockplacement.fastbreakingdisabled": "Vanilla block breaking mode is now enabled!", + "text.autoconfig.accurateblockplacement.title": "Accurate Block Placement", + "text.autoconfig.accurateblockplacement.option.accuratePlacementEnabled": "Accurate block placement enabled", + "text.autoconfig.accurateblockplacement.option.fastBreakingEnabled": "Fast block breaking enabled", + "text.autoconfig.accurateblockplacement.option.confirmation": "Confirmation on Toggle", + "text.autoconfig.accurateblockplacement.option.confirmationType": "Confirmation Type", + "text.autoconfig.accurateblockplacement.option.confirmationType.CHAT": "Chat", + "text.autoconfig.accurateblockplacement.option.confirmationType.HUD": "HUD" +} \ No newline at end of file diff --git a/src/main/resources/assets/accurateblockplacement/lang/uk_ua.json b/src/main/resources/assets/accurateblockplacement/lang/uk_ua.json index 1aa491b..bd41fcf 100644 --- a/src/main/resources/assets/accurateblockplacement/lang/uk_ua.json +++ b/src/main/resources/assets/accurateblockplacement/lang/uk_ua.json @@ -1,5 +1,16 @@ { - "net.clayborn.accurateblockplacement.togglevanillaplacement": "Перемикання класичного розміщення", - "net.clayborn.accurateblockplacement.modplacementmodemessage": "Акуратне розміщення блоків увімкнено!", - "net.clayborn.accurateblockplacement.vanillaplacementmodemessage": "Класичне розміщення блоків увімкнено!" + "key.category.accurateblockplacement.category": "Accurate Block Placement", + "net.clayborn.accurateblockplacement.togglevanillaplacement": "Перемикання режиму розміщення", + "net.clayborn.accurateblockplacement.modplacementmodemessage": "Точне розміщення блоків увімкнено!", + "net.clayborn.accurateblockplacement.vanillaplacementmodemessage": "Класичне розміщення блоків увімкнено!", + "net.clayborn.accurateblockplacement.togglefastbreaking": "Toggle Breaking Mode", + "net.clayborn.accurateblockplacement.fastbreakingenabled": "Fast block breaking mode is now enabled!", + "net.clayborn.accurateblockplacement.fastbreakingdisabled": "Vanilla block breaking mode is now enabled!", + "text.autoconfig.accurateblockplacement.title": "Accurate Block Placement", + "text.autoconfig.accurateblockplacement.option.accuratePlacementEnabled": "Accurate block placement enabled", + "text.autoconfig.accurateblockplacement.option.fastBreakingEnabled": "Fast block breaking enabled", + "text.autoconfig.accurateblockplacement.option.confirmation": "Confirmation on Toggle", + "text.autoconfig.accurateblockplacement.option.confirmationType": "Confirmation Type", + "text.autoconfig.accurateblockplacement.option.confirmationType.CHAT": "Chat", + "text.autoconfig.accurateblockplacement.option.confirmationType.HUD": "HUD" } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 6643cb4..6eed78b 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -7,14 +7,21 @@ "description": "Build at super speed with your bare hands!", "authors": [ "Clayborn", - "Flourick" + "Flourick", + "KadTheHunter" ], "contributors": [ - "Andolamin" + "schwar", + "Andolamin", + "MrErenK", + "VladAndreiMorariu", + "LordEnder-Kitty", + "chtko", + "seriousfreezing" ], "contact": { - "homepage": "https://minecraft.curseforge.com/projects/accurate-block-placement", - "sources": "https://github.com/Flourick/AccurateBlockPlacement" + "homepage": "https://modrinth.com/mod/accurate-block-placement-reborn", + "sources": "https://github.com/hschwar/AccurateBlockPlacement-Reborn" }, "license": "MIT", @@ -24,6 +31,9 @@ "entrypoints": { "client": [ "net.clayborn.accurateblockplacement.AccurateBlockPlacementMod" + ], + "modmenu": [ + "net.clayborn.accurateblockplacement.config.ModMenuPlugin" ] }, "mixins": [ @@ -31,9 +41,13 @@ ], "depends": { - "minecraft": "~1.19.3", - "fabricloader": ">=0.14.11", - "fabric": "*", - "java": ">=17" + "minecraft": ">=1.21.9", + "fabricloader": ">=0.16.9", + "fabric-api": "*", + "java": ">=21" + }, + "suggests": { + "cloth-config": ">=16.0.141", + "modmenu": ">=12.0.0" } }