Compare commits

..

No commits in common. "f4f4c7ff03b45fcbe6edc4e22a54952985f887ef" and "2cc9d592b265593d4e1b92f389f8261cb1a89ddb" have entirely different histories.

18 changed files with 51 additions and 534 deletions

View File

@ -1,17 +1,9 @@
package net.shadowfacts.phycon package net.shadowfacts.phycon
import net.fabricmc.api.ModInitializer import net.fabricmc.api.ModInitializer
import net.fabricmc.fabric.api.container.ContainerFactory
import net.fabricmc.fabric.api.container.ContainerProviderRegistry
import net.minecraft.container.Container
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.util.Identifier
import net.minecraft.util.PacketByteBuf
import net.shadowfacts.phycon.init.PhyBlockEntities import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.init.PhyBlocks import net.shadowfacts.phycon.init.PhyBlocks
import net.shadowfacts.phycon.init.PhyItems import net.shadowfacts.phycon.init.PhyItems
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
import net.shadowfacts.phycon.network.block.terminal.TerminalContainer
/** /**
* @author shadowfacts * @author shadowfacts
@ -24,13 +16,5 @@ object PhysicalConnectivity: ModInitializer {
PhyBlocks.init() PhyBlocks.init()
PhyBlockEntities.init() PhyBlockEntities.init()
PhyItems.init() PhyItems.init()
ContainerProviderRegistry.INSTANCE.registerFactory(TerminalContainer.ID, ContainerFactory(::createTerminalContainer))
} }
private fun createTerminalContainer(syncId: Int, identifier: Identifier, player: PlayerEntity, buf: PacketByteBuf): Container {
val pos = buf.readBlockPos()
val terminalEntity = PhyBlocks.TERMINAL.getBlockEntity(player.world, pos)!!
return TerminalContainer(syncId, player.inventory, terminalEntity)
}
} }

View File

@ -1,22 +0,0 @@
package net.shadowfacts.phycon
import net.fabricmc.api.ClientModInitializer
import net.fabricmc.fabric.api.client.screen.ContainerScreenFactory
import net.fabricmc.fabric.api.client.screen.ScreenProviderRegistry
import net.minecraft.client.MinecraftClient
import net.minecraft.util.Identifier
import net.shadowfacts.phycon.network.block.terminal.TerminalContainer
import net.shadowfacts.phycon.network.block.terminal.TerminalScreen
/**
* @author shadowfacts
*/
object PhysicalConnectivityClient: ClientModInitializer {
override fun onInitializeClient() {
ScreenProviderRegistry.INSTANCE.registerFactory(TerminalContainer.ID, ContainerScreenFactory(::createTerminalScreen))
}
fun createTerminalScreen(container: TerminalContainer): TerminalScreen {
return TerminalScreen(container, MinecraftClient.getInstance().player.inventory)
}
}

View File

