From 72dca1457b682b46add8110df4cdd8379d9824ef Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 10 Sep 2022 13:37:31 +0700 Subject: [PATCH] Exosuit effect list, clearDepth(), functional EditablePanel#remove Fixes #78 --- .../mc/otm/client/render/RenderHelper.kt | 115 +++++++++- .../mc/otm/client/render/SkinElement.kt | 44 ++++ .../mc/otm/client/render/UVStuff.kt | 2 + .../otm/client/screen/AndroidStationScreen.kt | 4 +- .../client/screen/ExoSuitInventoryScreen.kt | 3 +- .../client/screen/panels/AbstractSlotPanel.kt | 8 +- .../otm/client/screen/panels/ButtonPanel.kt | 10 +- .../otm/client/screen/panels/EditablePanel.kt | 75 ++++-- .../client/screen/panels/EffectListPanel.kt | 216 ++++++++++++++++++ .../mc/otm/client/screen/panels/Label.kt | 3 + .../mc/otm/client/screen/panels/SlotPanel.kt | 2 +- .../client/screen/widget/MatterGaugePanel.kt | 4 +- .../client/screen/widget/PatternGaugePanel.kt | 4 +- .../client/screen/widget/PowerGaugePanel.kt | 4 +- .../screen/widget/ProgressGaugePanel.kt | 4 +- 15 files changed, 460 insertions(+), 38 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EffectListPanel.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/RenderHelper.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/RenderHelper.kt index 24052188b..5fc44970c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/RenderHelper.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/RenderHelper.kt @@ -1,15 +1,20 @@ package ru.dbotthepony.mc.otm.client.render +import com.mojang.blaze3d.platform.GlStateManager import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.vertex.* import com.mojang.math.Matrix4f import net.minecraft.client.renderer.GameRenderer +import net.minecraft.client.renderer.texture.TextureAtlasSprite import org.lwjgl.opengl.GL11 +import org.lwjgl.opengl.GL11.GL_ALWAYS +import org.lwjgl.opengl.GL11.GL_LESS import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.core.RGBAColor import kotlin.math.acos import kotlin.math.cos import kotlin.math.pow +import kotlin.math.roundToInt import kotlin.math.sin private val identity = Matrix4f().also { it.setIdentity() } @@ -404,7 +409,40 @@ fun drawLine( width: Float ) = drawLine(identity, startX, startY, endX, endY, width) -private data class ScissorRect(val x: Int, val y: Int, val width: Int, val height: Int) +data class ScissorRect(val x: Int, val y: Int, val width: Int, val height: Int) { + fun withinBounds(x: Int, y: Int): Boolean { + return (x in this.x .. this.x + width) && (y in this.y .. this.y + height) + } + + fun cross(x: Int, y: Int, width: Int, height: Int): Boolean { + if (withinBounds(x, y) || withinBounds(x + width, y) || withinBounds(x, y + height) || withinBounds(x + width, y + height)) { + return true + } + + if (y in this.y .. this.y + height) { + if (x < this.x && x + width > this.x + this.width) { + return true + } + } else if (x in this.x .. this.x + width) { + if (y < this.y && y + height > this.y + this.height) { + return true + } + } + + return false + } + + fun crossScaled(x: Float, y: Float, width: Float, height: Float): Boolean { + val scale = minecraft.window.guiScale + return cross((x * scale).roundToInt(), (y * scale).roundToInt(), (width * scale).roundToInt(), (height * scale).roundToInt()) + } + + fun crossScaled(x: Double, y: Double, width: Double, height: Double): Boolean { + val scale = minecraft.window.guiScale + return cross((x * scale).roundToInt(), (y * scale).roundToInt(), (width * scale).roundToInt(), (height * scale).roundToInt()) + } +} + private val scissorStack = ArrayDeque() @Suppress("NAME_SHADOWING") @@ -447,3 +485,78 @@ fun popScissorRect() { RenderSystem.enableScissor(peek.x, y, peek.width, peek.height) } +val currentScissorRect get() = scissorStack.lastOrNull() + +fun TextureAtlasSprite.render( + stack: PoseStack, + x: Float = 0f, + y: Float = 0f, + width: Float = this.width.toFloat(), + height: Float = this.height.toFloat(), + winding: UVWindingOrder = UVWindingOrder.NORMAL +) { + RenderSystem.setShaderTexture(0, atlas().location()) + + if (winding.isIdentity) { + drawTexturedRect(stack.last().pose(), x, y, width, height, u0, v0, u1, v1) + } else { + drawTexturedRect(stack.last().pose(), x, y, width, height, winding.translate(u0, v0, u1, v1)) + } +} + +fun determineTooltipPosition(x: Float, y: Float, width: Float, height: Float): Pair { + val windowWidth = minecraft.window.guiScaledWidth.toFloat() + val windowHeight = minecraft.window.guiScaledHeight.toFloat() + + if (x + width <= windowWidth) { + if (y + height <= windowHeight) { + return x to y + } + + return x to (windowHeight - height) + } else { + if (y + height <= windowHeight) { + return (x - width - 4f) to y + } + + return (x - width - 4f) to (windowHeight - height) + } +} + +/** + * Draws literally nothing to color buffer, but draws to depth buffer. + * + * Allows to fix a fuckton of issues inside GUI. + * + * thanks Mojang + */ +fun clearDepth(stack: PoseStack, x: Float, y: Float, width: Float, height: Float, depth: Float = -600f) { + val oldShader = RenderSystem.getShader() + RenderSystem.setShader(GameRenderer::getPositionShader) + + RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.ZERO, GlStateManager.DestFactor.ONE, GlStateManager.SourceFactor.ZERO, GlStateManager.DestFactor.ONE) + RenderSystem.enableBlend() + + RenderSystem.enableDepthTest() + RenderSystem.depthFunc(GL_ALWAYS) + + val builder = tesselator.builder + + val matrix = stack.last().pose() + + builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION) + builder.vertex(matrix, x, y + height, depth).endVertex() + builder.vertex(matrix, x + width, y + height, depth).endVertex() + builder.vertex(matrix, x + width, y, depth).endVertex() + builder.vertex(matrix, x, y, depth).endVertex() + + BufferUploader.drawWithShader(builder.end()) + + RenderSystem.defaultBlendFunc() + RenderSystem.depthFunc(GL_LESS) + RenderSystem.disableDepthTest() + + if (oldShader != null) { + RenderSystem.setShader { oldShader } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/SkinElement.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/SkinElement.kt index 97435aaee..2892999a1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/SkinElement.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/SkinElement.kt @@ -111,6 +111,17 @@ data class SkinElement @JvmOverloads constructor( require(imageHeight > 0f) { "Invalid image height $imageHeight" } } + /** + * See [ru.dbotthepony.mc.otm.client.render.clearDepth] + */ + fun clearDepth( + stack: PoseStack, + x: Float = 0f, + y: Float = 0f, + width: Float = this.width, + height: Float = this.height, + ) = ru.dbotthepony.mc.otm.client.render.clearDepth(stack, x, y, width, height) + @JvmOverloads fun render( stack: PoseStack, @@ -312,5 +323,38 @@ data class StretchingRectangleElement( bottomLeft.render(stack, x, y + height - bottomLeft.height) bottomRight.render(stack, x + width - bottomRight.width, y + height - bottomLeft.height) } + + companion object { + fun square( + texture: ResourceLocation, + x: Float, + y: Float, + cornerWidth: Float, + cornerHeight: Float, + width: Float, + height: Float, + sideThickness: Float, + imageWidth: Float = 256f, + imageHeight: Float = 256f, + ): StretchingRectangleElement { + val innerThickness = sideThickness.coerceAtLeast(cornerWidth).coerceAtLeast(cornerHeight) + val padding = sideThickness - innerThickness + + return StretchingRectangleElement( + topLeft = texture.element(x, y, cornerWidth, cornerHeight, imageWidth, imageHeight), + topRight = texture.element(x + width - cornerWidth, y, cornerWidth, cornerHeight, imageWidth, imageHeight), + bottomLeft = texture.element(x, y + height - cornerHeight, cornerWidth, cornerHeight, imageWidth, imageHeight), + bottomRight = texture.element(x + width - cornerWidth, y + height - cornerHeight, cornerWidth, cornerHeight, imageWidth, imageHeight), + + top = texture.element(x + cornerWidth, y, width - cornerWidth * 2f, sideThickness, imageWidth, imageHeight), + bottom = texture.element(x + cornerWidth, y + height - sideThickness, width - cornerWidth * 2f, sideThickness, imageWidth, imageHeight), + left = texture.element(x, y, sideThickness, height - cornerHeight * 2f, imageWidth, imageHeight), + right = texture.element(x, y + width - sideThickness, sideThickness, height - cornerHeight * 2f, imageWidth, imageHeight), + + middle = texture.element(x + innerThickness, y + innerThickness, width - innerThickness * 2f, height - innerThickness * 2f, imageWidth, imageHeight), + padding = DockProperty(padding, padding, padding, padding) + ) + } + } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/UVStuff.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/UVStuff.kt index b41f86206..f26b7ede7 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/UVStuff.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/UVStuff.kt @@ -80,6 +80,8 @@ enum class UVWindingOrder( U1_V1_U0_V0(2, 3, 0, 1), // mirror both FLIP_FLOP(2, 3, 0, 1); // mirror both + val isIdentity: Boolean = u0 == 0 && v0 == 1 && u1 == 2 && v1 == 3 + val u0Picker = pickers[u0] val v0Picker = pickers[v0] val u1Picker = pickers[u1] diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/AndroidStationScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/AndroidStationScreen.kt index feaf12aa3..b3dd16177 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/AndroidStationScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/AndroidStationScreen.kt @@ -387,7 +387,7 @@ private class AndroidResearchButton( return true } - override fun innerRenderTooltips(stack: PoseStack, mouse_x: Float, mouse_y: Float, flag: Float): Boolean { + override fun innerRenderTooltips(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float): Boolean { if (isHovered) { val list = ArrayList().also { it.addAll(node.screenTooltipLines) } @@ -409,7 +409,7 @@ private class AndroidResearchButton( } } - screen.renderComponentTooltip(stack, list, mouse_x.toInt(), mouse_y.toInt()) + screen.renderComponentTooltip(stack, list, mouseX.toInt(), mouseY.toInt()) } return isHovered diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExoSuitInventoryScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExoSuitInventoryScreen.kt index d4ea3f74b..4142a4f18 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExoSuitInventoryScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExoSuitInventoryScreen.kt @@ -169,6 +169,8 @@ class ExoSuitInventoryScreen(menu: ExoSuitInventoryMenu) : MatteryScreen> @JvmOverloads constru } } - override fun innerRenderTooltips(stack: PoseStack, mouse_x: Float, mouse_y: Float, flag: Float): Boolean { + override fun innerRenderTooltips(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float): Boolean { if (isHovered) { val itemstack = getItemStack() @@ -104,8 +102,8 @@ abstract class AbstractSlotPanel> @JvmOverloads constru screen.renderComponentTooltip( stack, getItemStackTooltip(itemstack), - mouse_x.toInt(), - mouse_y.toInt(), + mouseX.toInt(), + mouseY.toInt(), font ?: screen.font, itemstack ) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/ButtonPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/ButtonPanel.kt index 11d36f2a6..8cd19dfb3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/ButtonPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/ButtonPanel.kt @@ -318,13 +318,13 @@ abstract class EnumRectangleButtonPanel>( } } - override fun innerRenderTooltips(stack: PoseStack, mouse_x: Float, mouse_y: Float, flag: Float): Boolean { + override fun innerRenderTooltips(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float): Boolean { if (!isHovered && !isTrappingMouseInput()) { - return super.innerRenderTooltips(stack, mouse_x, mouse_y, flag) + return super.innerRenderTooltips(stack, mouseX, mouseY, partialTick) } if (mainTooltip == null && tooltipMapping.size == 0) { - return super.innerRenderTooltips(stack, mouse_x, mouse_y, flag) + return super.innerRenderTooltips(stack, mouseX, mouseY, partialTick) } val listing = ArrayList() @@ -345,8 +345,8 @@ abstract class EnumRectangleButtonPanel>( screen.renderComponentTooltip( stack, listing, - mouse_x.toInt(), - mouse_y.toInt(), + mouseX.toInt(), + mouseY.toInt(), font ) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt index 144f850b5..ecb5a5576 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt @@ -3,7 +3,6 @@ package ru.dbotthepony.mc.otm.client.screen.panels import com.google.common.collect.ImmutableList import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.vertex.PoseStack -import net.minecraft.client.Minecraft import net.minecraft.client.gui.Font import net.minecraft.client.gui.components.events.GuiEventListener import net.minecraft.client.gui.screens.Screen @@ -12,13 +11,13 @@ import net.minecraft.world.inventory.Slot import org.apache.logging.log4j.LogManager import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.client.moveMousePosScaled +import ru.dbotthepony.mc.otm.client.render.currentScissorRect import ru.dbotthepony.mc.otm.client.render.popScissorRect import ru.dbotthepony.mc.otm.client.render.pushScissorRect import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import java.util.* import kotlin.collections.ArrayList import kotlin.math.max -import kotlin.math.roundToInt @JvmRecord data class ScreenPos(val x: Float, val y: Float) @@ -367,12 +366,26 @@ open class EditablePanel @JvmOverloads constructor( } protected open fun innerRender(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float) {} - protected open fun innerRenderTooltips(stack: PoseStack, mouse_x: Float, mouse_y: Float, flag: Float): Boolean { + protected open fun innerRenderTooltips(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float): Boolean { return false } fun isVisible(): Boolean { - return visible && visibleAsChildren + return visible && visibleAsChildren && !isRemoved + } + + fun isScissored(): Boolean { + var parent = parent + + while (parent != null) { + if (parent.scissor) { + return true + } + + parent = parent.parent + } + + return false } fun render(poseStack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float): Float { @@ -408,7 +421,7 @@ open class EditablePanel @JvmOverloads constructor( val scissor = this.scissor if (scissor) { - val scale = Minecraft.getInstance().window.guiScale + val scale = minecraft.window.guiScale pushScissorRect( (absoluteX * scale).toInt(), @@ -418,10 +431,16 @@ open class EditablePanel @JvmOverloads constructor( ) } - poseStack.pushPose() - poseStack.translate(absoluteX.toDouble(), absoluteY.toDouble(), accumulatedDepth.toDouble()) - innerRender(poseStack, mouseX, mouseY, partialTick) - poseStack.popPose() + val currentScissorRect = currentScissorRect + + if (currentScissorRect == null || currentScissorRect.crossScaled(absoluteX, absoluteY, width, height)) { + // do not render if we are getting cut off by screen scissor + poseStack.pushPose() + poseStack.translate(absoluteX.toDouble(), absoluteY.toDouble(), accumulatedDepth.toDouble()) + RenderSystem.setShaderColor(1f, 1f, 1f, 1f) + innerRender(poseStack, mouseX, mouseY, partialTick) + poseStack.popPose() + } for (child in children) { if (child.isVisible()) { @@ -429,7 +448,6 @@ open class EditablePanel @JvmOverloads constructor( child.absoluteX = absoluteX + child.x + xOffset child.absoluteY = absoluteY + child.y + yOffset - RenderSystem.setShaderColor(1f, 1f, 1f, 1f) depth = max(depth, child.render(poseStack, mouseX, mouseY, partialTick)) } } @@ -442,6 +460,10 @@ open class EditablePanel @JvmOverloads constructor( } open fun tickHover(mouseX: Float, mouseY: Float): Boolean { + if (isRemoved) { + return false + } + if ((boundingHeight > height || boundingWidth > width || boundingX < 0 || boundingY < 0) && parent == null) { var hit = false @@ -469,6 +491,10 @@ open class EditablePanel @JvmOverloads constructor( } fun findSlot(mouseX: Float, mouseY: Float): Pair { + if (!isVisible()) { + return false to null + } + if (!acceptMouseInput) { return (mouseX >= absoluteX && mouseX <= absoluteX + width && @@ -509,6 +535,12 @@ open class EditablePanel @JvmOverloads constructor( return false } + val currentScissorRect = currentScissorRect + + if (currentScissorRect != null && !currentScissorRect.crossScaled(absoluteX, absoluteY, width, height)) { + return false + } + for (child in children) { if (child.isVisible() && child.renderTooltips(stack, mouseX, mouseY, partialTick)) { return true @@ -1164,34 +1196,42 @@ open class EditablePanel @JvmOverloads constructor( open fun tick() { tick++ - for (child in children) { + for (child in Array(children.size) { children[it] }) { child.tick() } } - var isRemoved = false private set protected open fun onRemoved() {} fun remove() { - if (isRemoved || screen !is MatteryScreen<*>) { + if (isRemoved) { return } killFocus() - screen.removePanel(this as EditablePanel>) - for (child in children) { + if (screen is MatteryScreen<*>) { + screen.removePanel(this as EditablePanel>) + } + + for (child in Array(children.size) { children[it] }) { child.remove() } + parent = null + onRemoved() isRemoved = true } fun popup() { + if (isRemoved) { + return + } + if (screen is MatteryScreen<*>) { screen.popup(this as EditablePanel>) } @@ -1212,4 +1252,9 @@ open class EditablePanel @JvmOverloads constructor( fun mouseToCenter() { moveMousePosScaled(absoluteX + width / 2f, absoluteY + height / 2f) } + + /** + * See [ru.dbotthepony.mc.otm.client.render.clearDepth] + */ + fun clearDepth(stack: PoseStack, x: Float = 0f, y: Float = 0f, width: Float = this.width, height: Float = this.height) = ru.dbotthepony.mc.otm.client.render.clearDepth(stack, x, y, width, height) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EffectListPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EffectListPanel.kt new file mode 100644 index 000000000..9ea1af431 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EffectListPanel.kt @@ -0,0 +1,216 @@ +package ru.dbotthepony.mc.otm.client.screen.panels + +import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.vertex.PoseStack +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap +import it.unimi.dsi.fastutil.objects.Object2ObjectFunction +import net.minecraft.client.gui.screens.Screen +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen +import net.minecraft.world.effect.MobEffect +import net.minecraft.world.effect.MobEffectInstance +import net.minecraft.world.effect.MobEffectUtil +import net.minecraft.world.entity.LivingEntity +import ru.dbotthepony.mc.otm.client.minecraft +import ru.dbotthepony.mc.otm.client.render.TextAlign +import ru.dbotthepony.mc.otm.client.render.determineTooltipPosition +import ru.dbotthepony.mc.otm.client.render.drawAligned +import ru.dbotthepony.mc.otm.client.render.element +import ru.dbotthepony.mc.otm.client.render.render +import ru.dbotthepony.mc.otm.core.RGBAColor +import ru.dbotthepony.mc.otm.core.TranslatableComponent +import ru.dbotthepony.mc.otm.core.maxScrollDivision +import java.util.stream.Collectors + +open class EffectListPanel @JvmOverloads constructor( + screen: S, + parent: EditablePanel<*>?, + val entity: LivingEntity, + x: Float = 0f, + y: Float = 0f, + gridWidth: Int = 2, + gridHeight: Int = 2, +) : EditablePanel(screen, parent, x, y, gridWidth * (SQUARE_THIN.width + 2f), gridHeight * (SQUARE_THIN.height + 2f)) { + val scroll: DiscreteScrollBarPanel = DiscreteScrollBarPanel(screen, this, this::calculateMaxScroll, this::onScrolled, height = height) + + var gridWidth: Int = gridWidth + set(value) { + if (field == value) + return + + field = value + width = value * (SQUARE_THIN.width + 2f) + canvas.invalidateLayout() + } + + var gridHeight: Int = gridHeight + set(value) { + if (field == value) + return + + field = value + height = value * (SQUARE_THIN.height + 2f) + canvas.invalidateLayout() + } + + var autoAlignOnScrollbarShow = true + + init { + scroll.visible = false + scissor = true + } + + open inner class EffectSquare( + val effect: MobEffectInstance, + x: Float = 0f, + y: Float = 0f, + width: Float = SQUARE_THIN.width, + height: Float = SQUARE_THIN.height, + ) : EditablePanel(screen, this@EffectListPanel.canvas, x, y, width, height) { + override fun mouseScrolledInner(x: Double, y: Double, scroll: Double): Boolean { + if (this@EffectListPanel.scroll.visible) { + this@EffectListPanel.scroll.mouseScrolledInner(x, y, scroll) + } + + return true + } + + override fun tick() { + super.tick() + + if (effect.duration <= 0) { + remove() + } + } + + override fun innerRender(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float) { + clearDepth(stack) + SQUARE_THIN.render(stack, width = width, height = height) + + RenderSystem.setShaderColor(1f, 1f, 1f, 0.5f) + minecraft.mobEffectTextures.get(effect.effect).render(stack, x = 3f, y = 3f, width = width - 6f, height = height - 6f) + + RenderSystem.setShaderColor(1f, 1f, 1f, 1f) + font.drawAligned(stack, MobEffectUtil.formatDuration(effect, 1.0f), TextAlign.CENTER_CENTER, width / 2f + 0.5f, height / 2f, RGBAColor.WHITE) + } + + override fun innerRenderTooltips(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float): Boolean { + if (isHovered) { + val (x, y) = determineTooltipPosition(mouseX + 4f, mouseY - 12f, BAR.width, BAR.height) + + BAR.clearDepth(stack, x, y) + BAR.render(stack, x, y) + + val renderWidth = 18f + val renderHeight = 18f + + minecraft.mobEffectTextures.get(effect.effect).render( + stack, + x = x + 8f, + y = y + BAR.height / 2f - renderHeight / 2f, + width = renderWidth, + height = renderHeight) + + val name = effect.effect.displayName.copy() + + if (effect.amplifier in 1 .. 9) { + name.append(" ").append(TranslatableComponent("enchantment.level.${effect.amplifier + 1}")) + } else if (effect.amplifier > 9) { + name.append(" ${effect.amplifier + 1}") + } + + font.drawAligned(stack, name, TextAlign.TOP_LEFT, x + renderWidth + 12f, y + 8f, RGBAColor.WHITE) + font.drawAligned(stack, MobEffectUtil.formatDuration(effect, 1.0f), TextAlign.TOP_LEFT, x + renderWidth + 12f, y + 8f + font.lineHeight + 2f, 8355711) + } + + return isHovered + } + } + + protected val effectButtons: MutableMap = Object2ObjectArrayMap() + + fun calculateMaxScroll(scrollBarPanel: DiscreteScrollBarPanel<*>): Int { + return maxScrollDivision(entity.activeEffects.size, gridWidth) + } + + fun onScrolled(scrollBarPanel: DiscreteScrollBarPanel<*>, oldScroll: Int, newScroll: Int) { + canvas.yOffset = newScroll * -26f + } + + override fun tick() { + for (effect in entity.activeEffects) { + effectButtons.computeIfAbsent(effect.effect, Object2ObjectFunction { + EffectSquare(effect) + }) + } + + super.tick() + } + + val canvas = object : EditablePanel(screen, this@EffectListPanel, 0f, 0f, width, height) { + override fun performLayout() { + super.performLayout() + + val sorted = children.stream().filter { it is EffectSquare }.collect(Collectors.toList()) as MutableList.EffectSquare> + + sorted.sortWith { a, b -> + a.effect.duration.compareTo(b.effect.duration) + } + + @Suppress("name_shadowing") + var y = 0 + @Suppress("name_shadowing") + var x = 0 + + for (panel in sorted) { + panel.setPos(x * 26f, y * 26f) + + x++ + + if (x >= gridWidth) { + x = 0 + y++ + } + } + + onSortedEffectPanels(sorted) + } + + override fun mouseScrolledInner(x: Double, y: Double, scroll: Double): Boolean { + if (this@EffectListPanel.scroll.visible) { + this@EffectListPanel.scroll.mouseScrolledInner(x, y, scroll) + } + + return true + } + } + + fun onSortedEffectPanels(sorted: List) { + if (sorted.size > (gridHeight * gridWidth) && !scroll.visible) { + scroll.visible = true + + if (autoAlignOnScrollbarShow) { + this.x -= scroll.width + 2f + canvas.x = scroll.width + 2f + this.width += scroll.width + 2f + } + + scroll.scroll = scroll.scroll + } else if (sorted.size <= (gridHeight * gridWidth) && scroll.visible) { + scroll.visible = false + scroll.scroll = 0 + + if (autoAlignOnScrollbarShow) { + this.x += scroll.width + 2f + canvas.x = 0f + this.width -= scroll.width + 2f + } + } + } + + companion object { + val BAR = AbstractContainerScreen.INVENTORY_LOCATION.element(0f, 166f, 120f, 32f) + val SQUARE = AbstractContainerScreen.INVENTORY_LOCATION.element(0f, 198f, 32f, 32f) + val SQUARE_THIN = AbstractContainerScreen.INVENTORY_LOCATION.element(141f, 166f, 24f, 24f) + val SQUARE_THIN_HIGHLIGHT = AbstractContainerScreen.INVENTORY_LOCATION.element(165f, 166f, 24f, 24f) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/Label.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/Label.kt index dd4a58e2e..bd701138d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/Label.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/Label.kt @@ -3,6 +3,7 @@ package ru.dbotthepony.mc.otm.client.screen.panels import com.mojang.blaze3d.vertex.PoseStack import net.minecraft.client.gui.screens.Screen import net.minecraft.network.chat.Component +import ru.dbotthepony.mc.otm.client.render.clearDepth import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.RGBAColor import ru.dbotthepony.mc.otm.client.screen.MatteryScreen @@ -30,6 +31,8 @@ open class Label @JvmOverloads constructor( var color = RGBAColor.SLATE_GRAY override fun innerRender(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float) { + clearDepth(stack) + if (shadow) { font.draw(stack, text, shadowX, shadowY, shadowColor.toInt()) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/SlotPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/SlotPanel.kt index 97c1bb88c..665797ef5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/SlotPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/SlotPanel.kt @@ -109,7 +109,7 @@ open class SlotPanel, T : Slot> @JvmOverloads construct } } - override fun innerRenderTooltips(@Nonnull stack: PoseStack, mouse_x: Float, mouse_y: Float, flag: Float): Boolean { + override fun innerRenderTooltips(@Nonnull stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float): Boolean { // no op, screen does it for us (completely) return false } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/MatterGaugePanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/MatterGaugePanel.kt index 5ccde7a24..a2c403ca0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/MatterGaugePanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/MatterGaugePanel.kt @@ -80,9 +80,9 @@ open class MatterGaugePanel @JvmOverloads constructor( BufferUploader.drawWithShader(builder.end()) } - override fun innerRenderTooltips(stack: PoseStack, mouse_x: Float, mouse_y: Float, flag: Float): Boolean { + override fun innerRenderTooltips(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float): Boolean { if (isHovered) { - screen.renderComponentTooltip(stack, makeTooltip(), mouse_x.toInt(), mouse_y.toInt()) + screen.renderComponentTooltip(stack, makeTooltip(), mouseX.toInt(), mouseY.toInt()) return true } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/PatternGaugePanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/PatternGaugePanel.kt index 8c62abd65..92e79a160 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/PatternGaugePanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/PatternGaugePanel.kt @@ -37,9 +37,9 @@ open class PatternGaugePanel @JvmOverloads constructor( GAUGE_FOREGROUND.renderPartial(stack, y = this.height - height, height = height, winding = UVWindingOrder.U0_V1_U1_V0) } - override fun innerRenderTooltips(stack: PoseStack, mouse_x: Float, mouse_y: Float, flag: Float): Boolean { + override fun innerRenderTooltips(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float): Boolean { if (isHovered) { - screen.renderComponentTooltip(stack, makeTooltip(), mouse_x.toInt(), mouse_y.toInt()) + screen.renderComponentTooltip(stack, makeTooltip(), mouseX.toInt(), mouseY.toInt()) return true } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/PowerGaugePanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/PowerGaugePanel.kt index 2a474f4bd..01dc48458 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/PowerGaugePanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/PowerGaugePanel.kt @@ -51,9 +51,9 @@ open class PowerGaugePanel @JvmOverloads constructor( } } - override fun innerRenderTooltips(stack: PoseStack, mouse_x: Float, mouse_y: Float, flag: Float): Boolean { + override fun innerRenderTooltips(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float): Boolean { if (isHovered) { - screen.renderComponentTooltip(stack, makeTooltip(), mouse_x.toInt(), mouse_y.toInt()) + screen.renderComponentTooltip(stack, makeTooltip(), mouseX.toInt(), mouseY.toInt()) return true } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/ProgressGaugePanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/ProgressGaugePanel.kt index b524e919a..ffb87bd2c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/ProgressGaugePanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/ProgressGaugePanel.kt @@ -68,9 +68,9 @@ open class ProgressGaugePanel @JvmOverloads constructor( } } - override fun innerRenderTooltips(stack: PoseStack, mouse_x: Float, mouse_y: Float, flag: Float): Boolean { + override fun innerRenderTooltips(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float): Boolean { if (isHovered) { - screen.renderComponentTooltip(stack, makeTooltip(), mouse_x.toInt(), mouse_y.toInt()) + screen.renderComponentTooltip(stack, makeTooltip(), mouseX.toInt(), mouseY.toInt()) return true }