├── .github └── workflows │ └── build.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle.kts └── src └── main ├── java └── com │ └── jelly │ └── mightyminerv2 │ ├── MightyMiner.java │ ├── command │ └── RouteBuilderCommand.java │ ├── config │ └── MightyMinerConfig.java │ ├── event │ ├── BlockChangeEvent.java │ ├── BlockDestroyEvent.java │ ├── MotionUpdateEvent.java │ ├── PacketEvent.java │ ├── SpawnParticleEvent.java │ ├── UpdateEntityEvent.java │ ├── UpdateScoreboardEvent.java │ ├── UpdateScoreboardLineEvent.java │ ├── UpdateTablistEvent.java │ └── UpdateTablistFooterEvent.java │ ├── failsafe │ ├── AbstractFailsafe.java │ ├── FailsafeManager.java │ └── impl │ │ ├── BadEffectFailsafe.java │ │ ├── BedrockBlockChangeFailsafe.java │ │ ├── BedrockCheckFailsafe.java │ │ ├── DisconnectFailsafe.java │ │ ├── ItemChangeFailsafe.java │ │ ├── KnockbackFailsafe.java │ │ ├── NameMentionFailsafe.java │ │ ├── PlayerFailsafe.java │ │ ├── ProfileFailsafe.java │ │ ├── RotationFailsafe.java │ │ ├── SlotChangeFailsafe.java │ │ ├── TeleportFailsafe.java │ │ └── WorldChangeFailsafe.java │ ├── feature │ ├── AbstractFeature.java │ ├── FeatureManager.java │ └── impl │ │ ├── AutoChestUnlocker.java │ │ ├── AutoCommissionClaim.java │ │ ├── AutoDrillRefuel │ │ ├── AutoDrillRefuel.java │ │ └── states │ │ │ ├── AbiphoneState.java │ │ │ ├── AutoDrillRefuelState.java │ │ │ ├── GreatforgeState.java │ │ │ └── StartingState.java │ │ ├── AutoGetStats │ │ ├── AutoGetStats.java │ │ └── tasks │ │ │ ├── AbstractInventoryTask.java │ │ │ ├── TaskStatus.java │ │ │ └── impl │ │ │ ├── MiningBoostRetrievalTask.java │ │ │ ├── MiningSpeedRetrievalTask.java │ │ │ └── PickaxeAbilityRetrievalTask.java │ │ ├── AutoMobKiller │ │ ├── AutoMobKiller.java │ │ └── states │ │ │ ├── AutoMobKillerState.java │ │ │ ├── FindMobState.java │ │ │ ├── KillState.java │ │ │ ├── PathfindingState.java │ │ │ └── StartingState.java │ │ ├── AutoSell.java │ │ ├── AutoWarp.java │ │ ├── BlockMiner │ │ ├── BlockMiner.java │ │ └── states │ │ │ ├── ApplyAbilityState.java │ │ │ ├── BlockMinerState.java │ │ │ ├── BreakingState.java │ │ │ ├── ChoosingBlockState.java │ │ │ └── StartingState.java │ │ ├── LagDetector.java │ │ ├── MouseUngrab.java │ │ ├── PathExecutor.java │ │ ├── Pathfinder.java │ │ ├── RouteBuilder.java │ │ ├── RouteNavigator.java │ │ └── WorldScanner.java │ ├── handler │ ├── GameStateHandler.java │ ├── GraphHandler.java │ ├── RotationHandler.java │ └── RouteHandler.java │ ├── hud │ ├── CommissionHUD.java │ ├── DebugHUD.java │ └── GlacialCommissionHUD.java │ ├── macro │ ├── AbstractMacro.java │ ├── MacroManager.java │ └── impl │ │ ├── CommissionMacro │ │ ├── Commission.java │ │ ├── CommissionMacro.java │ │ └── states │ │ │ ├── ClaimingCommissionState.java │ │ │ ├── CommissionMacroState.java │ │ │ ├── GettingStatsState.java │ │ │ ├── MiningState.java │ │ │ ├── MobKillingState.java │ │ │ ├── NewLobbyState.java │ │ │ ├── PathingState.java │ │ │ ├── RefuelState.java │ │ │ ├── StartingState.java │ │ │ └── WarpingState.java │ │ ├── GlacialMacro │ │ ├── GlacialMacro.java │ │ ├── GlaciteVeins.java │ │ └── states │ │ │ ├── ClaimingCommissionState.java │ │ │ ├── ErrorHandlingState.java │ │ │ ├── GettingStatsState.java │ │ │ ├── GlacialMacroState.java │ │ │ ├── MiningState.java │ │ │ ├── NewLobbyState.java │ │ │ ├── PathfindingState.java │ │ │ ├── StartingState.java │ │ │ └── TeleportingState.java │ │ ├── MiningMacro │ │ └── MiningMacro.java │ │ └── RouteMiner │ │ ├── RouteMinerMacro.java │ │ └── states │ │ ├── GettingStatsState.java │ │ ├── MiningState.java │ │ ├── MovingState.java │ │ ├── RouteMinerMacroState.java │ │ └── StartingState.java │ ├── mixin │ ├── FML │ │ └── MixinFMLHandshakeMessage.java │ ├── client │ │ ├── EntityPlayerSPAccessor.java │ │ ├── MinecraftAccessor.java │ │ ├── MixinBlockStainedGlassPane.java │ │ ├── MixinChunk.java │ │ ├── MixinChunkProviderClient.java │ │ ├── MixinEntityLivingBase.java │ │ ├── MixinEntityPlayerSP.java │ │ ├── MixinMinecraft.java │ │ ├── MixinScoreboard.java │ │ └── MixinSoundManager.java │ ├── gui │ │ ├── MixinGuiContainer.java │ │ └── MixinInventoryPlayer.java │ ├── network │ │ ├── MixinNetHandlerPlayClient.java │ │ └── MixinNetworkManager.java │ └── render │ │ └── MixinModelBiped.java │ └── util │ ├── AngleUtil.java │ ├── BlockUtil.java │ ├── CommissionUtil.java │ ├── EntityUtil.java │ ├── IChunkProviderClient.java │ ├── InventoryUtil.java │ ├── KeyBindUtil.java │ ├── Logger.java │ ├── PlayerUtil.java │ ├── RaytracingUtil.java │ ├── ReflectionUtils.java │ ├── RenderUtil.java │ ├── ScoreboardUtil.java │ ├── StrafeUtil.java │ ├── TablistUtil.java │ └── helper │ ├── Angle.java │ ├── AudioManager.java │ ├── Clock.java │ ├── FifoQueue.java │ ├── MineableBlock.java │ ├── RotationConfiguration.java │ ├── Target.java │ ├── graph │ ├── Graph.java │ └── GraphSerializer.java │ ├── heap │ ├── HeapNode.java │ └── MinHeap.java │ ├── location │ ├── Location.java │ └── SubLocation.java │ └── route │ ├── Route.java │ ├── RouteWaypoint.java │ ├── TransportMethod.java │ └── WaypointType.java ├── kotlin └── com │ └── jelly │ └── mightyminerv2 │ └── pathfinder │ ├── calculate │ ├── Path.kt │ ├── PathNode.kt │ ├── openset │ │ └── BinaryHeapOpenSet.kt │ └── path │ │ └── AStarPathFinder.kt │ ├── costs │ └── ActionCost.kt │ ├── goal │ ├── Goal.kt │ └── IGoal.kt │ ├── helper │ ├── BlockStateAccessor.kt │ ├── BlockStateInterfaceAccessWrapper.kt │ └── player │ │ ├── IPlayerContext.kt │ │ └── PlayerContext.kt │ ├── movement │ ├── CalculationContext.kt │ ├── IMovement.kt │ ├── Movement.kt │ ├── MovementHelper.kt │ ├── MovementResult.kt │ ├── Moves.kt │ └── movements │ │ ├── MovementAscend.kt │ │ ├── MovementDescend.kt │ │ ├── MovementDiagonal.kt │ │ ├── MovementFall.kt │ │ └── MovementTraverse.kt │ └── util │ ├── BlockUtil.kt │ ├── Extension.kt │ └── Ref.kt └── resources ├── mcmod.info ├── mightyminer ├── Commission Macro.json ├── Glacial Macro.json └── sounds │ ├── AAAAAAAAAA.wav │ ├── loud_buzz.wav │ ├── metal_pipe.wav │ └── staff_check_voice_notification.wav └── mixins.mightyminerv2.json /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Run Gradle Build 2 | on: [push] 3 | jobs: 4 | gradle: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: Checkout source 8 | uses: actions/checkout@v4 9 | - name: Get Gradle version and check if it's pre release 10 | run: | 11 | VERSION=$(grep -Po '^version=.*' gradle.properties | cut -d= -f2) 12 | VERSION=${VERSION#[[:space:]]} 13 | SHOULD_RELEASE=$(grep -Po '^shouldRelease=.*' gradle.properties | cut -d= -f2) 14 | SHOULD_RELEASE=${SHOULD_RELEASE#[[:space:]]} 15 | echo "$VERSION" 16 | echo "VERSION=$VERSION" >> $GITHUB_OUTPUT 17 | if [[ $VERSION == *-pre* ]] 18 | then 19 | echo "Version is pre-release" 20 | RELEASE_TYPE="pre-release" 21 | else 22 | echo "Version is full release" 23 | RELEASE_TYPE="full" 24 | fi 25 | echo "Version is $VERSION and release type is $RELEASE_TYPE" 26 | echo "RELEASE_TYPE=$RELEASE_TYPE" >> $GITHUB_OUTPUT 27 | echo "shouldRelease=$SHOULD_RELEASE" >> $GITHUB_OUTPUT 28 | id: get_version 29 | - name: Get short commit sha 30 | id: short_sha 31 | run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT 32 | - uses: actions/setup-java@v4 33 | name: Setup Java 34 | with: 35 | distribution: temurin 36 | java-version: 17 37 | - uses: gradle/actions/setup-gradle@v3 38 | name: Setup Gradle 39 | - name: Execute Gradle build 40 | run: ./gradlew build 41 | - uses: actions/upload-artifact@v4 42 | name: Upload built mod JAR 43 | with: 44 | name: mod-jar 45 | path: build/libs/*.jar 46 | - name: Create release with files 47 | uses: softprops/action-gh-release@v2 48 | id: create_release 49 | if: steps.get_version.outputs.shouldRelease == 'true' 50 | with: 51 | draft: false 52 | prerelease: ${{ steps.get_version.outputs.RELEASE_TYPE == 'pre-release' }} 53 | name: MightyMinerV2 ${{ steps.get_version.outputs.VERSION }} 54 | tag_name: ${{ steps.get_version.outputs.VERSION }}.${{ steps.short_sha.outputs.sha_short }} 55 | files: | 56 | build/libs/*.jar 57 | body: | 58 | Changelog: 59 | ${{ github.event.head_commit.message }} 60 | env: 61 | GITHUB_TOKEN: ${{ github.token }} 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | run/ 4 | build/ 5 | .gradle/ 6 | 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # MightyMiner V2 Changelog 2 | 3 | ## v2.7.1 (2025-1-7) 4 | 5 | ## Changes 6 | - New name-mention failsafe 7 | - New option to auto warp to forge in Commission Macro 8 | - Will no longer start Dwarven Commissions if the slayer weapon has not been set in the config 9 | - Will warp to a new mining lobby if the pathfinding fails 10 | - Changed the error message getMiningStats throws 11 | 12 | ## Fixes 13 | - Duplicate mining tools causing ItemChangeFailsafe to trigger 14 | - Pickaxe ability issue 15 | - Issues with macro not mining after tabbing out 16 | 17 | ## v2.7.0 (2025-18-6) 18 | 19 | This update marks the first stable update of MightyMiner v2.7.0 20 | 21 | ## Current Macros Included 22 | - Commission Macro 23 | - Powder Macro 24 | 25 | ## Changes 26 | - Auto Refuel is now usable 27 | - Fixed lag issues 28 | - Fixed personal compactors not working 29 | - Fixed accidentally clicking on players 30 | - Fixed calling royal pigeons twice 31 | - Detecting item names properly 32 | - Added support for all pickaxe abilities 33 | - Added options to disable using pickaxe ability 34 | - New commission HUD and configs 35 | - Enhanced mining algorithm 36 | 37 | ## v2.7.0-alpha (2025-5-1) 38 | 39 | This update marks the official resumption of development on Mighty Miner. 40 | 41 | ## Current Macros Included 42 | - Commission Macro 43 | - Powder Macro 44 | - Glacial Macro 45 | - Mining Macro 46 | - Route Mining Macro 47 | 48 | ## Changes 49 | - Completely rewritten Mining Macro for improved efficiency and maintainability. 50 | - Block Miner has been overhauled with cleaner structure and better logic separation. 51 | - Automatically disable macro when there is an error 52 | 53 | ## Updated Coding Standards 54 | - Avoid deeply nested switch statements when possible. Implement PROPER state machine patterns (see BlockMiner.java for a reference implementation). 55 | - Add Javadocs and inline comments, especially for abstract classes. (Tip: ChatGPT can assist with generating documentation.) 56 | - Standardize logging and error handling across the project. For example, all errors should be routed through the main macro class for consistency. 57 | - Disable macro automatically when there is an error 58 | 59 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JellyLabScripts/MightyMiner/62aec611784d81973a9ce9fcba02d659b776d0b8/LICENSE -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MightyMinerV2 2 | 3 | MightyMinerV2 is a cutting-edge mining macro designed specifically for Hypixel Skyblock. This powerful tool enhances your gameplay experience by automating various mining-related tasks, allowing you to focus on progressing through the game. With a host of advanced features and many more under development, MightyMinerV2 is your ultimate companion for efficient mining. 4 | 5 | ## Features 6 | 7 | ### Current Features: 8 | - **Commission Macro**: Automatically completes mining commissions, helping you earn rewards faster and with minimal effort. 9 | - **Mining Macro**: Optimized for efficient mithril / pure ore mining, ensuring you collect the maximum amount of resources. 10 | - **Glacial Macro**: Experimental! 11 | - **Route Mining Macro**: Experimental! 12 | - **Powder Macro**: Re-release soon! 13 | 14 | ### Upcoming Features: 15 | Our dedicated development team is actively working on integrating more features, including but not limited to: 16 | - Advanced gemstone mining automation. 17 | - Customized pathing for specific resource collection. 18 | - Enhanced anti-detection mechanisms to ensure safe usage. 19 | - And much more! Stay tuned for updates. 20 | 21 | ## Developers 22 | MightyMinerV2 is brought to you by a talented team of developers: 23 | - **Tama** 24 | - **Osama** 25 | - **Nima0908** 26 | - **Mr. Shadow** 27 | - **Nathan**