@ -3,11 +3,13 @@ package net.shadowfacts.phycon.network.block.netinterface
import alexiil.mc.lib.attributes.SearchOptions import alexiil.mc.lib.attributes.SearchOptions
import alexiil.mc.lib.attributes.item.GroupedItemInv import alexiil.mc.lib.attributes.item.GroupedItemInv
import alexiil.mc.lib.attributes.item.ItemAttributes import alexiil.mc.lib.attributes.item.ItemAttributes
import net.minecraft.item.ItemStack
import net.minecraft.util.math.Direction import net.minecraft.util.math.Direction
import net.shadowfacts.phycon.api.packet.Packet import net.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.init.PhyBlockEntities import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.network.DeviceBlockEntity import net.shadowfacts.phycon.network.DeviceBlockEntity
import net.shadowfacts.phycon.network.packet.* import net.shadowfacts.phycon.network.packet.ReadAllPacket
import net.shadowfacts.phycon.network.packet.RequestReadAllPacket
/** /**
* @author shadowfacts * @author shadowfacts
@ -26,39 +28,24 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE) {
inventory = ItemAttributes.GROUPED_INV.getFirstOrNull(world, offsetPos, option) inventory = ItemAttributes.GROUPED_INV.getFirstOrNull(world, offsetPos, option)
} }
private fun getInventory(): GroupedItemInv? { override fun handlePacket(packet: Packet) {
when (packet) {
is RequestReadAllPacket -> handleReadAll(packet)
}
}
fun handleReadAll(packet: RequestReadAllPacket) {
enqueueToSingle(ReadAllPacket(readAll(), macAddress, packet.source))
}
fun readAll(): Map<ItemStack, Int> {
// if we don't have an inventory, try to get one // if we don't have an inventory, try to get one
// this happens when readAll is called before a neighbor state changes, such as immediately after world load // this happens when readAll is called before a neighbor state changes, such as immediately after world load
if (inventory == null) updateInventory() if (inventory == null) updateInventory()
return inventory
}
override fun handlePacket(packet: Packet) { return inventory?.let {
when (packet) { it.storedStacks.associateWith(it::getAmount)
is RequestInventoryPacket -> handleRequestInventory(packet) } ?: mapOf()
is LocateStackPacket -> handleLocateStack(packet)
is ExtractStackPacket -> handleExtractStack(packet)
}
}
private fun handleRequestInventory(packet: RequestInventoryPacket) {
getInventory()?.also { inv ->
enqueueToSingle(ReadInventoryPacket(inv, macAddress, packet.source))
}
}
private fun handleLocateStack(packet: LocateStackPacket) {
getInventory()?.also { inv ->
val amount = inv.getAmount(packet.stack)
enqueueToSingle(StackLocationPacket(packet.stack, amount, this, macAddress, packet.source))
}
}
private fun handleExtractStack(packet: ExtractStackPacket) {
getInventory()?.also { inv ->
val extracted = inv.extract(packet.stack, packet.amount)
enqueueToSingle(ItemStackPacket(extracted, macAddress, packet.source))
}
} }
} }

View File

@ -31,8 +31,8 @@ class TerminalBlock: BlockWithEntity<TerminalBlockEntity>(Settings.of(Material.M
override fun createBlockEntity(world: BlockView) = TerminalBlockEntity() override fun createBlockEntity(world: BlockView) = TerminalBlockEntity()
override fun activate(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hitResult: BlockHitResult): Boolean { override fun activate(blockState_1: BlockState?, world_1: World?, blockPos_1: BlockPos?, playerEntity_1: PlayerEntity?, hand_1: Hand?, blockHitResult_1: BlockHitResult?): Boolean {
getBlockEntity(world, pos)!!.onActivate(player) getBlockEntity(world_1!!, blockPos_1!!)!!.onActivate()
return true return true
} }

View File

@ -1,227 +1,57 @@
package net.shadowfacts.phycon.network.block.terminal package net.shadowfacts.phycon.network.block.terminal
import alexiil.mc.lib.attributes.item.GroupedItemInv
import alexiil.mc.lib.attributes.item.ItemStackCollections import alexiil.mc.lib.attributes.item.ItemStackCollections
import alexiil.mc.lib.attributes.item.ItemStackUtil import it.unimi.dsi.fastutil.objects.Object2IntMap
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
import net.fabricmc.fabric.api.container.ContainerProviderRegistry
import net.minecraft.entity.ItemEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.inventory.BasicInventory
import net.minecraft.inventory.Inventory
import net.minecraft.inventory.InventoryListener
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.shadowfacts.phycon.api.packet.Packet import net.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.api.util.MACAddress
import net.shadowfacts.phycon.init.PhyBlockEntities import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.network.DeviceBlockEntity import net.shadowfacts.phycon.network.DeviceBlockEntity
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
import net.shadowfacts.phycon.network.packet.* import net.shadowfacts.phycon.network.packet.DeviceRemovedPacket
import net.shadowfacts.phycon.util.fromTag import net.shadowfacts.phycon.network.packet.ReadAllPacket
import net.shadowfacts.phycon.util.toTag import net.shadowfacts.phycon.network.packet.RequestReadAllPacket
import java.util.* import java.util.*
import kotlin.math.min
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), InventoryListener, BlockEntityClientSerializable { class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL) {
companion object { private val inventoryCache = mutableMapOf<MACAddress, Map<ItemStack, Int>>()
val LOCATE_REQUEST_TIMEOUT = 40 // ticks
}
private val inventoryCache = mutableMapOf<MACAddress, GroupedItemInv>()
val internalBuffer = BasicInventory(18)
private val pendingRequests = LinkedList<StackLocateRequest>()
private var observers = 0
val cachedNetItems = ItemStackCollections.intMap()
var cachedSortedNetItems = listOf<ItemStack>()
var counter = 0
init {
internalBuffer.addListener(this)
}
override fun handlePacket(packet: Packet) { override fun handlePacket(packet: Packet) {
when (packet) { when (packet) {
is ReadInventoryPacket -> handleReadInventory(packet) is ReadAllPacket -> handleReadAll(packet)
is DeviceRemovedPacket -> handleDeviceRemoved(packet) is DeviceRemovedPacket -> handleDeviceRemoved(packet)
is StackLocationPacket -> handleStackLocation(packet)
is ItemStackPacket -> handleItemStack(packet)
} }
} }
private fun handleReadInventory(packet: ReadInventoryPacket) { private fun handleReadAll(packet: ReadAllPacket) {
inventoryCache[packet.source] = packet.inventory inventoryCache[packet.source] = packet.items
updateNetItems()
sync() println("new items: ${computeNetItems()}")
} }
private fun handleDeviceRemoved(packet: DeviceRemovedPacket) { private fun handleDeviceRemoved(packet: DeviceRemovedPacket) {
inventoryCache.remove(packet.source) inventoryCache.remove(packet.source)
updateNetItems()
sync()
} }
private fun handleStackLocation(packet: StackLocationPacket) { fun computeNetItems(): Map<ItemStack, Int> {
val request = pendingRequests.firstOrNull { val net = ItemStackCollections.intMap()
ItemStackUtil.areEqualIgnoreAmounts(it.stack, packet.stack) for (map in inventoryCache.values) {
} for ((stack, amount) in map) {
if (request != null) { net.mergeInt(stack, amount) { a, b -> a + b }
request.results.add(packet.amount to packet.sourceInterface)
if (request.totalResultAmount >= request.amount || counter - request.timestamp >= LOCATE_REQUEST_TIMEOUT || request.results.size >= inventoryCache.size) {
pendingRequests.remove(request)
stackLocateRequestCompleted(request)
} }
} }
return net
} }
private fun handleItemStack(packet: ItemStackPacket) { fun onActivate() {
// todo: handle merging stacks into the buffer better?
for (i in 0 until internalBuffer.invSize) {
if (internalBuffer.getInvStack(i).isEmpty) {
internalBuffer.setInvStack(i, packet.stack)
return
}
}
// todo: calculate entity spawn point by finding non-obstructed location
val entity = ItemEntity(world!!, pos.x.toDouble(), pos.y + 1.0, pos.z.toDouble(), packet.stack)
world!!.spawnEntity(entity)
}
private fun updateNetItems() {
cachedNetItems.clear()
for (inventory in inventoryCache.values) {
for (stack in inventory.storedStacks) {
val amount = inventory.getAmount(stack)
cachedNetItems.mergeInt(stack, amount) { a, b -> a + b }
}
}
// todo: is the map necessary or is just the sorted list enough?
cachedSortedNetItems = cachedNetItems.object2IntEntrySet().sortedByDescending { it.intValue }.map {
val stack = it.key.copy()
stack.count = it.intValue
stack
}
}
fun addObserver() {
observers++
}
fun removeObserver() {
observers--
}
override fun tick() {
super.tick()
if (observers > 0 && (++counter % 20) == 0) {
if (world!!.isClient) {
println(cachedNetItems)
} else {
updateNetItems()
sync()
}
}
}
fun onActivate(player: PlayerEntity) {
if (!world!!.isClient) { if (!world!!.isClient) {
updateNetItems()
sync()
inventoryCache.clear() inventoryCache.clear()
enqueueToSingle(RequestInventoryPacket(macAddress)) enqueueToSingle(RequestReadAllPacket(macAddress))
ContainerProviderRegistry.INSTANCE.openContainer(TerminalContainer.ID, player) { buf ->
buf.writeBlockPos(pos)
}
}
addObserver()
}
fun requestItem(stack: ItemStack, amount: Int = stack.count) {
pendingRequests.add(StackLocateRequest(stack, amount, counter))
enqueueToSingle(LocateStackPacket(stack, macAddress))
}
private fun stackLocateRequestCompleted(request: StackLocateRequest) {
// todo: also sort results by interface priority
val sortedResults = request.results.sortedByDescending { it.first }.toMutableList()
var amountRequested = 0
while (amountRequested < request.amount && sortedResults.isNotEmpty()) {
val (sourceAmount, sourceInterface) = sortedResults.removeAt(0)
val amountToRequest = min(sourceAmount, request.amount - amountRequested)
amountRequested += amountToRequest
enqueueToSingle(ExtractStackPacket(request.stack, amountToRequest, macAddress, sourceInterface.macAddress))
}
}
override fun onInvChange(inv: Inventory) {
if (inv == internalBuffer && !world!!.isClient) {
markDirty()
sync()
}
}
override fun toTag(tag: CompoundTag): CompoundTag {
tag.put("InternalBuffer", internalBuffer.toTag())
return super.toTag(tag)
}
override fun fromTag(tag: CompoundTag) {
super.fromTag(tag)
internalBuffer.fromTag(tag.getList("InternalBuffer", 10))
}
override fun toClientTag(tag: CompoundTag): CompoundTag {
tag.put("InternalBuffer", internalBuffer.toTag())
val list = ListTag()
tag.put("CachedNetItems", list)
for ((stack, amount) in cachedNetItems) {
val entryTag = stack.toTag(CompoundTag())
entryTag.putInt("NetAmount", amount)
list.add(entryTag)
}
return tag
}
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()
}
}
val list = tag.getList("CachedNetItems", 10)
cachedNetItems.clear()
for (entryTag in list) {
val stack = ItemStack.fromTag(entryTag as CompoundTag)
val netAmount = entryTag.getInt("NetAmount")
cachedNetItems[stack] = netAmount
}
cachedSortedNetItems = cachedNetItems.object2IntEntrySet().sortedByDescending { it.intValue }.map {
val stack = it.key.copy()
stack.count = it.intValue
stack
} }
} }
} }
data class StackLocateRequest(
val stack: ItemStack,
val amount: Int,
val timestamp: Int,
var results: MutableSet<Pair<Int, InterfaceBlockEntity>> = mutableSetOf()
) {
val totalResultAmount: Int
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
}

View File

@ -1,73 +0,0 @@
package net.shadowfacts.phycon.network.block.terminal
import net.minecraft.container.Container
import net.minecraft.container.Slot
import net.minecraft.container.SlotActionType
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.item.ItemStack
import net.minecraft.util.Identifier
import net.shadowfacts.phycon.PhysicalConnectivity
import kotlin.math.max
/**
* @author shadowfacts
*/
class TerminalContainer(syncId: Int, playerInv: PlayerInventory, val terminal: TerminalBlockEntity): Container(null, syncId) {
companion object {
val ID = Identifier(PhysicalConnectivity.MODID, "terminal")
}
init {
// network
for (y in 0 until 6) {
for (x in 0 until 9) {
addSlot(TerminalFakeSlot(terminal, y * 9 + x, 66 + x * 18, 18 + y * 18))
}
}
// internal buffer
for (y in 0 until 6) {
for (x in 0 until 3) {
addSlot(Slot(terminal.internalBuffer, y * 3 + x, 8 + x * 18, 18 + y * 18))
}
}
// player inv
for (y in 0 until 3) {
for (x in 0 until 9) {
addSlot(Slot(playerInv, x + y * 9 + 9, 66 + x * 18, 140 + y * 18))
}
}
// hotbar
for (x in 0 until 9) {
addSlot(Slot(playerInv, x, 66 + x * 18, 198))
}
}
override fun canUse(player: PlayerEntity): Boolean {
return true
}
override fun close(player: PlayerEntity) {
super.close(player)
terminal.removeObserver()
}
override fun onSlotClick(slotId: Int, clickData: Int, actionType: SlotActionType, player: PlayerEntity): ItemStack {
if (actionType == SlotActionType.QUICK_MOVE) {
if (slotId < 54) {
// the slot clicked was one of the network stacks
val slot = slotList[slotId]
val stack = slotList[slotId].stack
if (!stack.isEmpty && !player.world.isClient) {
terminal.requestItem(stack, max(stack.count, stack.maxCount))
}
return ItemStack.EMPTY
}
}
return super.onSlotClick(slotId, clickData, actionType, player)
}
}

