#apply NBT tag to item only while in specific slot

1 messages · Page 1 of 1 (latest)

honest fern
#

Hi, I'm trying to solve this problem:

I'd like to set NBT data on an item when it is placed in a specific inventory slot, and remove it if it's it's not in that slot. I had thought about getting InventoryClick events and using that to tell if a player is putting an item in a specific slot, but I realised that the item will still have the custom NBT if the player were to drop it or drop it on death. What approach can I use for this problem?

gloomy crown
#

use a PlayerDeathEvent to get the item from the inventory and remove the nbt data

honest fern
#

ok, another question: The item slot I'm trying to detect items in is the helmet slot, I couldn't find any events specific to armour slots, are there any I missed?

#

also, I was planning on removing the NBT data by testing if a player had removed the item from the helmet slot, and then removing the NBT data from the item in the cursor. I realised that the player may just press Q on the helmet, or shift click it out of the slot, which would mean I couldn't then test for the cursor item

#

I do not want to iterate through all items in a player's inventory just to remove NBT data from a single item

gloomy crown
#

The PlayerInteractEvent can be used to detect a right click

#

and the InventoryClickEvent can also be used to detect when they put the helmet in the helmet slot

gloomy crown
honest fern
#

Okay

#

My main issue is with removing the NBT data though

#

since there are many more ways of removing an item than equipping a helmet

gloomy crown
#

pressing q in the helmet also triggers the InventoryClickEvent iirc

honest fern
#

Oh excellent

#

how can I detect if the player drops an item on death though? is there any way to access the player's inventory before they drop all their items?

gloomy crown
honest fern
#

brilliant

#

So I can detect the inventory click for when a player drops an item and when they shift-click it out of their helmet slot, but how do I then find that item so that I can remove the NBT data?

#

do i have to iterate through the inventory? and how would I get the dropped item?

#

does inventoryclick fire before the item is dropped?

gloomy crown
honest fern
#

oh buoy

gloomy crown
#

all events fire 1 tick before it happens

#

so you can cancel them

honest fern
#

wouldn't running ~30 ifs per inventory click event slow things down a bit?

#

I don't know much about plugin performance

gloomy crown
#

the event should give you which item was clicked

#

just check if that clicked item is your item

honest fern
#

so i can get the item even before it moves slot with shift-click?

gloomy crown
#

yes

#

you can also get which slot it will shift click to

honest fern
#

Pizza Guy you have been the most helpful discord user I've ever met in any programming server

gloomy crown
#

:)

honest fern
#

that should be all my questions for now, will this thread close itself or can I leave this here?

#

so i can reference it later

gloomy crown
#

it should archive, but not delete

honest fern
#

good

gloomy crown
#

good luck with your plugin

honest fern
#

thank you :)

honest fern
#

i have another question, what is NMS? When I've searched how to edit NBT data, all examples have a line where they convert an ItemStack into a NMS itemstack, why is this required/what can you do with a NMS itemstack that you can't with a bukkit one?

gloomy crown
#

you can edit the NBT data with UnsafeValues, without the need of nms

#

UnsafeValues is unsafe because it edits the raw nbt of an item, but you can use it to edit nbt

honest fern
#

what is best practice

#

or most common

gloomy crown
#

UnsafeValues

honest fern
#

oh great

gloomy crown
#

if you need to do really complicated NBT things, you can touch on nms, but its very confusing and complicated

honest fern
#

but what happens if you do something unsafe? does the server crash?

gloomy crown
#

it cant crash from UnsafeValues

#

the name only means that if you did something wrong, the item would get corrupted

honest fern
#

ok

#

is the data in {} in this command NBT data? /give @p lantern{CustomModelData:400000} just to make sure

gloomy crown
#

oh

#

are you editing custom model data?

honest fern
#

?

#

Yes

#

Well

gloomy crown
#

customModelData is in the API

#

you dont need to edit nbt

honest fern
#

I'm not editing, there is a resource pack which has customModelData for certain NBT data

#

huh??

#

so I don't even need a resource pack?

#

or will I still

gloomy crown
#

wait, do you understand how custommodeldata works?

honest fern
#

as far as I'm aware, a resource pack can apply a custom model to an item with certain NBT data, and one NBT tag you can use specifically for this purpose is the CustomModelData tag

#

so I've made a resource pack which will apply a certain model to a lantern with customModelData value 400,000

#

it works

#

But if there is a more intentional and streamlined way of doing this without any resource pack I'd love to learn about it

gloomy crown
#

this is the correct way to do it

#

