From ab3471738baadad1056cbede6e9fd58a236b5a46 Mon Sep 17 00:00:00 2001 From: Avanatiker Date: Fri, 12 Mar 2021 17:32:12 +0100 Subject: [PATCH] [enhancement] Rewrote World Utils (#2100) Co-authored-by: Xiaro <62033805+Xiaro@users.noreply.github.com> --- .../client/module/modules/combat/AutoTrap.kt | 34 ++- .../client/module/modules/combat/BedAura.kt | 29 +- .../module/modules/combat/CrystalAura.kt | 11 +- .../module/modules/combat/CrystalBasePlace.kt | 23 +- .../client/module/modules/combat/Surround.kt | 24 +- .../client/module/modules/misc/AutoFish.kt | 4 +- .../module/modules/misc/AutoObsidian.kt | 20 +- .../client/module/modules/misc/AutoSpawner.kt | 9 +- .../client/module/modules/misc/AutoTool.kt | 38 ++- .../client/module/modules/misc/NoteBot.kt | 18 +- .../module/modules/movement/ElytraFlight.kt | 14 +- .../client/module/modules/player/NoFall.kt | 4 +- .../client/module/modules/player/Scaffold.kt | 21 +- .../org/kamiblue/client/util/WorldUtils.kt | 262 ---------------- .../org/kamiblue/client/util/items/Block.kt | 36 +++ .../org/kamiblue/client/util/items/Slot.kt | 4 + .../client/util/math/BoundingBoxUtils.kt | 33 +- .../kamiblue/client/util/math/VectorUtils.kt | 14 + .../org/kamiblue/client/util/world/Block.kt | 33 ++ .../org/kamiblue/client/util/world/Check.kt | 110 +++++++ .../kamiblue/client/util/world/Interact.kt | 286 ++++++++++++++++++ .../kamiblue/client/util/world/PlaceInfo.kt | 14 + 22 files changed, 656 insertions(+), 385 deletions(-) delete mode 100644 src/main/kotlin/org/kamiblue/client/util/WorldUtils.kt create mode 100644 src/main/kotlin/org/kamiblue/client/util/world/Block.kt create mode 100644 src/main/kotlin/org/kamiblue/client/util/world/Check.kt create mode 100644 src/main/kotlin/org/kamiblue/client/util/world/Interact.kt create mode 100644 src/main/kotlin/org/kamiblue/client/util/world/PlaceInfo.kt diff --git a/src/main/kotlin/org/kamiblue/client/module/modules/combat/AutoTrap.kt b/src/main/kotlin/org/kamiblue/client/module/modules/combat/AutoTrap.kt index 8f4f00f4..68400bb2 100644 --- a/src/main/kotlin/org/kamiblue/client/module/modules/combat/AutoTrap.kt +++ b/src/main/kotlin/org/kamiblue/client/module/modules/combat/AutoTrap.kt @@ -11,11 +11,10 @@ import org.kamiblue.client.manager.managers.CombatManager import org.kamiblue.client.manager.managers.PlayerPacketManager import org.kamiblue.client.module.Category import org.kamiblue.client.module.Module -import org.kamiblue.client.setting.settings.impl.primitive.BooleanSetting +import org.kamiblue.client.module.modules.combat.Surround.setting import org.kamiblue.client.util.* -import org.kamiblue.client.util.WorldUtils.buildStructure -import org.kamiblue.client.util.WorldUtils.getPlaceInfo -import org.kamiblue.client.util.WorldUtils.isPlaceable +import org.kamiblue.client.util.EntityUtils.flooredPosition +import org.kamiblue.client.util.combat.SurroundUtils import org.kamiblue.client.util.items.HotbarSlot import org.kamiblue.client.util.items.firstBlock import org.kamiblue.client.util.items.hotbarSlots @@ -24,6 +23,8 @@ import org.kamiblue.client.util.text.MessageSendHelper import org.kamiblue.client.util.threads.defaultScope import org.kamiblue.client.util.threads.isActiveOrFalse import org.kamiblue.client.util.threads.safeListener +import org.kamiblue.client.util.world.buildStructure +import org.kamiblue.client.util.world.isPlaceable import org.kamiblue.event.listener.listener import org.lwjgl.input.Keyboard @@ -38,6 +39,7 @@ internal object AutoTrap : Module( private val selfTrap = setting("Self Trap", false) private val bindSelfTrap = setting("Bind Self Trap", Bind()) private val autoDisable = setting("Auto Disable", true) + private val strictDirection by setting("Strict Direction", false) private val placeSpeed = setting("Places Per Tick", 4f, 0.25f..5f, 0.25f) private var job: Job? = null @@ -67,17 +69,14 @@ internal object AutoTrap : Module( listener { if (bindSelfTrap.value.isDown(Keyboard.getEventKey())) { selfTrap.value = !selfTrap.value - MessageSendHelper.sendChatMessage(selfTrap.toggleMsg()) } } } - private fun BooleanSetting.toggleMsg() = "$chatName Turned ${this.name} ${if (this.value) "&aon" else "&coff"}&f!" - private fun SafeClientEvent.canRun(): Boolean { (if (selfTrap.value) player else CombatManager.target)?.positionVector?.toBlockPos()?.let { for (offset in trapMode.value.offset) { - if (!isPlaceable(it.add(offset))) continue + if (!world.isPlaceable(it.add(offset))) continue return true } } @@ -97,14 +96,19 @@ internal object AutoTrap : Module( } private fun SafeClientEvent.runAutoTrap() = defaultScope.launch { - buildStructure(placeSpeed.value) { - if (isEnabled && CombatManager.isOnTopPriority(this@AutoTrap)) { - val center = (if (selfTrap.value) player else CombatManager.target)?.positionVector?.toBlockPos() - getPlaceInfo(center, trapMode.value.offset, it, 3) - } else { - null - } + val entity = if (selfTrap.value) player else CombatManager.target ?: return@launch + + buildStructure( + entity.flooredPosition, + SurroundUtils.surroundOffset, + placeSpeed.value, + 3, + 4.25f, + strictDirection + ) { + isEnabled && CombatManager.isOnTopPriority(AutoTrap) } + if (autoDisable.value) disable() } diff --git a/src/main/kotlin/org/kamiblue/client/module/modules/combat/BedAura.kt b/src/main/kotlin/org/kamiblue/client/module/modules/combat/BedAura.kt index d0595cc8..58a176b3 100644 --- a/src/main/kotlin/org/kamiblue/client/module/modules/combat/BedAura.kt +++ b/src/main/kotlin/org/kamiblue/client/module/modules/combat/BedAura.kt @@ -19,8 +19,6 @@ import org.kamiblue.client.manager.managers.PlayerPacketManager import org.kamiblue.client.module.Category import org.kamiblue.client.module.Module import org.kamiblue.client.util.* -import org.kamiblue.client.util.WorldUtils.getHitSide -import org.kamiblue.client.util.WorldUtils.rayTraceTo import org.kamiblue.client.util.combat.CrystalUtils.calcCrystalDamage import org.kamiblue.client.util.items.* import org.kamiblue.client.util.math.RotationUtils @@ -28,7 +26,9 @@ import org.kamiblue.client.util.math.RotationUtils.getRotationTo import org.kamiblue.client.util.math.Vec2f import org.kamiblue.client.util.math.VectorUtils import org.kamiblue.client.util.math.VectorUtils.distanceTo +import org.kamiblue.client.util.math.VectorUtils.toVec3d import org.kamiblue.client.util.threads.safeListener +import org.kamiblue.client.util.world.* import java.util.* import kotlin.collections.HashMap @@ -79,8 +79,8 @@ internal object BedAura : Module( if (!CombatManager.isOnTopPriority(this@BedAura) || it.packet !is CPacketPlayer || state == State.NONE || CombatSetting.pause) return@safeListener val hand = getBedHand() ?: EnumHand.MAIN_HAND - val facing = if (state == State.PLACE) EnumFacing.UP else getHitSide(clickPos) - val hitVecOffset = WorldUtils.getHitVecOffset(facing) + val facing = if (state == State.PLACE) EnumFacing.UP else getClosestVisibleSide(clickPos) ?: EnumFacing.UP + val hitVecOffset = getHitVecOffset(facing) val packet = CPacketPlayerTryUseItemOnBlock(clickPos, facing, hand, hitVecOffset.x.toFloat(), hitVecOffset.y.toFloat(), hitVecOffset.z.toFloat()) connection.sendPacket(packet) @@ -126,18 +126,25 @@ internal object BedAura : Module( val cacheMap = CombatManager.target?.let { val posList = VectorUtils.getBlockPosInSphere(player.getPositionEyes(1f), range.value) val damagePosMap = HashMap, BlockPos>() + val eyePos = player.getPositionEyes(1.0f) + for (pos in posList) { val dist = player.distanceTo(pos) - if (rayTraceTo(pos) == null && dist > wallRange.value) continue - val topSideVec = Vec3d(pos).add(0.5, 1.0, 0.5) + + if (!world.isVisible(pos) && dist > wallRange.value) continue + + val topSideVec = pos.toVec3d(0.5, 1.0, 0.5) val rotation = getRotationTo(topSideVec) val facing = EnumFacing.fromAngle(rotation.x.toDouble()) if (!canPlaceBed(pos)) continue + val targetDamage = calcCrystalDamage(pos.offset(facing), it) val selfDamage = calcCrystalDamage(pos.offset(facing), player) - if (targetDamage < minDamage.value && (suicideMode.value || selfDamage > maxSelfDamage.value)) + if (targetDamage < minDamage.value && (suicideMode.value || selfDamage > maxSelfDamage.value)) { damagePosMap[Pair(targetDamage, selfDamage)] = pos + } } + damagePosMap } placeMap.clear() @@ -151,8 +158,8 @@ internal object BedAura : Module( return (!ignoreSecondBaseBlock.value || world.getBlockState(bedPos2.down()).isSideSolid(world, bedPos2.down(), EnumFacing.UP)) && !isFire(bedPos1) && !isFire(bedPos2) - && world.getBlockState(bedPos1).material.isReplaceable - && (!ignoreSecondBaseBlock.value || world.getBlockState(bedPos2).material.isReplaceable) + && world.getBlockState(bedPos1).isReplaceable + && (!ignoreSecondBaseBlock.value || world.getBlockState(bedPos2).isReplaceable) } private fun SafeClientEvent.isFire(pos: BlockPos): Boolean { @@ -165,9 +172,11 @@ internal object BedAura : Module( for (tileEntity in world.loadedTileEntityList) { if (tileEntity !is TileEntityBed) continue if (!tileEntity.isHeadPiece) continue + val dist = player.distanceTo(tileEntity.pos).toFloat() if (dist > range.value) continue - if (rayTraceTo(tileEntity.pos) == null && dist > wallRange.value) continue + if (!world.isVisible(tileEntity.pos) && dist > wallRange.value) continue + damagePosMap[dist] = tileEntity.pos } damagePosMap diff --git a/src/main/kotlin/org/kamiblue/client/module/modules/combat/CrystalAura.kt b/src/main/kotlin/org/kamiblue/client/module/modules/combat/CrystalAura.kt index b88c6e0a..077f7507 100644 --- a/src/main/kotlin/org/kamiblue/client/module/modules/combat/CrystalAura.kt +++ b/src/main/kotlin/org/kamiblue/client/module/modules/combat/CrystalAura.kt @@ -12,6 +12,7 @@ import net.minecraft.network.play.client.CPacketPlayerTryUseItemOnBlock import net.minecraft.network.play.client.CPacketUseEntity import net.minecraft.network.play.server.SPacketSoundEffect import net.minecraft.network.play.server.SPacketSpawnObject +import net.minecraft.util.EnumFacing import net.minecraft.util.EnumHand import net.minecraft.util.SoundCategory import net.minecraft.util.math.AxisAlignedBB @@ -31,7 +32,6 @@ import org.kamiblue.client.mixin.extension.packetAction import org.kamiblue.client.module.Category import org.kamiblue.client.module.Module import org.kamiblue.client.util.* -import org.kamiblue.client.util.WorldUtils.getHitSide import org.kamiblue.client.util.combat.CombatUtils.equipBestWeapon import org.kamiblue.client.util.combat.CombatUtils.scaledHealth import org.kamiblue.client.util.combat.CrystalUtils.canPlaceCollide @@ -48,6 +48,7 @@ import org.kamiblue.client.util.math.VectorUtils.toVec3dCenter import org.kamiblue.client.util.text.MessageSendHelper import org.kamiblue.client.util.threads.runSafeR import org.kamiblue.client.util.threads.safeListener +import org.kamiblue.client.util.world.getClosestVisibleSide import org.kamiblue.commons.extension.synchronized import org.kamiblue.commons.interfaces.DisplayEnum import org.kamiblue.event.listener.listener @@ -317,8 +318,10 @@ internal object CrystalAura : Module( } } - private fun SafeClientEvent.getPlacePacket(pos: BlockPos, hand: EnumHand) = - CPacketPlayerTryUseItemOnBlock(pos, getHitSide(pos), hand, 0.5f, placeOffset, 0.5f) + private fun SafeClientEvent.getPlacePacket(pos: BlockPos, hand: EnumHand): CPacketPlayerTryUseItemOnBlock { + val side = getClosestVisibleSide(pos) ?: EnumFacing.UP + return CPacketPlayerTryUseItemOnBlock(pos, side, hand, 0.5f, placeOffset, 0.5f) + } private fun SafeClientEvent.packetExplode(entityID: Int, pos: BlockPos, vec3d: Vec3d) { if (!preExplode()) return @@ -564,4 +567,4 @@ internal object CrystalAura : Module( lastLookAt = CombatManager.target?.positionVector ?: Vec3d.ZERO } /* End of rotation */ -} \ No newline at end of file +} diff --git a/src/main/kotlin/org/kamiblue/client/module/modules/combat/CrystalBasePlace.kt b/src/main/kotlin/org/kamiblue/client/module/modules/combat/CrystalBasePlace.kt index e6d3b30c..2710ffb6 100644 --- a/src/main/kotlin/org/kamiblue/client/module/modules/combat/CrystalBasePlace.kt +++ b/src/main/kotlin/org/kamiblue/client/module/modules/combat/CrystalBasePlace.kt @@ -4,7 +4,6 @@ import net.minecraft.entity.EntityLivingBase import net.minecraft.init.Blocks import net.minecraft.item.ItemStack import net.minecraft.network.play.client.CPacketPlayerTryUseItemOnBlock -import net.minecraft.util.EnumFacing import net.minecraft.util.EnumHand import net.minecraft.util.math.AxisAlignedBB import net.minecraft.util.math.BlockPos @@ -18,9 +17,6 @@ import org.kamiblue.client.manager.managers.PlayerPacketManager import org.kamiblue.client.module.Category import org.kamiblue.client.module.Module import org.kamiblue.client.util.* -import org.kamiblue.client.util.WorldUtils.getNeighbour -import org.kamiblue.client.util.WorldUtils.hasNeighbour -import org.kamiblue.client.util.WorldUtils.isPlaceable import org.kamiblue.client.util.color.ColorHolder import org.kamiblue.client.util.combat.CrystalUtils.calcCrystalDamage import org.kamiblue.client.util.graphics.ESPRenderer @@ -31,6 +27,10 @@ import org.kamiblue.client.util.math.RotationUtils.getRotationTo import org.kamiblue.client.util.math.VectorUtils import org.kamiblue.client.util.math.VectorUtils.distanceTo import org.kamiblue.client.util.threads.safeListener +import org.kamiblue.client.util.world.PlaceInfo +import org.kamiblue.client.util.world.getNeighbour +import org.kamiblue.client.util.world.hasNeighbour +import org.kamiblue.client.util.world.isPlaceable import org.kamiblue.event.listener.listener import org.lwjgl.input.Keyboard import java.util.* @@ -117,13 +117,14 @@ internal object CrystalBasePlace : Module( private fun SafeClientEvent.prePlace(entity: EntityLivingBase) { if (rotationTo != null || !timer.tick((delay.value * 50.0f).toLong(), false)) return val placeInfo = getPlaceInfo(entity) + if (placeInfo != null) { - val offset = WorldUtils.getHitVecOffset(placeInfo.first) - val hitVec = Vec3d(placeInfo.second).add(offset) - rotationTo = hitVec - placePacket = CPacketPlayerTryUseItemOnBlock(placeInfo.second, placeInfo.first, EnumHand.MAIN_HAND, offset.x.toFloat(), offset.y.toFloat(), offset.z.toFloat()) + rotationTo = placeInfo.hitVec + placePacket = CPacketPlayerTryUseItemOnBlock(placeInfo.pos, placeInfo.side, EnumHand.MAIN_HAND, placeInfo.hitVecOffset.x.toFloat(), placeInfo.hitVecOffset.y.toFloat(), placeInfo.hitVecOffset.z.toFloat()) + renderer.clear() - renderer.add(placeInfo.second.offset(placeInfo.first), ColorHolder(255, 255, 255)) + renderer.add(placeInfo.placedPos, ColorHolder(255, 255, 255)) + inactiveTicks = 0 timer.reset() } else { @@ -131,7 +132,7 @@ internal object CrystalBasePlace : Module( } } - private fun SafeClientEvent.getPlaceInfo(entity: EntityLivingBase): Pair? { + private fun SafeClientEvent.getPlaceInfo(entity: EntityLivingBase): PlaceInfo? { val cacheMap = TreeMap(compareByDescending { it }) val prediction = CombatSetting.getPrediction(entity) val eyePos = player.getPositionEyes(1.0f) @@ -143,7 +144,7 @@ internal object CrystalBasePlace : Module( for (pos in posList) { // Placeable check - if (!isPlaceable(pos, false)) continue + if (!world.isPlaceable(pos)) continue // Neighbour blocks check if (!hasNeighbour(pos)) continue diff --git a/src/main/kotlin/org/kamiblue/client/module/modules/combat/Surround.kt b/src/main/kotlin/org/kamiblue/client/module/modules/combat/Surround.kt index 2b2954f0..463e37a5 100644 --- a/src/main/kotlin/org/kamiblue/client/module/modules/combat/Surround.kt +++ b/src/main/kotlin/org/kamiblue/client/module/modules/combat/Surround.kt @@ -12,11 +12,9 @@ import org.kamiblue.client.module.Category import org.kamiblue.client.module.Module import org.kamiblue.client.module.modules.movement.Strafe import org.kamiblue.client.util.* +import org.kamiblue.client.util.EntityUtils.flooredPosition import org.kamiblue.client.util.MovementUtils.centerPlayer import org.kamiblue.client.util.MovementUtils.speed -import org.kamiblue.client.util.WorldUtils.buildStructure -import org.kamiblue.client.util.WorldUtils.getPlaceInfo -import org.kamiblue.client.util.WorldUtils.isPlaceable import org.kamiblue.client.util.combat.SurroundUtils import org.kamiblue.client.util.combat.SurroundUtils.checkHole import org.kamiblue.client.util.items.firstBlock @@ -26,6 +24,8 @@ import org.kamiblue.client.util.text.MessageSendHelper import org.kamiblue.client.util.threads.defaultScope import org.kamiblue.client.util.threads.isActiveOrFalse import org.kamiblue.client.util.threads.safeListener +import org.kamiblue.client.util.world.buildStructure +import org.kamiblue.client.util.world.isPlaceable @CombatManager.CombatModule internal object Surround : Module( @@ -36,6 +36,7 @@ internal object Surround : Module( ) { private val placeSpeed by setting("Places Per Tick", 4f, 0.25f..5f, 0.25f) private val disableStrafe by setting("Disable Strafe", true) + private val strictDirection by setting("Strict Direction", false) private val autoDisable by setting("Auto Disable", AutoDisableMode.OUT_OF_HOLE) private val outOfHoleTimeout by setting("Out Of Hole Timeout", 10, 1..50, 5, { autoDisable == AutoDisableMode.OUT_OF_HOLE }, description = "Delay before disabling Surround when you are out of hole, in ticks") private val enableInHole = setting("Enable In Hole", false) @@ -155,19 +156,22 @@ internal object Surround : Module( private fun SafeClientEvent.canRun(): Boolean { val playerPos = player.positionVector.toBlockPos() return SurroundUtils.surroundOffset.any { - isPlaceable(playerPos.add(it), true) + world.isPlaceable(playerPos.add(it), true) } } private fun SafeClientEvent.runSurround() = defaultScope.launch { spoofHotbar() - buildStructure(placeSpeed) { - if (isEnabled && CombatManager.isOnTopPriority(this@Surround)) { - getPlaceInfo(player.positionVector.toBlockPos(), SurroundUtils.surroundOffset, it, 2) - } else { - null - } + buildStructure( + player.flooredPosition, + SurroundUtils.surroundOffset, + placeSpeed, + 2, + 4.25f, + strictDirection + ) { + isEnabled && CombatManager.isOnTopPriority(Surround) } } diff --git a/src/main/kotlin/org/kamiblue/client/module/modules/misc/AutoFish.kt b/src/main/kotlin/org/kamiblue/client/module/modules/misc/AutoFish.kt index 8d7209f6..34458bb4 100644 --- a/src/main/kotlin/org/kamiblue/client/module/modules/misc/AutoFish.kt +++ b/src/main/kotlin/org/kamiblue/client/module/modules/misc/AutoFish.kt @@ -9,8 +9,8 @@ import org.kamiblue.client.mixin.extension.rightClickMouse import org.kamiblue.client.module.Category import org.kamiblue.client.module.Module import org.kamiblue.client.util.TickTimer -import org.kamiblue.client.util.WorldUtils.isWater import org.kamiblue.client.util.threads.safeListener +import org.kamiblue.client.util.world.isWater import java.lang.Math.random import kotlin.math.abs @@ -88,7 +88,7 @@ internal object AutoFish : Module( private fun SafeClientEvent.isOnWater(): Boolean { if (player.fishEntity?.isAirBorne != false) return false val pos = player.fishEntity!!.position - return isWater(pos) || isWater(pos.down()) + return world.isWater(pos) || world.isWater(pos.down()) } private fun SafeClientEvent.isSplash(packet: SPacketSoundEffect): Boolean { diff --git a/src/main/kotlin/org/kamiblue/client/module/modules/misc/AutoObsidian.kt b/src/main/kotlin/org/kamiblue/client/module/modules/misc/AutoObsidian.kt index e4dafe29..98f33deb 100644 --- a/src/main/kotlin/org/kamiblue/client/module/modules/misc/AutoObsidian.kt +++ b/src/main/kotlin/org/kamiblue/client/module/modules/misc/AutoObsidian.kt @@ -40,9 +40,6 @@ import org.kamiblue.client.process.PauseProcess import org.kamiblue.client.util.* import org.kamiblue.client.util.EntityUtils.getDroppedItem import org.kamiblue.client.util.EntityUtils.getDroppedItems -import org.kamiblue.client.util.WorldUtils.getNeighbour -import org.kamiblue.client.util.WorldUtils.isPlaceable -import org.kamiblue.client.util.WorldUtils.placeBlock import org.kamiblue.client.util.color.ColorHolder import org.kamiblue.client.util.graphics.ESPRenderer import org.kamiblue.client.util.items.* @@ -51,6 +48,7 @@ import org.kamiblue.client.util.math.VectorUtils import org.kamiblue.client.util.math.VectorUtils.toVec3dCenter import org.kamiblue.client.util.text.MessageSendHelper import org.kamiblue.client.util.threads.* +import org.kamiblue.client.util.world.* import org.kamiblue.commons.interfaces.DisplayEnum import org.kamiblue.event.listener.asyncListener import org.kamiblue.event.listener.listener @@ -294,9 +292,9 @@ internal object AutoObsidian : Module( } private fun SafeClientEvent.isPositionValid(pos: BlockPos, blockState: IBlockState, eyePos: Vec3d) = - !world.getBlockState(pos.down()).material.isReplaceable + !world.getBlockState(pos.down()).isReplaceable && (blockState.block.let { it == Blocks.ENDER_CHEST || it is BlockShulkerBox } - || isPlaceable(pos)) + || world.isPlaceable(pos)) && world.isAirBlock(pos.up()) && world.rayTraceBlocks(eyePos, pos.toVec3dCenter())?.let { it.typeOfHit == RayTraceResult.Type.MISS } ?: true @@ -530,9 +528,9 @@ internal object AutoObsidian : Module( val normalizedVec = diff.normalize() val side = EnumFacing.getFacingFromVector(normalizedVec.x.toFloat(), normalizedVec.y.toFloat(), normalizedVec.z.toFloat()) - val hitVecOffset = WorldUtils.getHitVecOffset(side) + val hitVecOffset = getHitVecOffset(side) - lastHitVec = WorldUtils.getHitVec(pos, side) + lastHitVec = getHitVec(pos, side) rotateTimer.reset() if (shulkerOpenTimer.tick(50)) { @@ -548,16 +546,16 @@ internal object AutoObsidian : Module( } private fun SafeClientEvent.placeBlock(pos: BlockPos) { - val pair = getNeighbour(pos, 1, 6.5f) + val placeInfo = getNeighbour(pos, 1, 6.5f) ?: run { MessageSendHelper.sendChatMessage("$chatName Can't find neighbour block") return } - lastHitVec = WorldUtils.getHitVec(pair.second, pair.first) + lastHitVec = placeInfo.hitVec rotateTimer.reset() - val isBlackListed = WorldUtils.blackList.contains(world.getBlockState(pair.second).block) + val isBlackListed = world.getBlockState(placeInfo.pos).isBlacklisted if (isBlackListed) { connection.sendPacket(CPacketEntityAction(player, CPacketEntityAction.Action.START_SNEAKING)) @@ -566,7 +564,7 @@ internal object AutoObsidian : Module( defaultScope.launch { delay(20L) onMainThreadSafe { - placeBlock(pair.second, pair.first) + placeBlock(placeInfo) } if (isBlackListed) { diff --git a/src/main/kotlin/org/kamiblue/client/module/modules/misc/AutoSpawner.kt b/src/main/kotlin/org/kamiblue/client/module/modules/misc/AutoSpawner.kt index ea956a3b..36d3d64a 100644 --- a/src/main/kotlin/org/kamiblue/client/module/modules/misc/AutoSpawner.kt +++ b/src/main/kotlin/org/kamiblue/client/module/modules/misc/AutoSpawner.kt @@ -22,6 +22,8 @@ import org.kamiblue.client.util.items.swapToSlot import org.kamiblue.client.util.math.VectorUtils import org.kamiblue.client.util.text.MessageSendHelper.sendChatMessage import org.kamiblue.client.util.threads.safeListener +import org.kamiblue.client.util.world.isBlacklisted +import org.kamiblue.client.util.world.isReplaceable /** * TODO: Rewrite @@ -307,8 +309,9 @@ internal object AutoSpawner : Module( val neighbour = pos.offset(side) val opposite = side.opposite val hitVec = Vec3d(neighbour).add(0.5, 0.5, 0.5).add(Vec3d(opposite.directionVec).scale(0.5)) - val neighbourBlock = world.getBlockState(neighbour).block - if (!isSneaking && (WorldUtils.blackList.contains(neighbourBlock) || WorldUtils.shulkerList.contains(neighbourBlock))) { + val blockState = world.getBlockState(neighbour) + + if (!isSneaking && blockState.isBlacklisted) { connection.sendPacket(CPacketEntityAction(player, CPacketEntityAction.Action.START_SNEAKING)) isSneaking = true } @@ -323,7 +326,7 @@ internal object AutoSpawner : Module( continue } val blockState = world.getBlockState(neighbour) - if (!blockState.material.isReplaceable && blockState.block !is BlockTallGrass && blockState.block !is BlockDeadBush) { + if (!blockState.isReplaceable && blockState.block !is BlockTallGrass && blockState.block !is BlockDeadBush) { return side } } diff --git a/src/main/kotlin/org/kamiblue/client/module/modules/misc/AutoTool.kt b/src/main/kotlin/org/kamiblue/client/module/modules/misc/AutoTool.kt index 5635c559..8e231ee4 100644 --- a/src/main/kotlin/org/kamiblue/client/module/modules/misc/AutoTool.kt +++ b/src/main/kotlin/org/kamiblue/client/module/modules/misc/AutoTool.kt @@ -15,8 +15,8 @@ import org.kamiblue.client.util.combat.CombatUtils import org.kamiblue.client.util.combat.CombatUtils.equipBestWeapon import org.kamiblue.client.util.items.swapToSlot import org.kamiblue.client.util.threads.safeListener +import org.kamiblue.client.util.items.hotbarSlots import org.lwjgl.input.Mouse -import kotlin.math.pow internal object AutoTool : Module( name = "AutoTool", @@ -58,30 +58,26 @@ internal object AutoTool : Module( } } - fun SafeClientEvent.equipBestTool(blockState: IBlockState) { - var bestSlot = -1 - var max = 0.0 + private fun SafeClientEvent.equipBestTool(blockState: IBlockState) { + player.hotbarSlots.maxByOrNull { + val stack = it.stack + if (stack.isEmpty) { + 0.0f + } else { + var speed = stack.getDestroySpeed(blockState) - for (i in 0..8) { - val stack = player.inventory.getStackInSlot(i) - if (stack.isEmpty) continue - var speed = stack.getDestroySpeed(blockState) - var eff: Int - - if (speed > 1) { - speed += ( - if (EnchantmentHelper.getEnchantmentLevel(Enchantments.EFFICIENCY, stack).also { eff = it } > 0.0) eff.toDouble().pow(2.0) + 1 - else 0.0 - ).toFloat() - if (speed > max) { - max = speed.toDouble() - bestSlot = i + if (speed > 1.0f) { + val efficiency = EnchantmentHelper.getEnchantmentLevel(Enchantments.EFFICIENCY, stack) + if (efficiency > 0) { + speed += efficiency * efficiency + 1.0f + } } - } + speed + } + }?.let { + swapToSlot(it) } - - if (bestSlot != -1) swapToSlot(bestSlot) } init { diff --git a/src/main/kotlin/org/kamiblue/client/module/modules/misc/NoteBot.kt b/src/main/kotlin/org/kamiblue/client/module/modules/misc/NoteBot.kt index b9952a34..5b1d305d 100644 --- a/src/main/kotlin/org/kamiblue/client/module/modules/misc/NoteBot.kt +++ b/src/main/kotlin/org/kamiblue/client/module/modules/misc/NoteBot.kt @@ -25,6 +25,7 @@ import org.kamiblue.client.util.threads.defaultScope import org.kamiblue.client.util.threads.runSafe import org.kamiblue.client.util.threads.runSafeR import org.kamiblue.client.util.threads.safeListener +import org.kamiblue.client.util.world.getMiningSide import org.kamiblue.event.listener.listener import java.io.DataInputStream import java.io.File @@ -383,23 +384,12 @@ internal object NoteBot : Module( } private fun SafeClientEvent.clickBlock(pos: BlockPos) { - val side = getExposedSide(pos) - connection.apply { - sendPacket(CPacketPlayerDigging(CPacketPlayerDigging.Action.START_DESTROY_BLOCK, pos, side)) - sendPacket(CPacketPlayerDigging(CPacketPlayerDigging.Action.ABORT_DESTROY_BLOCK, pos, side)) - } + val side = getMiningSide(pos) ?: EnumFacing.UP + connection.sendPacket(CPacketPlayerDigging(CPacketPlayerDigging.Action.START_DESTROY_BLOCK, pos, side)) + connection.sendPacket(CPacketPlayerDigging(CPacketPlayerDigging.Action.ABORT_DESTROY_BLOCK, pos, side)) player.swingArm(EnumHand.MAIN_HAND) } - private fun SafeClientEvent.getExposedSide(pos: BlockPos): EnumFacing { - val playerPos = player.positionVector - - return EnumFacing.values() - .filter { world.isAirBlock(pos.offset(it)) } - .minByOrNull { WorldUtils.getHitVec(pos, it).distanceTo(playerPos) } - ?: EnumFacing.UP - } - private class Note(val note: Int, val track: Int) { val noteBlockNote: Int get() { diff --git a/src/main/kotlin/org/kamiblue/client/module/modules/movement/ElytraFlight.kt b/src/main/kotlin/org/kamiblue/client/module/modules/movement/ElytraFlight.kt index 1f086c85..a8307330 100644 --- a/src/main/kotlin/org/kamiblue/client/module/modules/movement/ElytraFlight.kt +++ b/src/main/kotlin/org/kamiblue/client/module/modules/movement/ElytraFlight.kt @@ -18,12 +18,12 @@ import org.kamiblue.client.module.Module import org.kamiblue.client.module.modules.player.LagNotifier import org.kamiblue.client.util.MovementUtils.calcMoveYaw import org.kamiblue.client.util.MovementUtils.speed -import org.kamiblue.client.util.WorldUtils.getGroundPos -import org.kamiblue.client.util.WorldUtils.isLiquidBelow import org.kamiblue.client.util.math.Vec2f import org.kamiblue.client.util.text.MessageSendHelper.sendChatMessage import org.kamiblue.client.util.threads.runSafe import org.kamiblue.client.util.threads.safeListener +import org.kamiblue.client.util.world.getGroundPos +import org.kamiblue.client.util.world.isLiquidBelow import org.kamiblue.commons.extension.toRadian import kotlin.math.* @@ -242,7 +242,7 @@ internal object ElytraFlight : Module( autoLanding = false return } - isLiquidBelow() -> { + world.isLiquidBelow(player) -> { sendChatMessage("$chatName Liquid below, disabling.") autoLanding = false } @@ -256,9 +256,9 @@ internal object ElytraFlight : Module( } else -> { when { - player.posY > getGroundPos().y + 1.0 -> { + player.posY > world.getGroundPos(player).y + 1.0 -> { mc.timer.tickLength = 50.0f - player.motionY = max(min(-(player.posY - getGroundPos().y) / 20.0, -0.5), -5.0) + player.motionY = max(min(-(player.posY - world.getGroundPos(player).y) / 20.0, -0.5), -5.0) } player.motionY != 0.0 -> { /* Pause falling to reset fall distance */ if (!mc.isSingleplayer) mc.timer.tickLength = 200.0f /* Use timer to pause longer */ @@ -279,10 +279,10 @@ internal object ElytraFlight : Module( /* Pause Takeoff if server is lagging, player is in water/lava, or player is on ground */ val timerSpeed = if (highPingOptimize) 400.0f else 200.0f val height = if (highPingOptimize) 0.0f else minTakeoffHeight - val closeToGround = player.posY <= getGroundPos().y + height && !wasInLiquid && !mc.isSingleplayer + val closeToGround = player.posY <= world.getGroundPos(player).y + height && !wasInLiquid && !mc.isSingleplayer if (!easyTakeOff || (LagNotifier.paused && LagNotifier.pauseTakeoff) || player.onGround) { - if (LagNotifier.paused && LagNotifier.pauseTakeoff && player.posY - getGroundPos().y > 4.0f) holdPlayer(event) /* Holds player in the air if server is lagging and the distance is enough for taking fall damage */ + if (LagNotifier.paused && LagNotifier.pauseTakeoff && player.posY - world.getGroundPos(player).y > 4.0f) holdPlayer(event) /* Holds player in the air if server is lagging and the distance is enough for taking fall damage */ reset(player.onGround) return } diff --git a/src/main/kotlin/org/kamiblue/client/module/modules/player/NoFall.kt b/src/main/kotlin/org/kamiblue/client/module/modules/player/NoFall.kt index fab13db9..ddfaa78b 100644 --- a/src/main/kotlin/org/kamiblue/client/module/modules/player/NoFall.kt +++ b/src/main/kotlin/org/kamiblue/client/module/modules/player/NoFall.kt @@ -17,9 +17,9 @@ import org.kamiblue.client.mixin.extension.onGround import org.kamiblue.client.module.Category import org.kamiblue.client.module.Module import org.kamiblue.client.util.EntityUtils -import org.kamiblue.client.util.WorldUtils.getGroundPos import org.kamiblue.client.util.text.MessageSendHelper import org.kamiblue.client.util.threads.safeListener +import org.kamiblue.client.util.world.getGroundPos internal object NoFall : Module( name = "NoFall", @@ -64,7 +64,7 @@ internal object NoFall : Module( } } - private fun SafeClientEvent.fallDistCheck() = (!voidOnly.value && player.fallDistance >= distance.value) || getGroundPos().y == -69420.0 + private fun SafeClientEvent.fallDistCheck() = (!voidOnly.value && player.fallDistance >= distance.value) || world.getGroundPos(player).y == -69420.0 // TODO: This really needs a rewrite to spoof placing and the such instead of manual rotations private fun SafeClientEvent.fallMode() { diff --git a/src/main/kotlin/org/kamiblue/client/module/modules/player/Scaffold.kt b/src/main/kotlin/org/kamiblue/client/module/modules/player/Scaffold.kt index 3b9df4bf..a02cea52 100644 --- a/src/main/kotlin/org/kamiblue/client/module/modules/player/Scaffold.kt +++ b/src/main/kotlin/org/kamiblue/client/module/modules/player/Scaffold.kt @@ -21,8 +21,6 @@ import org.kamiblue.client.module.Category import org.kamiblue.client.module.Module import org.kamiblue.client.util.* import org.kamiblue.client.util.EntityUtils.prevPosVector -import org.kamiblue.client.util.WorldUtils.getNeighbour -import org.kamiblue.client.util.WorldUtils.placeBlock import org.kamiblue.client.util.items.HotbarSlot import org.kamiblue.client.util.items.firstItem import org.kamiblue.client.util.items.hotbarSlots @@ -33,6 +31,9 @@ import org.kamiblue.client.util.math.VectorUtils.toBlockPos import org.kamiblue.client.util.threads.defaultScope import org.kamiblue.client.util.threads.onMainThreadSafe import org.kamiblue.client.util.threads.safeListener +import org.kamiblue.client.util.world.PlaceInfo +import org.kamiblue.client.util.world.getNeighbour +import org.kamiblue.client.util.world.placeBlock import org.kamiblue.event.listener.listener import kotlin.math.floor import kotlin.math.roundToInt @@ -51,11 +52,12 @@ internal object Scaffold : Module( private val spoofHotbar by setting("Spoof Hotbar", true) val safeWalk by setting("Safe Walk", true) private val sneak by setting("Sneak", true) + private val strictDirection by setting("Strict Direction", false) private val delay by setting("Delay", 2, 1..10, 1) private val maxRange by setting("Max Range", 1, 0..3, 1) private var lastRotation = Vec2f.ZERO - private var placeInfo: Pair? = null + private var placeInfo: PlaceInfo? = null private var inactiveTicks = 69 private val placeTimer = TickTimer(TimeUnit.TICKS) @@ -99,14 +101,13 @@ internal object Scaffold : Module( inactiveTicks++ placeInfo = calcNextPos()?.let { - getNeighbour(it, 1, sides = arrayOf(EnumFacing.DOWN)) - ?: getNeighbour(it, 3, sides = EnumFacing.HORIZONTALS) + getNeighbour(it, 1, visibleSideCheck = strictDirection, sides = arrayOf(EnumFacing.DOWN)) + ?: getNeighbour(it, 3, visibleSideCheck = strictDirection, sides = EnumFacing.HORIZONTALS) } placeInfo?.let { - val hitVec = WorldUtils.getHitVec(it.second, it.first) - lastRotation = getRotationTo(hitVec) - swapAndPlace(it.second, it.first) + lastRotation = getRotationTo(it.hitVec) + swapAndPlace(it) } if (inactiveTicks > 5) { @@ -144,7 +145,7 @@ internal object Scaffold : Module( private fun roundToRange(value: Double) = (value * 2.5 * maxRange).roundToInt().coerceAtMost(maxRange) - private fun SafeClientEvent.swapAndPlace(pos: BlockPos, side: EnumFacing) { + private fun SafeClientEvent.swapAndPlace(placeInfo: PlaceInfo) { getBlockSlot()?.let { slot -> if (spoofHotbar) PlayerPacketManager.spoofHotbar(slot.hotbarSlot) else swapToSlot(slot) @@ -161,7 +162,7 @@ internal object Scaffold : Module( } delay(5) onMainThreadSafe { - placeBlock(pos, side) + placeBlock(placeInfo) if (shouldSneak) { connection.sendPacket(CPacketEntityAction(player, CPacketEntityAction.Action.STOP_SNEAKING)) } diff --git a/src/main/kotlin/org/kamiblue/client/util/WorldUtils.kt b/src/main/kotlin/org/kamiblue/client/util/WorldUtils.kt deleted file mode 100644 index 136c0698..00000000 --- a/src/main/kotlin/org/kamiblue/client/util/WorldUtils.kt +++ /dev/null @@ -1,262 +0,0 @@ -package org.kamiblue.client.util - -import kotlinx.coroutines.delay -import net.minecraft.entity.Entity -import net.minecraft.init.Blocks -import net.minecraft.item.ItemBlock -import net.minecraft.network.play.client.CPacketPlayer -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 net.minecraft.util.math.RayTraceResult -import net.minecraft.util.math.Vec3d -import org.kamiblue.client.event.SafeClientEvent -import org.kamiblue.client.manager.managers.PlayerPacketManager -import org.kamiblue.client.util.math.RotationUtils.getRotationTo -import org.kamiblue.client.util.math.corners -import org.kamiblue.client.util.threads.runSafeSuspend -import org.kamiblue.commons.extension.add -import kotlin.math.floor - -object WorldUtils { - val blackList = linkedSetOf( - Blocks.ENDER_CHEST, - Blocks.CHEST, - Blocks.TRAPPED_CHEST, - Blocks.CRAFTING_TABLE, - Blocks.ANVIL, - Blocks.BREWING_STAND, - Blocks.HOPPER, - Blocks.DROPPER, - Blocks.DISPENSER, - Blocks.TRAPDOOR, - Blocks.ENCHANTING_TABLE - ) - - val shulkerList = linkedSetOf( - Blocks.WHITE_SHULKER_BOX, - Blocks.ORANGE_SHULKER_BOX, - Blocks.MAGENTA_SHULKER_BOX, - Blocks.LIGHT_BLUE_SHULKER_BOX, - Blocks.YELLOW_SHULKER_BOX, - Blocks.LIME_SHULKER_BOX, - Blocks.PINK_SHULKER_BOX, - Blocks.GRAY_SHULKER_BOX, - Blocks.SILVER_SHULKER_BOX, - Blocks.CYAN_SHULKER_BOX, - Blocks.PURPLE_SHULKER_BOX, - Blocks.BLUE_SHULKER_BOX, - Blocks.BROWN_SHULKER_BOX, - Blocks.GREEN_SHULKER_BOX, - Blocks.RED_SHULKER_BOX, - Blocks.BLACK_SHULKER_BOX - ) - - fun SafeClientEvent.isLiquidBelow(entity: Entity = player): Boolean { - val results = rayTraceBoundingBoxToGround(entity, true) - if (results.all { it.typeOfHit == RayTraceResult.Type.MISS || it.hitVec?.y ?: 911.0 < 0.0 }) { - return true - } - - val pos = results.maxByOrNull { it.hitVec?.y ?: -69420.0 }?.blockPos ?: return false - return isLiquid(pos) - } - - fun SafeClientEvent.getGroundPos(entity: Entity = player): Vec3d { - val results = rayTraceBoundingBoxToGround(entity, false) - if (results.all { it.typeOfHit == RayTraceResult.Type.MISS || it.hitVec?.y ?: 911.0 < 0.0 }) { - return Vec3d(0.0, -999.0, 0.0) - } - - return results.maxByOrNull { it.hitVec?.y ?: -69420.0 }?.hitVec ?: Vec3d(0.0, -69420.0, 0.0) - } - - private fun SafeClientEvent.rayTraceBoundingBoxToGround(entity: Entity, stopOnLiquid: Boolean): List { - val boundingBox = entity.entityBoundingBox - val xArray = arrayOf(floor(boundingBox.minX), floor(boundingBox.maxX)) - val zArray = arrayOf(floor(boundingBox.minZ), floor(boundingBox.maxZ)) - - val results = ArrayList(4) - - for (x in xArray) { - for (z in zArray) { - val result = rayTraceToGround(Vec3d(x, boundingBox.minY, z), stopOnLiquid) - results.add(result) - } - } - - return results - } - - private fun SafeClientEvent.rayTraceToGround(vec3d: Vec3d, stopOnLiquid: Boolean): RayTraceResult? { - return world.rayTraceBlocks(vec3d, Vec3d(vec3d.x, -1.0, vec3d.z), stopOnLiquid, true, false) - } - - fun SafeClientEvent.isLiquid(pos: BlockPos): Boolean { - return world.getBlockState(pos).material.isLiquid - } - - fun SafeClientEvent.isWater(pos: BlockPos): Boolean { - return world.getBlockState(pos).block == Blocks.WATER - } - - /** - * Checks if given [pos] is able to place block in it - * - * @return true playing is not colliding with [pos] and there is block below it - */ - fun SafeClientEvent.isPlaceable(pos: BlockPos, ignoreSelfCollide: Boolean = false) = world.getBlockState(pos).material.isReplaceable - && world.checkNoEntityCollision(AxisAlignedBB(pos), if (ignoreSelfCollide) player else null) - - fun SafeClientEvent.getHitSide(blockPos: BlockPos): EnumFacing { - return rayTraceTo(blockPos)?.sideHit ?: EnumFacing.UP - } - - fun SafeClientEvent.rayTraceTo(blockPos: BlockPos): RayTraceResult? { - return world.rayTraceBlocks(player.getPositionEyes(1f), Vec3d(blockPos).add(0.5, 0.5, 0.5)) - } - - fun getHitVec(pos: BlockPos, facing: EnumFacing): Vec3d { - val vec = facing.directionVec - return Vec3d(vec.x * 0.5 + 0.5 + pos.x, vec.y * 0.5 + 0.5 + pos.y, vec.z * 0.5 + 0.5 + pos.z) - } - - fun getHitVecOffset(facing: EnumFacing): Vec3d { - val vec = facing.directionVec - return Vec3d(vec.x * 0.5 + 0.5, vec.y * 0.5 + 0.5, vec.z * 0.5 + 0.5) - } - - fun SafeClientEvent.rayTraceHitVec(pos: BlockPos): RayTraceResult? { - val eyePos = player.getPositionEyes(1f) - val bb = world.getBlockState(pos).getSelectedBoundingBox(world, pos) - - return world.rayTraceBlocks(eyePos, bb.center, false, false, true)?.takeIf { - it.isEqualTo(pos) - } ?: bb.corners(0.95).mapNotNull { corner -> - world.rayTraceBlocks(eyePos, corner, false, false, true)?.takeIf { it.isEqualTo(pos) } - }.minByOrNull { - it.hitVec?.distanceTo(eyePos) ?: 69420.0 - } - } - - private fun RayTraceResult.isEqualTo(pos: BlockPos) = typeOfHit == RayTraceResult.Type.BLOCK && blockPos == pos - - suspend fun SafeClientEvent.buildStructure( - placeSpeed: Float, - getPlaceInfo: SafeClientEvent.(HashSet) -> Pair? - ) { - val emptyHashSet = HashSet() - val placed = HashSet() - var placeCount = 0 - while (getPlaceInfo(emptyHashSet) != null) { - val placingInfo = getPlaceInfo(placed) ?: getPlaceInfo(emptyHashSet) ?: break - placeCount++ - placed.add(placingInfo.second.offset(placingInfo.first)) - runSafeSuspend { - doPlace(placingInfo.second, placingInfo.first, placeSpeed) - } - if (placeCount >= 4) { - delay(100L) - placeCount = 0 - placed.clear() - } - } - } - - fun SafeClientEvent.hasNeighbour(blockPos: BlockPos): Boolean { - return EnumFacing.values().any { - !world.getBlockState(blockPos.offset(it)).material.isReplaceable - } - } - - fun SafeClientEvent.getPlaceInfo( - center: BlockPos?, - structureOffset: Array, - toIgnore: HashSet, - maxAttempts: Int, - attempts: Int = 1 - ): Pair? { - center?.let { - for (offset in structureOffset) { - val pos = it.add(offset) - if (toIgnore.contains(pos)) continue - if (!isPlaceable(pos)) continue - return getNeighbour(pos, attempts) ?: continue - } - if (attempts <= maxAttempts) return getPlaceInfo(it, structureOffset, toIgnore, maxAttempts, attempts + 1) - } - return null - } - - fun SafeClientEvent.getNeighbour( - blockPos: BlockPos, - attempts: Int = 3, - range: Float = 4.25f, - sides: Array = EnumFacing.values(), - toIgnore: HashSet = HashSet() - ): Pair? { - for (side in sides) { - val pos = blockPos.offset(side) - if (!toIgnore.add(pos)) continue - if (world.getBlockState(pos).material.isReplaceable) continue - if (player.getPositionEyes(1f).distanceTo(Vec3d(pos).add(getHitVecOffset(side))) > range) continue - return Pair(side.opposite, pos) - } - if (attempts > 1) { - toIgnore.add(blockPos) - for (side in sides) { - val pos = blockPos.offset(side) - if (!isPlaceable(pos)) continue - return getNeighbour(pos, attempts - 1, range, sides, toIgnore) ?: continue - } - } - return null - } - - /** - * Placing function for multithreading only - */ - suspend fun SafeClientEvent.doPlace( - pos: BlockPos, - facing: EnumFacing, - placeSpeed: Float - ) { - val hitVecOffset = getHitVecOffset(facing) - val rotation = getRotationTo(Vec3d(pos).add(hitVecOffset)) - val rotationPacket = CPacketPlayer.PositionRotation(player.posX, player.posY, player.posZ, rotation.x, rotation.y, player.onGround) - val placePacket = CPacketPlayerTryUseItemOnBlock(pos, facing, EnumHand.MAIN_HAND, hitVecOffset.x.toFloat(), hitVecOffset.y.toFloat(), hitVecOffset.z.toFloat()) - - connection.sendPacket(rotationPacket) - delay((40f / placeSpeed).toLong()) - - connection.sendPacket(placePacket) - player.swingArm(EnumHand.MAIN_HAND) - delay((10f / placeSpeed).toLong()) - } - - /** - * Placing block without desync - */ - fun SafeClientEvent.placeBlock( - pos: BlockPos, - side: EnumFacing - ) { - if (!isPlaceable(pos.offset(side))) return - - val hitVecOffset = getHitVecOffset(side) - val placePacket = CPacketPlayerTryUseItemOnBlock(pos, side, EnumHand.MAIN_HAND, hitVecOffset.x.toFloat(), hitVecOffset.y.toFloat(), hitVecOffset.z.toFloat()) - connection.sendPacket(placePacket) - player.swingArm(EnumHand.MAIN_HAND) - - val itemStack = PlayerPacketManager.getHoldingItemStack() - val block = (itemStack.item as? ItemBlock?)?.block ?: return - val metaData = itemStack.metadata - val blockState = block.getStateForPlacement(world, pos, side, hitVecOffset.x.toFloat(), hitVecOffset.y.toFloat(), hitVecOffset.z.toFloat(), metaData, player, EnumHand.MAIN_HAND) - val soundType = blockState.block.getSoundType(blockState, world, pos, player) - world.playSound(player, pos, soundType.placeSound, SoundCategory.BLOCKS, (soundType.getVolume() + 1.0f) / 2.0f, soundType.getPitch() * 0.8f) - } - -} \ No newline at end of file diff --git a/src/main/kotlin/org/kamiblue/client/util/items/Block.kt b/src/main/kotlin/org/kamiblue/client/util/items/Block.kt index dc98e347..f6d355fe 100644 --- a/src/main/kotlin/org/kamiblue/client/util/items/Block.kt +++ b/src/main/kotlin/org/kamiblue/client/util/items/Block.kt @@ -1,8 +1,44 @@ package org.kamiblue.client.util.items import net.minecraft.block.Block +import net.minecraft.init.Blocks import net.minecraft.item.Item +val shulkerList : Set = hashSetOf( + Blocks.WHITE_SHULKER_BOX, + Blocks.ORANGE_SHULKER_BOX, + Blocks.MAGENTA_SHULKER_BOX, + Blocks.LIGHT_BLUE_SHULKER_BOX, + Blocks.YELLOW_SHULKER_BOX, + Blocks.LIME_SHULKER_BOX, + Blocks.PINK_SHULKER_BOX, + Blocks.GRAY_SHULKER_BOX, + Blocks.SILVER_SHULKER_BOX, + Blocks.CYAN_SHULKER_BOX, + Blocks.PURPLE_SHULKER_BOX, + Blocks.BLUE_SHULKER_BOX, + Blocks.BROWN_SHULKER_BOX, + Blocks.GREEN_SHULKER_BOX, + Blocks.RED_SHULKER_BOX, + Blocks.BLACK_SHULKER_BOX +) + +val blockBlacklist : Set = hashSetOf( + Blocks.ENDER_CHEST, + Blocks.CHEST, + Blocks.TRAPPED_CHEST, + Blocks.CRAFTING_TABLE, + Blocks.ANVIL, + Blocks.BREWING_STAND, + Blocks.HOPPER, + Blocks.DROPPER, + Blocks.DISPENSER, + Blocks.TRAPDOOR, + Blocks.ENCHANTING_TABLE +).apply { + addAll(shulkerList) +} + val Block.item: Item get() = Item.getItemFromBlock(this) val Block.id: Int get() = Block.getIdFromBlock(this) \ No newline at end of file diff --git a/src/main/kotlin/org/kamiblue/client/util/items/Slot.kt b/src/main/kotlin/org/kamiblue/client/util/items/Slot.kt index 75b456a7..3fee3c43 100644 --- a/src/main/kotlin/org/kamiblue/client/util/items/Slot.kt +++ b/src/main/kotlin/org/kamiblue/client/util/items/Slot.kt @@ -7,6 +7,7 @@ import net.minecraft.inventory.Slot import net.minecraft.item.Item import net.minecraft.item.ItemBlock import net.minecraft.item.ItemStack +import org.kamiblue.client.util.Wrapper val EntityPlayer.allSlots: List get() = inventoryContainer.getSlots(1..45) @@ -126,6 +127,9 @@ fun Iterable.filterByID(itemID: Int, predicate: (ItemStack) -> Boo inline fun Iterable.filterByStack(predicate: (ItemStack) -> Boolean = { true }) = filter { predicate(it.stack) } +fun Slot.toHotbarSlotOrNull() = + if (this.slotNumber in 36..44 && this.inventory == Wrapper.player?.inventory) HotbarSlot(this) + else null class HotbarSlot(slot: Slot) : Slot(slot.inventory, slot.slotIndex, slot.xPos, slot.yPos) { init { diff --git a/src/main/kotlin/org/kamiblue/client/util/math/BoundingBoxUtils.kt b/src/main/kotlin/org/kamiblue/client/util/math/BoundingBoxUtils.kt index e85f1857..d8107f04 100644 --- a/src/main/kotlin/org/kamiblue/client/util/math/BoundingBoxUtils.kt +++ b/src/main/kotlin/org/kamiblue/client/util/math/BoundingBoxUtils.kt @@ -1,11 +1,14 @@ package org.kamiblue.client.util.math -import net.minecraft.util.EnumFacing -import net.minecraft.util.math.AxisAlignedBB -import net.minecraft.util.math.Vec3d import org.kamiblue.client.util.math.VectorUtils.plus import org.kamiblue.client.util.math.VectorUtils.times import org.kamiblue.client.util.math.VectorUtils.toVec3d +import org.kamiblue.client.util.math.VectorUtils.toViewVec +import net.minecraft.util.EnumFacing +import net.minecraft.util.math.AxisAlignedBB +import net.minecraft.util.math.RayTraceResult +import net.minecraft.util.math.Vec3d +import org.kamiblue.client.util.Wrapper val AxisAlignedBB.xLength get() = maxX - minX @@ -35,4 +38,28 @@ fun AxisAlignedBB.side(side: EnumFacing, scale: Double = 0.5): Vec3d { val lengths = lengths val sideDirectionVec = side.directionVec.toVec3d() return lengths * sideDirectionVec * scale + center +} + +/** + * Check if a box is in sight + */ +fun AxisAlignedBB.isInSight( + posFrom: Vec3d = Wrapper.player?.getPositionEyes(1.0f) ?: Vec3d.ZERO, + rotation: Vec2f = Wrapper.player?.let { Vec2f(it) } ?: Vec2f.ZERO, + range: Double = 4.25, + tolerance: Double = 1.05 +) = isInSight(posFrom, rotation.toViewVec(), range, tolerance) + +/** + * Check if a box is in sight + */ +fun AxisAlignedBB.isInSight( + posFrom: Vec3d, + viewVec: Vec3d, + range: Double = 4.25, + tolerance: Double = 1.05 +): RayTraceResult? { + val sightEnd = posFrom.add(viewVec.scale(range)) + + return grow(tolerance - 1.0).calculateIntercept(posFrom, sightEnd) } \ No newline at end of file diff --git a/src/main/kotlin/org/kamiblue/client/util/math/VectorUtils.kt b/src/main/kotlin/org/kamiblue/client/util/math/VectorUtils.kt index 93dff0ca..23c56b58 100644 --- a/src/main/kotlin/org/kamiblue/client/util/math/VectorUtils.kt +++ b/src/main/kotlin/org/kamiblue/client/util/math/VectorUtils.kt @@ -5,6 +5,7 @@ import net.minecraft.util.math.BlockPos import net.minecraft.util.math.ChunkPos import net.minecraft.util.math.Vec3d import net.minecraft.util.math.Vec3i +import org.kamiblue.commons.extension.PI_FLOAT import org.kamiblue.commons.extension.ceilToInt import org.kamiblue.commons.extension.floorToInt import kotlin.math.* @@ -63,6 +64,19 @@ object VectorUtils { return IntRange((d1 - d2).floorToInt(), (d1 + d2).ceilToInt()) } + fun Vec2f.toViewVec(): Vec3d { + val rotationRad = toRadians() + val yaw = -rotationRad.x - PI_FLOAT + val pitch = -rotationRad.y + + val cosYaw = cos(yaw) + val sinYaw = sin(yaw) + val cosPitch = -cos(pitch) + val sinPitch = sin(pitch) + + return Vec3d((sinYaw * cosPitch).toDouble(), sinPitch.toDouble(), (cosYaw * cosPitch).toDouble()) + } + fun Vec3d.toBlockPos(): BlockPos { return BlockPos(x.floorToInt(), y.floorToInt(), z.floorToInt()) } diff --git a/src/main/kotlin/org/kamiblue/client/util/world/Block.kt b/src/main/kotlin/org/kamiblue/client/util/world/Block.kt new file mode 100644 index 00000000..d0b9da75 --- /dev/null +++ b/src/main/kotlin/org/kamiblue/client/util/world/Block.kt @@ -0,0 +1,33 @@ +package org.kamiblue.client.util.world + +import net.minecraft.block.Block +import net.minecraft.block.state.IBlockState +import net.minecraft.client.multiplayer.WorldClient +import net.minecraft.init.Blocks +import net.minecraft.util.math.AxisAlignedBB +import net.minecraft.util.math.BlockPos +import org.kamiblue.client.util.Wrapper +import org.kamiblue.client.util.items.blockBlacklist + +val IBlockState.isBlacklisted: Boolean + get() = blockBlacklist.contains(this.block) + +val IBlockState.isLiquid: Boolean + get() = this.material.isLiquid + +val IBlockState.isWater: Boolean + get() = this.block == Blocks.WATER + +val IBlockState.isReplaceable: Boolean + get() = this.material.isReplaceable + +val IBlockState.isFullBox: Boolean + get() = Wrapper.world?.let { + this.getCollisionBoundingBox(it, BlockPos.ORIGIN) + } == Block.FULL_BLOCK_AABB + +fun WorldClient.getSelectedBox(pos: BlockPos): AxisAlignedBB = + this.getBlockState(pos).getSelectedBoundingBox(this, pos) + +fun WorldClient.getCollisionBox(pos: BlockPos): AxisAlignedBB? = + this.getBlockState(pos).getCollisionBoundingBox(this, pos) \ No newline at end of file diff --git a/src/main/kotlin/org/kamiblue/client/util/world/Check.kt b/src/main/kotlin/org/kamiblue/client/util/world/Check.kt new file mode 100644 index 00000000..7a3ae6d7 --- /dev/null +++ b/src/main/kotlin/org/kamiblue/client/util/world/Check.kt @@ -0,0 +1,110 @@ +package org.kamiblue.client.util.world + +import net.minecraft.entity.Entity +import net.minecraft.util.EnumFacing +import net.minecraft.util.math.AxisAlignedBB +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.RayTraceResult +import net.minecraft.util.math.Vec3d +import net.minecraft.world.World +import org.kamiblue.client.event.SafeClientEvent +import org.kamiblue.client.util.Wrapper +import org.kamiblue.client.util.math.VectorUtils.toVec3dCenter +import kotlin.math.floor + +fun World.isLiquidBelow(entity: Entity): Boolean { + val results = rayTraceBoundingBoxToGround(entity, true) + if (results.all { it.typeOfHit == RayTraceResult.Type.MISS || it.hitVec?.y ?: 911.0 < 0.0 }) { + return true + } + + val pos = results.maxByOrNull { it.hitVec?.y ?: -69420.0 }?.blockPos ?: return false + return isLiquid(pos) +} + +private fun World.rayTraceBoundingBoxToGround(entity: Entity, stopOnLiquid: Boolean): List { + val boundingBox = entity.entityBoundingBox + val xArray = arrayOf(floor(boundingBox.minX), floor(boundingBox.maxX)) + val zArray = arrayOf(floor(boundingBox.minZ), floor(boundingBox.maxZ)) + + val results = ArrayList(4) + + for (x in xArray) { + for (z in zArray) { + val result = rayTraceToGround(Vec3d(x, boundingBox.minY, z), stopOnLiquid) + if (result != null) { + results.add(result) + } + } + } + + return results +} + +fun World.getGroundPos(entity: Entity): Vec3d { + val results = rayTraceBoundingBoxToGround(entity, false) + if (results.all { it.typeOfHit == RayTraceResult.Type.MISS || it.hitVec?.y ?: 911.0 < 0.0 }) { + return Vec3d(0.0, -999.0, 0.0) + } + + return results.maxByOrNull { it.hitVec?.y ?: -69420.0 }?.hitVec ?: Vec3d(0.0, -69420.0, 0.0) +} + +private fun World.rayTraceToGround(vec3d: Vec3d, stopOnLiquid: Boolean): RayTraceResult? { + return this.rayTrace( + vec3d, + Vec3d(vec3d.x, -1.0, vec3d.z), + stopOnLiquid, + ignoreBlockWithoutBoundingBox = true, + returnLastUncollidableBlock = false + ) +} + +fun World.isVisible( + pos: BlockPos, + tolerance: Double = 1.0 +) = Wrapper.player?.let { + val center = pos.toVec3dCenter() + val result = rayTrace( + it.getPositionEyes(1.0f), + center, + stopOnLiquid = false, + ignoreBlockWithoutBoundingBox = true + ) + + result != null + && (result.blockPos == pos + || (result.hitVec != null && result.hitVec.distanceTo(center) <= tolerance)) +} ?: false + +fun World.rayTrace( + start: Vec3d, + end: Vec3d, + stopOnLiquid: Boolean = false, + ignoreBlockWithoutBoundingBox: Boolean = false, + returnLastUncollidableBlock: Boolean = false +): RayTraceResult? = + this.rayTraceBlocks(start, end, stopOnLiquid, ignoreBlockWithoutBoundingBox, returnLastUncollidableBlock) + +fun World.isLiquid(pos: BlockPos): Boolean { + return this.getBlockState(pos).isLiquid +} + +fun World.isWater(pos: BlockPos): Boolean { + return this.getBlockState(pos).isWater +} + +fun SafeClientEvent.hasNeighbour(pos: BlockPos): Boolean { + return EnumFacing.values().any { + !world.getBlockState(pos.offset(it)).isReplaceable + } +} + +/** + * Checks if given [pos] is able to place block in it + * + * @return true playing is not colliding with [pos] and there is block below it + */ +fun World.isPlaceable(pos: BlockPos, ignoreSelfCollide: Boolean = false) = + this.getBlockState(pos).isReplaceable + && this.checkNoEntityCollision(AxisAlignedBB(pos), if (ignoreSelfCollide) Wrapper.player else null) \ No newline at end of file diff --git a/src/main/kotlin/org/kamiblue/client/util/world/Interact.kt b/src/main/kotlin/org/kamiblue/client/util/world/Interact.kt new file mode 100644 index 00000000..ac31fc03 --- /dev/null +++ b/src/main/kotlin/org/kamiblue/client/util/world/Interact.kt @@ -0,0 +1,286 @@ +package org.kamiblue.client.util.world + +import kotlinx.coroutines.delay +import net.minecraft.init.Blocks +import net.minecraft.item.ItemBlock +import net.minecraft.network.play.client.CPacketPlayer +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.BlockPos +import net.minecraft.util.math.Vec3d +import org.kamiblue.client.event.SafeClientEvent +import org.kamiblue.client.manager.managers.PlayerPacketManager +import org.kamiblue.client.util.math.RotationUtils.getRotationTo +import org.kamiblue.client.util.math.VectorUtils.toVec3dCenter +import org.kamiblue.client.util.threads.runSafeSuspend +import java.util.* +import java.util.function.BooleanSupplier +import kotlin.collections.ArrayList + +fun SafeClientEvent.getNeighbourSequence( + pos: BlockPos, + attempts: Int = 3, + range: Float = 4.25f, + visibleSideCheck: Boolean = false, + sides: Array = EnumFacing.values() +) = + getNeighbourSequence(player.getPositionEyes(1.0f), pos, attempts, range, visibleSideCheck, sides, ArrayList(), HashSet()) + +private fun SafeClientEvent.getNeighbourSequence( + eyePos: Vec3d, + pos: BlockPos, + attempts: Int, + range: Float, + visibleSideCheck: Boolean, + sides: Array, + sequence: ArrayList, + toIgnore: HashSet> +): List? { + for (side in sides) { + checkNeighbour(eyePos, pos, side, range, visibleSideCheck, true, toIgnore)?.let { + sequence.add(it) + sequence.reverse() + return sequence + } + } + + if (attempts > 1) { + for (side in sides) { + val newPos = pos.offset(side) + + val placeInfo = checkNeighbour(eyePos, pos, side, range, visibleSideCheck, false, toIgnore) ?: continue + val newSequence = ArrayList(sequence) + newSequence.add(placeInfo) + + return getNeighbourSequence(eyePos, newPos, attempts - 1, range, visibleSideCheck, sides, newSequence, toIgnore) + ?: continue + } + } + + return null +} + +fun SafeClientEvent.getNeighbour( + pos: BlockPos, + attempts: Int = 3, + range: Float = 4.25f, + visibleSideCheck: Boolean = false, + sides: Array = EnumFacing.values() +) = + getNeighbour(player.getPositionEyes(1.0f), pos, attempts, range, visibleSideCheck, sides, HashSet()) + +private fun SafeClientEvent.getNeighbour( + eyePos: Vec3d, + pos: BlockPos, + attempts: Int, + range: Float, + visibleSideCheck: Boolean, + sides: Array, + toIgnore: HashSet> +): PlaceInfo? { + for (side in sides) { + val result = checkNeighbour(eyePos, pos, side, range, visibleSideCheck, true, toIgnore) + if (result != null) return result + } + + if (attempts > 1) { + for (side in sides) { + val newPos = pos.offset(side) + if (!world.isPlaceable(newPos)) continue + + return getNeighbour(eyePos, newPos, attempts - 1, range, visibleSideCheck, sides, toIgnore) + ?: continue + } + } + + return null +} + +private fun SafeClientEvent.checkNeighbour( + eyePos: Vec3d, + pos: BlockPos, + side: EnumFacing, + range: Float, + visibleSideCheck: Boolean, + checkReplaceable: Boolean, + toIgnore: HashSet>? +): PlaceInfo? { + val offsetPos = pos.offset(side) + val oppositeSide = side.opposite + + if (toIgnore?.add(offsetPos to oppositeSide) == false) return null + + val hitVec = getHitVec(offsetPos, oppositeSide) + val dist = eyePos.distanceTo(hitVec) + + if (dist > range) return null + if (visibleSideCheck && !getVisibleSides(offsetPos, true).contains(oppositeSide)) return null + if (checkReplaceable && world.getBlockState(offsetPos).isReplaceable) return null + if (!world.isPlaceable(pos)) return null + + val hitVecOffset = getHitVecOffset(oppositeSide) + return PlaceInfo(offsetPos, oppositeSide, dist, hitVecOffset, hitVec, pos) +} + +fun SafeClientEvent.getMiningSide(pos: BlockPos): EnumFacing? { + val eyePos = player.getPositionEyes(1.0f) + + return getVisibleSides(pos) + .filter { !world.getBlockState(pos.offset(it)).isFullBox } + .minByOrNull { eyePos.squareDistanceTo(getHitVec(pos, it)) } +} + +fun SafeClientEvent.getClosestVisibleSide(pos: BlockPos): EnumFacing? { + val eyePos = player.getPositionEyes(1.0f) + + return getVisibleSides(pos) + .minByOrNull { eyePos.squareDistanceTo(getHitVec(pos, it)) } +} + +/** + * Get the "visible" sides related to player's eye position + */ +fun SafeClientEvent.getVisibleSides(pos: BlockPos, assumeAirAsFullBox: Boolean = false): Set { + val visibleSides = EnumSet.noneOf(EnumFacing::class.java) + + val eyePos = player.getPositionEyes(1.0f) + val blockCenter = pos.toVec3dCenter() + val blockState = world.getBlockState(pos) + val isFullBox = assumeAirAsFullBox && blockState.block == Blocks.AIR || blockState.isFullBox + + return visibleSides + .checkAxis(eyePos.x - blockCenter.x, EnumFacing.WEST, EnumFacing.EAST, !isFullBox) + .checkAxis(eyePos.y - blockCenter.y, EnumFacing.DOWN, EnumFacing.UP, true) + .checkAxis(eyePos.z - blockCenter.z, EnumFacing.NORTH, EnumFacing.SOUTH, !isFullBox) +} + +private fun EnumSet.checkAxis(diff: Double, negativeSide: EnumFacing, positiveSide: EnumFacing, bothIfInRange: Boolean) = + this.apply { + when { + diff < -0.5 -> { + add(negativeSide) + } + diff > 0.5 -> { + add(positiveSide) + } + else -> { + if (bothIfInRange) { + add(negativeSide) + add(positiveSide) + } + } + } + } + +fun getHitVec(pos: BlockPos, facing: EnumFacing): Vec3d { + val vec = facing.directionVec + return Vec3d(vec.x * 0.5 + 0.5 + pos.x, vec.y * 0.5 + 0.5 + pos.y, vec.z * 0.5 + 0.5 + pos.z) +} + +fun getHitVecOffset(facing: EnumFacing): Vec3d { + val vec = facing.directionVec + return Vec3d(vec.x * 0.5 + 0.5, vec.y * 0.5 + 0.5, vec.z * 0.5 + 0.5) +} + +suspend fun SafeClientEvent.buildStructure( + center: BlockPos, + structureOffset: Array, + placeSpeed: Float, + attempts: Int, + range: Float, + visibleSideCheck: Boolean, + block: BooleanSupplier +) { + val emptySet = emptySet() + val placed = HashSet() + + var placeCount = 0 + var lastInfo = getStructurePlaceInfo(center, structureOffset, emptySet, attempts, range, visibleSideCheck) + + while (lastInfo != null) { + if (!block.asBoolean) return + + val placingInfo = getStructurePlaceInfo(center, structureOffset, placed, attempts, range, visibleSideCheck) + ?: lastInfo + + placeCount++ + placed.add(placingInfo.placedPos) + + runSafeSuspend { + doPlace(placingInfo, placeSpeed) + } + + if (placeCount >= 4) { + delay(100L) + placeCount = 0 + placed.clear() + } + + lastInfo = getStructurePlaceInfo(center, structureOffset, emptySet, attempts, range, visibleSideCheck) + } +} + +private fun SafeClientEvent.getStructurePlaceInfo( + center: BlockPos, + structureOffset: Array, + toIgnore: Set, + attempts: Int, + range: Float, + visibleSideCheck: Boolean +): PlaceInfo? { + for (offset in structureOffset) { + val pos = center.add(offset) + if (toIgnore.contains(pos)) continue + if (!world.isPlaceable(pos)) continue + + return getNeighbour(pos, attempts, range, visibleSideCheck) ?: continue + } + + if (attempts > 1) return getStructurePlaceInfo(center, structureOffset, toIgnore, attempts - 1, range, visibleSideCheck) + + return null +} + +/** + * Placing function for multithreading only + */ +private suspend fun SafeClientEvent.doPlace( + placeInfo: PlaceInfo, + placeSpeed: Float +) { + val rotation = getRotationTo(placeInfo.hitVec) + val rotationPacket = CPacketPlayer.PositionRotation(player.posX, player.posY, player.posZ, rotation.x, rotation.y, player.onGround) + val placePacket = placeInfo.toPlacePacket(EnumHand.MAIN_HAND) + + connection.sendPacket(rotationPacket) + delay((40.0f / placeSpeed).toLong()) + + connection.sendPacket(placePacket) + player.swingArm(EnumHand.MAIN_HAND) + delay((10.0f / placeSpeed).toLong()) +} + +/** + * Placing block without desync + */ +fun SafeClientEvent.placeBlock( + placeInfo: PlaceInfo, + hand: EnumHand = EnumHand.MAIN_HAND +) { + if (!world.isPlaceable(placeInfo.placedPos)) return + + connection.sendPacket(placeInfo.toPlacePacket(hand)) + player.swingArm(hand) + + val itemStack = PlayerPacketManager.getHoldingItemStack() + val block = (itemStack.item as? ItemBlock?)?.block ?: return + val metaData = itemStack.metadata + val blockState = block.getStateForPlacement(world, placeInfo.pos, placeInfo.side, placeInfo.hitVecOffset.x.toFloat(), placeInfo.hitVecOffset.y.toFloat(), placeInfo.hitVecOffset.z.toFloat(), metaData, player, EnumHand.MAIN_HAND) + val soundType = blockState.block.getSoundType(blockState, world, placeInfo.pos, player) + world.playSound(player, placeInfo.pos, soundType.placeSound, SoundCategory.BLOCKS, (soundType.getVolume() + 1.0f) / 2.0f, soundType.getPitch() * 0.8f) +} + +private fun PlaceInfo.toPlacePacket(hand: EnumHand) = + CPacketPlayerTryUseItemOnBlock(this.pos, this.side, hand, hitVecOffset.x.toFloat(), hitVecOffset.y.toFloat(), hitVecOffset.z.toFloat()) diff --git a/src/main/kotlin/org/kamiblue/client/util/world/PlaceInfo.kt b/src/main/kotlin/org/kamiblue/client/util/world/PlaceInfo.kt new file mode 100644 index 00000000..41246d75 --- /dev/null +++ b/src/main/kotlin/org/kamiblue/client/util/world/PlaceInfo.kt @@ -0,0 +1,14 @@ +package org.kamiblue.client.util.world + +import net.minecraft.util.EnumFacing +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Vec3d + +class PlaceInfo( + val pos: BlockPos, + val side: EnumFacing, + val dist: Double, + val hitVecOffset: Vec3d, + val hitVec: Vec3d, + val placedPos: BlockPos +) \ No newline at end of file