diff --git a/patches/viabedrock/deferred/0003-translate-server-authoritative-bedrock-requests.patch b/patches/viabedrock/deferred/0003-translate-server-authoritative-bedrock-requests.patch index 7c3d196a..a0a10dbf 100644 --- a/patches/viabedrock/deferred/0003-translate-server-authoritative-bedrock-requests.patch +++ b/patches/viabedrock/deferred/0003-translate-server-authoritative-bedrock-requests.patch @@ -1,4 +1,4 @@ -From 766d63ec9879dcf7ec959d0905f3eb03b51f5dcd Mon Sep 17 00:00:00 2001 +From d983e2b657e13603f4747ab1cb9c3632795d8198 Mon Sep 17 00:00:00 2001 From: AlexProgrammerDE <40795980+AlexProgrammerDE@users.noreply.github.com> Date: Sun, 18 Oct 2026 16:55:37 +0200 Subject: [PATCH] feat(inventory): translate server-authoritative Bedrock @@ -906,7 +906,7 @@ Validate every network ID needed by bundle swaps and compaction before changing .../ItemRegistryComponentUpdatesTest.java | 118 + .../model/ItemRegistryTagIndexTest.java | 127 + .../protocol/model/ItemRegistryTagsTest.java | 173 + - .../protocol/model/ItemRegistryTest.java | 223 +- + .../protocol/model/ItemRegistryTest.java | 224 +- .../protocol/model/ItemStackHeaderTest.java | 67 + .../LegacyItemStackingPropertiesTest.java | 104 + .../model/NamedItemConstructionTest.java | 77 + @@ -948,7 +948,7 @@ Validate every network ID needed by bundle swaps and compaction before changing .../item/NetworkItemConstructionTest.java | 171 + .../types/item/NetworkItemCountTest.java | 35 +- .../types/item/NetworkItemStackFixtures.java | 69 + - 139 files changed, 29203 insertions(+), 2049 deletions(-) + 139 files changed, 29203 insertions(+), 2050 deletions(-) create mode 100644 src/main/java/net/raphimc/viabedrock/api/model/PlayerInventoryScreenClose.java create mode 100644 src/main/java/net/raphimc/viabedrock/api/model/PlayerInventoryScreenReady.java create mode 100644 src/main/java/net/raphimc/viabedrock/api/model/PlayerInventoryScreenRequest.java @@ -32756,13 +32756,13 @@ index 00000000..fb6fc02a + +} diff --git a/src/test/java/net/raphimc/viabedrock/protocol/model/ItemRegistryTest.java b/src/test/java/net/raphimc/viabedrock/protocol/model/ItemRegistryTest.java -index 914b28a1..08ae32d1 100644 +index 04d8c44b..597d7344 100644 --- a/src/test/java/net/raphimc/viabedrock/protocol/model/ItemRegistryTest.java +++ b/src/test/java/net/raphimc/viabedrock/protocol/model/ItemRegistryTest.java -@@ -6,12 +6,23 @@ - package net.raphimc.viabedrock.protocol.model; +@@ -7,13 +7,23 @@ package net.raphimc.viabedrock.protocol.model; import com.viaversion.nbt.tag.CompoundTag; + import com.viaversion.nbt.tag.ListTag; +import com.viaversion.viaversion.libs.gson.JsonParser; import io.netty.buffer.Unpooled; +import java.nio.file.Files; @@ -32781,11 +32781,12 @@ index 914b28a1..08ae32d1 100644 import org.junit.jupiter.api.Test; - -import java.util.List; +-import java.util.Map; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import static org.junit.jupiter.api.Assertions.*; -@@ -269,4 +280,212 @@ class ItemRegistryTest { +@@ -302,4 +312,212 @@ class ItemRegistryTest { return new ItemEntry(name, id, false, version, null); } diff --git a/patches/viabedrock/upstreamable/0095-integrate-authored-native-ui-presentation.patch b/patches/viabedrock/upstreamable/0095-integrate-authored-native-ui-presentation.patch index a8c0a8d4..bba5a156 100644 --- a/patches/viabedrock/upstreamable/0095-integrate-authored-native-ui-presentation.patch +++ b/patches/viabedrock/upstreamable/0095-integrate-authored-native-ui-presentation.patch @@ -1,4 +1,4 @@ -From e03b81e1cceb1c0949ec1367d6d3e8b0f32bb9a0 Mon Sep 17 00:00:00 2001 +From 455632d9a1d43fd8905775eb6fc6c81df40464e8 Mon Sep 17 00:00:00 2001 From: AlexProgrammerDE <40795980+AlexProgrammerDE@users.noreply.github.com> Date: Sun, 18 Oct 2026 16:55:37 +0200 Subject: [PATCH] feat(ui): resolve authored Bedrock server UI scenes @@ -745,17 +745,46 @@ merges, holes, partial destinations, nested weight, filters and rejections. Original ContainerModel setter143a7b610 confirms incoming identity copying and the identity-only notification fast path. Request-scope ID assignment, trusted controller sessions and installed input remain separate work. + +Decode native storage identity with separate NBT presence and typed-int reads. +A present non-integer bundle_id resolves container zero; a missing identity +does not select a container. Share that rule across storage weight, physical +tooltip snapshots, and transfer planning. Keep transported snapshot validation +strict and keep unavailable dynamic contents unknown. + +Original Bedrock 1.26.60.5/protocol 2225 storage admission and child lookup +execute 42 controls through the real CompoundTag presence1429659f0 and +typed-int142965cf0 getters. Resolver142f32c90 and child lookup144fe4a60 retain +signed Int3 payloads and use zero for a present String8 discriminator. The PE +SHA-256 is 988f6a61403b4381aa41e6c66d64cce441b14e561a9b10f647c2758ef3f2672a. +These controls use explicit native tag-map and component fixtures; they do not +establish full protocol NBT construction or installed controller parity. + +Retain storage_item slot limits, nesting admission, and allowed/banned +descriptor maps on the selected native Item definition. Copy the typed +component data into immutable policy values so packet mutation and numeric +ID collisions cannot replace a retained owner's rules. A partial or wrong-typed +replacement leaves policy unavailable instead of inventing empty filters. + +The 1.26.60.5/protocol2225 captured bundle definitions expose these fields. +Original legacy reader141a72880 and storage vector conversion148f31150 +establish lowercase string-map descriptors, with tags/name/item_tag precedence +and wildcard32767 for a named entry. Seventeen original controls cover the +map reader, four-entry vector conversion, and default Legacy construction. +Raw policy retention does not resolve those descriptors or assume a Molang +version context. Bind them in the runtime layer with the existing registry +and descriptor contracts before enabling native transfer actions. --- Data Asset Sources.md | 33 + build.gradle | 1 + .../chunk/blockstate/BuiltinBlockNames.java | 46 + - .../api/model/NativeBundleTooltipData.java | 86 + + .../api/model/NativeBundleTooltipData.java | 87 + .../api/model/NativeBundleTooltipItems.java | 170 + .../viabedrock/api/model/NativeItemNames.java | 14 + .../api/model/NativeItemStacking.java | 85 + - .../api/model/NativeItemStorageData.java | 116 + + .../api/model/NativeItemStorageData.java | 123 + .../api/model/container/ChestContainer.java | 3 +- - .../container/NativeBundleTransferPlan.java | 294 + + .../container/NativeBundleTransferPlan.java | 289 + .../container/NativeContainerActionSlots.java | 75 + .../NativeContainerLegacyActions.java | 130 + .../container/NativeContainerTransfer.java | 63 + @@ -788,7 +817,8 @@ trusted controller sessions and installed input remain separate work. .../protocol/model/ItemNameContext.java | 23 + .../protocol/model/ItemRegistry.java | 187 + .../model/ItemStackingProperties.java | 36 + - .../protocol/model/ItemStorageProperties.java | 40 + + .../protocol/model/ItemStoragePolicy.java | 61 + + .../protocol/model/ItemStorageProperties.java | 45 + .../model/LegacyItemStackingProperties.java | 54 + .../protocol/model/NativeItemDefinitions.java | 309 + .../protocol/model/NativeItemName.java | 78 + @@ -813,12 +843,12 @@ trusted controller sessions and installed input remain separate work. .../data/bedrock/item_factories.json | 10234 +++++++++++ .../data/bedrock/item_registry.json | 14496 ++++++++++++++++ .../viabedrock/data/bedrock/potion_names.json | 194 + - .../model/NativeBundleTooltipDataTest.java | 97 + + .../model/NativeBundleTooltipDataTest.java | 113 + .../model/NativeBundleTooltipItemsTest.java | 147 + .../api/model/NativeItemNamesTest.java | 83 + .../api/model/NativeItemStackingTest.java | 149 + - .../api/model/NativeItemStorageDataTest.java | 96 + - .../NativeBundleTransferPlanTest.java | 175 + + .../api/model/NativeItemStorageDataTest.java | 112 + + .../NativeBundleTransferPlanTest.java | 188 + .../NativeContainerLegacyActionsTest.java | 323 + .../NativeContainerTransferTest.java | 115 + .../container/NativeItemStackMatcherTest.java | 191 + @@ -830,7 +860,8 @@ trusted controller sessions and installed input remain separate work. .../model/ItemRegistryAliasesTest.java | 36 + .../model/ItemRegistryComponentNamesTest.java | 84 + .../model/ItemRegistryOrdinaryNamesTest.java | 72 + - .../protocol/model/ItemRegistryTest.java | 272 + + .../protocol/model/ItemRegistryTest.java | 305 + + .../protocol/model/ItemStoragePolicyTest.java | 51 + .../model/NativeItemDefinitionsTest.java | 207 + .../protocol/model/NativeItemNameTest.java | 61 + .../packet/ModalFormTransitionTest.java | 165 + @@ -844,7 +875,7 @@ trusted controller sessions and installed input remain separate work. .../native-bundle-tooltip-layout.json | 266 + .../inventory/native-bundle-transfers.json | 1622 ++ .../inventory/native-item-storage.json | 568 + - 98 files changed, 40157 insertions(+), 364 deletions(-) + 100 files changed, 40355 insertions(+), 364 deletions(-) create mode 100644 src/main/java/net/raphimc/viabedrock/api/chunk/blockstate/BuiltinBlockNames.java create mode 100644 src/main/java/net/raphimc/viabedrock/api/model/NativeBundleTooltipData.java create mode 100644 src/main/java/net/raphimc/viabedrock/api/model/NativeBundleTooltipItems.java @@ -875,6 +906,7 @@ trusted controller sessions and installed input remain separate work. create mode 100644 src/main/java/net/raphimc/viabedrock/protocol/model/ItemNameContext.java create mode 100644 src/main/java/net/raphimc/viabedrock/protocol/model/ItemRegistry.java create mode 100644 src/main/java/net/raphimc/viabedrock/protocol/model/ItemStackingProperties.java + create mode 100644 src/main/java/net/raphimc/viabedrock/protocol/model/ItemStoragePolicy.java create mode 100644 src/main/java/net/raphimc/viabedrock/protocol/model/ItemStorageProperties.java create mode 100644 src/main/java/net/raphimc/viabedrock/protocol/model/LegacyItemStackingProperties.java create mode 100644 src/main/java/net/raphimc/viabedrock/protocol/model/NativeItemDefinitions.java @@ -905,6 +937,7 @@ trusted controller sessions and installed input remain separate work. create mode 100644 src/test/java/net/raphimc/viabedrock/protocol/model/ItemRegistryComponentNamesTest.java create mode 100644 src/test/java/net/raphimc/viabedrock/protocol/model/ItemRegistryOrdinaryNamesTest.java create mode 100644 src/test/java/net/raphimc/viabedrock/protocol/model/ItemRegistryTest.java + create mode 100644 src/test/java/net/raphimc/viabedrock/protocol/model/ItemStoragePolicyTest.java create mode 100644 src/test/java/net/raphimc/viabedrock/protocol/model/NativeItemDefinitionsTest.java create mode 100644 src/test/java/net/raphimc/viabedrock/protocol/model/NativeItemNameTest.java create mode 100644 src/test/java/net/raphimc/viabedrock/protocol/packet/ModalFormTransitionTest.java @@ -1024,10 +1057,10 @@ index 00000000..c9581911 +} diff --git a/src/main/java/net/raphimc/viabedrock/api/model/NativeBundleTooltipData.java b/src/main/java/net/raphimc/viabedrock/api/model/NativeBundleTooltipData.java new file mode 100644 -index 00000000..eca249b8 +index 00000000..705bd265 --- /dev/null +++ b/src/main/java/net/raphimc/viabedrock/api/model/NativeBundleTooltipData.java -@@ -0,0 +1,86 @@ +@@ -0,0 +1,87 @@ +/* + * This file is part of ViaBedrock - https://github.com/RaphiMC/ViaBedrock + * Copyright (C) 2026 RK_01/RaphiMC and contributors @@ -1101,15 +1134,16 @@ index 00000000..eca249b8 + + public static NativeBundleTooltipData resolve(final BedrockItem item, final ItemStorageProperties properties, + final IntFunction contents) { ++ final Integer identity = NativeItemStorageData.containerIdentity(item); + if (item.isEmpty() || !properties.storage() || properties.viewableSlots() == null || properties.viewableSlots() <= 0 -+ || item.tag() == null || !(item.tag().get("bundle_id") instanceof IntTag id)) { ++ || identity == null) { + return null; + } -+ final var items = contents.apply(id.asInt()); ++ final var items = contents.apply(identity); + if (items == null || items.length > 64) { + return null; + } -+ return new NativeBundleTooltipData(id.asInt(), properties.viewableSlots(), Arrays.stream(items) ++ return new NativeBundleTooltipData(identity, properties.viewableSlots(), Arrays.stream(items) + .map(child -> child.isEmpty() ? 0 : child.amount()).toList()); + } + @@ -1422,10 +1456,10 @@ index 00000000..9bd1f5b7 +} diff --git a/src/main/java/net/raphimc/viabedrock/api/model/NativeItemStorageData.java b/src/main/java/net/raphimc/viabedrock/api/model/NativeItemStorageData.java new file mode 100644 -index 00000000..65c4c91c +index 00000000..c95fff7a --- /dev/null +++ b/src/main/java/net/raphimc/viabedrock/api/model/NativeItemStorageData.java -@@ -0,0 +1,116 @@ +@@ -0,0 +1,123 @@ +/* + * This file is part of ViaBedrock - https://github.com/RaphiMC/ViaBedrock + * Copyright (C) 2026 RK_01/RaphiMC and contributors @@ -1474,6 +1508,13 @@ index 00000000..65c4c91c + return resolve(item, source, work, 0, new HashSet<>()); + } + ++ /** Native presence and typed lookup are separate: a present non-integer identity reads as zero. */ ++ public static Integer containerIdentity(final BedrockItem item) { ++ final CompoundTag tag = item.tag(); ++ return tag == null || !tag.contains("bundle_id") ? null ++ : tag.get("bundle_id") instanceof IntTag id ? id.asInt() : 0; ++ } ++ + private static NativeItemStorageData resolve(final BedrockItem item, final Source source, final Work work, + final int depth, final Set path) { + if (++work.items > MAX_ITEMS || depth > MAX_DEPTH) { @@ -1488,10 +1529,10 @@ index 00000000..65c4c91c + if (tag != null && tag.get("bundle_weight") instanceof IntTag cached && cached.asInt() != 0) { + return new NativeItemStorageData(properties.modifier(), cached.asInt() - properties.modifier(), properties.capacity()); + } -+ if (tag == null || !(tag.get("bundle_id") instanceof IntTag id)) { ++ final Integer identity = containerIdentity(item); ++ if (identity == null) { + return new NativeItemStorageData(properties.modifier(), 0, properties.capacity()); + } -+ final int identity = id.asInt(); + if (!path.add(identity)) { + work.incomplete = true; + return null; @@ -1558,10 +1599,10 @@ index a37f1b07..913255f8 100644 } diff --git a/src/main/java/net/raphimc/viabedrock/api/model/container/NativeBundleTransferPlan.java b/src/main/java/net/raphimc/viabedrock/api/model/container/NativeBundleTransferPlan.java new file mode 100644 -index 00000000..a2eb508e +index 00000000..fb69ab1a --- /dev/null +++ b/src/main/java/net/raphimc/viabedrock/api/model/container/NativeBundleTransferPlan.java -@@ -0,0 +1,294 @@ +@@ -0,0 +1,289 @@ +/* + * This file is part of ViaBedrock - https://github.com/RaphiMC/ViaBedrock + * Copyright (C) 2026 RK_01/RaphiMC and contributors @@ -1569,7 +1610,6 @@ index 00000000..a2eb508e + */ +package net.raphimc.viabedrock.api.model.container; + -+import com.viaversion.nbt.tag.IntTag; +import net.raphimc.viabedrock.api.model.NativeItemStorageData; +import net.raphimc.viabedrock.protocol.model.BedrockItem; +import net.raphimc.viabedrock.protocol.model.ItemStorageProperties; @@ -1588,7 +1628,7 @@ index 00000000..a2eb508e + final BedrockItem destination, final int destinationSlot, + final int selectedSlot, final Source source) { + final var state = new State(contents, destination, destinationSlot, source); -+ if (identity(bundle) == null || selectedSlot < 0 || selectedSlot >= contents.length ++ if (NativeItemStorageData.containerIdentity(bundle) == null || selectedSlot < 0 || selectedSlot >= contents.length + || state.items[selectedSlot].isEmpty()) { + return state.result(false); + } @@ -1613,7 +1653,7 @@ index 00000000..a2eb508e + final BedrockItem incoming, final int incomingSlot, + final Integer quantity, final Source source) { + final var state = new State(contents, incoming, incomingSlot, source); -+ final Integer identity = identity(bundle); ++ final Integer identity = NativeItemStorageData.containerIdentity(bundle); + if (identity == null) { + return state.result(false); + } @@ -1634,7 +1674,7 @@ index 00000000..a2eb508e + return state.result(false); + } + final var properties = source.properties(incoming); -+ final Integer incomingIdentity = identity(incoming); ++ final Integer incomingIdentity = NativeItemStorageData.containerIdentity(incoming); + final int weight; + if (properties != null && properties.complete()) { + if (incomingIdentity != null) { @@ -1682,10 +1722,6 @@ index 00000000..a2eb508e + return state.result(false); + } + -+ private static Integer identity(final BedrockItem item) { -+ return item.tag() != null && item.tag().get("bundle_id") instanceof IntTag id ? id.asInt() : null; -+ } -+ + public enum Kind { + TAKE, PLACE, SWAP + } @@ -4510,12 +4546,79 @@ index 00000000..06361312 + } + +} +diff --git a/src/main/java/net/raphimc/viabedrock/protocol/model/ItemStoragePolicy.java b/src/main/java/net/raphimc/viabedrock/protocol/model/ItemStoragePolicy.java +new file mode 100644 +index 00000000..0e59c214 +--- /dev/null ++++ b/src/main/java/net/raphimc/viabedrock/protocol/model/ItemStoragePolicy.java +@@ -0,0 +1,61 @@ ++/* ++ * This file is part of ViaBedrock - https://github.com/RaphiMC/ViaBedrock ++ * Copyright (C) 2026 RK_01/RaphiMC and contributors ++ * SPDX-License-Identifier: GPL-3.0-or-later ++ */ ++package net.raphimc.viabedrock.protocol.model; ++ ++import com.viaversion.nbt.tag.ByteTag; ++import com.viaversion.nbt.tag.CompoundTag; ++import com.viaversion.nbt.tag.IntTag; ++import com.viaversion.nbt.tag.ListTag; ++import com.viaversion.nbt.tag.StringTag; ++import com.viaversion.nbt.tag.Tag; ++ ++import java.util.ArrayList; ++import java.util.HashMap; ++import java.util.List; ++import java.util.Map; ++ ++/** Definition-owned storage rules, before descriptor resolution through the native registry. */ ++public record ItemStoragePolicy(int maxSlots, boolean allowNested, List> allowedItems, ++ List> bannedItems) { ++ ++ public ItemStoragePolicy { ++ allowedItems = allowedItems.stream().map(Map::copyOf).toList(); ++ bannedItems = bannedItems.stream().map(Map::copyOf).toList(); ++ } ++ ++ /** Unavailable fields cannot silently become empty filters or an invented slot limit. */ ++ public static ItemStoragePolicy fromComponent(final CompoundTag component) { ++ if (!(component.get("max_slots") instanceof IntTag slots) ++ || !(component.get("allow_nested_storage_items") instanceof ByteTag nested)) { ++ return null; ++ } ++ final var allowed = descriptors(component.get("allowed_items")); ++ final var banned = descriptors(component.get("banned_items")); ++ return allowed != null && banned != null ? new ItemStoragePolicy(slots.asInt(), nested.asByte() != 0, allowed, banned) : null; ++ } ++ ++ private static List> descriptors(final Tag input) { ++ if (!(input instanceof ListTag values)) { ++ return null; ++ } ++ final List> result = new ArrayList<>(values.size()); ++ for (final var value : values) { ++ if (!(value instanceof CompoundTag descriptor)) { ++ return null; ++ } ++ final Map fields = new HashMap<>(); ++ for (final var field : descriptor.getValue().entrySet()) { ++ if (!(field.getValue() instanceof StringTag text)) { ++ return null; ++ } ++ fields.put(field.getKey(), text.getValue()); ++ } ++ result.add(fields); ++ } ++ return result; ++ } ++ ++} diff --git a/src/main/java/net/raphimc/viabedrock/protocol/model/ItemStorageProperties.java b/src/main/java/net/raphimc/viabedrock/protocol/model/ItemStorageProperties.java new file mode 100644 -index 00000000..08ca66d6 +index 00000000..9d70dedd --- /dev/null +++ b/src/main/java/net/raphimc/viabedrock/protocol/model/ItemStorageProperties.java -@@ -0,0 +1,40 @@ +@@ -0,0 +1,45 @@ +/* + * This file is part of ViaBedrock - https://github.com/RaphiMC/ViaBedrock + * Copyright (C) 2026 RK_01/RaphiMC and contributors @@ -4527,12 +4630,16 @@ index 00000000..08ca66d6 +import com.viaversion.nbt.tag.IntTag; + +/** Storage components belong to the selected native Item definition. */ -+public record ItemStorageProperties(boolean storage, Integer modifier, Integer capacity, Integer viewableSlots) { ++public record ItemStorageProperties(boolean storage, Integer modifier, Integer capacity, Integer viewableSlots, ItemStoragePolicy policy) { + + public static final ItemStorageProperties NONE = new ItemStorageProperties(false, null, null); + + public ItemStorageProperties(final boolean storage, final Integer modifier, final Integer capacity) { -+ this(storage, modifier, capacity, null); ++ this(storage, modifier, capacity, null, null); ++ } ++ ++ public ItemStorageProperties(final boolean storage, final Integer modifier, final Integer capacity, final Integer viewableSlots) { ++ this(storage, modifier, capacity, viewableSlots, null); + } + + public ItemStorageProperties withComponentData(final CompoundTag components) { @@ -4540,7 +4647,8 @@ index 00000000..08ca66d6 + return new ItemStorageProperties(storage, + integer(components, "minecraft:storage_weight_modifier", "weight_in_storage_item", this.modifier), + integer(components, "minecraft:storage_weight_limit", "max_weight_limit", this.capacity), -+ integer(components, "minecraft:bundle_interaction", "num_viewable_slots", this.viewableSlots)); ++ integer(components, "minecraft:bundle_interaction", "num_viewable_slots", this.viewableSlots), ++ components.get("minecraft:storage_item") instanceof CompoundTag value ? ItemStoragePolicy.fromComponent(value) : this.policy); + } + + public boolean complete() { @@ -35804,10 +35912,10 @@ index 00000000..cd681cd4 +} diff --git a/src/test/java/net/raphimc/viabedrock/api/model/NativeBundleTooltipDataTest.java b/src/test/java/net/raphimc/viabedrock/api/model/NativeBundleTooltipDataTest.java new file mode 100644 -index 00000000..6ee62355 +index 00000000..2d663c47 --- /dev/null +++ b/src/test/java/net/raphimc/viabedrock/api/model/NativeBundleTooltipDataTest.java -@@ -0,0 +1,97 @@ +@@ -0,0 +1,113 @@ +/* + * This file is part of ViaBedrock - https://github.com/RaphiMC/ViaBedrock + * Copyright (C) 2026 RK_01/RaphiMC and contributors @@ -35829,6 +35937,22 @@ index 00000000..6ee62355 +class NativeBundleTooltipDataTest { + + @Test ++ void presentNonIntegerIdentitySelectsZeroContainerWhileMissingIdentityCannotPublish() { ++ final var parent = item(1); ++ parent.setTag(new CompoundTag()); ++ parent.tag().putString("bundle_id", "7"); ++ final var properties = new ItemStorageProperties(true, 4, 64, 12); ++ final var snapshot = NativeBundleTooltipData.resolve(parent, properties, id -> { ++ assertEquals(0, id); ++ return new BedrockItem[]{BedrockItem.empty(), item(3)}; ++ }); ++ assertNotNull(snapshot); ++ assertEquals(new NativeBundleTooltipData(0, 12, List.of(0, 3)), NativeBundleTooltipData.fromTag(snapshot.toTag())); ++ parent.tag().remove("bundle_id"); ++ assertNull(NativeBundleTooltipData.resolve(parent, properties, id -> fail("Missing identity must not select a container"))); ++ } ++ ++ @Test + void serializedSparseSnapshotRetainsPhysicalSlotsAcrossLaterContainerChanges() { + final var parent = item(1); + final var tag = new CompoundTag(); @@ -36329,10 +36453,10 @@ index 00000000..75b7dbfb +} diff --git a/src/test/java/net/raphimc/viabedrock/api/model/NativeItemStorageDataTest.java b/src/test/java/net/raphimc/viabedrock/api/model/NativeItemStorageDataTest.java new file mode 100644 -index 00000000..3b25d258 +index 00000000..0332336d --- /dev/null +++ b/src/test/java/net/raphimc/viabedrock/api/model/NativeItemStorageDataTest.java -@@ -0,0 +1,96 @@ +@@ -0,0 +1,112 @@ +/* + * This file is part of ViaBedrock - https://github.com/RaphiMC/ViaBedrock + * Copyright (C) 2026 RK_01/RaphiMC and contributors @@ -36358,6 +36482,22 @@ index 00000000..3b25d258 +class NativeItemStorageDataTest { + + @Test ++ void presentNonIntegerIdentityUsesZeroContainerWeightAndKeepsUnavailableContentsUnknown() { ++ final var source = new FixtureSource(); ++ final var parent = source.item(JsonParser.parseString(""" ++ {"amount":1,"storage":true,"modifier":4,"capacity":64,"maximum":1,"supported":true,"tag":{"bundle_id":9}} ++ """).getAsJsonObject()); ++ parent.tag().putString("bundle_id", "9"); ++ final var child = source.item(JsonParser.parseString(""" ++ {"amount":3,"storage":false,"modifier":null,"capacity":null,"maximum":64,"supported":true,"tag":null} ++ """).getAsJsonObject()); ++ source.containers.put(0, new BedrockItem[]{child}); ++ assertEquals(new NativeItemStorageData(4, 3, 64), NativeItemStorageData.resolve(parent, source)); ++ source.containers.clear(); ++ assertNull(NativeItemStorageData.resolve(parent, source)); ++ } ++ ++ @Test + void cachedAndDynamicWeightsMatchTheOriginalNativeStorageProducer() throws Exception { + try (var stream = getClass().getResourceAsStream("/inventory/native-item-storage.json")) { + assertNotNull(stream); @@ -36431,10 +36571,10 @@ index 00000000..3b25d258 +} diff --git a/src/test/java/net/raphimc/viabedrock/api/model/container/NativeBundleTransferPlanTest.java b/src/test/java/net/raphimc/viabedrock/api/model/container/NativeBundleTransferPlanTest.java new file mode 100644 -index 00000000..75410469 +index 00000000..23d4e9bb --- /dev/null +++ b/src/test/java/net/raphimc/viabedrock/api/model/container/NativeBundleTransferPlanTest.java -@@ -0,0 +1,175 @@ +@@ -0,0 +1,188 @@ +/* + * This file is part of ViaBedrock - https://github.com/RaphiMC/ViaBedrock + * Copyright (C) 2026 RK_01/RaphiMC and contributors @@ -36460,6 +36600,19 @@ index 00000000..75410469 +class NativeBundleTransferPlanTest { + + @Test ++ void presentNonIntegerBundleIdentityCanInsertIntoItsZeroContainer() { ++ final var bundle = item(1001, 1, 99); ++ bundle.setTag(new CompoundTag()); ++ bundle.tag().putString("bundle_id", "42"); ++ final var result = NativeBundleTransferPlan.insert(bundle, new BedrockItem[]{BedrockItem.empty()}, ++ item(31, 5, 7), 3, null, new FixtureSource(new JsonObject())); ++ assertTrue(result.successful()); ++ assertEquals(5, result.contents().getFirst().amount()); ++ assertTrue(result.external().isEmpty()); ++ assertEquals(3, result.transfers().getFirst().source().index()); ++ } ++ ++ @Test + void retainsOwnedRawIdentitiesBeforeTheRequestExecutorAssignsPredictedIds() { + final var bundle = item(1001, 1, 99); + bundle.setTag(new CompoundTag()); @@ -38169,10 +38322,10 @@ index 00000000..db6b7e37 +} diff --git a/src/test/java/net/raphimc/viabedrock/protocol/model/ItemRegistryTest.java b/src/test/java/net/raphimc/viabedrock/protocol/model/ItemRegistryTest.java new file mode 100644 -index 00000000..914b28a1 +index 00000000..04d8c44b --- /dev/null +++ b/src/test/java/net/raphimc/viabedrock/protocol/model/ItemRegistryTest.java -@@ -0,0 +1,272 @@ +@@ -0,0 +1,305 @@ +/* + * This file is part of ViaBedrock - https://github.com/RaphiMC/ViaBedrock + * Copyright (C) 2026 RK_01/RaphiMC and contributors @@ -38181,18 +38334,51 @@ index 00000000..914b28a1 +package net.raphimc.viabedrock.protocol.model; + +import com.viaversion.nbt.tag.CompoundTag; ++import com.viaversion.nbt.tag.ListTag; +import io.netty.buffer.Unpooled; +import net.raphimc.viabedrock.protocol.data.enums.bedrock.generated.ItemVersion; +import net.raphimc.viabedrock.protocol.types.BedrockTypes; +import org.junit.jupiter.api.Test; + +import java.util.List; ++import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +class ItemRegistryTest { + + @Test ++ void storagePoliciesKeepTheirDefinitionOwnerAndDoNotBorrowMutablePacketFields() { ++ final var storage = new CompoundTag(); ++ storage.putInt("max_slots", 64); ++ storage.putByte("allow_nested_storage_items", (byte) 1); ++ storage.put("allowed_items", new ListTag<>(CompoundTag.class)); ++ final var blocked = new CompoundTag(); ++ blocked.putString("name", "minecraft:shulker_box"); ++ final var banned = new ListTag<>(CompoundTag.class); ++ banned.add(blocked); ++ storage.put("banned_items", banned); ++ final var components = new CompoundTag(); ++ components.put("minecraft:storage_item", storage); ++ final var first = component("test:first_storage", 30011, ItemVersion.DataDriven, components); ++ storage.putInt("max_slots", 3); ++ storage.putByte("allow_nested_storage_items", (byte) 0); ++ blocked.putString("name", "minecraft:stone"); ++ final var second = component("test:second_storage", 30011, ItemVersion.DataDriven, components); ++ final var registry = new ItemRegistry(new ItemEntry[]{first, second}); ++ final var retained = new BedrockItem(registry.definition("test:first_storage"), (short) 0, (byte) 1); ++ final var original = registry.storageProperties(retained).policy(); ++ assertEquals(new ItemStoragePolicy(64, true, List.of(), List.of(Map.of("name", "minecraft:shulker_box"))), original); ++ assertEquals(new ItemStoragePolicy(3, false, List.of(), List.of(Map.of("name", "minecraft:stone"))), ++ registry.storageProperties(new BedrockItem(30011)).policy()); ++ components.clear(); ++ registry.registrations().getFirst().componentData().clear(); ++ assertEquals("minecraft:shulker_box", original.bannedItems().getFirst().get("name")); ++ assertThrows(UnsupportedOperationException.class, () -> original.bannedItems().clear()); ++ assertThrows(UnsupportedOperationException.class, () -> original.bannedItems().getFirst().put("name", "minecraft:stone")); ++ } ++ ++ @Test + void emptyDeclarationsKeepBuiltinAndLateBlockDefinitions() { + final var registry = new ItemRegistry(new ItemEntry[0]); + assertTrue(registry.registrations().isEmpty()); @@ -38445,6 +38631,63 @@ index 00000000..914b28a1 + } + +} +diff --git a/src/test/java/net/raphimc/viabedrock/protocol/model/ItemStoragePolicyTest.java b/src/test/java/net/raphimc/viabedrock/protocol/model/ItemStoragePolicyTest.java +new file mode 100644 +index 00000000..bc8b1962 +--- /dev/null ++++ b/src/test/java/net/raphimc/viabedrock/protocol/model/ItemStoragePolicyTest.java +@@ -0,0 +1,51 @@ ++/* ++ * This file is part of ViaBedrock - https://github.com/RaphiMC/ViaBedrock ++ * Copyright (C) 2026 RK_01/RaphiMC and contributors ++ * SPDX-License-Identifier: GPL-3.0-or-later ++ */ ++package net.raphimc.viabedrock.protocol.model; ++ ++import com.viaversion.nbt.tag.CompoundTag; ++import com.viaversion.nbt.tag.ListTag; ++import org.junit.jupiter.api.Test; ++ ++import java.util.List; ++import java.util.Map; ++ ++import static org.junit.jupiter.api.Assertions.*; ++ ++class ItemStoragePolicyTest { ++ ++ @Test ++ void absentComponentsRetainPolicyButUnverifiedReplacementCannotClearItsFilters() { ++ final var storage = new CompoundTag(); ++ storage.putInt("max_slots", 64); ++ storage.putByte("allow_nested_storage_items", (byte) 1); ++ storage.put("allowed_items", new ListTag<>(CompoundTag.class)); ++ final var descriptor = new CompoundTag(); ++ descriptor.putString("tags", "q.any_tag('fixture')"); ++ descriptor.putString("name", "minecraft:stone:3"); ++ final var banned = new ListTag<>(CompoundTag.class); ++ banned.add(descriptor); ++ storage.put("banned_items", banned); ++ final var components = new CompoundTag(); ++ components.put("minecraft:storage_item", storage); ++ final var properties = ItemStorageProperties.NONE.withComponentData(components); ++ assertEquals(new ItemStoragePolicy(64, true, List.of(), ++ List.of(Map.of("tags", "q.any_tag('fixture')", "name", "minecraft:stone:3"))), properties.policy()); ++ assertSame(properties.policy(), properties.withComponentData(new CompoundTag()).policy()); ++ descriptor.putInt("name", 3); ++ assertNull(properties.withComponentData(components).policy()); ++ descriptor.putString("name", "minecraft:stone:3"); ++ storage.remove("allowed_items"); ++ assertNull(properties.withComponentData(components).policy()); ++ storage.put("allowed_items", new ListTag<>(CompoundTag.class)); ++ storage.putString("allow_nested_storage_items", "true"); ++ assertNull(properties.withComponentData(components).policy()); ++ storage.putByte("allow_nested_storage_items", (byte) 1); ++ storage.putShort("max_slots", (short) 64); ++ assertNull(properties.withComponentData(components).policy()); ++ assertEquals("minecraft:stone:3", properties.policy().bannedItems().getFirst().get("name")); ++ } ++ ++} diff --git a/src/test/java/net/raphimc/viabedrock/protocol/model/NativeItemDefinitionsTest.java b/src/test/java/net/raphimc/viabedrock/protocol/model/NativeItemDefinitionsTest.java new file mode 100644 index 00000000..ccbc7903 diff --git a/patches/viabedrock/upstreamable/0095-integrate-authored-native-ui-presentation.pr.md b/patches/viabedrock/upstreamable/0095-integrate-authored-native-ui-presentation.pr.md index 0febebf1..bf68237d 100644 --- a/patches/viabedrock/upstreamable/0095-integrate-authored-native-ui-presentation.pr.md +++ b/patches/viabedrock/upstreamable/0095-integrate-authored-native-ui-presentation.pr.md @@ -24,6 +24,15 @@ The original 1.26.60.5 producer executes 159 controls; 24 representative cases s The controls supply Item queries, typed NBT lookup, container/vector backing, and descriptor storage. Component defaults, tooltip selection, source timing, and complete installed pixels remain unverified. +Storage weight, physical tooltip snapshots, and transfer planning share the native container-identity decoder. +Original storage admission and child lookup controls execute the native CompoundTag presence and typed-int getters: a present string identity selects container zero, while an absent identity selects none. +Local regressions cover zero-container weight, unknown contents, tooltip transport, and physical insertion. +Full protocol tag construction and installed controller behavior remain outside these controls. + +`ItemStoragePolicy` retains typed slot limits, nesting flags, and immutable lowercase descriptor maps on each selected definition. +Registry regressions cover packet mutation, numeric-ID collisions, absent updates, and malformed replacements without inventing unrestricted filters. +Descriptor binding, its version context, and live request execution remain unfinished. + Packet, menu-lifetime, and action tests cover supported adapters. Complete installed player/cooking controllers and live native parity remain unfinished. Action-form dialog labels use the accepted pack translator, as the title and body already do.