View File

@ -1,61 +0,0 @@
package net.shadowfacts.phycon.network.block.terminal
import net.minecraft.container.Slot
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.inventory.Inventory
import net.minecraft.item.ItemStack
/**
* @author shadowfacts
*/
class TerminalFakeSlot(val terminal: TerminalBlockEntity, slot: Int, x: Int, y: Int): Slot(FakeInventory(terminal, slot), slot, x, y) {
override fun canInsert(stack: ItemStack): Boolean {
return false
}
override fun setStack(stack: ItemStack) {
}
override fun canTakeItems(player: PlayerEntity): Boolean {
return false
}
}
class FakeInventory(val terminal: TerminalBlockEntity, val slot: Int): Inventory {
override fun getInvStack(_slot: Int): ItemStack {
if (slot >= terminal.cachedSortedNetItems.size) return ItemStack.EMPTY
return terminal.cachedSortedNetItems[slot]
}
override fun markDirty() {
}
override fun clear() {
}
override fun setInvStack(p0: Int, p1: ItemStack?) {
}
override fun removeInvStack(p0: Int): ItemStack {
return ItemStack.EMPTY
}
override fun canPlayerUseInv(p0: PlayerEntity?): Boolean {
return false
}
override fun getInvSize(): Int {
return 1
}
override fun takeInvStack(p0: Int, p1: Int): ItemStack {
return ItemStack.EMPTY
}
override fun isInvEmpty(): Boolean {
return false
}
}