if your trying to remove and add the custommodeldata of an item, you dont need to mess with the raw nbt

#

spigotapi has methods for this

honest fern
#

setCustomModelData(Integer data)

#

is this basically just a function which does what I'm trying to do manually with NBT?

gloomy crown
#

ItemStack#getItemMeta().setCustomModelData()

#

yes

honest fern
#

that's nice

gloomy crown
#

theres also ItemStack#getItemMeta().getCustomModelData() and ItemStack#getItemMeta().hasCustomModelData()

honest fern
#

saves me learning that NMS and unsafe stuff

gloomy crown
#

:)

honest fern
#

so I will still require the resource pack though

gloomy crown
#

yes

honest fern
#

that's not an issue

#

ok

gloomy crown
#

it needs somewhere to get the texture

honest fern
#

thank you :)

gloomy crown
#

you can actually tell the server to recommend installing a texture pack to a user

honest fern
#

yes I think you can even make it mandatory

honest fern
#

on an inventory click I'm trying to get the slot the item was clicked into, is the only way to do this with InventoryDrag

gloomy crown
#

im pretty sure shiftclick sends two events

#

one for picking it up and one for placing it down

honest fern
#

?

gloomy crown
#

when you shiftclick on your client

#

what it really does

#

is the game quickly picks up the item

#

and quickly places it down in another slot

#

2 events

honest fern
#

ok, what about for regular click though

#

like I've clicked an item into my cursor, and now I'm clicking that item into a slot

#

how do I get that slot number

gloomy crown
#

InventoryClickEvent#getSlot() should return the numerical id of the slot

#

slot 1 being 0

honest fern
#

so that won't return that the item slot was the cursor?

gloomy crown
#

it returns one of these

honest fern
#

oh thanks for that image, google told me the helmet slot was 5???

gloomy crown
#

hm

honest fern
#

hold on I will test and see if it returns the slot number i click it into

#

yay it gives the index i want :)

#

!! head item slot is #39

#

not 103

gloomy crown
#

:)

#

i guess the slots change every update

honest fern
#

another question

#

the click event will give me the slot that I've clicked the item into, but if I try and get the item in that slot it will say it's empty

#

how can I delay the check for the item slot till after the item actually gets put in that slot?

gloomy crown
#

you can use a BukkitRunnable to schedule a task to be run maybe a few ticks after

honest fern
#

will 1 tick be too quick?

#

or is the timing precise

gloomy crown
#

a lot of things can happen in 1 tick

#

1 tick is just one step in the game loop

honest fern
#

yes

#

so i can only schedule events by delay, i can't say "do this after this has happened"?

#

like callback after the current tick has finished

gloomy crown
#

well "do this after this has happened" is kind of what events are for

honest fern
#

i mean the inventoryclick listener is firing right before the inventory click event actually gets processed, i'd just like to run something immediately after the click event is done

#

do i have to use a bukkit runnable for that

gloomy crown
#

yea

#

just delay 1 tick

honest fern
#

;o

gloomy crown
#

runTaskLater is prefered

honest fern
#

why is that?

gloomy crown
#

it runs the task with a delay

#

BukkitRunnable#runTaskLater(JavaPlugin plugin, Long delay)

#

should be something like that iirc

honest fern
#

yes but why for a 1 tick delay like this is runTaskLayer preferred over runTask which just runs it on the next tick?

gloomy crown
honest fern
#

also the syntax of this confuses me, how does passing it the plugin work

#

what part of the plugin runs?

gloomy crown
#

pass in the main JavaPlugin class

honest fern
#

but what part of that will run

gloomy crown
#

it wont

#

it just needs to know which plugin is scheduling

honest fern
#

I'm so confused

gloomy crown
#

what is your main class called?

honest fern
#

Hats

gloomy crown
#

ok

#

so in your Hats file

#

create a private static Hats instance = null;

#

then in your onEnable, set instance = this;

#

