mirror of https://github.com/kami-blue/client
[enhancement] Threaded HoleESP, VoidESP, StorageESP, StashLogger, Search (#1816)
This commit is contained in:
parent
b4467fa0e1
commit
385fb1660d
|
@ -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!")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<TickEvent.ClientTickEvent> { event ->
|
||||
if (event.phase != TickEvent.Phase.END) return@safeAsyncListener
|
||||
safeListener<TickEvent.ClientTickEvent> { event ->
|
||||
if (event.phase != TickEvent.Phase.END) return@safeListener
|
||||
|
||||
val moduleSet = ModuleManager.modules.toSet()
|
||||
|
||||
|
|
|
@ -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,39 +48,47 @@ object HoleESP : Module(
|
|||
private val timer = TickTimer()
|
||||
|
||||
init {
|
||||
listener<RenderWorldEvent> {
|
||||
if (mc.world == null || mc.player == null) return@listener
|
||||
if (timer.tick(133L)) updateRenderer() // Avoid running this on a tick
|
||||
safeListener<RenderWorldEvent> {
|
||||
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
|
||||
|
||||
defaultScope.launch {
|
||||
val cached = ArrayList<Triple<AxisAlignedBB, ColorHolder, Int>>()
|
||||
|
||||
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)
|
||||
|
||||
val holeType = checkHole(pos)
|
||||
if (holeType == SurroundUtils.HoleType.NONE) continue
|
||||
val renderPos = if (renderMode.value == Mode.BLOCK_FLOOR) pos.down() else pos
|
||||
|
||||
val bb = AxisAlignedBB(if (renderMode.value == Mode.BLOCK_FLOOR) pos.down() else pos)
|
||||
|
||||
if (holeType == SurroundUtils.HoleType.OBBY && shouldAddObsidian()) {
|
||||
renderer.add(renderPos, colorObsidian, side)
|
||||
cached.add(Triple(bb, colorObsidian, side))
|
||||
}
|
||||
|
||||
if (holeType == SurroundUtils.HoleType.BEDROCK && shouldAddBedrock()) {
|
||||
renderer.add(renderPos, colorBedrock, side)
|
||||
cached.add(Triple(bb, colorBedrock, side))
|
||||
}
|
||||
}
|
||||
|
||||
renderer.replaceAll(cached)
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldAddObsidian() = holeType.value == HoleType.OBSIDIAN || holeType.value == HoleType.BOTH
|
||||
|
|
|
@ -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<Long, ChunkStats>()
|
||||
private val knownPositions = LinkedHashSet<BlockPos>()
|
||||
|
||||
override fun onEnable() {
|
||||
chunkData.clear()
|
||||
knownPositions.clear()
|
||||
}
|
||||
|
||||
init {
|
||||
safeListener<TickEvent.ClientTickEvent> {
|
||||
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<TileEntity>()
|
||||
|
||||
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)"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<Long, ChunkStats>())
|
||||
private val knownPositions = HashSet<BlockPos>()
|
||||
private val timer = TickTimer(TimeUnit.SECONDS)
|
||||
|
||||
override fun onEnable() {
|
||||
chunkData.clear()
|
||||
knownPositions.clear()
|
||||
}
|
||||
|
||||
init {
|
||||
safeListener<TickEvent.ClientTickEvent> {
|
||||
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<TileEntity>())
|
||||
|
||||
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)"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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<ChunkPos, Thread>()
|
||||
private val chunkThreadPool = Executors.newCachedThreadPool()
|
||||
private val loadedChunks = ConcurrentSet<ChunkPos>()
|
||||
private val mainList = ConcurrentHashMap<ChunkPos, List<BlockPos>>()
|
||||
private val renderList = ConcurrentHashMap<BlockPos, ColorHolder>()
|
||||
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<TickEvent.ClientTickEvent> {
|
||||
if (shouldUpdateChunk()) {
|
||||
updateLoadedChunkList()
|
||||
updateMainList()
|
||||
}
|
||||
|
||||
if (shouldUpdateRender()) {
|
||||
updateRenderList()
|
||||
}
|
||||
}
|
||||
|
||||
listener<RenderWorldEvent> {
|
||||
if (dirty > 1) {
|
||||
dirty = 0
|
||||
renderer.clear()
|
||||
for ((pos, colour) in renderList) renderer.add(pos, colour)
|
||||
}
|
||||
safeListener<RenderWorldEvent> {
|
||||
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<Double, Pair<BlockPos, IBlockState>>()
|
||||
|
||||
coroutineScope {
|
||||
launch {
|
||||
updateAlpha()
|
||||
}
|
||||
launch {
|
||||
val eyePos = player.getPositionEyes(1f)
|
||||
getBlockPosList(eyePos, posMap)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
val renderList = ArrayList<Triple<AxisAlignedBB, ColorHolder, Int>>()
|
||||
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))
|
||||
}
|
||||
|
||||
/* Adds new loaded chunks to the list */
|
||||
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<Double, Pair<BlockPos, IBlockState>>) {
|
||||
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)
|
||||
if (player.distanceTo(chunk.pos) > range + 16) continue
|
||||
|
||||
launch {
|
||||
findBlocksInChunk(chunk, eyePos, map)
|
||||
}
|
||||
delay(1L)
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
private fun updateMainList() {
|
||||
Thread {
|
||||
for (chunkPos in loadedChunks) {
|
||||
val thread = Thread {
|
||||
findBlocksInChunk(chunkPos, searchList.toHashSet())
|
||||
}
|
||||
thread.priority = 1
|
||||
chunkThreads.putIfAbsent(chunkPos, thread)
|
||||
}
|
||||
for (thread in chunkThreads.values) {
|
||||
chunkThreadPool.execute(thread)
|
||||
Thread.sleep(5L)
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
private fun findBlocksInChunk(chunk: Chunk, eyePos: Vec3d, map: MutableMap<Double, Pair<BlockPos, IBlockState>>) {
|
||||
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
|
||||
|
||||
private fun findBlocksInChunk(chunkPos: ChunkPos, blocksToFind: HashSet<String>) {
|
||||
val yRange = IntRange(0, 256)
|
||||
val xRange = IntRange(chunkPos.xStart, chunkPos.xEnd)
|
||||
val zRange = IntRange(chunkPos.zStart, chunkPos.zEnd)
|
||||
val foundBlocks = ArrayList<BlockPos>()
|
||||
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
|
||||
if (block == Blocks.AIR) continue
|
||||
if (!blocksToFind.contains(block.registryName.toString())) continue
|
||||
foundBlocks.add(BlockPos(blockPos))
|
||||
}
|
||||
mainList[chunkPos] = foundBlocks
|
||||
}
|
||||
/* End of main list updating */
|
||||
|
||||
/* Rendering */
|
||||
private fun shouldUpdateRender(): Boolean {
|
||||
return if (System.currentTimeMillis() - startTimeRender < renderUpdate.value) {
|
||||
false
|
||||
} else {
|
||||
startTimeRender = System.currentTimeMillis()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun SafeClientEvent.updateRenderList() {
|
||||
Thread {
|
||||
val cacheDistMap = TreeMap<Double, BlockPos>(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)
|
||||
val pos = BlockPos(x, y, z)
|
||||
val blockState = chunk.getBlockState(pos)
|
||||
val block = blockState.block
|
||||
return if (!customColours.value) {
|
||||
|
||||
if (block == Blocks.AIR) continue
|
||||
if (!searchList.contains(block.registryName.toString())) continue
|
||||
|
||||
val dist = eyePos.distanceTo(pos)
|
||||
if (dist > range) continue
|
||||
|
||||
map[dist] = (pos to blockState)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SafeClientEvent.getBlockColor(pos: BlockPos, blockState: IBlockState): ColorHolder {
|
||||
val block = blockState.block
|
||||
|
||||
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
|
||||
}
|
||||
}
|
|
@ -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,79 +20,98 @@ 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<AxisAlignedBB, Pair<ColorHolder, Int>>()
|
||||
override fun getHudInfo(): String {
|
||||
return renderer.getSize().toString()
|
||||
}
|
||||
|
||||
private var cycler = HueCycler(600)
|
||||
private val renderer = ESPRenderer()
|
||||
|
||||
init {
|
||||
listener<RenderWorldEvent> {
|
||||
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<TickEvent.ClientTickEvent> {
|
||||
safeAsyncListener<TickEvent.ClientTickEvent> {
|
||||
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) {
|
||||
renderer.clear()
|
||||
val cached = ArrayList<Triple<AxisAlignedBB, ColorHolder, Int>>()
|
||||
|
||||
coroutineScope {
|
||||
launch(Dispatchers.Default) {
|
||||
updateRenderer()
|
||||
}
|
||||
launch(Dispatchers.Default) {
|
||||
updateTileEntities(cached)
|
||||
}
|
||||
launch(Dispatchers.Default) {
|
||||
updateEntities(cached)
|
||||
}
|
||||
}
|
||||
|
||||
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<Triple<AxisAlignedBB, ColorHolder, Int>>) {
|
||||
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()
|
||||
|
@ -96,22 +119,18 @@ object StorageESP : Module(
|
|||
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)
|
||||
|
||||
list.add(Triple(box, color, side))
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
|
@ -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<Triple<AxisAlignedBB, ColorHolder, Int>>) {
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -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,30 +34,40 @@ object VoidESP : Module(
|
|||
}
|
||||
|
||||
private val renderer = ESPRenderer()
|
||||
private val timer = TickTimer()
|
||||
|
||||
init {
|
||||
safeListener<TickEvent.ClientTickEvent> {
|
||||
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<RenderWorldEvent> {
|
||||
if (timer.tick(133L)) { // Avoid running this on a tick
|
||||
updateRenderer()
|
||||
}
|
||||
}
|
||||
|
||||
listener<RenderWorldEvent> {
|
||||
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<Triple<AxisAlignedBB, ColorHolder, Int>>()
|
||||
|
||||
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())
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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<AxisAlignedBB, Pair<ColorHolder, Int>>()
|
||||
private var toRender: MutableList<Triple<AxisAlignedBB, ColorHolder, Int>> = 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<AxisAlignedBB, ColorHolder, Int>) {
|
||||
toRender.add(triple)
|
||||
}
|
||||
|
||||
fun replaceAll(list: MutableList<Triple<AxisAlignedBB, ColorHolder, Int>>) {
|
||||
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<ColorHolder, Int>) {
|
||||
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<ColorHolder, Int>) {
|
||||
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<ColorHolder, Int>) {
|
||||
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 {
|
||||
|
|
Loading…
Reference in New Issue