mirror of
https://github.com/GTNewHorizons/Postea.git
synced 2026-10-26 14:24:19 +00:00
Add recursive item stack NBT walker
This commit is contained in:
2 files changed
+141
No files matched your search
@@ -0,0 +1,43 @@
|
||||
package com.gtnewhorizons.postea.utility;
|
||||
|
||||
import static net.minecraftforge.common.util.Constants.NBT.TAG_ANY_NUMERIC;
|
||||
import static net.minecraftforge.common.util.Constants.NBT.TAG_COMPOUND;
|
||||
import static net.minecraftforge.common.util.Constants.NBT.TAG_INT;
|
||||
import static net.minecraftforge.common.util.Constants.NBT.TAG_SHORT;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
|
||||
/**
|
||||
* Visits every serialized item stack in an NBT tree. A compound is a stack when it has a numeric {@code id} or an
|
||||
* EndlessIDs {@code idExt} together with a {@code Count}. The walk is pre-order and descends into every compound
|
||||
* and every list of compounds, so stacks nested inside another stack's {@code tag} (backpacks, storage cells) are
|
||||
* visited too. Lists of lists are not descended.
|
||||
*/
|
||||
public final class NbtItemStacks {
|
||||
|
||||
private NbtItemStacks() {}
|
||||
|
||||
public static void forEach(NBTBase root, Consumer<NBTTagCompound> visitor) {
|
||||
if (root instanceof NBTTagCompound compound) {
|
||||
if (isStack(compound)) visitor.accept(compound);
|
||||
for (Object key : new ArrayList<>(compound.func_150296_c())) {
|
||||
forEach(compound.getTag((String) key), visitor);
|
||||
}
|
||||
} else if (root instanceof NBTTagList list && list.func_150303_d() == TAG_COMPOUND) {
|
||||
for (int i = 0; i < list.tagCount(); i++) {
|
||||
forEach(list.getCompoundTagAt(i), visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isStack(NBTTagCompound compound) {
|
||||
return compound.hasKey("Count", TAG_ANY_NUMERIC)
|
||||
&& (compound.hasKey("id", TAG_SHORT) || compound.hasKey("id", TAG_INT)
|
||||
|| compound.hasKey("idExt", TAG_INT));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.gtnewhorizons.postea.utility;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class NbtItemStacksTest {
|
||||
|
||||
private static NBTTagCompound stack(int id, int damage) {
|
||||
NBTTagCompound stack = new NBTTagCompound();
|
||||
stack.setShort("id", (short) id);
|
||||
stack.setByte("Count", (byte) 1);
|
||||
stack.setShort("Damage", (short) damage);
|
||||
return stack;
|
||||
}
|
||||
|
||||
private static List<NBTTagCompound> visited(NBTTagCompound root) {
|
||||
List<NBTTagCompound> stacks = new ArrayList<>();
|
||||
NbtItemStacks.forEach(root, stacks::add);
|
||||
return stacks;
|
||||
}
|
||||
|
||||
@Test
|
||||
void visitsStacksInInventoryListsAndStacksNestedInsideAStacksTag() {
|
||||
NBTTagCompound nested = stack(2, 0);
|
||||
NBTTagCompound backpack = stack(1, 0);
|
||||
NBTTagCompound backpackTag = new NBTTagCompound();
|
||||
NBTTagList contents = new NBTTagList();
|
||||
contents.appendTag(nested);
|
||||
backpackTag.setTag("Items", contents);
|
||||
backpack.setTag("tag", backpackTag);
|
||||
NBTTagList items = new NBTTagList();
|
||||
items.appendTag(backpack);
|
||||
NBTTagCompound tileEntity = new NBTTagCompound();
|
||||
tileEntity.setString("id", "Chest");
|
||||
tileEntity.setTag("Items", items);
|
||||
NBTTagList tileEntities = new NBTTagList();
|
||||
tileEntities.appendTag(tileEntity);
|
||||
NBTTagCompound level = new NBTTagCompound();
|
||||
level.setTag("TileEntities", tileEntities);
|
||||
|
||||
assertEquals(Arrays.asList(backpack, nested), visited(level));
|
||||
}
|
||||
|
||||
@Test
|
||||
void ignoresCompoundsThatAreNotStacks() {
|
||||
NBTTagCompound enchantment = new NBTTagCompound();
|
||||
enchantment.setShort("id", (short) 3);
|
||||
enchantment.setShort("lvl", (short) 1);
|
||||
NBTTagCompound tileEntity = new NBTTagCompound();
|
||||
tileEntity.setString("id", "Chest");
|
||||
tileEntity.setInteger("Count", 1);
|
||||
NBTTagCompound root = new NBTTagCompound();
|
||||
root.setTag("ench", enchantment);
|
||||
root.setTag("te", tileEntity);
|
||||
|
||||
assertEquals(Collections.emptyList(), visited(root));
|
||||
}
|
||||
|
||||
@Test
|
||||
void recognisesExtendedIdStacksWithoutADamageKey() {
|
||||
NBTTagCompound extended = new NBTTagCompound();
|
||||
extended.setShort("id", (short) 0);
|
||||
extended.setInteger("idExt", 40000);
|
||||
extended.setByte("Count", (byte) 3);
|
||||
NBTTagCompound root = new NBTTagCompound();
|
||||
root.setTag("Item", extended);
|
||||
|
||||
assertEquals(Collections.singletonList(extended), visited(root));
|
||||
}
|
||||
|
||||
@Test
|
||||
void aVisitorMayInvalidateTheStackItIsGiven() {
|
||||
NBTTagCompound first = stack(5, 1);
|
||||
NBTTagCompound second = stack(5, 2);
|
||||
NBTTagList items = new NBTTagList();
|
||||
items.appendTag(first);
|
||||
items.appendTag(second);
|
||||
NBTTagCompound root = new NBTTagCompound();
|
||||
root.setTag("Items", items);
|
||||
List<NBTTagCompound> seen = new ArrayList<>();
|
||||
|
||||
NbtItemStacks.forEach(root, tag -> {
|
||||
seen.add(tag);
|
||||
tag.removeTag("id");
|
||||
});
|
||||
|
||||
assertEquals(Arrays.asList(first, second), seen);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user