From 4bb8f999d15ec6956e7675ccf0f888cd1ea28ee9 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Tue, 28 Jun 2022 19:41:40 +0700 Subject: [PATCH] New item viewer screen, that just does absolutely nothing --- .../mc/otm/network/MatteryNetworking.java | 10 ++ src/main/kotlin/ru/dbotthepony/mc/otm/Ext.kt | 17 +++ .../entity/storage/ItemMonitorBlockEntity.kt | 135 ++++++++++++++++++ .../mc/otm/client/screen/ItemMonitorScreen.kt | 78 ++++++++-- .../otm/client/screen/panels/ButtonPanel.kt | 16 +-- .../mc/otm/menu/ItemMonitorMenu.kt | 25 +++- .../textures/gui/widgets_8.png | Bin 727 -> 731 bytes .../textures/gui/widgets_8.xcf | 4 +- 8 files changed, 264 insertions(+), 21 deletions(-) diff --git a/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java b/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java index f22b49d29..07787bc1a 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java +++ b/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java @@ -8,6 +8,7 @@ import net.minecraftforge.network.PacketDistributor; import net.minecraftforge.network.simple.SimpleChannel; import ru.dbotthepony.mc.otm.OverdriveThatMatters; import ru.dbotthepony.mc.otm.block.entity.EnergyCounterPacket; +import ru.dbotthepony.mc.otm.block.entity.storage.ItemMonitorPlayerSettings; import ru.dbotthepony.mc.otm.container.ItemFilterSlotPacket; import ru.dbotthepony.mc.otm.item.weapon.WeaponScopePacket; import ru.dbotthepony.mc.otm.item.weapon.WeaponFireInputPacket; @@ -304,5 +305,14 @@ public class MatteryNetworking { ItemFilterSlotPacket::play // Optional.of(NetworkDirection.) ); + + CHANNEL.registerMessage( + next_network_id++, + ItemMonitorPlayerSettings.class, + ItemMonitorPlayerSettings::write, + ItemMonitorPlayerSettings.Companion::read, + ItemMonitorPlayerSettings::play + // Optional.of(NetworkDirection.) + ); } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/Ext.kt index dcac7f4b2..330d7737a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/Ext.kt @@ -169,3 +169,20 @@ val ItemStack.tagNotNull: CompoundTag get() = orCreateTag inline var Entity.position: Vec3 get() = position() set(value) { setPos(value) } + +inline val > T.next: T get() { + val values = enumValues() + val next = (ordinal + 1) % values.size + return values[next] +} + +inline val > T.prev: T get() { + val values = enumValues() + var next = ordinal - 1 + + if (next < 0) { + next = values.size - 1 + } + + return values[next] +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt index baabdf6cd..dda0023fc 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt @@ -2,23 +2,127 @@ package ru.dbotthepony.mc.otm.block.entity.storage import net.minecraft.core.BlockPos import net.minecraft.core.Direction +import net.minecraft.nbt.CompoundTag +import net.minecraft.nbt.StringTag +import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.chat.Component import net.minecraft.network.chat.TranslatableComponent import net.minecraft.server.level.ServerLevel +import net.minecraft.server.level.ServerPlayer import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player import net.minecraft.world.inventory.AbstractContainerMenu import net.minecraft.world.level.Level import net.minecraft.world.level.block.state.BlockState import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.util.INBTSerializable import net.minecraftforge.common.util.LazyOptional +import net.minecraftforge.network.NetworkEvent +import org.apache.logging.log4j.LogManager import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage +import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph +import ru.dbotthepony.mc.otm.ifHas import ru.dbotthepony.mc.otm.menu.ItemMonitorMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities +import ru.dbotthepony.mc.otm.set +import java.util.UUID +import java.util.function.Supplier + +class ItemMonitorPlayerSettings : INBTSerializable { + enum class MatchMode { + FUZZY, + EXACT + } + + enum class Target { + SYSTEM, + INVENTORY + } + + enum class Amount { + ONE, + STACK, + FULL + } + + var ingredientMatchingMode: MatchMode = MatchMode.FUZZY + var ingredientPriority = Target.SYSTEM + var resultTarget = Target.INVENTORY + var craftingAmount = Amount.STACK + + override fun serializeNBT(): CompoundTag { + return CompoundTag().also { + it["ingredientMatchingMode"] = ingredientMatchingMode.name + it["ingredientPriority"] = ingredientPriority.name + it["resultTarget"] = resultTarget.name + it["craftingAmount"] = craftingAmount.name + } + } + + override fun deserializeNBT(nbt: CompoundTag) { + nbt.ifHas("ingredientMatchingMode", StringTag::class.java) { ingredientMatchingMode = MatchMode.valueOf(it.asString) } + nbt.ifHas("ingredientPriority", StringTag::class.java) { ingredientPriority = Target.valueOf(it.asString) } + nbt.ifHas("resultTarget", StringTag::class.java) { resultTarget = Target.valueOf(it.asString) } + nbt.ifHas("craftingAmount", StringTag::class.java) { craftingAmount = Amount.valueOf(it.asString) } + } + + fun read(buff: FriendlyByteBuf) { + ingredientMatchingMode = buff.readEnum(MatchMode::class.java) + ingredientPriority = buff.readEnum(Target::class.java) + resultTarget = buff.readEnum(Target::class.java) + craftingAmount = buff.readEnum(Amount::class.java) + } + + fun read(other: ItemMonitorPlayerSettings) { + ingredientMatchingMode = other.ingredientMatchingMode + ingredientPriority = other.ingredientPriority + resultTarget = other.resultTarget + craftingAmount = other.craftingAmount + } + + fun write(buff: FriendlyByteBuf) { + buff.writeEnum(ingredientMatchingMode) + buff.writeEnum(ingredientPriority) + buff.writeEnum(resultTarget) + buff.writeEnum(craftingAmount) + } + + private fun playClient() { + val ply = minecraft.player ?: throw IllegalStateException("Player is missing") + val container = ply.containerMenu as? ItemMonitorMenu ?: return LOGGER.error("Received ItemMonitorPlayerSettings but container is missing or not of right type ({})!", ply.containerMenu) + + container.settings.read(this) + } + + private fun playServer(ply: ServerPlayer) { + val container = ply.containerMenu as? ItemMonitorMenu ?: return LOGGER.error("Received ItemMonitorPlayerSettings from {} but container is missing or not of right type ({})!", ply, ply.containerMenu) + container.settings.read(this) + (container.tile as ItemMonitorBlockEntity).setChangedLight() + } + + fun play(context: Supplier) { + context.get().packetHandled = true + val ply = context.get().sender + + if (ply != null) { + playServer(ply) + } else { + playClient() + } + } + + companion object { + fun read(buff: FriendlyByteBuf): ItemMonitorPlayerSettings { + return ItemMonitorPlayerSettings().also { it.read(buff) } + } + + private val LOGGER = LogManager.getLogger() + } +} class ItemMonitorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.ITEM_MONITOR, p_155229_, p_155230_) { @@ -26,6 +130,37 @@ class ItemMonitorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : override val energy = WorkerEnergyStorage(this) val cell = BasicStorageGraphNode(energy) + val settings = HashMap() + + override fun saveAdditional(nbt: CompoundTag) { + super.saveAdditional(nbt) + + nbt.put("player_settings", CompoundTag().also { + for ((key, value) in this.settings) { + it[key.toString()] = value.serializeNBT() + } + }) + } + + override fun load(nbt: CompoundTag) { + super.load(nbt) + this.settings.clear() + + val settings = nbt.getCompound("player_settings") + + for (key in settings.allKeys) { + val uuid = UUID.fromString(key) + val deserialized = ItemMonitorPlayerSettings() + deserialized.deserializeNBT(settings.getCompound(key)) + + check(this.settings.put(uuid, deserialized) == null) { "Duplicate UUID??? $uuid" } + } + } + + fun getSettings(ply: ServerPlayer): ItemMonitorPlayerSettings { + return settings.computeIfAbsent(ply.uuid) { ItemMonitorPlayerSettings() } + } + fun tick() { batteryChargeLoop() cell.tickEnergyDemanding() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ItemMonitorScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ItemMonitorScreen.kt index 55e5e6952..502065361 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ItemMonitorScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ItemMonitorScreen.kt @@ -5,20 +5,21 @@ import net.minecraft.network.chat.Component import net.minecraft.world.entity.player.Inventory import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Items +import ru.dbotthepony.mc.otm.block.entity.storage.ItemMonitorPlayerSettings +import ru.dbotthepony.mc.otm.client.render.RenderHelper +import ru.dbotthepony.mc.otm.client.render.SkinGrid +import ru.dbotthepony.mc.otm.client.render.UVWindingOrder import ru.dbotthepony.mc.otm.client.screen.panels.* import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel import ru.dbotthepony.mc.otm.menu.ItemMonitorMenu +import ru.dbotthepony.mc.otm.next +import ru.dbotthepony.mc.otm.prev class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Component) : MatteryScreen(menu, inventory, title) { override fun makeMainFrame(): FramePanel { - val frame = object : FramePanel(this@ItemMonitorScreen, null, 0f, 0f, FRAME_WIDTH, FRAME_HEIGHT, getTitle()) { - override fun innerRender(stack: PoseStack, mouse_x: Float, mouse_y: Float, flag: Float) { - super.innerRender(stack, mouse_x, mouse_y, flag) - // ProgressGaugePanel.GAUGE_BACKGROUND.render(stack, 28f + 3 * 18f + 6f, (ITEM_GRID_HEIGHT + 1) * 18f + 16f + 6f) - } - } + val frame = FramePanel(this@ItemMonitorScreen, null, 0f, 0f, FRAME_WIDTH, FRAME_HEIGHT, getTitle()) val topPanel = EditablePanel(this, frame) topPanel.height = ITEM_GRID_HEIGHT * 18f @@ -82,8 +83,32 @@ class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Comp val arrowLine = EditablePanel(this, arrowAndButtons, y = 8f, height = 8f, width = arrowAndButtons.width) - val autoRefillMatchMode = SmallSquareButtonPanel(this, arrowLine) - val refillPriority = SmallSquareButtonPanel(this, arrowLine) + val autoRefillMatchMode = SmallSquareButtonPanel(this, arrowLine, skinElement = { REFILL_MATCH_MODE[menu.settings.ingredientMatchingMode.ordinal] }) { + when (it) { + 0 -> menu.settings.ingredientMatchingMode = menu.settings.ingredientMatchingMode.next + 1 -> menu.settings.ingredientMatchingMode = menu.settings.ingredientMatchingMode.prev + } + + menu.sendSettingsToServer() + } + + val refillPriority = object : SmallSquareButtonPanel(this@ItemMonitorScreen, arrowLine, lambdaOnPress = { + when (it) { + 0 -> menu.settings.ingredientPriority = menu.settings.ingredientPriority.next + 1 -> menu.settings.ingredientPriority = menu.settings.ingredientPriority.prev + } + + menu.sendSettingsToServer() + }) { + override fun innerRender(stack: PoseStack, mouse_x: Float, mouse_y: Float, flag: Float) { + super.innerRender(stack, mouse_x, mouse_y, flag) + + when (menu.settings.ingredientPriority) { + ItemMonitorPlayerSettings.Target.SYSTEM -> ARROW.render(stack, 0f, 0f, width, height, UVWindingOrder.FLIP) + ItemMonitorPlayerSettings.Target.INVENTORY -> ARROW.render(stack) + } + } + } refillPriority.setDockMargin(2f) @@ -101,8 +126,32 @@ class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Comp } } - val whereToPutResult = SmallSquareButtonPanel(this, resultAndButtons, y = 8f) - val howMuchToCraft = SmallSquareButtonPanel(this, resultAndButtons, x = 10f, y = 8f) + object : SmallSquareButtonPanel(this@ItemMonitorScreen, resultAndButtons, y = 8f, lambdaOnPress = { + when (it) { + 0 -> menu.settings.resultTarget = menu.settings.resultTarget.next + 1 -> menu.settings.resultTarget = menu.settings.resultTarget.prev + } + + menu.sendSettingsToServer() + }) { + override fun innerRender(stack: PoseStack, mouse_x: Float, mouse_y: Float, flag: Float) { + super.innerRender(stack, mouse_x, mouse_y, flag) + + when (menu.settings.resultTarget) { + ItemMonitorPlayerSettings.Target.SYSTEM -> ARROW.render(stack, 0f, 0f, width, height, UVWindingOrder.FLIP) + ItemMonitorPlayerSettings.Target.INVENTORY -> ARROW.render(stack) + } + } + } + + SmallSquareButtonPanel(this, resultAndButtons, x = 10f, y = 8f, skinElement = { HOW_MUCH_TO_CRAFT[menu.settings.craftingAmount.ordinal] }) { + when (it) { + 0 -> menu.settings.craftingAmount = menu.settings.craftingAmount.next + 1 -> menu.settings.craftingAmount = menu.settings.craftingAmount.prev + } + + menu.sendSettingsToServer() + } val craftingHistory = GridPanel(this, bottomPanel, width = 3 * 18f, height = 3 * 18f, columns = 3, rows = 3) craftingHistory.dock = Dock.LEFT @@ -133,5 +182,14 @@ class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Comp const val ITEM_GRID_WIDTH = 9 const val ITEM_GRID_HEIGHT = 5 + + val ARROW = SkinGrid.WIDGETS_8[1, 0] + val S = SkinGrid.WIDGETS_8[2, 0] + val F = SkinGrid.WIDGETS_8[3, 0] + val E = SkinGrid.WIDGETS_8[4, 0] + val ONE = SkinGrid.WIDGETS_8[5, 0] + + val HOW_MUCH_TO_CRAFT = listOf(ONE, S, F) + val REFILL_MATCH_MODE = listOf(F, E) } } 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 d7d9a003f..3bc1ea22e 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 @@ -61,8 +61,8 @@ abstract class SquareButtonPanel( y: Float = 0f, width: Float, height: Float, - var skinElement: SkinElement? = null, - val lambdaOnPress: (() -> Unit)? = null, + val skinElement: (() -> SkinElement)? = null, + val lambdaOnPress: ((clickButton: Int) -> Unit)? = null, ) : EditablePanel(screen, parent, x, y, width, height) { protected var pressed = false @@ -91,7 +91,7 @@ abstract class SquareButtonPanel( IDLE.render(stack, 0f, 0f, width, height) } - skinElement?.render(stack, 0f, 0f, width, height) + skinElement?.invoke()?.render(stack, 0f, 0f, width, height) } override fun mouseClickedInner(mouse_x: Double, mouse_y: Double, mouse_click_type: Int): Boolean { @@ -112,7 +112,7 @@ abstract class SquareButtonPanel( pressed = false if (isHovered) { - lambdaOnPress?.invoke() + lambdaOnPress?.invoke(flag) } } @@ -129,8 +129,8 @@ open class LargeSquareButtonPanel( y: Float = 0f, width: Float = SIZE, height: Float = SIZE, - skinElement: SkinElement? = null, - lambdaOnPress: (() -> Unit)? = null, + skinElement: (() -> SkinElement)? = null, + lambdaOnPress: ((clickButton: Int) -> Unit)? = null, ) : SquareButtonPanel(screen, parent, x, y, width, height, skinElement, lambdaOnPress) { final override val IDLE = SkinGrid.WIDGETS_18[0, 0] final override val HOVERED = SkinGrid.WIDGETS_18[1, 0] @@ -148,8 +148,8 @@ open class SmallSquareButtonPanel( y: Float = 0f, width: Float = SIZE, height: Float = SIZE, - skinElement: SkinElement? = null, - lambdaOnPress: (() -> Unit)? = null, + skinElement: (() -> SkinElement)? = null, + lambdaOnPress: ((clickButton: Int) -> Unit)? = null, ) : SquareButtonPanel(screen, parent, x, y, width, height, skinElement, lambdaOnPress) { final override val IDLE = SkinGrid.WIDGETS_8[0, 0] final override val HOVERED = SkinGrid.WIDGETS_8[0, 0] diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ItemMonitorMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ItemMonitorMenu.kt index d73facdc2..001fe444f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ItemMonitorMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ItemMonitorMenu.kt @@ -1,12 +1,17 @@ package ru.dbotthepony.mc.otm.menu +import net.minecraft.server.level.ServerPlayer import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player import net.minecraft.world.item.ItemStack +import net.minecraftforge.network.PacketDistributor import ru.dbotthepony.mc.otm.block.entity.storage.ItemMonitorBlockEntity +import ru.dbotthepony.mc.otm.block.entity.storage.ItemMonitorPlayerSettings import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.menu.data.INetworkedItemViewSupplier import ru.dbotthepony.mc.otm.menu.data.NetworkedItemView +import ru.dbotthepony.mc.otm.network.MatteryNetworking +import ru.dbotthepony.mc.otm.orThrow import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.storage.* @@ -20,6 +25,9 @@ class ItemMonitorMenu @JvmOverloads constructor( private val subscribed: VirtualComponent? private val local: PoweredVirtualComponent? + val settings: ItemMonitorPlayerSettings = tile?.getSettings(inventory.player as ServerPlayer) ?: ItemMonitorPlayerSettings() + private var settingsNetworked = false + override fun getNetworkedItemView(): NetworkedItemView { return view } @@ -27,7 +35,7 @@ class ItemMonitorMenu @JvmOverloads constructor( init { if (tile != null) { subscribed = tile.cell.storageGraph!!.getVirtualComponent(ITEM_STORAGE) - local = PoweredVirtualComponent(subscribed, tile.getCapability(MatteryCapability.ENERGY).resolve().get()) + local = PoweredVirtualComponent(subscribed, tile.getCapability(MatteryCapability.ENERGY).orThrow()) view.setComponent(local) } else { subscribed = null @@ -37,6 +45,16 @@ class ItemMonitorMenu @JvmOverloads constructor( addInventorySlots() } + override fun broadcastFullState() { + super.broadcastFullState() + MatteryNetworking.CHANNEL.send(PacketDistributor.PLAYER.with { ply as ServerPlayer }, settings) + settingsNetworked = true + } + + fun sendSettingsToServer() { + MatteryNetworking.CHANNEL.sendToServer(settings) + } + override fun removed(p_38940_: Player) { super.removed(p_38940_) view.removed() @@ -46,6 +64,11 @@ class ItemMonitorMenu @JvmOverloads constructor( override fun broadcastChanges() { super.broadcastChanges() view.network() + + if (!settingsNetworked) { + MatteryNetworking.CHANNEL.send(PacketDistributor.PLAYER.with { ply as ServerPlayer }, settings) + settingsNetworked = true + } } override fun getWorkingSlotStart(): Int { diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets_8.png b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets_8.png index 900cfef3a5e4dace185262f22a0f5a2d99f31120..4fb4c61b332cd326eed28162abb38d9933b6d3c2 100644 GIT binary patch delta 206 zcmV;<05Sj91=|I%8c>b#7L!rytf^(;Gg-8oO4YLrIfTROC%mEa?Z7svOApTIYq>F0Y1ypT8iHMd(qb&kW0S{_`qlzE-3pmpR>hHw-gCmX~$>Hvj+t07*qo IM6N<$f;r1wa{vGU delta 202 zcmV;*05$*H1=j_zOn=f1g{AmO9)OoHn z0T*h3y^8Po0*