Terminal: Shift-click transferring, draw slot modes

This commit is contained in:
Shadowfacts 2021-02-11 00:10:24 -05:00
parent dedfcae79b
commit 1c3e358f2e
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
8 changed files with 158 additions and 16 deletions

View File

@ -0,0 +1,26 @@
package net.shadowfacts.phycon.mixin.client;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.screen.slot.Slot;
import net.shadowfacts.phycon.network.block.terminal.TerminalScreen;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
/**
* @author shadowfacts
*/
@Mixin(HandledScreen.class)
public class MixinHandledScreen {
@Inject(method = "drawSlot(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/screen/slot/Slot;)V", at = @At(value = "INVOKE", target = "enableDepthTest()V"))
private void drawSlot(MatrixStack matrixStack, Slot slot, CallbackInfo ci) {
if ((Object)this instanceof TerminalScreen) {
TerminalScreen self = (TerminalScreen)(Object)this;
self.drawSlotUnderlay(matrixStack, slot);
}
}
}

View File

@ -238,7 +238,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), Invento
override fun fromTag(state: BlockState, tag: CompoundTag) {
super.fromTag(state, tag)
internalBuffer.fromTag(tag.getList("InternalBuffer", 10))
internalBuffer.fromTag(tag.getCompound("InternalBuffer"))
}
override fun toClientTag(tag: CompoundTag): CompoundTag {
@ -254,14 +254,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), Invento
}
override fun fromClientTag(tag: CompoundTag) {
tag.getList("InternalBuffer", 10)?.also { list ->
if (list.isNotEmpty()) {
internalBuffer.fromTag(list)
} else {
// todo: should this clear or just do nothing?
internalBuffer.clear()
}
}
internalBuffer.fromTag(tag.getCompound("InternalBuffer"))
val list = tag.getList("CachedNetItems", 10)
cachedNetItems.clear()
for (entryTag in list) {

View File

@ -3,6 +3,10 @@ package net.shadowfacts.phycon.network.block.terminal
import alexiil.mc.lib.attributes.item.ItemStackUtil
import net.minecraft.inventory.SimpleInventory
import net.minecraft.item.ItemStack
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.IntArrayTag
import net.shadowfacts.phycon.util.fromTag
import net.shadowfacts.phycon.util.toTag
import kotlin.math.min
/**
@ -14,8 +18,21 @@ class TerminalBufferInventory(size: Int): SimpleInventory(size) {
TO_NETWORK, FROM_NETWORK, UNASSIGNED
}
// todo: modes should be saved to NBT
private val modes = Array(size) { Mode.UNASSIGNED }
var modes = Array(size) { Mode.UNASSIGNED }
private set
fun toTag(): CompoundTag {
val compound = CompoundTag()
compound.put("Inventory", (this as SimpleInventory).toTag())
compound.put("Modes", IntArrayTag(modes.map(Mode::ordinal)))
return compound
}
fun fromTag(tag: CompoundTag) {
val inventory = tag.getList("Inventory", 10)
(this as SimpleInventory).fromTag(inventory)
tag.getIntArray("Modes").forEachIndexed { i, it -> modes[i] = Mode.values()[it] }
}
fun insertFromNetwork(stack: ItemStack): ItemStack {
var remaining = stack.copy()
@ -57,6 +74,11 @@ class TerminalBufferInventory(size: Int): SimpleInventory(size) {
super.setStack(slot, stack)
}
override fun clear() {
super.clear()
this.modes = Array(size()) { Mode.UNASSIGNED }
}
fun getMode(slot: Int): Mode {
return modes[slot]
}

View File

@ -1,9 +1,11 @@
package net.shadowfacts.phycon.network.block.terminal
import com.mojang.blaze3d.platform.GlStateManager
import net.minecraft.client.gui.DrawableHelper
import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.screen.slot.Slot
import net.minecraft.text.LiteralText
import net.minecraft.text.Text
import net.minecraft.util.Identifier
@ -38,4 +40,19 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
}
@ExperimentalUnsignedTypes
fun drawSlotUnderlay(matrixStack: MatrixStack, slot: Slot) {
if (!handler.isBufferSlot(slot.id)) {
return
}
val mode = handler.terminal.internalBuffer.getMode(slot.id - handler.bufferSlotsStart)
val color: UInt = when (mode) {
TerminalBufferInventory.Mode.TO_NETWORK -> 0xFFFF0000u
TerminalBufferInventory.Mode.FROM_NETWORK -> 0xFF00FF00u
else -> return
}
DrawableHelper.fill(matrixStack, slot.x, slot.y, slot.x + 16, slot.y + 16, color.toInt())
}
}

View File

@ -64,7 +64,7 @@ class TerminalScreenHandler(syncId: Int, playerInv: PlayerInventory, val termina
}
override fun onSlotClick(slotId: Int, clickData: Int, actionType: SlotActionType, player: PlayerEntity): ItemStack {
if (slotId in 0 until 54) {
if (isNetworkSlot(slotId)) {
// the slot clicked was one of the network stacks
if (actionType == SlotActionType.QUICK_MOVE) {
val stack = slots[slotId].stack
@ -83,14 +83,79 @@ class TerminalScreenHandler(syncId: Int, playerInv: PlayerInventory, val termina
}
}
return ItemStack.EMPTY
} else if (slotId in 54 until 72) {
} else if (isBufferSlot(slotId)) {
// internal buffer
if (actionType == SlotActionType.PICKUP && !player.inventory.cursorStack.isEmpty) {
// todo: why does this think it's quick_craft sometimes?
if ((actionType == SlotActionType.PICKUP || actionType == SlotActionType.QUICK_CRAFT) && !player.inventory.cursorStack.isEmpty) {
// placing cursor stack into buffer
val bufferSlot = slotId - 54 // subtract 54 to convert the handler slot ID to a valid buffer index
val bufferSlot = slotId - bufferSlotsStart // subtract 54 to convert the handler slot ID to a valid buffer index
terminal.internalBuffer.markSlot(bufferSlot, TerminalBufferInventory.Mode.TO_NETWORK)
}
}
return super.onSlotClick(slotId, clickData, actionType, player)
}
override fun transferSlot(player: PlayerEntity, slotId: Int): ItemStack {
if (isNetworkSlot(slotId)) {
return ItemStack.EMPTY;
}
val slot = slots[slotId]
if (!slot.hasStack()) {
return ItemStack.EMPTY
}
val result = slot.stack.copy()
if (isBufferSlot(slotId)) {
if (!insertItem(slot.stack, playerSlotsStart, playerSlotsEnd, false)) {
return ItemStack.EMPTY
}
if (slot.stack.isEmpty) {
terminal.internalBuffer.markSlot(slotId - bufferSlotsStart, TerminalBufferInventory.Mode.UNASSIGNED)
}
} else if (isPlayerSlot(slotId)) {
val slotsInsertedInto = tryInsertItem(slot.stack, bufferSlotsStart until playerSlotsStart) { terminal.internalBuffer.getMode(it - bufferSlotsStart) != TerminalBufferInventory.Mode.FROM_NETWORK }
slotsInsertedInto.forEach { terminal.internalBuffer.markSlot(it - bufferSlotsStart, TerminalBufferInventory.Mode.TO_NETWORK) }
if (slot.stack.isEmpty) {
return ItemStack.EMPTY
}
}
return result
}
private fun tryInsertItem(stack: ItemStack, slots: IntRange, slotPredicate: (Int) -> Boolean): Collection<Int> {
val slotsInsertedInto = mutableListOf<Int>()
for (index in slots) {
if (stack.isEmpty) break
if (!slotPredicate(index)) continue
val slot = this.slots[index]
val slotStack = slot.stack
if (slotStack.isEmpty) {
slot.stack = stack.copy()
stack.count = 0
slot.markDirty()
slotsInsertedInto.add(index)
} else if (canStacksCombine(slotStack, stack) && slotStack.count < slotStack.maxCount) {
val maxToMove = slotStack.maxCount - slotStack.count
val toMove = min(maxToMove, stack.count)
slotStack.increment(toMove)
stack.decrement(toMove)
slot.markDirty()
slotsInsertedInto.add(index)
}
}
return slotsInsertedInto
}
val bufferSlotsStart = 54
val playerSlotsStart = 72
val playerSlotsEnd = 72 + 36
fun isNetworkSlot(id: Int) = id in 0 until bufferSlotsStart
fun isBufferSlot(id: Int) = id in bufferSlotsStart until playerSlotsStart
fun isPlayerSlot(id: Int) = id >= playerSlotsStart
}

View File

@ -25,6 +25,10 @@ fun SimpleInventory.toTag(): ListTag {
}
fun SimpleInventory.fromTag(list: ListTag) {
if (list.isEmpty()) {
this.clear()
return
}
if (list.elementType != 10.toByte()) throw RuntimeException("Can't decode BasicInventory from list tag that does not contain compound tags")
this.clear()
for (tag in list) {

View File

@ -28,7 +28,11 @@
]
},
"mixins": [
"phycon.mixins.json"
"phycon.mixins.json",
{
"config": "phycon-client.mixins.json",
"environment": "client"
}
],
"depends": {
"fabricloader": ">=0.4.0",

View File

@ -0,0 +1,11 @@
{
"required": true,
"package": "net.shadowfacts.phycon.mixin.client",
"compatibilityLevel": "JAVA_8",
"mixins": [
"MixinHandledScreen"
],
"injectors": {
"defaultRequire": 1
}
}