From a98cbf19c1757af0bfcf2601c07e59291efeb5a7 Mon Sep 17 00:00:00 2001 From: Osama Date: Tue, 9 Apr 2024 16:16:03 +0600 Subject: [PATCH] First pathfinder --- build.gradle.kts | 124 ++++++++--------- .../mixin/world/MixinChunkProviderClient.java | 31 +++++ .../dev/macrohq/swiftslayer/SwiftSlayer.kt | 113 +++++++++------- .../swiftslayer/command/PathfindTest.kt | 63 +++++---- .../swiftslayer/command/TestCommand.kt | 126 ++++++++++++++++-- .../swiftslayer/config/SwiftSlayerConfig.kt | 38 ++++++ .../swiftslayer/event/GameEventHandler.kt | 22 +++ .../macrohq/swiftslayer/feature/Failsafe.kt | 2 +- .../feature/implementation/AutoRotation.kt | 2 +- .../swiftslayer/pathfinder/calculate/Path.kt | 27 ++++ .../pathfinder/calculate/PathNode.kt | 39 ++++++ .../calculate/openset/BinaryHeapOpenSet.kt | 67 ++++++++++ .../calculate/path/AStarPathFinder.kt | 72 ++++++++++ .../pathfinder/costs/ActionCost.kt | 86 ++++++++++++ .../swiftslayer/pathfinder/goal/Goal.kt | 27 ++++ .../swiftslayer/pathfinder/goal/IGoal.kt | 6 + .../pathfinder/helper/BlockStateAccessor.kt | 48 +++++++ .../helper/player/IPlayerContext.kt | 15 +++ .../pathfinder/helper/player/PlayerContext.kt | 16 +++ .../pathfinder/movement/CalculationContext.kt | 17 +++ .../pathfinder/movement/IMovement.kt | 14 ++ .../pathfinder/movement/Movement.kt | 11 ++ .../pathfinder/movement/MovementHelper.kt | 102 ++++++++++++++ .../pathfinder/movement/MovementResult.kt | 26 ++++ .../swiftslayer/pathfinder/movement/Moves.kt | 106 +++++++++++++++ .../pathfinder/movement/config/PathConfig.kt | 14 ++ .../movement/movements/MovementAscend.kt | 49 +++++++ .../movement/movements/MovementDescend.kt | 105 +++++++++++++++ .../movement/movements/MovementDiagonal.kt | 117 ++++++++++++++++ .../movement/movements/MovementFall.kt | 22 +++ .../movement/movements/MovementTraverse.kt | 47 +++++++ .../util/accessor/IChunkProviderClient.kt | 9 ++ src/main/resources/mixins.swiftslayer.json | 3 +- 33 files changed, 1411 insertions(+), 155 deletions(-) create mode 100644 src/main/java/dev/macrohq/swiftslayer/mixin/world/MixinChunkProviderClient.java create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/event/GameEventHandler.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/calculate/Path.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/calculate/PathNode.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/calculate/openset/BinaryHeapOpenSet.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/calculate/path/AStarPathFinder.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/costs/ActionCost.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/goal/Goal.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/goal/IGoal.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/helper/BlockStateAccessor.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/helper/player/IPlayerContext.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/helper/player/PlayerContext.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/CalculationContext.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/IMovement.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/Movement.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/MovementHelper.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/MovementResult.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/Moves.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/config/PathConfig.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/movements/MovementAscend.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/movements/MovementDescend.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/movements/MovementDiagonal.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/movements/MovementFall.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/movements/MovementTraverse.kt create mode 100644 src/main/kotlin/dev/macrohq/swiftslayer/util/accessor/IChunkProviderClient.kt diff --git a/build.gradle.kts b/build.gradle.kts index bfe7fe1..a1a0778 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,96 +1,100 @@ plugins { - kotlin("jvm") version "1.9.0" - id("cc.polyfrost.loom") version "0.10.0.5" - id("dev.architectury.architectury-pack200") version "0.1.3" - id("com.github.johnrengelman.shadow") version "8.1.1" - id("net.kyori.blossom") version "1.3.1" + kotlin("jvm") version "1.9.0" + id("cc.polyfrost.loom") version "0.10.0.5" + id("dev.architectury.architectury-pack200") version "0.1.3" + id("com.github.johnrengelman.shadow") version "8.1.1" + id("net.kyori.blossom") version "1.3.1" } group = "dev.macrohq" version = "1.0.0" repositories { - maven("https://repo.polyfrost.cc/releases") - maven("https://repo.spongepowered.org/repository/maven-public") - maven("https://pkgs.dev.azure.com/djtheredstoner/DevAuth/_packaging/public/maven/v1") + maven("https://repo.polyfrost.cc/releases") + maven("https://repo.spongepowered.org/repository/maven-public") + maven("https://pkgs.dev.azure.com/djtheredstoner/DevAuth/_packaging/public/maven/v1") } val embed: Configuration by configurations.creating configurations.implementation.get().extendsFrom(embed) dependencies { - minecraft("com.mojang:minecraft:1.8.9") - mappings("de.oceanlabs.mcp:mcp_stable:22-1.8.9") - forge("net.minecraftforge:forge:1.8.9-11.15.1.2318-1.8.9") - compileOnly("cc.polyfrost:oneconfig-1.8.9-forge:0.2.0-alpha+") - embed("cc.polyfrost:oneconfig-wrapper-launchwrapper:1.0.0-beta+") - compileOnly("org.spongepowered:mixin:0.8.5-SNAPSHOT") - annotationProcessor("org.spongepowered:mixin:0.8.5-SNAPSHOT:processor") - modRuntimeOnly("me.djtheredstoner:DevAuth-forge-legacy:1.1.2") - embed("com.squareup.okhttp3:okhttp:3.14.9") + minecraft("com.mojang:minecraft:1.8.9") + mappings("de.oceanlabs.mcp:mcp_stable:22-1.8.9") + forge("net.minecraftforge:forge:1.8.9-11.15.1.2318-1.8.9") + compileOnly("cc.polyfrost:oneconfig-1.8.9-forge:0.2.0-alpha+") + embed("cc.polyfrost:oneconfig-wrapper-launchwrapper:1.0.0-beta+") + compileOnly("org.spongepowered:mixin:0.8.5-SNAPSHOT") + annotationProcessor("org.spongepowered:mixin:0.8.5-SNAPSHOT:processor") + modRuntimeOnly("me.djtheredstoner:DevAuth-forge-legacy:1.1.2") + embed("com.squareup.okhttp3:okhttp:3.14.9") + implementation("it.unimi.dsi:fastutil:8.2.1") } blossom { - replaceToken("%%VERSION%%", version) + replaceToken("%%VERSION%%", version) } loom { - runConfigs { - named("client") { - ideConfigGenerated(true) - } + runConfigs { + named("client") { + ideConfigGenerated(true) } + } - launchConfigs { - getByName("client") { - arg("--tweakClass", "cc.polyfrost.oneconfig.loader.stage0.LaunchWrapperTweaker") - property("devauth.enabled", "false") - } + launchConfigs { + getByName("client") { + arg("--tweakClass", "cc.polyfrost.oneconfig.loader.stage0.LaunchWrapperTweaker") + property("devauth.enabled", "false") } + } - forge { - pack200Provider.set(dev.architectury.pack200.java.Pack200Adapter()) - mixinConfig("mixins.swiftslayer.json") - } + forge { + pack200Provider.set(dev.architectury.pack200.java.Pack200Adapter()) + mixinConfig("mixins.swiftslayer.json") + } } tasks { - jar { - manifest.attributes( - mapOf( - "ModSide" to "CLIENT", - "TweakOrder" to "0", - "ForceLoadAsMod" to true, - "TweakClass" to "cc.polyfrost.oneconfig.loader.stage0.LaunchWrapperTweaker", - "MixinConfigs" to "mixins.swiftslayer.json" - ) - ) - dependsOn(shadowJar) - } + jar { + manifest.attributes( + mapOf( + "ModSide" to "CLIENT", + "TweakOrder" to "0", + "ForceLoadAsMod" to true, + "TweakClass" to "cc.polyfrost.oneconfig.loader.stage0.LaunchWrapperTweaker", + "MixinConfigs" to "mixins.swiftslayer.json" + ) + ) + dependsOn(shadowJar) + } - remapJar { - input.set(shadowJar.get().archiveFile) - archiveClassifier.set("") - } + remapJar { + input.set(shadowJar.get().archiveFile) + archiveClassifier.set("") + } - shadowJar { - isEnableRelocation = true - relocationPrefix = "dev.macrohq.swiftslayer.relocate" - relocate("cc.polyfrost", "cc.polyfrost") // this is so oneconfig doesn't get relocated, causing the tweaker to not be found - configurations = listOf(embed) - } + shadowJar { + isEnableRelocation = true + relocationPrefix = "dev.macrohq.swiftslayer.relocate" + relocate( + "cc.polyfrost", + "cc.polyfrost" + ) // this is so oneconfig doesn't get relocated, causing the tweaker to not be found + configurations = listOf(embed) + } - processResources { - inputs.property("version", version) - filesMatching(listOf("mcmod.info")) { - expand(mapOf("version" to version)) - } + processResources { + inputs.property("version", version) + filesMatching(listOf("mcmod.info")) { + expand(mapOf("version" to version)) } + } } java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 } java.toolchain.languageVersion = JavaLanguageVersion.of(8) \ No newline at end of file diff --git a/src/main/java/dev/macrohq/swiftslayer/mixin/world/MixinChunkProviderClient.java b/src/main/java/dev/macrohq/swiftslayer/mixin/world/MixinChunkProviderClient.java new file mode 100644 index 0000000..024786b --- /dev/null +++ b/src/main/java/dev/macrohq/swiftslayer/mixin/world/MixinChunkProviderClient.java @@ -0,0 +1,31 @@ +package dev.macrohq.swiftslayer.mixin.world; + +import dev.macrohq.swiftslayer.util.accessor.IChunkProviderClient; +import net.minecraft.client.multiplayer.ChunkProviderClient; +import net.minecraft.util.LongHashMap; +import net.minecraft.world.chunk.Chunk; +import org.jetbrains.annotations.NotNull; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.List; + +@Mixin(ChunkProviderClient.class) +public class MixinChunkProviderClient implements IChunkProviderClient { + + @Shadow + private LongHashMap chunkMapping; + + @Shadow + private List chunkListing; + + @Override + public LongHashMap chunkMapping() { + return this.chunkMapping; + } + + @Override + public List chunkListing() { + return this.chunkListing; + } +} \ No newline at end of file diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/SwiftSlayer.kt b/src/main/kotlin/dev/macrohq/swiftslayer/SwiftSlayer.kt index 92893bf..22bcf47 100644 --- a/src/main/kotlin/dev/macrohq/swiftslayer/SwiftSlayer.kt +++ b/src/main/kotlin/dev/macrohq/swiftslayer/SwiftSlayer.kt @@ -5,16 +5,21 @@ import dev.macrohq.swiftslayer.command.PathfindTest import dev.macrohq.swiftslayer.command.SwiftSlayerCommand import dev.macrohq.swiftslayer.command.TestCommand import dev.macrohq.swiftslayer.config.SwiftSlayerConfig +import dev.macrohq.swiftslayer.event.GameEventHandler import dev.macrohq.swiftslayer.feature.* import dev.macrohq.swiftslayer.macro.EndermanBossKiller import dev.macrohq.swiftslayer.macro.GenericBossKiller import dev.macrohq.swiftslayer.macro.MacroManager import dev.macrohq.swiftslayer.macro.MobKiller import dev.macrohq.swiftslayer.macro.Revenant +import dev.macrohq.swiftslayer.pathfinder.helper.BlockStateAccessor +import dev.macrohq.swiftslayer.pathfinder.helper.player.IPlayerContext +import dev.macrohq.swiftslayer.pathfinder.helper.player.PlayerContext import dev.macrohq.swiftslayer.pathfinding.PathExecutor import dev.macrohq.swiftslayer.util.KeyBindUtil import dev.macrohq.swiftslayer.util.RenderUtil import dev.macrohq.swiftslayer.util.RotationUtil +import net.minecraft.client.Minecraft import net.minecraft.util.BlockPos import net.minecraftforge.client.event.RenderWorldLastEvent import net.minecraftforge.common.MinecraftForge @@ -38,62 +43,68 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @Mod(modid = "swiftslayer", name = "SwiftSlayer", version = "%%VERSION%%") class SwiftSlayer { - companion object { - @Mod.Instance("swiftslayer") - lateinit var instance: SwiftSlayer private set - } + companion object { + @Mod.Instance("swiftslayer") + lateinit var instance: SwiftSlayer private set + } - lateinit var pathExecutor: PathExecutor private set - lateinit var config: SwiftSlayerConfig private set - lateinit var mobKiller: MobKiller private set - lateinit var endermanBossKiller: EndermanBossKiller private set - lateinit var autoBatphone: AutoBatphone private set - lateinit var macroManager: MacroManager private set - lateinit var genericBossKiller: GenericBossKiller private set - lateinit var revenant: Revenant private set - lateinit var tracker: Tracker private set - var removeLater: BlockPos? = null + lateinit var pathExecutor: PathExecutor private set + lateinit var config: SwiftSlayerConfig private set + lateinit var mobKiller: MobKiller private set + lateinit var endermanBossKiller: EndermanBossKiller private set + lateinit var autoBatphone: AutoBatphone private set + lateinit var macroManager: MacroManager private set + lateinit var genericBossKiller: GenericBossKiller private set + lateinit var revenant: Revenant private set + lateinit var tracker: Tracker private set + var removeLater: BlockPos? = null - @Mod.EventHandler - fun init(event: FMLInitializationEvent) { - config = SwiftSlayerConfig() - pathExecutor = PathExecutor() - mobKiller = MobKiller() - endermanBossKiller = EndermanBossKiller() - autoBatphone = AutoBatphone() - macroManager = MacroManager() - genericBossKiller = GenericBossKiller() - revenant = Revenant() - tracker = Tracker() - MinecraftForge.EVENT_BUS.register(this) - MinecraftForge.EVENT_BUS.register(pathExecutor) - MinecraftForge.EVENT_BUS.register(mobKiller) - MinecraftForge.EVENT_BUS.register(autoBatphone) - MinecraftForge.EVENT_BUS.register(macroManager) - MinecraftForge.EVENT_BUS.register(genericBossKiller) - MinecraftForge.EVENT_BUS.register(Failsafe()) - MinecraftForge.EVENT_BUS.register(revenant) - MinecraftForge.EVENT_BUS.register(tracker) - MinecraftForge.EVENT_BUS.register(SupportItem()) - CommandManager.register(PathfindTest()) - CommandManager.register(SwiftSlayerCommand()) + @Mod.EventHandler + fun init(event: FMLInitializationEvent) { + config = SwiftSlayerConfig() + pathExecutor = PathExecutor() + mobKiller = MobKiller() + endermanBossKiller = EndermanBossKiller() + autoBatphone = AutoBatphone() + macroManager = MacroManager() + genericBossKiller = GenericBossKiller() + revenant = Revenant() + tracker = Tracker() + MinecraftForge.EVENT_BUS.register(this) + MinecraftForge.EVENT_BUS.register(pathExecutor) + MinecraftForge.EVENT_BUS.register(mobKiller) + MinecraftForge.EVENT_BUS.register(autoBatphone) + MinecraftForge.EVENT_BUS.register(macroManager) + MinecraftForge.EVENT_BUS.register(genericBossKiller) + MinecraftForge.EVENT_BUS.register(Failsafe()) + MinecraftForge.EVENT_BUS.register(revenant) + MinecraftForge.EVENT_BUS.register(tracker) + MinecraftForge.EVENT_BUS.register(SupportItem()) + CommandManager.register(PathfindTest()) + CommandManager.register(SwiftSlayerCommand()) - val cmd = TestCommand() - CommandManager.register(cmd) - MinecraftForge.EVENT_BUS.register(cmd) + val cmd = TestCommand() + CommandManager.register(cmd) + MinecraftForge.EVENT_BUS.register(cmd) - // New Structure - FeatureManager.getInstance().loadFeatures().forEach(MinecraftForge.EVENT_BUS::register) + // New Structure + FeatureManager.getInstance().loadFeatures().forEach(MinecraftForge.EVENT_BUS::register) + MinecraftForge.EVENT_BUS.register(GameEventHandler(this)) - } + } - fun isTrackerInitialized() = ::tracker.isInitialized + fun isTrackerInitialized() = ::tracker.isInitialized - @SubscribeEvent - fun onRenderWorldLast(event: RenderWorldLastEvent) { - // this is here because im not sure if objects can have events cuz they are kinda static - RotationUtil.onRenderWorldLast() - RenderUtil.onRenderWorldLast(event) - KeyBindUtil.onRenderWorldLast() - } + @SubscribeEvent + fun onRenderWorldLast(event: RenderWorldLastEvent) { + // this is here because im not sure if objects can have events cuz they are kinda static + RotationUtil.onRenderWorldLast() + RenderUtil.onRenderWorldLast(event) + KeyBindUtil.onRenderWorldLast() + } + + // Hellow + val mc: Minecraft = Minecraft.getMinecraft() + val playerContext: IPlayerContext = PlayerContext(this, mc) + var bsa: BlockStateAccessor? = null } diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/command/PathfindTest.kt b/src/main/kotlin/dev/macrohq/swiftslayer/command/PathfindTest.kt index 48175eb..fce0719 100644 --- a/src/main/kotlin/dev/macrohq/swiftslayer/command/PathfindTest.kt +++ b/src/main/kotlin/dev/macrohq/swiftslayer/command/PathfindTest.kt @@ -3,6 +3,8 @@ package dev.macrohq.swiftslayer.command import cc.polyfrost.oneconfig.utils.commands.annotations.Command import cc.polyfrost.oneconfig.utils.commands.annotations.Main import cc.polyfrost.oneconfig.utils.commands.annotations.SubCommand +import dev.macrohq.swiftslayer.SwiftSlayer +import dev.macrohq.swiftslayer.pathfinder.movement.CalculationContext import dev.macrohq.swiftslayer.util.KeyBindUtil import dev.macrohq.swiftslayer.util.Logger import dev.macrohq.swiftslayer.util.PathingUtil @@ -18,40 +20,35 @@ import dev.macrohq.swiftslayer.util.swiftSlayer @Command(value = "pathfindtest", aliases = ["pft"]) class PathfindTest { - @Main - private fun main() { - Logger.info(SlayerUtil.getActive().toString()) - //revenant.enable() - // PathingUtil.goto(swiftSlayer.removeLater!!) -// world.getLoadedEntityList().forEach { -// println(it) -// } - } + @Main + private fun main() { + val ctx = CalculationContext(SwiftSlayer.instance) + } - @SubCommand - private fun end() { - RenderUtil.filledBox.remove(swiftSlayer.removeLater) - RenderUtil.filledBox.add(player.getStandingOnCeil()) - swiftSlayer.removeLater = player.getStandingOnCeil() - } + @SubCommand + private fun end() { + RenderUtil.filledBox.remove(swiftSlayer.removeLater) + RenderUtil.filledBox.add(player.getStandingOnCeil()) + swiftSlayer.removeLater = player.getStandingOnCeil() + } - @SubCommand - private fun clear() { - RenderUtil.filledBox.clear() - RenderUtil.markers.clear() - RenderUtil.lines.clear() - RenderUtil.points.clear() - RenderUtil.entites.clear() - swiftSlayer.removeLater = null - } + @SubCommand + private fun clear() { + RenderUtil.filledBox.clear() + RenderUtil.markers.clear() + RenderUtil.lines.clear() + RenderUtil.points.clear() + RenderUtil.entites.clear() + swiftSlayer.removeLater = null + } - @SubCommand - private fun stop() { - mobKiller.disable() - PathingUtil.stop() - RotationUtil.stop() - autoBatphone.disable() - KeyBindUtil.stopClicking() - revenant.disable() - } + @SubCommand + private fun stop() { + mobKiller.disable() + PathingUtil.stop() + RotationUtil.stop() + autoBatphone.disable() + KeyBindUtil.stopClicking() + revenant.disable() + } } diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/command/TestCommand.kt b/src/main/kotlin/dev/macrohq/swiftslayer/command/TestCommand.kt index 6bfc37f..90afd9b 100644 --- a/src/main/kotlin/dev/macrohq/swiftslayer/command/TestCommand.kt +++ b/src/main/kotlin/dev/macrohq/swiftslayer/command/TestCommand.kt @@ -3,33 +3,136 @@ package dev.macrohq.swiftslayer.command import cc.polyfrost.oneconfig.utils.commands.annotations.Command import cc.polyfrost.oneconfig.utils.commands.annotations.Main import cc.polyfrost.oneconfig.utils.commands.annotations.SubCommand +import cc.polyfrost.oneconfig.utils.dsl.runAsync import dev.macrohq.swiftslayer.feature.helper.Target import dev.macrohq.swiftslayer.feature.implementation.AutoRotation import dev.macrohq.swiftslayer.feature.implementation.LockType -import dev.macrohq.swiftslayer.util.Logger -import dev.macrohq.swiftslayer.util.RenderUtil -import dev.macrohq.swiftslayer.util.getStandingOnCeil -import dev.macrohq.swiftslayer.util.player import net.minecraft.util.BlockPos import net.minecraftforge.client.event.RenderWorldLastEvent import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import java.awt.Color +import dev.macrohq.swiftslayer.SwiftSlayer.Companion.instance +import dev.macrohq.swiftslayer.pathfinder.calculate.Path +import dev.macrohq.swiftslayer.pathfinder.calculate.PathNode +import dev.macrohq.swiftslayer.pathfinder.calculate.path.AStarPathFinder +import dev.macrohq.swiftslayer.pathfinder.goal.Goal +import dev.macrohq.swiftslayer.pathfinder.movement.CalculationContext +import dev.macrohq.swiftslayer.pathfinder.movement.MovementResult +import dev.macrohq.swiftslayer.pathfinder.movement.Moves +import dev.macrohq.swiftslayer.pathfinder.movement.movements.MovementAscend +import dev.macrohq.swiftslayer.pathfinder.movement.movements.MovementDescend +import dev.macrohq.swiftslayer.pathfinder.movement.movements.MovementDiagonal +import dev.macrohq.swiftslayer.pathfinder.movement.movements.MovementTraverse +import dev.macrohq.swiftslayer.util.* +import dev.macrohq.swiftslayer.util.Logger.note @Command("test", aliases = ["set"]) class TestCommand { private var rotationTargetBlock: BlockPos? = null + private var ns = mutableListOf() + + @SubCommand + private fun pf(a: String) { + if (a == "end") { + rotationTargetBlock = instance.playerContext.playerPosition + return + } + + if (rotationTargetBlock == null) return + val ctx = CalculationContext(instance) + val goal = Goal(rotationTargetBlock!!.x, rotationTargetBlock!!.y, rotationTargetBlock!!.z, ctx) + val start = instance.playerContext.playerPosition + val pathfinder = AStarPathFinder(start.x, start.y, start.z, goal, ctx) + var path: Path? = null + runAsync { + path = pathfinder.calculatePath() + if (path == null) { + note("No path found") + } else { + note("Size: ${path!!.path.size}") + ns.addAll(path!!.path) + } + } +// note("NeighbourSize: ${niggas.size}") + } + + fun getNode(x: Int, y: Int, z: Int, goal: Goal, hash: Long): PathNode { + val n = PathNode(x, y, z, goal) + return n + } + + @SubCommand + private fun neighbour() { + val ctx = CalculationContext(instance) + val start = instance.playerContext.playerPosition + val goal = Goal(rotationTargetBlock!!.x, rotationTargetBlock!!.y, rotationTargetBlock!!.z, ctx) + val currentNode = PathNode(start.x, start.y, start.z, goal) + currentNode.costSoFar = 0.0 + currentNode.totalCost = currentNode.costToEnd + val res = MovementResult() + + val list = mutableListOf() + + for (move in Moves.entries) { + res.reset() + move.calculate(ctx, currentNode.x, currentNode.y, currentNode.z, res) + val cost = res.cost + + if (cost >= ctx.cost.INF_COST) continue + val neighbourNode = getNode(res.x, res.y, res.z, goal, PathNode.longHash(res.x, res.y, res.z)) + val neighbourCostSoFar = currentNode.costSoFar + cost + + if (neighbourNode.costSoFar > neighbourCostSoFar) { + neighbourNode.parentNode = currentNode + neighbourNode.costSoFar = neighbourCostSoFar + neighbourNode.totalCost = neighbourCostSoFar + neighbourNode.costToEnd + + note("$neighbourNode, parentGCost: ${currentNode.costSoFar}, gCost: $neighbourCostSoFar") + + if (neighbourNode.heapPosition == -1) { + list.add(neighbourNode) + } + } + } + + list.forEach { ns.add(it.getBlock()); } + note("Size: ${list.size}") + } @Main private fun main() { - Logger.note("Test") +// val move = MovementDiagonal(instance, instance.playerContext.playerPosition, instance.playerContext.playerPosition.add(1, 0, 1)) +// val ctx = CalculationContext(instance) +// val res = MovementResult() +// move.getCost(ctx, res) +// note("Cost: ${res.cost}") +// rotationTargetBlock = res.getDest() +//// rotationTargetBlock = instance.playerContext.playerPosition.add(0, -1, 1) +// note("Dest: ${res.getDest()}") + val moves = Moves.values() + val move = moves[12] + val ctx = CalculationContext(instance) + val res = MovementResult() + move.calculate( + ctx, + instance.playerContext.playerPosition.x, + instance.playerContext.playerPosition.y, + instance.playerContext.playerPosition.z, + res + ) + note("Cost: ${res.cost}") + rotationTargetBlock = res.getDest() +// rotationTargetBlock = instance.playerContext.playerPosition.add(0, -1, 1) + note("Dest: ${res.getDest()}") } @SubCommand private fun rotate(lock: Boolean = false) { if (rotationTargetBlock == null) return - if(!AutoRotation.getInstance().enabled) { - AutoRotation.getInstance().easeTo(Target(rotationTargetBlock!!), 500, if (lock) LockType.INSTANT else LockType.NONE) - }else{ + if (!AutoRotation.getInstance().enabled) { + AutoRotation.getInstance() + .easeTo(Target(rotationTargetBlock!!), 500, if (lock) LockType.SMOOTH else LockType.NONE, 500) + } else { AutoRotation.getInstance().disable(); } } @@ -42,6 +145,7 @@ class TestCommand { @SubCommand private fun clear() { rotationTargetBlock = null + ns.clear() } @SubscribeEvent @@ -49,5 +153,11 @@ class TestCommand { if (rotationTargetBlock != null) { RenderUtil.drawBox(event, rotationTargetBlock!!, Color.GREEN, true) } + + if (ns.size > 0) { + ns.forEach { + RenderUtil.drawBox(event, it, Color.CYAN, true) + } + } } } \ No newline at end of file diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/config/SwiftSlayerConfig.kt b/src/main/kotlin/dev/macrohq/swiftslayer/config/SwiftSlayerConfig.kt index b9aa237..207559a 100644 --- a/src/main/kotlin/dev/macrohq/swiftslayer/config/SwiftSlayerConfig.kt +++ b/src/main/kotlin/dev/macrohq/swiftslayer/config/SwiftSlayerConfig.kt @@ -156,6 +156,44 @@ class SwiftSlayerConfig : Config(Mod("SwiftSlayer", ModType.SKYBLOCK), "swiftsla ) var macroGuiDelayRandomness: Float = 350f + + // ============================== + // Pathfinder Debug Config + // ============================== + @Switch( + name = "allowJump", + category = "PF" + ) + var allowJump = true + + + @Switch( + name = "holdSneak", + category = "PF" + ) + var holdSneak = true + + @Switch( + name = "allowDiagonalAscend", + category = "PF" + ) + var allowDiagonalAscend = true + + + @Switch( + name = "allowDiagonalDescend", + category = "PF" + ) + var allowDiagonalDescend = true + + @Slider( + name = "maxFallHeight", + category = "PF", + min = 1f, + max = 256f + ) + var maxFallHeight = 20 + fun getRandomGUIMacroDelay(): Long { return (macroGuiDelay + Math.random().toFloat() * macroGuiDelayRandomness).toLong() } diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/event/GameEventHandler.kt b/src/main/kotlin/dev/macrohq/swiftslayer/event/GameEventHandler.kt new file mode 100644 index 0000000..22c56ac --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/event/GameEventHandler.kt @@ -0,0 +1,22 @@ +package dev.macrohq.swiftslayer.event + +import dev.macrohq.swiftslayer.SwiftSlayer +import dev.macrohq.swiftslayer.pathfinder.helper.BlockStateAccessor +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.common.gameevent.TickEvent + +// a warpper for events that dont desrve their own class but is needed to make stuff work +class GameEventHandler(private val ss: SwiftSlayer) { + @SubscribeEvent + fun onTick(event: TickEvent.ClientTickEvent) { + // fun fact this is not always false so dont remove it + // i bypassed kotlin nullsafe + if (ss.playerContext.world == null) return + try { + ss.bsa = BlockStateAccessor(ss) + } catch (ex: Exception) { + ss.bsa = null + ex.printStackTrace() + } + } +} diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/feature/Failsafe.kt b/src/main/kotlin/dev/macrohq/swiftslayer/feature/Failsafe.kt index 193b35d..ec0caeb 100644 --- a/src/main/kotlin/dev/macrohq/swiftslayer/feature/Failsafe.kt +++ b/src/main/kotlin/dev/macrohq/swiftslayer/feature/Failsafe.kt @@ -24,7 +24,7 @@ class Failsafe { macroManager.disable() } - @SubscribeEvent +// @SubscribeEvent fun onItemChange(event: ReceivePacketEvent) { if (!macroManager.enabled) return if (event.packet !is S09PacketHeldItemChange) return diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/feature/implementation/AutoRotation.kt b/src/main/kotlin/dev/macrohq/swiftslayer/feature/implementation/AutoRotation.kt index a9eaf17..2aaf9a3 100644 --- a/src/main/kotlin/dev/macrohq/swiftslayer/feature/implementation/AutoRotation.kt +++ b/src/main/kotlin/dev/macrohq/swiftslayer/feature/implementation/AutoRotation.kt @@ -107,7 +107,7 @@ class AutoRotation: AbstractFeature() { player.rotationYaw += angChange.yaw player.rotationPitch += angChange.pitch } else { - this.easeTo(this.target!!, 200, LockType.SMOOTH, this.smoothLockTime) + this.easeTo(this.target!!, this.smoothLockTime, LockType.SMOOTH, this.smoothLockTime) } } } diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/calculate/Path.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/calculate/Path.kt new file mode 100644 index 0000000..ae30c38 --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/calculate/Path.kt @@ -0,0 +1,27 @@ +package dev.macrohq.swiftslayer.pathfinder.calculate + +import dev.macrohq.swiftslayer.pathfinder.goal.Goal +import dev.macrohq.swiftslayer.pathfinder.movement.CalculationContext +import dev.macrohq.swiftslayer.util.Logger.note +import net.minecraft.util.BlockPos +import java.util.* + + +class Path(start: PathNode, end: PathNode, val goal: Goal, val ctx: CalculationContext) { + var start: BlockPos = BlockPos(start.x, start.y, start.z) + var end: BlockPos = BlockPos(end.x, end.y, end.z) + var path: List + var node: List + init{ + var temp: PathNode? = end; + val listOfBlocks = LinkedList() + val listOfNodes = LinkedList() + while (temp != null){ + listOfNodes.addFirst(temp) + listOfBlocks.addFirst(BlockPos(temp.x, temp.y, temp.z)) + temp = temp.parentNode + } + path = listOfBlocks.toList() + node = listOfNodes.toList() + } +} \ No newline at end of file diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/calculate/PathNode.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/calculate/PathNode.kt new file mode 100644 index 0000000..997038d --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/calculate/PathNode.kt @@ -0,0 +1,39 @@ +package dev.macrohq.swiftslayer.pathfinder.calculate + +import dev.macrohq.swiftslayer.pathfinder.goal.Goal +import net.minecraft.util.BlockPos + +class PathNode(var x: Int, var y: Int, var z: Int, val goal: Goal) { + var costSoFar: Double = 1e6 // gCost - INF_COST + var costToEnd: Double = goal.heuristic(x, y, z) // hCost / Heuristic + var totalCost: Double = 1.0; // INF_COST + var heapPosition = -1; // Smart + var parentNode: PathNode? = null + + override fun equals(other: Any?): Boolean { + val otter = other as PathNode // otter just means other bt written weird to remove warning + return otter.x == this.x && otter.y == this.y && otter.z == this.z + } + + override fun hashCode(): Int { + return longHash(this.x, this.y, this.z).toInt() + } + + fun getBlock(): BlockPos{ + return BlockPos(x, y, z) + } + + override fun toString(): String { + return "PathNode(x: $x, y: $y, z: $z, totalCost: $totalCost)" + } + + companion object { + fun longHash(x: Int, y: Int, z: Int): Long { + var hash = 3241L; + hash = 3457689L * hash + x; + hash = 8734625L * hash + y; + hash = 2873465L * hash + z; + return hash; + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/calculate/openset/BinaryHeapOpenSet.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/calculate/openset/BinaryHeapOpenSet.kt new file mode 100644 index 0000000..49a8bbc --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/calculate/openset/BinaryHeapOpenSet.kt @@ -0,0 +1,67 @@ +package dev.macrohq.swiftslayer.pathfinder.calculate.openset + +import dev.macrohq.swiftslayer.pathfinder.calculate.PathNode +import scala.Array +import java.util.Arrays + +class BinaryHeapOpenSet(initialSize: Int = 1024) { + var items = arrayOfNulls(initialSize) + var size = 0 + + fun add(node: PathNode) { + if (size >= items.size - 1) { + items = Arrays.copyOf(items, items.size shl 1) + } + node.heapPosition = ++size + items[size] = node + relocate(node) + } + + fun relocate(node: PathNode) { + var parent = node.heapPosition ushr 1 + var parentNode = items[parent] + while (node.heapPosition > 1 && node.totalCost < parentNode!!.totalCost) { + items[node.heapPosition] = parentNode + items[parent] = node + node.heapPosition = parent + parent = parent ushr 1 + parentNode = items[parent] + } + } + + fun poll(): PathNode { + val itemToPoll = items[1] + itemToPoll!!.heapPosition = -1 + val itemToSwap = items[size--] + itemToSwap!!.heapPosition = 1 + items[1] = itemToSwap + val itemToSwapCost = itemToSwap.totalCost + + if(size <= 1) return itemToPoll + + var parentIndex = 1 + var smallestChildIndex = 2 + while (smallestChildIndex <= size) { + val rightChildIndex = smallestChildIndex + 1 + if (rightChildIndex < size && items[rightChildIndex]!!.totalCost < items[smallestChildIndex]!!.totalCost) { + smallestChildIndex = rightChildIndex + } + + if (items[smallestChildIndex]!!.totalCost >= itemToSwapCost) { + break + } + + val swapTemp = items[smallestChildIndex] + swapTemp!!.heapPosition = parentIndex + items[parentIndex] = swapTemp + itemToSwap.heapPosition = smallestChildIndex + items[smallestChildIndex] = itemToSwap + + parentIndex = smallestChildIndex + smallestChildIndex = parentIndex shl 1 + } + return itemToPoll + } + + fun isEmpty() = size <= 0 +} \ No newline at end of file diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/calculate/path/AStarPathFinder.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/calculate/path/AStarPathFinder.kt new file mode 100644 index 0000000..bc02b0c --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/calculate/path/AStarPathFinder.kt @@ -0,0 +1,72 @@ +package dev.macrohq.swiftslayer.pathfinder.calculate.path + +import dev.macrohq.swiftslayer.pathfinder.calculate.Path +import dev.macrohq.swiftslayer.pathfinder.calculate.PathNode +import dev.macrohq.swiftslayer.pathfinder.calculate.openset.BinaryHeapOpenSet +import dev.macrohq.swiftslayer.pathfinder.goal.Goal +import dev.macrohq.swiftslayer.pathfinder.movement.CalculationContext +import dev.macrohq.swiftslayer.pathfinder.movement.MovementResult +import dev.macrohq.swiftslayer.pathfinder.movement.Moves +import dev.macrohq.swiftslayer.util.Logger.note +import it.unimi.dsi.fastutil.longs.Long2ObjectMap +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap +import scala.tools.nsc.interpreter.JavapClass.PathOps +import java.util.Scanner + +class AStarPathFinder(val startX: Int, val startY: Int, val startZ: Int, val goal: Goal, val ctx: CalculationContext) { + val closedSet: Long2ObjectMap = Long2ObjectOpenHashMap() + + fun calculatePath(): Path? { + val openSet = BinaryHeapOpenSet() + val startNode = PathNode(startX, startY, startZ, goal) + val res = MovementResult() + val st = System.currentTimeMillis() + val end = System.currentTimeMillis() + 20 + var nodesConsidered = 0 + val moves = Moves.values() + startNode.costSoFar = 0.0 + startNode.totalCost = startNode.costToEnd + openSet.add(startNode) + + while (!openSet.isEmpty()) { + if (end - st <= 0) break + val currentNode = openSet.poll() + nodesConsidered++ + + if (goal.isAtGoal(currentNode.x, currentNode.y, currentNode.z)) { + return Path(startNode, currentNode, goal, ctx) + } + + for (move in moves) { + res.reset() + move.calculate(ctx, currentNode.x, currentNode.y, currentNode.z, res) + val cost = res.cost + if (cost >= ctx.cost.INF_COST) continue + val neighbourNode = getNode(res.x, res.y, res.z, PathNode.longHash(res.x, res.y, res.z)) + val neighbourCostSoFar = currentNode.costSoFar + cost + + if (neighbourNode.costSoFar > neighbourCostSoFar) { + neighbourNode.parentNode = currentNode + neighbourNode.costSoFar = neighbourCostSoFar + neighbourNode.totalCost = neighbourCostSoFar + neighbourNode.costToEnd + + if (neighbourNode.heapPosition == -1) { + openSet.add(neighbourNode) + } else { + openSet.relocate(neighbourNode) + } + } + } + } + return null + } + + fun getNode(x: Int, y: Int, z: Int, hash: Long): PathNode { + var n: PathNode? = closedSet.get(hash) + if (n == null) { + n = PathNode(x, y, z, goal) + closedSet.put(hash, n) + } + return n + } +} \ No newline at end of file diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/costs/ActionCost.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/costs/ActionCost.kt new file mode 100644 index 0000000..c1da7ff --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/costs/ActionCost.kt @@ -0,0 +1,86 @@ +package dev.macrohq.swiftslayer.pathfinder.costs + +class ActionCosts( + SPRINT_MOVEMENT_FACTOR: Double = 0.13, + WALKING_MOVEMENT_FACTOR: Double = 0.1, + SNEAKING_MOVEMENT_FACTOR: Double = 0.03 +) { + + val INF_COST = 1e6 + val N_BLOCK_FALL_COST: DoubleArray = generateNBlocksFallCost() + val ONE_UP_LADDER_COST: Double = 1 / (0.12 * 9.8) // 1 / (0.12b/t upward velocity * gravity) + val ONE_DOWN_LADDER_COST: Double = 1 / 0.15 // 1 / .15b/t downward velocity + val JUMP_ONE_BLOCK_COST = 6.234399666206506 + + val ONE_BLOCK_WALK_COST = 1 / actionTime(getWalkingFriction(WALKING_MOVEMENT_FACTOR)) + val ONE_BLOCK_SPRINT_COST = 1 / actionTime(getWalkingFriction(SPRINT_MOVEMENT_FACTOR)) + val ONE_BLOCK_SNEAK_COST = 1 / actionTime(getWalkingFriction(SNEAKING_MOVEMENT_FACTOR)) + + val ONE_BLOCK_WALK_IN_WATER_COST = 20 * actionTime(getWalkingInWaterFriction(WALKING_MOVEMENT_FACTOR)) + val ONE_BLOCK_WALK_OVER_SOUL_SAND_COST = ONE_BLOCK_WALK_COST * 2 + + val WALK_OFF_ONE_BLOCK_COST = ONE_BLOCK_WALK_COST * 0.8 + val CENTER_AFTER_FALL_COST = ONE_BLOCK_WALK_COST * 0.2 + + val SPRINT_MULTIPLIER = WALKING_MOVEMENT_FACTOR / SPRINT_MOVEMENT_FACTOR + + private fun getWalkingFriction(landMovementFactor: Double): Double { + return landMovementFactor * ((0.16277136) / (0.91 * 0.91 * 0.91)) + } + + private fun getWalkingInWaterFriction(landMovementFactor: Double): Double { + return 0.02 + (landMovementFactor - 0.02) * (1.0 / 3.0) + } + + private fun actionTime(friction: Double): Double { + return friction * 10 + } + + fun motionYAtTick(tick: Int): Double { + var velocity = -0.0784000015258789 + for (i in 1..tick) { + velocity = (velocity - 0.08) * 0.9800000190734863 + } + return velocity + } + + fun fallDistanceToTicks(distance: Double): Double { + if (distance == 0.0) return 0.0 + var tmpDistance = distance + var tickCount = 0 + while (true) { + val fallDistance = downwardMotionAtTick(tickCount) + if (tmpDistance <= fallDistance) { + return tickCount + tmpDistance / fallDistance + } + tmpDistance -= fallDistance + tickCount++ + } + } + + private fun downwardMotionAtTick(tick: Int): Double { + return (Math.pow(0.98, tick.toDouble()) - 1) * -3.92 + } + + private fun generateNBlocksFallCost(): DoubleArray { + val timeCost = DoubleArray(257) + var currentDistance = 0.0 + var targetDistance = 1 + var tickCount = 0 + + while (true) { + val velocityAtTick = downwardMotionAtTick(tickCount) + + if (currentDistance + velocityAtTick >= targetDistance) { + timeCost[targetDistance] = tickCount + (targetDistance - currentDistance) / velocityAtTick + targetDistance++ + if (targetDistance > 256) break + continue + } + + currentDistance += velocityAtTick + tickCount++ + } + return timeCost + } +} diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/goal/Goal.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/goal/Goal.kt new file mode 100644 index 0000000..31b733a --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/goal/Goal.kt @@ -0,0 +1,27 @@ +package dev.macrohq.swiftslayer.pathfinder.goal + +import dev.macrohq.swiftslayer.pathfinder.movement.CalculationContext +import kotlin.math.abs +import kotlin.math.min +import kotlin.math.sqrt + +class Goal(val goalX: Int, val goalY: Int, val goalZ: Int, val ctx: CalculationContext) : IGoal { + private val SQRT_2 = sqrt(2.0) + + override fun isAtGoal(x: Int, y: Int, z: Int): Boolean { + return goalX == x && goalY == y && goalZ == z + } + + override fun heuristic(x: Int, y: Int, z: Int): Double { + val dx = abs(goalX - x) + val dz = abs(goalZ - z) + val straight = abs(dx - dz).toDouble() + var vertical = abs(goalY - y).toDouble() + val diagonal = min(dx, dz).toDouble() + + vertical *= if (goalY > y) { ctx.cost.JUMP_ONE_BLOCK_COST } + else { ctx.cost.N_BLOCK_FALL_COST[2] / 2.0 } + + return (straight + diagonal * SQRT_2) * ctx.cost.ONE_BLOCK_SPRINT_COST + vertical + } +} \ No newline at end of file diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/goal/IGoal.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/goal/IGoal.kt new file mode 100644 index 0000000..24f1a0c --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/goal/IGoal.kt @@ -0,0 +1,6 @@ +package dev.macrohq.swiftslayer.pathfinder.goal + +interface IGoal { + fun isAtGoal(x: Int, y: Int, z: Int): Boolean + fun heuristic(x: Int, y: Int, z: Int): Double +} \ No newline at end of file diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/helper/BlockStateAccessor.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/helper/BlockStateAccessor.kt new file mode 100644 index 0000000..a445ec5 --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/helper/BlockStateAccessor.kt @@ -0,0 +1,48 @@ +package dev.macrohq.swiftslayer.pathfinder.helper + +import dev.macrohq.swiftslayer.SwiftSlayer +import dev.macrohq.swiftslayer.util.accessor.IChunkProviderClient +import it.unimi.dsi.fastutil.longs.Long2ObjectMap +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap +import net.minecraft.block.state.IBlockState +import net.minecraft.init.Blocks +import net.minecraft.util.BlockPos +import net.minecraft.world.World +import net.minecraft.world.chunk.Chunk + +class BlockStateAccessor(private val ss: SwiftSlayer) { + private val world: World = this.ss.playerContext.world + private val loadedChunks: Long2ObjectMap = Long2ObjectOpenHashMap() + private var cached: Chunk? = null + + init { + val loadedWorld: List = (this.world.chunkProvider as IChunkProviderClient).chunkListing() + + for (chunk in loadedWorld) { + this.loadedChunks[this.getKey(chunk.xPosition, chunk.zPosition)] = chunk + } + } + + fun get(x: Int, y: Int, z: Int): IBlockState { + var current = this.cached + if (current != null && current.xPosition == x shr 4 && current.zPosition == z shr 4) { + return current.getBlockState(BlockPos(x, y, z)) + } + + current = this.loadedChunks[this.getKey(x shr 4, z shr 4)] + + if (current != null && current.isLoaded) { + this.cached = current + return current.getBlockState(BlockPos(x, y, z)) + } + return Blocks.air.defaultState + } + + fun isBlockInLoadedChunks(blockX: Int, blockZ: Int): Boolean { + return this.loadedChunks.containsKey(getKey(blockX shr 4, blockZ shr 4)) + } + + private fun getKey(x: Int, z: Int): Long { + return (x.toLong() and 4294967295L) or ((z.toLong() and 4294967295L) shl 32) + } +} diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/helper/player/IPlayerContext.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/helper/player/IPlayerContext.kt new file mode 100644 index 0000000..1479e43 --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/helper/player/IPlayerContext.kt @@ -0,0 +1,15 @@ +package dev.macrohq.swiftslayer.pathfinder.helper.player + +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.multiplayer.PlayerControllerMP; +import net.minecraft.util.BlockPos +import net.minecraft.world.World; + +interface IPlayerContext { + val mc: Minecraft + val player: EntityPlayerSP + val playerController: PlayerControllerMP + val world: World + val playerPosition: BlockPos +} \ No newline at end of file diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/helper/player/PlayerContext.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/helper/player/PlayerContext.kt new file mode 100644 index 0000000..eaf1c75 --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/helper/player/PlayerContext.kt @@ -0,0 +1,16 @@ +package dev.macrohq.swiftslayer.pathfinder.helper.player + +import dev.macrohq.swiftslayer.SwiftSlayer +import net.minecraft.client.Minecraft +import net.minecraft.util.BlockPos +import kotlin.math.ceil + +class PlayerContext(val ss: SwiftSlayer, override val mc: Minecraft) : IPlayerContext { + override val player get() = mc.thePlayer + override val playerController get() = mc.playerController + override val world get() = mc.theWorld + + // Block player is standing on + // Todo: Change name + override val playerPosition get() = BlockPos(player.posX, ceil(player.posY) - 1, player.posZ) +} \ No newline at end of file diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/CalculationContext.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/CalculationContext.kt new file mode 100644 index 0000000..d390d3d --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/CalculationContext.kt @@ -0,0 +1,17 @@ +package dev.macrohq.swiftslayer.pathfinder.movement + +import dev.macrohq.swiftslayer.SwiftSlayer +import dev.macrohq.swiftslayer.pathfinder.costs.ActionCosts +import dev.macrohq.swiftslayer.pathfinder.movement.config.PathConfig +import net.minecraft.block.state.IBlockState + +class CalculationContext(val ss: SwiftSlayer, val pathConfig: PathConfig = PathConfig()) { + val world = ss.playerContext.world + val player = ss.playerContext.player + val bsa = ss.bsa!! // If this is a null pls fix ur brain dev + val cost = ActionCosts(pathConfig.sprintFactor, pathConfig.walkFactor, pathConfig.sneakFactor) + + fun get(x: Int, y: Int, z: Int): IBlockState{ + return bsa.get(x, y, z) + } +} \ No newline at end of file diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/IMovement.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/IMovement.kt new file mode 100644 index 0000000..a4a14af --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/IMovement.kt @@ -0,0 +1,14 @@ +package dev.macrohq.swiftslayer.pathfinder.movement + +import dev.macrohq.swiftslayer.SwiftSlayer +import net.minecraft.util.BlockPos + +interface IMovement { + val ss: SwiftSlayer + val source: BlockPos + val dest: BlockPos + val costs: Double // plural cuz kotlin gae + + fun getCost(): Double + fun calculateCost(ctx: CalculationContext, res: MovementResult) +} \ No newline at end of file diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/Movement.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/Movement.kt new file mode 100644 index 0000000..2a3cba3 --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/Movement.kt @@ -0,0 +1,11 @@ +package dev.macrohq.swiftslayer.pathfinder.movement + +import dev.macrohq.swiftslayer.SwiftSlayer +import net.minecraft.util.BlockPos + +abstract class Movement(override val ss: SwiftSlayer, override val source: BlockPos, override val dest: BlockPos) : + IMovement { + + override var costs: Double = 1e6 + override fun getCost() = costs +} \ No newline at end of file diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/MovementHelper.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/MovementHelper.kt new file mode 100644 index 0000000..41c8b83 --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/MovementHelper.kt @@ -0,0 +1,102 @@ +package dev.macrohq.swiftslayer.pathfinder.movement + +import dev.macrohq.swiftslayer.pathfinder.helper.BlockStateAccessor +import net.minecraft.block.* +import net.minecraft.block.state.IBlockState +import net.minecraft.init.Blocks +import net.minecraft.util.EnumFacing + +object MovementHelper { + + fun canWalkThrough(bsa: BlockStateAccessor, x: Int, y: Int, z: Int): Boolean { + return canWalkThroughBlockState(bsa, x, y, z, bsa.get(x, y, z)) + } + + fun canWalkThroughBlockState(bsa: BlockStateAccessor, x: Int, y: Int, z: Int, state: IBlockState): Boolean { + val block = state.block + return when { + block is BlockAir -> true + block is BlockBush || block is BlockTorch -> true + block == Blocks.fire || block == Blocks.web || block == Blocks.tripwire || block == Blocks.end_portal || block == Blocks.cocoa || block is BlockSkull || block is BlockSlab || block is BlockTrapDoor -> false + block is BlockCarpet || block == Blocks.waterlily -> true + block is BlockSnow -> state.getValue(BlockSnow.LAYERS) < 3 + block == Blocks.water -> bsa.get(x, y + 1, z).block != Blocks.waterlily + block == Blocks.flowing_water -> false + else -> block.isPassable(null, null) + } + } + + fun canStandOnBlock(bsa: BlockStateAccessor, x: Int, y: Int, z: Int): Boolean { + return canStandOnBlockState(bsa, x, y, z, bsa.get(x, y, z)) + } + + fun canStandOnBlockState(bsa: BlockStateAccessor, x: Int, y: Int, z: Int, state: IBlockState): Boolean { + val block = state.block + return when { + block is BlockAir -> false + block is BlockSnow -> true + block.isBlockNormalCube -> true + block == Blocks.ladder -> true + block == Blocks.farmland -> true + block == Blocks.ender_chest || block == Blocks.chest || block == Blocks.trapped_chest -> true + block == Blocks.glass || block is BlockStainedGlass -> true + block is BlockStairs -> true + block is BlockLiquid -> { + if(block == Blocks.lava || block == Blocks.flowing_lava || block == Blocks.flowing_water) return false + return bsa.get(x,y + 1, z).block == Blocks.waterlily + } + else -> block is BlockSlab + } + } + + fun isWotah(state: IBlockState): Boolean { + val block = state.block + return block == Blocks.water || block == Blocks.flowing_water + } + + fun isLava(state: IBlockState): Boolean { + val block = state.block + return block == Blocks.lava || block == Blocks.flowing_lava + } + + fun isBottomSlab(state: IBlockState): Boolean { + return state.block is BlockSlab && !(state.block as BlockSlab).isDouble && state.getValue(BlockSlab.HALF) == BlockSlab.EnumBlockHalf.BOTTOM + } + + fun isValidStair(state: IBlockState, dx: Int, dz: Int): Boolean { + if (dx == 0 && dz == 0) return false + if (state.block !is BlockStairs) return false + if (state.getValue(BlockStairs.HALF) != BlockStairs.EnumHalf.BOTTOM) return false + + val stairFacing = state.getValue(BlockStairs.FACING) + + return when { + dz == -1 -> stairFacing == EnumFacing.NORTH + dz == 1 -> stairFacing == EnumFacing.SOUTH + dx == -1 -> stairFacing == EnumFacing.WEST + dx == 1 -> stairFacing == EnumFacing.EAST + else -> false + } + } + + fun hasTop(state: IBlockState, dX: Int, dZ: Int): Boolean { + return !(isBottomSlab(state) || isValidStair(state, dX, dZ)) + } + + fun avoidWalkingInto(state: IBlockState): Boolean { + val block = state.block + return block is BlockLiquid || block is BlockFire || block == Blocks.cactus || block == Blocks.end_portal || block == Blocks.web + } + + fun getFacing(dx: Int, dz: Int): EnumFacing { + return if (dx == 0 && dz == 0) EnumFacing.UP else EnumFacing.HORIZONTALS[Math.abs(dx) * (2 + dx) + Math.abs(dz) * (1 - dz)] + } + + fun isLadder(state: IBlockState): Boolean { + return state.block == Blocks.ladder + } + + fun canWalkIntoLadder(ladderState: IBlockState, dx: Int, dz: Int): Boolean { + return isLadder(ladderState) && ladderState.getValue(BlockLadder.FACING) != getFacing(dx, dz) + } +} diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/MovementResult.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/MovementResult.kt new file mode 100644 index 0000000..6a60d53 --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/MovementResult.kt @@ -0,0 +1,26 @@ +package dev.macrohq.swiftslayer.pathfinder.movement + +import net.minecraft.util.BlockPos +class MovementResult { + var x: Int = 0 + var y: Int = 0 + var z: Int = 0 + var cost: Double = 1e6 + + fun set(x: Int, y: Int, z: Int) { + this.x = x + this.y = y + this.z = z + } + + fun reset() { + x = 0 + y = 0 + z = 0 + cost = 1e6 + } + + fun getDest(): BlockPos { + return BlockPos(x, y, z) + } +} diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/Moves.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/Moves.kt new file mode 100644 index 0000000..4f15c1d --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/Moves.kt @@ -0,0 +1,106 @@ +package dev.macrohq.swiftslayer.pathfinder.movement + +import dev.macrohq.swiftslayer.pathfinder.movement.movements.MovementAscend +import dev.macrohq.swiftslayer.pathfinder.movement.movements.MovementDescend +import dev.macrohq.swiftslayer.pathfinder.movement.movements.MovementDiagonal +import dev.macrohq.swiftslayer.pathfinder.movement.movements.MovementTraverse + +enum class Moves(val offsetX: Int, val offsetZ: Int) { + TRAVERSE_NORTH(0, -1) { + override fun calculate(ctx: CalculationContext, parentX: Int, parentY: Int, parentZ: Int, res: MovementResult) { + MovementTraverse.calculateCost(ctx, parentX, parentY, parentZ, parentX + offsetX, parentZ + offsetZ, res) + } + }, + + TRAVERSE_SOUTH(0, +1) { + override fun calculate(ctx: CalculationContext, parentX: Int, parentY: Int, parentZ: Int, res: MovementResult) { + MovementTraverse.calculateCost(ctx, parentX, parentY, parentZ, parentX + offsetX, parentZ + offsetZ, res) + } + }, + + TRAVERSE_EAST(+1, 0) { + override fun calculate(ctx: CalculationContext, parentX: Int, parentY: Int, parentZ: Int, res: MovementResult) { + MovementTraverse.calculateCost(ctx, parentX, parentY, parentZ, parentX + offsetX, parentZ + offsetZ, res) + } + }, + + TRAVERSE_WEST(-1, 0) { + override fun calculate(ctx: CalculationContext, parentX: Int, parentY: Int, parentZ: Int, res: MovementResult) { + MovementTraverse.calculateCost(ctx, parentX, parentY, parentZ, parentX + offsetX, parentZ + offsetZ, res) + } + }, + + ASCEND_NORTH(0, -1) { + override fun calculate(ctx: CalculationContext, parentX: Int, parentY: Int, parentZ: Int, res: MovementResult) { + MovementAscend.calculateCost(ctx, parentX, parentY, parentZ, parentX + offsetX, parentZ + offsetZ, res) + } + }, + + ASCEND_SOUTH(0, +1) { + override fun calculate(ctx: CalculationContext, parentX: Int, parentY: Int, parentZ: Int, res: MovementResult) { + MovementAscend.calculateCost(ctx, parentX, parentY, parentZ, parentX + offsetX, parentZ + offsetZ, res) + } + }, + + ASCEND_EAST(+1, 0) { + override fun calculate(ctx: CalculationContext, parentX: Int, parentY: Int, parentZ: Int, res: MovementResult) { + MovementAscend.calculateCost(ctx, parentX, parentY, parentZ, parentX + offsetX, parentZ + offsetZ, res) + } + }, + + ASCEND_WEST(-1, 0) { + override fun calculate(ctx: CalculationContext, parentX: Int, parentY: Int, parentZ: Int, res: MovementResult) { + MovementAscend.calculateCost(ctx, parentX, parentY, parentZ, parentX + offsetX, parentZ + offsetZ, res) + } + }, + + DESCEND_NORTH(0, -1) { + override fun calculate(ctx: CalculationContext, parentX: Int, parentY: Int, parentZ: Int, res: MovementResult) { + MovementDescend.calculateCost(ctx, parentX, parentY, parentZ, parentX + offsetX, parentZ + offsetZ, res) + } + }, + + DESCEND_SOUTH(0, +1) { + override fun calculate(ctx: CalculationContext, parentX: Int, parentY: Int, parentZ: Int, res: MovementResult) { + MovementDescend.calculateCost(ctx, parentX, parentY, parentZ, parentX + offsetX, parentZ + offsetZ, res) + } + }, + + DESCEND_EAST(+1, 0) { + override fun calculate(ctx: CalculationContext, parentX: Int, parentY: Int, parentZ: Int, res: MovementResult) { + MovementDescend.calculateCost(ctx, parentX, parentY, parentZ, parentX + offsetX, parentZ + offsetZ, res) + } + }, + + DESCEND_WEST(-1, 0) { + override fun calculate(ctx: CalculationContext, parentX: Int, parentY: Int, parentZ: Int, res: MovementResult) { + MovementDescend.calculateCost(ctx, parentX, parentY, parentZ, parentX + offsetX, parentZ + offsetZ, res) + } + }, + + DIAGONAL_NORTHEAST(+1, -1) { + override fun calculate(ctx: CalculationContext, parentX: Int, parentY: Int, parentZ: Int, res: MovementResult) { + MovementDiagonal.calculateCost(ctx, parentX, parentY, parentZ, parentX + offsetX, parentZ + offsetZ, res) + } + }, + + DIAGONAL_NORTHWEST(-1, -1) { + override fun calculate(ctx: CalculationContext, parentX: Int, parentY: Int, parentZ: Int, res: MovementResult) { + MovementDiagonal.calculateCost(ctx, parentX, parentY, parentZ, parentX + offsetX, parentZ + offsetZ, res) + } + }, + + DIAGONAL_SOUTHEAST(+1, +1) { + override fun calculate(ctx: CalculationContext, parentX: Int, parentY: Int, parentZ: Int, res: MovementResult) { + MovementDiagonal.calculateCost(ctx, parentX, parentY, parentZ, parentX + offsetX, parentZ + offsetZ, res) + } + }, + + DIAGONAL_SOUTHWEST(-1, +1) { + override fun calculate(ctx: CalculationContext, parentX: Int, parentY: Int, parentZ: Int, res: MovementResult) { + MovementDiagonal.calculateCost(ctx, parentX, parentY, parentZ, parentX + offsetX, parentZ + offsetZ, res) + } + }; + + abstract fun calculate(ctx: CalculationContext, parentX: Int, parentY: Int, parentZ: Int, res: MovementResult) +} \ No newline at end of file diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/config/PathConfig.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/config/PathConfig.kt new file mode 100644 index 0000000..9d681a7 --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/config/PathConfig.kt @@ -0,0 +1,14 @@ +package dev.macrohq.swiftslayer.pathfinder.movement.config + +import dev.macrohq.swiftslayer.SwiftSlayer + +class PathConfig( + var sprintFactor: Double = 0.13, + var walkFactor: Double = 0.1, + var sneakFactor: Double = 0.03, + var allowJump: Boolean = SwiftSlayer.instance.config.allowJump, + var holdSneak: Boolean = SwiftSlayer.instance.config.holdSneak, + var maxFallHeight: Int = SwiftSlayer.instance.config.maxFallHeight, + var allowDiagonalAscend: Boolean = SwiftSlayer.instance.config.allowDiagonalAscend, + var allowDiagonalDescend: Boolean = SwiftSlayer.instance.config.allowDiagonalDescend +){} \ No newline at end of file diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/movements/MovementAscend.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/movements/MovementAscend.kt new file mode 100644 index 0000000..2161c8d --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/movements/MovementAscend.kt @@ -0,0 +1,49 @@ +package dev.macrohq.swiftslayer.pathfinder.movement.movements + +import dev.macrohq.swiftslayer.SwiftSlayer +import dev.macrohq.swiftslayer.pathfinder.movement.CalculationContext +import dev.macrohq.swiftslayer.pathfinder.movement.Movement +import dev.macrohq.swiftslayer.pathfinder.movement.MovementHelper +import dev.macrohq.swiftslayer.pathfinder.movement.MovementResult +import net.minecraft.util.BlockPos + +class MovementAscend(ss: SwiftSlayer, from: BlockPos, to: BlockPos) : Movement(ss, from, to) { + override fun calculateCost(ctx: CalculationContext, res: MovementResult) { + calculateCost(ctx, source.x, source.y, source.z, dest.x, dest.z, res) + costs = res.cost + } + + companion object { + fun calculateCost(ctx: CalculationContext, x: Int, y: Int, z: Int, destX: Int, destZ: Int, res: MovementResult) { + res.set(destX, y + 1, destZ) + cost(ctx, x, y, z, destX, destZ, res) + } + + private fun cost(ctx: CalculationContext, x: Int, y: Int, z: Int, destX: Int, destZ: Int, res: MovementResult) { + val destState = ctx.get(destX, y + 1, destZ) + if (!MovementHelper.canStandOnBlockState(ctx.bsa, destX, y + 1, destZ, destState)) return + if (!MovementHelper.canWalkThrough(ctx.bsa, destX, y + 3, destZ)) return + if (!MovementHelper.canWalkThrough(ctx.bsa, destX, y + 2, destZ)) return + if (!MovementHelper.canWalkThrough(ctx.bsa, x, y + 3, z)) return + + val sourceState = ctx.get(x, y, z) + if (MovementHelper.isLadder(sourceState)) return + + if (MovementHelper.isLadder(destState) && !MovementHelper.canWalkIntoLadder( + destState, + destX - x, + destZ - z + ) + ) return + + val sourceMaxY = sourceState.block.getCollisionBoundingBox(ctx.world, BlockPos(x, y, z), sourceState)?.maxY ?: y.toDouble() + val destMaxY = destState.block.getCollisionBoundingBox(ctx.world, BlockPos(destX, y + 1, destZ), destState)?.maxY ?: (y + 1.0) + + res.cost = when { + destMaxY - sourceMaxY <= 0.5 -> ctx.cost.ONE_BLOCK_SPRINT_COST + destMaxY - sourceMaxY <= 1.125 && ctx.pathConfig.allowJump -> ctx.cost.JUMP_ONE_BLOCK_COST + else -> ctx.cost.INF_COST // Should never trigger. Maybe throw exception in case it triggers? + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/movements/MovementDescend.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/movements/MovementDescend.kt new file mode 100644 index 0000000..8c8a3d7 --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/movements/MovementDescend.kt @@ -0,0 +1,105 @@ +package dev.macrohq.swiftslayer.pathfinder.movement.movements + +import dev.macrohq.swiftslayer.SwiftSlayer +import dev.macrohq.swiftslayer.pathfinder.movement.CalculationContext +import dev.macrohq.swiftslayer.pathfinder.movement.Movement +import dev.macrohq.swiftslayer.pathfinder.movement.MovementHelper +import dev.macrohq.swiftslayer.pathfinder.movement.MovementResult +import net.minecraft.block.state.IBlockState +import net.minecraft.util.BlockPos + +class MovementDescend(ss: SwiftSlayer, from: BlockPos, to: BlockPos) : Movement(ss, from, to) { + override fun calculateCost(ctx: CalculationContext, res: MovementResult) { + calculateCost(ctx, source.x, source.y, source.z, dest.x, dest.z, res) + costs = res.cost + } + + + companion object { + fun calculateCost(ctx: CalculationContext, x: Int, y: Int, z: Int, destX: Int, destZ: Int, res: MovementResult) { + res.set(destX, y - 1, destZ) + cost(ctx, x, y, z, destX, destZ, res) + } + + private fun cost(ctx: CalculationContext, x: Int, y: Int, z: Int, destX: Int, destZ: Int, res: MovementResult) { + val destUpState = ctx.get(destX, y, destZ); + if (!MovementHelper.canWalkThrough(ctx.bsa, destX, y + 2, destZ) + || !MovementHelper.canWalkThrough(ctx.bsa, destX, y + 1, destZ) + || !MovementHelper.canWalkThroughBlockState(ctx.bsa, destX, y, destZ, destUpState) + ) { + return; + } + val sourceState = ctx.get(x, y, z); + if (MovementHelper.isLadder(sourceState) || MovementHelper.isLadder(destUpState)) { // Cannot descend from ladder it'll be MovementDownward + return; + } + val destState = ctx.get(destX, y - 1, destZ); + if (!MovementHelper.canStandOnBlockState(ctx.bsa, destX, y - 1, destZ, destState) || MovementHelper.isLadder( + destState + ) + ) { + freeFallCost(ctx, x, y, z, destX, destZ, destState, res); + return; + } + res.cost = ctx.cost.WALK_OFF_ONE_BLOCK_COST * ctx.cost.SPRINT_MULTIPLIER + ctx.cost.N_BLOCK_FALL_COST[1]; + } + + private fun freeFallCost( + ctx: CalculationContext, + x: Int, + y: Int, + z: Int, + destX: Int, + destZ: Int, + destState: IBlockState, + res: MovementResult + ) { + // im starting from 2 because I work with the blocks itself. x, y, z aren't for sourceBlock.up() like its in baritone its sourceBlock + if (!MovementHelper.canWalkThroughBlockState(ctx.bsa, destX, y - 1, destZ, destState)) { + return + } + + var effStartHeight = y // for ladder + var cost = 0.0 + for (fellSoFar in 2..Int.MAX_VALUE) { + // cant visualize reachedMinimum - yet + val newY = y - fellSoFar + if (newY < 0) return + + val blockOnto = ctx.get(destX, newY, destZ) + val unprotectedFallHeight = fellSoFar - (y - effStartHeight) // basic math + val costUpUntilThisBlock = + ctx.cost.WALK_OFF_ONE_BLOCK_COST + ctx.cost.N_BLOCK_FALL_COST[unprotectedFallHeight] + cost + + // This is probably a massive monkeypatch. Can't wait to suffer + if (!MovementHelper.canStandOnBlockState(ctx.bsa, destX, newY, destZ, blockOnto)) { + if (MovementHelper.isWotah(blockOnto)) { + if (MovementHelper.canStandOnBlock(ctx.bsa, destX, newY - 1, destZ)) { + res.y = newY - 1 + res.cost = costUpUntilThisBlock + return + } + return + } + + if (!MovementHelper.canWalkThroughBlockState(ctx.bsa, destX, newY, destZ, blockOnto)) { + return + } + continue + } + if (unprotectedFallHeight <= 11 && MovementHelper.isLadder(blockOnto)) { + // very cool logic baritone is built by smart ppl ong + cost += ctx.cost.N_BLOCK_FALL_COST[unprotectedFallHeight - 1] + ctx.cost.ONE_DOWN_LADDER_COST + effStartHeight = newY + continue + } + if (fellSoFar <= ctx.pathConfig.maxFallHeight) { + res.y = newY + res.cost = costUpUntilThisBlock + return + } + return + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/movements/MovementDiagonal.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/movements/MovementDiagonal.kt new file mode 100644 index 0000000..a881667 --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/movements/MovementDiagonal.kt @@ -0,0 +1,117 @@ +package dev.macrohq.swiftslayer.pathfinder.movement.movements + +import dev.macrohq.swiftslayer.SwiftSlayer +import dev.macrohq.swiftslayer.pathfinder.movement.CalculationContext +import dev.macrohq.swiftslayer.pathfinder.movement.Movement +import dev.macrohq.swiftslayer.pathfinder.movement.MovementHelper +import dev.macrohq.swiftslayer.pathfinder.movement.MovementResult +import net.minecraft.util.BlockPos +import kotlin.math.sqrt + +class MovementDiagonal(ss: SwiftSlayer, from: BlockPos, to: BlockPos) : Movement(ss, from, to) { + + override fun calculateCost(ctx: CalculationContext, res: MovementResult) { + calculateCost(ctx, source.x, source.y, source.z, dest.x, dest.z, res) + costs = res.cost + } + + companion object { + private val SQRT_2 = sqrt(2.0) + fun calculateCost(ctx: CalculationContext, x: Int, y: Int, z: Int, destX: Int, destZ: Int, res: MovementResult) { + res.set(destX, y, destZ) + cost(ctx, x, y, z, destX, destZ, res) + } + + // when walking from bottom to bottom slab if theres lava on the sides it'll still go. maybe add that? maybe not idk + private fun cost(ctx: CalculationContext, x: Int, y: Int, z: Int, destX: Int, destZ: Int, res: MovementResult) { + if (!MovementHelper.canWalkThrough(ctx.bsa, destX, y + 2, destZ)) return + + val destUpState = ctx.get(destX, y + 1, destZ) + val isSourceBottomSlab = MovementHelper.isBottomSlab(ctx.get(x, y, z)) + var isDestBottomSlab = false + var canAscend = false + var canDescend = false + if (!MovementHelper.canWalkThroughBlockState(ctx.bsa, destX, y + 1, destZ, destUpState)) { + canAscend = true + isDestBottomSlab = MovementHelper.isBottomSlab(destUpState) + if (!ctx.pathConfig.allowDiagonalAscend || (isSourceBottomSlab && !isDestBottomSlab) || MovementHelper.isLadder( + destUpState + ) || !MovementHelper.canWalkThrough(ctx.bsa, x, y + 3, z) || !MovementHelper.canStandOnBlockState( + ctx.bsa, + destX, + y + 1, + destZ, + destUpState + ) || !MovementHelper.canWalkThrough(ctx.bsa, destX, y + 3, destZ) + ) { + return + } + } else { + if (!MovementHelper.canStandOnBlock(ctx.bsa, destX, y, destZ)) { + canDescend = true + val newDestState = ctx.get(destX, y - 1, destZ) + if (!ctx.pathConfig.allowDiagonalDescend || !MovementHelper.canStandOnBlockState( + ctx.bsa, + destX, + y - 1, + destZ, + newDestState + ) || !MovementHelper.canWalkThrough(ctx.bsa, destX, y, destZ) + ) { + return + } + isDestBottomSlab = MovementHelper.isBottomSlab(newDestState) + } + } + var cost = ctx.cost.ONE_BLOCK_WALK_COST + + val sourceState = ctx.get(x, y, z) + if (MovementHelper.isLadder(sourceState)) { + return + } + + var water = false + if (MovementHelper.isWotah(ctx.get(x, y + 1, z))) { + if (canAscend) { + return + } + cost = ctx.cost.ONE_BLOCK_WALK_IN_WATER_COST * SQRT_2 + water = true + } + val ALOWState = ctx.get(x, y + 1, destZ) + val BLOWState = ctx.get(destX, y + 1, z) + + val ATOP = MovementHelper.canWalkThrough(ctx.bsa, x, y + 3, destZ) + val AMID = MovementHelper.canWalkThrough(ctx.bsa, x, y + 2, destZ) + val ALOW = MovementHelper.canWalkThroughBlockState(ctx.bsa, x, y + 1, destZ, ALOWState) + val BTOP = MovementHelper.canWalkThrough(ctx.bsa, destX, y + 3, z) + val BMID = MovementHelper.canWalkThrough(ctx.bsa, destX, y + 2, z) + val BLOW = MovementHelper.canWalkThroughBlockState(ctx.bsa, destX, y + 1, z, BLOWState) + + if (!(ATOP && AMID && ALOW && BTOP && BMID && BLOW)) { + return + } + if (canAscend) { + res.y = y + 1 + res.cost = cost * SQRT_2 + if (isSourceBottomSlab || !isDestBottomSlab) { + res.cost += ctx.cost.JUMP_ONE_BLOCK_COST + } else { + res.cost *= ctx.cost.SPRINT_MULTIPLIER + } + return + } + + if (!water) { + cost *= SQRT_2 * ctx.cost.SPRINT_MULTIPLIER + } + if (canDescend) { + if (isSourceBottomSlab == isDestBottomSlab) { + cost += ctx.cost.N_BLOCK_FALL_COST[1] + } + res.y = y - 1 + } + res.cost = cost + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/movements/MovementFall.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/movements/MovementFall.kt new file mode 100644 index 0000000..91b91fa --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/movements/MovementFall.kt @@ -0,0 +1,22 @@ +package dev.macrohq.swiftslayer.pathfinder.movement.movements + +import dev.macrohq.swiftslayer.SwiftSlayer +import dev.macrohq.swiftslayer.pathfinder.movement.CalculationContext +import dev.macrohq.swiftslayer.pathfinder.movement.Movement +import dev.macrohq.swiftslayer.pathfinder.movement.MovementResult +import net.minecraft.util.BlockPos +import kotlin.concurrent.fixedRateTimer + +class MovementFall(ss: SwiftSlayer, source: BlockPos, dest: BlockPos) : Movement(ss, source, dest) { + override fun calculateCost(ctx: CalculationContext, res: MovementResult) { + calculateCost(ctx, source.x, source.y, source.z, dest.x, dest.z, res) + costs = res.cost + } + + companion object{ + fun calculateCost(ctx: CalculationContext, x: Int, y: Int, z: Int, destX: Int, destZ: Int, res: MovementResult) { + res.set(destX, y - 1, destZ) + MovementDescend.calculateCost(ctx, x, y, z, destX, destZ, res) + } + } +} diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/movements/MovementTraverse.kt b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/movements/MovementTraverse.kt new file mode 100644 index 0000000..ab0df83 --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/pathfinder/movement/movements/MovementTraverse.kt @@ -0,0 +1,47 @@ +package dev.macrohq.swiftslayer.pathfinder.movement.movements + +import dev.macrohq.swiftslayer.SwiftSlayer +import dev.macrohq.swiftslayer.pathfinder.movement.CalculationContext +import dev.macrohq.swiftslayer.pathfinder.movement.Movement +import dev.macrohq.swiftslayer.pathfinder.movement.MovementHelper +import dev.macrohq.swiftslayer.pathfinder.movement.MovementResult +import net.minecraft.util.BlockPos + +class MovementTraverse(ss: SwiftSlayer, from: BlockPos, to: BlockPos) : Movement(ss, from, to) { + + override fun calculateCost(ctx: CalculationContext, res: MovementResult) { + calculateCost(ctx, source.x, source.y, source.z, dest.x, dest.z, res) + costs = res.cost + } + + companion object { + fun calculateCost(ctx: CalculationContext, x: Int, y: Int, z: Int, destX: Int, destZ: Int, res: MovementResult) { + res.set(destX, y, destZ) + cost(ctx, x, y, z, destX, destZ, res) + } + + private fun cost(ctx: CalculationContext, x: Int, y: Int, z: Int, destX: Int, destZ: Int, res: MovementResult) { + if (!MovementHelper.canStandOnBlock(ctx.bsa, destX, y, destZ)) return + + val destUpState = ctx.get(destX, y + 1, destZ) + if (!MovementHelper.canWalkThroughBlockState(ctx.bsa, destX, y + 1, destZ, destUpState) || + !MovementHelper.canWalkThrough(ctx.bsa, destX, y + 2, destZ) + ) return + + val srcUpState = ctx.get(x, y + 1, z) + + val isSourceTopWalkableLadder = MovementHelper.canWalkIntoLadder(srcUpState, x - destX, z - destZ) + val isDestTopWalkableLadder = MovementHelper.canWalkIntoLadder(destUpState, destX - x, destZ - z) + res.cost = ctx.cost.ONE_BLOCK_WALK_COST + if (MovementHelper.isLadder(destUpState) && !isDestTopWalkableLadder) { + res.cost = ctx.cost.INF_COST + return + } + if (MovementHelper.isLadder(srcUpState) && !isSourceTopWalkableLadder) { + res.cost = ctx.cost.INF_COST + return + } + res.cost = ctx.cost.ONE_BLOCK_SPRINT_COST + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/dev/macrohq/swiftslayer/util/accessor/IChunkProviderClient.kt b/src/main/kotlin/dev/macrohq/swiftslayer/util/accessor/IChunkProviderClient.kt new file mode 100644 index 0000000..743c410 --- /dev/null +++ b/src/main/kotlin/dev/macrohq/swiftslayer/util/accessor/IChunkProviderClient.kt @@ -0,0 +1,9 @@ +package dev.macrohq.swiftslayer.util.accessor + +import net.minecraft.util.LongHashMap; +import net.minecraft.world.chunk.Chunk; + +interface IChunkProviderClient { + fun chunkMapping(): LongHashMap + fun chunkListing(): List +} \ No newline at end of file diff --git a/src/main/resources/mixins.swiftslayer.json b/src/main/resources/mixins.swiftslayer.json index 66e737e..7923d42 100644 --- a/src/main/resources/mixins.swiftslayer.json +++ b/src/main/resources/mixins.swiftslayer.json @@ -3,7 +3,8 @@ "package": "dev.macrohq.swiftslayer.mixin", "client": [ "FMLHandshakeMessageMixin", - "MinecraftInvoker" + "MinecraftInvoker", + "world.MixinChunkProviderClient" ], "verbose": true, "mixins": [