now create a ```java
public static Hats getInstance() {
return instance;
}

#

now when you do runTask or runTaskLater

#

just pass in Hats.getInstance() as the plugin

honest fern
#

why would you do that

#

why not just pass this

gloomy crown
#

wait, where are you creating your BukkitRunnable

honest fern
#

also I was confused about where the code I want to run goes

#

I have no idea where I'm creating my bukkit runnable

gloomy crown
#

BukkitRunnables usually go in their own class

honest fern
#

i'm just trying to schedule some code to run in 1 tick

gloomy crown
#

so you want to create a class and name it something related to what the runnable will do

gloomy crown
#
new BukkitRunnable() {
  public void run() {
    // code...
  }
}.runTask(Hats.getInstance(), 1L);
honest fern
#

ohhhhhh

gloomy crown
#

that will create a new class that extends BukkitRunnable

honest fern
#

that's just instantiating a bukkitrunnable wdym

#

o

#

wait is this an extension syntax i've not seen

#

o wait yes i've only ever seen new ObjectName()

#

never new ObjectName() { wow new stuff }

gloomy crown
honest fern
#

ye :>

gloomy crown
#

you can extend a class by writing the extended code in brackets after the instantiating in the {}

honest fern
#

yes

#

if i want to pass args to the runnable

gloomy crown
#

pass into the run() method?

honest fern
#

it puts red squiggles under the BukkitRunnable

gloomy crown
#

show me code?

#

did you import BukkitRunnable?

honest fern
#

yes

#

hold on getting screenshot

#

I have imported it

#

the squiggles go away without the arguments in run()

gloomy crown
#

there arent supposed to be any arguments in run()

honest fern
gloomy crown
#

i was asking if you wanted to know how to pass variables into the run method lol

honest fern
#

oops

#

well i imagine you know now what i want to do

#

how do i?

gloomy crown
#

i was gonna say that you dont need to pass anything, it should just be able to access variables in it's scope

#

where are you declaring the runnable?

honest fern
#

directly in the inventoryclick event

gloomy crown
#

ok, so you should be able to just use player in the run method

honest fern
#

:v it keeps the same frame?

#

uh scope

gloomy crown
#

yes

honest fern
#

omg yay

gloomy crown
#
// event code
Player p = e.getPlayer();

new BukkitRunnable() {
  public void run() {
    p.sendMessage("Sent on the next tick");
  }
}.runTask(Hats.getInstance(), 1L);
// blah blah...
gloomy crown
#

in the main class?

honest fern
#

yes

gloomy crown
#

hm ok

#

you should move all of your events to a different class that implements Listener

#

and have all of your code there

honest fern
#

there is one single event

#

my entire plugin is a single event handler

#

no onEnable or onDisable

gloomy crown
#

oh

#

how do you register your event handler if you dont have an onEnable?

honest fern
#

wait i forgot that bit yes

#

that exists

#

but that's it!!

gloomy crown
#

you didnt register your events?

honest fern
#

no i did, i have them register in onEnable, i just forgot that onEnable actually did something in my code

honest fern
#

ItemStack cursor = event.getCursor();

#

no matter what I do, this always gives an air block

#

oh no :( i've figured out why

#

I'm relying on EssentialsX's hat feature, but that doesn't move an item from the cursor to the player's head in the same way equipping a helmet does

#

equipping a helmet shows me there was a helmet in the cursor, but using the hat feature tells me there was only air ;(

honest fern
#

i've found a workaround

#

also i saw somewhere, someone said that you need to like "apply" changes? I'm setting custom model data, but it's not showing any NBT tags ingame

#

do I have to do this other step? I'm going to @ you in this thread instead of #help-development since it's busy

#

@gloomy crown

#

blixten are u here

marsh dew
#

I didn't necessarily say I had the means to help

honest fern
#

ok but are you familiar with custom model data

marsh dew
#

I happen to be actually

honest fern
#

i'm trying to apply it to an item but it's not applying ingame

marsh dew
#

How are you applying it?

honest fern
#

i think there's an extra step i need to do to make it show up

marsh dew
#

There's a common pitfall; setting custom_model_data to 0

honest fern
#

item.getItemMeta().setCustomModelData(CUSTOM_MODEL_DATA);

#

the value is 400,000

#

also, to clear custom model data do you null it

marsh dew
#

You could set it to zero

honest fern
#

ok

marsh dew
#

Haven't tried nulling it

honest fern
#

so that line there is in my code

marsh dew
#

That won't really work

honest fern
#

:V

#

how so

marsh dew
#

You need to first create a variable with the value item.getItemMeta()

#

Then you call .setCustomModelData on that

honest fern
#

🤔

#

ok i will try

marsh dew
#

then you do item.setItemMeta(theothervar)

honest fern
#

what?

#

setCustomModelData

#

oh wait no i get you

#

i update original item's metadata to this new data i've just made

marsh dew
#
ItemMeta itemMeta = item.getItemMeta();
itemMeta.setCustomModelData(2);
item.setItemMeta(itemMeta);
honest fern
#

so uhh

marsh dew
#

The item's meta is encapsulated

#

.getItemMeta gives you a clone

honest fern
#

yes

#

okey thank you

marsh dew
#

You're welcome

honest fern
#

blixten are you still there