Jump to content

Recommended Posts

Posted (edited)

Hey everyone.

 

So I have this block that takes enchants from items and turns it into "enchant essence", this part of the block works great, however I also want the block to "learn" the enchants given, so it can be applied to a different item using said essence. I have most of that system figured out; the only part I don't is:

  • Saving all given enchants to a hashset, then storing it to NBT
  • Have a list of buttons (with a scroll menu) for the user to select their enchant, and have another set of buttons to display what level of enchant (have this  figured out other than the scroll menu )

So my question is: How can I save the array list to NBT & create a list of buttons (via scroll menu) to display all enchants?

 

 

Edited by Lambda
dog jumped on keyboard and did a lot of shit LOL

Relatively new to modding.

Currently developing:

https://github.com/LambdaXV/DynamicGenerators

Posted

A HashSet is just a collection of values, so you can save it to an NBTTagList. If all you're storing in the HashSet is the enchantment types (i.e. Enchantment instances), you can save the registry names to the NBTTagList.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Posted (edited)

I quite literally just did this the othe day. Feel free to take a look at the code. What it does is generate two numbers and stores them. It coverts one of the number to the string value which acts as the key (since that works for my uses) and then it simply stores the whole set in a tag list. 

 

https://hastebin.com/netoleheya.cpp

 

You can ignore the commented HashMap as I used that originally to make sure that no values were getting lost and calculated incorrectly. I commented it out but just forgot to remove it from the code base. Feel free to take an edit as you need for your uses.

Edited by HalestormXV
Posted

Okay, so I got completely rid of the hashmap and I'm now using:

	public NBTTagList enchantNBT = new NBTTagList();

and every time an Item is used by the machine -- this line runs:

							this.enchantNBT.appendTag(itemInput.getEnchantmentTagList());

 

However, I'm having issues with finding how to save this NBTListTag to the TE's NBT.

 

thanks for the help!

Relatively new to modding.

Currently developing:

https://github.com/LambdaXV/DynamicGenerators

Posted

You should not be using NBT for runtime data.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted

Oh yeah, for some reason that totally slipped my mind.

 

So still have the hashmap, still save to it every time it needs to. However, how do I write to it then? Do I iterate through the hashmap and append it to the TagList within the write NBT method? Then how would I read it and assign it back to the map?

 

Thanks

Relatively new to modding.

Currently developing:

https://github.com/LambdaXV/DynamicGenerators

Posted

When writing to NBT, iterate through the HashSet and add a tag for each entry to the NBTTagList. When reading from NBT, iterate through the NBTTagList and add an entry for each tag to the HashSet. Note that you don't need to store the NBTTagList in a field or use it at runtime in any way, just read it from/write it to the NBTTagCompound argument of the TileEntity#readFromNBT/writeToNBT methods.

 

Forge patches NBTTagList to implement Iterable<NBTTagBase>, but you can't really do much with an NBTTagBase without casting it to the appropriate subtype so it's not all that useful. Instead, you'll probably want to use a numeric for loop with NBTTagList#tagCount and NBTTagList#getStringTagAt.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Posted

ok, so I think I have it mostly right, however I'm getting a crash:

Spoiler

[11:36:36] [Server thread/ERROR]: Encountered an unexpected exception
net.minecraft.util.ReportedException: Exception ticking world
	at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:835) ~[MinecraftServer.class:?]
	at net.minecraft.server.MinecraftServer.tick(MinecraftServer.java:741) ~[MinecraftServer.class:?]
	at net.minecraft.server.integrated.IntegratedServer.tick(IntegratedServer.java:192) ~[IntegratedServer.class:?]
	at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:590) [MinecraftServer.class:?]
	at java.lang.Thread.run(Unknown Source) [?:1.8.0_111]
Caused by: java.lang.NullPointerException
	at com.unassigned.customenchants.blocks.tile.TileEntityEnchantmentFab.writeSyncableNBT(TileEntityEnchantmentFab.java:71) ~[TileEntityEnchantmentFab.class:?]
	at com.unassigned.customenchants.blocks.tile.base.TileEntityBase.getUpdateTag(TileEntityBase.java:111) ~[TileEntityBase.class:?]
	at net.minecraft.network.play.server.SPacketChunkData.<init>(SPacketChunkData.java:51) ~[SPacketChunkData.class:?]
	at net.minecraft.server.management.PlayerChunkMapEntry.sendToPlayers(PlayerChunkMapEntry.java:161) ~[PlayerChunkMapEntry.class:?]
	at net.minecraft.server.management.PlayerChunkMap.tick(PlayerChunkMap.java:212) ~[PlayerChunkMap.class:?]
	at net.minecraft.world.WorldServer.tick(WorldServer.java:236) ~[WorldServer.class:?]
	at net.minecraft.server.MinecraftServer.updateTimeLightAndEntities(MinecraftServer.java:829) ~[MinecraftServer.class:?]
	... 4 more

 

