diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt index 906ed79b6..065c0413e 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt @@ -416,6 +416,8 @@ private fun gui(provider: MatteryLanguageProvider) { 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.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") } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/DriveViewerScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/DriveViewerScreen.kt index c5d82d1aa..8012f9768 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/DriveViewerScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/DriveViewerScreen.kt @@ -1,5 +1,6 @@ package ru.dbotthepony.mc.otm.client.screen +import com.mojang.blaze3d.vertex.PoseStack import net.minecraft.network.chat.Component import net.minecraft.network.chat.TranslatableComponent 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 scroll_bar = ScrollBarPanel(this, frame, 192f, 14f, 92f) - scroll_bar.setupRowMultiplier { menu.view.itemCount / GRID_WIDTH } + val scrollBar = ScrollBarPanel(this, frame, 192f, 14f, 92f) + scrollBar.setupRowMultiplier { menu.view.itemCount / GRID_WIDTH } views.add(grid) - views.add(scroll_bar) + views.add(scrollBar) for (i in 0 until GRID_WIDTH * GRID_HEIGHT) { object : AbstractSlotPanel(this@DriveViewerScreen, grid, 0f, 0f) { override fun getItemStack(): ItemStack { - val index = i + scroll_bar.getScroll(menu.view.sortedView.size / GRID_WIDTH) - return menu.view.sortedView.getOrNull(index)?.stack ?: ItemStack.EMPTY + val index = i + scrollBar.getScroll(menu.view.sortedView.size / GRID_WIDTH) + return menu.view.sortedView.getOrNull(index)?.stack?.item ?: ItemStack.EMPTY } 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 { - val index = i + scroll_bar.getScroll(GRID_WIDTH) + val index = i + scrollBar.getScroll(GRID_WIDTH) menu.view.mouseClick(index, mouse_click_type) 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 { + return super.getItemStackTooltip(stack).also { + it as MutableList + 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())) + } + } } } 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 d36b4e22f..f2af625fc 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 @@ -1,6 +1,7 @@ package ru.dbotthepony.mc.otm.client.screen import com.mojang.blaze3d.vertex.PoseStack +import net.minecraft.ChatFormatting import net.minecraft.network.chat.Component import net.minecraft.network.chat.TranslatableComponent 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.screen.panels.* 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.next -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 -} +import java.text.NumberFormat class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Component) : MatteryScreen(menu, inventory, title) { @@ -42,7 +36,7 @@ class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Comp 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) - viewScrollBar.setupRowMultiplier { div(menu.view.itemCount, ITEM_GRID_WIDTH) } + viewScrollBar.setupRowMultiplier { equalDownDivision(menu.view.itemCount, ITEM_GRID_WIDTH) } viewScrollBar.dock = Dock.RIGHT 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) { object : AbstractSlotPanel(this@ItemMonitorScreen, gridPanel) { override fun getItemStack(): ItemStack { - val index = i + viewScrollBar.getScroll(div(menu.view.itemCount, ITEM_GRID_WIDTH)) * ITEM_GRID_WIDTH - return menu.view.sortedView.getOrNull(index)?.stack ?: ItemStack.EMPTY + val index = i + viewScrollBar.getScroll(equalDownDivision(menu.view.itemCount, ITEM_GRID_WIDTH)) * ITEM_GRID_WIDTH + return menu.view.sortedView.getOrNull(index)?.stack?.item ?: ItemStack.EMPTY } 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 { - 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) 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 { + return super.getItemStackTooltip(stack).also { + it as MutableList + 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)) + } + } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/AbstractSlotPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/AbstractSlotPanel.kt index 425c05d8d..fe3c3ef74 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/AbstractSlotPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/AbstractSlotPanel.kt @@ -8,6 +8,7 @@ import net.minecraft.network.chat.Component import net.minecraft.world.item.ItemStack import net.minecraftforge.client.RenderProperties import org.lwjgl.opengl.GL11 +import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.core.RGBAColor import ru.dbotthepony.mc.otm.client.render.RenderHelper 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.renderAndDecorateItem( - Minecraft.getInstance().player, + requireNotNull(minecraft.player) { "yo, dude, what the fuck" }, itemstack, 0, 0, diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt index 533389318..569d8e7c8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt @@ -6,7 +6,10 @@ package ru.dbotthepony.mc.otm.core import net.minecraft.core.BlockPos import net.minecraft.core.Direction 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: Direction): BlockPos = this.offset(direction.normal) @@ -217,3 +220,20 @@ fun Byte.toImpreciseFraction() = ImpreciseFraction(this) fun Short.toImpreciseFraction() = ImpreciseFraction(this) fun Long.toImpreciseFraction() = ImpreciseFraction(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)) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Formatting.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Formatting.kt new file mode 100644 index 000000000..8c1ca5d4d --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Formatting.kt @@ -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) +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Math.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Math.kt index b5961eac9..a529d8367 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Math.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Math.kt @@ -1,20 +1,16 @@ package ru.dbotthepony.mc.otm.core -import net.minecraft.nbt.ByteArrayTag -import net.minecraft.nbt.Tag import java.math.BigInteger inline val BigInteger.isZero get() = this == BigInteger.ZERO inline val BigInteger.isPositive get() = this > BigInteger.ZERO inline val BigInteger.isNegative get() = this < BigInteger.ZERO -fun BigInteger.serializeNBT(): ByteArrayTag { - return ByteArrayTag(toByteArray()) -} +@Suppress("SameParameterValue") +fun equalDownDivision(a: Int, b: Int): Int { + if (a % b == 0) { + return a / b - 1 + } -fun BigInteger(tag: Tag?): BigInteger { - if (tag !is ByteArrayTag) - return BigInteger.ZERO - - return BigInteger(tag.asByteArray) + return a / b } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/data/NetworkedItemView.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/data/NetworkedItemView.kt index fa93d2e88..43eeed33f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/data/NetworkedItemView.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/data/NetworkedItemView.kt @@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.menu.data import com.mojang.blaze3d.platform.InputConstants import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap -import it.unimi.dsi.fastutil.longs.Long2ObjectAVLTreeMap import net.minecraft.client.Minecraft import net.minecraft.client.gui.screens.Screen 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.inventory.ClickAction import net.minecraft.world.inventory.ClickType -import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack import net.minecraftforge.network.NetworkEvent 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.network.MatteryNetworking import ru.dbotthepony.mc.otm.network.SetCarriedPacket @@ -23,15 +22,11 @@ import java.math.BigInteger import java.util.* 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) { + buffer.writeInt(containerId) buffer.writeInt(id) - buffer.writeInt(stack_id) - buffer.writeRegistryId(stack.item) - buffer.writeInt(stack.count) - buffer.writeBoolean(stack.shareTag != null) - - if (stack.tag != null) buffer.writeNbt(stack.shareTag) + buffer.writeBigItem(stack) } fun play(context: Supplier) { @@ -39,17 +34,17 @@ class StackAddPacket(val id: Int, val stack_id: Int, val stack: ItemStack) { context.get().enqueueWork { val get = Minecraft.getInstance().player?.containerMenu ?: return@enqueueWork - if (get.containerId != id) + if (get.containerId != containerId) 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)) { - throw IllegalStateException("Item tracker $id already has stack with id of $stack_id") + if (view.localState.containsKey(id)) { + throw IllegalStateException("Item tracker $containerId already has stack with id of $id") } - val state = NetworkedItemView.NetworkedItem(stack_id, stack) - view.localState[stack_id] = state + val state = NetworkedItemView.NetworkedItem(id, stack) + view.localState[id] = state /*val iterator = view.sortedView.iterator().withIndex() var lastCompare = 0 @@ -77,22 +72,19 @@ class StackAddPacket(val id: Int, val stack_id: Int, val stack: ItemStack) { companion object { fun read(buffer: FriendlyByteBuf): StackAddPacket { + val containerId = buffer.readInt() val id = buffer.readInt() - val stack = buffer.readInt() - val item = buffer.readRegistryIdSafe(Item::class.java) - val count = buffer.readInt() - val state = ItemStack(item, count) - if (buffer.readBoolean()) state.readShareTag(buffer.readNbt()) - return StackAddPacket(id, stack, state) + val item = buffer.readBigItem() + return StackAddPacket(containerId, id, item) } } } -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) { buffer.writeInt(id) buffer.writeInt(stackID) - buffer.writeInt(newCount) + buffer.writeBigInteger(newCount) } fun play(context: Supplier) { @@ -115,7 +107,7 @@ class StackChangePacket(val id: Int, val stackID: Int, val newCount: Int) { fun read(buffer: FriendlyByteBuf): StackChangePacket { val id = buffer.readInt() val stackID = buffer.readInt() - val newCount = buffer.readInt() + val newCount = buffer.readBigInteger() 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. */ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote: Boolean) : IStorageEventConsumer { - 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 get() = ITEM_STORAGE @@ -188,7 +180,7 @@ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote: fun resort() { 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 - override fun addStack(stack: ItemStackWrapper, id: UUID, provider: IStorageProvider) = addObject(stack.stack, id) - override fun changeStack(stack: ItemStackWrapper, id: UUID, oldCount: BigInteger) = changeObject(id, stack.count.toInt()) + override fun addStack(stack: ItemStackWrapper, id: UUID, provider: IStorageProvider) { + 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) { if (!remote) { @@ -248,22 +253,6 @@ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote: 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() { sortedView.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 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 MatteryNetworking.send(ply as ServerPlayer, SetCarriedPacket(ply.containerMenu.carried)) ply.containerMenu.setRemoteCarried(ply.containerMenu.carried.copy()) @@ -308,9 +296,9 @@ open class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val remote: val amount = if (action == ClickAction.PRIMARY) - state.stack.maxStackSize + state.stack.item.maxStackSize else - 1.coerceAtLeast(state.stack.maxStackSize / 2) + 1.coerceAtLeast(state.stack.item.maxStackSize / 2) 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 = if (action == ClickAction.PRIMARY) - state.stack.maxStackSize + state.stack.item.maxStackSize 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) menu.carried = extracted.stack diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/storage/ItemStackWrapper.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/ItemStackWrapper.kt index e9852735c..332b373e8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/storage/ItemStackWrapper.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/ItemStackWrapper.kt @@ -1,5 +1,6 @@ package ru.dbotthepony.mc.otm.storage +import net.minecraft.network.FriendlyByteBuf import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack import net.minecraftforge.registries.ForgeRegistries @@ -7,6 +8,8 @@ import net.minecraftforge.registries.ForgeRegistry import org.jetbrains.annotations.ApiStatus import ru.dbotthepony.mc.otm.core.ImpreciseFraction 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 /** @@ -86,8 +89,22 @@ class ItemStackWrapper : IStorageStack { return "ItemStackWrapper[$count $registryName]" } + fun write(buff: FriendlyByteBuf) { + buff.writeItem(item) + buff.writeBigInteger(count) + } + companion object { @JvmField 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) diff --git a/src/test/kotlin/ru/dbotthepony/mc/otm/tests/FormattingTests.kt b/src/test/kotlin/ru/dbotthepony/mc/otm/tests/FormattingTests.kt new file mode 100644 index 000000000..6402b6ead --- /dev/null +++ b/src/test/kotlin/ru/dbotthepony/mc/otm/tests/FormattingTests.kt @@ -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()) + } +}