From 7d9d18c372b06e6301c75e26688db7eaec8db16d Mon Sep 17 00:00:00 2001 From: Adrian Siekierka Date: Tue, 7 Jun 2022 17:39:19 +0200 Subject: [PATCH] Fix inconsistent 3D print item stacking Now prints that consist of the same set of shapes stack as they should. Co-authored-by: Quant1um --- .../cil/oc/common/item/data/PrintData.scala | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/main/scala/li/cil/oc/common/item/data/PrintData.scala b/src/main/scala/li/cil/oc/common/item/data/PrintData.scala index 35ded28d7..c162d58c0 100644 --- a/src/main/scala/li/cil/oc/common/item/data/PrintData.scala +++ b/src/main/scala/li/cil/oc/common/item/data/PrintData.scala @@ -1,11 +1,11 @@ package li.cil.oc.common.item.data import java.lang.reflect.Method - import li.cil.oc.Constants import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.common.IMC +import li.cil.oc.common.item.data.PrintData.Shape import li.cil.oc.util.ExtendedAABB._ import li.cil.oc.util.ExtendedNBT._ import net.minecraft.item.ItemStack @@ -82,13 +82,35 @@ class PrintData extends ItemData(Constants.BlockName.Print) { nbt.setBoolean("isButtonMode", isButtonMode) nbt.setInteger("redstoneLevel", redstoneLevel) nbt.setBoolean("pressurePlate", pressurePlate) - nbt.setNewTagList("stateOff", stateOff.map(PrintData.shapeToNBT)) - nbt.setNewTagList("stateOn", stateOn.map(PrintData.shapeToNBT)) + setNewShapeSet(nbt, "stateOff", stateOff) + setNewShapeSet(nbt, "stateOn", stateOn) nbt.setBoolean("isBeaconBase", isBeaconBase) nbt.setByte("lightLevel", lightLevel.toByte) nbt.setBoolean("noclipOff", noclipOff) nbt.setBoolean("noclipOn", noclipOn) } + + // Shapes are stored in a set and sets do not have an order, that means NBT shape lists may be in any order. + // Because NBT list comparison considers order of tags in a list, and prints may have arbitrarily ordered list of shapes, + // the comparison fails and minecraft considers two identical prints different. + // One possible solution is to sort the shapes before serializing them to NBT + private def setNewShapeSet(nbt: NBTTagCompound, name: String, values: Iterable[Shape]) = { + val seq = values.toSeq.sortWith(compareShape); + nbt.setNewTagList(name, seq.map(PrintData.shapeToNBT)) + } + + private def compareShape(a: Shape, b: Shape): Boolean = { + import scala.math.Ordering.Implicits._ + if (a.bounds.minX != b.bounds.minX) return a.bounds.minX > b.bounds.minX; + if (a.bounds.minY != b.bounds.minY) return a.bounds.minY > b.bounds.minY; + if (a.bounds.minZ != b.bounds.minZ) return a.bounds.minZ > b.bounds.minZ; + if (a.bounds.maxX != b.bounds.maxX) return a.bounds.maxX > b.bounds.maxX; + if (a.bounds.maxY != b.bounds.maxY) return a.bounds.maxY > b.bounds.maxY; + if (a.bounds.maxZ != b.bounds.maxZ) return a.bounds.maxZ > b.bounds.maxZ; + if (a.tint != b.tint) return a.tint > b.tint; + if (a.texture != b.texture) return a.texture > b.texture; + false + } } object PrintData {