diff --git a/src/main/java/me/zeroeightsix/kami/command/commands/SearchCommand.kt b/src/main/java/me/zeroeightsix/kami/command/commands/SearchCommand.kt index 321dce6bc..8c12ea874 100644 --- a/src/main/java/me/zeroeightsix/kami/command/commands/SearchCommand.kt +++ b/src/main/java/me/zeroeightsix/kami/command/commands/SearchCommand.kt @@ -86,7 +86,7 @@ object SearchCommand : ClientCommand( literal("override") { execute("Override the Intel Integrated GPU check") { - Search.overrideWarning.value = true + Search.overrideWarning = true MessageSendHelper.sendWarningMessage("Override for Intel Integrated GPUs enabled!") } } diff --git a/src/main/java/me/zeroeightsix/kami/gui/hudgui/elements/client/ModuleList.kt b/src/main/java/me/zeroeightsix/kami/gui/hudgui/elements/client/ModuleList.kt index 6b043e3bb..ded589bda 100644 --- a/src/main/java/me/zeroeightsix/kami/gui/hudgui/elements/client/ModuleList.kt +++ b/src/main/java/me/zeroeightsix/kami/gui/hudgui/elements/client/ModuleList.kt @@ -13,7 +13,7 @@ import me.zeroeightsix.kami.util.graphics.font.FontRenderAdapter import me.zeroeightsix.kami.util.graphics.font.HAlign import me.zeroeightsix.kami.util.graphics.font.TextComponent import me.zeroeightsix.kami.util.graphics.font.VAlign -import me.zeroeightsix.kami.util.threads.safeAsyncListener +import me.zeroeightsix.kami.util.threads.safeListener import net.minecraft.client.renderer.GlStateManager import net.minecraftforge.fml.common.gameevent.TickEvent import org.kamiblue.commons.extension.sumByFloat @@ -67,8 +67,8 @@ object ModuleList : HudElement( .toMutableMap() init { - safeAsyncListener { event -> - if (event.phase != TickEvent.Phase.END) return@safeAsyncListener + safeListener { event -> + if (event.phase != TickEvent.Phase.END) return@safeListener val moduleSet = ModuleManager.modules.toSet() diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/HoleESP.kt b/src/main/java/me/zeroeightsix/kami/module/modules/combat/HoleESP.kt index ae51e9519..aafb2c439 100644 --- a/src/main/java/me/zeroeightsix/kami/module/modules/combat/HoleESP.kt +++ b/src/main/java/me/zeroeightsix/kami/module/modules/combat/HoleESP.kt @@ -1,22 +1,27 @@ package me.zeroeightsix.kami.module.modules.combat +import kotlinx.coroutines.launch +import me.zeroeightsix.kami.event.SafeClientEvent import me.zeroeightsix.kami.event.events.RenderWorldEvent import me.zeroeightsix.kami.module.Module import me.zeroeightsix.kami.setting.ModuleConfig.setting import me.zeroeightsix.kami.util.TickTimer import me.zeroeightsix.kami.util.color.ColorHolder import me.zeroeightsix.kami.util.combat.SurroundUtils +import me.zeroeightsix.kami.util.combat.SurroundUtils.checkHole import me.zeroeightsix.kami.util.graphics.ESPRenderer import me.zeroeightsix.kami.util.graphics.GeometryMasks import me.zeroeightsix.kami.util.math.VectorUtils.toBlockPos -import org.kamiblue.event.listener.listener +import me.zeroeightsix.kami.util.threads.defaultScope +import me.zeroeightsix.kami.util.threads.safeListener +import net.minecraft.util.math.AxisAlignedBB object HoleESP : Module( name = "HoleESP", category = Category.COMBAT, description = "Show safe holes for crystal pvp" ) { - private val range = setting("RenderDistance", 8, 4..16, 1) + private val range = setting("RenderDistance", 8, 4..32, 1) private val filled = setting("Filled", true) private val outline = setting("Outline", true) private val hideOwn = setting("HideOwn", true) @@ -43,38 +48,46 @@ object HoleESP : Module( private val timer = TickTimer() init { - listener { - if (mc.world == null || mc.player == null) return@listener - if (timer.tick(133L)) updateRenderer() // Avoid running this on a tick + safeListener { + if (timer.tick(133L)) { // Avoid running this on a tick + updateRenderer() + } renderer.render(false) } } - private fun updateRenderer() { - renderer.clear() + private fun SafeClientEvent.updateRenderer() { renderer.aFilled = if (filled.value) aFilled.value else 0 renderer.aOutline = if (outline.value) aOutline.value else 0 val colorObsidian = ColorHolder(r1.value, g1.value, b1.value) val colorBedrock = ColorHolder(r2.value, g2.value, b2.value) - val playerPos = mc.player.positionVector.toBlockPos() + val playerPos = player.positionVector.toBlockPos() val side = if (renderMode.value != Mode.FLAT) GeometryMasks.Quad.ALL else GeometryMasks.Quad.DOWN - for (x in -range.value..range.value) for (y in -range.value..range.value) for (z in -range.value..range.value) { - if (hideOwn.value && x == 0 && y == 0 && z == 0) continue - val pos = playerPos.add(x, y, z) - val holeType = SurroundUtils.checkHole(pos) - if (holeType == SurroundUtils.HoleType.NONE) continue - val renderPos = if (renderMode.value == Mode.BLOCK_FLOOR) pos.down() else pos + defaultScope.launch { + val cached = ArrayList>() - if (holeType == SurroundUtils.HoleType.OBBY && shouldAddObsidian()) { - renderer.add(renderPos, colorObsidian, side) + for (x in -range.value..range.value) for (y in -range.value..range.value) for (z in -range.value..range.value) { + if (hideOwn.value && x == 0 && y == 0 && z == 0) continue + val pos = playerPos.add(x, y, z) + + val holeType = checkHole(pos) + if (holeType == SurroundUtils.HoleType.NONE) continue + + val bb = AxisAlignedBB(if (renderMode.value == Mode.BLOCK_FLOOR) pos.down() else pos) + + if (holeType == SurroundUtils.HoleType.OBBY && shouldAddObsidian()) { + cached.add(Triple(bb, colorObsidian, side)) + } + + if (holeType == SurroundUtils.HoleType.BEDROCK && shouldAddBedrock()) { + cached.add(Triple(bb, colorBedrock, side)) + } } - if (holeType == SurroundUtils.HoleType.BEDROCK && shouldAddBedrock()) { - renderer.add(renderPos, colorBedrock, side) - } + renderer.replaceAll(cached) } } diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/misc/StashFinder.kt b/src/main/java/me/zeroeightsix/kami/module/modules/misc/StashFinder.kt deleted file mode 100644 index cfcd40cfd..000000000 --- a/src/main/java/me/zeroeightsix/kami/module/modules/misc/StashFinder.kt +++ /dev/null @@ -1,122 +0,0 @@ -package me.zeroeightsix.kami.module.modules.misc - -import me.zeroeightsix.kami.manager.managers.WaypointManager -import me.zeroeightsix.kami.module.Module -import me.zeroeightsix.kami.setting.ModuleConfig.setting -import me.zeroeightsix.kami.util.math.CoordinateConverter.asString -import me.zeroeightsix.kami.util.text.MessageSendHelper -import me.zeroeightsix.kami.util.threads.safeListener -import net.minecraft.client.audio.PositionedSoundRecord -import net.minecraft.init.SoundEvents -import net.minecraft.tileentity.* -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.ChunkPos -import net.minecraftforge.fml.common.gameevent.TickEvent -import kotlin.math.roundToInt - -object StashFinder : Module( - name = "StashFinder", - category = Category.MISC, - description = "Logs storage units in render distance." -) { - private val saveToFile = setting("SaveToFile", true) - private val logToChat = setting("LogToChat", true) - private val playSound = setting("PlaySound", true) - - private val logChests = setting("Chests", true) - private val chestDensity = setting("MinChests", 5, 1..20, 1, { logChests.value }) - - private val logShulkers = setting("Shulkers", true) - private val shulkerDensity = setting("MinShulkers", 1, 1..20, 1, { logShulkers.value }) - - private val logDroppers = setting("Droppers", true) - private val dropperDensity = setting("MinDroppers", 5, 1..20, 1, { logDroppers.value }) - - private val logDispensers = setting("Dispensers", true) - private val dispenserDensity = setting("MinDispensers", 5, 1..20, 1, { logDispensers.value }) - - private val logHoppers = setting("Hoppers", true) - private val hopperDensity = setting("MinHoppers", 5, 1..20, 1, { logHoppers.value }) - - - private val chunkData = LinkedHashMap() - private val knownPositions = LinkedHashSet() - - override fun onEnable() { - chunkData.clear() - knownPositions.clear() - } - - init { - safeListener { - world.loadedTileEntityList - .filter { - logChests.value && it is TileEntityChest - || logShulkers.value && it is TileEntityShulkerBox - || logDroppers.value && it is TileEntityDropper - || logDispensers.value && it is TileEntityDispenser - || logHoppers.value && it is TileEntityHopper - } - .forEach { logTileEntity(it) } - - chunkData.values.filter { it.hot }.forEach { chunkStats -> - chunkStats.hot = false - - // mfw int array instead of Vec3i - if (saveToFile.value) { - WaypointManager.add(chunkStats.getBlockPos(), chunkStats.toString()) - } - - if (playSound.value) { - mc.soundHandler.playSound(PositionedSoundRecord.getRecord(SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0f, 1.0f)) - } - - if (logToChat.value) { - val positionString = chunkStats.getBlockPos().asString() - MessageSendHelper.sendChatMessage("$chatName $positionString $chunkStats") - } - } - } - } - - private fun logTileEntity(tileEntity: TileEntity) { - if (knownPositions.contains(tileEntity.pos)) return - - knownPositions.add(tileEntity.pos) - - val chunk = ChunkPos.asLong(tileEntity.pos.x / 16, tileEntity.pos.z / 16) - val chunkStats = chunkData.getOrPut(chunk, { ChunkStats() }) - - chunkStats.add(tileEntity) - if (chunkStats.chests >= chestDensity.value || chunkStats.shulkers >= shulkerDensity.value || chunkStats.droppers >= dropperDensity.value || chunkStats.dispensers >= dispenserDensity.value || chunkStats.hoppers >= hopperDensity.value) { - chunkStats.hot = true - } - } - - private data class ChunkStats(var chests: Int = 0, var shulkers: Int = 0, var droppers: Int = 0, var dispensers: Int = 0, var hoppers: Int = 0, var hot: Boolean = false) { - private val tileEntities = ArrayList() - - fun add(tileEntity: TileEntity) { - when (tileEntity) { - is TileEntityChest -> chests++ - is TileEntityShulkerBox -> shulkers++ - is TileEntityDropper -> droppers++ - is TileEntityDispenser -> dispensers++ - } - - tileEntities.add(tileEntity) - } - - // Averages the positions of all the tile entities - fun getBlockPos(): BlockPos { - val x = tileEntities.map { it.pos.x }.average().roundToInt() - val y = tileEntities.map { it.pos.y }.average().roundToInt() - val z = tileEntities.map { it.pos.z }.average().roundToInt() - return BlockPos(x, y, z) - } - - override fun toString(): String { - return "($chests chests, $shulkers shulkers, $droppers droppers, $dispensers dispensers, $hoppers hoppers)" - } - } -} diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/misc/StashLogger.kt b/src/main/java/me/zeroeightsix/kami/module/modules/misc/StashLogger.kt new file mode 100644 index 000000000..87d92f579 --- /dev/null +++ b/src/main/java/me/zeroeightsix/kami/module/modules/misc/StashLogger.kt @@ -0,0 +1,164 @@ +package me.zeroeightsix.kami.module.modules.misc + +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch +import me.zeroeightsix.kami.manager.managers.WaypointManager +import me.zeroeightsix.kami.module.Module +import me.zeroeightsix.kami.setting.ModuleConfig.setting +import me.zeroeightsix.kami.util.TickTimer +import me.zeroeightsix.kami.util.TimeUnit +import me.zeroeightsix.kami.util.math.CoordinateConverter.asString +import me.zeroeightsix.kami.util.text.MessageSendHelper +import me.zeroeightsix.kami.util.threads.defaultScope +import me.zeroeightsix.kami.util.threads.onMainThread +import me.zeroeightsix.kami.util.threads.safeListener +import net.minecraft.client.audio.PositionedSoundRecord +import net.minecraft.init.SoundEvents +import net.minecraft.tileentity.* +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.ChunkPos +import net.minecraftforge.fml.common.gameevent.TickEvent +import java.util.* +import kotlin.collections.ArrayList +import kotlin.collections.HashSet +import kotlin.collections.LinkedHashMap +import kotlin.math.roundToInt + +object StashLogger : Module( + name = "StashLogger", + category = Category.MISC, + description = "Logs storage units in render distance." +) { + private val saveToFile by setting("SaveToFile", true) + private val logToChat by setting("LogToChat", true) + private val playSound by setting("PlaySound", true) + private val logChests by setting("Chests", true) + private val chestDensity by setting("MinChests", 5, 1..20, 1, { logChests }) + private val logShulkers by setting("Shulkers", true) + private val shulkerDensity by setting("MinShulkers", 1, 1..20, 1, { logShulkers }) + private val logDroppers by setting("Droppers", true) + private val dropperDensity by setting("MinDroppers", 5, 1..20, 1, { logDroppers }) + private val logDispensers by setting("Dispensers", true) + private val dispenserDensity by setting("MinDispensers", 5, 1..20, 1, { logDispensers }) + private val logHoppers by setting("Hoppers", true) + private val hopperDensity by setting("MinHoppers", 5, 1..20, 1, { logHoppers }) + + private val chunkData = Collections.synchronizedMap(LinkedHashMap()) + private val knownPositions = HashSet() + private val timer = TickTimer(TimeUnit.SECONDS) + + override fun onEnable() { + chunkData.clear() + knownPositions.clear() + } + + init { + safeListener { + if (it.phase != TickEvent.Phase.END || !timer.tick(3L)) return@safeListener + + defaultScope.launch { + coroutineScope { + launch { + world.loadedTileEntityList.toList().forEach(::logTileEntity) + } + launch { + for (chunkStats in chunkData.values) { + if (!chunkStats.hot) continue + + chunkStats.hot = false + val center = chunkStats.center() + val string = chunkStats.toString() + + if (saveToFile) { + WaypointManager.add(center, string) + } + + if (playSound) { + onMainThread { + mc.soundHandler.playSound(PositionedSoundRecord.getRecord(SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0f, 1.0f)) + } + } + + if (logToChat) { + val positionString = center.asString() + MessageSendHelper.sendChatMessage("$chatName $positionString $string") + } + } + } + } + } + } + } + + private fun logTileEntity(tileEntity: TileEntity) { + if (!checkTileEntityType(tileEntity)) return + if (!knownPositions.add(tileEntity.pos)) return + + val chunk = ChunkPos.asLong(tileEntity.pos.x shl 4, tileEntity.pos.z shl 4) + val chunkStats = chunkData.getOrPut(chunk, ::ChunkStats) + + chunkStats.add(tileEntity) + } + + private fun checkTileEntityType(tileEntity: TileEntity) = + logChests && tileEntity is TileEntityChest + || logShulkers && tileEntity is TileEntityShulkerBox + || logDroppers && tileEntity is TileEntityDropper + || logDispensers && tileEntity is TileEntityDispenser + || logHoppers && tileEntity is TileEntityHopper + + private class ChunkStats { + var chests: Int = 0; private set + var shulkers: Int = 0; private set + var droppers: Int = 0; private set + var dispensers: Int = 0; private set + var hoppers: Int = 0; private set + + var hot: Boolean = false + + private val tileEntities = Collections.synchronizedList(ArrayList()) + + fun add(tileEntity: TileEntity) { + when (tileEntity) { + is TileEntityChest -> chests++ + is TileEntityShulkerBox -> shulkers++ + is TileEntityDropper -> droppers++ + is TileEntityDispenser -> dispensers++ + is TileEntityHopper -> hoppers++ + } + + tileEntities.add(tileEntity) + + if (chests >= chestDensity + || shulkers >= shulkerDensity + || droppers >= dropperDensity + || dispensers >= dispenserDensity + || hoppers >= hopperDensity) { + hot = true + } + } + + fun center(): BlockPos { + var x = 0.0 + var y = 0.0 + var z = 0.0 + val size = tileEntities.size + + for (tileEntity in tileEntities) { + x += tileEntity.pos.x + y += tileEntity.pos.y + z += tileEntity.pos.z + } + + x /= size + y /= size + z /= size + + return BlockPos(x.roundToInt(), y.roundToInt(), z.roundToInt()) + } + + override fun toString(): String { + return "($chests chests, $shulkers shulkers, $droppers droppers, $dispensers dispensers, $hoppers hoppers)" + } + } +} diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/render/ESP.kt b/src/main/java/me/zeroeightsix/kami/module/modules/render/ESP.kt index 2f8e3845a..604f8ee7e 100644 --- a/src/main/java/me/zeroeightsix/kami/module/modules/render/ESP.kt +++ b/src/main/java/me/zeroeightsix/kami/module/modules/render/ESP.kt @@ -139,13 +139,13 @@ object ESP : Module( if (mc.renderManager.options == null) return@listener when (mode.value) { ESPMode.BOX -> { - val colour = ColorHolder(r.value, g.value, b.value) + val color = ColorHolder(r.value, g.value, b.value) val renderer = ESPRenderer() renderer.aFilled = if (filled.value) aFilled.value else 0 renderer.aOutline = if (outline.value) aOutline.value else 0 renderer.thickness = width.value for (entity in entityList) { - renderer.add(entity, colour) + renderer.add(entity, color) } renderer.render(true) } diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/render/Search.kt b/src/main/java/me/zeroeightsix/kami/module/modules/render/Search.kt index 1ccc51266..fbb534922 100644 --- a/src/main/java/me/zeroeightsix/kami/module/modules/render/Search.kt +++ b/src/main/java/me/zeroeightsix/kami/module/modules/render/Search.kt @@ -1,30 +1,34 @@ package me.zeroeightsix.kami.module.modules.render -import io.netty.util.internal.ConcurrentSet +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import me.zeroeightsix.kami.command.CommandManager import me.zeroeightsix.kami.event.SafeClientEvent import me.zeroeightsix.kami.event.events.RenderWorldEvent import me.zeroeightsix.kami.module.Module import me.zeroeightsix.kami.setting.ModuleConfig.setting import me.zeroeightsix.kami.setting.settings.impl.collection.CollectionSetting +import me.zeroeightsix.kami.util.TickTimer import me.zeroeightsix.kami.util.color.ColorHolder import me.zeroeightsix.kami.util.graphics.ESPRenderer +import me.zeroeightsix.kami.util.graphics.GeometryMasks import me.zeroeightsix.kami.util.graphics.ShaderHelper import me.zeroeightsix.kami.util.math.VectorUtils.distanceTo import me.zeroeightsix.kami.util.text.MessageSendHelper import me.zeroeightsix.kami.util.text.formatValue +import me.zeroeightsix.kami.util.threads.defaultScope import me.zeroeightsix.kami.util.threads.safeListener +import net.minecraft.block.state.IBlockState import net.minecraft.init.Blocks +import net.minecraft.util.math.AxisAlignedBB import net.minecraft.util.math.BlockPos import net.minecraft.util.math.ChunkPos -import net.minecraftforge.fml.common.gameevent.TickEvent -import org.kamiblue.event.listener.listener +import net.minecraft.util.math.Vec3d +import net.minecraft.world.chunk.Chunk import java.util.* -import java.util.concurrent.ConcurrentHashMap -import java.util.concurrent.Executors import kotlin.collections.ArrayList import kotlin.collections.set -import kotlin.math.max object Search : Module( name = "Search", @@ -33,189 +37,130 @@ object Search : Module( ) { private val defaultSearchList = linkedSetOf("minecraft:portal", "minecraft:end_portal_frame", "minecraft:bed") - private val renderUpdate = setting("RenderUpdate", 1500, 500..3000, 100) - val overrideWarning = setting("OverrideWarning", false, { false }) - private val range = setting("SearchRange", 128, 0..256, 8) - private val maximumBlocks = setting("MaximumBlocks", 256, 16..4096, 128) - private val filled = setting("Filled", true) - private val outline = setting("Outline", true) - private val tracer = setting("Tracer", true) - private val customColours = setting("CustomColours", false) - private val r = setting("Red", 155, 0..255, 1, { customColours.value }) - private val g = setting("Green", 144, 0..255, 1, { customColours.value }) - private val b = setting("Blue", 255, 0..255, 1, { customColours.value }) - private val aFilled = setting("FilledAlpha", 31, 0..255, 1, { filled.value }) - private val aOutline = setting("OutlineAlpha", 127, 0..255, 1, { outline.value }) - private val aTracer = setting("TracerAlpha", 200, 0..255, 1, { tracer.value }) - private val thickness = setting("LineThickness", 2.0f, 0.25f..5.0f, 0.25f) + private val updateDelay by setting("UpdateDelay", 1000, 500..3000, 50) + private val range by setting("SearchRange", 128, 0..256, 8) + private val maximumBlocks by setting("MaximumBlocks", 256, 16..4096, 128) + private val filled by setting("Filled", true) + private val outline by setting("Outline", true) + private val tracer by setting("Tracer", true) + private val customColors by setting("CustomColors", false) + private val r by setting("Red", 155, 0..255, 1, { customColors }) + private val g by setting("Green", 144, 0..255, 1, { customColors }) + private val b by setting("Blue", 255, 0..255, 1, { customColors }) + private val aFilled by setting("FilledAlpha", 31, 0..255, 1, { filled }) + private val aOutline by setting("OutlineAlpha", 127, 0..255, 1, { outline }) + private val aTracer by setting("TracerAlpha", 200, 0..255, 1, { tracer }) + private val thickness by setting("LineThickness", 2.0f, 0.25f..5.0f, 0.25f) + + var overrideWarning by setting("OverrideWarning", false, { false }) val searchList = setting(CollectionSetting("SearchList", defaultSearchList, { false })) - private val chunkThreads = ConcurrentHashMap() - private val chunkThreadPool = Executors.newCachedThreadPool() - private val loadedChunks = ConcurrentSet() - private val mainList = ConcurrentHashMap>() - private val renderList = ConcurrentHashMap() private val renderer = ESPRenderer() - private var dirty = 0 - private var startTimeChunk = 0L - private var startTimeRender = 0L + private val updateTimer = TickTimer() override fun getHudInfo(): String { - return if (renderList.isNotEmpty()) renderList.size.toString() else "0" + return renderer.getSize().toString() } override fun onEnable() { - if (!overrideWarning.value && ShaderHelper.isIntegratedGraphics) { + if (!overrideWarning && ShaderHelper.isIntegratedGraphics) { MessageSendHelper.sendErrorMessage("$chatName Warning: Running Search with an Intel Integrated GPU is not recommended, as it has a &llarge&r impact on performance.") MessageSendHelper.sendWarningMessage("$chatName If you're sure you want to try, run the ${formatValue("${CommandManager.prefix}search override")} command") disable() return } - startTimeChunk = 0L - startTimeRender = 0L } init { - safeListener { - if (shouldUpdateChunk()) { - updateLoadedChunkList() - updateMainList() - } - - if (shouldUpdateRender()) { - updateRenderList() - } - } - - listener { - if (dirty > 1) { - dirty = 0 - renderer.clear() - for ((pos, colour) in renderList) renderer.add(pos, colour) - } + safeListener { renderer.render(false) + + if (updateTimer.tick(updateDelay.toLong())) { + updateRenderer() + } } } - /* Main list updating */ - private fun shouldUpdateChunk(): Boolean { - return if (System.currentTimeMillis() - startTimeChunk < max(renderUpdate.value * 2, 500)) { - false - } else { - startTimeChunk = System.currentTimeMillis() - true - } - } + private fun SafeClientEvent.updateRenderer() { + defaultScope.launch { + val posMap = TreeMap>() - private fun SafeClientEvent.updateLoadedChunkList() { - /* Removes unloaded chunks from the list */ - Thread { - for (chunkPos in loadedChunks) { - if (isChunkLoaded(chunkPos)) continue - chunkThreads.remove(chunkPos) - loadedChunks.remove(chunkPos) - mainList.remove(chunkPos) + coroutineScope { + launch { + updateAlpha() + } + launch { + val eyePos = player.getPositionEyes(1f) + getBlockPosList(eyePos, posMap) + } } - /* Adds new loaded chunks to the list */ - val renderDist = mc.gameSettings.renderDistanceChunks - val playerChunkPos = ChunkPos(player.position) - val chunkPos1 = ChunkPos(playerChunkPos.x - renderDist, playerChunkPos.z - renderDist) - val chunkPos2 = ChunkPos(playerChunkPos.x + renderDist, playerChunkPos.z + renderDist) + val renderList = ArrayList>() + val sides = GeometryMasks.Quad.ALL + + for ((index, pair) in posMap.values.withIndex()) { + if (index >= maximumBlocks) break + val bb = pair.second.getSelectedBoundingBox(world, pair.first) + val color = getBlockColor(pair.first, pair.second) + + renderList.add(Triple(bb, color, sides)) + } + + renderer.replaceAll(renderList) + } + } + + private fun updateAlpha() { + renderer.aFilled = if (filled) aFilled else 0 + renderer.aOutline = if (outline) aOutline else 0 + renderer.aTracer = if (tracer) aTracer else 0 + renderer.thickness = thickness + } + + private suspend fun SafeClientEvent.getBlockPosList(eyePos: Vec3d, map: MutableMap>) { + val renderDist = mc.gameSettings.renderDistanceChunks + val playerChunkPos = ChunkPos(player.position) + val chunkPos1 = ChunkPos(playerChunkPos.x - renderDist, playerChunkPos.z - renderDist) + val chunkPos2 = ChunkPos(playerChunkPos.x + renderDist, playerChunkPos.z + renderDist) + + coroutineScope { for (x in chunkPos1.x..chunkPos2.x) for (z in chunkPos1.z..chunkPos2.z) { val chunk = world.getChunk(x, z) if (!chunk.isLoaded) continue - loadedChunks.add(chunk.pos) - } - }.start() - } + if (player.distanceTo(chunk.pos) > range + 16) continue - private fun updateMainList() { - Thread { - for (chunkPos in loadedChunks) { - val thread = Thread { - findBlocksInChunk(chunkPos, searchList.toHashSet()) + launch { + findBlocksInChunk(chunk, eyePos, map) } - thread.priority = 1 - chunkThreads.putIfAbsent(chunkPos, thread) + delay(1L) } - for (thread in chunkThreads.values) { - chunkThreadPool.execute(thread) - Thread.sleep(5L) - } - }.start() + } } - private fun findBlocksInChunk(chunkPos: ChunkPos, blocksToFind: HashSet) { - val yRange = IntRange(0, 256) - val xRange = IntRange(chunkPos.xStart, chunkPos.xEnd) - val zRange = IntRange(chunkPos.zStart, chunkPos.zEnd) - val foundBlocks = ArrayList() + private fun findBlocksInChunk(chunk: Chunk, eyePos: Vec3d, map: MutableMap>) { + val yRange = 0..256 + val xRange = (chunk.x shl 4)..(chunk.x shl 4) + 15 + val zRange = (chunk.z shl 4)..(chunk.z shl 4) + 15 + for (y in yRange) for (x in xRange) for (z in zRange) { - val blockPos = BlockPos(x, y, z) - val block = mc.world.getBlockState(blockPos).block + val pos = BlockPos(x, y, z) + val blockState = chunk.getBlockState(pos) + val block = blockState.block + if (block == Blocks.AIR) continue - if (!blocksToFind.contains(block.registryName.toString())) continue - foundBlocks.add(BlockPos(blockPos)) - } - mainList[chunkPos] = foundBlocks - } - /* End of main list updating */ + if (!searchList.contains(block.registryName.toString())) continue - /* Rendering */ - private fun shouldUpdateRender(): Boolean { - return if (System.currentTimeMillis() - startTimeRender < renderUpdate.value) { - false - } else { - startTimeRender = System.currentTimeMillis() - true + val dist = eyePos.distanceTo(pos) + if (dist > range) continue + + map[dist] = (pos to blockState) } } - private fun SafeClientEvent.updateRenderList() { - Thread { - val cacheDistMap = TreeMap(Comparator.naturalOrder()) - /* Calculates distance for all BlockPos, ignores the ones out of the setting range, and puts them into the cacheMap to sort them */ - for (posList in mainList.values) { - for (i in posList.indices) { - val pos = posList[i] - val distance = player.distanceTo(pos) - if (distance > range.value) continue - cacheDistMap[distance] = pos - } - } - - /* Removes the furthest blocks to keep it in the maximum block limit */ - while (cacheDistMap.size > maximumBlocks.value) { - cacheDistMap.pollLastEntry() - } - - renderList.keys.removeIf { pos -> - !cacheDistMap.containsValue(pos) - } - - for (pos in cacheDistMap.values) { - renderList[pos] = getPosColor(pos) - } - - /* Updates renderer */ - renderer.aFilled = if (filled.value) aFilled.value else 0 - renderer.aOutline = if (outline.value) aOutline.value else 0 - renderer.aTracer = if (tracer.value) aTracer.value else 0 - renderer.thickness = thickness.value - - if (renderList.size != renderer.getSize()) { - dirty = 2 - } else { - dirty++ - } - }.start() - } - - private fun SafeClientEvent.getPosColor(pos: BlockPos): ColorHolder { - val blockState = world.getBlockState(pos) + private fun SafeClientEvent.getBlockColor(pos: BlockPos, blockState: IBlockState): ColorHolder { val block = blockState.block - return if (!customColours.value) { + + return if (!customColors) { if (block == Blocks.PORTAL) { ColorHolder(82, 49, 153) } else { @@ -223,12 +168,8 @@ object Search : Module( ColorHolder((colorInt shr 16), (colorInt shr 8 and 255), (colorInt and 255)) } } else { - ColorHolder(r.value, g.value, b.value) + ColorHolder(r, g, b) } } - /* End of rendering */ - private fun SafeClientEvent.isChunkLoaded(chunkPos: ChunkPos): Boolean { - return world.getChunk(chunkPos.x, chunkPos.z).isLoaded - } } \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/render/StorageESP.kt b/src/main/java/me/zeroeightsix/kami/module/modules/render/StorageESP.kt index d69143f7f..b2a010d21 100644 --- a/src/main/java/me/zeroeightsix/kami/module/modules/render/StorageESP.kt +++ b/src/main/java/me/zeroeightsix/kami/module/modules/render/StorageESP.kt @@ -1,5 +1,9 @@ package me.zeroeightsix.kami.module.modules.render +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch +import me.zeroeightsix.kami.event.SafeClientEvent import me.zeroeightsix.kami.event.events.RenderWorldEvent import me.zeroeightsix.kami.module.Module import me.zeroeightsix.kami.setting.ModuleConfig.setting @@ -8,7 +12,7 @@ import me.zeroeightsix.kami.util.color.DyeColors import me.zeroeightsix.kami.util.color.HueCycler import me.zeroeightsix.kami.util.graphics.ESPRenderer import me.zeroeightsix.kami.util.graphics.GeometryMasks -import me.zeroeightsix.kami.util.threads.safeListener +import me.zeroeightsix.kami.util.threads.safeAsyncListener import net.minecraft.entity.Entity import net.minecraft.entity.item.* import net.minecraft.item.ItemShulkerBox @@ -16,103 +20,118 @@ import net.minecraft.tileentity.* import net.minecraft.util.math.AxisAlignedBB import net.minecraftforge.fml.common.gameevent.TickEvent import org.kamiblue.event.listener.listener -import java.util.concurrent.ConcurrentHashMap object StorageESP : Module( name = "StorageESP", description = "Draws an ESP on top of storage units", category = Category.RENDER ) { - private val page = setting("Page", Page.TYPE) + private val page by setting("Page", Page.TYPE) /* Type settings */ - private val chest = setting("Chest", true, { page.value == Page.TYPE }) - private val shulker = setting("Shulker", true, { page.value == Page.TYPE }) - private val enderChest = setting("EnderChest", true, { page.value == Page.TYPE }) - private val frame = setting("ItemFrame", true, { page.value == Page.TYPE }) - private val frameShulker = setting("ItFShulkerOnly", true, { frame.value && page.value == Page.TYPE }) - private val furnace = setting("Furnace", false, { page.value == Page.TYPE }) - private val dispenser = setting("Dispenser", false, { page.value == Page.TYPE }) - private val hopper = setting("Hopper", false, { page.value == Page.TYPE }) - private val cart = setting("Minecart", false, { page.value == Page.TYPE }) + private val chest by setting("Chest", true, { page == Page.TYPE }) + private val shulker by setting("Shulker", true, { page == Page.TYPE }) + private val enderChest by setting("EnderChest", true, { page == Page.TYPE }) + private val frame by setting("ItemFrame", true, { page == Page.TYPE }) + private val withShulkerOnly by setting("WithShulkerOnly", true, { page == Page.TYPE && frame }) + private val furnace by setting("Furnace", false, { page == Page.TYPE }) + private val dispenser by setting("Dispenser", false, { page == Page.TYPE }) + private val hopper by setting("Hopper", false, { page == Page.TYPE }) + private val cart by setting("Minecart", false, { page == Page.TYPE }) /* Color settings */ - private val colorChest = setting("ChestColor", DyeColors.ORANGE, { page.value == Page.COLOR }) - private val colorDispenser = setting("DispenserColor", DyeColors.LIGHT_GRAY, { page.value == Page.COLOR }) - private val colorShulker = setting("ShulkerColor", DyeColors.MAGENTA, { page.value == Page.COLOR }) - private val colorEnderChest = setting("EnderChestColor", DyeColors.PURPLE, { page.value == Page.COLOR }) - private val colorFurnace = setting("FurnaceColor", DyeColors.LIGHT_GRAY, { page.value == Page.COLOR }) - private val colorHopper = setting("HopperColor", DyeColors.GRAY, { page.value == Page.COLOR }) - private val colorCart = setting("CartColor", DyeColors.GREEN, { page.value == Page.COLOR }) - private val colorFrame = setting("FrameColor", DyeColors.ORANGE, { page.value == Page.COLOR }) + private val colorChest by setting("ChestColor", DyeColors.ORANGE, { page == Page.COLOR }) + private val colorDispenser by setting("DispenserColor", DyeColors.LIGHT_GRAY, { page == Page.COLOR }) + private val colorShulker by setting("ShulkerColor", DyeColors.MAGENTA, { page == Page.COLOR }) + private val colorEnderChest by setting("EnderChestColor", DyeColors.PURPLE, { page == Page.COLOR }) + private val colorFurnace by setting("FurnaceColor", DyeColors.LIGHT_GRAY, { page == Page.COLOR }) + private val colorHopper by setting("HopperColor", DyeColors.GRAY, { page == Page.COLOR }) + private val colorCart by setting("CartColor", DyeColors.GREEN, { page == Page.COLOR }) + private val colorFrame by setting("FrameColor", DyeColors.ORANGE, { page == Page.COLOR }) /* Render settings */ - private val filled = setting("Filled", true, { page.value == Page.RENDER }) - private val outline = setting("Outline", true, { page.value == Page.RENDER }) - private val tracer = setting("Tracer", false, { page.value == Page.RENDER }) - private val cull = setting("Culling", true, { page.value == Page.RENDER }) - private val aFilled = setting("FilledAlpha", 31, 0..255, 1, { page.value == Page.RENDER && filled.value }) - private val aOutline = setting("OutlineAlpha", 127, 0..255, 1, { page.value == Page.RENDER && outline.value }) - private val aTracer = setting("TracerAlpha", 200, 0..255, 1, { page.value == Page.RENDER && tracer.value }) - private val thickness = setting("LineThickness", 2.0f, 0.25f..5.0f, 0.25f, { page.value == Page.RENDER }) + private val filled by setting("Filled", true, { page == Page.RENDER }) + private val outline by setting("Outline", true, { page == Page.RENDER }) + private val tracer by setting("Tracer", false, { page == Page.RENDER }) + private val aFilled by setting("FilledAlpha", 31, 0..255, 1, { page == Page.RENDER && filled }) + private val aOutline by setting("OutlineAlpha", 127, 0..255, 1, { page == Page.RENDER && outline }) + private val aTracer by setting("TracerAlpha", 200, 0..255, 1, { page == Page.RENDER && tracer }) + private val thickness by setting("LineThickness", 2.0f, 0.25f..5.0f, 0.25f, { page == Page.RENDER }) private enum class Page { TYPE, COLOR, RENDER } - private val renderList = ConcurrentHashMap>() + override fun getHudInfo(): String { + return renderer.getSize().toString() + } + private var cycler = HueCycler(600) + private val renderer = ESPRenderer() init { listener { - val renderer = ESPRenderer() - renderer.aFilled = if (filled.value) aFilled.value else 0 - renderer.aOutline = if (outline.value) aOutline.value else 0 - renderer.aTracer = if (tracer.value) aTracer.value else 0 - renderer.thickness = thickness.value - for ((box, pair) in renderList) { - renderer.add(box, pair.first, pair.second) - } - renderer.render(true, cull.value) + renderer.render(false) } - safeListener { + safeAsyncListener { + if (it.phase != TickEvent.Phase.START) return@safeAsyncListener + cycler++ - renderList.clear() - for (tileEntity in world.loadedTileEntityList) { - if (tileEntity is TileEntityChest && chest.value - || tileEntity is TileEntityDispenser && dispenser.value - || tileEntity is TileEntityShulkerBox && shulker.value - || tileEntity is TileEntityEnderChest && enderChest.value - || tileEntity is TileEntityFurnace && furnace.value - || tileEntity is TileEntityHopper && hopper.value) { - val box = world.getBlockState(tileEntity.pos).getSelectedBoundingBox(world, tileEntity.pos) - val color = getTileEntityColor(tileEntity) ?: continue - var side = GeometryMasks.Quad.ALL - if (tileEntity is TileEntityChest) { - // Leave only the colliding face and then flip the bits (~) to have ALL but that face - if (tileEntity.adjacentChestZNeg != null) side = (side and GeometryMasks.Quad.NORTH).inv() - if (tileEntity.adjacentChestXPos != null) side = (side and GeometryMasks.Quad.EAST).inv() - if (tileEntity.adjacentChestZPos != null) side = (side and GeometryMasks.Quad.SOUTH).inv() - if (tileEntity.adjacentChestXNeg != null) side = (side and GeometryMasks.Quad.WEST).inv() - } - renderList[box] = Pair(color, side) + renderer.clear() + val cached = ArrayList>() + + coroutineScope { + launch(Dispatchers.Default) { + updateRenderer() + } + launch(Dispatchers.Default) { + updateTileEntities(cached) + } + launch(Dispatchers.Default) { + updateEntities(cached) } } - for (entity in world.loadedEntityList) { - if (entity is EntityItemFrame && frameShulkerOrAny(entity) - || (entity is EntityMinecartChest - || entity is EntityMinecartHopper - || entity is EntityMinecartFurnace) && cart.value) { - val box = entity.renderBoundingBox - val color = getEntityColor(entity) ?: continue - renderList[box] = Pair(color, GeometryMasks.Quad.ALL) - } - } + renderer.replaceAll(cached) } } + private fun updateRenderer() { + renderer.aFilled = if (filled) aFilled else 0 + renderer.aOutline = if (outline) aOutline else 0 + renderer.aTracer = if (tracer) aTracer else 0 + renderer.thickness = thickness + } + + private fun SafeClientEvent.updateTileEntities(list: MutableList>) { + for (tileEntity in world.loadedTileEntityList.toList()) { + if (!checkTileEntityType(tileEntity)) continue + + val box = world.getBlockState(tileEntity.pos).getSelectedBoundingBox(world, tileEntity.pos) + val color = getTileEntityColor(tileEntity) ?: continue + var side = GeometryMasks.Quad.ALL + + if (tileEntity is TileEntityChest) { + // Leave only the colliding face and then flip the bits (~) to have ALL but that face + if (tileEntity.adjacentChestZNeg != null) side = (side and GeometryMasks.Quad.NORTH).inv() + if (tileEntity.adjacentChestXPos != null) side = (side and GeometryMasks.Quad.EAST).inv() + if (tileEntity.adjacentChestZPos != null) side = (side and GeometryMasks.Quad.SOUTH).inv() + if (tileEntity.adjacentChestXNeg != null) side = (side and GeometryMasks.Quad.WEST).inv() + } + + list.add(Triple(box, color, side)) + } + } + + private fun checkTileEntityType(tileEntity: TileEntity) = + chest && tileEntity is TileEntityChest + || dispenser && tileEntity is TileEntityDispenser + || shulker && tileEntity is TileEntityShulkerBox + || enderChest && tileEntity is TileEntityEnderChest + || furnace && tileEntity is TileEntityFurnace + || hopper && tileEntity is TileEntityHopper + private fun getTileEntityColor(tileEntity: TileEntity): ColorHolder? { val color = when (tileEntity) { is TileEntityChest -> colorChest @@ -122,28 +141,38 @@ object StorageESP : Module( is TileEntityFurnace -> colorFurnace is TileEntityHopper -> colorHopper else -> return null - }.value.color + }.color return if (color == DyeColors.RAINBOW.color) { cycler.currentRgb() } else color } + private fun SafeClientEvent.updateEntities(list: MutableList>) { + for (entity in world.loadedEntityList.toList()) { + if (!checkEntityType(entity)) continue + + val box = entity.renderBoundingBox + val color = getEntityColor(entity) ?: continue + + list.add(Triple(box, color, GeometryMasks.Quad.ALL)) + } + } + + private fun checkEntityType(entity: Entity) = + entity is EntityItemFrame && frameShulkerOrAny(entity) + || (entity is EntityMinecartChest || entity is EntityMinecartHopper || entity is EntityMinecartFurnace) && cart + private fun getEntityColor(entity: Entity): ColorHolder? { val color = when (entity) { is EntityMinecartContainer -> colorCart is EntityItemFrame -> colorFrame else -> return null - }.value.color + }.color return if (color == DyeColors.RAINBOW.color) { cycler.currentRgb() } else color } - private fun frameShulkerOrAny(e: EntityItemFrame): Boolean { - return when { - !frame.value -> false - !frameShulker.value -> true - else -> e.displayedItem.getItem() is ItemShulkerBox - } - } + private fun frameShulkerOrAny(entity: EntityItemFrame) = + frame && (!withShulkerOnly || entity.displayedItem.item is ItemShulkerBox) } diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/render/VoidESP.kt b/src/main/java/me/zeroeightsix/kami/module/modules/render/VoidESP.kt index b79e13691..79cd9d739 100644 --- a/src/main/java/me/zeroeightsix/kami/module/modules/render/VoidESP.kt +++ b/src/main/java/me/zeroeightsix/kami/module/modules/render/VoidESP.kt @@ -1,32 +1,32 @@ package me.zeroeightsix.kami.module.modules.render +import kotlinx.coroutines.launch import me.zeroeightsix.kami.event.SafeClientEvent import me.zeroeightsix.kami.event.events.RenderWorldEvent import me.zeroeightsix.kami.module.Module import me.zeroeightsix.kami.setting.ModuleConfig.setting +import me.zeroeightsix.kami.util.TickTimer import me.zeroeightsix.kami.util.color.ColorHolder import me.zeroeightsix.kami.util.graphics.ESPRenderer import me.zeroeightsix.kami.util.graphics.GeometryMasks import me.zeroeightsix.kami.util.math.VectorUtils.distanceTo +import me.zeroeightsix.kami.util.threads.defaultScope import me.zeroeightsix.kami.util.threads.safeListener +import net.minecraft.util.math.AxisAlignedBB import net.minecraft.util.math.BlockPos -import net.minecraftforge.fml.common.gameevent.TickEvent -import org.kamiblue.event.listener.listener object VoidESP : Module( name = "VoidESP", description = "Highlights holes leading to the void", category = Category.RENDER ) { - private val renderDistance = setting("RenderDistance", 6, 4..32, 1) - private val filled = setting("Filled", true) - private val outline = setting("Outline", true) - private val r = setting("Red", 148, 0..255, 1) - private val g = setting("Green", 161, 0..255, 1) - private val b = setting("Blue", 255, 0..255, 1) - private val aFilled = setting("FilledAlpha", 127, 0..255, 1) - private val aOutline = setting("OutlineAlpha", 255, 0..255, 1) - private val renderMode = setting("Mode", Mode.BLOCK_HOLE) + private val filled by setting("Filled", true) + private val outline by setting("Outline", true) + private val color by setting("Color", ColorHolder(148, 161, 255), false) + private val aFilled by setting("FilledAlpha", 127, 0..255, 1) + private val aOutline by setting("OutlineAlpha", 255, 0..255, 1) + private val renderMode by setting("Mode", Mode.BLOCK_HOLE) + private val range by setting("Range", 8, 4..32, 1) @Suppress("UNUSED") private enum class Mode { @@ -34,32 +34,42 @@ object VoidESP : Module( } private val renderer = ESPRenderer() + private val timer = TickTimer() init { - safeListener { - if (it.phase != TickEvent.Phase.END) return@safeListener - renderer.clear() - renderer.aFilled = if (filled.value) aFilled.value else 0 - renderer.aOutline = if (outline.value) aOutline.value else 0 - val color = ColorHolder(r.value, g.value, b.value) - val side = if (renderMode.value != Mode.FLAT) GeometryMasks.Quad.ALL else GeometryMasks.Quad.DOWN - - for (x in -renderDistance.value..renderDistance.value) for (z in -renderDistance.value..renderDistance.value) { - val pos = BlockPos(player.posX + x, 0.0, player.posZ + z) - if (player.distanceTo(pos) > renderDistance.value) continue - if (!isVoid(pos)) continue - val renderPos = if (renderMode.value == Mode.BLOCK_VOID) pos.down() else pos - renderer.add(renderPos, color, side) + safeListener { + if (timer.tick(133L)) { // Avoid running this on a tick + updateRenderer() } - } - - listener { renderer.render(false) } } + private fun SafeClientEvent.updateRenderer() { + renderer.aFilled = if (filled) aFilled else 0 + renderer.aOutline = if (outline) aOutline else 0 + + val color = color.clone() + val side = if (renderMode != Mode.FLAT) GeometryMasks.Quad.ALL else GeometryMasks.Quad.DOWN + + defaultScope.launch { + val cached = ArrayList>() + + for (x in -range..range) for (z in -range..range) { + val pos = BlockPos(player.posX + x, 0.0, player.posZ + z) + if (player.distanceTo(pos) > range) continue + if (!isVoid(pos)) continue + + val renderPos = if (renderMode == Mode.BLOCK_VOID) pos.down() else pos + cached.add(Triple(AxisAlignedBB(renderPos), color, side)) + } + + renderer.replaceAll(cached) + } + } + private fun SafeClientEvent.isVoid(pos: BlockPos) = world.isAirBlock(pos) - && world.isAirBlock(pos.up()) - && world.isAirBlock(pos.up().up()) + && world.isAirBlock(pos.up()) + && world.isAirBlock(pos.up().up()) } diff --git a/src/main/java/me/zeroeightsix/kami/util/combat/SurroundUtils.kt b/src/main/java/me/zeroeightsix/kami/util/combat/SurroundUtils.kt index 7f80dc855..fbfd46768 100644 --- a/src/main/java/me/zeroeightsix/kami/util/combat/SurroundUtils.kt +++ b/src/main/java/me/zeroeightsix/kami/util/combat/SurroundUtils.kt @@ -1,7 +1,10 @@ package me.zeroeightsix.kami.util.combat +import me.zeroeightsix.kami.event.ClientEvent +import me.zeroeightsix.kami.event.SafeClientEvent import me.zeroeightsix.kami.util.EntityUtils.flooredPosition import me.zeroeightsix.kami.util.Wrapper +import me.zeroeightsix.kami.util.threads.toSafe import net.minecraft.block.Block import net.minecraft.entity.Entity import net.minecraft.init.Blocks @@ -39,14 +42,15 @@ object SurroundUtils { return checkHole(entity.flooredPosition) } - @JvmStatic - fun checkHole(pos: BlockPos): HoleType { + fun checkHole(pos: BlockPos) = ClientEvent().toSafe()?.checkHole(pos) ?: HoleType.NONE + + fun SafeClientEvent.checkHole(pos: BlockPos): HoleType { // Must be a 1 * 3 * 1 empty space - if (!mc.world.isAirBlock(pos) || !mc.world.isAirBlock(pos.up()) || !mc.world.isAirBlock(pos.up().up())) return HoleType.NONE + if (!world.isAirBlock(pos) || !world.isAirBlock(pos.up()) || !world.isAirBlock(pos.up().up())) return HoleType.NONE var type = HoleType.BEDROCK for (offset in surroundOffset) { - val block = mc.world.getBlockState(pos.add(offset)).block + val block = world.getBlockState(pos.add(offset)).block if (!checkBlock(block)) { type = HoleType.NONE break @@ -56,7 +60,6 @@ object SurroundUtils { return type } - @JvmStatic fun checkBlock(block: Block): Boolean { return block == Blocks.BEDROCK || block == Blocks.OBSIDIAN || block == Blocks.ENDER_CHEST || block == Blocks.ANVIL } diff --git a/src/main/java/me/zeroeightsix/kami/util/graphics/ESPRenderer.kt b/src/main/java/me/zeroeightsix/kami/util/graphics/ESPRenderer.kt index b81939cf2..aa92f24e3 100644 --- a/src/main/java/me/zeroeightsix/kami/util/graphics/ESPRenderer.kt +++ b/src/main/java/me/zeroeightsix/kami/util/graphics/ESPRenderer.kt @@ -1,15 +1,15 @@ package me.zeroeightsix.kami.util.graphics +import me.zeroeightsix.kami.util.EntityUtils import me.zeroeightsix.kami.util.EntityUtils.getInterpolatedAmount +import me.zeroeightsix.kami.util.Wrapper import me.zeroeightsix.kami.util.color.ColorHolder -import net.minecraft.client.Minecraft import net.minecraft.client.renderer.GlStateManager import net.minecraft.client.renderer.culling.Frustum import net.minecraft.client.renderer.culling.ICamera import net.minecraft.entity.Entity import net.minecraft.util.math.AxisAlignedBB import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Vec3d import org.lwjgl.opengl.GL11.GL_LINES import org.lwjgl.opengl.GL11.GL_QUADS @@ -19,10 +19,8 @@ import org.lwjgl.opengl.GL11.GL_QUADS * Created by Xiaro on 30/07/20 */ class ESPRenderer { - private lateinit var camPos: Vec3d private val frustumCamera: ICamera = Frustum() - private val mc = Minecraft.getMinecraft() - private val toRender = HashMap>() + private var toRender: MutableList> = ArrayList() var aFilled = 0 var aOutline = 0 @@ -58,15 +56,28 @@ class ESPRenderer { } fun add(box: AxisAlignedBB, color: ColorHolder, sides: Int) { - toRender[box] = Pair(color, sides) + add(Triple(box, color, sides)) + } + + fun add(triple: Triple) { + toRender.add(triple) + } + + fun replaceAll(list: MutableList>) { + toRender = list } fun clear() { toRender.clear() } - fun render(clear: Boolean, cull: Boolean = false) { + fun render(clear: Boolean, cull: Boolean = true) { if (toRender.isEmpty() && (aFilled == 0 && aOutline == 0 && aTracer == 0)) return + + val entity = Wrapper.minecraft.renderViewEntity ?: Wrapper.player ?: return + val interpolatedPos = EntityUtils.getInterpolatedPos(entity, KamiTessellator.pTicks()) + frustumCamera.setPosition(interpolatedPos.x, interpolatedPos.y, interpolatedPos.z) + if (through) GlStateManager.disableDepth() if (aFilled != 0) drawList(Type.FILLED, cull) @@ -81,41 +92,39 @@ class ESPRenderer { private fun drawList(type: Type, cull: Boolean = false) { KamiTessellator.begin(if (type == Type.FILLED) GL_QUADS else GL_LINES) - camPos = KamiTessellator.camPos.add(0.0, (-mc.player.eyeHeight).toDouble(), 0.0) // realign camPos to player eye pos - frustumCamera.setPosition(camPos.x, camPos.y, camPos.z) - for ((box, pair) in toRender) when (type) { - Type.FILLED -> drawFilled(cull, box, pair) - Type.OUTLINE -> drawOutline(cull, box, pair) - Type.TRACER -> drawTracer(box, pair) + for ((box, color, sides) in toRender) when (type) { + Type.FILLED -> drawFilled(cull, box, color, sides) + Type.OUTLINE -> drawOutline(cull, box, color, sides) + Type.TRACER -> drawTracer(box, color) } KamiTessellator.render() } - private fun drawFilled(cull: Boolean, box: AxisAlignedBB, pair: Pair) { - val a = (aFilled * (pair.first.a / 255f)).toInt() + private fun drawFilled(cull: Boolean, box: AxisAlignedBB, color: ColorHolder, sides: Int) { + val a = (aFilled * (color.a / 255f)).toInt() if (!cull || frustumCamera.isBoundingBoxInFrustum(box)) { - KamiTessellator.drawBox(box, pair.first, a, pair.second) + KamiTessellator.drawBox(box, color, a, sides) } } - private fun drawOutline(cull: Boolean, box: AxisAlignedBB, pair: Pair) { - val a = (aOutline * (pair.first.a / 255f)).toInt() - val side = if (fullOutline) GeometryMasks.Quad.ALL else pair.second + private fun drawOutline(cull: Boolean, box: AxisAlignedBB, color: ColorHolder, sides: Int) { + val a = (aOutline * (color.a / 255f)).toInt() + val side = if (fullOutline) GeometryMasks.Quad.ALL else sides if (!cull || frustumCamera.isBoundingBoxInFrustum(box)) { - KamiTessellator.drawOutline(box, pair.first, a, side, thickness) + KamiTessellator.drawOutline(box, color, a, side, thickness) } } - private fun drawTracer(box: AxisAlignedBB, pair: Pair) { - val a = (aTracer * (pair.first.a / 255f)).toInt() + private fun drawTracer(box: AxisAlignedBB, color: ColorHolder) { + val a = (aTracer * (color.a / 255f)).toInt() val offset = (tracerOffset - 50) / 100.0 * (box.maxY - box.minY) val offsetBox = box.center.add(0.0, offset, 0.0) - KamiTessellator.drawLineTo(offsetBox, pair.first, a, thickness) + KamiTessellator.drawLineTo(offsetBox, color, a, thickness) } private enum class Type {