View File

@ -1,40 +0,0 @@
package net.shadowfacts.phycon.network.block.terminal
import com.mojang.blaze3d.platform.GlStateManager
import net.minecraft.client.gui.screen.ingame.AbstractContainerScreen
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.text.LiteralText
import net.minecraft.util.Identifier
import net.shadowfacts.phycon.PhysicalConnectivity
/**
* @author shadowfacts
*/
// todo: translate title
class TerminalScreen(container: TerminalContainer, playerInv: PlayerInventory): AbstractContainerScreen<TerminalContainer>(container, playerInv, LiteralText("Terminal")) {
companion object {
val BACKGROUND = Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal.png")
}
init {
containerWidth = 252
containerHeight = 222
}
override fun drawForeground(mouseX: Int, mouseY: Int) {
font.draw(title.asFormattedString(), 65f, 6f, 0x404040)
font.draw(playerInventory.displayName.asFormattedString(), 65f, containerHeight - 94f, 0x404040)
// todo: translate this
font.draw("Buffer", 7f, 6f, 0x404040)
}
override fun drawBackground(delta: Float, mouseX: Int, mouseY: Int) {
GlStateManager.color4f(1f, 1f, 1f, 1f)
minecraft!!.textureManager.bindTexture(BACKGROUND)
val x = (width - containerWidth) / 2
val y = (height - containerHeight) / 2
blit(x, y, 0, 0, containerWidth, containerHeight)
}
}

