Network storage items as ItemStackWrappers

so they can have counts of more than 2bil
Add some formatting for biginteger
This commit is contained in:
DBotThePony 2022-06-30 14:06:38 +07:00
parent 11f416c601
commit 5833448584
Signed by: DBot
GPG Key ID: DCC23B5715498507
10 changed files with 205 additions and 84 deletions

View File

@ -416,6 +416,8 @@ private fun gui(provider: MatteryLanguageProvider) {
gui("item_monitor.amount.one", "Exactly one item") gui("item_monitor.amount.one", "Exactly one item")
gui("item_monitor.amount.stack", "Exactly one stack. This is the behavior you see in AE2 and Refined Storage") gui("item_monitor.amount.stack", "Exactly one stack. This is the behavior you see in AE2 and Refined Storage")
gui("item_monitor.amount.full", "Stack of ingredients. Craft until reaching stack size of one of ingredients. If at least one of inputs is not stackable then 'one stack' mode is used instead") gui("item_monitor.amount.full", "Stack of ingredients. Craft until reaching stack size of one of ingredients. If at least one of inputs is not stackable then 'one stack' mode is used instead")
gui("stored_amount", "Exact amount stored: %s")
} }
} }

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.client.screen package ru.dbotthepony.mc.otm.client.screen
import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.network.chat.TranslatableComponent import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
@ -50,27 +51,41 @@ class DriveViewerScreen(menu: DriveViewerMenu, inventory: Inventory, title: Comp
val grid = GridPanel(this, frame, 28f, 16f, GRID_WIDTH * 18f, GRID_HEIGHT * 18f, GRID_WIDTH, GRID_HEIGHT) val grid = GridPanel(this, frame, 28f, 16f, GRID_WIDTH * 18f, GRID_HEIGHT * 18f, GRID_WIDTH, GRID_HEIGHT)
val scroll_bar = ScrollBarPanel(this, frame, 192f, 14f, 92f) val scrollBar = ScrollBarPanel(this, frame, 192f, 14f, 92f)
scroll_bar.setupRowMultiplier { menu.view.itemCount / GRID_WIDTH } scrollBar.setupRowMultiplier { menu.view.itemCount / GRID_WIDTH }
views.add(grid) views.add(grid)
views.add(scroll_bar) views.add(scrollBar)
for (i in 0 until GRID_WIDTH * GRID_HEIGHT) { for (i in 0 until GRID_WIDTH * GRID_HEIGHT) {
object : AbstractSlotPanel(this@DriveViewerScreen, grid, 0f, 0f) { object : AbstractSlotPanel(this@DriveViewerScreen, grid, 0f, 0f) {
override fun getItemStack(): ItemStack { override fun getItemStack(): ItemStack {
val index = i + scroll_bar.getScroll(menu.view.sortedView.size / GRID_WIDTH) val index = i + scrollBar.getScroll(menu.view.sortedView.size / GRID_WIDTH)
return menu.view.sortedView.getOrNull(index)?.stack ?: ItemStack.EMPTY return menu.view.sortedView.getOrNull(index)?.stack?.item ?: ItemStack.EMPTY
} }
override fun mouseScrolledInner(mouse_x: Double, mouse_y: Double, scroll: Double): Boolean { override fun mouseScrolledInner(mouse_x: Double, mouse_y: Double, scroll: Double): Boolean {
return scroll_bar.mouseScrolledInner(mouse_x, mouse_y, scroll) return scrollBar.mouseScrolledInner(mouse_x, mouse_y, scroll)
} }
override fun mouseClickedInner(mouse_x: Double, mouse_y: Double, mouse_click_type: Int): Boolean { override fun mouseClickedInner(mouse_x: Double, mouse_y: Double, mouse_click_type: Int): Boolean {
val index = i + scroll_bar.getScroll(GRID_WIDTH) val index = i + scrollBar.getScroll(GRID_WIDTH)
menu.view.mouseClick(index, mouse_click_type) menu.view.mouseClick(index, mouse_click_type)
return true return true
} }
override fun innerRender(stack: PoseStack, mouse_x: Float, mouse_y: Float, flag: Float) {
renderSlotBackground(stack, mouse_x, mouse_y, flag)
renderRegular(stack, getItemStack(), "")
}
override fun getItemStackTooltip(stack: ItemStack): List<Component> {
return super.getItemStackTooltip(stack).also {
it as MutableList<Component>
val index = i + scrollBar.getScroll(menu.view.sortedView.size / GRID_WIDTH)
val realStack = menu.view.sortedView.getOrNull(index)!!.stack
it.add(TranslatableComponent("otm.gui.item_amount", realStack.count.toString()))
}
}
} }
} }

View File

@ -1,6 +1,7 @@
package ru.dbotthepony.mc.otm.client.screen package ru.dbotthepony.mc.otm.client.screen
import com.mojang.blaze3d.vertex.PoseStack import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.ChatFormatting
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.network.chat.TranslatableComponent import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
@ -11,17 +12,10 @@ import ru.dbotthepony.mc.otm.client.render.SkinGrid
import ru.dbotthepony.mc.otm.client.render.UVWindingOrder import ru.dbotthepony.mc.otm.client.render.UVWindingOrder
import ru.dbotthepony.mc.otm.client.screen.panels.* import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
import ru.dbotthepony.mc.otm.core.equalDownDivision
import ru.dbotthepony.mc.otm.core.formatReadableNumber
import ru.dbotthepony.mc.otm.menu.ItemMonitorMenu import ru.dbotthepony.mc.otm.menu.ItemMonitorMenu
import ru.dbotthepony.mc.otm.next import java.text.NumberFormat
import ru.dbotthepony.mc.otm.prev
private fun div(a: Int, b: Int): Int {
if (a % b == 0) {
return a / b - 1
}
return a / b
}
class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Component) : class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Component) :
MatteryScreen<ItemMonitorMenu>(menu, inventory, title) { MatteryScreen<ItemMonitorMenu>(menu, inventory, title) {
@ -42,7 +36,7 @@ class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Comp
frame.width = 178f + frame.dockPadding.left + frame.dockPadding.right frame.width = 178f + frame.dockPadding.left + frame.dockPadding.right
val viewScrollBar = ScrollBarPanel(this, topPanel, 28f + ITEM_GRID_WIDTH * 18f + 2f, 16f, ITEM_GRID_HEIGHT * 18f) val viewScrollBar = ScrollBarPanel(this, topPanel, 28f + ITEM_GRID_WIDTH * 18f + 2f, 16f, ITEM_GRID_HEIGHT * 18f)
viewScrollBar.setupRowMultiplier { div(menu.view.itemCount, ITEM_GRID_WIDTH) } viewScrollBar.setupRowMultiplier { equalDownDivision(menu.view.itemCount, ITEM_GRID_WIDTH) }
viewScrollBar.dock = Dock.RIGHT viewScrollBar.dock = Dock.RIGHT
viewScrollBar.setDockMargin(left = 2f) viewScrollBar.setDockMargin(left = 2f)
@ -53,8 +47,8 @@ class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Comp
for (i in 0 until ITEM_GRID_WIDTH * ITEM_GRID_HEIGHT) { for (i in 0 until ITEM_GRID_WIDTH * ITEM_GRID_HEIGHT) {
object : AbstractSlotPanel(this@ItemMonitorScreen, gridPanel) { object : AbstractSlotPanel(this@ItemMonitorScreen, gridPanel) {
override fun getItemStack(): ItemStack { override fun getItemStack(): ItemStack {
val index = i + viewScrollBar.getScroll(div(menu.view.itemCount, ITEM_GRID_WIDTH)) * ITEM_GRID_WIDTH val index = i + viewScrollBar.getScroll(equalDownDivision(menu.view.itemCount, ITEM_GRID_WIDTH)) * ITEM_GRID_WIDTH
return menu.view.sortedView.getOrNull(index)?.stack ?: ItemStack.EMPTY return menu.view.sortedView.getOrNull(index)?.stack?.item ?: ItemStack.EMPTY
} }
override fun mouseScrolledInner(mouse_x: Double, mouse_y: Double, scroll: Double): Boolean { override fun mouseScrolledInner(mouse_x: Double, mouse_y: Double, scroll: Double): Boolean {
@ -62,10 +56,24 @@ class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Comp
} }
override fun mouseClickedInner(mouse_x: Double, mouse_y: Double, mouse_click_type: Int): Boolean { override fun mouseClickedInner(mouse_x: Double, mouse_y: Double, mouse_click_type: Int): Boolean {
val index = i + viewScrollBar.getScroll(div(menu.view.itemCount, ITEM_GRID_WIDTH)) * ITEM_GRID_WIDTH val index = i + viewScrollBar.getScroll(equalDownDivision(menu.view.itemCount, ITEM_GRID_WIDTH)) * ITEM_GRID_WIDTH
menu.view.mouseClick(index, mouse_click_type) menu.view.mouseClick(index, mouse_click_type)
return true return true
} }
override fun innerRender(stack: PoseStack, mouse_x: Float, mouse_y: Float, flag: Float) {
renderSlotBackground(stack, mouse_x, mouse_y, flag)
renderRegular(stack, getItemStack(), "")
}
override fun getItemStackTooltip(stack: ItemStack): List<Component> {
return super.getItemStackTooltip(stack).also {
it as MutableList<Component>
val index = i + viewScrollBar.getScroll(menu.view.sortedView.size / DriveViewerScreen.GRID_WIDTH)
val realStack = menu.view.sortedView.getOrNull(index)!!.stack
it.add(TranslatableComponent("otm.gui.stored_amount", realStack.count.formatReadableNumber()).withStyle(ChatFormatting.DARK_GRAY))
}
}
} }
} }

View File

@ -8,6 +8,7 @@ import net.minecraft.network.chat.Component
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraftforge.client.RenderProperties import net.minecraftforge.client.RenderProperties
import org.lwjgl.opengl.GL11 import org.lwjgl.opengl.GL11
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.core.RGBAColor import ru.dbotthepony.mc.otm.core.RGBAColor
import ru.dbotthepony.mc.otm.client.render.RenderHelper import ru.dbotthepony.mc.otm.client.render.RenderHelper
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
@ -47,7 +48,7 @@ abstract class AbstractSlotPanel @JvmOverloads constructor(
screen.itemRenderer.blitOffset = accumulatedDepth - 100 // force item to draw only 50 units "above" background screen.itemRenderer.blitOffset = accumulatedDepth - 100 // force item to draw only 50 units "above" background
screen.itemRenderer.renderAndDecorateItem( screen.itemRenderer.renderAndDecorateItem(
Minecraft.getInstance().player, requireNotNull(minecraft.player) { "yo, dude, what the fuck" },
itemstack, itemstack,
0, 0,
0, 0,

View File

@ -6,7 +6,10 @@ package ru.dbotthepony.mc.otm.core
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.core.Vec3i import net.minecraft.core.Vec3i
import java.math.BigDecimal import net.minecraft.nbt.ByteArrayTag
import net.minecraft.nbt.Tag
import net.minecraft.network.FriendlyByteBuf
import java.math.BigInteger
operator fun BlockPos.plus(direction: Vec3i): BlockPos = this.offset(direction) operator fun BlockPos.plus(direction: Vec3i): BlockPos = this.offset(direction)
operator fun BlockPos.plus(direction: Direction): BlockPos = this.offset(direction.normal) operator fun BlockPos.plus(direction: Direction): BlockPos = this.offset(direction.normal)
@ -217,3 +220,20 @@ fun Byte.toImpreciseFraction() = ImpreciseFraction(this)
fun Short.toImpreciseFraction() = ImpreciseFraction(this) fun Short.toImpreciseFraction() = ImpreciseFraction(this)
fun Long.toImpreciseFraction() = ImpreciseFraction(this) fun Long.toImpreciseFraction() = ImpreciseFraction(this)
fun ImpreciseFraction.toImpreciseFraction() = this fun ImpreciseFraction.toImpreciseFraction() = this
fun BigInteger(tag: Tag?): BigInteger {
if (tag !is ByteArrayTag)
return BigInteger.ZERO
return BigInteger(tag.asByteArray)
}
fun BigInteger.serializeNBT(): ByteArrayTag {
return ByteArrayTag(toByteArray())
}
fun FriendlyByteBuf.writeBigInteger(value: BigInteger) {
writeByteArray(value.toByteArray())
}
fun FriendlyByteBuf.readBigInteger(byteLimit: Int = 128) = BigInteger(readByteArray(byteLimit))

View File

@ -0,0 +1,42 @@
package ru.dbotthepony.mc.otm.core
import java.math.BigInteger
fun BigInteger.formatReadableNumber(): String {
if (isZero) {
return "0"
}
val strValue = toString()
val absLength = strValue.length - (if (isNegative) 1 else 0)
val remainder = absLength % 3
var groups = absLength / 3
if (remainder == 0) {
groups--
}
val buffer = CharArray((if (remainder == 0) 3 else remainder) + groups * 4 + if (isNegative) 1 else 0)
var c = 0
var index = buffer.size - 1
for (i in strValue.length - 1 downTo (if (isNegative) 1 else 0)) {
c++
if (c == 4) {
buffer[index] = ' '
index--
c = 1
}
buffer[index] = strValue[i]
index--
}
if (isNegative) {
buffer[index] = '-'
}
return String(buffer)
}

View File

@ -1,20 +1,16 @@
package ru.dbotthepony.mc.otm.core package ru.dbotthepony.mc.otm.core
import net.minecraft.nbt.ByteArrayTag
import net.minecraft.nbt.Tag
import java.math.BigInteger import java.math.BigInteger
inline val BigInteger.isZero get() = this == BigInteger.ZERO inline val BigInteger.isZero get() = this == BigInteger.ZERO
inline val BigInteger.isPositive get() = this > BigInteger.ZERO inline val BigInteger.isPositive get() = this > BigInteger.ZERO
inline val BigInteger.isNegative get() = this < BigInteger.ZERO inline val BigInteger.isNegative get() = this < BigInteger.ZERO
fun BigInteger.serializeNBT(): ByteArrayTag { @Suppress("SameParameterValue")
return ByteArrayTag(toByteArray()) fun equalDownDivision(a: Int, b: Int): Int {
if (a % b == 0) {
return a / b - 1
} }
fun BigInteger(tag: Tag?): BigInteger { return a / b
if (tag !is ByteArrayTag)
return BigInteger.ZERO
return BigInteger(tag.asByteArray)
} }

View File

@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.menu.data
import com.mojang.blaze3d.platform.InputConstants import com.mojang.blaze3d.platform.InputConstants
import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap
import it.unimi.dsi.fastutil.longs.Long2ObjectAVLTreeMap
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.client.gui.screens.Screen import net.minecraft.client.gui.screens.Screen
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
@ -10,11 +9,11 @@ import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.ClickAction import net.minecraft.world.inventory.ClickAction
import net.minecraft.world.inventory.ClickType import net.minecraft.world.inventory.ClickType
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraftforge.network.NetworkEvent import net.minecraftforge.network.NetworkEvent
import net.minecraftforge.network.PacketDistributor import net.minecraftforge.network.PacketDistributor
import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.core.readBigInteger
import ru.dbotthepony.mc.otm.core.writeBigInteger
import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.MatteryMenu
import ru.dbotthepony.mc.otm.network.MatteryNetworking import ru.dbotthepony.mc.otm.network.MatteryNetworking
import ru.dbotthepony.mc.otm.network.SetCarriedPacket import ru.dbotthepony.mc.otm.network.SetCarriedPacket
@ -23,15 +22,11 @@ import java.math.BigInteger
import java.util.* import java.util.*
import java.util.function.Supplier import java.util.function.Supplier
class StackAddPacket(val id: Int, val stack_id: Int, val stack: ItemStack) { class StackAddPacket(val containerId: Int, val id: Int, val stack: ItemStackWrapper) {
fun write(buffer: FriendlyByteBuf) { fun write(buffer: FriendlyByteBuf) {
buffer.writeInt(containerId)
buffer.writeInt(id) buffer.writeInt(id)
buffer.writeInt(stack_id) buffer.writeBigItem(stack)
buffer.writeRegistryId(stack.item)
buffer.writeInt(stack.count)
buffer.writeBoolean(stack.shareTag != null)
if (stack.tag != null) buffer.writeNbt(stack.shareTag)
} }
fun play(context: Supplier<NetworkEvent.Context>) { fun play(context: Supplier<NetworkEvent.Context>) {
@ -39,17 +34,17 @@ class StackAddPacket(val id: Int, val stack_id: Int, val stack: ItemStack) {
context.get().enqueueWork { context.get().enqueueWork {
val get = Minecraft.getInstance().player?.containerMenu ?: return@enqueueWork val get = Minecraft.getInstance().player?.containerMenu ?: return@enqueueWork
if (get.containerId != id) if (get.containerId != containerId)
return@enqueueWork return@enqueueWork
val view = (get as? INetworkedItemViewSupplier)?.networkedItemView ?: throw IllegalStateException("No such item tracker with id $id") val view = (get as? INetworkedItemViewSupplier)?.networkedItemView ?: throw IllegalStateException("No such item tracker with id $containerId")
if (view.localState.containsKey(stack_id)) { if (view.localState.containsKey(id)) {
throw IllegalStateException("Item tracker $id already has stack with id of $stack_id") throw IllegalStateException("Item tracker $containerId already has stack with id of $id")
} }
val state = NetworkedItemView.NetworkedItem(stack_id, stack) val state = NetworkedItemView.NetworkedItem(id, stack)
view.localState[stack_id] = state view.localState[id] = state
/*val iterator = view.sortedView.iterator().withIndex() /*val iterator = view.sortedView.iterator().withIndex()
var lastCompare = 0 var lastCompare = 0
@ -77,22 +72,19 @@ class StackAddPacket(val id: Int, val stack_id: Int, val stack: ItemStack) {
companion object { companion object {
fun read(buffer: FriendlyByteBuf): StackAddPacket { fun read(buffer: FriendlyByteBuf): StackAddPacket {
val containerId = buffer.readInt()
val id = buffer.readInt() val id = buffer.readInt()
val stack = buffer.readInt() val item = buffer.readBigItem()
val item = buffer.readRegistryIdSafe(Item::class.java) return StackAddPacket(containerId, id, item)
val count = buffer.readInt()
val state = ItemStack(item, count)
if (buffer.readBoolean()) state.readShareTag(buffer.readNbt())
return StackAddPacket(id, stack, state)
} }
} }
} }
class StackChangePacket(val id: Int, val stackID: Int, val newCount: Int) { class StackChangePacket(val id: Int, val stackID: Int, val newCount: BigInteger) {
fun write(buffer: FriendlyByteBuf) { fun write(buffer: FriendlyByteBuf) {
buffer.writeInt(id) buffer.writeInt(id)
buffer.writeInt(stackID) buffer.writeInt(stackID)
buffer.writeInt(newCount) buffer.writeBigInteger(newCount)
} }
fun play(context: Supplier<NetworkEvent.Context>) { fun play(context: Supplier<NetworkEvent.Context>) {
@ -115,7 +107,7 @@ class StackChangePacket(val id: Int, val stackID: Int, val newCount: Int) {
fun read(buffer: FriendlyByteBuf): StackChangePacket { fun read(buffer: FriendlyByteBuf): StackChangePacket {
val id = buffer.readInt() val id = buffer.readInt()
val stackID = buffer.readInt() val stackID = buffer.readInt()
val newCount = buffer.readInt() val newCount = buffer.readBigInteger()
return StackChangePacket(id, stackID, newCount) return StackChangePacket(id, stackID, newCount)
} }
} }
@ -155,7 +147,7 @@ class StackRemovePacket(val id: Int, val stackID: Int) {
* Creates a virtual, slotless container for Player to interaction with. * Creates a virtual, slotless container for Player to interaction with.
*/ */
open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote: Boolean) : IStorageEventConsumer<ItemStackWrapper> { open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote: Boolean) : IStorageEventConsumer<ItemStackWrapper> {
data class NetworkedItem constructor(val id: Int, val stack: ItemStack, val upstreamId: UUID? = null) data class NetworkedItem constructor(val id: Int, val stack: ItemStackWrapper, val upstreamId: UUID? = null)
override val storageType: StorageStackType<ItemStackWrapper> override val storageType: StorageStackType<ItemStackWrapper>
get() = ITEM_STORAGE get() = ITEM_STORAGE
@ -188,7 +180,7 @@ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote:
fun resort() { fun resort() {
sortedView.sortWith { a, b -> sortedView.sortWith { a, b ->
return@sortWith sorter.compare(a.stack, b.stack) return@sortWith sorter.compare(a.stack.item, b.stack.item)
} }
} }
@ -230,8 +222,21 @@ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote:
val itemCount get() = localState.values.size val itemCount get() = localState.values.size
override fun addStack(stack: ItemStackWrapper, id: UUID, provider: IStorageProvider<ItemStackWrapper>) = addObject(stack.stack, id) override fun addStack(stack: ItemStackWrapper, id: UUID, provider: IStorageProvider<ItemStackWrapper>) {
override fun changeStack(stack: ItemStackWrapper, id: UUID, oldCount: BigInteger) = changeObject(id, stack.count.toInt()) check(!upstreamState.containsKey(id)) { "Already tracking ItemStack with upstream id $id!" }
val state = NetworkedItem(nextItemID++, stack.copy(), id)
this.localState[state.id] = state
upstreamState[id] = state
network { StackAddPacket(menu.containerId, state.id, state.stack) }
}
override fun changeStack(stack: ItemStackWrapper, id: UUID, oldCount: BigInteger) {
val get = upstreamState[id] ?: throw IllegalStateException("Unknown ItemStack with upstream id $id!")
get.stack.count = stack.count
network { StackChangePacket(menu.containerId, get.id, stack.count) }
}
protected fun network(fn: () -> Any) { protected fun network(fn: () -> Any) {
if (!remote) { if (!remote) {
@ -248,22 +253,6 @@ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote:
protected var nextItemID = 0 protected var nextItemID = 0
fun addObject(stack: ItemStack, id_upstream: UUID) {
check(!upstreamState.containsKey(id_upstream)) { "Already tracking ItemStack with upstream id $id_upstream!" }
val state = NetworkedItem(nextItemID++, stack.copy(), id_upstream)
this.localState[state.id] = state
upstreamState[id_upstream] = state
network { StackAddPacket(menu.containerId, state.id, stack) }
}
fun changeObject(id_upstream: UUID, new_count: Int) {
val get = upstreamState[id_upstream] ?: throw IllegalStateException("Unknown ItemStack with upstream id $id_upstream!")
get.stack.count = new_count
network { StackChangePacket(menu.containerId, get.id, new_count) }
}
fun clear() { fun clear() {
sortedView.clear() sortedView.clear()
upstreamState.clear() upstreamState.clear()
@ -293,9 +282,8 @@ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote:
if (stack_id < 0 || !ply.abilities.instabuild) return if (stack_id < 0 || !ply.abilities.instabuild) return
val state = get(stack_id) ?: return val state = get(stack_id) ?: return
val copy: ItemStack = state.stack.copy() val copy = state.stack.stack.also { it.count = it.maxStackSize }
copy.count = Math.min(copy.count, copy.maxStackSize)
ply.containerMenu.carried = copy ply.containerMenu.carried = copy
MatteryNetworking.send(ply as ServerPlayer, SetCarriedPacket(ply.containerMenu.carried)) MatteryNetworking.send(ply as ServerPlayer, SetCarriedPacket(ply.containerMenu.carried))
ply.containerMenu.setRemoteCarried(ply.containerMenu.carried.copy()) ply.containerMenu.setRemoteCarried(ply.containerMenu.carried.copy())
@ -308,9 +296,9 @@ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote:
val amount = val amount =
if (action == ClickAction.PRIMARY) if (action == ClickAction.PRIMARY)
state.stack.maxStackSize state.stack.item.maxStackSize
else else
1.coerceAtLeast(state.stack.maxStackSize / 2) 1.coerceAtLeast(state.stack.item.maxStackSize / 2)
val extracted = provider.extractStack(state.upstreamId!!, amount.toBigInteger(), true) val extracted = provider.extractStack(state.upstreamId!!, amount.toBigInteger(), true)
@ -352,9 +340,9 @@ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote:
val amount = val amount =
if (action == ClickAction.PRIMARY) if (action == ClickAction.PRIMARY)
state.stack.maxStackSize state.stack.item.maxStackSize
else else
(state.stack.count / 2).coerceAtMost(state.stack.maxStackSize / 2).coerceAtLeast(1) (state.stack.stack.count / 2).coerceAtMost(state.stack.item.maxStackSize / 2).coerceAtLeast(1)
val extracted = provider.extractStack(state.upstreamId!!, amount.toBigInteger(), false) val extracted = provider.extractStack(state.upstreamId!!, amount.toBigInteger(), false)
menu.carried = extracted.stack menu.carried = extracted.stack

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.storage package ru.dbotthepony.mc.otm.storage
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraftforge.registries.ForgeRegistries import net.minecraftforge.registries.ForgeRegistries
@ -7,6 +8,8 @@ import net.minecraftforge.registries.ForgeRegistry
import org.jetbrains.annotations.ApiStatus import org.jetbrains.annotations.ApiStatus
import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.core.isPositive import ru.dbotthepony.mc.otm.core.isPositive
import ru.dbotthepony.mc.otm.core.readBigInteger
import ru.dbotthepony.mc.otm.core.writeBigInteger
import java.math.BigInteger import java.math.BigInteger
/** /**
@ -86,8 +89,22 @@ class ItemStackWrapper : IStorageStack {
return "ItemStackWrapper[$count $registryName]" return "ItemStackWrapper[$count $registryName]"
} }
fun write(buff: FriendlyByteBuf) {
buff.writeItem(item)
buff.writeBigInteger(count)
}
companion object { companion object {
@JvmField @JvmField
val EMPTY = ItemStackWrapper(ItemStack.EMPTY) val EMPTY = ItemStackWrapper(ItemStack.EMPTY)
fun read(buff: FriendlyByteBuf): ItemStackWrapper {
val item = buff.readItem()
val count = buff.readBigInteger()
return ItemStackWrapper(item, copy = false).also { it.count = count }
} }
} }
}
fun FriendlyByteBuf.writeBigItem(value: ItemStackWrapper) = value.write(this)
fun FriendlyByteBuf.readBigItem() = ItemStackWrapper.read(this)

View File

@ -0,0 +1,32 @@
package ru.dbotthepony.mc.otm.tests
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import ru.dbotthepony.mc.otm.core.formatReadableNumber
import java.math.BigInteger
object FormattingTests {
@Test
@DisplayName("BigInteger formatting")
fun biginteger() {
assertEquals("0", BigInteger("0").formatReadableNumber())
assertEquals("45", BigInteger("45").formatReadableNumber())
assertEquals("-45", BigInteger("-45").formatReadableNumber())
assertEquals("0", BigInteger("-0").formatReadableNumber())
assertEquals("100", BigInteger("100").formatReadableNumber())
assertEquals("-100", BigInteger("-100").formatReadableNumber())
assertEquals("999", BigInteger("999").formatReadableNumber())
assertEquals("1 999", BigInteger("1999").formatReadableNumber())
assertEquals("8 992", BigInteger("8992").formatReadableNumber())
assertEquals("-8 992", BigInteger("-8992").formatReadableNumber())
assertEquals("100 200", BigInteger("100200").formatReadableNumber())
assertEquals("-100 200", BigInteger("-100200").formatReadableNumber())
assertEquals("-1 100 200", BigInteger("-1100200").formatReadableNumber())
assertEquals("1 100 200", BigInteger("1100200").formatReadableNumber())
assertEquals("2 730 250 200", BigInteger("2730250200").formatReadableNumber())
assertEquals("1 222 730 250 200", BigInteger("1222730250200").formatReadableNumber())
}
}