#How do I add a custom NBT tag to an item?
61 messages · Page 1 of 1 (latest)
In what version? From 1.21 onward, nbt tags are no longer encouraged
But yes, you can. You can save the entities type and it's custom nbt to a component of your making and then simply create a new entity of the same type, initialize it with the saved data and call world#spawnEntity
oops, sorry. I'm in 1.20.4. So ok, I can, is there any documentation about it? the one I found is for 1.21 and uses components (If they are the preferred practice, is there someplace where they get explained?)
It looks like item components are later than you are by a version. https://fabricmc.net/2024/04/19/1205.html
Minecraft 1.20.5 is to be released in the near future with significant changes affecting mod makers.
There probably won't be too much documentation on what you want, but it shouldn't be that hard.
do you have any heads up? (or better, do they work like blockState proeprties?
public static final IntProperty CHARGES = IntProperty.of("charges", 0, 8);
@Override
protected void appendProperties(StateManager.Builder<Item, ItemStack> builder) {
builder.add(CHARGES);
}
would something like this work?
Are you planning on staying on 1.20.4?
Would you suggest I backport to 1.20/ update to 1.20.6?
Not necessarily, it depends on what version you want the mod to be playable on.
I kinda wanted 1.20.4, but the Big Version is now 1.20.1 no?
Idk. If you want 1.20.4, do 1.20.4
In that case though, you just need an item with useOnEntity and useOnBlock methods
An because no components, pick a namespace key and write to the nbt of the item stack
OK, I understand this
this piece I'm missing. how do I write to the nbt?
You will create a new nbt compound, use the writeNBT method on the entity to save its data, remove it using remove and save the compound to your item
and for creating the compound? I have found the class at least
Maybe not remove if you want to copy instead of move
Use the constructor
ok so a map of strings, which I guess are the nbt identifiers, and NbtElements, which are ?
It should be a parameterless constructor
and I can just put whatever in it with WriteNBT?
Write nbt is the method on entity to save that entities data to that compound
You can use the methods on the compound to save arbitrary namespaced data
EntityType#loadEntityWithPassengers may be helpful to you as well
@Override
public ActionResult useOnEntity(ItemStack stack, PlayerEntity player, LivingEntity entity, Hand hand) {
if (!player.getWorld().isClient()) {
// Get or create NBT for the item
NbtCompound itemNbt = stack.getOrCreateNbt();
// Save the entity data into the NBT
NbtCompound entityData = new NbtCompound();
entity.saveNbt(entityData); // Serialize the entity to NBT
// Save entity's class name to reconstruct the exact entity later
entityData.putString("EntityType", EntityType.getId(entity.getType()).toString());
// Store the entity's NBT data inside the item's NBT under the "StoredEntity" key
itemNbt.put("StoredEntity", entityData);
// Apply the updated NBT back to the item
stack.setNbt(itemNbt);
// Feedback to the player
player.sendMessage(Text.of("Entity data stored"), true);
return ActionResult.SUCCESS;
}
return ActionResult.PASS;
}
I'm really not getting the hang of this... this doesn't store any nbt in the item
.
Sorry, I had classes.
It doesn't look like you're calling writeNBT
It's in Entity
I'm calling setNbt though?
Yes
But write nbt tells the entity to save its data to the nbt. Without write nbt, you are just saving an empty compound without the entity data
SetNBT just saves the nbt you have to the itemstack
sorry, what should I do then? I'm getting confused
entity.saveNbt(entityData); // Serialize the entity to NBT
so here I should use writeNbt instead?
entity.writeNbt(compound)
Itemstack.setNbt(compound)
You have most of it right, you're just not quite there
if (!player.getWorld().isClient()) {
// Get or create NBT for the item
NbtCompound itemNbt = stack.getOrCreateNbt();
// Save the entity data into the NBT
NbtCompound entityData = new NbtCompound();
//added this
entity.writeNbt(entityData);
entity.saveNbt(entityData); // Serialize the entity to NBT
// Save entity's class name to reconstruct the exact entity later
entityData.putString("EntityType", EntityType.getId(entity.getType()).toString());
// Store the entity's NBT data inside the item's NBT under the "StoredEntity" key
itemNbt.put("StoredEntity", entityData);
// Apply the updated NBT back to the item
stack.setNbt(itemNbt);
// Feedback to the player
player.sendMessage(Text.of("Entity data stored"), true);
}
return ActionResult.SUCCESS;```
like this?
The saveNbt call should not be nessesary, writeNbt does it if needed.
You shouldn't need to save the entity type if you use this when recreating
But that looks good
Ok, so I think I get it in this case, but what do all those functions actually do? like write put save set? is it all in the docs?
Most of it is not documented, unfortunately. You can learn these things by reading mc code
The fabric + yarn javadocs can also be a good resource
nope, still doesn't work...
@Override
public ActionResult useOnEntity(ItemStack stack, PlayerEntity player, LivingEntity entity, Hand hand) {
if (!player.getWorld().isClient()) {
// Get or create NBT for the item
NbtCompound itemNbt = stack.getOrCreateNbt();
// Save the entity data into the NBT
NbtCompound entityData = new NbtCompound();
//added this
entity.writeNbt(entityData);
entity.saveNbt(entityData); // Serialize the entity to NBT
// Save entity's class name to reconstruct the exact entity later
entityData.putString("EntityType", EntityType.getId(entity.getType()).toString());
// Store the entity's NBT data inside the item's NBT under the "StoredEntity" key
itemNbt.put("StoredEntity", entityData);
// Apply the updated NBT back to the item
stack.setNbt(itemNbt);
// Feedback to the player
player.sendMessage(Text.of("Entity data stored"), true);
}
return ActionResult.SUCCESS;
}
reposting the full code for clarity
:(
What's wrong?
doesn't store the nbt in the item :(
You may need to set the item in the players hand, it's been a bug in Minecraft for a while
ok, it stores the nbt now (thanks), but now there's an issue with spawning the clone
[Server thread/WARN] (Minecraft) UUID of added entity already exists: CowEntity['Cow'/10, l='ServerLevel[New World]', x=-18.50, y=56.00, z=-25.50]
this is very funny I'm going to throw myself off a cliff
@Override
public ActionResult useOnBlock(ItemUsageContext context) {
ItemStack stack = context.getStack();
PlayerEntity player = context.getPlayer();
if (!context.getWorld().isClient()) {
// Get the NBT from the item
NbtCompound itemNbt = stack.getNbt();
if (itemNbt != null && itemNbt.contains("StoredEntity")) {
// Retrieve the stored entity data
NbtCompound entityData = itemNbt.getCompound("StoredEntity");
String entityTypeString = entityData.getString("EntityType");
EntityType<?> entityType = Registries.ENTITY_TYPE.get(new Identifier(entityTypeString));
if (entityType != null) {
Entity clonedEntity = entityType.create(context.getWorld());
if (clonedEntity != null) {
clonedEntity.readNbt(entityData);
clonedEntity.refreshPositionAndAngles(
context.getBlockPos().getX() + 0.5,
context.getBlockPos().getY() + 1,
context.getBlockPos().getZ() + 0.5,
player.getYaw(),
player.getPitch()
);
context.getWorld().spawnEntity(clonedEntity);
}
} else {
player.sendMessage(Text.of("Failed to spawn entity"), true);
}
} else {
player.sendMessage(Text.of("No entity stored"), true);
}
}
return ActionResult.SUCCESS;
}```
code
You may wish to look into how the uuid is stored and where it comes from for new entities. It shouldn't be a problem to assign a new one to the clone
Are you using an llm
Well, I found a gpt for fabric, and since I'm new, I figured at least it should know about some things. Usually it gets a lot things wrong though :/
Yeah, we have a warning tag cause they tend to be wrong more than right
Do you have strong java knowledge?
Also that is not really my strong suit, but as long as I'm working with things I know in fabric, I get around fine enough