View File

@ -1,10 +0,0 @@
package net.shadowfacts.phycon.network.packet
import net.minecraft.item.ItemStack
import net.shadowfacts.phycon.api.util.MACAddress
/**
* @author shadowfacts
*/
class ExtractStackPacket(val stack: ItemStack, val amount: Int, source: MACAddress, destination: MACAddress): BasePacket(source, destination) {
}

View File

@ -1,10 +0,0 @@
package net.shadowfacts.phycon.network.packet
import net.minecraft.item.ItemStack
import net.shadowfacts.phycon.api.util.MACAddress
/**
* @author shadowfacts
*/
class ItemStackPacket(val stack: ItemStack, source: MACAddress, destination: MACAddress): BasePacket(source, destination) {
}

View File

@ -1,10 +0,0 @@
package net.shadowfacts.phycon.network.packet
import net.minecraft.item.ItemStack
import net.shadowfacts.phycon.api.util.MACAddress
/**
* @author shadowfacts
*/
class LocateStackPacket(val stack: ItemStack, source: MACAddress, destination: MACAddress = MACAddress.BROADCAST): BasePacket(source, destination) {
}

View File

@ -1,13 +1,13 @@
package net.shadowfacts.phycon.network.packet package net.shadowfacts.phycon.network.packet
import alexiil.mc.lib.attributes.item.GroupedItemInv import net.minecraft.item.ItemStack
import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.api.util.MACAddress
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
class ReadInventoryPacket( class ReadAllPacket(
val inventory: GroupedItemInv, val items: Map<ItemStack, Int>,
source: MACAddress, source: MACAddress,
destination: MACAddress destination: MACAddress
): BasePacket(source, destination) ): BasePacket(source, destination)

