diff --git a/.gitignore b/.gitignore index a8f8b9447..d7b8f4832 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # User-specific stuff .idea/ +.vs/ baritone/ *.iml @@ -117,4 +118,3 @@ run/ # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) !gradle-wrapper.jar - diff --git a/README.md b/README.md index 6c833cbb7..4e31c23a0 100644 --- a/README.md +++ b/README.md @@ -46,10 +46,6 @@ If the Nightly Link doesn't work, check the latest [Build Action](https://github that succeeded and download `Artifacts.zip` (you must be signed into GitHub). Replace your existing `altoclef-4.0-SNAPSHOT.jar` with the one found in `Artifacts.zip` -Then, copy `altoclef-4.0-SNAPSHOT.jar` from `Artifacts.zip` to `./mods`. - -Then, copy the `baritone-unoptimized-fabric-1.XX.X.jar` from the long term release zip file to `./mods` - ### Long Term Release [Check releases](https://github.com/gaucho-matrero/altoclef/releases). Note you will need to copy over both jar files @@ -65,7 +61,7 @@ out now if you'd like: ### Versions -This is a **fabric only** mod, currently only available for **Minecraft 1.19.2-1.19.3**. +This is a **fabric only** mod, currently only available for **Minecraft 1.19.2-1.19.4**. For older MC versions, try [multiconnect](https://www.curseforge.com/minecraft/mc-mods/multiconnect) (NOTE: multiconnect is untested and not affiliated with altoclef, use at your own risk!) diff --git a/build.gradle b/build.gradle index 5f5ab0026..f48564d07 100644 --- a/build.gradle +++ b/build.gradle @@ -1,11 +1,11 @@ plugins { - id "fabric-loom" version "1.1-SNAPSHOT" + id "fabric-loom" version "1.7-SNAPSHOT" id "maven-publish" id 'com.github.johnrengelman.shadow' version '8.1.1' } -sourceCompatibility = JavaVersion.VERSION_17 -targetCompatibility = JavaVersion.VERSION_17 +sourceCompatibility = JavaVersion.VERSION_21 +targetCompatibility = JavaVersion.VERSION_21 archivesBaseName = project.archives_base_name version = project.mod_version @@ -14,8 +14,12 @@ group = project.maven_group repositories { mavenCentral() maven { - name = "gaucho-matrero-repo" - url = "https://gaucho-matrero.github.io/maven/" + name = "MarvionKiritoRepo" + url = "https://marvionkirito.github.io/maven/" + } + maven { + name = 'babbaj-repo' + url = 'https://babbaj.github.io/maven/' } flatDir { dirs '../baritone/dist' @@ -32,25 +36,28 @@ dependencies { modImplementation("net.fabricmc.fabric-api:fabric-api:${project.fabric_version}") // Jackson JSON - implementation 'com.fasterxml.jackson.core:jackson-core:2.15.0-rc1' - implementation 'com.fasterxml.jackson.core:jackson-annotations:2.15.0-rc1' - implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.0-rc1' + implementation 'com.fasterxml.jackson.core:jackson-core:2.17.2' + implementation 'com.fasterxml.jackson.core:jackson-annotations:2.17.2' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' + + // Nether pathfinder + implementation 'dev.babbaj:nether-pathfinder:1.5' // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // You may need to force-disable transitiveness on them. - shadow('com.fasterxml.jackson.core:jackson-core:2.15.0-rc1') - shadow('com.fasterxml.jackson.core:jackson-annotations:2.15.0-rc1') - shadow('com.fasterxml.jackson.core:jackson-databind:2.15.0-rc1') + shadow('com.fasterxml.jackson.core:jackson-core:2.17.2') + shadow('com.fasterxml.jackson.core:jackson-annotations:2.17.2') + shadow('com.fasterxml.jackson.core:jackson-databind:2.17.2') // Thank you georgeagostino for fixing my garbage -// if (getProject().hasProperty("altoclef.development")) { - // Must run build from baritone-plus once - modImplementation 'baritone-api-fabric:baritone-unoptimized-fabric-1.19.4-beta1' - include "baritone-api-fabric:baritone-unoptimized-fabric-1.19.4-beta1" - //} else { - // modImplementation "cabaletta:baritone-unoptimized-fabric:1.18.2" - // include "cabaletta:baritone-unoptimized-fabric:1.18.2" - //} + if (getProject().hasProperty("altoclef.development")) { + // Must run build from baritone-plus once + modImplementation 'baritone-api-fabric:baritone-unoptimized-fabric-1.21-beta1' + include "baritone-api-fabric:baritone-unoptimized-fabric-1.21-beta1" + } else { + modImplementation "cabaletta:baritone-unoptimized-fabric:1.21-beta1" + include "cabaletta:baritone-unoptimized-fabric:1.21-beta1" + } //modImplementation 'baritone-api-fabric:baritone-api-fabric:1.6.3' //implementation files('baritone-plus/build/libs/baritone-unoptimized-fabric-1.6.3.jar') } diff --git a/develop.md b/develop.md index 7f71e2518..ee1c4e4f6 100644 --- a/develop.md +++ b/develop.md @@ -30,11 +30,11 @@ Click `File > New > Project from Version Control...` ![image](https://user-image If the gradle tab doesn't exist, try `View > Tool Windows > Gradle` -## Get it Running (Command line, Linux & macOS) +## Get it Running (Command line) 1) Git Clone project 2) `cd` into cloned local repo -3) `sudo / doas chmod +x gradlew` +3) `sudo / doas chmod +x gradlew` (skip this step if you are on windows) 4) `./gradlew build` or `./gradlew runClient` ## Modifying Baritone (dev mode) diff --git a/gradle.properties b/gradle.properties index 7de342db3..2e913968d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,13 +8,13 @@ org.gradle.caching=true org.gradle.warning.mode=all # Fabric Properties # check these on https://modmuss50.me/fabric.html -minecraft_version=1.19.4 -yarn_mappings=1.19.4+build.1 -loader_version=0.14.18 +minecraft_version=1.21 +yarn_mappings=1.21+build.9 +loader_version=0.15.11 # Mod Properties -mod_version=1.19.4-beta1 +mod_version=1.21-beta1 maven_group=gaucho-matrero.altoclef archives_base_name=altoclef # Dependencies # check this on https://modmuss50.me/fabric.html -fabric_version=0.76.0+1.19.4 +fabric_version=0.100.7+1.21 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e1bef7e87..19cfad969 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/adris/altoclef/AltoClef.java b/src/main/java/adris/altoclef/AltoClef.java index 21c497577..dcebbc204 100644 --- a/src/main/java/adris/altoclef/AltoClef.java +++ b/src/main/java/adris/altoclef/AltoClef.java @@ -231,9 +231,10 @@ private void initializeBaritoneSettings() { getClientBaritoneSettings().blocksToAvoid.value = List.of(Blocks.FLOWERING_AZALEA, Blocks.AZALEA, Blocks.POWDER_SNOW, Blocks.BIG_DRIPLEAF, Blocks.BIG_DRIPLEAF_STEM, Blocks.CAVE_VINES, Blocks.CAVE_VINES_PLANT, Blocks.TWISTING_VINES, Blocks.TWISTING_VINES_PLANT, Blocks.SWEET_BERRY_BUSH, - Blocks.WARPED_ROOTS, Blocks.VINE, Blocks.GRASS, Blocks.FERN, Blocks.TALL_GRASS, Blocks.LARGE_FERN, + Blocks.WARPED_ROOTS, Blocks.VINE, Blocks.GRASS_BLOCK, Blocks.FERN, Blocks.TALL_GRASS, Blocks.LARGE_FERN, Blocks.SMALL_AMETHYST_BUD, Blocks.MEDIUM_AMETHYST_BUD, Blocks.LARGE_AMETHYST_BUD, - Blocks.AMETHYST_CLUSTER, Blocks.SCULK, Blocks.SCULK_VEIN); + Blocks.AMETHYST_CLUSTER, Blocks.SCULK, Blocks.SCULK_VEIN, Blocks.SUNFLOWER, Blocks.LILAC, + Blocks.ROSE_BUSH, Blocks.PEONY); // Let baritone move items to hotbar to use them // Reduces a bit of far rendering to save FPS getClientBaritoneSettings().fadePath.value = true; diff --git a/src/main/java/adris/altoclef/AltoClefCommands.java b/src/main/java/adris/altoclef/AltoClefCommands.java index 431604ad7..dbd8417c0 100644 --- a/src/main/java/adris/altoclef/AltoClefCommands.java +++ b/src/main/java/adris/altoclef/AltoClefCommands.java @@ -36,7 +36,8 @@ public AltoClefCommands() throws CommandException { new SetGammaCommand(), new ListCommand(), new CoverWithSandCommand(), - new CoverWithBlocksCommand() + new CoverWithBlocksCommand(), + new SelfCareCommand() //new TestMoveInventoryCommand(), // new TestSwapInventoryCommand() ); diff --git a/src/main/java/adris/altoclef/Playground.java b/src/main/java/adris/altoclef/Playground.java index 945d037f8..42766eabc 100644 --- a/src/main/java/adris/altoclef/Playground.java +++ b/src/main/java/adris/altoclef/Playground.java @@ -10,6 +10,7 @@ import adris.altoclef.tasks.container.SmeltInFurnaceTask; import adris.altoclef.tasks.container.StoreInAnyContainerTask; import adris.altoclef.tasks.entity.KillEntityTask; +import adris.altoclef.tasks.entity.ShootArrowSimpleProjectileTask; import adris.altoclef.tasks.examples.ExampleTask2; import adris.altoclef.tasks.misc.EquipArmorTask; import adris.altoclef.tasks.misc.PlaceBedAndSetSpawnTask; @@ -31,7 +32,9 @@ import adris.altoclef.util.helpers.WorldHelper; import net.minecraft.block.Block; import net.minecraft.block.Blocks; +import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.mob.GhastEntity; import net.minecraft.entity.mob.ZombieEntity; import net.minecraft.item.Item; import net.minecraft.item.Items; @@ -43,6 +46,7 @@ import java.io.*; import java.util.List; +import java.util.Optional; import java.util.Scanner; /** @@ -335,6 +339,18 @@ public static void TEMP_TEST_FUNCTION(AltoClef mod, String arg) { new ItemTarget("netherite_leggings", 1), new ItemTarget("netherite_boots", 1))); break; + case "arrow": + + List ghasts = mod.getEntityTracker().getTrackedEntities(GhastEntity.class); + + if (ghasts.size() == 0) { + Debug.logWarning("No ghasts found."); + break; + } + + GhastEntity ghast = ghasts.get(0); + mod.runUserTask(new ShootArrowSimpleProjectileTask(ghast)); + break; case "whisper": { File check = new File("whisper.txt"); try { diff --git a/src/main/java/adris/altoclef/Settings.java b/src/main/java/adris/altoclef/Settings.java index 32e19c3dd..0ab8f6033 100644 --- a/src/main/java/adris/altoclef/Settings.java +++ b/src/main/java/adris/altoclef/Settings.java @@ -283,6 +283,19 @@ public class Settings implements IFailableConfigFile { */ private String idleCommand = ""; + + /** + * If set, will run this command after death. + * Also {deathmessage} will be replaced with the death message. + *

+ * For example, try setting this to "@goto " to make the bot go to the base before continuing the task it was given. + * Or setting it to "I died!" will send the i died message + * Or setting it to "/back" will execute /back on the server + * When running altoclef commands, if the prefix is not @, the set prefix should be used for the command and not @ + * You may run multiple commands even commands of differet type by splitting them with " & ". Example: /home & i died with message: {deathmessage} & @get diamond + */ + private String deathCommand = ""; + /** * If we need to throw away something, throw away these items first. */ @@ -507,6 +520,10 @@ public String getIdleCommand() { return idleCommand; } + public String getDeathCommand() { + return deathCommand; + } + public boolean shouldRunIdleCommandWhenNotActive() { return idleCommand != null && !idleCommand.isBlank(); } diff --git a/src/main/java/adris/altoclef/TaskCatalogue.java b/src/main/java/adris/altoclef/TaskCatalogue.java index 90ba145f7..1819331f5 100644 --- a/src/main/java/adris/altoclef/TaskCatalogue.java +++ b/src/main/java/adris/altoclef/TaskCatalogue.java @@ -71,7 +71,7 @@ public class TaskCatalogue { mine("diamond", MiningRequirement.IRON, new Block[]{Blocks.DIAMOND_ORE, Blocks.DEEPSLATE_DIAMOND_ORE}, Items.DIAMOND); mine("emerald", MiningRequirement.IRON, new Block[]{Blocks.EMERALD_ORE, Blocks.DEEPSLATE_EMERALD_ORE}, Items.EMERALD); mine("redstone", MiningRequirement.IRON, new Block[]{Blocks.REDSTONE_ORE, Blocks.DEEPSLATE_REDSTONE_ORE}, Items.REDSTONE); - mine("lapis_lazuli", MiningRequirement.IRON, new Block[]{Blocks.LAPIS_ORE, Blocks.DEEPSLATE_LAPIS_ORE}, Items.LAPIS_LAZULI); + mine("lapis_lazuli", MiningRequirement.STONE, new Block[]{Blocks.LAPIS_ORE, Blocks.DEEPSLATE_LAPIS_ORE}, Items.LAPIS_LAZULI); alias("lapis", "lapis_lazuli"); mine("amethyst_shard", MiningRequirement.WOOD, Blocks.AMETHYST_CLUSTER, Items.AMETHYST_SHARD); mine("pointed_dripstone", MiningRequirement.WOOD, Blocks.POINTED_DRIPSTONE, Items.POINTED_DRIPSTONE); @@ -88,6 +88,7 @@ public class TaskCatalogue { mine("acacia_sapling", Blocks.ACACIA_LEAVES, Items.ACACIA_SAPLING); mine("dark_oak_sapling", Blocks.DARK_OAK_LEAVES, Items.DARK_OAK_SAPLING); mine("mangrove_propagule", Blocks.MANGROVE_PROPAGULE, Items.MANGROVE_PROPAGULE); + mine("cherry_sapling", Blocks.CHERRY_LEAVES, Items.CHERRY_SAPLING); simple("sapling", ItemHelper.SAPLINGS, CollectSaplingsTask::new); simple("sandstone", Items.SANDSTONE, CollectSandstoneTask::new).dontMineIfPresent(); simple("red_sandstone", Items.RED_SANDSTONE, CollectRedSandstoneTask::new).dontMineIfPresent(); @@ -100,7 +101,7 @@ public class TaskCatalogue { simple("egg", Items.EGG, CollectEggsTask::new); mob("bone", Items.BONE, SkeletonEntity.class); mob("gunpowder", Items.GUNPOWDER, CreeperEntity.class); - mob("ender_pearl", Items.ENDER_PEARL, EndermanEntity.class).anyDimension(); + simple("ender_pearl", Items.ENDER_PEARL, KillEndermanTask::new); mob("spider_eye", Items.SPIDER_EYE, SpiderEntity.class); mob("leather", Items.LEATHER, CowEntity.class); mob("feather", Items.FEATHER, ChickenEntity.class); @@ -153,7 +154,7 @@ public class TaskCatalogue { } mine("bamboo", Blocks.BAMBOO, Items.BAMBOO); shear("vine", Blocks.VINE, Items.VINE).dontMineIfPresent(); - shear("grass", Blocks.GRASS, Items.GRASS).dontMineIfPresent(); + shear("grass", Blocks.GRASS_BLOCK, Items.GRASS_BLOCK).dontMineIfPresent(); shear("lily_pad", Blocks.LILY_PAD, Items.LILY_PAD).dontMineIfPresent(); shear("tall_grass", Blocks.TALL_GRASS, Items.TALL_GRASS).dontMineIfPresent(); shear("fern", Blocks.FERN, Items.FERN).dontMineIfPresent(); @@ -190,6 +191,9 @@ public class TaskCatalogue { // MATERIALS + //mine("netherite_upgrade_smithing_template", MiningRequirement.HAND, Blocks.CHEST, Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE).forceDimension(Dimension.NETHER); + simple("netherite_upgrade_smithing_template", Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, GetSmithingTemplateTask::new); + alias("netherite_upgrade", "netherite_upgrade_smithing_template"); simple("planks", ItemHelper.PLANKS, CollectPlanksTask::new).dontMineIfPresent(); // Per-tree Planks. At the moment, nether planks need to be specified that their logs are in the nether. for (CataloguedResource woodCatalogue : woodTasks("planks", wood -> wood.planks, (wood, count) -> { @@ -203,6 +207,11 @@ public class TaskCatalogue { // Don't mine individual planks either!! Handled internally. woodCatalogue.dontMineIfPresent(); } + simple("stripped_logs", ItemHelper.STRIPPED_LOGS, CollectStrippedLogTask::new).dontMineIfPresent(); + for (CataloguedResource woodCatalogue : woodTasks("stripped_logs", wood -> wood.strippedLog, + (wood, count) -> new CollectStrippedLogTask(wood.strippedLog, count))) { + woodCatalogue.dontMineIfPresent(); + } // shapedRecipe2x2("stick", Items.STICK, 4, p, o, p, o); simple("stick", Items.STICK, CollectSticksTask::new); smelt("stone", Items.STONE, "cobblestone").dontMineIfPresent(); @@ -243,6 +252,8 @@ public class TaskCatalogue { shapedRecipe2x2("sugar", Items.SUGAR, 1, "sugar_cane", o, o, o); shapedRecipe2x2("bone_meal", Items.BONE_MEAL, 3, "bone", o, o, o); shapedRecipe2x2("melon_seeds", Items.MELON_SEEDS, 1, "melon_slice", o, o, o); + shapedRecipe2x2("bamboo_planks", Items.BAMBOO_PLANKS, 2, "bamboo_block", o, o, o); + shapedRecipe3x3Block("bamboo_block", Items.BAMBOO_BLOCK, "bamboo"); simple("hay_block", Items.HAY_BLOCK, CollectHayBlockTask::new).dontMineIfPresent(); shapedRecipe2x2Block("polished_andesite", Items.POLISHED_ANDESITE, 4, "andesite"); shapedRecipe2x2Block("polished_diorite", Items.POLISHED_DIORITE, 4, "diorite"); @@ -276,6 +287,7 @@ public class TaskCatalogue { String b = "nether_brick"; shapedRecipe3x3("nether_brick_fence", Items.NETHER_BRICK_FENCE, 6, o, o, o, B, b, B, B, b, B); } + shapedRecipe3x3("brush", Items.BRUSH, 1, o, "feather", o, o, "copper_ingot", o, o, s, o); shapedRecipe3x3("paper", Items.PAPER, 3, "sugar_cane", "sugar_cane", "sugar_cane", o, o, o, o, o, o); shapedRecipe2x2("book", Items.BOOK, 1, "paper", "paper", "paper", "leather"); shapedRecipe2x2("writable_book", Items.WRITABLE_BOOK, 1, "book", "ink_sac", o, "feather"); @@ -459,6 +471,8 @@ public class TaskCatalogue { shapedRecipe3x3("observer", Items.OBSERVER, 1, c, c, c, "redstone", "redstone", "quartz", c, c, c); shapedRecipe2x2("lever", Items.LEVER, 1, s, o, c, o); } + simple("hanging_sign", ItemHelper.WOOD_HANGING_SIGN, CollectHangingSignTask::new).dontMineIfPresent(); + woodTasks("hanging_sign", woodItems -> woodItems.hangingSign, (woodItems, count) -> new CollectHangingSignTask(woodItems.hangingSign, woodItems.prefix + "_stripped_logs", count)); shapedRecipe3x3("chest", Items.CHEST, 1, p, p, p, p, o, p, p, p, p).dontMineIfPresent(); shapedRecipe2x2("torch", Items.TORCH, 4, "coal", o, s, o); simple("bed", ItemHelper.BED, CollectBedTask::new); @@ -483,6 +497,7 @@ public class TaskCatalogue { } { String b = "brick"; + shapedRecipe3x3("decorated_pot", Items.DECORATED_POT, 1, o, b, o, b, o, b, o, b, o); shapedRecipe3x3("flower_pot", Items.FLOWER_POT, 1, b, o, b, o, b, o, o, o, o); shapedRecipe2x2Block("bricks", Items.BRICKS, b); shapedRecipeSlab("brick_slab", Items.BRICK_SLAB, b); @@ -537,6 +552,7 @@ public class TaskCatalogue { woodTasks("fence_gate", woodItems -> woodItems.fenceGate, (woodItems, count) -> new CollectFenceGateTask(woodItems.fenceGate, woodItems.prefix + "_planks", count)); { String r = "wooden_slab"; + shapedRecipe3x3("chiseled_bookshelf", Items.CHISELED_BOOKSHELF, 1, p, p, p, r, r, r, p, p, p).dontMineIfPresent(); shapedRecipe3x3("barrel", Items.BARREL, 1, p, r, p, p, o, p, p, r, p); shapedRecipe3x3("cartography_table", Items.CARTOGRAPHY_TABLE, 1, "paper", "paper", o, p, p, o, p, p, o); shapedRecipe3x3("composter", Items.COMPOSTER, 1, r, o, r, r, o, r, r, r, r); @@ -715,6 +731,11 @@ private static CataloguedResource simple(String name, Item matches, Function getTask){ + // + //} + private static CataloguedResource mine(String name, MiningRequirement requirement, Item[] toMine, Item... targets) { Block[] toMineBlocks = new Block[toMine.length]; for (int i = 0; i < toMine.length; ++i) toMineBlocks[i] = Block.getBlockFromItem(toMine[i]); diff --git a/src/main/java/adris/altoclef/butler/Butler.java b/src/main/java/adris/altoclef/butler/Butler.java index d0476bf08..4b2fb1d3e 100644 --- a/src/main/java/adris/altoclef/butler/Butler.java +++ b/src/main/java/adris/altoclef/butler/Butler.java @@ -6,7 +6,9 @@ import adris.altoclef.eventbus.events.ChatMessageEvent; import adris.altoclef.eventbus.events.TaskFinishedEvent; import adris.altoclef.ui.MessagePriority; -import net.minecraft.client.MinecraftClient; +import net.minecraft.network.message.MessageType; + +import java.util.Objects; /** * The butler system lets authorized players send commands to the bot to execute. @@ -46,19 +48,26 @@ public Butler(AltoClef mod) { // Receive system events EventBus.subscribe(ChatMessageEvent.class, evt -> { boolean debug = ButlerConfig.getInstance().whisperFormatDebug; - String message = evt.toString(); - if (debug) { - Debug.logMessage("RECEIVED WHISPER: \"" + message + "\"."); + String message = evt.messageContent(); + String sender = evt.senderName(); + MessageType messageType = evt.messageType(); + String receiver = mod.getPlayer().getName().getString(); + if (sender != null && !Objects.equals(sender, receiver) && messageType.chat().style().isItalic() + && messageType.chat().style().getColor() != null + && Objects.equals(messageType.chat().style().getColor().getName(), "gray")) { + String wholeMessage = sender + " " + receiver + " " + message; + if (debug) { + Debug.logMessage("RECEIVED WHISPER: \"" + wholeMessage + "\"."); + } + _mod.getButler().receiveMessage(wholeMessage, receiver); } - _mod.getButler().receiveMessage(message); }); } - private void receiveMessage(String msg) { + private void receiveMessage(String msg, String receiver) { // Format: whispers to you: // Format: whispers: - String ourName = MinecraftClient.getInstance().getName(); - WhisperChecker.MessageResult result = this._whisperChecker.receiveMessage(_mod, ourName, msg); + WhisperChecker.MessageResult result = this._whisperChecker.receiveMessage(_mod, receiver, msg); if (result != null) { this.receiveWhisper(result.from, result.message); } else if (ButlerConfig.getInstance().whisperFormatDebug) { diff --git a/src/main/java/adris/altoclef/butler/ButlerConfig.java b/src/main/java/adris/altoclef/butler/ButlerConfig.java index 053cb1def..58558029e 100644 --- a/src/main/java/adris/altoclef/butler/ButlerConfig.java +++ b/src/main/java/adris/altoclef/butler/ButlerConfig.java @@ -17,7 +17,7 @@ public class ButlerConfig { /** * If true, will use whitelist to only accept users from said whitelist. */ - public boolean useButlerWhitelist = true; + public boolean useButlerWhitelist = false; /** * Servers have different messaging plugins that change the way messages are displayed. * Rather than attempt to implement all of them and introduce a big security risk, @@ -35,9 +35,7 @@ public class ButlerConfig { * create the following messages. */ public String[] whisperFormats = new String[]{ - "{from} whispers to you: {message}", - "{from} whispers: {message}", - "\\[{from} -> {to}\\] {message}" + "{from} {to} {message}" }; /** * If set to true, will print information about whispers that are parsed and those @@ -45,7 +43,7 @@ public class ButlerConfig { *

* Enable this if you need help setting up the whisper format. */ - public boolean whisperFormatDebug = false; + public boolean whisperFormatDebug = true; /** * Determines if failure messages should be sent to a non-authorized entity attempting to use butler *

diff --git a/src/main/java/adris/altoclef/chains/DeathMenuChain.java b/src/main/java/adris/altoclef/chains/DeathMenuChain.java index 25bee08bc..bd0cd08c2 100644 --- a/src/main/java/adris/altoclef/chains/DeathMenuChain.java +++ b/src/main/java/adris/altoclef/chains/DeathMenuChain.java @@ -2,15 +2,21 @@ import adris.altoclef.AltoClef; import adris.altoclef.Debug; +import adris.altoclef.mixins.DeathScreenAccessor; import adris.altoclef.tasksystem.TaskChain; import adris.altoclef.tasksystem.TaskRunner; import adris.altoclef.util.time.TimerGame; import adris.altoclef.util.time.TimerReal; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.*; +import net.minecraft.client.gui.screen.DeathScreen; +import net.minecraft.client.gui.screen.DisconnectedScreen; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.TitleScreen; +import net.minecraft.client.gui.screen.multiplayer.ConnectScreen; import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen; import net.minecraft.client.network.ServerAddress; import net.minecraft.client.network.ServerInfo; +import net.minecraft.text.Text; public class DeathMenuChain extends TaskChain { @@ -23,6 +29,7 @@ public class DeathMenuChain extends TaskChain { private int _deathCount = 0; private Class _prevScreen = null; + public DeathMenuChain(TaskRunner runner) { super(runner); } @@ -55,7 +62,6 @@ public float getPriority(AltoClef mod) { //MinecraftClient.getInstance().getCurrentServerEntry().address; // MinecraftClient.getInstance(). Screen screen = MinecraftClient.getInstance().currentScreen; - // This might fix Weird fail to respawn that happened only once if (_prevScreen == DeathScreen.class) { if (_deathRetryTimer.elapsed()) { @@ -78,8 +84,25 @@ public float getPriority(AltoClef mod) { _deathCount++; Debug.logMessage("RESPAWNING... (this is death #" + _deathCount + ")"); assert MinecraftClient.getInstance().player != null; + Text screenMessage = ((DeathScreenAccessor) screen).getMessage(); + String deathMessage = screenMessage != null ? screenMessage.getString() : "Unknown"; //"(not implemented yet)"; //screen.children().toString(); MinecraftClient.getInstance().player.requestRespawn(); MinecraftClient.getInstance().setScreen(null); + for (String i : mod.getModSettings().getDeathCommand().split(" & ")) { + String command = i.replace("{deathmessage}", deathMessage); + String prefix = mod.getModSettings().getCommandPrefix(); + while (MinecraftClient.getInstance().player.isAlive()) ; + if (!command.isEmpty()) { + if (command.startsWith(prefix)) { + AltoClef.getCommandExecutor().execute(command, () -> { + }, Throwable::printStackTrace); + } else if (command.startsWith("/")) { + MinecraftClient.getInstance().player.networkHandler.sendChatCommand(command.substring(1)); + } else { + MinecraftClient.getInstance().player.networkHandler.sendChatMessage(command); + } + } + } } else { // Cancel if we die and are not auto-respawning. mod.cancelUserTask(); @@ -107,7 +130,8 @@ public float getPriority(AltoClef mod) { Debug.logWarning("Failed to re-connect to server, no server entry cached."); } else { MinecraftClient client = MinecraftClient.getInstance(); - ConnectScreen.connect(screen, client, ServerAddress.parse(_prevServerEntry.address), _prevServerEntry); + ConnectScreen.connect(screen, client, ServerAddress.parse(_prevServerEntry.address), _prevServerEntry, false, null); + //ConnectScreen.connect(screen, client, ServerAddress.parse(_prevServerEntry.address), _prevServerEntry); //client.setScreen(new ConnectScreen(screen, client, _prevServerEntry)); } } diff --git a/src/main/java/adris/altoclef/chains/FoodChain.java b/src/main/java/adris/altoclef/chains/FoodChain.java index a57625d51..2915829af 100644 --- a/src/main/java/adris/altoclef/chains/FoodChain.java +++ b/src/main/java/adris/altoclef/chains/FoodChain.java @@ -10,8 +10,9 @@ import baritone.api.utils.input.Input; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.FoodComponent; import net.minecraft.entity.effect.StatusEffects; -import net.minecraft.item.FoodComponent; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; @@ -24,13 +25,13 @@ @SuppressWarnings("OptionalUsedAsFieldOrParameterType") public class FoodChain extends SingleTaskChain { private static FoodChainConfig _config; + private static boolean _hasFood; static { ConfigHelper.loadConfig("configs/food_chain_settings.json", FoodChainConfig::new, FoodChainConfig.class, newConfig -> _config = newConfig); } private final DragonBreathTracker _dragonBreathTracker = new DragonBreathTracker(); - boolean _hasFood; private boolean _isTryingToEat = false; private boolean _requestFillup = false; private boolean _needsFood = false; @@ -54,6 +55,7 @@ private void startEat(AltoClef mod, Item food) { mod.getInputControls().hold(Input.CLICK_RIGHT); mod.getExtraBaritoneSettings().setInteractionPaused(true); } + private void stopEat(AltoClef mod) { if (_isTryingToEat) { if (mod.getItemStorage().hasItem(Items.SHIELD) || mod.getItemStorage().hasItemInOffhand(Items.SHIELD)) { @@ -93,12 +95,6 @@ public float getPriority(AltoClef mod) { return Float.NEGATIVE_INFINITY; } } - - if (!AltoClef.inGame()) { - stopEat(mod); - return Float.NEGATIVE_INFINITY; - } - if (!mod.getModSettings().isAutoEat()) { stopEat(mod); return Float.NEGATIVE_INFINITY; @@ -126,25 +122,20 @@ public float getPriority(AltoClef mod) { Pair> calculation = calculateFood(mod); int _cachedFoodScore = calculation.getLeft(); _cachedPerfectFood = calculation.getRight(); - - boolean hasFood = _cachedFoodScore > 0; - _hasFood = hasFood; - + _hasFood = _cachedFoodScore > 0; // If we requested a fillup but we're full, stop. if (_requestFillup && mod.getPlayer().getHungerManager().getFoodLevel() >= 20) { _requestFillup = false; } // If we no longer have food, we no longer can eat. - if (!hasFood) { + if (!_hasFood) { _requestFillup = false; } - if (hasFood && (needsToEat() || _requestFillup) && _cachedPerfectFood.isPresent() && + if (_hasFood && (needsToEat() || _requestFillup) && _cachedPerfectFood.isPresent() && !mod.getMLGBucketChain().isChorusFruiting() && !mod.getPlayer().isBlocking()) { Item toUse = _cachedPerfectFood.get(); // Make sure we're not facing a container - if (!LookHelper.tryAvoidingInteractable(mod)) { - return Float.NEGATIVE_INFINITY; - } + LookHelper.tryAvoidingInteractable(mod); startEat(mod, toUse); } else { stopEat(mod); @@ -219,7 +210,7 @@ public boolean needsToEat() { if (foodLevel < _config.alwaysEatWhenBelowHungerAndPerfectFit && _cachedPerfectFood.isPresent()) { int need = 20 - foodLevel; Item best = _cachedPerfectFood.get(); - int fills = (best.getFoodComponent() != null) ? best.getFoodComponent().getHunger() : -1; + int fills = (best.getComponents().get(DataComponentTypes.FOOD) != null) ? Objects.requireNonNull(best.getComponents().get(DataComponentTypes.FOOD)).nutrition() : -1; return fills == need; } @@ -237,7 +228,7 @@ private Pair> calculateFood(AltoClef mod) { float saturation = player != null ? player.getHungerManager().getSaturationLevel() : 20; // Get best food item + calculate food total for (ItemStack stack : mod.getItemStorage().getItemStacksPlayerInventory(true)) { - if (stack.isFood()) { + if (stack.getItem().getComponents().contains(DataComponentTypes.FOOD)) { // Ignore protected items if (!ItemHelper.canThrowAwayStack(mod, stack)) continue; @@ -246,17 +237,17 @@ private Pair> calculateFood(AltoClef mod) { continue; } - FoodComponent food = stack.getItem().getFoodComponent(); + FoodComponent food = stack.getItem().getComponents().get(DataComponentTypes.FOOD); assert food != null; - float hungerIfEaten = Math.min(hunger + food.getHunger(), 20); - float saturationIfEaten = Math.min(hungerIfEaten, saturation + food.getSaturationModifier()); + float hungerIfEaten = Math.min(hunger + food.nutrition(), 20); + float saturationIfEaten = Math.min(hungerIfEaten, saturation + food.saturation()); float gainedSaturation = (saturationIfEaten - saturation); float gainedHunger = (hungerIfEaten - hunger); float hungerNotFilled = 20 - hungerIfEaten; - float saturationWasted = food.getSaturationModifier() - gainedSaturation; - float hungerWasted = food.getHunger() - gainedHunger; + float saturationWasted = food.saturation() - gainedSaturation; + float hungerWasted = food.nutrition() - gainedHunger; boolean prioritizeSaturation = health < _config.prioritizeSaturationWhenBelowHealth; float saturationGoodScore = prioritizeSaturation ? gainedSaturation * _config.foodPickPrioritizeSaturationSaturationMultiplier : gainedSaturation; @@ -274,7 +265,7 @@ private Pair> calculateFood(AltoClef mod) { bestFood = stack.getItem(); } - foodTotal += Objects.requireNonNull(stack.getItem().getFoodComponent()).getHunger() * stack.getCount(); + foodTotal += Objects.requireNonNull(stack.getItem().getComponents().get(DataComponentTypes.FOOD)).nutrition() * stack.getCount(); } } diff --git a/src/main/java/adris/altoclef/chains/MobDefenseChain.java b/src/main/java/adris/altoclef/chains/MobDefenseChain.java index ecb856a75..3f2546fba 100644 --- a/src/main/java/adris/altoclef/chains/MobDefenseChain.java +++ b/src/main/java/adris/altoclef/chains/MobDefenseChain.java @@ -14,19 +14,19 @@ import adris.altoclef.util.helpers.*; import adris.altoclef.util.slots.PlayerSlot; import adris.altoclef.util.slots.Slot; -import adris.altoclef.util.time.TimerGame; import baritone.Baritone; +import baritone.api.utils.Rotation; import baritone.api.utils.input.Input; import net.minecraft.block.AbstractFireBlock; import net.minecraft.block.Block; import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.component.DataComponentTypes; import net.minecraft.entity.Entity; import net.minecraft.entity.boss.WitherEntity; import net.minecraft.entity.effect.StatusEffects; import net.minecraft.entity.mob.*; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.projectile.DragonFireballEntity; -import net.minecraft.entity.projectile.FireballEntity; +import net.minecraft.entity.projectile.*; import net.minecraft.entity.projectile.thrown.PotionEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -36,7 +36,13 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; -import java.util.*; +import java.util.ArrayList; +import java.util.ConcurrentModificationException; +import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; + +import static java.lang.Math.abs; public class MobDefenseChain extends SingleTaskChain { private static final double DANGER_KEEP_DISTANCE = 30; @@ -44,11 +50,10 @@ public class MobDefenseChain extends SingleTaskChain { private static final double ARROW_KEEP_DISTANCE_HORIZONTAL = 2;//4; private static final double ARROW_KEEP_DISTANCE_VERTICAL = 10;//15; private static final double SAFE_KEEP_DISTANCE = 8; + private static boolean _shielding = false; private final DragonBreathTracker _dragonBreathTracker = new DragonBreathTracker(); private final KillAura _killAura = new KillAura(); - private final HashMap _closeAnnoyingEntities = new HashMap<>(); private Entity _targetEntity; - private boolean _shielding = false; private boolean _doingFunkyStuff = false; private boolean _wasPuttingOutFire = false; private CustomBaritoneGoalTask _runAwayTask; @@ -68,21 +73,15 @@ public static double getCreeperSafety(Vec3d pos, CreeperEntity creeper) { return distance * 0.2; // less is WORSE } - @Override - public float getPriority(AltoClef mod) { - _cachedLastPriority = getPriorityInner(mod); - return _cachedLastPriority; - } - - private void startShielding(AltoClef mod) { + private static void startShielding(AltoClef mod) { _shielding = true; mod.getInputControls().hold(Input.SNEAK); mod.getInputControls().hold(Input.CLICK_RIGHT); - mod.getClientBaritone().getPathingBehavior().softCancelIfSafe(); + mod.getClientBaritone().getPathingBehavior().requestPause(); mod.getExtraBaritoneSettings().setInteractionPaused(true); if (!mod.getPlayer().isBlocking()) { ItemStack handItem = StorageHelper.getItemStackInSlot(PlayerSlot.getEquipSlot()); - if (handItem.isFood()) { + if (handItem.getItem().getComponents().contains(DataComponentTypes.FOOD)) { List spaceSlots = mod.getItemStorage().getItemStacksPlayerInventory(false); if (!spaceSlots.isEmpty()) { for (ItemStack spaceSlot : spaceSlots) { @@ -98,10 +97,16 @@ private void startShielding(AltoClef mod) { } } + @Override + public float getPriority(AltoClef mod) { + _cachedLastPriority = getPriorityInner(mod); + return _cachedLastPriority; + } + private void stopShielding(AltoClef mod) { if (_shielding) { ItemStack cursor = StorageHelper.getItemStackInCursorSlot(); - if (cursor.isFood()) { + if (cursor.getItem().getComponents().contains(DataComponentTypes.FOOD)) { Optional toMoveTo = mod.getItemStorage().getSlotThatCanFitInPlayerInventory(cursor, false).or(() -> StorageHelper.getGarbageSlot(mod)); if (toMoveTo.isPresent()) { Slot garbageSlot = toMoveTo.get(); @@ -170,19 +175,23 @@ public float getPriorityInner(AltoClef mod) { // Run away if a weird mob is close by. Optional universallyDangerous = getUniversallyDangerousMob(mod); - if (universallyDangerous.isPresent()) { + if (universallyDangerous.isPresent() && mod.getPlayer().getHealth() <= 10) { _runAwayTask = new RunAwayFromHostilesTask(DANGER_KEEP_DISTANCE, true); setTask(_runAwayTask); return 70; } _doingFunkyStuff = false; + PlayerSlot offhandSlot = PlayerSlot.OFFHAND_SLOT; + Item offhandItem = StorageHelper.getItemStackInSlot(offhandSlot).getItem(); // Run away from creepers CreeperEntity blowingUp = getClosestFusingCreeper(mod); if (blowingUp != null) { if (!mod.getFoodChain().needsToEat() && (mod.getItemStorage().hasItem(Items.SHIELD) || mod.getItemStorage().hasItemInOffhand(Items.SHIELD)) && - !mod.getEntityTracker().entityFound(PotionEntity.class) && _runAwayTask == null) { + !mod.getEntityTracker().entityFound(PotionEntity.class) && _runAwayTask == null + && !mod.getPlayer().getItemCooldownManager().isCoolingDown(offhandItem) + && mod.getClientBaritone().getPathingBehavior().isSafeToCancel()) { _doingFunkyStuff = true; LookHelper.lookAt(mod, blowingUp.getEyePos()); ItemStack shieldSlot = StorageHelper.getItemStackInSlot(PlayerSlot.OFFHAND_SLOT); @@ -204,12 +213,11 @@ public float getPriorityInner(AltoClef mod) { } } // Block projectiles with shield - PlayerSlot offhandSlot = PlayerSlot.OFFHAND_SLOT; - Item offhandItem = StorageHelper.getItemStackInSlot(offhandSlot).getItem(); if (!mod.getFoodChain().needsToEat() && mod.getModSettings().isDodgeProjectiles() && isProjectileClose(mod) && (mod.getItemStorage().hasItem(Items.SHIELD) || mod.getItemStorage().hasItemInOffhand(Items.SHIELD)) && - !mod.getEntityTracker().entityFound(PotionEntity.class) && _runAwayTask == null && - !mod.getPlayer().getItemCooldownManager().isCoolingDown(offhandItem)) { + !mod.getEntityTracker().entityFound(PotionEntity.class) && _runAwayTask == null + && !mod.getPlayer().getItemCooldownManager().isCoolingDown(offhandItem) + && mod.getClientBaritone().getPathingBehavior().isSafeToCancel()) { ItemStack shieldSlot = StorageHelper.getItemStackInSlot(PlayerSlot.OFFHAND_SLOT); if (shieldSlot.getItem() != Items.SHIELD) { mod.getSlotHandler().forceEquipItemToOffhand(Items.SHIELD); @@ -256,68 +264,21 @@ public float getPriorityInner(AltoClef mod) { } List toDealWith = new ArrayList<>(); - // TODO: I don't think this lock is necessary at all. if (!hostiles.isEmpty()) { - synchronized (BaritoneHelper.MINECRAFT_LOCK) { - for (Entity hostile : hostiles) { - int annoyingRange = (hostile instanceof SkeletonEntity || hostile instanceof WitchEntity || hostile - instanceof PillagerEntity || hostile instanceof PiglinEntity || hostile instanceof StrayEntity) ? 15 : 8; - boolean isClose = hostile.isInRange(mod.getPlayer(), annoyingRange); - - if (isClose) { - isClose = LookHelper.seesPlayer(hostile, mod.getPlayer(), annoyingRange); - } - - // Give each hostile a timer, if they're close for too long deal with them. - if (isClose) { - if (!_closeAnnoyingEntities.containsKey(hostile)) { - boolean wardenAttacking = hostile instanceof WardenEntity; - boolean witherAttacking = hostile instanceof WitherEntity; - boolean endermanAttacking = hostile instanceof EndermanEntity; - boolean blazeAttacking = hostile instanceof BlazeEntity; - boolean witherSkeletonAttacking = hostile instanceof WitherSkeletonEntity; - boolean hoglinAttacking = hostile instanceof HoglinEntity; - boolean zoglinAttacking = hostile instanceof ZoglinEntity; - boolean piglinBruteAttacking = hostile instanceof PiglinBruteEntity; - if (blazeAttacking || witherSkeletonAttacking || hoglinAttacking || zoglinAttacking || - piglinBruteAttacking || endermanAttacking || witherAttacking || wardenAttacking) { - if (mod.getPlayer().getHealth() <= 10) { - _closeAnnoyingEntities.put(hostile, new TimerGame(0)); - } else { - _closeAnnoyingEntities.put(hostile, new TimerGame(Float.POSITIVE_INFINITY)); - } - } else { - _closeAnnoyingEntities.put(hostile, new TimerGame(0)); - } - _closeAnnoyingEntities.get(hostile).reset(); - } - if (_closeAnnoyingEntities.get(hostile).elapsed()) { - toDealWith.add(hostile); - } - } else { - _closeAnnoyingEntities.remove(hostile); + for (Entity entity : hostiles) { + if (entity instanceof MobEntity mob) { + boolean isAttackingPlayer = EntityHelper.isAngryAtPlayer(mod, mob); + if (isAttackingPlayer) { + toDealWith.add(mob); } } } } - - // Clear dead/non existing hostiles - List toRemove = new ArrayList<>(); - if (!_closeAnnoyingEntities.keySet().isEmpty()) { - for (Entity check : _closeAnnoyingEntities.keySet()) { - if (!check.isAlive()) { - toRemove.add(check); - } - } - } - if (!toRemove.isEmpty()) { - for (Entity remove : toRemove) _closeAnnoyingEntities.remove(remove); - } int numberOfProblematicEntities = toDealWith.size(); if (!toDealWith.isEmpty()) { for (Entity ToDealWith : toDealWith) { - if (ToDealWith.getClass() == SlimeEntity.class || ToDealWith.getClass() == MagmaCubeEntity.class) { + if (ToDealWith instanceof SlimeEntity) { numberOfProblematicEntities = 1; break; } @@ -355,31 +316,30 @@ public float getPriorityInner(AltoClef mod) { // We can deal with it. _runAwayTask = null; for (Entity ToDealWith : toDealWith) { + Predicate valid = entity -> EntityHelper.isAngryAtPlayer(mod, entity); + // Prioritize ranged enemies first. if (ToDealWith instanceof SkeletonEntity || ToDealWith instanceof WitchEntity || ToDealWith instanceof PillagerEntity || ToDealWith instanceof PiglinEntity || ToDealWith instanceof StrayEntity) { - setTask(new KillEntitiesTask(ToDealWith.getClass())); + setTask(new KillEntitiesTask(valid, ToDealWith.getClass())); return 65; } - setTask(new KillEntitiesTask(ToDealWith.getClass())); + setTask(new KillEntitiesTask(valid, ToDealWith.getClass())); return 65; } - return 65; - } else { - // We can't deal with it - _runAwayTask = new RunAwayFromHostilesTask(DANGER_KEEP_DISTANCE, true); - setTask(_runAwayTask); - return 80; } + // We can't deal with it + _runAwayTask = new RunAwayFromHostilesTask(DANGER_KEEP_DISTANCE, true); + setTask(_runAwayTask); + return 80; } } // By default if we aren't "immediately" in danger but were running away, keep running away until we're good. if (_runAwayTask != null && !_runAwayTask.isFinished(mod)) { setTask(_runAwayTask); return _cachedLastPriority; - } else { - _runAwayTask = null; } + _runAwayTask = null; return 0; } @@ -408,11 +368,15 @@ private BlockPos isInsideFireAndOnFire(AltoClef mod) { } private void putOutFire(AltoClef mod, BlockPos pos) { - LookHelper.lookAt(mod, pos); - Baritone b = mod.getClientBaritone(); - if (LookHelper.isLookingAt(mod, pos)) { - b.getPathingBehavior().requestPause(); - b.getInputOverrideHandler().setInputForceState(Input.CLICK_LEFT, true); + Optional reach = LookHelper.getReach(pos); + if (reach.isPresent()) { + Baritone b = mod.getClientBaritone(); + if (LookHelper.isLookingAt(mod, pos)) { + b.getPathingBehavior().requestPause(); + b.getInputOverrideHandler().setInputForceState(Input.CLICK_LEFT, true); + return; + } + LookHelper.lookAt(mod, reach.get()); } } @@ -463,19 +427,19 @@ private CreeperEntity getClosestFusingCreeper(AltoClef mod) { double worstSafety = Float.POSITIVE_INFINITY; CreeperEntity target = null; try { - List creepers = mod.getEntityTracker().getTrackedEntities(CreeperEntity.class); - if (!creepers.isEmpty()) { - for (CreeperEntity creeper : creepers) { - if (creeper == null) continue; - if (creeper.getClientFuseTime(1) < 0.001) continue; - + Optional creeper = mod.getEntityTracker().getClosestEntity(CreeperEntity.class); + if (creeper.isPresent()) { + CreeperEntity creeperEntity = (CreeperEntity) creeper.get(); + if (!(creeperEntity.getClientFuseTime(1) < 0.001)) { // We want to pick the closest creeper, but FIRST pick creepers about to blow // At max fuse, the cost goes to basically zero. - double safety = getCreeperSafety(mod.getPlayer().getPos(), creeper); + double safety = getCreeperSafety(mod.getPlayer().getPos(), creeperEntity); if (safety < worstSafety) { - target = creeper; + target = creeperEntity; } } + ; + } } catch (ConcurrentModificationException | ArrayIndexOutOfBoundsException | NullPointerException e) { // IDK why but these exceptions happen sometimes. It's extremely bizarre and I have no idea why. @@ -495,8 +459,9 @@ private boolean isProjectileClose(AltoClef mod) { if (isGhastBall) { Optional ghastBall = mod.getEntityTracker().getClosestEntity(FireballEntity.class); Optional ghast = mod.getEntityTracker().getClosestEntity(GhastEntity.class); - if (ghastBall.isPresent() && ghast.isPresent() && _runAwayTask == null) { - mod.getClientBaritone().getPathingBehavior().softCancelIfSafe(); + if (ghastBall.isPresent() && ghast.isPresent() && _runAwayTask == null + && mod.getClientBaritone().getPathingBehavior().isSafeToCancel()) { + mod.getClientBaritone().getPathingBehavior().requestPause(); LookHelper.lookAt(mod, ghast.get().getEyePos()); } return false; @@ -506,6 +471,17 @@ private boolean isProjectileClose(AltoClef mod) { // Ignore dragon fireballs return false; } + if (projectile.projectileType == ArrowEntity.class || projectile.projectileType == SpectralArrowEntity.class || projectile.projectileType == SmallFireballEntity.class) { + // check if the velocity of the projectile is going away from us + // oh no fancy math + Vec3d velocity = projectile.velocity; + Vec3d delta = mod.getPlayer().getPos().subtract(projectile.position); + double epsilon = 0.25; + if (abs(velocity.dotProduct(delta)) <= epsilon) { + // Arrow is going away from us, ignore it. + continue; + } + } Vec3d expectedHit = ProjectileHelper.calculateArrowClosestApproach(projectile, mod.getPlayer()); @@ -514,11 +490,21 @@ private boolean isProjectileClose(AltoClef mod) { //Debug.logMessage("EXPECTED HIT OFFSET: " + delta + " ( " + projectile.gravity + ")"); double horizontalDistanceSq = delta.x * delta.x + delta.z * delta.z; - double verticalDistance = Math.abs(delta.y); + double verticalDistance = abs(delta.y); if (horizontalDistanceSq < ARROW_KEEP_DISTANCE_HORIZONTAL * ARROW_KEEP_DISTANCE_HORIZONTAL && verticalDistance < ARROW_KEEP_DISTANCE_VERTICAL) { - if (_runAwayTask == null) { - mod.getClientBaritone().getPathingBehavior().softCancelIfSafe(); + if (_runAwayTask == null && mod.getClientBaritone().getPathingBehavior().isSafeToCancel()) { + mod.getClientBaritone().getPathingBehavior().requestPause(); + if (projectile.projectileType instanceof ProjectileEntity projectileEntity) { + Entity owner = projectileEntity.getOwner(); + if (owner != null) { + LookHelper.lookAt(mod, owner.getEyePos()); + return true; + } + LookHelper.lookAt(mod, projectile.position); + return true; + } LookHelper.lookAt(mod, projectile.position); + return true; } return true; } @@ -577,6 +563,13 @@ private Optional getUniversallyDangerousMob(AltoClef mod) { return piglinBrute; } } + Optional vindicator = mod.getEntityTracker().getClosestEntity(VindicatorEntity.class); + if (vindicator.isPresent()) { + double range = SAFE_KEEP_DISTANCE - 2; + if (vindicator.get().squaredDistanceTo(mod.getPlayer()) < range * range && EntityHelper.isAngryAtPlayer(mod, vindicator.get())) { + return vindicator; + } + } return Optional.empty(); } diff --git a/src/main/java/adris/altoclef/chains/PlayerInteractionFixChain.java b/src/main/java/adris/altoclef/chains/PlayerInteractionFixChain.java index 5a49219b6..602b43f39 100644 --- a/src/main/java/adris/altoclef/chains/PlayerInteractionFixChain.java +++ b/src/main/java/adris/altoclef/chains/PlayerInteractionFixChain.java @@ -7,18 +7,15 @@ import adris.altoclef.util.helpers.ItemHelper; import adris.altoclef.util.helpers.LookHelper; import adris.altoclef.util.helpers.StorageHelper; -import adris.altoclef.util.slots.PlayerSlot; import adris.altoclef.util.slots.Slot; import adris.altoclef.util.time.TimerGame; import baritone.api.utils.Rotation; import baritone.api.utils.input.Input; -import net.minecraft.block.BlockState; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.ChatScreen; import net.minecraft.client.gui.screen.DeathScreen; import net.minecraft.client.gui.screen.GameMenuScreen; import net.minecraft.client.gui.screen.Screen; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.screen.slot.SlotActionType; @@ -58,31 +55,31 @@ public float getPriority(AltoClef mod) { if (!AltoClef.inGame()) return Float.NEGATIVE_INFINITY; - if (mod.getUserTaskChain().isActive() && _betterToolTimer.elapsed()) { - // Equip the right tool for the job if we're not using one. - _betterToolTimer.reset(); - if (mod.getControllerExtras().isBreakingBlock()) { - BlockState state = mod.getWorld().getBlockState(mod.getControllerExtras().getBreakingBlockPos()); - Optional bestToolSlot = StorageHelper.getBestToolSlot(mod, state); - Slot currentEquipped = PlayerSlot.getEquipSlot(); - - // if baritone is running, only accept tools OUTSIDE OF HOTBAR! - // Baritone will take care of tools inside the hotbar. - if (bestToolSlot.isPresent() && !bestToolSlot.get().equals(currentEquipped)) { - // ONLY equip if the item class is STRICTLY different (otherwise we swap around a lot) - if (StorageHelper.getItemStackInSlot(currentEquipped).getItem() != StorageHelper.getItemStackInSlot(bestToolSlot.get()).getItem()) { - boolean isAllowedToManage = (!mod.getClientBaritone().getPathingBehavior().isPathing() || - bestToolSlot.get().getInventorySlot() >= 9) && !mod.getFoodChain().isTryingToEat(); - if (isAllowedToManage) { - Debug.logMessage("Found better tool in inventory, equipping."); - ItemStack bestToolItemStack = StorageHelper.getItemStackInSlot(bestToolSlot.get()); - Item bestToolItem = bestToolItemStack.getItem(); - mod.getSlotHandler().forceEquipItem(bestToolItem); - } - } - } - } - } +// if (mod.getUserTaskChain().isActive() && _betterToolTimer.elapsed()) { +// // Equip the right tool for the job if we're not using one. +// _betterToolTimer.reset(); +// if (mod.getControllerExtras().isBreakingBlock()) { +// BlockState state = mod.getWorld().getBlockState(mod.getControllerExtras().getBreakingBlockPos()); +// Optional bestToolSlot = StorageHelper.getBestToolSlot(mod, state); +// Slot currentEquipped = PlayerSlot.getEquipSlot(); +// +// // if baritone is running, only accept tools OUTSIDE OF HOTBAR! +// // Baritone will take care of tools inside the hotbar. +// if (bestToolSlot.isPresent() && !bestToolSlot.get().equals(currentEquipped)) { +// // ONLY equip if the item class is STRICTLY different (otherwise we swap around a lot) +// if (StorageHelper.getItemStackInSlot(currentEquipped).getItem() != StorageHelper.getItemStackInSlot(bestToolSlot.get()).getItem()) { +// boolean isAllowedToManage = (!mod.getClientBaritone().getPathingBehavior().isPathing() || +// bestToolSlot.get().getInventorySlot() >= 9) && !mod.getFoodChain().isTryingToEat(); +// if (isAllowedToManage) { +// Debug.logMessage("Found better tool in inventory, equipping."); +// ItemStack bestToolItemStack = StorageHelper.getItemStackInSlot(bestToolSlot.get()); +// Item bestToolItem = bestToolItemStack.getItem(); +// mod.getSlotHandler().forceEquipItem(bestToolItem); +// } +// } +// } +// } +// } // Unpress shift (it gets stuck for some reason???) if (mod.getInputControls().isHeldDown(Input.SNEAK)) { diff --git a/src/main/java/adris/altoclef/commands/CoordsCommand.java b/src/main/java/adris/altoclef/commands/CoordsCommand.java index 496409997..14b04e7d0 100644 --- a/src/main/java/adris/altoclef/commands/CoordsCommand.java +++ b/src/main/java/adris/altoclef/commands/CoordsCommand.java @@ -7,7 +7,7 @@ public class CoordsCommand extends Command { public CoordsCommand() { - super("coords", "Get bot's current coordinates"); + super("coords", "Get the bot's current coordinates"); } @Override diff --git a/src/main/java/adris/altoclef/commands/CoverWithBlocksCommand.java b/src/main/java/adris/altoclef/commands/CoverWithBlocksCommand.java index 12b59bb80..fb9a549b9 100644 --- a/src/main/java/adris/altoclef/commands/CoverWithBlocksCommand.java +++ b/src/main/java/adris/altoclef/commands/CoverWithBlocksCommand.java @@ -8,7 +8,7 @@ public class CoverWithBlocksCommand extends Command { public CoverWithBlocksCommand() { - super("coverwithblocks", "Cover nether lava with blocks."); + super("coverwithblocks", "Cover nether lava with blocks"); } @Override diff --git a/src/main/java/adris/altoclef/commands/CoverWithSandCommand.java b/src/main/java/adris/altoclef/commands/CoverWithSandCommand.java index 86ac74574..60b6d61bf 100644 --- a/src/main/java/adris/altoclef/commands/CoverWithSandCommand.java +++ b/src/main/java/adris/altoclef/commands/CoverWithSandCommand.java @@ -8,7 +8,7 @@ public class CoverWithSandCommand extends Command { public CoverWithSandCommand() { - super("coverwithsand", "Cover nether lava with sand."); + super("coverwithsand", "Cover nether lava with sand"); } @Override diff --git a/src/main/java/adris/altoclef/commands/GotoCommand.java b/src/main/java/adris/altoclef/commands/GotoCommand.java index 68b6d81f8..f0f6bd0fa 100644 --- a/src/main/java/adris/altoclef/commands/GotoCommand.java +++ b/src/main/java/adris/altoclef/commands/GotoCommand.java @@ -21,7 +21,7 @@ public GotoCommand() throws CommandException { // x y z dimension // (dimension) // (x z dimension) - super("goto", "Tell bot to travel to a set of coordinates.", + super("goto", "Tell bot to travel to a set of coordinates", new Arg(GotoTarget.class, "[x y z dimension]/[x z dimension]/[y dimension]/[dimension]/[x y z]/[x z]/[y]") ); } diff --git a/src/main/java/adris/altoclef/commands/HeroCommand.java b/src/main/java/adris/altoclef/commands/HeroCommand.java index f74138ab3..14600522d 100644 --- a/src/main/java/adris/altoclef/commands/HeroCommand.java +++ b/src/main/java/adris/altoclef/commands/HeroCommand.java @@ -8,7 +8,7 @@ public class HeroCommand extends Command { public HeroCommand() { - super("hero", "Kill all hostile mobs."); + super("hero", "Kill all hostile mobs"); } @Override diff --git a/src/main/java/adris/altoclef/commands/MarvionCommand.java b/src/main/java/adris/altoclef/commands/MarvionCommand.java index 700ae54b3..5ff363e55 100644 --- a/src/main/java/adris/altoclef/commands/MarvionCommand.java +++ b/src/main/java/adris/altoclef/commands/MarvionCommand.java @@ -7,7 +7,7 @@ public class MarvionCommand extends Command { public MarvionCommand() { - super("marvion", "Beats the game (Marvion version)."); + super("marvion", "Beats the game (Marvion version)"); } @Override diff --git a/src/main/java/adris/altoclef/commands/SelfCareCommand.java b/src/main/java/adris/altoclef/commands/SelfCareCommand.java new file mode 100644 index 000000000..257fe2b1e --- /dev/null +++ b/src/main/java/adris/altoclef/commands/SelfCareCommand.java @@ -0,0 +1,17 @@ +package adris.altoclef.commands; + +import adris.altoclef.AltoClef; +import adris.altoclef.commandsystem.ArgParser; +import adris.altoclef.commandsystem.Command; +import adris.altoclef.tasks.entity.SelfCareTask; + +public class SelfCareCommand extends Command { + public SelfCareCommand() { + super("selfcare", "Care for self (Not finished and tested yet)"); + } + + @Override + protected void call(AltoClef mod, ArgParser parser) { + mod.runUserTask(new SelfCareTask(), this::finish); + } +} diff --git a/src/main/java/adris/altoclef/commands/SetGammaCommand.java b/src/main/java/adris/altoclef/commands/SetGammaCommand.java index 817259ba4..472a0bd91 100644 --- a/src/main/java/adris/altoclef/commands/SetGammaCommand.java +++ b/src/main/java/adris/altoclef/commands/SetGammaCommand.java @@ -11,7 +11,7 @@ public class SetGammaCommand extends Command { public SetGammaCommand() throws CommandException { - super("gamma", "sets the brightness to a value", new Arg(Double.class, "gamma", 1.0, 0)); + super("gamma", "Sets the brightness to a value", new Arg<>(Double.class, "gamma", 1.0, 0)); } @Override diff --git a/src/main/java/adris/altoclef/control/KillAura.java b/src/main/java/adris/altoclef/control/KillAura.java index 4d6058a33..344180220 100644 --- a/src/main/java/adris/altoclef/control/KillAura.java +++ b/src/main/java/adris/altoclef/control/KillAura.java @@ -8,6 +8,7 @@ import adris.altoclef.util.slots.Slot; import adris.altoclef.util.time.TimerGame; import baritone.api.utils.input.Input; +import net.minecraft.component.DataComponentTypes; import net.minecraft.entity.Entity; import net.minecraft.entity.boss.WitherEntity; import net.minecraft.entity.mob.*; @@ -71,30 +72,30 @@ public void setRange(double range) { } public void tickEnd(AltoClef mod) { - PlayerSlot offhandSlot = PlayerSlot.OFFHAND_SLOT; - Item offhandItem = StorageHelper.getItemStackInSlot(offhandSlot).getItem(); Optional entities = _targets.stream().min(StlHelper.compareValues(entity -> entity.squaredDistanceTo(mod.getPlayer()))); if (entities.isPresent() && mod.getPlayer().getHealth() >= 10 && !mod.getEntityTracker().entityFound(PotionEntity.class) && !mod.getFoodChain().needsToEat() && - (mod.getItemStorage().hasItem(Items.SHIELD) || mod.getItemStorage().hasItemInOffhand(Items.SHIELD)) && (Double.isInfinite(_forceFieldRange) || entities.get().squaredDistanceTo(mod.getPlayer()) < _forceFieldRange * _forceFieldRange || entities.get().squaredDistanceTo(mod.getPlayer()) < 40) && !mod.getMLGBucketChain().isFallingOhNo(mod) && mod.getMLGBucketChain().doneMLG() && - !mod.getMLGBucketChain().isChorusFruiting() && - !mod.getPlayer().getItemCooldownManager().isCoolingDown(offhandItem)) { + !mod.getMLGBucketChain().isChorusFruiting()) { + PlayerSlot offhandSlot = PlayerSlot.OFFHAND_SLOT; + Item offhandItem = StorageHelper.getItemStackInSlot(offhandSlot).getItem(); if (entities.get().getClass() != CreeperEntity.class && entities.get().getClass() != HoglinEntity.class && entities.get().getClass() != ZoglinEntity.class && entities.get().getClass() != WardenEntity.class && - entities.get().getClass() != WitherEntity.class) { + entities.get().getClass() != WitherEntity.class + && (mod.getItemStorage().hasItem(Items.SHIELD) || mod.getItemStorage().hasItemInOffhand(Items.SHIELD)) + && !mod.getPlayer().getItemCooldownManager().isCoolingDown(offhandItem) + && mod.getClientBaritone().getPathingBehavior().isSafeToCancel()) { LookHelper.lookAt(mod, entities.get().getEyePos()); ItemStack shieldSlot = StorageHelper.getItemStackInSlot(PlayerSlot.OFFHAND_SLOT); if (shieldSlot.getItem() != Items.SHIELD) { mod.getSlotHandler().forceEquipItemToOffhand(Items.SHIELD); } else { startShielding(mod); - performDelayedAttack(mod); - return; } } + performDelayedAttack(mod); } else { stopShielding(mod); } @@ -201,11 +202,11 @@ public void startShielding(AltoClef mod) { _shielding = true; mod.getInputControls().hold(Input.SNEAK); mod.getInputControls().hold(Input.CLICK_RIGHT); - mod.getClientBaritone().getPathingBehavior().softCancelIfSafe(); + mod.getClientBaritone().getPathingBehavior().requestPause(); mod.getExtraBaritoneSettings().setInteractionPaused(true); if (!mod.getPlayer().isBlocking()) { ItemStack handItem = StorageHelper.getItemStackInSlot(PlayerSlot.getEquipSlot()); - if (handItem.isFood()) { + if (handItem.getItem().getComponents().contains(DataComponentTypes.FOOD)) { List spaceSlots = mod.getItemStorage().getItemStacksPlayerInventory(false); if (!spaceSlots.isEmpty()) { for (ItemStack spaceSlot : spaceSlots) { @@ -224,7 +225,7 @@ public void startShielding(AltoClef mod) { public void stopShielding(AltoClef mod) { if (_shielding) { ItemStack cursor = StorageHelper.getItemStackInCursorSlot(); - if (cursor.isFood()) { + if (cursor.getItem().getComponents().contains(DataComponentTypes.FOOD)) { Optional toMoveTo = mod.getItemStorage().getSlotThatCanFitInPlayerInventory(cursor, false).or(() -> StorageHelper.getGarbageSlot(mod)); if (toMoveTo.isPresent()) { Slot garbageSlot = toMoveTo.get(); diff --git a/src/main/java/adris/altoclef/eventbus/events/ChatMessageEvent.java b/src/main/java/adris/altoclef/eventbus/events/ChatMessageEvent.java index 44b1a8e4c..d9cc2ca63 100644 --- a/src/main/java/adris/altoclef/eventbus/events/ChatMessageEvent.java +++ b/src/main/java/adris/altoclef/eventbus/events/ChatMessageEvent.java @@ -1,14 +1,31 @@ package adris.altoclef.eventbus.events; -import net.minecraft.network.packet.s2c.play.ChatMessageS2CPacket; +import com.mojang.authlib.GameProfile; +import net.minecraft.network.message.MessageType; +import net.minecraft.network.message.SignedMessage; /** * Whenever chat appears */ public class ChatMessageEvent { - ChatMessageS2CPacket packet; + SignedMessage message; + GameProfile sender; + MessageType.Parameters messageType; - public ChatMessageEvent(ChatMessageS2CPacket packet) { - this.packet = packet; + public ChatMessageEvent(SignedMessage message, GameProfile sender, MessageType.Parameters messageType) { + this.message = message; + this.sender = sender; + this.messageType = messageType; + } + public String messageContent() { + return message.getContent().getString(); + } + + public String senderName() { + return sender.getName(); + } + + public MessageType messageType() { + return messageType.type().value(); } } diff --git a/src/main/java/adris/altoclef/eventbus/events/ClientRenderEvent.java b/src/main/java/adris/altoclef/eventbus/events/ClientRenderEvent.java index 32d27a888..be711daf5 100644 --- a/src/main/java/adris/altoclef/eventbus/events/ClientRenderEvent.java +++ b/src/main/java/adris/altoclef/eventbus/events/ClientRenderEvent.java @@ -1,12 +1,13 @@ package adris.altoclef.eventbus.events; +import net.minecraft.client.render.RenderTickCounter; import net.minecraft.client.util.math.MatrixStack; public class ClientRenderEvent { public MatrixStack stack; - public float tickDelta; + public RenderTickCounter tickDelta; - public ClientRenderEvent(MatrixStack stack, float tickDelta) { + public ClientRenderEvent(MatrixStack stack, RenderTickCounter tickDelta) { this.stack = stack; this.tickDelta = tickDelta; } diff --git a/src/main/java/adris/altoclef/mixins/BlockModifiedByPlayerMixin.java b/src/main/java/adris/altoclef/mixins/BlockModifiedByPlayerMixin.java index 1e7c5177c..f289a2344 100644 --- a/src/main/java/adris/altoclef/mixins/BlockModifiedByPlayerMixin.java +++ b/src/main/java/adris/altoclef/mixins/BlockModifiedByPlayerMixin.java @@ -14,6 +14,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(Block.class) public class BlockModifiedByPlayerMixin { @@ -22,8 +23,8 @@ public class BlockModifiedByPlayerMixin { method = "onBreak", at = @At("HEAD") ) - public void onBlockBroken(World world, BlockPos pos, BlockState state, PlayerEntity player, CallbackInfo ci) { - if (player.world == world) { + public void onBlockBroken(World world, BlockPos pos, BlockState state, PlayerEntity player, CallbackInfoReturnable ci) { + if (player.getWorld() == world) { BlockBrokenEvent evt = new BlockBrokenEvent(); evt.blockPos = pos; evt.blockState = state; diff --git a/src/main/java/adris/altoclef/mixins/ChatReadMixin.java b/src/main/java/adris/altoclef/mixins/ChatReadMixin.java index 8cfc5999c..ced4ed2d9 100644 --- a/src/main/java/adris/altoclef/mixins/ChatReadMixin.java +++ b/src/main/java/adris/altoclef/mixins/ChatReadMixin.java @@ -2,22 +2,24 @@ import adris.altoclef.eventbus.EventBus; import adris.altoclef.eventbus.events.ChatMessageEvent; -import net.minecraft.client.network.ClientPlayNetworkHandler; -import net.minecraft.network.packet.s2c.play.ChatMessageS2CPacket; +import com.mojang.authlib.GameProfile; +import net.minecraft.client.network.message.MessageHandler; +import net.minecraft.network.message.MessageType; +import net.minecraft.network.message.SignedMessage; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(ClientPlayNetworkHandler.class) +@Mixin(MessageHandler.class) public final class ChatReadMixin { @Inject( method = "onChatMessage", at = @At("HEAD") ) - private void onChatMessage(ChatMessageS2CPacket packet, CallbackInfo ci) { - ChatMessageEvent evt = new ChatMessageEvent(packet); + private void onChatMessage(SignedMessage message, GameProfile sender, MessageType.Parameters params, CallbackInfo ci) { + ChatMessageEvent evt = new ChatMessageEvent(message, sender, params); EventBus.publish(evt); } } \ No newline at end of file diff --git a/src/main/java/adris/altoclef/mixins/ClientUIMixin.java b/src/main/java/adris/altoclef/mixins/ClientUIMixin.java index 8e508381d..122845353 100644 --- a/src/main/java/adris/altoclef/mixins/ClientUIMixin.java +++ b/src/main/java/adris/altoclef/mixins/ClientUIMixin.java @@ -2,8 +2,9 @@ import adris.altoclef.eventbus.EventBus; import adris.altoclef.eventbus.events.ClientRenderEvent; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.hud.InGameHud; -import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.render.RenderTickCounter; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -15,7 +16,7 @@ public final class ClientUIMixin { method = "render", at = @At("TAIL") ) - private void clientRender(MatrixStack stack, float tickDelta, CallbackInfo ci) { - EventBus.publish(new ClientRenderEvent(stack, tickDelta)); + private void clientRender(DrawContext context, RenderTickCounter tickDelta, CallbackInfo ci) { + EventBus.publish(new ClientRenderEvent(context.getMatrices(), tickDelta)); } } diff --git a/src/main/java/adris/altoclef/mixins/DeathScreenAccessor.java b/src/main/java/adris/altoclef/mixins/DeathScreenAccessor.java new file mode 100644 index 000000000..56951fe44 --- /dev/null +++ b/src/main/java/adris/altoclef/mixins/DeathScreenAccessor.java @@ -0,0 +1,13 @@ +package adris.altoclef.mixins; + +import net.minecraft.client.gui.screen.DeathScreen; +import net.minecraft.text.Text; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + + +@Mixin(DeathScreen.class) +public interface DeathScreenAccessor { + @Accessor("message") + Text getMessage(); +} \ No newline at end of file diff --git a/src/main/java/adris/altoclef/mixins/EntityAccessor.java b/src/main/java/adris/altoclef/mixins/EntityAccessor.java deleted file mode 100644 index 77428d632..000000000 --- a/src/main/java/adris/altoclef/mixins/EntityAccessor.java +++ /dev/null @@ -1,11 +0,0 @@ -package adris.altoclef.mixins; - -import net.minecraft.entity.Entity; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(Entity.class) -public interface EntityAccessor { - @Accessor("inNetherPortal") - boolean isInNetherPortal(); -} diff --git a/src/main/java/adris/altoclef/mixins/LoadChunkMixin.java b/src/main/java/adris/altoclef/mixins/LoadChunkMixin.java index 97dfdd9bc..6b19b1e5a 100644 --- a/src/main/java/adris/altoclef/mixins/LoadChunkMixin.java +++ b/src/main/java/adris/altoclef/mixins/LoadChunkMixin.java @@ -20,19 +20,36 @@ @Mixin(ClientChunkManager.class) public class LoadChunkMixin { + /** + * Loads a chunk from a packet and executes necessary actions. + * + * @param x The x-coordinate of the chunk. + * @param z The z-coordinate of the chunk. + * @param buf The packet containing the chunk data. + * @param nbt The NBT compound of the chunk. + * @param consumer A consumer for visiting block entities in the chunk. + * @param ci The callback info returnable object. + */ @Inject( method = "loadChunkFromPacket", at = @At("RETURN") ) private void onLoadChunk(int x, int z, PacketByteBuf buf, NbtCompound nbt, Consumer consumer, CallbackInfoReturnable ci) { + // Publish a ChunkLoadEvent with the return value of the method as the argument EventBus.publish(new ChunkLoadEvent(ci.getReturnValue())); } + /** + * Publishes a ChunkUnloadEvent when a chunk is unloaded. + * + * @param pos The position of the unloaded chunk. + * @param ci The callback info object. + */ @Inject( method = "unload", at = @At("TAIL") ) - private void onChunkUnload(int x, int z, CallbackInfo ci) { - EventBus.publish(new ChunkUnloadEvent(new ChunkPos(x, z))); + private void onChunkUnload(ChunkPos pos, CallbackInfo ci) { + EventBus.publish(new ChunkUnloadEvent(pos)); } } diff --git a/src/main/java/adris/altoclef/tasks/CraftGenericWithRecipeBooksTask.java b/src/main/java/adris/altoclef/tasks/CraftGenericWithRecipeBooksTask.java index 06c36de35..408218368 100644 --- a/src/main/java/adris/altoclef/tasks/CraftGenericWithRecipeBooksTask.java +++ b/src/main/java/adris/altoclef/tasks/CraftGenericWithRecipeBooksTask.java @@ -1,17 +1,22 @@ package adris.altoclef.tasks; import adris.altoclef.AltoClef; +import adris.altoclef.Debug; import adris.altoclef.tasks.slot.EnsureFreePlayerCraftingGridTask; import adris.altoclef.tasks.slot.ReceiveCraftingOutputSlotTask; import adris.altoclef.tasksystem.ITaskUsesCraftingGrid; import adris.altoclef.tasksystem.Task; +import adris.altoclef.util.JankCraftingRecipeMapping; import adris.altoclef.util.RecipeTarget; import adris.altoclef.util.helpers.ItemHelper; import adris.altoclef.util.helpers.StorageHelper; import adris.altoclef.util.slots.CraftingTableSlot; import adris.altoclef.util.slots.PlayerSlot; import adris.altoclef.util.slots.Slot; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.item.ItemStack; +import net.minecraft.recipe.RecipeEntry; import net.minecraft.screen.slot.SlotActionType; import java.util.Optional; @@ -24,96 +29,176 @@ public CraftGenericWithRecipeBooksTask(RecipeTarget target) { _target = target; } + /** + * This method is called when the mod starts. + * + * @param mod The AltoClef mod instance. + */ @Override protected void onStart(AltoClef mod) { } + /** + * This method handles the logic for the onTick event. + * It checks various conditions and performs actions accordingly. + * + * @param mod The instance of the mod. + * @return The next task to execute. + */ @Override protected Task onTick(AltoClef mod) { - boolean bigCrafting = StorageHelper.isBigCraftingOpen(); - if (!bigCrafting && !StorageHelper.isPlayerInventoryOpen()) { - ItemStack cursorStack = StorageHelper.getItemStackInCursorSlot(); + // Check if the big crafting UI or player inventory UI is open + boolean isBigCraftingOpen = StorageHelper.isBigCraftingOpen(); + boolean isPlayerInventoryOpen = StorageHelper.isPlayerInventoryOpen(); + + // Get the item stack in the cursor slot + ItemStack cursorStack = StorageHelper.getItemStackInCursorSlot(); + + // Declare variables for the slots to move to and the garbage slot + Optional moveTo; + Optional garbage; + + // Check if neither the big crafting UI nor the player inventory UI is open + if (!isBigCraftingOpen && !isPlayerInventoryOpen) { + // Check if the cursor stack is not empty if (!cursorStack.isEmpty()) { - Optional moveTo = mod.getItemStorage().getSlotThatCanFitInPlayerInventory(cursorStack, false); + // Find a slot in the player's inventory to move the item to + moveTo = mod.getItemStorage().getSlotThatCanFitInPlayerInventory(cursorStack, false); if (moveTo.isPresent()) { + // Click the slot to move the item to the player's inventory mod.getSlotHandler().clickSlot(moveTo.get(), 0, SlotActionType.PICKUP); return null; } + // Check if the item can be thrown away if (ItemHelper.canThrowAwayStack(mod, cursorStack)) { + // Click an undefined slot to throw away the item mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); return null; } - Optional garbage = StorageHelper.getGarbageSlot(mod); - // Try throwing away cursor slot if it's garbage + // Find the garbage slot and click it to move the item there + garbage = StorageHelper.getGarbageSlot(mod); if (garbage.isPresent()) { mod.getSlotHandler().clickSlot(garbage.get(), 0, SlotActionType.PICKUP); - return null; } + // Click an undefined slot to clear the cursor stack mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); } else { + // Close the screen StorageHelper.closeScreen(); } } - Slot outputSlot = bigCrafting ? CraftingTableSlot.OUTPUT_SLOT : PlayerSlot.CRAFT_OUTPUT_SLOT; + + // Determine the output slot based on whether the big crafting UI is open + Slot outputSlot = isBigCraftingOpen ? CraftingTableSlot.OUTPUT_SLOT : PlayerSlot.CRAFT_OUTPUT_SLOT; + // Get the item stack in the output slot ItemStack output = StorageHelper.getItemStackInSlot(outputSlot); - if (_target.getOutputItem() == output.getItem() && mod.getItemStorage().getItemCount(_target.getOutputItem()) < - _target.getTargetCount()) { - setDebugState("Getting output."); + + // Check if the output item matches the target item and the target count has not been reached + if (_target.getOutputItem() == output.getItem() && mod.getItemStorage().getItemCount(_target.getOutputItem()) < _target.getTargetCount()) { + // Return a task to receive the crafting output slot return new ReceiveCraftingOutputSlotTask(outputSlot, _target.getTargetCount()); } - ItemStack cursorStack = StorageHelper.getItemStackInCursorSlot(); + + // Check if the cursor stack is not empty if (!cursorStack.isEmpty()) { - Optional moveTo = mod.getItemStorage().getSlotThatCanFitInPlayerInventory(cursorStack, false); + // Find a slot in the player's inventory to move the item to + moveTo = mod.getItemStorage().getSlotThatCanFitInPlayerInventory(cursorStack, false); if (moveTo.isPresent()) { + // Click the slot to move the item to the player's inventory mod.getSlotHandler().clickSlot(moveTo.get(), 0, SlotActionType.PICKUP); return null; } + // Check if the item can be thrown away if (ItemHelper.canThrowAwayStack(mod, cursorStack)) { + // Click an undefined slot to throw away the item mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); return null; } - Optional garbage = StorageHelper.getGarbageSlot(mod); - // Try throwing away cursor slot if it's garbage - if (garbage.isPresent()) { - mod.getSlotHandler().clickSlot(garbage.get(), 0, SlotActionType.PICKUP); - return null; - } + // Find the garbage slot and click it to move the item there + garbage = StorageHelper.getGarbageSlot(mod); + garbage.ifPresent(slot -> mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP)); + // Click an undefined slot to clear the cursor stack mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); return null; } - if (!bigCrafting) { - PlayerSlot[] playerInputSlot = PlayerSlot.CRAFT_INPUT_SLOTS; - for (PlayerSlot PlayerInputSlot : playerInputSlot) { - ItemStack playerInput = StorageHelper.getItemStackInSlot(PlayerInputSlot); + + // Check if neither the big crafting UI nor the player inventory UI is open + if (!isBigCraftingOpen) { + PlayerSlot[] playerInputSlots = PlayerSlot.CRAFT_INPUT_SLOTS; + for (PlayerSlot playerInputSlot : playerInputSlots) { + ItemStack playerInput = StorageHelper.getItemStackInSlot(playerInputSlot); if (!playerInput.isEmpty()) { + // Return a task to ensure a free player crafting grid return new EnsureFreePlayerCraftingGridTask(); } } } - setDebugState("Crafting."); - if (mod.getSlotHandler().canDoSlotAction()) { - StorageHelper.instantFillRecipeViaBook(mod, _target.getRecipe(), _target.getOutputItem(), true); - mod.getSlotHandler().registerSlotAction(); + + Optional> recipeToSend = JankCraftingRecipeMapping.getMinecraftMappedRecipe(_target.getRecipe(), _target.getOutputItem()); + if (recipeToSend.isPresent()) { + if (mod.getSlotHandler().canDoSlotAction()) { + ClientPlayerEntity player = MinecraftClient.getInstance().player; + assert player != null; + // Click the recipe to send it + mod.getController().clickRecipe(player.currentScreenHandler.syncId, recipeToSend.get(), true); + mod.getSlotHandler().registerSlotAction(); + } } + return null; } + /** + * This method is called when the task is interrupted. + * + * @param mod The AltoClef mod. + * @param interruptTask The task that interrupted the current task. + */ @Override protected void onStop(AltoClef mod, Task interruptTask) { } + /** + * Checks if a given Task object is equal to this CraftGenericWithRecipeBooksTask object. + * + * @param other The Task object to compare with. + * @return True if the given Task is equal to this CraftGenericWithRecipeBooksTask, false otherwise. + */ @Override protected boolean isEqual(Task other) { - if (other instanceof CraftGenericWithRecipeBooksTask task) { - return task._target.equals(_target); + // Check if the other Task is an instance of CraftGenericWithRecipeBooksTask + if (other instanceof CraftGenericWithRecipeBooksTask) { + CraftGenericWithRecipeBooksTask task = (CraftGenericWithRecipeBooksTask) other; + + // Check if the target of the other task is equal to the target of this task + boolean isEqual = task._target.equals(_target); + + // Log a message if the targets are not equal + if (!isEqual) { + Debug.logInternal("Task targets are not equal"); + } + + // Return the result of the equality check + return isEqual; } + + // Log a message if the other Task is not an instance of CraftGenericWithRecipeBooksTask + Debug.logInternal("Task is not an instance of CraftGenericWithRecipeBooksTask"); + + // Return false if the other Task is not an instance of CraftGenericWithRecipeBooksTask return false; } + /** + * Returns a debug string representation of the object. + * + * @return The debug string representation. + */ @Override protected String toDebugString() { - return "Crafting (w/ RECIPE): " + _target; + // Return the debug string. + return getClass().getSimpleName() + " (w/ RECIPE): " + _target; } } diff --git a/src/main/java/adris/altoclef/tasks/CraftInInventoryTask.java b/src/main/java/adris/altoclef/tasks/CraftInInventoryTask.java index b1d5598e3..917b2dfd5 100644 --- a/src/main/java/adris/altoclef/tasks/CraftInInventoryTask.java +++ b/src/main/java/adris/altoclef/tasks/CraftInInventoryTask.java @@ -77,7 +77,9 @@ protected Task onResourceTick(AltoClef mod) { } } } - + if (StorageHelper.isBigCraftingOpen()) { + StorageHelper.closeScreen(); + } ItemTarget toGet = _itemTargets[0]; Item toGetItem = toGet.getMatches()[0]; if (_collect && !StorageHelper.hasRecipeMaterialsOrTarget(mod, _target)) { diff --git a/src/main/java/adris/altoclef/tasks/InteractWithBlockTask.java b/src/main/java/adris/altoclef/tasks/InteractWithBlockTask.java index f7bf80ab9..f3796340b 100644 --- a/src/main/java/adris/altoclef/tasks/InteractWithBlockTask.java +++ b/src/main/java/adris/altoclef/tasks/InteractWithBlockTask.java @@ -61,7 +61,7 @@ public class InteractWithBlockTask extends Task { Blocks.BIG_DRIPLEAF_STEM, Blocks.SMALL_DRIPLEAF, Blocks.TALL_GRASS, - Blocks.GRASS, + Blocks.GRASS_BLOCK, Blocks.SWEET_BERRY_BUSH }; private Task _unstuckTask = null; @@ -110,10 +110,22 @@ public InteractWithBlockTask(Item toUse, Direction direction, BlockPos target, b this(new ItemTarget(toUse, 1), direction, target, walkInto); } + public InteractWithBlockTask(Item toUse, Direction direction, BlockPos target) { + this(new ItemTarget(toUse, 1), direction, target, Input.CLICK_RIGHT, false, false); + } + public InteractWithBlockTask(Item toUse, BlockPos target, boolean walkInto, Vec3i interactOffset) { this(new ItemTarget(toUse, 1), target, walkInto, interactOffset); } + public InteractWithBlockTask(Item toUse, Direction direction, BlockPos target, Vec3i interactOffset) { + this(new ItemTarget(toUse, 1), direction, target, Input.CLICK_RIGHT, false, interactOffset, false); + } + + public InteractWithBlockTask(Item toUse, BlockPos target, Vec3i interactOffset) { + this(new ItemTarget(toUse, 1), null, target, Input.CLICK_RIGHT, false, interactOffset, false); + } + public InteractWithBlockTask(Item toUse, BlockPos target, boolean walkInto) { this(new ItemTarget(toUse, 1), target, walkInto); } @@ -122,6 +134,10 @@ public InteractWithBlockTask(Item toUse, BlockPos target) { this(new ItemTarget(toUse, 1), target); } + public InteractWithBlockTask(BlockPos target, boolean shiftClick) { + this(ItemTarget.EMPTY, null, target, Input.CLICK_RIGHT, false, shiftClick); + } + public InteractWithBlockTask(BlockPos target) { this(ItemTarget.EMPTY, null, target, Input.CLICK_RIGHT, false, false); } @@ -274,7 +290,12 @@ protected Task onTick(AltoClef mod) { } int reachDistance = 0; - Goal moveGoal = createGoalForInteract(_target, reachDistance, _direction, _interactOffset, _walkInto); + Goal moveGoal; + if (mod.getExtraBaritoneSettings().shouldAvoidBreaking(_target.up())) { + moveGoal = new GoalTwoBlocks(_target.north()); + } else { + moveGoal = createGoalForInteract(_target, reachDistance, _direction, _interactOffset, _walkInto); + } ICustomGoalProcess proc = mod.getClientBaritone().getCustomGoalProcess(); _cachedClickStatus = rightClick(mod); @@ -379,22 +400,24 @@ private ClickResponse rightClick(AltoClef mod) { } Optional reachable = getCurrentReach(); - if (reachable.isPresent()) { - LookHelper.lookAt(mod, reachable.get()); - if (mod.getClientBaritone().getPlayerContext().isLookingAt(_target)) { + if (reachable.isPresent() && mod.getClientBaritone().getPathingBehavior().isSafeToCancel()) { + if (LookHelper.isLookingAt(mod, _target)) { if (_toUse != null) { mod.getSlotHandler().forceEquipItem(_toUse, false); } else { mod.getSlotHandler().forceDeequipRightClickableItem(); } - mod.getInputControls().tryPress(_interactInput); + mod.getInputControls().hold(_interactInput); if (mod.getInputControls().isHeldDown(_interactInput)) { if (_shiftClick) { mod.getInputControls().hold(Input.SNEAK); } + mod.getInputControls().release(_interactInput); return ClickResponse.CLICK_ATTEMPTED; } //mod.getClientBaritone().getInputOverrideHandler().setInputForceState(_interactInput, true); + } else { + LookHelper.lookAt(mod, reachable.get()); } return ClickResponse.WAIT_FOR_CLICK; } diff --git a/src/main/java/adris/altoclef/tasks/construction/DestroyBlockTask.java b/src/main/java/adris/altoclef/tasks/construction/DestroyBlockTask.java index 9ff3817af..f9b5c98df 100644 --- a/src/main/java/adris/altoclef/tasks/construction/DestroyBlockTask.java +++ b/src/main/java/adris/altoclef/tasks/construction/DestroyBlockTask.java @@ -11,6 +11,7 @@ import adris.altoclef.util.helpers.StorageHelper; import adris.altoclef.util.helpers.WorldHelper; import adris.altoclef.util.progresscheck.MovementProgressChecker; +import adris.altoclef.util.slots.PlayerSlot; import adris.altoclef.util.slots.Slot; import baritone.api.pathing.goals.GoalBlock; import baritone.api.pathing.goals.GoalNear; @@ -19,10 +20,12 @@ import net.minecraft.block.*; import net.minecraft.entity.Entity; import net.minecraft.entity.mob.PillagerEntity; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.screen.slot.SlotActionType; import net.minecraft.util.math.BlockPos; +import java.util.Objects; import java.util.Optional; /** @@ -45,7 +48,7 @@ public class DestroyBlockTask extends Task implements ITaskRequiresGrounded { Blocks.BIG_DRIPLEAF_STEM, Blocks.SMALL_DRIPLEAF, Blocks.TALL_GRASS, - Blocks.GRASS, + Blocks.GRASS_BLOCK, Blocks.SWEET_BERRY_BUSH }; private Task _unstuckTask = null; @@ -55,94 +58,188 @@ public DestroyBlockTask(BlockPos pos) { _pos = pos; } + /** + * Generates the surrounding BlockPos based on the given position. + * + * @param pos The center BlockPos + * @return An array of surrounding BlockPos + */ private static BlockPos[] generateSides(BlockPos pos) { + int x = pos.getX(); + int y = pos.getY(); + int z = pos.getZ(); + return new BlockPos[]{ - pos.add(1, 0, 0), - pos.add(-1, 0, 0), - pos.add(0, 0, 1), - pos.add(0, 0, -1), - pos.add(1, 0, -1), - pos.add(1, 0, 1), - pos.add(-1, 0, -1), - pos.add(-1, 0, 1) + new BlockPos(x + 1, y, z), + new BlockPos(x - 1, y, z), + new BlockPos(x, y, z + 1), + new BlockPos(x, y, z - 1), + new BlockPos(x + 1, y, z - 1), + new BlockPos(x + 1, y, z + 1), + new BlockPos(x - 1, y, z - 1), + new BlockPos(x - 1, y, z + 1) }; } + /** + * Checks if the block at the specified position is annoying. + * + * @param mod the AltoClef instance + * @param pos the position to check + * @return true if the block is annoying, false otherwise + */ private boolean isAnnoying(AltoClef mod, BlockPos pos) { - for (Block AnnoyingBlocks : annoyingBlocks) { - return mod.getWorld().getBlockState(pos).getBlock() == AnnoyingBlocks || - mod.getWorld().getBlockState(pos).getBlock() instanceof DoorBlock || - mod.getWorld().getBlockState(pos).getBlock() instanceof FenceBlock || - mod.getWorld().getBlockState(pos).getBlock() instanceof FenceGateBlock || - mod.getWorld().getBlockState(pos).getBlock() instanceof FlowerBlock; + for (Block annoyingBlock : annoyingBlocks) { + boolean isAnnoying = mod.getWorld().getBlockState(pos).getBlock() == annoyingBlock + || mod.getWorld().getBlockState(pos).getBlock() instanceof DoorBlock + || mod.getWorld().getBlockState(pos).getBlock() instanceof FenceBlock + || mod.getWorld().getBlockState(pos).getBlock() instanceof FenceGateBlock + || mod.getWorld().getBlockState(pos).getBlock() instanceof FlowerBlock; + if (isAnnoying) { + return true; + } } return false; } - // This happens all the time in mineshafts and swamps/jungles + /** + * Finds the position where the player is stuck in a block. + * + * @param mod the mod instance + * @return the position where the player is stuck, or null if not stuck + */ private BlockPos stuckInBlock(AltoClef mod) { - BlockPos p = mod.getPlayer().getBlockPos(); - if (isAnnoying(mod, p)) return p; - if (isAnnoying(mod, p.up())) return p.up(); - BlockPos[] toCheck = generateSides(p); - for (BlockPos check : toCheck) { + // Check if player is stuck in their current position + if (isAnnoying(mod, mod.getPlayer().getBlockPos())) { + return mod.getPlayer().getBlockPos(); + } + + // Check if player is stuck when moving up + if (isAnnoying(mod, mod.getPlayer().getBlockPos().up())) { + return mod.getPlayer().getBlockPos().up(); + } + + // Check for stuck positions in the sides of the player's current position + for (BlockPos check : generateSides(mod.getPlayer().getBlockPos())) { if (isAnnoying(mod, check)) { return check; } } - BlockPos[] toCheckHigh = generateSides(p.up()); - for (BlockPos check : toCheckHigh) { + + // Check for stuck positions in the sides of the player's position when moving up + for (BlockPos check : generateSides(mod.getPlayer().getBlockPos().up())) { if (isAnnoying(mod, check)) { return check; } } - return null; + + return null; // Player is not stuck } + /** + * Gets a task to unstick a fence. + * + * @return the task to unstick the fence, or null if an exception is caught + */ private Task getFenceUnstuckTask() { + try { + // Create a safe random shimmy task + Task task = createSafeRandomShimmyTask(); + + // Return the task + return task; + } catch (Exception e) { + e.printStackTrace(); + // Handle the exception or rethrow it as needed + return null; + } + } + + /** + * Creates and returns a new instance of SafeRandomShimmyTask. + * + * @return a new SafeRandomShimmyTask instance + */ + private Task createSafeRandomShimmyTask() { return new SafeRandomShimmyTask(); } + /** + * This method is called when the AltoClef mod starts. + * It cancels any ongoing pathing behavior, resets move checker and stuck check, + * and handles the item stack in the cursor slot. + * If the cursor stack is not empty, it calls handleNonEmptyCursorStack, + * otherwise, it closes the screen. + */ @Override protected void onStart(AltoClef mod) { + // Cancel any ongoing pathing behavior. mod.getClientBaritone().getPathingBehavior().forceCancel(); + + // Reset move checker and stuck check. _moveChecker.reset(); stuckCheck.reset(); + + // Get the item stack in the cursor slot. ItemStack cursorStack = StorageHelper.getItemStackInCursorSlot(); + + // If the cursor stack is not empty, handle it. if (!cursorStack.isEmpty()) { - Optional moveTo = mod.getItemStorage().getSlotThatCanFitInPlayerInventory(cursorStack, false); - moveTo.ifPresent(slot -> mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP)); - if (ItemHelper.canThrowAwayStack(mod, cursorStack)) { - mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); - } - Optional garbage = StorageHelper.getGarbageSlot(mod); - // Try throwing away cursor slot if it's garbage - garbage.ifPresent(slot -> mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP)); - mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); + handleNonEmptyCursorStack(mod, cursorStack); } else { + // If the cursor stack is empty, close the screen. StorageHelper.closeScreen(); } } + /** + * Handles the non-empty cursor stack by performing various actions. + * @param mod the AltoClef mod + * @param cursorStack the cursor stack + */ + private void handleNonEmptyCursorStack(AltoClef mod, ItemStack cursorStack) { + // Get the slot that can fit the cursor stack in the player inventory and click it to pick up the item. + mod.getItemStorage().getSlotThatCanFitInPlayerInventory(cursorStack, false) + .ifPresent(slot -> mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP)); + + // If the cursor stack can be thrown away, click an undefined slot to pick up the item. + if (ItemHelper.canThrowAwayStack(mod, cursorStack)) { + mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); + } + + // Get the garbage slot and click it to pick up the item. + StorageHelper.getGarbageSlot(mod) + .ifPresent(slot -> mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP)); + + // Click an undefined slot to pick up the item. + mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); + } + @Override protected Task onTick(AltoClef mod) { + // Check if there is white wool at the specified position if (mod.getWorld().getBlockState(_pos).getBlock() == Blocks.WHITE_WOOL) { + // Iterate over all entities in the world Iterable entities = mod.getWorld().getEntities(); for (Entity entity : entities) { - if (entity instanceof PillagerEntity) { - if (_pos.isWithinDistance(entity.getPos(), 144)) { - Debug.logMessage("Blacklisting pillager wool."); - mod.getBlockTracker().requestBlockUnreachable(_pos, 0); - } + // Check if the entity is a PillagerEntity and is within a distance of 144 blocks from the position + if (entity instanceof PillagerEntity && _pos.isWithinDistance(entity.getPos(), 144)) { + // Request the block at the position to be marked as unreachable + mod.getBlockTracker().requestBlockUnreachable(_pos, 0); } } } + + // Reset the move checker if Baritone is currently pathing if (mod.getClientBaritone().getPathingBehavior().isPathing()) { _moveChecker.reset(); } + + // Check if the player is in a Nether portal if (WorldHelper.isInNetherPortal(mod)) { if (!mod.getClientBaritone().getPathingBehavior().isPathing()) { setDebugState("Getting out from nether portal"); + // Hold the sneak and move forward inputs to exit the Nether portal mod.getInputControls().hold(Input.SNEAK); mod.getInputControls().hold(Input.MOVE_FORWARD); return null; @@ -151,21 +248,23 @@ protected Task onTick(AltoClef mod) { mod.getInputControls().release(Input.MOVE_BACK); mod.getInputControls().release(Input.MOVE_FORWARD); } - } else { - if (mod.getClientBaritone().getPathingBehavior().isPathing()) { - mod.getInputControls().release(Input.SNEAK); - mod.getInputControls().release(Input.MOVE_BACK); - mod.getInputControls().release(Input.MOVE_FORWARD); - } + } else if (mod.getClientBaritone().getPathingBehavior().isPathing()) { + mod.getInputControls().release(Input.SNEAK); + mod.getInputControls().release(Input.MOVE_BACK); + mod.getInputControls().release(Input.MOVE_FORWARD); } + + // Check if there is an active unstuck task and the player is stuck in a block if (_unstuckTask != null && _unstuckTask.isActive() && !_unstuckTask.isFinished(mod) && stuckInBlock(mod) != null) { setDebugState("Getting unstuck from block."); stuckCheck.reset(); - // Stop other tasks, we are JUST shimmying + // Release control of Baritone's custom goal process and explore process mod.getClientBaritone().getCustomGoalProcess().onLostControl(); mod.getClientBaritone().getExploreProcess().onLostControl(); return _unstuckTask; } + + // Check if the move checker or the stuck check failed if (!_moveChecker.check(mod) || !stuckCheck.check(mod)) { BlockPos blockStuck = stuckInBlock(mod); if (blockStuck != null) { @@ -174,12 +273,16 @@ protected Task onTick(AltoClef mod) { } stuckCheck.reset(); } + + // Check if the move checker failed if (!_moveChecker.check(mod)) { _moveChecker.reset(); + // Request the block at the position to be marked as unreachable mod.getBlockTracker().requestBlockUnreachable(_pos); } - // do NOT break if we're standing above it and it's dangerous below... + // Check if the block above the position is not solid, the player is above the position, + // and the player is within a distance of 0.89 blocks from the position if (!WorldHelper.isSolid(mod, _pos.up()) && mod.getPlayer().getPos().y > _pos.getY() && _pos.isWithinDistance(mod.getPlayer().isOnGround() ? mod.getPlayer().getPos() : mod.getPlayer().getPos().add(0, -1, 0), 0.89)) { if (WorldHelper.dangerousToBreakIfRightAbove(mod, _pos)) { setDebugState("It's dangerous to break as we're right above it, moving away and trying again."); @@ -187,26 +290,41 @@ protected Task onTick(AltoClef mod) { } } - // We're trying to mine Optional reach = LookHelper.getReach(_pos); - if (reach.isPresent() && (mod.getPlayer().isTouchingWater() || mod.getPlayer().isOnGround()) && - !mod.getFoodChain().needsToEat() && !WorldHelper.isInNetherPortal(mod)) { + if (reach.isPresent() && (mod.getPlayer().isTouchingWater() || mod.getPlayer().isOnGround()) + && !mod.getFoodChain().needsToEat() && !WorldHelper.isInNetherPortal(mod) + && mod.getClientBaritone().getPathingBehavior().isSafeToCancel()) { setDebugState("Block in range, mining..."); stuckCheck.reset(); isMining = true; mod.getInputControls().release(Input.SNEAK); mod.getInputControls().release(Input.MOVE_BACK); mod.getInputControls().release(Input.MOVE_FORWARD); - // Break the block, force it. mod.getClientBaritone().getCustomGoalProcess().onLostControl(); mod.getClientBaritone().getBuilderProcess().onLostControl(); - if (!LookHelper.isLookingAt(mod, _pos)) { - reach.ifPresent(rotation -> LookHelper.lookAt(mod, rotation)); + if (!LookHelper.isLookingAt(mod, reach.get())) { + LookHelper.lookAt(mod, reach.get()); } - if (LookHelper.isLookingAt(mod, _pos)) { - // Tool equip is handled in `PlayerInteractionFixChain`. Oof. - mod.getClientBaritone().getInputOverrideHandler().setInputForceState(Input.CLICK_LEFT, true); + BlockState state = mod.getWorld().getBlockState(_pos); + Optional bestToolSlot = StorageHelper.getBestToolSlot(mod, state); + Slot currentEquipped = PlayerSlot.getEquipSlot(); + // if baritone is running, only accept tools OUTSIDE OF HOTBAR! + // Baritone will take care of tools inside the hotbar. + if (bestToolSlot.isPresent() && bestToolSlot.get() != currentEquipped) { + // ONLY equip if the item class is STRICTLY different (otherwise we swap around a lot) + if (StorageHelper.getItemStackInSlot(currentEquipped).getItem() != StorageHelper.getItemStackInSlot(bestToolSlot.get()).getItem()) { + boolean isAllowedToManage = !mod.getClientBaritone().getPathingBehavior().isPathing() + && !mod.getFoodChain().isTryingToEat(); + if (isAllowedToManage) { + Debug.logMessage("Found better tool in inventory, equipping."); + ItemStack bestToolItemStack = StorageHelper.getItemStackInSlot(bestToolSlot.get()); + Item bestToolItem = bestToolItemStack.getItem(); + mod.getSlotHandler().forceEquipItem(bestToolItem); + } + return null; + } } + mod.getClientBaritone().getInputOverrideHandler().setInputForceState(Input.CLICK_LEFT, true); } else { setDebugState("Getting to block..."); if (isMining && mod.getPlayer().isTouchingWater()) { @@ -219,11 +337,11 @@ protected Task onTick(AltoClef mod) { if (isCloseToMoveBack) { if (!mod.getClientBaritone().getPathingBehavior().isPathing() && !mod.getPlayer().isTouchingWater() && !mod.getFoodChain().needsToEat()) { - mod.getInputControls().hold(Input.SNEAK); mod.getInputControls().hold(Input.MOVE_BACK); + mod.getInputControls().hold(Input.SNEAK); } else { - mod.getInputControls().release(Input.SNEAK); mod.getInputControls().release(Input.MOVE_BACK); + mod.getInputControls().release(Input.SNEAK); } } if (!mod.getClientBaritone().getCustomGoalProcess().isActive()) { @@ -235,35 +353,71 @@ protected Task onTick(AltoClef mod) { return null; } + /** + * This method is called when the task is interrupted. + * It cancels Baritone pathing and releases input controls if in game. + * + * @param mod The AltoClef mod instance + * @param interruptTask The interrupting task + */ @Override protected void onStop(AltoClef mod, Task interruptTask) { + // Cancel Baritone pathing mod.getClientBaritone().getPathingBehavior().forceCancel(); + + // If not in game, return if (!AltoClef.inGame()) { return; } - // Do not keep breaking. - // Can lead to trouble, for example, if lava is right above the NEXT block. + + // Release input controls mod.getClientBaritone().getInputOverrideHandler().setInputForceState(Input.CLICK_LEFT, false); mod.getInputControls().release(Input.SNEAK); mod.getInputControls().release(Input.MOVE_BACK); mod.getInputControls().release(Input.MOVE_FORWARD); } + /** + * Check if the specified position is finished. + * + * @param mod The AltoClef instance + * @return True if the block at the specified position is air, false otherwise. + */ @Override public boolean isFinished(AltoClef mod) { - return WorldHelper.isAir(mod, _pos);//; + // Check if the world or position is null + if (mod.getWorld() == null || _pos == null) { + return false; + } + // Get the block state at the specified position and check if it's air + BlockState blockState = mod.getWorld().getBlockState(_pos); + return blockState.isAir(); } + /** + * Overrides the isEqual method to compare with another Task object. + * + * @param other The other Task object to compare with. + * @return true if the other object is a DestroyBlockTask and has the same position, false otherwise. + */ @Override protected boolean isEqual(Task other) { - if (other instanceof DestroyBlockTask task) { - return task._pos.equals(_pos); + if (other instanceof DestroyBlockTask destroyBlockTask) { + return Objects.equals(destroyBlockTask._pos, _pos); } return false; } + /** + * Returns a debug string describing the block destruction action. + * If the position is known, it includes the position in the string, otherwise it indicates an unknown position. + */ @Override protected String toDebugString() { - return "Destroy block at " + _pos.toShortString(); + if (_pos != null) { + return "Destroy block at " + _pos.toShortString(); + } else { + return "Destroy block at unknown position"; + } } } diff --git a/src/main/java/adris/altoclef/tasks/construction/PlaceBlockNearbyTask.java b/src/main/java/adris/altoclef/tasks/construction/PlaceBlockNearbyTask.java index 84f2a41e8..0a940b788 100644 --- a/src/main/java/adris/altoclef/tasks/construction/PlaceBlockNearbyTask.java +++ b/src/main/java/adris/altoclef/tasks/construction/PlaceBlockNearbyTask.java @@ -145,7 +145,7 @@ protected Task onTick(AltoClef mod) { if (_tryPlace != null) { setDebugState("Trying to place at " + _tryPlace); _justPlaced = _tryPlace; - return new PlaceBlockTask(_tryPlace, _toPlace); + return new PlaceBlockTask(_tryPlace, _toPlace, false, true); } // Look in random places to maybe get a random hit diff --git a/src/main/java/adris/altoclef/tasks/construction/PlaceBlockTask.java b/src/main/java/adris/altoclef/tasks/construction/PlaceBlockTask.java index aa6ae3deb..1efaa5627 100644 --- a/src/main/java/adris/altoclef/tasks/construction/PlaceBlockTask.java +++ b/src/main/java/adris/altoclef/tasks/construction/PlaceBlockTask.java @@ -8,6 +8,7 @@ import adris.altoclef.tasksystem.ITaskRequiresGrounded; import adris.altoclef.tasksystem.Task; import adris.altoclef.util.ItemTarget; +import adris.altoclef.util.helpers.ItemHelper; import adris.altoclef.util.helpers.WorldHelper; import adris.altoclef.util.progresscheck.MovementProgressChecker; import baritone.api.schematic.AbstractSchematic; @@ -64,6 +65,8 @@ public static Task getMaterialTask(int count) { @Override protected void onStart(AltoClef mod) { _progressChecker.reset(); + mod.getBehaviour().push(); + mod.getBehaviour().addProtectedItems(ItemHelper.blocksToItems(_toPlace)); // If we get interrupted by another task, this might cause problems... //_wanderTask.resetWander(); } @@ -94,7 +97,6 @@ protected Task onTick(AltoClef mod) { _progressChecker.reset(); return _wanderTask; } - if (_autoCollectStructureBlocks) { if (_materialTask != null && _materialTask.isActive() && !_materialTask.isFinished(mod)) { setDebugState("No structure items, collecting cobblestone + dirt as default."); @@ -145,6 +147,7 @@ protected Task onTick(AltoClef mod) { @Override protected void onStop(AltoClef mod, Task interruptTask) { + mod.getBehaviour().pop(); mod.getClientBaritone().getBuilderProcess().onLostControl(); } @@ -203,7 +206,7 @@ public BlockState desiredState(int x, int y, int z, BlockState blockState, List< } Debug.logInternal("Failed to find throwaway block"); // No throwaways available!! - return new BlockOptionalMeta(Blocks.COBBLESTONE).getAnyBlockState(); + return new BlockOptionalMeta(Blocks.DIRT).getAnyBlockState(); } // Don't care. return blockState; diff --git a/src/main/java/adris/altoclef/tasks/construction/PlaceObsidianBucketTask.java b/src/main/java/adris/altoclef/tasks/construction/PlaceObsidianBucketTask.java index 766d2ab0c..fd705959d 100644 --- a/src/main/java/adris/altoclef/tasks/construction/PlaceObsidianBucketTask.java +++ b/src/main/java/adris/altoclef/tasks/construction/PlaceObsidianBucketTask.java @@ -6,9 +6,11 @@ import adris.altoclef.tasks.movement.GetToBlockTask; import adris.altoclef.tasks.movement.TimeoutWanderTask; import adris.altoclef.tasksystem.Task; +import adris.altoclef.trackers.BlockTracker; import adris.altoclef.util.ItemTarget; import adris.altoclef.util.helpers.WorldHelper; import adris.altoclef.util.progresscheck.MovementProgressChecker; +import baritone.api.utils.input.Input; import net.minecraft.block.Blocks; import net.minecraft.item.Items; import net.minecraft.util.math.BlockPos; @@ -22,6 +24,10 @@ public class PlaceObsidianBucketTask extends Task { public static final Vec3i[] CAST_FRAME = new Vec3i[]{ new Vec3i(0, -1, 0), + new Vec3i(0, -1, -1), + new Vec3i(0, -1, 1), + new Vec3i(-1, -1, 0), + new Vec3i(1, -1, 0), new Vec3i(0, 0, -1), new Vec3i(0, 0, 1), new Vec3i(-1, 0, 0), @@ -60,8 +66,16 @@ protected void onStart(AltoClef mod) { _progressChecker.reset(); } + /** + * This method is called periodically to perform a specific task. + * It handles the logic for casting a spell using lava and water buckets. + * + * @param mod The mod instance + * @return The next task to be executed + */ @Override protected Task onTick(AltoClef mod) { + // Reset progress if pathing if (mod.getClientBaritone().getPathingBehavior().isPathing()) { _progressChecker.reset(); } @@ -70,11 +84,14 @@ protected Task onTick(AltoClef mod) { if (mod.getBlockTracker().blockIsValid(_pos, Blocks.OBSIDIAN) && mod.getBlockTracker().blockIsValid(_pos.up(), Blocks.WATER)) { return new ClearLiquidTask(_pos.up()); } - // Make sure we have water, juuust in case we have another creeper appear run end here + + // Make sure we have a water bucket if (!mod.getItemStorage().hasItem(Items.WATER_BUCKET)) { _progressChecker.reset(); return TaskCatalogue.getItemTask(Items.WATER_BUCKET, 1); } + + // Make sure we have a lava bucket if (!mod.getItemStorage().hasItem(Items.LAVA_BUCKET)) { // The only excuse is that we have lava at our position. if (!mod.getBlockTracker().blockIsValid(_pos, Blocks.LAVA)) { @@ -82,6 +99,8 @@ protected Task onTick(AltoClef mod) { return TaskCatalogue.getItemTask(Items.LAVA_BUCKET, 1); } } + + // Check progress if (!_progressChecker.check(mod)) { mod.getClientBaritone().getPathingBehavior().forceCancel(); mod.getBlockTracker().requestBlockUnreachable(_pos); @@ -89,6 +108,7 @@ protected Task onTick(AltoClef mod) { return new TimeoutWanderTask(5); } + // Build cast frame if not already built if (_currentCastTarget != null) { if (WorldHelper.isSolid(mod, _currentCastTarget)) { _currentCastTarget = null; @@ -96,6 +116,8 @@ protected Task onTick(AltoClef mod) { return new PlaceStructureBlockTask(_currentCastTarget); } } + + // Destroy block if needed if (_currentDestroyTarget != null) { if (!WorldHelper.isSolid(mod, _currentDestroyTarget)) { _currentDestroyTarget = null; @@ -104,7 +126,7 @@ protected Task onTick(AltoClef mod) { } } - // Build the cast frame + // Build the cast frame if not already built if (_currentCastTarget != null && WorldHelper.isSolid(mod, _currentCastTarget)) { // Current cast frame already built. _currentCastTarget = null; @@ -117,76 +139,120 @@ protected Task onTick(AltoClef mod) { } } - // Cast frame built. Now, place lava. + // Place lava if (mod.getWorld().getBlockState(_pos).getBlock() != Blocks.LAVA) { // Don't place lava at our position! // Would lead to an embarrassing death. BlockPos targetPos = _pos.add(-1, 1, 0); if (!mod.getPlayer().getBlockPos().equals(targetPos) && mod.getItemStorage().hasItem(Items.LAVA_BUCKET)) { - setDebugState("Positioning player before lava"); + if (!mod.getClientBaritone().getPathingBehavior().isPathing() + && targetPos.isWithinDistance(mod.getPlayer().getBlockPos(), 2)) { + mod.getInputControls().hold(Input.SNEAK); + mod.getInputControls().hold(Input.MOVE_BACK); + } else { + mod.getInputControls().release(Input.SNEAK); + mod.getInputControls().release(Input.MOVE_BACK); + mod.getInputControls().release(Input.MOVE_FORWARD); + } return new GetToBlockTask(targetPos, false); } if (WorldHelper.isSolid(mod, _pos)) { - setDebugState("Clearing space around lava"); _currentDestroyTarget = _pos; return null; - //return new DestroyBlockTask(framePos); } // Clear the upper two as well, to make placing more reliable. if (WorldHelper.isSolid(mod, _pos.up())) { - setDebugState("Clearing space around lava"); _currentDestroyTarget = _pos.up(); return null; } if (WorldHelper.isSolid(mod, _pos.up(2))) { - setDebugState("Clearing space around lava"); _currentDestroyTarget = _pos.up(2); return null; } - setDebugState("Placing lava for cast"); return new InteractWithBlockTask(new ItemTarget(Items.LAVA_BUCKET, 1), Direction.WEST, _pos.add(1, 0, 0), false); } // Lava placed, Now, place water. BlockPos waterCheck = _pos.up(); if (mod.getWorld().getBlockState(waterCheck).getBlock() != Blocks.WATER) { - setDebugState("Placing water for cast"); // Get to position to avoid weird stuck scenario BlockPos targetPos = _pos.add(-1, 1, 0); if (!mod.getPlayer().getBlockPos().equals(targetPos) && mod.getItemStorage().hasItem(Items.WATER_BUCKET)) { - setDebugState("Positioning player before water"); return new GetToBlockTask(targetPos, false); } if (WorldHelper.isSolid(mod, waterCheck)) { _currentDestroyTarget = waterCheck; return null; - //return new DestroyBlockTask(waterCheck); - } if (WorldHelper.isSolid(mod, waterCheck.up())) { _currentDestroyTarget = waterCheck.up(); return null; - //return new DestroyBlockTask(waterCheck.up()); } return new InteractWithBlockTask(new ItemTarget(Items.WATER_BUCKET, 1), Direction.WEST, _pos.add(1, 1, 0), true); } return null; } + /** + * This method is called when the task is interrupted. + * + * @param mod The instance of the AltoClef class. + * @param interruptTask The task that caused the interruption. + */ @Override protected void onStop(AltoClef mod, Task interruptTask) { - mod.getBehaviour().pop(); + // Check if the mod's behaviour is not null + if (mod.getBehaviour() != null) { + // Pop the behaviour from the stack + mod.getBehaviour().pop(); + } } + /** + * Check if the current task is finished. + * The task is considered finished if the block at the specified position is obsidian + * and there is no water block above it. + * + * @param mod The AltoClef mod instance. + * @return True if the task is finished, False otherwise. + */ @Override public boolean isFinished(AltoClef mod) { - return mod.getBlockTracker().blockIsValid(_pos, Blocks.OBSIDIAN) && !mod.getBlockTracker().blockIsValid(_pos.up(), Blocks.WATER); + // Get the BlockTracker instance from the mod + BlockTracker blockTracker = mod.getBlockTracker(); + + // Get the position of the block to check + BlockPos pos = _pos; + + // Check if the block at the specified position is obsidian + boolean isObsidian = blockTracker.blockIsValid(pos, Blocks.OBSIDIAN); + + // Check if there is no water block above the specified position + boolean isNotWaterAbove = !blockTracker.blockIsValid(pos.up(), Blocks.WATER); + + // The task is considered finished if the block is obsidian and there is no water above + boolean isFinished = isObsidian && isNotWaterAbove; + + return isFinished; } + /** + * Checks if the given task is equal to this PlaceObsidianBucketTask. + * Two PlaceObsidianBucketTasks are considered equal if their positions are equal. + * Overrides the isEqual() method from the parent class. + * + * @param other the task to compare with + * @return true if the tasks are equal, false otherwise + */ @Override protected boolean isEqual(Task other) { + // Check if the other task is an instance of PlaceObsidianBucketTask if (other instanceof PlaceObsidianBucketTask task) { - return task._pos.equals(_pos); + // Check if the positions are equal + boolean isEqual = task.getPos().equals(getPos()); + // Return the result + return isEqual; } + // Return false return false; } @@ -195,7 +261,13 @@ protected String toDebugString() { return "Placing obsidian at " + _pos + " with a cast"; } + /** + * Retrieves the position of the object. + * + * @return The position of the object. + */ public BlockPos getPos() { + return _pos; } } diff --git a/src/main/java/adris/altoclef/tasks/construction/compound/ConstructNetherPortalBucketTask.java b/src/main/java/adris/altoclef/tasks/construction/compound/ConstructNetherPortalBucketTask.java index f551f620d..c217e90f3 100644 --- a/src/main/java/adris/altoclef/tasks/construction/compound/ConstructNetherPortalBucketTask.java +++ b/src/main/java/adris/altoclef/tasks/construction/compound/ConstructNetherPortalBucketTask.java @@ -126,7 +126,8 @@ protected void onStart(AltoClef mod) { @Override protected Task onTick(AltoClef mod) { - if (MarvionBeatMinecraftTask.getConfig().renderDistanceManipulation) { + if (MarvionBeatMinecraftTask.getConfig().renderDistanceManipulation + && !mod.getClientBaritone().getExploreProcess().isActive()) { MinecraftClient.getInstance().options.getViewDistance().setValue(2); MinecraftClient.getInstance().options.getEntityDistanceScaling().setValue(0.5); } diff --git a/src/main/java/adris/altoclef/tasks/construction/compound/ConstructNetherPortalObsidianTask.java b/src/main/java/adris/altoclef/tasks/construction/compound/ConstructNetherPortalObsidianTask.java index 93c708cc9..877d7f130 100644 --- a/src/main/java/adris/altoclef/tasks/construction/compound/ConstructNetherPortalObsidianTask.java +++ b/src/main/java/adris/altoclef/tasks/construction/compound/ConstructNetherPortalObsidianTask.java @@ -11,6 +11,7 @@ import adris.altoclef.util.ItemTarget; import adris.altoclef.util.helpers.WorldHelper; import adris.altoclef.util.time.TimerGame; +import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.client.MinecraftClient; @@ -161,7 +162,7 @@ protected Task onTick(AltoClef mod) { // Place frame if (placeTarget != null) { setDebugState("Placing frame..."); - return new PlaceBlockTask(placeTarget, Blocks.OBSIDIAN); + return new PlaceBlockTask(placeTarget, new Block[]{Blocks.OBSIDIAN}, false, true); } // Clear middle diff --git a/src/main/java/adris/altoclef/tasks/construction/compound/ConstructNetherPortalSpeedrunTask.java b/src/main/java/adris/altoclef/tasks/construction/compound/ConstructNetherPortalSpeedrunTask.java index ab9e60e20..64c21eea1 100644 --- a/src/main/java/adris/altoclef/tasks/construction/compound/ConstructNetherPortalSpeedrunTask.java +++ b/src/main/java/adris/altoclef/tasks/construction/compound/ConstructNetherPortalSpeedrunTask.java @@ -20,7 +20,7 @@ import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3i; -import java.util.HashSet; +import java.util.Optional; @SuppressWarnings("ALL") @Deprecated @@ -168,7 +168,7 @@ protected adris.altoclef.tasksystem.Task onTick(AltoClef mod) { _firstSearch = false; _lavaSearchTimer.reset(); Debug.logMessage("(Searching for lava lake with portalable spot nearby...)"); - BlockPos lavaPos = findLavaLake(mod, mod.getPlayer().getBlockPos()); + BlockPos lavaPos = findLavaLake(mod); if (lavaPos != null) { // We have a lava lake, set our portal origin! BlockPos foundPortalRegion = getPortalableRegion(lavaPos, mod.getPlayer().getBlockPos(), new Vec3i(-1, 0, 0), PORTALABLE_REGION_SIZE, 20); @@ -335,34 +335,27 @@ protected String toDebugString() { // Scans to find the nearest lava lake (collection of lava bigger than 12 blocks) - private BlockPos findLavaLake(AltoClef mod, BlockPos playerPos) { - HashSet alreadyExplored = new HashSet<>(); - - double nearestSqDistance = Double.POSITIVE_INFINITY; + private BlockPos findLavaLake(AltoClef mod) { BlockPos nearestLake = null; - for (BlockPos pos : mod.getBlockTracker().getKnownLocations(Blocks.LAVA)) { - if (alreadyExplored.contains(pos)) continue; - double sqDist = playerPos.getSquaredDistance(pos); - if (sqDist < nearestSqDistance) { - int depth = getNumberOfBlocksAdjacent(alreadyExplored, pos); - Debug.logMessage("Found with depth " + depth); - if (depth >= 12) { - nearestSqDistance = sqDist; - nearestLake = pos; + if (mod.getBlockTracker().isTracking(Blocks.LAVA)) { + Optional lavas = mod.getBlockTracker().getNearestTracking(Blocks.LAVA); + if (lavas.isPresent()) { + int depth = getNumberOfBlocksAdjacent(lavas.get()); + if (depth != 0) { + Debug.logMessage("Found with depth " + depth); + if (depth >= 12) { + nearestLake = lavas.get(); + } } } } - return nearestLake; } // Used to flood-scan for blocks of lava. - private int getNumberOfBlocksAdjacent(HashSet alreadyExplored, BlockPos origin) { - // Base case: We already explored this one - if (alreadyExplored.contains(origin)) return 0; - alreadyExplored.add(origin); - + private int getNumberOfBlocksAdjacent(BlockPos origin) { // Base case: We hit a non-full lava block. + assert MinecraftClient.getInstance().world != null; BlockState s = MinecraftClient.getInstance().world.getBlockState(origin); if (s.getBlock() != Blocks.LAVA) { return 0; @@ -380,7 +373,7 @@ private int getNumberOfBlocksAdjacent(HashSet alreadyExplored, BlockPo int bonus = 0; for (BlockPos check : toCheck) { // This block is new! Explore out from it. - bonus += getNumberOfBlocksAdjacent(alreadyExplored, check); + bonus += getNumberOfBlocksAdjacent(check); } return bonus + 1; diff --git a/src/main/java/adris/altoclef/tasks/container/CraftInTableTask.java b/src/main/java/adris/altoclef/tasks/container/CraftInTableTask.java index c2247df65..8183d5a21 100644 --- a/src/main/java/adris/altoclef/tasks/container/CraftInTableTask.java +++ b/src/main/java/adris/altoclef/tasks/container/CraftInTableTask.java @@ -1,7 +1,6 @@ package adris.altoclef.tasks.container; import adris.altoclef.AltoClef; -import adris.altoclef.Debug; import adris.altoclef.tasks.CraftGenericManuallyTask; import adris.altoclef.tasks.CraftGenericWithRecipeBooksTask; import adris.altoclef.tasks.CraftInInventoryTask; @@ -12,6 +11,7 @@ import adris.altoclef.tasks.slot.ReceiveCraftingOutputSlotTask; import adris.altoclef.tasksystem.Task; import adris.altoclef.util.ItemTarget; +import adris.altoclef.util.JankCraftingRecipeMapping; import adris.altoclef.util.RecipeTarget; import adris.altoclef.util.helpers.ItemHelper; import adris.altoclef.util.helpers.StorageHelper; @@ -19,8 +19,11 @@ import adris.altoclef.util.slots.Slot; import adris.altoclef.util.time.TimerGame; import net.minecraft.block.Blocks; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.recipe.RecipeEntry; import net.minecraft.screen.CraftingScreenHandler; import net.minecraft.screen.slot.SlotActionType; import net.minecraft.util.math.BlockPos; @@ -52,63 +55,124 @@ public CraftInTableTask(RecipeTarget target) { this(target, true, true); } + /** + * Extracts item targets from recipe targets. + * + * @param recipeTargets The array of recipe targets. + * @return The array of item targets. + */ private static ItemTarget[] extractItemTargets(RecipeTarget[] recipeTargets) { - List result = new ArrayList<>(recipeTargets.length); - for (RecipeTarget target : recipeTargets) { - result.add(new ItemTarget(target.getOutputItem(), target.getTargetCount())); - } - return result.toArray(ItemTarget[]::new); + // Use Java streams to map each recipe target to a new item target + return Arrays.stream(recipeTargets) + .map(t -> new ItemTarget(t.getOutputItem(), t.getTargetCount())) + .toArray(ItemTarget[]::new); } + /** + * Determines whether the player should avoid picking up items. + * + * @param mod The AltoClef mod instance. + * @return true if the player should avoid picking up items, false otherwise. + */ @Override protected boolean shouldAvoidPickingUp(AltoClef mod) { return false; } + /** + * Called when the resource starts. + * + * @param mod The AltoClef mod instance. + */ @Override protected void onResourceStart(AltoClef mod) { } + /** + * This method is called on each tick of the resource manager. + * It returns the task that should be executed on each tick. + * + * @param mod The instance of the AltoClef mod. + * @return The task to be executed on each tick. + */ @Override protected Task onResourceTick(AltoClef mod) { return _craftTask; } + /** + * Override method called when the resource stops. + * + * @param mod The AltoClef mod. + * @param interruptTask The interrupt task. + */ @Override protected void onResourceStop(AltoClef mod, Task interruptTask) { + // Get the item stack in the cursor slot. ItemStack cursorStack = StorageHelper.getItemStackInCursorSlot(); + + // If the cursor stack is not empty, handle it. if (!cursorStack.isEmpty()) { - Optional moveTo = mod.getItemStorage().getSlotThatCanFitInPlayerInventory(cursorStack, false); - moveTo.ifPresent(slot -> mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP)); + // Find a slot in the player inventory that can fit the cursor stack. + Optional moveToSlot = mod.getItemStorage().getSlotThatCanFitInPlayerInventory(cursorStack, false); + + // If a slot is found, pick up the item from the cursor slot and move it to the found slot. + moveToSlot.ifPresent(slot -> mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP)); + + // If the item can be thrown away, pick up the item from the cursor slot and throw it away. if (ItemHelper.canThrowAwayStack(mod, cursorStack)) { mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); } - Optional garbage = StorageHelper.getGarbageSlot(mod); - // Try throwing away cursor slot if it's garbage - garbage.ifPresent(slot -> mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP)); - mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); + + // Find the garbage slot and move the item from the cursor slot to the garbage slot. + Optional garbageSlot = StorageHelper.getGarbageSlot(mod); + garbageSlot.ifPresent(slot -> mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP)); } else { + // If the cursor stack is empty, close the screen. StorageHelper.closeScreen(); } - //mod.getControllerExtras().closeCurrentContainer(); + + // Pick up an undefined slot. + mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); } + /** + * Checks if the given ResourceTask is equal to this CraftInTableTask. + * + * @param other The ResourceTask to compare with. + * @return true if the ResourceTask is a CraftInTableTask and its craftTask is equal to this task's craftTask, false otherwise. + */ @Override protected boolean isEqualResource(ResourceTask other) { + // Check if the other task is an instance of CraftInTableTask if (other instanceof CraftInTableTask task) { + // Compare the craftTask of the two tasks return _craftTask.isEqual(task._craftTask); } + // The other task is not a CraftInTableTask, return false return false; } + /** + * Returns the debug string name of the craft task. + * If the craft task is not null, it calls the toDebugString() method of the craft task and returns the result. + * Otherwise, it returns null. + * + * @return the debug string name of the craft task, or null if the craft task is null. + */ @Override protected String toDebugStringName() { - return _craftTask.toDebugString(); + return (_craftTask != null) ? _craftTask.toDebugString() : null; } + /** + * Returns a copy of the recipe targets. + * + * @return The recipe targets. + */ public RecipeTarget[] getRecipeTargets() { - return _targets; + return Arrays.copyOf(_targets, _targets.length); } } @@ -136,96 +200,132 @@ public DoCraftInTableTask(RecipeTarget[] targets) { this(targets, true, false); } + /** + * Override method called when the mod starts. + * Refactored to handle item management and screen closing. + * Resets the collect task. + * + * @param mod The AltoClef mod instance. + */ @Override protected void onStart(AltoClef mod) { super.onStart(mod); + + // Save the current behaviour and craft count mod.getBehaviour().push(); _craftCount = 0; + + // Check if there is an item in the cursor slot ItemStack cursorStack = StorageHelper.getItemStackInCursorSlot(); + if (!cursorStack.isEmpty()) { + // Move the item to a slot in the player's inventory that can fit it Optional moveTo = mod.getItemStorage().getSlotThatCanFitInPlayerInventory(cursorStack, false); moveTo.ifPresent(slot -> mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP)); + + // Check if the item can be thrown away if (ItemHelper.canThrowAwayStack(mod, cursorStack)) { + // Throw away the item mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); } - Optional garbage = StorageHelper.getGarbageSlot(mod); - // Try throwing away cursor slot if it's garbage - garbage.ifPresent(slot -> mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP)); + + // Move the item to the garbage slot + StorageHelper.getGarbageSlot(mod).ifPresent(slot -> mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP)); + + // Clear the cursor slot mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); } else { + // Close the screen if there is no item in the cursor slot StorageHelper.closeScreen(); } + + // Reset the collect task _collectTask.reset(); } + /** + * This method is called when the task is interrupted or stopped. + * It performs the necessary actions to handle the interruption or stopping of the task. + * + * @param mod The instance of the AltoClef mod. + * @param interruptTask The task that caused the interruption, or null if the task was stopped manually. + */ @Override protected void onStop(AltoClef mod, Task interruptTask) { + // Get the item stack in the cursor slot ItemStack cursorStack = StorageHelper.getItemStackInCursorSlot(); - if (!cursorStack.isEmpty()) { - Optional moveTo = mod.getItemStorage().getSlotThatCanFitInPlayerInventory(cursorStack, false); - moveTo.ifPresent(slot -> mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP)); + + // If the cursor stack is empty, close the screen + if (cursorStack.isEmpty()) { + StorageHelper.closeScreen(); + } else { + // Get a slot that can fit the cursor stack + Optional moveToSlot = mod.getItemStorage().getSlotThatCanFitInPlayerInventory(cursorStack, false); + + // If a slot is found, move the cursor stack to that slot + moveToSlot.ifPresent(slot -> mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP)); + + // If the cursor stack can be thrown away, throw it away if (ItemHelper.canThrowAwayStack(mod, cursorStack)) { mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); } - Optional garbage = StorageHelper.getGarbageSlot(mod); - // Try throwing away cursor slot if it's garbage - garbage.ifPresent(slot -> mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP)); + + // Get the garbage slot + Optional garbageSlot = StorageHelper.getGarbageSlot(mod); + + // If a garbage slot is found, move the cursor stack to that slot + garbageSlot.ifPresent(slot -> mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP)); + + // Move the cursor stack to an undefined slot mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); - } else { - StorageHelper.closeScreen(); } + + // Call the onStop method of the super class super.onStop(mod, interruptTask); + + // Pop the behaviour from the stack mod.getBehaviour().pop(); } + /** + * This method is called periodically to perform crafting-related tasks. + * + * @param mod The AltoClef mod instance. + * @return The next task to execute. + */ @Override protected Task onTick(AltoClef mod) { + // Add protected items to the behaviour mod.getBehaviour().addProtectedItems(getMaterialsArray()); - List craftingTablePos = mod.getBlockTracker().getKnownLocations(Blocks.CRAFTING_TABLE); - if (!craftingTablePos.isEmpty()) { - for (BlockPos CraftingTablePos : craftingTablePos) { - mod.getBehaviour().avoidBlockBreaking(CraftingTablePos); - } + + // Avoid breaking crafting tables + if (mod.getBlockTracker().isTracking(Blocks.CRAFTING_TABLE)) { + Optional craftingTable = mod.getBlockTracker().getNearestTracking(Blocks.CRAFTING_TABLE); + craftingTable.ifPresent(blockPos -> mod.getBehaviour().avoidBlockBreaking(blockPos)); } - // TODO: This shouldn't be here. - // This is duct tape for the following scenario: - // - // The Collect Recipe Resources task does NOT actually grab all of the resources we "claim" to need. - // It will finish while we STILL need resources. - // - // - // When is this OK? - // - // Only if we ASSUME that hasRecipeMaterials is TOO STRICT and the Collect Task is CORRECT. - // - - // Grab from output FIRST - if (StorageHelper.isPlayerInventoryOpen()) { - if (StorageHelper.getItemStackInCursorSlot().isEmpty()) { - Item outputItem = StorageHelper.getItemStackInSlot(PlayerSlot.CRAFT_OUTPUT_SLOT).getItem(); - for (RecipeTarget target : _targets) { - if (target.getOutputItem() == outputItem && mod.getItemStorage().getItemCount(target.getOutputItem()) < target.getTargetCount()) { - return new ReceiveCraftingOutputSlotTask(PlayerSlot.CRAFT_OUTPUT_SLOT, target.getTargetCount()); - } + // Check if the player inventory is open and the cursor slot is empty + if (StorageHelper.isPlayerInventoryOpen() && StorageHelper.getItemStackInCursorSlot().isEmpty()) { + // Get the item in the craft output slot + Item outputItem = StorageHelper.getItemStackInSlot(PlayerSlot.CRAFT_OUTPUT_SLOT).getItem(); + // Check if the output item matches any of the targets and the target count is not reached + for (RecipeTarget target : _targets) { + if (target.getOutputItem() == outputItem && mod.getItemStorage().getItemCount(target.getOutputItem()) < target.getTargetCount()) { + return new ReceiveCraftingOutputSlotTask(PlayerSlot.CRAFT_OUTPUT_SLOT, target.getTargetCount()); } } } - if (_collect) { - if (!_collectTask.isFinished(mod)) { - - if (!StorageHelper.hasRecipeMaterialsOrTarget(mod, _targets)) { - setDebugState("craft does NOT have RECIPE MATERIALS: " + Arrays.toString(_targets)); - return _collectTask; - } - } + // Check if we need to collect items and the collect task is not finished + if (_collect && !_collectTask.isFinished(mod) && !StorageHelper.hasRecipeMaterialsOrTarget(mod, _targets)) { + return _collectTask; } + // Reset the craft reset timer if the container is not open if (!isContainerOpen(mod)) { _craftResetTimer.reset(); } - // Make sure our recipe items are accessible in our inventory + // Check if there is any inaccessible item in the recipes and move it to the inventory if (!thisOrChildSatisfies(task -> task instanceof CraftInInventoryTask)) { for (RecipeTarget target : _targets) { for (int slot = 0; slot < target.getRecipe().getSlotCount(); ++slot) { @@ -237,79 +337,143 @@ protected Task onTick(AltoClef mod) { } } + // Call the parent method return super.onTick(mod); } + /** + * Checks if the given DoStuffInContainerTask is equal to this task. + * + * @param other The other DoStuffInContainerTask to compare. + * @return True if the tasks are equal, False otherwise. + */ @Override protected boolean isSubTaskEqual(DoStuffInContainerTask other) { + // Check if the other task is an instance of DoCraftInTableTask if (other instanceof DoCraftInTableTask task) { + // Compare the targets arrays of the two tasks return Arrays.equals(task._targets, _targets); } + // The other task is not an instance of DoCraftInTableTask, so they are not equal return false; } + /** + * Checks if the container is open. + * + * @param mod The AltoClef mod instance. + * @return True if the container is open, false otherwise. + */ @Override protected boolean isContainerOpen(AltoClef mod) { - return (mod.getPlayer().currentScreenHandler instanceof CraftingScreenHandler); + return mod.getPlayer().currentScreenHandler instanceof CraftingScreenHandler; } + /** + * Executes the container subtask. + * + * @param mod The AltoClef mod instance. + * @return The subtask to be executed. + */ @Override protected Task containerSubTask(AltoClef mod) { - // Refresh crafting table Juuust in case - _craftResetTimer.setInterval(mod.getModSettings().getContainerItemMoveDelay() * 10 + CRAFT_RESET_TIMER_BONUS_SECONDS); + // Calculate the interval based on the container item move delay and a bonus duration + float interval = mod.getModSettings().getContainerItemMoveDelay() * 10 + CRAFT_RESET_TIMER_BONUS_SECONDS; + _craftResetTimer.setInterval(interval); + + // If the craft reset timer has elapsed, return a TimeoutWanderTask if (_craftResetTimer.elapsed()) { - Debug.logMessage("Refreshing crafting table."); return new TimeoutWanderTask(5); } + // Iterate through each target recipe for (RecipeTarget target : _targets) { - if (mod.getItemStorage().getItemCount(target.getOutputItem()) >= target.getTargetCount()) + // Check if the output item count meets the target count + if (mod.getItemStorage().getItemCount(target.getOutputItem()) >= target.getTargetCount()) { continue; - // No need to free, handled automatically I believe. - setDebugState("Crafting"); + } + + // Get the recipe to send based on the target recipe and output item + Optional> recipeToSend = JankCraftingRecipeMapping.getMinecraftMappedRecipe(target.getRecipe(), target.getOutputItem()); + + // Get the client player entity + ClientPlayerEntity player = MinecraftClient.getInstance().player; + + // If crafting book is enabled, the recipe to send exists, and the player has the recipe in their recipe book, return a CraftGenericWithRecipeBooksTask + if (mod.getModSettings().shouldUseCraftingBookToCraft() && recipeToSend.isPresent()) { + assert player != null; + if (player.getRecipeBook().contains(recipeToSend.get())) { + return new CraftGenericWithRecipeBooksTask(target); + } + } - return mod.getModSettings().shouldUseCraftingBookToCraft() - ? new CraftGenericWithRecipeBooksTask(target) - : new CraftGenericManuallyTask(target); + // Return a CraftGenericManuallyTask by default + return new CraftGenericManuallyTask(target); } - setDebugState("DONE? Shouldn't be here"); return null; } + /** + * Checks if the specified mod is finished. + * + * @param mod The mod to check. + * @return True if the mod is finished, false otherwise. + */ @Override public boolean isFinished(AltoClef mod) { - return _craftCount >= _targets.length;//_crafted; + // Check if the craft count is greater than or equal to the number of targets + return _craftCount >= _targets.length; } + /** + * Returns the cost to make a new AltoClef mod. + * + * @param mod The AltoClef mod instance. + * @return The cost to make a new AltoClef mod. + */ @Override protected double getCostToMakeNew(AltoClef mod) { + // Get the nearest crafting table. Optional closestCraftingTable = mod.getBlockTracker().getNearestTracking(Blocks.CRAFTING_TABLE); - if (closestCraftingTable.isPresent()) { - if (closestCraftingTable.get().isWithinDistance(mod.getPlayer().getPos(), 40)) { - return Double.POSITIVE_INFINITY; - } + + // If a crafting table is within 40 blocks of the player, return positive infinity. + if (closestCraftingTable.isPresent() && closestCraftingTable.get().isWithinDistance(mod.getPlayer().getPos(), 40)) { + return Double.POSITIVE_INFINITY; } - // TODO: If we have an axe, lower the cost. + + // If the mod has logs or enough planks, return a cost of 10. if (mod.getItemStorage().hasItem(ItemHelper.LOG) || mod.getItemStorage().getItemCount(ItemHelper.PLANKS) >= 4) { - // We can craft it right now, so it's real cheap return 10; } - // TODO: If cached and the closest log is really far away, strike the price UP + + // Otherwise, return a cost of 100. return 100; } + /** + * Returns an array of materials. + * + * @return the array of materials + */ private Item[] getMaterialsArray() { List result = new ArrayList<>(); + + // Iterate over each target for (RecipeTarget target : _targets) { + // Iterate over each slot in the recipe for (int i = 0; i < target.getRecipe().getSlotCount(); ++i) { ItemTarget materialTarget = target.getRecipe().getSlot(i); - if (materialTarget == null || materialTarget.getMatches() == null) continue; - Collections.addAll(result, materialTarget.getMatches()); + // Check if the material target is not null and has matches + if (materialTarget != null && materialTarget.getMatches() != null) { + // Add all the matches to the result list + Collections.addAll(result, materialTarget.getMatches()); + } } } - return result.toArray(Item[]::new); + // Convert the result list to an array and return it + return result.toArray(new Item[0]); } } diff --git a/src/main/java/adris/altoclef/tasks/container/PickupFromContainerTask.java b/src/main/java/adris/altoclef/tasks/container/PickupFromContainerTask.java index 55d54f78d..5204f100e 100644 --- a/src/main/java/adris/altoclef/tasks/container/PickupFromContainerTask.java +++ b/src/main/java/adris/altoclef/tasks/container/PickupFromContainerTask.java @@ -5,6 +5,7 @@ import adris.altoclef.tasksystem.Task; import adris.altoclef.trackers.storage.ContainerCache; import adris.altoclef.util.ItemTarget; +import adris.altoclef.util.helpers.ItemHelper; import adris.altoclef.util.helpers.StorageHelper; import adris.altoclef.util.slots.FurnaceSlot; import adris.altoclef.util.slots.Slot; @@ -114,7 +115,22 @@ protected Task onContainerOpenSubtask(AltoClef mod, ContainerCache containerCach // Pick the best slot to grab from. Optional bestPotential = getBestSlotToTransfer(mod, target, count, potentials, stack -> mod.getItemStorage().getSlotThatCanFitInPlayerInventory(stack, false).isPresent()); - + ItemStack cursorStack = StorageHelper.getItemStackInCursorSlot(); + if (!cursorStack.isEmpty()) { + Optional toPlace = mod.getItemStorage().getSlotThatCanFitInPlayerInventory(cursorStack, false).or(() -> StorageHelper.getGarbageSlot(mod)); + if (toPlace.isPresent() && target.matches(cursorStack.getItem())) { + mod.getSlotHandler().clickSlot(toPlace.get(), 0, SlotActionType.PICKUP); + return null; + } + if (ItemHelper.canThrowAwayStack(mod, cursorStack)) { + mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); + return null; + } + if (toPlace.isPresent()) { + mod.getSlotHandler().clickSlot(toPlace.get(), 0, SlotActionType.PICKUP); + return null; + } + } if (bestPotential.isPresent()) { // Just pick it up, it's now ours. mod.getSlotHandler().clickSlot(bestPotential.get(), 0, SlotActionType.PICKUP); diff --git a/src/main/java/adris/altoclef/tasks/container/UpgradeInSmithingTableTask.java b/src/main/java/adris/altoclef/tasks/container/UpgradeInSmithingTableTask.java index eaea582d9..4eef5b558 100644 --- a/src/main/java/adris/altoclef/tasks/container/UpgradeInSmithingTableTask.java +++ b/src/main/java/adris/altoclef/tasks/container/UpgradeInSmithingTableTask.java @@ -25,6 +25,7 @@ public class UpgradeInSmithingTableTask extends ResourceTask { private final ItemTarget _tool; + private final ItemTarget _template; private final ItemTarget _material; private final ItemTarget _output; @@ -34,6 +35,7 @@ public UpgradeInSmithingTableTask(ItemTarget tool, ItemTarget material, ItemTarg super(output); _tool = new ItemTarget(tool, output.getTargetCount()); _material = new ItemTarget(material, output.getTargetCount()); + _template = new ItemTarget("netherite_upgrade_smithing_template", output.getTargetCount()); _output = output; _innerTask = new UpgradeInSmithingTableInternalTask(); } @@ -61,6 +63,7 @@ protected Task onResourceTick(AltoClef mod) { boolean inSmithingTable = (mod.getPlayer().currentScreenHandler instanceof SmithingScreenHandler); + int templatesInSlot = inSmithingTable ? getItemsInSlot(SmithingTableSlot.INPUT_SLOT_TEMPLATE, _template) : 0; int materialsInSlot = inSmithingTable ? getItemsInSlot(SmithingTableSlot.INPUT_SLOT_MATERIALS, _material) : 0; int toolsInSlot = inSmithingTable ? getItemsInSlot(SmithingTableSlot.INPUT_SLOT_TOOL, _tool) : 0; int ouputInSlot = inSmithingTable ? getItemsInSlot(SmithingTableSlot.OUTPUT_SLOT, _output) : 0; @@ -68,9 +71,10 @@ protected Task onResourceTick(AltoClef mod) { int desiredOutput = _output.getTargetCount() - ouputInSlot; if (mod.getItemStorage().getItemCount(_tool) + toolsInSlot < desiredOutput || - mod.getItemStorage().getItemCount(_material) + materialsInSlot < desiredOutput) { + mod.getItemStorage().getItemCount(_material) + materialsInSlot < desiredOutput || + mod.getItemStorage().getItemCount(_template) + templatesInSlot < desiredOutput) { setDebugState("Getting materials + tools"); - return TaskCatalogue.getSquashedItemTask(_tool, _material); + return TaskCatalogue.getSquashedItemTask(_tool, _material, _template); } // Edge case: We are wearing the armor we want to upgrade. If so, remove it. @@ -175,10 +179,12 @@ protected Task containerSubTask(AltoClef mod) { } _invTimer.reset(); + Slot templateSlot = SmithingTableSlot.INPUT_SLOT_TEMPLATE; Slot materialSlot = SmithingTableSlot.INPUT_SLOT_MATERIALS; Slot toolSlot = SmithingTableSlot.INPUT_SLOT_TOOL; Slot outputSlot = SmithingTableSlot.OUTPUT_SLOT; + ItemStack currentTemplates = StorageHelper.getItemStackInSlot(templateSlot); ItemStack currentMaterials = StorageHelper.getItemStackInSlot(materialSlot); ItemStack currentTools = StorageHelper.getItemStackInSlot(toolSlot); ItemStack currentOutput = StorageHelper.getItemStackInSlot(outputSlot); @@ -196,6 +202,10 @@ protected Task containerSubTask(AltoClef mod) { return new MoveItemToSlotFromInventoryTask(new ItemTarget(_tool, 1), toolSlot); } + if (currentTemplates.isEmpty() || !_template.matches(currentTemplates.getItem())) { + return new MoveItemToSlotFromInventoryTask(new ItemTarget(_template, 1), templateSlot); + } + setDebugState("PROBLEM: Nothing to do!"); return null; } diff --git a/src/main/java/adris/altoclef/tasks/entity/AbstractDoToEntityTask.java b/src/main/java/adris/altoclef/tasks/entity/AbstractDoToEntityTask.java index 5f5fd4e14..b73feba3e 100644 --- a/src/main/java/adris/altoclef/tasks/entity/AbstractDoToEntityTask.java +++ b/src/main/java/adris/altoclef/tasks/entity/AbstractDoToEntityTask.java @@ -112,7 +112,9 @@ protected Task onTick(AltoClef mod) { if (mod.getControllerExtras().inRange(entity) && result != null && result.getType() == HitResult.Type.ENTITY && !mod.getFoodChain().needsToEat() && !mod.getMLGBucketChain().isFallingOhNo(mod) && mod.getMLGBucketChain().doneMLG() && - !mod.getMLGBucketChain().isChorusFruiting()) { + !mod.getMLGBucketChain().isChorusFruiting() && + mod.getClientBaritone().getPathingBehavior().isSafeToCancel() && + mod.getPlayer().isOnGround()) { _progress.reset(); return onEntityInteract(mod, entity); } else if (!tooClose) { @@ -126,6 +128,9 @@ protected Task onTick(AltoClef mod) { return new GetToEntityTask(entity, maintainDistance); } } + if (!mod.getClientBaritone().getPathingBehavior().isSafeToCancel()) { + return null; + } return new TimeoutWanderTask(); } diff --git a/src/main/java/adris/altoclef/tasks/entity/AbstractKillEntityTask.java b/src/main/java/adris/altoclef/tasks/entity/AbstractKillEntityTask.java index 433f3ac2a..9c9a06dc8 100644 --- a/src/main/java/adris/altoclef/tasks/entity/AbstractKillEntityTask.java +++ b/src/main/java/adris/altoclef/tasks/entity/AbstractKillEntityTask.java @@ -33,10 +33,11 @@ public AbstractKillEntityTask(double maintainDistance, double combatGuardLowerRa super(maintainDistance, combatGuardLowerRange, combatGuardLowerFieldRadius); } - public static void equipWeapon(AltoClef mod) { + public static Item bestWeapon(AltoClef mod) { List invStacks = mod.getItemStorage().getItemStacksPlayerInventory(true); if (!invStacks.isEmpty()) { float handDamage = Float.NEGATIVE_INFINITY; + Item bestItem = null; for (ItemStack invStack : invStacks) { if (invStack.getItem() instanceof SwordItem item) { float itemDamage = item.getMaterial().getAttackDamage(); @@ -45,26 +46,39 @@ public static void equipWeapon(AltoClef mod) { handDamage = handToolItem.getMaterial().getAttackDamage(); } if (itemDamage > handDamage) { - mod.getSlotHandler().forceEquipItem(item); + bestItem = item; } else { - mod.getSlotHandler().forceEquipItem(handItem); + bestItem = handItem; } } } + return bestItem; } + return null; + } + + public static boolean equipWeapon(AltoClef mod) { + Item bestWeapon = bestWeapon(mod); + Item equipedWeapon = StorageHelper.getItemStackInSlot(PlayerSlot.getEquipSlot()).getItem(); + if (bestWeapon != null && bestWeapon != equipedWeapon) { + mod.getSlotHandler().forceEquipItem(bestWeapon); + return true; + } + return false; } @Override protected Task onEntityInteract(AltoClef mod, Entity entity) { // Equip weapon - equipWeapon(mod); - float hitProg = mod.getPlayer().getAttackCooldownProgress(0); - if (hitProg >= 1) { - if (mod.getPlayer().isOnGround() || mod.getPlayer().getVelocity().getY() < 0 || mod.getPlayer().isTouchingWater()) { - LookHelper.lookAt(mod, entity.getEyePos()); - mod.getControllerExtras().attack(entity); + if (!equipWeapon(mod)) { + float hitProg = mod.getPlayer().getAttackCooldownProgress(0); + if (hitProg >= 1) { + if (mod.getPlayer().isOnGround() || mod.getPlayer().getVelocity().getY() < 0 || mod.getPlayer().isTouchingWater()) { + LookHelper.lookAt(mod, entity.getEyePos()); + mod.getControllerExtras().attack(entity); + } } } return null; } -} +} \ No newline at end of file diff --git a/src/main/java/adris/altoclef/tasks/entity/SelfCareTask.java b/src/main/java/adris/altoclef/tasks/entity/SelfCareTask.java new file mode 100644 index 000000000..ef22d2ff1 --- /dev/null +++ b/src/main/java/adris/altoclef/tasks/entity/SelfCareTask.java @@ -0,0 +1,191 @@ +package adris.altoclef.tasks.entity; + +import adris.altoclef.AltoClef; +import adris.altoclef.TaskCatalogue; +import adris.altoclef.tasks.misc.EquipArmorTask; +import adris.altoclef.tasks.misc.SleepThroughNightTask; +import adris.altoclef.tasks.movement.GetToEntityTask; +import adris.altoclef.tasks.movement.TimeoutWanderTask; +import adris.altoclef.tasks.resources.CollectFoodTask; +import adris.altoclef.tasksystem.Task; +import adris.altoclef.util.ItemTarget; +import adris.altoclef.util.helpers.ItemHelper; +import adris.altoclef.util.helpers.StorageHelper; +import adris.altoclef.util.helpers.WorldHelper; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.Items; + +import java.util.Optional; + +public class SelfCareTask extends Task { + private static final ItemTarget[] woodToolSet = new ItemTarget[]{ + new ItemTarget(Items.WOODEN_SWORD, 1), + new ItemTarget(Items.WOODEN_PICKAXE, 1), + new ItemTarget(Items.WOODEN_AXE, 1), + new ItemTarget(Items.WOODEN_SHOVEL, 1), + }; + private static final ItemTarget[] stoneToolSet = new ItemTarget[]{ + new ItemTarget(Items.STONE_SWORD, 1), + new ItemTarget(Items.STONE_PICKAXE, 1), + new ItemTarget(Items.STONE_AXE, 1), + new ItemTarget(Items.STONE_SHOVEL, 1), + }; + private static final ItemTarget[] ironToolSet = new ItemTarget[]{ + new ItemTarget(Items.IRON_SWORD, 1), + new ItemTarget(Items.IRON_PICKAXE, 1), + new ItemTarget(Items.IRON_AXE, 1), + new ItemTarget(Items.IRON_SHOVEL, 1), + }; + private static final ItemTarget[] diamondToolSet = new ItemTarget[]{ + new ItemTarget(Items.DIAMOND_SWORD, 1), + new ItemTarget(Items.DIAMOND_PICKAXE, 1), + new ItemTarget(Items.DIAMOND_AXE, 1), + new ItemTarget(Items.DIAMOND_SHOVEL, 1) + }; + private static final ItemTarget[] netheriteToolSet = new ItemTarget[]{ + new ItemTarget(Items.NETHERITE_SWORD, 1), + new ItemTarget(Items.NETHERITE_PICKAXE, 1), + new ItemTarget(Items.NETHERITE_AXE, 1), + new ItemTarget(Items.NETHERITE_SHOVEL, 1) + }; + private static final Item[] ironArmorSet = new Item[]{ + Items.IRON_HELMET, Items.IRON_CHESTPLATE, Items.IRON_LEGGINGS, Items.IRON_BOOTS + }; + private static final Item[] diamondArmorSet = new Item[]{ + Items.DIAMOND_HELMET, Items.DIAMOND_CHESTPLATE, Items.DIAMOND_LEGGINGS, Items.DIAMOND_BOOTS + }; + private static final Item[] netheriteArmorSet = new Item[]{ + Items.NETHERITE_HELMET, Items.NETHERITE_CHESTPLATE, Items.NETHERITE_LEGGINGS, Items.NETHERITE_BOOTS + }; + private static final Item[] beds = ItemHelper.BED; + private static final Task getBed = TaskCatalogue.getItemTask("bed", 1); + private static final Task getFood = new CollectFoodTask(100); + private static final Task sleepThroughNight = new SleepThroughNightTask(); + private static final Task equipShield = new EquipArmorTask(Items.SHIELD); + private static Task getToolSet; + private static Task equipArmorSet; + private static String debugStateName; + + private static boolean isTaskNotFinished(AltoClef mod, Task task) { + return task != null && task.isActive() && !task.isFinished(mod); + } + + @Override + protected void onStart(AltoClef mod) { + + } + + @Override + protected Task onTick(AltoClef mod) { + boolean hasWoodToolSet = mod.getItemStorage().hasItem(woodToolSet); + boolean hasStoneToolSet = mod.getItemStorage().hasItem(stoneToolSet); + boolean hasIronToolSet = mod.getItemStorage().hasItem(ironToolSet); + boolean hasBed = mod.getItemStorage().hasItem(beds); + boolean hasShield = StorageHelper.isArmorEquipped(mod, Items.SHIELD); + boolean hasIronArmorSet = StorageHelper.isArmorEquippedAll(mod, ironArmorSet); + boolean hasDiamondToolSet = mod.getItemStorage().hasItem(diamondToolSet); + boolean hasDiamondArmorSet = StorageHelper.isArmorEquippedAll(mod, diamondArmorSet); + boolean hasNetheriteToolSet = mod.getItemStorage().hasItem(netheriteToolSet); + boolean hasNetheriteArmorSet = StorageHelper.isArmorEquippedAll(mod, netheriteArmorSet); + Optional player = mod.getEntityTracker().getClosestEntity(PlayerEntity.class); + if (hasBed && WorldHelper.canSleep()) { + setDebugState("Sleeping through night"); + return sleepThroughNight; + } + if (isTaskNotFinished(mod, getToolSet)) { + setDebugState(debugStateName); + return getToolSet; + } + if (isTaskNotFinished(mod, equipShield)) { + setDebugState(debugStateName); + return equipShield; + } + if (isTaskNotFinished(mod, equipArmorSet)) { + setDebugState(debugStateName); + return equipArmorSet; + } + if (isTaskNotFinished(mod, getBed)) { + setDebugState(debugStateName); + return getBed; + } + if (isTaskNotFinished(mod, getFood)) { + setDebugState(debugStateName); + return getFood; + } + if (!hasWoodToolSet) { + debugStateName = "Getting wood tool set"; + getToolSet = TaskCatalogue.getSquashedItemTask(woodToolSet); + return getToolSet; + } + if (!hasStoneToolSet) { + debugStateName = "Getting stone tool set"; + getToolSet = TaskCatalogue.getSquashedItemTask(stoneToolSet); + return getToolSet; + } + if (!hasBed) { + debugStateName = "Getting bed"; + return getBed; + } + if (!mod.getFoodChain().hasFood()) { + debugStateName = "Getting food"; + return getFood; + } + if (!hasIronToolSet) { + debugStateName = "Getting iron tool set"; + getToolSet = TaskCatalogue.getSquashedItemTask(ironToolSet); + return getToolSet; + } + if (!hasShield) { + debugStateName = "Getting shield"; + return equipShield; + } + if (!hasIronArmorSet) { + debugStateName = "Getting and equipping iron armor set"; + equipArmorSet = new EquipArmorTask(ironArmorSet); + return equipArmorSet; + } + if (!hasDiamondToolSet) { + debugStateName = "Getting diamond tool set"; + getToolSet = TaskCatalogue.getSquashedItemTask(diamondToolSet); + return getToolSet; + } + if (!hasDiamondArmorSet) { + debugStateName = "Getting and equipping diamond armor set"; + equipArmorSet = new EquipArmorTask(diamondArmorSet); + return equipArmorSet; + } + if (!hasNetheriteToolSet) { + debugStateName = "Getting netherite tool set"; + getToolSet = TaskCatalogue.getSquashedItemTask(netheriteToolSet); + return getToolSet; + } + if (!hasNetheriteArmorSet) { + debugStateName = "Getting and equipping netherite armor set"; + equipArmorSet = new EquipArmorTask(netheriteArmorSet); + return equipArmorSet; + } + if (player.isPresent()) { + setDebugState("Following player"); + return new GetToEntityTask(player.get(), 2); + } + setDebugState("Wandering until a player is found"); + return new TimeoutWanderTask(); + } + + @Override + protected void onStop(AltoClef mod, Task interruptTask) { + + } + + @Override + protected boolean isEqual(Task other) { + return other instanceof SelfCareTask; + } + + @Override + protected String toDebugString() { + return "Caring self"; + } +} diff --git a/src/main/java/adris/altoclef/tasks/entity/ShootArrowSimpleProjectileTask.java b/src/main/java/adris/altoclef/tasks/entity/ShootArrowSimpleProjectileTask.java new file mode 100644 index 000000000..d706c610a --- /dev/null +++ b/src/main/java/adris/altoclef/tasks/entity/ShootArrowSimpleProjectileTask.java @@ -0,0 +1,147 @@ +package adris.altoclef.tasks.entity; + +import adris.altoclef.AltoClef; +import adris.altoclef.Debug; +import adris.altoclef.tasks.speedrun.BeatMinecraft2Task; +import adris.altoclef.tasksystem.Task; +import adris.altoclef.util.helpers.LookHelper; +import adris.altoclef.util.time.TimerGame; +import baritone.api.utils.Rotation; +import baritone.api.utils.input.Input; +import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.Entity; +import net.minecraft.entity.projectile.ArrowEntity; +import net.minecraft.item.Item; +import net.minecraft.item.Items; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; + +import java.util.Arrays; +import java.util.List; + +public class ShootArrowSimpleProjectileTask extends Task { + + private final Entity target; + private boolean shooting = false; + private boolean shot = false; + + private final TimerGame shotTimer = new TimerGame(1); + + public ShootArrowSimpleProjectileTask(Entity target) { + this.target = target; + } + + @Override + protected void onStart(AltoClef mod) { + shooting = false; + } + + private static Rotation calculateThrowLook(AltoClef mod, Entity target) { + // Velocity based on bow charge. + float velocity = (mod.getPlayer().getItemUseTime() - mod.getPlayer().getItemUseTimeLeft()) / 20f; + velocity = (velocity * velocity + velocity * 2) / 3; + if (velocity > 1) velocity = 1; + + // Find the position of the center + Vec3d targetCenter = target.getBoundingBox().getCenter(); + + double posX = targetCenter.getX(); + double posY = targetCenter.getY(); + double posZ = targetCenter.getZ(); + + // Adjusting for hitbox heights + posY -= 1.9f - target.getHeight(); + + double relativeX = posX - mod.getPlayer().getX(); + double relativeY = posY - mod.getPlayer().getY(); + double relativeZ = posZ - mod.getPlayer().getZ(); + + // Calculate the pitch + double hDistance = Math.sqrt(relativeX * relativeX + relativeZ * relativeZ); + double hDistanceSq = hDistance * hDistance; + final float g = 0.006f; + float velocitySq = velocity * velocity; + float pitch = (float) -Math.toDegrees(Math.atan((velocitySq - Math.sqrt(velocitySq * velocitySq - g * (g * hDistanceSq + 2 * relativeY * velocitySq))) / (g * hDistance))); + + // Set player rotation + if (Float.isNaN(pitch)) { + return new Rotation(target.getYaw(), target.getPitch()); + } else { + return new Rotation(Vec3dToYaw(mod, new Vec3d(posX, posY, posZ)), pitch); + } + } + + private static float Vec3dToYaw(AltoClef mod, Vec3d vec) { + return (mod.getPlayer().getYaw() + + MathHelper.wrapDegrees((float) Math.toDegrees(Math.atan2(vec.getZ() - mod.getPlayer().getZ(), vec.getX() - mod.getPlayer().getX())) - 90f - mod.getPlayer().getYaw())); + } + + @Override + protected Task onTick(AltoClef mod) { + setDebugState("Shooting projectile"); + List requiredArrows = Arrays.asList(Items.ARROW, Items.SPECTRAL_ARROW, Items.TIPPED_ARROW); + + if (!(mod.getItemStorage().hasItem(Items.BOW) && + requiredArrows.stream().anyMatch(mod.getItemStorage()::hasItem))) { + Debug.logMessage("Missing items, stopping."); + return null; + } + + Rotation lookTarget = calculateThrowLook(mod, target); + LookHelper.lookAt(mod, lookTarget); + + // check if we are holding a bow + boolean charged = mod.getPlayer().getItemUseTime() > 20 && mod.getPlayer().getActiveItem().getItem() == Items.BOW; + + mod.getSlotHandler().forceEquipItem(Items.BOW); + + if (LookHelper.isLookingAt(mod, lookTarget) && !shooting) { + mod.getInputControls().hold(Input.CLICK_RIGHT); + shooting = true; + shotTimer.reset(); + } + if (shooting && charged) { + List arrows = mod.getEntityTracker().getTrackedEntities(ArrowEntity.class); + // If any of the arrows belong to us and are moving, do not shoot yet + // Prevents from shooting multiple arrows to the same target + for (ArrowEntity arrow : arrows) { + if (arrow.getOwner() == mod.getPlayer()) { + Vec3d velocity = arrow.getVelocity(); + Vec3d delta = target.getPos().subtract(arrow.getPos()); + boolean isMovingTowardsTarget = velocity.dotProduct(delta) > 0; + if (isMovingTowardsTarget) { + return null; + } + } + } + + if (BeatMinecraft2Task.getConfig().renderDistanceManipulation && MinecraftClient.getInstance().options.getSimulationDistance().getValue() < 32) { + // For farther entities, the arrow may get stuck in the air, so we need to increase the simulation distance + MinecraftClient.getInstance().options.getSimulationDistance().setValue(32); + } + mod.getInputControls().release(Input.CLICK_RIGHT); // Release the arrow + shot = true; + } + return null; + } + + @Override + protected void onStop(AltoClef mod, Task interruptTask) { + mod.getInputControls().release(Input.CLICK_RIGHT); + } + + @Override + public boolean isFinished(AltoClef mod) { + return shot; + } + + @Override + protected boolean isEqual(Task other) { + return false; + } + + @Override + protected String toDebugString() { + return "Shooting arrow at " + target.getType().getTranslationKey(); + } +} \ No newline at end of file diff --git a/src/main/java/adris/altoclef/tasks/misc/PlaceBedAndSetSpawnTask.java b/src/main/java/adris/altoclef/tasks/misc/PlaceBedAndSetSpawnTask.java index 58f79bb29..3c796c947 100644 --- a/src/main/java/adris/altoclef/tasks/misc/PlaceBedAndSetSpawnTask.java +++ b/src/main/java/adris/altoclef/tasks/misc/PlaceBedAndSetSpawnTask.java @@ -11,6 +11,7 @@ import adris.altoclef.tasks.InteractWithBlockTask; import adris.altoclef.tasks.construction.DestroyBlockTask; import adris.altoclef.tasks.construction.PlaceStructureBlockTask; +import adris.altoclef.tasks.entity.KillEntitiesTask; import adris.altoclef.tasks.movement.DefaultGoToDimensionTask; import adris.altoclef.tasks.movement.GetToBlockTask; import adris.altoclef.tasks.movement.TimeoutWanderTask; @@ -28,26 +29,58 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.SleepingChatScreen; +import net.minecraft.entity.Entity; +import net.minecraft.entity.mob.HostileEntity; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.HitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; -import net.minecraft.util.math.Vec3i; +import net.minecraft.util.math.*; import org.apache.commons.lang3.ArrayUtils; +import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; + public class PlaceBedAndSetSpawnTask extends Task { private final TimerGame _regionScanTimer = new TimerGame(9); - private final Vec3i BED_CLEAR_SIZE = new Vec3i(3, 2, 2); + private final Vec3i BED_CLEAR_SIZE = new Vec3i(3, 2, 3); private final Vec3i[] BED_BOTTOM_PLATFORM = new Vec3i[]{ new Vec3i(0, -1, 0), new Vec3i(1, -1, 0), new Vec3i(2, -1, 0), + new Vec3i(0, -1, -1), + new Vec3i(1, -1, -1), + new Vec3i(2, -1, -1), + new Vec3i(0, -1, 1), + new Vec3i(1, -1, 1), + new Vec3i(2, -1, 1) }; // Kinda silly but who knows if we ever want to change it. - private final Vec3i BED_PLACE_STAND_POS = new Vec3i(0, 0, 0); - private final Vec3i BED_PLACE_POS = new Vec3i(1, 0, 0); + private final Vec3i BED_PLACE_STAND_POS = new Vec3i(0, 0, 1); + private final Vec3i BED_PLACE_POS = new Vec3i(1, 0, 1); + private final Vec3i[] BED_PLACE_POS_OFFSET = new Vec3i[]{ + BED_PLACE_POS, + BED_PLACE_POS.north(), + BED_PLACE_POS.south(), + BED_PLACE_POS.east(), + BED_PLACE_POS.west(), + BED_PLACE_POS.add(-1, 0, 1), + BED_PLACE_POS.add(1, 0, 1), + BED_PLACE_POS.add(-1, 0, -1), + BED_PLACE_POS.add(1, 0, -1), + BED_PLACE_POS.north(2), + BED_PLACE_POS.south(2), + BED_PLACE_POS.east(2), + BED_PLACE_POS.west(2), + BED_PLACE_POS.add(-2, 0, 1), + BED_PLACE_POS.add(-2, 0, 2), + BED_PLACE_POS.add(2, 0, 1), + BED_PLACE_POS.add(2, 0, 2), + BED_PLACE_POS.add(-2, 0, -1), + BED_PLACE_POS.add(-2, 0, -2), + BED_PLACE_POS.add(2, 0, -1), + BED_PLACE_POS.add(2, 0, -2) + }; private final Direction BED_PLACE_DIRECTION = Direction.UP; private final TimerGame _bedInteractTimeout = new TimerGame(5); private final TimerGame _inBedTimer = new TimerGame(1); @@ -66,63 +99,96 @@ public PlaceBedAndSetSpawnTask() { } + /** + * Sets the _stayInBed flag to true and returns the current instance. + * + * @return the current instance + */ public PlaceBedAndSetSpawnTask stayInBed() { - _stayInBed = true; + this._stayInBed = true; return this; } + /** + * This method is called when the bot is started. + * It tracks bed blocks, resets progress checkers, and sets up behaviors for placing and breaking blocks near beds. + * It also resets variables for sleep handling and subscribes to events for respawn point and failure messages. + */ @Override protected void onStart(AltoClef mod) { - mod.getBlockTracker().trackBlock(ItemHelper.itemsToBlocks(ItemHelper.BED)); - mod.getBehaviour().push(); - _progressChecker.reset(); - _currentBedRegion = null; - - // Don't break our bed thing. - mod.getBehaviour().avoidBlockPlacing(pos -> { - if (_currentBedRegion != null) { - BlockPos start = _currentBedRegion, - end = _currentBedRegion.add(BED_CLEAR_SIZE); - return start.getX() <= pos.getX() && pos.getX() < end.getX() - && start.getZ() <= pos.getZ() && pos.getZ() < end.getZ() - && start.getY() <= pos.getY() && pos.getY() < end.getY(); - } - return false; - }); - mod.getBehaviour().avoidBlockBreaking(pos -> { - if (_currentBedRegion != null) { - for (Vec3i baseOffs : BED_BOTTOM_PLATFORM) { - BlockPos base = _currentBedRegion.add(baseOffs); - if (base.equals(pos)) return true; + try { + // Track bed blocks + mod.getBlockTracker().trackBlock(ItemHelper.itemsToBlocks(ItemHelper.BED)); + + // Push the current behaviour + mod.getBehaviour().push(); + + // Reset progress checker + _progressChecker.reset(); + + // Reset current bed region + _currentBedRegion = null; + + // Avoid placing blocks near bed + mod.getBehaviour().avoidBlockPlacing(pos -> { + if (_currentBedRegion != null) { + BlockPos start = _currentBedRegion; + BlockPos end = _currentBedRegion.add(BED_CLEAR_SIZE); + return start.getX() <= pos.getX() && pos.getX() < end.getX() + && start.getZ() <= pos.getZ() && pos.getZ() < end.getZ() + && start.getY() <= pos.getY() && pos.getY() < end.getY(); } - } - // Don't ever break beds. If one exists, we will sleep in it. - if (mod.getWorld() != null) { - return mod.getWorld().getBlockState(pos).getBlock() instanceof BedBlock; - } - return false; - }); - _spawnSet = false; - _sleepAttemptMade = false; - _wasSleeping = false; - _respawnPointSetMessageCheck = EventBus.subscribe(ChatMessageEvent.class, evt -> { - String msg = evt.toString(); - if (msg.contains("Respawn point set")) { - _spawnSet = true; - _inBedTimer.reset(); - } - }); - _respawnFailureMessageCheck = EventBus.subscribe(GameOverlayEvent.class, evt -> { - final String[] NEUTRAL_MESSAGES = new String[]{"You can sleep only at night", "You can only sleep at night", "You may not rest now; there are monsters nearby"}; - for (String checkMessage : NEUTRAL_MESSAGES) { - if (evt.message.contains(checkMessage)) { - if (!_sleepAttemptMade) { - _bedInteractTimeout.reset(); + return false; + }); + + // Avoid breaking blocks near bed + mod.getBehaviour().avoidBlockBreaking(pos -> { + if (_currentBedRegion != null) { + for (Vec3i baseOffs : BED_BOTTOM_PLATFORM) { + BlockPos base = _currentBedRegion.add(baseOffs); + if (base.equals(pos)) return true; } - _sleepAttemptMade = true; } - } - }); + // Don't ever break beds. If one exists, we will sleep in it. + if (mod.getWorld() != null) { + return mod.getWorld().getBlockState(pos).getBlock() instanceof BedBlock; + } + return false; + }); + + // Reset variables for sleep handling + _spawnSet = false; + _sleepAttemptMade = false; + _wasSleeping = false; + + // Subscribe to respawn point set message event + _respawnPointSetMessageCheck = EventBus.subscribe(ChatMessageEvent.class, evt -> { + String msg = evt.toString(); + if (msg.contains("Respawn point set")) { + _spawnSet = true; + _inBedTimer.reset(); + } + }); + + // Subscribe to respawn failure message event + _respawnFailureMessageCheck = EventBus.subscribe(GameOverlayEvent.class, evt -> { + final String[] NEUTRAL_MESSAGES = new String[]{ + "You can sleep only at night", + "You can only sleep at night", + "You may not rest now; there are monsters nearby" + }; + for (String checkMessage : NEUTRAL_MESSAGES) { + if (evt.message.contains(checkMessage)) { + if (!_sleepAttemptMade) { + _bedInteractTimeout.reset(); + } + _sleepAttemptMade = true; + } + } + }); + } catch (Exception e) { + e.printStackTrace(); + } } public void resetSleep() { @@ -177,59 +243,81 @@ protected Task onTick(AltoClef mod) { return null; } } - if (mod.getBlockTracker().anyFound(blockPos -> (WorldHelper.canReach(mod, blockPos) && - blockPos.isWithinDistance(mod.getPlayer().getPos(), 40) && - mod.getItemStorage().hasItem(ItemHelper.BED)) || (WorldHelper.canReach(mod, blockPos) && - !mod.getItemStorage().hasItem(ItemHelper.BED)), ItemHelper.itemsToBlocks(ItemHelper.BED))) { - // Sleep in the nearest bed - setDebugState("Going to bed to sleep..."); - return new DoToClosestBlockTask(toSleepIn -> { - boolean closeEnough = toSleepIn.isWithinDistance(mod.getPlayer().getPos(), 3); - if (closeEnough) { - // why 0.2? I'm tired. - Vec3d centerBed = new Vec3d(toSleepIn.getX() + 0.5, toSleepIn.getY() + 0.2, toSleepIn.getZ() + 0.5); - BlockHitResult hit = LookHelper.raycast(mod.getPlayer(), centerBed, 6); - // TODO: Kinda ugly, but I'm tired and fixing for the 2nd attempt speedrun so I will fix this block later - closeEnough = false; - if (hit.getType() != HitResult.Type.MISS) { - // At this poinAt, if we miss, we probably are close enough. - BlockPos p = hit.getBlockPos(); - if (ArrayUtils.contains(ItemHelper.itemsToBlocks(ItemHelper.BED), mod.getWorld().getBlockState(p).getBlock())) { - // We have a bed! - closeEnough = true; - } - } - } - _bedForSpawnPoint = WorldHelper.getBedHead(mod, toSleepIn); - if (_bedForSpawnPoint == null) { - _bedForSpawnPoint = toSleepIn; + Block[] copperBlocks = ItemHelper.itemsToBlocks(ItemHelper.COPPER_BLOCKS); + Optional nearestBed = mod.getBlockTracker().getNearestTracking(ItemHelper.itemsToBlocks(ItemHelper.BED)); + if (nearestBed.isPresent() && !WorldHelper.isAir(mod, nearestBed.get())) { + Block bed = mod.getWorld().getBlockState(nearestBed.get()).getBlock(); + for (Block CopperBlock : copperBlocks) { + Block blockBelow = mod.getWorld().getBlockState(nearestBed.get().down()).getBlock(); + if (blockBelow == CopperBlock) { + mod.getBlockTracker().requestBlockUnreachable(nearestBed.get(), 0); + return null; } - if (!closeEnough) { - try { - Direction face = mod.getWorld().getBlockState(toSleepIn).get(BedBlock.FACING); - Direction side = face.rotateYClockwise(); - /* - BlockPos targetMove = toSleepIn.offset(side).offset(side); // Twice, juust to make sure... - */ - return new GetToBlockTask(_bedForSpawnPoint.add(side.getVector())); - } catch (IllegalArgumentException e) { - // If bed is not loaded, this will happen. In that case just get to the bed first. + } + if (nearestBed.get().isWithinDistance(mod.getPlayer().getPos(), 40)) { + // Check if there are monsters nearby + Vec3d vec3d = Vec3d.ofBottomCenter(nearestBed.get()); + List list = mod.getWorld().getEntitiesByClass(HostileEntity.class, new Box(vec3d.getX() - 8.0, vec3d.getY() - 5.0, vec3d.getZ() - 8.0, vec3d.getX() + 8.0, vec3d.getY() + 5.0, vec3d.getZ() + 8.0), (entity) -> entity.isAngryAt(mod.getPlayer())); + if (!list.isEmpty()) { + for (HostileEntity entity : list) { + setDebugState("Killing monster nearby"); + Predicate valid = e -> e == entity; + return new KillEntitiesTask(valid, entity.getClass()); } - } else { - _inBedTimer.reset(); - } - if (closeEnough) { - _inBedTimer.reset(); } - // Keep track of where our spawn point is - _progressChecker.reset(); - return new InteractWithBlockTask(_bedForSpawnPoint); - }, ItemHelper.itemsToBlocks(ItemHelper.BED)); + // Sleep in the nearest bed + setDebugState("Going to bed to sleep..."); + return new DoToClosestBlockTask(toSleepIn -> { + boolean closeEnough = toSleepIn.isWithinDistance(mod.getPlayer().getPos(), 3); + if (closeEnough) { + // why 0.2? I'm tired. + Vec3d centerBed = new Vec3d(toSleepIn.getX() + 0.5, toSleepIn.getY() + 0.2, toSleepIn.getZ() + 0.5); + BlockHitResult hit = LookHelper.raycast(mod.getPlayer(), centerBed, 6); + // TODO: Kinda ugly, but I'm tired and fixing for the 2nd attempt speedrun so I will fix this block later + closeEnough = false; + if (hit.getType() != HitResult.Type.MISS) { + // At this poinAt, if we miss, we probably are close enough. + BlockPos p = hit.getBlockPos(); + if (ArrayUtils.contains(new Block[]{bed}, mod.getWorld().getBlockState(p).getBlock())) { + // We have a bed! + closeEnough = true; + } + } + } + _bedForSpawnPoint = WorldHelper.getBedHead(mod, toSleepIn); + if (_bedForSpawnPoint == null) { + _bedForSpawnPoint = toSleepIn; + } + if (!closeEnough) { + try { + Direction face = mod.getWorld().getBlockState(toSleepIn).get(BedBlock.FACING); + Direction side = face.rotateYClockwise(); + /* + BlockPos targetMove = toSleepIn.offset(side).offset(side); // Twice, juust to make sure... + */ + return new GetToBlockTask(_bedForSpawnPoint.add(side.getVector())); + } catch (IllegalArgumentException e) { + // If bed is not loaded, this will happen. In that case just get to the bed first. + } + } else { + _inBedTimer.reset(); + } + if (closeEnough) { + _inBedTimer.reset(); + } + // Keep track of where our spawn point is + _progressChecker.reset(); + return new InteractWithBlockTask(_bedForSpawnPoint); + }, bed); + } } if (_currentBedRegion != null) { - Block getBlock = mod.getWorld().getBlockState(_currentBedRegion.add(BED_PLACE_POS)).getBlock(); - if (getBlock instanceof BedBlock) { - mod.getBlockTracker().addBlock(getBlock, _currentBedRegion.add(BED_PLACE_POS)); + for (Vec3i BedPlacePos : BED_PLACE_POS_OFFSET) { + Block getBlock = mod.getWorld().getBlockState(_currentBedRegion.add(BedPlacePos)).getBlock(); + if (getBlock instanceof BedBlock) { + mod.getBlockTracker().addBlock(getBlock, _currentBedRegion.add(BedPlacePos)); + break; + } } } // Get a bed if we don't have one. @@ -324,75 +412,180 @@ protected Task onTick(AltoClef mod) { return new InteractWithBlockTask(new ItemTarget("bed", 1), BED_PLACE_DIRECTION, toPlace.offset(BED_PLACE_DIRECTION.getOpposite()), false); } + /** + * Perform cleanup tasks when the task is stopped. + * + * @param mod The AltoClef mod instance + * @param interruptTask The task that caused the interruption + */ @Override protected void onStop(AltoClef mod, Task interruptTask) { - mod.getBlockTracker().stopTracking(ItemHelper.itemsToBlocks(ItemHelper.BED)); - mod.getBehaviour().pop(); - EventBus.unsubscribe(_respawnPointSetMessageCheck); - EventBus.unsubscribe(_respawnFailureMessageCheck); + // Stop tracking beds + if (mod.getBlockTracker() != null) { + mod.getBlockTracker().stopTracking(ItemHelper.itemsToBlocks(ItemHelper.BED)); + } + + // Pop the behaviour stack + if (mod.getBehaviour() != null) { + mod.getBehaviour().pop(); + } + + // Unsubscribe from respawn point set message + if (_respawnPointSetMessageCheck != null) { + EventBus.unsubscribe(_respawnPointSetMessageCheck); + } + + // Unsubscribe from respawn failure message + if (_respawnFailureMessageCheck != null) { + EventBus.unsubscribe(_respawnFailureMessageCheck); + } } + /** + * Check if the given task is equal to this task. + * + * @param other The other task to compare with + * @return True if the other task is equal to this task, false otherwise + */ @Override protected boolean isEqual(Task other) { + if (other == null) { + return false; + } + // Check if the other task is an instance of PlaceBedAndSetSpawnTask return other instanceof PlaceBedAndSetSpawnTask; } + /** + * Returns a debug string representing the action of placing a bed nearby and resetting the spawn point. + * + * @return the debug string + */ @Override protected String toDebugString() { - return "Placing a bed nearby + resetting spawn point"; + try { + // Place a bed nearby and reset spawn point + return "Placing a bed nearby + resetting spawn point"; + } catch (Exception e) { + e.printStackTrace(); + return "Error generating debug string"; + } } + /** + * Check if the player is finished with the sleeping task. + * + * @param mod the AltoClef mod + * @return true if the player is finished, false otherwise + */ @Override public boolean isFinished(AltoClef mod) { + // Check if we are in the overworld if (WorldHelper.getCurrentDimension() != Dimension.OVERWORLD) { - Debug.logWarning("Can't place spawnpoint/sleep in a bed unless we're in the overworld!"); - return true; + return true; // If not in the overworld, the player is considered finished } - return _spawnSet && !mod.getPlayer().isSleeping() && _inBedTimer.elapsed(); + + // Check if player is sleeping + boolean isSleeping = mod.getPlayer() != null && mod.getPlayer().isSleeping(); + + // Check if timer has elapsed + boolean timerElapsed = _inBedTimer != null && _inBedTimer.elapsed(); + + // Check if spawnpoint is set, player is not sleeping, and timer has elapsed + boolean isFinished = _spawnSet && !isSleeping && timerElapsed; + + return isFinished; } + /** + * Returns the position of the bed where the player last slept. + * @return the position of the bed where the player last slept + * @throws IllegalStateException if the bed position has not been set + */ public BlockPos getBedSleptPos() { - return _bedForSpawnPoint; + if (_bedForSpawnPoint != null) { + return _bedForSpawnPoint; + } else { + throw new IllegalStateException("Bed position has not been set"); + } } + /** + * Check if the spawn point is set. + * @return true if the spawn point is set, false otherwise + */ public boolean isSpawnSet() { return _spawnSet; } + /** + * Locates the closest good position within a certain range of the origin. + * + * @param mod the mod instance + * @param origin the origin position + * @return the closest good position within the range of the origin + */ private BlockPos locateBedRegion(AltoClef mod, BlockPos origin) { final int SCAN_RANGE = 10; - BlockPos closestGood = null; - double closestDist = Double.POSITIVE_INFINITY; - for (int dx = origin.getX() - SCAN_RANGE; dx < origin.getX() + SCAN_RANGE; ++dx) { - for (int dz = origin.getZ() - SCAN_RANGE; dz < origin.getZ() + SCAN_RANGE; ++dz) { - outer: - for (int dy = origin.getY() - SCAN_RANGE; dy < origin.getY() + SCAN_RANGE; ++dy) { - // Test range - BlockPos attemptStandPos = new BlockPos(dx, dy, dz); - double distance = attemptStandPos.getSquaredDistance(mod.getPlayer().getPos()); - if (distance > closestDist) continue; - // Everything from here on out is checking for a BETTER pos. - for (int checkX = 0; checkX < BED_CLEAR_SIZE.getX(); ++checkX) { - for (int checkY = 0; checkY < BED_CLEAR_SIZE.getY(); ++checkY) { - for (int checkZ = 0; checkZ < BED_CLEAR_SIZE.getZ(); ++checkZ) { - BlockPos checkAsGoodArea = attemptStandPos.add(checkX, checkY, checkZ); - if (!isGoodToPlaceInsideOrClear(mod, checkAsGoodArea)) { - continue outer; - } - } - } + BlockPos closestGood = null; // The closest good position found so far + double closestDist = Double.POSITIVE_INFINITY; // The closest distance found so far + + for (int x = origin.getX() - SCAN_RANGE; x < origin.getX() + SCAN_RANGE; ++x) { + for (int z = origin.getZ() - SCAN_RANGE; z < origin.getZ() + SCAN_RANGE; ++z) { + for (int y = origin.getY() - SCAN_RANGE; y < origin.getY() + SCAN_RANGE; ++y) { + BlockPos attemptPos = new BlockPos(x, y, z); + double distance = attemptPos.getSquaredDistance(mod.getPlayer().getPos()); + + if (distance > closestDist) { + continue; // Skip if the distance is greater than the closest distance found so far + } + + if (isGoodPosition(mod, attemptPos)) { + closestGood = attemptPos; + closestDist = distance; } - closestGood = attemptStandPos; - closestDist = distance; } } } + return closestGood; } + /** + * Checks if the position is suitable for placing an object. + * + * @param mod the AltoClef object + * @param pos the position to check + * @return true if the position is suitable, false otherwise + */ + private boolean isGoodPosition(AltoClef mod, BlockPos pos) { + final BlockPos BED_CLEAR_SIZE = new BlockPos(2, 1, 2); + + // Iterate over the area around the position + for (int x = 0; x < BED_CLEAR_SIZE.getX(); ++x) { + for (int y = 0; y < BED_CLEAR_SIZE.getY(); ++y) { + for (int z = 0; z < BED_CLEAR_SIZE.getZ(); ++z) { + BlockPos checkPos = pos.add(x, y, z); + if (!isGoodToPlaceInsideOrClear(mod, checkPos)) { + return false; + } + } + } + } + + return true; + } + + /** + * Check if it is good to place inside or clear at the given position + * @param mod the AltoClef object + * @param pos the position to check + * @return true if it is good to place inside or clear, false otherwise + */ private boolean isGoodToPlaceInsideOrClear(AltoClef mod, BlockPos pos) { - final Vec3i[] CHECK = new Vec3i[]{ + // Define the offsets to check around the position + final Vec3i[] CHECK = { new Vec3i(0, 0, 0), new Vec3i(-1, 0, 0), new Vec3i(1, 0, 0), @@ -401,15 +594,33 @@ private boolean isGoodToPlaceInsideOrClear(AltoClef mod, BlockPos pos) { new Vec3i(0, 0, 1), new Vec3i(0, 0, -1) }; - for (Vec3i offs : CHECK) { - if (!isGoodAsBorder(mod, pos.add(offs))) return false; + + // Check each offset + for (Vec3i offset : CHECK) { + BlockPos newPos = pos.add(offset); + if (!isGoodAsBorder(mod, newPos)) { + return false; + } } + return true; } + /** + * Check if the given position is suitable as a border. + * + * @param mod The AltoClef object + * @param pos The position to check + * @return true if the position is suitable as a border, false otherwise + */ private boolean isGoodAsBorder(AltoClef mod, BlockPos pos) { + // Check if the position is solid if (WorldHelper.isSolid(mod, pos)) { + // If solid, check if it can be broken return WorldHelper.canBreak(mod, pos); - } else return (WorldHelper.isAir(mod, pos)); + } else { + // If not solid, check if it is air + return WorldHelper.isAir(mod, pos); + } } } diff --git a/src/main/java/adris/altoclef/tasks/movement/CustomBaritoneGoalTask.java b/src/main/java/adris/altoclef/tasks/movement/CustomBaritoneGoalTask.java index b8729f059..e7a427e77 100644 --- a/src/main/java/adris/altoclef/tasks/movement/CustomBaritoneGoalTask.java +++ b/src/main/java/adris/altoclef/tasks/movement/CustomBaritoneGoalTask.java @@ -33,7 +33,7 @@ public abstract class CustomBaritoneGoalTask extends Task implements ITaskRequir Blocks.BIG_DRIPLEAF_STEM, Blocks.SMALL_DRIPLEAF, Blocks.TALL_GRASS, - Blocks.GRASS, + Blocks.GRASS_BLOCK, Blocks.SWEET_BERRY_BUSH }; private Task _unstuckTask = null; @@ -113,17 +113,15 @@ protected Task onTick(AltoClef mod) { mod.getInputControls().hold(Input.SNEAK); mod.getInputControls().hold(Input.MOVE_FORWARD); return null; - } else { - mod.getInputControls().release(Input.SNEAK); - mod.getInputControls().release(Input.MOVE_BACK); - mod.getInputControls().release(Input.MOVE_FORWARD); - } - } else { - if (mod.getClientBaritone().getPathingBehavior().isPathing()) { - mod.getInputControls().release(Input.SNEAK); - mod.getInputControls().release(Input.MOVE_BACK); - mod.getInputControls().release(Input.MOVE_FORWARD); } + mod.getInputControls().release(Input.SNEAK); + mod.getInputControls().release(Input.MOVE_BACK); + mod.getInputControls().release(Input.MOVE_FORWARD); + } + if (mod.getClientBaritone().getPathingBehavior().isPathing()) { + mod.getInputControls().release(Input.SNEAK); + mod.getInputControls().release(Input.MOVE_BACK); + mod.getInputControls().release(Input.MOVE_FORWARD); } if (_unstuckTask != null && _unstuckTask.isActive() && !_unstuckTask.isFinished(mod) && stuckInBlock(mod) != null) { setDebugState("Getting unstuck from block."); @@ -162,8 +160,8 @@ protected Task onTick(AltoClef mod) { } } } - - if (!mod.getClientBaritone().getCustomGoalProcess().isActive()) { + if (!mod.getClientBaritone().getCustomGoalProcess().isActive() + && mod.getClientBaritone().getPathingBehavior().isSafeToCancel()) { mod.getClientBaritone().getCustomGoalProcess().setGoalAndPath(_cachedGoal); } setDebugState("Completing goal."); diff --git a/src/main/java/adris/altoclef/tasks/movement/EscapeFromLavaTask.java b/src/main/java/adris/altoclef/tasks/movement/EscapeFromLavaTask.java index 6bc9afbe3..65af80201 100644 --- a/src/main/java/adris/altoclef/tasks/movement/EscapeFromLavaTask.java +++ b/src/main/java/adris/altoclef/tasks/movement/EscapeFromLavaTask.java @@ -24,6 +24,7 @@ public EscapeFromLavaTask() { @Override protected void onStart(AltoClef mod) { + mod.getFoodChain().shouldStop(true); mod.getBehaviour().push(); mod.getClientBaritone().getExploreProcess().onLostControl(); mod.getClientBaritone().getCustomGoalProcess().onLostControl(); @@ -41,15 +42,18 @@ protected Task onTick(AltoClef mod) { if (mod.getPlayer().isInLava() || mod.getWorld().getBlockState(mod.getPlayer().getBlockPos().down()).getBlock() == Blocks.LAVA) { mod.getInputControls().hold(Input.JUMP); mod.getInputControls().hold(Input.SPRINT); + mod.getInputControls().hold(Input.MOVE_FORWARD); } return super.onTick(mod); } @Override protected void onStop(AltoClef mod, Task interruptTask) { + mod.getFoodChain().shouldStop(false); mod.getBehaviour().pop(); mod.getInputControls().release(Input.JUMP); mod.getInputControls().release(Input.SPRINT); + mod.getInputControls().release(Input.MOVE_FORWARD); } @Override diff --git a/src/main/java/adris/altoclef/tasks/movement/GetToEntityTask.java b/src/main/java/adris/altoclef/tasks/movement/GetToEntityTask.java index 4a85d4c02..b838d4778 100644 --- a/src/main/java/adris/altoclef/tasks/movement/GetToEntityTask.java +++ b/src/main/java/adris/altoclef/tasks/movement/GetToEntityTask.java @@ -30,7 +30,7 @@ public class GetToEntityTask extends Task implements ITaskRequiresGrounded { Blocks.BIG_DRIPLEAF_STEM, Blocks.SMALL_DRIPLEAF, Blocks.TALL_GRASS, - Blocks.GRASS, + Blocks.GRASS_BLOCK, Blocks.SWEET_BERRY_BUSH }; private Task _unstuckTask = null; diff --git a/src/main/java/adris/altoclef/tasks/movement/GoToStrongholdPortalTask.java b/src/main/java/adris/altoclef/tasks/movement/GoToStrongholdPortalTask.java index 36348c10e..e231799df 100644 --- a/src/main/java/adris/altoclef/tasks/movement/GoToStrongholdPortalTask.java +++ b/src/main/java/adris/altoclef/tasks/movement/GoToStrongholdPortalTask.java @@ -13,6 +13,7 @@ public class GoToStrongholdPortalTask extends Task { private final LocateStrongholdCoordinatesTask _locateCoordsTask; private final int _targetEyes; + private final int MINIMUM_EYES = 12; private BlockPos _strongholdCoordinates; public GoToStrongholdPortalTask(int targetEyes) { @@ -36,9 +37,9 @@ protected Task onTick(AltoClef mod) { if (_strongholdCoordinates == null) { _strongholdCoordinates = _locateCoordsTask.getStrongholdCoordinates().orElse(null); if (_strongholdCoordinates == null) { - if (mod.getItemStorage().getItemCount(Items.ENDER_EYE) < _targetEyes && mod.getEntityTracker().itemDropped(Items.ENDER_EYE)) { + if (mod.getItemStorage().getItemCount(Items.ENDER_EYE) < MINIMUM_EYES && mod.getEntityTracker().itemDropped(Items.ENDER_EYE)) { setDebugState("Picking up dropped eye"); - return new PickupDroppedItemTask(Items.ENDER_EYE, _targetEyes); + return new PickupDroppedItemTask(Items.ENDER_EYE, MINIMUM_EYES); } setDebugState("Triangulating stronghold..."); return _locateCoordsTask; diff --git a/src/main/java/adris/altoclef/tasks/movement/LocateStrongholdCoordinatesTask.java b/src/main/java/adris/altoclef/tasks/movement/LocateStrongholdCoordinatesTask.java index 69ece43ed..9d24d7864 100644 --- a/src/main/java/adris/altoclef/tasks/movement/LocateStrongholdCoordinatesTask.java +++ b/src/main/java/adris/altoclef/tasks/movement/LocateStrongholdCoordinatesTask.java @@ -18,7 +18,6 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3i; -import java.util.List; import java.util.Optional; public class LocateStrongholdCoordinatesTask extends Task { @@ -28,16 +27,23 @@ public class LocateStrongholdCoordinatesTask extends Task { private static final int SECOND_EYE_THROW_DISTANCE = 30; // target distance between first throw and second throw private final int _targetEyes; + private final int _minimumEyes; private final TimerGame _throwTimer = new TimerGame(5); private LocateStrongholdCoordinatesTask.EyeDirection _cachedEyeDirection = null; private LocateStrongholdCoordinatesTask.EyeDirection _cachedEyeDirection2 = null; private Entity _currentThrownEye = null; private Vec3i _strongholdEstimatePos = null; - public LocateStrongholdCoordinatesTask(int targetEyes) { + public LocateStrongholdCoordinatesTask(int targetEyes, int minimumEyes) { _targetEyes = targetEyes; + _minimumEyes = minimumEyes; } + public LocateStrongholdCoordinatesTask(int targetEyes) { + this(targetEyes, 12); + } + + @SuppressWarnings("UnnecessaryLocalVariable") static Vec3i calculateIntersection(Vec3d start1, Vec3d direction1, Vec3d start2, Vec3d direction2) { Vec3d s1 = start1; @@ -67,7 +73,7 @@ protected Task onTick(AltoClef mod) { } // Pick up eye if we need to/want to. - if (mod.getItemStorage().getItemCount(Items.ENDER_EYE) < _targetEyes && mod.getEntityTracker().itemDropped(Items.ENDER_EYE) && + if (mod.getItemStorage().getItemCount(Items.ENDER_EYE) < _minimumEyes && mod.getEntityTracker().itemDropped(Items.ENDER_EYE) && !mod.getEntityTracker().entityFound(EyeOfEnderEntity.class)) { setDebugState("Picking up dropped ender eye."); return new PickupDroppedItemTask(Items.ENDER_EYE, _targetEyes); @@ -77,19 +83,15 @@ protected Task onTick(AltoClef mod) { if (mod.getEntityTracker().entityFound(EyeOfEnderEntity.class)) { if (_currentThrownEye == null || !_currentThrownEye.isAlive()) { Debug.logMessage("New eye direction"); - List enderEyes = mod.getEntityTracker().getTrackedEntities(EyeOfEnderEntity.class); - if (!enderEyes.isEmpty()) { - for (EyeOfEnderEntity enderEye : enderEyes) { - _currentThrownEye = enderEye; - } - } + Optional eye = mod.getEntityTracker().getClosestEntity(EyeOfEnderEntity.class); + eye.ifPresent(entity -> _currentThrownEye = entity); if (_cachedEyeDirection2 != null) { _cachedEyeDirection = null; _cachedEyeDirection2 = null; } else if (_cachedEyeDirection == null) { - _cachedEyeDirection = new LocateStrongholdCoordinatesTask.EyeDirection(_currentThrownEye.getPos()); + _cachedEyeDirection = new EyeDirection(_currentThrownEye.getPos()); } else { - _cachedEyeDirection2 = new LocateStrongholdCoordinatesTask.EyeDirection(_currentThrownEye.getPos()); + _cachedEyeDirection2 = new EyeDirection(_currentThrownEye.getPos()); } } if (_cachedEyeDirection2 != null) { @@ -98,6 +100,12 @@ protected Task onTick(AltoClef mod) { _cachedEyeDirection.updateEyePos(_currentThrownEye.getPos()); } + if (mod.getEntityTracker().getClosestEntity(EyeOfEnderEntity.class).isPresent() && + !mod.getClientBaritone().getPathingBehavior().isPathing()) { + LookHelper.lookAt(mod, + mod.getEntityTracker().getClosestEntity(EyeOfEnderEntity.class).get().getEyePos()); + } + setDebugState("Waiting for eye to travel."); return null; } diff --git a/src/main/java/adris/altoclef/tasks/movement/MLGBucketTask.java b/src/main/java/adris/altoclef/tasks/movement/MLGBucketTask.java index 14c38aa97..a086d250e 100644 --- a/src/main/java/adris/altoclef/tasks/movement/MLGBucketTask.java +++ b/src/main/java/adris/altoclef/tasks/movement/MLGBucketTask.java @@ -29,7 +29,6 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.RaycastContext; -import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -182,7 +181,7 @@ private Task placeMLGBucketTask(AltoClef mod, BlockPos toPlaceOn) { } IPlayerContext ctx = mod.getClientBaritone().getPlayerContext(); - Optional reachable = RotationUtils.reachableCenter(ctx.player(), toPlaceOn, ctx.playerController().getBlockReachDistance(), false); + Optional reachable = RotationUtils.reachable(ctx, toPlaceOn); if (reachable.isPresent()) { setDebugState("Performing MLG"); LookHelper.lookAt(mod, reachable.get()); @@ -199,9 +198,7 @@ private Task placeMLGBucketTask(AltoClef mod, BlockPos toPlaceOn) { } } } - // Try to capture tall grass as well... - BlockPos[] toCheckLook = new BlockPos[]{toPlaceOn, toPlaceOn.up(), toPlaceOn.up(2)}; - if (hasClutch && Arrays.stream(toCheckLook).anyMatch(check -> mod.getClientBaritone().getPlayerContext().isLookingAt(check))) { + if (hasClutch) { Debug.logMessage("HIT: " + willLandIn); _placedPos = willLandIn; mod.getInputControls().tryPress(Input.CLICK_RIGHT); @@ -287,8 +284,6 @@ private void handleJumpForLand(AltoClef mod, BlockPos willLandOn) { private Optional getBlockWeWillLandOn(AltoClef mod) { Vec3d velCheck = mod.getPlayer().getVelocity(); - // Flatten and slightly exaggerate the velocity - velCheck.multiply(10, 0, 10); Box b = mod.getPlayer().getBoundingBox().offset(velCheck); Vec3d c = b.getCenter(); Vec3d[] coords = new Vec3d[]{ diff --git a/src/main/java/adris/altoclef/tasks/movement/PickupDroppedItemTask.java b/src/main/java/adris/altoclef/tasks/movement/PickupDroppedItemTask.java index 51a38bb53..9c3d0b31c 100644 --- a/src/main/java/adris/altoclef/tasks/movement/PickupDroppedItemTask.java +++ b/src/main/java/adris/altoclef/tasks/movement/PickupDroppedItemTask.java @@ -49,7 +49,7 @@ public class PickupDroppedItemTask extends AbstractDoToClosestObjectTask getEntities(AltoClef mod) { - return new ArrayList<>(mod.getEntityTracker().getTrackedEntities(CreeperEntity.class)); + protected Optional getEntities(AltoClef mod) { + return mod.getEntityTracker().getClosestEntity(CreeperEntity.class); } @Override diff --git a/src/main/java/adris/altoclef/tasks/movement/RunAwayFromEntitiesTask.java b/src/main/java/adris/altoclef/tasks/movement/RunAwayFromEntitiesTask.java index 23aae3b60..c74b54bcc 100644 --- a/src/main/java/adris/altoclef/tasks/movement/RunAwayFromEntitiesTask.java +++ b/src/main/java/adris/altoclef/tasks/movement/RunAwayFromEntitiesTask.java @@ -5,26 +5,25 @@ import baritone.api.pathing.goals.Goal; import net.minecraft.entity.Entity; -import java.util.List; -import java.util.function.Supplier; +import java.util.Optional; public abstract class RunAwayFromEntitiesTask extends CustomBaritoneGoalTask { - private final Supplier> _runAwaySupplier; + private final Entity _runAwaySupplier; private final double _distanceToRun; private final boolean _xz; // See GoalrunAwayFromEntities penalty value private final double _penalty; - public RunAwayFromEntitiesTask(Supplier> toRunAwayFrom, double distanceToRun, boolean xz, double penalty) { + public RunAwayFromEntitiesTask(Entity toRunAwayFrom, double distanceToRun, boolean xz, double penalty) { _runAwaySupplier = toRunAwayFrom; _distanceToRun = distanceToRun; _xz = xz; _penalty = penalty; } - public RunAwayFromEntitiesTask(Supplier> toRunAwayFrom, double distanceToRun, double penalty) { + public RunAwayFromEntitiesTask(Entity toRunAwayFrom, double distanceToRun, double penalty) { this(toRunAwayFrom, distanceToRun, false, penalty); } @@ -42,8 +41,8 @@ public GoalRunAwayStuff(AltoClef mod, double distance, boolean xz) { } @Override - protected List getEntities(AltoClef mod) { - return _runAwaySupplier.get(); + protected Optional getEntities(AltoClef mod) { + return Optional.ofNullable(_runAwaySupplier); } } } diff --git a/src/main/java/adris/altoclef/tasks/movement/RunAwayFromHostilesTask.java b/src/main/java/adris/altoclef/tasks/movement/RunAwayFromHostilesTask.java index 39163080d..0e1c04854 100644 --- a/src/main/java/adris/altoclef/tasks/movement/RunAwayFromHostilesTask.java +++ b/src/main/java/adris/altoclef/tasks/movement/RunAwayFromHostilesTask.java @@ -3,14 +3,12 @@ import adris.altoclef.AltoClef; import adris.altoclef.tasksystem.Task; import adris.altoclef.util.baritone.GoalRunAwayFromEntities; -import adris.altoclef.util.helpers.BaritoneHelper; import baritone.api.pathing.goals.Goal; import net.minecraft.entity.Entity; import net.minecraft.entity.mob.SkeletonEntity; import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import java.util.Optional; public class RunAwayFromHostilesTask extends CustomBaritoneGoalTask { @@ -54,15 +52,20 @@ public GoalRunAwayFromHostiles(AltoClef mod, double distance) { } @Override - protected List getEntities(AltoClef mod) { - List result; - Stream stream = mod.getEntityTracker().getHostiles().stream(); - synchronized (BaritoneHelper.MINECRAFT_LOCK) { - if (!_includeSkeletons) { - stream = stream.filter(hostile -> !(hostile instanceof SkeletonEntity)); + protected Optional getEntities(AltoClef mod) { + List hostiles = mod.getEntityTracker().getHostiles(); + if (!hostiles.isEmpty()) { + for (Entity hostile : hostiles) { + Optional closestHostile = mod.getEntityTracker().getClosestEntity(hostile.getClass()); + if (closestHostile.isPresent()) { + if (!_includeSkeletons && closestHostile.get() instanceof SkeletonEntity) { + return Optional.empty(); + } + return closestHostile; + } } - return stream.collect(Collectors.toList()); } + return Optional.empty(); } } } diff --git a/src/main/java/adris/altoclef/tasks/movement/TimeoutWanderTask.java b/src/main/java/adris/altoclef/tasks/movement/TimeoutWanderTask.java index 1d79eb6d8..f2390439e 100644 --- a/src/main/java/adris/altoclef/tasks/movement/TimeoutWanderTask.java +++ b/src/main/java/adris/altoclef/tasks/movement/TimeoutWanderTask.java @@ -22,8 +22,8 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; -import java.util.List; import java.util.Optional; +import java.util.function.Predicate; /** * Call this when the place you're currently at is bad for some reason and you just wanna get away. @@ -47,7 +47,7 @@ public class TimeoutWanderTask extends Task implements ITaskRequiresGrounded { Blocks.BIG_DRIPLEAF_STEM, Blocks.SMALL_DRIPLEAF, Blocks.TALL_GRASS, - Blocks.GRASS, + Blocks.GRASS_BLOCK, Blocks.SWEET_BERRY_BUSH }; private Vec3d _origin; @@ -184,13 +184,11 @@ protected Task onTick(AltoClef mod) { return _unstuckTask; } if (!_progressChecker.check(mod) || !stuckCheck.check(mod)) { - List closeEntities = mod.getEntityTracker().getCloseEntities(); - for (Entity CloseEntities : closeEntities) { - if (CloseEntities instanceof MobEntity && - CloseEntities.getPos().isInRange(mod.getPlayer().getPos(), 1)) { - setDebugState("Killing annoying entity."); - return new KillEntitiesTask(CloseEntities.getClass()); - } + Optional mob = mod.getEntityTracker().getClosestEntity(MobEntity.class); + if (mob.isPresent() && mob.get().getPos().isInRange(mod.getPlayer().getPos(), 1)) { + setDebugState("Killing annoying entity."); + Predicate valid = entity -> entity == mob.get(); + return new KillEntitiesTask(valid, mob.get().getClass()); } BlockPos blockStuck = stuckInBlock(mod); if (blockStuck != null) { diff --git a/src/main/java/adris/altoclef/tasks/resources/CollectBedTask.java b/src/main/java/adris/altoclef/tasks/resources/CollectBedTask.java index f2a9790e2..929e4349f 100644 --- a/src/main/java/adris/altoclef/tasks/resources/CollectBedTask.java +++ b/src/main/java/adris/altoclef/tasks/resources/CollectBedTask.java @@ -1,6 +1,7 @@ package adris.altoclef.tasks.resources; import adris.altoclef.AltoClef; +import adris.altoclef.Debug; import adris.altoclef.TaskCatalogue; import adris.altoclef.tasks.ResourceTask; import adris.altoclef.tasksystem.Task; @@ -8,8 +9,12 @@ import adris.altoclef.util.ItemTarget; import adris.altoclef.util.MiningRequirement; import adris.altoclef.util.helpers.ItemHelper; +import adris.altoclef.util.helpers.WorldHelper; import net.minecraft.block.Block; import net.minecraft.item.Item; +import net.minecraft.util.math.BlockPos; + +import java.util.Optional; public class CollectBedTask extends CraftWithMatchingWoolTask { @@ -57,9 +62,18 @@ protected void onResourceStop(AltoClef mod, Task interruptTask) { @Override protected Task onResourceTick(AltoClef mod) { // Break beds from the world if possible, that would be pretty fast. - if (mod.getBlockTracker().anyFound(BEDS)) { - // Failure + blacklisting is encapsulated within THIS task - return new MineAndCollectTask(new ItemTarget(ItemHelper.BED, 1), BEDS, MiningRequirement.HAND); + Block[] copperBlocks = ItemHelper.itemsToBlocks(ItemHelper.COPPER_BLOCKS); + Optional nearestBed = mod.getBlockTracker().getNearestTracking(BEDS); + if (nearestBed.isPresent() && WorldHelper.canBreak(mod, nearestBed.get())) { + for (Block CopperBlock : copperBlocks) { + Block blockBelow = mod.getWorld().getBlockState(nearestBed.get().down()).getBlock(); + if (blockBelow == CopperBlock) { + Debug.logMessage("Blacklisting bed in trial chambers."); + mod.getBlockTracker().requestBlockUnreachable(nearestBed.get(), 0); + } + } + // Failure + blacklisting is encapsulated within THIS task) + return new MineAndCollectTask(new ItemTarget(ItemHelper.BED), BEDS, MiningRequirement.HAND); } return super.onResourceTick(mod); } diff --git a/src/main/java/adris/altoclef/tasks/resources/CollectBlazeRodsTask.java b/src/main/java/adris/altoclef/tasks/resources/CollectBlazeRodsTask.java index e6ede0137..ecaf99f8d 100644 --- a/src/main/java/adris/altoclef/tasks/resources/CollectBlazeRodsTask.java +++ b/src/main/java/adris/altoclef/tasks/resources/CollectBlazeRodsTask.java @@ -22,6 +22,7 @@ import net.minecraft.world.RaycastContext; import java.util.Optional; +import java.util.function.Predicate; public class CollectBlazeRodsTask extends ResourceTask { @@ -61,23 +62,19 @@ protected Task onResourceTick(AltoClef mod) { setDebugState("Going to nether"); return new DefaultGoToDimensionTask(Dimension.NETHER); } - - Optional toKill = Optional.empty(); // If there is a blaze, kill it. - if (mod.getEntityTracker().entityFound(BlazeEntity.class)) { - toKill = mod.getEntityTracker().getClosestEntity(BlazeEntity.class); - if (toKill.isPresent()) { - if (mod.getPlayer().getHealth() <= TOO_LITTLE_HEALTH_BLAZE && - mod.getEntityTracker().getTrackedEntities(BlazeEntity.class).size() >= TOO_MANY_BLAZES) { - setDebugState("Running away as there are too many blazes nearby."); - return new RunAwayFromHostilesTask(15 * 2, true); - } + Predicate safeToPursue = entity -> !isHoveringAboveLavaOrTooHigh(mod, entity); + Optional toKill; + toKill = mod.getEntityTracker().getClosestEntity(safeToPursue, BlazeEntity.class); + if (toKill.isPresent()) { + if (mod.getPlayer().getHealth() <= TOO_LITTLE_HEALTH_BLAZE && + mod.getEntityTracker().getTrackedEntities(BlazeEntity.class).size() >= TOO_MANY_BLAZES) { + setDebugState("Running away as there are too many blazes nearby."); + return new RunAwayFromHostilesTask(15 * 2, true); } - - if (_foundBlazeSpawner != null && toKill.isPresent()) { + if (_foundBlazeSpawner != null) { Entity kill = toKill.get(); Vec3d nearest = kill.getPos(); - double sqDistanceToPlayer = nearest.squaredDistanceTo(mod.getPlayer().getPos());//_foundBlazeSpawner.getX(), _foundBlazeSpawner.getY(), _foundBlazeSpawner.getZ()); // Ignore if the blaze is too far away. if (sqDistanceToPlayer > SPAWNER_BLAZE_RADIUS * SPAWNER_BLAZE_RADIUS) { @@ -89,14 +86,9 @@ protected Task onResourceTick(AltoClef mod) { } } } - if (toKill.isPresent() && toKill.get().isAlive()) { - if (isHoveringAboveLavaOrTooHigh(mod, toKill.get())) { - toKill = Optional.empty(); - } + if (toKill.isPresent()) { setDebugState("Killing blaze"); - if (toKill.isPresent()) { - return new KillEntitiesTask(toKill.get().getClass()); - } + return new KillEntitiesTask(safeToPursue, toKill.get().getClass()); } @@ -111,28 +103,23 @@ protected Task onResourceTick(AltoClef mod) { if (!_foundBlazeSpawner.isWithinDistance(mod.getPlayer().getPos(), 4)) { setDebugState("Going to blaze spawner"); return new GetToBlockTask(_foundBlazeSpawner.up(), false); - } else { - - // Put out fire that might mess with us. - Optional nearestFire = mod.getBlockTracker().getNearestWithinRange(_foundBlazeSpawner, 5, Blocks.FIRE); - if (nearestFire.isPresent()) { - setDebugState("Clearing fire around spawner to prevent loss of blaze rods."); - return new PutOutFireTask(nearestFire.get()); - } - - setDebugState("Waiting near blaze spawner for blazes to spawn"); - return null; } - } else { - // Search for blaze - for (BlockPos pos : mod.getBlockTracker().getKnownLocations(Blocks.SPAWNER)) { - if (isValidBlazeSpawner(mod, pos)) { - _foundBlazeSpawner = pos; - break; - } + // Put out fire that might mess with us. + Optional nearestFire = mod.getBlockTracker().getNearestWithinRange(_foundBlazeSpawner, 5, Blocks.FIRE); + if (nearestFire.isPresent()) { + setDebugState("Clearing fire around spawner to prevent loss of blaze rods."); + return new PutOutFireTask(nearestFire.get()); + } + setDebugState("Waiting near blaze spawner for blazes to spawn"); + return null; + } + // Search for blaze + if (mod.getBlockTracker().isTracking(Blocks.SPAWNER)) { + Optional spawner = mod.getBlockTracker().getNearestTracking(Blocks.SPAWNER); + if (spawner.isPresent() && isValidBlazeSpawner(mod, spawner.get())) { + _foundBlazeSpawner = spawner.get(); } } - // We need to find our fortress. setDebugState("Searching for fortress/Traveling around fortress"); return _searcher; diff --git a/src/main/java/adris/altoclef/tasks/resources/CollectBucketLiquidTask.java b/src/main/java/adris/altoclef/tasks/resources/CollectBucketLiquidTask.java index b6dfa4b96..46446ed8f 100644 --- a/src/main/java/adris/altoclef/tasks/resources/CollectBucketLiquidTask.java +++ b/src/main/java/adris/altoclef/tasks/resources/CollectBucketLiquidTask.java @@ -24,10 +24,10 @@ import net.minecraft.item.Item; import net.minecraft.item.Items; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3i; import net.minecraft.world.RaycastContext; import java.util.HashSet; +import java.util.Optional; import java.util.function.Predicate; public class CollectBucketLiquidTask extends ResourceTask { @@ -137,39 +137,42 @@ protected Task onResourceTick(AltoClef mod) { }; // Find nearest water and right click it - if (mod.getBlockTracker().anyFound(isSourceLiquid, _toCollect)) { - // We want to MINIMIZE this distance to liquid. - setDebugState("Trying to collect..."); - //Debug.logMessage("TEST: " + RayTraceUtils.fluidHandling); - - return new DoToClosestBlockTask(blockPos -> { - // Clear above if lava because we can't enter. - // but NOT if we're standing right above. - if (WorldHelper.isSolid(mod, blockPos.up())) { - if (!_progressChecker.check(mod)) { - mod.getClientBaritone().getPathingBehavior().cancelEverything(); - mod.getClientBaritone().getPathingBehavior().forceCancel(); - mod.getClientBaritone().getExploreProcess().onLostControl(); - mod.getClientBaritone().getCustomGoalProcess().onLostControl(); - Debug.logMessage("Failed to break, blacklisting."); - mod.getBlockTracker().requestBlockUnreachable(blockPos); - _blacklist.add(blockPos); + if (mod.getBlockTracker().isTracking(_toCollect)) { + Optional nearestSource = mod.getBlockTracker().getNearestTracking(isSourceLiquid, _toCollect); + if (nearestSource.isPresent()) { + Block nearestSourceBlock = mod.getWorld().getBlockState(nearestSource.get()).getBlock(); + // We want to MINIMIZE this distance to liquid. + setDebugState("Trying to collect..."); + //Debug.logMessage("TEST: " + RayTraceUtils.fluidHandling); + return new DoToClosestBlockTask(blockPos -> { + // Clear above if lava because we can't enter. + // but NOT if we're standing right above. + if (WorldHelper.isSolid(mod, blockPos.up())) { + if (!_progressChecker.check(mod)) { + mod.getClientBaritone().getPathingBehavior().cancelEverything(); + mod.getClientBaritone().getPathingBehavior().forceCancel(); + mod.getClientBaritone().getExploreProcess().onLostControl(); + mod.getClientBaritone().getCustomGoalProcess().onLostControl(); + Debug.logMessage("Failed to break, blacklisting."); + mod.getBlockTracker().requestBlockUnreachable(blockPos); + _blacklist.add(blockPos); + } + return new DestroyBlockTask(blockPos.up()); } - return new DestroyBlockTask(blockPos.up()); - } - - // We can reach the block. - if (LookHelper.getReach(blockPos).isPresent()) { - return new InteractWithBlockTask(new ItemTarget(Items.BUCKET, 1), blockPos, _toCollect != Blocks.LAVA, new Vec3i(0, 1, 0)); - } - // Get close enough. - // up because if we go below we'll try to move next to the liquid (for lava, not a good move) - if (this.thisOrChildAreTimedOut() && !wasWandering) { - mod.getBlockTracker().requestBlockUnreachable(blockPos.up()); - wasWandering = true; - } - return new GetCloseToBlockTask(blockPos.up()); - }, isSourceLiquid, _toCollect); + // We can reach the block. + if (LookHelper.getReach(blockPos).isPresent() && + mod.getClientBaritone().getPathingBehavior().isSafeToCancel()) { + return new InteractWithBlockTask(new ItemTarget(Items.BUCKET, 1), blockPos, _toCollect != Blocks.LAVA); + } + // Get close enough. + // up because if we go below we'll try to move next to the liquid (for lava, not a good move) + if (this.thisOrChildAreTimedOut() && !wasWandering) { + mod.getBlockTracker().requestBlockUnreachable(blockPos.up()); + wasWandering = true; + } + return new GetCloseToBlockTask(blockPos.up()); + }, isSourceLiquid, nearestSourceBlock); + } } // Dimension diff --git a/src/main/java/adris/altoclef/tasks/resources/CollectFoodTask.java b/src/main/java/adris/altoclef/tasks/resources/CollectFoodTask.java index 6e639efc4..b6b12ed06 100644 --- a/src/main/java/adris/altoclef/tasks/resources/CollectFoodTask.java +++ b/src/main/java/adris/altoclef/tasks/resources/CollectFoodTask.java @@ -22,6 +22,7 @@ import adris.altoclef.util.time.TimerGame; import net.minecraft.block.*; import net.minecraft.client.MinecraftClient; +import net.minecraft.component.DataComponentTypes; import net.minecraft.entity.Entity; import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; @@ -35,25 +36,20 @@ import net.minecraft.screen.SmokerScreenHandler; import net.minecraft.util.math.BlockPos; -import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.function.Predicate; public class CollectFoodTask extends Task { - // Actually screw fish baritone does NOT play nice underwater. - // Fish kinda suck to harvest so heavily penalize them. - private static final double FISH_PENALTY = 0 * 0.03; - // Represents order of preferred mobs to least preferred private static final CookableFoodTarget[] COOKABLE_FOODS = new CookableFoodTarget[]{ - new CookableFoodTarget("beef", CowEntity.class), new CookableFoodTarget("porkchop", PigEntity.class), - new CookableFoodTargetFish("salmon", SalmonEntity.class), + new CookableFoodTarget("beef", CowEntity.class), new CookableFoodTarget("chicken", ChickenEntity.class), + new CookableFoodTarget("mutton", SheepEntity.class), new CookableFoodTargetFish("cod", CodEntity.class), - new CookableFoodTarget("mutton", SheepEntity.class) + new CookableFoodTargetFish("salmon", SalmonEntity.class) }; private static final Item[] ITEMS_TO_PICK_UP = new Item[]{ @@ -84,14 +80,14 @@ private static double getFoodPotential(ItemStack food) { if (count <= 0) return 0; for (CookableFoodTarget cookable : COOKABLE_FOODS) { if (food.getItem() == cookable.getRaw()) { - assert cookable.getCooked().getFoodComponent() != null; - return count * cookable.getCooked().getFoodComponent().getHunger(); + assert cookable.getCooked().getComponents().get(DataComponentTypes.FOOD) != null; + return count * Objects.requireNonNull(cookable.getCooked().getComponents().get(DataComponentTypes.FOOD)).nutrition(); } } // We're just an ordinary item. - if (food.getItem().isFood()) { - assert food.getItem().getFoodComponent() != null; - return count * food.getItem().getFoodComponent().getHunger(); + if (food.getItem().getComponents().contains(DataComponentTypes.FOOD)) { + assert food.getItem().getComponents().get(DataComponentTypes.FOOD) != null; + return count * Objects.requireNonNull(food.getItem().getComponents().get(DataComponentTypes.FOOD)).nutrition(); } return 0; } @@ -104,7 +100,7 @@ private static double calculateFoodPotential(AltoClef mod) { potentialFood += getFoodPotential(food); } int potentialBread = (int) (mod.getItemStorage().getItemCount(Items.WHEAT) / 3) + mod.getItemStorage().getItemCount(Items.HAY_BLOCK) * 3; - potentialFood += Objects.requireNonNull(Items.BREAD.getFoodComponent()).getHunger() * potentialBread; + potentialFood += Objects.requireNonNull(Items.BREAD.getComponents().get(DataComponentTypes.FOOD)).nutrition() * potentialBread; // Check smelting ScreenHandler screen = mod.getPlayer().currentScreenHandler; if (screen instanceof SmokerScreenHandler) { @@ -154,12 +150,14 @@ protected Task onTick(AltoClef mod) { } } } - List haysPos = mod.getBlockTracker().getKnownLocations(Blocks.HAY_BLOCK); - for (BlockPos HaysPos : haysPos) { - BlockPos haysUpPos = HaysPos.up(); - if (mod.getWorld().getBlockState(haysUpPos).getBlock() == Blocks.CARVED_PUMPKIN) { - Debug.logMessage("Blacklisting pillage hay bales."); - mod.getBlockTracker().requestBlockUnreachable(HaysPos, 0); + if (mod.getBlockTracker().isTracking(Blocks.HAY_BLOCK)) { + Optional hay = mod.getBlockTracker().getNearestTracking(Blocks.HAY_BLOCK); + if (hay.isPresent()) { + BlockPos haysUpPos = hay.get().up(); + if (mod.getWorld().getBlockState(haysUpPos).getBlock() == Blocks.CARVED_PUMPKIN) { + Debug.logMessage("Blacklisting pillage hay bales."); + mod.getBlockTracker().requestBlockUnreachable(hay.get(), 0); + } } } // If we were previously smelting, keep on smelting. @@ -274,33 +272,26 @@ protected Task onTick(AltoClef mod) { } } // Cooked foods - double bestScore = 0; - Entity bestEntity = null; - Item bestRawFood = null; for (CookableFoodTarget cookable : COOKABLE_FOODS) { - if (!mod.getEntityTracker().entityFound(cookable.mobToKill)) continue; - Optional nearest = mod.getEntityTracker().getClosestEntity(mod.getPlayer().getPos(), cookable.mobToKill); - if (nearest.isEmpty()) continue; // ?? This crashed once? - if (nearest.get() instanceof LivingEntity livingEntity) { - // Peta - if (livingEntity.isBaby()) continue; - } - int hungerPerformance = cookable.getCookedUnits(); - double sqDistance = nearest.get().squaredDistanceTo(mod.getPlayer()); - double score = (double) 100 * hungerPerformance / (sqDistance); - if (cookable.isFish()) { - score *= FISH_PENALTY; - } - if (score > bestScore) { - bestScore = score; - bestEntity = nearest.get(); - bestRawFood = cookable.getRaw(); + Predicate notBaby = entity -> entity instanceof LivingEntity livingEntity && !livingEntity.isBaby(); + Optional nearest = mod.getEntityTracker().getClosestEntity(notBaby, cookable.mobToKill); + if (nearest.isPresent()) { + setDebugState("Killing " + nearest.get().getType().getTranslationKey()); + _currentResourceTask = killTaskOrNull(nearest.get(), notBaby, cookable.getRaw()); + return _currentResourceTask; } - } - if (bestEntity != null) { - setDebugState("Killing " + bestEntity.getType().getTranslationKey()); - _currentResourceTask = killTaskOrNull(bestEntity, bestRawFood); - return _currentResourceTask; +// if (nearest.isEmpty()) continue; // ?? This crashed once? +// int hungerPerformance = cookable.getCookedUnits(); +// double sqDistance = nearest.get().squaredDistanceTo(mod.getPlayer()); +// double score = (double) 100 * hungerPerformance / (sqDistance); +// if (cookable.isFish()) { +// score *= FISH_PENALTY; +// } +// if (score > bestScore) { +// bestScore = score; +// bestEntity = nearest.get(); +// bestRawFood = cookable.getRaw(); +// } } // Sweet berries (separate from crops because they should have a lower priority than everything else cause they suck) @@ -380,8 +371,8 @@ private Task pickupBlockTaskOrNull(AltoClef mod, Block blockToCheck, Item itemTo return pickupBlockTaskOrNull(mod, blockToCheck, itemToGrab, toAccept -> true, maxRange); } - private Task killTaskOrNull(Entity entity, Item itemToGrab) { - return new KillAndLootTask(entity.getClass(), new ItemTarget(itemToGrab, 1)); + private Task killTaskOrNull(Entity entity, Predicate entityPredicate, Item itemToGrab) { + return new KillAndLootTask(entity.getClass(), entityPredicate, new ItemTarget(itemToGrab, 1)); } /** @@ -431,8 +422,8 @@ private Item getCooked() { } public int getCookedUnits() { - assert getCooked().getFoodComponent() != null; - return getCooked().getFoodComponent().getHunger(); + assert getCooked().getComponents().get(DataComponentTypes.FOOD) != null; + return Objects.requireNonNull(getCooked().getComponents().get(DataComponentTypes.FOOD)).nutrition(); } public boolean isFish() { diff --git a/src/main/java/adris/altoclef/tasks/resources/CollectIronIngotTask.java b/src/main/java/adris/altoclef/tasks/resources/CollectIronIngotTask.java index cf8cbdd6e..f39b21ece 100644 --- a/src/main/java/adris/altoclef/tasks/resources/CollectIronIngotTask.java +++ b/src/main/java/adris/altoclef/tasks/resources/CollectIronIngotTask.java @@ -31,6 +31,7 @@ protected boolean shouldAvoidPickingUp(AltoClef mod) { @Override protected void onResourceStart(AltoClef mod) { mod.getBehaviour().push(); + mod.getBlockTracker().trackBlock(Blocks.FURNACE, Blocks.BLAST_FURNACE); } @Override @@ -44,7 +45,6 @@ protected Task onResourceTick(AltoClef mod) { if (_count < 5) { return new SmeltInFurnaceTask(new SmeltTarget(new ItemTarget(Items.IRON_INGOT, _count), new ItemTarget(Items.RAW_IRON, _count))); } - mod.getBehaviour().addProtectedItems(Items.COBBLESTONE, Items.STONE, Items.SMOOTH_STONE); Optional furnacePos = mod.getBlockTracker().getNearestTracking(Blocks.FURNACE); furnacePos.ifPresent(blockPos -> mod.getBehaviour().avoidBlockBreaking(blockPos)); if (mod.getItemStorage().getItemCount(Items.IRON_INGOT) >= 5) { @@ -58,6 +58,7 @@ protected Task onResourceTick(AltoClef mod) { @Override protected void onResourceStop(AltoClef mod, Task interruptTask) { mod.getBehaviour().pop(); + mod.getBlockTracker().stopTracking(Blocks.FURNACE, Blocks.BLAST_FURNACE); } @Override diff --git a/src/main/java/adris/altoclef/tasks/resources/CollectMeatTask.java b/src/main/java/adris/altoclef/tasks/resources/CollectMeatTask.java index b8ae63cd1..9cb3ac29b 100644 --- a/src/main/java/adris/altoclef/tasks/resources/CollectMeatTask.java +++ b/src/main/java/adris/altoclef/tasks/resources/CollectMeatTask.java @@ -15,6 +15,7 @@ import adris.altoclef.util.slots.SmokerSlot; import adris.altoclef.util.time.TimerGame; import net.minecraft.client.MinecraftClient; +import net.minecraft.component.DataComponentTypes; import net.minecraft.entity.Entity; import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; @@ -31,6 +32,7 @@ import java.util.Objects; import java.util.Optional; +import java.util.function.Predicate; public class CollectMeatTask extends Task { private static final CookableFoodTarget[] COOKABLE_FOODS = new CookableFoodTarget[]{ @@ -54,8 +56,8 @@ private static double getFoodPotential(ItemStack food) { if (count <= 0) return 0; for (CookableFoodTarget cookable : COOKABLE_FOODS) { if (food.getItem() == cookable.getRaw()) { - assert cookable.getCooked().getFoodComponent() != null; - return count * cookable.getCooked().getFoodComponent().getHunger(); + assert cookable.getCooked().getComponents().get(DataComponentTypes.FOOD) != null; + return count * Objects.requireNonNull(cookable.getCooked().getComponents().get(DataComponentTypes.FOOD)).nutrition(); } } return 0; @@ -153,10 +155,6 @@ protected Task onTick(AltoClef mod) { if (!mod.getEntityTracker().entityFound(cookable.mobToKill)) continue; Optional nearest = mod.getEntityTracker().getClosestEntity(mod.getPlayer().getPos(), cookable.mobToKill); if (nearest.isEmpty()) continue; // ?? This crashed once? - if (nearest.get() instanceof LivingEntity livingEntity) { - // Peta - if (livingEntity.isBaby()) continue; - } int hungerPerformance = cookable.getCookedUnits(); double sqDistance = nearest.get().squaredDistanceTo(mod.getPlayer()); double score = (double) 100 * hungerPerformance / (sqDistance); @@ -168,7 +166,8 @@ protected Task onTick(AltoClef mod) { } if (bestEntity != null) { setDebugState("Killing " + bestEntity.getType().getTranslationKey()); - _currentResourceTask = killTaskOrNull(bestEntity, bestRawFood); + Predicate notBaby = entity -> entity instanceof LivingEntity livingEntity && !livingEntity.isBaby(); + _currentResourceTask = killTaskOrNull(bestEntity, notBaby, bestRawFood); return _currentResourceTask; } } @@ -187,8 +186,8 @@ protected Task onTick(AltoClef mod) { return new TimeoutWanderTask(); } - private Task killTaskOrNull(Entity entity, Item itemToGrab) { - return new KillAndLootTask(entity.getClass(), new ItemTarget(itemToGrab, 1)); + private Task killTaskOrNull(Entity entity, Predicate entityPredicate, Item itemToGrab) { + return new KillAndLootTask(entity.getClass(), entityPredicate, new ItemTarget(itemToGrab, 1)); } private Task pickupTaskOrNull(AltoClef mod, Item itemToGrab, double maxRange) { @@ -256,8 +255,8 @@ private Item getCooked() { } public int getCookedUnits() { - assert getCooked().getFoodComponent() != null; - return getCooked().getFoodComponent().getHunger(); + assert getCooked().getComponents().get(DataComponentTypes.FOOD) != null; + return Objects.requireNonNull(getCooked().getComponents().get(DataComponentTypes.FOOD)).nutrition(); } } } diff --git a/src/main/java/adris/altoclef/tasks/resources/CollectObsidianTask.java b/src/main/java/adris/altoclef/tasks/resources/CollectObsidianTask.java index c1594cd8f..354341c6b 100644 --- a/src/main/java/adris/altoclef/tasks/resources/CollectObsidianTask.java +++ b/src/main/java/adris/altoclef/tasks/resources/CollectObsidianTask.java @@ -145,9 +145,11 @@ protected adris.altoclef.tasksystem.Task onResourceTick(AltoClef mod) { return new MineAndCollectTask(new ItemTarget(Items.OBSIDIAN, _count), new Block[]{Blocks.OBSIDIAN}, MiningRequirement.DIAMOND); } - if (WorldHelper.getCurrentDimension() != Dimension.OVERWORLD) { - setDebugState("We can't place water, so we're wandering."); - return new TimeoutWanderTask(); + if (WorldHelper.getCurrentDimension() == Dimension.NETHER) { + final double AVERAGE_GOLD_PER_OBSIDIAN = 11.475; + int gold_buffer = (int) (AVERAGE_GOLD_PER_OBSIDIAN * _count); + setDebugState("We can't place water, so we're trading for obsidian"); + return new TradeWithPiglinsTask(gold_buffer, Items.OBSIDIAN, _count); } if (_placeObsidianTask == null) { diff --git a/src/main/java/adris/altoclef/tasks/resources/CollectStrippedLogTask.java b/src/main/java/adris/altoclef/tasks/resources/CollectStrippedLogTask.java new file mode 100644 index 000000000..b3a85d8ed --- /dev/null +++ b/src/main/java/adris/altoclef/tasks/resources/CollectStrippedLogTask.java @@ -0,0 +1,95 @@ +package adris.altoclef.tasks.resources; + +import adris.altoclef.AltoClef; +import adris.altoclef.TaskCatalogue; +import adris.altoclef.tasks.InteractWithBlockTask; +import adris.altoclef.tasks.ResourceTask; +import adris.altoclef.tasks.movement.TimeoutWanderTask; +import adris.altoclef.tasksystem.Task; +import adris.altoclef.util.ItemTarget; +import adris.altoclef.util.MiningRequirement; +import adris.altoclef.util.helpers.ItemHelper; +import net.minecraft.item.Item; +import net.minecraft.item.Items; +import net.minecraft.util.math.BlockPos; + +import java.util.Optional; + +public class CollectStrippedLogTask extends ResourceTask { + private static final Item[] _axes = new Item[]{Items.WOODEN_AXE, Items.STONE_AXE, Items.GOLDEN_AXE, Items.IRON_AXE, + Items.DIAMOND_AXE, Items.NETHERITE_AXE}; + private final Item[] _strippedLogs; + private final Item[] _strippableLogs; + private final int _targetCount; + + public CollectStrippedLogTask(Item[] strippedLogs, Item[] strippableLogs, int count) { + super(new ItemTarget(strippedLogs, count)); + _strippedLogs = strippedLogs; + _strippableLogs = strippableLogs; + _targetCount = count; + } + + public CollectStrippedLogTask(int count) { + this(ItemHelper.STRIPPED_LOGS, ItemHelper.STRIPPABLE_LOGS, count); + } + + public CollectStrippedLogTask(Item strippedLogs, Item strippableLogs, int count) { + this(new Item[]{strippedLogs}, new Item[]{strippableLogs}, count); + } + + public CollectStrippedLogTask(Item strippedLog, int count) { + this(strippedLog, ItemHelper.strippedToLogs(strippedLog), count); + } + + @Override + protected boolean shouldAvoidPickingUp(AltoClef mod) { + return false; + } + + @Override + protected void onResourceStart(AltoClef mod) { + mod.getBlockTracker().trackBlock(ItemHelper.itemsToBlocks(_strippedLogs)); + mod.getBlockTracker().trackBlock(ItemHelper.itemsToBlocks(_strippableLogs)); + } + + @Override + protected Task onResourceTick(AltoClef mod) { + if (!mod.getItemStorage().hasItem(_axes)) { + setDebugState("Getting axe for stripping"); + return TaskCatalogue.getItemTask(Items.WOODEN_AXE, 1); + } + if (mod.getItemStorage().getItemCount(_strippedLogs) < _targetCount) { + Optional strippedLogBlockPos = mod.getBlockTracker().getNearestTracking(ItemHelper.itemsToBlocks(_strippedLogs)); + if (strippedLogBlockPos.isPresent()) { + setDebugState("Getting stripped log"); + return new MineAndCollectTask(new ItemTarget(_strippedLogs), ItemHelper.itemsToBlocks(_strippedLogs), MiningRequirement.HAND); + } + } + Optional strippableLogBlockPos = mod.getBlockTracker().getNearestTracking(ItemHelper.itemsToBlocks(_strippableLogs)); + if (strippableLogBlockPos.isPresent()) { + setDebugState("Stripping log"); + return new InteractWithBlockTask(new ItemTarget(_axes), strippableLogBlockPos.get()); + } + setDebugState("Searching log"); + return new TimeoutWanderTask(); + } + + @Override + protected void onResourceStop(AltoClef mod, Task interruptTask) { + mod.getBlockTracker().stopTracking(ItemHelper.itemsToBlocks(_strippedLogs)); + mod.getBlockTracker().stopTracking(ItemHelper.itemsToBlocks(_strippableLogs)); + } + + @Override + protected boolean isEqualResource(ResourceTask other) { + if (other instanceof CollectStrippedLogTask task) { + return task._targetCount == _targetCount; + } + return false; + } + + @Override + protected String toDebugStringName() { + return "Collect Stripped Log"; + } +} diff --git a/src/main/java/adris/altoclef/tasks/resources/CollectWheatSeedsTask.java b/src/main/java/adris/altoclef/tasks/resources/CollectWheatSeedsTask.java index f2e0b843a..c16f1df23 100644 --- a/src/main/java/adris/altoclef/tasks/resources/CollectWheatSeedsTask.java +++ b/src/main/java/adris/altoclef/tasks/resources/CollectWheatSeedsTask.java @@ -34,7 +34,7 @@ protected Task onResourceTick(AltoClef mod) { return new CollectCropTask(Items.AIR, 999, Blocks.WHEAT, Items.WHEAT_SEEDS); } // Otherwise, break grass blocks. - return new MineAndCollectTask(Items.WHEAT_SEEDS, _count, new Block[]{Blocks.GRASS, Blocks.TALL_GRASS}, MiningRequirement.HAND); + return new MineAndCollectTask(Items.WHEAT_SEEDS, _count, new Block[]{Blocks.GRASS_BLOCK, Blocks.TALL_GRASS}, MiningRequirement.HAND); } @Override diff --git a/src/main/java/adris/altoclef/tasks/resources/CraftWithMatchingStrippedLogsTask.java b/src/main/java/adris/altoclef/tasks/resources/CraftWithMatchingStrippedLogsTask.java new file mode 100644 index 000000000..3a1fe8128 --- /dev/null +++ b/src/main/java/adris/altoclef/tasks/resources/CraftWithMatchingStrippedLogsTask.java @@ -0,0 +1,70 @@ +package adris.altoclef.tasks.resources; + +import adris.altoclef.AltoClef; +import adris.altoclef.Debug; +import adris.altoclef.TaskCatalogue; +import adris.altoclef.tasks.ResourceTask; +import adris.altoclef.tasksystem.Task; +import adris.altoclef.util.CraftingRecipe; +import adris.altoclef.util.ItemTarget; +import adris.altoclef.util.helpers.ItemHelper; +import net.minecraft.item.Item; + +import java.util.function.Function; + +public class CraftWithMatchingStrippedLogsTask extends CraftWithMatchingMaterialsTask { + + private final ItemTarget _visualTarget; + private final Function _getTargetItem; + + public CraftWithMatchingStrippedLogsTask(Item[] validTargets, Function getTargetItem, CraftingRecipe recipe, boolean[] sameMask, int count) { + super(new ItemTarget(validTargets, count), recipe, sameMask); + _getTargetItem = getTargetItem; + _visualTarget = new ItemTarget(validTargets, count); + } + + + @Override + protected Task getSpecificSameResourceTask(AltoClef mod, Item[] toGet) { + for (Item strippedLogToGet : toGet) { + Item log = ItemHelper.strippedToLogs(strippedLogToGet); + // Convert logs to stripped + if (mod.getItemStorage().getItemCount(log) >= 1) { + return TaskCatalogue.getItemTask(strippedLogToGet, 1);//new CraftInInventoryTask(new ItemTarget(plankToGet, 1), CraftingRecipe.newShapedRecipe("planks", new ItemTarget[]{new ItemTarget(log, 1), empty, empty, empty}, 4), false, true); + } + } + Debug.logError("CraftWithMatchingStrippedLogs: Should never happen!"); + return null; + } + + @Override + protected Item getSpecificItemCorrespondingToMajorityResource(Item majority) { + for (ItemHelper.WoodItems woodItems : ItemHelper.getWoodItems()) { + if (woodItems.strippedLog == majority) { + return _getTargetItem.apply(woodItems); + } + } + return null; + } + + + @Override + protected boolean isEqualResource(ResourceTask other) { + if (other instanceof CraftWithMatchingStrippedLogsTask task) { + return task._visualTarget.equals(_visualTarget); + } + return false; + } + + @Override + protected String toDebugStringName() { + return "Getting: " + _visualTarget; + } + + + @Override + protected boolean shouldAvoidPickingUp(AltoClef mod) { + return false; + } + +} diff --git a/src/main/java/adris/altoclef/tasks/resources/GetSmithingTemplateTask.java b/src/main/java/adris/altoclef/tasks/resources/GetSmithingTemplateTask.java new file mode 100644 index 000000000..01069759d --- /dev/null +++ b/src/main/java/adris/altoclef/tasks/resources/GetSmithingTemplateTask.java @@ -0,0 +1,91 @@ +package adris.altoclef.tasks.resources; + +import adris.altoclef.AltoClef; +import adris.altoclef.tasks.ResourceTask; +import adris.altoclef.tasks.construction.DestroyBlockTask; +import adris.altoclef.tasks.movement.DefaultGoToDimensionTask; +import adris.altoclef.tasks.movement.SearchChunkForBlockTask; +import adris.altoclef.tasksystem.Task; +import adris.altoclef.util.Dimension; +import adris.altoclef.util.helpers.WorldHelper; +import net.minecraft.block.Blocks; +import net.minecraft.item.Items; +import net.minecraft.util.math.BlockPos; + +import java.util.Optional; + +public class GetSmithingTemplateTask extends ResourceTask { + + private final Task _searcher = new SearchChunkForBlockTask(Blocks.BLACKSTONE); + private final int _count; + private BlockPos _chestloc = null; + + public GetSmithingTemplateTask(int count) { + super(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE, count); + _count = count; + } + + @Override + protected void onResourceStart(AltoClef mod) { + mod.getBlockTracker().trackBlock(Blocks.CHEST); + } + + @Override + protected Task onResourceTick(AltoClef mod) { + // We must go to the nether. + if (WorldHelper.getCurrentDimension() != Dimension.NETHER) { + setDebugState("Going to nether"); + return new DefaultGoToDimensionTask(Dimension.NETHER); + } + //if (_bastionloc != null && !mod.getChunkTracker().isChunkLoaded(_bastionloc)) { + // Debug.logMessage("Bastion at " + _bastionloc + " too far away. Re-searching."); + // _bastionloc = null; + // } + if (_chestloc == null) { + if (mod.getBlockTracker().isTracking(Blocks.CHEST)) { + Optional chest = mod.getBlockTracker().getNearestTracking(Blocks.CHEST); + if (chest.isPresent() && WorldHelper.isInteractableBlock(mod, chest.get())) { + _chestloc = chest.get(); + } + } + } + if (_chestloc != null) { + //if (!_chestloc.isWithinDistance(mod.getPlayer().getPos(), 150)) { + setDebugState("Destroying Chest"); // TODO: Make It check the chest instead of destroying it + if (WorldHelper.isInteractableBlock(mod, _chestloc)) { + return new DestroyBlockTask(_chestloc); + } else { + _chestloc = null; + if (mod.getBlockTracker().isTracking(Blocks.CHEST)) { + Optional chest = mod.getBlockTracker().getNearestTracking(Blocks.CHEST); + if (chest.isPresent() && WorldHelper.isInteractableBlock(mod, chest.get())) { + _chestloc = chest.get(); + } + } + } + //} + } + setDebugState("Searching for/Traveling around bastion"); + return _searcher; + } + + @Override + protected void onResourceStop(AltoClef mod, Task interruptTask) { + mod.getBlockTracker().stopTracking(Blocks.CHEST); + } + + @Override + protected boolean isEqualResource(ResourceTask other) { + return other instanceof GetSmithingTemplateTask; + } + + @Override + protected String toDebugStringName() { + return "Collect " + _count + " smithing templates"; + } + + @Override + protected boolean shouldAvoidPickingUp(AltoClef mod) { + return false; + } +} diff --git a/src/main/java/adris/altoclef/tasks/resources/KillAndLootTask.java b/src/main/java/adris/altoclef/tasks/resources/KillAndLootTask.java index 35c8e5f9b..bbe71f311 100644 --- a/src/main/java/adris/altoclef/tasks/resources/KillAndLootTask.java +++ b/src/main/java/adris/altoclef/tasks/resources/KillAndLootTask.java @@ -12,17 +12,17 @@ public class KillAndLootTask extends ResourceTask { - private final Class _toKill; + private final Class _toKill; private final Task _killTask; - public KillAndLootTask(Class toKill, Predicate shouldKill, ItemTarget... itemTargets) { + public KillAndLootTask(Class toKill, Predicate shouldKill, ItemTarget... itemTargets) { super(itemTargets.clone()); _toKill = toKill; _killTask = new KillEntitiesTask(shouldKill, _toKill); } - public KillAndLootTask(Class toKill, ItemTarget... itemTargets) { + public KillAndLootTask(Class toKill, ItemTarget... itemTargets) { super(itemTargets.clone()); _toKill = toKill; _killTask = new KillEntitiesTask(_toKill); diff --git a/src/main/java/adris/altoclef/tasks/resources/KillEndermanTask.java b/src/main/java/adris/altoclef/tasks/resources/KillEndermanTask.java new file mode 100644 index 000000000..a1766e740 --- /dev/null +++ b/src/main/java/adris/altoclef/tasks/resources/KillEndermanTask.java @@ -0,0 +1,74 @@ +package adris.altoclef.tasks.resources; + +import adris.altoclef.AltoClef; +import adris.altoclef.tasks.ResourceTask; +import adris.altoclef.tasks.entity.KillEntitiesTask; +import adris.altoclef.tasks.entity.KillEntityTask; +import adris.altoclef.tasksystem.Task; +import adris.altoclef.util.ItemTarget; +import adris.altoclef.util.time.TimerGame; +import net.minecraft.entity.Entity; +import net.minecraft.entity.mob.EndermanEntity; +import net.minecraft.item.Items; + +import java.util.Optional; + +public class KillEndermanTask extends ResourceTask { + + private final int _count; + + private final TimerGame _lookDelay = new TimerGame(0.2); + + public KillEndermanTask(int count) { + super(new ItemTarget(Items.ENDER_PEARL, count)); + _count = count; + } + + @Override + protected boolean shouldAvoidPickingUp(AltoClef mod) { + return false; + } + + @Override + protected void onResourceStart(AltoClef mod) { + + } + + @Override + protected Task onResourceTick(AltoClef mod) { + // Dimension + if (!mod.getEntityTracker().entityFound(EndermanEntity.class)) { + return getToCorrectDimensionTask(mod); + } + + // Kill the angry one + Optional enderman = mod.getEntityTracker().getClosestEntity(EndermanEntity.class); + if (enderman.isPresent()) { + EndermanEntity endermanEntity = (EndermanEntity) enderman.get(); + final int TOO_FAR_AWAY = 256; + if (endermanEntity.isAngry() && endermanEntity.getPos().isInRange(mod.getPlayer().getPos(), TOO_FAR_AWAY)) { + return new KillEntityTask(endermanEntity); + } + } + // Attack the closest one + return new KillEntitiesTask(EndermanEntity.class); + } + + @Override + protected void onResourceStop(AltoClef mod, Task interruptTask) { + + } + + @Override + protected boolean isEqualResource(ResourceTask other) { + if (other instanceof KillEndermanTask task) { + return task._count == _count; + } + return false; + } + + @Override + protected String toDebugStringName() { + return "Hunting enderman for " + _count + " pearls."; + } +} \ No newline at end of file diff --git a/src/main/java/adris/altoclef/tasks/resources/MineAndCollectTask.java b/src/main/java/adris/altoclef/tasks/resources/MineAndCollectTask.java index a68f6662e..e25a3f6a4 100644 --- a/src/main/java/adris/altoclef/tasks/resources/MineAndCollectTask.java +++ b/src/main/java/adris/altoclef/tasks/resources/MineAndCollectTask.java @@ -129,14 +129,13 @@ private void makeSureToolIsEquipped(AltoClef mod) { ItemStack cursorStack = StorageHelper.getItemStackInCursorSlot(); if (cursorStack != null && !cursorStack.isEmpty()) { // We have something in our cursor stack - Item item = cursorStack.getItem(); - if (item.isSuitableFor(mod.getWorld().getBlockState(_subtask.miningPos()))) { + if (cursorStack.isSuitableFor(mod.getWorld().getBlockState(_subtask.miningPos()))) { // Our cursor stack would help us mine our current block Item currentlyEquipped = StorageHelper.getItemStackInSlot(PlayerSlot.getEquipSlot()).getItem(); - if (item instanceof MiningToolItem) { + if (cursorStack.getItem() instanceof MiningToolItem) { if (currentlyEquipped instanceof MiningToolItem currentPick) { - MiningToolItem swapPick = (MiningToolItem) item; - if (swapPick.getMaterial().getMiningLevel() > currentPick.getMaterial().getMiningLevel()) { + MiningToolItem swapPick = (MiningToolItem) cursorStack.getItem(); + if (swapPick.getMaterial().getMiningSpeedMultiplier() > currentPick.getMaterial().getMiningSpeedMultiplier()) { // We can equip a better pickaxe. mod.getSlotHandler().forceEquipSlot(CursorSlot.SLOT); } diff --git a/src/main/java/adris/altoclef/tasks/resources/wood/CollectHangingSignTask.java b/src/main/java/adris/altoclef/tasks/resources/wood/CollectHangingSignTask.java new file mode 100644 index 000000000..bf4937506 --- /dev/null +++ b/src/main/java/adris/altoclef/tasks/resources/wood/CollectHangingSignTask.java @@ -0,0 +1,31 @@ +package adris.altoclef.tasks.resources.wood; + +import adris.altoclef.TaskCatalogue; +import adris.altoclef.tasks.resources.CraftWithMatchingStrippedLogsTask; +import adris.altoclef.util.CraftingRecipe; +import adris.altoclef.util.ItemTarget; +import adris.altoclef.util.helpers.ItemHelper; +import net.minecraft.item.Item; + +public class CollectHangingSignTask extends CraftWithMatchingStrippedLogsTask { + + public CollectHangingSignTask(Item[] targets, ItemTarget strippedLogs, int count) { + // Bottom 6 are stripped logs, must be the same. + super(targets, woodItems -> woodItems.hangingSign, createRecipe(strippedLogs), new boolean[]{false, false, false, true, true, true, true, true, true}, count); + } + + public CollectHangingSignTask(Item target, String strippedLogCatalogueName, int count) { + this(new Item[]{target}, new ItemTarget(strippedLogCatalogueName, 1), count); + } + + public CollectHangingSignTask(int count) { + this(ItemHelper.WOOD_HANGING_SIGN, TaskCatalogue.getItemTarget("stripped_logs", 1), count); + } + + + private static CraftingRecipe createRecipe(ItemTarget strippedLogs) { + ItemTarget s = strippedLogs; + ItemTarget chain = TaskCatalogue.getItemTarget("chain", 1); + return CraftingRecipe.newShapedRecipe(new ItemTarget[]{chain, null, chain, s, s, s, s, s, s}, 6); + } +} diff --git a/src/main/java/adris/altoclef/tasks/speedrun/BeatMinecraft2Task.java b/src/main/java/adris/altoclef/tasks/speedrun/BeatMinecraft2Task.java index b1b31b330..13d1679cc 100644 --- a/src/main/java/adris/altoclef/tasks/speedrun/BeatMinecraft2Task.java +++ b/src/main/java/adris/altoclef/tasks/speedrun/BeatMinecraft2Task.java @@ -37,8 +37,7 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtElement; +import net.minecraft.registry.tag.EnchantmentTags; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3i; @@ -84,12 +83,8 @@ public class BeatMinecraft2Task extends Task { private static final double END_PORTAL_BED_SPAWN_RANGE = 8; // We don't want curse of binding private static final Predicate _noCurseOfBinding = stack -> { - boolean hasBinding = false; - for (NbtElement elm : stack.getEnchantments()) { - NbtCompound comp = (NbtCompound) elm; - if (comp.getString("id").equals("minecraft:binding_curse")) { - return false; - } + if (stack.getEnchantments().getEnchantments().contains(EnchantmentTags.CURSE)) { + return false; } return true; }; diff --git a/src/main/java/adris/altoclef/tasks/speedrun/DragonBreathTracker.java b/src/main/java/adris/altoclef/tasks/speedrun/DragonBreathTracker.java index cc8af2fdd..67fce56ab 100644 --- a/src/main/java/adris/altoclef/tasks/speedrun/DragonBreathTracker.java +++ b/src/main/java/adris/altoclef/tasks/speedrun/DragonBreathTracker.java @@ -8,17 +8,20 @@ import baritone.api.pathing.goals.Goal; import baritone.api.pathing.goals.GoalRunAway; import net.minecraft.entity.AreaEffectCloudEntity; +import net.minecraft.entity.Entity; import net.minecraft.util.math.BlockPos; import java.util.HashSet; +import java.util.Optional; public class DragonBreathTracker { private final HashSet _breathBlocks = new HashSet<>(); public void updateBreath(AltoClef mod) { _breathBlocks.clear(); - for (AreaEffectCloudEntity cloud : mod.getEntityTracker().getTrackedEntities(AreaEffectCloudEntity.class)) { - for (BlockPos bad : WorldHelper.getBlocksTouchingBox(mod, cloud.getBoundingBox())) { + Optional cloud = mod.getEntityTracker().getClosestEntity(AreaEffectCloudEntity.class); + if (cloud.isPresent()) { + for (BlockPos bad : WorldHelper.getBlocksTouchingBox(mod, cloud.get().getBoundingBox())) { _breathBlocks.add(bad); } } diff --git a/src/main/java/adris/altoclef/tasks/speedrun/KillEnderDragonTask.java b/src/main/java/adris/altoclef/tasks/speedrun/KillEnderDragonTask.java index 0f4c6459d..5081eb68a 100644 --- a/src/main/java/adris/altoclef/tasks/speedrun/KillEnderDragonTask.java +++ b/src/main/java/adris/altoclef/tasks/speedrun/KillEnderDragonTask.java @@ -35,10 +35,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; +import java.util.*; /** * Here we go @@ -269,93 +266,92 @@ protected Task onTick(AltoClef mod) { setDebugState("No dragon found."); return null; } - List dragons = mod.getEntityTracker().getTrackedEntities(EnderDragonEntity.class); - if (!dragons.isEmpty()) { - for (EnderDragonEntity dragon : dragons) { - Phase dragonPhase = dragon.getPhaseManager().getCurrent(); - //Debug.logInternal("PHASE: " + dragonPhase); - boolean perchingOrGettingReady = dragonPhase.getType() == PhaseType.LANDING || dragonPhase.isSittingOrHovering(); - switch (_mode) { - case RAILING -> { - if (!perchingOrGettingReady) { - Debug.logMessage("Dragon no longer perching."); - mod.getClientBaritone().getCustomGoalProcess().onLostControl(); - _mode = Mode.WAITING_FOR_PERCH; - break; - } - //DamageSource.DRAGON_BREATH - Entity head = dragon.head; - // Go for the head - if (head.isInRange(mod.getPlayer(), 7.5) && dragon.ticksSinceDeath <= 1) { - // Equip weapon - AbstractKillEntityTask.equipWeapon(mod); - // Look torwards da dragon - Vec3d targetLookPos = head.getPos().add(0, 3, 0); - Rotation targetRotation = RotationUtils.calcRotationFromVec3d(mod.getClientBaritone().getPlayerContext().playerHead(), targetLookPos, mod.getClientBaritone().getPlayerContext().playerRotations()); - mod.getClientBaritone().getLookBehavior().updateTarget(targetRotation, true); - // Also look towards da dragon - MinecraftClient.getInstance().options.getAutoJump().setValue(false); - mod.getClientBaritone().getInputOverrideHandler().setInputForceState(Input.MOVE_FORWARD, true); - hit(mod); - } else { - stopHitting(mod); - } - if (!mod.getClientBaritone().getCustomGoalProcess().isActive()) { - // Set goal to closest block within the pillar that's by the head. - if (_exitPortalTop != null) { - int bottomYDelta = -3; - BlockPos closest = null; - double closestDist = Double.POSITIVE_INFINITY; - for (int dx = -2; dx <= 2; ++dx) { - for (int dz = -2; dz <= 2; ++dz) { - // We have sort of a rounded circle here. - if (Math.abs(dx) == 2 && Math.abs(dz) == 2) continue; - BlockPos toCheck = _exitPortalTop.add(dx, bottomYDelta, dz); - double distSq = toCheck.getSquaredDistance(head.getPos()); - if (distSq < closestDist) { - closest = toCheck; - closestDist = distSq; - } + Optional dragon = mod.getEntityTracker().getClosestEntity(EnderDragonEntity.class); + if (dragon.isPresent()) { + EnderDragonEntity dragonEntity = (EnderDragonEntity) dragon.get(); + Phase dragonPhase = dragonEntity.getPhaseManager().getCurrent(); + //Debug.logInternal("PHASE: " + dragonPhase); + boolean perchingOrGettingReady = dragonPhase.getType() == PhaseType.LANDING || dragonPhase.isSittingOrHovering(); + switch (_mode) { + case RAILING -> { + if (!perchingOrGettingReady) { + Debug.logMessage("Dragon no longer perching."); + mod.getClientBaritone().getCustomGoalProcess().onLostControl(); + _mode = Mode.WAITING_FOR_PERCH; + break; + } + //DamageSource.DRAGON_BREATH + Entity head = dragonEntity.head; + // Go for the head + if (head.isInRange(mod.getPlayer(), 7.5) && dragonEntity.ticksSinceDeath <= 1) { + // Equip weapon + AbstractKillEntityTask.equipWeapon(mod); + // Look torwards da dragon + Vec3d targetLookPos = head.getPos().add(0, 3, 0); + Rotation targetRotation = RotationUtils.calcRotationFromVec3d(mod.getClientBaritone().getPlayerContext().playerHead(), targetLookPos, mod.getClientBaritone().getPlayerContext().playerRotations()); + mod.getClientBaritone().getLookBehavior().updateTarget(targetRotation, true); + // Also look towards da dragon + MinecraftClient.getInstance().options.getAutoJump().setValue(false); + mod.getClientBaritone().getInputOverrideHandler().setInputForceState(Input.MOVE_FORWARD, true); + hit(mod); + } else { + stopHitting(mod); + } + if (!mod.getClientBaritone().getCustomGoalProcess().isActive()) { + // Set goal to closest block within the pillar that's by the head. + if (_exitPortalTop != null) { + int bottomYDelta = -3; + BlockPos closest = null; + double closestDist = Double.POSITIVE_INFINITY; + for (int dx = -2; dx <= 2; ++dx) { + for (int dz = -2; dz <= 2; ++dz) { + // We have sort of a rounded circle here. + if (Math.abs(dx) == 2 && Math.abs(dz) == 2) continue; + BlockPos toCheck = _exitPortalTop.add(dx, bottomYDelta, dz); + double distSq = toCheck.getSquaredDistance(head.getPos()); + if (distSq < closestDist) { + closest = toCheck; + closestDist = distSq; } } - if (closest != null) { - mod.getClientBaritone().getCustomGoalProcess().setGoalAndPath( - new GoalGetToBlock(closest) - ); - } + } + if (closest != null) { + mod.getClientBaritone().getCustomGoalProcess().setGoalAndPath( + new GoalGetToBlock(closest) + ); } } - setDebugState("Railing on dragon"); } - case WAITING_FOR_PERCH -> { - stopHitting(mod); - if (perchingOrGettingReady) { - // We're perching!! - mod.getClientBaritone().getCustomGoalProcess().onLostControl(); - Debug.logMessage("Dragon perching detected. Dabar duosiu į snuki."); - _mode = Mode.RAILING; - break; - } - // Run around aimlessly, dodging dragon fire - if (_randomWanderPos != null && WorldHelper.inRangeXZ(mod.getPlayer(), _randomWanderPos, 2)) { - _randomWanderPos = null; - } - if (_randomWanderPos != null && _randomWanderChangeTimeout.elapsed()) { - _randomWanderPos = null; - Debug.logMessage("Reset wander pos after timeout, oof"); - } - if (_randomWanderPos == null) { - _randomWanderPos = getRandomWanderPos(mod); - _randomWanderChangeTimeout.reset(); - mod.getClientBaritone().getCustomGoalProcess().onLostControl(); - } - if (!mod.getClientBaritone().getCustomGoalProcess().isActive()) { - mod.getClientBaritone().getCustomGoalProcess().setGoalAndPath( - new GoalGetToBlock(_randomWanderPos) - ); - } - setDebugState("Waiting for perch"); + setDebugState("Railing on dragon"); + } + case WAITING_FOR_PERCH -> { + stopHitting(mod); + if (perchingOrGettingReady) { + // We're perching!! + mod.getClientBaritone().getCustomGoalProcess().onLostControl(); + Debug.logMessage("Dragon perching detected. Dabar duosiu į snuki."); + _mode = Mode.RAILING; + break; + } + // Run around aimlessly, dodging dragon fire + if (_randomWanderPos != null && WorldHelper.inRangeXZ(mod.getPlayer(), _randomWanderPos, 2)) { + _randomWanderPos = null; + } + if (_randomWanderPos != null && _randomWanderChangeTimeout.elapsed()) { + _randomWanderPos = null; + Debug.logMessage("Reset wander pos after timeout, oof"); + } + if (_randomWanderPos == null) { + _randomWanderPos = getRandomWanderPos(mod); + _randomWanderChangeTimeout.reset(); + mod.getClientBaritone().getCustomGoalProcess().onLostControl(); + } + if (!mod.getClientBaritone().getCustomGoalProcess().isActive()) { + mod.getClientBaritone().getCustomGoalProcess().setGoalAndPath( + new GoalGetToBlock(_randomWanderPos) + ); } + setDebugState("Waiting for perch"); } } } diff --git a/src/main/java/adris/altoclef/tasks/speedrun/KillEnderDragonWithBedsTask.java b/src/main/java/adris/altoclef/tasks/speedrun/KillEnderDragonWithBedsTask.java index 9e129509b..694f5c13c 100644 --- a/src/main/java/adris/altoclef/tasks/speedrun/KillEnderDragonWithBedsTask.java +++ b/src/main/java/adris/altoclef/tasks/speedrun/KillEnderDragonWithBedsTask.java @@ -11,6 +11,7 @@ import adris.altoclef.util.helpers.WorldHelper; import baritone.api.utils.input.Input; import net.minecraft.block.Blocks; +import net.minecraft.entity.Entity; import net.minecraft.entity.boss.dragon.EnderDragonEntity; import net.minecraft.entity.boss.dragon.phase.Phase; import net.minecraft.entity.boss.dragon.phase.PhaseType; @@ -18,7 +19,7 @@ import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; -import java.util.List; +import java.util.Optional; public class KillEnderDragonWithBedsTask extends Task { private final Task _whenNotPerchingTask; @@ -26,6 +27,9 @@ public class KillEnderDragonWithBedsTask extends Task { private BlockPos _endPortalTop; private Task _positionTask; + private static boolean isDragonDead; + private static boolean isDragonPresent; + public KillEnderDragonWithBedsTask(IDragonWaiter notPerchingOverride) { _whenNotPerchingTask = (Task) notPerchingOverride; } @@ -39,7 +43,8 @@ private static BlockPos locateExitPortalTop(AltoClef mod) { @Override protected void onStart(AltoClef mod) { - + isDragonDead = false; + isDragonPresent = false; } @Override @@ -57,6 +62,14 @@ Get in position (XZ) Else: // Perform "Default Wander" mode and avoid dragon breath. */ + Optional dragon = mod.getEntityTracker().getClosestEntity(EnderDragonEntity.class); + if (dragon.isEmpty() && !isDragonPresent) { + setDebugState("Waiting for dragon to spawn."); + return null; + } + if (!isDragonPresent) { + isDragonPresent = true; + } if (_endPortalTop == null) { _endPortalTop = locateExitPortalTop(mod); if (_endPortalTop != null) { @@ -69,87 +82,101 @@ Get in position (XZ) return new GetToXZTask(0, 0); } + if (isDragonDead) { + setDebugState("Waiting for overworld portal to spawn."); + if (mod.getPlayer().getPitch() != -90) { + mod.getPlayer().setPitch(-90); + } + return null; + } + if (!mod.getEntityTracker().entityFound(EnderDragonEntity.class)) { setDebugState("No dragon found."); - return new GetToXZTask(0, 0); + + if (!WorldHelper.inRangeXZ(mod.getPlayer(), _endPortalTop, 0.25)) { + setDebugState("Going to end portal top at " + _endPortalTop.toString() + "."); + return new GetToXZTask(_endPortalTop.getX(), _endPortalTop.getZ()); + } + isDragonDead = true; } - List dragons = mod.getEntityTracker().getTrackedEntities(EnderDragonEntity.class); - if (!dragons.isEmpty()) { - for (EnderDragonEntity dragon : dragons) { - Phase dragonPhase = dragon.getPhaseManager().getCurrent(); - boolean perching = dragonPhase.getType() == PhaseType.LANDING || dragonPhase.isSittingOrHovering(); - if (dragon.getY() < _endPortalTop.getY() + 2) { - // Dragon is already perched. - perching = false; + if (dragon.isPresent()) { + EnderDragonEntity dragonEntity = (EnderDragonEntity) dragon.get(); + Phase dragonPhase = dragonEntity.getPhaseManager().getCurrent(); + + boolean perching = dragonPhase.getType() == PhaseType.LANDING || dragonPhase.isSittingOrHovering() || dragonPhase.getType() == PhaseType.LANDING_APPROACH; + if (dragonEntity.getY() < _endPortalTop.getY() + 2) { + // Dragon is already perched. + perching = false; + } + ((IDragonWaiter) _whenNotPerchingTask).setPerchState(perching); + // When the dragon is not perching... + if (_whenNotPerchingTask.isActive() && !_whenNotPerchingTask.isFinished(mod)) { + setDebugState("Dragon not perching, performing special behavior..."); + return _whenNotPerchingTask; + } + if (perching) { + mod.getFoodChain().shouldStop(true); + BlockPos targetStandPosition = _endPortalTop.add(-1, -1, 0); + BlockPos playerPosition = mod.getPlayer().getBlockPos(); + // If we're not positioned (above is OK), go there and make sure we're at the right height. + if (_positionTask != null && _positionTask.isActive() && !_positionTask.isFinished(mod)) { + setDebugState("Going to position for bed cycle..."); + return _positionTask; } - ((IDragonWaiter) _whenNotPerchingTask).setPerchState(perching); - // When the dragon is not perching... - if (_whenNotPerchingTask.isActive() && !_whenNotPerchingTask.isFinished(mod)) { - setDebugState("Dragon not perching, performing special behavior..."); - return _whenNotPerchingTask; + if ((!WorldHelper.inRangeXZ(WorldHelper.toVec3d(targetStandPosition), mod.getPlayer().getPos(), 0.50)) +// && mod.getPlayer().getVelocity().getX() == 0 && mod.getPlayer().getVelocity().getY() == 0 && mod.getPlayer().getVelocity().getZ() == 0 + ) { + _positionTask = new GetToBlockTask(targetStandPosition); + Debug.logMessage("Going to position for bed cycle..."); + setDebugState("Moving to target stand position"); + return _positionTask; } - if (perching) { - mod.getFoodChain().shouldStop(true); - BlockPos targetStandPosition = _endPortalTop.add(-1, -1, 0); - BlockPos playerPosition = mod.getPlayer().getBlockPos(); - // If we're not positioned (above is OK), go there and make sure we're at the right height. - if (_positionTask != null && _positionTask.isActive() && !_positionTask.isFinished(mod)) { - setDebugState("Going to position for bed cycle..."); - return _positionTask; - } - if ((!WorldHelper.inRangeXZ(WorldHelper.toVec3d(targetStandPosition), mod.getPlayer().getPos(), 1) - || playerPosition.getY() < targetStandPosition.getY()) && mod.getPlayer().getVelocity().getX() == 0 && - mod.getPlayer().getVelocity().getY() == 0 && mod.getPlayer().getVelocity().getZ() == 0) { - _positionTask = new GetToBlockTask(targetStandPosition); - setDebugState("Moving to target stand position"); - return _positionTask; - } - // We're positioned. Perform bed strats! - BlockPos bedTargetPosition = _endPortalTop.up(); - boolean bedPlaced = mod.getBlockTracker().blockIsValid(bedTargetPosition, ItemHelper.itemsToBlocks(ItemHelper.BED)); - if (!bedPlaced) { - setDebugState("Placing bed"); - // If no bed, place bed. - // Fire messes up our "reach" so we just assume we're good when we're above a height. - boolean canPlace = LookHelper.getCameraPos(mod).y > bedTargetPosition.getY(); - //Optional placeReach = LookHelper.getReach(bedTargetPosition.down(), Direction.UP); - if (canPlace) { - // Look at and place! - if (mod.getSlotHandler().forceEquipItem(ItemHelper.BED, true)) { - LookHelper.lookAt(mod, bedTargetPosition.down(), Direction.UP); - //mod.getClientBaritone().getLookBehavior().updateTarget(placeReach.get(), true); - //if (mod.getClientBaritone().getPlayerContext().isLookingAt(bedTargetPosition.down())) { - // There could be fire so eh place right away - mod.getInputControls().tryPress(Input.CLICK_RIGHT); - //} - } - } else { - if (mod.getPlayer().isOnGround()) { - // Jump - mod.getInputControls().tryPress(Input.JUMP); - } + // We're positioned. Perform bed strats! + BlockPos bedTargetPosition = _endPortalTop.up(); + boolean bedPlaced = mod.getBlockTracker().blockIsValid(bedTargetPosition, ItemHelper.itemsToBlocks(ItemHelper.BED)); + if (!bedPlaced) { + setDebugState("Placing bed"); + // If no bed, place bed. + // Fire messes up our "reach" so we just assume we're good when we're above a height. + boolean canPlace = LookHelper.getCameraPos(mod).y > bedTargetPosition.getY(); + //Optional placeReach = LookHelper.getReach(bedTargetPosition.down(), Direction.UP); + if (canPlace) { + // Look at and place! + if (mod.getSlotHandler().forceEquipItem(ItemHelper.BED, true)) { + LookHelper.lookAt(mod, bedTargetPosition.down(), Direction.UP, true); + //mod.getClientBaritone().getLookBehavior().updateTarget(placeReach.get(), true); + //if (mod.getClientBaritone().getPlayerContext().isLookingAt(bedTargetPosition.down())) { + // There could be fire so eh place right away + mod.getInputControls().tryPress(Input.CLICK_RIGHT); + //} } } else { - setDebugState("Wait for it..."); - // Make sure we're standing on the ground so we don't blow ourselves up lmfao - if (!mod.getPlayer().isOnGround()) { - // Wait to fall - return null; + if (mod.getPlayer().isOnGround()) { + // Jump + mod.getInputControls().tryPress(Input.JUMP); } - // Wait for dragon head to be close enough to the bed's head... - BlockPos bedfoot = WorldHelper.getBedFoot(mod, bedTargetPosition); - assert bedfoot != null; - Vec3d headPos = dragon.head.getBoundingBox().getCenter(); // dragon.head.getPos(); - double dist = headPos.distanceTo(WorldHelper.toVec3d(bedfoot)); - Debug.logMessage("Dist: " + dist); - if (dist < BeatMinecraft2Task.getConfig().dragonHeadCloseEnoughClickBedRange) { - // Interact with the bed. - return new InteractWithBlockTask(bedTargetPosition); - } - // Wait for it... } - return null; + } else { + setDebugState("Wait for it..."); + // Make sure we're standing on the ground so we don't blow ourselves up lmfao + if (!mod.getPlayer().isOnGround()) { + // Wait to fall + return null; + } + // Wait for dragon head to be close enough to the bed's head... + BlockPos bedfoot = WorldHelper.getBedFoot(mod, bedTargetPosition); + assert bedfoot != null; + Vec3d headPos = dragonEntity.head.getBoundingBox().getCenter(); // dragon.head.getPos(); + double dist = headPos.distanceTo(WorldHelper.toVec3d(bedfoot)); + Debug.logMessage("Dist: " + dist + " Health: " + dragonEntity.getHealth()); + + if (dist < BeatMinecraft2Task.getConfig().dragonHeadCloseEnoughClickBedRange) { + // Interact with the bed. + return new InteractWithBlockTask(bedTargetPosition); + } + // Wait for it... } + return null; } } mod.getFoodChain().shouldStop(false); @@ -176,4 +203,4 @@ protected boolean isEqual(Task other) { protected String toDebugString() { return "Bedding the Ender Dragon"; } -} +} \ No newline at end of file diff --git a/src/main/java/adris/altoclef/tasks/speedrun/MarvionBeatMinecraftTask.java b/src/main/java/adris/altoclef/tasks/speedrun/MarvionBeatMinecraftTask.java index aebf6cf43..3e2704cde 100644 --- a/src/main/java/adris/altoclef/tasks/speedrun/MarvionBeatMinecraftTask.java +++ b/src/main/java/adris/altoclef/tasks/speedrun/MarvionBeatMinecraftTask.java @@ -6,9 +6,7 @@ import adris.altoclef.tasks.DoToClosestBlockTask; import adris.altoclef.tasks.InteractWithBlockTask; import adris.altoclef.tasks.construction.DestroyBlockTask; -import adris.altoclef.tasks.container.DoStuffInContainerTask; -import adris.altoclef.tasks.container.LootContainerTask; -import adris.altoclef.tasks.container.SmeltInSmokerTask; +import adris.altoclef.tasks.container.*; import adris.altoclef.tasks.misc.EquipArmorTask; import adris.altoclef.tasks.misc.LootDesertTempleTask; import adris.altoclef.tasks.misc.PlaceBedAndSetSpawnTask; @@ -16,6 +14,8 @@ import adris.altoclef.tasks.movement.*; import adris.altoclef.tasks.resources.*; import adris.altoclef.tasksystem.Task; +import adris.altoclef.trackers.BlockTracker; +import adris.altoclef.trackers.EntityTracker; import adris.altoclef.util.Dimension; import adris.altoclef.util.ItemTarget; import adris.altoclef.util.MiningRequirement; @@ -27,27 +27,24 @@ import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.EndPortalFrameBlock; -import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.CreditsScreen; import net.minecraft.entity.Entity; import net.minecraft.entity.ItemEntity; -import net.minecraft.entity.boss.dragon.EnderDragonEntity; -import net.minecraft.entity.mob.*; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.mob.EndermanEntity; +import net.minecraft.entity.mob.PillagerEntity; +import net.minecraft.entity.mob.SilverfishEntity; +import net.minecraft.entity.mob.WitchEntity; import net.minecraft.entity.passive.PigEntity; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtElement; +import net.minecraft.item.*; +import net.minecraft.registry.tag.EnchantmentTags; import net.minecraft.screen.slot.SlotActionType; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3i; import net.minecraft.world.biome.BiomeKeys; import org.apache.commons.lang3.ArrayUtils; import java.util.*; import java.util.function.Predicate; -import java.util.stream.Stream; import static net.minecraft.client.MinecraftClient.getInstance; @@ -65,51 +62,64 @@ public class MarvionBeatMinecraftTask extends Task { Blocks.STONE_PRESSURE_PLATE // For desert temples }; private static final Item[] COLLECT_EYE_ARMOR = new Item[]{ - Items.DIAMOND_HELMET, Items.DIAMOND_CHESTPLATE, Items.DIAMOND_LEGGINGS, - Items.GOLDEN_BOOTS + Items.GOLDEN_HELMET, Items.DIAMOND_CHESTPLATE, Items.DIAMOND_LEGGINGS, + Items.DIAMOND_BOOTS }; private static final ItemTarget[] COLLECT_STONE_GEAR = combine( toItemTargets(Items.STONE_SWORD, 1), - toItemTargets(Items.STONE_PICKAXE, 2)); + toItemTargets(Items.STONE_PICKAXE, 2), + toItemTargets(Items.STONE_HOE), + toItemTargets(Items.COAL, 13) + ); private static final Item COLLECT_SHIELD = Items.SHIELD; private static final Item[] COLLECT_IRON_ARMOR = ItemHelper.IRON_ARMORS; private static final Item[] COLLECT_EYE_ARMOR_END = ItemHelper.DIAMOND_ARMORS; private static final ItemTarget[] COLLECT_IRON_GEAR = combine( toItemTargets(Items.IRON_SWORD, 2), - toItemTargets(Items.IRON_PICKAXE, 3) + toItemTargets(Items.STONE_SHOVEL), + toItemTargets(Items.STONE_AXE), + toItemTargets(Items.DIAMOND_PICKAXE) ); private static final ItemTarget[] COLLECT_EYE_GEAR = combine( toItemTargets(Items.DIAMOND_SWORD), toItemTargets(Items.DIAMOND_PICKAXE, 3), + toItemTargets(Items.BUCKET, 2), toItemTargets(Items.CRAFTING_TABLE) ); private static final ItemTarget[] COLLECT_IRON_GEAR_MIN = combine( - toItemTargets(Items.IRON_SWORD, 2) + toItemTargets(Items.IRON_SWORD), + toItemTargets(Items.DIAMOND_PICKAXE) ); private static final ItemTarget[] COLLECT_EYE_GEAR_MIN = combine( toItemTargets(Items.DIAMOND_SWORD), - toItemTargets(Items.DIAMOND_PICKAXE, 3) + toItemTargets(Items.DIAMOND_PICKAXE) ); private static final ItemTarget[] IRON_GEAR = combine( toItemTargets(Items.IRON_SWORD, 2), - toItemTargets(Items.IRON_PICKAXE, 3) + toItemTargets(Items.IRON_PICKAXE, 2), + toItemTargets(Items.STONE_SHOVEL), + toItemTargets(Items.STONE_AXE), + toItemTargets(Items.SHIELD) ); private static final ItemTarget[] IRON_GEAR_MIN = combine( - toItemTargets(Items.IRON_SWORD, 2) + toItemTargets(Items.IRON_SWORD), + toItemTargets(Items.SHIELD) ); private static final int END_PORTAL_FRAME_COUNT = 12; private static final double END_PORTAL_BED_SPAWN_RANGE = 8; + + private static final int TWISTING_VINES_COUNT = 28; + private static final int TWISTING_VINES_COUNT_MIN = 14; // We don't want curse of binding private static final Predicate _noCurseOfBinding = stack -> { - for (NbtElement elm : stack.getEnchantments()) { - NbtCompound comp = (NbtCompound) elm; - if (comp.getString("id").equals("minecraft:binding_curse")) { - return false; - } + if (stack.getEnchantments().getEnchantments().contains(EnchantmentTags.CURSE)) { + return false; } return true; }; private static BeatMinecraftConfig _config; + private static GoToStrongholdPortalTask _locateStrongholdTask; + private static boolean openingEndPortal = false; static { ConfigHelper.loadConfig("configs/beat_minecraft.json", BeatMinecraftConfig::new, BeatMinecraftConfig.class, newConfig -> _config = newConfig); @@ -120,7 +130,6 @@ public class MarvionBeatMinecraftTask extends Task { private final TimerGame _cachedEndItemNothingWaitTime = new TimerGame(10); private final Task _buildMaterialsTask; private final PlaceBedAndSetSpawnTask _setBedSpawnTask = new PlaceBedAndSetSpawnTask(); - private final GoToStrongholdPortalTask _locateStrongholdTask; private final Task _goToNetherTask = new DefaultGoToDimensionTask(Dimension.NETHER); // To keep the portal build cache. private final Task _getOneBedTask = TaskCatalogue.getItemTask("bed", 1); private final Task _sleepThroughNightTask = new SleepThroughNightTask(); @@ -131,16 +140,16 @@ public class MarvionBeatMinecraftTask extends Task { private final TimerGame _timer2 = new TimerGame(35); private final TimerGame _timer3 = new TimerGame(60); boolean _weHaveEyes; - private boolean _dragonIsDead = false; + private static boolean dragonIsDead; private BlockPos _endPortalCenterLocation; - private boolean _isEquippingDiamondArmor; + private boolean isEquippingDiamondArmor; private boolean _ranStrongholdLocator; private boolean _endPortalOpened; private BlockPos _bedSpawnLocation; private List _notRuinedPortalChests = new ArrayList<>(); private int _cachedFilledPortalFrames = 0; // Controls whether we CAN walk on the end portal. - private boolean _enterindEndPortal = false; + private static boolean enteringEndPortal; private Task _foodTask; private Task _gearTask; private Task _lootTask; @@ -164,398 +173,783 @@ public MarvionBeatMinecraftTask() { _buildMaterialsTask = new GetBuildingMaterialsTask(_config.buildMaterialCount); } + /** + * Retrieves the BeatMinecraftConfig instance, creating a new one if it doesn't exist. + * @return the BeatMinecraftConfig instance + */ public static BeatMinecraftConfig getConfig() { + if (_config == null) { + _config = new BeatMinecraftConfig(); + } return _config; } + /** + * Retrieves the frame blocks surrounding the end portal center. + * @param endPortalCenter the center position of the end portal + * @return the list of frame blocks + */ private static List getFrameBlocks(BlockPos endPortalCenter) { - Vec3i[] frameOffsets = new Vec3i[]{ - new Vec3i(2, 0, 1), - new Vec3i(2, 0, 0), - new Vec3i(2, 0, -1), - new Vec3i(-2, 0, 1), - new Vec3i(-2, 0, 0), - new Vec3i(-2, 0, -1), - new Vec3i(1, 0, 2), - new Vec3i(0, 0, 2), - new Vec3i(-1, 0, 2), - new Vec3i(1, 0, -2), - new Vec3i(0, 0, -2), - new Vec3i(-1, 0, -2) - }; - return Arrays.stream(frameOffsets).map(endPortalCenter::add).toList(); + // Create a list to store the frame blocks + List frameBlocks = new ArrayList<>(); + + // Check if the end portal center is not null + if (endPortalCenter != null) { + // Define the offsets for the frame blocks + int[][] frameOffsets = { + {2, 0, 1}, + {2, 0, 0}, + {2, 0, -1}, + {-2, 0, 1}, + {-2, 0, 0}, + {-2, 0, -1}, + {1, 0, 2}, + {0, 0, 2}, + {-1, 0, 2}, + {1, 0, -2}, + {0, 0, -2}, + {-1, 0, -2} + }; + + // Iterate over each offset + for (int[] offset : frameOffsets) { + // Calculate the frame block position by adding the offset to the end portal center + BlockPos frameBlock = endPortalCenter.add(offset[0], offset[1], offset[2]); + + // Add the frame block to the list + frameBlocks.add(frameBlock); + } + } + + // Return the list of frame blocks + return frameBlocks; } + /** + * Converts an array of Item objects to an array of ItemTarget objects. + * + * @param items the array of Item objects to convert + * @return an array of ItemTarget objects + */ private static ItemTarget[] toItemTargets(Item... items) { - return Arrays.stream(items).map(item -> new ItemTarget(item, 1)).toArray(ItemTarget[]::new); + // Create a new array of ItemTarget objects with the same length as the input array + ItemTarget[] itemTargets = new ItemTarget[items.length]; + // Iterate over each item in the input array + for (int i = 0; i < items.length; i++) { + // Create a new ItemTarget object for the current item + itemTargets[i] = new ItemTarget(items[i]); + } + // Return the array of ItemTarget objects + return itemTargets; } + + /** + * Converts an Item and count into an array of ItemTargets. + * + * @param item The item to convert + * @param count The count of the item + * @return An array of ItemTargets + */ private static ItemTarget[] toItemTargets(Item item, int count) { - return new ItemTarget[]{new ItemTarget(item, count)}; + // Create a new array of ItemTargets with a length of 1. + ItemTarget[] itemTargets = {new ItemTarget(item, count)}; + + // Return the array of ItemTargets. + return itemTargets; } + /** + * Combines multiple arrays of ItemTarget objects into a single array. + * + * @param targets The arrays of ItemTarget objects to be combined + * @return The combined array of ItemTarget objects + */ private static ItemTarget[] combine(ItemTarget[]... targets) { - List result = new ArrayList<>(); - for (ItemTarget[] ts : targets) { - result.addAll(Arrays.asList(ts)); + List combinedTargets = new ArrayList<>(); + + // Iterate over each array of ItemTarget objects + for (ItemTarget[] targetArray : targets) { + if (targetArray != null) { + // Add all elements of the array to the combinedTargets list + combinedTargets.addAll(Arrays.asList(targetArray)); + } } - return result.toArray(ItemTarget[]::new); + + // Convert the combinedTargets list to an array and log it + ItemTarget[] combinedArray = combinedTargets.toArray(new ItemTarget[0]); + + // Return the combined array + return combinedArray; } + /** + * Check if the end portal frame at the specified position is filled with an eye of ender. + * @param mod the AltoClef mod + * @param pos the position of the end portal frame + * @return true if the end portal frame is filled with an eye of ender, false otherwise + */ private static boolean isEndPortalFrameFilled(AltoClef mod, BlockPos pos) { - if (!mod.getChunkTracker().isChunkLoaded(pos)) + // Check if the chunk at the specified position is loaded + if (!mod.getChunkTracker().isChunkLoaded(pos)) { return false; - BlockState state = mod.getWorld().getBlockState(pos); - if (state.getBlock() != Blocks.END_PORTAL_FRAME) { - Debug.logWarning("BLOCK POS " + pos + " DOES NOT CONTAIN END PORTAL FRAME! This is probably due to a bug/incorrect assumption."); + } + + // Get the block state at the specified position + BlockState blockState = mod.getWorld().getBlockState(pos); + + // Check if the block at the specified position is an end portal frame + if (blockState.getBlock() != Blocks.END_PORTAL_FRAME) { return false; } - return state.get(EndPortalFrameBlock.EYE); + + // Return true if the end portal frame is filled with an eye of ender, false otherwise + return blockState.get(EndPortalFrameBlock.EYE); } - // Just a helpful utility to reduce reuse recycle. + /** + * Check if the task should be forced for the given alto clef mod. + * @param mod the alto clef mod + * @param task the task to check + * @return true if the task should be forced, false otherwise + */ private static boolean shouldForce(AltoClef mod, Task task) { + // Task must not be null, must be active, and must not be finished for the given mod return task != null && task.isActive() && !task.isFinished(mod); } + /** + * Check if the condition for finishing the game is met. + * + * @param mod the AltoClef object + * @return true if the game is finished, false otherwise + */ @Override public boolean isFinished(AltoClef mod) { - return getInstance().currentScreen instanceof CreditsScreen || - (WorldHelper.getCurrentDimension() == Dimension.OVERWORLD && _dragonIsDead); + // Check if the current screen is the CreditsScreen + if (getInstance().currentScreen instanceof CreditsScreen) { + return true; + } + + // Check if the dragon is dead in the Overworld + if (WorldHelper.getCurrentDimension() == Dimension.OVERWORLD && dragonIsDead) { + return true; + } + return false; } + /** + * Check if the bot needs more building materials to start building. + * + * @param mod the AltoClef mod instance + * @return true if the bot needs more building materials, false otherwise + */ private boolean needsBuildingMaterials(AltoClef mod) { - return StorageHelper.getBuildingMaterialCount(mod) < _config.minBuildMaterialCount || shouldForce(mod, _buildMaterialsTask); + // Get the count of building materials in storage + int materialCount = StorageHelper.getBuildingMaterialCount(mod); + + // Check if the bot should force building or if the material count is below the minimum required + boolean shouldForce = shouldForce(mod, _buildMaterialsTask); + + // Return true if the material count is below the minimum required or if the bot should force building + return materialCount < _config.minBuildMaterialCount || shouldForce; } + /** + * Update the cached end items based on the dropped items from the entity tracker. + * + * @param mod The AltoClef mod + */ private void updateCachedEndItems(AltoClef mod) { + // Get the list of dropped items from the entity tracker. List droppedItems = mod.getEntityTracker().getDroppedItems(); - // If we have no items, it COULD be because we're dead. Wait a little. - if (droppedItems.isEmpty()) { - if (!_cachedEndItemNothingWaitTime.elapsed()) { - return; - } - } else { - _cachedEndItemNothingWaitTime.reset(); - } + + // Reset the cache wait time and clear the cached end item drops. + _cachedEndItemNothingWaitTime.reset(); _cachedEndItemDrops.clear(); + + // Iterate over the dropped items to update the cached end item drops. for (ItemEntity entity : droppedItems) { + if (entity.getStack().isEmpty()) { + continue; + } Item item = entity.getStack().getItem(); int count = entity.getStack().getCount(); + + // Add the dropped item to the cached end item drops. _cachedEndItemDrops.put(item, _cachedEndItemDrops.getOrDefault(item, 0) + count); } } + /** + * Retrieves the count of a specific item from the cached end item drops. + * If the item does not exist in the cache, it returns 0. + * + * @param item The item to retrieve the count for + * @return The count of the specified item in the cached end item drops + */ private int getEndCachedCount(Item item) { - return _cachedEndItemDrops.getOrDefault(item, 0); + // Check if the item exists in the cachedEndItemDrops map before retrieving the count + if (_cachedEndItemDrops.containsKey(item)) { + return _cachedEndItemDrops.get(item); + } else { + return 0; // Return 0 if the item is not found in the map + } } + /** + * Checks if the given item has been dropped in the end. + * + * @param item The item to check + * @return True if the item has been dropped in the end, false otherwise + */ private boolean droppedInEnd(Item item) { - return getEndCachedCount(item) > 0; + // Get the cached count from the end. + Integer cachedCount = getEndCachedCount(item); + + return cachedCount != null && cachedCount > 0; } + /** + * Check if the item is present in the item storage or if it has been dropped in the end. + * + * @param mod the AltoClef object + * @param item the Item object + * @return true if the item is present in the item storage or if it has been dropped in the end, false otherwise + * @throws IllegalArgumentException if mod or item is null + */ private boolean hasItemOrDroppedInEnd(AltoClef mod, Item item) { - return mod.getItemStorage().hasItem(item) || droppedInEnd(item); + if (mod == null || item == null) { + throw new IllegalArgumentException("mod and item must not be null"); + } + + // Check if the item is present in the item storage. + boolean hasItem = mod.getItemStorage().hasItem(item); + + // Check if the item has been dropped in the end. + boolean droppedInEnd = droppedInEnd(item); + + // Return true if the item is present in the item storage or if it has been dropped in the end. + return hasItem || droppedInEnd; } + /** + * Generates a list of lootable items based on certain conditions. + * + * @param mod the AltoClef mod + * @return a list of lootable items + */ private List lootableItems(AltoClef mod) { List lootable = new ArrayList<>(); - lootable.add(Items.GOLDEN_APPLE); - lootable.add(Items.ENCHANTED_GOLDEN_APPLE); - lootable.add(Items.GLISTERING_MELON_SLICE); - lootable.add(Items.GOLDEN_CARROT); - lootable.add(Items.OBSIDIAN); - if (!StorageHelper.isArmorEquipped(mod, Items.GOLDEN_BOOTS) && !mod.getItemStorage().hasItemInventoryOnly(Items.GOLDEN_BOOTS)) { - lootable.add(Items.GOLDEN_BOOTS); - } - if ((mod.getItemStorage().getItemCountInventoryOnly(Items.GOLD_INGOT) < 4 && !StorageHelper.isArmorEquipped(mod, Items.GOLDEN_BOOTS) && !mod.getItemStorage().hasItemInventoryOnly(Items.GOLDEN_BOOTS)) || _config.barterPearlsInsteadOfEndermanHunt) { + + // Add initial lootable items + lootable.addAll(Arrays.asList( + Items.GOLDEN_APPLE, + Items.ENCHANTED_GOLDEN_APPLE, + Items.GLISTERING_MELON_SLICE, + Items.GOLDEN_CARROT, + Items.OBSIDIAN + )); + + // Check if golden helmet is equipped or available in inventory + boolean isGoldenHelmetEquipped = StorageHelper.isArmorEquipped(mod, Items.GOLDEN_HELMET); + boolean hasGoldenHelmet = mod.getItemStorage().hasItemInventoryOnly(Items.GOLDEN_HELMET); + + // Check if there are enough gold ingots + boolean hasEnoughGoldIngots = mod.getItemStorage().getItemCountInventoryOnly(Items.GOLD_INGOT) >= 5; + + // Add golden helmet if not equipped or available in inventory + if (!isGoldenHelmetEquipped && !hasGoldenHelmet) { + lootable.add(Items.GOLDEN_HELMET); + } + + // Add gold ingot if enough gold ingots are available or if barterPearlsInsteadOfEndermanHunt is true + if ((hasEnoughGoldIngots && !isGoldenHelmetEquipped && !hasGoldenHelmet) || _config.barterPearlsInsteadOfEndermanHunt) { lootable.add(Items.GOLD_INGOT); } + + // Add flint and steel and fire charge if not available in inventory if (!mod.getItemStorage().hasItemInventoryOnly(Items.FLINT_AND_STEEL)) { lootable.add(Items.FLINT_AND_STEEL); - if (!mod.getItemStorage().hasItemInventoryOnly(Items.FIRE_CHARGE)) { - lootable.add(Items.FIRE_CHARGE); - } } + if (!mod.getItemStorage().hasItemInventoryOnly(Items.FIRE_CHARGE)) { + lootable.add(Items.FIRE_CHARGE); + } + + // Add iron ingot if neither bucket nor water bucket is available in inventory if (!mod.getItemStorage().hasItemInventoryOnly(Items.BUCKET) && !mod.getItemStorage().hasItemInventoryOnly(Items.WATER_BUCKET)) { lootable.add(Items.IRON_INGOT); } + + // Add diamond if item targets for eye gear are not met in inventory if (!StorageHelper.itemTargetsMetInventory(mod, COLLECT_EYE_GEAR_MIN)) { lootable.add(Items.DIAMOND); } + + // Add flint if not available in inventory if (!mod.getItemStorage().hasItemInventoryOnly(Items.FLINT)) { lootable.add(Items.FLINT); } + return lootable; } + /** + * This method is called when the task is interrupted + * + * @param mod The AltoClef mod instance + * @param interruptTask The task that is interrupting the current task + */ @Override protected void onStop(AltoClef mod, Task interruptTask) { + // Disable walking on end portal mod.getExtraBaritoneSettings().canWalkOnEndPortal(false); + + // Pop the top behaviour from the stack mod.getBehaviour().pop(); - mod.getBlockTracker().stopTracking(ItemHelper.itemsToBlocks(ItemHelper.BED)); - mod.getBlockTracker().stopTracking(TRACK_BLOCKS); + + // Stop tracking bed blocks + if (mod.getBlockTracker() != null) { + mod.getBlockTracker().stopTracking(ItemHelper.itemsToBlocks(ItemHelper.BED)); + } + + // Stop tracking custom blocks + if (mod.getBlockTracker() != null) { + mod.getBlockTracker().stopTracking(TRACK_BLOCKS); + } } + /** + * Checks if the given task is equal to this MarvionBeatMinecraftTask. + * @param other the task to compare + * @return true if the tasks are equal, false otherwise + */ @Override protected boolean isEqual(Task other) { - return other instanceof MarvionBeatMinecraftTask; + if (other == null || !(other instanceof MarvionBeatMinecraftTask)) { + return false; + } + return true; } + /** + * Returns a debug string representing the action of beating the game in the Marvion version. + */ @Override protected String toDebugString() { - return "Beating the game (Marvion version)."; + return "Beating the game (Marvion version)"; } + /** + * Checks if the end portal is found at the specified center position. + * + * @param mod The AltoClef mod instance + * @param endPortalCenter The center position of the end portal + * @return true if the end portal is found, false otherwise + */ private boolean endPortalFound(AltoClef mod, BlockPos endPortalCenter) { + // If the end portal center is null, return false if (endPortalCenter == null) { return false; } + // If the end portal is already opened, return true if (endPortalOpened(mod, endPortalCenter)) { return true; } - return getFrameBlocks(endPortalCenter).stream().anyMatch(frame -> mod.getBlockTracker().blockIsValid(frame, Blocks.END_PORTAL_FRAME)); + // Get the frame blocks of the end portal + List frameBlocks = getFrameBlocks(endPortalCenter); + // Check if any of the frame blocks is a valid end portal frame block + for (BlockPos frame : frameBlocks) { + // If the block is a valid end portal frame block, return true + if (mod.getBlockTracker().blockIsValid(frame, Blocks.END_PORTAL_FRAME)) { + return true; + } + } + // If none of the frame blocks are valid, return false + return false; } + + /** + * Check if the end portal is already opened and the center position is provided + * + * @param mod The AltoClef mod instance + * @param endPortalCenter The center position of the end portal + * @return Whether the end portal is opened at the provided center position + */ private boolean endPortalOpened(AltoClef mod, BlockPos endPortalCenter) { - return _endPortalOpened && endPortalCenter != null && mod.getBlockTracker().blockIsValid(endPortalCenter, Blocks.END_PORTAL); + // Check if the end portal is already opened and the center position is provided + if (_endPortalOpened && endPortalCenter != null) { + // Get the block tracker from the mod instance + BlockTracker blockTracker = mod.getBlockTracker(); + // Check if the block tracker is available and the end portal block at the center position is valid + return blockTracker != null && blockTracker.blockIsValid(endPortalCenter, Blocks.END_PORTAL); + } + return false; } + /** + * Checks if the bed spawn location is near the end portal. + * + * @param mod the AltoClef mod + * @param endPortalCenter the BlockPos of the end portal center + * @return true if the bed spawn location is near the end portal, false otherwise + */ private boolean spawnSetNearPortal(AltoClef mod, BlockPos endPortalCenter) { - return _bedSpawnLocation != null && mod.getBlockTracker().blockIsValid(_bedSpawnLocation, ItemHelper.itemsToBlocks(ItemHelper.BED)); + if (_bedSpawnLocation == null) { + return false; + } + + BlockTracker blockTracker = mod.getBlockTracker(); + + try { + // Check if the bed spawn location is a valid bed block + return blockTracker.blockIsValid(_bedSpawnLocation, ItemHelper.itemsToBlocks(ItemHelper.BED)); + } catch (Exception e) { + // Handle the exception here, for example log it or return a default value + return false; + } } + /** + * Locates the closest unopened ruined portal chest in the overworld. + * If not in the overworld, returns an empty optional. + * + * @param mod The game modification instance + * @return Optional The position of the closest unopened ruined portal chest, or empty if not found + */ private Optional locateClosestUnopenedRuinedPortalChest(AltoClef mod) { - if (WorldHelper.getCurrentDimension() != Dimension.OVERWORLD) { + // Check if the current dimension is not the overworld + if (!WorldHelper.getCurrentDimension().equals(Dimension.OVERWORLD)) { + return Optional.empty(); + } + + // Find the nearest tracking block position + try { + return mod.getBlockTracker().getNearestTracking(blockPos -> { + boolean isNotRuinedPortalChest = !_notRuinedPortalChests.contains(blockPos); + boolean isUnopenedChest = WorldHelper.isUnopenedChest(mod, blockPos); + boolean isWithinDistance = mod.getPlayer().getBlockPos().isWithinDistance(blockPos, 150); + boolean isLootablePortalChest = canBeLootablePortalChest(mod, blockPos); + + // Return true if all conditions are met + return isNotRuinedPortalChest && isUnopenedChest && isWithinDistance && isLootablePortalChest; + }, Blocks.CHEST); + } catch (Exception e) { + e.printStackTrace(); return Optional.empty(); } - return mod.getBlockTracker().getNearestTracking(blockPos -> !_notRuinedPortalChests.contains(blockPos) && WorldHelper.isUnopenedChest(mod, blockPos) && mod.getPlayer().getBlockPos().isWithinDistance(blockPos, 150) && canBeLootablePortalChest(mod, blockPos), Blocks.CHEST); } + /** + * This method is called when the bot starts. + * It resets timers, pushes initial behavior onto the stack, + * adds warning for throwaway items, tracks blocks in the world, + * adds protected items, allows walking on the end portal, + * avoids dragon breath, and avoids breaking the bed. + * Any exceptions are caught and printed. + */ @Override protected void onStart(AltoClef mod) { - _timer1.reset(); - _timer2.reset(); - _timer3.reset(); - mod.getBehaviour().push(); - // Add a warning to make sure the user at least knows to change the settings. + try { + dragonIsDead = false; + enteringEndPortal = false; + // Reset all timers + resetTimers(); + + // Push the initial behaviour onto the stack + pushBehaviour(mod); + + // Add warning for throwaway items + addThrowawayItemsWarning(mod); + + // Track blocks in the world + trackBlocks(mod); + + // Add protected items + addProtectedItems(mod); + + // Allow walking on the end portal + allowWalkingOnEndPortal(mod); + + // Avoid dragon breath + avoidDragonBreath(mod); + + // Avoid breaking the bed + avoidBreakingBed(mod); + } catch (Exception e) { + e.printStackTrace(); + // Handle the exception here + } + } + + /** + * Resets all timers to their initial state. + */ + private void resetTimers() { + try { + // Reset timer 1 + _timer1.reset(); + + // Reset timer 2 + _timer2.reset(); + + // Reset timer 3 + _timer3.reset(); + } catch (Exception e) { + // Handle any unanticipated exceptions + e.printStackTrace(); + } + } + + /** + * Pushes the behaviour of the given AltoClef object. + * + * @param mod the AltoClef object + */ + private void pushBehaviour(AltoClef mod) { + // Check if the behaviour is not null and push it + if (mod.getBehaviour() != null) { + mod.getBehaviour().push(); + } else { + // Handle the case where the behaviour is null + } + } + + /** + * Adds warning messages for missing configuration settings. + * @param mod The AltoClef mod instance. + */ + private void addThrowawayItemsWarning(AltoClef mod) { + // Warning message tail that will be appended to the warning message. String settingsWarningTail = "in \".minecraft/altoclef_settings.json\". @gamer may break if you don't add this! (sorry!)"; + + // Check if "end_stone" is not part of the "throwawayItems" list and log a warning. if (!ArrayUtils.contains(mod.getModSettings().getThrowawayItems(mod), Items.END_STONE)) { Debug.logWarning("\"end_stone\" is not part of your \"throwawayItems\" list " + settingsWarningTail); } + + // Check if "throwawayUnusedItems" is not set to true and log a warning. if (!mod.getModSettings().shouldThrowawayUnusedItems()) { Debug.logWarning("\"throwawayUnusedItems\" is not set to true " + settingsWarningTail); } + } - mod.getBlockTracker().trackBlock(ItemHelper.itemsToBlocks(ItemHelper.BED)); - mod.getBlockTracker().trackBlock(TRACK_BLOCKS); - mod.getBehaviour().addProtectedItems(Items.ENDER_EYE, Items.BLAZE_ROD, Items.ENDER_PEARL, Items.CRAFTING_TABLE, - Items.IRON_INGOT, Items.WATER_BUCKET, Items.FLINT_AND_STEEL, Items.SHIELD, Items.SHEARS, Items.BUCKET, - Items.GOLDEN_BOOTS, Items.SMOKER, Items.FURNACE, Items.BLAST_FURNACE); - mod.getBehaviour().addProtectedItems(ItemHelper.BED); - mod.getBehaviour().addProtectedItems(ItemHelper.IRON_ARMORS); - mod.getBehaviour().addProtectedItems(ItemHelper.LOG); - // Allow walking on end portal - mod.getBehaviour().allowWalkingOn(blockPos -> _enterindEndPortal && mod.getChunkTracker().isChunkLoaded(blockPos) && mod.getWorld().getBlockState(blockPos).getBlock() == Blocks.END_PORTAL); + /** + * Tracks specific blocks using the provided mod's BlockTracker. + * + * @param mod The AltoClef mod instance. + */ + private void trackBlocks(AltoClef mod) { + // Get the BlockTracker from the mod + BlockTracker blockTracker = mod.getBlockTracker(); - // Avoid dragon breath - mod.getBehaviour().avoidWalkingThrough(blockPos -> { - return WorldHelper.getCurrentDimension() == Dimension.END && !_escapingDragonsBreath && _dragonBreathTracker.isTouchingDragonBreath(blockPos); - }); + // Track the BED block + if (blockTracker != null) { + blockTracker.trackBlock(ItemHelper.itemsToBlocks(ItemHelper.BED)); + blockTracker.trackBlock(TRACK_BLOCKS); + } else { + // Handle the case when blockTracker is null + } + } + + /** + * Adds protected items to the specified AltoClef mod. + * + * @param mod the AltoClef mod to add protected items to + */ + private void addProtectedItems(AltoClef mod) { + // Add individual protected items + mod.getBehaviour().addProtectedItems( + Items.ENDER_EYE, // Ender Eye + Items.BLAZE_ROD, // Blaze Rod + Items.ENDER_PEARL, // Ender Pearl + Items.CRAFTING_TABLE, // Crafting Table + Items.IRON_INGOT, // Iron Ingot + Items.WATER_BUCKET, // Water Bucket + Items.FLINT_AND_STEEL, // Flint and Steel + Items.SHIELD, // Shield + Items.SHEARS, // Shears + Items.BUCKET, // Bucket + Items.GOLDEN_HELMET, // Golden Helmet + Items.SMOKER, // Smoker + Items.FURNACE, // Furnace + Items.BLAST_FURNACE // Blast Furnace + ); - // Don't break the bed we placed near the end portal - mod.getBehaviour().avoidBlockBreaking(blockPos -> { - if (_bedSpawnLocation != null) { - return blockPos.equals(WorldHelper.getBedHead(mod, _bedSpawnLocation)) || blockPos.equals(WorldHelper.getBedFoot(mod, _bedSpawnLocation)); + // Add protected items using helper classes + mod.getBehaviour().addProtectedItems(ItemHelper.BED); // Bed + mod.getBehaviour().addProtectedItems(ItemHelper.IRON_ARMORS); // Iron Armors + mod.getBehaviour().addProtectedItems(ItemHelper.LOG); // Log + } + + /** + * Allows walking on the end portal if entering the end portal and the chunk at the block position is loaded. + * + * @param mod The AltoClef mod instance + */ + private void allowWalkingOnEndPortal(AltoClef mod) { + mod.getBehaviour().allowWalkingOn(blockPos -> { + if (enteringEndPortal && mod.getChunkTracker().isChunkLoaded(blockPos)) { + BlockState blockState = mod.getWorld().getBlockState(blockPos); + return blockState.getBlock() == Blocks.END_PORTAL; } return false; }); } + /** + * Prevents the player from walking through dragon breath in the specified dimension. + * + * @param mod the AltoClef mod instance + */ + private void avoidDragonBreath(AltoClef mod) { + mod.getBehaviour().avoidWalkingThrough(blockPos -> { + Dimension currentDimension = WorldHelper.getCurrentDimension(); + boolean isEndDimension = currentDimension == Dimension.END; + boolean isTouchingDragonBreath = _dragonBreathTracker.isTouchingDragonBreath(blockPos); + + return isEndDimension && !_escapingDragonsBreath && isTouchingDragonBreath; + }); + } + + /** + * Avoid breaking the bed by preventing block breaking at the bed location. + * + * @param mod The AltoClef mod instance + */ + private void avoidBreakingBed(AltoClef mod) { + // Check if the bed spawn location is not null + if (_bedSpawnLocation != null) { + // Get the head and foot position of the bed + BlockPos bedHead = WorldHelper.getBedHead(mod, _bedSpawnLocation); + BlockPos bedFoot = WorldHelper.getBedFoot(mod, _bedSpawnLocation); + + // Prevent block breaking at the bed location + mod.getBehaviour().avoidBlockBreaking(blockPos -> blockPos.equals(bedHead) || blockPos.equals(bedFoot)); + } + } + @Override protected Task onTick(AltoClef mod) { + if (mod.getPlayer().getMainHandStack().getItem() instanceof EnderEyeItem && !openingEndPortal + && StorageHelper.getItemStackInCursorSlot().isEmpty()) { + List itemStacks = mod.getItemStorage().getItemStacksPlayerInventory(true); + for (ItemStack itemStack : itemStacks) { + Item item = itemStack.getItem(); + if (item instanceof SwordItem) { + mod.getSlotHandler().forceEquipItem(item); + } + } + } boolean eyeGearSatisfied = StorageHelper.isArmorEquippedAll(mod, COLLECT_EYE_ARMOR); boolean ironGearSatisfied = StorageHelper.isArmorEquippedAll(mod, COLLECT_IRON_ARMOR); if (mod.getItemStorage().hasItem(Items.DIAMOND_PICKAXE)) { - mod.getBehaviour().setBlockBreakAdditionalPenalty(0); + if (mod.getClientBaritoneSettings().blockBreakAdditionalPenalty.value != 0) { + mod.getBehaviour().setBlockBreakAdditionalPenalty(0); + } } else { - mod.getBehaviour().setBlockBreakAdditionalPenalty(mod.getClientBaritoneSettings().blockBreakAdditionalPenalty.defaultValue); + if (mod.getClientBaritoneSettings().blockBreakAdditionalPenalty.value != mod.getClientBaritoneSettings().blockBreakAdditionalPenalty.defaultValue) { + mod.getBehaviour().setBlockBreakAdditionalPenalty(mod.getClientBaritoneSettings().blockBreakAdditionalPenalty.defaultValue); + } } Predicate isCraftingTableTask = task -> { - if (task instanceof DoStuffInContainerTask cont) { - return cont.getContainerTarget().matches(Items.CRAFTING_TABLE); + if (task instanceof CraftInTableTask || task instanceof PickupFromContainerTask) { + return true; } return false; }; - List craftingTables = mod.getBlockTracker().getKnownLocations(Blocks.CRAFTING_TABLE); - if (!craftingTables.isEmpty()) { - for (BlockPos craftingTable : craftingTables) { - if (mod.getItemStorage().hasItem(Items.CRAFTING_TABLE) && !thisOrChildSatisfies(isCraftingTableTask)) { - if (!mod.getBlockTracker().unreachable(craftingTable)) { - Debug.logMessage("Blacklisting extra crafting table."); - mod.getBlockTracker().requestBlockUnreachable(craftingTable, 0); - } - } - if (!mod.getBlockTracker().unreachable(craftingTable)) { - BlockState craftingTablePosUp = mod.getWorld().getBlockState(craftingTable.up(2)); - if (mod.getEntityTracker().entityFound(WitchEntity.class)) { - Optional witch = mod.getEntityTracker().getClosestEntity(WitchEntity.class); - if (witch.isPresent()) { - if (craftingTable.isWithinDistance(witch.get().getPos(), 15)) { - Debug.logMessage("Blacklisting witch crafting table."); - mod.getBlockTracker().requestBlockUnreachable(craftingTable, 0); - } - } - } - if (craftingTablePosUp.getBlock() == Blocks.WHITE_WOOL) { - Debug.logMessage("Blacklisting pillage crafting table."); - mod.getBlockTracker().requestBlockUnreachable(craftingTable, 0); - } - } + Predicate isSmokerTask = task -> { + if (task instanceof SmeltInSmokerTask || task instanceof PickupFromContainerTask) { + return true; } - } - List smokers = mod.getBlockTracker().getKnownLocations(Blocks.SMOKER); - if (!smokers.isEmpty()) { - for (BlockPos smoker : smokers) { - if (mod.getItemStorage().hasItem(Items.SMOKER) && _smeltTask == null && _foodTask == null) { - if (!mod.getBlockTracker().unreachable(smoker)) { - Debug.logMessage("Blacklisting extra smoker."); - mod.getBlockTracker().requestBlockUnreachable(smoker, 0); - } - } + return false; + }; + Predicate isFurnaceTask = task -> { + if (task instanceof SmeltInFurnaceTask || task instanceof PickupFromContainerTask || task instanceof CraftInTableTask) { + return true; } - } - List furnaces = mod.getBlockTracker().getKnownLocations(Blocks.FURNACE); - if (!furnaces.isEmpty()) { - for (BlockPos furnace : furnaces) { - if ((mod.getItemStorage().hasItem(Items.FURNACE) || mod.getItemStorage().hasItem(Items.BLAST_FURNACE)) && - _starterGearTask == null && _shieldTask == null && _ironGearTask == null && _gearTask == null && - !_goToNetherTask.isActive() && !_ranStrongholdLocator) { - if (!mod.getBlockTracker().unreachable(furnace)) { - Debug.logMessage("Blacklisting extra furnace."); - mod.getBlockTracker().requestBlockUnreachable(furnace, 0); - } - } + return false; + }; + Predicate isBlastFurnaceTask = task -> { + if (task instanceof SmeltInBlastFurnaceTask || task instanceof PickupFromContainerTask) { + return true; } - } - List blastFurnaces = mod.getBlockTracker().getKnownLocations(Blocks.BLAST_FURNACE); - if (!blastFurnaces.isEmpty()) { - for (BlockPos blastFurnace : blastFurnaces) { - if (mod.getItemStorage().hasItem(Items.BLAST_FURNACE) && _starterGearTask == null && _shieldTask == null && - _ironGearTask == null && _gearTask == null && !_goToNetherTask.isActive() && !_ranStrongholdLocator) { - if (!mod.getBlockTracker().unreachable(blastFurnace)) { - Debug.logMessage("Blacklisting extra blast furnace."); - mod.getBlockTracker().requestBlockUnreachable(blastFurnace, 0); - } + return false; + }; + if (mod.getBlockTracker().isTracking(Blocks.CRAFTING_TABLE)) { + Optional craftingTables = mod.getBlockTracker().getNearestTracking(Blocks.CRAFTING_TABLE); + if (craftingTables.isPresent() && mod.getItemStorage().hasItem(Items.CRAFTING_TABLE) + && !thisOrChildSatisfies(isCraftingTableTask) && !mod.getBlockTracker().unreachable(craftingTables.get())) { + Debug.logMessage("Blacklisting extra crafting table."); + mod.getBlockTracker().requestBlockUnreachable(craftingTables.get(), 0); + BlockState craftingTablePosUp = mod.getWorld().getBlockState(craftingTables.get().up(2)); + Optional witch = mod.getEntityTracker().getClosestEntity(WitchEntity.class); + if (witch.isPresent() && craftingTables.get().isWithinDistance(witch.get().getPos(), 15)) { + Debug.logMessage("Blacklisting witch crafting table."); + mod.getBlockTracker().requestBlockUnreachable(craftingTables.get(), 0); + } + if (craftingTablePosUp.getBlock() == Blocks.WHITE_WOOL) { + Debug.logMessage("Blacklisting pillage crafting table."); + mod.getBlockTracker().requestBlockUnreachable(craftingTables.get(), 0); } } } - List logs = mod.getBlockTracker().getKnownLocations(ItemHelper.itemsToBlocks(ItemHelper.LOG)); - if (!logs.isEmpty()) { - for (BlockPos log : logs) { - Iterable entities = mod.getWorld().getEntities(); - for (Entity entity : entities) { - if (entity instanceof PillagerEntity) { - if (!mod.getBlockTracker().unreachable(log)) { - if (log.isWithinDistance(entity.getPos(), 40)) { - Debug.logMessage("Blacklisting pillage log."); - mod.getBlockTracker().requestBlockUnreachable(log, 0); - } - } - } - } - if (log.getY() < 62) { - if (!mod.getBlockTracker().unreachable(log)) { - if (!ironGearSatisfied && !eyeGearSatisfied) { - Debug.logMessage("Blacklisting dangerous log."); - mod.getBlockTracker().requestBlockUnreachable(log, 0); - } - } - } + if (mod.getBlockTracker().isTracking(Blocks.SMOKER)) { + Optional smokers = mod.getBlockTracker().getNearestTracking(Blocks.SMOKER); + if (smokers.isPresent() && mod.getItemStorage().hasItem(Items.SMOKER) + && !thisOrChildSatisfies(isSmokerTask) && !mod.getBlockTracker().unreachable(smokers.get())) { + Debug.logMessage("Blacklisting extra smoker."); + mod.getBlockTracker().requestBlockUnreachable(smokers.get(), 0); } } - if (mod.getBlockTracker().isTracking(Blocks.DEEPSLATE_COAL_ORE)) { - Optional deepslateCoalOre = mod.getBlockTracker().getNearestTracking(Blocks.DEEPSLATE_COAL_ORE); - if (deepslateCoalOre.isPresent()) { - Iterable entities = mod.getWorld().getEntities(); - for (Entity entity : entities) { - if (entity instanceof HostileEntity) { - if (!mod.getBlockTracker().unreachable(deepslateCoalOre.get())) { - if (mod.getPlayer().squaredDistanceTo(entity.getPos()) < 150 && - deepslateCoalOre.get().isWithinDistance(entity.getPos(), 30)) { - if (!ironGearSatisfied && !eyeGearSatisfied) { - Debug.logMessage("Blacklisting dangerous coal ore."); - mod.getBlockTracker().requestBlockUnreachable(deepslateCoalOre.get(), 0); - } - } - } - } - } + if (mod.getBlockTracker().isTracking(Blocks.FURNACE)) { + Optional furnaces = mod.getBlockTracker().getNearestTracking(Blocks.FURNACE); + if (furnaces.isPresent() && (mod.getItemStorage().hasItem(Items.FURNACE) || mod.getItemStorage().hasItem(Items.BLAST_FURNACE)) + && !thisOrChildSatisfies(isFurnaceTask) && !mod.getBlockTracker().unreachable(furnaces.get())) { + Debug.logMessage("Blacklisting extra furnace."); + mod.getBlockTracker().requestBlockUnreachable(furnaces.get(), 0); } } - if (mod.getBlockTracker().isTracking(Blocks.COAL_ORE)) { - Optional coalOrePos = mod.getBlockTracker().getNearestTracking(Blocks.COAL_ORE); - if (coalOrePos.isPresent()) { - Iterable entities = mod.getWorld().getEntities(); - for (Entity entity : entities) { - if (entity instanceof HostileEntity) { - if (!mod.getBlockTracker().unreachable(coalOrePos.get())) { - if (mod.getPlayer().squaredDistanceTo(entity.getPos()) < 150 && - coalOrePos.get().isWithinDistance(entity.getPos(), 30)) { - if (!ironGearSatisfied && !eyeGearSatisfied) { - Debug.logMessage("Blacklisting dangerous coal ore."); - mod.getBlockTracker().requestBlockUnreachable(coalOrePos.get(), 0); - } - } - } - } - } + if (mod.getBlockTracker().isTracking(Blocks.BLAST_FURNACE)) { + Optional blastFurnaces = mod.getBlockTracker().getNearestTracking(Blocks.BLAST_FURNACE); + if (blastFurnaces.isPresent() && mod.getItemStorage().hasItem(Items.BLAST_FURNACE) + && !thisOrChildSatisfies(isBlastFurnaceTask) && !mod.getBlockTracker().unreachable(blastFurnaces.get())) { + Debug.logMessage("Blacklisting extra blast furnace."); + mod.getBlockTracker().requestBlockUnreachable(blastFurnaces.get(), 0); } } - if (mod.getBlockTracker().isTracking(Blocks.DEEPSLATE_IRON_ORE)) { - Optional deepslateIronOrePos = mod.getBlockTracker().getNearestTracking(Blocks.DEEPSLATE_IRON_ORE); - if (deepslateIronOrePos.isPresent()) { - Iterable entities = mod.getWorld().getEntities(); - for (Entity entity : entities) { - if (entity instanceof HostileEntity) { - if (!mod.getBlockTracker().unreachable(deepslateIronOrePos.get())) { - if (mod.getPlayer().squaredDistanceTo(entity.getPos()) < 150 && - deepslateIronOrePos.get().isWithinDistance(entity.getPos(), 30)) { - if (!ironGearSatisfied && !eyeGearSatisfied) { - Debug.logMessage("Blacklisting dangerous iron ore."); - mod.getBlockTracker().requestBlockUnreachable(deepslateIronOrePos.get(), 0); - } - } - } - } + Block[] wools = ItemHelper.itemsToBlocks(ItemHelper.WOOL); + for (Block wool : wools) { + if (mod.getBlockTracker().isTracking(wool)) { + Optional woolsPos = mod.getBlockTracker().getNearestTracking(wool); + if (woolsPos.isPresent() && woolsPos.get().getY() < 62 && !mod.getBlockTracker().unreachable(woolsPos.get())) { + Debug.logMessage("Blacklisting dangerous wool."); + mod.getBlockTracker().requestBlockUnreachable(woolsPos.get(), 0); } } } - if (mod.getBlockTracker().isTracking(Blocks.IRON_ORE)) { - Optional ironOrePos = mod.getBlockTracker().getNearestTracking(Blocks.IRON_ORE); - if (ironOrePos.isPresent()) { - Iterable entities = mod.getWorld().getEntities(); - for (Entity entity : entities) { - if (entity instanceof HostileEntity) { - if (!mod.getBlockTracker().unreachable(ironOrePos.get())) { - if (mod.getPlayer().squaredDistanceTo(entity.getPos()) < 150 && - ironOrePos.get().isWithinDistance(entity.getPos(), 30)) { - if (!ironGearSatisfied && !eyeGearSatisfied) { - Debug.logMessage("Blacklisting dangerous iron ore."); - mod.getBlockTracker().requestBlockUnreachable(ironOrePos.get(), 0); - } - } + Block[] logBlocks = ItemHelper.itemsToBlocks(ItemHelper.LOG); + for (Block logBlock : logBlocks) { + if (mod.getBlockTracker().isTracking(logBlock)) { + Optional logs = mod.getBlockTracker().getNearestTracking(logBlock); + if (logs.isPresent()) { + Iterable entities = mod.getWorld().getEntities(); + for (Entity entity : entities) { + if (entity instanceof PillagerEntity && !mod.getBlockTracker().unreachable(logs.get()) + && logs.get().isWithinDistance(entity.getPos(), 40)) { + Debug.logMessage("Blacklisting pillage log."); + mod.getBlockTracker().requestBlockUnreachable(logs.get(), 0); } } + if (logs.get().getY() < 62 && !mod.getBlockTracker().unreachable(logs.get()) && !ironGearSatisfied + && !eyeGearSatisfied) { + Debug.logMessage("Blacklisting dangerous log."); + mod.getBlockTracker().requestBlockUnreachable(logs.get(), 0); + } } } } - if (!mod.getItemStorage().hasItem(Items.NETHERRACK) && - WorldHelper.getCurrentDimension() == Dimension.NETHER && !isGettingBlazeRods && - !isGettingEnderPearls) { - setDebugState("Getting netherrack."); - return TaskCatalogue.getItemTask(Items.NETHERRACK, 1); - } if (_locateStrongholdTask.isActive()) { if (WorldHelper.getCurrentDimension() == Dimension.OVERWORLD) { if (!mod.getClientBaritone().getExploreProcess().isActive()) { @@ -613,128 +1007,110 @@ protected Task onTick(AltoClef mod) { } } } - List torches = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, - Items.TORCH); - List beds = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, - ItemHelper.BED); - List excessWaterBuckets = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, - Items.WATER_BUCKET); - List excessLighters = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, - Items.FLINT_AND_STEEL); - List sands = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, - Items.SAND); - List gravels = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, - Items.GRAVEL); - List furnaceSlots = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, - Items.FURNACE); - List shears = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, - Items.SHEARS); - if (!StorageHelper.isBigCraftingOpen() && !StorageHelper.isFurnaceOpen() && - !StorageHelper.isSmokerOpen() && !StorageHelper.isBlastFurnaceOpen()) { - if (!shears.isEmpty() && !needsBeds(mod)) { - for (Slot shear : shears) { - if (Slot.isCursor(shear)) { - if (!mod.getControllerExtras().isBreakingBlock()) { - LookHelper.randomOrientation(mod); - } - mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); - } else { - mod.getSlotHandler().clickSlot(shear, 0, SlotActionType.PICKUP); + List torches = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, Items.TORCH); + if (!torches.isEmpty()) { + for (Slot torch : torches) { + if (Slot.isCursor(torch)) { + if (!mod.getControllerExtras().isBreakingBlock()) { + LookHelper.randomOrientation(mod); } + mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); + } else { + mod.getSlotHandler().clickSlot(torch, 0, SlotActionType.PICKUP); } } - if (!furnaceSlots.isEmpty() && mod.getItemStorage().hasItem(Items.SMOKER) && - mod.getItemStorage().hasItem(Items.BLAST_FURNACE) && mod.getModSettings().shouldUseBlastFurnace()) { - for (Slot furnace : furnaceSlots) { - if (Slot.isCursor(furnace)) { - if (!mod.getControllerExtras().isBreakingBlock()) { - LookHelper.randomOrientation(mod); - } - mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); - } else { - mod.getSlotHandler().clickSlot(furnace, 0, SlotActionType.PICKUP); + } + List beds = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, ItemHelper.BED); + if (!beds.isEmpty() && mod.getItemStorage().getItemCount(ItemHelper.BED) > getTargetBeds(mod) && + !endPortalFound(mod, _endPortalCenterLocation) && WorldHelper.getCurrentDimension() != Dimension.END) { + for (Slot bed : beds) { + if (Slot.isCursor(bed)) { + if (!mod.getControllerExtras().isBreakingBlock()) { + LookHelper.randomOrientation(mod); } + mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); + } else { + mod.getSlotHandler().clickSlot(bed, 0, SlotActionType.PICKUP); } } - if (!sands.isEmpty()) { - for (Slot sand : sands) { - if (Slot.isCursor(sand)) { - if (!mod.getControllerExtras().isBreakingBlock()) { - LookHelper.randomOrientation(mod); - } - mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); - } else { - mod.getSlotHandler().clickSlot(sand, 0, SlotActionType.PICKUP); + } + List excessWaterBuckets = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, Items.WATER_BUCKET); + if (!excessWaterBuckets.isEmpty() && mod.getItemStorage().getItemCount(Items.WATER_BUCKET) > 1) { + for (Slot excessWaterBucket : excessWaterBuckets) { + if (Slot.isCursor(excessWaterBucket)) { + if (!mod.getControllerExtras().isBreakingBlock()) { + LookHelper.randomOrientation(mod); } + mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); + } else { + mod.getSlotHandler().clickSlot(excessWaterBucket, 0, SlotActionType.PICKUP); } } - if (mod.getItemStorage().hasItem(Items.FLINT) || mod.getItemStorage().hasItem(Items.FLINT_AND_STEEL)) { - if (!gravels.isEmpty()) { - for (Slot gravel : gravels) { - if (Slot.isCursor(gravel)) { - if (!mod.getControllerExtras().isBreakingBlock()) { - LookHelper.randomOrientation(mod); - } - mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); - } else { - mod.getSlotHandler().clickSlot(gravel, 0, SlotActionType.PICKUP); - } + } + List excessLighters = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, Items.FLINT_AND_STEEL); + if (!excessLighters.isEmpty() && mod.getItemStorage().getItemCount(Items.FLINT_AND_STEEL) > 1) { + for (Slot excessLighter : excessLighters) { + if (Slot.isCursor(excessLighter)) { + if (!mod.getControllerExtras().isBreakingBlock()) { + LookHelper.randomOrientation(mod); } + mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); + } else { + mod.getSlotHandler().clickSlot(excessLighter, 0, SlotActionType.PICKUP); } } - if (!torches.isEmpty()) { - for (Slot torch : torches) { - if (Slot.isCursor(torch)) { - if (!mod.getControllerExtras().isBreakingBlock()) { - LookHelper.randomOrientation(mod); - } - mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); - } else { - mod.getSlotHandler().clickSlot(torch, 0, SlotActionType.PICKUP); + } + List sands = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, Items.SAND); + if (!sands.isEmpty()) { + for (Slot sand : sands) { + if (Slot.isCursor(sand)) { + if (!mod.getControllerExtras().isBreakingBlock()) { + LookHelper.randomOrientation(mod); } + mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); + } else { + mod.getSlotHandler().clickSlot(sand, 0, SlotActionType.PICKUP); } } - if (mod.getItemStorage().getItemCount(Items.WATER_BUCKET) > 1) { - if (!excessWaterBuckets.isEmpty()) { - for (Slot excessWaterBucket : excessWaterBuckets) { - if (Slot.isCursor(excessWaterBucket)) { - if (!mod.getControllerExtras().isBreakingBlock()) { - LookHelper.randomOrientation(mod); - } - mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); - } else { - mod.getSlotHandler().clickSlot(excessWaterBucket, 0, SlotActionType.PICKUP); - } + } + List gravels = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, Items.GRAVEL); + if (!gravels.isEmpty() && (mod.getItemStorage().hasItem(Items.FLINT) || mod.getItemStorage().hasItem(Items.FLINT_AND_STEEL))) { + for (Slot gravel : gravels) { + if (Slot.isCursor(gravel)) { + if (!mod.getControllerExtras().isBreakingBlock()) { + LookHelper.randomOrientation(mod); } + mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); + } else { + mod.getSlotHandler().clickSlot(gravel, 0, SlotActionType.PICKUP); } } - if (mod.getItemStorage().getItemCount(Items.FLINT_AND_STEEL) > 1) { - if (!excessLighters.isEmpty()) { - for (Slot excessLighter : excessLighters) { - if (Slot.isCursor(excessLighter)) { - if (!mod.getControllerExtras().isBreakingBlock()) { - LookHelper.randomOrientation(mod); - } - mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); - } else { - mod.getSlotHandler().clickSlot(excessLighter, 0, SlotActionType.PICKUP); - } + } + List furnaceSlots = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, Items.FURNACE); + if (!furnaceSlots.isEmpty() && mod.getItemStorage().hasItem(Items.SMOKER) && + mod.getItemStorage().hasItem(Items.BLAST_FURNACE) && mod.getModSettings().shouldUseBlastFurnace()) { + for (Slot furnaceSlot : furnaceSlots) { + if (Slot.isCursor(furnaceSlot)) { + if (!mod.getControllerExtras().isBreakingBlock()) { + LookHelper.randomOrientation(mod); } + mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); + } else { + mod.getSlotHandler().clickSlot(furnaceSlot, 0, SlotActionType.PICKUP); } } - if (mod.getItemStorage().getItemCount(ItemHelper.BED) > getTargetBeds(mod) && - !endPortalFound(mod, _endPortalCenterLocation) && WorldHelper.getCurrentDimension() != Dimension.END) { - if (!beds.isEmpty()) { - for (Slot bed : beds) { - if (Slot.isCursor(bed)) { - if (!mod.getControllerExtras().isBreakingBlock()) { - LookHelper.randomOrientation(mod); - } - mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); - } else { - mod.getSlotHandler().clickSlot(bed, 0, SlotActionType.PICKUP); - } + } + List shears = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, Items.SHEARS); + if (!shears.isEmpty() && !StorageHelper.isBigCraftingOpen() && !StorageHelper.isFurnaceOpen() && + !StorageHelper.isSmokerOpen() && !StorageHelper.isBlastFurnaceOpen() && !needsBeds(mod)) { + for (Slot shear : shears) { + if (Slot.isCursor(shear)) { + if (!mod.getControllerExtras().isBreakingBlock()) { + LookHelper.randomOrientation(mod); } + mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); + } else { + mod.getSlotHandler().clickSlot(shear, 0, SlotActionType.PICKUP); } } } @@ -769,10 +1145,14 @@ protected Task onTick(AltoClef mod) { */ // By default, don't walk over end portals. - _enterindEndPortal = false; + enteringEndPortal = false; // End stuff. if (WorldHelper.getCurrentDimension() == Dimension.END) { + if (!mod.getWorld().isChunkLoaded(0, 0)) { + setDebugState("Waiting for chunks to load"); + return null; + } if (_config.renderDistanceManipulation) { getInstance().options.getViewDistance().setValue(12); getInstance().options.getEntityDistanceScaling().setValue(1.0); @@ -804,11 +1184,6 @@ protected Task onTick(AltoClef mod) { } } } - if (!mod.getEntityTracker().entityFound(EnderDragonEntity.class)) { - if (mod.getPlayer().getBlockPos().getX() == 0 && mod.getPlayer().getBlockPos().getZ() == 0) { - getInstance().player.setPitch(-90); - } - } // Dragons breath avoidance _dragonBreathTracker.updateBreath(mod); for (BlockPos playerIn : WorldHelper.getBlocksTouchingPlayer(mod)) { @@ -823,8 +1198,8 @@ protected Task onTick(AltoClef mod) { // If we find an ender portal, just GO to it!!! if (mod.getBlockTracker().anyFound(Blocks.END_PORTAL)) { setDebugState("WOOHOO"); - _dragonIsDead = true; - _enterindEndPortal = true; + dragonIsDead = true; + enteringEndPortal = true; if (!mod.getExtraBaritoneSettings().isCanWalkOnEndPortal()) { mod.getExtraBaritoneSettings().canWalkOnEndPortal(true); } @@ -847,76 +1222,113 @@ protected Task onTick(AltoClef mod) { // Check for end portals. Always. if (!endPortalOpened(mod, _endPortalCenterLocation) && WorldHelper.getCurrentDimension() == Dimension.OVERWORLD) { - Optional endPortal = mod.getBlockTracker().getNearestTracking(Blocks.END_PORTAL); - if (endPortal.isPresent()) { - _endPortalCenterLocation = endPortal.get(); - _endPortalOpened = true; - } else { - // TODO: Test that this works, for some reason the bot gets stuck near the stronghold and it keeps "Searching" for the portal - _endPortalCenterLocation = doSimpleSearchForEndPortal(mod); + if (mod.getBlockTracker().isTracking(Blocks.END_PORTAL)) { + Optional endPortal = mod.getBlockTracker().getNearestTracking(Blocks.END_PORTAL); + if (endPortal.isPresent()) { + _endPortalCenterLocation = endPortal.get(); + _endPortalOpened = true; + } else { + // TODO: Test that this works, for some reason the bot gets stuck near the stronghold and it keeps "Searching" for the portal + _endPortalCenterLocation = doSimpleSearchForEndPortal(mod); + } } } - if (getBedTask != null) { - // for smoker - _smeltTask = null; - _foodTask = null; - // for furnace - _starterGearTask = null; - _shieldTask = null; - _ironGearTask = null; - _gearTask = null; - } // Portable crafting table. // If we're NOT using our crafting table right now and there's one nearby, grab it. - if (!_endPortalOpened && WorldHelper.getCurrentDimension() != Dimension.END && _config.rePickupCraftingTable && - !mod.getItemStorage().hasItem(Items.CRAFTING_TABLE) && !thisOrChildSatisfies(isCraftingTableTask) - && (mod.getBlockTracker().anyFound(blockPos -> WorldHelper.canBreak(mod, blockPos) && - WorldHelper.canReach(mod, blockPos), Blocks.CRAFTING_TABLE) || - mod.getEntityTracker().itemDropped(Items.CRAFTING_TABLE))) { - setDebugState("Picking up the crafting table while we are at it."); - return new MineAndCollectTask(Items.CRAFTING_TABLE, 1, new Block[]{Blocks.CRAFTING_TABLE}, MiningRequirement.HAND); - } - if (_config.rePickupSmoker && !_endPortalOpened && WorldHelper.getCurrentDimension() != Dimension.END && - !mod.getItemStorage().hasItem(Items.SMOKER) && - (mod.getBlockTracker().anyFound(blockPos -> WorldHelper.canBreak(mod, blockPos) && - WorldHelper.canReach(mod, blockPos), Blocks.SMOKER) - || mod.getEntityTracker().itemDropped(Items.SMOKER)) && _smeltTask == null && - _foodTask == null) { - setDebugState("Picking up the smoker while we are at it."); - return new MineAndCollectTask(Items.SMOKER, 1, new Block[]{Blocks.SMOKER}, MiningRequirement.WOOD); - } - if (_config.rePickupFurnace && !_endPortalOpened && WorldHelper.getCurrentDimension() != Dimension.END && - !mod.getItemStorage().hasItem(Items.FURNACE) && - (mod.getBlockTracker().anyFound(blockPos -> WorldHelper.canBreak(mod, blockPos) && - WorldHelper.canReach(mod, blockPos), Blocks.FURNACE) || - mod.getEntityTracker().itemDropped(Items.FURNACE)) && _starterGearTask == null && - _shieldTask == null && _ironGearTask == null && _gearTask == null && !_goToNetherTask.isActive() && - !_ranStrongholdLocator && !mod.getModSettings().shouldUseBlastFurnace()) { - setDebugState("Picking up the furnace while we are at it."); - return new MineAndCollectTask(Items.FURNACE, 1, new Block[]{Blocks.FURNACE}, MiningRequirement.WOOD); - } - if (_config.rePickupFurnace && !_endPortalOpened && WorldHelper.getCurrentDimension() != Dimension.END && - !mod.getItemStorage().hasItem(Items.BLAST_FURNACE) && - (mod.getBlockTracker().anyFound(blockPos -> WorldHelper.canBreak(mod, blockPos) && - WorldHelper.canReach(mod, blockPos), Blocks.BLAST_FURNACE) || - mod.getEntityTracker().itemDropped(Items.BLAST_FURNACE)) && _starterGearTask == null && - _shieldTask == null && _ironGearTask == null && _gearTask == null && !_goToNetherTask.isActive() && - !_ranStrongholdLocator && mod.getModSettings().shouldUseBlastFurnace()) { - setDebugState("Picking up the blast furnace while we are at it."); - return new MineAndCollectTask(Items.BLAST_FURNACE, 1, new Block[]{Blocks.BLAST_FURNACE}, MiningRequirement.WOOD); + Block[] copperBlocks = ItemHelper.itemsToBlocks(ItemHelper.COPPER_BLOCKS); + if (mod.getBlockTracker().isTracking(Blocks.CRAFTING_TABLE)) { + Optional nearestCraftingTable = mod.getBlockTracker().getNearestTracking(Blocks.CRAFTING_TABLE); + if (nearestCraftingTable.isPresent() && WorldHelper.canBreak(mod, nearestCraftingTable.get())) { + Block craftingTable = mod.getWorld().getBlockState(nearestCraftingTable.get()).getBlock(); + for (Block CopperBlock : copperBlocks) { + Block blockBelow = mod.getWorld().getBlockState(nearestCraftingTable.get().down()).getBlock(); + if (blockBelow == CopperBlock) { + Debug.logMessage("Blacklisting crafting table in trial chambers."); + mod.getBlockTracker().requestBlockUnreachable(nearestCraftingTable.get(), 0); + } + } + } + } + boolean noEyesPlease = (endPortalOpened(mod, _endPortalCenterLocation) || WorldHelper.getCurrentDimension() == Dimension.END); + int filledPortalFrames = getFilledPortalFrames(mod, _endPortalCenterLocation); + int eyesNeededMin = noEyesPlease ? 0 : _config.minimumEyes - filledPortalFrames; + int eyesNeeded = noEyesPlease ? 0 : _config.targetEyes - filledPortalFrames; + int eyes = mod.getItemStorage().getItemCount(Items.ENDER_EYE); + if (eyes < eyesNeededMin || (!_ranStrongholdLocator && _collectingEyes && eyes < eyesNeeded)) { + if (mod.getBlockTracker().isTracking(Blocks.BLAST_FURNACE)) { + Optional blastFurnacePos = mod.getBlockTracker().getNearestTracking(Blocks.BLAST_FURNACE); + Optional blastFurnaceEntity = mod.getEntityTracker().getClosestItemDrop(Items.BLAST_FURNACE); + if (blastFurnacePos.isPresent() && !_endPortalOpened && WorldHelper.getCurrentDimension() != Dimension.END + && _config.rePickupCraftingTable && !mod.getItemStorage().hasItem(Items.BLAST_FURNACE) + && !thisOrChildSatisfies(isBlastFurnaceTask) && WorldHelper.canBreak(mod, blastFurnacePos.get()) + || (blastFurnaceEntity.isPresent() + && mod.getEntityTracker().itemDropped(blastFurnaceEntity.get().getStack().getItem()) + && !thisOrChildSatisfies(isBlastFurnaceTask) && !mod.getItemStorage().hasItem(Items.BLAST_FURNACE))) { + setDebugState("Picking up the blast furnace while we are at it."); + Item blastFurnaceItem = blastFurnaceEntity.isPresent() ? blastFurnaceEntity.get().getStack().getItem() : Items.BLAST_FURNACE; + Block blastFurnaceBlock = blastFurnacePos.isPresent() ? mod.getWorld().getBlockState(blastFurnacePos.get()).getBlock() : Blocks.BLAST_FURNACE; + return new MineAndCollectTask(blastFurnaceItem, 1, new Block[]{blastFurnaceBlock}, MiningRequirement.WOOD); + } + } + if (mod.getBlockTracker().isTracking(Blocks.FURNACE)) { + Optional furnacePos = mod.getBlockTracker().getNearestTracking(Blocks.FURNACE); + Optional furnaceEntity = mod.getEntityTracker().getClosestItemDrop(Items.FURNACE); + if (furnacePos.isPresent() && !_endPortalOpened && WorldHelper.getCurrentDimension() != Dimension.END + && _config.rePickupCraftingTable && !mod.getItemStorage().hasItem(Items.FURNACE) + && !mod.getItemStorage().hasItem(Items.BLAST_FURNACE) && !thisOrChildSatisfies(isFurnaceTask) + && WorldHelper.canBreak(mod, furnacePos.get()) + || (furnaceEntity.isPresent() && mod.getEntityTracker().itemDropped(furnaceEntity.get().getStack().getItem()) + && !thisOrChildSatisfies(isFurnaceTask) && !mod.getItemStorage().hasItem(Items.FURNACE) + && !mod.getItemStorage().hasItem(Items.BLAST_FURNACE))) { + setDebugState("Picking up the furnace while we are at it."); + Item furnaceItem = furnaceEntity.isPresent() ? furnaceEntity.get().getStack().getItem() : Items.FURNACE; + Block furnaceBlock = furnacePos.isPresent() ? mod.getWorld().getBlockState(furnacePos.get()).getBlock() : Blocks.FURNACE; + return new MineAndCollectTask(furnaceItem, 1, new Block[]{furnaceBlock}, MiningRequirement.WOOD); + } + } + if (mod.getBlockTracker().isTracking(Blocks.SMOKER)) { + Optional smokerPos = mod.getBlockTracker().getNearestTracking(Blocks.SMOKER); + Optional smokerEntity = mod.getEntityTracker().getClosestItemDrop(Items.SMOKER); + if (smokerPos.isPresent() && !_endPortalOpened && WorldHelper.getCurrentDimension() != Dimension.END + && _config.rePickupCraftingTable && !mod.getItemStorage().hasItem(Items.SMOKER) + && !thisOrChildSatisfies(isSmokerTask) && WorldHelper.canBreak(mod, smokerPos.get()) + || (smokerEntity.isPresent() + && mod.getEntityTracker().itemDropped(smokerEntity.get().getStack().getItem()) + && !thisOrChildSatisfies(isSmokerTask) && !mod.getItemStorage().hasItem(Items.SMOKER))) { + setDebugState("Picking up the smoker while we are at it."); + Item smokerItem = smokerEntity.isPresent() ? smokerEntity.get().getStack().getItem() : Items.SMOKER; + Block smokerBlock = smokerPos.isPresent() ? mod.getWorld().getBlockState(smokerPos.get()).getBlock() : Blocks.SMOKER; + return new MineAndCollectTask(smokerItem, 1, new Block[]{smokerBlock}, MiningRequirement.WOOD); + } + } + if (mod.getBlockTracker().isTracking(Blocks.CRAFTING_TABLE)) { + Optional craftingTablePos = mod.getBlockTracker().getNearestTracking(Blocks.CRAFTING_TABLE); + Optional craftingTableEntity = mod.getEntityTracker().getClosestItemDrop(Items.CRAFTING_TABLE); + if (craftingTablePos.isPresent() && !_endPortalOpened && WorldHelper.getCurrentDimension() != Dimension.END + && _config.rePickupCraftingTable && !mod.getItemStorage().hasItem(Items.CRAFTING_TABLE) + && !thisOrChildSatisfies(isCraftingTableTask) && WorldHelper.canBreak(mod, craftingTablePos.get()) + || (craftingTableEntity.isPresent() + && mod.getEntityTracker().itemDropped(craftingTableEntity.get().getStack().getItem()) + && !thisOrChildSatisfies(isCraftingTableTask) && !mod.getItemStorage().hasItem(Items.CRAFTING_TABLE))) { + setDebugState("Picking up the crafting table while we are at it."); + Item craftingTableItem = craftingTableEntity.isPresent() ? craftingTableEntity.get().getStack().getItem() : Items.CRAFTING_TABLE; + Block craftingTableBlock = craftingTablePos.isPresent() ? mod.getWorld().getBlockState(craftingTablePos.get()).getBlock() : Blocks.CRAFTING_TABLE; + return new MineAndCollectTask(craftingTableItem, 1, new Block[]{craftingTableBlock}, MiningRequirement.HAND); + } + } + if (!mod.getItemStorage().hasItem(Items.NETHERRACK) && + WorldHelper.getCurrentDimension() == Dimension.NETHER && !isGettingBlazeRods && + !isGettingEnderPearls) { + setDebugState("Getting netherrack."); + if (mod.getEntityTracker().itemDropped(Items.NETHERRACK)) { + return new PickupDroppedItemTask(Items.NETHERRACK, 1, true); + } + return TaskCatalogue.getItemTask(Items.NETHERRACK, 1); + } } - // Sleep through night. if (_config.sleepThroughNight && !_endPortalOpened && WorldHelper.getCurrentDimension() == Dimension.OVERWORLD) { if (WorldHelper.canSleep()) { - // for smoker - _smeltTask = null; - _foodTask = null; - // for furnace - _starterGearTask = null; - _shieldTask = null; - _ironGearTask = null; - _gearTask = null; if (_config.renderDistanceManipulation && mod.getItemStorage().hasItem(ItemHelper.BED)) { if (!mod.getClientBaritone().getExploreProcess().isActive()) { if (_timer1.elapsed()) { @@ -929,7 +1341,8 @@ protected Task onTick(AltoClef mod) { if (_timer2.elapsed()) { _timer2.reset(); } - if (_timer2.getDuration() >= 30) { + if (_timer2.getDuration() >= 30 && + !mod.getPlayer().isSleeping()) { if (mod.getEntityTracker().itemDropped(ItemHelper.BED) && needsBeds(mod)) { setDebugState("Resetting sleep through night task."); return new PickupDroppedItemTask(new ItemTarget(ItemHelper.BED), true); @@ -942,11 +1355,29 @@ protected Task onTick(AltoClef mod) { setDebugState("Sleeping through night"); return _sleepThroughNightTask; } + if (shouldForce(mod, _getOneBedTask)) { + setDebugState("Getting one bed to sleep in at night."); + return _getOneBedTask; + } if (!mod.getItemStorage().hasItem(ItemHelper.BED)) { - if (mod.getBlockTracker().anyFound(blockPos -> WorldHelper.canBreak(mod, blockPos), ItemHelper.itemsToBlocks(ItemHelper.BED)) - || shouldForce(mod, _getOneBedTask)) { - setDebugState("Getting one bed to sleep in at night."); - return _getOneBedTask; + Block[] bedBlocks = ItemHelper.itemsToBlocks(ItemHelper.BED); + for (Block bedBlock : bedBlocks) { + if (mod.getBlockTracker().isTracking(bedBlock)) { + Optional nearestBed = mod.getBlockTracker().getNearestTracking(bedBlock); + if (nearestBed.isPresent() && WorldHelper.canBreak(mod, nearestBed.get())) { + boolean isValid = true; + for (Block CopperBlock : copperBlocks) { + Block blockBelow = mod.getWorld().getBlockState(nearestBed.get().down()).getBlock(); + if (blockBelow == CopperBlock) { + isValid = false; + break; + } + } + if (isValid) { + return _getOneBedTask; + } + } + } } } } @@ -964,17 +1395,11 @@ protected Task onTick(AltoClef mod) { } getBedTask = getBedTask(mod); return getBedTask; - } else { - getBedTask = null; } + getBedTask = null; } // Do we need more eyes? - boolean noEyesPlease = (endPortalOpened(mod, _endPortalCenterLocation) || WorldHelper.getCurrentDimension() == Dimension.END); - int filledPortalFrames = getFilledPortalFrames(mod, _endPortalCenterLocation); - int eyesNeededMin = noEyesPlease ? 0 : _config.minimumEyes - filledPortalFrames; - int eyesNeeded = noEyesPlease ? 0 : _config.targetEyes - filledPortalFrames; - int eyes = mod.getItemStorage().getItemCount(Items.ENDER_EYE); if (eyes < eyesNeededMin || (!_ranStrongholdLocator && _collectingEyes && eyes < eyesNeeded)) { _collectingEyes = true; _weHaveEyes = false; @@ -987,38 +1412,34 @@ protected Task onTick(AltoClef mod) { // We have eyes. Locate our portal + enter. switch (WorldHelper.getCurrentDimension()) { case OVERWORLD -> { - if (mod.getItemStorage().hasItem(Items.DIAMOND_PICKAXE)) { + if (mod.getItemStorage().hasItem(Items.DIAMOND_PICKAXE) && !StorageHelper.isBigCraftingOpen() + && !StorageHelper.isFurnaceOpen() && !StorageHelper.isSmokerOpen() + && !StorageHelper.isBlastFurnaceOpen() && (mod.getItemStorage().hasItem(Items.FLINT_AND_STEEL) + || mod.getItemStorage().hasItem(Items.FIRE_CHARGE))) { Item[] throwGearItems = {Items.STONE_SWORD, Items.STONE_PICKAXE, Items.IRON_SWORD, Items.IRON_PICKAXE}; - List ironArmors = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, - COLLECT_IRON_ARMOR); - List throwGears = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, - throwGearItems); - if (!StorageHelper.isBigCraftingOpen() && !StorageHelper.isFurnaceOpen() && - !StorageHelper.isSmokerOpen() && !StorageHelper.isBlastFurnaceOpen() && - (mod.getItemStorage().hasItem(Items.FLINT_AND_STEEL) || - mod.getItemStorage().hasItem(Items.FIRE_CHARGE))) { - if (!throwGears.isEmpty()) { - for (Slot throwGear : throwGears) { - if (Slot.isCursor(throwGear)) { - if (!mod.getControllerExtras().isBreakingBlock()) { - LookHelper.randomOrientation(mod); - } - mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); - } else { - mod.getSlotHandler().clickSlot(throwGear, 0, SlotActionType.PICKUP); + List throwGearSlot = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, throwGearItems); + if (!throwGearSlot.isEmpty()) { + for (Slot slot : throwGearSlot) { + if (Slot.isCursor(slot)) { + if (!mod.getControllerExtras().isBreakingBlock()) { + LookHelper.randomOrientation(mod); } + mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); + } else { + mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP); } } - if (!ironArmors.isEmpty()) { - for (Slot ironArmor : ironArmors) { - if (Slot.isCursor(ironArmor)) { - if (!mod.getControllerExtras().isBreakingBlock()) { - LookHelper.randomOrientation(mod); - } - mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); - } else { - mod.getSlotHandler().clickSlot(ironArmor, 0, SlotActionType.PICKUP); + } + List ironArmorSlot = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, COLLECT_IRON_ARMOR); + if (!ironArmorSlot.isEmpty()) { + for (Slot slot : ironArmorSlot) { + if (Slot.isCursor(slot)) { + if (!mod.getControllerExtras().isBreakingBlock()) { + LookHelper.randomOrientation(mod); } + mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); + } else { + mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP); } } } @@ -1026,7 +1447,8 @@ protected Task onTick(AltoClef mod) { // If we found our end portal... if (endPortalFound(mod, _endPortalCenterLocation)) { // Destroy silverfish spawner - if (StorageHelper.miningRequirementMetInventory(mod, MiningRequirement.WOOD)) { + if (StorageHelper.miningRequirementMetInventory(mod, MiningRequirement.WOOD) + && mod.getBlockTracker().isTracking(Blocks.SPAWNER)) { Optional silverfish = mod.getBlockTracker().getNearestTracking(blockPos -> { return WorldHelper.getSpawnerEntity(mod, blockPos) instanceof SilverfishEntity; }, Blocks.SPAWNER); @@ -1036,6 +1458,7 @@ protected Task onTick(AltoClef mod) { } } if (endPortalOpened(mod, _endPortalCenterLocation)) { + openingEndPortal = false; if (needsBuildingMaterials(mod)) { setDebugState("Collecting building materials."); return _buildMaterialsTask; @@ -1048,7 +1471,7 @@ protected Task onTick(AltoClef mod) { } // We're as ready as we'll ever be, hop into the portal! setDebugState("Entering End"); - _enterindEndPortal = true; + enteringEndPortal = true; if (!mod.getExtraBaritoneSettings().isCanWalkOnEndPortal()) { mod.getExtraBaritoneSettings().canWalkOnEndPortal(true); } @@ -1059,6 +1482,7 @@ protected Task onTick(AltoClef mod) { } else { // Open the portal! (we have enough eyes, do it) setDebugState("Opening End Portal"); + openingEndPortal = true; return new DoToClosestBlockTask( blockPos -> new InteractWithBlockTask(Items.ENDER_EYE, blockPos), blockPos -> !isEndPortalFrameFilled(mod, blockPos), @@ -1081,9 +1505,8 @@ protected Task onTick(AltoClef mod) { } getBedTask = getBedTask(mod); return getBedTask; - } else { - getBedTask = null; } + getBedTask = null; if (!mod.getItemStorage().hasItem(Items.WATER_BUCKET)) { setDebugState("Getting water bucket."); return TaskCatalogue.getItemTask(Items.WATER_BUCKET, 1); @@ -1102,36 +1525,33 @@ protected Task onTick(AltoClef mod) { } } case NETHER -> { - Item[] throwGearItems = {Items.STONE_SWORD, Items.STONE_PICKAXE, Items.IRON_SWORD, Items.IRON_PICKAXE}; - List ironArmors = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, - COLLECT_IRON_ARMOR); - List throwGears = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, - throwGearItems); - if (!StorageHelper.isBigCraftingOpen() && !StorageHelper.isFurnaceOpen() && - !StorageHelper.isSmokerOpen() && !StorageHelper.isBlastFurnaceOpen() && - (mod.getItemStorage().hasItem(Items.FLINT_AND_STEEL) || - mod.getItemStorage().hasItem(Items.FIRE_CHARGE))) { - if (!throwGears.isEmpty()) { - for (Slot throwGear : throwGears) { - if (Slot.isCursor(throwGear)) { + if (!StorageHelper.isBigCraftingOpen() && !StorageHelper.isFurnaceOpen() && !StorageHelper.isSmokerOpen() + && !StorageHelper.isBlastFurnaceOpen() && (mod.getItemStorage().hasItem(Items.FLINT_AND_STEEL) + || mod.getItemStorage().hasItem(Items.FIRE_CHARGE))) { + Item[] throwGearItems = {Items.STONE_SWORD, Items.STONE_PICKAXE, Items.IRON_SWORD, Items.IRON_PICKAXE}; + List throwGearSlot = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, throwGearItems); + if (!throwGearSlot.isEmpty()) { + for (Slot slot : throwGearSlot) { + if (Slot.isCursor(slot)) { if (!mod.getControllerExtras().isBreakingBlock()) { LookHelper.randomOrientation(mod); } mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); } else { - mod.getSlotHandler().clickSlot(throwGear, 0, SlotActionType.PICKUP); + mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP); } } } - if (!ironArmors.isEmpty()) { - for (Slot ironArmor : ironArmors) { - if (Slot.isCursor(ironArmor)) { + List ironArmorSlot = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, COLLECT_IRON_ARMOR); + if (!ironArmorSlot.isEmpty()) { + for (Slot slot : ironArmorSlot) { + if (Slot.isCursor(slot)) { if (!mod.getControllerExtras().isBreakingBlock()) { LookHelper.randomOrientation(mod); } mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); } else { - mod.getSlotHandler().clickSlot(ironArmor, 0, SlotActionType.PICKUP); + mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP); } } } @@ -1144,18 +1564,27 @@ protected Task onTick(AltoClef mod) { return null; } + /** + * Sets the spawn point near the portal. + * + * @param mod the AltoClef mod + * @return the task for setting the spawn point near the portal + */ private Task setSpawnNearPortalTask(AltoClef mod) { + // Check if bed spawn is set if (_setBedSpawnTask.isSpawnSet()) { _bedSpawnLocation = _setBedSpawnTask.getBedSleptPos(); } else { _bedSpawnLocation = null; } + + // Check if spawn should be forced if (shouldForce(mod, _setBedSpawnTask)) { - // Set spawnpoint and set our bed spawn when it happens. setDebugState("Setting spawnpoint now."); return _setBedSpawnTask; } - // Get close to portal. If we're close enough, set our bed spawn somewhere nearby. + + // Check if player is near the end portal if (WorldHelper.inRangeXZ(mod.getPlayer(), WorldHelper.toVec3d(_endPortalCenterLocation), END_PORTAL_BED_SPAWN_RANGE)) { return _setBedSpawnTask; } else { @@ -1164,128 +1593,295 @@ private Task setSpawnNearPortalTask(AltoClef mod) { } } + /** + * Retrieves a task related to collecting blaze rods. + * + * @param mod The AltoClef mod instance + * @param count The count of blaze rods to collect + * @return The task related to collecting blaze rods + */ private Task getBlazeRodsTask(AltoClef mod, int count) { - isGettingBlazeRods = true; - if (mod.getEntityTracker().itemDropped(Items.BLAZE_ROD)) { + EntityTracker entityTracker = mod.getEntityTracker(); + + // Check if blaze rods are dropped, if so, pick them up + if (entityTracker.itemDropped(Items.BLAZE_ROD)) { return new PickupDroppedItemTask(Items.BLAZE_ROD, 1); - } - if (mod.getEntityTracker().itemDropped(Items.BLAZE_POWDER)) { + } else if (entityTracker.itemDropped(Items.BLAZE_POWDER)) { + // Check if blaze powder is dropped, if so, pick it up return new PickupDroppedItemTask(Items.BLAZE_POWDER, 1); + } else { + // If no blaze rods or powder is dropped, collect blaze rods + return new CollectBlazeRodsTask(count); } - return new CollectBlazeRodsTask(count); } + /** + * This method retrieves a task for obtaining Ender Pearls. + * @param mod the AltoClef mod instance + * @param count the number of Ender Pearls to obtain + * @return the task for obtaining Ender Pearls + */ private Task getEnderPearlTask(AltoClef mod, int count) { isGettingEnderPearls = true; + + // Check if we should force getting Twisting Vines. if (shouldForce(mod, getTwistingVines)) { - setDebugState("Getting twisting vines for MLG purposes."); return getTwistingVines; } + + // Check if Ender Pearls have been dropped as items. if (mod.getEntityTracker().itemDropped(Items.ENDER_PEARL)) { return new PickupDroppedItemTask(Items.ENDER_PEARL, 1); } + + // Check if we should barter Pearls instead of hunting Endermen. if (_config.barterPearlsInsteadOfEndermanHunt) { - // Equip golden boots before trading... - if (!StorageHelper.isArmorEquipped(mod, Items.GOLDEN_BOOTS)) { - return new EquipArmorTask(Items.GOLDEN_BOOTS); + // Check if Golden Helmet is not equipped, and equip it. + if (!StorageHelper.isArmorEquipped(mod, Items.GOLDEN_HELMET)) { + return new EquipArmorTask(Items.GOLDEN_HELMET); } + // Trade with Piglins for Ender Pearls. return new TradeWithPiglinsTask(32, Items.ENDER_PEARL, count); - } else { - if ((mod.getEntityTracker().entityFound(EndermanEntity.class) || - mod.getEntityTracker().itemDropped(Items.ENDER_PEARL)) && - mod.getItemStorage().getItemCount(Items.TWISTING_VINES) > 14) { - Optional toKill = mod.getEntityTracker().getClosestEntity(EndermanEntity.class); - if (toKill.isPresent()) { - if (mod.getEntityTracker().isEntityReachable(toKill.get())) { - return new KillAndLootTask(toKill.get().getClass(), new ItemTarget(Items.ENDER_PEARL, count)); - } - } + } + + boolean endermanFound = mod.getEntityTracker().entityFound(EndermanEntity.class); + boolean pearlDropped = mod.getEntityTracker().itemDropped(Items.ENDER_PEARL); + boolean hasTwistingVines = mod.getItemStorage().getItemCount(Items.TWISTING_VINES) > TWISTING_VINES_COUNT_MIN; + + // Check if we have found an Enderman or Ender Pearl and have enough Twisting Vines. + if ((endermanFound || pearlDropped) && hasTwistingVines) { + Optional toKill = mod.getEntityTracker().getClosestEntity(EndermanEntity.class); + if (toKill.isPresent()) { + return new KillEndermanTask(count); } - if (mod.getItemStorage().getItemCount(Items.TWISTING_VINES) < 14) { - getTwistingVines = TaskCatalogue.getItemTask(Items.TWISTING_VINES, 28); + } + + boolean hasEnoughTwistingVines = mod.getItemStorage().getItemCount(Items.TWISTING_VINES) >= TWISTING_VINES_COUNT_MIN; + + // Check if we need to obtain more Twisting Vines. + if (!hasEnoughTwistingVines) { + BlockTracker blockTracker = mod.getBlockTracker(); + if (!blockTracker.isTracking(Blocks.TWISTING_VINES) || !blockTracker.isTracking(Blocks.TWISTING_VINES_PLANT)) { + blockTracker.trackBlock(Blocks.TWISTING_VINES, Blocks.TWISTING_VINES_PLANT); + } + + boolean vinesFound = blockTracker.anyFound(Blocks.TWISTING_VINES, Blocks.TWISTING_VINES_PLANT); + if (vinesFound) { + getTwistingVines = TaskCatalogue.getItemTask(Items.TWISTING_VINES, TWISTING_VINES_COUNT); return getTwistingVines; } - // Search for warped forests this way... - setDebugState("Searching Warped Forest"); - return new SearchWithinBiomeTask(BiomeKeys.WARPED_FOREST); + return new SearchChunkForBlockTask(Blocks.TWISTING_VINES, Blocks.TWISTING_VINES_PLANT, Blocks.WARPED_HYPHAE, Blocks.WARPED_NYLIUM); } + + // Search for Ender Pearls within the warped forest biome. + return new SearchWithinBiomeTask(BiomeKeys.WARPED_FOREST); } + /** + * Calculates the target number of beds based on the current configuration and the number of beds in the end. + * + * @param mod The AltoClef instance. + * @return The target number of beds. + */ private int getTargetBeds(AltoClef mod) { - boolean needsToSetSpawn = _config.placeSpawnNearEndPortal && - ( - !spawnSetNearPortal(mod, _endPortalCenterLocation) - && !shouldForce(mod, _setBedSpawnTask) - ); + // Calculate the number of beds in the end int bedsInEnd = 0; for (Item bed : ItemHelper.BED) { bedsInEnd += _cachedEndItemDrops.getOrDefault(bed, 0); } - - return _config.requiredBeds + (needsToSetSpawn ? 1 : 0) - bedsInEnd; + // Calculate the target number of beds + int targetBeds = _config.requiredBeds; + if (_config.placeSpawnNearEndPortal) { + // Check if the spawn should be set near the end portal + if (!spawnSetNearPortal(mod, _endPortalCenterLocation) && !shouldForce(mod, _setBedSpawnTask)) { + targetBeds += 1; // Add 1 bed if the spawn should be set near the end portal + } + } + targetBeds -= bedsInEnd; // Subtract the number of beds already in the end + return targetBeds; } + + /** + * Check if the given AltoClef mod needs more beds based on the item count and cached end item drops. + * + * @param mod The AltoClef mod to check. + * @return True if more beds are needed, false otherwise. + */ private boolean needsBeds(AltoClef mod) { - int inEnd = 0; - for (Item item : ItemHelper.BED) { - inEnd += _cachedEndItemDrops.getOrDefault(item, 0); + // Calculate the total end items dropped + int totalEndItems = 0; + for (Item bed : ItemHelper.BED) { + totalEndItems += _cachedEndItemDrops.getOrDefault(bed, 0); } - return (mod.getItemStorage().getItemCount(ItemHelper.BED) + inEnd) < getTargetBeds(mod); + + // Get the current count of beds in the item storage + int itemCount = mod.getItemStorage().getItemCount(ItemHelper.BED); + + // Get the target number of beds needed + int targetBeds = getTargetBeds(mod); + + // Check if more beds are needed + return (itemCount + totalEndItems) < targetBeds; } + /** + * Get the task related to obtaining beds. + * + * @param mod The AltoClef instance + * @return The task related to obtaining beds + */ private Task getBedTask(AltoClef mod) { + // Get the target number of beds int targetBeds = getTargetBeds(mod); - // Collect beds. If we want to set our spawn, collect 1 more. + + // Check if shears are not available and no beds are found if (!mod.getItemStorage().hasItem(Items.SHEARS) && !anyBedsFound(mod)) { + // Return the task to obtain shears return TaskCatalogue.getItemTask(Items.SHEARS, 1); } + Block[] copperBlocks = ItemHelper.itemsToBlocks(ItemHelper.COPPER_BLOCKS); + Block[] beds = ItemHelper.itemsToBlocks(ItemHelper.BED); + for (Block bed : beds) { + if (mod.getBlockTracker().isTracking(bed)) { + Optional nearestBed = mod.getBlockTracker().getNearestTracking(bed); + if (nearestBed.isPresent() && WorldHelper.canBreak(mod, nearestBed.get())) { + for (Block CopperBlock : copperBlocks) { + Block blockBelow = mod.getWorld().getBlockState(nearestBed.get().down()).getBlock(); + if (blockBelow == CopperBlock) { + Debug.logMessage("Blacklisting bed in trial chambers."); + mod.getBlockTracker().requestBlockUnreachable(nearestBed.get(), 0); + } + } + } + } + } + // Return the task to obtain the target number of beds return TaskCatalogue.getItemTask("bed", targetBeds); } + /** + * Checks if any beds are found in the world. + * + * @param mod The AltoClef mod instance + * @return true if beds are found either in blocks or entities + */ private boolean anyBedsFound(AltoClef mod) { - return mod.getBlockTracker().anyFound(ItemHelper.itemsToBlocks(ItemHelper.BED)) || - mod.getEntityTracker().itemDropped(ItemHelper.BED); + // Get the block and entity trackers from the mod instance. + BlockTracker blockTracker = mod.getBlockTracker(); + EntityTracker entityTracker = mod.getEntityTracker(); + + // Check if the beds are not in the trial chamber. + boolean validBedsFoundInBlocks = false; + Block[] copperBlocks = ItemHelper.itemsToBlocks(ItemHelper.COPPER_BLOCKS); + Block[] beds = ItemHelper.itemsToBlocks(ItemHelper.BED); + for (Block bed : beds) { + if (mod.getBlockTracker().isTracking(bed)) { + Optional nearestBed = blockTracker.getNearestTracking(bed); + if (nearestBed.isPresent() && WorldHelper.canBreak(mod, nearestBed.get())) { + validBedsFoundInBlocks = true; + for (Block CopperBlock : copperBlocks) { + Block blockBelow = mod.getWorld().getBlockState(nearestBed.get().down()).getBlock(); + if (blockBelow == CopperBlock) { + validBedsFoundInBlocks = false; + break; + } + } + } + } + } + + // Check if any beds are dropped by entities. + boolean bedsFoundInEntities = entityTracker.itemDropped(ItemHelper.BED); + // Return true if beds are found either in blocks or entities. + return validBedsFoundInBlocks || bedsFoundInEntities; } + /** + * Perform a simple search for the end portal. + *

+ * This method searches for the end portal frames in the world and calculates the average position of those frames. + * If the number of frames found is less than the constant END_PORTAL_FRAME_COUNT, it returns null. + * + * @param mod The AltoClef mod instance + * @return The average position of the end portal frames, or null if not found + */ private BlockPos doSimpleSearchForEndPortal(AltoClef mod) { + // Get the known locations of end portal frames List frames = mod.getBlockTracker().getKnownLocations(Blocks.END_PORTAL_FRAME); - if (frames.size() >= END_PORTAL_FRAME_COUNT) { - // Get the center of the frames. - Vec3i average = frames.stream() - .reduce(Vec3i.ZERO, (accum, bpos) -> accum.add((int) Math.round(bpos.getX() + 0.5), (int) Math.round(bpos.getY() + 0.5), (int) Math.round(bpos.getZ() + 0.5)), Vec3i::add) - .multiply(1 / frames.size()); - return new BlockPos(average); + // If the number of frames found is less than the constant END_PORTAL_FRAME_COUNT, return null + if (frames.size() < END_PORTAL_FRAME_COUNT) { + return null; } - return null; + // Calculate the sum of the x, y, and z coordinates of the frames + int sumX = 0, sumY = 0, sumZ = 0; + for (BlockPos frame : frames) { + sumX += frame.getX(); + sumY += frame.getY(); + sumZ += frame.getZ(); + } + // Calculate the average position of the frames + return new BlockPos(sumX / frames.size(), sumY / frames.size(), sumZ / frames.size()); } + + + /** + * Counts the number of filled portal frames around the end portal center. + * + * @param mod The AltoClef mod instance. + * @param endPortalCenter The center of the end portal. + * @return The count of filled portal frames, or 0 if the end portal is not found or the frame blocks are not loaded. + */ private int getFilledPortalFrames(AltoClef mod, BlockPos endPortalCenter) { - // If we have our end portal, this doesn't matter. - if (endPortalFound(mod, endPortalCenter)) { - return END_PORTAL_FRAME_COUNT; - } - if (endPortalFound(mod, endPortalCenter)) { - List frameBlocks = getFrameBlocks(endPortalCenter); - // If EVERY portal frame is loaded, consider updating our cached filled portal count. - if (frameBlocks.stream().allMatch(blockPos -> mod.getChunkTracker().isChunkLoaded(blockPos))) { - _cachedFilledPortalFrames = frameBlocks.stream().reduce(0, (count, blockPos) -> - count + (isEndPortalFrameFilled(mod, blockPos) ? 1 : 0), - Integer::sum); + // Check if the end portal is found + if (!endPortalFound(mod, endPortalCenter)) { + return 0; + } + int filledFramesCount = 0; + // Iterate over each frame block + for (BlockPos frame : getFrameBlocks(endPortalCenter)) { + // Check if the frame block is loaded and filled + if (mod.getChunkTracker().isChunkLoaded(frame) && isEndPortalFrameFilled(mod, frame)) { + filledFramesCount++; } - return _cachedFilledPortalFrames; } - return 0; + return filledFramesCount; } + + /** + * Checks if a chest at the specified position can be looted from a portal + * @param mod The game mod + * @param blockPos The position of the chest + * @return true if the chest is lootable, false otherwise + */ private boolean canBeLootablePortalChest(AltoClef mod, BlockPos blockPos) { - if (mod.getWorld().getBlockState(blockPos.up(1)).getBlock() == Blocks.WATER || blockPos.getY() < 50) { + // Check if the chest is under water or below y level 50 + if (mod.getWorld().getBlockState(blockPos.up()).getBlock() == Blocks.WATER || + blockPos.getY() < 50) { return false; } - for (BlockPos check : WorldHelper.scanRegion(mod, blockPos.add(-4, -2, -4), blockPos.add(4, 2, 4))) { - if (mod.getWorld().getBlockState(check).getBlock() == Blocks.NETHERRACK) { - return true; + + // Define the minimum and maximum positions for scanning + BlockPos minPos = blockPos.add(-4, -2, -4); + BlockPos maxPos = blockPos.add(4, 2, 4); + + try { + // Scan the region around the chest + for (BlockPos checkPos : WorldHelper.scanRegion(mod, minPos, maxPos)) { + // Check if the chest is on netherrack + if (mod.getWorld().getBlockState(checkPos).getBlock() == Blocks.NETHERRACK) { + return true; + } } + } catch (Exception e) { + e.printStackTrace(); + // Handle the exception or log it as needed } + + // Add the chest to the list of non-ruined portal chests _notRuinedPortalChests.add(blockPos); + return false; } @@ -1326,67 +1922,65 @@ private Task getEyesOfEnderTask(AltoClef mod, int targetEyes) { if (_config.renderDistanceManipulation) { if (!mod.getClientBaritone().getExploreProcess().isActive()) { if (_timer1.elapsed()) { - MinecraftClient.getInstance().options.getViewDistance().setValue(2); - MinecraftClient.getInstance().options.getEntityDistanceScaling().setValue(0.5); + getInstance().options.getViewDistance().setValue(2); + getInstance().options.getEntityDistanceScaling().setValue(0.5); _timer1.reset(); } } } getBedTask = getBedTask(mod); return getBedTask; - } else { - getBedTask = null; } + getBedTask = null; if (shouldForce(mod, _logsTask)) { setDebugState("Getting logs for later."); return _logsTask; - } else { - _logsTask = null; } + _logsTask = null; if (shouldForce(mod, _stoneGearTask)) { setDebugState("Getting stone gear for later."); return _stoneGearTask; - } else { - _stoneGearTask = null; } + _stoneGearTask = null; if (shouldForce(mod, _getPorkchopTask)) { - setDebugState("Getting porkchop just for fun."); + setDebugState("Getting pork chop just for fun."); if (_config.renderDistanceManipulation) { if (!mod.getClientBaritone().getExploreProcess().isActive()) { - MinecraftClient.getInstance().options.getViewDistance().setValue(32); - MinecraftClient.getInstance().options.getEntityDistanceScaling().setValue(5.0); + getInstance().options.getViewDistance().setValue(32); + getInstance().options.getEntityDistanceScaling().setValue(5.0); } } return _getPorkchopTask; - } else { - _getPorkchopTask = null; } + _getPorkchopTask = null; if (shouldForce(mod, _starterGearTask)) { setDebugState("Getting starter gear."); return _starterGearTask; - } else { - _starterGearTask = null; } + _starterGearTask = null; + if (shouldForce(mod, _shieldTask) && !StorageHelper.isArmorEquipped(mod, COLLECT_SHIELD)) { + setDebugState("Getting shield for defense purposes only."); + return _shieldTask; + } + _shieldTask = null; if (shouldForce(mod, _foodTask)) { setDebugState("Getting food for ender eye journey."); return _foodTask; - } else { - _foodTask = null; } + _foodTask = null; if (shouldForce(mod, _smeltTask)) { if (_config.renderDistanceManipulation) { if (!mod.getClientBaritone().getExploreProcess().isActive()) { if (_timer1.elapsed()) { - MinecraftClient.getInstance().options.getViewDistance().setValue(2); - MinecraftClient.getInstance().options.getEntityDistanceScaling().setValue(0.5); + getInstance().options.getViewDistance().setValue(2); + getInstance().options.getEntityDistanceScaling().setValue(0.5); _timer1.reset(); } } } return _smeltTask; - } else { - _smeltTask = null; } + _smeltTask = null; // Smelt remaining raw food if (_config.alwaysCookRawFood) { for (Item raw : ItemHelper.RAW_FOODS) { @@ -1398,146 +1992,134 @@ private Task getEyesOfEnderTask(AltoClef mod, int targetEyes) { _smeltTask = new SmeltInSmokerTask(new SmeltTarget(new ItemTarget(cooked.get(), targetCount), new ItemTarget(raw, targetCount))); return _smeltTask; } - } else { - _smeltTask = null; } } } + _smeltTask = null; // Make sure we have gear, then food. if (shouldForce(mod, _lootTask)) { setDebugState("Looting chest for goodies"); return _lootTask; } - if (shouldForce(mod, _shieldTask) && !StorageHelper.isArmorEquipped(mod, COLLECT_SHIELD)) { - setDebugState("Getting shield for defense purposes only."); - return _shieldTask; - } else { - _shieldTask = null; - } + _lootTask = null; if (shouldForce(mod, _ironGearTask) && !StorageHelper.isArmorEquipped(mod, COLLECT_IRON_ARMOR)) { setDebugState("Getting iron gear before diamond gear for defense purposes only."); return _ironGearTask; - } else { - _ironGearTask = null; } + _ironGearTask = null; if (shouldForce(mod, _gearTask) && !StorageHelper.isArmorEquipped(mod, COLLECT_EYE_ARMOR)) { setDebugState("Getting diamond gear for ender eye journey."); return _gearTask; - } else { - _gearTask = null; } + _gearTask = null; boolean eyeGearSatisfied = StorageHelper.itemTargetsMet(mod, COLLECT_EYE_GEAR_MIN) && StorageHelper.isArmorEquippedAll(mod, COLLECT_EYE_ARMOR); boolean ironGearSatisfied = StorageHelper.itemTargetsMet(mod, COLLECT_IRON_GEAR_MIN) && StorageHelper.isArmorEquippedAll(mod, COLLECT_IRON_ARMOR); boolean shieldSatisfied = StorageHelper.isArmorEquipped(mod, COLLECT_SHIELD); - // Search for a better place - if (!mod.getItemStorage().hasItem(Items.PORKCHOP) && - !mod.getItemStorage().hasItem(Items.COOKED_PORKCHOP) && - !StorageHelper.itemTargetsMet(mod, IRON_GEAR_MIN) && !ironGearSatisfied && !eyeGearSatisfied) { - if (mod.getItemStorage().getItemCount(ItemHelper.LOG) < 12 && !StorageHelper.itemTargetsMet(mod, COLLECT_STONE_GEAR) && - !StorageHelper.itemTargetsMet(mod, IRON_GEAR_MIN) && !eyeGearSatisfied && - !ironGearSatisfied) { - _logsTask = TaskCatalogue.getItemTask("log", 18); - return _logsTask; - } else { - _logsTask = null; - } - if (!StorageHelper.itemTargetsMet(mod, COLLECT_STONE_GEAR) && - !StorageHelper.itemTargetsMet(mod, IRON_GEAR_MIN) && !eyeGearSatisfied && - !ironGearSatisfied) { - if (mod.getItemStorage().getItemCount(Items.STICK) < 7) { - _stoneGearTask = TaskCatalogue.getItemTask(Items.STICK, 15); + if (!isEquippingDiamondArmor) { + // Search for a better place + if (!mod.getItemStorage().hasItem(Items.PORKCHOP) && + !mod.getItemStorage().hasItem(Items.COOKED_PORKCHOP) && + !StorageHelper.itemTargetsMet(mod, IRON_GEAR_MIN) && !ironGearSatisfied && !eyeGearSatisfied) { + if (mod.getItemStorage().getItemCount(ItemHelper.LOG) < 12 + && mod.getItemStorage().getItemCount(ItemHelper.PLANKS) < 12 * 4 + && !StorageHelper.itemTargetsMet(mod, COLLECT_STONE_GEAR) + && !StorageHelper.itemTargetsMet(mod, IRON_GEAR_MIN) && !eyeGearSatisfied && !ironGearSatisfied) { + _logsTask = TaskCatalogue.getItemTask("log", 18); + return _logsTask; + } + if (!StorageHelper.itemTargetsMet(mod, COLLECT_STONE_GEAR) && + !StorageHelper.itemTargetsMet(mod, IRON_GEAR_MIN) && !eyeGearSatisfied && + !ironGearSatisfied) { + if (mod.getItemStorage().getItemCount(Items.STICK) < 7) { + _stoneGearTask = TaskCatalogue.getItemTask(Items.STICK, 15); + return _stoneGearTask; + } + _stoneGearTask = TaskCatalogue.getSquashedItemTask(COLLECT_STONE_GEAR); return _stoneGearTask; } - _stoneGearTask = TaskCatalogue.getSquashedItemTask(COLLECT_STONE_GEAR); - return _stoneGearTask; - } else { - _stoneGearTask = null; + if (mod.getEntityTracker().entityFound(PigEntity.class) && (StorageHelper.itemTargetsMet(mod, + COLLECT_STONE_GEAR) || StorageHelper.itemTargetsMet(mod, IRON_GEAR_MIN) || + eyeGearSatisfied || ironGearSatisfied)) { + Predicate notBaby = entity -> entity instanceof LivingEntity livingEntity && !livingEntity.isBaby(); + _getPorkchopTask = new KillAndLootTask(PigEntity.class, notBaby, new ItemTarget(Items.PORKCHOP, 1)); + return _getPorkchopTask; + } + setDebugState("Searching a better place to start with."); + if (_config.renderDistanceManipulation) { + if (!mod.getClientBaritone().getExploreProcess().isActive()) { + if (_timer1.elapsed()) { + getInstance().options.getViewDistance().setValue(32); + getInstance().options.getEntityDistanceScaling().setValue(5.0); + _timer1.reset(); + } + } + } + searchBiomeTask = new SearchWithinBiomeTask(BiomeKeys.PLAINS); + return searchBiomeTask; } - if (mod.getEntityTracker().entityFound(PigEntity.class) && (StorageHelper.itemTargetsMet(mod, - COLLECT_STONE_GEAR) || StorageHelper.itemTargetsMet(mod, IRON_GEAR_MIN) || - eyeGearSatisfied || ironGearSatisfied)) { - _getPorkchopTask = new KillAndLootTask(PigEntity.class, new - ItemTarget(Items.PORKCHOP, 1)); - return _getPorkchopTask; - } else { - _getPorkchopTask = null; + // Then get one bed + if (!mod.getItemStorage().hasItem(ItemHelper.BED) && _config.sleepThroughNight) { + return _getOneBedTask; } - setDebugState("Searching a better place to start with."); - if (_config.renderDistanceManipulation) { - if (!mod.getClientBaritone().getExploreProcess().isActive()) { - if (_timer1.elapsed()) { - MinecraftClient.getInstance().options.getViewDistance().setValue(32); - MinecraftClient.getInstance().options.getEntityDistanceScaling().setValue(5.0); - _timer1.reset(); - } + // Then starter gear + if (!StorageHelper.itemTargetsMet(mod, IRON_GEAR_MIN) && !eyeGearSatisfied && + !ironGearSatisfied && !StorageHelper.isArmorEquipped(mod, Items.SHIELD)) { + _starterGearTask = TaskCatalogue.getSquashedItemTask(IRON_GEAR); + return _starterGearTask; + } + // Then get shield + if (_config.getShield && !shieldSatisfied && !mod.getFoodChain().needsToEat()) { + ItemTarget shield = new ItemTarget(COLLECT_SHIELD); + if (mod.getItemStorage().hasItem(shield) && !StorageHelper.isArmorEquipped(mod, COLLECT_SHIELD)) { + setDebugState("Equipping shield."); + return new EquipArmorTask(COLLECT_SHIELD); } + _shieldTask = TaskCatalogue.getItemTask(shield); + return _shieldTask; } - searchBiomeTask = new SearchWithinBiomeTask(BiomeKeys.PLAINS); - return searchBiomeTask; - } else { - searchBiomeTask = null; - } - // Then get one bed - if (!mod.getItemStorage().hasItem(ItemHelper.BED) && _config.sleepThroughNight) { - return _getOneBedTask; - } - // Then starter gear - if (!StorageHelper.itemTargetsMet(mod, IRON_GEAR_MIN) && !eyeGearSatisfied && - !ironGearSatisfied) { - _starterGearTask = TaskCatalogue.getSquashedItemTask(IRON_GEAR); - return _starterGearTask; - } else { - _starterGearTask = null; - } - // Then get food - if (StorageHelper.calculateInventoryFoodScore(mod) < _config.minFoodUnits) { - _foodTask = new CollectFoodTask(_config.foodUnits); - return _foodTask; - } else { - _foodTask = null; - } - // Then loot chest if there is any - if (_config.searchRuinedPortals) { - // Check for ruined portals - Optional chest = locateClosestUnopenedRuinedPortalChest(mod); - if (chest.isPresent()) { - _lootTask = new LootContainerTask(chest.get(), lootableItems(mod), _noCurseOfBinding); - return _lootTask; + // Then get food + if (StorageHelper.calculateInventoryFoodScore(mod) < _config.minFoodUnits) { + _foodTask = new CollectFoodTask(_config.foodUnits); + return _foodTask; } - } - if (_config.searchDesertTemples && StorageHelper.miningRequirementMetInventory(mod, MiningRequirement.WOOD)) { - // Check for desert temples - BlockPos temple = WorldHelper.getADesertTemple(mod); - if (temple != null) { - _lootTask = new LootDesertTempleTask(temple, lootableItems(mod)); - return _lootTask; + // Then loot chest if there is any + if (_config.searchRuinedPortals) { + // Check for ruined portals + Optional chest = locateClosestUnopenedRuinedPortalChest(mod); + if (chest.isPresent()) { + _lootTask = new LootContainerTask(chest.get(), lootableItems(mod), _noCurseOfBinding); + return _lootTask; + } } - } - // Then get shield - if (_config.getShield && !shieldSatisfied && !mod.getFoodChain().needsToEat()) { - ItemTarget shield = new ItemTarget(COLLECT_SHIELD); - if (mod.getItemStorage().hasItem(shield) && !StorageHelper.isArmorEquipped(mod, COLLECT_SHIELD)) { - setDebugState("Equipping shield."); - return new EquipArmorTask(COLLECT_SHIELD); + if (_config.searchDesertTemples && StorageHelper.miningRequirementMetInventory(mod, MiningRequirement.WOOD)) { + // Check for desert temples + BlockPos temple = WorldHelper.getADesertTemple(mod); + if (temple != null) { + _lootTask = new LootDesertTempleTask(temple, lootableItems(mod)); + return _lootTask; + } } - _shieldTask = TaskCatalogue.getItemTask(shield); - return _shieldTask; - } else { - _shieldTask = null; - } - // Then get iron - if (_config.ironGearBeforeDiamondGear && !ironGearSatisfied && !eyeGearSatisfied && - !_isEquippingDiamondArmor) { - for (Item iron : COLLECT_IRON_ARMOR) { - if (mod.getItemStorage().hasItem(iron) && !StorageHelper.isArmorEquipped(mod, iron)) { - setDebugState("Equipping armor."); - return new EquipArmorTask(COLLECT_IRON_ARMOR); + // Then get iron + if (_config.ironGearBeforeDiamondGear && !ironGearSatisfied && !eyeGearSatisfied) { + for (Item ironArmor : COLLECT_IRON_ARMOR) { + if (mod.getItemStorage().hasItem(ironArmor) && !StorageHelper.isArmorEquipped(mod, ironArmor)) { + setDebugState("Equipping armor."); + return new EquipArmorTask(ironArmor); + } + } + List ironGearsAndArmors = new ArrayList<>(); + for (ItemTarget ironGear : COLLECT_IRON_GEAR) { + ironGearsAndArmors.add(ironGear); + } + for (Item ironArmor : COLLECT_IRON_ARMOR) { + if (!mod.getItemStorage().hasItem(ironArmor) && !StorageHelper.isArmorEquipped(mod, ironArmor)) { + ironGearsAndArmors.add(new ItemTarget(ironArmor, 1)); + } } + _ironGearTask = TaskCatalogue.getSquashedItemTask(ironGearsAndArmors.toArray(ItemTarget[]::new)); + return _ironGearTask; } - _ironGearTask = TaskCatalogue.getSquashedItemTask(Stream.concat(Arrays.stream(COLLECT_IRON_ARMOR).filter(item -> !mod.getItemStorage().hasItem(item) && !StorageHelper.isArmorEquipped(mod, item)).map(item -> new ItemTarget(item, 1)), Arrays.stream(COLLECT_IRON_GEAR)).toArray(ItemTarget[]::new)); - return _ironGearTask; - } else { _ironGearTask = null; } // Then get diamond @@ -1545,44 +2127,50 @@ private Task getEyesOfEnderTask(AltoClef mod, int targetEyes) { for (Item diamond : COLLECT_EYE_ARMOR) { if (mod.getItemStorage().hasItem(diamond) && !StorageHelper.isArmorEquipped(mod, diamond)) { setDebugState("Equipping armor."); - _isEquippingDiamondArmor = true; - return new EquipArmorTask(COLLECT_EYE_ARMOR); + isEquippingDiamondArmor = true; + return new EquipArmorTask(diamond); + } + } + List diamondGearsAndArmors = new ArrayList<>(); + for (ItemTarget diamondGear : COLLECT_EYE_GEAR) { + diamondGearsAndArmors.add(diamondGear); + } + for (Item diamondArmor : COLLECT_EYE_ARMOR) { + if (!mod.getItemStorage().hasItem(diamondArmor) && !StorageHelper.isArmorEquipped(mod, diamondArmor)) { + diamondGearsAndArmors.add(new ItemTarget(diamondArmor, 1)); } } - _gearTask = TaskCatalogue.getSquashedItemTask(Stream.concat(Arrays.stream(COLLECT_EYE_ARMOR).filter(item -> !mod.getItemStorage().hasItem(item) && !StorageHelper.isArmorEquipped(mod, item)).map(item -> new ItemTarget(item, 1)), Arrays.stream(COLLECT_EYE_GEAR)).toArray(ItemTarget[]::new)); + _gearTask = TaskCatalogue.getSquashedItemTask(diamondGearsAndArmors.toArray(ItemTarget[]::new)); return _gearTask; } else { _gearTask = null; - Item[] throwGearItems = {Items.STONE_SWORD, Items.STONE_PICKAXE, Items.IRON_SWORD, Items.IRON_PICKAXE}; - List ironArmors = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, - COLLECT_IRON_ARMOR); - List throwGears = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, - throwGearItems); - if (!StorageHelper.isBigCraftingOpen() && !StorageHelper.isFurnaceOpen() && - !StorageHelper.isSmokerOpen() && !StorageHelper.isBlastFurnaceOpen() && - (mod.getItemStorage().hasItem(Items.FLINT_AND_STEEL) || - mod.getItemStorage().hasItem(Items.FIRE_CHARGE))) { - if (!throwGears.isEmpty()) { - for (Slot throwGear : throwGears) { - if (Slot.isCursor(throwGear)) { + if (!StorageHelper.isBigCraftingOpen() && !StorageHelper.isFurnaceOpen() && !StorageHelper.isSmokerOpen() + && !StorageHelper.isBlastFurnaceOpen() && (mod.getItemStorage().hasItem(Items.FLINT_AND_STEEL) + || mod.getItemStorage().hasItem(Items.FIRE_CHARGE))) { + Item[] throwGearItems = {Items.STONE_SWORD, Items.STONE_PICKAXE, Items.IRON_SWORD, Items.IRON_PICKAXE}; + List throwGearSlot = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, throwGearItems); + if (!throwGearSlot.isEmpty()) { + for (Slot slot : throwGearSlot) { + if (Slot.isCursor(slot)) { if (!mod.getControllerExtras().isBreakingBlock()) { LookHelper.randomOrientation(mod); } mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); } else { - mod.getSlotHandler().clickSlot(throwGear, 0, SlotActionType.PICKUP); + mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP); } } } - if (!ironArmors.isEmpty()) { - for (Slot ironArmor : ironArmors) { - if (Slot.isCursor(ironArmor)) { + List ironArmorSlot = mod.getItemStorage().getSlotsWithItemPlayerInventory(true, COLLECT_IRON_ARMOR); + if (!ironArmorSlot.isEmpty()) { + for (Slot slot : ironArmorSlot) { + if (Slot.isCursor(slot)) { if (!mod.getControllerExtras().isBreakingBlock()) { LookHelper.randomOrientation(mod); } mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); } else { - mod.getSlotHandler().clickSlot(ironArmor, 0, SlotActionType.PICKUP); + mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP); } } } @@ -1608,4 +2196,4 @@ private Task getEyesOfEnderTask(AltoClef mod, int targetEyes) { } return null; } -} \ No newline at end of file +} diff --git a/src/main/java/adris/altoclef/tasks/speedrun/WaitForDragonAndPearlTask.java b/src/main/java/adris/altoclef/tasks/speedrun/WaitForDragonAndPearlTask.java index e0014d263..280b61e50 100644 --- a/src/main/java/adris/altoclef/tasks/speedrun/WaitForDragonAndPearlTask.java +++ b/src/main/java/adris/altoclef/tasks/speedrun/WaitForDragonAndPearlTask.java @@ -4,10 +4,9 @@ import adris.altoclef.Debug; import adris.altoclef.TaskCatalogue; import adris.altoclef.tasks.entity.DoToClosestEntityTask; -import adris.altoclef.tasks.entity.KillEntitiesTask; +import adris.altoclef.tasks.movement.GetToBlockTask; import adris.altoclef.tasks.movement.GetToXZTask; import adris.altoclef.tasks.movement.GetToYTask; -import adris.altoclef.tasks.movement.RunAwayFromPositionTask; import adris.altoclef.tasks.movement.ThrowEnderPearlSimpleProjectileTask; import adris.altoclef.tasks.resources.GetBuildingMaterialsTask; import adris.altoclef.tasksystem.Task; @@ -18,7 +17,6 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.boss.dragon.EnderDragonEntity; import net.minecraft.entity.decoration.EndCrystalEntity; -import net.minecraft.entity.mob.EndermanEntity; import net.minecraft.entity.projectile.DragonFireballEntity; import net.minecraft.item.Items; import net.minecraft.util.math.BlockPos; @@ -42,6 +40,8 @@ public class WaitForDragonAndPearlTask extends Task implements IDragonWaiter { private static final int CLOSE_ENOUGH_DISTANCE = 15; + private final int Y_COORDINATE = 75; + private static final double DRAGON_FIREBALL_TOO_CLOSE_RANGE = 40; private final Task _buildingMaterialsTask = new GetBuildingMaterialsTask(HEIGHT + 10); boolean inCenter; @@ -52,6 +52,8 @@ public class WaitForDragonAndPearlTask extends Task implements IDragonWaiter { // To avoid dragons breath private Task _pillarUpFurther; + private boolean _hasPillar = false; + @Override public void setExitPortalTop(BlockPos top) { BlockPos actualTarget = top.down(); @@ -72,25 +74,26 @@ protected void onStart(AltoClef mod) { @Override protected Task onTick(AltoClef mod) { - Iterable entities = mod.getWorld().getEntities(); - if (entities != null) { - for (Entity entity : entities) { - if (entity instanceof EndermanEntity enderman) { - if (enderman.isAngryAt(mod.getPlayer()) && enderman.isAngry()) { - setDebugState("Kill angry enderman first."); - return new KillEntitiesTask(enderman.getClass()); - } - } - } - } if (_throwPearlTask != null && _throwPearlTask.isActive() && !_throwPearlTask.isFinished(mod)) { setDebugState("Throwing pearl!"); return _throwPearlTask; } - if (_pillarUpFurther != null && _pillarUpFurther.isActive() && !_pillarUpFurther.isFinished(mod)) { - setDebugState("PILLAR UP FURTHER to avoid dragon's breath"); - return _pillarUpFurther; + if (_pillarUpFurther != null && _pillarUpFurther.isActive() && !_pillarUpFurther.isFinished(mod) && (mod.getEntityTracker().getClosestEntity(AreaEffectCloudEntity.class).isPresent())) { + + Optional cloud = mod.getEntityTracker().getClosestEntity(AreaEffectCloudEntity.class); + + if (cloud.isPresent() && cloud.get().isInRange(mod.getPlayer(), 4)) { + setDebugState("PILLAR UP FURTHER to avoid dragon's breath"); + return _pillarUpFurther; + } + + Optional fireball = mod.getEntityTracker().getClosestEntity(DragonFireballEntity.class); + + if (isFireballDangerous(mod, fireball)) { + setDebugState("PILLAR UP FURTHER to avoid dragon's breath"); + return _pillarUpFurther; + } } if (!mod.getItemStorage().hasItem(Items.ENDER_PEARL) && inCenter) { @@ -121,6 +124,7 @@ protected Task onTick(AltoClef mod) { return null; } if (_heightPillarTask != null && _heightPillarTask.isActive() && !_heightPillarTask.isFinished(mod)) { + setDebugState("Pillaring up!"); inCenter = true; if (mod.getEntityTracker().entityFound(EndCrystalEntity.class)) { return new DoToClosestEntityTask( @@ -141,7 +145,6 @@ protected Task onTick(AltoClef mod) { EndCrystalEntity.class ); } - setDebugState("Pillaring up!"); return _heightPillarTask; } } else { @@ -178,19 +181,7 @@ protected Task onTick(AltoClef mod) { } return null; } - if (WorldHelper.inRangeXZ(mod.getPlayer(), _targetToPearl, XZ_RADIUS)) { - if (mod.getEntityTracker().entityFound(entity -> - mod.getPlayer().getPos().isInRange(entity.getPos(), 4), AreaEffectCloudEntity.class)) { - if (mod.getEntityTracker().getClosestEntity(EnderDragonEntity.class).isPresent() && - !mod.getClientBaritone().getPathingBehavior().isPathing()) { - LookHelper.lookAt(mod, mod.getEntityTracker().getClosestEntity(EnderDragonEntity.class).get().getEyePos()); - } - return null; - } - setDebugState("Moving away from center..."); - return new RunAwayFromPositionTask(XZ_RADIUS, _targetToPearl); - } - if (!WorldHelper.inRangeXZ(mod.getPlayer(), _targetToPearl, XZ_RADIUS_TOO_FAR)) { + if (!WorldHelper.inRangeXZ(mod.getPlayer(), _targetToPearl, XZ_RADIUS_TOO_FAR) && mod.getPlayer().getPos().getY() < minHeight && !_hasPillar) { if (mod.getEntityTracker().entityFound(entity -> mod.getPlayer().getPos().isInRange(entity.getPos(), 4), AreaEffectCloudEntity.class)) { if (mod.getEntityTracker().getClosestEntity(EnderDragonEntity.class).isPresent() && @@ -203,10 +194,23 @@ protected Task onTick(AltoClef mod) { return new GetToXZTask(0, 0); } // We're far enough, pillar up! - _heightPillarTask = new GetToYTask(minHeight); + if (!_hasPillar) { + _hasPillar = true; + } + _heightPillarTask = new GetToBlockTask(new BlockPos(0, minHeight, Y_COORDINATE)); return _heightPillarTask; } + private boolean isFireballDangerous(AltoClef mod, Optional fireball) { + if (!fireball.isPresent()) + return false; + + boolean fireballTooClose = fireball.get().isInRange(mod.getPlayer(), DRAGON_FIREBALL_TOO_CLOSE_RANGE); + boolean fireballInSight = LookHelper.cleanLineOfSight(mod.getPlayer(), fireball.get().getPos(), DRAGON_FIREBALL_TOO_CLOSE_RANGE); + + return fireballTooClose && fireballInSight; + } + @Override protected void onStop(AltoClef mod, Task interruptTask) { @@ -228,4 +232,4 @@ public boolean isFinished(AltoClef mod) { protected String toDebugString() { return "Waiting for Dragon Perch + Pearling"; } -} +} \ No newline at end of file diff --git a/src/main/java/adris/altoclef/tasks/stupid/BeeMovieTask.java b/src/main/java/adris/altoclef/tasks/stupid/BeeMovieTask.java index 72652ba80..c19e21a05 100644 --- a/src/main/java/adris/altoclef/tasks/stupid/BeeMovieTask.java +++ b/src/main/java/adris/altoclef/tasks/stupid/BeeMovieTask.java @@ -56,7 +56,7 @@ public BeeMovieTask(String uniqueId, BlockPos start, InputStreamReader input) { _textParser = new StreamedSignStringParser(input); _extraSignAcquireTask = new CataloguedResourceTask(new ItemTarget("sign", 256));//TaskCatalogue.getItemTask("sign", 32); - _structureMaterialsTask = new MineAndCollectTask(new ItemTarget(new Item[]{Items.DIRT, Items.COBBLESTONE}, STRUCTURE_MATERIALS_BUFFER), new Block[]{Blocks.STONE, Blocks.COBBLESTONE, Blocks.DIRT, Blocks.GRASS, Blocks.GRASS_BLOCK}, MiningRequirement.WOOD); + _structureMaterialsTask = new MineAndCollectTask(new ItemTarget(new Item[]{Items.DIRT, Items.COBBLESTONE}, STRUCTURE_MATERIALS_BUFFER), new Block[]{Blocks.STONE, Blocks.COBBLESTONE, Blocks.DIRT, Blocks.GRASS_BLOCK, Blocks.GRASS_BLOCK}, MiningRequirement.WOOD); } private static int sign(int num) { diff --git a/src/main/java/adris/altoclef/tasks/stupid/ReplaceBlocksTask.java b/src/main/java/adris/altoclef/tasks/stupid/ReplaceBlocksTask.java index baa6f5f6b..3626cca77 100644 --- a/src/main/java/adris/altoclef/tasks/stupid/ReplaceBlocksTask.java +++ b/src/main/java/adris/altoclef/tasks/stupid/ReplaceBlocksTask.java @@ -20,7 +20,7 @@ import java.util.ArrayDeque; import java.util.Arrays; import java.util.Deque; -import java.util.List; +import java.util.Optional; public class ReplaceBlocksTask extends Task { @@ -92,10 +92,14 @@ protected Task onTick(AltoClef mod) { // Get to replace item if (!mod.getItemStorage().hasItem(_toReplace.getMatches())) { - List locations = mod.getBlockTracker().getKnownLocations(_toFind); int need = 0; - if (!locations.isEmpty()) { - for (BlockPos loc : locations) if (isWithinRange(loc) && need < MAX_MATERIALS_NEEDED_AT_A_TIME) need++; + for (Block toFind : _toFind) { + if (mod.getBlockTracker().isTracking(toFind)) { + Optional location = mod.getBlockTracker().getNearestTracking(toFind); + if (location.isPresent() && isWithinRange(location.get()) && need < MAX_MATERIALS_NEEDED_AT_A_TIME) { + need++; + } + } } if (need == 0) { setDebugState("No replaceable blocks found, wandering."); @@ -112,7 +116,7 @@ protected Task onTick(AltoClef mod) { while (!_forceReplace.isEmpty()) { BlockPos toReplace = _forceReplace.pop(); if (!ArrayUtils.contains(blocksToPlace, mod.getWorld().getBlockState(toReplace).getBlock())) { - _replaceTask = new PlaceBlockTask(toReplace, blocksToPlace); + _replaceTask = new PlaceBlockTask(toReplace, blocksToPlace, false, true); return _replaceTask; } } @@ -120,7 +124,7 @@ protected Task onTick(AltoClef mod) { // Now replace setDebugState("Searching for blocks to replace..."); return new DoToClosestBlockTask(whereToPlace -> { - _replaceTask = new PlaceBlockTask(whereToPlace, blocksToPlace); + _replaceTask = new PlaceBlockTask(whereToPlace, blocksToPlace, false, true); return _replaceTask; }, this::isWithinRange, diff --git a/src/main/java/adris/altoclef/tasks/stupid/TerminatorTask.java b/src/main/java/adris/altoclef/tasks/stupid/TerminatorTask.java index 28183b381..057a39dc7 100644 --- a/src/main/java/adris/altoclef/tasks/stupid/TerminatorTask.java +++ b/src/main/java/adris/altoclef/tasks/stupid/TerminatorTask.java @@ -16,7 +16,6 @@ import adris.altoclef.ui.MessagePriority; import adris.altoclef.util.ItemTarget; import adris.altoclef.util.SmeltTarget; -import adris.altoclef.util.helpers.BaritoneHelper; import adris.altoclef.util.helpers.ItemHelper; import adris.altoclef.util.helpers.LookHelper; import adris.altoclef.util.helpers.StorageHelper; @@ -34,9 +33,6 @@ import java.util.List; import java.util.Optional; import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.Stream; /** * Roams around the world to terminate Sarah Khaannah @@ -126,12 +122,11 @@ protected Task onTick(AltoClef mod) { _runAwayExtraTime.reset(); try { - _runAwayTask = new RunAwayFromPlayersTask(() -> { - Stream stream = mod.getEntityTracker().getTrackedEntities(PlayerEntity.class).stream(); - synchronized (BaritoneHelper.MINECRAFT_LOCK) { - return stream.filter(toAccept -> shouldPunk(mod, toAccept)).collect(Collectors.toList()); - } - }, RUN_AWAY_DISTANCE); + Optional player = mod.getEntityTracker().getClosestEntity(PlayerEntity.class); + if (player.isPresent() && player.get() instanceof PlayerEntity playerEntity + && shouldPunk(mod, playerEntity)) { + _runAwayTask = new RunAwayFromPlayersTask(player.get(), RUN_AWAY_DISTANCE); + } } catch (ConcurrentModificationException e) { // oof Debug.logWarning("Duct tape over ConcurrentModificationException (see log)"); @@ -278,7 +273,7 @@ private String getRandomFunnyMessage() { private static class RunAwayFromPlayersTask extends RunAwayFromEntitiesTask { - public RunAwayFromPlayersTask(Supplier> toRunAwayFrom, double distanceToRun) { + public RunAwayFromPlayersTask(Entity toRunAwayFrom, double distanceToRun) { super(toRunAwayFrom, distanceToRun, true, 0.1); // More lenient progress checker _checker = new MovementProgressChecker(); diff --git a/src/main/java/adris/altoclef/tasksystem/TaskRunner.java b/src/main/java/adris/altoclef/tasksystem/TaskRunner.java index 0da162494..07523b66c 100644 --- a/src/main/java/adris/altoclef/tasksystem/TaskRunner.java +++ b/src/main/java/adris/altoclef/tasksystem/TaskRunner.java @@ -19,7 +19,7 @@ public TaskRunner(AltoClef mod) { } public void tick() { - if (!_active) return; + if (!_active || !AltoClef.inGame()) return; // Get highest priority chain and run TaskChain maxChain = null; float maxPriority = Float.NEGATIVE_INFINITY; diff --git a/src/main/java/adris/altoclef/trackers/EntityTracker.java b/src/main/java/adris/altoclef/trackers/EntityTracker.java index a8734adb3..60b4f324b 100644 --- a/src/main/java/adris/altoclef/trackers/EntityTracker.java +++ b/src/main/java/adris/altoclef/trackers/EntityTracker.java @@ -369,7 +369,7 @@ protected synchronized void updateState() { if (EntityHelper.isAngryAtPlayer(_mod, entity)) { // Check if the mob is facing us or is close enough - boolean closeEnough = entity.isInRange(_mod.getPlayer(), 26); + boolean closeEnough = entity.isInRange(_mod.getPlayer(), 16); //Debug.logInternal("TARGET: " + hostile.is); if (closeEnough) { diff --git a/src/main/java/adris/altoclef/ui/CommandStatusOverlay.java b/src/main/java/adris/altoclef/ui/CommandStatusOverlay.java index 3e08ce1db..325c885a7 100644 --- a/src/main/java/adris/altoclef/ui/CommandStatusOverlay.java +++ b/src/main/java/adris/altoclef/ui/CommandStatusOverlay.java @@ -4,7 +4,9 @@ import adris.altoclef.tasksystem.Task; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.util.math.MatrixStack; +import org.joml.Matrix4f; import java.time.Instant; import java.time.ZoneId; @@ -28,13 +30,16 @@ public void render(AltoClef mod, MatrixStack matrixstack) { } int color = 0xFFFFFFFF; - drawTaskChain(MinecraftClient.getInstance().textRenderer, matrixstack, 0, 0, color, 10, tasks, mod); + drawTaskChain(MinecraftClient.getInstance().textRenderer, 0, 0, color, false, + matrixstack.peek().getPositionMatrix(), + MinecraftClient.getInstance().getBufferBuilders().getOutlineVertexConsumers(), + TextRenderer.TextLayerType.NORMAL, 0, 255, 10, tasks, mod); } } - private void drawTaskChain(TextRenderer renderer, MatrixStack stack, float dx, float dy, int color, int maxLines, List tasks, AltoClef mod) { + private void drawTaskChain(TextRenderer renderer, float x, float y, int color, boolean shadow, Matrix4f matrix, VertexConsumerProvider vertexConsumers, TextRenderer.TextLayerType layerType, int backgroundColor, int light, int maxLines, List tasks, AltoClef mod) { if (tasks.size() == 0) { - renderer.draw(stack, " (no task running) ", dx, dy, color); + renderer.draw(" (no task running) ", x, y, color, shadow, matrix, vertexConsumers, layerType, backgroundColor, light); if (_lastTime + 10000 < Instant.now().toEpochMilli() && mod.getModSettings().shouldShowTimer()) {//if it doesn't run any task in 10 secs _timeRunning = Instant.now().toEpochMilli();//reset the timer } @@ -43,29 +48,29 @@ private void drawTaskChain(TextRenderer renderer, MatrixStack stack, float dx, f if (mod.getModSettings().shouldShowTimer()) { //If it's enabled _lastTime = Instant.now().toEpochMilli(); //keep the last time for the timer reset String _realTime = DATE_TIME_FORMATTER.format(Instant.now().minusMillis(_timeRunning)); //Format the running time to string - renderer.draw(stack, "<" + _realTime + ">", dx, dy, color);//Draw the timer before drawing tasks list - dx += 8;//Do the same thing to list the tasks - dy += fontHeight + 2; + renderer.draw("<" + _realTime + ">", x, y, color, shadow, matrix, vertexConsumers, layerType, backgroundColor, light); + x += 8;//Do the same thing to list the tasks + y += fontHeight + 2; } if (tasks.size() > maxLines) { for (int i = 0; i < tasks.size(); ++i) { // Skip over the next tasks if (i == 0 || i > tasks.size() - maxLines) { - renderer.draw(stack, tasks.get(i).toString(), dx, dy, color); + renderer.draw(tasks.get(i).toString(), x, y, color, shadow, matrix, vertexConsumers, layerType, backgroundColor, light); } else if (i == 1) { - renderer.draw(stack, " ... ", dx, dy, color); + renderer.draw(" ... ", x, y, color, shadow, matrix, vertexConsumers, layerType, backgroundColor, light); } else { continue; } - dx += 8; - dy += fontHeight + 2; + x += 8; + y += fontHeight + 2; } } else { if (!tasks.isEmpty()) { for (Task task : tasks) { - renderer.draw(stack, task.toString(), dx, dy, color); - dx += 8; - dy += fontHeight + 2; + renderer.draw(task.toString(), x, y, color, shadow, matrix, vertexConsumers, layerType, backgroundColor, light); + x += 8; + y += fontHeight + 2; } } } diff --git a/src/main/java/adris/altoclef/util/JankCraftingRecipeMapping.java b/src/main/java/adris/altoclef/util/JankCraftingRecipeMapping.java index 1a9affee7..70a73fbc5 100644 --- a/src/main/java/adris/altoclef/util/JankCraftingRecipeMapping.java +++ b/src/main/java/adris/altoclef/util/JankCraftingRecipeMapping.java @@ -1,12 +1,12 @@ package adris.altoclef.util; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.world.ClientWorld; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.recipe.Ingredient; -import net.minecraft.recipe.Recipe; +import net.minecraft.recipe.RecipeEntry; import net.minecraft.recipe.RecipeManager; -import net.minecraft.registry.DynamicRegistryManager; import java.util.*; import java.util.stream.Collectors; @@ -15,42 +15,62 @@ * For crafting table/inventory recipe book crafting, we need to figure out identifiers given a recipe. */ public class JankCraftingRecipeMapping { - private static final HashMap>> _recipeMapping = new HashMap<>(); + private static final HashMap>> _recipeMapping = new HashMap<>(); + /** + * Reloads the recipe mapping. + */ private static void reloadRecipeMapping() { - if (MinecraftClient.getInstance().getNetworkHandler() != null) { - RecipeManager recipes = MinecraftClient.getInstance().getNetworkHandler().getRecipeManager(); + MinecraftClient client = MinecraftClient.getInstance(); + + // Check if the network handler is available + if (client.getNetworkHandler() != null) { + RecipeManager recipes = client.getNetworkHandler().getRecipeManager(); + ClientWorld world = client.world; + + // Check if the recipe manager is available if (recipes != null) { - for (Recipe recipe : recipes.values()) { - Item output = recipe.getOutput(DynamicRegistryManager.EMPTY).getItem(); - if (!_recipeMapping.containsKey(output)) { - _recipeMapping.put(output, new ArrayList<>()); - } - _recipeMapping.get(output).add(recipe); + for (RecipeEntry recipe : recipes.values()) { + assert world != null; + Item output = recipe.value().getResult(world.getRegistryManager()).getItem(); + _recipeMapping.computeIfAbsent(output, k -> new ArrayList<>()).add(recipe); } } } } - public static Optional> getMinecraftMappedRecipe(CraftingRecipe recipe, Item output) { - if (_recipeMapping.isEmpty()) { - reloadRecipeMapping(); - } + /** + * Retrieves the mapped recipe for a given output item from the Minecraft crafting recipe. + * + * @param recipe The crafting recipe to check against. + * @param output The output item of the recipe. + * @return An Optional containing the mapped recipe entry if found, or an empty Optional if not found. + */ + public static Optional> getMinecraftMappedRecipe(CraftingRecipe recipe, Item output) { + reloadRecipeMapping(); + // Check if the output item is present in the recipe mapping if (_recipeMapping.containsKey(output)) { - for (Recipe checkRecipe : _recipeMapping.get(output)) { - // Check for item count/satisfiability and not shape satisfiability (that would be annoying) - // Assumes there are no 2 recipes with the same output and same inputs in a different order. - List toSatisfy = Arrays.stream(recipe.getSlots()).filter(itemTarget -> itemTarget != null && !itemTarget.isEmpty()).collect(Collectors.toList()); - if (!checkRecipe.getIngredients().isEmpty()) { - for (Ingredient ingredientObj : checkRecipe.getIngredients()) { - if (ingredientObj.isEmpty()) + // Iterate through all the recipes mapped to the output item + for (RecipeEntry checkRecipe : _recipeMapping.get(output)) { + // Create a list of item targets to satisfy + List toSatisfy = Arrays.stream(recipe.getSlots()) + .filter(itemTarget -> itemTarget != null && !itemTarget.isEmpty()) + .collect(Collectors.toList()); + // Check if the recipe has ingredients + if (!checkRecipe.value().getIngredients().isEmpty()) { + // Iterate through the ingredients of the recipe + for (Ingredient ingredient : checkRecipe.value().getIngredients()) { + // Skip empty ingredients + if (ingredient.isEmpty()) { continue; - // Remove from "toSatisfy" if we find something that fits + } + // Iterate through the items to satisfy outer: for (int i = 0; i < toSatisfy.size(); ++i) { - ItemTarget check = toSatisfy.get(i); - for (ItemStack match : ingredientObj.getMatchingStacks()) { - if (check.matches(match.getItem())) { + ItemTarget target = toSatisfy.get(i); + // Check if any of the ingredient's matching stacks matches the item target + for (ItemStack stack : ingredient.getMatchingStacks()) { + if (target.matches(stack.getItem())) { toSatisfy.remove(i); break outer; } @@ -58,34 +78,7 @@ public static Optional> getMinecraftMappedRecipe(CraftingRecipe recipe } } } - /*int i = -1; // ++i first - boolean found = true; - for (Object ingredientObj : checkRecipe.getIngredients()) { - ++i; - // Out of range - if (i >= recipe.getSlotCount()) { - found = false; - break; - } - ItemTarget ourIngredient = recipe.getSlot(i); - Ingredient checkIngredient = (Ingredient) ingredientObj; - // If our ingredient is null, our check ingredient MUST be empty (Empty = null) - if (ourIngredient == null || ourIngredient.isEmpty()) { - if (checkIngredient.isEmpty()) - continue; - found = false; - break; - } - // At least one item must satisfy to move on. - if (Arrays.stream(checkIngredient.getMatchingStacks()).noneMatch(itemStack -> ourIngredient.matches(itemStack.getItem()))) { - found = false; - break; - } - } - if (found) - return Optional.of(checkRecipe); - */ - // We satisfied every material, so assume it's the right recipe. + // Check if all the item targets have been satisfied if (toSatisfy.isEmpty()) { return Optional.of(checkRecipe); } diff --git a/src/main/java/adris/altoclef/util/MiningRequirement.java b/src/main/java/adris/altoclef/util/MiningRequirement.java index acde58107..378810a41 100644 --- a/src/main/java/adris/altoclef/util/MiningRequirement.java +++ b/src/main/java/adris/altoclef/util/MiningRequirement.java @@ -2,15 +2,15 @@ import adris.altoclef.Debug; import net.minecraft.block.Block; -import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; import net.minecraft.item.Items; public enum MiningRequirement implements Comparable { - HAND(Items.AIR), WOOD(Items.WOODEN_PICKAXE), STONE(Items.STONE_PICKAXE), IRON(Items.IRON_PICKAXE), DIAMOND(Items.DIAMOND_PICKAXE); + HAND(Items.AIR.getDefaultStack()), WOOD(Items.WOODEN_PICKAXE.getDefaultStack()), STONE(Items.STONE_PICKAXE.getDefaultStack()), IRON(Items.IRON_PICKAXE.getDefaultStack()), DIAMOND(Items.DIAMOND_PICKAXE.getDefaultStack()), NETHERITE(Items.NETHERITE_PICKAXE.getDefaultStack()); - private final Item _minPickaxe; + private final ItemStack _minPickaxe; - MiningRequirement(Item minPickaxe) { + MiningRequirement(ItemStack minPickaxe) { _minPickaxe = minPickaxe; } @@ -18,7 +18,7 @@ public static MiningRequirement getMinimumRequirementForBlock(Block block) { if (block.getDefaultState().isToolRequired()) { for (MiningRequirement req : MiningRequirement.values()) { if (req == MiningRequirement.HAND) continue; - Item pick = req.getMinimumPickaxe(); + ItemStack pick = req.getMinimumPickaxe(); if (pick.isSuitableFor(block.getDefaultState())) { return req; } @@ -29,7 +29,7 @@ public static MiningRequirement getMinimumRequirementForBlock(Block block) { return MiningRequirement.HAND; } - public Item getMinimumPickaxe() { + public ItemStack getMinimumPickaxe() { return _minPickaxe; } diff --git a/src/main/java/adris/altoclef/util/WoodType.java b/src/main/java/adris/altoclef/util/WoodType.java index 033870521..1a8e3d2cd 100644 --- a/src/main/java/adris/altoclef/util/WoodType.java +++ b/src/main/java/adris/altoclef/util/WoodType.java @@ -9,5 +9,7 @@ public enum WoodType { JUNGLE, SPRUCE, WARPED, - MANGROVE + MANGROVE, + BAMBOO, + CHERRY } diff --git a/src/main/java/adris/altoclef/util/baritone/GoalRunAwayFromEntities.java b/src/main/java/adris/altoclef/util/baritone/GoalRunAwayFromEntities.java index cee1b3437..357e22f00 100644 --- a/src/main/java/adris/altoclef/util/baritone/GoalRunAwayFromEntities.java +++ b/src/main/java/adris/altoclef/util/baritone/GoalRunAwayFromEntities.java @@ -1,13 +1,12 @@ package adris.altoclef.util.baritone; import adris.altoclef.AltoClef; -import adris.altoclef.util.helpers.BaritoneHelper; import baritone.api.pathing.goals.Goal; import baritone.api.pathing.goals.GoalXZ; import baritone.api.pathing.goals.GoalYLevel; import net.minecraft.entity.Entity; -import java.util.List; +import java.util.Optional; public abstract class GoalRunAwayFromEntities implements Goal { @@ -30,19 +29,16 @@ public GoalRunAwayFromEntities(AltoClef mod, double distance, boolean xzOnly, do @Override public boolean isInGoal(int x, int y, int z) { - List entities = getEntities(_mod); - synchronized (BaritoneHelper.MINECRAFT_LOCK) { - if (!entities.isEmpty()) { - for (Entity entity : entities) { - if (entity == null || !entity.isAlive()) continue; - double sqDistance; - if (_xzOnly) { - sqDistance = entity.getPos().subtract(x, y, z).multiply(1, 0, 1).lengthSquared(); - } else { - sqDistance = entity.squaredDistanceTo(x, y, z); - } - if (sqDistance < _distance * _distance) return false; + if (getEntities(_mod).isPresent()) { + Entity entity = getEntities(_mod).get(); + if (entity.isAlive()) { + double sqDistance; + if (_xzOnly) { + sqDistance = entity.getPos().subtract(x, y, z).multiply(1, 0, 1).lengthSquared(); + } else { + sqDistance = entity.squaredDistanceTo(x, y, z); } + return !(sqDistance < _distance * _distance); } } return true; @@ -52,33 +48,29 @@ public boolean isInGoal(int x, int y, int z) { public double heuristic(int x, int y, int z) { // The lower the cost, the better. double costSum = 0; - List entities = getEntities(_mod); - synchronized (BaritoneHelper.MINECRAFT_LOCK) { - int max = 10; // If we have 100 players, this will never calculate. - int counter = 0; - if (!entities.isEmpty()) { - for (Entity entity : entities) { - counter++; - if (entity == null || !entity.isAlive()) continue; - double cost = getCostOfEntity(entity, x, y, z); - if (cost != 0) { - // We want the CLOSER entities to have a bigger weight than the further ones. - costSum += 1 / cost; - } else { - // Bad >:( - costSum += 1000; - } - if (counter >= max) break; + int counter = 0; + if (getEntities(_mod).isPresent()) { + Entity entity = getEntities(_mod).get(); + counter++; + if (entity.isAlive()) { + double cost = getCostOfEntity(entity, x, y, z); + if (cost != 0) { + // We want the CLOSER entities to have a bigger weight than the further ones. + costSum += 1 / cost; + } else { + // Bad >:( + costSum += 1000; } + ; } - if (counter > 0) { - costSum /= counter; - } - return costSum * _penaltyFactor; } + if (counter > 0) { + costSum /= counter; + } + return costSum * _penaltyFactor; } - protected abstract List getEntities(AltoClef mod); + protected abstract Optional getEntities(AltoClef mod); // Virtual protected double getCostOfEntity(Entity entity, int x, int y, int z) { diff --git a/src/main/java/adris/altoclef/util/helpers/ConfigHelper.java b/src/main/java/adris/altoclef/util/helpers/ConfigHelper.java index d3f8e94ea..13a9756b0 100644 --- a/src/main/java/adris/altoclef/util/helpers/ConfigHelper.java +++ b/src/main/java/adris/altoclef/util/helpers/ConfigHelper.java @@ -12,11 +12,9 @@ import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.Vec3d; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; +import java.io.*; import java.nio.file.Files; -import java.nio.file.Paths; +import java.nio.file.Path; import java.util.HashMap; import java.util.Scanner; import java.util.function.Consumer; @@ -31,18 +29,40 @@ public class ConfigHelper { // For reloading private static final HashMap _loadedConfigs = new HashMap<>(); + /** + * Returns a File object representing the configuration file located at the given path. + * + * @param path The relative path of the configuration file. + * @return The File object representing the configuration file. + */ private static File getConfigFile(String path) { - return Paths.get(ALTO_FOLDER, path).toFile(); + // Get the full path by concatenating the ALTO_FOLDER and the given path + String fullPath = ALTO_FOLDER + File.separator + path; + + // Create a new File object using the full path + return new File(fullPath); } + /** + * Reloads all configurations. + */ public static void reloadAllConfigs() { - if (!_loadedConfigs.values().isEmpty()) { - for (Runnable reload : _loadedConfigs.values()) { - reload.run(); - } + for (Runnable config : _loadedConfigs.values()) { + config.run(); } } + /** + * Retrieves the configuration from the specified path. + * If the configuration file does not exist, it creates a new one using the default value. + * If there is an error reading or parsing the configuration file, it returns the default value. + * + * @param path The path to the configuration file. + * @param getDefault A supplier that provides the default value for the configuration. + * @param classToLoad The class of the configuration object. + * @param The type of the configuration object. + * @return The retrieved configuration object or the default value. + */ private static T getConfig(String path, Supplier getDefault, Class classToLoad) { T result = getDefault.get(); File loadFrom = getConfigFile(path); @@ -58,7 +78,6 @@ private static T getConfig(String path, Supplier getDefault, Class cla module.addDeserializer(BlockPos.class, new BlockPosDeserializer()); mapper.registerModule(module); - boolean failed = false; try { result = mapper.readValue(loadFrom, classToLoad); } catch (JsonMappingException ex) { @@ -66,116 +85,241 @@ private static T getConfig(String path, Supplier getDefault, Class cla ex.printStackTrace(); if (result instanceof IFailableConfigFile failable) failable.failedToLoad(); - failed = true; + return result; } catch (IOException e) { Debug.logError("Failed to read Config at " + path + "."); e.printStackTrace(); if (result instanceof IFailableConfigFile failable) failable.failedToLoad(); - failed = true; + return result; } - // Save over to include NEW settings - // but only if a load was successful. Don't want to override user settings! - if (!failed) { - saveConfig(path, result); - } + saveConfig(path, result); return result; } + /** + * Load the configuration from the given path, using the provided default value, + * class to load, and callback function for when the configuration is reloaded. + * + * @param path The path to the configuration file. + * @param getDefault A supplier function that provides the default value of the configuration. + * @param classToLoad The class of the configuration object to load. + * @param onReload A consumer function that is called when the configuration is reloaded. + * @param The type of the configuration object. + */ public static void loadConfig(String path, Supplier getDefault, Class classToLoad, Consumer onReload) { - T result = getConfig(path, getDefault, classToLoad); - _loadedConfigs.put(path, () -> onReload.accept(getConfig(path, getDefault, classToLoad))); - onReload.accept(result); + // Get the configuration object using the getConfig function. + T config = getConfig(path, getDefault, classToLoad); + + // Store the configuration object and the reload callback in the loadedConfigs map. + _loadedConfigs.put(path, () -> onReload.accept(config)); + + // Call the onReload callback function to notify that the configuration is loaded. + onReload.accept(config); } + /** + * Save the configuration object to a file at the specified path. + * + * @param path The path of the file to save the configuration to. + * @param config The configuration object to be saved. + */ public static void saveConfig(String path, T config) { + // Create an object mapper to serialize the configuration object ObjectMapper mapper = new ObjectMapper(); + + // Create a module to register custom serializers for specific classes SimpleModule module = new SimpleModule(); module.addSerializer(Vec3d.class, new Vec3dSerializer()); module.addSerializer(BlockPos.class, new BlockPosSerializer()); module.addSerializer(ChunkPos.class, new ChunkPosSerializer()); mapper.registerModule(module); - File toSave = getConfigFile(path); - if (!toSave.getParentFile().exists()) { - //noinspection ResultOfMethodCallIgnored - toSave.getParentFile().mkdirs(); + // Get the file object for the specified path + File configFile = getConfigFile(path); + + // Create parent directories if they don't exist + createParentDirectories(configFile); + + try { + // Enable pretty printing for the serialized JSON + enablePrettyPrinting(mapper); + + // Write the serialized configuration object to the file + writeConfigToFile(mapper, configFile, config); + } catch (IOException e) { + // Handle any IO exceptions that occur during the write process + handleIOException(e); } + } + /** + * Creates the parent directories for a given file. + * + * @param file the file to create parent directories for + */ + private static void createParentDirectories(File file) { try { + // Get the parent path of the file + Path parentPath = file.getParentFile().toPath(); + + // Create the parent directories + Files.createDirectories(parentPath); + } catch (IOException e) { + // Print an error message if failed to create parent directories + System.err.println("Failed to create parent directories: " + e.getMessage()); + } + } + + /** + * Enable pretty printing for the given ObjectMapper. + * + * @param mapper The ObjectMapper to enable pretty printing for. + */ + private static void enablePrettyPrinting(ObjectMapper mapper) { + // Check if the ObjectMapper is not null + if (mapper != null) { + // Enable indentation for the output mapper.enable(SerializationFeature.INDENT_OUTPUT); - // Pretty print and indent arrays too. + // Create a DefaultPrettyPrinter with a line feed indenter DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter(); prettyPrinter.indentArraysWith(DefaultIndenter.SYSTEM_LINEFEED_INSTANCE); - mapper.writer(prettyPrinter).writeValue(toSave, config); - } catch (IOException e) { - e.printStackTrace(); + // Set the pretty printer for the ObjectMapper's writer + mapper.writer(prettyPrinter); + } + } + + /** + * Writes the given configuration data to the specified file using the provided ObjectMapper. + * + * @param objectMapper the ObjectMapper used to serialize the configuration data + * @param configFile the file to write the configuration data to + * @param configData the configuration data to write to the file + * @throws IOException if an I/O error occurs while writing to the file + */ + private static void writeConfigToFile(ObjectMapper objectMapper, File configFile, T configData) throws IOException { + try (Writer writer = new FileWriter(configFile)) { + objectMapper.writeValue(writer, configData); } } + /** + * Handles an IOException by printing an error message to the standard error stream. + * + * @param exception The IOException to handle. + */ + private static void handleIOException(IOException exception) { + // Create an error message with the exception message + String errorMessage = "An IOException occurred: " + exception.getMessage(); + + // Print the error message to the standard error stream + System.err.println(errorMessage); + } + + /** + * Retrieves a list configuration from the specified path. + * + * @param path The path of the configuration file. + * @param getDefault A supplier that provides a default configuration object. + * @param The type of the configuration object. + * @return The retrieved configuration object, or null if an error occurs. + */ private static T getListConfig(String path, Supplier getDefault) { T result = getDefault.get(); - result.onLoadStart(); - File loadFrom = getConfigFile(path); - if (!loadFrom.exists()) { - // Empty - Debug.logInternal("Lists file not found at " + path); + File configFile = getConfigFile(path); + if (!configFile.exists()) { return result; } - try { - FileInputStream fis = new FileInputStream(loadFrom); - Scanner sc = new Scanner(fis); //file to be scanned - //returns true if there is another line to read - while (sc.hasNextLine()) { - String line = trimComment(sc.nextLine()).trim(); - if (line.length() == 0) continue; + try (FileInputStream fis = new FileInputStream(configFile); + Scanner scanner = new Scanner(fis)) { + while (scanner.hasNextLine()) { + String line = trimComment(scanner.nextLine()).trim(); + if (line.isEmpty()) { + continue; + } result.addLine(line); } - sc.close(); } catch (IOException e) { e.printStackTrace(); return null; } + return result; } + /** + * Loads a list configuration file from the given path. + * + * @param path the path of the configuration file + * @param getDefault a supplier function that provides a default configuration object + * @param onReload a consumer function that handles the reload of the configuration object + * @param the type of the configuration object + */ public static void loadListConfig(String path, Supplier getDefault, Consumer onReload) { + // Get the configuration object from the specified path T result = getListConfig(path, getDefault); - _loadedConfigs.put(path, () -> onReload.accept(getListConfig(path, getDefault))); + + // Store a lambda function in the map to handle the reload of the configuration object + _loadedConfigs.put(path, () -> onReload.accept(result)); + + // Trigger the reload of the configuration object onReload.accept(result); } + /** + * This method trims a comment from the given line. + * If the line does not contain a comment, the original line is returned. + * + * @param line The line to trim the comment from + * @return The line with the comment trimmed + */ private static String trimComment(String line) { - int pound = line.indexOf('#'); - if (pound == -1) { + int poundIndex = line.indexOf('#'); + if (poundIndex == -1) { return line; + } else { + return line.substring(0, poundIndex); } - return line.substring(0, pound); } + /** + * Ensures that the commented list file exists at the specified path. + * + * @param path The path where the commented list file should be located. + * @param startingComment The starting comment for the file. + */ public static void ensureCommentedListFileExists(String path, String startingComment) { - File loadFrom = getConfigFile(path); - if (loadFrom.exists()) { - // Already exists, don't make a new one. + File configFile = getConfigFile(path); + if (configFile.exists()) { return; } - StringBuilder result = new StringBuilder(); + StringBuilder commentBuilder = new StringBuilder(); for (String line : startingComment.split("\\r?\\n")) { - if (line.length() != 0) { - result.append("# ").append(line).append("\n"); + if (!line.isEmpty()) { + commentBuilder.append("# ").append(line).append("\n"); } } try { - Files.write(loadFrom.toPath(), result.toString().getBytes()); + Files.write(configFile.toPath(), commentBuilder.toString().getBytes()); } catch (IOException e) { - e.printStackTrace(); + handleException(e); } } + + /** + * Handles an IOException by printing an error message to the standard error stream. + * + * @param exception The IOException to handle. + */ + private static void handleException(IOException exception) { + // Print the error message to the standard error stream + System.err.println("An error occurred: " + exception.getMessage()); + } } diff --git a/src/main/java/adris/altoclef/util/helpers/EntityHelper.java b/src/main/java/adris/altoclef/util/helpers/EntityHelper.java index c114e5eb4..abf752153 100644 --- a/src/main/java/adris/altoclef/util/helpers/EntityHelper.java +++ b/src/main/java/adris/altoclef/util/helpers/EntityHelper.java @@ -4,44 +4,43 @@ import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.DamageUtil; import net.minecraft.entity.Entity; -import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.Tameable; import net.minecraft.entity.attribute.EntityAttributes; import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.damage.DamageTypes; import net.minecraft.entity.effect.StatusEffects; import net.minecraft.entity.mob.*; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.raid.RaiderEntity; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.registry.tag.DamageTypeTags; +import java.util.Objects; + /** * Helper functions to interpret entity state */ public class EntityHelper { public static final double ENTITY_GRAVITY = 0.08; // per second - public static boolean isAngryAtPlayer(AltoClef mod, Entity mob) { - boolean hostile = isGenerallyHostileToPlayer(mod, mob); - if (mob instanceof LivingEntity entity) { - return hostile && entity.canSee(mod.getPlayer()); - } - return hostile; + public static boolean isAngryAtPlayer(AltoClef mod, Entity entity) { + return isGenerallyHostileToPlayer(mod, entity); } - public static boolean isGenerallyHostileToPlayer(AltoClef mod, Entity hostile) { - // This is only temporary. - if (hostile instanceof MobEntity entity) { - if (entity instanceof HostileEntity entity1) { - return entity1.isAttacking() || !(entity1 instanceof EndermanEntity || entity1 instanceof PiglinEntity || - entity1 instanceof SpiderEntity || entity1 instanceof ZombifiedPiglinEntity); - } - if (entity instanceof SlimeEntity entity1) { - return entity1.canSee(mod.getPlayer()); - } - return entity.isAttacking(); - } - return !isTradingPiglin(hostile); + public static boolean isGenerallyHostileToPlayer(AltoClef mod, Entity entity) { + if (entity instanceof Tameable tameable && tameable.getOwnerUuid() != null + && tameable.getOwnerUuid().equals(mod.getPlayer().getUuid())) return false; + if (entity instanceof SlimeEntity slime && mod.getPlayer().isInRange(slime, 3)) return true; + if (entity instanceof RaiderEntity raider && mod.getPlayer().isInRange(raider, 16)) return true; + if (entity instanceof WardenEntity warden && mod.getPlayer().isInRange(warden, 16)) return true; + if (entity instanceof EndermanEntity enderman && enderman.canSee(mod.getPlayer()) && enderman.isAttacking()) + return true; + if (entity instanceof BlazeEntity blaze && mod.getPlayer().isInRange(blaze, 3)) return true; + if (entity instanceof SlimeEntity || entity instanceof RaiderEntity || entity instanceof WardenEntity + || entity instanceof EndermanEntity || entity instanceof BlazeEntity) return false; + if (entity instanceof MobEntity mob && !mob.isAttacking()) return false; + return !isTradingPiglin(entity); } public static boolean isTradingPiglin(Entity entity) { @@ -70,16 +69,16 @@ public static double calculateResultingPlayerDamage(PlayerEntity player, DamageS // Armor Base if (!source.isIn(DamageTypeTags.BYPASSES_ARMOR)) { - damageAmount = DamageUtil.getDamageLeft((float) damageAmount, (float) player.getArmor(), (float) player.getAttributeValue(EntityAttributes.GENERIC_ARMOR_TOUGHNESS)); + damageAmount = DamageUtil.getDamageLeft(player, (float) damageAmount, source, (float) player.getArmor(), (float) player.getAttributeValue(EntityAttributes.GENERIC_ARMOR_TOUGHNESS)); } // Enchantments & Potions if (!source.isIn(DamageTypeTags.BYPASSES_SHIELD)) { - int k; + float k; if (player.hasStatusEffect(StatusEffects.RESISTANCE) && source.isOf(DamageTypes.OUT_OF_WORLD)) { //noinspection ConstantConditions k = (player.getStatusEffect(StatusEffects.RESISTANCE).getAmplifier() + 1) * 5; - int j = 25 - k; + float j = 25 - k; double f = damageAmount * (double) j; double g = damageAmount; damageAmount = Math.max(f / 25.0F, 0.0F); @@ -88,9 +87,9 @@ public static double calculateResultingPlayerDamage(PlayerEntity player, DamageS if (damageAmount <= 0.0) { damageAmount = 0.0; } else { - k = EnchantmentHelper.getProtectionAmount(player.getArmorItems(), source); + k = EnchantmentHelper.getProtectionAmount(Objects.requireNonNull(player.getServer()).getWorld(player.getWorld().getRegistryKey()), player, source); if (k > 0) { - damageAmount = DamageUtil.getInflictedDamage((float) damageAmount, (float) k); + damageAmount = DamageUtil.getInflictedDamage((float) damageAmount, k); } } } diff --git a/src/main/java/adris/altoclef/util/helpers/ItemHelper.java b/src/main/java/adris/altoclef/util/helpers/ItemHelper.java index 83d13ed74..4ac40c502 100644 --- a/src/main/java/adris/altoclef/util/helpers/ItemHelper.java +++ b/src/main/java/adris/altoclef/util/helpers/ItemHelper.java @@ -7,6 +7,7 @@ import net.minecraft.block.LeavesBlock; import net.minecraft.block.MapColor; import net.minecraft.block.entity.AbstractFurnaceBlockEntity; +import net.minecraft.component.DataComponentTypes; import net.minecraft.item.BlockItem; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -22,11 +23,18 @@ * Helper functions and definitions for useful groupings of items */ public class ItemHelper { + public static final Item[] COPPER_BLOCKS = new Item[]{Items.COPPER_BLOCK, Items.EXPOSED_COPPER, + Items.WEATHERED_COPPER, Items.OXIDIZED_COPPER, Items.CUT_COPPER, Items.EXPOSED_CUT_COPPER, + Items.WEATHERED_CUT_COPPER, Items.OXIDIZED_CUT_COPPER, Items.WAXED_COPPER_BLOCK, + Items.WAXED_EXPOSED_COPPER, Items.WAXED_WEATHERED_COPPER, Items.WAXED_OXIDIZED_COPPER, + Items.WAXED_CUT_COPPER, Items.WAXED_EXPOSED_CUT_COPPER, Items.WAXED_WEATHERED_CUT_COPPER, + Items.WAXED_OXIDIZED_CUT_COPPER}; public static final Item[] SAPLINGS = new Item[]{Items.OAK_SAPLING, Items.SPRUCE_SAPLING, Items.BIRCH_SAPLING, - Items.JUNGLE_SAPLING, Items.ACACIA_SAPLING, Items.DARK_OAK_SAPLING, Items.MANGROVE_PROPAGULE}; + Items.JUNGLE_SAPLING, Items.ACACIA_SAPLING, Items.DARK_OAK_SAPLING, Items.MANGROVE_PROPAGULE, + Items.CHERRY_SAPLING}; public static final Block[] SAPLING_SOURCES = new Block[]{Blocks.OAK_LEAVES, Blocks.SPRUCE_LEAVES, Blocks.BIRCH_LEAVES, Blocks.JUNGLE_LEAVES, Blocks.ACACIA_LEAVES, Blocks.DARK_OAK_LEAVES, - Blocks.MANGROVE_PROPAGULE}; + Blocks.MANGROVE_PROPAGULE, Blocks.CHERRY_LEAVES}; public static final Item[] HOSTILE_MOB_DROPS = new Item[]{Items.BLAZE_ROD, Items.FEATHER, Items.CHICKEN, Items.COOKED_CHICKEN, Items.ROTTEN_FLESH, Items.ZOMBIE_HEAD, Items.GUNPOWDER, Items.CREEPER_HEAD, Items.TOTEM_OF_UNDYING, Items.EMERALD, Items.PORKCHOP, Items.COOKED_PORKCHOP, Items.LEATHER, @@ -37,42 +45,49 @@ public class ItemHelper { Items.CARROT, Items.POTATO, Items.BAKED_POTATO, Items.COPPER_INGOT}; public static final Item[] DIRTS = new Item[]{Items.DIRT, Items.DIRT_PATH, Items.COARSE_DIRT, Items.ROOTED_DIRT}; public static final Item[] PLANKS = new Item[]{Items.ACACIA_PLANKS, Items.BIRCH_PLANKS, Items.CRIMSON_PLANKS, - Items.DARK_OAK_PLANKS, Items.OAK_PLANKS, Items.JUNGLE_PLANKS, Items.SPRUCE_PLANKS, Items.WARPED_PLANKS, Items.MANGROVE_PLANKS}; + Items.DARK_OAK_PLANKS, Items.OAK_PLANKS, Items.JUNGLE_PLANKS, Items.SPRUCE_PLANKS, Items.WARPED_PLANKS, + Items.MANGROVE_PLANKS, Items.CHERRY_PLANKS, Items.BAMBOO_PLANKS, Items.CHERRY_PLANKS}; public static final Item[] LEAVES = new Item[]{Items.ACACIA_LEAVES, Items.BIRCH_LEAVES, Items.DARK_OAK_LEAVES, - Items.OAK_LEAVES, Items.JUNGLE_LEAVES, Items.SPRUCE_LEAVES, Items.MANGROVE_LEAVES}; + Items.OAK_LEAVES, Items.JUNGLE_LEAVES, Items.SPRUCE_LEAVES, Items.MANGROVE_LEAVES, Items.CHERRY_LEAVES}; public static final Item[] WOOD = new Item[]{Items.ACACIA_WOOD, Items.BIRCH_WOOD, Items.CRIMSON_HYPHAE, Items.DARK_OAK_WOOD, Items.OAK_WOOD, Items.JUNGLE_WOOD, Items.SPRUCE_WOOD, Items.WARPED_HYPHAE, Items.MANGROVE_WOOD}; public static final Item[] WOOD_BUTTON = new Item[]{Items.ACACIA_BUTTON, Items.BIRCH_BUTTON, Items.CRIMSON_BUTTON, Items.DARK_OAK_BUTTON, Items.OAK_BUTTON, Items.JUNGLE_BUTTON, Items.SPRUCE_BUTTON, Items.WARPED_BUTTON, - Items.MANGROVE_BUTTON}; + Items.MANGROVE_BUTTON, Items.BAMBOO_BUTTON, Items.CHERRY_BUTTON}; public static final Item[] WOOD_SIGN = new Item[]{Items.ACACIA_SIGN, Items.BIRCH_SIGN, Items.CRIMSON_SIGN, Items.DARK_OAK_SIGN, Items.OAK_SIGN, Items.JUNGLE_SIGN, Items.SPRUCE_SIGN, Items.WARPED_SIGN, - Items.MANGROVE_SIGN}; + Items.MANGROVE_SIGN, Items.BAMBOO_SIGN, Items.CHERRY_SIGN}; + public static final Item[] WOOD_HANGING_SIGN = new Item[]{Items.ACACIA_HANGING_SIGN, Items.BIRCH_HANGING_SIGN, + Items.CRIMSON_HANGING_SIGN, Items.DARK_OAK_HANGING_SIGN, Items.OAK_HANGING_SIGN, Items.JUNGLE_HANGING_SIGN, + Items.SPRUCE_HANGING_SIGN, Items.WARPED_HANGING_SIGN, Items.MANGROVE_HANGING_SIGN, Items.BAMBOO_HANGING_SIGN, + Items.CHERRY_HANGING_SIGN}; public static final Item[] WOOD_PRESSURE_PLATE = new Item[]{Items.ACACIA_PRESSURE_PLATE, Items.BIRCH_PRESSURE_PLATE, Items.CRIMSON_PRESSURE_PLATE, Items.DARK_OAK_PRESSURE_PLATE, Items.OAK_PRESSURE_PLATE, Items.JUNGLE_PRESSURE_PLATE, Items.SPRUCE_PRESSURE_PLATE, Items.WARPED_PRESSURE_PLATE, - Items.MANGROVE_PRESSURE_PLATE}; + Items.MANGROVE_PRESSURE_PLATE, Items.BAMBOO_PRESSURE_PLATE, Items.CHERRY_PRESSURE_PLATE}; public static final Item[] WOOD_FENCE = new Item[]{Items.ACACIA_FENCE, Items.BIRCH_FENCE, Items.DARK_OAK_FENCE, Items.OAK_FENCE, Items.JUNGLE_FENCE, Items.SPRUCE_FENCE, Items.CRIMSON_FENCE, Items.WARPED_FENCE, - Items.MANGROVE_FENCE}; + Items.MANGROVE_FENCE, Items.BAMBOO_FENCE, Items.CHERRY_FENCE}; public static final Item[] WOOD_FENCE_GATE = new Item[]{Items.ACACIA_FENCE_GATE, Items.BIRCH_FENCE_GATE, Items.DARK_OAK_FENCE_GATE, Items.OAK_FENCE_GATE, Items.JUNGLE_FENCE_GATE, Items.SPRUCE_FENCE_GATE, - Items.CRIMSON_FENCE_GATE, Items.WARPED_FENCE_GATE, Items.MANGROVE_FENCE_GATE}; + Items.CRIMSON_FENCE_GATE, Items.WARPED_FENCE_GATE, Items.MANGROVE_FENCE_GATE, Items.BAMBOO_FENCE_GATE, + Items.CHERRY_FENCE_GATE}; public static final Item[] WOOD_BOAT = new Item[]{Items.ACACIA_BOAT, Items.BIRCH_BOAT, Items.DARK_OAK_BOAT, - Items.OAK_BOAT, Items.JUNGLE_BOAT, Items.SPRUCE_BOAT, Items.MANGROVE_BOAT}; + Items.OAK_BOAT, Items.JUNGLE_BOAT, Items.SPRUCE_BOAT, Items.MANGROVE_BOAT, Items.CHERRY_BOAT}; public static final Item[] WOOD_DOOR = new Item[]{Items.ACACIA_DOOR, Items.BIRCH_DOOR, Items.CRIMSON_DOOR, Items.DARK_OAK_DOOR, Items.OAK_DOOR, Items.JUNGLE_DOOR, Items.SPRUCE_DOOR, Items.WARPED_DOOR, - Items.MANGROVE_DOOR}; + Items.MANGROVE_DOOR, Items.BAMBOO_DOOR, Items.CHERRY_DOOR}; public static final Item[] WOOD_SLAB = new Item[]{Items.ACACIA_SLAB, Items.BIRCH_SLAB, Items.CRIMSON_SLAB, Items.DARK_OAK_SLAB, Items.OAK_SLAB, Items.JUNGLE_SLAB, Items.SPRUCE_SLAB, Items.WARPED_SLAB, - Items.MANGROVE_SLAB}; + Items.MANGROVE_SLAB, Items.BAMBOO_SLAB, Items.CHERRY_SLAB}; public static final Item[] WOOD_STAIRS = new Item[]{Items.ACACIA_STAIRS, Items.BIRCH_STAIRS, Items.CRIMSON_STAIRS, Items.DARK_OAK_STAIRS, Items.OAK_STAIRS, Items.JUNGLE_STAIRS, Items.SPRUCE_STAIRS, Items.WARPED_STAIRS, - Items.MANGROVE_STAIRS}; + Items.MANGROVE_STAIRS, Items.BAMBOO_STAIRS, Items.CHERRY_STAIRS}; public static final Item[] WOOD_TRAPDOOR = new Item[]{Items.ACACIA_TRAPDOOR, Items.BIRCH_TRAPDOOR, Items.CRIMSON_TRAPDOOR, Items.DARK_OAK_TRAPDOOR, Items.OAK_TRAPDOOR, Items.JUNGLE_TRAPDOOR, - Items.SPRUCE_TRAPDOOR, Items.WARPED_TRAPDOOR, Items.MANGROVE_TRAPDOOR}; + Items.SPRUCE_TRAPDOOR, Items.WARPED_TRAPDOOR, Items.MANGROVE_TRAPDOOR, Items.BAMBOO_TRAPDOOR, + Items.CHERRY_TRAPDOOR}; public static final Item[] LOG = new Item[]{Items.ACACIA_LOG, Items.BIRCH_LOG, Items.DARK_OAK_LOG, Items.OAK_LOG, Items.JUNGLE_LOG, Items.SPRUCE_LOG, Items.ACACIA_WOOD, Items.BIRCH_WOOD, Items.DARK_OAK_WOOD, Items.OAK_WOOD, Items.JUNGLE_WOOD, Items.SPRUCE_WOOD, Items.STRIPPED_ACACIA_LOG, Items.STRIPPED_BIRCH_LOG, Items.STRIPPED_DARK_OAK_LOG, Items.STRIPPED_OAK_LOG, Items.STRIPPED_JUNGLE_LOG, Items.STRIPPED_SPRUCE_LOG, @@ -80,7 +95,15 @@ public class ItemHelper { Items.CRIMSON_STEM, Items.WARPED_STEM, Items.CRIMSON_HYPHAE, Items.WARPED_HYPHAE, Items.STRIPPED_CRIMSON_STEM, Items.STRIPPED_WARPED_STEM, Items.STRIPPED_CRIMSON_HYPHAE, Items.STRIPPED_WARPED_HYPHAE, Items.MANGROVE_LOG, Items.MANGROVE_WOOD, Items.STRIPPED_MANGROVE_LOG, - Items.STRIPPED_MANGROVE_WOOD}; + Items.STRIPPED_MANGROVE_WOOD, Items.CHERRY_LOG, Items.CHERRY_WOOD, Items.STRIPPED_CHERRY_LOG, + Items.STRIPPED_CHERRY_WOOD}; + public static final Item[] STRIPPED_LOGS = new Item[]{Items.STRIPPED_ACACIA_LOG, Items.STRIPPED_BIRCH_LOG, + Items.STRIPPED_DARK_OAK_LOG, Items.STRIPPED_OAK_LOG, Items.STRIPPED_JUNGLE_LOG, Items.STRIPPED_SPRUCE_LOG, + Items.STRIPPED_CRIMSON_STEM, Items.STRIPPED_WARPED_STEM, Items.STRIPPED_MANGROVE_LOG, + Items.STRIPPED_CHERRY_LOG}; + public static final Item[] STRIPPABLE_LOGS = new Item[]{Items.ACACIA_LOG, Items.BIRCH_LOG, Items.DARK_OAK_LOG, + Items.OAK_LOG, Items.JUNGLE_LOG, Items.SPRUCE_LOG, Items.CRIMSON_STEM, Items.WARPED_STEM, Items.MANGROVE_LOG, + Items.CHERRY_LOG}; public static final Item[] DYE = new Item[]{Items.WHITE_DYE, Items.BLACK_DYE, Items.BLUE_DYE, Items.BROWN_DYE, Items.CYAN_DYE, Items.GRAY_DYE, Items.GREEN_DYE, Items.LIGHT_BLUE_DYE, Items.LIGHT_GRAY_DYE, Items.LIME_DYE, Items.MAGENTA_DYE, Items.ORANGE_DYE, Items.PINK_DYE, Items.PURPLE_DYE, Items.RED_DYE, Items.YELLOW_DYE}; public static final Item[] WOOL = new Item[]{Items.WHITE_WOOL, Items.BLACK_WOOL, Items.BLUE_WOOL, Items.BROWN_WOOL, Items.CYAN_WOOL, Items.GRAY_WOOL, Items.GREEN_WOOL, Items.LIGHT_BLUE_WOOL, Items.LIGHT_GRAY_WOOL, Items.LIME_WOOL, Items.MAGENTA_WOOL, Items.ORANGE_WOOL, Items.PINK_WOOL, Items.PURPLE_WOOL, Items.RED_WOOL, Items.YELLOW_WOOL}; public static final Item[] BED = new Item[]{Items.WHITE_BED, Items.BLACK_BED, Items.BLUE_BED, Items.BROWN_BED, Items.CYAN_BED, Items.GRAY_BED, Items.GREEN_BED, Items.LIGHT_BLUE_BED, Items.LIGHT_GRAY_BED, Items.LIME_BED, Items.MAGENTA_BED, Items.ORANGE_BED, Items.PINK_BED, Items.PURPLE_BED, Items.RED_BED, Items.YELLOW_BED}; @@ -101,9 +124,21 @@ public class ItemHelper { public static final Block[] WOOD_SIGNS_ALL = new Block[]{Blocks.ACACIA_SIGN, Blocks.BIRCH_SIGN, Blocks.DARK_OAK_SIGN, Blocks.OAK_SIGN, Blocks.JUNGLE_SIGN, Blocks.SPRUCE_SIGN, Blocks.ACACIA_WALL_SIGN, Blocks.BIRCH_WALL_SIGN, Blocks.DARK_OAK_WALL_SIGN, Blocks.OAK_WALL_SIGN, Blocks.JUNGLE_WALL_SIGN, Blocks.SPRUCE_WALL_SIGN, - Blocks.MANGROVE_WALL_SIGN}; + Blocks.MANGROVE_SIGN, Blocks.MANGROVE_WALL_SIGN, Blocks.BAMBOO_SIGN, Blocks.BAMBOO_WALL_SIGN, + Blocks.CHERRY_SIGN, Blocks.CHERRY_WALL_SIGN}; + public static final Block[] WOOD_HANGING_SIGNS_ALL = new Block[]{Blocks.ACACIA_HANGING_SIGN, + Blocks.ACACIA_WALL_HANGING_SIGN, Blocks.BIRCH_HANGING_SIGN, Blocks.BIRCH_WALL_HANGING_SIGN, + Blocks.DARK_OAK_HANGING_SIGN, Blocks.DARK_OAK_WALL_HANGING_SIGN, Blocks.OAK_HANGING_SIGN, + Blocks.OAK_WALL_HANGING_SIGN, Blocks.JUNGLE_HANGING_SIGN, Blocks.JUNGLE_WALL_HANGING_SIGN, + Blocks.SPRUCE_HANGING_SIGN, Blocks.SPRUCE_WALL_HANGING_SIGN, Blocks.MANGROVE_HANGING_SIGN, + Blocks.MANGROVE_WALL_HANGING_SIGN, Blocks.BAMBOO_HANGING_SIGN, Blocks.BAMBOO_WALL_HANGING_SIGN, + Blocks.CHERRY_HANGING_SIGN, Blocks.CHERRY_WALL_HANGING_SIGN}; private static final Map _logToPlanks = new HashMap<>() { { + put(Items.CHERRY_LOG, Items.CHERRY_PLANKS); + put(Items.CHERRY_WOOD, Items.CHERRY_PLANKS); + put(Items.STRIPPED_CHERRY_LOG, Items.CHERRY_PLANKS); + put(Items.STRIPPED_CHERRY_WOOD, Items.CHERRY_PLANKS); put(Items.MANGROVE_LOG, Items.MANGROVE_PLANKS); put(Items.MANGROVE_WOOD, Items.MANGROVE_PLANKS); put(Items.STRIPPED_MANGROVE_LOG, Items.MANGROVE_PLANKS); @@ -144,6 +179,7 @@ public class ItemHelper { }; private static final Map _planksToLogs = new HashMap<>() { { + put(Items.CHERRY_PLANKS, Items.CHERRY_LOG); put(Items.MANGROVE_PLANKS, Items.MANGROVE_LOG); put(Items.ACACIA_PLANKS, Items.ACACIA_LOG); put(Items.BIRCH_PLANKS, Items.BIRCH_LOG); @@ -155,6 +191,20 @@ public class ItemHelper { put(Items.WARPED_PLANKS, Items.WARPED_STEM); } }; + private static final Map _strippedToLogs = new HashMap<>() { + { + put(Items.STRIPPED_CHERRY_LOG, Items.CHERRY_LOG); + put(Items.STRIPPED_MANGROVE_LOG, Items.MANGROVE_LOG); + put(Items.STRIPPED_ACACIA_LOG, Items.ACACIA_LOG); + put(Items.STRIPPED_BIRCH_LOG, Items.BIRCH_LOG); + put(Items.STRIPPED_CRIMSON_STEM, Items.CRIMSON_STEM); + put(Items.STRIPPED_DARK_OAK_LOG, Items.DARK_OAK_LOG); + put(Items.STRIPPED_OAK_LOG, Items.OAK_LOG); + put(Items.STRIPPED_JUNGLE_LOG, Items.JUNGLE_LOG); + put(Items.STRIPPED_SPRUCE_LOG, Items.SPRUCE_LOG); + put(Items.STRIPPED_WARPED_STEM, Items.WARPED_STEM); + } + }; // This is kinda jank ngl private static final Map _colorMap = new HashMap() { { @@ -183,19 +233,21 @@ void p(DyeColor color, String colorName, Item dye, Item wool, Item bed, Item car }; private static final Map _woodMap = new HashMap() { { - p(WoodType.MANGROVE, "mangrove", Items.MANGROVE_PLANKS, Items.MANGROVE_LOG, Items.STRIPPED_MANGROVE_LOG, Items.STRIPPED_MANGROVE_WOOD, Items.MANGROVE_WOOD, Items.MANGROVE_SIGN, Items.MANGROVE_DOOR, Items.MANGROVE_BUTTON, Items.MANGROVE_STAIRS, Items.MANGROVE_SLAB, Items.MANGROVE_FENCE, Items.MANGROVE_FENCE_GATE, Items.MANGROVE_BOAT, Items.MANGROVE_PROPAGULE, Items.MANGROVE_LEAVES, Items.MANGROVE_PRESSURE_PLATE, Items.MANGROVE_TRAPDOOR); - p(WoodType.ACACIA, "acacia", Items.ACACIA_PLANKS, Items.ACACIA_LOG, Items.STRIPPED_ACACIA_LOG, Items.STRIPPED_ACACIA_WOOD, Items.ACACIA_WOOD, Items.ACACIA_SIGN, Items.ACACIA_DOOR, Items.ACACIA_BUTTON, Items.ACACIA_STAIRS, Items.ACACIA_SLAB, Items.ACACIA_FENCE, Items.ACACIA_FENCE_GATE, Items.ACACIA_BOAT, Items.ACACIA_SAPLING, Items.ACACIA_LEAVES, Items.ACACIA_PRESSURE_PLATE, Items.ACACIA_TRAPDOOR); - p(WoodType.BIRCH, "birch", Items.BIRCH_PLANKS, Items.BIRCH_LOG, Items.STRIPPED_BIRCH_LOG, Items.STRIPPED_BIRCH_WOOD, Items.BIRCH_WOOD, Items.BIRCH_SIGN, Items.BIRCH_DOOR, Items.BIRCH_BUTTON, Items.BIRCH_STAIRS, Items.BIRCH_SLAB, Items.BIRCH_FENCE, Items.BIRCH_FENCE_GATE, Items.BIRCH_BOAT, Items.BIRCH_SAPLING, Items.BIRCH_LEAVES, Items.BIRCH_PRESSURE_PLATE, Items.BIRCH_TRAPDOOR); - p(WoodType.CRIMSON, "crimson", Items.CRIMSON_PLANKS, Items.CRIMSON_STEM, Items.STRIPPED_CRIMSON_STEM, Items.STRIPPED_CRIMSON_HYPHAE, Items.CRIMSON_HYPHAE, Items.CRIMSON_SIGN, Items.CRIMSON_DOOR, Items.CRIMSON_BUTTON, Items.CRIMSON_STAIRS, Items.CRIMSON_SLAB, Items.CRIMSON_FENCE, Items.CRIMSON_FENCE_GATE, null, Items.CRIMSON_FUNGUS, null, Items.CRIMSON_PRESSURE_PLATE, Items.CRIMSON_TRAPDOOR); - p(WoodType.DARK_OAK, "dark_oak", Items.DARK_OAK_PLANKS, Items.DARK_OAK_LOG, Items.STRIPPED_DARK_OAK_LOG, Items.STRIPPED_DARK_OAK_WOOD, Items.DARK_OAK_WOOD, Items.DARK_OAK_SIGN, Items.DARK_OAK_DOOR, Items.DARK_OAK_BUTTON, Items.DARK_OAK_STAIRS, Items.DARK_OAK_SLAB, Items.DARK_OAK_FENCE, Items.DARK_OAK_FENCE_GATE, Items.DARK_OAK_BOAT, Items.DARK_OAK_SAPLING, Items.DARK_OAK_LEAVES, Items.DARK_OAK_PRESSURE_PLATE, Items.DARK_OAK_TRAPDOOR); - p(WoodType.OAK, "oak", Items.OAK_PLANKS, Items.OAK_LOG, Items.STRIPPED_OAK_LOG, Items.STRIPPED_OAK_WOOD, Items.OAK_WOOD, Items.OAK_SIGN, Items.OAK_DOOR, Items.OAK_BUTTON, Items.OAK_STAIRS, Items.OAK_SLAB, Items.OAK_FENCE, Items.OAK_FENCE_GATE, Items.OAK_BOAT, Items.OAK_SAPLING, Items.OAK_LEAVES, Items.OAK_PRESSURE_PLATE, Items.OAK_TRAPDOOR); - p(WoodType.JUNGLE, "jungle", Items.JUNGLE_PLANKS, Items.JUNGLE_LOG, Items.STRIPPED_JUNGLE_LOG, Items.STRIPPED_JUNGLE_WOOD, Items.JUNGLE_WOOD, Items.JUNGLE_SIGN, Items.JUNGLE_DOOR, Items.JUNGLE_BUTTON, Items.JUNGLE_STAIRS, Items.JUNGLE_SLAB, Items.JUNGLE_FENCE, Items.JUNGLE_FENCE_GATE, Items.JUNGLE_BOAT, Items.JUNGLE_SAPLING, Items.JUNGLE_LEAVES, Items.JUNGLE_PRESSURE_PLATE, Items.JUNGLE_TRAPDOOR); - p(WoodType.SPRUCE, "spruce", Items.SPRUCE_PLANKS, Items.SPRUCE_LOG, Items.STRIPPED_SPRUCE_LOG, Items.STRIPPED_SPRUCE_WOOD, Items.SPRUCE_WOOD, Items.SPRUCE_SIGN, Items.SPRUCE_DOOR, Items.SPRUCE_BUTTON, Items.SPRUCE_STAIRS, Items.SPRUCE_SLAB, Items.SPRUCE_FENCE, Items.SPRUCE_FENCE_GATE, Items.SPRUCE_BOAT, Items.SPRUCE_SAPLING, Items.SPRUCE_LEAVES, Items.SPRUCE_PRESSURE_PLATE, Items.SPRUCE_TRAPDOOR); - p(WoodType.WARPED, "warped", Items.WARPED_PLANKS, Items.WARPED_STEM, Items.STRIPPED_WARPED_STEM, Items.STRIPPED_WARPED_HYPHAE, Items.WARPED_HYPHAE, Items.WARPED_SIGN, Items.WARPED_DOOR, Items.WARPED_BUTTON, Items.WARPED_STAIRS, Items.WARPED_SLAB, Items.WARPED_FENCE, Items.WARPED_FENCE_GATE, null, Items.WARPED_FUNGUS, null, Items.WARPED_PRESSURE_PLATE, Items.WARPED_TRAPDOOR); + p(WoodType.CHERRY, "cherry", Items.CHERRY_PLANKS, Items.CHERRY_LOG, Items.STRIPPED_CHERRY_LOG, Items.STRIPPED_CHERRY_WOOD, Items.CHERRY_WOOD, Items.CHERRY_SIGN, Items.CHERRY_HANGING_SIGN, Items.CHERRY_DOOR, Items.CHERRY_BUTTON, Items.CHERRY_STAIRS, Items.CHERRY_SLAB, Items.CHERRY_FENCE, Items.CHERRY_FENCE_GATE, Items.CHERRY_BOAT, Items.CHERRY_SAPLING, Items.CHERRY_LEAVES, Items.CHERRY_PRESSURE_PLATE, Items.CHERRY_TRAPDOOR); + p(WoodType.BAMBOO, "bamboo", null, null, Items.STRIPPED_BAMBOO_BLOCK, null, null, Items.BAMBOO_SIGN, Items.BAMBOO_HANGING_SIGN, Items.BAMBOO_DOOR, Items.BAMBOO_BUTTON, Items.BAMBOO_STAIRS, Items.BAMBOO_SLAB, Items.BAMBOO_FENCE, Items.BAMBOO_FENCE_GATE, Items.BAMBOO_RAFT, Items.BAMBOO, null, Items.BAMBOO_PRESSURE_PLATE, Items.BAMBOO_TRAPDOOR); + p(WoodType.MANGROVE, "mangrove", Items.MANGROVE_PLANKS, Items.MANGROVE_LOG, Items.STRIPPED_MANGROVE_LOG, Items.STRIPPED_MANGROVE_WOOD, Items.MANGROVE_WOOD, Items.MANGROVE_SIGN, Items.MANGROVE_HANGING_SIGN, Items.MANGROVE_DOOR, Items.MANGROVE_BUTTON, Items.MANGROVE_STAIRS, Items.MANGROVE_SLAB, Items.MANGROVE_FENCE, Items.MANGROVE_FENCE_GATE, Items.MANGROVE_BOAT, Items.MANGROVE_PROPAGULE, Items.MANGROVE_LEAVES, Items.MANGROVE_PRESSURE_PLATE, Items.MANGROVE_TRAPDOOR); + p(WoodType.ACACIA, "acacia", Items.ACACIA_PLANKS, Items.ACACIA_LOG, Items.STRIPPED_ACACIA_LOG, Items.STRIPPED_ACACIA_WOOD, Items.ACACIA_WOOD, Items.ACACIA_SIGN, Items.ACACIA_HANGING_SIGN, Items.ACACIA_DOOR, Items.ACACIA_BUTTON, Items.ACACIA_STAIRS, Items.ACACIA_SLAB, Items.ACACIA_FENCE, Items.ACACIA_FENCE_GATE, Items.ACACIA_BOAT, Items.ACACIA_SAPLING, Items.ACACIA_LEAVES, Items.ACACIA_PRESSURE_PLATE, Items.ACACIA_TRAPDOOR); + p(WoodType.BIRCH, "birch", Items.BIRCH_PLANKS, Items.BIRCH_LOG, Items.STRIPPED_BIRCH_LOG, Items.STRIPPED_BIRCH_WOOD, Items.BIRCH_WOOD, Items.BIRCH_SIGN, Items.BIRCH_HANGING_SIGN, Items.BIRCH_DOOR, Items.BIRCH_BUTTON, Items.BIRCH_STAIRS, Items.BIRCH_SLAB, Items.BIRCH_FENCE, Items.BIRCH_FENCE_GATE, Items.BIRCH_BOAT, Items.BIRCH_SAPLING, Items.BIRCH_LEAVES, Items.BIRCH_PRESSURE_PLATE, Items.BIRCH_TRAPDOOR); + p(WoodType.CRIMSON, "crimson", Items.CRIMSON_PLANKS, Items.CRIMSON_STEM, Items.STRIPPED_CRIMSON_STEM, Items.STRIPPED_CRIMSON_HYPHAE, Items.CRIMSON_HYPHAE, Items.CRIMSON_SIGN, Items.CRIMSON_HANGING_SIGN, Items.CRIMSON_DOOR, Items.CRIMSON_BUTTON, Items.CRIMSON_STAIRS, Items.CRIMSON_SLAB, Items.CRIMSON_FENCE, Items.CRIMSON_FENCE_GATE, null, Items.CRIMSON_FUNGUS, null, Items.CRIMSON_PRESSURE_PLATE, Items.CRIMSON_TRAPDOOR); + p(WoodType.DARK_OAK, "dark_oak", Items.DARK_OAK_PLANKS, Items.DARK_OAK_LOG, Items.STRIPPED_DARK_OAK_LOG, Items.STRIPPED_DARK_OAK_WOOD, Items.DARK_OAK_WOOD, Items.DARK_OAK_SIGN, Items.DARK_OAK_HANGING_SIGN, Items.DARK_OAK_DOOR, Items.DARK_OAK_BUTTON, Items.DARK_OAK_STAIRS, Items.DARK_OAK_SLAB, Items.DARK_OAK_FENCE, Items.DARK_OAK_FENCE_GATE, Items.DARK_OAK_BOAT, Items.DARK_OAK_SAPLING, Items.DARK_OAK_LEAVES, Items.DARK_OAK_PRESSURE_PLATE, Items.DARK_OAK_TRAPDOOR); + p(WoodType.OAK, "oak", Items.OAK_PLANKS, Items.OAK_LOG, Items.STRIPPED_OAK_LOG, Items.STRIPPED_OAK_WOOD, Items.OAK_WOOD, Items.OAK_SIGN, Items.OAK_HANGING_SIGN, Items.OAK_DOOR, Items.OAK_BUTTON, Items.OAK_STAIRS, Items.OAK_SLAB, Items.OAK_FENCE, Items.OAK_FENCE_GATE, Items.OAK_BOAT, Items.OAK_SAPLING, Items.OAK_LEAVES, Items.OAK_PRESSURE_PLATE, Items.OAK_TRAPDOOR); + p(WoodType.JUNGLE, "jungle", Items.JUNGLE_PLANKS, Items.JUNGLE_LOG, Items.STRIPPED_JUNGLE_LOG, Items.STRIPPED_JUNGLE_WOOD, Items.JUNGLE_WOOD, Items.JUNGLE_SIGN, Items.JUNGLE_HANGING_SIGN, Items.JUNGLE_DOOR, Items.JUNGLE_BUTTON, Items.JUNGLE_STAIRS, Items.JUNGLE_SLAB, Items.JUNGLE_FENCE, Items.JUNGLE_FENCE_GATE, Items.JUNGLE_BOAT, Items.JUNGLE_SAPLING, Items.JUNGLE_LEAVES, Items.JUNGLE_PRESSURE_PLATE, Items.JUNGLE_TRAPDOOR); + p(WoodType.SPRUCE, "spruce", Items.SPRUCE_PLANKS, Items.SPRUCE_LOG, Items.STRIPPED_SPRUCE_LOG, Items.STRIPPED_SPRUCE_WOOD, Items.SPRUCE_WOOD, Items.SPRUCE_SIGN, Items.SPRUCE_HANGING_SIGN, Items.SPRUCE_DOOR, Items.SPRUCE_BUTTON, Items.SPRUCE_STAIRS, Items.SPRUCE_SLAB, Items.SPRUCE_FENCE, Items.SPRUCE_FENCE_GATE, Items.SPRUCE_BOAT, Items.SPRUCE_SAPLING, Items.SPRUCE_LEAVES, Items.SPRUCE_PRESSURE_PLATE, Items.SPRUCE_TRAPDOOR); + p(WoodType.WARPED, "warped", Items.WARPED_PLANKS, Items.WARPED_STEM, Items.STRIPPED_WARPED_STEM, Items.STRIPPED_WARPED_HYPHAE, Items.WARPED_HYPHAE, Items.WARPED_SIGN, Items.WARPED_HANGING_SIGN, Items.WARPED_DOOR, Items.WARPED_BUTTON, Items.WARPED_STAIRS, Items.WARPED_SLAB, Items.WARPED_FENCE, Items.WARPED_FENCE_GATE, null, Items.WARPED_FUNGUS, null, Items.WARPED_PRESSURE_PLATE, Items.WARPED_TRAPDOOR); } - void p(WoodType type, String prefix, Item planks, Item log, Item strippedLog, Item strippedWood, Item wood, Item sign, Item door, Item button, Item stairs, Item slab, Item fence, Item fenceGate, Item boat, Item sapling, Item leaves, Item pressurePlate, Item trapdoor) { - put(type, new WoodItems(prefix, planks, log, strippedLog, strippedWood, wood, sign, door, button, stairs, slab, fence, fenceGate, boat, sapling, leaves, pressurePlate, trapdoor)); + void p(WoodType type, String prefix, Item planks, Item log, Item strippedLog, Item strippedWood, Item wood, Item sign, Item hangingSign, Item door, Item button, Item stairs, Item slab, Item fence, Item fenceGate, Item boat, Item sapling, Item leaves, Item pressurePlate, Item trapdoor) { + put(type, new WoodItems(prefix, planks, log, strippedLog, strippedWood, wood, sign, hangingSign, door, button, stairs, slab, fence, fenceGate, boat, sapling, leaves, pressurePlate, trapdoor)); } }; private static final HashMap _cookableFoodMap = new HashMap<>() { @@ -282,6 +334,10 @@ public static Item planksToLog(Item plankItem) { return _planksToLogs.getOrDefault(plankItem, null); } + public static Item strippedToLogs(Item logItem) { + return _strippedToLogs.getOrDefault(logItem, null); + } + public static ColorfulItems getColorfulItems(MapColor color) { return _colorMap.get(color); } @@ -316,20 +372,17 @@ public static String trimItemName(String name) { } public static boolean areShearsEffective(Block b) { - return - //b.getRegistryEntry().streamTags().anyMatch(t -> t == - // BlockTags.LEAVES); should also work... but is slower - b instanceof LeavesBlock - || b == Blocks.COBWEB - || b == Blocks.GRASS - || b == Blocks.TALL_GRASS - || b == Blocks.LILY_PAD - || b == Blocks.FERN - || b == Blocks.DEAD_BUSH - || b == Blocks.VINE - || b == Blocks.TRIPWIRE - || isOfBlockType(b, BlockTags.WOOL) - || b == Blocks.NETHER_SPROUTS; + return b instanceof LeavesBlock + || b == Blocks.COBWEB + || b == Blocks.GRASS_BLOCK + || b == Blocks.TALL_GRASS + || b == Blocks.LILY_PAD + || b == Blocks.FERN + || b == Blocks.DEAD_BUSH + || b == Blocks.VINE + || b == Blocks.TRIPWIRE + || isOfBlockType(b, BlockTags.WOOL) + || b == Blocks.NETHER_SPROUTS; } public static boolean isOfBlockType(Block b, TagKey tag) { @@ -339,7 +392,7 @@ public static boolean isOfBlockType(Block b, TagKey tag) { private static boolean isStackProtected(AltoClef mod, ItemStack stack) { if (stack.hasEnchantments() && mod.getModSettings().getDontThrowAwayEnchantedItems()) return true; - if (stack.hasCustomName() && mod.getModSettings().getDontThrowAwayCustomNameItems()) + if (stack.getItem().getComponents().contains(DataComponentTypes.CUSTOM_NAME) && mod.getModSettings().getDontThrowAwayCustomNameItems()) return true; return mod.getBehaviour().isProtected(stack.getItem()) || mod.getModSettings().isImportant(stack.getItem()); } @@ -436,6 +489,7 @@ public static class WoodItems { public Item strippedWood; public Item wood; public Item sign; + public Item hangingSign; public Item door; public Item button; public Item stairs; @@ -448,7 +502,7 @@ public static class WoodItems { public Item pressurePlate; public Item trapdoor; - public WoodItems(String prefix, Item planks, Item log, Item strippedLog, Item strippedWood, Item wood, Item sign, Item door, Item button, Item stairs, Item slab, Item fence, Item fenceGate, Item boat, Item sapling, Item leaves, Item pressurePlate, Item trapdoor) { + public WoodItems(String prefix, Item planks, Item log, Item strippedLog, Item strippedWood, Item wood, Item sign, Item hangingSign, Item door, Item button, Item stairs, Item slab, Item fence, Item fenceGate, Item boat, Item sapling, Item leaves, Item pressurePlate, Item trapdoor) { this.prefix = prefix; this.planks = planks; this.log = log; @@ -456,6 +510,7 @@ public WoodItems(String prefix, Item planks, Item log, Item strippedLog, Item st this.strippedWood = strippedWood; this.wood = wood; this.sign = sign; + this.hangingSign = hangingSign; this.door = door; this.button = button; this.stairs = stairs; diff --git a/src/main/java/adris/altoclef/util/helpers/LookHelper.java b/src/main/java/adris/altoclef/util/helpers/LookHelper.java index f60689338..d2879e8ba 100644 --- a/src/main/java/adris/altoclef/util/helpers/LookHelper.java +++ b/src/main/java/adris/altoclef/util/helpers/LookHelper.java @@ -20,143 +20,370 @@ import net.minecraft.util.hit.HitResult; import net.minecraft.util.math.*; import net.minecraft.world.RaycastContext; +import net.minecraft.world.World; +import java.util.Objects; import java.util.Optional; /** * Helper functions to interpret and change our player's look direction */ public interface LookHelper { - + /** + * Calculate the reachable rotation for a given target and side. + * + * @param target the target block position + * @param side the side direction + * @return an optional rotation if reachable, otherwise empty + */ static Optional getReach(BlockPos target, Direction side) { - Optional reachable; - IPlayerContext ctx = BaritoneAPI.getProvider().getPrimaryBaritone().getPlayerContext(); + // Get the player context + IPlayerContext context = BaritoneAPI.getProvider().getPrimaryBaritone().getPlayerContext(); + + // Declare the reachable rotation variable + Optional reachableRotation; + + // Check if the side is null if (side == null) { - assert MinecraftClient.getInstance().player != null; - reachable = RotationUtils.reachable(ctx.player(), target, ctx.playerController().getBlockReachDistance()); + // Calculate the reachable rotation from the player's position to the target position + reachableRotation = RotationUtils.reachable(context, target); } else { + // Calculate the center offset vector based on the side direction Vec3i sideVector = side.getVector(); - Vec3d centerOffset = new Vec3d(0.5 + sideVector.getX() * 0.5, 0.5 + sideVector.getY() * 0.5, 0.5 + sideVector.getZ() * 0.5); + Vec3d centerOffset = new Vec3d(0.5 + sideVector.getX() * 0.5, 0.5 + sideVector.getY() * 0.5, + 0.5 + sideVector.getZ() * 0.5); + // Calculate the side point based on the center offset and target position Vec3d sidePoint = centerOffset.add(target.getX(), target.getY(), target.getZ()); - //reachable(this.ctx.player(), _target, this.ctx.playerController().getBlockReachDistance()); - reachable = RotationUtils.reachableOffset(ctx.player(), target, sidePoint, ctx.playerController().getBlockReachDistance(), false); + // Calculate the reachable rotation from the player's position to the side point + reachableRotation = RotationUtils.reachableOffset(context, target, sidePoint, + context.playerController().getBlockReachDistance(), false); - // Check for right angle - if (reachable.isPresent()) { - // Note: If sneak, use RotationUtils.inferSneakingEyePosition - Vec3d camPos = ctx.player().getCameraPosVec(1.0F); - Vec3d vecToPlayerPos = camPos.subtract(sidePoint); + // Check if the reachable rotation is present + if (reachableRotation.isPresent()) { + // Calculate the camera position and vector to player position + Vec3d cameraPos = context.player().getCameraPosVec(1.0F); + Vec3d vecToPlayerPos = cameraPos.subtract(sidePoint); - double dot = vecToPlayerPos.normalize().dotProduct(new Vec3d(sideVector.getX(), sideVector.getY(), sideVector.getZ())); - if (dot < 0) { - // We're perpendicular and cannot face. + // Calculate the dot product between the vector to player position and the side vector + double dotProduct = vecToPlayerPos.normalize().dotProduct( + new Vec3d(sideVector.getX(), sideVector.getY(), sideVector.getZ())); + + // Check if the dot product is less than 0 + if (dotProduct < 0) { + // Return an empty optional rotation return Optional.empty(); } } } - return reachable; + + // Return the reachable rotation + return reachableRotation; } + /** + * Gets the reach for a given target position. + * + * @param target The target position. + * @return An Optional containing the Rotation if reach is possible, or an empty Optional otherwise. + */ static Optional getReach(BlockPos target) { + + // Delegate to the overloaded method with a null entity return getReach(target, null); } + /** + * Calculates a raycast from one entity to another. + * + * @param from The entity from which the raycast originates. + * @param to The entity at which the raycast is aimed. + * @param reachDistance The maximum distance the raycast can reach. + * @return The result of the raycast. + */ static EntityHitResult raycast(Entity from, Entity to, double reachDistance) { - Vec3d fromPos = getCameraPos(from), - toPos = getCameraPos(to); - Vec3d direction = (toPos.subtract(fromPos).normalize().multiply(reachDistance)); + // Get the starting position of the raycast + Vec3d start = getCameraPos(from); + + // Get the ending position of the raycast + Vec3d end = getCameraPos(to); + + // Calculate the direction of the raycast + Vec3d direction = end.subtract(start).normalize().multiply(reachDistance); + + // Get the bounding box of the target entity Box box = to.getBoundingBox(); - return ProjectileUtil.raycast(from, fromPos, fromPos.add(direction), box, entity -> entity.equals(to), 0); + + // Perform the raycast and return the result + return ProjectileUtil.raycast(from, start, start.add(direction), box, entity -> entity.equals(to), 0); } - static boolean seesPlayer(Entity entity, Entity player, double maxRange, Vec3d entityOffs, Vec3d playerOffs) { - return seesPlayerOffset(entity, player, maxRange, entityOffs, playerOffs) || seesPlayerOffset(entity, player, maxRange, entityOffs, new Vec3d(0, -1, 0).add(playerOffs)); + /** + * Check if an entity can see a player within a certain range, taking into account entity and player offsets. + * + * @param entity The entity to check. + * @param player The player entity to check against. + * @param maxRange The maximum range within which the entity can see the player. + * @param entityOffset The offset of the entity. + * @param playerOffset The offset of the player. + * @return True if the entity can see the player, false otherwise. + */ + static boolean seesPlayer(Entity entity, Entity player, double maxRange, Vec3d entityOffset, Vec3d playerOffset) { + return seesPlayerOffset(entity, player, maxRange, entityOffset, playerOffset) + || seesPlayerOffset(entity, player, maxRange, entityOffset, playerOffset.add(0, -1, 0)); } + /** + * Determines if the given entity can see the player within the specified range. + * + * @param entity the entity to check visibility from + * @param player the player entity to check visibility to + * @param maxRange the maximum range within which the player can be seen + * @return true if the player is visible within the specified range, false otherwise + */ static boolean seesPlayer(Entity entity, Entity player, double maxRange) { - return seesPlayer(entity, player, maxRange, Vec3d.ZERO, Vec3d.ZERO); + return seesPlayer(entity, player, maxRange, new Vec3d(0, 0, 0), new Vec3d(0, 0, 0)); } + /** + * Checks if there is a clear line of sight between the start and end points for the given entity. + * + * @param entity The entity to check line of sight for. + * @param start The starting position of the line of sight. + * @param end The ending position of the line of sight. + * @param maxRange The maximum range for the line of sight. + * @return true if there is a clear line of sight, false otherwise. + */ static boolean cleanLineOfSight(Entity entity, Vec3d start, Vec3d end, double maxRange) { - return raycast(entity, start, end, maxRange).getType() == HitResult.Type.MISS; + // Perform a raycast between the start and end points with the given max range + HitResult result = raycast(entity, start, end, maxRange); + + // Check the type of the hit result to determine if there is a clear line of sight + return result.getType() == HitResult.Type.MISS; } + /** + * Checks if there is a clear line of sight between an entity and a specified location. + * + * @param entity The entity from which to check the line of sight. + * @param end The end location to check the line of sight to. + * @param maxRange The maximum range at which the line of sight can be checked. + * @return True if there is a clear line of sight, false otherwise. + */ static boolean cleanLineOfSight(Entity entity, Vec3d end, double maxRange) { + // Get the starting position of the line of sight Vec3d start = getCameraPos(entity); + + // Check if there is a clear line of sight between the starting and end positions, + // within the maximum range return cleanLineOfSight(entity, start, end, maxRange); } + /** + * Checks if there is a clear line of sight between the player and a given point. + * + * @param end The end point to check for line of sight. + * @param maxRange The maximum range to check for line of sight. + * @return True if there is a clear line of sight, false otherwise. + */ static boolean cleanLineOfSight(Vec3d end, double maxRange) { - return cleanLineOfSight(MinecraftClient.getInstance().player, end, maxRange); + MinecraftClient minecraftClient = MinecraftClient.getInstance(); + PlayerEntity playerEntity = minecraftClient.player; + return cleanLineOfSight(playerEntity, end, maxRange); } + /** + * Checks if there is a clear line of sight between an entity and a block position within a given maximum range. + * + * @param entity The entity from which the line of sight is checked. + * @param block The block position to check the line of sight to. + * @param maxRange The maximum range to check for line of sight. + * @return True if there is a clear line of sight, false otherwise. + */ static boolean cleanLineOfSight(Entity entity, BlockPos block, double maxRange) { - Vec3d center = WorldHelper.toVec3d(block); - BlockHitResult hit = raycast(entity, getCameraPos(entity), center, maxRange); - if (hit == null) return true; - return switch (hit.getType()) { - case MISS -> true; - case BLOCK -> hit.getBlockPos().equals(block); - case ENTITY -> false; - }; + // Convert the block position to a Vec3d + Vec3d targetPosition = WorldHelper.toVec3d(block); + + // Perform a raycast from the entity's camera position to the target position with the specified max range + BlockHitResult hitResult = raycast(entity, getCameraPos(entity), targetPosition, maxRange); + + // Check the result of the raycast + if (hitResult == null) { + // No hit result, clear line of sight + return true; + } else { + return switch (hitResult.getType()) { + case MISS -> + // Missed the target, clear line of sight + true; + case BLOCK -> + // Hit a block, check if it's the same as the target block + hitResult.getBlockPos().equals(block); + case ENTITY -> + // Hit an entity, line of sight blocked + false; + }; + } } - static Vec3d toVec3d(Rotation rotation) { - return RotationUtils.calcVector3dFromRotation(rotation); + /** + * Convert a Rotation object to a Vec3d object. + * + * @param rotation the Rotation object to convert + * @return the corresponding Vec3d object + * @throws NullPointerException if the rotation is null + */ + static Vec3d toVec3d(Rotation rotation) throws NullPointerException { + // make sure rotation is not null + Objects.requireNonNull(rotation, "Rotation cannot be null"); + + // calculate the look direction from the rotation + return RotationUtils.calcLookDirectionFromRotation(rotation); } + /** + * Performs a raycast from the start point to the end point within a maximum range. + * + * @param entity the entity performing the raycast + * @param start the starting point of the raycast + * @param end the ending point of the raycast + * @param maxRange the maximum range of the raycast + * @return the result of the raycast + */ static BlockHitResult raycast(Entity entity, Vec3d start, Vec3d end, double maxRange) { - Vec3d delta = end.subtract(start); - if (delta.lengthSquared() > maxRange * maxRange) { - end = start.add(delta.normalize().multiply(maxRange)); + // Calculate the direction vector + Vec3d direction = end.subtract(start); + + // Check if the direction vector length exceeds the maximum range + if (direction.lengthSquared() > maxRange * maxRange) { + // If it does, normalize the direction vector and multiply it by the maximum range + direction = direction.normalize().multiply(maxRange); + // Update the end point of the raycast to the new calculated position + end = start.add(direction); } - return entity.world.raycast(new RaycastContext(start, end, RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, entity)); + + // Get the world of the entity + World world = entity.getWorld(); + + // Create a raycast context with the start and end points, shape type, fluid handling, and entity performing the raycast + RaycastContext context = new RaycastContext(start, end, RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, entity); + + // Perform the raycast in the world and return the result + return world.raycast(context); } + /** + * Performs a raycast from the entity's camera position to the specified end point + * with a maximum range. + * + * @param entity The entity performing the raycast + * @param end The end point of the raycast + * @param maxRange The maximum range of the raycast + * @return The result of the raycast + */ static BlockHitResult raycast(Entity entity, Vec3d end, double maxRange) { Vec3d start = getCameraPos(entity); return raycast(entity, start, end, maxRange); } + /** + * Get the look rotation of an entity. + * + * @param entity the entity to get the look rotation for + * @return the look rotation of the entity + */ static Rotation getLookRotation(Entity entity) { float pitch = entity.getPitch(); float yaw = entity.getYaw(); return new Rotation(yaw, pitch); } + /** + * Retrieves the look rotation of the player. + * If the player is null, returns a default rotation of (0, 0). + * + * @return The look rotation of the player. + */ static Rotation getLookRotation() { - if (MinecraftClient.getInstance().player == null) { + // Retrieve the player instance + PlayerEntity player = MinecraftClient.getInstance().player; + + // If the player is null, return a default rotation + if (player == null) { return new Rotation(0, 0); } - return getLookRotation(MinecraftClient.getInstance().player); + + // Get the look rotation of the player + return getLookRotation(player); } + /** + * Retrieves the camera position of the given entity. + * If the entity is a player and is sneaking, the sneaking eye position is inferred. + * Otherwise, the default camera position of the entity is returned. + * + * @param entity The entity for which to retrieve the camera position. + * @return The camera position of the entity. + */ static Vec3d getCameraPos(Entity entity) { - boolean isSneaking = false; - if (entity instanceof PlayerEntity player) { - isSneaking = player.isSneaking(); + boolean isPlayerSneaking = entity instanceof PlayerEntity && entity.isSneaking(); + + // If the entity is a player and is sneaking, infer the sneaking eye position + if (isPlayerSneaking) { + return RayTraceUtils.inferSneakingEyePosition(entity); + } else { + // Otherwise, return the default camera position of the entity + return entity.getCameraPosVec(1.0F); } - return isSneaking ? RayTraceUtils.inferSneakingEyePosition(entity) : entity.getCameraPosVec(1.0F); } + /** + * Retrieves the camera position vector of the player. + * + * @param mod The instance of the AltoClef mod. + * @return The camera position vector. + */ static Vec3d getCameraPos(AltoClef mod) { - IPlayerContext ctx = BaritoneAPI.getProvider().getPrimaryBaritone().getPlayerContext(); - return ctx.player().getCameraPosVec(1); + // Get the player context from the Baritone API + IPlayerContext playerContext = BaritoneAPI.getProvider().getPrimaryBaritone().getPlayerContext(); + + // Get the camera position vector from the player context + return playerContext.player().getCameraPosVec(1); } - // 1: Looking straight at pos - // 0: pos is 90 degrees to the side - // -1: pos is 180 degrees away (looking away completely) + /** + * Calculates the closeness between an entity's look direction and a given position. + * + * @param entity The entity to calculate the closeness for. + * @param pos The position to compare the look direction to. + * @return The closeness value between the look direction and the position. + */ static double getLookCloseness(Entity entity, Vec3d pos) { + // Get the direction that the entity is facing Vec3d rotDirection = entity.getRotationVecClient(); + + // Get the starting position of the entity's line of sight Vec3d lookStart = getCameraPos(entity); + + // Calculate the vector from the look start position to the given position Vec3d deltaToPos = pos.subtract(lookStart); + + // Normalize the delta vector to get the direction Vec3d deltaDirection = deltaToPos.normalize(); + + // Calculate the dot product of the rotation direction and the delta direction return rotDirection.dotProduct(deltaDirection); } + /** + * Tries to avoid colliding with an interactable object. + * If a collision is detected, the function randomly changes the orientation and returns false. + * If no collision is detected, the function returns true. + * + * @param mod The AltoClef object. + * @return True if no collision is detected, false otherwise. + */ static boolean tryAvoidingInteractable(AltoClef mod) { if (isCollidingInteractable(mod)) { randomOrientation(mod); @@ -165,88 +392,306 @@ static boolean tryAvoidingInteractable(AltoClef mod) { return true; } + /** + * Determines whether an entity can see another entity with specified offsets. + * + * @param entity The entity that is trying to see the player. + * @param player The player entity that is being looked at. + * @param maxRange The maximum range within which the player can be seen. + * @param offsetEntity The offset of the camera position for the entity. + * @param offsetPlayer The offset of the camera position for the player. + * @return True if the entity can see the player, false otherwise. + */ private static boolean seesPlayerOffset(Entity entity, Entity player, double maxRange, Vec3d offsetEntity, Vec3d offsetPlayer) { - Vec3d start = getCameraPos(entity).add(offsetEntity); - Vec3d end = getCameraPos(player).add(offsetPlayer); - return cleanLineOfSight(entity, start, end, maxRange); + // Calculate the camera positions for the entity and player + Vec3d entityCameraPos = getCameraPos(entity).add(offsetEntity); + Vec3d playerCameraPos = getCameraPos(player).add(offsetPlayer); + + // Check if there is a clean line of sight between the entity and player within the specified range + return cleanLineOfSight(entity, entityCameraPos, playerCameraPos, maxRange); } + /** + * Checks if the player is colliding with an interactable object. + * + * @param mod The instance of the AltoClef mod. + * @return True if the player is colliding with an interactable object, false otherwise. + */ private static boolean isCollidingInteractable(AltoClef mod) { - + // Check if the player is in a screen other than the player screen if (!(mod.getPlayer().currentScreenHandler instanceof PlayerScreenHandler)) { + // Get the item stack in the cursor slot ItemStack cursorStack = StorageHelper.getItemStackInCursorSlot(); + + // Check if the cursor stack is not empty if (!cursorStack.isEmpty()) { + // Find a slot in the player's inventory to move the cursor stack to Optional moveTo = mod.getItemStorage().getSlotThatCanFitInPlayerInventory(cursorStack, false); moveTo.ifPresent(slot -> mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP)); + + // Check if the cursor stack can be thrown away if (ItemHelper.canThrowAwayStack(mod, cursorStack)) { mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); } + + // Find the garbage slot and move the cursor stack to it Optional garbage = StorageHelper.getGarbageSlot(mod); - // Try throwing away cursor slot if it's garbage garbage.ifPresent(slot -> mod.getSlotHandler().clickSlot(slot, 0, SlotActionType.PICKUP)); + + // Move the cursor stack to an undefined slot mod.getSlotHandler().clickSlot(Slot.UNDEFINED, 0, SlotActionType.PICKUP); } else { + // Close the screen if the cursor stack is empty StorageHelper.closeScreen(); } + return true; } + // Get the crosshair target HitResult result = MinecraftClient.getInstance().crosshairTarget; - if (result == null) return false; + + // Check if the crosshair target is null + if (result == null) { + return false; + } + + // Check if the crosshair target is a block if (result.getType() == HitResult.Type.BLOCK) { + // Get the block position from the crosshair target Vec3i resultGetPosOrigin = new Vec3i((int) result.getPos().getX(), (int) result.getPos().getY(), (int) result.getPos().getZ()); + // Check if the block is an interactable block return WorldHelper.isInteractableBlock(mod, new BlockPos(resultGetPosOrigin)); - } else if (result.getType() == HitResult.Type.ENTITY) { - if (result instanceof EntityHitResult) { - Entity entity = ((EntityHitResult) result).getEntity(); - return entity instanceof MerchantEntity; - } } + // Check if the crosshair target is an entity + else if (result.getType() == HitResult.Type.ENTITY && result instanceof EntityHitResult) { + // Get the entity from the crosshair target + Entity entity = ((EntityHitResult) result).getEntity(); + // Check if the entity is a merchant + return entity instanceof MerchantEntity; + } + return false; } + /** + * Sets a random orientation for the given mod. + * + * @param mod The mod to set the orientation for. + */ static void randomOrientation(AltoClef mod) { - Rotation r = new Rotation((float) Math.random() * 360f, -90 + (float) Math.random() * 180f); + // Generate random rotation angles + float randomRotationX = (float) (Math.random() * 360f); + float randomRotationY = -90 + (float) (Math.random() * 180f); + + // Create a new Rotation object with the random angles + Rotation r = new Rotation(randomRotationX, randomRotationY); + + // Set the mod to look at the rotation lookAt(mod, r); } + /** + * Checks if the given rotation is close to the current look rotation. + * + * @param mod The instance of the AltoClef class. + * @param rotation The rotation to compare with the current look rotation. + * @return True if the rotation is close to the current look rotation, false otherwise. + */ static boolean isLookingAt(AltoClef mod, Rotation rotation) { return rotation.isReallyCloseTo(getLookRotation()); } - static boolean isLookingAt(AltoClef mod, BlockPos blockPos) { - return mod.getClientBaritone().getPlayerContext().isLookingAt(blockPos); + /** + * Check if the player is looking at a specific block position. + * + * @param mod The instance of the AltoClef mod. + * @param pos The block position to check. + * @return True if the player is looking at the given block position, false otherwise. + */ + static boolean isLookingAt(AltoClef mod, BlockPos pos) { + return mod.getClientBaritone().getPlayerContext().isLookingAt(pos); } + /** + * Updates the player's look direction and rotation. + * + * @param mod The instance of AltoClef. + * @param rotation The desired rotation to look at. + * @param withBaritone Whether to use Baritone to look. + */ + static void lookAt(AltoClef mod, Rotation rotation, boolean withBaritone) { + if (withBaritone) { + // Update the target rotation in the LookBehavior + mod.getClientBaritone().getLookBehavior().updateTarget(rotation, true); + } + + // Set the player's yaw and pitch + mod.getPlayer().setYaw(rotation.getYaw()); + mod.getPlayer().setPitch(rotation.getPitch()); + } + + /** + * Updates the player's look direction and rotation. + * + * @param mod The instance of AltoClef. + * @param rotation The desired rotation to look at. + */ static void lookAt(AltoClef mod, Rotation rotation) { + // Update the target rotation in the LookBehavior mod.getClientBaritone().getLookBehavior().updateTarget(rotation, true); + + // Set the player's yaw and pitch mod.getPlayer().setYaw(rotation.getYaw()); mod.getPlayer().setPitch(rotation.getPitch()); } + /** + * Adjusts the player's look direction to the specified target position. + * + * @param mod The AltoClef instance. + * @param toLook The position to look at. + * @param withBaritone Whether to use Baritone to look. + * @throws IllegalArgumentException if mod or toLook is null. + */ + static void lookAt(AltoClef mod, Vec3d toLook, boolean withBaritone) { + if (mod == null || toLook == null) { + throw new IllegalArgumentException("mod and toLook cannot be null"); + } + + Rotation targetRotation = getLookRotation(mod, toLook); + lookAt(mod, targetRotation, withBaritone); + } + + /** + * Adjusts the player's look direction to the specified target position. + * + * @param mod The AltoClef instance. + * @param toLook The position to look at. + * @throws IllegalArgumentException if mod or toLook is null. + */ static void lookAt(AltoClef mod, Vec3d toLook) { + if (mod == null || toLook == null) { + throw new IllegalArgumentException("mod and toLook cannot be null"); + } + Rotation targetRotation = getLookRotation(mod, toLook); - lookAt(mod, targetRotation); + lookAt(mod, targetRotation, true); + } + + /** + * Adjusts the player's view to look at a specific location from a specific direction. + * + * @param mod The AltoClef mod instance. + * @param toLook The position to look at. + * @param side The direction to look from. + * @param withBaritone Whether to use Baritone to look. + */ + static void lookAt(AltoClef mod, BlockPos toLook, Direction side, boolean withBaritone) { + // Calculate the center coordinates of the target location + double centerX = toLook.getX() + 0.5; + double centerY = toLook.getY() + 0.5; + double centerZ = toLook.getZ() + 0.5; + + // Adjust the center coordinates based on the specified side + if (side != null) { + double offsetX = side.getVector().getX() * 0.5; + double offsetY = side.getVector().getY() * 0.5; + double offsetZ = side.getVector().getZ() * 0.5; + centerX += offsetX; + centerY += offsetY; + centerZ += offsetZ; + } + + // Create a target vector based on the adjusted center coordinates + Vec3d target = new Vec3d(centerX, centerY, centerZ); + + // Adjust the player's view to look at the target location + lookAt(mod, target, withBaritone); } + /** + * Adjusts the player's view to look at a specific location from a specific direction. + * + * @param mod The AltoClef mod instance. + * @param toLook The position to look at. + * @param side The direction to look from. + */ static void lookAt(AltoClef mod, BlockPos toLook, Direction side) { - Vec3d target = new Vec3d(toLook.getX() + 0.5, toLook.getY() + 0.5, toLook.getZ() + 0.5); + // Calculate the center coordinates of the target location + double centerX = toLook.getX() + 0.5; + double centerY = toLook.getY() + 0.5; + double centerZ = toLook.getZ() + 0.5; + + // Adjust the center coordinates based on the specified side if (side != null) { - target.add(side.getVector().getX() * 0.5, side.getVector().getY() * 0.5, side.getVector().getZ() * 0.5); + double offsetX = side.getVector().getX() * 0.5; + double offsetY = side.getVector().getY() * 0.5; + double offsetZ = side.getVector().getZ() * 0.5; + centerX += offsetX; + centerY += offsetY; + centerZ += offsetZ; } - lookAt(mod, target); + + // Create a target vector based on the adjusted center coordinates + Vec3d target = new Vec3d(centerX, centerY, centerZ); + + // Adjust the player's view to look at the target location + lookAt(mod, target, true); } + /** + * Looks at the specified block position. + * + * @param mod The AltoClef instance. + * @param toLook The block position to look at. + * @param withBaritone Whether to use Baritone to look. + */ + static void lookAt(AltoClef mod, BlockPos toLook, boolean withBaritone) { + lookAt(mod, toLook, null, withBaritone); + } + + /** + * Looks at the specified block position. + * + * @param mod The AltoClef instance. + * @param toLook The block position to look at. + */ static void lookAt(AltoClef mod, BlockPos toLook) { - lookAt(mod, toLook, null); + lookAt(mod, toLook, null, true); } + /** + * Calculates the rotation needed for a player to look at a specified point. + * + * @param mod The instance of the main mod class. + * @param toLook The coordinates to look at. + * @return The rotation needed to look at the specified point. + */ static Rotation getLookRotation(AltoClef mod, Vec3d toLook) { - return RotationUtils.calcRotationFromVec3d(mod.getClientBaritone().getPlayerContext().playerHead(), toLook, mod.getClientBaritone().getPlayerContext().playerRotations()); + // Get the player's head position + Vec3d playerHead = mod.getClientBaritone().getPlayerContext().playerHead(); + + // Get the player's current rotations + Rotation playerRotations = mod.getClientBaritone().getPlayerContext().playerRotations(); + + // Calculate the rotation needed to look at the specified point + return RotationUtils.calcRotationFromVec3d(playerHead, toLook, playerRotations); } + /** + * Returns the rotation needed to look at a specified position. + * + * @param mod The AltoClef mod instance. + * @param toLook The position to look at, specified by its BlockPos. + * @return The Rotation object representing the rotation needed to look at the position. + */ static Rotation getLookRotation(AltoClef mod, BlockPos toLook) { - return getLookRotation(mod, WorldHelper.toVec3d(toLook)); + // Convert BlockPos to Vec3d + Vec3d targetPosition = WorldHelper.toVec3d(toLook); + + // Delegate to the overloaded version of getLookRotation + return getLookRotation(mod, targetPosition); } } diff --git a/src/main/java/adris/altoclef/util/helpers/StorageHelper.java b/src/main/java/adris/altoclef/util/helpers/StorageHelper.java index 9809d0fe5..3e8bc5157 100644 --- a/src/main/java/adris/altoclef/util/helpers/StorageHelper.java +++ b/src/main/java/adris/altoclef/util/helpers/StorageHelper.java @@ -5,7 +5,10 @@ import adris.altoclef.TaskCatalogue; import adris.altoclef.mixins.AbstractFurnaceScreenHandlerAccessor; import adris.altoclef.tasks.CraftInInventoryTask; -import adris.altoclef.util.*; +import adris.altoclef.util.CraftingRecipe; +import adris.altoclef.util.ItemTarget; +import adris.altoclef.util.MiningRequirement; +import adris.altoclef.util.RecipeTarget; import adris.altoclef.util.slots.CraftingTableSlot; import adris.altoclef.util.slots.CursorSlot; import adris.altoclef.util.slots.PlayerSlot; @@ -18,9 +21,9 @@ import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.option.GameOptionsScreen; import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.component.DataComponentTypes; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.*; -import net.minecraft.recipe.Recipe; import net.minecraft.screen.*; import org.apache.commons.lang3.ArrayUtils; @@ -142,7 +145,7 @@ public static Optional getBestToolSlot(AltoClef mod, BlockState state) { continue; ItemStack stack = getItemStackInSlot(slot); if (stack.getItem() instanceof ToolItem) { - if (stack.getItem().isSuitableFor(state)) { + if (stack.isSuitableFor(state)) { double speed = ToolSet.calculateSpeedVsBlock(stack, state); if (speed > highestSpeed) { highestSpeed = speed; @@ -201,7 +204,7 @@ public static Optional getGarbageSlot(AltoClef mod) { Item item = stack.getItem(); if (item instanceof ToolItem tool) { Class c = tool.getClass(); - int level = tool.getMaterial().getMiningLevel(); + int level = tool.getMaterial().getDurability(); int prevBest = bestMaterials.getOrDefault(c, 0); if (level > prevBest) { // We had a WORSE tool before. @@ -240,8 +243,8 @@ public static Optional getGarbageSlot(AltoClef mod) { if (ItemHelper.canThrowAwayStack(mod, stack)) { possibleSlots.add(slot); } - if (stack.getItem().isFood()) { - calcTotalFoodScore += Objects.requireNonNull(stack.getItem().getFoodComponent()).getHunger(); + if (stack.getItem().getComponents().contains(DataComponentTypes.FOOD)) { + calcTotalFoodScore += Objects.requireNonNull(stack.getItem().getComponents().get(DataComponentTypes.FOOD)).nutrition(); } } } @@ -264,8 +267,8 @@ public static Optional getGarbageSlot(AltoClef mod) { // Prioritize material type, then durability. ToolItem leftTool = (ToolItem) left.getItem(); ToolItem rightTool = (ToolItem) right.getItem(); - if (leftTool.getMaterial().getMiningLevel() != rightTool.getMaterial().getMiningLevel()) { - return leftTool.getMaterial().getMiningLevel() - rightTool.getMaterial().getMiningLevel(); + if (leftTool.getMaterial().getDurability() != rightTool.getMaterial().getDurability()) { + return (int) (leftTool.getMaterial().getDurability() - rightTool.getMaterial().getDurability()); } // We want less damage. return left.getDamage() - right.getDamage(); @@ -273,8 +276,8 @@ public static Optional getGarbageSlot(AltoClef mod) { // Prioritize food over other things if we lack food. boolean lacksFood = totalFoodScore < 8; - boolean leftIsFood = left.getItem().isFood() && left.getItem() != Items.SPIDER_EYE; - boolean rightIsFood = right.getItem().isFood() && right.getItem() != Items.SPIDER_EYE; + boolean leftIsFood = left.getItem().getComponents().contains(DataComponentTypes.FOOD) && left.getItem() != Items.SPIDER_EYE; + boolean rightIsFood = right.getItem().getComponents().contains(DataComponentTypes.FOOD) && right.getItem() != Items.SPIDER_EYE; if (lacksFood) { if (rightIsFood && !leftIsFood) { return -1; @@ -284,11 +287,11 @@ public static Optional getGarbageSlot(AltoClef mod) { } // If both are food, pick the better cost. if (leftIsFood && rightIsFood) { - assert left.getItem().getFoodComponent() != null; - assert right.getItem().getFoodComponent() != null; - int leftCost = left.getItem().getFoodComponent().getHunger() * left.getCount(), - rightCost = right.getItem().getFoodComponent().getHunger() * right.getCount(); - return -1 * (leftCost - rightCost); + assert left.getItem().getComponents().get(DataComponentTypes.FOOD) != null; + assert right.getItem().getComponents().get(DataComponentTypes.FOOD) != null; + int leftCost = left.getItem().getComponents().get(DataComponentTypes.FOOD).nutrition() * left.getCount(), + rightCost = right.getItem().getComponents().get(DataComponentTypes.FOOD).nutrition() * right.getCount(); + return leftCost - rightCost; } // Just discard the one with the smallest quantity, but this doesn't really matter. @@ -387,8 +390,8 @@ public static int calculateInventoryFoodScore(AltoClef mod) { int result = 0; if (!mod.getItemStorage().getItemStacksPlayerInventory(true).isEmpty()) { for (ItemStack stack : mod.getItemStorage().getItemStacksPlayerInventory(true)) { - if (stack.isFood()) - result += Objects.requireNonNull(stack.getItem().getFoodComponent()).getHunger() * stack.getCount(); + if (stack.getItem().getComponents().contains(DataComponentTypes.FOOD)) + result += Objects.requireNonNull(stack.getItem().getComponents().get(DataComponentTypes.FOOD)).nutrition() * stack.getCount(); } } return result; @@ -622,13 +625,4 @@ public static ItemTarget[] getAllInventoryItemsAsTargets(Predicate accept) } return results; } - - public static void instantFillRecipeViaBook(AltoClef mod, CraftingRecipe recipe, Item output, boolean craftAll) { - Optional> recipeToSend = JankCraftingRecipeMapping.getMinecraftMappedRecipe(recipe, output); - if (recipeToSend.isPresent()) { - mod.getController().clickRecipe(MinecraftClient.getInstance().player.currentScreenHandler.syncId, recipeToSend.get(), craftAll); - } else { - Debug.logError("Could not find recipe stored in Minecraft!! Recipe: " + recipe + " with output " + output); - } - } } diff --git a/src/main/java/adris/altoclef/util/helpers/WorldHelper.java b/src/main/java/adris/altoclef/util/helpers/WorldHelper.java index 9bb4feb88..ad8f8ae41 100644 --- a/src/main/java/adris/altoclef/util/helpers/WorldHelper.java +++ b/src/main/java/adris/altoclef/util/helpers/WorldHelper.java @@ -2,7 +2,6 @@ import adris.altoclef.AltoClef; import adris.altoclef.mixins.ClientConnectionAccessor; -import adris.altoclef.mixins.EntityAccessor; import adris.altoclef.util.Dimension; import baritone.api.BaritoneAPI; import baritone.pathing.movement.CalculationContext; @@ -20,10 +19,10 @@ import net.minecraft.network.ClientConnection; import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.util.math.*; -import net.minecraft.util.math.random.Random; import net.minecraft.world.World; import net.minecraft.world.biome.Biome; import net.minecraft.world.biome.BiomeKeys; +import net.minecraft.world.dimension.PortalManager; import java.util.*; @@ -77,7 +76,7 @@ static boolean isSourceBlock(AltoClef mod, BlockPos pos, boolean onlyAcceptStill static double distanceXZSquared(Vec3d from, Vec3d to) { Vec3d delta = to.subtract(from); - return delta.x * delta.x + delta.z * delta.z; + return (delta.x * delta.x) + (delta.z * delta.z); } static double distanceXZ(Vec3d from, Vec3d to) { @@ -180,14 +179,12 @@ static int getGroundHeight(AltoClef mod, int x, int z) { } static BlockPos getADesertTemple(AltoClef mod) { - List stonePressurePlates = mod.getBlockTracker().getKnownLocations(Blocks.STONE_PRESSURE_PLATE); - if (!stonePressurePlates.isEmpty()) { - for (BlockPos pos : stonePressurePlates) { - if (mod.getWorld().getBlockState(pos).getBlock() == Blocks.STONE_PRESSURE_PLATE && // Duct tape - mod.getWorld().getBlockState(pos.down()).getBlock() == Blocks.CUT_SANDSTONE && - mod.getWorld().getBlockState(pos.down(2)).getBlock() == Blocks.TNT) { - return pos; - } + if (mod.getBlockTracker().isTracking(Blocks.STONE_PRESSURE_PLATE)) { + Optional stonePressurePlates = mod.getBlockTracker().getNearestTracking(Blocks.STONE_PRESSURE_PLATE); + if (stonePressurePlates.isPresent() && mod.getWorld().getBlockState(stonePressurePlates.get()).getBlock() == Blocks.STONE_PRESSURE_PLATE && // Duct tape + mod.getWorld().getBlockState(stonePressurePlates.get().down()).getBlock() == Blocks.CUT_SANDSTONE && + mod.getWorld().getBlockState(stonePressurePlates.get().down(2)).getBlock() == Blocks.TNT) { + return stonePressurePlates.get(); } } return null; @@ -215,7 +212,7 @@ static boolean canBreak(AltoClef mod, BlockPos pos) { boolean result = mod.getWorld().getBlockState(pos).getHardness(mod.getWorld(), pos) >= 0 && !mod.getExtraBaritoneSettings().shouldAvoidBreaking(pos) && MineProcess.plausibleToBreak(new CalculationContext(mod.getClientBaritone()), pos) - && canReach(mod, pos); + && canReach(mod, pos) && !mod.getBlockTracker().unreachable(pos); mod.getExtraBaritoneSettings().setInteractionPaused(prevInteractionPaused); return result; } @@ -223,7 +220,10 @@ static boolean canBreak(AltoClef mod, BlockPos pos) { static boolean isInNetherPortal(AltoClef mod) { if (mod.getPlayer() == null) return false; - return ((EntityAccessor) mod.getPlayer()).isInNetherPortal(); + PortalManager portalManager = mod.getPlayer().portalManager; + if (portalManager == null) + return false; + return portalManager.isInPortal(); } static boolean dangerousToBreakIfRightAbove(AltoClef mod, BlockPos toBreak) { @@ -369,7 +369,7 @@ static Entity getSpawnerEntity(AltoClef mod, BlockPos pos) { if (state.getBlock() instanceof SpawnerBlock) { BlockEntity be = mod.getWorld().getBlockEntity(pos); if (be instanceof MobSpawnerBlockEntity blockEntity) { - return blockEntity.getLogic().getRenderedEntity(mod.getWorld(), Random.create(), pos); + return blockEntity.getLogic().getRenderedEntity(mod.getWorld(), pos); } } return null; diff --git a/src/main/java/adris/altoclef/util/serialization/ItemDeserializer.java b/src/main/java/adris/altoclef/util/serialization/ItemDeserializer.java index 36c3d57b1..c70b277d5 100644 --- a/src/main/java/adris/altoclef/util/serialization/ItemDeserializer.java +++ b/src/main/java/adris/altoclef/util/serialization/ItemDeserializer.java @@ -42,7 +42,7 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOEx // Translation key (the proper way) String itemKey = p.getText(); itemKey = ItemHelper.trimItemName(itemKey); - Identifier identifier = new Identifier(itemKey); + Identifier identifier = Identifier.of(itemKey); if (Registries.ITEM.containsId(identifier)) { item = Registries.ITEM.get(identifier); } else { diff --git a/src/main/java/adris/altoclef/util/slots/SmithingTableSlot.java b/src/main/java/adris/altoclef/util/slots/SmithingTableSlot.java index fd84eb900..4e9b056d1 100644 --- a/src/main/java/adris/altoclef/util/slots/SmithingTableSlot.java +++ b/src/main/java/adris/altoclef/util/slots/SmithingTableSlot.java @@ -1,10 +1,10 @@ package adris.altoclef.util.slots; public class SmithingTableSlot extends Slot { - - public static final SmithingTableSlot INPUT_SLOT_TOOL = new SmithingTableSlot(0); - public static final SmithingTableSlot INPUT_SLOT_MATERIALS = new SmithingTableSlot(1); - public static final SmithingTableSlot OUTPUT_SLOT = new SmithingTableSlot(2); + public static final SmithingTableSlot INPUT_SLOT_TEMPLATE = new SmithingTableSlot(0); + public static final SmithingTableSlot INPUT_SLOT_TOOL = new SmithingTableSlot(1); + public static final SmithingTableSlot INPUT_SLOT_MATERIALS = new SmithingTableSlot(2); + public static final SmithingTableSlot OUTPUT_SLOT = new SmithingTableSlot(3); public SmithingTableSlot(int slot) { this(slot, false); diff --git a/src/main/resources/altoclef.mixins.json b/src/main/resources/altoclef.mixins.json index ca6e2d4d8..d057dfacd 100644 --- a/src/main/resources/altoclef.mixins.json +++ b/src/main/resources/altoclef.mixins.json @@ -11,7 +11,7 @@ "ClientInteractWithBlockMixin", "ClientPlayerInteractionAccessor", "ClientUIMixin", - "EntityAccessor", + "DeathScreenAccessor", "GameOverlayMixin", "PersistentProjectileEntityAccessor", "SlotClickMixin", diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 703f363d9..22f7dffc7 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -1,7 +1,7 @@ { "schemaVersion": 1, "id": "altoclef", - "version": "1.19.4-beta1", + "version": "1.21-beta1", "name": "Alto Clef", "description": "Plays Block Game", "authors": [ diff --git a/usage.md b/usage.md index fb943e167..f8af8c6bb 100644 --- a/usage.md +++ b/usage.md @@ -8,29 +8,29 @@ Keep in mind this project is still in rapid development. A lot of features are p Commands are prefixed with `@`. Here's a list along with their functions: -| command | description | examples | -| --------| ------------|---| -| `help` | Lists all commands | | -| `coords` | Prints the bot's current coordinates. This is here in cases where the `F3` menu gets too crowded.| -| `equip {material}` or `equip [items...]` | Equips a `material` armor set or `[items...]`. If not in the bot's inventory, bot will obtain it. | `@equip [diamond_chestplate, gold_leggings]` `@equip netherite`| -| `follow {player = }` | Follow a player. If sent via `/msg`, will follow the player who sent the command. | `@follow TacoTechnica` `/msg Bot follow` | -| `hero` | Kills all hostile mobs | `@hero` | -| `food {amount}` | Collects `amount` units of food (1 unit = 1/2 drumstick). Collects from various sources (animals, crops) | `@food 20` | -| `gamer` | Beats the game epic style | `@gamer` | -| `get [items...]` | Gets all items in `[items...]`. Can either do one item or pass a comma-separated list to get multiple items. Not every resource is get-able. | `@get diamond 3` `@get [cobblestone 40, wooden_door, glass 4]` | -| `list` | Prints a list of all get-able items | | -| `give {player = } {item} {quantity=1}` | Gives `player` `quantity` units of `item`, getting said items if the bot doesn't have them. If sent via `/msg`, will follow the player who sent the command. | `/msg Bot give iron_pickaxe` | -| `deposit [items... = ]` | Deposit a list of items in the nearest container, making a chest if we can't find one. Will only deposit items present in the bot's inventory (at the time of running this command). Leave out the list to deposit every non-tool/armor item in the bot's inventory. Useful with command chaining. | `@deposit diamond 3` `@deposit [cobblestone 1000, raw_iron 100]` `@deposit` | -| `stash {x0} {y0} {z0} {x1} {y0} {z1} [items... = ]` | Same as `@deposit`, but you specify an area from `(x0, y0, z0)` to `(x1, y1, z1)` where the bot stores the item list (these coordinates being a chest stash). Just like `@deposit`, providing no items simply deposits everything in the bots inventory. | `@stash 100 64 100 200 70 100 diamond 3` | -| `goto {x} {y} {z} {dimension=}` | Goes to (`x`,`y`, `z`) in a given `dimension`. Travels to `dimension` if not there already. Can also omit coordinates to just go to a dimension. Passing 2 values as coordinates goes to X Z coordinates instead. | `@goto 100 64 100 overworld` `@goto nether` `@goto 100 100` | -| `inventory {item=}` | Prints the bots inventory, OR how many items of a specific type the bot has. Mostly useful when running through `/msg`. | `/msg Bot inventory` `/msg Bot inventory cobblestone` | -| `locate_structure {structure_type}` | Attempts to locate a `structure_type` structure. Can find strongholds or desert temples. | `@locate_structure stronghold`, `@locate_structure desert_temple` | -| `punk {player}` | Attacks `player`. | | -| `reload_settings` | Reloads the local settings file. Run this every time you want your settings to be updated. | | -| `gamma {brightness=1}` | Sets the game's gamma. Useful for testing. 0 is "Moody" and 1 is "Bright", and you can go beyond to enable fullbright. | `@gamma 1000` | -| `status` | Prints the status of the currently executing command. Mostly useful when running through `/msg`. | | -| `stop` | Forcefully stops the currently running command. The shortcut `CTRL+K` also achieves this. | | -| `test {testname}` | Runs a "test" command. These vary, and will be described below. | | +| command | description | examples | +|-----------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------| +| `help` | Lists all commands | | +| `coords` | Prints the bot's current coordinates. This is here in cases where the `F3` menu gets too crowded. | +| `equip {material}` or `equip [items...]` | Equips a `material` armor set or `[items...]`. If not in the bot's inventory, bot will obtain it. | `@equip [diamond_chestplate, gold_leggings]` `@equip netherite` | +| `follow {player = }` | Follow a player. If sent via `/msg`, will follow the player who sent the command. | `@follow TacoTechnica` `/msg Bot follow` | +| `hero` | Kills all hostile mobs | `@hero` | +| `food {amount}` | Collects `amount` units of food (1 unit = 1/2 drumstick). Collects from various sources (animals, crops) | `@food 20` | +| `gamer` | Beats the game epic style | `@gamer` | +| `get [items...]` | Gets all items in `[items...]`. Can either do one item or pass a comma-separated list to get multiple items. Not every resource is get-able. | `@get diamond 3` `@get [cobblestone 40, wooden_door, glass 4]` | +| `list` | Prints a list of all get-able items | | +| `give {player = } {item} {quantity=1}` | Gives `player` `quantity` units of `item`, getting said items if the bot doesn't have them. If sent via `/msg`, will follow the player who sent the command. | `/msg Bot give iron_pickaxe` | +| `deposit [items... = ]` | Deposit a list of items in the nearest container, making a chest if we can't find one. Will only deposit items present in the bot's inventory (at the time of running this command). Leave out the list to deposit every non-tool/armor item in the bot's inventory. Useful with command chaining. | `@deposit diamond 3` `@deposit [cobblestone 1000, raw_iron 100]` `@deposit` | +| `stash {x0} {y0} {z0} {x1} {y0} {z1} [items... = ]` | Same as `@deposit`, but you specify an area from `(x0, y0, z0)` to `(x1, y1, z1)` where the bot stores the item list (these coordinates being a chest stash). Just like `@deposit`, providing no items simply deposits everything in the bots inventory. | `@stash 100 64 100 200 70 100 diamond 3` | +| `goto {x} {y} {z} {dimension=}` | Goes to (`x`,`y`, `z`) in a given `dimension`. Travels to `dimension` if not there already. Can also omit coordinates to just go to a dimension. Passing 2 values as coordinates goes to X Z coordinates instead. | `@goto 100 64 100 overworld` `@goto nether` `@goto 100 100` | +| `inventory {item=}` | Prints the bots inventory, OR how many items of a specific type the bot has. Mostly useful when running through `/msg`. | `/msg Bot inventory` `/msg Bot inventory cobblestone` | +| `locate_structure {structure_type}` | Attempts to locate a `structure_type` structure. Can find strongholds or desert temples. | `@locate_structure stronghold`, `@locate_structure desert_temple` | +| `punk {player}` | Attacks `player`. | | +| `reload_settings` | Reloads the local settings file. Run this every time you want your settings to be updated. | | +| `gamma {brightness=1}` | Sets the game's gamma. Useful for testing. 0 is "Moody" and 1 is "Bright", and you can go beyond to enable fullbright. | `@gamma 1000` | +| `status` | Prints the status of the currently executing command. Mostly useful when running through `/msg`. | | +| `stop` | Forcefully stops the currently running command. The shortcut `CTRL+K` also achieves this. | | +| `test {testname}` | Runs a "test" command. These vary, and will be described below. | | ### Command chaining