Terminal: Shift-click transferring, draw slot modes
This commit is contained in:
parent
dedfcae79b
commit
1c3e358f2e
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -238,7 +238,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), Invento
|
||||||
|
|
||||||
override fun fromTag(state: BlockState, tag: CompoundTag) {
|
override fun fromTag(state: BlockState, tag: CompoundTag) {
|
||||||
super.fromTag(state, tag)
|
super.fromTag(state, tag)
|
||||||
internalBuffer.fromTag(tag.getList("InternalBuffer", 10))
|
internalBuffer.fromTag(tag.getCompound("InternalBuffer"))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toClientTag(tag: CompoundTag): CompoundTag {
|
override fun toClientTag(tag: CompoundTag): CompoundTag {
|
||||||
|
@ -254,14 +254,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), Invento
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromClientTag(tag: CompoundTag) {
|
override fun fromClientTag(tag: CompoundTag) {
|
||||||
tag.getList("InternalBuffer", 10)?.also { list ->
|
internalBuffer.fromTag(tag.getCompound("InternalBuffer"))
|
||||||
if (list.isNotEmpty()) {
|
|
||||||
internalBuffer.fromTag(list)
|
|
||||||
} else {
|
|
||||||
// todo: should this clear or just do nothing?
|
|
||||||
internalBuffer.clear()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val list = tag.getList("CachedNetItems", 10)
|
val list = tag.getList("CachedNetItems", 10)
|
||||||
cachedNetItems.clear()
|
cachedNetItems.clear()
|
||||||
for (entryTag in list) {
|
for (entryTag in list) {
|
||||||
|
|
|
@ -3,6 +3,10 @@ package net.shadowfacts.phycon.network.block.terminal
|
||||||
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||||
import net.minecraft.inventory.SimpleInventory
|
import net.minecraft.inventory.SimpleInventory
|
||||||
import net.minecraft.item.ItemStack
|
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
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,8 +18,21 @@ class TerminalBufferInventory(size: Int): SimpleInventory(size) {
|
||||||
TO_NETWORK, FROM_NETWORK, UNASSIGNED
|
TO_NETWORK, FROM_NETWORK, UNASSIGNED
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: modes should be saved to NBT
|
var modes = Array(size) { Mode.UNASSIGNED }
|
||||||
private val 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 {
|
fun insertFromNetwork(stack: ItemStack): ItemStack {
|
||||||
var remaining = stack.copy()
|
var remaining = stack.copy()
|
||||||
|
@ -57,6 +74,11 @@ class TerminalBufferInventory(size: Int): SimpleInventory(size) {
|
||||||
super.setStack(slot, stack)
|
super.setStack(slot, stack)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun clear() {
|
||||||
|
super.clear()
|
||||||
|
this.modes = Array(size()) { Mode.UNASSIGNED }
|
||||||
|
}
|
||||||
|
|
||||||
fun getMode(slot: Int): Mode {
|
fun getMode(slot: Int): Mode {
|
||||||
return modes[slot]
|
return modes[slot]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package net.shadowfacts.phycon.network.block.terminal
|
package net.shadowfacts.phycon.network.block.terminal
|
||||||
|
|
||||||
import com.mojang.blaze3d.platform.GlStateManager
|
import com.mojang.blaze3d.platform.GlStateManager
|
||||||
|
import net.minecraft.client.gui.DrawableHelper
|
||||||
import net.minecraft.client.gui.screen.ingame.HandledScreen
|
import net.minecraft.client.gui.screen.ingame.HandledScreen
|
||||||
import net.minecraft.client.util.math.MatrixStack
|
import net.minecraft.client.util.math.MatrixStack
|
||||||
import net.minecraft.entity.player.PlayerInventory
|
import net.minecraft.entity.player.PlayerInventory
|
||||||
|
import net.minecraft.screen.slot.Slot
|
||||||
import net.minecraft.text.LiteralText
|
import net.minecraft.text.LiteralText
|
||||||
import net.minecraft.text.Text
|
import net.minecraft.text.Text
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
|
@ -38,4 +40,19 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
|
||||||
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
|
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())
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ class TerminalScreenHandler(syncId: Int, playerInv: PlayerInventory, val termina
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSlotClick(slotId: Int, clickData: Int, actionType: SlotActionType, player: PlayerEntity): ItemStack {
|
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
|
// the slot clicked was one of the network stacks
|
||||||
if (actionType == SlotActionType.QUICK_MOVE) {
|
if (actionType == SlotActionType.QUICK_MOVE) {
|
||||||
val stack = slots[slotId].stack
|
val stack = slots[slotId].stack
|
||||||
|
@ -83,14 +83,79 @@ class TerminalScreenHandler(syncId: Int, playerInv: PlayerInventory, val termina
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ItemStack.EMPTY
|
return ItemStack.EMPTY
|
||||||
} else if (slotId in 54 until 72) {
|
} else if (isBufferSlot(slotId)) {
|
||||||
// internal buffer
|
// 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
|
// 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)
|
terminal.internalBuffer.markSlot(bufferSlot, TerminalBufferInventory.Mode.TO_NETWORK)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.onSlotClick(slotId, clickData, actionType, player)
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,10 @@ fun SimpleInventory.toTag(): ListTag {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun SimpleInventory.fromTag(list: 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")
|
if (list.elementType != 10.toByte()) throw RuntimeException("Can't decode BasicInventory from list tag that does not contain compound tags")
|
||||||
this.clear()
|
this.clear()
|
||||||
for (tag in list) {
|
for (tag in list) {
|
||||||
|
|
|
@ -28,7 +28,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"phycon.mixins.json"
|
"phycon.mixins.json",
|
||||||
|
{
|
||||||
|
"config": "phycon-client.mixins.json",
|
||||||
|
"environment": "client"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"depends": {
|
"depends": {
|
||||||
"fabricloader": ">=0.4.0",
|
"fabricloader": ">=0.4.0",
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"package": "net.shadowfacts.phycon.mixin.client",
|
||||||
|
"compatibilityLevel": "JAVA_8",
|
||||||
|
"mixins": [
|
||||||
|
"MixinHandledScreen"
|
||||||
|
],
|
||||||
|
"injectors": {
|
||||||
|
"defaultRequire": 1
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue