Cosmetic armor support in exosuit gui

This commit is contained in:
DBotThePony 2022-09-24 14:44:36 +07:00
parent 0511802a8c
commit fafa42b9b7
Signed by: DBot
GPG Key ID: DCC23B5715498507
11 changed files with 288 additions and 15 deletions

View File

@ -181,8 +181,10 @@ dependencies {
val the_one_probe_version: String by project val the_one_probe_version: String by project
val mekanism_version: String by project val mekanism_version: String by project
val curios_version: String by project val curios_version: String by project
val cosmetic_armor_reworked_version: String by project
implementation(fg.deobf("top.theillusivec4.curios:curios-forge:${mc_version}-${curios_version}")) implementation(fg.deobf("top.theillusivec4.curios:curios-forge:${mc_version}-${curios_version}"))
implementation(fg.deobf("lain.mods.cos:CosmeticArmorReworked:${mc_version}-${cosmetic_armor_reworked_version}"))
compileOnly(fg.deobf("mezz.jei:jei-${mc_version}-common-api:${jei_version}")) compileOnly(fg.deobf("mezz.jei:jei-${mc_version}-common-api:${jei_version}"))
compileOnly(fg.deobf("mezz.jei:jei-${mc_version}-forge-api:${jei_version}")) compileOnly(fg.deobf("mezz.jei:jei-${mc_version}-forge-api:${jei_version}"))

View File

@ -18,6 +18,7 @@ jupiter_version=5.8.2
the_one_probe_version=6.2.1 the_one_probe_version=6.2.1
mekanism_version=10.3.2.homebaked mekanism_version=10.3.2.homebaked
curios_version=5.1.1.0 curios_version=5.1.1.0
cosmetic_armor_reworked_version=v1
kotlin_for_forge_version=3.1.0 kotlin_for_forge_version=3.1.0
kotlin_version=1.6.10 kotlin_version=1.6.10

View File

@ -12,6 +12,7 @@ import ru.dbotthepony.mc.otm.client.render.Widgets18
import ru.dbotthepony.mc.otm.client.screen.ExoSuitInventoryScreen import ru.dbotthepony.mc.otm.client.screen.ExoSuitInventoryScreen
import ru.dbotthepony.mc.otm.client.screen.panels.LargeRectangleButtonPanel import ru.dbotthepony.mc.otm.client.screen.panels.LargeRectangleButtonPanel
import ru.dbotthepony.mc.otm.client.screen.panels.Panel2Widget import ru.dbotthepony.mc.otm.client.screen.panels.Panel2Widget
import ru.dbotthepony.mc.otm.compat.cos.isCosmeticArmorScreen
import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.registry.AndroidFeatures import ru.dbotthepony.mc.otm.registry.AndroidFeatures
@ -52,7 +53,7 @@ fun onPostScreenInit(event: ScreenEvent.Init.Post) {
val player = minecraft.player?.matteryPlayer ?: return val player = minecraft.player?.matteryPlayer ?: return
val eventScreen = event.screen val eventScreen = event.screen
val screen = if (eventScreen is AbstractContainerScreen<*> && eventScreen.menu is InventoryMenu) eventScreen else return val screen = if (eventScreen is AbstractContainerScreen<*> && (eventScreen.menu is InventoryMenu || eventScreen.isCosmeticArmorScreen)) eventScreen else return
if (player.hasExoSuit) { if (player.hasExoSuit) {
val widget = Panel2Widget(LargeRectangleButtonPanel(screen, null, val widget = Panel2Widget(LargeRectangleButtonPanel(screen, null,

View File

@ -12,12 +12,14 @@ import ru.dbotthepony.mc.otm.client.render.element
import ru.dbotthepony.mc.otm.client.screen.panels.* import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.client.setMousePos import ru.dbotthepony.mc.otm.client.setMousePos
import ru.dbotthepony.mc.otm.client.shouldOpenVanillaInventory import ru.dbotthepony.mc.otm.client.shouldOpenVanillaInventory
import ru.dbotthepony.mc.otm.compat.cos.CosmeticToggleButton
import ru.dbotthepony.mc.otm.compat.curios.curiosSlots import ru.dbotthepony.mc.otm.compat.curios.curiosSlots
import ru.dbotthepony.mc.otm.core.maxScrollDivision import ru.dbotthepony.mc.otm.core.maxScrollDivision
import ru.dbotthepony.mc.otm.menu.ExoSuitInventoryMenu import ru.dbotthepony.mc.otm.menu.ExoSuitInventoryMenu
import ru.dbotthepony.mc.otm.network.ExoSuitMenuOpen import ru.dbotthepony.mc.otm.network.ExoSuitMenuOpen
import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel
import yalter.mousetweaks.api.MouseTweaksDisableWheelTweak import yalter.mousetweaks.api.MouseTweaksDisableWheelTweak
import kotlin.math.cos
@MouseTweaksDisableWheelTweak @MouseTweaksDisableWheelTweak
class ExoSuitInventoryScreen(menu: ExoSuitInventoryMenu) : MatteryScreen<ExoSuitInventoryMenu>(menu, TranslatableComponent("otm.gui.exosuit")) { class ExoSuitInventoryScreen(menu: ExoSuitInventoryMenu) : MatteryScreen<ExoSuitInventoryMenu>(menu, TranslatableComponent("otm.gui.exosuit")) {
@ -103,8 +105,22 @@ class ExoSuitInventoryScreen(menu: ExoSuitInventoryMenu) : MatteryScreen<ExoSuit
armorSlotsStrip.dock = Dock.LEFT armorSlotsStrip.dock = Dock.LEFT
for (slot in menu.armorSlots) { for (slot in menu.armorSlots) {
val panel = SlotPanel(this, armorSlotsStrip, slot) val cosmeticSlot = menu.cosmeticArmorSlots[slot.type]
panel.dock = Dock.TOP
if (cosmeticSlot == null) {
SlotPanel(this, armorSlotsStrip, slot).also {
it.dock = Dock.TOP
}
} else {
FoldableSlotPanel(this, armorSlotsStrip,
SlotPanel(this, null, slot).also {
CosmeticToggleButton(this, it, slot.type)
},
listOf(SlotPanel(this, null, cosmeticSlot))
).also {
it.dock = Dock.TOP
}
}
} }
val playerRectangle = EntityRendererPanel(this, topLine, minecraft!!.player!!) val playerRectangle = EntityRendererPanel(this, topLine, minecraft!!.player!!)

View File

@ -13,7 +13,7 @@ open class EditBoxPanel<out S : Screen>(
width: Float = 0f, width: Float = 0f,
height: Float = 20f, height: Float = 20f,
val defaultText: Component = TextComponent("") val defaultText: Component = TextComponent("")
) : MinecraftWidgetPanel<S, EditBox>(screen, parent, x, y, width, height) { ) : Widget2Panel<S, EditBox>(screen, parent, x, y, width, height) {
override fun makeNew(): EditBox { override fun makeNew(): EditBox {
return object : EditBox(font, 0, 0, width.toInt(), height.toInt().coerceAtMost(20), defaultText) { return object : EditBox(font, 0, 0, width.toInt(), height.toInt().coerceAtMost(20), defaultText) {
override fun isHoveredOrFocused(): Boolean { override fun isHoveredOrFocused(): Boolean {

View File

@ -41,7 +41,7 @@ enum class DockResizeMode(val changeWidth: Boolean, val changeHeight: Boolean) {
ALL(true, true), NONE(false, false), WIDTH(true, false), HEIGHT(false, true) ALL(true, true), NONE(false, false), WIDTH(true, false), HEIGHT(false, true)
} }
interface ISlotPanel<S : Slot> { interface ISlotPanel<out S : Slot> {
val slot: S val slot: S
} }
@ -464,13 +464,10 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
return return
} }
val old = field
field = value field = value
if (value) { onHoverUpdate(old, value)
onHovered()
} else {
onUnHovered()
}
} }
fun unsetHovered() { fun unsetHovered() {
@ -481,6 +478,14 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
} }
} }
protected open fun onHoverUpdate(oldHover: Boolean, newHover: Boolean) {
if (newHover) {
onHovered()
} else {
onUnHovered()
}
}
protected open fun onHovered() {} protected open fun onHovered() {}
protected open fun onUnHovered() {} protected open fun onUnHovered() {}
@ -1468,6 +1473,7 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
var isRemoved = false var isRemoved = false
private set private set
protected open fun beforeRemoved() {}
protected open fun onRemoved() {} protected open fun onRemoved() {}
fun remove() { fun remove() {
@ -1476,6 +1482,7 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
} }
killFocus() killFocus()
beforeRemoved()
if (screen is MatteryScreen<*>) { if (screen is MatteryScreen<*>) {
screen.removePanel(this as EditablePanel<MatteryScreen<*>>) screen.removePanel(this as EditablePanel<MatteryScreen<*>>)

View File

@ -0,0 +1,103 @@
package ru.dbotthepony.mc.otm.client.screen.panels
import net.minecraft.world.inventory.Slot
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
open class FoldableSlotPanel<out S : MatteryScreen<*>, out T : Slot> @JvmOverloads constructor(
screen: S,
parent: EditablePanel<*>?,
val mainSlot: SlotPanel<S, T>,
val extraSlots: Collection<EditablePanel<S>>,
x: Float = 0f,
y: Float = 0f,
width: Float = AbstractSlotPanel.SIZE,
height: Float = AbstractSlotPanel.SIZE,
) : EditablePanel<S>(screen, parent, x, y, width, height), ISlotPanel<T> {
init {
mainSlot.parent = this
mainSlot.dock = Dock.FILL
}
open inner class HoverPanel : BackgroundPanel<S>(
screen,
null,
this@FoldableSlotPanel.absoluteX,
this@FoldableSlotPanel.absoluteY,
width = extraSlots.stream().mapToDouble { (it.width + it.dockMargin.right + it.dockMargin.left).toDouble() }.sum().toFloat() + mainSlot.width + mainSlot.dockMargin.left + mainSlot.dockMargin.right,
height = extraSlots.stream().mapToDouble { (it.height + it.dockMargin.top + it.dockMargin.bottom).toDouble() }.max().orElse(0.0).toFloat().coerceAtLeast(mainSlot.height + mainSlot.dockMargin.top + mainSlot.dockMargin.bottom),
) {
init {
x -= dockPadding.left
y -= dockPadding.top
width += dockPadding.left + dockPadding.right
height += dockPadding.top + dockPadding.bottom
mainSlot.parent = this
mainSlot.dock = Dock.LEFT
for (slot in extraSlots) {
slot.parent = this
slot.dock = Dock.LEFT
}
screen.addPanel(this)
}
override fun beforeRemoved() {
mainSlot.parent = this@FoldableSlotPanel
mainSlot.dock = Dock.FILL
for (slot in extraSlots) {
slot.parent = null
}
this@FoldableSlotPanel.hoverPanel = null
}
override fun onUnHovered() {
remove()
}
override fun tick() {
super.tick()
x = this@FoldableSlotPanel.absoluteX - dockPadding.left
y = this@FoldableSlotPanel.absoluteY - dockPadding.top
}
}
override val slot: T
get() = mainSlot.slot
var hoveringSince: Long? = null
protected set
var hoverPanel: HoverPanel? = null
protected set
override fun onHovered() {
hoveringSince = System.nanoTime()
}
override fun onUnHovered() {
hoveringSince = null
}
override fun beforeRemoved() {
hoverPanel?.remove()
}
override fun tick() {
super.tick()
val hoveringSince = hoveringSince
if (hoveringSince != null && System.nanoTime() - hoveringSince >= MAX_HOVER_TIME && hoverPanel == null && extraSlots.isNotEmpty()) {
hoverPanel = HoverPanel()
}
}
companion object {
const val MAX_HOVER_TIME = 1_000_000_000
}
}

View File

@ -19,7 +19,7 @@ import ru.dbotthepony.mc.otm.client.render.setDrawColor
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
import javax.annotation.Nonnull import javax.annotation.Nonnull
open class SlotPanel<out S : MatteryScreen<*>, T : Slot> @JvmOverloads constructor( open class SlotPanel<out S : MatteryScreen<*>, out T : Slot> @JvmOverloads constructor(
screen: S, screen: S,
parent: EditablePanel<*>?, parent: EditablePanel<*>?,
final override val slot: T, final override val slot: T,

View File

@ -4,11 +4,9 @@ import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.PoseStack import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.client.gui.components.AbstractWidget import net.minecraft.client.gui.components.AbstractWidget
import net.minecraft.client.gui.screens.Screen import net.minecraft.client.gui.screens.Screen
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
import org.lwjgl.opengl.GL11 import org.lwjgl.opengl.GL11
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
abstract class MinecraftWidgetPanel<out S : Screen, T : AbstractWidget>( abstract class Widget2Panel<out S : Screen, T : AbstractWidget>(
screen: S, screen: S,
parent: EditablePanel<*>?, parent: EditablePanel<*>?,
x: Float, x: Float,

View File

@ -0,0 +1,142 @@
package ru.dbotthepony.mc.otm.compat.cos
import com.mojang.blaze3d.platform.InputConstants
import com.mojang.blaze3d.vertex.PoseStack
import lain.mods.cos.impl.ModObjects
import lain.mods.cos.impl.client.gui.GuiCosArmorInventory
import lain.mods.cos.impl.client.gui.GuiCosArmorToggleButton
import lain.mods.cos.impl.network.packet.PacketSetSkinArmor
import net.minecraft.client.gui.screens.Screen
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.Container
import net.minecraft.world.entity.EquipmentSlot
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.InventoryMenu
import net.minecraft.world.inventory.Slot
import net.minecraft.world.item.ItemStack
import net.minecraftforge.fml.ModList
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.client.render.SkinElement
import ru.dbotthepony.mc.otm.client.render.element
import ru.dbotthepony.mc.otm.client.screen.panels.AbstractSlotPanel
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.client.screen.panels.RectangleButtonPanel
import ru.dbotthepony.mc.otm.menu.MatterySlot
val isCosmeticArmorLoaded by lazy {
ModList.get().isLoaded("cosmeticarmorreworked")
}
val Player.cosmeticArmorSlots: Map<EquipmentSlot, Slot>? get() {
if (!isCosmeticArmorLoaded) {
return null
}
return cosmeticArmorSlotsImpl
}
private class CosmeticSlot(container: Container, private val slot: EquipmentSlot, private val player: Player) : MatterySlot(container, when (slot) {
EquipmentSlot.FEET -> 0
EquipmentSlot.LEGS -> 1
EquipmentSlot.CHEST -> 2
EquipmentSlot.HEAD -> 3
else -> throw IllegalArgumentException()
}) {
override fun mayPlace(itemStack: ItemStack): Boolean {
return super.mayPlace(itemStack) && itemStack.canEquip(slot, player)
}
override fun getMaxStackSize(): Int {
return 1
}
override fun getNoItemIcon(): com.mojang.datafixers.util.Pair<ResourceLocation, ResourceLocation>? {
return when (slot) {
EquipmentSlot.FEET -> com.mojang.datafixers.util.Pair.of(InventoryMenu.BLOCK_ATLAS, InventoryMenu.EMPTY_ARMOR_SLOT_BOOTS)
EquipmentSlot.LEGS -> com.mojang.datafixers.util.Pair.of(InventoryMenu.BLOCK_ATLAS, InventoryMenu.EMPTY_ARMOR_SLOT_LEGGINGS)
EquipmentSlot.CHEST -> com.mojang.datafixers.util.Pair.of(InventoryMenu.BLOCK_ATLAS, InventoryMenu.EMPTY_ARMOR_SLOT_CHESTPLATE)
EquipmentSlot.HEAD -> com.mojang.datafixers.util.Pair.of(InventoryMenu.BLOCK_ATLAS, InventoryMenu.EMPTY_ARMOR_SLOT_HELMET)
else -> null
}
}
}
private val Player.cosmeticArmorSlotsImpl: Map<EquipmentSlot, Slot>? get() {
val manager = ModObjects.invMan ?: return null
val container = if (this !is ServerPlayer) {
manager.getCosArmorInventoryClient(uuid)
} else {
manager.getCosArmorInventory(uuid)
}
return mapOf(
EquipmentSlot.HEAD to CosmeticSlot(container, EquipmentSlot.HEAD, this),
EquipmentSlot.CHEST to CosmeticSlot(container, EquipmentSlot.CHEST, this),
EquipmentSlot.LEGS to CosmeticSlot(container, EquipmentSlot.LEGS, this),
EquipmentSlot.FEET to CosmeticSlot(container, EquipmentSlot.FEET, this),
)
}
val Screen.isCosmeticArmorScreen: Boolean get() {
if (!isCosmeticArmorLoaded) {
return false
}
return isCosmeticArmorScreenImpl
}
private val Screen.isCosmeticArmorScreenImpl: Boolean get() {
return this is GuiCosArmorInventory
}
class CosmeticToggleButton<out S : Screen>(
screen: S,
parent: EditablePanel<S>? = null,
index: EquipmentSlot,
x: Float = 0f,
y: Float = 0f,
width: Float = 5f,
height: Float = 5f
) : RectangleButtonPanel<S>(screen, parent, x, y, width, height) {
override val PRESSED: SkinElement
get() = BUTTON_ACTIVE
override val HOVERED: SkinElement
get() = BUTTON_ACTIVE
override val IDLE: SkinElement
get() = BUTTON_INACTIVE
override val DISABLED: SkinElement
get() = BUTTON_INACTIVE
private val index = when (index) {
EquipmentSlot.FEET -> 0
EquipmentSlot.LEGS -> 1
EquipmentSlot.CHEST -> 2
EquipmentSlot.HEAD -> 3
else -> throw IllegalArgumentException()
}
override fun onClick(clickButton: Int) {
if (clickButton == InputConstants.MOUSE_BUTTON_LEFT) {
val inv = ModObjects.invMan.getCosArmorInventoryClient(minecraft.player?.uuid ?: throw ConcurrentModificationException())
inv.setSkinArmor(index, !inv.isSkinArmor(index))
ModObjects.network.sendToServer(PacketSetSkinArmor(index, inv.isSkinArmor(index)))
}
}
override fun innerRender(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float) {
val inv = ModObjects.invMan.getCosArmorInventoryClient(minecraft.player?.uuid ?: throw ConcurrentModificationException())
if (inv.isSkinArmor(index)) {
BUTTON_ACTIVE.render(stack, x, y, width, height)
} else {
BUTTON_INACTIVE.render(stack, x, y, width, height)
}
}
companion object {
val BUTTON_INACTIVE = GuiCosArmorInventory.TEXTURE.element(0f, 176f, 5f, 5f)
val BUTTON_ACTIVE = GuiCosArmorInventory.TEXTURE.element(5f, 176f, 5f, 5f)
}
}

View File

@ -10,6 +10,7 @@ import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.* import net.minecraft.world.inventory.*
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.compat.cos.cosmeticArmorSlots
import ru.dbotthepony.mc.otm.compat.curios.curiosSlots import ru.dbotthepony.mc.otm.compat.curios.curiosSlots
import ru.dbotthepony.mc.otm.container.iterator import ru.dbotthepony.mc.otm.container.iterator
import ru.dbotthepony.mc.otm.network.ExoSuitCarriedPacket import ru.dbotthepony.mc.otm.network.ExoSuitCarriedPacket
@ -85,6 +86,8 @@ class ExoSuitInventoryMenu(val capability: MatteryPlayerCapability) : MatteryMen
} }
} }
val cosmeticArmorSlots: Map<net.minecraft.world.entity.EquipmentSlot, Slot> = ply.cosmeticArmorSlots?.also { it.values.forEach(this::addSlot) } ?: mapOf()
override fun slotsChanged(container: Container) { override fun slotsChanged(container: Container) {
super.slotsChanged(container) super.slotsChanged(container)