28 | - **JellyLab** (returned!!!) 29 | 30 | Their combined expertise and passion for Hypixel Skyblock drive the continuous improvement and innovation of MightyMinerV2. 31 | 32 | ## Installation 33 | 1. Download the latest release from the repository. 34 | 2. Follow the setup instructions provided in the `INSTALL.md` file (WIP). 35 | 3. Enjoy effortless mining with MightyMinerV2! 36 | 37 | ## Support 38 | For support, bug reports, or feature requests, feel free to open an issue in the repository or join our [community Discord channel](https://discord.gg/6mSHC2Xd9y). 39 | 40 | 41 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | loom.platform=forge 2 | org.gradle.jvmargs=-Xmx3g 3 | baseGroup=com.jelly.mightyminerv2 4 | modName=MightyMinerV2 5 | modid=mightyminerv2 6 | mcVersion=1.8.9 7 | version=2.7.3-pre1 8 | shouldRelease=true 9 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JellyLabScripts/MightyMiner/62aec611784d81973a9ce9fcba02d659b776d0b8/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | mavenCentral() 4 | gradlePluginPortal() 5 | maven("https://maven.fabricmc.net") 6 | maven("https://maven.architectury.dev") 7 | maven("https://maven.minecraftforge.net") 8 | maven("https://repo.polyfrost.cc/releases") 9 | } 10 | } 11 | 12 | rootProject.name = "MightyMinerV2" -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/event/BlockChangeEvent.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.event; 2 | 3 | import net.minecraft.block.state.IBlockState; 4 | import net.minecraft.util.BlockPos; 5 | import net.minecraftforge.fml.common.eventhandler.Event; 6 | 7 | public class BlockChangeEvent extends Event { 8 | public BlockPos pos; 9 | public IBlockState old; 10 | public IBlockState update; 11 | 12 | public BlockChangeEvent(BlockPos pos, IBlockState old, IBlockState update) { 13 | this.pos = pos; 14 | this.old = old; 15 | this.update = update; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/event/BlockDestroyEvent.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.event; 2 | 3 | import lombok.Getter; 4 | import net.minecraft.util.BlockPos; 5 | import net.minecraftforge.fml.common.eventhandler.Event; 6 | 7 | @Getter 8 | public class BlockDestroyEvent extends Event { 9 | 10 | private final BlockPos block; 11 | private final float progress; 12 | 13 | public BlockDestroyEvent(final BlockPos block, final float progress) { 14 | this.block = block; 15 | this.progress = progress; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/event/MotionUpdateEvent.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.event; 2 | 3 | import net.minecraftforge.fml.common.eventhandler.Event; 4 | 5 | public class MotionUpdateEvent extends Event { 6 | public float yaw; 7 | public float pitch; 8 | 9 | public MotionUpdateEvent(float yaw, float pitch) { 10 | this.yaw = yaw; 11 | this.pitch = pitch; 12 | } 13 | 14 | // public static class Pre extends MotionUpdateEvent { 15 | // public Pre(final float yaw, final float pitch) { 16 | // super(yaw, pitch); 17 | // } 18 | // } 19 | 20 | // public static class Post extends MotionUpdateEvent { 21 | // public Post(final float yaw, final float pitch) { 22 | // super(yaw, pitch); 23 | // } 24 | // } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/event/PacketEvent.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.event; 2 | 3 | import net.minecraft.network.Packet; 4 | import net.minecraftforge.fml.common.eventhandler.Cancelable; 5 | import net.minecraftforge.fml.common.eventhandler.Event; 6 | 7 | @Cancelable 8 | public class PacketEvent extends Event { 9 | public final Packet packet; 10 | 11 | public PacketEvent(Packet packet) { 12 | this.packet = packet; 13 | } 14 | 15 | @Cancelable 16 | public static class Sent extends PacketEvent { 17 | public Sent(Packet packet) { 18 | super(packet); 19 | } 20 | } 21 | 22 | @Cancelable 23 | public static class Received extends PacketEvent { 24 | public Received(Packet packet) { 25 | super(packet); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/event/SpawnParticleEvent.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.event; 2 | 3 | import lombok.Getter; 4 | import net.minecraft.util.EnumParticleTypes; 5 | import net.minecraft.util.Vec3; 6 | import net.minecraftforge.fml.common.eventhandler.Cancelable; 7 | import net.minecraftforge.fml.common.eventhandler.Event; 8 | 9 | @Cancelable 10 | @Getter 11 | public class SpawnParticleEvent extends Event { 12 | 13 | EnumParticleTypes particleTypes; 14 | boolean isLongDistance; 15 | double xCoord; 16 | double yCoord; 17 | double zCoord; 18 | double xOffset; 19 | double yOffset; 20 | double zOffset; 21 | int[] params; 22 | 23 | public SpawnParticleEvent( 24 | EnumParticleTypes particleTypes, 25 | boolean isLongDistance, 26 | double xCoord, double yCoord, double zCoord, 27 | double xOffset, double yOffset, double zOffset, 28 | int[] params 29 | ) { 30 | this.particleTypes = particleTypes; 31 | this.isLongDistance = isLongDistance; 32 | this.xCoord = xCoord; 33 | this.yCoord = yCoord; 34 | this.zCoord = zCoord; 35 | this.xOffset = xOffset; 36 | this.yOffset = yOffset; 37 | this.zOffset = zOffset; 38 | this.params = params; 39 | } 40 | 41 | public Vec3 getPos() { 42 | return new Vec3(xCoord, yCoord, zCoord); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/event/UpdateEntityEvent.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.event; 2 | 3 | import net.minecraft.entity.EntityLivingBase; 4 | import net.minecraftforge.fml.common.eventhandler.Event; 5 | 6 | public class UpdateEntityEvent extends Event { 7 | 8 | public final EntityLivingBase entity; 9 | public final byte updateType; // 0 = entity spawned, 1 = entity despawned, 2 = entity moved 10 | public long newHash; // maybe instead of saving new hash i should just save the coord - but i dont have a use for the coord so L 11 | 12 | public UpdateEntityEvent(EntityLivingBase entity) { 13 | this.entity = entity; 14 | this.updateType = 0; 15 | } 16 | 17 | public UpdateEntityEvent(EntityLivingBase entity, byte updateType) { 18 | this.entity = entity; 19 | this.updateType = updateType; 20 | } 21 | 22 | public UpdateEntityEvent(EntityLivingBase entity, long newHash) { 23 | this.entity = entity; 24 | this.updateType = 2; 25 | this.newHash = newHash; 26 | } 27 | // public Vec3 newPos; 28 | // public UpdateEntityEvent(EntityLivingBase entity, long newHash, Vec3 newPos) { 29 | // this.entity = entity; 30 | // this.updateType = 2; 31 | // this.newHash = newHash; 32 | // this.newPos = newPos; 33 | // } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/event/UpdateScoreboardEvent.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.event; 2 | 3 | import net.minecraftforge.fml.common.eventhandler.Event; 4 | 5 | import java.util.List; 6 | 7 | public class UpdateScoreboardEvent extends Event { 8 | public final List scoreboard; 9 | public final long timestamp; 10 | 11 | public UpdateScoreboardEvent(List scoreboard, long timestamp) { 12 | this.scoreboard = scoreboard; 13 | this.timestamp = timestamp; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/event/UpdateScoreboardLineEvent.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.event; 2 | 3 | import lombok.Getter; 4 | import net.minecraftforge.fml.common.eventhandler.Event; 5 | 6 | @Getter 7 | public class UpdateScoreboardLineEvent extends Event { 8 | 9 | private final String line; 10 | 11 | public UpdateScoreboardLineEvent(String line) { 12 | this.line = line; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/event/UpdateTablistEvent.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.event; 2 | 3 | import net.minecraftforge.fml.common.eventhandler.Event; 4 | 5 | import java.util.List; 6 | 7 | public class UpdateTablistEvent extends Event { 8 | public final List tablist; 9 | public final long timestamp; 10 | 11 | public UpdateTablistEvent(List tablist, long timestamp) { 12 | this.tablist = tablist; 13 | this.timestamp = timestamp; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/event/UpdateTablistFooterEvent.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.event; 2 | 3 | import net.minecraftforge.fml.common.eventhandler.Event; 4 | 5 | import java.util.List; 6 | 7 | public class UpdateTablistFooterEvent extends Event { 8 | public final List footer; 9 | 10 | public UpdateTablistFooterEvent(List footer) { 11 | this.footer = footer; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/failsafe/AbstractFailsafe.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.failsafe; 2 | 3 | import com.jelly.mightyminerv2.event.BlockChangeEvent; 4 | import com.jelly.mightyminerv2.event.PacketEvent; 5 | import com.jelly.mightyminerv2.util.Logger; 6 | import net.minecraft.client.Minecraft; 7 | import net.minecraftforge.client.event.ClientChatReceivedEvent; 8 | import net.minecraftforge.client.event.GuiOpenEvent; 9 | import net.minecraftforge.event.world.WorldEvent; 10 | import net.minecraftforge.fml.common.gameevent.TickEvent; 11 | import net.minecraftforge.fml.common.network.FMLNetworkEvent; 12 | 13 | public abstract class AbstractFailsafe { 14 | 15 | protected final Minecraft mc = Minecraft.getMinecraft(); 16 | 17 | public abstract int getPriority(); 18 | 19 | public abstract String getName(); 20 | 21 | public abstract Failsafe getFailsafeType(); 22 | 23 | public boolean onBlockChange(BlockChangeEvent event) { 24 | return false; 25 | } 26 | 27 | public boolean onPacketReceive(PacketEvent.Received event) { 28 | return false; 29 | } 30 | 31 | public boolean onTick(TickEvent.ClientTickEvent event) { 32 | return false; 33 | } 34 | 35 | public boolean onChat(ClientChatReceivedEvent event) { 36 | return false; 37 | } 38 | 39 | public boolean onGuiOpen(GuiOpenEvent event) { return false; } 40 | 41 | public boolean onWorldUnload(WorldEvent.Unload event) { 42 | return false; 43 | } 44 | 45 | public boolean onDisconnect(FMLNetworkEvent.ClientDisconnectionFromServerEvent event) { 46 | return false; 47 | } 48 | 49 | public abstract boolean react(); 50 | 51 | public void resetStates() {} 52 | 53 | protected void log(String message) { 54 | Logger.sendLog(formatMessage(message)); 55 | } 56 | 57 | protected void send(String message) { 58 | Logger.sendMessage(formatMessage(message)); 59 | } 60 | 61 | protected void error(String message) { 62 | Logger.sendError(formatMessage(message)); 63 | } 64 | 65 | protected void warn(String message) { 66 | Logger.sendWarning(formatMessage(message)); 67 | } 68 | 69 | protected void note(String message) { 70 | Logger.sendNote(formatMessage(message)); 71 | } 72 | 73 | protected String formatMessage(String message) { 74 | return "[" + getName() + "] " + message; 75 | } 76 | 77 | public enum Failsafe { 78 | BAD_EFFECTS, 79 | BLOCK_CHANGE, 80 | DISCONNECT, 81 | ITEM_CHANGE, 82 | KNOCKBACK, 83 | ROTATION, 84 | TELEPORT, 85 | BEDROCK_CHECK, 86 | SLOT_CHANGE, 87 | PLAYER_PROFILE_OPEN, 88 | NAME_MENTION 89 | } 90 | } -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/failsafe/impl/BadEffectFailsafe.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.failsafe.impl; 2 | 3 | import com.google.common.collect.ImmutableSet; 4 | import com.jelly.mightyminerv2.event.PacketEvent; 5 | import com.jelly.mightyminerv2.failsafe.AbstractFailsafe; 6 | import com.jelly.mightyminerv2.macro.MacroManager; 7 | import lombok.Getter; 8 | import net.minecraft.client.entity.EntityPlayerSP; 9 | import net.minecraft.network.play.server.S1DPacketEntityEffect; 10 | import net.minecraft.potion.Potion; 11 | import net.minecraft.potion.PotionEffect; 12 | import net.minecraftforge.fml.common.gameevent.TickEvent; 13 | 14 | import java.util.Set; 15 | 16 | public class BadEffectFailsafe extends AbstractFailsafe { 17 | 18 | @Getter 19 | private static final BadEffectFailsafe instance = new BadEffectFailsafe(); 20 | private final Set BAD_EFFECTS = ImmutableSet.of( 21 | Potion.poison.id, 22 | Potion.wither.id, 23 | Potion.weakness.id, 24 | Potion.blindness.id, 25 | Potion.hunger.id, 26 | Potion.moveSlowdown.id, 27 | Potion.digSlowdown.id 28 | ); 29 | 30 | @Override 31 | public String getName() { 32 | return "BadEffectFailsafe"; 33 | } 34 | 35 | @Override 36 | public Failsafe getFailsafeType() { 37 | return Failsafe.BAD_EFFECTS; 38 | } 39 | 40 | @Override 41 | public int getPriority() { 42 | return 7; 43 | } 44 | 45 | @Override 46 | public boolean onTick(TickEvent.ClientTickEvent event) { 47 | for (PotionEffect effect : mc.thePlayer.getActivePotionEffects()) { 48 | if (BAD_EFFECTS.contains(effect.getPotionID())) return true; 49 | } 50 | 51 | return false; 52 | } 53 | 54 | @Override 55 | public boolean react() { 56 | MacroManager.getInstance().disable(); 57 | warn("Bad effect detected! Disabling macro."); 58 | return true; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/failsafe/impl/BedrockCheckFailsafe.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.failsafe.impl; 2 | 3 | import com.jelly.mightyminerv2.failsafe.AbstractFailsafe; 4 | import com.jelly.mightyminerv2.macro.MacroManager; 5 | import lombok.Getter; 6 | import net.minecraft.block.Block; 7 | import net.minecraft.init.Blocks; 8 | import net.minecraft.util.BlockPos; 9 | import net.minecraft.util.Vec3; 10 | 11 | public class BedrockCheckFailsafe extends AbstractFailsafe { 12 | 13 | @Getter 14 | private static final BedrockCheckFailsafe instance = new BedrockCheckFailsafe(); 15 | private static final int CHECK_RADIUS = 5; 16 | private static final int BEDROCK_THRESHOLD = 10; 17 | 18 | @Override 19 | public String getName() { 20 | return "BedrockCheckFailsafe"; 21 | } 22 | 23 | @Override 24 | public Failsafe getFailsafeType() { 25 | return Failsafe.BEDROCK_CHECK; 26 | } 27 | 28 | @Override 29 | public int getPriority() { 30 | return 6; 31 | } 32 | 33 | 34 | public boolean checkForBedrock(Vec3 playerPos) { 35 | int bedrockCount = 0; 36 | 37 | for (int x = -CHECK_RADIUS; x <= CHECK_RADIUS; x++) { 38 | for (int y = -CHECK_RADIUS; y <= CHECK_RADIUS; y++) { 39 | for (int z = -CHECK_RADIUS; z <= CHECK_RADIUS; z++) { 40 | BlockPos blockPos = new BlockPos( 41 | playerPos.xCoord + x, 42 | playerPos.yCoord + y, 43 | playerPos.zCoord + z 44 | ); 45 | Block block = mc.theWorld.getBlockState(blockPos).getBlock(); 46 | 47 | if (block == Blocks.bedrock) { 48 | bedrockCount++; 49 | } 50 | 51 | if (bedrockCount >= BEDROCK_THRESHOLD) { 52 | return true; 53 | } 54 | } 55 | } 56 | } 57 | 58 | return false; 59 | } 60 | 61 | @Override 62 | public boolean react() { 63 | MacroManager.getInstance().disable(); 64 | warn("Disabling macro due to bedrock surroundings."); 65 | return true; 66 | } 67 | 68 | } 69 | 70 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/failsafe/impl/DisconnectFailsafe.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.failsafe.impl; 2 | 3 | import com.jelly.mightyminerv2.event.PacketEvent; 4 | import com.jelly.mightyminerv2.failsafe.AbstractFailsafe; 5 | import com.jelly.mightyminerv2.macro.MacroManager; 6 | import lombok.Getter; 7 | import net.minecraft.client.gui.GuiDisconnected; 8 | import net.minecraft.network.play.server.S40PacketDisconnect; 9 | 10 | public class DisconnectFailsafe extends AbstractFailsafe { 11 | 12 | @Getter 13 | private static final DisconnectFailsafe instance = new DisconnectFailsafe(); 14 | 15 | @Override 16 | public String getName() { 17 | return "DisconnectFailsafe"; 18 | } 19 | 20 | @Override 21 | public Failsafe getFailsafeType() { 22 | return Failsafe.DISCONNECT; 23 | } 24 | 25 | @Override 26 | public int getPriority() { 27 | return 10; 28 | } 29 | 30 | @Override 31 | public boolean onPacketReceive(PacketEvent.Received event) { 32 | return event.packet instanceof S40PacketDisconnect || mc.currentScreen instanceof GuiDisconnected; 33 | } 34 | 35 | @Override 36 | public boolean react() { 37 | warn("Disconnected. Disabling Macro"); 38 | MacroManager.getInstance().disable(); 39 | return true; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/failsafe/impl/KnockbackFailsafe.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.failsafe.impl; 2 | 3 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 4 | import com.jelly.mightyminerv2.event.PacketEvent; 5 | import com.jelly.mightyminerv2.failsafe.AbstractFailsafe; 6 | import com.jelly.mightyminerv2.macro.MacroManager; 7 | import com.jelly.mightyminerv2.util.Logger; 8 | import lombok.Getter; 9 | import net.minecraft.network.play.server.S12PacketEntityVelocity; 10 | 11 | public class KnockbackFailsafe extends AbstractFailsafe { 12 | 13 | @Getter 14 | private static final KnockbackFailsafe instance = new KnockbackFailsafe(); 15 | 16 | public int getPriority() { 17 | return 8; 18 | } 19 | 20 | @Override 21 | public String getName() { 22 | return ""; 23 | } 24 | 25 | @Override 26 | public Failsafe getFailsafeType() { 27 | return Failsafe.KNOCKBACK; 28 | } 29 | 30 | 31 | @Override 32 | public boolean onPacketReceive(PacketEvent.Received event) { 33 | if (!(event.packet instanceof S12PacketEntityVelocity)) return false; 34 | if (((S12PacketEntityVelocity) event.packet).getEntityID() != mc.thePlayer.getEntityId()) return false; 35 | return ((S12PacketEntityVelocity) event.packet).getMotionY() >= MightyMinerConfig.verticalKnockbackThreshold; 36 | } 37 | 38 | @Override 39 | public boolean react() { 40 | MacroManager.getInstance().disable(); 41 | Logger.sendWarning("Knockback has been detected! Disabling macro."); 42 | return true; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/failsafe/impl/NameMentionFailsafe.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.failsafe.impl; 2 | 3 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 4 | import com.jelly.mightyminerv2.failsafe.AbstractFailsafe; 5 | import com.jelly.mightyminerv2.macro.MacroManager; 6 | import lombok.Getter; 7 | import net.minecraftforge.client.event.ClientChatReceivedEvent; 8 | 9 | import java.util.regex.Matcher; 10 | import java.util.regex.Pattern; 11 | 12 | public class NameMentionFailsafe extends AbstractFailsafe { 13 | 14 | @Getter 15 | private static final NameMentionFailsafe instance = new NameMentionFailsafe(); 16 | 17 | private static final Pattern SENDER_NAME_PATTERN = Pattern.compile("^.*?(?[a-zA-Z0-9_]+)§?f?:"); 18 | 19 | @Getter 20 | private boolean lobbyChangeRequested = false; 21 | 22 | @Override 23 | public int getPriority() { return 10; } 24 | 25 | @Override 26 | public String getName() { return "NameMentionFailsafe"; } 27 | 28 | @Override 29 | public Failsafe getFailsafeType() { return Failsafe.NAME_MENTION; } 30 | 31 | @Override 32 | public void resetStates() { 33 | this.lobbyChangeRequested = false; 34 | } 35 | 36 | @Override 37 | public boolean onChat(ClientChatReceivedEvent event) { 38 | String playerName = mc.thePlayer.getName(); 39 | String unformattedMessage = event.message.getUnformattedText(); 40 | 41 | String senderName = null; 42 | Matcher matcher = SENDER_NAME_PATTERN.matcher(unformattedMessage); 43 | if (matcher.find()) { senderName = matcher.group("senderName"); } 44 | 45 | if (senderName != null && senderName.equalsIgnoreCase(playerName)) { return false; } 46 | 47 | if (unformattedMessage.toLowerCase().contains(playerName.toLowerCase() + " invited ")) { return false; } 48 | 49 | //if (unformattedMessage.toLowerCase().contains("has invited you to join their party!")) { notify() } 50 | 51 | Pattern mentionPattern = Pattern.compile("\\b" + Pattern.quote(playerName) + "\\b", Pattern.CASE_INSENSITIVE); 52 | boolean isMentioned = mentionPattern.matcher(unformattedMessage).find(); 53 | 54 | if (isMentioned) { 55 | if (MightyMinerConfig.nameMentionFailsafeBehaviour) { // If true, the player wants to warp to a new lobby 56 | warn("Your name was mentioned in chat. Changing lobbies."); 57 | lobbyChangeRequested = true; 58 | return false; 59 | } else { // If false, the player wants to disable the macro 60 | return true; 61 | } 62 | } 63 | return false; 64 | } 65 | 66 | @Override 67 | public boolean react() { 68 | MacroManager.getInstance().disable(); 69 | warn("Your name was mentioned in chat. Macro disabled."); 70 | return true; 71 | } 72 | } -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/failsafe/impl/ProfileFailsafe.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.failsafe.impl; 2 | 3 | import com.jelly.mightyminerv2.failsafe.AbstractFailsafe; 4 | import com.jelly.mightyminerv2.macro.MacroManager; 5 | import com.jelly.mightyminerv2.util.Logger; 6 | import lombok.Getter; 7 | import net.minecraft.client.gui.inventory.GuiChest; 8 | import net.minecraft.inventory.ContainerChest; 9 | import net.minecraft.inventory.IInventory; 10 | import net.minecraft.util.StringUtils; 11 | import net.minecraftforge.client.event.GuiOpenEvent; 12 | 13 | public class ProfileFailsafe extends AbstractFailsafe { 14 | 15 | @Getter 16 | private static final ProfileFailsafe instance = new ProfileFailsafe(); 17 | 18 | private static final String TRIGGER_PHRASE = "Profile"; 19 | 20 | @Override 21 | public String getName() { 22 | return "ProfileFailsafe"; 23 | } 24 | 25 | @Override 26 | public Failsafe getFailsafeType() { 27 | return Failsafe.PLAYER_PROFILE_OPEN; 28 | } 29 | 30 | @Override 31 | public int getPriority() { return 2; } 32 | 33 | @Override 34 | public boolean onGuiOpen(GuiOpenEvent event) { 35 | if (event.gui == null) { 36 | return false; 37 | } 38 | 39 | if (event.gui instanceof GuiChest) { 40 | GuiChest guiChest = (GuiChest) event.gui; 41 | 42 | if (guiChest.inventorySlots instanceof ContainerChest) { 43 | ContainerChest container = (ContainerChest) guiChest.inventorySlots; 44 | IInventory chestInventory = container.getLowerChestInventory(); 45 | 46 | if (chestInventory != null && chestInventory.hasCustomName()) { 47 | String inventoryName = StringUtils.stripControlCodes(chestInventory.getDisplayName().getUnformattedText()); 48 | if (inventoryName.toLowerCase().contains(TRIGGER_PHRASE.toLowerCase())) { 49 | note("Detected inventory open with name containing " + inventoryName); 50 | return true; 51 | } 52 | } 53 | } 54 | } 55 | return false; 56 | } 57 | 58 | @Override 59 | public boolean react() { 60 | if (mc.currentScreen != null && mc.thePlayer != null) { 61 | mc.addScheduledTask(() -> { 62 | if (mc.currentScreen != null && mc.thePlayer != null) { 63 | mc.thePlayer.closeScreen(); 64 | note("Closing the menu... continuing"); 65 | } 66 | }); 67 | } else { 68 | warn("Menu already closed... continuing"); 69 | } 70 | return true; 71 | } 72 | } -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/failsafe/impl/RotationFailsafe.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.failsafe.impl; 2 | 3 | import com.jelly.mightyminerv2.event.PacketEvent; 4 | import com.jelly.mightyminerv2.failsafe.AbstractFailsafe; 5 | import com.jelly.mightyminerv2.macro.MacroManager; 6 | import com.jelly.mightyminerv2.util.Logger; 7 | import com.jelly.mightyminerv2.util.helper.Angle; 8 | import com.jelly.mightyminerv2.util.helper.Clock; 9 | import lombok.Getter; 10 | import net.minecraft.network.play.server.S08PacketPlayerPosLook; 11 | import net.minecraftforge.fml.common.gameevent.TickEvent; 12 | 13 | public class RotationFailsafe extends AbstractFailsafe { 14 | 15 | @Getter 16 | private static final RotationFailsafe instance = new RotationFailsafe(); 17 | 18 | public int getPriority() { 19 | return 5; 20 | } 21 | 22 | @Override 23 | public String getName() { 24 | return ""; 25 | } 26 | 27 | @Override 28 | public Failsafe getFailsafeType() { 29 | return Failsafe.ROTATION; 30 | } 31 | 32 | 33 | private final Clock triggerCheck = new Clock(); 34 | private Angle rotationBeforeReacting = null; 35 | 36 | @Override 37 | public boolean onPacketReceive(PacketEvent.Received event) { 38 | if (!MacroManager.getInstance().isEnabled()) return false; 39 | 40 | if (event.packet instanceof S08PacketPlayerPosLook) { 41 | S08PacketPlayerPosLook packet = (S08PacketPlayerPosLook) event.packet; 42 | double packetYaw = packet.getYaw(); 43 | double packetPitch = packet.getPitch(); 44 | double playerYaw = mc.thePlayer.rotationYaw; 45 | double playerPitch = mc.thePlayer.rotationPitch; 46 | 47 | float yawDifference = Math.abs((mc.thePlayer.rotationYaw - ((S08PacketPlayerPosLook) event.packet).getYaw())); 48 | float pitchDifference = Math.abs((mc.thePlayer.rotationPitch - ((S08PacketPlayerPosLook) event.packet).getPitch())); 49 | 50 | if (yawDifference == 360F && pitchDifference == 0F) return false; 51 | 52 | if (shouldTriggerCheck(packetYaw, packetPitch)) { 53 | if (rotationBeforeReacting == null) rotationBeforeReacting = new Angle((float) playerYaw, (float) playerPitch); 54 | } 55 | 56 | triggerCheck.schedule(500); 57 | } 58 | 59 | return false; 60 | } 61 | 62 | @Override 63 | public boolean onTick(TickEvent.ClientTickEvent event) { 64 | if (!MacroManager.getInstance().isEnabled()) { 65 | rotationBeforeReacting = null; 66 | return false; 67 | } 68 | 69 | if (triggerCheck.passed() && triggerCheck.isScheduled()) { 70 | if (rotationBeforeReacting == null) return false; 71 | 72 | if (shouldTriggerCheck(rotationBeforeReacting.getYaw(), rotationBeforeReacting.getPitch())) { 73 | return true; 74 | } 75 | 76 | rotationBeforeReacting = null; 77 | triggerCheck.reset(); 78 | } 79 | 80 | return false; 81 | } 82 | 83 | private boolean shouldTriggerCheck(double newYaw, double newPitch) { 84 | double yawDiff = Math.abs(newYaw - mc.thePlayer.rotationYaw) % 360; 85 | double pitchDiff = Math.abs(newPitch - mc.thePlayer.rotationPitch) % 360; 86 | return yawDiff >= 10 || pitchDiff >= 10; 87 | } 88 | 89 | @Override 90 | public boolean react() { 91 | MacroManager.getInstance().disable(); 92 | Logger.sendWarning("You`ve got rotated! Disabeling macro."); 93 | return true; 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/failsafe/impl/SlotChangeFailsafe.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.failsafe.impl; 2 | 3 | import com.jelly.mightyminerv2.event.PacketEvent; 4 | import com.jelly.mightyminerv2.failsafe.AbstractFailsafe; 5 | import com.jelly.mightyminerv2.macro.MacroManager; 6 | import com.jelly.mightyminerv2.util.Logger; 7 | import com.jelly.mightyminerv2.util.helper.Clock; 8 | import lombok.Getter; 9 | import net.minecraft.client.Minecraft; 10 | import net.minecraft.network.play.server.S09PacketHeldItemChange; 11 | import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent; 12 | 13 | public class SlotChangeFailsafe extends AbstractFailsafe { 14 | 15 | @Getter 16 | private static final SlotChangeFailsafe instance = new SlotChangeFailsafe(); 17 | private final Minecraft mc = Minecraft.getMinecraft(); 18 | private final Clock timer = new Clock(); 19 | private int lastSelectedSlot; 20 | private boolean slotChanged = false; 21 | 22 | private SlotChangeFailsafe() { 23 | this.lastSelectedSlot = mc.thePlayer != null ? mc.thePlayer.inventory.currentItem : -1; 24 | } 25 | 26 | @Override 27 | public String getName() { 28 | return "SlotChangeFailsafe"; 29 | } 30 | 31 | @Override 32 | public Failsafe getFailsafeType() { 33 | return Failsafe.SLOT_CHANGE; 34 | } 35 | 36 | @Override 37 | public int getPriority() { 38 | return 5; 39 | } 40 | 41 | @Override 42 | public boolean onTick(ClientTickEvent event) { 43 | if (slotChanged && timer.passed()) { 44 | Logger.sendLog("Timer passed after slot change"); 45 | return true; 46 | } 47 | 48 | return false; 49 | } 50 | 51 | @Override 52 | public boolean onPacketReceive(PacketEvent.Received event) { 53 | if (event.packet instanceof S09PacketHeldItemChange) { 54 | S09PacketHeldItemChange packet = (S09PacketHeldItemChange) event.packet; 55 | int slotIndex = packet.getHeldItemHotbarIndex(); 56 | 57 | if (slotIndex != lastSelectedSlot) { 58 | log("Slot changed by S09 packet from " + lastSelectedSlot + " to " + slotIndex); 59 | slotChanged = true; 60 | lastSelectedSlot = slotIndex; 61 | 62 | if (!timer.isScheduled()) { 63 | timer.schedule(2000); 64 | } 65 | } 66 | } 67 | 68 | return false; 69 | } 70 | 71 | @Override 72 | public boolean react() { 73 | if (slotChanged) { 74 | MacroManager.getInstance().disable(); 75 | warn("Slot selection changed! Disabling macro."); 76 | slotChanged = false; 77 | return true; 78 | } 79 | 80 | return false; 81 | } 82 | 83 | @Override 84 | public void resetStates() { 85 | timer.reset(); 86 | slotChanged = false; 87 | log("SlotChangeFailsafe state reset."); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/failsafe/impl/WorldChangeFailsafe.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.failsafe.impl; 2 | 3 | import com.jelly.mightyminerv2.failsafe.AbstractFailsafe; 4 | import com.jelly.mightyminerv2.feature.impl.AutoWarp; 5 | import com.jelly.mightyminerv2.macro.MacroManager; 6 | import lombok.Getter; 7 | import net.minecraft.client.Minecraft; 8 | import net.minecraftforge.event.world.WorldEvent; 9 | 10 | public class WorldChangeFailsafe extends AbstractFailsafe { 11 | 12 | @Getter 13 | private static final WorldChangeFailsafe instance = new WorldChangeFailsafe(); 14 | private static final Failsafe failsafeType = Failsafe.TELEPORT; 15 | 16 | // Then remove the getFailsafeType() method entirely 17 | // Update any code to access the field directly 18 | 19 | @Override 20 | public String getName() { 21 | return "WorldChangeFailsafe"; 22 | } 23 | 24 | @Override 25 | public Failsafe getFailsafeType() { 26 | return failsafeType; 27 | } 28 | 29 | @Override 30 | public int getPriority() { 31 | return 5; 32 | } 33 | 34 | @Override 35 | public boolean react() { 36 | warn("Stopping macro due to world change."); 37 | MacroManager.getInstance().disable(); 38 | return true; 39 | } 40 | 41 | @Override 42 | public boolean onWorldUnload(WorldEvent.Unload event) { 43 | if (!MacroManager.getInstance().isEnabled()) return false; 44 | return AutoWarp.getInstance().isDoneWarping(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/FeatureManager.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature; 2 | 3 | import com.jelly.mightyminerv2.failsafe.AbstractFailsafe.Failsafe; 4 | import com.jelly.mightyminerv2.feature.impl.*; 5 | import com.jelly.mightyminerv2.feature.impl.AutoDrillRefuel.AutoDrillRefuel; 6 | import com.jelly.mightyminerv2.feature.impl.AutoGetStats.AutoGetStats; 7 | import com.jelly.mightyminerv2.feature.impl.AutoMobKiller.AutoMobKiller; 8 | import com.jelly.mightyminerv2.feature.impl.BlockMiner.BlockMiner; 9 | 10 | import java.util.Arrays; 11 | import java.util.HashSet; 12 | import java.util.LinkedHashSet; 13 | import java.util.Set; 14 | 15 | // TODO: Finish AutoSell and WorldScanner 16 | public class FeatureManager { 17 | 18 | private static FeatureManager instance; 19 | public final Set allFeatures = new LinkedHashSet<>(); 20 | 21 | public FeatureManager() { 22 | this.allFeatures.addAll(Arrays.asList( 23 | AutoCommissionClaim.getInstance(), 24 | AutoGetStats.getInstance(), 25 | AutoMobKiller.getInstance(), 26 | AutoWarp.getInstance(), 27 | BlockMiner.getInstance(), 28 | MouseUngrab.getInstance(), 29 | Pathfinder.getInstance(), 30 | RouteBuilder.getInstance(), 31 | RouteNavigator.getInstance(), 32 | AutoDrillRefuel.getInstance(), 33 | AutoChestUnlocker.instance, 34 | WorldScanner.getInstance(), 35 | AutoSell.getInstance() 36 | )); 37 | } 38 | 39 | public static FeatureManager getInstance() { 40 | if (instance == null) { 41 | instance = new FeatureManager(); 42 | } 43 | return instance; 44 | } 45 | 46 | public void enableAll() { 47 | this.allFeatures.forEach(it -> { 48 | if (it.shouldStartAtLaunch()) { 49 | it.start(); 50 | } 51 | }); 52 | } 53 | 54 | public void disableAll() { 55 | this.allFeatures.forEach(it -> { 56 | if (it.isRunning()) { 57 | it.stop(); 58 | } 59 | }); 60 | } 61 | 62 | public void pauseAll() { 63 | this.allFeatures.forEach(it -> { 64 | if (it.isRunning()) { 65 | it.pause(); 66 | } 67 | }); 68 | } 69 | 70 | public void resumeAll() { 71 | this.allFeatures.forEach(it -> { 72 | if (it.isRunning()) { 73 | it.resume(); 74 | } 75 | }); 76 | } 77 | 78 | public boolean shouldNotCheckForFailsafe() { 79 | return this.allFeatures.stream().filter(AbstractFeature::isRunning).anyMatch(AbstractFeature::shouldNotCheckForFailsafe); 80 | } 81 | 82 | public Set getFailsafesToIgnore() { 83 | Set failsafes = new HashSet<>(); 84 | this.allFeatures.forEach(it -> { 85 | if (it.isRunning()) { 86 | failsafes.addAll(it.getFailsafesToIgnore()); 87 | } 88 | }); 89 | return failsafes; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/AutoDrillRefuel/AutoDrillRefuel.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl.AutoDrillRefuel; 2 | 3 | import com.jelly.mightyminerv2.failsafe.AbstractFailsafe.Failsafe; 4 | import com.jelly.mightyminerv2.feature.AbstractFeature; 5 | import com.jelly.mightyminerv2.feature.impl.AutoDrillRefuel.states.AutoDrillRefuelState; 6 | import com.jelly.mightyminerv2.feature.impl.AutoDrillRefuel.states.StartingState; 7 | import lombok.Getter; 8 | import lombok.Setter; 9 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 10 | import net.minecraftforge.fml.common.gameevent.TickEvent; 11 | import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent; 12 | 13 | public class AutoDrillRefuel extends AbstractFeature { 14 | @Getter 15 | private static final AutoDrillRefuel instance = new AutoDrillRefuel(); 16 | 17 | public enum AutoDrillRefuelError { 18 | NONE, 19 | NO_DRILL, 20 | NO_FUEL, 21 | NO_ABIPHONE, 22 | NO_GREATFORGE_CONTACT 23 | } 24 | @Setter 25 | @Getter 26 | private AutoDrillRefuelError error = AutoDrillRefuelError.NONE; 27 | 28 | public enum FuelType{ 29 | VOLTA ("Volta"), 30 | OIL_BARREL ("Oil Barrel"); 31 | 32 | @Getter 33 | private final String name; 34 | 35 | FuelType(String name) { 36 | this.name = name; 37 | } 38 | } 39 | @Getter 40 | private FuelType fuelType; 41 | 42 | @Getter 43 | private String drillName; 44 | 45 | private AutoDrillRefuelState currentState; 46 | 47 | @Override 48 | public String getName() { 49 | return "AutoDrillRefuel"; 50 | } 51 | 52 | @Override 53 | public void resetStatesAfterStop() { 54 | this.failsafesToIgnore.remove(Failsafe.ITEM_CHANGE); 55 | } 56 | 57 | public void start(String drillName, FuelType fuelType) { 58 | this.enabled = true; 59 | this.drillName = drillName; 60 | this.fuelType = fuelType; 61 | this.error = AutoDrillRefuelError.NONE; 62 | currentState = new StartingState(); 63 | } 64 | 65 | @Override 66 | public void stop() { 67 | super.stop(); 68 | } 69 | 70 | @SubscribeEvent 71 | public void onTick(ClientTickEvent event) { 72 | if (!this.enabled || event.phase == TickEvent.Phase.END) { 73 | return; 74 | } 75 | 76 | if (currentState == null) 77 | return; 78 | 79 | AutoDrillRefuelState nextState = currentState.onTick(this); 80 | transitionTo(nextState); 81 | } 82 | 83 | private void transitionTo(AutoDrillRefuelState nextState){ 84 | // Skip if no state change 85 | if (currentState == nextState) 86 | return; 87 | 88 | currentState.onEnd(this); 89 | currentState = nextState; 90 | 91 | if (currentState == null) { 92 | log("null state, returning"); 93 | return; 94 | } 95 | 96 | currentState.onStart(this); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/AutoDrillRefuel/states/AbiphoneState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl.AutoDrillRefuel.states; 2 | 3 | import com.jelly.mightyminerv2.feature.impl.AutoDrillRefuel.AutoDrillRefuel; 4 | import com.jelly.mightyminerv2.util.InventoryUtil; 5 | import com.jelly.mightyminerv2.util.KeyBindUtil; 6 | import net.minecraft.client.Minecraft; 7 | 8 | public class AbiphoneState implements AutoDrillRefuelState{ 9 | 10 | private final Minecraft mc = Minecraft.getMinecraft(); 11 | 12 | @Override 13 | public void onStart(AutoDrillRefuel refueler) { 14 | int abiphoneSlot = InventoryUtil.getHotbarSlotOfItem("Abiphone"); 15 | if (abiphoneSlot == -1) { 16 | logError("No abiphone found!"); 17 | refueler.stop(); 18 | refueler.setError(AutoDrillRefuel.AutoDrillRefuelError.NO_ABIPHONE); 19 | return; 20 | } 21 | 22 | mc.thePlayer.inventory.currentItem = abiphoneSlot; 23 | KeyBindUtil.rightClick(); 24 | log("Entering abiphone state"); 25 | } 26 | 27 | @Override 28 | public AutoDrillRefuelState onTick(AutoDrillRefuel refueler) { 29 | 30 | if (InventoryUtil.getInventoryName().contains("Abiphone") && InventoryUtil.isInventoryLoaded()) { 31 | log("Opened Abiphone GUI"); 32 | int greatforgeSlot = InventoryUtil.getSlotIdOfItemInContainer("Greatforge"); 33 | 34 | if(greatforgeSlot == -1){ 35 | logError("No Greatforge contact!"); 36 | refueler.stop(); 37 | refueler.setError(AutoDrillRefuel.AutoDrillRefuelError.NO_GREATFORGE_CONTACT); 38 | return null; 39 | } 40 | 41 | InventoryUtil.clickContainerSlot(greatforgeSlot, 0, InventoryUtil.ClickMode.PICKUP); 42 | return new GreatforgeState(); 43 | } 44 | 45 | return this; 46 | } 47 | 48 | @Override 49 | public void onEnd(AutoDrillRefuel refueler) { 50 | log("Ending abiphone state"); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/AutoDrillRefuel/states/AutoDrillRefuelState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl.AutoDrillRefuel.states; 2 | 3 | import com.jelly.mightyminerv2.feature.impl.AutoDrillRefuel.AutoDrillRefuel; 4 | 5 | 6 | public interface AutoDrillRefuelState { 7 | 8 | void onStart(AutoDrillRefuel refueler); 9 | AutoDrillRefuelState onTick(AutoDrillRefuel refueler); 10 | void onEnd(AutoDrillRefuel refueler); 11 | 12 | default void log(String message) { 13 | System.out.println("[" + this.getClass().getSimpleName() + "] " + message); 14 | } 15 | 16 | default void logError(String message) { 17 | System.out.println("[" + this.getClass().getSimpleName() + "] ERROR: " + message); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/AutoDrillRefuel/states/StartingState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl.AutoDrillRefuel.states; 2 | 3 | import com.jelly.mightyminerv2.feature.impl.AutoDrillRefuel.AutoDrillRefuel; 4 | import com.jelly.mightyminerv2.util.InventoryUtil; 5 | 6 | public class StartingState implements AutoDrillRefuelState{ 7 | @Override 8 | public void onStart(AutoDrillRefuel refueler) { 9 | log("Entering starting state"); 10 | } 11 | 12 | @Override 13 | public AutoDrillRefuelState onTick(AutoDrillRefuel refueler) { 14 | if (InventoryUtil.getSlotIdOfItemInContainer(refueler.getDrillName()) == -1) { 15 | logError("No drill found!"); 16 | refueler.stop(); 17 | refueler.setError(AutoDrillRefuel.AutoDrillRefuelError.NO_DRILL); 18 | return null; 19 | } 20 | 21 | if (InventoryUtil.getSlotIdOfItemInContainer(refueler.getFuelType().getName()) == -1) { 22 | logError("No fuel found!"); 23 | refueler.stop(); 24 | refueler.setError(AutoDrillRefuel.AutoDrillRefuelError.NO_FUEL); 25 | return null; 26 | } 27 | return new AbiphoneState(); 28 | } 29 | 30 | @Override 31 | public void onEnd(AutoDrillRefuel refueler) { 32 | log("Ending starting state"); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/AutoGetStats/AutoGetStats.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl.AutoGetStats; 2 | 3 | import com.jelly.mightyminerv2.feature.AbstractFeature; 4 | import com.jelly.mightyminerv2.feature.impl.AutoGetStats.tasks.AbstractInventoryTask; 5 | import com.jelly.mightyminerv2.util.helper.Clock; 6 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 7 | import net.minecraftforge.fml.common.gameevent.TickEvent; 8 | 9 | import java.util.ArrayDeque; 10 | import java.util.Queue; 11 | 12 | /** 13 | * AutoGetStats handles a simple internal queue of AbstractInventoryTask, 14 | * running one at a time in FIFO order. Goes onto the next task (if any) when one fails. 15 | */ 16 | public class AutoGetStats extends AbstractFeature { 17 | 18 | private static AutoGetStats instance; 19 | 20 | private final Queue> taskQueue = new ArrayDeque<>(); 21 | private AbstractInventoryTask currentTask; 22 | 23 | private final Clock delay = new Clock(); 24 | 25 | public static AutoGetStats getInstance() { 26 | if (instance == null) { 27 | instance = new AutoGetStats(); 28 | } 29 | return instance; 30 | } 31 | 32 | @Override 33 | public String getName() { 34 | return "AutoGetStats"; 35 | } 36 | 37 | @SubscribeEvent 38 | protected void onTick(TickEvent.ClientTickEvent event) { 39 | if (!enabled || mc.thePlayer == null || mc.theWorld == null || event.phase == TickEvent.Phase.END) 40 | return; 41 | 42 | if (currentTask != null) { 43 | currentTask.onTick(); 44 | 45 | if (currentTask.getTaskStatus().isFailure() || currentTask.getTaskStatus().isSuccessful()) { 46 | currentTask.end(); 47 | currentTask = null; 48 | delay.schedule(1000); // 1-second delay between each task 49 | } 50 | } 51 | else if (delay.isScheduled() && delay.passed() && !taskQueue.isEmpty()) { 52 | currentTask = taskQueue.poll(); 53 | currentTask.init(); 54 | } 55 | } 56 | 57 | /** 58 | * Adds a new task to the queue and starts it immediately if idle. 59 | */ 60 | public void startTask(AbstractInventoryTask task) { 61 | 62 | if (task == null) return; 63 | taskQueue.add(task); 64 | 65 | // If no current task running, start this one immediately 66 | if (currentTask == null) { 67 | currentTask = taskQueue.poll(); 68 | currentTask.init(); 69 | this.enabled = true; 70 | this.start(); 71 | } 72 | } 73 | 74 | public boolean hasFinishedAllTasks() { 75 | return currentTask == null && taskQueue.isEmpty(); 76 | } 77 | } 78 | 79 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/AutoGetStats/tasks/AbstractInventoryTask.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl.AutoGetStats.tasks; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * An abstract task class with a generic type parameter representing the result type. 7 | *

