diff --git a/.github/workflows/nightly_build.yml b/.github/workflows/nightly_build.yml
new file mode 100644
index 0000000..9bd0075
--- /dev/null
+++ b/.github/workflows/nightly_build.yml
@@ -0,0 +1,53 @@
+name: Nightly Build
+
+on:
+ push:
+ pull_request:
+ workflow_dispatch:
+
+jobs:
+ build:
+ runs-on : ubuntu-latest
+ env :
+ BUILD : ${{ github.run_number }}
+ WEBHOOK : ${{ secrets.HIGHWAYTOOLS_NIGHTLY }}
+
+ steps:
+ - name: Check out repository
+ uses: actions/checkout@v2
+
+ - name: Set up JDK
+ uses: actions/setup-java@v1
+ with:
+ java-version: 1.8
+
+ - name: Change wrapper permissions
+ run: chmod +x ./gradlew
+
+ - name: Gradle cache
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
+
+ - name: Gradle build
+ run: ./gradlew --build-cache build
+
+ - name: Archive artifact
+ uses: actions/upload-artifact@v2
+ with:
+ name: HighwayTools-${{ github.sha }}
+ path: build/libs/
+
+ - name: Get branch name
+ uses: nelonoel/branch-name@v1.0.1
+
+ - name: Send Discord build message
+ if: github.ref == 'refs/heads/master'
+ run: |
+ COMMITMESSAGE=`git log --pretty=format:'- \`%h\` %s' -5 --reverse` &&
+ (curl "$WEBHOOK" -sS -H "Content-Type:application/json" -X POST -d "{\"content\":null,\"embeds\":[{\"title\":\"Build $BUILD\",\"description\":\"**Branch:** $BRANCH_NAME\\n**Changes:**\\n$COMMITMESSAGE\",\"url\":\"https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID\",\"color\":1487872,\"fields\":[{\"name\":\"Artifacts:\",\"value\":\"- [HighwayTools-${{ github.sha }}.zip](https://nightly.link/$GITHUB_REPOSITORY/workflows/nightly_build/$BRANCH_NAME/HighwayTools-${{ github.sha }}.zip)\"}],\"footer\":{\"text\":\"$GITHUB_REPOSITORY\"},\"thumbnail\":{\"url\":\"https://raw.githubusercontent.com/lambda-client/lambda/master/src/main/resources/assets/minecraft/lambda/lambda_map.png\"}}],\"username\":\"Github Actions\",\"avatar_url\":\"https://www.2b2t.com.au/assets/github.jpeg\"}")
\ No newline at end of file
diff --git a/README.md b/README.md
index 851cb9a..8113893 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,12 @@
### Description
-Adding fully automated highway building as plugin to Lambda. The tool places building material and destroys wrong blocks in high frequency using well-timed packets. The module can build autonomously highways in all 8 directions while its pathfinder keeps you at the desired position and takes care of any possible dangerous situation. It is highly customizable and allows deep changes in system using configurations. It is fully compatible with most modules of Lambda like `LagNotifier`, `AutoEat` etc and also is confirmed to work with `Rusherhack`, `Future`, `Impact` etc.
+Adding fully automated highway building as plugin to Lambda.
+The tool places building material and destroys wrong blocks in high frequency using well-timed packets.
+The module can build autonomously in all 8 directions while the pathfinder keeps the desired position and takes care of any possible dangerous situations like liquids or gaps.
+Advanced inventory management allows the bot to fully utilize materials stocked in shulker boxes or in the ender chest.
+It is highly customizable and allows deep changes in system using configurations.
+It is fully compatible with most modules of Lambda like `LagNotifier`, `AutoEat` etc and also is confirmed to work with `Rusherhack`, `Future`, `Impact` etc.
### Features
- [x] Digs tunnel and paves Obsidian floor at the same time
@@ -56,21 +61,20 @@ Adding fully automated highway building as plugin to Lambda. The tool places bui
1. Get the latest Lambda release here https://github.com/lambda-client/lambda/releases
2. Open Lambda menu in main menu to open plugin settings
3. Press `Open Plugin Folder`
-4. Move plugin `HighwayTools-v9.9.1.jar` into the folder `.minecraft/lambda/plugins`
+4. Move plugin `HighwayTools-*.jar` into the folder `.minecraft/lambda/plugins`
### Known issues
-- [x] `AutoLog` is not compatible with `AutoReconnect` > Should
+- `AutoLog` is not compatible with `AutoReconnect`
### Troubleshooting
-- [x] Deactivate `AntiHunger` for faster block breaking
-- [x] If stuck check if AutoCenter is on `MOTION` to get moved to middle of the block (Baritone can't move exactly to block center)
-- [x] If placed block disappear increase the `TickDelayPlace` until it works
-- [x] Deactivate `IllegalPlacements` if the server requires (like 2b2t)
-- [x] Check if the Baritone process `Lambda Pauser` is active in GUI. Sometimes it does not stop correctly
+- Deactivate `AntiHunger` for faster block breaking because it makes you basically float.
+- If stuck check, if AutoCenter is on `MOTION` to get moved to middle of the block (Baritone can't move exactly to block center)
+- If placed block disappear increase the `TickDelayPlace` until it works
+- Deactivate `IllegalPlacements` if the server requires (like 2b2t)
-This is a pre-release. Use with care. Any suggestions and questions: Constructor#9948 on Discord Made by @Avanatiker
-Report bugs on Issues and if not possible message EnigmA_008#1505 on Discord.
+Any suggestions and questions: Constructor#9948 on Discord Made by @Avanatiker
+Report bugs on [Issues](https://github.com/lambda-plugins/HighwayTools/issues) and if not possible message EnigmA_008#1505 on Discord.
-`Copyright ©2021` Constructor#9948 alias Avanatiker. All Rights Reserved. Permission to use, copy, modify, and distribute this software and its documentation for educational, research, and not-for-profit purposes, without fee and without a signed licensing agreement, is hereby granted, provided that the above copyright notice, this paragraph appears in all copies, modifications, and distributions.
+`Copyright ©2019-2022` Constructor#9948 alias Avanatiker. All Rights Reserved. Permission to use, copy, modify, and distribute this software and its documentation for educational, research, and not-for-profit purposes, without fee and without a signed licensing agreement, is hereby granted, provided that the above copyright notice, this paragraph appears in all copies, modifications, and distributions.
By downloading this software you agree to be bound by the terms of service.
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index fe4474e..e8729f6 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,46 +1,50 @@
-version project.modVersion
-group project.modGroup
-
buildscript {
repositories {
- maven { url = 'https://files.minecraftforge.net/maven' }
- maven { url = 'https://repo.spongepowered.org/repository/maven-public/' }
+ mavenCentral()
+ maven { url = 'https://maven.minecraftforge.net/' }
+ maven { url = 'https://repo.spongepowered.org/maven/' }
}
-
dependencies {
- classpath 'net.minecraftforge.gradle:ForgeGradle:4.+'
+ classpath 'net.minecraftforge.gradle:ForgeGradle:5.+'
classpath 'org.spongepowered:mixingradle:0.7-SNAPSHOT'
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath 'com.github.jengelman.gradle.plugins:shadow:6.1.0'
}
}
-apply plugin: 'idea'
-apply plugin: 'kotlin'
+plugins {
+ id 'org.jetbrains.kotlin.jvm' version "$kotlinVersion"
+}
+
apply plugin: 'net.minecraftforge.gradle'
-apply plugin: 'org.spongepowered.mixin'
+apply plugin: 'com.github.johnrengelman.shadow'
-compileKotlin {
- kotlinOptions {
- jvmTarget = "1.8"
- useIR = true
- freeCompilerArgs += '-Xlambdas=indy'
- }
-}
+version project.modVersion
+group project.modGroup
compileJava {
sourceCompatibility = targetCompatibility = '1.8'
options.encoding = 'UTF-8'
+ // Disables Gradle build caching for this task
+ // If build caching is enabled this can cause the refmap to not be built and included
+ outputs.upToDateWhen { false }
+}
+
+compileKotlin.kotlinOptions {
+ freeCompilerArgs += '-Xlambdas=indy'
+ freeCompilerArgs += '-Xopt-in=kotlin.RequiresOptIn'
+ freeCompilerArgs += '-Xopt-in=kotlin.contracts.ExperimentalContracts'
}
repositories {
maven { url = 'https://repo.spongepowered.org/repository/maven-public/' }
maven { url = 'https://impactdevelopment.github.io/maven/' }
maven { url = "https://jitpack.io" }
+ mavenCentral()
}
minecraft {
- mappings channel: 'stable', version: '39-1.12'
+ mappings channel: "$mappingsChannel", version: "$mappingsVersion"
runs {
client {
@@ -51,12 +55,6 @@ minecraft {
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
property 'forge.logging.console.level', 'debug'
-
- mods {
- highwaytools {
- source sourceSets.main
- }
- }
}
}
}
@@ -72,13 +70,12 @@ configurations {
}
dependencies {
- minecraft 'net.minecraftforge:forge:1.12.2-14.23.5.2855'
+ minecraft "net.minecraftforge:forge:$minecraftVersion-$forgeVersion"
- // API coming soon
-// implementation 'com.github.lambda-client:lambda:2.06'
- implementation(files("lib/lambda-2.07.xx-dev-api.jar"))
+ // Online maven dependency coming soon
+ implementation files("lib/lambda-3.3.0-api.jar")
- implementation('org.spongepowered:mixin:0.7.11-SNAPSHOT') {
+ implementation('org.spongepowered:mixin:0.8.5') {
exclude module: 'commons-io'
exclude module: 'gson'
exclude module: 'guava'
@@ -87,51 +84,83 @@ dependencies {
}
// Hacky way to get mixin work
- annotationProcessor('org.spongepowered:mixin:0.8.2:processor') {
+ annotationProcessor('org.spongepowered:mixin:0.8.5:processor') {
exclude module: 'gson'
}
// Kotlin libs
// kotlin-stdlib-common and annotations aren't required at runtime
- implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version") {
+ implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion") {
exclude module: 'kotlin-stdlib-common'
exclude module: 'annotations'
}
- implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version") {
+ implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion") {
exclude module: 'kotlin-stdlib-common'
exclude module: 'annotations'
}
- implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version") {
+ implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion") {
exclude module: 'kotlin-stdlib-common'
exclude module: 'annotations'
}
- implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlin_version") {
+ implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion") {
exclude module: 'kotlin-stdlib-common'
exclude module: 'annotations'
}
- implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinx_coroutines_version") {
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion") {
exclude module: 'kotlin-stdlib-common'
exclude module: 'annotations'
}
// Add them back to compileOnly (provided)
- compileOnly "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlin_version"
- compileOnly 'org.jetbrains:annotations:20.1.0'
+ compileOnly "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion"
+ compileOnly 'org.jetbrains:annotations:23.0.0'
// This Baritone will NOT be included in the jar
implementation 'com.github.cabaletta:baritone:1.2.14'
+ // Unit Testing frameworks
+ testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
+ testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
+
// Add your dependencies below
// jarLibs 'com.lambda:example:1.0.0'
}
-mixin {
- defaultObfuscationEnv 'searge'
- add sourceSets.main, 'mixins.lambda.refmap.json'
+processResources {
+ exclude '**/rawimagefiles'
+
+ from(sourceSets.main.resources.srcDirs) {
+ duplicatesStrategy = DuplicatesStrategy.INCLUDE
+ include 'plugin_info.json'
+ expand 'version': project.version
+ }
+}
+
+test {
+ useJUnitPlatform()
+}
+
+jar.finalizedBy('reobfJar')
+
+shadowJar {
+ archiveClassifier.set('')
+ configurations = []
+ relocate 'kotlin', 'com.lambda.shadow.kotlin'
+ relocate 'kotlinx', 'com.lambda.shadow.kotlinx'
+ finalizedBy 'reobfShadowJar'
+}
+
+reobf {
+ shadowJar {}
+ jar {
+ enabled = false
+ }
}
-jar.finalizedBy('reobfJar')
\ No newline at end of file
+artifacts {
+ shadowJar
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 8185c4c..bb17730 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,6 +1,13 @@
org.gradle.jvmargs=-Xmx3G
-modGroup=com.lambda
-modVersion=10.0
-kotlin_version=1.5.20
-kotlinx_coroutines_version=1.5.0-RC
org.gradle.parallel=true
+
+modGroup=com.lambda
+modVersion=10.3.1
+
+minecraftVersion=1.12.2
+forgeVersion=14.23.5.2860
+mappingsChannel=stable
+mappingsVersion=39-1.12
+
+kotlinVersion=1.8.10
+kotlinxCoroutinesVersion=1.6.4
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 442d913..ae04661 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-6.8.3-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/lib/lambda-2.07.xx-dev-api.jar b/lib/lambda-2.07.xx-dev-api.jar
deleted file mode 100644
index 7993ff9..0000000
Binary files a/lib/lambda-2.07.xx-dev-api.jar and /dev/null differ
diff --git a/lib/lambda-3.3.0-api-source.jar b/lib/lambda-3.3.0-api-source.jar
new file mode 100644
index 0000000..d293d8b
Binary files /dev/null and b/lib/lambda-3.3.0-api-source.jar differ
diff --git a/lib/lambda-3.3.0-api.jar b/lib/lambda-3.3.0-api.jar
new file mode 100644
index 0000000..d2ef77c
Binary files /dev/null and b/lib/lambda-3.3.0-api.jar differ
diff --git a/setupWorkspace.sh b/setupWorkspace.sh
new file mode 100755
index 0000000..74e4296
--- /dev/null
+++ b/setupWorkspace.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+# Used to setup workspace and fix building on unix / Git BASH
+#
+# Usage: "./setupWorkspace.sh"
+
+#
+
+# To allow use from outside the lambda directory
+cd "$(dirname "$0")" || exit
+
+echo "[$(date +"%H:%M:%S")] Running gradlew classes without daemon..."
+./gradlew --no-daemon classes || {
+ echo "[$(date +"%H:%M:%S")] ERROR: Running gradlew build failed! Run './gradlew --no-daemon classes' manually"
+ exit 1
+}
+
+cat logo_ascii.txt 2>/dev/null
+echo "=========================================================================="
+echo ""
+echo "[$(date +"%H:%M:%S")] Build succeeded! All checks passed, you can build normally now! Welcome to Lambda."
+echo ""
+echo "=========================================================================="
diff --git a/src/main/kotlin/HighwayTools.kt b/src/main/kotlin/HighwayTools.kt
index 1d016b1..00c83e8 100644
--- a/src/main/kotlin/HighwayTools.kt
+++ b/src/main/kotlin/HighwayTools.kt
@@ -2,31 +2,29 @@ import com.lambda.client.event.events.PacketEvent
import com.lambda.client.event.events.PlayerTravelEvent
import com.lambda.client.event.events.RenderOverlayEvent
import com.lambda.client.event.events.RenderWorldEvent
+import com.lambda.client.event.listener.listener
import com.lambda.client.module.Category
import com.lambda.client.plugin.api.PluginModule
import com.lambda.client.setting.settings.impl.collection.CollectionSetting
import com.lambda.client.util.items.shulkerList
-import com.lambda.client.util.threads.runSafe
-import com.lambda.client.util.threads.runSafeR
-import com.lambda.client.util.threads.safeListener
-import com.lambda.event.listener.listener
+import com.lambda.client.util.threads.*
import net.minecraft.block.Block
import net.minecraft.init.Blocks
+import net.minecraft.init.Items
+import net.minecraft.item.Item
import net.minecraftforge.fml.common.gameevent.TickEvent
-import trombone.IO.DebugMessages
+import trombone.IO.DebugLevel
import trombone.IO.DisableMode
import trombone.IO.pauseCheck
import trombone.Pathfinder.updatePathing
import trombone.Renderer.renderOverlay
import trombone.Renderer.renderWorld
-import trombone.Trombone.Mode
+import trombone.Trombone.Structure
import trombone.Trombone.active
+import trombone.Trombone.tick
import trombone.Trombone.onDisable
import trombone.Trombone.onEnable
-import trombone.Trombone.tick
import trombone.handler.Packet.handlePacket
-import trombone.handler.Player.LimitMode
-import trombone.handler.Player.RotationMode
/**
* @author Avanatiker
@@ -40,7 +38,7 @@ object HighwayTools : PluginModule(
modulePriority = 10,
pluginMain = HighwayToolsPlugin
) {
- private val page by setting("Page", Page.BUILD, description = "Switch between the setting pages")
+ private val page by setting("Page", Page.BLUEPRINT, description = "Switch between setting pages")
private val defaultIgnoreBlocks = linkedSetOf(
"minecraft:standing_sign",
@@ -50,76 +48,90 @@ object HighwayTools : PluginModule(
"minecraft:bedrock",
"minecraft:end_portal",
"minecraft:end_portal_frame",
- "minecraft:portal"
+ "minecraft:portal",
+ "minecraft:piston_extension",
+ "minecraft:barrier"
)
- // build settings
- val mode by setting("Mode", Mode.HIGHWAY, { page == Page.BUILD }, description = "Choose the structure")
- val width by setting("Width", 6, 1..11, 1, { page == Page.BUILD }, description = "Sets the width of blueprint")
- val height by setting("Height", 4, 1..6, 1, { page == Page.BUILD && clearSpace }, description = "Sets height of blueprint")
- val backfill by setting("Backfill", false, { page == Page.BUILD && mode == Mode.TUNNEL }, description = "Fills the tunnel behind you")
- val clearSpace by setting("Clear Space", true, { page == Page.BUILD && mode == Mode.HIGHWAY }, description = "Clears out the tunnel if necessary")
- val cleanFloor by setting("Clean Floor", false, { page == Page.BUILD && mode == Mode.TUNNEL && !backfill }, description = "Cleans up the tunnels floor")
- val cleanWalls by setting("Clean Walls", false, { page == Page.BUILD && mode == Mode.TUNNEL && !backfill }, description = "Cleans up the tunnels walls")
- val cleanRoof by setting("Clean Roof", false, { page == Page.BUILD && mode == Mode.TUNNEL && !backfill }, description = "Cleans up the tunnels roof")
- val cleanCorner by setting("Clean Corner", false, { page == Page.BUILD && mode == Mode.TUNNEL && !cornerBlock && !backfill && width > 2 }, description = "Cleans up the tunnels corner")
- val cornerBlock by setting("Corner Block", false, { page == Page.BUILD && (mode == Mode.HIGHWAY || (mode == Mode.TUNNEL && !backfill && width > 2)) }, description = "If activated will break the corner in tunnel or place a corner while paving")
- val railing by setting("Railing", true, { page == Page.BUILD && mode == Mode.HIGHWAY }, description = "Adds a railing / rim / border to the highway")
- val railingHeight by setting("Railing Height", 1, 1..4, 1, { railing && page == Page.BUILD && mode == Mode.HIGHWAY }, description = "Sets height of railing")
+ // blueprint
+ val mode by setting("Mode", Structure.HIGHWAY, { page == Page.BLUEPRINT }, description = "Choose the structure")
+ val width by setting("Width", 6, 1..11, 1, { page == Page.BLUEPRINT }, description = "Sets the width of blueprint", unit = " blocks")
+ val height by setting("Height", 4, 2..6, 1, { page == Page.BLUEPRINT && clearSpace }, description = "Sets height of blueprint", unit = " blocks")
+ val backfill by setting("Backfill", false, { page == Page.BLUEPRINT && mode == Structure.TUNNEL }, description = "Fills the tunnel behind you")
+ val clearSpace by setting("Clear Space", true, { page == Page.BLUEPRINT && mode == Structure.HIGHWAY }, description = "Clears out the tunnel if necessary")
+ val cleanFloor by setting("Clean Floor", false, { page == Page.BLUEPRINT && mode == Structure.TUNNEL && !backfill }, description = "Cleans up the tunnels floor")
+ val cleanRightWall by setting("Clean Right Wall", false, { page == Page.BLUEPRINT && mode == Structure.TUNNEL && !backfill }, description = "Cleans up the right wall")
+ val cleanLeftWall by setting("Clean Left Wall", false, { page == Page.BLUEPRINT && mode == Structure.TUNNEL && !backfill }, description = "Cleans up the left wall")
+ val cleanRoof by setting("Clean Roof", false, { page == Page.BLUEPRINT && mode == Structure.TUNNEL && !backfill }, description = "Cleans up the tunnels roof")
+ val cleanCorner by setting("Clean Corner", false, { page == Page.BLUEPRINT && mode == Structure.TUNNEL && !cornerBlock && !backfill && width > 2 }, description = "Cleans up the tunnels corner")
+ val cornerBlock by setting("Corner Block", false, { page == Page.BLUEPRINT && (mode == Structure.HIGHWAY || (mode == Structure.TUNNEL && !backfill && width > 2)) }, description = "If activated will break the corner in tunnel or place a corner while paving")
+ val railing by setting("Railing", true, { page == Page.BLUEPRINT && mode == Structure.HIGHWAY }, description = "Adds a railing/rim/border to the highway")
+ val railingHeight by setting("Railing Height", 1, 1..4, 1, { railing && page == Page.BLUEPRINT && mode == Structure.HIGHWAY }, description = "Sets height of railing", unit = " blocks")
private val materialSaved = setting("Material", "minecraft:obsidian", { false })
private val fillerMatSaved = setting("FillerMat", "minecraft:netherrack", { false })
+ private val foodItem = setting("FoodItem", "minecraft:golden_apple", { false })
val ignoreBlocks = setting(CollectionSetting("IgnoreList", defaultIgnoreBlocks, { false }))
- // behavior settings
- val interacting by setting("Rotation Mode", RotationMode.SPOOF, { page == Page.BEHAVIOR }, description = "Force view client side, only server side or no interaction at all")
- val dynamicDelay by setting("Dynamic Place Delay", true, { page == Page.BEHAVIOR }, description = "Slows down on failed placement attempts")
- val placeDelay by setting("Place Delay", 3, 1..20, 1, { page == Page.BEHAVIOR }, description = "Sets the delay ticks between placement tasks")
- val breakDelay by setting("Break Delay", 1, 1..20, 1, { page == Page.BEHAVIOR }, description = "Sets the delay ticks between break tasks")
- val illegalPlacements by setting("Illegal Placements", false, { page == Page.BEHAVIOR }, description = "Do not use on 2b2t. Tries to interact with invisible surfaces")
- val bridging by setting("Bridging", true, { page == Page.BEHAVIOR }, description = "Tries to bridge / scaffold when stuck placing")
- val instantMine by setting("Instant Mine", true, { page == Page.BEHAVIOR }, description = "Instant mine NCP exploit.")
- val alwaysBoth by setting("More Packets", false, { page == Page.BEHAVIOR }, description = "Exploit for faster breaks.")
- val multiBuilding by setting("Shuffle Tasks", false, { page == Page.BEHAVIOR }, description = "Only activate when working with several players")
- val taskTimeout by setting("Task Timeout", 8, 0..20, 1, { page == Page.BEHAVIOR }, description = "Timeout for waiting for the server to try again")
+ // behavior
+ val maxReach by setting("Max Reach", 4.9f, 1.0f..7.0f, 0.1f, { page == Page.BEHAVIOR }, description = "Sets the range of the blueprint. Decrease when tasks fail!", unit = " blocks")
+ val multiBuilding by setting("Shuffle Tasks", false, { page == Page.PLACING }, description = "Only activate when working with several players")
val rubberbandTimeout by setting("Rubberband Timeout", 50, 5..100, 5, { page == Page.BEHAVIOR }, description = "Timeout for pausing after a lag")
- val maxReach by setting("Max Reach", 4.9f, 1.0f..7.0f, 0.1f, { page == Page.BEHAVIOR }, description = "Sets the range of the blueprint. Decrease when tasks fail!")
- val maxBreaks by setting("Multi Break", 1, 1..5, 1, { page == Page.BEHAVIOR }, description = "EXPERIMENTAL: Breaks multiple instant breaking blocks per tick in view")
- val limitOrigin by setting("Limited by", LimitMode.FIXED, { page == Page.BEHAVIOR }, description = "Changes the origin of limit: Client / Server TPS")
- val limitFactor by setting("Limit Factor", 1.0f, 0.5f..2.0f, 0.01f, { page == Page.BEHAVIOR }, description = "EXPERIMENTAL: Factor for TPS which acts as limit for maximum breaks per second.")
- val placementSearch by setting("Place Deep Search", 2, 1..4, 1, { page == Page.BEHAVIOR }, description = "EXPERIMENTAL: Attempts to find a support block for placing against")
- val moveSpeed by setting("Packet Move Speed", 0.2f, 0.0f..1.0f, 0.01f, { page == Page.BEHAVIOR }, description = "Maximum player velocity per tick")
+ val taskTimeout by setting("Task Timeout", 8, 0..20, 1, { page == Page.BEHAVIOR }, description = "Timeout for waiting for the server to try again", unit = " ticks")
+ val moveSpeed by setting("Packet Move Speed", 0.2f, 0.0f..1.0f, 0.01f, { page == Page.BEHAVIOR }, description = "Maximum player velocity per tick", unit = "m/t")
+
+ // mining
+ val breakDelay by setting("Break Delay", 1, 1..20, 1, { page == Page.MINING }, description = "Sets the delay ticks between break tasks", unit = " ticks")
+ val miningSpeedFactor by setting("Mining Speed Factor", 1.0f, 0.0f..2.0f, 0.01f, { page == Page.MINING }, description = "Factor to manipulate calculated mining speed")
+ val interactionLimit by setting("Interaction Limit", 20, 1..100, 1, { page == Page.MINING }, description = "Set the interaction limit per second", unit = " interactions/s")
+ val multiBreak by setting("Multi Break", true, { page == Page.MINING }, description = "Breaks multiple instant breaking blocks intersecting with view vector")
+ val packetFlood by setting("Packet Flood", false, { page == Page.MINING }, description = "Exploit for faster packet breaks. Sends START and STOP packet on same tick.")
+ val instantMine by setting("Ender Chest Instant Mine", false, { page == Page.MINING && packetFlood }, description = "Instant mine NCP exploit")
+
+ // placing
+ val placeDelay by setting("Place Delay", 3, 1..20, 1, { page == Page.PLACING }, description = "Sets the delay ticks between placement tasks")
+ val dynamicDelay by setting("Dynamic Place Delay", true, { page == Page.PLACING }, description = "Slows down on failed placement attempts")
+ val illegalPlacements by setting("Illegal Placements", false, { page == Page.PLACING }, description = "Do not use on 2b2t. Tries to interact with invisible surfaces")
+ val scaffold by setting("Scaffold", true, { page == Page.PLACING }, description = "Tries to bridge / scaffold when stuck placing")
+ val placementSearch by setting("Place Deep Search", 2, 1..4, 1, { page == Page.PLACING }, description = "EXPERIMENTAL: Attempts to find a support block for placing against", unit = " blocks")
// storage management
- val storageManagement by setting("Manage Storage", true, { page == Page.STORAGE_MANAGEMENT }, description = "Choose to interact with container using only packets.")
- val leaveEmptyShulkers by setting("Leave Empty Shulkers", true, { page == Page.STORAGE_MANAGEMENT && storageManagement }, description = "Does not break empty shulkers.")
- val grindObsidian by setting("Grind Obsidian", true, { page == Page.STORAGE_MANAGEMENT }, description = "Destroy Ender Chests to obtain Obsidian.")
- val saveMaterial by setting("Save Material", 12, 0..64, 1, { page == Page.STORAGE_MANAGEMENT }, description = "How many material blocks are saved")
- val saveTools by setting("Save Tools", 1, 0..36, 1, { page == Page.STORAGE_MANAGEMENT }, description = "How many tools are saved")
- val saveEnder by setting("Save Ender Chests", 1, 0..64, 1, { page == Page.STORAGE_MANAGEMENT }, description = "How many ender chests are saved")
+ val storageManagement by setting("Manage Storage", true, { page == Page.STORAGE_MANAGEMENT }, description = "Choose to interact with container using only packets")
+ val searchEChest by setting("Search Ender Chest", false, { page == Page.STORAGE_MANAGEMENT && storageManagement }, description = "Allow access to your ender chest")
+ val leaveEmptyShulkers by setting("Leave Empty Shulkers", true, { page == Page.STORAGE_MANAGEMENT && storageManagement }, description = "Does not break empty shulkers")
+ val grindObsidian by setting("Grind Obsidian", true, { page == Page.STORAGE_MANAGEMENT && storageManagement }, description = "Destroy Ender Chests to obtain Obsidian")
+ val fastFill by setting("Fast Fill", true, { page == Page.STORAGE_MANAGEMENT && storageManagement }, description = "Moves as many item stacks to inventory as possible")
+ val keepFreeSlots by setting("Free Slots", 1, 0..30, 1, { page == Page.STORAGE_MANAGEMENT && storageManagement }, description = "How many inventory slots are untouched on refill", unit = " slots")
+ val preferEnderChests by setting("Prefer Ender Chests", false, { page == Page.STORAGE_MANAGEMENT && storageManagement }, description = "Prevent using raw material shulkers")
+ val manageFood by setting("Manage Food", true, { page == Page.STORAGE_MANAGEMENT && storageManagement }, description = "Choose to manage food")
+ val saveMaterial by setting("Save Material", 12, 0..64, 1, { page == Page.STORAGE_MANAGEMENT && storageManagement }, description = "How many material blocks are saved")
+ val saveTools by setting("Save Tools", 1, 0..36, 1, { page == Page.STORAGE_MANAGEMENT && storageManagement }, description = "How many tools are saved")
+ val saveEnder by setting("Save Ender Chests", 1, 0..64, 1, { page == Page.STORAGE_MANAGEMENT && storageManagement }, description = "How many ender chests are saved")
+ val saveFood by setting("Save Food", 1, 0..64, 1, { page == Page.STORAGE_MANAGEMENT && manageFood && storageManagement}, description = "How many food items are saved")
+ val minDistance by setting("Min Container Distance", 1.5, 0.0..3.0, 0.1, { page == Page.STORAGE_MANAGEMENT && storageManagement }, description = "Avoid player movement collision with placement.", unit = " blocks")
val disableMode by setting("Disable Mode", DisableMode.NONE, { page == Page.STORAGE_MANAGEMENT }, description = "Choose action when bot is out of materials or tools")
val usingProxy by setting("Proxy", false, { disableMode == DisableMode.LOGOUT && page == Page.STORAGE_MANAGEMENT }, description = "Enable this if you are using a proxy to call the given command")
val proxyCommand by setting("Proxy Command", "/dc", { usingProxy && disableMode == DisableMode.LOGOUT && page == Page.STORAGE_MANAGEMENT }, description = "Command to be sent to log out")
- // config
- val anonymizeStats by setting("Anonymize", false, { page == Page.CONFIG }, description = "Censors all coordinates in HUD and Chat")
- val fakeSounds by setting("Fake Sounds", true, { page == Page.CONFIG }, description = "Adds artificial sounds to the actions")
- val info by setting("Show Info", true, { page == Page.CONFIG }, description = "Prints session stats in chat")
- val printDebug by setting("Show Queue", false, { page == Page.CONFIG }, description = "Shows task queue in HUD")
- val debugMessages by setting("Debug Messages", DebugMessages.IMPORTANT, { page == Page.CONFIG }, description = "Sets the debug log depth level")
- val goalRender by setting("Goal Render", false, { page == Page.CONFIG }, description = "Renders the baritone goal")
- val showCurrentPos by setting("Current Pos Render", false, { page == Page.CONFIG }, description = "Renders the current position")
- val filled by setting("Filled", true, { page == Page.CONFIG }, description = "Renders colored task surfaces")
- val outline by setting("Outline", true, { page == Page.CONFIG }, description = "Renders colored task outlines")
- val popUp by setting("Pop up", true, { page == Page.CONFIG }, description = "Funny render effect")
- val popUpSpeed by setting("Pop up speed", 150, 0..500, 1, { popUp && page == Page.CONFIG }, description = "Sets speed of the pop up effect")
- val showDebugRender by setting("Debug Render", false, { page == Page.CONFIG }, description = "Render debug info on tasks")
- val textScale by setting("Text Scale", 1.0f, 0.0f..4.0f, 0.25f, { showDebugRender && page == Page.CONFIG }, description = "Scale of debug text")
- val aFilled by setting("Filled Alpha", 26, 0..255, 1, { filled && page == Page.CONFIG }, description = "Sets the opacity")
- val aOutline by setting("Outline Alpha", 91, 0..255, 1, { outline && page == Page.CONFIG }, description = "Sets the opacity")
- val thickness by setting("Thickness", 2.0f, 0.25f..4.0f, 0.25f, { outline && page == Page.CONFIG }, description = "Sets thickness of outline")
+ // render
+ val anonymizeStats by setting("Anonymize", false, { page == Page.RENDER }, description = "Censors all coordinates in HUD and Chat")
+ val fakeSounds by setting("Fake Sounds", true, { page == Page.RENDER }, description = "Adds artificial sounds to the actions")
+ val info by setting("Show Info", true, { page == Page.RENDER }, description = "Prints session stats in chat")
+ val debugLevel by setting("Debug Level", DebugLevel.IMPORTANT, { page == Page.RENDER }, description = "Sets the debug log depth level")
+ val goalRender by setting("Baritone Goal", false, { page == Page.RENDER }, description = "Renders the baritone goal")
+ val showCurrentPos by setting("Current Pos", false, { page == Page.RENDER }, description = "Renders the current position")
+ val filled by setting("Filled", true, { page == Page.RENDER }, description = "Renders colored task surfaces")
+ val outline by setting("Outline", true, { page == Page.RENDER }, description = "Renders colored task outlines")
+ val popUp by setting("Pop up", true, { page == Page.RENDER }, description = "Funny render effect")
+ val popUpSpeed by setting("Pop up speed", 150, 0..500, 1, { popUp && page == Page.RENDER }, description = "Sets speed of the pop up effect", unit = "ms")
+ val showDebugRender by setting("Debug Render", false, { page == Page.RENDER }, description = "Render debug info on tasks")
+ val textScale by setting("Text Scale", 1.0f, 0.0f..4.0f, 0.25f, { showDebugRender && page == Page.RENDER }, description = "Scale of debug text")
+ val disableWarnings by setting("Disable Warnings", false, { page == Page.RENDER }, description = "DANGEROUS: Disable warnings on enable")
+ val aFilled by setting("Filled Alpha", 26, 0..255, 1, { filled && page == Page.RENDER }, description = "Sets the opacity")
+ val aOutline by setting("Outline Alpha", 91, 0..255, 1, { outline && page == Page.RENDER }, description = "Sets the opacity")
+ val thickness by setting("Thickness", 2.0f, 0.25f..4.0f, 0.25f, { outline && page == Page.RENDER }, description = "Sets thickness of outline")
private enum class Page {
- BUILD, BEHAVIOR, STORAGE_MANAGEMENT, CONFIG
+ BLUEPRINT, BEHAVIOR, MINING, PLACING, STORAGE_MANAGEMENT, RENDER
}
// internal settings
@@ -133,6 +145,12 @@ object HighwayTools : PluginModule(
set(value) {
fillerMatSaved.value = value.registryName.toString()
}
+ var food: Item
+ get() = Item.getByNameOrId(foodItem.value) ?: Items.GOLDEN_APPLE
+ set(value) {
+ foodItem.value = value.registryName.toString()
+ }
+
override fun isActive(): Boolean {
return isEnabled && active
@@ -157,8 +175,8 @@ object HighwayTools : PluginModule(
}
init {
- safeListener { event ->
- handlePacket(event.packet)
+ safeListener {
+ handlePacket(it.packet)
}
listener {
@@ -169,8 +187,8 @@ object HighwayTools : PluginModule(
renderOverlay()
}
- safeListener { event ->
- if (event.phase == TickEvent.Phase.START) tick()
+ safeListener {
+ if (it.phase == TickEvent.Phase.START) tick()
}
safeListener {
diff --git a/src/main/kotlin/HighwayToolsCommand.kt b/src/main/kotlin/HighwayToolsCommand.kt
index d3edf1b..ce79396 100644
--- a/src/main/kotlin/HighwayToolsCommand.kt
+++ b/src/main/kotlin/HighwayToolsCommand.kt
@@ -12,7 +12,7 @@ object HighwayToolsCommand : ClientCommand(
init {
literal("add", "new", "+") {
block("block") { blockArg ->
- execute("Add a block to ignore list") {
+ execute("Adds a block to ignore list") {
val added = HighwayTools.ignoreBlocks.add(blockArg.value.registryName.toString())
if (added) {
printSettings()
@@ -24,9 +24,9 @@ object HighwayToolsCommand : ClientCommand(
}
}
- literal("del", "rem", "-") {
+ literal("remove", "rem", "-", "del") {
block("block") { blockArg ->
- execute("Remove a block from ignore list") {
+ execute("Removes a block from ignore list") {
val removed = HighwayTools.ignoreBlocks.remove(blockArg.value.registryName.toString())
if (removed) {
printSettings()
@@ -63,7 +63,7 @@ object HighwayToolsCommand : ClientCommand(
literal("distance") {
int("distance") { distanceArg ->
- execute("Set the target distance until the bot stops") {
+ execute("Sets the target distance until the bot stops") {
distancePending = distanceArg.value
sendChatMessage("HighwayTools will stop after (${distanceArg.value}) blocks distance. To remove the limit use distance 0")
}
@@ -72,7 +72,7 @@ object HighwayToolsCommand : ClientCommand(
literal("material", "mat") {
block("block") { blockArg ->
- execute("Set a block as main material") {
+ execute("Sets a block as main material") {
HighwayTools.material = blockArg.value
sendChatMessage("Set your building material to &7${blockArg.value.localizedName}&r.")
}
@@ -81,14 +81,23 @@ object HighwayToolsCommand : ClientCommand(
literal("filler", "fil") {
block("block") { blockArg ->
- execute("Set a block as filler material") {
+ execute("Sets a block as filler material") {
HighwayTools.fillerMat = blockArg.value
sendChatMessage("Set your filling material to &7${blockArg.value.localizedName}&r.")
}
}
}
- execute("Print the settings") {
+ literal("food", "fd") {
+ item("item") { itemArg ->
+ execute("Sets a type of food") {
+ HighwayTools.food = itemArg.value
+ sendChatMessage("Set your food item to &7${itemArg.value.registryName}&r.")
+ }
+ }
+ }
+
+ execute("Print settings") {
printSettings()
}
}
diff --git a/src/main/kotlin/HighwayToolsHud.kt b/src/main/kotlin/HighwayToolsHud.kt
index f809617..9e86f5d 100644
--- a/src/main/kotlin/HighwayToolsHud.kt
+++ b/src/main/kotlin/HighwayToolsHud.kt
@@ -16,6 +16,7 @@ internal object HighwayToolsHud : PluginLabelHud(
val showEnvironment by setting("Show Environment", true, description = "Toggles the Environment section in HUD")
val showTask by setting("Show Task", true, description = "Toggles the Task section in HUD")
val showEstimations by setting("Show Estimations", true, description = "Toggles the Estimations section in HUD")
+ val showQueue by setting("Show Queue", false, description = "Shows task queue in HUD")
private val resetStats = setting("Reset Stats", false, description = "Resets the stats")
init {
diff --git a/src/main/kotlin/trombone/BaritoneHelper.kt b/src/main/kotlin/trombone/BaritoneHelper.kt
index d8e2d78..c8a4f44 100644
--- a/src/main/kotlin/trombone/BaritoneHelper.kt
+++ b/src/main/kotlin/trombone/BaritoneHelper.kt
@@ -7,22 +7,23 @@ object BaritoneHelper {
private var baritoneSettingAllowPlace = false
private var baritoneSettingAllowBreak = false
private var baritoneSettingRenderGoal = false
+ private var baritoneSettingAllowInventory = false
fun setupBaritone() {
baritoneSettingAllowPlace = BaritoneUtils.settings?.allowPlace?.value ?: true
baritoneSettingAllowBreak = BaritoneUtils.settings?.allowBreak?.value ?: true
+ baritoneSettingRenderGoal = BaritoneUtils.settings?.renderGoal?.value ?: true
+ baritoneSettingAllowInventory = BaritoneUtils.settings?.allowInventory?.value ?: true
BaritoneUtils.settings?.allowPlace?.value = false
-// BaritoneUtils.settings?.allowBreak?.value = false
-
- if (!goalRender) {
- baritoneSettingRenderGoal = BaritoneUtils.settings?.renderGoal?.value ?: true
- BaritoneUtils.settings?.renderGoal?.value = false
- }
+ BaritoneUtils.settings?.allowBreak?.value = false
+ BaritoneUtils.settings?.renderGoal?.value = goalRender
+ BaritoneUtils.settings?.allowInventory?.value = false
}
fun resetBaritone() {
BaritoneUtils.settings?.allowPlace?.value = baritoneSettingAllowPlace
-// BaritoneUtils.settings?.allowBreak?.value = baritoneSettingAllowBreak
+ BaritoneUtils.settings?.allowBreak?.value = baritoneSettingAllowBreak
BaritoneUtils.settings?.renderGoal?.value = baritoneSettingRenderGoal
+ BaritoneUtils.settings?.allowInventory?.value = baritoneSettingAllowInventory
}
}
\ No newline at end of file
diff --git a/src/main/kotlin/trombone/IO.kt b/src/main/kotlin/trombone/IO.kt
index 87c2651..6251d61 100644
--- a/src/main/kotlin/trombone/IO.kt
+++ b/src/main/kotlin/trombone/IO.kt
@@ -2,6 +2,7 @@ package trombone
import HighwayTools.anonymizeStats
import HighwayTools.disableMode
+import HighwayTools.disableWarnings
import HighwayTools.fillerMat
import HighwayTools.height
import HighwayTools.ignoreBlocks
@@ -13,13 +14,14 @@ import HighwayTools.proxyCommand
import HighwayTools.rubberbandTimeout
import HighwayTools.usingProxy
import com.lambda.client.event.SafeClientEvent
-import com.lambda.client.module.modules.combat.AutoLog
+import com.lambda.client.module.modules.combat.AutoDisconnect
import com.lambda.client.module.modules.misc.AntiAFK
import com.lambda.client.module.modules.misc.AutoObsidian
import com.lambda.client.module.modules.movement.AntiHunger
import com.lambda.client.module.modules.movement.Velocity
import com.lambda.client.module.modules.player.AutoEat
import com.lambda.client.module.modules.player.LagNotifier
+import com.lambda.client.module.modules.player.NoGhostItems
import com.lambda.client.process.PauseProcess
import com.lambda.client.util.math.Direction
import com.lambda.client.util.math.VectorUtils.distanceTo
@@ -31,13 +33,14 @@ import kotlinx.coroutines.launch
import net.minecraft.client.audio.PositionedSoundRecord
import net.minecraft.init.SoundEvents
import net.minecraft.util.text.TextComponentString
+import net.minecraft.util.text.TextFormatting
import net.minecraft.world.EnumDifficulty
import trombone.Pathfinder.currentBlockPos
import trombone.Pathfinder.startingBlockPos
import trombone.Pathfinder.startingDirection
import trombone.Statistics.totalBlocksBroken
import trombone.Statistics.totalBlocksPlaced
-import trombone.Trombone.Mode
+import trombone.Trombone.Structure
import trombone.Trombone.module
import kotlin.math.abs
@@ -46,73 +49,84 @@ object IO {
NONE, ANTI_AFK, LOGOUT
}
- enum class DebugMessages {
- OFF, IMPORTANT, ALL
+ enum class DebugLevel {
+ OFF, IMPORTANT, VERBOSE
}
fun SafeClientEvent.pauseCheck(): Boolean =
- !Pathfinder.rubberbandTimer.tick(rubberbandTimeout.toLong(), false) ||
- player.inventory.isEmpty ||
- PauseProcess.isActive ||
- AutoObsidian.isActive() ||
- (world.difficulty == EnumDifficulty.PEACEFUL &&
- player.dimension == 1 &&
- @Suppress("UNNECESSARY_SAFE_CALL")
- player.serverBrand?.contains("2b2t") == true)
-
- fun printEnable() {
- if (info) {
- MessageSendHelper.sendRawChatMessage(" §9> §7Direction: §a${startingDirection.displayName} / ${startingDirection.displayNameXY}§r")
-
- if (!anonymizeStats) {
- if (startingDirection.isDiagonal) {
- MessageSendHelper.sendRawChatMessage(" §9> §7Axis offset: §a%,d %,d§r".format(startingBlockPos.x, startingBlockPos.z))
-
- if (abs(startingBlockPos.x) != abs(startingBlockPos.z)) {
- MessageSendHelper.sendRawChatMessage(" §9> §cYou may have an offset to diagonal highway position!")
- }
+ !Pathfinder.rubberbandTimer.tick(rubberbandTimeout.toLong(), false)
+ || player.inventory.isEmpty
+ || PauseProcess.isActive
+ || AutoObsidian.isActive()
+ || isInQueue()
+ || !player.isEntityAlive
+ || !player.onGround
+
+ private fun SafeClientEvent.isInQueue() =
+ world.difficulty == EnumDifficulty.PEACEFUL
+ && player.dimension == 1
+ && @Suppress("UNNECESSARY_SAFE_CALL")
+ player.serverBrand?.contains("2b2t") == true
+
+ fun SafeClientEvent.printEnable() {
+ MessageSendHelper.sendRawChatMessage(" §9> §7Direction: §a${startingDirection.displayName} / ${startingDirection.displayNameXY}§r")
+
+ if (!anonymizeStats) {
+ if (startingDirection.isDiagonal) {
+ MessageSendHelper.sendRawChatMessage(" §9> §7Axis offset: §a%,d %,d§r".format(startingBlockPos.x, startingBlockPos.z))
+
+ if (abs(startingBlockPos.x) != abs(startingBlockPos.z)) {
+ MessageSendHelper.sendRawChatMessage(" §c[!] You may have an offset to diagonal highway position!")
+ }
+ } else {
+ if (startingDirection == Direction.NORTH || startingDirection == Direction.SOUTH) {
+ MessageSendHelper.sendRawChatMessage(" §9> §7Axis offset: §a%,d§r".format(startingBlockPos.x))
} else {
- if (startingDirection == Direction.NORTH || startingDirection == Direction.SOUTH) {
- MessageSendHelper.sendRawChatMessage(" §9> §7Axis offset: §a%,d§r".format(startingBlockPos.x))
- } else {
- MessageSendHelper.sendRawChatMessage(" §9> §7Axis offset: §a%,d§r".format(startingBlockPos.z))
- }
-
+ MessageSendHelper.sendRawChatMessage(" §9> §7Axis offset: §a%,d§r".format(startingBlockPos.z))
}
}
+ }
- if (startingBlockPos.y != 120 && mode != Mode.TUNNEL) {
- MessageSendHelper.sendRawChatMessage(" §9> §cCheck altitude and make sure to build at Y: 120 for the correct height")
+ if (!disableWarnings) {
+ if (startingBlockPos.y != 120 && mode != Structure.TUNNEL) {
+ MessageSendHelper.sendRawChatMessage(" §c[!] Check altitude and make sure to build at Y: 120 for the correct height")
}
if (AntiHunger.isEnabled) {
- MessageSendHelper.sendRawChatMessage(" §9> §cAntiHunger does slow down block interactions.")
+ MessageSendHelper.sendRawChatMessage(" §c[!] AntiHunger does slow down block interactions.")
}
if (LagNotifier.isDisabled) {
- MessageSendHelper.sendRawChatMessage(" §9> §cYou should activate LagNotifier to make the bot stop on server lag.")
+ MessageSendHelper.sendRawChatMessage(" §c[!] You should activate LagNotifier to make the bot stop on server lag.")
}
if (AutoEat.isDisabled) {
- MessageSendHelper.sendRawChatMessage(" §9> §cYou should activate AutoEat to not die on starvation.")
+ MessageSendHelper.sendRawChatMessage(" §c[!] You should activate AutoEat to not die on starvation.")
}
- if (AutoLog.isDisabled) {
- MessageSendHelper.sendRawChatMessage(" §9> §cYou should activate AutoLog to prevent most deaths when afk.")
+ if (AutoDisconnect.isDisabled) {
+ MessageSendHelper.sendRawChatMessage(" §c[!] You should activate AutoLog to prevent most deaths when afk.")
}
if (multiBuilding && Velocity.isDisabled) {
- MessageSendHelper.sendRawChatMessage(" §9> §cMake sure to enable Velocity to not get pushed from your mates.")
+ MessageSendHelper.sendRawChatMessage(" §c[!] Make sure to enable Velocity to not get pushed from your mates.")
}
if (material == fillerMat) {
- MessageSendHelper.sendRawChatMessage(" §9> §cMake sure to use §aTunnel Mode§c instead of having same material for both main and filler!")
+ MessageSendHelper.sendRawChatMessage(" §c[!] Make sure to use §aTunnel Mode§c instead of having same material for both main and filler!")
+ }
+
+ if (mode == Structure.HIGHWAY && height < 3) {
+ MessageSendHelper.sendRawChatMessage(" §c[!] You may increase the height to at least 3")
}
- if (mode == Mode.HIGHWAY && height < 3) {
- MessageSendHelper.sendRawChatMessage(" §9> §cYou may increase the height to at least 3")
+ if (isInQueue()) {
+ MessageSendHelper.sendRawChatMessage(" §c[!] You should not activate the bot in queue! Bot will move to 0 0.")
}
+ if (NoGhostItems.isDisabled) {
+ MessageSendHelper.sendRawChatMessage(" §c[!] Please consider using the module NoGhostItems to minimize item desyncs")
+ }
}
}
@@ -139,20 +153,20 @@ object IO {
}
}
- fun SafeClientEvent.disableError(message: String) {
- MessageSendHelper.sendChatMessage("${module.chatName} $message")
+ fun SafeClientEvent.disableError(error: String) {
+ MessageSendHelper.sendErrorMessage("${module.chatName} §c[!] $error")
mc.soundHandler.playSound(PositionedSoundRecord.getRecord(SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0f, 1.0f))
module.disable()
when (disableMode) {
DisableMode.ANTI_AFK -> {
- MessageSendHelper.sendChatMessage("${module.chatName} Going into AFK mode.")
+ MessageSendHelper.sendWarningMessage("${module.chatName} §c[!] ${TextFormatting.AQUA}Going into AFK mode.")
AntiAFK.enable()
}
DisableMode.LOGOUT -> {
- MessageSendHelper.sendChatMessage("${module.chatName} CAUTION: Logging of in 1 minute!")
+ MessageSendHelper.sendWarningMessage("${module.chatName} §c[!] ${TextFormatting.DARK_RED}CAUTION: Logging off in 1 minute!")
defaultScope.launch {
delay(6000L)
- if (disableMode == DisableMode.LOGOUT && module.isEnabled) {
+ if (disableMode == DisableMode.LOGOUT && module.isDisabled) {
onMainThreadSafe {
if (usingProxy) {
player.sendChatMessage(proxyCommand)
@@ -160,6 +174,8 @@ object IO {
connection.networkManager.closeChannel(TextComponentString("Done building highways."))
}
}
+ } else {
+ MessageSendHelper.sendChatMessage("${module.chatName} ${TextFormatting.GREEN}Logout canceled.")
}
}
}
diff --git a/src/main/kotlin/trombone/Pathfinder.kt b/src/main/kotlin/trombone/Pathfinder.kt
index eba56c7..0361196 100644
--- a/src/main/kotlin/trombone/Pathfinder.kt
+++ b/src/main/kotlin/trombone/Pathfinder.kt
@@ -1,8 +1,7 @@
package trombone
-import HighwayTools.bridging
-import HighwayTools.maxReach
import HighwayTools.moveSpeed
+import HighwayTools.scaffold
import com.lambda.client.event.SafeClientEvent
import com.lambda.client.util.BaritoneUtils
import com.lambda.client.util.EntityUtils.flooredPosition
@@ -13,16 +12,19 @@ import com.lambda.client.util.math.VectorUtils.distanceTo
import com.lambda.client.util.math.VectorUtils.multiply
import com.lambda.client.util.math.VectorUtils.toVec3dCenter
import com.lambda.client.util.world.isReplaceable
+import net.minecraft.block.BlockLiquid
+import net.minecraft.init.Blocks
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Vec3d
import trombone.IO.disableError
import trombone.Statistics.simpleMovingAverageDistance
import trombone.Trombone.active
+import trombone.handler.Container.containerTask
import trombone.handler.Container.getCollectingPosition
-import trombone.handler.Player.lastHitVec
-import trombone.handler.Tasks.isTaskDone
-import trombone.handler.Tasks.tasks
-import trombone.handler.Tasks.updateTasks
+import trombone.handler.Inventory.lastHitVec
+import trombone.task.TaskManager.isBehindPos
+import trombone.task.TaskManager.populateTasks
+import trombone.task.TaskManager.tasks
import trombone.task.TaskState
object Pathfinder {
@@ -53,27 +55,7 @@ object Pathfinder {
MovementState.RUNNING -> {
goal = currentBlockPos
- val current = currentBlockPos
- val possiblePos = current.add(startingDirection.directionVec)
-
- if (!isTaskDone(possiblePos) ||
- !isTaskDone(possiblePos.up()) ||
- !isTaskDone(possiblePos.down())) return
-
- if (!checkTasks(possiblePos.up())) return
-
- // ToDo: Blocked by entities
-// if (!world.checkNoEntityCollision(AxisAlignedBB(possiblePos.down()), null)) {
-// possiblePos = possiblePos.add(startingDirection.directionVec)
-// }
-
- if (current != possiblePos && player.positionVector.distanceTo(possiblePos) < 3) {
- simpleMovingAverageDistance.add(System.currentTimeMillis())
- lastHitVec = Vec3d.ZERO
- currentBlockPos = possiblePos
- updateTasks()
- }
-
+ // ToDo: Rewrite
if (currentBlockPos.distanceTo(targetBlockPos) < 2 ||
(distancePending > 0 &&
startingBlockPos.add(
@@ -82,6 +64,26 @@ object Pathfinder {
disableError("Reached target destination")
return
}
+
+ val possiblePos = currentBlockPos.add(startingDirection.directionVec)
+
+ if (!isTaskDone(possiblePos.up())
+ || !isTaskDone(possiblePos)
+ || !isTaskDone(possiblePos.down())
+ ) return
+
+ if (!checkForResidue(possiblePos.up())) return
+
+ if (world.getBlockState(possiblePos.down()).isReplaceable) return
+
+ if (currentBlockPos != possiblePos
+ && player.positionVector.distanceTo(currentBlockPos.toVec3dCenter()) < 2
+ ) {
+ simpleMovingAverageDistance.add(System.currentTimeMillis())
+ lastHitVec = Vec3d.ZERO
+ currentBlockPos = possiblePos
+ populateTasks()
+ }
}
MovementState.BRIDGE -> {
goal = null
@@ -111,27 +113,33 @@ object Pathfinder {
}
}
- private fun checkTasks(pos: BlockPos): Boolean {
- return tasks.values.all {
- it.taskState == TaskState.DONE ||
- pos.toVec3dCenter().distanceTo(it.blockPos.toVec3dCenter()) < maxReach - 0.5
- }
+ private fun checkForResidue(pos: BlockPos) =
+ containerTask.taskState == TaskState.DONE
+ && tasks.values.all {
+ it.taskState == TaskState.DONE || !isBehindPos(pos, it.blockPos)
+ }
+
+ private fun SafeClientEvent.isTaskDone(pos: BlockPos): Boolean {
+ val block = world.getBlockState(pos).block
+ return tasks[pos]?.let {
+ it.taskState == TaskState.DONE
+ && block != Blocks.PORTAL
+ && block != Blocks.END_PORTAL
+ && block !is BlockLiquid
+ } ?: false
}
fun SafeClientEvent.shouldBridge(): Boolean {
- return bridging &&
- world.isAirBlock(currentBlockPos.add(startingDirection.directionVec)) &&
- world.isAirBlock(currentBlockPos.add(startingDirection.directionVec).up()) &&
- world.getBlockState(currentBlockPos.add(startingDirection.directionVec).down()).isReplaceable &&
- tasks.values.filter {
- it.taskState == TaskState.PLACE ||
- it.taskState == TaskState.LIQUID
- }.none {
- it.sequence.isNotEmpty()
- } &&
- tasks.values.none {
- it.taskState == TaskState.PENDING_PLACE
- }
+ return scaffold
+ && containerTask.taskState == TaskState.DONE
+ && world.isAirBlock(currentBlockPos.add(startingDirection.directionVec))
+ && world.isAirBlock(currentBlockPos.add(startingDirection.directionVec).up())
+ && world.getBlockState(currentBlockPos.add(startingDirection.directionVec).down()).isReplaceable
+ && tasks.values.none { it.taskState == TaskState.PENDING_PLACE }
+ && tasks.values.filter {
+ it.taskState == TaskState.PLACE
+ || it.taskState == TaskState.LIQUID
+ }.none { it.sequence.isNotEmpty() }
}
private fun SafeClientEvent.moveTo(target: Vec3d) {
diff --git a/src/main/kotlin/trombone/Process.kt b/src/main/kotlin/trombone/Process.kt
index 779e047..cc1ae3a 100644
--- a/src/main/kotlin/trombone/Process.kt
+++ b/src/main/kotlin/trombone/Process.kt
@@ -8,7 +8,7 @@ import baritone.api.process.PathingCommand
import baritone.api.process.PathingCommandType
import com.lambda.client.util.math.CoordinateConverter.asString
import trombone.Pathfinder.goal
-import trombone.handler.Tasks.lastTask
+import trombone.task.TaskManager.lastTask
/**
* @author Avanatiker
diff --git a/src/main/kotlin/trombone/Renderer.kt b/src/main/kotlin/trombone/Renderer.kt
index ef9da8a..5599b2f 100644
--- a/src/main/kotlin/trombone/Renderer.kt
+++ b/src/main/kotlin/trombone/Renderer.kt
@@ -11,7 +11,6 @@ import HighwayTools.showCurrentPos
import HighwayTools.showDebugRender
import HighwayTools.textScale
import HighwayTools.thickness
-import com.lambda.client.event.SafeClientEvent
import com.lambda.client.util.color.ColorHolder
import com.lambda.client.util.graphics.ESPRenderer
import com.lambda.client.util.graphics.GlStateUtils
@@ -24,8 +23,8 @@ import net.minecraft.util.math.BlockPos
import org.lwjgl.opengl.GL11
import trombone.Pathfinder.currentBlockPos
import trombone.handler.Container.containerTask
-import trombone.handler.Tasks.tasks
import trombone.task.BlockTask
+import trombone.task.TaskManager.tasks
import trombone.task.TaskState
import kotlin.math.PI
import kotlin.math.cos
@@ -48,7 +47,7 @@ object Renderer {
}
tasks.values.forEach {
- if (it.block == Blocks.AIR && it.taskState == TaskState.DONE) return@forEach
+ if (it.targetBlock == Blocks.AIR && it.taskState == TaskState.DONE) return@forEach
if (it.toRemove) {
addToRenderer(it, currentTime, true)
} else {
@@ -66,24 +65,13 @@ object Renderer {
updateOverlay(containerTask.blockPos, containerTask)
}
- tasks.forEach { (pos, blockTask) ->
- if (blockTask.taskState == TaskState.DONE) return@forEach
+ tasks.filterValues {
+ it.taskState != TaskState.DONE
+ }.forEach { (pos, blockTask) ->
updateOverlay(pos, blockTask)
}
}
- fun SafeClientEvent.updateRenderer() {
- containerTask.aabb = world
- .getBlockState(containerTask.blockPos)
- .getSelectedBoundingBox(world, containerTask.blockPos)
-
- tasks.values.forEach {
- it.aabb = world
- .getBlockState(it.blockPos)
- .getSelectedBoundingBox(world, it.blockPos)
- }
- }
-
private fun updateOverlay(pos: BlockPos, blockTask: BlockTask) {
GL11.glPushMatrix()
val screenPos = ProjectionUtils.toScreenPos(pos.toVec3dCenter())
diff --git a/src/main/kotlin/trombone/Statistics.kt b/src/main/kotlin/trombone/Statistics.kt
index dc83546..7f10476 100644
--- a/src/main/kotlin/trombone/Statistics.kt
+++ b/src/main/kotlin/trombone/Statistics.kt
@@ -8,13 +8,13 @@ import HighwayTools.height
import HighwayTools.material
import HighwayTools.mode
import HighwayTools.placeDelay
-import HighwayTools.printDebug
import HighwayTools.width
import HighwayToolsHud
import HighwayToolsHud.showEnvironment
import HighwayToolsHud.showEstimations
import HighwayToolsHud.showLifeTime
import HighwayToolsHud.showPerformance
+import HighwayToolsHud.showQueue
import HighwayToolsHud.showSession
import HighwayToolsHud.showTask
import com.lambda.client.event.SafeClientEvent
@@ -28,8 +28,6 @@ import com.lambda.client.util.items.item
import com.lambda.client.util.math.CoordinateConverter.asString
import com.lambda.client.util.math.VectorUtils.distanceTo
import com.lambda.client.util.math.VectorUtils.multiply
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.sync.withLock
import net.minecraft.init.Blocks
import net.minecraft.init.Items
import net.minecraft.item.ItemPickaxe
@@ -40,20 +38,20 @@ import trombone.Pathfinder.currentBlockPos
import trombone.Pathfinder.moveState
import trombone.Pathfinder.startingBlockPos
import trombone.Pathfinder.startingDirection
-import trombone.Trombone.Mode
+import trombone.Trombone.Structure
import trombone.handler.Container.containerTask
import trombone.handler.Container.grindCycles
-import trombone.handler.Player.packetLimiter
-import trombone.handler.Player.packetLimiterMutex
-import trombone.handler.Tasks.sortedTasks
+import trombone.handler.Inventory.packetLimiter
import trombone.interaction.Place.extraPlaceDelay
import trombone.task.BlockTask
+import trombone.task.TaskManager.sortedTasks
import trombone.task.TaskState
+import java.util.concurrent.ConcurrentLinkedDeque
object Statistics {
- val simpleMovingAveragePlaces = ArrayDeque()
- val simpleMovingAverageBreaks = ArrayDeque()
- val simpleMovingAverageDistance = ArrayDeque()
+ val simpleMovingAveragePlaces = ConcurrentLinkedDeque()
+ val simpleMovingAverageBreaks = ConcurrentLinkedDeque()
+ val simpleMovingAverageDistance = ConcurrentLinkedDeque()
var totalBlocksPlaced = 0
var totalBlocksBroken = 0
private var totalDistance = 0.0
@@ -63,8 +61,9 @@ object Statistics {
private var materialLeft = 0
private var fillerMatLeft = 0
private var lastToolDamage = 0
- private var durabilityUsages = 0
+ var durabilityUsages = 0
private var matPlaced = 0
+ private var matMined = 0
private var enderMined = 0
private var netherrackMined = 0
private var pickaxeBroken = 0
@@ -103,14 +102,10 @@ object Statistics {
updateDeque(simpleMovingAverageBreaks, removeTime)
updateDeque(simpleMovingAverageDistance, removeTime)
- runBlocking {
- packetLimiterMutex.withLock {
- updateDeque(packetLimiter, System.currentTimeMillis() - 1000L)
- }
- }
+ updateDeque(packetLimiter, System.currentTimeMillis() - 1000L)
}
- private fun updateDeque(deque: ArrayDeque, removeTime: Long) {
+ private fun updateDeque(deque: ConcurrentLinkedDeque, removeTime: Long) {
while (deque.isNotEmpty() && deque.first() < removeTime) {
deque.removeFirst()
}
@@ -132,17 +127,7 @@ object Statistics {
if (showEstimations) gatherEstimations(displayText, runtimeSec, distanceDone)
- if (printDebug) {
- if (containerTask.taskState != TaskState.DONE) {
- displayText.addLine("Container", primaryColor, scale = 0.6f)
- displayText.addLine(containerTask.prettyPrint(), primaryColor, scale = 0.6f)
- }
-
- if (sortedTasks.isNotEmpty()) {
- displayText.addLine("Pending", primaryColor, scale = 0.6f)
- addTaskComponentList(displayText, sortedTasks)
- }
- }
+ if (showQueue) gatherQueue(displayText)
displayText.addLine("by Constructor#9948/Avanatiker", primaryColor, scale = 0.6f)
}
@@ -163,7 +148,7 @@ object Statistics {
if (!anonymizeStats) displayText.add(" Start:", primaryColor)
if (!anonymizeStats) displayText.addLine("(${startingBlockPos.asString()})", secondaryColor)
- displayText.add(" Session placed / destroyed:", primaryColor)
+ displayText.add(" Placed / destroyed:", primaryColor)
displayText.addLine("%,d".format(totalBlocksPlaced) + " / " + "%,d".format(totalBlocksBroken), secondaryColor)
@@ -173,6 +158,9 @@ object Statistics {
matPlaced = StatList.getObjectUseStats(material.item)?.let {
player.statFileWriter.readStat(it)
} ?: 0
+ matMined = StatList.getBlockStats(material)?.let {
+ player.statFileWriter.readStat(it)
+ } ?: 0
enderMined = StatList.getBlockStats(Blocks.ENDER_CHEST)?.let {
player.statFileWriter.readStat(it)
} ?: 0
@@ -183,16 +171,21 @@ object Statistics {
player.statFileWriter.readStat(it)
} ?: 0
- if (matPlaced + enderMined + netherrackMined + pickaxeBroken > 0) {
+ if (matPlaced + matMined + enderMined + netherrackMined + pickaxeBroken > 0) {
displayText.addLine("Lifetime", primaryColor)
}
- if (mode == Mode.HIGHWAY || mode == Mode.FLAT) {
+ if (mode == Structure.HIGHWAY || mode == Structure.FLAT) {
if (matPlaced > 0) {
displayText.add(" ${material.localizedName} placed:", primaryColor)
displayText.addLine("%,d".format(matPlaced), secondaryColor)
}
+ if (matMined > 0) {
+ displayText.add(" ${material.localizedName} mined:", primaryColor)
+ displayText.addLine("%,d".format(matMined), secondaryColor)
+ }
+
if (enderMined > 0) {
displayText.add(" ${Blocks.ENDER_CHEST.localizedName} mined:", primaryColor)
displayText.addLine("%,d".format(enderMined), secondaryColor)
@@ -227,6 +220,9 @@ object Statistics {
displayText.add(" Pickaxes / h:", primaryColor)
displayText.addLine("%.2f".format((durabilityUsages / runtimeSec) * 60.0 * 60.0 / 1561.0), secondaryColor)
+
+ displayText.add(" Mining packets / s:", primaryColor)
+ displayText.addLine("${packetLimiter.size}", secondaryColor)
}
private fun gatherEnvironment(displayText: TextComponent) {
@@ -262,10 +258,17 @@ object Statistics {
displayText.addLine("${it.taskState}", secondaryColor)
displayText.add(" Target block:", primaryColor)
- displayText.addLine(it.block.localizedName, secondaryColor)
+ displayText.addLine(it.targetBlock.localizedName, secondaryColor)
- if (!anonymizeStats) displayText.add(" Position:", primaryColor)
- if (!anonymizeStats) displayText.addLine("(${it.blockPos.asString()})", secondaryColor)
+ if (it.item != Items.AIR) {
+ displayText.add(" Target item:", primaryColor)
+ displayText.addLine(it.targetBlock.localizedName, secondaryColor)
+ }
+
+ if (!anonymizeStats) {
+ displayText.add(" Position:", primaryColor)
+ displayText.addLine("(${it.blockPos.asString()})", secondaryColor)
+ }
displayText.add(" Ticks stuck:", primaryColor)
displayText.addLine("${it.stuckTicks}", secondaryColor)
@@ -274,7 +277,7 @@ object Statistics {
private fun SafeClientEvent.gatherEstimations(displayText: TextComponent, runtimeSec: Double, distanceDone: Double) {
when (mode) {
- Mode.HIGHWAY, Mode.FLAT -> {
+ Structure.HIGHWAY, Structure.FLAT -> {
materialLeft = player.inventorySlots.countBlock(material)
fillerMatLeft = player.inventorySlots.countBlock(fillerMat)
val indirectMaterialLeft = 8 * player.inventorySlots.countBlock(Blocks.ENDER_CHEST)
@@ -302,8 +305,8 @@ object Statistics {
displayText.add(" ${fillerMat.localizedName}:", primaryColor)
displayText.addLine("$fillerMatLeft", secondaryColor)
- if (moveState == Pathfinder.MovementState.RESTOCK) {
- displayText.add(" Ender Chest cycles:", primaryColor)
+ if (grindCycles > 0) {
+ displayText.add(" Ender Chest cycles left:", primaryColor)
displayText.addLine("$grindCycles", secondaryColor)
} else {
displayText.add(" Distance left:", primaryColor)
@@ -316,7 +319,7 @@ object Statistics {
displayText.addLine("$hoursLeft:$minutesLeft:$secondsLeft", secondaryColor)
}
}
- Mode.TUNNEL -> {
+ Structure.TUNNEL -> {
val pickaxesLeft = player.inventorySlots.countItem()
val tunnelingLeft = (pickaxesLeft * 1561) / (durabilityUsages.coerceAtLeast(1) / distanceDone.coerceAtLeast(1.0))
@@ -343,6 +346,18 @@ object Statistics {
}
}
+ private fun gatherQueue(displayText: TextComponent) {
+ if (containerTask.taskState != TaskState.DONE) {
+ displayText.addLine("Container", primaryColor, scale = 0.6f)
+ displayText.addLine(containerTask.prettyPrint(), primaryColor, scale = 0.6f)
+ }
+
+ if (sortedTasks.isNotEmpty()) {
+ displayText.addLine("Pending", primaryColor, scale = 0.6f)
+ addTaskComponentList(displayText, sortedTasks)
+ }
+ }
+
private fun addTaskComponentList(displayText: TextComponent, tasks: Collection) {
tasks.forEach {
displayText.addLine(it.prettyPrint(), primaryColor, scale = 0.6f)
@@ -364,4 +379,4 @@ object Statistics {
lastToolDamage = 0
durabilityUsages = 0
}
-}
\ No newline at end of file
+}
diff --git a/src/main/kotlin/trombone/Trombone.kt b/src/main/kotlin/trombone/Trombone.kt
index b533961..23d13ba 100644
--- a/src/main/kotlin/trombone/Trombone.kt
+++ b/src/main/kotlin/trombone/Trombone.kt
@@ -1,6 +1,7 @@
package trombone
import HighwayTools
+import HighwayTools.info
import com.lambda.client.event.SafeClientEvent
import trombone.BaritoneHelper.resetBaritone
import trombone.BaritoneHelper.setupBaritone
@@ -10,19 +11,18 @@ import trombone.IO.printEnable
import trombone.Pathfinder.clearProcess
import trombone.Pathfinder.setupPathing
import trombone.Pathfinder.updateProcess
-import trombone.Renderer.updateRenderer
import trombone.Statistics.updateStats
import trombone.Statistics.updateTotalDistance
-import trombone.handler.Player.updateRotation
-import trombone.handler.Tasks.clearTasks
-import trombone.handler.Tasks.runTasks
-import trombone.handler.Tasks.updateTasks
+import trombone.handler.Inventory.updateRotation
+import trombone.task.TaskManager.clearTasks
+import trombone.task.TaskManager.populateTasks
+import trombone.task.TaskManager.runTasks
object Trombone {
val module = HighwayTools
var active = false
- enum class Mode {
+ enum class Structure {
HIGHWAY, FLAT, TUNNEL
}
@@ -30,8 +30,7 @@ object Trombone {
clearTasks()
setupPathing()
setupBaritone()
- printEnable()
- updateTasks()
+ if (info) printEnable()
}
fun onDisable() {
@@ -43,8 +42,7 @@ object Trombone {
}
fun SafeClientEvent.tick() {
- updateRenderer()
- updateTasks()
+ populateTasks()
updateStats()
if (pauseCheck()) return
diff --git a/src/main/kotlin/trombone/Blueprint.kt b/src/main/kotlin/trombone/blueprint/BlueprintGenerator.kt
similarity index 53%
rename from src/main/kotlin/trombone/Blueprint.kt
rename to src/main/kotlin/trombone/blueprint/BlueprintGenerator.kt
index 1f95a5b..b9ce776 100644
--- a/src/main/kotlin/trombone/Blueprint.kt
+++ b/src/main/kotlin/trombone/blueprint/BlueprintGenerator.kt
@@ -1,10 +1,11 @@
-package trombone
+package trombone.blueprint
import HighwayTools.backfill
import HighwayTools.cleanCorner
import HighwayTools.cleanFloor
+import HighwayTools.cleanLeftWall
+import HighwayTools.cleanRightWall
import HighwayTools.cleanRoof
-import HighwayTools.cleanWalls
import HighwayTools.clearSpace
import HighwayTools.cornerBlock
import HighwayTools.fillerMat
@@ -15,60 +16,63 @@ import HighwayTools.mode
import HighwayTools.railing
import HighwayTools.railingHeight
import HighwayTools.width
+import com.lambda.client.commons.extension.ceilToInt
+import com.lambda.client.commons.extension.floorToInt
import com.lambda.client.util.math.Direction
import com.lambda.client.util.math.VectorUtils.distanceTo
import com.lambda.client.util.math.VectorUtils.multiply
-import com.lambda.commons.extension.ceilToInt
-import com.lambda.commons.extension.floorToInt
-import net.minecraft.block.Block
+import com.lambda.client.util.math.VectorUtils.toVec3dCenter
import net.minecraft.init.Blocks
import net.minecraft.util.math.BlockPos
import trombone.Pathfinder.currentBlockPos
+import trombone.Pathfinder.startingBlockPos
import trombone.Pathfinder.startingDirection
-import trombone.Trombone.Mode
+import trombone.Trombone.Structure
-object Blueprint {
- val blueprint = LinkedHashMap()
+object BlueprintGenerator {
+ val blueprint = HashMap()
fun generateBluePrint() {
blueprint.clear()
val basePos = currentBlockPos.down()
- if (mode != Mode.FLAT) {
- val zDirection = startingDirection
- val xDirection = zDirection.clockwise(if (zDirection.isDiagonal) 1 else 2)
-
- for (x in -maxReach.floorToInt() * 5..maxReach.ceilToInt() * 5) {
- val thisPos = basePos.add(zDirection.directionVec.multiply(x))
- if (clearSpace) generateClear(thisPos, xDirection)
- if (mode == Mode.TUNNEL) {
- if (backfill) {
- generateBackfill(thisPos, xDirection)
- } else {
- if (cleanFloor) generateFloor(thisPos, xDirection)
- if (cleanWalls) generateWalls(thisPos, xDirection)
- if (cleanRoof) generateRoof(thisPos, xDirection)
- if (cleanCorner && !cornerBlock && width > 2) generateCorner(thisPos, xDirection)
- }
+ if (mode == Structure.FLAT) {
+ generateFlat(basePos)
+ return
+ }
+
+ val zDirection = startingDirection
+ val xDirection = zDirection.clockwise(if (zDirection.isDiagonal) 1 else 2)
+
+ for (x in -maxReach.floorToInt() * 5..maxReach.ceilToInt() * 5) {
+ val thisPos = basePos.add(zDirection.directionVec.multiply(x))
+ if (clearSpace) generateClear(thisPos, xDirection)
+ if (mode == Structure.TUNNEL) {
+ if (backfill) {
+ generateBackfill(thisPos, xDirection)
} else {
- generateBase(thisPos, xDirection)
+ if (cleanFloor) generateFloor(thisPos, xDirection)
+ if (cleanRightWall || cleanLeftWall) generateWalls(thisPos, xDirection)
+ if (cleanRoof) generateRoof(thisPos, xDirection)
+ if (cleanCorner && !cornerBlock && width > 2) generateCorner(thisPos, xDirection)
}
+ } else {
+ generateBase(thisPos, xDirection)
}
- if (mode == Mode.TUNNEL && (!cleanFloor || backfill)) {
- if (startingDirection.isDiagonal) {
- for (x in 0..maxReach.floorToInt()) {
- val pos = basePos.add(zDirection.directionVec.multiply(x))
- blueprint[pos] = fillerMat
- blueprint[pos.add(startingDirection.clockwise(7).directionVec)] = fillerMat
- }
- } else {
- for (x in 0..maxReach.floorToInt()) {
- blueprint[basePos.add(zDirection.directionVec.multiply(x))] = fillerMat
- }
+ }
+
+ if (mode == Structure.TUNNEL && (!cleanFloor || backfill)) {
+ if (startingDirection.isDiagonal) {
+ for (x in 0..maxReach.floorToInt()) {
+ val pos = basePos.add(zDirection.directionVec.multiply(x))
+ blueprint[pos] = BlueprintTask(fillerMat, isFiller = true)
+ blueprint[pos.add(startingDirection.clockwise(7).directionVec)] = BlueprintTask(fillerMat, isFiller = true)
+ }
+ } else {
+ for (x in 0..maxReach.floorToInt()) {
+ blueprint[basePos.add(zDirection.directionVec.multiply(x))] = BlueprintTask(fillerMat, isFiller = true)
}
}
- } else {
- generateFlat(basePos)
}
}
@@ -78,14 +82,14 @@ object Blueprint {
val x = w - width / 2
val pos = basePos.add(xDirection.directionVec.multiply(x)).up(h)
- if (mode == Mode.HIGHWAY && h == 0 && isRail(w)) {
+ if (mode == Structure.HIGHWAY && h == 0 && isRail(w)) {
continue
}
- if (mode == Mode.HIGHWAY) {
- blueprint[pos] = Blocks.AIR
+ if (mode == Structure.HIGHWAY) {
+ blueprint[pos] = BlueprintTask(Blocks.AIR)
} else {
- if (!(isRail(w) && h == 0 && !cornerBlock && width > 2)) blueprint[pos.up()] = Blocks.AIR
+ if (!(isRail(w) && h == 0 && !cornerBlock && width > 2)) blueprint[pos.up()] = BlueprintTask(Blocks.AIR)
}
}
}
@@ -96,14 +100,14 @@ object Blueprint {
val x = w - width / 2
val pos = basePos.add(xDirection.directionVec.multiply(x))
- if (mode == Mode.HIGHWAY && isRail(w)) {
- if (!cornerBlock && width > 2 && startingDirection.isDiagonal) blueprint[pos] = fillerMat
+ if (mode == Structure.HIGHWAY && isRail(w)) {
+ if (!cornerBlock && width > 2 && startingDirection.isDiagonal) blueprint[pos] = BlueprintTask(fillerMat, isSupport = true)
val startHeight = if (cornerBlock && width > 2) 0 else 1
for (y in startHeight..railingHeight) {
- blueprint[pos.up(y)] = material
+ blueprint[pos.up(y)] = BlueprintTask(material)
}
} else {
- blueprint[pos] = material
+ blueprint[pos] = BlueprintTask(material)
}
}
}
@@ -117,7 +121,7 @@ object Blueprint {
for (w in 0 until wid) {
val x = w - wid / 2
val pos = basePos.add(xDirection.directionVec.multiply(x))
- blueprint[pos] = fillerMat
+ blueprint[pos] = BlueprintTask(fillerMat, isFiller = true)
}
}
@@ -128,8 +132,8 @@ object Blueprint {
0
}
for (h in cb until height) {
- blueprint[basePos.add(xDirection.directionVec.multiply(-1 - width / 2)).up(h + 1)] = fillerMat
- blueprint[basePos.add(xDirection.directionVec.multiply(width - width / 2)).up(h + 1)] = fillerMat
+ if (cleanRightWall) blueprint[basePos.add(xDirection.directionVec.multiply(width - width / 2)).up(h + 1)] = BlueprintTask(fillerMat, isFiller = true)
+ if (cleanLeftWall) blueprint[basePos.add(xDirection.directionVec.multiply(-1 - width / 2)).up(h + 1)] = BlueprintTask(fillerMat, isFiller = true)
}
}
@@ -137,13 +141,13 @@ object Blueprint {
for (w in 0 until width) {
val x = w - width / 2
val pos = basePos.add(xDirection.directionVec.multiply(x))
- blueprint[pos.up(height + 1)] = fillerMat
+ blueprint[pos.up(height + 1)] = BlueprintTask(fillerMat, isFiller = true)
}
}
private fun generateCorner(basePos: BlockPos, xDirection: Direction) {
- blueprint[basePos.add(xDirection.directionVec.multiply(-1 - width / 2 + 1)).up()] = fillerMat
- blueprint[basePos.add(xDirection.directionVec.multiply(width - width / 2 - 1)).up()] = fillerMat
+ blueprint[basePos.add(xDirection.directionVec.multiply(-1 - width / 2 + 1)).up()] = BlueprintTask(fillerMat, isFiller = true)
+ blueprint[basePos.add(xDirection.directionVec.multiply(width - width / 2 - 1)).up()] = BlueprintTask(fillerMat, isFiller = true)
}
private fun generateBackfill(basePos: BlockPos, xDirection: Direction) {
@@ -152,8 +156,8 @@ object Blueprint {
val x = w - width / 2
val pos = basePos.add(xDirection.directionVec.multiply(x)).up(h + 1)
- if (Pathfinder.startingBlockPos.distanceTo(pos) < Pathfinder.startingBlockPos.distanceTo(Pathfinder.currentBlockPos)) {
- blueprint[pos] = fillerMat
+ if (startingBlockPos.toVec3dCenter().distanceTo(pos.toVec3dCenter()) + 1 < startingBlockPos.toVec3dCenter().distanceTo(currentBlockPos.toVec3dCenter())) {
+ blueprint[pos] = BlueprintTask(fillerMat, isFiller = true)
}
}
}
@@ -169,7 +173,7 @@ object Blueprint {
val z = w2 - width / 2
val pos = basePos.add(x, 0, z)
- blueprint[pos] = material
+ blueprint[pos] = BlueprintTask(material)
}
}
@@ -182,7 +186,7 @@ object Blueprint {
val z = w2 - width / 2
val pos = basePos.add(x, y, z)
- blueprint[pos] = Blocks.AIR
+ blueprint[pos] = BlueprintTask(Blocks.AIR)
}
}
}
@@ -193,6 +197,6 @@ object Blueprint {
}
fun isInsideBlueprintBuild(pos: BlockPos): Boolean {
- return blueprint[pos]?.let { it == material } ?: false
+ return blueprint[pos]?.let { it.targetBlock == material } ?: false
}
}
\ No newline at end of file
diff --git a/src/main/kotlin/trombone/blueprint/BlueprintTask.kt b/src/main/kotlin/trombone/blueprint/BlueprintTask.kt
new file mode 100644
index 0000000..e74b980
--- /dev/null
+++ b/src/main/kotlin/trombone/blueprint/BlueprintTask.kt
@@ -0,0 +1,5 @@
+package trombone.blueprint
+
+import net.minecraft.block.Block
+
+data class BlueprintTask(val targetBlock: Block, val isFiller: Boolean = false, val isSupport: Boolean = false)
diff --git a/src/main/kotlin/trombone/handler/Container.kt b/src/main/kotlin/trombone/handler/Container.kt
index 21fa325..8f983d5 100644
--- a/src/main/kotlin/trombone/handler/Container.kt
+++ b/src/main/kotlin/trombone/handler/Container.kt
@@ -1,8 +1,19 @@
package trombone.handler
+import HighwayTools.grindObsidian
+import HighwayTools.keepFreeSlots
+import HighwayTools.material
import HighwayTools.maxReach
+import HighwayTools.minDistance
+import HighwayTools.preferEnderChests
import HighwayTools.saveEnder
+import HighwayTools.saveFood
+import HighwayTools.saveMaterial
+import HighwayTools.saveTools
+import HighwayTools.searchEChest
+import com.lambda.client.commons.extension.ceilToInt
import com.lambda.client.event.SafeClientEvent
+import com.lambda.client.module.modules.player.InventoryManager
import com.lambda.client.util.EntityUtils.getDroppedItems
import com.lambda.client.util.TickTimer
import com.lambda.client.util.TimeUnit
@@ -12,7 +23,6 @@ import com.lambda.client.util.math.VectorUtils.toVec3dCenter
import com.lambda.client.util.world.getVisibleSides
import com.lambda.client.util.world.isPlaceable
import com.lambda.client.util.world.isReplaceable
-import com.lambda.commons.extension.ceilToInt
import net.minecraft.init.Blocks
import net.minecraft.init.Items
import net.minecraft.inventory.ItemStackHelper
@@ -22,43 +32,52 @@ import net.minecraft.item.ItemShulkerBox
import net.minecraft.item.ItemStack
import net.minecraft.util.EnumFacing
import net.minecraft.util.NonNullList
+import net.minecraft.util.math.AxisAlignedBB
import net.minecraft.util.math.BlockPos
-import trombone.Blueprint.isInsideBlueprintBuild
+import net.minecraft.util.text.TextFormatting
+import trombone.blueprint.BlueprintGenerator.isInsideBlueprintBuild
import trombone.IO.disableError
import trombone.Pathfinder.currentBlockPos
+import trombone.handler.Inventory.zipInventory
import trombone.task.BlockTask
import trombone.task.TaskState
import kotlin.math.abs
object Container {
- var containerTask = BlockTask(BlockPos.ORIGIN, TaskState.DONE, Blocks.AIR, Items.AIR)
+ var containerTask = BlockTask(BlockPos.ORIGIN, TaskState.DONE, Blocks.AIR)
val shulkerOpenTimer = TickTimer(TimeUnit.TICKS)
var grindCycles = 0
fun SafeClientEvent.handleRestock(item: Item) {
- getShulkerWith(player.inventorySlots, item)?.let { slot ->
- getRemotePos()?.let { pos ->
- containerTask = BlockTask(pos, TaskState.PLACE, slot.stack.item.block, item)
- containerTask.isShulker = true
+ if (preferEnderChests && item.block == Blocks.OBSIDIAN) {
+ handleEnderChest(item)
+ } else {
+ // Case 1: item is in a shulker in the inventory
+ getShulkerWith(player.inventorySlots, item)?.let { slot ->
+ getRemotePos()?.let { pos ->
+ containerTask = BlockTask(pos, TaskState.PLACE, slot.stack.item.block, item = item)
+ } ?: run {
+ disableError("Can't find possible container position (Case: 1)")
+ }
} ?: run {
- disableError("Can't find possible container position (Case: 1)")
+ handleEnderChest(item)
}
- } ?: run {
- if (item.block == Blocks.OBSIDIAN) {
- if (player.inventorySlots.countBlock(Blocks.ENDER_CHEST) <= saveEnder) {
- getShulkerWith(player.inventorySlots, Blocks.ENDER_CHEST.item)?.let { slot ->
- getRemotePos()?.let { pos ->
- containerTask = BlockTask(pos, TaskState.PLACE, slot.stack.item.block, Blocks.ENDER_CHEST.item)
- containerTask.isShulker = true
- } ?: run {
- disableError("Can't find possible container position (Case: 2)")
- }
- } ?: run {
- dispatchEnderChest(Blocks.ENDER_CHEST.item)
- }
- } else {
+ }
+ }
+
+ private fun SafeClientEvent.handleEnderChest(item: Item) {
+ if (grindObsidian && item.block == Blocks.OBSIDIAN) {
+ // Case 2: desired item is Obsidian and grinding E-Chests is allowed
+
+ if (player.inventorySlots.countBlock(Blocks.ENDER_CHEST) <= saveEnder) {
+ handleRestock(Blocks.ENDER_CHEST.item)
+ return
+ }
+
+ if (player.inventorySlots.countBlock(Blocks.ENDER_CHEST) > saveEnder) {
+ if (grindCycles > 0) {
getRemotePos()?.let { pos ->
- containerTask = BlockTask(pos, TaskState.PLACE, Blocks.ENDER_CHEST, Blocks.OBSIDIAN.item)
+ containerTask = BlockTask(pos, TaskState.PLACE, Blocks.ENDER_CHEST, item = Blocks.OBSIDIAN.item)
containerTask.destroy = true
if (grindCycles > 1) containerTask.collect = false
containerTask.itemID = Blocks.OBSIDIAN.id
@@ -66,17 +85,38 @@ object Container {
} ?: run {
disableError("Can't find possible container position (Case: 3)")
}
+ } else {
+ val freeSlots = player.inventorySlots.count {
+ it.stack.isEmpty
+ || InventoryManager.ejectList.contains(it.stack.item.registryName.toString())
+ }
+
+ val cycles = (freeSlots - 1 - keepFreeSlots) * 8
+
+ if (cycles > 0) {
+ grindCycles = cycles
+ } else {
+ zipInventory()
+ }
}
- } else {
- dispatchEnderChest(item)
}
+ } else {
+ // Case 3: last hope is the ender chest
+
+ if (!searchEChest) {
+ disableError("${insufficientMaterial(item)}\nTo provide sufficient material, grant access to your ender chest. Activate in settings: ${TextFormatting.GRAY}Storage Management > Search Ender Chest")
+ return
+ }
+
+ dispatchEnderChest(item)
}
+
}
private fun SafeClientEvent.dispatchEnderChest(item: Item) {
- if (player.inventorySlots.countBlock(Blocks.ENDER_CHEST) > 0) {
+ if (player.inventorySlots.countBlock(Blocks.ENDER_CHEST) > saveEnder) {
getRemotePos()?.let { pos ->
- containerTask = BlockTask(pos, TaskState.PLACE, Blocks.ENDER_CHEST, item)
+ containerTask = BlockTask(pos, TaskState.PLACE, Blocks.ENDER_CHEST, item = item)
containerTask.itemID = Blocks.OBSIDIAN.id
} ?: run {
disableError("Can't find possible container position (Case: 4)")
@@ -84,13 +124,12 @@ object Container {
} else {
getShulkerWith(player.inventorySlots, Blocks.ENDER_CHEST.item)?.let { slot ->
getRemotePos()?.let { pos ->
- containerTask = BlockTask(pos, TaskState.PLACE, slot.stack.item.block, Blocks.ENDER_CHEST.item)
- containerTask.isShulker = true
+ containerTask = BlockTask(pos, TaskState.PLACE, slot.stack.item.block, item = Blocks.ENDER_CHEST.item)
} ?: run {
disableError("Can't find possible container position (Case: 5)")
}
} ?: run {
- disableError("No ${Blocks.ENDER_CHEST.item.registryName} was found in inventory.")
+ disableError("No ${Blocks.ENDER_CHEST.localizedName} was found in inventory.")
}
}
}
@@ -100,15 +139,17 @@ object Container {
return VectorUtils.getBlockPosInSphere(origin, maxReach).asSequence()
.filter { pos ->
- !isInsideBlueprintBuild(pos) &&
- pos != currentBlockPos &&
- world.isPlaceable(pos) &&
- !world.getBlockState(pos.down()).isReplaceable &&
- world.isAirBlock(pos.up()) &&
- getVisibleSides(pos.down()).contains(EnumFacing.UP)
+ !isInsideBlueprintBuild(pos)
+ && pos != currentBlockPos
+ && world.isPlaceable(pos)
+ && !world.getBlockState(pos.down()).isReplaceable
+ && world.isAirBlock(pos.up())
+ && getVisibleSides(pos.down()).contains(EnumFacing.UP)
+ && player.positionVector.distanceTo(pos.toVec3dCenter()) > minDistance
+ && pos.y >= currentBlockPos.y
}.sortedWith(
compareByDescending {
- safeValue(it)
+ secureScore(it)
}.thenBy {
it.distanceSqToCenter(origin.x, origin.y, origin.z).ceilToInt()
}.thenBy {
@@ -117,7 +158,7 @@ object Container {
).firstOrNull()
}
- private fun SafeClientEvent.safeValue(pos: BlockPos): Int {
+ private fun SafeClientEvent.secureScore(pos: BlockPos): Int {
var safe = 0
if (!world.getBlockState(pos.down().north()).isReplaceable) safe++
if (!world.getBlockState(pos.down().east()).isReplaceable) safe++
@@ -157,9 +198,9 @@ object Container {
?.let { itemVec ->
return VectorUtils.getBlockPosInSphere(itemVec, range).asSequence()
.filter { pos ->
- world.isAirBlock(pos.up()) &&
- world.isAirBlock(pos) &&
- !world.isPlaceable(pos.down())
+ world.isAirBlock(pos.up())
+ && world.isAirBlock(pos)
+ && !world.isPlaceable(pos.down())
}
.sortedWith(
compareBy {
@@ -171,4 +212,17 @@ object Container {
}
return null
}
+
+ private fun SafeClientEvent.insufficientMaterial(item: Item): String {
+ val itemCount = player.inventorySlots.countItem(item)
+ var message = ""
+ if (saveMaterial > 0 && item == material.item) message += insufficientMaterialPrint(itemCount, saveMaterial, material.localizedName)
+ if (saveEnder > 0 && item.block == Blocks.ENDER_CHEST) message += insufficientMaterialPrint(itemCount, saveEnder, Blocks.ENDER_CHEST.localizedName)
+ if (saveTools > 0 && item == Items.DIAMOND_PICKAXE) message += insufficientMaterialPrint(itemCount, saveTools, "Diamond Pickaxe(s)")
+ if (saveFood > 0 && item == Items.GOLDEN_APPLE) message += insufficientMaterialPrint(itemCount, saveFood, "Golden Apple(s)")
+ return "$message\nTo continue anyways, set setting in ${TextFormatting.GRAY}Storage Management > Save ${TextFormatting.RESET} to zero."
+ }
+
+ private fun insufficientMaterialPrint(itemCount: Int, settingCount: Int, name: String) =
+ "For safety purposes you need ${TextFormatting.AQUA}${settingCount - itemCount + 1}${TextFormatting.RED} more $name in your inventory ($itemCount/${settingCount + 1})."
}
\ No newline at end of file
diff --git a/src/main/kotlin/trombone/handler/Inventory.kt b/src/main/kotlin/trombone/handler/Inventory.kt
new file mode 100644
index 0000000..3cd6838
--- /dev/null
+++ b/src/main/kotlin/trombone/handler/Inventory.kt
@@ -0,0 +1,248 @@
+package trombone.handler
+
+import HighwayTools.keepFreeSlots
+import HighwayTools.material
+import HighwayTools.saveMaterial
+import HighwayTools.saveTools
+import HighwayTools.storageManagement
+import com.lambda.client.event.SafeClientEvent
+import com.lambda.client.manager.managers.PlayerInventoryManager
+import com.lambda.client.manager.managers.PlayerInventoryManager.addInventoryTask
+import com.lambda.client.manager.managers.PlayerPacketManager.sendPlayerPacket
+import com.lambda.client.module.modules.player.InventoryManager
+import com.lambda.client.util.items.*
+import com.lambda.client.util.math.RotationUtils.getRotationTo
+import net.minecraft.block.Block
+import net.minecraft.block.Block.getBlockFromName
+import net.minecraft.enchantment.EnchantmentHelper
+import net.minecraft.init.Blocks
+import net.minecraft.init.Enchantments
+import net.minecraft.init.Items
+import net.minecraft.inventory.ClickType
+import net.minecraft.inventory.Container
+import net.minecraft.inventory.Slot
+import net.minecraft.item.ItemBlock
+import net.minecraft.util.math.Vec3d
+import trombone.IO.disableError
+import trombone.Trombone.module
+import trombone.handler.Container.containerTask
+import trombone.handler.Container.getShulkerWith
+import trombone.handler.Container.handleRestock
+import trombone.task.BlockTask
+import trombone.task.TaskState
+import java.util.concurrent.ConcurrentLinkedDeque
+
+object Inventory {
+ var lastHitVec: Vec3d = Vec3d.ZERO
+ var waitTicks = 0
+
+ val packetLimiter = ConcurrentLinkedDeque()
+
+ @Suppress("UNUSED")
+ enum class RotationMode {
+ OFF, SPOOF
+ }
+
+ fun SafeClientEvent.updateRotation() {
+ if (lastHitVec == Vec3d.ZERO) return
+ val rotation = getRotationTo(lastHitVec)
+
+ module.sendPlayerPacket {
+ rotate(rotation)
+ }
+ }
+
+ private fun SafeClientEvent.getBestTool(blockTask: BlockTask): Slot? {
+ return player.inventorySlots.asReversed().maxByOrNull {
+ val stack = it.stack
+ if (stack.isEmpty) {
+ 0.0f
+ } else {
+ var speed = stack.getDestroySpeed(world.getBlockState(blockTask.blockPos))
+
+ if (speed > 1.0f) {
+ val efficiency = EnchantmentHelper.getEnchantmentLevel(Enchantments.EFFICIENCY, stack)
+ if (efficiency > 0) {
+ speed += efficiency * efficiency + 1.0f
+ }
+ }
+
+ speed
+ }
+ }
+ }
+
+ fun SafeClientEvent.swapOrMoveBlock(blockTask: BlockTask): Boolean {
+ if (blockTask.isShulker()) {
+ getShulkerWith(player.inventorySlots, blockTask.item)?.let { slot ->
+ blockTask.itemID = slot.stack.item.id
+ slot.toHotbarSlotOrNull()?.let {
+ swapToSlot(it)
+ } ?: run {
+ val slotTo = player.hotbarSlots.firstEmpty()?.hotbarSlot ?: 0
+ moveToHotbar(module, slot.slotNumber, slotTo)
+ }
+ }
+ return true
+ } else {
+ val useMat = findMaterial(blockTask)
+ if (useMat == Blocks.AIR) return false
+
+ val success = swapToBlockOrMove(module, useMat, predicateSlot = {
+ it.item is ItemBlock
+ })
+
+ return if (!success) {
+ disableError("Inventory transaction of $useMat failed.")
+ false
+ } else {
+ true
+ }
+ }
+ }
+
+ private fun SafeClientEvent.findMaterial(blockTask: BlockTask): Block {
+ return if (blockTask.targetBlock == material) {
+ if (player.inventorySlots.countBlock(material) > saveMaterial) {
+ material
+ } else {
+ restockFallback(blockTask)
+ Blocks.AIR
+ }
+ } else {
+ if (player.inventorySlots.countBlock(blockTask.targetBlock) > 0) {
+ blockTask.targetBlock
+ } else {
+ val possibleMaterials = mutableSetOf()
+ InventoryManager.ejectList.forEach { stringName ->
+ getBlockFromName(stringName)?.let {
+ if (player.inventorySlots.countBlock(it) > 0) possibleMaterials.add(it)
+ }
+ }
+
+ if (possibleMaterials.isEmpty()) {
+ if (player.inventorySlots.countBlock(material) > saveMaterial) {
+ material
+ } else {
+ restockFallback(blockTask)
+ Blocks.AIR
+ }
+ } else {
+ possibleMaterials.first()
+ }
+ }
+ }
+ }
+
+ private fun SafeClientEvent.restockFallback(blockTask: BlockTask) {
+ if (storageManagement) {
+ handleRestock(blockTask.targetBlock.item)
+ } else {
+ disableError("No usable material was found in inventory.")
+ }
+ }
+
+ fun SafeClientEvent.swapOrMoveBestTool(blockTask: BlockTask): Boolean {
+ if (player.inventorySlots.countItem(Items.DIAMOND_PICKAXE) <= saveTools) {
+ return if (containerTask.taskState == TaskState.DONE && storageManagement) {
+ handleRestock(Items.DIAMOND_PICKAXE)
+ false
+ } else {
+ swapOrMoveTool(blockTask)
+ }
+ }
+
+ return swapOrMoveTool(blockTask)
+ }
+
+ fun SafeClientEvent.zipInventory() {
+ val compressibleStacks = player.inventorySlots.filter { comp ->
+ comp.stack.count < comp.stack.maxStackSize
+ && player.inventorySlots.countByStack { comp.stack.item == it.item } > 1
+ }
+
+ if (compressibleStacks.isEmpty()) {
+ disableError("Inventory full. (Considering that $keepFreeSlots slots are supposed to stay free)")
+ return
+ }
+
+ compressibleStacks.forEach { slot ->
+ module.addInventoryTask(
+ PlayerInventoryManager.ClickInfo(slot = slot.slotNumber, type = ClickType.QUICK_MOVE)
+ )
+ }
+ }
+
+ private fun SafeClientEvent.swapOrMoveTool(blockTask: BlockTask) =
+ getBestTool(blockTask)?.let { slotFrom ->
+ blockTask.toolToUse = slotFrom.stack
+ slotFrom.toHotbarSlotOrNull()?.let {
+ swapToSlot(it)
+ } ?: run {
+ val slotTo = player.hotbarSlots.firstEmpty()?.hotbarSlot ?: 0
+ moveToHotbar(module, slotFrom.slotNumber, slotTo)
+ }
+ true
+ } ?: run {
+ false
+ }
+
+ fun SafeClientEvent.moveToInventory(originSlot: Slot, container: Container) {
+ container.getSlots(27..62).firstOrNull {
+ originSlot.stack.item == it.stack.item
+ && it.stack.count < originSlot.stack.maxStackSize - originSlot.stack.count
+ }?.let { _ ->
+ module.addInventoryTask(
+ PlayerInventoryManager.ClickInfo(
+ container.windowId,
+ originSlot.slotNumber,
+ 0,
+ ClickType.QUICK_MOVE
+ )
+ )
+ } ?: run {
+ container.getSlots(54..62).firstOrNull {
+ InventoryManager.ejectList.contains(it.stack.item.registryName.toString())
+ || it.stack.isEmpty
+ }?.let { freeHotbarSlot ->
+ module.addInventoryTask(
+ PlayerInventoryManager.ClickInfo(
+ container.windowId,
+ originSlot.slotNumber,
+ freeHotbarSlot.slotNumber - 54,
+ ClickType.SWAP
+ )
+ )
+ } ?: run {
+ container.getSlots(27..53).firstOrNull {
+ InventoryManager.ejectList.contains(it.stack.item.registryName.toString())
+ || it.stack.isEmpty
+ }?.let { freeSlot ->
+ module.addInventoryTask(
+ PlayerInventoryManager.ClickInfo(
+ container.windowId,
+ 0,
+ freeSlot.slotNumber,
+ ClickType.SWAP
+ ),
+ PlayerInventoryManager.ClickInfo(
+ container.windowId,
+ freeSlot.slotNumber,
+ 0,
+ ClickType.SWAP
+ )
+ )
+ } ?: run {
+ zipInventory()
+ }
+ }
+ }
+ }
+
+ fun SafeClientEvent.getEjectSlot(): Slot? {
+ return player.inventorySlots.firstByStack {
+ !it.isEmpty &&
+ InventoryManager.ejectList.contains(it.item.registryName.toString())
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/trombone/handler/Liquid.kt b/src/main/kotlin/trombone/handler/Liquid.kt
index 43b7a35..8c32517 100644
--- a/src/main/kotlin/trombone/handler/Liquid.kt
+++ b/src/main/kotlin/trombone/handler/Liquid.kt
@@ -1,20 +1,22 @@
package trombone.handler
-import HighwayTools.anonymizeStats
-import HighwayTools.debugMessages
+import HighwayTools.debugLevel
import HighwayTools.fillerMat
+import HighwayTools.illegalPlacements
import HighwayTools.maxReach
+import HighwayTools.placementSearch
+import com.lambda.client.LambdaMod
import com.lambda.client.event.SafeClientEvent
import com.lambda.client.util.math.CoordinateConverter.asString
import com.lambda.client.util.math.VectorUtils.distanceTo
-import com.lambda.client.util.text.MessageSendHelper
+import com.lambda.client.util.world.getNeighbourSequence
import net.minecraft.block.BlockLiquid
import net.minecraft.util.EnumFacing
import trombone.IO
-import trombone.Trombone.module
-import trombone.handler.Tasks.safeTask
-import trombone.handler.Tasks.tasks
+import trombone.blueprint.BlueprintTask
import trombone.task.BlockTask
+import trombone.task.TaskManager.addTask
+import trombone.task.TaskManager.tasks
import trombone.task.TaskState
object Liquid {
@@ -27,13 +29,11 @@ object Liquid {
if (world.getBlockState(neighbourPos).block !is BlockLiquid) continue
- if (player.distanceTo(neighbourPos) > maxReach) {
- if (debugMessages == IO.DebugMessages.ALL) {
- if (!anonymizeStats) {
- MessageSendHelper.sendChatMessage("${module.chatName} Liquid@(${neighbourPos.asString()}) out of reach (${player.distanceTo(neighbourPos)})")
- } else {
- MessageSendHelper.sendChatMessage("${module.chatName} Liquid out of reach (${player.distanceTo(neighbourPos)})")
- }
+ if (player.distanceTo(neighbourPos) > maxReach
+ || getNeighbourSequence(neighbourPos, placementSearch, maxReach, !illegalPlacements).isEmpty()
+ ) {
+ if (debugLevel == IO.DebugLevel.VERBOSE) {
+ LambdaMod.LOG.info("[Trombone] Skipping liquid block at ${neighbourPos.asString()} due to distance")
}
blockTask.updateState(TaskState.DONE)
return true
@@ -44,7 +44,10 @@ object Liquid {
tasks[neighbourPos]?.let {
updateLiquidTask(it)
} ?: run {
- safeTask(neighbourPos, TaskState.LIQUID, fillerMat).updateLiquid(this)
+ val newTask = BlockTask(neighbourPos, TaskState.LIQUID, fillerMat)
+ val blueprintTask = BlueprintTask(fillerMat, isFiller = true, isSupport = false)
+
+ addTask(newTask, blueprintTask)
}
}
@@ -53,6 +56,6 @@ object Liquid {
fun SafeClientEvent.updateLiquidTask(blockTask: BlockTask) {
blockTask.updateState(TaskState.LIQUID)
- blockTask.updateLiquid(this)
+ blockTask.updateTask(this)
}
}
\ No newline at end of file
diff --git a/src/main/kotlin/trombone/handler/Packet.kt b/src/main/kotlin/trombone/handler/Packet.kt
index 6d7bf6d..7a9b1c8 100644
--- a/src/main/kotlin/trombone/handler/Packet.kt
+++ b/src/main/kotlin/trombone/handler/Packet.kt
@@ -1,19 +1,20 @@
package trombone.handler
+import com.lambda.client.LambdaMod
import com.lambda.client.event.SafeClientEvent
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.sync.withLock
+import com.lambda.client.util.items.hotbarSlots
import net.minecraft.init.Blocks
import net.minecraft.network.Packet
import net.minecraft.network.play.server.SPacketBlockChange
import net.minecraft.network.play.server.SPacketOpenWindow
import net.minecraft.network.play.server.SPacketPlayerPosLook
+import net.minecraft.network.play.server.SPacketSetSlot
import net.minecraft.network.play.server.SPacketWindowItems
-import trombone.Blueprint.isInsideBlueprint
+import trombone.blueprint.BlueprintGenerator.isInsideBlueprint
import trombone.Pathfinder.rubberbandTimer
+import trombone.Statistics.durabilityUsages
import trombone.handler.Container.containerTask
-import trombone.handler.Tasks.stateUpdateMutex
-import trombone.handler.Tasks.tasks
+import trombone.task.TaskManager.tasks
import trombone.task.TaskState
object Packet {
@@ -24,7 +25,7 @@ object Packet {
if (!isInsideBlueprint(pos)) return
val prev = world.getBlockState(pos).block
- val new = packet.getBlockState().block
+ val new = packet.blockState.block
if (prev != new) {
val task = if (pos == containerTask.blockPos) {
@@ -36,20 +37,14 @@ object Packet {
when (task.taskState) {
TaskState.PENDING_BREAK, TaskState.BREAKING -> {
if (new == Blocks.AIR) {
- runBlocking {
- stateUpdateMutex.withLock {
- task.updateState(TaskState.BROKEN)
- }
- }
+ task.updateState(TaskState.BROKEN)
}
}
TaskState.PENDING_PLACE -> {
- if (task.block != Blocks.AIR && task.block == new) {
- runBlocking {
- stateUpdateMutex.withLock {
- task.updateState(TaskState.PLACED)
- }
- }
+ if (new != Blocks.AIR
+ && (task.targetBlock == new || task.isFiller)
+ ) {
+ task.updateState(TaskState.PLACED)
}
}
else -> {
@@ -63,17 +58,24 @@ object Packet {
}
is SPacketOpenWindow -> {
if (containerTask.taskState != TaskState.DONE &&
- packet.guiId == "minecraft:shulker_box" && containerTask.isShulker ||
- packet.guiId == "minecraft:container" && !containerTask.isShulker) {
+ packet.guiId == "minecraft:shulker_box" && containerTask.isShulker() ||
+ packet.guiId == "minecraft:container" && !containerTask.isShulker()) {
containerTask.isOpen = true
}
}
is SPacketWindowItems -> {
if (containerTask.isOpen) containerTask.isLoaded = true
}
- else -> {
- // Nothing
+ is SPacketSetSlot -> {
+ val currentStack = player.hotbarSlots[player.inventory.currentItem].stack
+ if (packet.slot == player.inventory.currentItem + 36
+ && packet.stack.item == currentStack.item
+ && packet.stack.itemDamage > currentStack.itemDamage
+ ) {
+ durabilityUsages += packet.stack.itemDamage - currentStack.itemDamage
+ }
}
+ else -> { /* Ignored */ }
}
}
}
\ No newline at end of file
diff --git a/src/main/kotlin/trombone/handler/Player.kt b/src/main/kotlin/trombone/handler/Player.kt
deleted file mode 100644
index 3beb8c2..0000000
--- a/src/main/kotlin/trombone/handler/Player.kt
+++ /dev/null
@@ -1,235 +0,0 @@
-package trombone.handler
-
-import HighwayTools.anonymizeStats
-import HighwayTools.debugMessages
-import HighwayTools.fillerMat
-import HighwayTools.grindObsidian
-import HighwayTools.interacting
-import HighwayTools.leaveEmptyShulkers
-import HighwayTools.material
-import HighwayTools.saveMaterial
-import HighwayTools.saveTools
-import HighwayTools.storageManagement
-import com.lambda.client.event.SafeClientEvent
-import com.lambda.client.manager.managers.PlayerPacketManager.sendPlayerPacket
-import com.lambda.client.module.modules.player.InventoryManager
-import com.lambda.client.util.items.*
-import com.lambda.client.util.math.CoordinateConverter.asString
-import com.lambda.client.util.math.RotationUtils.getRotationTo
-import com.lambda.client.util.text.MessageSendHelper
-import kotlinx.coroutines.sync.Mutex
-import net.minecraft.enchantment.EnchantmentHelper
-import net.minecraft.init.Blocks
-import net.minecraft.init.Enchantments
-import net.minecraft.init.Items
-import net.minecraft.inventory.ClickType
-import net.minecraft.inventory.Slot
-import net.minecraft.item.ItemBlock
-import net.minecraft.util.math.Vec3d
-import trombone.Blueprint.isInsideBlueprintBuild
-import trombone.IO.DebugMessages
-import trombone.IO.disableError
-import trombone.Pathfinder.MovementState
-import trombone.Pathfinder.moveState
-import trombone.Trombone.module
-import trombone.handler.Container.containerTask
-import trombone.handler.Container.getShulkerWith
-import trombone.handler.Container.grindCycles
-import trombone.handler.Container.handleRestock
-import trombone.task.BlockTask
-import trombone.task.TaskState
-
-object Player {
- var lastHitVec: Vec3d = Vec3d.ZERO
- var waitTicks = 0
-
- val packetLimiterMutex = Mutex()
- val packetLimiter = ArrayDeque()
-
- enum class LimitMode {
- FIXED, SERVER
- }
-
- @Suppress("UNUSED")
- enum class RotationMode {
- OFF, SPOOF, VIEW_LOCK
- }
-
- fun SafeClientEvent.updateRotation() {
- if (lastHitVec == Vec3d.ZERO) return
- val rotation = getRotationTo(lastHitVec)
-
- when (interacting) {
- RotationMode.SPOOF -> {
- module.sendPlayerPacket {
- rotate(rotation)
- }
- }
- RotationMode.VIEW_LOCK -> {
- player.rotationYaw = rotation.x
- player.rotationPitch = rotation.y
- }
- else -> {
- // RotationMode.OFF
- }
- }
- }
-
- private fun SafeClientEvent.getBestTool(blockTask: BlockTask): Slot? {
- return player.inventorySlots.asReversed().maxByOrNull {
- val stack = it.stack
- if (stack.isEmpty) {
- 0.0f
- } else {
- var speed = stack.getDestroySpeed(world.getBlockState(blockTask.blockPos))
-
- if (speed > 1.0f) {
- val efficiency = EnchantmentHelper.getEnchantmentLevel(Enchantments.EFFICIENCY, stack)
- if (efficiency > 0) {
- speed += efficiency * efficiency + 1.0f
- }
- }
-
- speed
- }
- }
- }
-
- fun SafeClientEvent.swapOrMoveBlock(blockTask: BlockTask): Boolean {
- if (blockTask.isShulker) {
- getShulkerWith(player.inventorySlots, blockTask.item)?.let { slot ->
- blockTask.itemID = slot.stack.item.id
- slot.toHotbarSlotOrNull()?.let {
- swapToSlot(it)
- } ?: run {
- val slotTo = player.hotbarSlots.firstEmpty()?.hotbarSlot ?: 0
- moveToHotbar(slot.slotNumber, slotTo)
- }
- }
- return true
- } else {
- if (storageManagement && grindObsidian &&
- containerTask.taskState == TaskState.DONE &&
- material == Blocks.OBSIDIAN &&
- (player.inventorySlots.countBlock(Blocks.OBSIDIAN) <= saveMaterial &&
- grindCycles == 0)) {
- val cycles = (player.inventorySlots.count { it.stack.isEmpty || InventoryManager.ejectList.contains(it.stack.item.registryName.toString()) } - 1) * 8
- if (cycles > 0) {
- moveState = MovementState.RESTOCK
- grindCycles = cycles
- } else {
- disableError("No free inventory space.")
- }
- return false
- }
-
- val useBlock = when {
- blockTask.isFiller -> {
- if (isInsideBlueprintBuild(blockTask.blockPos)) {
- if (player.inventorySlots.countBlock(material) > 0) {
- material
- } else {
- disableError("No ${blockTask.block.localizedName} was found in inventory. (1)")
- return false
- }
- } else {
- if (player.inventorySlots.countBlock(fillerMat) > 0) {
- fillerMat
- } else {
- disableError("No ${blockTask.block.localizedName} was found in inventory. (2)")
- return false
- }
- }
- }
- player.inventorySlots.countBlock(blockTask.block) > 0 -> blockTask.block
- else -> {
- if (blockTask.block == material) {
- handleRestock(Blocks.OBSIDIAN.item)
- } else {
- disableError("No ${blockTask.block.localizedName} was found in inventory. (3)")
- }
- return false
- }
- }
-
- val success = swapToBlockOrMove(useBlock, predicateSlot = {
- it.item is ItemBlock
- })
-
- return if (!success) {
- disableError("No ${blockTask.block.localizedName} was found in inventory. (4)")
- false
- } else {
- true
- }
- }
- }
-
- fun SafeClientEvent.swapOrMoveBestTool(blockTask: BlockTask): Boolean {
- if (player.inventorySlots.countItem(Items.DIAMOND_PICKAXE) <= saveTools) {
- return if (containerTask.taskState == TaskState.DONE && storageManagement) {
- handleRestock(Items.DIAMOND_PICKAXE)
- false
- } else {
- swapOrMoveTool(blockTask)
- }
- }
-
- return swapOrMoveTool(blockTask)
- }
-
- private fun SafeClientEvent.swapOrMoveTool(blockTask: BlockTask) =
- getBestTool(blockTask)?.let { slotFrom ->
- slotFrom.toHotbarSlotOrNull()?.let {
- swapToSlot(it)
- } ?: run {
- val slotTo = player.hotbarSlots.firstEmpty()?.hotbarSlot ?: 0
- moveToHotbar(slotFrom.slotNumber, slotTo)
- }
- true
- } ?: run {
- false
- }
-
- fun SafeClientEvent.moveToInventory(slot: Slot) {
- player.openContainer.getSlots(27..62).firstOrNull {
- (slot.stack.item == it.stack.item && it.stack.count < slot.slotStackLimit - slot.stack.count) ||
- it.stack.item == Items.AIR
- }?.let {
- clickSlot(player.openContainer.windowId, slot, 0, ClickType.QUICK_MOVE)
- } ?: run {
- player.hotbarSlots.firstOrNull {
- InventoryManager.ejectList.contains(it.stack.item.registryName.toString())
- }?.let {
- clickSlot(player.openContainer.windowId, slot, it.hotbarSlot, ClickType.SWAP)
- } ?: run {
- // ToDo: SWAP Item from hotbar to ejectable item in inventory and then swap target slot with hotbar
- disableError("Inventory full.")
- }
- }
-
- if (leaveEmptyShulkers &&
- player.openContainer.getSlots(0..26).all { it.stack.isEmpty || InventoryManager.ejectList.contains(it.stack.item.registryName.toString()) }) {
- if (debugMessages != DebugMessages.OFF) {
- if (!anonymizeStats) {
- MessageSendHelper.sendChatMessage("${module.chatName} Left empty ${containerTask.block.localizedName}@(${containerTask.blockPos.asString()})")
- } else {
- MessageSendHelper.sendChatMessage("${module.chatName} Left empty ${containerTask.block.localizedName}")
- }
- }
- containerTask.updateState(TaskState.DONE)
- } else {
- containerTask.updateState(TaskState.BREAK)
- }
-
- containerTask.isOpen = false
- player.closeScreen()
- }
-
- fun SafeClientEvent.getEjectSlot(): Slot? {
- return player.inventorySlots.firstByStack {
- !it.isEmpty &&
- InventoryManager.ejectList.contains(it.item.registryName.toString())
- }
- }
-}
\ No newline at end of file
diff --git a/src/main/kotlin/trombone/handler/Tasks.kt b/src/main/kotlin/trombone/handler/Tasks.kt
deleted file mode 100644
index ba74389..0000000
--- a/src/main/kotlin/trombone/handler/Tasks.kt
+++ /dev/null
@@ -1,671 +0,0 @@
-package trombone.handler
-
-import HighwayTools.anonymizeStats
-import HighwayTools.breakDelay
-import HighwayTools.debugMessages
-import HighwayTools.dynamicDelay
-import HighwayTools.fakeSounds
-import HighwayTools.fillerMat
-import HighwayTools.ignoreBlocks
-import HighwayTools.material
-import HighwayTools.maxReach
-import HighwayTools.mode
-import HighwayTools.multiBuilding
-import HighwayTools.saveTools
-import com.lambda.client.event.SafeClientEvent
-import com.lambda.client.module.modules.player.InventoryManager
-import com.lambda.client.util.items.*
-import com.lambda.client.util.math.CoordinateConverter.asString
-import com.lambda.client.util.math.VectorUtils.distanceTo
-import com.lambda.client.util.math.VectorUtils.multiply
-import com.lambda.client.util.math.VectorUtils.toVec3dCenter
-import com.lambda.client.util.text.MessageSendHelper
-import com.lambda.client.util.world.*
-import com.lambda.commons.extension.ceilToInt
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.sync.Mutex
-import kotlinx.coroutines.sync.withLock
-import net.minecraft.block.Block
-import net.minecraft.block.BlockLiquid
-import net.minecraft.client.gui.inventory.GuiContainer
-import net.minecraft.init.Blocks
-import net.minecraft.init.Items
-import net.minecraft.network.play.client.CPacketPlayerTryUseItemOnBlock
-import net.minecraft.util.EnumFacing
-import net.minecraft.util.EnumHand
-import net.minecraft.util.SoundCategory
-import net.minecraft.util.math.AxisAlignedBB
-import net.minecraft.util.math.BlockPos
-import trombone.Blueprint.blueprint
-import trombone.Blueprint.generateBluePrint
-import trombone.Blueprint.isInsideBlueprintBuild
-import trombone.IO.DebugMessages
-import trombone.IO.disableError
-import trombone.Pathfinder.MovementState
-import trombone.Pathfinder.currentBlockPos
-import trombone.Pathfinder.moveState
-import trombone.Pathfinder.shouldBridge
-import trombone.Pathfinder.startingBlockPos
-import trombone.Pathfinder.startingDirection
-import trombone.Statistics.simpleMovingAverageBreaks
-import trombone.Statistics.simpleMovingAveragePlaces
-import trombone.Statistics.totalBlocksBroken
-import trombone.Statistics.totalBlocksPlaced
-import trombone.Trombone.Mode
-import trombone.Trombone.module
-import trombone.handler.Container.containerTask
-import trombone.handler.Container.getCollectingPosition
-import trombone.handler.Container.getShulkerWith
-import trombone.handler.Container.grindCycles
-import trombone.handler.Container.handleRestock
-import trombone.handler.Container.shulkerOpenTimer
-import trombone.handler.Liquid.handleLiquid
-import trombone.handler.Liquid.updateLiquidTask
-import trombone.handler.Player.getEjectSlot
-import trombone.handler.Player.lastHitVec
-import trombone.handler.Player.moveToInventory
-import trombone.handler.Player.swapOrMoveBestTool
-import trombone.handler.Player.swapOrMoveBlock
-import trombone.handler.Player.waitTicks
-import trombone.interaction.Break.mineBlock
-import trombone.interaction.Break.prePrimedPos
-import trombone.interaction.Break.primedPos
-import trombone.interaction.Place.extraPlaceDelay
-import trombone.interaction.Place.placeBlock
-import trombone.task.BlockTask
-import trombone.task.TaskState
-import java.util.*
-
-object Tasks {
- val tasks = LinkedHashMap()
- var sortedTasks: List = emptyList()
- var lastTask: BlockTask? = null
-
- val stateUpdateMutex = Mutex()
-
- fun clearTasks() {
- tasks.clear()
- sortedTasks = emptyList()
- containerTask.updateState(TaskState.DONE)
- lastTask = null
- grindCycles = 0
- }
-
- fun SafeClientEvent.updateTasks() {
- val toRemove = LinkedList()
- tasks.filter {
- it.value.taskState == TaskState.DONE
- }.forEach {
- if (currentBlockPos.distanceTo(it.key) > maxReach + 2) {
- if (it.value.toRemove) {
- if (System.currentTimeMillis() - it.value.timestamp > 1000L) {
- toRemove.add(it.key)
- }
- } else {
- it.value.toRemove = true
- it.value.timestamp = System.currentTimeMillis()
- }
- }
- }
- toRemove.forEach {
- tasks.remove(it)
- }
-
- generateBluePrint()
-
- blueprint.forEach { (pos, block) ->
- addTask(pos, block)
- }
- }
-
- private fun SafeClientEvent.addTask(blockPos: BlockPos, targetBlock: Block) {
- val currentState = world.getBlockState(blockPos)
- when {
- /* Out of range, or is container pos and start padding */
- // ToDo: Fix padding for diagonal
- currentBlockPos.distanceTo(blockPos) > maxReach ||
- (blockPos == containerTask.blockPos && containerTask.taskState != TaskState.DONE) ||
- startingBlockPos.add(
- startingDirection
- .clockwise(4)
- .directionVec
- .multiply((maxReach * 2).ceilToInt() - 1)
- ).distanceTo(blockPos) < maxReach * 2 -> {
- //
- }
- /* Ignored blocks */
- ignoreBlocks.contains(currentState.block.registryName.toString()) -> {
- safeTask(blockPos, TaskState.DONE, currentState.block)
- }
- /* Is in desired state */
- currentState.block == targetBlock -> {
- safeTask(blockPos, TaskState.DONE, currentState.block)
- }
- /* To place */
- currentState.isReplaceable && targetBlock != Blocks.AIR -> {
- if (checkSupport(blockPos, targetBlock) ||
- !world.checkNoEntityCollision(AxisAlignedBB(blockPos), null)) {
- safeTask(blockPos, TaskState.DONE, targetBlock)
- } else {
- safeTask(blockPos, TaskState.PLACE, targetBlock)
- }
- }
- /* Is liquid */
- currentState.block is BlockLiquid -> {
- safeTask(blockPos, TaskState.LIQUID, Blocks.AIR).updateLiquid(this)
- }
- /* Break to place */
- else -> {
- if (checkSupport(blockPos, targetBlock)) {
- safeTask(blockPos, TaskState.DONE, currentState.block)
- } else {
- safeTask(blockPos, TaskState.BREAK, targetBlock)
- }
- }
- }
- }
-
- fun SafeClientEvent.runTasks() {
- when {
- containerTask.taskState != TaskState.DONE -> {
- val eyePos = player.getPositionEyes(1.0f)
- containerTask.updateTask(this, eyePos)
- if (containerTask.stuckTicks > containerTask.taskState.stuckTimeout) {
- if (containerTask.taskState == TaskState.PICKUP) {
- MessageSendHelper.sendChatMessage("${module.chatName} Can't pickup ${containerTask.item.registryName}@(${containerTask.blockPos.asString()})")
- moveState = MovementState.RUNNING
- } else {
- MessageSendHelper.sendChatMessage("${module.chatName} Failed container action: ${containerTask.item.registryName}@(${containerTask.blockPos.asString()})")
- }
- containerTask.updateState(TaskState.DONE)
- return
- }
- tasks.values.forEach {
- doTask(it, true)
- }
- doTask(containerTask, false)
- }
- grindCycles > 0 -> {
- if (player.inventorySlots.countItem(Items.DIAMOND_PICKAXE) > saveTools) {
- handleRestock(material.item)
- } else {
- handleRestock(Items.DIAMOND_PICKAXE)
- }
- }
- tasks.values.all { it.taskState == TaskState.DONE } -> {
- updateTasks()
- }
- else -> {
- waitTicks--
-
- tasks.values.toList().forEach {
- doTask(it, true)
- }
-
- sortTasks()
-
- for (task in sortedTasks) {
- if (!checkStuckTimeout(task)) return
- if (task.taskState != TaskState.DONE && waitTicks > 0) return
- if (task.taskState == TaskState.PLACE && task.sequence.isEmpty()) continue
-
- doTask(task, false)
- when (task.taskState) {
- TaskState.DONE, TaskState.BROKEN, TaskState.PLACED -> {
- continue
- }
- else -> {
- break
- }
- }
- }
- }
- }
- }
-
- private fun SafeClientEvent.checkSupport(pos: BlockPos, block: Block): Boolean {
- return mode == Mode.HIGHWAY &&
- startingDirection.isDiagonal &&
- world.getBlockState(pos.up()).block == material &&
- block == fillerMat
- }
-
- fun SafeClientEvent.safeTask(blockPos: BlockPos, taskState: TaskState, material: Block): BlockTask {
- val task = BlockTask(blockPos, taskState, material)
- tasks[blockPos]?.let {
- if (it.stuckTicks > it.taskState.stuckTimeout ||
- taskState == TaskState.LIQUID ||
- (it.taskState != taskState &&
- (it.taskState == TaskState.DONE ||
- (it.taskState == TaskState.PLACE && !world.isPlaceable(it.blockPos))))) {
-// (it.taskState != taskState &&
-// it.taskState != TaskState.BREAKING &&
-// it.taskState != TaskState.PENDING_BREAK &&
-// it.taskState != TaskState.PENDING_PLACE)) {
- tasks[blockPos] = task
- }
- } ?: run {
- tasks[blockPos] = task
- }
- return task
- }
-
- fun SafeClientEvent.isTaskDone(pos: BlockPos) =
- tasks[pos]?.let {
- it.taskState == TaskState.DONE && world.getBlockState(pos).block != Blocks.PORTAL
- } ?: false
-
- private fun SafeClientEvent.sortTasks() {
- val eyePos = player.getPositionEyes(1.0f)
- tasks.values.forEach {
- it.updateTask(this, eyePos)
- }
-
- if (multiBuilding) {
- tasks.values.forEach {
- it.shuffle()
- }
-
- runBlocking {
- stateUpdateMutex.withLock {
- sortedTasks = tasks.values.sortedWith(
- compareBy {
- it.taskState.ordinal
- }.thenBy {
- it.stuckTicks
- }.thenBy {
- it.shuffle
- }
- )
- }
- }
- } else {
- runBlocking {
- stateUpdateMutex.withLock {
- sortedTasks = tasks.values.sortedWith(
- compareBy {
- it.taskState.ordinal
- }.thenBy {
- it.stuckTicks
- }.thenBy {
- if (it.isLiquidSource) {
- 0
- } else {
- 1
- }
- }.thenBy {
- if (moveState == MovementState.BRIDGE) {
- if (it.sequence.isEmpty()) {
- 69
- } else {
- it.sequence.size
- }
- } else {
- it.startDistance
- }
- }.thenBy {
- it.eyeDistance
- }
- )
- }
- }
- }
- }
-
- private fun SafeClientEvent.checkStuckTimeout(blockTask: BlockTask): Boolean {
- val timeout = blockTask.taskState.stuckTimeout
-
- if (blockTask.stuckTicks > timeout) {
- when (blockTask.taskState) {
- TaskState.PENDING_BREAK -> {
- blockTask.updateState(TaskState.BREAK)
- }
- TaskState.PENDING_PLACE -> {
- blockTask.updateState(TaskState.PLACE)
- }
- else -> {
- if (debugMessages != DebugMessages.OFF) {
- if (!anonymizeStats) {
- MessageSendHelper.sendChatMessage("${module.chatName} Stuck while ${blockTask.taskState}@(${blockTask.blockPos.asString()}) for more than $timeout ticks (${blockTask.stuckTicks}), refreshing data.")
- } else {
- MessageSendHelper.sendChatMessage("${module.chatName} Stuck while ${blockTask.taskState} for more than $timeout ticks (${blockTask.stuckTicks}), refreshing data.")
- }
- }
-
- when (blockTask.taskState) {
- TaskState.PLACE -> {
- if (dynamicDelay && extraPlaceDelay < 10 && moveState != MovementState.BRIDGE) extraPlaceDelay += 1
- }
- TaskState.PICKUP -> {
- MessageSendHelper.sendChatMessage("${module.chatName} Can't pickup ${containerTask.item.registryName}@(${containerTask.blockPos.asString()})")
- blockTask.updateState(TaskState.DONE)
- moveState = MovementState.RUNNING
- }
- else -> {
- blockTask.updateState(TaskState.DONE)
- }
- }
-
- updateTasks()
- return false
- }
- }
- }
-
- return true
- }
-
- private fun SafeClientEvent.doTask(blockTask: BlockTask, updateOnly: Boolean) {
- if (!updateOnly) blockTask.onTick()
-
- when (blockTask.taskState) {
- TaskState.RESTOCK -> {
- doRestock()
- }
- TaskState.PICKUP -> {
- doPickup()
- }
- TaskState.OPEN_CONTAINER -> {
- doOpenContainer()
- }
- TaskState.BREAKING -> {
- doBreaking(blockTask, updateOnly)
- }
- TaskState.BROKEN -> {
- doBroken(blockTask)
- }
- TaskState.PLACED -> {
- doPlaced(blockTask)
- }
- TaskState.BREAK -> {
- doBreak(blockTask, updateOnly)
- }
- TaskState.PLACE, TaskState.LIQUID -> {
- doPlace(blockTask, updateOnly)
- }
- TaskState.PENDING_BREAK, TaskState.PENDING_PLACE -> {
- blockTask.onStuck()
- }
- else -> { }
- }
- }
-
- private fun SafeClientEvent.doRestock() {
- if (mc.currentScreen is GuiContainer && containerTask.isLoaded) {
- val container = player.openContainer
-
- container.getSlots(0..26).firstItem(containerTask.item)?.let {
- moveToInventory(it)
- } ?: run {
- getShulkerWith(container.getSlots(0..26), containerTask.item)?.let {
- moveToInventory(it)
- } ?: run {
- disableError("No ${containerTask.item.registryName} left in any container.")
- }
- }
- } else {
- containerTask.updateState(TaskState.OPEN_CONTAINER)
- }
- }
-
- private fun SafeClientEvent.doPickup() {
- if (getCollectingPosition() == null) {
- moveState = MovementState.RUNNING
- containerTask.updateState(TaskState.DONE)
- if (grindCycles > 0) {
- grindCycles = (player.inventorySlots.count { it.stack.isEmpty ||
- InventoryManager.ejectList.contains(it.stack.item.registryName.toString()) } - 1) * 8 -
- (player.inventorySlots.countBlock(Blocks.OBSIDIAN) / 8)
- }
- } else {
- if (player.inventorySlots.firstEmpty() == null) {
- getEjectSlot()?.let {
- throwAllInSlot(it)
- }
- } else {
- // ToDo: Resolve ghost slot
- }
- containerTask.onStuck()
- }
- }
-
- private fun SafeClientEvent.doOpenContainer() {
- if (containerTask.isOpen) {
- containerTask.updateState(TaskState.RESTOCK)
- } else {
- val center = containerTask.blockPos.toVec3dCenter()
- val diff = player.getPositionEyes(1f).subtract(center)
- val normalizedVec = diff.normalize()
-
- val side = EnumFacing.getFacingFromVector(normalizedVec.x.toFloat(), normalizedVec.y.toFloat(), normalizedVec.z.toFloat())
- val hitVecOffset = getHitVecOffset(side)
-
- lastHitVec = getHitVec(containerTask.blockPos, side)
-
- if (shulkerOpenTimer.tick(20)) {
- connection.sendPacket(CPacketPlayerTryUseItemOnBlock(containerTask.blockPos, side, EnumHand.MAIN_HAND, hitVecOffset.x.toFloat(), hitVecOffset.y.toFloat(), hitVecOffset.z.toFloat()))
- player.swingArm(EnumHand.MAIN_HAND)
- }
- }
- }
-
- private fun SafeClientEvent.doBreaking(blockTask: BlockTask, updateOnly: Boolean) {
- when (world.getBlockState(blockTask.blockPos).block) {
- Blocks.AIR -> {
- waitTicks = breakDelay
- blockTask.updateState(TaskState.BROKEN)
- return
- }
- is BlockLiquid -> {
- updateLiquidTask(blockTask)
- return
- }
- }
-
- if (!updateOnly && swapOrMoveBestTool(blockTask)) {
- mineBlock(blockTask)
- }
- }
-
- private fun SafeClientEvent.doBroken(blockTask: BlockTask) {
- when (world.getBlockState(blockTask.blockPos).block) {
- Blocks.AIR -> {
- totalBlocksBroken++
- if (blockTask.blockPos == prePrimedPos) {
- primedPos = prePrimedPos
- prePrimedPos = BlockPos.NULL_VECTOR
- }
- simpleMovingAverageBreaks.add(System.currentTimeMillis())
-
- when {
- blockTask.block == Blocks.AIR -> {
- if (fakeSounds) {
- val soundType = blockTask.block.getSoundType(world.getBlockState(blockTask.blockPos), world, blockTask.blockPos, player)
- world.playSound(player, blockTask.blockPos, soundType.breakSound, SoundCategory.BLOCKS, (soundType.getVolume() + 1.0f) / 2.0f, soundType.getPitch() * 0.8f)
- }
- blockTask.updateState(TaskState.DONE)
- }
- blockTask == containerTask -> {
- if (containerTask.collect) {
- moveState = MovementState.PICKUP
- blockTask.updateState(TaskState.PICKUP)
- } else {
- blockTask.updateState(TaskState.DONE)
- }
- }
- else -> {
- blockTask.updateState(TaskState.PLACE)
- }
- }
- }
- else -> {
- blockTask.updateState(TaskState.BREAK)
- }
- }
- }
-
- private fun SafeClientEvent.doPlaced(blockTask: BlockTask) {
- val currentBlock = world.getBlockState(blockTask.blockPos).block
-
- when {
- blockTask.block == currentBlock && currentBlock != Blocks.AIR -> {
- totalBlocksPlaced++
- prePrimedPos = blockTask.blockPos
- simpleMovingAveragePlaces.add(System.currentTimeMillis())
-
- if (dynamicDelay && extraPlaceDelay > 0) extraPlaceDelay -= 1
-
- if (blockTask == containerTask) {
- if (blockTask.destroy) {
- blockTask.updateState(TaskState.BREAK)
- } else {
- blockTask.updateState(TaskState.RESTOCK)
- }
- } else {
- blockTask.updateState(TaskState.DONE)
- }
- if (fakeSounds) {
- val soundType = currentBlock.getSoundType(world.getBlockState(blockTask.blockPos), world, blockTask.blockPos, player)
- world.playSound(player, blockTask.blockPos, soundType.placeSound, SoundCategory.BLOCKS, (soundType.getVolume() + 1.0f) / 2.0f, soundType.getPitch() * 0.8f)
- }
- }
- blockTask.block == currentBlock && currentBlock == Blocks.AIR -> {
- blockTask.updateState(TaskState.BREAK)
- }
- blockTask.block == Blocks.AIR && currentBlock != Blocks.AIR -> {
- blockTask.updateState(TaskState.BREAK)
- }
- else -> {
- blockTask.updateState(TaskState.PLACE)
- }
- }
- }
-
- private fun SafeClientEvent.doBreak(blockTask: BlockTask, updateOnly: Boolean) {
- val currentBlock = world.getBlockState(blockTask.blockPos).block
-
- if (ignoreBlocks.contains(currentBlock.registryName.toString()) &&
- !blockTask.isShulker &&
- !isInsideBlueprintBuild(blockTask.blockPos) ||
- currentBlock == Blocks.PORTAL ||
- currentBlock == Blocks.END_PORTAL ||
- currentBlock == Blocks.END_PORTAL_FRAME ||
- currentBlock == Blocks.BEDROCK) {
- blockTask.updateState(TaskState.DONE)
- }
-
- when (blockTask.block) {
- fillerMat -> {
- if (world.getBlockState(blockTask.blockPos.up()).block == material ||
- (!world.isPlaceable(blockTask.blockPos) &&
- world.getCollisionBox(blockTask.blockPos) != null)) {
- blockTask.updateState(TaskState.DONE)
- return
- }
- }
- material -> {
- if (currentBlock == material) {
- blockTask.updateState(TaskState.DONE)
- return
- }
- }
- }
-
- when (currentBlock) {
- Blocks.AIR -> {
- if (blockTask.block == Blocks.AIR) {
- blockTask.updateState(TaskState.BROKEN)
- return
- } else {
- blockTask.updateState(TaskState.PLACE)
- return
- }
- }
- is BlockLiquid -> {
- updateLiquidTask(blockTask)
- return
- }
- }
-
- if (!updateOnly && player.onGround && swapOrMoveBestTool(blockTask)) {
- if (handleLiquid(blockTask)) return
- mineBlock(blockTask)
- }
- }
-
- private fun SafeClientEvent.doPlace(blockTask: BlockTask, updateOnly: Boolean) {
- val currentBlock = world.getBlockState(blockTask.blockPos).block
-
- if (shouldBridge() &&
- moveState != MovementState.RESTOCK &&
- player.positionVector.distanceTo(currentBlockPos) < 1) {
- moveState = MovementState.BRIDGE
- }
-
- if (blockTask.taskState == TaskState.LIQUID &&
- world.getBlockState(blockTask.blockPos).block !is BlockLiquid) {
- blockTask.updateState(TaskState.DONE)
- return
- }
-
- when (blockTask.block) {
- material -> {
- if (currentBlock == material) {
- blockTask.updateState(TaskState.PLACED)
- return
- }
- }
- fillerMat -> {
- if (currentBlock == fillerMat) {
- blockTask.updateState(TaskState.PLACED)
- return
- } else if (currentBlock != fillerMat &&
- mode == Mode.HIGHWAY &&
- world.getBlockState(blockTask.blockPos.up()).block == material) {
- blockTask.updateState(TaskState.DONE)
- return
- }
- }
- Blocks.AIR -> {
- if (world.getBlockState(blockTask.blockPos).block !is BlockLiquid) {
- if (currentBlock != Blocks.AIR) {
- blockTask.updateState(TaskState.BREAK)
- } else {
- blockTask.updateState(TaskState.BROKEN)
- }
- return
- }
- }
- }
-
- if (!updateOnly) {
- if (!world.isPlaceable(blockTask.blockPos)) {
- if (debugMessages == DebugMessages.ALL) {
- if (!anonymizeStats) {
- MessageSendHelper.sendChatMessage("${module.chatName} Invalid place position @(${blockTask.blockPos.asString()}) Removing task")
- } else {
- MessageSendHelper.sendChatMessage("${module.chatName} Invalid place position. Removing task")
- }
- }
-
- if (blockTask == containerTask) {
- if (containerTask.block == currentBlock) {
- containerTask.updateState(TaskState.BREAK)
- } else {
- containerTask.updateState(TaskState.DONE)
- }
- } else {
- tasks.remove(blockTask.blockPos)
- }
- return
- }
-
- if (!swapOrMoveBlock(blockTask)) {
- blockTask.onStuck()
- return
- }
-
- placeBlock(blockTask)
- }
- }
-}
\ No newline at end of file
diff --git a/src/main/kotlin/trombone/interaction/Break.kt b/src/main/kotlin/trombone/interaction/Break.kt
index 482bb4d..ba370a7 100644
--- a/src/main/kotlin/trombone/interaction/Break.kt
+++ b/src/main/kotlin/trombone/interaction/Break.kt
@@ -1,46 +1,39 @@
package trombone.interaction
-import HighwayTools.alwaysBoth
import HighwayTools.breakDelay
-import HighwayTools.debugMessages
import HighwayTools.illegalPlacements
import HighwayTools.instantMine
-import HighwayTools.limitFactor
-import HighwayTools.limitOrigin
-import HighwayTools.maxBreaks
+import HighwayTools.interactionLimit
import HighwayTools.maxReach
+import HighwayTools.miningSpeedFactor
+import HighwayTools.multiBreak
+import HighwayTools.packetFlood
import HighwayTools.taskTimeout
+import com.lambda.client.commons.extension.ceilToInt
import com.lambda.client.event.SafeClientEvent
-import com.lambda.client.util.TpsCalculator
import com.lambda.client.util.math.isInSight
-import com.lambda.client.util.text.MessageSendHelper
import com.lambda.client.util.threads.defaultScope
import com.lambda.client.util.threads.onMainThreadSafe
-import com.lambda.client.util.threads.runSafeSuspend
+import com.lambda.client.util.threads.runSafe
import com.lambda.client.util.world.getHitVec
import com.lambda.client.util.world.getMiningSide
-import com.lambda.client.util.world.getNeighbourSequence
+import com.lambda.client.util.world.getNeighbour
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
-import kotlinx.coroutines.sync.withLock
import net.minecraft.init.Blocks
import net.minecraft.network.play.client.CPacketPlayerDigging
import net.minecraft.util.EnumFacing
import net.minecraft.util.EnumHand
import net.minecraft.util.math.AxisAlignedBB
import net.minecraft.util.math.BlockPos
-import trombone.IO.DebugMessages
-import trombone.Trombone.module
+import trombone.handler.Inventory.lastHitVec
+import trombone.handler.Inventory.packetLimiter
+import trombone.handler.Inventory.waitTicks
import trombone.handler.Liquid.handleLiquid
-import trombone.handler.Player.LimitMode
-import trombone.handler.Player.lastHitVec
-import trombone.handler.Player.packetLimiter
-import trombone.handler.Player.packetLimiterMutex
-import trombone.handler.Player.waitTicks
-import trombone.handler.Tasks.sortedTasks
-import trombone.handler.Tasks.stateUpdateMutex
import trombone.task.BlockTask
+import trombone.task.TaskManager.tasks
import trombone.task.TaskState
+import kotlin.math.ceil
object Break {
var prePrimedPos = BlockPos.NULL_VECTOR!!
@@ -50,16 +43,16 @@ object Break {
val blockState = world.getBlockState(blockTask.blockPos)
if (blockState.block == Blocks.FIRE) {
- val sides = getNeighbourSequence(blockTask.blockPos, 1, maxReach, !illegalPlacements)
- if (sides.isEmpty()) {
+ getNeighbour(blockTask.blockPos, 1, maxReach, !illegalPlacements)?.let {
+ lastHitVec = getHitVec(it.pos, it.side)
+
+ extinguishFire(blockTask, it.pos, it.side)
+ } ?: run {
blockTask.updateState(TaskState.PLACE)
- return
}
-
- lastHitVec = getHitVec(sides.last().pos, sides.last().side)
-
- mineBlockNormal(blockTask, sides.last().side)
} else {
+ val ticksNeeded = ceil((1 / blockState.getPlayerRelativeBlockHardness(player, world, blockTask.blockPos)) * miningSpeedFactor).toInt()
+
var side = getMiningSide(blockTask.blockPos) ?: run {
blockTask.onStuck()
return
@@ -68,14 +61,23 @@ object Break {
if (blockTask.blockPos == primedPos && instantMine) {
side = side.opposite
}
+
lastHitVec = getHitVec(blockTask.blockPos, side)
- if (blockState.getPlayerRelativeBlockHardness(player, world, blockTask.blockPos) > 2.8) {
+ if (blockTask.ticksMined > ticksNeeded * 1.1 &&
+ blockTask.taskState == TaskState.BREAKING) {
+ blockTask.updateState(TaskState.BREAK)
+ blockTask.ticksMined = 0
+ }
+
+ if (ticksNeeded == 1 || player.capabilities.isCreativeMode) {
mineBlockInstant(blockTask, side)
} else {
- mineBlockNormal(blockTask, side)
+ mineBlockNormal(blockTask, side, ticksNeeded)
}
}
+
+ blockTask.ticksMined += 1
}
private fun mineBlockInstant(blockTask: BlockTask, side: EnumFacing) {
@@ -83,93 +85,90 @@ object Break {
blockTask.updateState(TaskState.PENDING_BREAK)
defaultScope.launch {
- packetLimiterMutex.withLock {
- packetLimiter.add(System.currentTimeMillis())
- }
-
sendMiningPackets(blockTask.blockPos, side, start = true)
- if (maxBreaks > 1) {
- tryMultiBreak(blockTask)
- }
+ if (multiBreak) tryMultiBreak(blockTask)
delay(50L * taskTimeout)
if (blockTask.taskState == TaskState.PENDING_BREAK) {
- stateUpdateMutex.withLock {
- blockTask.updateState(TaskState.BREAK)
- }
+ blockTask.updateState(TaskState.BREAK)
}
}
}
- private suspend fun tryMultiBreak(blockTask: BlockTask) {
- runSafeSuspend {
+ private fun tryMultiBreak(blockTask: BlockTask) {
+ runSafe {
val eyePos = player.getPositionEyes(1.0f)
val viewVec = lastHitVec.subtract(eyePos).normalize()
- var breakCount = 1
- for (task in sortedTasks) {
- if (breakCount >= maxBreaks) break
-
- val size = packetLimiterMutex.withLock {
- packetLimiter.size
- }
-
- val limit = when (limitOrigin) {
- LimitMode.FIXED -> 20.0f
- LimitMode.SERVER -> TpsCalculator.tickRate
- }
-
- if (size > limit * limitFactor) {
-// if (debugMessages == DebugMessages.ALL) {
-// MessageSendHelper.sendChatMessage("${module.chatName} Dropped possible instant mine action @ TPS($limit) Actions(${size})")
-// }
- break
- }
+ tasks.values.filter {
+ it.taskState == TaskState.BREAK
+ && it != blockTask
+ }.forEach { task ->
+ val relativeHardness = world.getBlockState(task.blockPos).getPlayerRelativeBlockHardness(player, world, task.blockPos)
+ if (ceil((1 / relativeHardness) * miningSpeedFactor).ceilToInt() > 1) return@forEach
- if (task == blockTask) continue
- if (task.taskState != TaskState.BREAK) continue
- if (world.getBlockState(task.blockPos).block != Blocks.NETHERRACK) continue
+ if (packetLimiter.size > interactionLimit || handleLiquid(task)) return@runSafe
val box = AxisAlignedBB(task.blockPos)
- val rayTraceResult = box.isInSight(eyePos, viewVec) ?: continue
+ val rayTraceResult = box.isInSight(eyePos, viewVec, range = maxReach.toDouble(), tolerance = 0.0)
+ ?: return@forEach
- if (handleLiquid(task)) break
-
- breakCount++
- packetLimiterMutex.withLock {
- packetLimiter.add(System.currentTimeMillis())
- }
+ task.updateState(TaskState.PENDING_BREAK)
defaultScope.launch {
sendMiningPackets(task.blockPos, rayTraceResult.sideHit, start = true)
delay(50L * taskTimeout)
- if (blockTask.taskState == TaskState.PENDING_BREAK) {
- stateUpdateMutex.withLock {
- blockTask.updateState(TaskState.BREAK)
- }
+ if (task.taskState == TaskState.PENDING_BREAK) {
+ task.updateState(TaskState.BREAK)
}
}
}
}
}
- private fun mineBlockNormal(blockTask: BlockTask, side: EnumFacing) {
+ private fun mineBlockNormal(blockTask: BlockTask, side: EnumFacing, ticks: Int) {
defaultScope.launch {
if (blockTask.taskState == TaskState.BREAK) {
- sendMiningPackets(blockTask.blockPos, side, start = true)
blockTask.updateState(TaskState.BREAKING)
+ sendMiningPackets(blockTask.blockPos, side, start = true)
} else {
- sendMiningPackets(blockTask.blockPos, side, stop = true)
+ if (blockTask.ticksMined >= ticks) {
+ sendMiningPackets(blockTask.blockPos, side, stop = true)
+ } else {
+ sendMiningPackets(blockTask.blockPos, side)
+ }
}
}
}
- private suspend fun sendMiningPackets(pos: BlockPos, side: EnumFacing, start: Boolean = false, stop: Boolean = false) {
+ private fun extinguishFire(blockTask: BlockTask, pos: BlockPos, side: EnumFacing) {
+ waitTicks = breakDelay
+ blockTask.updateState(TaskState.PENDING_BREAK)
+
+ defaultScope.launch {
+ sendMiningPackets(pos, side, start = true, abort = true)
+
+ delay(50L * taskTimeout)
+ if (blockTask.taskState == TaskState.PENDING_BREAK) {
+ blockTask.updateState(TaskState.BREAK)
+ }
+ }
+ }
+
+ private suspend fun sendMiningPackets(pos: BlockPos, side: EnumFacing, start: Boolean = false, stop: Boolean = false, abort: Boolean = false) {
+ packetLimiter.add(System.currentTimeMillis())
onMainThreadSafe {
- if (start || alwaysBoth) connection.sendPacket(CPacketPlayerDigging(CPacketPlayerDigging.Action.START_DESTROY_BLOCK, pos, side))
- if (stop || alwaysBoth) connection.sendPacket(CPacketPlayerDigging(CPacketPlayerDigging.Action.STOP_DESTROY_BLOCK, pos, side))
+ if (start || packetFlood) {
+ connection.sendPacket(CPacketPlayerDigging(CPacketPlayerDigging.Action.START_DESTROY_BLOCK, pos, side))
+ }
+ if (abort) {
+ connection.sendPacket(CPacketPlayerDigging(CPacketPlayerDigging.Action.ABORT_DESTROY_BLOCK, pos, side))
+ }
+ if (stop || packetFlood) {
+ connection.sendPacket(CPacketPlayerDigging(CPacketPlayerDigging.Action.STOP_DESTROY_BLOCK, pos, side))
+ }
player.swingArm(EnumHand.MAIN_HAND)
}
}
diff --git a/src/main/kotlin/trombone/interaction/Place.kt b/src/main/kotlin/trombone/interaction/Place.kt
index 7296436..3a022ed 100644
--- a/src/main/kotlin/trombone/interaction/Place.kt
+++ b/src/main/kotlin/trombone/interaction/Place.kt
@@ -1,10 +1,10 @@
package trombone.interaction
-import HighwayTools.anonymizeStats
-import HighwayTools.debugMessages
+import HighwayTools.debugLevel
import HighwayTools.dynamicDelay
import HighwayTools.placeDelay
import HighwayTools.taskTimeout
+import com.lambda.client.LambdaMod
import com.lambda.client.event.SafeClientEvent
import com.lambda.client.util.items.blockBlacklist
import com.lambda.client.util.math.CoordinateConverter.asString
@@ -15,18 +15,16 @@ import com.lambda.client.util.world.getHitVec
import com.lambda.client.util.world.getHitVecOffset
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
-import kotlinx.coroutines.sync.withLock
import net.minecraft.network.play.client.CPacketEntityAction
import net.minecraft.network.play.client.CPacketPlayerTryUseItemOnBlock
import net.minecraft.util.EnumFacing
import net.minecraft.util.EnumHand
import net.minecraft.util.math.BlockPos
-import trombone.IO.DebugMessages
+import trombone.IO.DebugLevel
import trombone.Trombone.module
import trombone.handler.Container.containerTask
-import trombone.handler.Player.lastHitVec
-import trombone.handler.Player.waitTicks
-import trombone.handler.Tasks.stateUpdateMutex
+import trombone.handler.Inventory.lastHitVec
+import trombone.handler.Inventory.waitTicks
import trombone.task.BlockTask
import trombone.task.TaskState
@@ -36,32 +34,28 @@ object Place {
fun SafeClientEvent.placeBlock(blockTask: BlockTask) {
when (blockTask.sequence.size) {
0 -> {
- if (blockTask.taskState == TaskState.LIQUID) {
- blockTask.updateState(TaskState.DONE)
+ if (debugLevel == DebugLevel.VERBOSE) {
+ LambdaMod.LOG.warn("${module.chatName} No neighbours found for ${blockTask.blockPos.asString()}")
}
- if (debugMessages == DebugMessages.ALL) {
- if (!anonymizeStats) {
- MessageSendHelper.sendChatMessage("${module.chatName} No neighbours found for ${blockTask.blockPos.asString()}")
- } else {
- MessageSendHelper.sendChatMessage("${module.chatName} No neighbours found")
- }
+ if (blockTask == containerTask) {
+ MessageSendHelper.sendChatMessage("${module.chatName} Can't find neighbour blocks to place down the container.")
}
- if (blockTask == containerTask) blockTask.updateState(TaskState.DONE)
blockTask.onStuck(21)
+ blockTask.updateState(TaskState.DONE)
return
}
- 1 -> {
+ else -> {
val last = blockTask.sequence.last()
lastHitVec = getHitVec(last.pos, last.side)
placeBlockNormal(blockTask, last.pos, last.side)
}
- else -> {
+// else -> {
// ToDo: Rewrite deep place
// blockTask.sequence.forEach {
// addTaskToPending(it.pos, TaskState.PLACE, fillerMat)
// }
- }
+// }
}
}
@@ -81,7 +75,7 @@ object Place {
}
defaultScope.launch {
- delay(20L)
+ delay(20L) // ToDo: Check if necessary
onMainThreadSafe {
val placePacket = CPacketPlayerTryUseItemOnBlock(placePos, side, EnumHand.MAIN_HAND, hitVecOffset.x.toFloat(), hitVecOffset.y.toFloat(), hitVecOffset.z.toFloat())
connection.sendPacket(placePacket)
@@ -97,9 +91,7 @@ object Place {
delay(50L * taskTimeout)
if (blockTask.taskState == TaskState.PENDING_PLACE) {
- stateUpdateMutex.withLock {
- blockTask.updateState(TaskState.PLACE)
- }
+ blockTask.updateState(TaskState.PLACE)
if (dynamicDelay && extraPlaceDelay < 10) extraPlaceDelay += 1
}
}
diff --git a/src/main/kotlin/trombone/task/BlockTask.kt b/src/main/kotlin/trombone/task/BlockTask.kt
index e4c42c7..315efa4 100644
--- a/src/main/kotlin/trombone/task/BlockTask.kt
+++ b/src/main/kotlin/trombone/task/BlockTask.kt
@@ -5,23 +5,26 @@ import HighwayTools.maxReach
import HighwayTools.placementSearch
import com.lambda.client.event.SafeClientEvent
import com.lambda.client.util.math.CoordinateConverter.asString
-import com.lambda.client.util.math.VectorUtils.distanceTo
+import com.lambda.client.util.math.VectorUtils.toVec3dCenter
import com.lambda.client.util.world.PlaceInfo
import com.lambda.client.util.world.getNeighbourSequence
import net.minecraft.block.Block
import net.minecraft.block.BlockLiquid
+import net.minecraft.block.BlockShulkerBox
import net.minecraft.init.Items
import net.minecraft.item.Item
+import net.minecraft.item.ItemStack
import net.minecraft.util.math.AxisAlignedBB
import net.minecraft.util.math.BlockPos
-import net.minecraft.util.math.Vec3d
import trombone.Pathfinder.startingBlockPos
import kotlin.random.Random
class BlockTask(
val blockPos: BlockPos,
var taskState: TaskState,
- var block: Block,
+ var targetBlock: Block,
+ var isSupport: Boolean = false,
+ var isFiller: Boolean = false,
var item: Item = Items.AIR
) {
private var ranTicks = 0
@@ -31,12 +34,11 @@ class BlockTask(
var eyeDistance = 0.0; private set
var sequence: List = emptyList(); private set
- var isFiller = false
var isLiquidSource = false
- var isSupport = false
- var isShulker = false
var isOpen = false
+ var stopPull = false
+ var stacksPulled = 0
var isLoaded = false
var itemID = 0
var destroy = false
@@ -46,14 +48,16 @@ class BlockTask(
var aabb = AxisAlignedBB(1.0, 1.0, 1.0, 1.0, 1.0, 1.0)
var toRemove = false
+ var ticksMined = 1
+ var toolToUse: ItemStack = ItemStack.EMPTY
fun updateState(state: TaskState) {
- if (state == taskState) return
+ if (state != taskState) {
+ timestamp = System.currentTimeMillis()
- taskState = state
- timestamp = System.currentTimeMillis()
- if (state == TaskState.DONE || state == TaskState.PLACED || state == TaskState.BROKEN) {
- onUpdate()
+ stuckTicks = 0
+ ranTicks = 0
+ taskState = state
}
}
@@ -68,40 +72,42 @@ class BlockTask(
stuckTicks += weight
}
- fun updateTask(event: SafeClientEvent, eyePos: Vec3d) {
+ fun resetStuck() {
+ stuckTicks = 0
+ }
+
+ fun updateTask(event: SafeClientEvent) {
+ isLiquidSource = event.world.getBlockState(blockPos).let {
+ it.block is BlockLiquid && it.getValue(BlockLiquid.LEVEL) == 0
+ }
+
when (taskState) {
TaskState.PLACE, TaskState.LIQUID -> {
sequence = event.getNeighbourSequence(blockPos, placementSearch, maxReach, !illegalPlacements)
}
- else -> { }
+ else -> {}
}
- startDistance = startingBlockPos.distanceTo(blockPos)
- eyeDistance = eyePos.distanceTo(blockPos)
- }
+ startDistance = startingBlockPos.toVec3dCenter().distanceTo(blockPos.toVec3dCenter())
+ eyeDistance = event.player.getPositionEyes(1f).distanceTo(blockPos.toVec3dCenter())
- fun updateLiquid(event: SafeClientEvent) {
- isLiquidSource = event.world.getBlockState(blockPos).let {
- it.block is BlockLiquid && it.getValue(BlockLiquid.LEVEL) == 0
- }
- isFiller = true
+ aabb = event.world
+ .getBlockState(blockPos)
+ .getSelectedBoundingBox(event.world, blockPos)
}
+ fun isShulker() = targetBlock is BlockShulkerBox
+
fun shuffle() {
shuffle = Random.nextInt(0, 1000)
}
fun prettyPrint(): String {
- return " ${block.localizedName}@(${blockPos.asString()}) State: $taskState Timings: (Threshold: ${taskState.stuckThreshold} Timeout: ${taskState.stuckTimeout}) Priority: ${taskState.ordinal} Stuck: $stuckTicks"
- }
-
- private fun onUpdate() {
- stuckTicks = 0
- ranTicks = 0
+ return " ${targetBlock.localizedName}@(${blockPos.asString()}) State: $taskState Timings: (Threshold: ${taskState.stuckThreshold} Timeout: ${taskState.stuckTimeout}) Priority: ${taskState.ordinal} Stuck: $stuckTicks"
}
override fun toString(): String {
- return "Block: ${block.localizedName} @ Position: (${blockPos.asString()}) State: ${taskState.name}"
+ return "Block: ${targetBlock.localizedName} @ Position: (${blockPos.asString()}) State: ${taskState.name}"
}
override fun equals(other: Any?) = this === other
diff --git a/src/main/kotlin/trombone/task/TaskExecutor.kt b/src/main/kotlin/trombone/task/TaskExecutor.kt
new file mode 100644
index 0000000..d43715c
--- /dev/null
+++ b/src/main/kotlin/trombone/task/TaskExecutor.kt
@@ -0,0 +1,460 @@
+package trombone.task
+
+import HighwayTools.anonymizeStats
+import HighwayTools.breakDelay
+import HighwayTools.debugLevel
+import HighwayTools.dynamicDelay
+import HighwayTools.fakeSounds
+import HighwayTools.fastFill
+import HighwayTools.fillerMat
+import HighwayTools.ignoreBlocks
+import HighwayTools.interactionLimit
+import HighwayTools.keepFreeSlots
+import HighwayTools.leaveEmptyShulkers
+import HighwayTools.material
+import HighwayTools.mode
+import com.lambda.client.event.SafeClientEvent
+import com.lambda.client.module.modules.player.InventoryManager
+import com.lambda.client.util.TickTimer
+import com.lambda.client.util.items.*
+import com.lambda.client.util.math.CoordinateConverter.asString
+import com.lambda.client.util.math.VectorUtils.toVec3dCenter
+import com.lambda.client.util.text.MessageSendHelper
+import com.lambda.client.util.world.*
+import net.minecraft.block.BlockLiquid
+import net.minecraft.client.gui.inventory.GuiContainer
+import net.minecraft.init.Blocks
+import net.minecraft.item.ItemPickaxe
+import net.minecraft.network.play.client.CPacketPlayerTryUseItemOnBlock
+import net.minecraft.util.EnumFacing
+import net.minecraft.util.EnumHand
+import net.minecraft.util.SoundCategory
+import net.minecraft.util.math.AxisAlignedBB
+import net.minecraft.util.math.BlockPos
+import trombone.*
+import trombone.IO.disableError
+import trombone.Pathfinder.moveState
+import trombone.Pathfinder.shouldBridge
+import trombone.Trombone.module
+import trombone.blueprint.BlueprintGenerator
+import trombone.handler.Container
+import trombone.handler.Container.containerTask
+import trombone.handler.Container.getCollectingPosition
+import trombone.handler.Inventory
+import trombone.handler.Inventory.getEjectSlot
+import trombone.handler.Inventory.moveToInventory
+import trombone.handler.Inventory.swapOrMoveBestTool
+import trombone.handler.Inventory.swapOrMoveBlock
+import trombone.handler.Liquid.handleLiquid
+import trombone.handler.Liquid.updateLiquidTask
+import trombone.interaction.Break
+import trombone.interaction.Break.mineBlock
+import trombone.interaction.Place
+import trombone.interaction.Place.placeBlock
+
+object TaskExecutor {
+ private val restockTimer = TickTimer()
+
+ fun SafeClientEvent.doTask(blockTask: BlockTask, updateOnly: Boolean = false) {
+ if (!updateOnly) blockTask.onTick()
+
+ when (blockTask.taskState) {
+ TaskState.RESTOCK -> {
+ if (!updateOnly) doRestock()
+ }
+ TaskState.PICKUP -> {
+ if (!updateOnly) doPickup()
+ }
+ TaskState.OPEN_CONTAINER -> {
+ if (!updateOnly) doOpenContainer()
+ }
+ TaskState.BREAKING -> {
+ doBreaking(blockTask, updateOnly)
+ }
+ TaskState.BROKEN -> {
+ doBroken(blockTask)
+ }
+ TaskState.PLACED -> {
+ doPlaced(blockTask)
+ }
+ TaskState.BREAK -> {
+ doBreak(blockTask, updateOnly)
+ }
+ TaskState.PLACE, TaskState.LIQUID -> {
+ doPlace(blockTask, updateOnly)
+ }
+ TaskState.PENDING_BREAK, TaskState.PENDING_PLACE -> {
+ blockTask.onStuck()
+ }
+ TaskState.IMPOSSIBLE_PLACE -> {
+ if (!updateOnly) doImpossiblePlace()
+ }
+ TaskState.DONE -> { /* do nothing */ }
+ }
+ }
+
+ private fun SafeClientEvent.doRestock() {
+ val container = player.openContainer
+
+ if (mc.currentScreen !is GuiContainer && !containerTask.isLoaded) {
+ containerTask.updateState(TaskState.OPEN_CONTAINER)
+ return
+ }
+
+ if (container.inventorySlots.size != 63) {
+ disableError("Inventory container changed. Current: ${player.openContainer.windowId} and saved ${container.windowId}")
+ return
+ }
+
+ if (leaveEmptyShulkers
+ && !InventoryManager.ejectList.contains(containerTask.item.registryName.toString())
+ && containerTask.isShulker()
+ && container.getSlots(0..26).all {
+ it.stack.isEmpty
+ || InventoryManager.ejectList.contains(it.stack.item.registryName.toString())
+ }
+ ) {
+ if (debugLevel != IO.DebugLevel.OFF) {
+ if (!anonymizeStats) {
+ MessageSendHelper.sendChatMessage("${module.chatName} Left empty ${containerTask.targetBlock.localizedName}@(${containerTask.blockPos.asString()})")
+ } else {
+ MessageSendHelper.sendChatMessage("${module.chatName} Left empty ${containerTask.targetBlock.localizedName}")
+ }
+ }
+
+ containerTask.isOpen = false
+ player.closeScreen()
+ containerTask.updateState(TaskState.DONE)
+ moveState = Pathfinder.MovementState.RUNNING
+ return
+ }
+
+ val freeSlots = container.getSlots(27..62).count {
+ InventoryManager.ejectList.contains(it.stack.item.registryName.toString())
+ || it.stack.isEmpty
+ } - 1 - keepFreeSlots
+
+ if (containerTask.stopPull || freeSlots < 1) {
+ containerTask.updateState(TaskState.BREAK)
+ containerTask.isOpen = false
+ player.closeScreen()
+ return
+ }
+
+ container.getSlots(0..26).firstItem(containerTask.item)?.let {
+ moveToInventory(it, container)
+ containerTask.stacksPulled++
+ containerTask.stopPull = true
+ if (fastFill) {
+ if (mode == Trombone.Structure.TUNNEL && containerTask.item is ItemPickaxe) {
+ containerTask.stopPull = false
+ } else if (mode != Trombone.Structure.TUNNEL && containerTask.item == material.item) {
+ containerTask.stopPull = false
+ }
+ }
+ } ?: run {
+ if (containerTask.stacksPulled == 0) {
+ Container.getShulkerWith(container.getSlots(0..26), containerTask.item)?.let {
+ moveToInventory(it, container)
+ containerTask.stopPull = true
+ } ?: run {
+ disableError("No ${containerTask.item.registryName} left in any container.")
+ }
+ } else {
+ containerTask.updateState(TaskState.BREAK)
+ containerTask.isOpen = false
+ player.closeScreen()
+ }
+ }
+ }
+
+ private fun SafeClientEvent.doPickup() {
+ if (getCollectingPosition() == null) {
+ containerTask.updateState(TaskState.DONE)
+ moveState = Pathfinder.MovementState.RUNNING
+ return
+ }
+
+ if (player.inventorySlots.firstEmpty() == null && restockTimer.tick(20)) {
+ getEjectSlot()?.let {
+ throwAllInSlot(module, it)
+ }
+ } else {
+ containerTask.onStuck()
+ }
+ }
+
+ private fun SafeClientEvent.doOpenContainer() {
+ moveState = Pathfinder.MovementState.RESTOCK
+
+ if (containerTask.isOpen) {
+ containerTask.updateState(TaskState.RESTOCK)
+ return
+ }
+
+ if (Container.shulkerOpenTimer.tick(20)) {
+ val center = containerTask.blockPos.toVec3dCenter()
+ val diff = player.getPositionEyes(1f).subtract(center)
+ val normalizedVec = diff.normalize()
+
+ val side = EnumFacing.getFacingFromVector(normalizedVec.x.toFloat(), normalizedVec.y.toFloat(), normalizedVec.z.toFloat())
+ val hitVecOffset = getHitVecOffset(side)
+
+ Inventory.lastHitVec = getHitVec(containerTask.blockPos, side)
+
+ connection.sendPacket(CPacketPlayerTryUseItemOnBlock(containerTask.blockPos, side, EnumHand.MAIN_HAND, hitVecOffset.x.toFloat(), hitVecOffset.y.toFloat(), hitVecOffset.z.toFloat()))
+ player.swingArm(EnumHand.MAIN_HAND)
+ }
+ }
+
+ private fun SafeClientEvent.doBreaking(blockTask: BlockTask, updateOnly: Boolean) {
+ val block = world.getBlockState(blockTask.blockPos).block
+
+ if (block == Blocks.AIR) {
+ Inventory.waitTicks =
+ breakDelay
+ blockTask.updateState(TaskState.BROKEN)
+ return
+ }
+
+ if (block is BlockLiquid) {
+ updateLiquidTask(blockTask)
+ return
+ }
+
+ if (!updateOnly
+ && swapOrMoveBestTool(blockTask)
+ && Inventory.packetLimiter.size < interactionLimit
+ ) {
+ mineBlock(blockTask)
+ }
+ }
+
+ private fun SafeClientEvent.doBroken(blockTask: BlockTask) {
+ if (world.getBlockState(blockTask.blockPos).block != Blocks.AIR) {
+ blockTask.updateState(TaskState.BREAK)
+ return
+ }
+
+ Statistics.totalBlocksBroken++
+
+ TaskManager.tasks.forEach { (_, task) ->
+ if (task.taskState == TaskState.BREAK) task.resetStuck()
+ }
+
+ // Instant break exploit
+ if (blockTask.blockPos == Break.prePrimedPos) {
+ Break.primedPos = Break.prePrimedPos
+ Break.prePrimedPos = BlockPos.NULL_VECTOR
+ }
+
+ Statistics.simpleMovingAverageBreaks.add(System.currentTimeMillis())
+
+ // Sound
+ if (fakeSounds) {
+ val soundType = blockTask.targetBlock.getSoundType(world.getBlockState(blockTask.blockPos), world, blockTask.blockPos, player)
+ world.playSound(player, blockTask.blockPos, soundType.breakSound, SoundCategory.BLOCKS, (soundType.getVolume() + 1.0f) / 2.0f, soundType.getPitch() * 0.8f)
+ }
+
+ if (blockTask == containerTask) {
+ if (containerTask.collect) {
+ moveState = Pathfinder.MovementState.PICKUP
+ blockTask.updateState(TaskState.PICKUP)
+ } else {
+ blockTask.updateState(TaskState.DONE)
+ }
+ return
+ }
+
+ if (blockTask.targetBlock == Blocks.AIR) {
+ blockTask.updateState(TaskState.DONE)
+ } else {
+ blockTask.updateState(TaskState.PLACE)
+ }
+ }
+
+ private fun SafeClientEvent.doPlaced(blockTask: BlockTask) {
+ val currentState = world.getBlockState(blockTask.blockPos)
+
+ when {
+ (blockTask.targetBlock == currentState.block || blockTask.isFiller) && !currentState.isReplaceable -> {
+ Statistics.totalBlocksPlaced++
+ Break.prePrimedPos = blockTask.blockPos
+ Statistics.simpleMovingAveragePlaces.add(System.currentTimeMillis())
+
+ if (
+ dynamicDelay && Place.extraPlaceDelay > 0) Place.extraPlaceDelay /= 2
+
+ if (blockTask == containerTask) {
+ if (containerTask.destroy) {
+ containerTask.updateState(TaskState.BREAK)
+ } else {
+ containerTask.updateState(TaskState.OPEN_CONTAINER)
+ }
+ } else {
+ blockTask.updateState(TaskState.DONE)
+ }
+
+ TaskManager.tasks.values.filter { it.taskState == TaskState.PLACE }.forEach { it.resetStuck() }
+
+ if (fakeSounds) {
+ val soundType = currentState.block.getSoundType(currentState, world, blockTask.blockPos, player)
+ world.playSound(player, blockTask.blockPos, soundType.placeSound, SoundCategory.BLOCKS, (soundType.getVolume() + 1.0f) / 2.0f, soundType.getPitch() * 0.8f)
+ }
+ }
+ blockTask.targetBlock == currentState.block && currentState.block == Blocks.AIR -> {
+ blockTask.updateState(TaskState.BREAK)
+ }
+ blockTask.targetBlock == Blocks.AIR && currentState.block != Blocks.AIR -> {
+ blockTask.updateState(TaskState.BREAK)
+ }
+ else -> {
+ blockTask.updateState(TaskState.PLACE)
+ }
+ }
+ }
+
+ private fun SafeClientEvent.doBreak(blockTask: BlockTask, updateOnly: Boolean) {
+ val currentBlock = world.getBlockState(blockTask.blockPos).block
+
+ if (ignoreBlocks.contains(currentBlock.registryName.toString())
+ && !blockTask.isShulker()
+ && !BlueprintGenerator.isInsideBlueprintBuild(blockTask.blockPos)
+ || currentBlock in arrayOf(Blocks.PORTAL, Blocks.END_PORTAL, Blocks.END_PORTAL_FRAME, Blocks.BEDROCK)
+ ) {
+ blockTask.updateState(TaskState.DONE)
+ return
+ }
+
+ // ToDo: Fix this
+// if (blockTask.targetBlock == fillerMat
+// && world.getBlockState(blockTask.blockPos.up()).block == material
+// || (!world.isPlaceable(blockTask.blockPos)
+// && world.getCollisionBox(blockTask.blockPos) != null)
+// ) {
+// blockTask.updateState(TaskState.DONE)
+// return
+// }
+
+ when (blockTask.targetBlock) {
+ fillerMat -> {
+ if (world.getBlockState(blockTask.blockPos.up()).block == material ||
+ (!world.isPlaceable(blockTask.blockPos) &&
+ world.getCollisionBox(blockTask.blockPos) != null)) {
+ blockTask.updateState(TaskState.DONE)
+ return
+ }
+ }
+ material -> {
+ if (currentBlock == material) {
+ blockTask.updateState(TaskState.DONE)
+ return
+ }
+ }
+ }
+
+ when (currentBlock) {
+ Blocks.AIR -> {
+ if (blockTask.targetBlock == Blocks.AIR) {
+ blockTask.updateState(TaskState.BROKEN)
+ return
+ } else {
+ blockTask.updateState(TaskState.PLACE)
+ return
+ }
+ }
+ is BlockLiquid -> {
+ updateLiquidTask(blockTask)
+ return
+ }
+ }
+
+ if (!updateOnly
+ && player.onGround
+ && swapOrMoveBestTool(blockTask)
+ && !handleLiquid(blockTask)
+ && Inventory.packetLimiter.size < interactionLimit
+ ) {
+ mineBlock(blockTask)
+ }
+ }
+
+ private fun SafeClientEvent.doPlace(blockTask: BlockTask, updateOnly: Boolean) {
+ val currentBlock = world.getBlockState(blockTask.blockPos).block
+
+ if (blockTask.taskState == TaskState.LIQUID
+ && world.getBlockState(blockTask.blockPos).block !is BlockLiquid
+ ) {
+ blockTask.updateState(TaskState.DONE)
+ return
+ }
+
+ when (blockTask.targetBlock) {
+ material -> {
+ if (currentBlock == material) {
+ blockTask.updateState(TaskState.PLACED)
+ return
+ }
+ }
+ fillerMat -> {
+ if (currentBlock == fillerMat) {
+ blockTask.updateState(TaskState.PLACED)
+ return
+ } else if (currentBlock != fillerMat
+ && mode == Trombone.Structure.HIGHWAY
+ && world.getBlockState(blockTask.blockPos.up()).block == material
+ ) {
+ blockTask.updateState(TaskState.DONE)
+ return
+ }
+ }
+ Blocks.AIR -> {
+ if (world.getBlockState(blockTask.blockPos).block !is BlockLiquid) {
+ if (currentBlock != Blocks.AIR) {
+ blockTask.updateState(TaskState.BREAK)
+ } else {
+ blockTask.updateState(TaskState.BROKEN)
+ }
+ return
+ }
+ }
+ }
+
+ if (updateOnly) return
+
+ if (!world.isPlaceable(blockTask.blockPos)) {
+ if (debugLevel == IO.DebugLevel.VERBOSE) {
+ if (!anonymizeStats) {
+ MessageSendHelper.sendChatMessage("${module.chatName} Invalid place position @(${blockTask.blockPos.asString()}) Removing task")
+ } else {
+ MessageSendHelper.sendChatMessage("${module.chatName} Invalid place position. Removing task")
+ }
+ }
+
+ if (blockTask == containerTask) {
+ MessageSendHelper.sendChatMessage("${module.chatName} Failed container task. Trying to break block.")
+ containerTask.updateState(TaskState.BREAK)
+ } else {
+ TaskManager.tasks.remove(blockTask.blockPos)
+ }
+
+ return
+ }
+
+ if (!swapOrMoveBlock(blockTask)) {
+ blockTask.onStuck()
+ return
+ }
+
+ placeBlock(blockTask)
+ }
+
+ private fun SafeClientEvent.doImpossiblePlace() {
+ if (shouldBridge()
+ && moveState != Pathfinder.MovementState.RESTOCK
+ && player.positionVector.distanceTo(Pathfinder.currentBlockPos.toVec3dCenter()) < 1
+ ) {
+ moveState = Pathfinder.MovementState.BRIDGE
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/trombone/task/TaskManager.kt b/src/main/kotlin/trombone/task/TaskManager.kt
new file mode 100644
index 0000000..e4f72af
--- /dev/null
+++ b/src/main/kotlin/trombone/task/TaskManager.kt
@@ -0,0 +1,332 @@
+package trombone.task
+
+import HighwayTools.anonymizeStats
+import HighwayTools.debugLevel
+import HighwayTools.dynamicDelay
+import HighwayTools.food
+import HighwayTools.ignoreBlocks
+import HighwayTools.manageFood
+import HighwayTools.material
+import HighwayTools.maxReach
+import HighwayTools.multiBuilding
+import HighwayTools.saveFood
+import HighwayTools.saveTools
+import HighwayTools.storageManagement
+import HighwayTools.width
+import com.lambda.client.event.SafeClientEvent
+import com.lambda.client.manager.managers.PlayerInventoryManager
+import com.lambda.client.util.items.countItem
+import com.lambda.client.util.items.inventorySlots
+import com.lambda.client.util.items.item
+import com.lambda.client.util.math.CoordinateConverter.asString
+import com.lambda.client.util.math.VectorUtils.distanceTo
+import com.lambda.client.util.math.VectorUtils.multiply
+import com.lambda.client.util.math.VectorUtils.toVec3dCenter
+import com.lambda.client.util.text.MessageSendHelper
+import com.lambda.client.util.world.isPlaceable
+import com.lambda.client.util.world.isReplaceable
+import net.minecraft.block.BlockLiquid
+import net.minecraft.block.state.IBlockState
+import net.minecraft.init.Blocks
+import net.minecraft.init.Items
+import net.minecraft.item.ItemFood
+import net.minecraft.item.ItemPickaxe
+import net.minecraft.util.math.AxisAlignedBB
+import net.minecraft.util.math.BlockPos
+import net.minecraft.util.math.Vec3d
+import trombone.blueprint.BlueprintGenerator.blueprint
+import trombone.blueprint.BlueprintGenerator.generateBluePrint
+import trombone.blueprint.BlueprintGenerator.isInsideBlueprintBuild
+import trombone.IO.DebugLevel
+import trombone.Pathfinder.MovementState
+import trombone.Pathfinder.currentBlockPos
+import trombone.Pathfinder.moveState
+import trombone.Pathfinder.startingBlockPos
+import trombone.Pathfinder.startingDirection
+import trombone.Trombone.module
+import trombone.blueprint.BlueprintTask
+import trombone.handler.Container.containerTask
+import trombone.handler.Container.grindCycles
+import trombone.handler.Container.handleRestock
+import trombone.handler.Inventory.waitTicks
+import trombone.interaction.Place.extraPlaceDelay
+import trombone.task.TaskExecutor.doTask
+import java.util.concurrent.ConcurrentHashMap
+import java.util.concurrent.ConcurrentSkipListSet
+
+object TaskManager {
+ val tasks = ConcurrentHashMap()
+ val sortedTasks = ConcurrentSkipListSet(blockTaskComparator())
+ var lastTask: BlockTask? = null
+
+ fun SafeClientEvent.populateTasks() {
+ generateBluePrint()
+
+ /* Generate tasks based on the blueprint */
+ blueprint.forEach { (pos, blueprintTask) ->
+ generateTask(pos, blueprintTask)
+ }
+
+ /* Remove old tasks */
+ tasks.filter {
+ it.value.taskState == TaskState.DONE
+ && currentBlockPos.distanceTo(it.key) > maxReach + 2
+ }.forEach {
+ if (it.value.toRemove) {
+ if (System.currentTimeMillis() - it.value.timestamp > 1000L) tasks.remove(it.key)
+ } else {
+ it.value.toRemove = true
+ it.value.timestamp = System.currentTimeMillis()
+ }
+ }
+ }
+
+ private fun SafeClientEvent.generateTask(blockPos: BlockPos, blueprintTask: BlueprintTask) {
+ val currentState = world.getBlockState(blockPos)
+ val eyePos = player.getPositionEyes(1f)
+
+ when {
+ /* start padding */
+ startPadding(blockPos) -> { /* Ignore task */ }
+
+ /* out of reach */
+ eyePos.distanceTo(blockPos.toVec3dCenter()) >= maxReach + 1 -> { /* Ignore task */ }
+
+ /* do not override container task */
+ containerTask.blockPos == blockPos -> { /* Ignore task */ }
+
+ /* ignored blocks */
+ shouldBeIgnored(blockPos, currentState) -> {
+ val blockTask = BlockTask(blockPos, TaskState.DONE, currentState.block)
+ addTask(blockTask, blueprintTask)
+ }
+
+ /* is in desired state */
+ currentState.block == blueprintTask.targetBlock -> {
+ val blockTask = BlockTask(blockPos, TaskState.DONE, currentState.block)
+ addTask(blockTask, blueprintTask)
+ }
+
+ /* is liquid */
+ currentState.block is BlockLiquid -> {
+ val blockTask = BlockTask(blockPos, TaskState.LIQUID, blueprintTask.targetBlock)
+ blockTask.updateTask(this)
+
+ if (blockTask.sequence.isNotEmpty()) {
+ addTask(blockTask, blueprintTask)
+ }
+ }
+
+ /* to place */
+ currentState.isReplaceable && blueprintTask.targetBlock != Blocks.AIR -> {
+ /* support not needed */
+ if (blueprintTask.isSupport && world.getBlockState(blockPos.up()).block == material) {
+ val blockTask = BlockTask(blockPos, TaskState.DONE, currentState.block)
+ addTask(blockTask, blueprintTask)
+ return
+ }
+
+ /* is blocked by entity */
+ if (!world.checkNoEntityCollision(AxisAlignedBB(blockPos), null)) {
+ val blockTask = BlockTask(blockPos, TaskState.DONE, currentState.block)
+ addTask(blockTask, blueprintTask)
+ return
+ }
+
+ val blockTask = BlockTask(blockPos, TaskState.PLACE, blueprintTask.targetBlock)
+ blockTask.updateTask(this)
+
+ if (blockTask.sequence.isNotEmpty()) {
+ addTask(blockTask, blueprintTask)
+ } else {
+ blockTask.updateState(TaskState.IMPOSSIBLE_PLACE)
+ addTask(blockTask, blueprintTask)
+ }
+ }
+
+ /* To break */
+ else -> {
+ /* Is already filled */
+ if (blueprintTask.isFiller) {
+ val blockTask = BlockTask(blockPos, TaskState.DONE, currentState.block)
+ addTask(blockTask, blueprintTask)
+ return
+ }
+
+ val blockTask = BlockTask(blockPos, TaskState.BREAK, blueprintTask.targetBlock)
+ blockTask.updateTask(this)
+
+ if (blockTask.eyeDistance < maxReach) {
+ addTask(blockTask, blueprintTask)
+ }
+ }
+ }
+ }
+
+ fun SafeClientEvent.runTasks() {
+ when {
+ /* Finish the container task first */
+ containerTask.taskState != TaskState.DONE -> {
+ containerTask.updateTask(this)
+ if (containerTask.stuckTicks > containerTask.taskState.stuckTimeout) {
+ if (containerTask.taskState == TaskState.PICKUP) moveState = MovementState.RUNNING
+
+ MessageSendHelper.sendWarningMessage("${module.chatName} Failed container action ${containerTask.taskState.name} with ${containerTask.item.registryName}@(${containerTask.blockPos.asString()}) stuck for ${containerTask.stuckTicks} ticks")
+ containerTask.updateState(TaskState.DONE)
+ } else {
+ tasks.values.forEach {
+ doTask(it, updateOnly = true)
+ }
+ doTask(containerTask)
+ }
+ }
+
+ /* Check tools */
+ storageManagement
+ && player.inventorySlots.countItem() <= saveTools -> {
+ // TODO: ItemPickaxe support
+ handleRestock(Items.DIAMOND_PICKAXE)
+ }
+
+ /* Fulfill basic needs */
+ storageManagement
+ && manageFood
+ && player.inventorySlots.countItem() <= saveFood -> {
+ // TODO: ItemFood support
+ handleRestock(food)
+ }
+
+ /* Restock obsidian if needed */
+ storageManagement && grindCycles > 0 && material == Blocks.OBSIDIAN -> {
+ handleRestock(material.item)
+ }
+
+ /* Actually run the tasks */
+ else -> {
+ waitTicks--
+
+ /* Only update tasks to check for changed circumstances */
+ tasks.values.forEach {
+ doTask(it, updateOnly = true)
+
+ it.updateTask(this)
+ if (multiBuilding) it.shuffle()
+ }
+
+ sortedTasks.clear()
+ sortedTasks.addAll(tasks.values)
+
+ sortedTasks.forEach taskExecution@{ task ->
+ if (!checkStuckTimeout(task)) return
+ if (task.taskState != TaskState.DONE && waitTicks > 0) return
+
+ doTask(task)
+ when (task.taskState) {
+ TaskState.DONE, TaskState.BROKEN, TaskState.PLACED -> return@taskExecution
+ else -> return
+ }
+ }
+ }
+ }
+ }
+
+ fun SafeClientEvent.addTask(blockTask: BlockTask, blueprintTask: BlueprintTask) {
+ blockTask.updateTask(this)
+ blockTask.isFiller = blueprintTask.isFiller
+ blockTask.isSupport = blueprintTask.isSupport
+
+ tasks[blockTask.blockPos]?.let {
+ if (it.stuckTicks > it.taskState.stuckTimeout
+ || blockTask.taskState == TaskState.LIQUID
+ || (it.taskState != blockTask.taskState
+ && (it.taskState == TaskState.DONE
+ || it.taskState == TaskState.IMPOSSIBLE_PLACE
+ || (it.taskState == TaskState.PLACE
+ && !world.isPlaceable(it.blockPos)
+ )))) {
+ tasks[blockTask.blockPos] = blockTask
+ }
+ } ?: run {
+ tasks[blockTask.blockPos] = blockTask
+ }
+ }
+
+ private fun checkStuckTimeout(blockTask: BlockTask): Boolean {
+ val timeout = blockTask.taskState.stuckTimeout
+
+ if (blockTask.stuckTicks < timeout) return true
+
+ if (blockTask.taskState == TaskState.DONE) return true
+
+ if (blockTask.taskState == TaskState.PENDING_BREAK) {
+ blockTask.updateState(TaskState.BREAK)
+ return false
+ }
+
+ if (blockTask.taskState == TaskState.PENDING_PLACE) {
+ blockTask.updateState(TaskState.PLACE)
+ return false
+ }
+
+ if (debugLevel != DebugLevel.OFF) {
+ if (!anonymizeStats) {
+ MessageSendHelper.sendChatMessage("${module.chatName} Stuck while ${blockTask.taskState}@(${blockTask.blockPos.asString()}) for more than $timeout ticks (${blockTask.stuckTicks}), refreshing data.")
+ } else {
+ MessageSendHelper.sendChatMessage("${module.chatName} Stuck while ${blockTask.taskState} for more than $timeout ticks (${blockTask.stuckTicks}), refreshing data.")
+ }
+ }
+
+ when (blockTask.taskState) {
+ TaskState.PLACE -> {
+ if (dynamicDelay && extraPlaceDelay < 10 && moveState != MovementState.BRIDGE) extraPlaceDelay += 1
+ }
+ TaskState.PICKUP -> {
+ MessageSendHelper.sendChatMessage("${module.chatName} Can't pickup ${containerTask.item.registryName}@(${containerTask.blockPos.asString()})")
+ blockTask.updateState(TaskState.DONE)
+ moveState = MovementState.RUNNING
+ }
+ else -> {
+ blockTask.updateState(TaskState.DONE)
+ }
+ }
+ return false
+ }
+
+ private fun startPadding(c: BlockPos) = isBehindPos(startingBlockPos.add(startingDirection.directionVec), c)
+
+ fun isBehindPos(origin: BlockPos, check: BlockPos): Boolean {
+ val a = origin.add(startingDirection.counterClockwise(2).directionVec.multiply(width))
+ val b = origin.add(startingDirection.clockwise(2).directionVec.multiply(width))
+
+ return ((b.x - a.x) * (check.z - a.z) - (b.z - a.z) * (check.x - a.x)) > 0
+ }
+
+ private fun shouldBeIgnored(blockPos: BlockPos, currentState: IBlockState) =
+ ignoreBlocks.contains(currentState.block.registryName.toString())
+ && !isInsideBlueprintBuild(blockPos)
+ && currentBlockPos.add(startingDirection.directionVec) != blockPos
+
+ fun clearTasks() {
+ tasks.clear()
+ sortedTasks.clear()
+ containerTask.updateState(TaskState.DONE)
+ lastTask = null
+ grindCycles = 0
+ }
+
+ private fun blockTaskComparator() = compareBy {
+ it.taskState.ordinal
+ }.thenBy {
+ it.stuckTicks
+ }.thenBy {
+ if (it.isLiquidSource) 0 else 1
+ }.thenBy {
+ if (moveState == MovementState.BRIDGE) {
+ if (it.sequence.isEmpty()) 69 else it.sequence.size
+ } else {
+ if (multiBuilding) it.shuffle else it.startDistance
+ }
+ }.thenBy {
+ it.eyeDistance
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/trombone/task/TaskState.kt b/src/main/kotlin/trombone/task/TaskState.kt
index e376c8f..f49884f 100644
--- a/src/main/kotlin/trombone/task/TaskState.kt
+++ b/src/main/kotlin/trombone/task/TaskState.kt
@@ -14,5 +14,6 @@ enum class TaskState(val stuckThreshold: Int, val stuckTimeout: Int, val color:
PLACE(20, 20, ColorHolder(35, 188, 254)),
PENDING_BREAK(100, 100, ColorHolder(0, 0, 0)),
PENDING_PLACE(100, 100, ColorHolder(0, 0, 0)),
+ IMPOSSIBLE_PLACE(100, 100, ColorHolder(16, 74, 94)),
DONE(69420, 0x22, ColorHolder(50, 50, 50))
}
\ No newline at end of file
diff --git a/src/main/resources/plugin_info.json b/src/main/resources/plugin_info.json
index 996d8c8..b0b0266 100644
--- a/src/main/resources/plugin_info.json
+++ b/src/main/resources/plugin_info.json
@@ -1,10 +1,9 @@
{
"name": "HighwayTools",
- "version": "10.0",
- "authors": [
- "Constructor"
- ],
+ "version": "${version}",
+ "authors": [ "Constructor" ],
"description": "Build highways with ease",
- "main_class": "HighwayToolsPlugin",
- "min_api_version": "2.07.01"
+ "url": "https://github.com/lambda-plugins/HighwayTools",
+ "min_api_version": "3.2",
+ "main_class": "HighwayToolsPlugin"
}
\ No newline at end of file