|
| 1 | +/* |
| 2 | + * Copyright 2025 Lambda |
| 3 | + * |
| 4 | + * This program is free software: you can redistribute it and/or modify |
| 5 | + * it under the terms of the GNU General Public License as published by |
| 6 | + * the Free Software Foundation, either version 3 of the License, or |
| 7 | + * (at your option) any later version. |
| 8 | + * |
| 9 | + * This program is distributed in the hope that it will be useful, |
| 10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | + * GNU General Public License for more details. |
| 13 | + * |
| 14 | + * You should have received a copy of the GNU General Public License |
| 15 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 16 | + */ |
| 17 | + |
| 18 | +package com.lambda.module.modules.render |
| 19 | + |
| 20 | +import com.lambda.context.SafeContext |
| 21 | +import com.lambda.event.events.RenderEvent |
| 22 | +import com.lambda.event.listener.SafeListener.Companion.listen |
| 23 | +import com.lambda.graphics.renderer.esp.DirectionMask |
| 24 | +import com.lambda.graphics.renderer.esp.DirectionMask.buildSideMesh |
| 25 | +import com.lambda.graphics.renderer.esp.builders.buildFilled |
| 26 | +import com.lambda.graphics.renderer.esp.builders.buildFilledMesh |
| 27 | +import com.lambda.graphics.renderer.esp.builders.buildOutline |
| 28 | +import com.lambda.graphics.renderer.esp.builders.buildOutlineMesh |
| 29 | +import com.lambda.graphics.renderer.esp.impl.StaticESPRenderer |
| 30 | +import com.lambda.module.Module |
| 31 | +import com.lambda.module.tag.ModuleTag |
| 32 | +import com.lambda.threading.runSafe |
| 33 | +import com.lambda.util.extension.blockColor |
| 34 | +import com.lambda.util.extension.outlineShape |
| 35 | +import com.lambda.util.math.setAlpha |
| 36 | +import com.lambda.util.world.blockEntitySearch |
| 37 | +import com.lambda.util.world.entitySearch |
| 38 | +import net.minecraft.block.entity.BarrelBlockEntity |
| 39 | +import net.minecraft.block.entity.BlastFurnaceBlockEntity |
| 40 | +import net.minecraft.block.entity.BlockEntity |
| 41 | +import net.minecraft.block.entity.BrewingStandBlockEntity |
| 42 | +import net.minecraft.block.entity.ChestBlockEntity |
| 43 | +import net.minecraft.block.entity.DispenserBlockEntity |
| 44 | +import net.minecraft.block.entity.EnderChestBlockEntity |
| 45 | +import net.minecraft.block.entity.FurnaceBlockEntity |
| 46 | +import net.minecraft.block.entity.HopperBlockEntity |
| 47 | +import net.minecraft.block.entity.ShulkerBoxBlockEntity |
| 48 | +import net.minecraft.block.entity.SmokerBlockEntity |
| 49 | +import net.minecraft.entity.Entity |
| 50 | +import net.minecraft.entity.decoration.ItemFrameEntity |
| 51 | +import net.minecraft.entity.vehicle.AbstractMinecartEntity |
| 52 | +import net.minecraft.entity.vehicle.MinecartEntity |
| 53 | +import net.minecraft.util.math.BlockPos |
| 54 | +import java.awt.Color |
| 55 | + |
| 56 | +object StorageESP : Module( |
| 57 | + name = "StorageESP", |
| 58 | + description = "Render storage blocks/entities", |
| 59 | + defaultTags = setOf(ModuleTag.RENDER), |
| 60 | +) { |
| 61 | + private val page by setting("Page", Page.Render) |
| 62 | + |
| 63 | + /* General settings */ |
| 64 | + private val distance by setting("Distance", 64.0, 10.0..256.0, 1.0, "Maximum distance for rendering") { page == Page.General } |
| 65 | + |
| 66 | + /* Render settings */ |
| 67 | + private var drawFaces: Boolean by setting("Draw Faces", true, "Draw faces of blocks") { page == Page.Render }.apply { onValueSet { _, to -> if (!to) drawOutlines = true } } |
| 68 | + private var drawOutlines: Boolean by setting("Draw Outlines", true, "Draw outlines of blocks") { page == Page.Render }.apply { onValueSet { _, to -> if (!to) drawFaces = true } } |
| 69 | + private val outlineMode by setting("Outline Mode", DirectionMask.OutlineMode.AND, "Outline mode") { page == Page.Render } |
| 70 | + private val mesh by setting("Mesh", true, "Connect similar adjacent blocks") { page == Page.Render } |
| 71 | + |
| 72 | + /* Color settings */ |
| 73 | + private val useBlockColor by setting("Use Block Color", true, "Use the color of the block instead") { page == Page.Color } |
| 74 | + private val alpha by setting("Alpha", 0.3, 0.1..1.0, 0.05) { page == Page.Color } |
| 75 | + |
| 76 | + // TODO: |
| 77 | + // val blockColors by setting("Block Colors", mapOf<String, Color>()) { page == Page.Color && !useBlockColor } |
| 78 | + // val renders by setting("Render Blocks", mapOf<String, Boolean>()) { page == Page.General } |
| 79 | + // |
| 80 | + // TODO: Create enum of MapColors |
| 81 | + |
| 82 | + // I used this to extract the colors as rgb format |
| 83 | + //> function extract(color) { |
| 84 | + // ... console.log((color >> 16) & 0xFF) |
| 85 | + // ... console.log((color >> 8) & 0xFF) |
| 86 | + // ... console.log(color & 0xFF) |
| 87 | + // ... } |
| 88 | + |
| 89 | + private val barrelColor by setting("Barrel Color", Color(143, 119, 72)) { page == Page.Color && !useBlockColor } |
| 90 | + private val blastFurnaceColor by setting("Blast Furnace Color", Color(153, 153, 153)) { page == Page.Color && !useBlockColor } |
| 91 | + private val brewingStandColor by setting("Brewing Stand Color", Color(167, 167, 167)) |
| 92 | + private val chestColor by setting("Chest Color", Color(216, 127, 51)) { page == Page.Color && !useBlockColor } |
| 93 | + private val dispenserColor by setting("Dispenser Color", Color(153, 153, 153)) { page == Page.Color && !useBlockColor } |
| 94 | + private val enderChestColor by setting("Ender Chest Color", Color(127, 63, 178)) { page == Page.Color && !useBlockColor } |
| 95 | + private val furnaceColor by setting("Furnace Color", Color(153, 153, 153)) { page == Page.Color && !useBlockColor } |
| 96 | + private val hopperColor by setting("Hopper Color", Color(76, 76, 76)) { page == Page.Color && !useBlockColor } |
| 97 | + private val smokerColor by setting("Smoker Color", Color(112, 112, 112)) { page == Page.Color && !useBlockColor } |
| 98 | + private val shulkerColor by setting("Shulker Color", Color(178, 76, 216)) { page == Page.Color && !useBlockColor } |
| 99 | + private val itemFrameColor by setting("Item Frame Color", Color(216, 127, 51)) { page == Page.Color && !useBlockColor } |
| 100 | + private val cartColor by setting("Minecart Color", Color(102, 127, 51)) { page == Page.Color && !useBlockColor } |
| 101 | + |
| 102 | + private val entities = setOf( |
| 103 | + BarrelBlockEntity::class, |
| 104 | + BlastFurnaceBlockEntity::class, |
| 105 | + BrewingStandBlockEntity::class, |
| 106 | + ChestBlockEntity::class, |
| 107 | + DispenserBlockEntity::class, |
| 108 | + EnderChestBlockEntity::class, |
| 109 | + FurnaceBlockEntity::class, |
| 110 | + HopperBlockEntity::class, |
| 111 | + SmokerBlockEntity::class, |
| 112 | + ShulkerBoxBlockEntity::class, |
| 113 | + AbstractMinecartEntity::class, |
| 114 | + ItemFrameEntity::class, |
| 115 | + MinecartEntity::class, |
| 116 | + ) |
| 117 | + |
| 118 | + init { |
| 119 | + listen<RenderEvent.StaticESP> { event -> |
| 120 | + blockEntitySearch<BlockEntity>(distance) |
| 121 | + .filter { it::class in entities } |
| 122 | + .forEach { event.renderer.build(it, it.pos, excludedSides(it)) } |
| 123 | + |
| 124 | + val mineCarts = entitySearch<AbstractMinecartEntity>(distance) |
| 125 | + val itemFrames = entitySearch<ItemFrameEntity>(distance) |
| 126 | + (mineCarts + itemFrames) |
| 127 | + .forEach { event.renderer.build(it, DirectionMask.ALL) } |
| 128 | + } |
| 129 | + } |
| 130 | + |
| 131 | + private fun SafeContext.excludedSides(blockEntity: BlockEntity): Int { |
| 132 | + val isFullCube = blockEntity.cachedState.isFullCube(world, blockEntity.pos) |
| 133 | + return if (mesh && isFullCube) { |
| 134 | + buildSideMesh(blockEntity.pos) { neighbor -> |
| 135 | + val other = world.getBlockEntity(neighbor) ?: return@buildSideMesh false |
| 136 | + val otherFullCube = other.cachedState.isFullCube(world, other.pos) |
| 137 | + val sameType = blockEntity.cachedState.block == other.cachedState.block |
| 138 | + val searchedFor = other::class in entities |
| 139 | + |
| 140 | + searchedFor && otherFullCube && sameType |
| 141 | + } |
| 142 | + } else DirectionMask.ALL |
| 143 | + } |
| 144 | + |
| 145 | + private fun StaticESPRenderer.build( |
| 146 | + block: BlockEntity, |
| 147 | + pos: BlockPos, |
| 148 | + sides: Int, |
| 149 | + ) = runSafe { |
| 150 | + val color = if (useBlockColor) { |
| 151 | + blockColor(block.cachedState, pos) |
| 152 | + } else getBlockEntityColor(block) ?: return@runSafe |
| 153 | + val shape = outlineShape(block.cachedState, pos) |
| 154 | + |
| 155 | + if (drawFaces) buildFilledMesh(shape, color.setAlpha(alpha), sides) |
| 156 | + if (drawOutlines) buildOutlineMesh(shape, color, sides, outlineMode) |
| 157 | + } |
| 158 | + |
| 159 | + private fun StaticESPRenderer.build( |
| 160 | + entity: Entity, |
| 161 | + sides: Int, |
| 162 | + ) = runSafe { |
| 163 | + val color = getEntityColor(entity) ?: return@runSafe |
| 164 | + |
| 165 | + if (drawFaces) buildFilled(entity.boundingBox, color.setAlpha(alpha), sides) |
| 166 | + if (drawOutlines) buildOutline(entity.boundingBox, color, sides, outlineMode) |
| 167 | + } |
| 168 | + |
| 169 | + private fun getBlockEntityColor(block: BlockEntity?) = |
| 170 | + when (block) { |
| 171 | + is BarrelBlockEntity -> barrelColor |
| 172 | + is BlastFurnaceBlockEntity -> blastFurnaceColor |
| 173 | + is BrewingStandBlockEntity -> brewingStandColor |
| 174 | + is ChestBlockEntity -> chestColor |
| 175 | + is DispenserBlockEntity -> dispenserColor |
| 176 | + is EnderChestBlockEntity -> enderChestColor |
| 177 | + is FurnaceBlockEntity -> furnaceColor |
| 178 | + is HopperBlockEntity -> hopperColor |
| 179 | + is SmokerBlockEntity -> smokerColor |
| 180 | + is ShulkerBoxBlockEntity -> shulkerColor |
| 181 | + else -> null |
| 182 | + } |
| 183 | + |
| 184 | + private fun getEntityColor(entity: Entity?) = |
| 185 | + when (entity) { |
| 186 | + is AbstractMinecartEntity -> cartColor |
| 187 | + is ItemFrameEntity -> itemFrameColor |
| 188 | + else -> null |
| 189 | + } |
| 190 | + |
| 191 | + private enum class Page { |
| 192 | + General, |
| 193 | + Render, |
| 194 | + Color |
| 195 | + } |
| 196 | +} |
0 commit comments