Which points to this line:

        	enRegStorage.setString(e.getRegistryName().toString(), e.getRegistryName().toString());

within this block of code in the writeNBT:

    	NBTTagList enchantList = new NBTTagList();
    	NBTTagCompound enRegStorage = new NBTTagCompound();
        
        for(Enchantment e : knownEnchants) {
        	enRegStorage.setString(e.getRegistryName().toString(), e.getRegistryName().toString());
        }
        enchantList.appendTag(enRegStorage);
        compound.setTag("enchantList", enchantList);

 

Now I know the line I wrote is wrong, because visually it doesn't look right, however thinking about it, it makes since.

and for reading I'm doing this:

        NBTTagList list = compound.getTagList("enchantList", 10);
        if(list != null) {
        	for(int i = 0; i < list.tagCount(); i++) {
        		Enchantment theEnch = Enchantment.getEnchantmentByLocation(list.getStringTagAt(i));
        		knownEnchants.add(theEnch);
        	}
        }

 

 

thanks.

Relatively new to modding.

Currently developing:

https://github.com/LambdaXV/DynamicGenerators

Posted

Yeah, and I thought this when coding it, but I'm so inexperienced within NBT that I can't figure out whats wrong.

 

So instead of creating a new NBTTagCompound, I'm going to use the one within the method itself.

How would my write method be written as then? I find all enchants within the hashmap, get their registry name then how would I write it to an NBTTagList then store it to the compound?

 

Thanks.

Relatively new to modding.

Currently developing:

https://github.com/LambdaXV/DynamicGenerators

Posted (edited)

For some reason, I thought setting it would be like "NBTTagString.setString()", however I did realize it is set in the contructor

 

So something like this?

    	NBTTagList enchantList = new NBTTagList();

        for(Enchantment e : knownEnchants) {
        	NBTTagString eString = new NBTTagString(e.getRegistryName().toString());
        	enchantList.appendTag(eString);
        }
        compound.setTag("enchantList", enchantList);

 

Edited by Lambda

Relatively new to modding.

Currently developing:

https://github.com/LambdaXV/DynamicGenerators

Posted

Tip: I highly recommend that when implementing tag functionality, especially if you're not highly familiar with it, that you print out the compounds to the console/logger throughout your code that reads and writes it. It can much more quickly get you a sense of what is going on.

 

NBT is technically very simple, but I think it can be confusing (for beginners) because you can "nest" them in different ways. You can have compounds of mixed types, lists of compounds, compounds of lists, and so forth. Furthermore, the reading and writing need to be perfectly "reciprocal" which a lot of people mess up. So seeing the compounds in print statements I find is extremely helpful to track what is going on.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

Yeah, I understand the basic concept of NBT, however when it comes down to other types of things (like creating NBTLists or strings) it just gets confusing, I only know writing to a compound values of my TE and having them saved and loaded back in. Thanks for the tip.

 

Also, I test my code above and still got the same crash, on this line however:

        	NBTTagString eString = new NBTTagString(e.getRegistryName().toString());

and I still cant see what I'm doing wrong

Relatively new to modding.

Currently developing:

https://github.com/LambdaXV/DynamicGenerators

Posted

Okay now I check if e!=null and it doesn't crash anymore, however the list still resets when I leave and join the game:

[13:40:56] [Server thread/INFO] [STDOUT]: [com.unassigned.customenchants.blocks.tile.TileEntityEnchantmentFab:update:111]: [net.minecraft.enchantment.EnchantmentLootBonus@5d98364c, net.minecraft.enchantment.EnchantmentDurability@cea67b1]

rejoins:

[13:41:04] [Server thread/INFO] [STDOUT]: [com.unassigned.customenchants.blocks.tile.TileEntityEnchantmentFab:update:111]: []

here is updated code:

write:

    	NBTTagList enchantList = new NBTTagList();

        for(Enchantment e : knownEnchants) {
        	if(e != null) {
        		NBTTagString eString = new NBTTagString(e.getRegistryName().toString());
        		enchantList.appendTag(eString);
        	}
        }
        compound.setTag("enchantList", enchantList);