View File

@ -1,8 +0,0 @@
package net.shadowfacts.phycon.network.packet
import net.shadowfacts.phycon.api.util.MACAddress
/**
* @author shadowfacts
*/
class RequestInventoryPacket(source: MACAddress, destination: MACAddress = MACAddress.BROADCAST): BasePacket(source, destination)

View File

@ -0,0 +1,8 @@
package net.shadowfacts.phycon.network.packet
import net.shadowfacts.phycon.api.util.MACAddress
/**
* @author shadowfacts
*/
class RequestReadAllPacket(source: MACAddress, destination: MACAddress = MACAddress.BROADCAST): BasePacket(source, destination)

View File

@ -1,18 +0,0 @@
package net.shadowfacts.phycon.network.packet
import net.minecraft.item.ItemStack
import net.shadowfacts.phycon.api.util.MACAddress
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
/**
* @author shadowfacts
*/
// todo: better name with LocateStackPacket
class StackLocationPacket(
val stack: ItemStack,
val amount: Int,
val sourceInterface: InterfaceBlockEntity,
source: MACAddress,
destination: MACAddress
): BasePacket(source, destination) {
}

View File

@ -1,34 +0,0 @@
package net.shadowfacts.phycon.util
import net.minecraft.inventory.BasicInventory
import net.minecraft.item.ItemStack
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import java.lang.RuntimeException
/**
* @author shadowfacts
*/
fun BasicInventory.toTag(): ListTag {
val list = ListTag()
for (slot in 0 until invSize) {
val stack = getInvStack(slot)
if (!stack.isEmpty) {
val stackTag = stack.toTag(CompoundTag())
stackTag.putInt("Slot", slot)
list.add(stackTag)
}
}
return list
}
fun BasicInventory.fromTag(list: ListTag) {
if (list.listType != 10) throw RuntimeException("Can't decode BasicInventory from list tag that does not contain compound tags")
this.clear()
for (tag in list) {
val compound = tag as CompoundTag
val stack = ItemStack.fromTag(compound)
val slot = compound.getInt("Slot")
setInvStack(slot, stack)
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

View File

@ -19,12 +19,6 @@
"adapter": "kotlin", "adapter": "kotlin",
"value": "net.shadowfacts.phycon.PhysicalConnectivity" "value": "net.shadowfacts.phycon.PhysicalConnectivity"
} }
],
"client": [
{
"adapter": "kotlin",
"value": "net.shadowfacts.phycon.PhysicalConnectivityClient"
}
] ]
}, },
"mixins": [ "mixins": [