8 | * Each task follows a lifecycle with {@code init()}, {@code onTick()}, and {@code end()} methods. 9 | * The task begins in a {@link TaskStatus#PENDING} state by default 10 | * Subclasses must implement {@code getResult()} to return the final output once the task is complete. 11 | *

12 | * In the subclass, please initialize taskStatus to {@link TaskStatus#RUNNING}. Once the task has successfully finished, 13 | * set it to{@link TaskStatus#SUCCESS}. If the task failed, set taskStatus to {@link TaskStatus#FAILURE}, and attach 14 | * an error. 15 | * @param the type of result this task produces upon successful completion 16 | */ 17 | public abstract class AbstractInventoryTask { 18 | @Getter 19 | protected TaskStatus taskStatus = TaskStatus.PENDING; 20 | 21 | @Getter 22 | protected String error; 23 | 24 | abstract public void init(); 25 | abstract public void onTick(); 26 | abstract public void end(); 27 | abstract public T getResult(); 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/AutoGetStats/tasks/TaskStatus.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl.AutoGetStats.tasks; 2 | 3 | public enum TaskStatus { 4 | PENDING, 5 | RUNNING, 6 | SUCCESS, 7 | FAILURE; 8 | 9 | public boolean isRunning() { 10 | return this == RUNNING; 11 | } 12 | 13 | public boolean isSuccessful() { 14 | return this == SUCCESS; 15 | } 16 | 17 | public boolean isFailure() { 18 | return this == FAILURE; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/AutoGetStats/tasks/impl/MiningBoostRetrievalTask.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl.AutoGetStats.tasks.impl; 2 | 3 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 4 | import com.jelly.mightyminerv2.feature.impl.AutoGetStats.tasks.AbstractInventoryTask; 5 | import com.jelly.mightyminerv2.feature.impl.AutoGetStats.tasks.TaskStatus; 6 | import com.jelly.mightyminerv2.util.InventoryUtil; 7 | import com.jelly.mightyminerv2.util.helper.Clock; 8 | import net.minecraft.client.Minecraft; 9 | 10 | import java.util.regex.Matcher; 11 | import java.util.regex.Pattern; 12 | 13 | /** 14 | * A task that retrieves the Mining boost value from the player's HOTM GUI. 15 | */ 16 | public class MiningBoostRetrievalTask extends AbstractInventoryTask { 17 | 18 | private final Minecraft mc = Minecraft.getMinecraft(); 19 | private final Clock timer = new Clock(); 20 | private Integer speedBoost; 21 | 22 | @Override 23 | public void init() { 24 | taskStatus = TaskStatus.RUNNING; 25 | 26 | InventoryUtil.holdItem(MightyMinerConfig.miningTool); 27 | 28 | if (mc.currentScreen != null) { 29 | InventoryUtil.closeScreen(); 30 | } 31 | 32 | mc.thePlayer.sendChatMessage("/hotm"); 33 | timer.schedule(1000); 34 | } 35 | 36 | @Override 37 | public void onTick() { 38 | if (!timer.passed() && timer.isScheduled()) { 39 | return; 40 | } 41 | 42 | final int speedBoostSlot = InventoryUtil.getSlotIdOfItemInContainer("Mining Speed Boost"); 43 | final String speedBoostLore = String.join(" ", InventoryUtil.getLoreOfItemInContainer(speedBoostSlot)); 44 | 45 | final Matcher matcher = Pattern.compile("\\+(\\d+)%").matcher(speedBoostLore); 46 | if (matcher.find()) { 47 | speedBoost = Integer.parseInt(matcher.group(1)); 48 | taskStatus = TaskStatus.SUCCESS; 49 | return; 50 | } 51 | 52 | taskStatus = TaskStatus.FAILURE; 53 | error = "Cannot parse speed boost. You may have scrolled up in your HOTM GUI."; 54 | } 55 | 56 | @Override 57 | public void end() { 58 | InventoryUtil.closeScreen(); 59 | } 60 | 61 | @Override 62 | public Integer getResult() { 63 | return speedBoost; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/AutoGetStats/tasks/impl/MiningSpeedRetrievalTask.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl.AutoGetStats.tasks.impl; 2 | 3 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 4 | import com.jelly.mightyminerv2.feature.impl.AutoGetStats.tasks.AbstractInventoryTask; 5 | import com.jelly.mightyminerv2.feature.impl.AutoGetStats.tasks.TaskStatus; 6 | import com.jelly.mightyminerv2.util.InventoryUtil; 7 | import com.jelly.mightyminerv2.util.helper.Clock; 8 | import net.minecraft.client.Minecraft; 9 | 10 | import java.util.List; 11 | import java.util.regex.Matcher; 12 | import java.util.regex.Pattern; 13 | 14 | /** 15 | * A task that retrieves the Mining Speed value from the player's SkyBlock GUI. 16 | */ 17 | public class MiningSpeedRetrievalTask extends AbstractInventoryTask { 18 | 19 | private final Minecraft mc = Minecraft.getMinecraft(); 20 | private final Clock timer = new Clock(); 21 | private Integer miningSpeed; 22 | private static final Pattern MINING_SPEED_PATTERN = Pattern.compile("Mining Speed\\s+([\\d,]+\\.?\\d*)"); 23 | 24 | @Override 25 | public void init() { 26 | taskStatus = TaskStatus.RUNNING; 27 | 28 | InventoryUtil.holdItem(MightyMinerConfig.miningTool); 29 | 30 | if(!InventoryUtil.getInventoryName().equals("Your Equipment and Stats")) { 31 | if (mc.currentScreen != null) { 32 | InventoryUtil.closeScreen(); 33 | } 34 | 35 | mc.thePlayer.sendChatMessage("/stats"); 36 | } 37 | 38 | timer.schedule(1000); 39 | } 40 | 41 | @Override 42 | public void onTick() { 43 | if (!timer.passed() && timer.isScheduled()) { 44 | return; 45 | } 46 | 47 | if (!InventoryUtil.getInventoryName().equals("Your Equipment and Stats")) { 48 | taskStatus = TaskStatus.FAILURE; 49 | error = "Cannot open Stats Menu"; 50 | return; 51 | } 52 | 53 | List loreList = InventoryUtil.getItemLoreFromOpenContainer("Mining Stats"); 54 | for (String lore : loreList) { 55 | Matcher matcher = MINING_SPEED_PATTERN.matcher(lore); 56 | if (matcher.find()) { 57 | try { 58 | // The number - for example, "2,000" or "123.45" or "1,234.56" 59 | String numberAsString = matcher.group(1); 60 | String cleanNumberString = numberAsString.replace(",", ""); 61 | 62 | // Mining speeds from the 'stats menu' can be a decimal 63 | double rawMiningSpeed = Double.parseDouble(cleanNumberString); 64 | miningSpeed = (int) rawMiningSpeed; 65 | 66 | taskStatus = TaskStatus.SUCCESS; 67 | return; 68 | } catch (NumberFormatException e) { 69 | taskStatus = TaskStatus.FAILURE; 70 | error = "Found 'Mining Speed' but failed to parse the number in line: '" + lore + "'. Exiting with error: " + e.getMessage(); 71 | return; 72 | } 73 | } 74 | } 75 | 76 | taskStatus = TaskStatus.FAILURE; 77 | error = "Failed to get mining speed in GUI"; 78 | } 79 | 80 | @Override 81 | public void end() { 82 | InventoryUtil.closeScreen(); 83 | } 84 | 85 | @Override 86 | public Integer getResult() { 87 | return miningSpeed; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/AutoGetStats/tasks/impl/PickaxeAbilityRetrievalTask.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl.AutoGetStats.tasks.impl; 2 | 3 | import com.jelly.mightyminerv2.feature.impl.AutoGetStats.tasks.AbstractInventoryTask; 4 | import com.jelly.mightyminerv2.feature.impl.AutoGetStats.tasks.TaskStatus; 5 | import com.jelly.mightyminerv2.feature.impl.BlockMiner.BlockMiner; 6 | import com.jelly.mightyminerv2.util.InventoryUtil; 7 | import com.jelly.mightyminerv2.util.helper.Clock; 8 | import net.minecraft.block.Block; 9 | import net.minecraft.client.Minecraft; 10 | import net.minecraft.init.Blocks; 11 | import net.minecraft.inventory.Slot; 12 | 13 | /** 14 | * A task that retrieves the players pickaxe ability from the HOTM GUI. 15 | */ 16 | public class PickaxeAbilityRetrievalTask extends AbstractInventoryTask { 17 | 18 | private final Minecraft mc = Minecraft.getMinecraft(); 19 | private final Clock timer = new Clock(); 20 | private BlockMiner.PickaxeAbility pickaxeAbility; 21 | 22 | @Override 23 | public void init() { 24 | pickaxeAbility = BlockMiner.PickaxeAbility.NONE; 25 | taskStatus = TaskStatus.RUNNING; 26 | 27 | // The case that the HOTM menu is already open 28 | if (!InventoryUtil.getInventoryName().equals("Heart of the Mountain")) { 29 | if (mc.currentScreen != null) { 30 | InventoryUtil.closeScreen(); 31 | } 32 | 33 | mc.thePlayer.sendChatMessage("/hotm"); 34 | } 35 | 36 | timer.schedule(1000); 37 | } 38 | 39 | @Override 40 | public void onTick() { 41 | if (!timer.passed() && timer.isScheduled()) { 42 | return; 43 | } 44 | 45 | if (isSelected("Pickobulus")) { 46 | pickaxeAbility = BlockMiner.PickaxeAbility.PICKOBULUS; 47 | } else { 48 | pickaxeAbility = BlockMiner.PickaxeAbility.MINING_SPEED_BOOST; 49 | } 50 | taskStatus = TaskStatus.SUCCESS; 51 | } 52 | 53 | private boolean isSelected(String name) { 54 | final Slot slot = InventoryUtil.getSlotOfItemInContainer(name); 55 | final Block block = slot != null 56 | ? Block.getBlockFromItem(slot.getStack().getItem()) 57 | : null; 58 | 59 | return block != null && block == Blocks.emerald_block; 60 | } 61 | 62 | @Override 63 | public void end() { 64 | InventoryUtil.closeScreen(); 65 | } 66 | 67 | @Override 68 | public BlockMiner.PickaxeAbility getResult() { 69 | return pickaxeAbility; 70 | } 71 | } -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/AutoMobKiller/states/AutoMobKillerState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl.AutoMobKiller.states; 2 | 3 | import com.jelly.mightyminerv2.feature.impl.AutoMobKiller.AutoMobKiller; 4 | 5 | /** 6 | * AutoMobKillerState 7 | *

8 | * Interface for all states in the AutoMobKiller state machine. 9 | * Implements the State design pattern to encapsulate different behaviors 10 | * for each phase of the mining process. 11 | */ 12 | public interface AutoMobKillerState { 13 | /** 14 | * Called when entering this state. 15 | * Use for initialization and setup logic. 16 | * 17 | * @param mobKiller Reference to the AutoMobKiller instance 18 | */ 19 | void onStart(AutoMobKiller mobKiller); 20 | 21 | /** 22 | * Called on each game tick while this state is active. 23 | * Contains the main processing logic for the state. 24 | * 25 | * @param mobKiller Reference to the AutoMobKiller instance 26 | * @return The next state to transition to, or this if staying in current state 27 | */ 28 | AutoMobKillerState onTick(AutoMobKiller mobKiller); 29 | 30 | /** 31 | * Called when exiting this state. 32 | * Use for cleanup and finalization logic. 33 | * 34 | * @param mobKiller Reference to the AutoMobKiller instance 35 | */ 36 | void onEnd(AutoMobKiller mobKiller); 37 | 38 | default void log(String message) { 39 | System.out.println("[" + this.getClass().getSimpleName() + "] " + message); 40 | } 41 | 42 | default void logError(String message) { 43 | System.out.println("[" + this.getClass().getSimpleName() + "] ERROR: " + message); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/AutoMobKiller/states/FindMobState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl.AutoMobKiller.states; 2 | 3 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 4 | import com.jelly.mightyminerv2.feature.impl.AutoMobKiller.AutoMobKiller; 5 | import com.jelly.mightyminerv2.feature.impl.Pathfinder; 6 | import com.jelly.mightyminerv2.util.BlockUtil; 7 | import com.jelly.mightyminerv2.util.EntityUtil; 8 | import com.jelly.mightyminerv2.util.PlayerUtil; 9 | import com.jelly.mightyminerv2.util.helper.Clock; 10 | import net.minecraft.client.Minecraft; 11 | import net.minecraft.entity.Entity; 12 | import net.minecraft.entity.EntityLivingBase; 13 | import net.minecraft.entity.player.EntityPlayer; 14 | import net.minecraft.util.BlockPos; 15 | 16 | import java.util.ArrayList; 17 | import java.util.Comparator; 18 | import java.util.List; 19 | import java.util.stream.Collector; 20 | import java.util.stream.Collectors; 21 | 22 | public class FindMobState implements AutoMobKillerState { 23 | 24 | private final Minecraft mc = Minecraft.getMinecraft(); 25 | private final Clock waitForMobsToSpawnTimer = new Clock(); 26 | 27 | @Override 28 | public void onStart(AutoMobKiller mobKiller) { 29 | log("Entering Find Mob State"); 30 | waitForMobsToSpawnTimer.reset(); 31 | } 32 | 33 | @Override 34 | public AutoMobKillerState onTick(AutoMobKiller mobKiller) { 35 | 36 | EntityLivingBase mob = findBestMob(mobKiller); 37 | 38 | if (mob == null) { 39 | if (!waitForMobsToSpawnTimer.isScheduled()) { 40 | log("Scheduled a 10-second timer to see if mobs spawn or not"); 41 | waitForMobsToSpawnTimer.schedule(10_000); 42 | } 43 | 44 | if (waitForMobsToSpawnTimer.isScheduled() && waitForMobsToSpawnTimer.passed()) { 45 | log("Cannot find a mob to kill!"); 46 | mobKiller.setError(AutoMobKiller.MKError.NO_ENTITIES); 47 | mobKiller.stop(); 48 | return null; 49 | } 50 | 51 | return this; 52 | } 53 | 54 | mobKiller.setTargetMob(mob); 55 | mobKiller.setTargetMobOriginalPos(mob.getPositionVector()); 56 | return new PathfindingState(); 57 | } 58 | 59 | private EntityLivingBase findBestMob(AutoMobKiller mobKiller) { 60 | Minecraft mc = Minecraft.getMinecraft(); 61 | List playerEntities = new ArrayList<>(Minecraft.getMinecraft().theWorld.playerEntities); 62 | playerEntities.remove(mc.thePlayer); 63 | 64 | List actualPlayers = playerEntities.stream() 65 | .filter(player -> !EntityUtil.isNpc(player)) 66 | .collect(Collectors.toList()); 67 | 68 | List mobs = EntityUtil.getEntities(mobKiller.getMobsToKill(), mobKiller.getBlacklistedMobs()); 69 | 70 | if(mobs.isEmpty()) 71 | return null; 72 | 73 | List filteredMobs = mobs.stream() 74 | .filter(mob -> mc.thePlayer.getDistanceSqToEntity(mob) < 1000) 75 | .filter(mob -> actualPlayers.stream() 76 | .noneMatch(player -> player.getDistanceSqToEntity(mob) < 9.0f)) 77 | .filter(mob -> BlockUtil.canStandOn(EntityUtil.getBlockStandingOn(mob))) 78 | .collect(Collectors.toList()); 79 | 80 | return filteredMobs.stream() 81 | .min(Comparator.comparingDouble(mob -> mc.thePlayer.getDistanceSqToEntity(mob))) 82 | .orElse(null); 83 | } 84 | 85 | 86 | @Override 87 | public void onEnd(AutoMobKiller mobKiller) { 88 | log("Exiting Find Mob State"); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/AutoMobKiller/states/KillState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl.AutoMobKiller.states; 2 | 3 | import com.jelly.mightyminerv2.feature.impl.AutoMobKiller.AutoMobKiller; 4 | import com.jelly.mightyminerv2.feature.impl.Pathfinder; 5 | import com.jelly.mightyminerv2.handler.RotationHandler; 6 | import com.jelly.mightyminerv2.util.KeyBindUtil; 7 | import com.jelly.mightyminerv2.util.helper.RotationConfiguration; 8 | import com.jelly.mightyminerv2.util.helper.Target; 9 | import net.minecraft.client.Minecraft; 10 | 11 | public class KillState implements AutoMobKillerState { 12 | 13 | private final Minecraft mc = Minecraft.getMinecraft(); 14 | private boolean hasRotated = false; 15 | 16 | @Override 17 | public void onStart(AutoMobKiller mobKiller) { 18 | log("Entering Kill State"); 19 | hasRotated = false; 20 | } 21 | 22 | @Override 23 | public AutoMobKillerState onTick(AutoMobKiller mobKiller) { 24 | // Initial rotation to mob 25 | if (!hasRotated) { 26 | RotationHandler.getInstance().easeTo(new RotationConfiguration( 27 | new Target(mobKiller.getTargetMob()), 28 | 400L, 29 | null 30 | )); 31 | 32 | hasRotated = true; 33 | return this; 34 | } 35 | 36 | // Attack as soon as the player is able to hit the entity 37 | if (mc.objectMouseOver.entityHit != mobKiller.getTargetMob()) { 38 | if (!Pathfinder.getInstance().isRunning() && !RotationHandler.getInstance().isEnabled()) { 39 | return new StartingState(); 40 | } 41 | 42 | return this; 43 | } 44 | 45 | KeyBindUtil.leftClick(); 46 | RotationHandler.getInstance().stop(); 47 | return new StartingState(); 48 | } 49 | 50 | @Override 51 | public void onEnd(AutoMobKiller mobKiller) { 52 | log("Exiting Kill State"); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/AutoMobKiller/states/PathfindingState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl.AutoMobKiller.states; 2 | 3 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 4 | import com.jelly.mightyminerv2.feature.impl.AutoMobKiller.AutoMobKiller; 5 | import com.jelly.mightyminerv2.feature.impl.Pathfinder; 6 | import com.jelly.mightyminerv2.util.EntityUtil; 7 | import com.jelly.mightyminerv2.util.PlayerUtil; 8 | import com.jelly.mightyminerv2.util.helper.Clock; 9 | import net.minecraft.client.Minecraft; 10 | 11 | public class PathfindingState implements AutoMobKillerState{ 12 | 13 | private int pathAttempts = 0; 14 | private final Clock timeout = new Clock(); 15 | 16 | @Override 17 | public void onStart(AutoMobKiller mobKiller) { 18 | log("Entering pathfinding state"); 19 | pathAttempts = 0; 20 | timeout.reset(); 21 | timeout.schedule(10_000); 22 | Pathfinder.getInstance().stopAndRequeue(EntityUtil.nearbyBlock(mobKiller.getTargetMob())); 23 | Pathfinder.getInstance().setSprintState(MightyMinerConfig.mobKillerSprint); 24 | Pathfinder.getInstance().setInterpolationState(MightyMinerConfig.mobKillerInterpolate); 25 | Pathfinder.getInstance().start(); 26 | } 27 | 28 | @Override 29 | public AutoMobKillerState onTick(AutoMobKiller mobKiller) { 30 | if (PlayerUtil.getNextTickPosition().squareDistanceTo(mobKiller.getTargetMob().getPositionVector()) < 8 31 | && Minecraft.getMinecraft().thePlayer.canEntityBeSeen(mobKiller.getTargetMob())) { 32 | return new KillState(); 33 | } 34 | 35 | if (!mobKiller.getTargetMob().isEntityAlive()) { 36 | Pathfinder.getInstance().stop(); 37 | log("Target mob is no longer alive. Re-choosing a mob."); 38 | return new StartingState(); 39 | } 40 | 41 | if (mobKiller.getTargetMob().getPositionVector().squareDistanceTo(mobKiller.getTargetMobOriginalPos()) > 9) { 42 | if (++pathAttempts > 3) { 43 | log("Target mob moved away from original location too many times. Re-choosing a mob."); 44 | mobKiller.getBlacklistedMobs().add(mobKiller.getTargetMob()); 45 | return new StartingState(); 46 | } 47 | mobKiller.setTargetMobOriginalPos(mobKiller.getTargetMob().getPositionVector()); 48 | Pathfinder.getInstance().stopAndRequeue(EntityUtil.nearbyBlock(mobKiller.getTargetMob())); 49 | return this; 50 | } 51 | 52 | if (timeout.passed()) { 53 | log("Pathfinding timeout. Re-choosing a mob."); 54 | mobKiller.getBlacklistedMobs().add(mobKiller.getTargetMob()); 55 | return new StartingState(); 56 | } 57 | 58 | return this; 59 | } 60 | 61 | @Override 62 | public void onEnd(AutoMobKiller mobKiller) { 63 | Pathfinder.getInstance().stop(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/AutoMobKiller/states/StartingState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl.AutoMobKiller.states; 2 | 3 | import com.jelly.mightyminerv2.feature.impl.AutoMobKiller.AutoMobKiller; 4 | import net.minecraft.entity.EntityLivingBase; 5 | 6 | public class StartingState implements AutoMobKillerState { 7 | 8 | @Override 9 | public void onStart(AutoMobKiller mobKiller) { 10 | log("Entering Starting State"); 11 | } 12 | 13 | @Override 14 | public AutoMobKillerState onTick(AutoMobKiller mobKiller) { 15 | return new FindMobState(); 16 | } 17 | 18 | @Override 19 | public void onEnd(AutoMobKiller mobKiller) { 20 | log("Exiting Starting State"); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/AutoSell.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl; 2 | 3 | import com.jelly.mightyminerv2.feature.AbstractFeature; 4 | import lombok.Getter; 5 | 6 | public class AutoSell extends AbstractFeature { 7 | 8 | @Getter 9 | public static AutoSell instance = new AutoSell(); 10 | 11 | @Override 12 | public String getName() { 13 | return "AutoSell"; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/BlockMiner/states/BlockMinerState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl.BlockMiner.states; 2 | 3 | import com.jelly.mightyminerv2.feature.impl.BlockMiner.BlockMiner; 4 | 5 | /** 6 | * BlockMinerState 7 | *

8 | * Interface for all states in the BlockMiner state machine. 9 | * Implements the State design pattern to encapsulate different behaviors 10 | * for each phase of the mining process. 11 | */ 12 | public interface BlockMinerState { 13 | /** 14 | * Called when entering this state. 15 | * Use for initialization and setup logic. 16 | * 17 | * @param miner Reference to the BlockMiner instance 18 | */ 19 | void onStart(BlockMiner miner); 20 | 21 | /** 22 | * Called on each game tick while this state is active. 23 | * Contains the main processing logic for the state. 24 | * 25 | * @param miner Reference to the BlockMiner instance 26 | * @return The next state to transition to, or this if staying in current state 27 | */ 28 | BlockMinerState onTick(BlockMiner miner); 29 | 30 | /** 31 | * Called when exiting this state. 32 | * Use for cleanup and finalization logic. 33 | * 34 | * @param miner Reference to the BlockMiner instance 35 | */ 36 | void onEnd(BlockMiner miner); 37 | 38 | default void log(String message) { 39 | System.out.println("[" + this.getClass().getSimpleName() + "] " + message); 40 | } 41 | 42 | default void logError(String message) { 43 | System.out.println("[" + this.getClass().getSimpleName() + "] ERROR: " + message); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/BlockMiner/states/ChoosingBlockState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl.BlockMiner.states; 2 | 3 | import com.jelly.mightyminerv2.feature.impl.BlockMiner.BlockMiner; 4 | import com.jelly.mightyminerv2.util.BlockUtil; 5 | import com.jelly.mightyminerv2.util.helper.Clock; 6 | import net.minecraft.client.Minecraft; 7 | import net.minecraft.util.BlockPos; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * ChoosingBlockState 13 | *

14 | * State responsible for finding the next block to mine. 15 | * Uses priority settings to determine the best block to target. 16 | * Includes wait logic if no blocks are immediately available. 17 | */ 18 | public class ChoosingBlockState implements BlockMinerState { 19 | private final Clock timer = new Clock(); 20 | 21 | @Override 22 | public void onStart(BlockMiner blockMiner) { 23 | log("Entering Choosing Block State"); 24 | timer.reset(); 25 | } 26 | 27 | @Override 28 | public BlockMinerState onTick(BlockMiner blockMiner) { 29 | // Try to find mineable blocks around the player based on priorities 30 | List blocks = BlockUtil.findMineableBlocksFromAccessiblePositions( 31 | blockMiner.getBlockPriority(), 32 | blockMiner.getTargetBlockPos(), 33 | blockMiner.getMiningSpeed() 34 | ); 35 | 36 | // Handle case where no blocks are found 37 | if (blocks.isEmpty()) { 38 | if (!timer.isScheduled()) { 39 | log("Scheduled a 2-second timer to see if blocks spawn or not"); 40 | timer.schedule(blockMiner.getWaitThreshold()); 41 | } 42 | 43 | // If the timer has ended and still no blocks, stop mining 44 | if (timer.isScheduled() && timer.passed()) { 45 | logError("Cannot find enough blocks to mine."); 46 | blockMiner.stop(); 47 | blockMiner.setError(BlockMiner.BlockMinerError.NOT_ENOUGH_BLOCKS); 48 | return null; 49 | } 50 | 51 | // Wait for the timer to expire 52 | return this; 53 | } 54 | 55 | // Found blocks - select the best one (first in list) and transition to breaking 56 | blockMiner.setTargetBlockPos(blocks.get(0)); 57 | blockMiner.setTargetBlockType(Minecraft.getMinecraft().theWorld.getBlockState(blocks.get(0)).getBlock()); 58 | return new BreakingState(); 59 | } 60 | 61 | @Override 62 | public void onEnd(BlockMiner blockMiner) { 63 | log("Exiting Choosing Block State"); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/BlockMiner/states/StartingState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl.BlockMiner.states; 2 | 3 | import com.jelly.mightyminerv2.feature.impl.BlockMiner.BlockMiner; 4 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 5 | 6 | /** 7 | * StartingState 8 | *

9 | * Initial state in the BlockMiner state machine. 10 | * Acts as an entry point and determines the next appropriate state. 11 | */ 12 | public class StartingState implements BlockMinerState { 13 | 14 | @Override 15 | public void onStart(BlockMiner miner) { 16 | log("Entering Starting State"); 17 | } 18 | 19 | @Override 20 | public BlockMinerState onTick(BlockMiner miner) { 21 | if (BlockMiner.getInstance().getPickaxeAbility() != BlockMiner.PickaxeAbility.NONE 22 | && miner.getPickaxeAbilityState() == BlockMiner.PickaxeAbilityState.AVAILABLE) { 23 | return new ApplyAbilityState(); 24 | } else 25 | return new ChoosingBlockState(); 26 | } 27 | 28 | @Override 29 | public void onEnd(BlockMiner miner) { 30 | log("Exiting Starting State"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/MouseUngrab.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl; 2 | 3 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 4 | import com.jelly.mightyminerv2.feature.AbstractFeature; 5 | import net.minecraft.util.MouseHelper; 6 | import org.lwjgl.input.Mouse; 7 | 8 | public class MouseUngrab extends AbstractFeature { 9 | 10 | private static volatile MouseUngrab instance; 11 | private MouseHelper oldMouseHelper; 12 | private boolean mouseUngrabbed = false; 13 | 14 | public static MouseUngrab getInstance() { 15 | if (instance == null) { 16 | synchronized (MouseUngrab.class) { 17 | if (instance == null) { 18 | instance = new MouseUngrab(); 19 | } 20 | } 21 | } 22 | return instance; 23 | } 24 | 25 | public void ungrabMouse() { 26 | if (mouseUngrabbed || !Mouse.isGrabbed()) { 27 | return; 28 | } 29 | 30 | oldMouseHelper = mc.mouseHelper; 31 | mc.mouseHelper.ungrabMouseCursor(); 32 | 33 | mc.mouseHelper = new MouseHelper() { 34 | @Override 35 | public void mouseXYChange() { 36 | } 37 | 38 | @Override 39 | public void grabMouseCursor() { 40 | } 41 | 42 | @Override 43 | public void ungrabMouseCursor() { 44 | } 45 | }; 46 | 47 | mouseUngrabbed = true; 48 | log("Mouse ungrabbed successfully."); 49 | } 50 | 51 | public void regrabMouse() { 52 | if (!mouseUngrabbed || Mouse.isGrabbed()) { 53 | return; 54 | } 55 | 56 | if (oldMouseHelper != null) { 57 | mc.mouseHelper = oldMouseHelper; 58 | oldMouseHelper = null; 59 | } 60 | 61 | if (mc.currentScreen == null) { 62 | mc.mouseHelper.grabMouseCursor(); 63 | } 64 | 65 | mouseUngrabbed = false; 66 | log("Mouse regrabbed successfully."); 67 | } 68 | 69 | @Override 70 | public String getName() { 71 | return "Ungrab Mouse"; 72 | } 73 | 74 | @Override 75 | public boolean isEnabled() { 76 | return MightyMinerConfig.ungrabMouse; 77 | } 78 | 79 | @Override 80 | public boolean shouldStartAtLaunch() { 81 | return this.isEnabled(); 82 | } 83 | 84 | @Override 85 | public void start() { 86 | log("MouseUngrab::start"); 87 | try { 88 | ungrabMouse(); 89 | } catch (Exception e) { 90 | log("Failed to ungrab mouse: " + e.getMessage()); 91 | e.printStackTrace(); 92 | } 93 | } 94 | 95 | @Override 96 | public void stop() { 97 | log("MouseUngrab::stop"); 98 | try { 99 | regrabMouse(); 100 | } catch (Exception e) { 101 | log("Failed to regrab mouse: " + e.getMessage()); 102 | e.printStackTrace(); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/RouteBuilder.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl; 2 | 3 | import cc.polyfrost.oneconfig.utils.Multithreading; 4 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 5 | import com.jelly.mightyminerv2.feature.AbstractFeature; 6 | import com.jelly.mightyminerv2.handler.RouteHandler; 7 | import com.jelly.mightyminerv2.util.Logger; 8 | import com.jelly.mightyminerv2.util.PlayerUtil; 9 | import com.jelly.mightyminerv2.util.helper.route.Route; 10 | import com.jelly.mightyminerv2.util.helper.route.RouteWaypoint; 11 | import com.jelly.mightyminerv2.util.helper.route.WaypointType; 12 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 13 | import net.minecraftforge.fml.common.gameevent.InputEvent; 14 | 15 | import java.util.concurrent.TimeUnit; 16 | 17 | public class RouteBuilder extends AbstractFeature { 18 | 19 | private static RouteBuilder instance; 20 | 21 | public static RouteBuilder getInstance() { 22 | if (instance == null) { 23 | instance = new RouteBuilder(); 24 | } 25 | return instance; 26 | } 27 | 28 | @Override 29 | public String getName() { 30 | return "RouteBuilder"; 31 | } 32 | 33 | public void toggle() { 34 | if (!this.enabled) { 35 | this.start(); 36 | } else { 37 | this.stop(); 38 | } 39 | } 40 | 41 | @Override 42 | public void start() { 43 | this.enabled = true; 44 | Multithreading.schedule(RouteHandler.getInstance()::saveData, 0, TimeUnit.MILLISECONDS); 45 | send("Enabling RouteBuilder."); 46 | } 47 | 48 | @Override 49 | public void stop() { 50 | this.enabled = false; 51 | send("Disabling RouteBuilder."); 52 | } 53 | 54 | @SubscribeEvent 55 | public void onKeyEvent(InputEvent.KeyInputEvent event) { 56 | if (!this.enabled) { 57 | return; 58 | } 59 | 60 | if (MightyMinerConfig.routeBuilderWalkAddKeybind.isActive()) { 61 | this.addToRoute(WaypointType.WALK); 62 | Logger.sendMessage("Added Walk"); 63 | } 64 | 65 | if (MightyMinerConfig.routeBuilderEtherwarpAddKeybind.isActive()) { 66 | this.addToRoute(WaypointType.ETHERWARP); 67 | Logger.sendMessage("Added Etherwarp"); 68 | } 69 | 70 | if (MightyMinerConfig.routeBuilderRemoveKeybind.isActive()) { 71 | Route selectedRoute = RouteHandler.getInstance().getSelectedRoute(); 72 | RouteWaypoint closest = selectedRoute.getClosest(PlayerUtil.getBlockStandingOn()).get(); 73 | int index = selectedRoute.indexOf(closest); 74 | 75 | if (index == -1) { 76 | return; 77 | } 78 | 79 | this.removeFromRoute(index); 80 | } 81 | } 82 | 83 | public void addToRoute(final WaypointType method) { 84 | RouteHandler.getInstance().addToCurrentRoute(PlayerUtil.getBlockStandingOn(), method); 85 | } 86 | 87 | public void removeFromRoute(int index) { 88 | RouteHandler.getInstance().removeFromCurrentRoute(index); 89 | } 90 | 91 | public void replaceNode(final int index) { 92 | RouteHandler.getInstance().replaceInCurrentRoute(index, new RouteWaypoint(PlayerUtil.getBlockStandingOn(), WaypointType.ETHERWARP)); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/feature/impl/WorldScanner.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.feature.impl; 2 | 3 | import com.jelly.mightyminerv2.feature.AbstractFeature; 4 | import lombok.Getter; 5 | 6 | public class WorldScanner extends AbstractFeature { 7 | 8 | @Getter 9 | public static WorldScanner instance = new WorldScanner(); 10 | 11 | @Override 12 | public String getName() { 13 | return "WorldScanner"; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/hud/DebugHUD.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.hud; 2 | 3 | import cc.polyfrost.oneconfig.config.core.OneColor; 4 | import cc.polyfrost.oneconfig.hud.TextHud; 5 | import com.jelly.mightyminerv2.handler.GameStateHandler; 6 | import com.jelly.mightyminerv2.util.ScoreboardUtil; 7 | import lombok.Getter; 8 | import net.minecraft.client.Minecraft; 9 | import org.lwjgl.opengl.Display; 10 | 11 | import java.util.List; 12 | 13 | public class DebugHUD extends TextHud { 14 | 15 | @Getter 16 | private final static DebugHUD instance = new DebugHUD(); 17 | private final transient Minecraft mc = Minecraft.getMinecraft(); 18 | 19 | public DebugHUD() { 20 | super( 21 | false, 22 | 1f, 23 | 10f, 24 | 0.8f, 25 | true, 26 | true, 27 | 1, 28 | 5, 29 | 5, 30 | new OneColor(0, 0, 0, 150), 31 | false, 32 | 2, 33 | new OneColor(0, 0, 0, 127) 34 | ); 35 | } 36 | 37 | @Override 38 | protected void getLines(List lines, boolean example) { 39 | 40 | lines.add("§6§lScoreboard"); 41 | lines.add("§7Title: §f" + ScoreboardUtil.getScoreboardTitle()); 42 | lines.addAll(ScoreboardUtil.getScoreboard()); 43 | lines.add("Custom Cold: " + ScoreboardUtil.cold); 44 | lines.add(""); 45 | 46 | lines.add("§6§lPlayer Location"); 47 | lines.add("§7Current Location: §f" + GameStateHandler.getInstance().getCurrentLocation().getName()); 48 | lines.add("§7Sub Location: §f" + GameStateHandler.getInstance().getCurrentSubLocation().getName()); 49 | lines.add(""); 50 | 51 | // Add display and game state information 52 | lines.add("§6§lDisplay & Game State"); 53 | lines.add("§7In-Game Focus: §f" + mc.inGameHasFocus); 54 | lines.add("§7Display Active: §f" + Display.isActive()); 55 | } 56 | 57 | /* 58 | public void addList(String featureName, DebugList list) { 59 | this.lists.put(featureName, list); 60 | } 61 | 62 | public void clearList() { 63 | this.lists.clear(); 64 | } 65 | 66 | public class DebugList implements Iterable { 67 | List debugLines = new ArrayList<>(); 68 | int current = 0; 69 | 70 | public DebugList(String... lines) { 71 | debugLines.addAll(Arrays.asList(lines)); 72 | } 73 | 74 | public DebugList append(String line) { 75 | debugLines.add(line); 76 | return this; 77 | } 78 | 79 | public DebugList append(int index, String line) { 80 | debugLines.add(index, line); 81 | return this; 82 | } 83 | 84 | public DebugList remove(int index) { 85 | debugLines.remove(index); 86 | return this; 87 | } 88 | 89 | @NotNull 90 | @Override 91 | public Iterator iterator() { 92 | return debugLines.listIterator(); 93 | } 94 | 95 | @Override 96 | public void forEach(Consumer action) { 97 | Iterable.super.forEach(action); 98 | } 99 | } 100 | */ 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/macro/impl/CommissionMacro/states/ClaimingCommissionState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.macro.impl.CommissionMacro.states; 2 | 3 | import com.jelly.mightyminerv2.feature.impl.AutoCommissionClaim; 4 | import com.jelly.mightyminerv2.macro.impl.CommissionMacro.Commission; 5 | import com.jelly.mightyminerv2.macro.impl.CommissionMacro.CommissionMacro; 6 | 7 | import java.util.List; 8 | 9 | public class ClaimingCommissionState implements CommissionMacroState{ 10 | @Override 11 | public void onStart(CommissionMacro macro) { 12 | log("Starting claiming commission state"); 13 | AutoCommissionClaim.getInstance().start(); 14 | } 15 | 16 | @Override 17 | public CommissionMacroState onTick(CommissionMacro macro) { 18 | 19 | if (AutoCommissionClaim.getInstance().isRunning()) { 20 | return this; 21 | } 22 | 23 | if (AutoCommissionClaim.getInstance().succeeded()) { 24 | List newCommissions = AutoCommissionClaim.getInstance().getNextComm(); 25 | 26 | if (newCommissions != null && !newCommissions.isEmpty()) { 27 | macro.setCurrentCommission(newCommissions.get(0)); 28 | log("Claiming successful. Next commission: " + newCommissions.get(0).getName()); 29 | } else { 30 | log("Claiming successful, but no new commissions were read. Restarting cycle."); 31 | return new StartingState(); 32 | } 33 | 34 | return new PathingState(); 35 | } 36 | 37 | switch (AutoCommissionClaim.getInstance().claimError()) { 38 | case NONE: 39 | macro.disable("Auto commission claiming failed, but no error is detected. Please contact the developer."); 40 | break; 41 | case INACCESSIBLE_NPC: 42 | log("The NPC was inaccessible while claiming commission"); 43 | return new WarpingState(); 44 | case TIMEOUT: 45 | log("Timeout in auto commission claiming"); 46 | return new StartingState(); 47 | case NO_ITEMS: 48 | macro.disable("No royal pigeons found, but this shouldn't happen. Please contact the developer."); 49 | break; 50 | case NPC_NOT_UNLOCKED: 51 | macro.disable("You have not unlocked Emissaries at Commission Milestone 1. Please post mc logs in #bug-report if this is a mistake."); 52 | break; 53 | } 54 | return null; 55 | } 56 | 57 | @Override 58 | public void onEnd(CommissionMacro macro) { 59 | AutoCommissionClaim.getInstance().stop(); 60 | log("Ending claiming commission state"); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/macro/impl/CommissionMacro/states/CommissionMacroState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.macro.impl.CommissionMacro.states; 2 | 3 | import com.jelly.mightyminerv2.macro.impl.CommissionMacro.CommissionMacro; 4 | import com.jelly.mightyminerv2.util.Logger; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.util.ChatComponentText; 7 | 8 | public interface CommissionMacroState { 9 | 10 | void onStart(CommissionMacro macro); 11 | 12 | CommissionMacroState onTick(CommissionMacro macro); 13 | 14 | void onEnd(CommissionMacro macro); 15 | 16 | default void log(String message) { 17 | System.out.println("[" + this.getClass().getSimpleName() + "] " + message); 18 | } 19 | 20 | default void logError(String message) { 21 | System.out.println("[" + this.getClass().getSimpleName() + "] ERROR: " + message); 22 | } 23 | 24 | default void send(String message) { 25 | Logger.addMessage("[" + this.getClass().getSimpleName() + "] " + message); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/macro/impl/CommissionMacro/states/GettingStatsState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.macro.impl.CommissionMacro.states; 2 | 3 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 4 | import com.jelly.mightyminerv2.feature.impl.AutoGetStats.AutoGetStats; 5 | import com.jelly.mightyminerv2.feature.impl.AutoGetStats.tasks.impl.MiningSpeedRetrievalTask; 6 | import com.jelly.mightyminerv2.feature.impl.AutoGetStats.tasks.impl.PickaxeAbilityRetrievalTask; 7 | import com.jelly.mightyminerv2.feature.impl.BlockMiner.BlockMiner; 8 | import com.jelly.mightyminerv2.macro.impl.CommissionMacro.CommissionMacro; 9 | 10 | public class GettingStatsState implements CommissionMacroState{ 11 | 12 | private final AutoGetStats autoInventory = AutoGetStats.getInstance(); 13 | private MiningSpeedRetrievalTask miningSpeedRetrievalTask; 14 | private PickaxeAbilityRetrievalTask pickaxeAbilityRetrievalTask; 15 | 16 | @Override 17 | public void onStart(CommissionMacro macro) { 18 | log("Entering getting stats state"); 19 | miningSpeedRetrievalTask = new MiningSpeedRetrievalTask(); 20 | pickaxeAbilityRetrievalTask = new PickaxeAbilityRetrievalTask(); 21 | AutoGetStats.getInstance().startTask(miningSpeedRetrievalTask); 22 | AutoGetStats.getInstance().startTask(pickaxeAbilityRetrievalTask); 23 | } 24 | 25 | @Override 26 | public CommissionMacroState onTick(CommissionMacro macro) { 27 | if (!AutoGetStats.getInstance().hasFinishedAllTasks()) 28 | return this; 29 | 30 | if (miningSpeedRetrievalTask.getError() != null) { 31 | macro.disable("Failed to get stats with the following error: " + miningSpeedRetrievalTask.getError()); 32 | return null; 33 | } 34 | 35 | if (pickaxeAbilityRetrievalTask.getError() != null) { 36 | macro.disable("Failed to get pickaxe ability with the following error: " + pickaxeAbilityRetrievalTask.getError()); 37 | return null; 38 | } 39 | 40 | macro.setMiningSpeed(miningSpeedRetrievalTask.getResult()); 41 | macro.setPickaxeAbility(MightyMinerConfig.usePickaxeAbility ? pickaxeAbilityRetrievalTask.getResult() : BlockMiner.PickaxeAbility.NONE); 42 | return new StartingState(); 43 | } 44 | 45 | @Override 46 | public void onEnd(CommissionMacro macro) { 47 | autoInventory.stop(); 48 | log("Exiting getting stats state"); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/macro/impl/CommissionMacro/states/MobKillingState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.macro.impl.CommissionMacro.states; 2 | 3 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 4 | import com.jelly.mightyminerv2.feature.impl.AutoMobKiller.AutoMobKiller; 5 | import com.jelly.mightyminerv2.macro.impl.CommissionMacro.Commission; 6 | import com.jelly.mightyminerv2.macro.impl.CommissionMacro.CommissionMacro; 7 | import com.jelly.mightyminerv2.util.CommissionUtil; 8 | 9 | import java.util.Set; 10 | 11 | public class MobKillingState implements CommissionMacroState { 12 | 13 | @Override 14 | public void onStart(CommissionMacro macro) { 15 | log("Starting mob killing state"); 16 | Set mobName = CommissionUtil.getMobForCommission(macro.getCurrentCommission()); 17 | 18 | if (mobName == null) { 19 | logError("Current commission: " + macro.getCurrentCommission()); 20 | macro.disable("Mob name not found! Please send the logs to the developer "); 21 | return; 22 | } 23 | 24 | AutoMobKiller.getInstance().start(mobName, macro.getCurrentCommission().getName().startsWith("Glacite") ? 25 | MightyMinerConfig.miningTool : MightyMinerConfig.slayerWeapon); 26 | } 27 | 28 | @Override 29 | public CommissionMacroState onTick(CommissionMacro macro) { 30 | if (macro.getCurrentCommission() == Commission.COMMISSION_CLAIM){ 31 | return new PathingState(); 32 | } 33 | 34 | if (AutoMobKiller.getInstance().isRunning()) { 35 | return this; 36 | } 37 | 38 | switch (AutoMobKiller.getInstance().getError()) { 39 | case NONE: 40 | return this; 41 | case NO_ENTITIES: 42 | log("No entities found in Mob Killer. Restarting"); 43 | return new StartingState(); 44 | } 45 | 46 | return null; 47 | } 48 | 49 | @Override 50 | public void onEnd(CommissionMacro macro) { 51 | AutoMobKiller.getInstance().stop(); 52 | log("Ending mob killing state"); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/macro/impl/CommissionMacro/states/RefuelState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.macro.impl.CommissionMacro.states; 2 | 3 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 4 | import com.jelly.mightyminerv2.feature.impl.AutoDrillRefuel.AutoDrillRefuel; 5 | import com.jelly.mightyminerv2.macro.impl.CommissionMacro.CommissionMacro; 6 | 7 | public class RefuelState implements CommissionMacroState{ 8 | 9 | private final AutoDrillRefuel.FuelType[] fuelTypeMap = 10 | {AutoDrillRefuel.FuelType.VOLTA, AutoDrillRefuel.FuelType.OIL_BARREL}; 11 | 12 | @Override 13 | public void onStart(CommissionMacro macro) { 14 | log("Starting refuel state"); 15 | AutoDrillRefuel.getInstance().start(MightyMinerConfig.miningTool, fuelTypeMap[MightyMinerConfig.refuelMachineFuel]); 16 | } 17 | 18 | @Override 19 | public CommissionMacroState onTick(CommissionMacro macro) { 20 | if (AutoDrillRefuel.getInstance().isRunning()) { 21 | return this; 22 | } 23 | 24 | switch (AutoDrillRefuel.getInstance().getError()) { 25 | case NONE: 26 | log("Done refilling"); 27 | return new StartingState(); 28 | case NO_DRILL: 29 | macro.disable("No drill found! This should not happen!"); 30 | break; 31 | case NO_ABIPHONE: 32 | macro.disable("No abiphone found! This should not happen!"); 33 | break; 34 | case NO_FUEL: 35 | macro.disable("No fuel found! Please put the fuel in the inventory, not mining sacks!"); 36 | break; 37 | case NO_GREATFORGE_CONTACT: 38 | macro.disable("No Greatforge contact in abiphone!"); 39 | break; 40 | } 41 | 42 | return null; 43 | } 44 | 45 | @Override 46 | public void onEnd(CommissionMacro macro) { 47 | AutoDrillRefuel.getInstance().stop(); 48 | log("Ending refuel state"); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/macro/impl/CommissionMacro/states/StartingState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.macro.impl.CommissionMacro.states; 2 | 3 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 4 | import com.jelly.mightyminerv2.macro.impl.CommissionMacro.CommissionMacro; 5 | import com.jelly.mightyminerv2.util.InventoryUtil; 6 | 7 | import java.util.Objects; 8 | 9 | public class StartingState implements CommissionMacroState{ 10 | 11 | @Override 12 | public void onStart(CommissionMacro macro) { 13 | log("Entering starting state"); 14 | } 15 | 16 | @Override 17 | public CommissionMacroState onTick(CommissionMacro macro) { 18 | if (Objects.equals(MightyMinerConfig.miningTool, "")) { 19 | macro.disable("Please set a Mining Tool in the config"); 20 | return null; 21 | } 22 | if (Objects.equals(MightyMinerConfig.slayerWeapon, "")) { 23 | macro.disable("Please set a Slayer Weapon in the config"); 24 | return null; 25 | } 26 | if (!InventoryUtil.areItemsInHotbar(macro.getNecessaryItems())) { 27 | macro.disable("Please put the following items in hotbar: " + InventoryUtil.getMissingItemsInHotbar(macro.getNecessaryItems())); 28 | return null; 29 | } 30 | return macro.getMiningSpeed() == 0 ? new GettingStatsState() : new PathingState(); 31 | } 32 | 33 | @Override 34 | public void onEnd(CommissionMacro macro) { 35 | log("Exiting starting state"); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/macro/impl/CommissionMacro/states/WarpingState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.macro.impl.CommissionMacro.states; 2 | 3 | import com.jelly.mightyminerv2.feature.impl.AutoWarp; 4 | import com.jelly.mightyminerv2.macro.impl.CommissionMacro.CommissionMacro; 5 | import com.jelly.mightyminerv2.util.helper.location.SubLocation; 6 | 7 | public class WarpingState implements CommissionMacroState{ 8 | 9 | AutoWarp autoWarp = AutoWarp.getInstance(); 10 | 11 | @Override 12 | public void onStart(CommissionMacro macro) { 13 | log("Starting warping state"); 14 | autoWarp.start(null, SubLocation.THE_FORGE); 15 | } 16 | 17 | @Override 18 | public CommissionMacroState onTick(CommissionMacro macro) { 19 | 20 | if (AutoWarp.getInstance().isRunning()) { 21 | return this; 22 | } 23 | 24 | if (AutoWarp.getInstance().hasSucceeded()) { 25 | log("Auto Warp Completed"); 26 | return new StartingState(); 27 | } 28 | 29 | switch (AutoWarp.getInstance().getFailReason()) { 30 | case NONE: 31 | macro.disable("Auto Warp failed, but no error is detected. Please contact the developer."); 32 | break; 33 | case FAILED_TO_WARP: 34 | log("Retrying Auto Warp"); 35 | autoWarp.start(null, SubLocation.THE_FORGE); 36 | break; 37 | case NO_SCROLL: 38 | macro.disable("You don't have the /warp forge scroll!"); 39 | break; 40 | } 41 | return null; 42 | } 43 | 44 | @Override 45 | public void onEnd(CommissionMacro macro) { 46 | autoWarp.stop(); 47 | log("Ending warping state"); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/macro/impl/GlacialMacro/states/ClaimingCommissionState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.macro.impl.GlacialMacro.states; 2 | 3 | import com.jelly.mightyminerv2.feature.impl.AutoCommissionClaim; 4 | import com.jelly.mightyminerv2.macro.impl.GlacialMacro.GlacialMacro; 5 | import com.jelly.mightyminerv2.util.helper.Clock; 6 | 7 | /** 8 | * State for claiming completed commissions in the Glacial Macro. 9 | * This state handles the claiming process, including retries and timeouts. 10 | */ 11 | public class ClaimingCommissionState implements GlacialMacroState { 12 | 13 | private final AutoCommissionClaim claimer = AutoCommissionClaim.getInstance(); 14 | private final Clock timeout = new Clock(); 15 | private int retries = 0; 16 | 17 | @Override 18 | public void onStart(GlacialMacro macro) { 19 | log("Claiming completed commission."); 20 | claimer.start(); 21 | timeout.schedule(10000); // 10s timeout 22 | } 23 | 24 | @Override 25 | public GlacialMacroState onTick(GlacialMacro macro) { 26 | if (claimer.isRunning()) { 27 | if (timeout.passed()) { 28 | logError("Claiming commission timed out."); 29 | return handleFailure(macro); 30 | } 31 | return this; 32 | } 33 | 34 | if (claimer.succeeded()) { 35 | log("Successfully claimed commission."); 36 | macro.incrementCommissionCounter(); 37 | macro.updateMiningTasks(); // Update tasks after claiming 38 | return new PathfindingState(); 39 | } else { 40 | logError("Failed to claim commission. Reason: " + claimer.claimError()); 41 | return handleFailure(macro); 42 | } 43 | } 44 | 45 | private GlacialMacroState handleFailure(GlacialMacro macro) { 46 | if (++retries > 3) { 47 | return new ErrorHandlingState("Failed to claim commission after 3 attempts."); 48 | } 49 | log("Retrying claim... (" + retries + "/3)"); 50 | onStart(macro); // Restart the claim process 51 | return this; 52 | } 53 | 54 | @Override 55 | public void onEnd(GlacialMacro macro) { 56 | if (claimer.isRunning()) { 57 | claimer.stop(); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/macro/impl/GlacialMacro/states/ErrorHandlingState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.macro.impl.GlacialMacro.states; 2 | 3 | import com.jelly.mightyminerv2.macro.impl.GlacialMacro.GlacialMacro; 4 | 5 | public class ErrorHandlingState implements GlacialMacroState { 6 | private final String reason; 7 | 8 | public ErrorHandlingState(String reason) { 9 | this.reason = reason; 10 | } 11 | 12 | @Override 13 | public void onStart(GlacialMacro macro) { 14 | logError("Entering Error Handling State"); 15 | macro.disable(reason); 16 | } 17 | 18 | @Override 19 | public GlacialMacroState onTick(GlacialMacro macro) { 20 | return this; 21 | } 22 | 23 | @Override 24 | public void onEnd(GlacialMacro macro) { 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/macro/impl/GlacialMacro/states/GettingStatsState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.macro.impl.GlacialMacro.states; 2 | 3 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 4 | import com.jelly.mightyminerv2.feature.impl.AutoGetStats.AutoGetStats; 5 | import com.jelly.mightyminerv2.feature.impl.AutoGetStats.tasks.impl.MiningSpeedRetrievalTask; 6 | import com.jelly.mightyminerv2.feature.impl.AutoGetStats.tasks.impl.PickaxeAbilityRetrievalTask; 7 | import com.jelly.mightyminerv2.feature.impl.BlockMiner.BlockMiner; 8 | import com.jelly.mightyminerv2.macro.impl.GlacialMacro.GlacialMacro; 9 | 10 | /** 11 | * This state is responsible for retrieving the mining speed and pickaxe ability 12 | * before proceeding to the pathfinding state in the Glacial Macro. 13 | */ 14 | public class GettingStatsState implements GlacialMacroState { 15 | 16 | private final AutoGetStats autoInventory = AutoGetStats.getInstance(); 17 | private MiningSpeedRetrievalTask miningSpeedTask; 18 | private PickaxeAbilityRetrievalTask pickaxeAbilityTask; 19 | 20 | @Override 21 | public void onStart(GlacialMacro macro) { 22 | log("Entering getting stats state"); 23 | miningSpeedTask = new MiningSpeedRetrievalTask(); 24 | pickaxeAbilityTask = new PickaxeAbilityRetrievalTask(); 25 | AutoGetStats.getInstance().startTask(pickaxeAbilityTask); 26 | AutoGetStats.getInstance().startTask(miningSpeedTask); 27 | } 28 | 29 | @Override 30 | public GlacialMacroState onTick(GlacialMacro macro) { 31 | if (!AutoGetStats.getInstance().hasFinishedAllTasks()) { 32 | return this; 33 | } 34 | 35 | if (miningSpeedTask.getError() != null) { 36 | if (miningSpeedTask.getError().equals("Failed to parse mining speed in GUI")) { 37 | macro.transitionTo(new NewLobbyState()); 38 | } else { 39 | macro.disable("Failed to get stats with the following error: " 40 | + miningSpeedTask.getError()); 41 | } 42 | return null; 43 | } 44 | 45 | if (pickaxeAbilityTask.getError() != null) { 46 | macro.disable("Failed to get pickaxe ability with the following error: " 47 | + pickaxeAbilityTask.getError()); 48 | return null; 49 | } 50 | 51 | macro.setMiningSpeed(miningSpeedTask.getResult()); 52 | log("MiningSpeed: " + macro.getMiningSpeed()); 53 | macro.setPickaxeAbility(MightyMinerConfig.usePickaxeAbility ? 54 | pickaxeAbilityTask.getResult() : BlockMiner.PickaxeAbility.NONE); 55 | return new PathfindingState(); 56 | } 57 | 58 | @Override 59 | public void onEnd(GlacialMacro macro) { 60 | autoInventory.stop(); 61 | log("Exiting getting stats state"); 62 | } 63 | } -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/macro/impl/GlacialMacro/states/GlacialMacroState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.macro.impl.GlacialMacro.states; 2 | 3 | import com.jelly.mightyminerv2.macro.impl.GlacialMacro.GlacialMacro; 4 | import com.jelly.mightyminerv2.util.Logger; 5 | 6 | /** 7 | * Interface representing the state of the Glacial Macro. 8 | * Each state defines its own behavior for starting, ticking, and ending. 9 | */ 10 | public interface GlacialMacroState { 11 | 12 | void onStart(GlacialMacro macro); 13 | 14 | GlacialMacroState onTick(GlacialMacro macro); 15 | 16 | void onEnd(GlacialMacro macro); 17 | 18 | default void log(String message) { 19 | System.out.println("[" + this.getClass().getSimpleName() + "] " + message); 20 | } 21 | 22 | default void logError(String message) { 23 | System.out.println("[" + this.getClass().getSimpleName() + "] ERROR: " + message); 24 | } 25 | 26 | default void send(String message) { 27 | Logger.addMessage("[" + this.getClass().getSimpleName() + "] " + message); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/macro/impl/GlacialMacro/states/NewLobbyState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.macro.impl.GlacialMacro.states; 2 | 3 | import com.jelly.mightyminerv2.feature.impl.AutoWarp; 4 | import com.jelly.mightyminerv2.macro.impl.GlacialMacro.GlacialMacro; 5 | import com.jelly.mightyminerv2.util.helper.location.Location; 6 | import com.jelly.mightyminerv2.util.helper.location.SubLocation; 7 | 8 | public class NewLobbyState implements GlacialMacroState { 9 | 10 | private final AutoWarp autoWarp = AutoWarp.getInstance(); 11 | private WarpPhase currentPhase = WarpPhase.TO_HUB; 12 | 13 | @Override 14 | public void onStart(GlacialMacro macro) { 15 | log("Starting NewLobbyState"); 16 | 17 | log("Clearing previously visited veins blacklist to prepare for new lobby."); 18 | macro.getPreviousVeins().clear(); 19 | 20 | if (currentPhase == WarpPhase.TO_HUB) { 21 | autoWarp.start(Location.HUB, null); 22 | } 23 | } 24 | 25 | @Override 26 | public GlacialMacroState onTick(GlacialMacro macro) { 27 | if (autoWarp.isRunning()) { 28 | return this; 29 | } 30 | 31 | if (autoWarp.hasSucceeded()) { 32 | if (currentPhase == WarpPhase.TO_HUB) { 33 | log("Successfully warped to Hub. Warping back to Dwarven Base Camp."); 34 | currentPhase = WarpPhase.TO_BASE; 35 | 36 | autoWarp.start(null, SubLocation.DWARVEN_BASE_CAMP); 37 | return this; 38 | } else if (currentPhase == WarpPhase.TO_BASE) { 39 | log("Successfully returned to Dwarven Base Camp. Resuming pathfinding."); 40 | 41 | return new GettingStatsState(); 42 | } 43 | } else { 44 | logError("AutoWarp failed during NewLobby sequence. Reason: " + autoWarp.getFailReason()); 45 | return new ErrorHandlingState("Failed to execute new lobby sequence with reason: " + autoWarp.getFailReason()); 46 | } 47 | 48 | return this; 49 | } 50 | 51 | @Override 52 | public void onEnd(GlacialMacro macro) { 53 | if (autoWarp.isRunning()) { 54 | autoWarp.stop(); 55 | } 56 | log("Ending NewLobbyState"); 57 | } 58 | 59 | private enum WarpPhase { 60 | TO_HUB, 61 | TO_BASE 62 | } 63 | } -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/macro/impl/GlacialMacro/states/StartingState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.macro.impl.GlacialMacro.states; 2 | 3 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 4 | import com.jelly.mightyminerv2.handler.GameStateHandler; 5 | import com.jelly.mightyminerv2.macro.impl.GlacialMacro.GlacialMacro; 6 | import com.jelly.mightyminerv2.util.InventoryUtil; 7 | import com.jelly.mightyminerv2.util.helper.location.SubLocation; 8 | 9 | import java.util.Objects; 10 | 11 | /** 12 | * The initial state of the Glacial Macro. 13 | * This state checks if the player is in the correct location to start the macro. 14 | * If not, it will attempt to teleport the player to the Dwarven Base Camp. 15 | */ 16 | public class StartingState implements GlacialMacroState { 17 | @Override 18 | public void onStart(GlacialMacro macro) { 19 | log("Entering starting state"); 20 | 21 | } 22 | 23 | @Override 24 | public GlacialMacroState onTick(GlacialMacro macro) { 25 | 26 | if (Objects.equals(MightyMinerConfig.miningTool, "")) { 27 | macro.disable("Mining tool is not set in the Mighty Miner config"); 28 | return null; 29 | } 30 | 31 | SubLocation subLocation = GameStateHandler.getInstance().getCurrentSubLocation(); 32 | if (subLocation == SubLocation.DWARVEN_BASE_CAMP) { 33 | if (!InventoryUtil.areItemsInHotbar(macro.getNecessaryItems())) { 34 | macro.disable("Please put the following items in hotbar: " + InventoryUtil.getMissingItemsInHotbar(macro.getNecessaryItems())); 35 | return null; 36 | } 37 | 38 | log("Player is in a valid location. Initialising stats"); 39 | return new GettingStatsState(); 40 | } else { 41 | log("Player is not at Dwarven Base Camp. Teleporting..."); 42 | return new TeleportingState(new StartingState()); 43 | } 44 | } 45 | 46 | @Override 47 | public void onEnd(GlacialMacro macro) { 48 | log("Exiting starting state"); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/macro/impl/GlacialMacro/states/TeleportingState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.macro.impl.GlacialMacro.states; 2 | 3 | import com.jelly.mightyminerv2.feature.impl.AutoWarp; 4 | import com.jelly.mightyminerv2.macro.impl.GlacialMacro.GlacialMacro; 5 | import com.jelly.mightyminerv2.util.helper.Clock; 6 | import com.jelly.mightyminerv2.util.helper.location.SubLocation; 7 | 8 | public class TeleportingState implements GlacialMacroState { 9 | private final GlacialMacroState nextState; 10 | private int retries = 0; 11 | private final Clock timeout = new Clock(); 12 | 13 | // The state to transition to upon successful warp 14 | public TeleportingState(GlacialMacroState nextState) { 15 | this.nextState = nextState; 16 | } 17 | 18 | @Override 19 | public void onStart(GlacialMacro macro) { 20 | log("Attempting to warp to Dwarven Base Camp."); 21 | AutoWarp.getInstance().start(null, SubLocation.DWARVEN_BASE_CAMP); 22 | timeout.schedule(15000); // 15 second timeout for warping 23 | } 24 | 25 | @Override 26 | public GlacialMacroState onTick(GlacialMacro macro) { 27 | if (AutoWarp.getInstance().isRunning()) { 28 | if (timeout.passed()) { 29 | logError("AutoWarp timed out."); 30 | AutoWarp.getInstance().stop(); 31 | return handleFailure(); 32 | } 33 | return this; // Stay in this state while warping 34 | } 35 | 36 | if (AutoWarp.getInstance().hasSucceeded()) { 37 | log("Successfully warped."); 38 | return nextState; 39 | } else { 40 | logError("AutoWarp failed. Reason: " + AutoWarp.getInstance().getFailReason()); 41 | return handleFailure(); 42 | } 43 | } 44 | 45 | private GlacialMacroState handleFailure() { 46 | if (++retries > 3) { 47 | return new ErrorHandlingState("Failed to warp to the Glacite Tunnels after 3 attempts."); 48 | } 49 | log("Retrying warp (" + retries + "/3)..."); 50 | AutoWarp.getInstance().start(null, SubLocation.DWARVEN_BASE_CAMP); 51 | timeout.schedule(15000); 52 | return this; 53 | } 54 | 55 | @Override 56 | public void onEnd(GlacialMacro macro) { 57 | if (AutoWarp.getInstance().isRunning()) { 58 | AutoWarp.getInstance().stop(); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/macro/impl/RouteMiner/states/GettingStatsState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.macro.impl.RouteMiner.states; 2 | 3 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 4 | import com.jelly.mightyminerv2.feature.impl.AutoGetStats.AutoGetStats; 5 | import com.jelly.mightyminerv2.feature.impl.AutoGetStats.tasks.impl.MiningSpeedRetrievalTask; 6 | import com.jelly.mightyminerv2.feature.impl.AutoGetStats.tasks.impl.PickaxeAbilityRetrievalTask; 7 | import com.jelly.mightyminerv2.feature.impl.BlockMiner.BlockMiner; 8 | import com.jelly.mightyminerv2.macro.impl.GlacialMacro.GlacialMacro; 9 | import com.jelly.mightyminerv2.macro.impl.GlacialMacro.states.GlacialMacroState; 10 | import com.jelly.mightyminerv2.macro.impl.GlacialMacro.states.NewLobbyState; 11 | import com.jelly.mightyminerv2.macro.impl.GlacialMacro.states.PathfindingState; 12 | import com.jelly.mightyminerv2.macro.impl.RouteMiner.RouteMinerMacro; 13 | 14 | /** 15 | * This state is responsible for retrieving the mining speed and pickaxe ability 16 | * before proceeding to the mining state in the Route Miner Macro. 17 | */ 18 | public class GettingStatsState implements RouteMinerMacroState { 19 | 20 | private final AutoGetStats autoInventory = AutoGetStats.getInstance(); 21 | private MiningSpeedRetrievalTask miningSpeedTask; 22 | private PickaxeAbilityRetrievalTask pickaxeAbilityTask; 23 | 24 | @Override 25 | public void onStart(RouteMinerMacro macro) { 26 | log("Entering getting stats state"); 27 | miningSpeedTask = new MiningSpeedRetrievalTask(); 28 | pickaxeAbilityTask = new PickaxeAbilityRetrievalTask(); 29 | AutoGetStats.getInstance().startTask(pickaxeAbilityTask); 30 | AutoGetStats.getInstance().startTask(miningSpeedTask); 31 | } 32 | 33 | @Override 34 | public RouteMinerMacroState onTick(RouteMinerMacro macro) { 35 | if (AutoGetStats.getInstance().hasFinishedAllTasks()) { 36 | if (miningSpeedTask.getError() != null) { 37 | macro.disable("Failed to get stats with the following error: " + miningSpeedTask.getError()); 38 | return null; 39 | } 40 | 41 | if (pickaxeAbilityTask.getError() != null) { 42 | macro.disable("Failed to get pickaxe ability with the following error: " + pickaxeAbilityTask.getError()); 43 | return null; 44 | } 45 | 46 | macro.setMiningSpeed(miningSpeedTask.getResult()); 47 | macro.setPickaxeAbility(MightyMinerConfig.usePickaxeAbility ? pickaxeAbilityTask.getResult() : BlockMiner.PickaxeAbility.NONE); 48 | return new MovingState(); 49 | } else { 50 | return this; 51 | } 52 | 53 | } 54 | 55 | @Override 56 | public void onEnd(RouteMinerMacro macro) { 57 | autoInventory.stop(); 58 | log("Exiting getting stats state"); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/macro/impl/RouteMiner/states/MiningState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.macro.impl.RouteMiner.states; 2 | 3 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 4 | import com.jelly.mightyminerv2.feature.impl.BlockMiner.BlockMiner; 5 | import com.jelly.mightyminerv2.macro.impl.GlacialMacro.GlacialMacro; 6 | import com.jelly.mightyminerv2.macro.impl.RouteMiner.RouteMinerMacro; 7 | import com.jelly.mightyminerv2.util.InventoryUtil; 8 | import com.jelly.mightyminerv2.util.helper.MineableBlock; 9 | 10 | /** 11 | * This state is responsible for starting BlockMiner and detecting when to move to next waypoint 12 | * before proceeding to the moving state in the Route Miner Macro. 13 | */ 14 | public class MiningState implements RouteMinerMacroState { 15 | 16 | @Override 17 | public void onStart(RouteMinerMacro macro) { 18 | log("Entering Mining State"); 19 | InventoryUtil.holdItem(MightyMinerConfig.miningTool); 20 | startMining(macro); 21 | } 22 | 23 | @Override 24 | public RouteMinerMacroState onTick(RouteMinerMacro macro) { 25 | if (BlockMiner.getInstance().getError() == BlockMiner.BlockMinerError.NOT_ENOUGH_BLOCKS) { 26 | BlockMiner.getInstance().stop(); 27 | macro.setRouteIndex(macro.getRouteIndex() + 1); 28 | return new MovingState(); 29 | } 30 | 31 | return this; 32 | } 33 | 34 | private void startMining(RouteMinerMacro macro) { 35 | MineableBlock[] blocksToMine = macro.getBlocksToMine(); 36 | 37 | if (blocksToMine.length == 0) { 38 | macro.disable("No targets provided in configuration."); 39 | return; 40 | } 41 | 42 | BlockMiner.getInstance().start( 43 | blocksToMine, 44 | macro.getMiningSpeed(), 45 | macro.getPickaxeAbility(), 46 | macro.getBlockPriority(), 47 | MightyMinerConfig.miningTool 48 | ); 49 | } 50 | 51 | @Override 52 | public void onEnd(RouteMinerMacro macro) { 53 | log("Exiting Mining State"); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/macro/impl/RouteMiner/states/RouteMinerMacroState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.macro.impl.RouteMiner.states; 2 | 3 | import com.jelly.mightyminerv2.macro.impl.RouteMiner.RouteMinerMacro; 4 | import com.jelly.mightyminerv2.util.Logger; 5 | import net.minecraft.client.Minecraft; 6 | 7 | /** 8 | * Interface representing the state of the RouteMiner Macro. 9 | * Each state defines its own behavior for starting, ticking, and ending. 10 | */ 11 | public interface RouteMinerMacroState { 12 | 13 | void onStart(RouteMinerMacro macro); 14 | 15 | RouteMinerMacroState onTick(RouteMinerMacro macro); 16 | 17 | void onEnd(RouteMinerMacro macro); 18 | 19 | default void log(String message) { 20 | System.out.println("[" + this.getClass().getSimpleName() + "] " + message); 21 | } 22 | 23 | default void logError(String message) { 24 | System.out.println("[" + this.getClass().getSimpleName() + "] ERROR: " + message); 25 | } 26 | 27 | default void send(String message) { 28 | Logger.addMessage("[" + this.getClass().getSimpleName() + "] " + message); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/macro/impl/RouteMiner/states/StartingState.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.macro.impl.RouteMiner.states; 2 | 3 | import com.jelly.mightyminerv2.macro.impl.RouteMiner.RouteMinerMacro; 4 | import com.jelly.mightyminerv2.util.InventoryUtil; 5 | 6 | /** 7 | * The initial state of the Route Miner Macro. 8 | * This state checks if the player has the proper items to start macro. 9 | * If not, it will disable itself. 10 | */ 11 | public class StartingState implements RouteMinerMacroState { 12 | 13 | @Override 14 | public void onStart(RouteMinerMacro macro) { 15 | log("Entering Starting State"); 16 | } 17 | 18 | @Override 19 | public RouteMinerMacroState onTick(RouteMinerMacro macro) { 20 | if (!InventoryUtil.areItemsInHotbar(macro.getNecessaryItems())) { 21 | macro.disable("Please put the following items in hotbar: " + InventoryUtil.getMissingItemsInHotbar(macro.getNecessaryItems())); 22 | return null; 23 | } 24 | 25 | return new GettingStatsState(); 26 | } 27 | 28 | @Override 29 | public void onEnd(RouteMinerMacro macro) { 30 | log("Exiting Starting State"); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/mixin/FML/MixinFMLHandshakeMessage.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.mixin.fml; 2 | 3 | import com.jelly.mightyminerv2.MightyMiner; 4 | import net.minecraft.client.Minecraft; 5 | import net.minecraftforge.fml.common.ModContainer; 6 | import net.minecraftforge.fml.common.network.handshake.FMLHandshakeMessage; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 12 | 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | @Mixin(value = FMLHandshakeMessage.ModList.class, remap = false, priority = Integer.MAX_VALUE) 17 | public abstract class MixinFMLHandshakeMessage { 18 | @Shadow(remap = false) 19 | private Map modTags; 20 | 21 | @Inject(method = "(Ljava/util/List;)V", at = @At("RETURN"), remap = false) 22 | private void init(List modList, CallbackInfo ci) { 23 | if (Minecraft.getMinecraft().isIntegratedServerRunning()) return; 24 | modTags.keySet().removeIf(s -> s.contains(MightyMiner.modid)); 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/mixin/client/EntityPlayerSPAccessor.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.mixin.client; 2 | 3 | import net.minecraft.client.entity.EntityPlayerSP; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.gen.Accessor; 6 | 7 | @Mixin(EntityPlayerSP.class) 8 | public interface EntityPlayerSPAccessor { 9 | @Accessor 10 | float getLastReportedYaw(); 11 | 12 | @Accessor 13 | float getLastReportedPitch(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/mixin/client/MinecraftAccessor.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.mixin.client; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraft.util.Timer; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | import org.spongepowered.asm.mixin.gen.Invoker; 8 | 9 | @Mixin(Minecraft.class) 10 | public interface MinecraftAccessor { 11 | @Accessor("timer") 12 | Timer getTimer(); 13 | 14 | @Accessor("leftClickCounter") 15 | void setLeftClickCounter(int leftClickCounter); 16 | 17 | @Accessor("rightClickDelayTimer") 18 | int getRightClickDelayTimer(); 19 | 20 | @Accessor("rightClickDelayTimer") 21 | void setRightClickDelayTimer(int rightClickDelayTimer); 22 | 23 | @Invoker("clickMouse") 24 | void leftClick(); 25 | 26 | @Invoker("rightClickMouse") 27 | void rightClick(); 28 | 29 | @Invoker("middleClickMouse") 30 | void middleClick(); 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/mixin/client/MixinBlockStainedGlassPane.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.mixin.client; 2 | 3 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 4 | import net.minecraft.block.BlockPane; 5 | import net.minecraft.block.BlockStainedGlassPane; 6 | import net.minecraft.block.material.Material; 7 | import net.minecraft.util.BlockPos; 8 | import net.minecraft.world.IBlockAccess; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | 11 | @Mixin({BlockStainedGlassPane.class}) 12 | public abstract class MixinBlockStainedGlassPane extends BlockPane { 13 | 14 | protected MixinBlockStainedGlassPane(Material materialIn, boolean canDrop) { 15 | super(materialIn, canDrop); 16 | } 17 | 18 | public void setBlockBoundsBasedOnState(IBlockAccess worldIn, BlockPos pos) { 19 | if (MightyMinerConfig.miscFullBlock) { 20 | this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); 21 | } else { 22 | super.setBlockBoundsBasedOnState(worldIn, pos); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/mixin/client/MixinChunk.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.mixin.client; 2 | 3 | import com.jelly.mightyminerv2.event.BlockChangeEvent; 4 | import net.minecraft.block.state.IBlockState; 5 | import net.minecraft.util.BlockPos; 6 | import net.minecraft.world.chunk.Chunk; 7 | import net.minecraftforge.common.MinecraftForge; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 12 | 13 | @Mixin(Chunk.class) 14 | public class MixinChunk { 15 | @Inject(method = "setBlockState", at = @At("RETURN")) 16 | public void setBlockState(BlockPos pos, IBlockState state, CallbackInfoReturnable cir) { 17 | final IBlockState old = cir.getReturnValue(); 18 | if (old == null || state == old) return; 19 | MinecraftForge.EVENT_BUS.post(new BlockChangeEvent(pos, old, state)); 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/mixin/client/MixinChunkProviderClient.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.mixin.client; 2 | 3 | import com.jelly.mightyminerv2.util.IChunkProviderClient; 4 | import net.minecraft.client.multiplayer.ChunkProviderClient; 5 | import net.minecraft.util.LongHashMap; 6 | import net.minecraft.world.chunk.Chunk; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | 10 | import java.util.List; 11 | 12 | @Mixin(ChunkProviderClient.class) 13 | public class MixinChunkProviderClient implements IChunkProviderClient { 14 | 15 | @Shadow 16 | private LongHashMap chunkMapping; 17 | 18 | @Shadow 19 | private List chunkListing; 20 | 21 | @Override 22 | public LongHashMap chunkMapping() { 23 | return chunkMapping; 24 | } 25 | 26 | @Override 27 | public List chunkListing() { 28 | return chunkListing; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/mixin/client/MixinEntityLivingBase.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.mixin.client; 2 | 3 | import com.jelly.mightyminerv2.util.StrafeUtil; 4 | import net.minecraft.client.entity.EntityPlayerSP; 5 | import net.minecraft.entity.Entity; 6 | import net.minecraft.entity.EntityLivingBase; 7 | import net.minecraft.world.World; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.Shadow; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Redirect; 12 | 13 | // From Baritone <3 14 | // Todo: Consider Adding a rotation check To disable omnisprint from within 15 | @Mixin(EntityLivingBase.class) 16 | public abstract class MixinEntityLivingBase extends Entity { 17 | 18 | @Shadow 19 | public float rotationYawHead; 20 | 21 | public MixinEntityLivingBase(World worldIn) { 22 | super(worldIn); 23 | } 24 | 25 | @Redirect( 26 | method = "jump", 27 | at = @At( 28 | value = "FIELD", 29 | target = "net/minecraft/entity/EntityLivingBase.rotationYaw:F" 30 | ) 31 | ) 32 | private float overrideYaw(EntityLivingBase self) { 33 | if (self instanceof EntityPlayerSP && StrafeUtil.shouldEnable()) { 34 | return StrafeUtil.yaw; 35 | } 36 | return self.rotationYaw; 37 | } 38 | 39 | @Redirect( 40 | method = "moveEntityWithHeading", 41 | at = @At( 42 | value = "INVOKE", 43 | target = "Lnet/minecraft/entity/EntityLivingBase;moveFlying(FFF)V" 44 | ) 45 | ) 46 | public void moveRelative(EntityLivingBase instance, float s, float f, float fr) { 47 | if (!StrafeUtil.shouldEnable()) { 48 | this.moveFlying(s, f, fr); 49 | return; 50 | } 51 | 52 | final float originalYaw = this.rotationYaw; 53 | this.rotationYaw = StrafeUtil.yaw; 54 | 55 | this.moveFlying(s, f, fr); 56 | 57 | this.rotationYaw = originalYaw; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/mixin/client/MixinEntityPlayerSP.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.mixin.client; 2 | 3 | import com.jelly.mightyminerv2.event.MotionUpdateEvent; 4 | import com.jelly.mightyminerv2.macro.MacroManager; 5 | import com.mojang.authlib.GameProfile; 6 | import net.minecraft.client.entity.AbstractClientPlayer; 7 | import net.minecraft.client.entity.EntityPlayerSP; 8 | import net.minecraft.entity.item.EntityItem; 9 | import net.minecraft.world.World; 10 | import net.minecraftforge.common.MinecraftForge; 11 | import org.objectweb.asm.Opcodes; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.Unique; 14 | import org.spongepowered.asm.mixin.injection.At; 15 | import org.spongepowered.asm.mixin.injection.Inject; 16 | import org.spongepowered.asm.mixin.injection.Redirect; 17 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 18 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 19 | 20 | @Mixin(value = EntityPlayerSP.class, priority = Integer.MAX_VALUE) 21 | public abstract class MixinEntityPlayerSP extends AbstractClientPlayer { 22 | 23 | @Unique 24 | float mightyMinerv2$serverYaw = 0f; 25 | @Unique 26 | float mightyMinerv2$serverPitch = 0f; 27 | public MixinEntityPlayerSP(World worldIn, GameProfile playerProfile) { 28 | super(worldIn, playerProfile); 29 | } 30 | 31 | @Inject(method = "onUpdateWalkingPlayer", at = @At("HEAD")) 32 | public void onUpdateWalkingPlayerPRE(CallbackInfo ci) { 33 | MotionUpdateEvent event = new MotionUpdateEvent(this.rotationYaw, this.rotationPitch); 34 | MinecraftForge.EVENT_BUS.post(event); 35 | this.mightyMinerv2$serverYaw = event.yaw; 36 | this.mightyMinerv2$serverPitch = event.pitch; 37 | } 38 | 39 | @Redirect(method = "onUpdateWalkingPlayer", at = @At(value = "FIELD", target = "Lnet/minecraft/client/entity/EntityPlayerSP;rotationYaw:F", opcode = Opcodes.GETFIELD)) 40 | public float onUpdateWalkingPlayerYaw(EntityPlayerSP instance) { 41 | return this.mightyMinerv2$serverYaw; 42 | } 43 | 44 | @Redirect(method = "onUpdateWalkingPlayer", at = @At(value = "FIELD", target = "Lnet/minecraft/client/entity/EntityPlayerSP;rotationPitch:F", opcode = Opcodes.GETFIELD)) 45 | public float onUpdateWalkingPlayerPitch(EntityPlayerSP instance) { 46 | return this.mightyMinerv2$serverPitch; 47 | } 48 | 49 | @Inject(method = "dropOneItem", at = @At("HEAD"), cancellable = true) 50 | public void onDropOneItem(boolean dropAll, CallbackInfoReturnable cir) { 51 | if (MacroManager.getInstance().isRunning()) { 52 | cir.setReturnValue(null); 53 | cir.cancel(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/mixin/client/MixinMinecraft.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.mixin.client; 2 | 3 | import com.jelly.mightyminerv2.macro.MacroManager; 4 | import net.minecraft.client.Minecraft; 5 | import net.minecraft.client.entity.EntityPlayerSP; 6 | import net.minecraft.client.settings.KeyBinding; 7 | import org.lwjgl.opengl.Display; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.Shadow; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Redirect; 12 | 13 | @Mixin(Minecraft.class) 14 | public class MixinMinecraft { 15 | 16 | @Shadow 17 | public EntityPlayerSP thePlayer; 18 | 19 | @Redirect(method = "runTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/settings/KeyBinding;isPressed()Z", ordinal = 2)) 20 | public boolean isPressed(KeyBinding instance) { 21 | return instance.isKeyDown() && !MacroManager.getInstance().isRunning(); 22 | } 23 | 24 | @Redirect(method = "setIngameFocus", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/Display;isActive()Z", remap = false)) 25 | public boolean isActive() { 26 | if (MacroManager.getInstance().isRunning()) { 27 | return true; 28 | } 29 | return Display.isActive(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/mixin/client/MixinScoreboard.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.mixin.client; 2 | 3 | import net.minecraft.scoreboard.ScoreObjective; 4 | import net.minecraft.scoreboard.ScorePlayerTeam; 5 | import net.minecraft.scoreboard.Scoreboard; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.Shadow; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.Redirect; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 13 | 14 | import java.util.Map; 15 | 16 | // Patcher's fix for the scoreboard log spam 17 | @Mixin(Scoreboard.class) 18 | public abstract class MixinScoreboard { 19 | @Shadow 20 | public abstract ScorePlayerTeam getTeam(String p_96508_1_); 21 | 22 | @Inject(method = "removeTeam", at = @At("HEAD"), cancellable = true) 23 | private void patcher$checkIfTeamIsNull(ScorePlayerTeam team, CallbackInfo ci) { 24 | if (team == null) ci.cancel(); 25 | } 26 | 27 | @Redirect(method = "removeTeam", at = @At(value = "INVOKE", target = "Ljava/util/Map;remove(Ljava/lang/Object;)Ljava/lang/Object;", ordinal = 0, remap = false)) 28 | private V patcher$checkIfRegisteredNameIsNull(Map instance, K o) { 29 | if (o != null) return instance.remove(o); 30 | return null; 31 | } 32 | 33 | @Inject(method = "removeObjective", at = @At("HEAD"), cancellable = true) 34 | private void patcher$checkIfObjectiveIsNull(ScoreObjective objective, CallbackInfo ci) { 35 | if (objective == null) ci.cancel(); 36 | } 37 | 38 | @Redirect(method = "removeObjective", at = @At(value = "INVOKE", target = "Ljava/util/Map;remove(Ljava/lang/Object;)Ljava/lang/Object;", ordinal = 0, remap = false)) 39 | private V patcher$checkIfNameIsNull(Map instance, K o) { 40 | if (o != null) return instance.remove(o); 41 | return null; 42 | } 43 | 44 | @Inject(method = "createTeam", at = @At(value = "CONSTANT", args = "stringValue=A team with the name '"), cancellable = true) 45 | private void patcher$returnExistingTeam(String name, CallbackInfoReturnable cir) { 46 | cir.setReturnValue(this.getTeam(name)); 47 | } 48 | 49 | @Inject(method = "removePlayerFromTeam", at = @At(value = "CONSTANT", args = "stringValue=Player is either on another team or not on any team. Cannot remove from team '"), cancellable = true) 50 | private void patcher$silenceException(CallbackInfo ci) { 51 | ci.cancel(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/mixin/client/MixinSoundManager.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.mixin.client; 2 | 3 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 4 | import com.jelly.mightyminerv2.failsafe.FailsafeManager; 5 | import com.jelly.mightyminerv2.macro.MacroManager; 6 | import net.minecraft.client.audio.ISound; 7 | import net.minecraft.client.audio.SoundCategory; 8 | import net.minecraft.client.audio.SoundManager; 9 | import net.minecraft.client.audio.SoundPoolEntry; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 14 | 15 | @Mixin(SoundManager.class) 16 | public class MixinSoundManager { 17 | @Inject(method = "getNormalizedVolume", at = @At("RETURN"), cancellable = true) 18 | private void getNormalizedVolume(ISound sound, SoundPoolEntry entry, SoundCategory category, CallbackInfoReturnable cir) { 19 | if (MacroManager.getInstance().isRunning() && MightyMinerConfig.muteGame && FailsafeManager.getInstance().emergencyQueue.isEmpty() && !FailsafeManager.getInstance().triggeredFailsafe.isPresent()) { 20 | cir.setReturnValue(0f); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/mixin/gui/MixinGuiContainer.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.mixin.gui; 2 | 3 | import com.jelly.mightyminerv2.macro.MacroManager; 4 | import net.minecraft.client.gui.inventory.GuiContainer; 5 | import net.minecraft.inventory.Slot; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 10 | 11 | @Mixin(GuiContainer.class) 12 | public abstract class MixinGuiContainer { 13 | 14 | @Inject(method = "handleMouseClick", at = @At("HEAD"), cancellable = true) 15 | public void handleMouseClick(Slot slotIn, int slotId, int clickedButton, int clickType, CallbackInfo ci) { 16 | if (MacroManager.getInstance().isRunning()) { 17 | ci.cancel(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/mixin/gui/MixinInventoryPlayer.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.mixin.gui; 2 | 3 | import com.jelly.mightyminerv2.macro.MacroManager; 4 | import net.minecraft.entity.player.InventoryPlayer; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 9 | 10 | @Mixin(InventoryPlayer.class) 11 | public abstract class MixinInventoryPlayer { 12 | 13 | @Inject(method = "changeCurrentItem", at = @At("HEAD"), cancellable = true) 14 | public void changeCurrentItem(int direction, CallbackInfo ci) { 15 | if (MacroManager.getInstance().isRunning()) { 16 | ci.cancel(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/mixin/render/MixinModelBiped.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.mixin.render; 2 | 3 | import com.jelly.mightyminerv2.handler.RotationHandler; 4 | import com.jelly.mightyminerv2.mixin.client.EntityPlayerSPAccessor; 5 | import com.jelly.mightyminerv2.mixin.client.MinecraftAccessor; 6 | import com.jelly.mightyminerv2.util.AngleUtil; 7 | import com.jelly.mightyminerv2.util.helper.RotationConfiguration; 8 | import net.minecraft.client.Minecraft; 9 | import net.minecraft.client.model.ModelBiped; 10 | import net.minecraft.client.model.ModelRenderer; 11 | import net.minecraft.entity.Entity; 12 | import net.minecraft.util.MathHelper; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.Shadow; 15 | import org.spongepowered.asm.mixin.Unique; 16 | import org.spongepowered.asm.mixin.injection.At; 17 | import org.spongepowered.asm.mixin.injection.Inject; 18 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 19 | 20 | @Mixin(value = ModelBiped.class, priority = Integer.MAX_VALUE) 21 | public class MixinModelBiped { 22 | 23 | @Unique 24 | private final Minecraft mightyMinerV2$mc = Minecraft.getMinecraft(); 25 | @Shadow 26 | public ModelRenderer bipedHead; 27 | 28 | @Inject(method = {"setRotationAngles"}, at = {@At(value = "FIELD", target = "Lnet/minecraft/client/model/ModelBiped;swingProgress:F")}) 29 | public void onSetRotationAngles(float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch, float scaleFactor, Entity entityIn, CallbackInfo ci) { 30 | if (!RotationHandler.getInstance().isEnabled() || RotationHandler.getInstance().getConfiguration() != null && RotationHandler.getInstance().getConfiguration().rotationType() != RotationConfiguration.RotationType.SERVER || entityIn == null || !entityIn.equals(mightyMinerV2$mc.thePlayer)) { 31 | return; 32 | } 33 | 34 | this.bipedHead.rotateAngleX = ((EntityPlayerSPAccessor) entityIn).getLastReportedPitch() / 57.295776f; 35 | float partialTicks = ((MinecraftAccessor) mightyMinerV2$mc).getTimer().renderPartialTicks; 36 | float yawOffset = mightyMinerV2$mc.thePlayer.renderYawOffset + AngleUtil.normalizeAngle(mightyMinerV2$mc.thePlayer.renderYawOffset - mightyMinerV2$mc.thePlayer.prevRenderYawOffset) * partialTicks; 37 | float calcNetHead = MathHelper.wrapAngleTo180_float(((EntityPlayerSPAccessor) entityIn).getLastReportedYaw() - yawOffset); 38 | this.bipedHead.rotateAngleY = calcNetHead / 57.295776f; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/util/IChunkProviderClient.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.util; 2 | 3 | import net.minecraft.util.LongHashMap; 4 | import net.minecraft.world.chunk.Chunk; 5 | 6 | import java.util.List; 7 | 8 | public interface IChunkProviderClient { 9 | LongHashMap chunkMapping(); 10 | 11 | List chunkListing(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/util/Logger.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.util; 2 | 3 | import cc.polyfrost.oneconfig.utils.Notifications; 4 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 5 | import net.minecraft.client.Minecraft; 6 | import net.minecraft.util.ChatComponentText; 7 | import net.minecraft.util.EnumChatFormatting; 8 | import net.minecraft.util.StringUtils; 9 | 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | public abstract class Logger { 14 | 15 | protected static final Minecraft mc = Minecraft.getMinecraft(); 16 | private static final Map lastMessages = new HashMap<>(); 17 | 18 | public static void addMessage(String text) { 19 | if (mc.thePlayer == null || mc.theWorld == null) { 20 | System.out.println("MightyMiner " + StringUtils.stripControlCodes(text)); 21 | } else { 22 | mc.thePlayer.addChatMessage(new ChatComponentText(text)); 23 | } 24 | } 25 | 26 | public static void sendMessage(final String message) { 27 | addMessage(formatPrefix("§bMighty Miner", message)); 28 | } 29 | 30 | public static void sendWarning(final String message) { 31 | addMessage("§c§l[WARNING] §8» §e" + message); 32 | } 33 | 34 | public static void sendError(final String message) { 35 | addMessage("§l§4§kZ§r§l§4[Mighty Miner]§kH§r §8» §c" + message); 36 | } 37 | 38 | public static void sendNote(final String message) { 39 | sendMessage(message); 40 | } 41 | 42 | public static void sendLog(final String message) { 43 | if (isDuplicate("debug", message)) return; 44 | 45 | if (MightyMinerConfig.debugMode && mc.thePlayer != null) { 46 | addMessage("§l§2[Mighty Miner] §8» §7" + message); 47 | } else { 48 | System.out.println("[Mighty Miner] " + message); 49 | } 50 | } 51 | 52 | public static void sendNotification(String title, String message, Long duration) { 53 | if (isDuplicate("notification", message)) return; 54 | Notifications.INSTANCE.send(title, message, duration); 55 | } 56 | 57 | private static boolean isDuplicate(String type, String message) { 58 | if (lastMessages.containsKey(type) && lastMessages.get(type).equals(message)) { 59 | return true; 60 | } 61 | lastMessages.put(type, message); 62 | return false; 63 | } 64 | 65 | private static String formatPrefix(String prefix, String message) { 66 | return EnumChatFormatting.RED + "[" + EnumChatFormatting.BLUE + prefix + EnumChatFormatting.RED + "] §8» §e" + message; 67 | } 68 | 69 | public abstract String getName(); 70 | 71 | protected void log(String message) { 72 | sendLog(formatMessage(message)); 73 | } 74 | 75 | protected void send(String message) { 76 | sendMessage(formatMessage(message)); 77 | } 78 | 79 | protected void error(String message) { 80 | sendError(formatMessage(message)); 81 | } 82 | 83 | protected void warn(String message) { 84 | sendWarning(formatMessage(message)); 85 | } 86 | 87 | protected void note(String message) { 88 | sendNote(formatMessage(message)); 89 | } 90 | 91 | protected String formatMessage(String message) { 92 | return "[" + getName() + "] " + message; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/util/PlayerUtil.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.util; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraft.entity.Entity; 5 | import net.minecraft.util.*; 6 | 7 | import java.util.Collections; 8 | import java.util.Comparator; 9 | import java.util.List; 10 | import java.util.function.Predicate; 11 | 12 | public class PlayerUtil { 13 | 14 | private static final Minecraft mc = Minecraft.getMinecraft(); 15 | 16 | // requires more testing 17 | public static BlockPos getBlockStandingOn() { 18 | // 0.25 = 3 layers of snow 19 | // if there is more than 3 layers of snow then i should consider that as a full block i guess 20 | // but there is no snow check in pathfinder so this will probably not work at all in snowy areas 21 | return new BlockPos(mc.thePlayer.posX, Math.ceil(mc.thePlayer.posY - 0.25) - 1, mc.thePlayer.posZ); 22 | } 23 | 24 | public static Vec3 getPlayerEyePos() { 25 | return mc.thePlayer.getPositionEyes(1f); 26 | } 27 | 28 | public static BlockPos getBlockStandingOnFloor() { 29 | return new BlockPos(mc.thePlayer.posX, Math.floor(mc.thePlayer.posY) - 1, mc.thePlayer.posZ); 30 | } 31 | 32 | public static Vec3 getNextTickPosition() { 33 | return mc.thePlayer.getPositionVector().addVector(mc.thePlayer.motionX, 0, mc.thePlayer.motionZ); 34 | } 35 | 36 | public static Vec3 getNextTickPosition(float mult) { 37 | return mc.thePlayer.getPositionVector().addVector(mc.thePlayer.motionX * mult, 0, mc.thePlayer.motionZ * mult); 38 | } 39 | 40 | public static Entity getEntityCuttingOtherEntity(Entity e) { 41 | return getEntityCuttingOtherEntity(e, entity -> true); 42 | } 43 | 44 | public static Entity getEntityCuttingOtherEntity(Entity e, Predicate predicate) { 45 | List possible = mc.theWorld.getEntitiesInAABBexcluding(e, e.getEntityBoundingBox().expand(0.3D, 2.0D, 0.3D), a -> { 46 | boolean flag1 = (!a.isDead && !a.equals(mc.thePlayer)); 47 | boolean flag2 = !(a instanceof net.minecraft.entity.projectile.EntityFireball); 48 | boolean flag3 = !(a instanceof net.minecraft.entity.projectile.EntityFishHook); 49 | boolean flag4 = predicate.test(a); 50 | return flag1 && flag2 && flag3 && flag4; 51 | }); 52 | if (!possible.isEmpty()) { 53 | return Collections.min(possible, Comparator.comparing(e2 -> e2.getDistanceToEntity(e))); 54 | } 55 | return null; 56 | } 57 | 58 | public static boolean isPlayerSuffocating() { 59 | AxisAlignedBB playerBB = mc.thePlayer.getEntityBoundingBox().expand(-0.15, -0.15, -0.15); 60 | List collidingBoxes = mc.theWorld.getCollidingBoundingBoxes(mc.thePlayer, playerBB); 61 | return !collidingBoxes.isEmpty(); 62 | } 63 | 64 | public static EnumFacing getHorizontalFacing(float yaw) { 65 | return EnumFacing.getHorizontal(MathHelper.floor_double((double) (yaw * 4.0F / 360.0F) + 0.5) & 3); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/util/RaytracingUtil.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.util; 2 | 3 | import net.minecraft.client.Minecraft; 4 | import net.minecraft.entity.Entity; 5 | import net.minecraft.util.MovingObjectPosition; 6 | import net.minecraft.util.Vec3; 7 | 8 | import java.util.List; 9 | 10 | public class RaytracingUtil { 11 | 12 | private static final Minecraft mc = Minecraft.getMinecraft(); 13 | 14 | public static boolean canSeePoint(Vec3 point) { 15 | return canSeePoint(PlayerUtil.getPlayerEyePos(), point); 16 | } 17 | 18 | public static boolean canSeePoint(Vec3 from, Vec3 point) { 19 | final MovingObjectPosition result = raytrace(from, point); 20 | if (result == null) { 21 | return true; 22 | } 23 | 24 | final Vec3 r = result.hitVec; 25 | 26 | if (r == null) { 27 | return false; 28 | } 29 | 30 | return Math.abs(r.xCoord - point.xCoord) < 0.1f && Math.abs(r.yCoord - point.yCoord) < 0.1f && Math.abs(r.zCoord - point.zCoord) < 0.1f; 31 | } 32 | 33 | public static MovingObjectPosition raytraceTowards(Vec3 v1, Vec3 v2, double distance) { 34 | Vec3 normalized = v2.subtract(v1).normalize(); 35 | return raytrace(v1, v1.add(new Vec3(normalized.xCoord * distance, normalized.yCoord * distance, normalized.zCoord * distance))); 36 | } 37 | 38 | public static MovingObjectPosition raytrace(Vec3 v1, Vec3 v2) { 39 | final Vec3 v3 = v2.subtract(v1); 40 | final List entities = mc.theWorld.getEntitiesInAABBexcluding(mc.thePlayer, mc.thePlayer.getEntityBoundingBox().addCoord(v3.xCoord, v3.yCoord, v3.zCoord).expand(1.0, 1.0, 1.0), it -> it.isEntityAlive() && it.canBeCollidedWith()); 41 | 42 | for (Entity entity : entities) { 43 | final MovingObjectPosition intercept = entity.getEntityBoundingBox().expand(0.5, 0.5, 0.5).calculateIntercept(v1, v2); 44 | if (intercept != null) { 45 | return new MovingObjectPosition(entity, intercept.hitVec); 46 | } 47 | } 48 | 49 | return mc.theWorld.rayTraceBlocks(v1, v2, false, true, false); 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/util/ReflectionUtils.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.util; 2 | 3 | import net.minecraft.client.Minecraft; 4 | 5 | import java.lang.reflect.Field; 6 | import java.lang.reflect.Method; 7 | import java.nio.file.Path; 8 | import java.util.Arrays; 9 | 10 | public class ReflectionUtils { 11 | public static boolean invoke(Object object, String methodName) { 12 | try { 13 | final Method method = object.getClass().getDeclaredMethod(methodName); 14 | method.setAccessible(true); 15 | method.invoke(object); 16 | return true; 17 | } catch (Exception ignored) { 18 | } 19 | return false; 20 | } 21 | 22 | public static Object field(Object object, String name) { 23 | try { 24 | Field field = object.getClass().getDeclaredField(name); 25 | field.setAccessible(true); 26 | return field.get(object); 27 | } catch (Exception ignored) { 28 | } 29 | return null; 30 | } 31 | 32 | public static boolean hasPackageInstalled(String name) { 33 | Package[] packages = Package.getPackages(); 34 | 35 | for (Package pack : packages) { 36 | if (pack.getName().contains(name)) { 37 | return true; 38 | } 39 | } 40 | return false; 41 | } 42 | 43 | public static boolean hasModFile(String name) { 44 | Path modsDir = Minecraft.getMinecraft().mcDataDir.toPath().resolve("mods"); 45 | String[] modFiles = modsDir.toFile().list(); 46 | return modFiles != null && Arrays.stream(modFiles).anyMatch(modFile -> modFile.toLowerCase().contains(name.toLowerCase()) && !modFile.toLowerCase().endsWith(".disabled")); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/util/ScoreboardUtil.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.util; 2 | 3 | import com.jelly.mightyminerv2.event.UpdateScoreboardLineEvent; 4 | import net.minecraft.client.Minecraft; 5 | import net.minecraft.scoreboard.ScoreObjective; 6 | import net.minecraft.scoreboard.Scoreboard; 7 | import net.minecraft.util.StringUtils; 8 | import net.minecraftforge.client.event.ClientChatReceivedEvent; 9 | import net.minecraftforge.event.world.WorldEvent; 10 | import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; 11 | 12 | import java.util.*; 13 | import java.util.regex.Matcher; 14 | import java.util.regex.Pattern; 15 | 16 | public class ScoreboardUtil { 17 | 18 | private final Pattern coldRegex = Pattern.compile("Cold: -?(\\d{1,3})"); 19 | public static int cold = 0; 20 | 21 | private static final Minecraft mc = Minecraft.getMinecraft(); 22 | public static Map> scoreboard = new HashMap<>(); 23 | public static String[] scoreObjNames = new String[19]; 24 | 25 | public static List getScoreboard() { 26 | try { 27 | return new ArrayList<>(scoreboard.get(scoreObjNames[1]).values()); 28 | } catch (Exception ignored) { 29 | return Collections.emptyList(); 30 | } 31 | } 32 | 33 | public static String getScoreboardTitle() { 34 | if (mc.theWorld == null) { 35 | return ""; 36 | } 37 | Scoreboard scoreboard = mc.theWorld.getScoreboard(); 38 | if (scoreboard == null) { 39 | return ""; 40 | } 41 | 42 | ScoreObjective objective = scoreboard.getObjectiveInDisplaySlot(1); 43 | if (objective == null) { 44 | return ""; 45 | } 46 | 47 | return sanitizeString(objective.getDisplayName()); 48 | } 49 | 50 | public static String sanitizeString(String scoreboard) { 51 | char[] arr = scoreboard.toCharArray(); 52 | StringBuilder cleaned = new StringBuilder(); 53 | for (int i = 0; i < arr.length; i++) { 54 | char c = arr[i]; 55 | if (c >= 32 && c < 127) { 56 | cleaned.append(c); 57 | } 58 | if (c == 167) { 59 | i++; 60 | } 61 | } 62 | return cleaned.toString(); 63 | } 64 | 65 | @SubscribeEvent 66 | public void onWorldChange(WorldEvent.Load event) { 67 | cold = 0; 68 | } 69 | 70 | @SubscribeEvent 71 | public void onScoreboardUpdate(UpdateScoreboardLineEvent event) { 72 | if (event.getLine().contains("Cold:")) { 73 | Matcher coldMatcher = coldRegex.matcher(event.getLine()); 74 | if (coldMatcher.find()) cold = Integer.parseInt(coldMatcher.group(1)); 75 | else cold = 0; 76 | } 77 | 78 | List scoreboardLines = getScoreboard(); 79 | if (scoreboardLines.stream().noneMatch(line -> sanitizeString(line).contains("Cold:"))) cold = 0; 80 | } 81 | 82 | @SubscribeEvent(receiveCanceled = true) 83 | public void onChatDetection(ClientChatReceivedEvent event) { 84 | if (event.type != 0) return; 85 | if (event.message == null) return; 86 | 87 | String message = StringUtils.stripControlCodes(event.message.getUnformattedText()); 88 | if (message.contains("The warmth of the campfire reduced your") && message.contains("Cold")) { 89 | cold = 0; 90 | } 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/util/StrafeUtil.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.util; 2 | 3 | public final class StrafeUtil { 4 | 5 | public static volatile boolean enabled = false; 6 | public static volatile boolean forceStop = false; 7 | public static volatile float yaw = 0.0f; 8 | 9 | public static boolean shouldEnable() { 10 | return !forceStop && enabled; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/util/helper/Angle.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.util.helper; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Getter 7 | @Setter 8 | public class Angle { 9 | public float yaw; 10 | public float pitch; 11 | 12 | public Angle(float yaw, float pitch) { 13 | this.yaw = yaw; 14 | this.pitch = pitch; 15 | } 16 | 17 | public void setRotation(Angle rotation) { 18 | this.yaw = rotation.getYaw(); 19 | this.pitch = rotation.getPitch(); 20 | } 21 | 22 | public float getValue() { 23 | return Math.abs(this.yaw) + Math.abs(this.pitch); 24 | } 25 | 26 | public float lengthSqrt() { 27 | return (float) Math.sqrt(this.yaw * this.yaw + this.pitch * this.pitch); 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return "Rotation{" + "yaw=" + yaw + ", pitch=" + pitch + "}"; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/util/helper/Clock.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.util.helper; 2 | 3 | public class Clock { 4 | 5 | private long deltaTime; 6 | private boolean paused; 7 | private boolean scheduled; 8 | private long endTime; 9 | private long startTime; 10 | 11 | // stopwatch 12 | 13 | public void schedule(long milliseconds) { 14 | this.endTime = System.currentTimeMillis() + milliseconds; 15 | this.deltaTime = milliseconds; 16 | this.scheduled = true; 17 | this.paused = false; 18 | } 19 | 20 | public void schedule(double milliseconds) { 21 | this.endTime = (System.currentTimeMillis() + (long) milliseconds); 22 | this.deltaTime = (long) milliseconds; 23 | this.scheduled = true; 24 | this.paused = false; 25 | } 26 | 27 | public boolean passed() { 28 | return System.currentTimeMillis() >= endTime; 29 | } 30 | 31 | public void pause() { 32 | if (scheduled && !paused) { 33 | deltaTime = endTime - System.currentTimeMillis(); 34 | paused = true; 35 | } 36 | } 37 | 38 | public void resume() { 39 | if (scheduled && paused) { 40 | endTime = System.currentTimeMillis() + deltaTime; 41 | paused = false; 42 | } 43 | } 44 | 45 | public long getRemainingTime() { 46 | if (this.paused) { 47 | return deltaTime; 48 | } 49 | return Math.max(0, endTime - System.currentTimeMillis()); 50 | } 51 | 52 | public void start(boolean reset) { 53 | if (!this.scheduled || reset) { 54 | this.startTime = System.currentTimeMillis(); 55 | } else { 56 | this.resumeTimer(); 57 | } 58 | this.scheduled = true; 59 | } 60 | 61 | public void stop(boolean reset) { 62 | if (!this.scheduled || reset) { 63 | this.reset(); 64 | } else { 65 | this.pauseTimer(); 66 | } 67 | } 68 | 69 | public long getTimePassed() { 70 | if (!this.scheduled || this.paused) { 71 | return deltaTime; 72 | } 73 | return System.currentTimeMillis() - startTime; 74 | } 75 | 76 | public void pauseTimer() { 77 | if (scheduled && !paused) { 78 | deltaTime = System.currentTimeMillis() - startTime; 79 | paused = true; 80 | } 81 | } 82 | 83 | public void resumeTimer() { 84 | if (scheduled && paused) { 85 | startTime = System.currentTimeMillis() - deltaTime; 86 | paused = false; 87 | } 88 | } 89 | 90 | public void reset() { 91 | scheduled = false; 92 | paused = false; 93 | endTime = 0; 94 | deltaTime = 0; 95 | } 96 | 97 | public boolean isScheduled() { 98 | return this.scheduled; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/util/helper/MineableBlock.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.util.helper; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public enum MineableBlock { 7 | 8 | QUARTZ(155, 153), 9 | DIAMOND(57), 10 | EMERALD(133), 11 | REDSTONE( 152), 12 | LAPIS(22), 13 | GOLD(41), 14 | IRON(42), 15 | COAL(173), 16 | SULPHUR(19), 17 | HARDSTONE(1), 18 | TITANIUM(16385), 19 | GRAY_MITHRIL(28707, 37023), 20 | GREEN_MITHRIL(168, 4264, 8360), 21 | BLUE_MITHRIL(12323), 22 | OPAL(95, 160), 23 | JASPER(8287, 8352), 24 | TOPAZ(16544, 16479), 25 | AMBER(4191, 4256), 26 | SAPPHIRE(12383, 12448), 27 | JADE(20575, 20640), 28 | AMETHYST(41055, 41120), 29 | RUBY(57504, 57436), 30 | AQUAMARINE(45151, 45216), 31 | PERIDOT(53343, 53408), 32 | ONYX(61535, 61600), 33 | CITRINE(49247, 49312), 34 | GLACITE(174), 35 | UMBER(172, 32949, 49311), 36 | TUNGSTEN(4193, 82),; 37 | 38 | public final List stateIds; 39 | 40 | MineableBlock(int... values) { 41 | stateIds = new ArrayList<>(); 42 | for (int value : values) { 43 | stateIds.add(value); 44 | } 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/util/helper/Target.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.util.helper; 2 | 3 | import com.jelly.mightyminerv2.util.AngleUtil; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import lombok.experimental.Accessors; 7 | import net.minecraft.entity.Entity; 8 | import net.minecraft.util.BlockPos; 9 | import net.minecraft.util.Vec3; 10 | 11 | public class Target { 12 | 13 | private Vec3 vec; 14 | @Getter 15 | private Entity entity; 16 | @Getter 17 | private BlockPos blockPos; 18 | @Getter 19 | private Angle angle; 20 | @Accessors(fluent = true) 21 | @Setter 22 | @Getter 23 | private float additionalY = (float) (1 + Math.random()) * 0.75f; 24 | 25 | public Target(Vec3 vec) { 26 | this.vec = vec; 27 | } 28 | 29 | public Target(Entity entity) { 30 | this.entity = entity; 31 | } 32 | 33 | public Target(BlockPos blockPos) { 34 | this.blockPos = blockPos; 35 | } 36 | 37 | public Target(Angle angle) { 38 | this.angle = angle; 39 | } 40 | 41 | // Ensures Rotation Always Ends 42 | public Angle getTargetAngle() { 43 | if (blockPos != null) { 44 | return AngleUtil.getRotation(blockPos); 45 | } 46 | 47 | if (vec != null) { 48 | return AngleUtil.getRotation(vec); 49 | } 50 | 51 | if (entity != null) { 52 | return AngleUtil.getRotation(entity.getPositionVector().addVector(0, additionalY, 0)); 53 | } 54 | 55 | return angle; 56 | } 57 | 58 | @Override 59 | public String toString() { 60 | return "Vec3: " + this.vec + ", Ent: " + (this.entity != null ? this.entity.getEntityId() : "null") + ", Pos: " + this.blockPos + ", Angle: " + this.angle; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/util/helper/graph/Graph.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.util.helper.graph; 2 | 3 | import com.google.gson.annotations.Expose; 4 | 5 | import java.util.*; 6 | 7 | public class Graph { 8 | 9 | @Expose 10 | public final Map> map = new HashMap<>(); 11 | 12 | public void add(T source) { 13 | if (!map.isEmpty()) { 14 | return; 15 | } 16 | map.computeIfAbsent(source, k -> new ArrayList<>()); 17 | } 18 | 19 | public void add(T source, T target, boolean bidi) { 20 | map.computeIfAbsent(source, k -> new ArrayList<>()).add(target); 21 | map.computeIfAbsent(target, k -> new ArrayList<>()); 22 | if (bidi) { 23 | map.get(target).add(source); 24 | } 25 | } 26 | 27 | public void update(T old, T now) { 28 | if (old == null || now == null) { 29 | throw new IllegalArgumentException("Nodes cannot be null"); 30 | } 31 | 32 | List edges = map.remove(old); 33 | if (edges != null) { 34 | map.put(now, edges); 35 | } 36 | 37 | for (Map.Entry> entry : map.entrySet()) { 38 | List updatedEdges = new ArrayList<>(); 39 | for (T edge : entry.getValue()) { 40 | if (edge.equals(old)) { 41 | updatedEdges.add(now); 42 | } else { 43 | updatedEdges.add(edge); 44 | } 45 | } 46 | map.put(entry.getKey(), updatedEdges); 47 | } 48 | } 49 | 50 | public void remove(T node) { 51 | if (map.remove(node) == null) { 52 | return; 53 | } 54 | 55 | for (T key : map.keySet()) { 56 | map.get(key).removeIf(edge -> edge.equals(node)); 57 | } 58 | } 59 | 60 | // Breadth First Search - Our graph is small enough so it finds path instantly. not worth using a star and wasting so much memory for that 61 | public List findPath(T start, T end) { 62 | 63 | if (start == null || end == null || !map.containsKey(start) || !map.containsKey(end)) { 64 | return new ArrayList<>(); 65 | } 66 | 67 | Queue queue = new LinkedList<>(); 68 | Set visited = new HashSet<>(); 69 | HashMap parent = new HashMap(); 70 | 71 | queue.add(start); 72 | visited.add(start); 73 | parent.put(start, null); 74 | 75 | while (!queue.isEmpty()) { 76 | T curr = queue.poll(); 77 | if (curr.equals(end)) { 78 | LinkedList path = new LinkedList<>(); 79 | for (T at = end; at != null; at = parent.get(at)) { 80 | path.addFirst(at); 81 | } 82 | return path; 83 | } 84 | 85 | for (T neighbour : map.get(curr)) { 86 | if (!visited.contains(neighbour)) { 87 | queue.offer(neighbour); 88 | visited.add(neighbour); 89 | parent.put(neighbour, curr); 90 | } 91 | } 92 | } 93 | return new ArrayList<>(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/util/helper/graph/GraphSerializer.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.util.helper.graph; 2 | 3 | import com.google.common.reflect.TypeToken; 4 | import com.google.gson.*; 5 | import com.jelly.mightyminerv2.util.helper.route.RouteWaypoint; 6 | import com.jelly.mightyminerv2.util.helper.route.WaypointType; 7 | 8 | import java.lang.reflect.Type; 9 | import java.util.List; 10 | import java.util.Map.Entry; 11 | 12 | public class GraphSerializer implements JsonSerializer>, JsonDeserializer> { 13 | 14 | @Override 15 | public JsonElement serialize(Graph src, Type typeOfSrc, JsonSerializationContext context) { 16 | JsonObject res = new JsonObject(); 17 | JsonObject map = new JsonObject(); 18 | 19 | for (Entry> entry : src.map.entrySet()) { 20 | RouteWaypoint waypoint = entry.getKey(); 21 | String keyString = waypoint.getX() + "," + waypoint.getY() + "," + waypoint.getZ() + "," + waypoint.getTransportMethod().name(); 22 | 23 | JsonElement valueElement = context.serialize(entry.getValue()); 24 | map.add(keyString, valueElement); 25 | } 26 | 27 | res.add("map", map); 28 | return res; 29 | } 30 | 31 | @Override 32 | @SuppressWarnings("unchecked") 33 | public Graph deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 34 | Graph graph = new Graph<>(); 35 | JsonObject map = json.getAsJsonObject().getAsJsonObject("map"); 36 | 37 | for (Entry entry : map.entrySet()) { 38 | try { 39 | // The key is a string like "33,119,419,WALK" so we need to manually parse it into RouteWaypoint 40 | String[] keyParts = entry.getKey().split(","); 41 | if (keyParts.length != 4) { 42 | throw new JsonParseException("Invalid RouteWaypoint key format: " + entry.getKey()); 43 | } 44 | 45 | int x = Integer.parseInt(keyParts[0]); 46 | int y = Integer.parseInt(keyParts[1]); 47 | int z = Integer.parseInt(keyParts[2]); 48 | WaypointType transportMethod = WaypointType.valueOf(keyParts[3]); 49 | RouteWaypoint key = new RouteWaypoint(x, y, z, transportMethod); 50 | 51 | List value = context.deserialize(entry.getValue(), new TypeToken>() { 52 | }.getType()); 53 | 54 | graph.map.put(key, value); 55 | } catch (JsonParseException | NumberFormatException e) { 56 | System.out.println("Error deserializing entry for key: " + entry.getKey()); 57 | e.printStackTrace(); 58 | } 59 | } 60 | 61 | return graph; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/util/helper/heap/HeapNode.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.util.helper.heap; 2 | 3 | public class HeapNode { 4 | public final T nodeVal; 5 | public final double nodeCost; 6 | 7 | public HeapNode(final T nodeVal, final double nodeCost) { 8 | this.nodeVal = nodeVal; 9 | this.nodeCost = nodeCost; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/util/helper/heap/MinHeap.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.util.helper.heap; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | // Starts from 1 8 | public class MinHeap { 9 | 10 | private HeapNode[] items; 11 | private int size; 12 | private int capacity; 13 | 14 | public MinHeap(int capacity) { 15 | this.capacity = capacity; 16 | this.items = new HeapNode[this.capacity]; 17 | this.size = 0; 18 | } 19 | 20 | public T poll() { 21 | HeapNode root = items[1]; 22 | items[1] = items[size]; 23 | items[size] = null; 24 | size--; 25 | 26 | int index = 1; 27 | int small; 28 | while ((small = index << 1) <= size) { 29 | if (small < size && items[small].nodeCost > items[small + 1].nodeCost) { 30 | small++; 31 | } 32 | 33 | if (items[index].nodeCost > items[small].nodeCost) { 34 | HeapNode temp = items[index]; 35 | items[index] = items[small]; 36 | items[small] = temp; 37 | index = small; 38 | } else { 39 | break; 40 | } 41 | } 42 | 43 | // should throw exception but oh well 44 | return root == null ? null : root.nodeVal; 45 | } 46 | 47 | private void heapDown(int index) { 48 | } 49 | 50 | public void add(T pos, double cost) { 51 | add(new HeapNode<>(pos, cost)); 52 | } 53 | 54 | public void add(HeapNode elem) { 55 | if (this.size >= capacity) { 56 | this.capacity *= 2; 57 | this.items = Arrays.copyOf(this.items, this.capacity); 58 | } 59 | this.items[++this.size] = elem; 60 | this.heapUp(this.size - 1); 61 | } 62 | 63 | public void heapUp(int index) { 64 | int parentIndex = index >>> 1; 65 | while (parentIndex > 0 && this.items[index].nodeCost < this.items[parentIndex].nodeCost) { 66 | swap(parentIndex, index); 67 | index = parentIndex; 68 | parentIndex = index >>> 1; 69 | } 70 | } 71 | 72 | public void swap(int i1, int i2) { 73 | HeapNode temp = this.items[i1]; 74 | this.items[i1] = this.items[i2]; 75 | this.items[i2] = temp; 76 | } 77 | 78 | public List getBlocks() { 79 | final List blocks = new ArrayList<>(); 80 | for (int i = 1; i < this.items.length; i++) { 81 | final HeapNode node = this.items[i]; 82 | if (node == null) { 83 | break; 84 | } 85 | blocks.add(node.nodeVal); 86 | } 87 | return blocks; 88 | } 89 | 90 | public double getCost(T value) { 91 | for (int i = 1; i <= size; i++) { 92 | HeapNode node = this.items[i]; 93 | if (node != null && node.nodeVal.equals(value)) { 94 | return node.nodeCost; 95 | } 96 | } 97 | throw new IllegalArgumentException("Value not found in heap."); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/util/helper/location/Location.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.util.helper.location; 2 | 3 | import lombok.Getter; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | // DO NOT REARRANGE THE LAST THREE LOCATIONS - ORDINAL USED IN GAMSTATEHANDLER#ISPLAYERINSKYBLOCK TO REDUCE CHECKS 9 | @Getter 10 | public enum Location { 11 | PRIVATE_ISLAND("Private Island"), 12 | HUB("Hub"), 13 | THE_PARK("The Park"), 14 | THE_FARMING_ISLANDS("The Farming Islands"), 15 | SPIDER_DEN("Spider's Den"), 16 | THE_END("The End"), 17 | CRIMSON_ISLE("Crimson Isle"), 18 | GOLD_MINE("Gold Mine"), 19 | DEEP_CAVERNS("Deep Caverns"), 20 | DWARVEN_MINES("Dwarven Mines"), 21 | CRYSTAL_HOLLOWS("Crystal Hollows"), 22 | JERRY_WORKSHOP("Jerry's Workshop"), 23 | DUNGEON_HUB("Dungeon Hub"), 24 | GARDEN("Garden"), 25 | DUNGEON("Dungeon"), 26 | LIMBO("UNKNOWN"), 27 | LOBBY("PROTOTYPE"), 28 | // Knowhere - Avengers: Infinity War 29 | KNOWHERE("Knowhere"); 30 | 31 | private static final Map nameToLocationMap = new HashMap<>(); 32 | 33 | static { 34 | for (Location location : Location.values()) { 35 | nameToLocationMap.put(location.getName(), location); 36 | } 37 | } 38 | 39 | private final String name; 40 | 41 | Location(String name) { 42 | this.name = name; 43 | } 44 | 45 | public static Location fromName(String name) { 46 | final Location loc = nameToLocationMap.get(name); 47 | if (loc == null) return Location.KNOWHERE; 48 | return loc; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/util/helper/route/Route.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.util.helper.route; 2 | 3 | import com.google.gson.annotations.Expose; 4 | import com.jelly.mightyminerv2.config.MightyMinerConfig; 5 | import com.jelly.mightyminerv2.util.RenderUtil; 6 | import net.minecraft.util.BlockPos; 7 | import net.minecraft.util.Vec3; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Comparator; 11 | import java.util.List; 12 | import java.util.Optional; 13 | 14 | public class Route { 15 | 16 | @Expose 17 | private final List waypoints = new ArrayList<>(); 18 | 19 | public Route() { 20 | } 21 | 22 | public Route(List routes) { 23 | this.waypoints.addAll(routes); 24 | } 25 | 26 | public void insert(final RouteWaypoint waypoint) { 27 | this.insert(this.waypoints.size(), waypoint); 28 | } 29 | 30 | public void insert(final int index, final RouteWaypoint waypoint) { 31 | this.waypoints.add(index, waypoint); 32 | } 33 | 34 | public void remove(final RouteWaypoint waypoint) { 35 | final int index = this.waypoints.indexOf(waypoint); 36 | if (index == -1) { 37 | return; 38 | } 39 | this.remove(index); 40 | } 41 | 42 | public void remove(final int index) { 43 | this.waypoints.remove(index); 44 | } 45 | 46 | public RouteWaypoint get(final int index) { 47 | return this.waypoints.get((index + this.waypoints.size()) % this.waypoints.size()); 48 | } 49 | 50 | public Optional getClosest(final BlockPos pos) { 51 | return this.waypoints.stream().min(Comparator.comparingDouble(wp -> wp.toVec3().squareDistanceTo(new Vec3(pos)))); 52 | } 53 | 54 | public int indexOf(final RouteWaypoint waypoint) { 55 | return this.waypoints.indexOf(waypoint); 56 | } 57 | 58 | public void replace(final int index, final RouteWaypoint waypoint) { 59 | this.waypoints.set(index, waypoint); 60 | } 61 | 62 | public boolean isEnd(final int index) { 63 | return index + 1 == this.waypoints.size(); 64 | } 65 | 66 | public boolean isEmpty() { 67 | return this.waypoints.isEmpty(); 68 | } 69 | 70 | public void drawRoute() { 71 | for (int i = 0; i < this.waypoints.size(); i++) { 72 | RouteWaypoint currWaypoint = this.get(i); 73 | String name = currWaypoint.getTransportMethod().name(); 74 | RenderUtil.drawBlock(currWaypoint.toBlockPos(), MightyMinerConfig.routeBuilderNodeColor.toJavaColor()); 75 | RenderUtil.drawText((i + 1) + ". " + name.charAt(0) + name.substring(1).toLowerCase(), currWaypoint.getX() + 0.5, currWaypoint.getY() + 1, currWaypoint.getZ() + 0.5, 0.8F); 76 | if (this.waypoints.size() == 1) { 77 | continue; 78 | } 79 | RouteWaypoint prevWaypoint = this.get(i - 1); 80 | RenderUtil.drawLine( 81 | prevWaypoint.toVec3().addVector(0.5, 0.5, 0.5), 82 | currWaypoint.toVec3().addVector(0.5, 0.5, 0.5), 83 | MightyMinerConfig.routeBuilderTracerColor.toJavaColor() 84 | ); 85 | } 86 | } 87 | 88 | public int size() { 89 | return this.waypoints.size(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/util/helper/route/RouteWaypoint.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.util.helper.route; 2 | 3 | import com.google.gson.annotations.Expose; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import net.minecraft.util.BlockPos; 7 | import net.minecraft.util.Vec3; 8 | 9 | @Data 10 | @EqualsAndHashCode(exclude = {"transportMethod"}) 11 | public class RouteWaypoint { 12 | 13 | @Expose 14 | private int x; 15 | @Expose 16 | private int y; 17 | @Expose 18 | private int z; 19 | @Expose 20 | private WaypointType transportMethod; 21 | 22 | public RouteWaypoint() {} 23 | 24 | public RouteWaypoint(int x, int y, int z, WaypointType transportMethod) { 25 | this.x = x; 26 | this.y = y; 27 | this.z = z; 28 | this.transportMethod = transportMethod; 29 | } 30 | 31 | public RouteWaypoint(BlockPos pos, WaypointType transportMethod) { 32 | this(pos.getX(), pos.getY(), pos.getZ(), transportMethod); 33 | } 34 | 35 | public boolean isWithinRange(BlockPos pos, int range) { 36 | return Math.abs(pos.getX() - x) <= range && Math.abs(pos.getY() - y) <= range && Math.abs(pos.getZ() - z) <= range; 37 | } 38 | 39 | public int distanceTo(BlockPos pos) { 40 | return (int) Math.sqrt(Math.pow(pos.getX() - x, 2) + Math.pow(pos.getY() - y, 2) + Math.pow(pos.getZ() - z, 2)); 41 | } 42 | 43 | public Vec3 toVec3() { 44 | return new Vec3(this.x, this.y, this.z); 45 | } 46 | 47 | public BlockPos toBlockPos() { 48 | return new BlockPos(this.x, this.y, this.z); 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return x + "," + y + "," + z + "," + transportMethod.name(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/util/helper/route/TransportMethod.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.util.helper.route; 2 | 3 | // Todo: Rename 4 | public enum TransportMethod { 5 | AOTV, // Right Click Aotv/Aote 6 | ETHERWARP, // Shift + Right Click Aotv/Aote 7 | WALK, // Walks Between Nodes (Add it after pathfinder) 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/jelly/mightyminerv2/util/helper/route/WaypointType.java: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.util.helper.route; 2 | 3 | public enum WaypointType { 4 | AOTV, // Right Click Aotv/Aote 5 | ETHERWARP, // Shift + Right Click Aotv/Aote 6 | WALK, // Walks Between Nodes (Add it after pathfinder) 7 | MINE // User starts mining at this node (needed for RouteMiner) 8 | } 9 | -------------------------------------------------------------------------------- /src/main/kotlin/com/jelly/mightyminerv2/pathfinder/calculate/Path.kt: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.pathfinder.calculate 2 | 3 | import com.jelly.mightyminerv2.pathfinder.goal.Goal 4 | import com.jelly.mightyminerv2.pathfinder.movement.CalculationContext 5 | import com.jelly.mightyminerv2.pathfinder.util.BlockUtil 6 | import com.jelly.mightyminerv2.pathfinder.util.toVec3 7 | import com.jelly.mightyminerv2.pathfinder.util.world 8 | import net.minecraft.init.Blocks 9 | import net.minecraft.util.BlockPos 10 | import java.util.* 11 | 12 | class Path(start: PathNode, end: PathNode, val goal: Goal, val ctx: CalculationContext) { 13 | var start: BlockPos = BlockPos(start.x, start.y, start.z) 14 | var end: BlockPos = BlockPos(end.x, end.y, end.z) 15 | var path: List 16 | var node: List 17 | var smoothPath: List = listOf() 18 | 19 | init { 20 | var temp: PathNode? = end 21 | val listOfBlocks = LinkedList() 22 | val listOfNodes = LinkedList() 23 | while (temp != null) { 24 | listOfNodes.addFirst(temp) 25 | listOfBlocks.addFirst(BlockPos(temp.x, temp.y, temp.z)) 26 | temp = temp.parentNode 27 | } 28 | path = listOfBlocks.toList() 29 | node = listOfNodes.toList() 30 | } 31 | 32 | // english is not my strong suit 33 | fun getSmoothedPath(): List { 34 | if (smoothPath.isNotEmpty()) return smoothPath 35 | 36 | val smooth = LinkedList() 37 | if (path.isNotEmpty()) { 38 | smooth.add(path[0]) 39 | var currPoint = 0 40 | 41 | while (currPoint + 1 < path.size) { 42 | var nextPos = currPoint + 1 43 | 44 | for (i in (path.size - 1) downTo nextPos) { 45 | if (BlockUtil.bresenham(ctx, path[currPoint], path[i])) { 46 | nextPos = i 47 | break 48 | } 49 | } 50 | smooth.add(path[nextPos]) 51 | currPoint = nextPos 52 | } 53 | } 54 | smoothPath = smooth.toList() 55 | return smoothPath 56 | } 57 | 58 | fun reconstructPath(end: PathNode): List { 59 | val path = mutableListOf() 60 | var currentNode: PathNode? = end 61 | while (currentNode != null) { 62 | path.add(0, currentNode.getBlock()) 63 | currentNode = currentNode.parentNode 64 | } 65 | 66 | val smooth = mutableListOf() 67 | if (path.isNotEmpty()) { 68 | smooth.add(path[0]) 69 | var currPoint = 0 70 | var maxiters = 2000 71 | 72 | while (currPoint + 1 < path.size && maxiters-- > 0) { 73 | var nextPos = currPoint + 1 74 | 75 | for (i in (path.size - 1) downTo nextPos) { 76 | if (BlockUtil.bresenham(ctx, path[currPoint].toVec3(), path[i].toVec3())) { 77 | nextPos = i 78 | break 79 | } 80 | } 81 | smooth.add(path[nextPos]) 82 | currPoint = nextPos 83 | } 84 | } 85 | smooth.removeIf { world.getBlockState(it).block == Blocks.air } 86 | return smooth 87 | } 88 | 89 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/jelly/mightyminerv2/pathfinder/calculate/PathNode.kt: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.pathfinder.calculate 2 | 3 | import com.jelly.mightyminerv2.pathfinder.goal.Goal 4 | import net.minecraft.util.BlockPos 5 | 6 | class PathNode(var x: Int, var y: Int, var z: Int, val goal: Goal) { 7 | var costSoFar: Double = 1e6 // gCost - INF_COST 8 | var costToEnd: Double = goal.heuristic(x, y, z) // hCost / Heuristic 9 | var totalCost: Double = 1.0 // INF_COST 10 | var heapPosition = -1 // Smart 11 | var parentNode: PathNode? = null 12 | 13 | override fun equals(other: Any?): Boolean { 14 | val otter = 15 | other as PathNode // otter just means other bt written weird to remove warning 16 | return otter.x == this.x && otter.y == this.y && otter.z == this.z 17 | } 18 | 19 | override fun hashCode(): Int { 20 | return longHash(this.x, this.y, this.z).toInt() 21 | } 22 | 23 | fun getBlock(): BlockPos { 24 | return BlockPos(x, y, z) 25 | } 26 | 27 | override fun toString(): String { 28 | return "PathNode(x: $x, y: $y, z: $z, costSoFar: $costSoFar, costToEnd: $costToEnd totalCost: $totalCost)" 29 | } 30 | 31 | companion object { 32 | fun longHash(x: Int, y: Int, z: Int): Long { 33 | var hash = 3241L 34 | hash = 3457689L * hash + x 35 | hash = 8734625L * hash + y 36 | hash = 2873465L * hash + z 37 | return hash 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/jelly/mightyminerv2/pathfinder/calculate/openset/BinaryHeapOpenSet.kt: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.pathfinder.calculate.openset 2 | 3 | import com.jelly.mightyminerv2.pathfinder.calculate.PathNode 4 | import java.util.* 5 | 6 | class BinaryHeapOpenSet(initialSize: Int = 1024) { 7 | var items = arrayOfNulls(initialSize) 8 | var size = 0 9 | 10 | fun add(node: PathNode) { 11 | if (size >= items.size - 1) { 12 | items = Arrays.copyOf(items, items.size shl 1) 13 | } 14 | node.heapPosition = ++size 15 | items[size] = node 16 | relocate(node) 17 | } 18 | 19 | fun relocate(node: PathNode) { 20 | var parent = node.heapPosition ushr 1 21 | var parentNode = items[parent] 22 | while (node.heapPosition > 1 && node.totalCost < parentNode!!.totalCost) { 23 | items[node.heapPosition] = parentNode 24 | items[parent] = node 25 | node.heapPosition = parent 26 | parent = parent ushr 1 27 | parentNode = items[parent] 28 | } 29 | } 30 | 31 | fun poll(): PathNode { 32 | val itemToPoll = items[1] 33 | itemToPoll!!.heapPosition = -1 34 | val itemToSwap = items[size--] 35 | itemToSwap!!.heapPosition = 1 36 | items[1] = itemToSwap 37 | val itemToSwapCost = itemToSwap.totalCost 38 | 39 | if (size <= 1) return itemToPoll 40 | 41 | var parentIndex = 1 42 | var smallestChildIndex = 2 43 | while (smallestChildIndex <= size) { 44 | val rightChildIndex = smallestChildIndex + 1 45 | if (rightChildIndex < size && items[rightChildIndex]!!.totalCost < items[smallestChildIndex]!!.totalCost) { 46 | smallestChildIndex = rightChildIndex 47 | } 48 | 49 | if (items[smallestChildIndex]!!.totalCost >= itemToSwapCost) { 50 | break 51 | } 52 | 53 | val swapTemp = items[smallestChildIndex] 54 | swapTemp!!.heapPosition = parentIndex 55 | items[parentIndex] = swapTemp 56 | itemToSwap.heapPosition = smallestChildIndex 57 | items[smallestChildIndex] = itemToSwap 58 | 59 | parentIndex = smallestChildIndex 60 | smallestChildIndex = parentIndex shl 1 61 | } 62 | return itemToPoll 63 | } 64 | 65 | fun isEmpty() = size <= 0 66 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/jelly/mightyminerv2/pathfinder/calculate/path/AStarPathFinder.kt: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.pathfinder.calculate.path 2 | 3 | import com.jelly.mightyminerv2.pathfinder.calculate.Path 4 | import com.jelly.mightyminerv2.pathfinder.calculate.PathNode 5 | import com.jelly.mightyminerv2.pathfinder.calculate.openset.BinaryHeapOpenSet 6 | import com.jelly.mightyminerv2.pathfinder.goal.Goal 7 | import com.jelly.mightyminerv2.pathfinder.movement.CalculationContext 8 | import com.jelly.mightyminerv2.pathfinder.movement.MovementResult 9 | import com.jelly.mightyminerv2.pathfinder.movement.Moves 10 | import it.unimi.dsi.fastutil.longs.Long2ObjectMap 11 | import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap 12 | 13 | class AStarPathFinder(val startX: Int, val startY: Int, val startZ: Int, val goal: Goal, val ctx: CalculationContext) { 14 | private val closedSet: Long2ObjectMap = Long2ObjectOpenHashMap() 15 | private var calculating = false 16 | 17 | fun calculatePath(): Path? { 18 | calculating = true 19 | val openSet = BinaryHeapOpenSet() 20 | val startNode = PathNode(startX, startY, startZ, goal) 21 | val res = MovementResult() 22 | val moves = Moves.values() 23 | startNode.costSoFar = 0.0 24 | startNode.totalCost = startNode.costToEnd 25 | openSet.add(startNode) 26 | 27 | while (!openSet.isEmpty() && calculating) { 28 | val currentNode = openSet.poll() 29 | 30 | if (goal.isAtGoal(currentNode.x, currentNode.y, currentNode.z)) { 31 | return Path(startNode, currentNode, goal, ctx) 32 | } 33 | 34 | for (move in moves) { 35 | res.reset() 36 | move.calculate(ctx, currentNode.x, currentNode.y, currentNode.z, res) 37 | val cost = res.cost 38 | if (cost >= ctx.cost.INF_COST) continue 39 | val neighbourNode = 40 | getNode(res.x, res.y, res.z, PathNode.longHash(res.x, res.y, res.z)) 41 | val neighbourCostSoFar = currentNode.costSoFar + cost 42 | 43 | if (neighbourNode.costSoFar > neighbourCostSoFar) { 44 | neighbourNode.parentNode = currentNode 45 | neighbourNode.costSoFar = neighbourCostSoFar 46 | neighbourNode.totalCost = neighbourCostSoFar + neighbourNode.costToEnd 47 | 48 | if (neighbourNode.heapPosition == -1) { 49 | openSet.add(neighbourNode) 50 | } else { 51 | openSet.relocate(neighbourNode) 52 | } 53 | } 54 | } 55 | } 56 | calculating = false 57 | return null 58 | } 59 | 60 | fun getNode(x: Int, y: Int, z: Int, hash: Long): PathNode { 61 | var n: PathNode? = closedSet.get(hash) 62 | if (n == null) { 63 | n = PathNode(x, y, z, goal) 64 | closedSet.put(hash, n) 65 | } 66 | return n 67 | } 68 | 69 | fun requestStop() { 70 | if (!calculating) return 71 | calculating = false 72 | } 73 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/jelly/mightyminerv2/pathfinder/goal/Goal.kt: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.pathfinder.goal 2 | 3 | import com.jelly.mightyminerv2.pathfinder.movement.CalculationContext 4 | import kotlin.math.abs 5 | import kotlin.math.min 6 | import kotlin.math.sqrt 7 | 8 | class Goal(val goalX: Int, val goalY: Int, val goalZ: Int, val ctx: CalculationContext) : IGoal { 9 | private val SQRT_2 = sqrt(2.0) 10 | 11 | override fun isAtGoal(x: Int, y: Int, z: Int): Boolean { 12 | return goalX == x && goalY == y && goalZ == z 13 | } 14 | 15 | override fun heuristic(x: Int, y: Int, z: Int): Double { 16 | val dx = abs(goalX - x) 17 | val dz = abs(goalZ - z) 18 | val straight = abs(dx - dz).toDouble() 19 | var vertical = abs(goalY - y).toDouble() 20 | val diagonal = min(dx, dz).toDouble() 21 | 22 | if (goalY > y) { 23 | vertical *= 6.234399666206506 24 | // vertical *= ctx.cost.JUMP_ONE_BLOCK_COST 25 | } else { 26 | vertical *= ctx.cost.N_BLOCK_FALL_COST[2] / 2.0 27 | } 28 | 29 | return (straight + diagonal * SQRT_2) * ctx.cost.ONE_BLOCK_SPRINT_COST + vertical 30 | } 31 | 32 | override fun toString(): String { 33 | return "x: $goalX, y: $goalY, z: $goalZ" 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/jelly/mightyminerv2/pathfinder/goal/IGoal.kt: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.pathfinder.goal 2 | 3 | interface IGoal { 4 | fun isAtGoal(x: Int, y: Int, z: Int): Boolean 5 | fun heuristic(x: Int, y: Int, z: Int): Double 6 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/jelly/mightyminerv2/pathfinder/helper/BlockStateAccessor.kt: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.pathfinder.helper 2 | 3 | import com.jelly.mightyminerv2.util.IChunkProviderClient 4 | import it.unimi.dsi.fastutil.longs.Long2ObjectMap 5 | import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap 6 | import net.minecraft.block.state.IBlockState 7 | import net.minecraft.init.Blocks 8 | import net.minecraft.util.BlockPos 9 | import net.minecraft.world.IBlockAccess 10 | import net.minecraft.world.World 11 | import net.minecraft.world.chunk.Chunk 12 | 13 | class BlockStateAccessor(private val world: World) { 14 | private val loadedChunks: Long2ObjectMap = Long2ObjectOpenHashMap() 15 | private var cached: Chunk? = null 16 | var access: IBlockAccess 17 | val isPassableBlockPos: BlockPos.MutableBlockPos 18 | 19 | init { 20 | val loadedWorld: List = (this.world.chunkProvider as IChunkProviderClient).chunkListing() 21 | 22 | for (chunk in loadedWorld) { 23 | this.loadedChunks[this.getKey(chunk.xPosition, chunk.zPosition)] = chunk 24 | } 25 | 26 | isPassableBlockPos = BlockPos.MutableBlockPos() 27 | access = BlockStateInterfaceAccessWrapper(this, world) 28 | } 29 | 30 | fun get(x: Int, y: Int, z: Int): IBlockState { 31 | var current = this.cached 32 | if (current != null && current.xPosition == x shr 4 && current.zPosition == z shr 4) { 33 | return current.getBlockState(BlockPos(x, y, z)) 34 | } 35 | 36 | current = this.loadedChunks[this.getKey(x shr 4, z shr 4)] 37 | 38 | if (current != null && current.isLoaded) { 39 | this.cached = current 40 | return current.getBlockState(BlockPos(x, y, z)) 41 | } 42 | return Blocks.air.defaultState 43 | } 44 | 45 | fun isBlockInLoadedChunks(blockX: Int, blockZ: Int): Boolean { 46 | return this.loadedChunks.containsKey(getKey(blockX shr 4, blockZ shr 4)) 47 | } 48 | 49 | private fun getKey(x: Int, z: Int): Long { 50 | return (x.toLong() and 4294967295L) or ((z.toLong() and 4294967295L) shl 32) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/kotlin/com/jelly/mightyminerv2/pathfinder/helper/BlockStateInterfaceAccessWrapper.kt: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.pathfinder.helper 2 | 3 | import net.minecraft.block.state.IBlockState 4 | import net.minecraft.init.Blocks 5 | import net.minecraft.tileentity.TileEntity 6 | import net.minecraft.util.BlockPos 7 | import net.minecraft.util.EnumFacing 8 | import net.minecraft.world.IBlockAccess 9 | import net.minecraft.world.WorldType 10 | import net.minecraft.world.biome.BiomeGenBase 11 | 12 | class BlockStateInterfaceAccessWrapper(private val bsi: BlockStateAccessor, private val world: IBlockAccess) : 13 | IBlockAccess { 14 | 15 | override fun getTileEntity(pos: BlockPos): TileEntity? { 16 | return null 17 | } 18 | 19 | override fun getCombinedLight(pos: BlockPos, lightValue: Int): Int { 20 | return 0 21 | } 22 | 23 | override fun getBlockState(pos: BlockPos): IBlockState { 24 | // BlockStateInterface#get0(BlockPos) btfo! 25 | return bsi.get(pos.x, pos.y, pos.z) 26 | } 27 | 28 | override fun isAirBlock(pos: BlockPos): Boolean { 29 | return bsi.get(pos.x, pos.y, pos.z).block == Blocks.air 30 | } 31 | 32 | override fun getBiomeGenForCoords(pos: BlockPos): BiomeGenBase? { 33 | return null 34 | } 35 | 36 | override fun extendedLevelsInChunkCache(): Boolean { 37 | return false 38 | } 39 | 40 | // Uncomment and implement if needed 41 | // override fun getBiome(pos: BlockPos): Biome { 42 | // return Biomes.FOREST 43 | // } 44 | 45 | override fun getStrongPower(pos: BlockPos, direction: EnumFacing): Int { 46 | return 0 47 | } 48 | 49 | override fun getWorldType(): WorldType { 50 | return world.worldType 51 | } 52 | 53 | override fun isSideSolid(pos: BlockPos, side: EnumFacing, _default: Boolean): Boolean { 54 | return false 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/kotlin/com/jelly/mightyminerv2/pathfinder/helper/player/IPlayerContext.kt: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.pathfinder.helper.player 2 | 3 | import net.minecraft.client.Minecraft 4 | import net.minecraft.client.entity.EntityPlayerSP 5 | import net.minecraft.client.multiplayer.PlayerControllerMP 6 | import net.minecraft.util.BlockPos 7 | import net.minecraft.world.World 8 | 9 | interface IPlayerContext { 10 | val mc: Minecraft 11 | val player: EntityPlayerSP 12 | val playerController: PlayerControllerMP 13 | val world: World 14 | val playerPosition: BlockPos 15 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/jelly/mightyminerv2/pathfinder/helper/player/PlayerContext.kt: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.pathfinder.helper.player 2 | 3 | import net.minecraft.client.Minecraft 4 | import net.minecraft.util.BlockPos 5 | import kotlin.math.ceil 6 | 7 | class PlayerContext(override val mc: Minecraft) : IPlayerContext { 8 | override val player get() = mc.thePlayer 9 | override val playerController get() = mc.playerController 10 | override val world get() = mc.theWorld 11 | 12 | // Block player is standing on 13 | // Todo: Change name 14 | override val playerPosition get() = BlockPos(player.posX, ceil(player.posY) - 1, player.posZ) 15 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/jelly/mightyminerv2/pathfinder/movement/CalculationContext.kt: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.pathfinder.movement 2 | 3 | import com.jelly.mightyminerv2.pathfinder.costs.ActionCosts 4 | import com.jelly.mightyminerv2.pathfinder.helper.BlockStateAccessor 5 | import com.jelly.mightyminerv2.pathfinder.helper.player.PlayerContext 6 | import net.minecraft.block.state.IBlockState 7 | import net.minecraft.client.Minecraft 8 | import net.minecraft.potion.Potion 9 | 10 | class CalculationContext(sprintFactor: Double = 0.13, walkFactor: Double = 0.1, sneakFactor: Double = 0.03) { 11 | val playerContext = PlayerContext(Minecraft.getMinecraft()) 12 | val world = playerContext.world 13 | val player = playerContext.player 14 | val bsa = BlockStateAccessor(world) 15 | val jumpBoostAmplifier = player.getActivePotionEffect(Potion.jump)?.amplifier ?: -1 16 | val cost = ActionCosts(sprintFactor, walkFactor, sneakFactor, jumpBoostAmplifier) 17 | val maxFallHeight = 20 18 | 19 | fun get(x: Int, y: Int, z: Int): IBlockState { 20 | return bsa.get(x, y, z) 21 | } 22 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/jelly/mightyminerv2/pathfinder/movement/IMovement.kt: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.pathfinder.movement 2 | 3 | import com.jelly.mightyminerv2.MightyMiner 4 | import net.minecraft.util.BlockPos 5 | 6 | interface IMovement { 7 | val mm: MightyMiner 8 | val source: BlockPos 9 | val dest: BlockPos 10 | val costs: Double // plural cuz kotlin gae 11 | 12 | fun getCost(): Double 13 | fun calculateCost(ctx: CalculationContext, res: MovementResult) 14 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/jelly/mightyminerv2/pathfinder/movement/Movement.kt: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.pathfinder.movement 2 | 3 | import com.jelly.mightyminerv2.MightyMiner 4 | import net.minecraft.util.BlockPos 5 | 6 | abstract class Movement(override val mm: MightyMiner, override val source: BlockPos, override val dest: BlockPos) : 7 | IMovement { 8 | 9 | override var costs: Double = 1e6 10 | override fun getCost() = costs 11 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/jelly/mightyminerv2/pathfinder/movement/MovementResult.kt: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.pathfinder.movement 2 | 3 | import net.minecraft.util.BlockPos 4 | 5 | class MovementResult { 6 | var x: Int = 0 7 | var y: Int = 0 8 | var z: Int = 0 9 | var cost: Double = 1e6 10 | 11 | fun set(x: Int, y: Int, z: Int) { 12 | this.x = x 13 | this.y = y 14 | this.z = z 15 | } 16 | 17 | fun reset() { 18 | x = 0 19 | y = 0 20 | z = 0 21 | cost = 1e6 22 | } 23 | 24 | fun getDest(): BlockPos { 25 | return BlockPos(x, y, z) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/kotlin/com/jelly/mightyminerv2/pathfinder/movement/movements/MovementAscend.kt: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.pathfinder.movement.movements 2 | 3 | import com.jelly.mightyminerv2.MightyMiner 4 | import com.jelly.mightyminerv2.pathfinder.movement.CalculationContext 5 | import com.jelly.mightyminerv2.pathfinder.movement.Movement 6 | import com.jelly.mightyminerv2.pathfinder.movement.MovementHelper 7 | import com.jelly.mightyminerv2.pathfinder.movement.MovementResult 8 | import net.minecraft.util.BlockPos 9 | 10 | class MovementAscend(mm: MightyMiner, from: BlockPos, to: BlockPos) : Movement(mm, from, to) { 11 | override fun calculateCost(ctx: CalculationContext, res: MovementResult) { 12 | calculateCost(ctx, source.x, source.y, source.z, dest.x, dest.z, res) 13 | costs = res.cost 14 | } 15 | 16 | companion object { 17 | fun calculateCost( 18 | ctx: CalculationContext, 19 | x: Int, 20 | y: Int, 21 | z: Int, 22 | destX: Int, 23 | destZ: Int, 24 | res: MovementResult 25 | ) { 26 | res.set(destX, y + 1, destZ) 27 | cost(ctx, x, y, z, destX, destZ, res) 28 | } 29 | 30 | private fun cost( 31 | ctx: CalculationContext, 32 | x: Int, 33 | y: Int, 34 | z: Int, 35 | destX: Int, 36 | destZ: Int, 37 | res: MovementResult 38 | ) { 39 | val destState = ctx.get(destX, y + 1, destZ) 40 | if (!MovementHelper.canStandOn(ctx.bsa, destX, y + 1, destZ, destState)) return 41 | if (!MovementHelper.canWalkThrough(ctx.bsa, destX, y + 3, destZ)) return 42 | if (!MovementHelper.canWalkThrough(ctx.bsa, destX, y + 2, destZ)) return 43 | if (!MovementHelper.canWalkThrough(ctx.bsa, x, y + 3, z)) return 44 | 45 | val sourceState = ctx.get(x, y, z) 46 | if (MovementHelper.isLadder(sourceState)) return 47 | if (MovementHelper.isLadder(destState) && !MovementHelper.canWalkIntoLadder( 48 | destState, 49 | destX - x, 50 | destZ - z 51 | ) 52 | ) return 53 | 54 | // small = half block / stair - in this case it doesnt matter which way the source stair(if it is a stair) is facing 55 | // big = fill block 56 | // this logic is actually fucking sick ngl 57 | 58 | val sourceHeight = 59 | sourceState.block.getCollisionBoundingBox(ctx.world, BlockPos(x, y, z), sourceState)?.maxY ?: return 60 | val destHeight = 61 | destState.block.getCollisionBoundingBox(ctx.world, BlockPos(destX, y + 1, destZ), destState)?.maxY 62 | ?: return 63 | // if (!snow) { 64 | // val srcSmall = MovementHelper.isBottomSlab(sourceState); 65 | // val destSmall = MovementHelper.isBottomSlab(destState); 66 | // 67 | // val destSmallStair = MovementHelper.isValidStair(destState, destX - x, destZ - z); 68 | // 69 | // if (!srcSmall == !(destSmall || destSmallStair)) { 70 | // res.cost = ctx.cost.JUMP_ONE_BLOCK_COST 71 | // } else if (!srcSmall) { 72 | // res.cost = ctx.cost.ONE_BLOCK_SPRINT_COST; 73 | // } 74 | // } else { 75 | val diff = destHeight - sourceHeight 76 | // println("SourceHeight: $sourceHeight, DestHeight: $destHeight, Diff: $diff") 77 | res.cost = when { 78 | diff <= 0.5 -> ctx.cost.ONE_BLOCK_SPRINT_COST 79 | diff <= 1.125 -> ctx.cost.JUMP_ONE_BLOCK_COST 80 | else -> ctx.cost.INF_COST 81 | } 82 | } 83 | // } 84 | } 85 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/jelly/mightyminerv2/pathfinder/movement/movements/MovementFall.kt: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.pathfinder.movement.movements 2 | 3 | import com.jelly.mightyminerv2.MightyMiner 4 | import com.jelly.mightyminerv2.pathfinder.movement.CalculationContext 5 | import com.jelly.mightyminerv2.pathfinder.movement.Movement 6 | import com.jelly.mightyminerv2.pathfinder.movement.MovementResult 7 | import net.minecraft.util.BlockPos 8 | 9 | class MovementFall(mm: MightyMiner, source: BlockPos, dest: BlockPos) : Movement(mm, source, dest) { 10 | override fun calculateCost(ctx: CalculationContext, res: MovementResult) { 11 | calculateCost(ctx, source.x, source.y, source.z, dest.x, dest.z, res) 12 | costs = res.cost 13 | } 14 | 15 | companion object { 16 | fun calculateCost( 17 | ctx: CalculationContext, 18 | x: Int, 19 | y: Int, 20 | z: Int, 21 | destX: Int, 22 | destZ: Int, 23 | res: MovementResult 24 | ) { 25 | res.set(destX, y - 1, destZ) 26 | MovementDescend.calculateCost(ctx, x, y, z, destX, destZ, res) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/kotlin/com/jelly/mightyminerv2/pathfinder/util/Extension.kt: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.pathfinder.util 2 | 3 | import net.minecraft.client.settings.KeyBinding 4 | import net.minecraft.entity.EntityLivingBase 5 | import net.minecraft.util.BlockPos 6 | import net.minecraft.util.Vec3 7 | import kotlin.math.ceil 8 | import kotlin.math.floor 9 | 10 | fun EntityLivingBase.getStandingOnCeil() = BlockPos(posX, ceil(posY) - 1, posZ) 11 | fun EntityLivingBase.getStandingOnFloor() = BlockPos(posX, floor(posY) - 1, posZ) 12 | fun KeyBinding.setPressed(pressed: Boolean) = KeyBinding.setKeyBindState(keyCode, pressed) 13 | fun BlockPos.toVec3() = Vec3(x.toDouble() + 0.5, y.toDouble() + 0.5, z.toDouble() + 0.5) 14 | fun BlockPos.toVec3Top(): Vec3 = toVec3().addVector(0.0, 0.5, 0.0) 15 | fun Vec3.toBlockPos(): BlockPos = BlockPos(xCoord, yCoord, zCoord) 16 | 17 | fun EntityLivingBase.lastTickPositionCeil() = BlockPos(lastTickPosX, ceil(lastTickPosY) - 1, lastTickPosZ) -------------------------------------------------------------------------------- /src/main/kotlin/com/jelly/mightyminerv2/pathfinder/util/Ref.kt: -------------------------------------------------------------------------------- 1 | package com.jelly.mightyminerv2.pathfinder.util 2 | 3 | import net.minecraft.client.Minecraft 4 | import net.minecraft.client.renderer.Tessellator 5 | 6 | val mc 7 | get() = Minecraft.getMinecraft() 8 | val player 9 | get() = mc.thePlayer 10 | val world 11 | get() = mc.theWorld 12 | val tessellator 13 | get() = Tessellator.getInstance() 14 | val gameSettings 15 | get() = mc.gameSettings -------------------------------------------------------------------------------- /src/main/resources/mcmod.info: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "modid": "mightyminerv2", 4 | "name": "MightyMiner V2", 5 | "description": "Best miner ever!!", 6 | "version": "${version}", 7 | "mcversion": "1.8.9", 8 | "url": "", 9 | "updateUrl": "", 10 | "authorList": [ 11 | "Me" 12 | ], 13 | "credits": "", 14 | "logoFile": "", 15 | "screenshots": [], 16 | "dependencies": [] 17 | } 18 | ] -------------------------------------------------------------------------------- /src/main/resources/mightyminer/sounds/AAAAAAAAAA.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JellyLabScripts/MightyMiner/62aec611784d81973a9ce9fcba02d659b776d0b8/src/main/resources/mightyminer/sounds/AAAAAAAAAA.wav -------------------------------------------------------------------------------- /src/main/resources/mightyminer/sounds/loud_buzz.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JellyLabScripts/MightyMiner/62aec611784d81973a9ce9fcba02d659b776d0b8/src/main/resources/mightyminer/sounds/loud_buzz.wav -------------------------------------------------------------------------------- /src/main/resources/mightyminer/sounds/metal_pipe.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JellyLabScripts/MightyMiner/62aec611784d81973a9ce9fcba02d659b776d0b8/src/main/resources/mightyminer/sounds/metal_pipe.wav -------------------------------------------------------------------------------- /src/main/resources/mightyminer/sounds/staff_check_voice_notification.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JellyLabScripts/MightyMiner/62aec611784d81973a9ce9fcba02d659b776d0b8/src/main/resources/mightyminer/sounds/staff_check_voice_notification.wav -------------------------------------------------------------------------------- /src/main/resources/mixins.mightyminerv2.json: -------------------------------------------------------------------------------- 1 | { 2 | "package": "com.jelly.mightyminerv2.mixin", 3 | "refmap": "mixins.mightyminerv2.refmap.json", 4 | "minVersion": "0.7", 5 | "compatibilityLevel": "JAVA_8", 6 | "mixins": [ 7 | "client.MixinBlockStainedGlassPane", 8 | "client.MixinChunk", 9 | "client.MixinEntityLivingBase", 10 | "client.MixinMinecraft", 11 | "client.MixinScoreboard", 12 | "client.MixinSoundManager", 13 | "fml.MixinFMLHandshakeMessage", 14 | "gui.MixinGuiContainer", 15 | "gui.MixinInventoryPlayer", 16 | "network.MixinNetworkManager" 17 | ], 18 | "client": [ 19 | "client.EntityPlayerSPAccessor", 20 | "client.MinecraftAccessor", 21 | "client.MixinChunkProviderClient", 22 | "client.MixinEntityPlayerSP", 23 | "network.MixinNetHandlerPlayClient", 24 | "render.MixinModelBiped" 25 | ] 26 | } 27 | --------------------------------------------------------------------------------