read:

        NBTTagList list = compound.getTagList("enchantList", 10);
        if(list != null) {
        	for(int i = 0; i < list.tagCount(); i++) {
        		Enchantment theEnch = Enchantment.getEnchantmentByLocation(list.getStringTagAt(i));
        		knownEnchants.add(theEnch);
        	}
        }

 

 

thanks for your help!

Relatively new to modding.

Currently developing:

https://github.com/LambdaXV/DynamicGenerators

Posted

I'm still confused:

		NBTTagList list = compound.getTagList("enchantList", Constants.NBT.TAG_COMPOUND);

So is the issue, correct? 

And what I'm trying to see is that the main reason why this isn't working is because i'm asking for a TAG_COMPOUND when I really want a Tag List? As you mentioned, minecraft ignores the different type, so how would I end up doing this then?

Relatively new to modding.

Currently developing:

https://github.com/LambdaXV/DynamicGenerators

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Version 1.19 - Forge 41.0.63 I want to create a wolf entity that I can ride, so far it seems to be working, but the problem is that when I get on the wolf, I can’t control it. I then discovered that the issue is that the server doesn’t detect that I’m riding the wolf, so I’m struggling with synchronization. However, it seems to not be working properly. As I understand it, the server receives the packet but doesn’t register it correctly. I’m a bit new to Java, and I’ll try to provide all the relevant code and prints *The comments and prints are translated by chatgpt since they were originally in Spanish* Thank you very much in advance No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. MountableWolfEntity package com.vals.valscraft.entity; import com.vals.valscraft.network.MountSyncPacket; import com.vals.valscraft.network.NetworkHandler; import net.minecraft.client.Minecraft; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.animal.Wolf; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.Entity; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.network.PacketDistributor; public class MountableWolfEntity extends Wolf { private boolean hasSaddle; private static final EntityDataAccessor<Byte> DATA_ID_FLAGS = SynchedEntityData.defineId(MountableWolfEntity.class, EntityDataSerializers.BYTE); public MountableWolfEntity(EntityType<? extends Wolf> type, Level level) { super(type, level); this.hasSaddle = false; } @Override protected void defineSynchedData() { super.defineSynchedData(); this.entityData.define(DATA_ID_FLAGS, (byte)0); } public static AttributeSupplier.Builder createAttributes() { return Wolf.createAttributes() .add(Attributes.MAX_HEALTH, 20.0) .add(Attributes.MOVEMENT_SPEED, 0.3); } @Override public InteractionResult mobInteract(Player player, InteractionHand hand) { ItemStack itemstack = player.getItemInHand(hand); if (itemstack.getItem() == Items.SADDLE && !this.hasSaddle()) { if (!player.isCreative()) { itemstack.shrink(1); } this.setSaddle(true); return InteractionResult.SUCCESS; } else if (!level.isClientSide && this.hasSaddle()) { player.startRiding(this); MountSyncPacket packet = new MountSyncPacket(true); // 'true' means the player is mounted NetworkHandler.CHANNEL.sendToServer(packet); // Ensure the server handles the packet return InteractionResult.SUCCESS; } return InteractionResult.PASS; } @Override public void travel(Vec3 travelVector) { if (this.isVehicle() && this.getControllingPassenger() instanceof Player) { System.out.println("The wolf has a passenger."); System.out.println("The passenger is a player."); Player player = (Player) this.getControllingPassenger(); // Ensure the player is the controller this.setYRot(player.getYRot()); this.yRotO = this.getYRot(); this.setXRot(player.getXRot() * 0.5F); this.setRot(this.getYRot(), this.getXRot()); this.yBodyRot = this.getYRot(); this.yHeadRot = this.yBodyRot; float forward = player.zza; float strafe = player.xxa; if (forward <= 0.0F) { forward *= 0.25F; } this.flyingSpeed = this.getSpeed() * 0.1F; this.setSpeed((float) this.getAttributeValue(Attributes.MOVEMENT_SPEED) * 1.5F); this.setDeltaMovement(new Vec3(strafe, travelVector.y, forward).scale(this.getSpeed())); this.calculateEntityAnimation(this, false); } else { // The wolf does not have a passenger or the passenger is not a player System.out.println("No player is mounted, or the passenger is not a player."); super.travel(travelVector); } } public boolean hasSaddle() { return this.hasSaddle; } public void setSaddle(boolean hasSaddle) { this.hasSaddle = hasSaddle; } @Override protected void dropEquipment() { super.dropEquipment(); if (this.hasSaddle()) { this.spawnAtLocation(Items.SADDLE); this.setSaddle(false); } } @SubscribeEvent public static void onServerTick(TickEvent.ServerTickEvent event) { if (event.phase == TickEvent.Phase.START) { MinecraftServer server = net.minecraftforge.server.ServerLifecycleHooks.getCurrentServer(); if (server != null) { for (ServerPlayer player : server.getPlayerList().getPlayers()) { if (player.isPassenger() && player.getVehicle() instanceof MountableWolfEntity) { MountableWolfEntity wolf = (MountableWolfEntity) player.getVehicle(); System.out.println("Tick: " + player.getName().getString() + " is correctly mounted on " + wolf); } } } } } private boolean lastMountedState = false; @Override public void tick() { super.tick(); if (!this.level.isClientSide) { // Only on the server boolean isMounted = this.isVehicle() && this.getControllingPassenger() instanceof Player; // Only print if the state changed if (isMounted != lastMountedState) { if (isMounted) { Player player = (Player) this.getControllingPassenger(); // Verify the passenger is a player System.out.println("Server: Player " + player.getName().getString() + " is now mounted."); } else { System.out.println("Server: The wolf no longer has a passenger."); } lastMountedState = isMounted; } } } @Override public void addPassenger(Entity passenger) { super.addPassenger(passenger); if (passenger instanceof Player) { Player player = (Player) passenger; if (!this.level.isClientSide && player instanceof ServerPlayer) { // Send the packet to the server to indicate the player is mounted NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(true)); } } } @Override public void removePassenger(Entity passenger) { super.removePassenger(passenger); if (passenger instanceof Player) { Player player = (Player) passenger; if (!this.level.isClientSide && player instanceof ServerPlayer) { // Send the packet to the server to indicate the player is no longer mounted NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(false)); } } } @Override public boolean isControlledByLocalInstance() { Entity entity = this.getControllingPassenger(); return entity instanceof Player; } @Override public void positionRider(Entity passenger) { if (this.hasPassenger(passenger)) { double xOffset = Math.cos(Math.toRadians(this.getYRot() + 90)) * 0.4; double zOffset = Math.sin(Math.toRadians(this.getYRot() + 90)) * 0.4; passenger.setPos(this.getX() + xOffset, this.getY() + this.getPassengersRidingOffset() + passenger.getMyRidingOffset(), this.getZ() + zOffset); } } } MountSyncPacket package com.vals.valscraft.network; import com.vals.valscraft.entity.MountableWolfEntity; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; public class MountSyncPacket { private final boolean isMounted; public MountSyncPacket(boolean isMounted) { this.isMounted = isMounted; } public void encode(FriendlyByteBuf buffer) { buffer.writeBoolean(isMounted); } public static MountSyncPacket decode(FriendlyByteBuf buffer) { return new MountSyncPacket(buffer.readBoolean()); } public void handle(NetworkEvent.Context context) { context.enqueueWork(() -> { ServerPlayer player = context.getSender(); // Get the player from the context if (player != null) { // Verifies if the player has dismounted if (!isMounted) { Entity vehicle = player.getVehicle(); if (vehicle instanceof MountableWolfEntity wolf) { // Logic to remove the player as a passenger wolf.removePassenger(player); System.out.println("Server: Player " + player.getName().getString() + " is no longer mounted."); } } } }); context.setPacketHandled(true); // Marks the packet as handled } } networkHandler package com.vals.valscraft.network; import com.vals.valscraft.valscraft; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.network.NetworkRegistry; import net.minecraftforge.network.simple.SimpleChannel; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; public class NetworkHandler { private static final String PROTOCOL_VERSION = "1"; public static final SimpleChannel CHANNEL = NetworkRegistry.newSimpleChannel( new ResourceLocation(valscraft.MODID, "main"), () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals, PROTOCOL_VERSION::equals ); public static void init() { int packetId = 0; // Register the mount synchronization packet CHANNEL.registerMessage( packetId++, MountSyncPacket.class, MountSyncPacket::encode, MountSyncPacket::decode, (msg, context) -> msg.handle(context.get()) // Get the context with context.get() ); } }  
    • Do you use features of inventory profiles next (ipnext) or is there a change without it?
    • Remove rubidium - you are already using embeddium, which is a fork of rubidium
  • Topics

  • Who's Online (See full list)

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.