lootgenerateevent.getloottable annotated as notnull but can be null sometimes
Expected behavior
loot table never null
Observed/Actual behavior
java.lang.NullPointerException: Cannot invoke "org.bukkit.loot.LootTable.getKey()" because the return value of "org.bukkit.event.world.LootGenerateEvent.getLootTable()" is null at ListenEvents.jar/com.calummc.test.Listeners.onLootTableGenerate(Listeners.java:120) ~[ListenEvents.jar:?] at co.aikar.timings.TimedEventExecutor.execute(TimedEventExecutor.java:80) ~[paper-api-1.21.8-R0.1-SNAPSHOT.jar:?] at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:71) ~[paper-api-1.21.8-R0.1-SNAPSHOT.jar:?]
code line: @EventHandler(priority = EventPriority.HIGH) public void onLootTableGenerate(LootGenerateEvent event) { if (event.getLootTable().getKey().getKey().contains("testloot")) {
Steps/models to reproduce
idk
Plugin and Datapack List
N/A
Paper version
https://github.com/PaperMC/Paper/commit/29c8822d90899c89d2689338e81a98f690bcba12
Other
No response
I can confirm, I faced this issue few months ago. Here's the steps to reproduce it:
- Place a chest with an unknown loot table:
/setblock ~ ~ ~ chest{LootTable:"unknownloottable"} - Register an event listener for
LootGenerateEventand printevent.getLootTable() - Open the chest
- The console will show
nullas a result, despite theLootGenerateEvent#getLootTable()method being annotated as@NotNull
This is because obviously the loot table does not exist, so the method can't return a LootTable object.
Additionally, since event.getLootTable().getKey() is the only way to get the key of the loot table involved in this event, this makes it impossible for plugins to get the unknownloottable key from my example. This is unfortunate, because even if the loot table does not exist on the server, that key is still present on the block, and could be interesting to know (at the very least to allow logging something like "Tried to generate loot for unknown loot table: unknownloottable").
So, my suggestion to fix this issue would be:
- Obviously annotate this method as
@Nullable, because it could returnnull; - Then, add another method
LootGenerateEvent#getLootTableKey()returning the@NotNull Keyof the loot table involved in this event, even if the real one does not exist.
To illustrate, my use case was to replace loots from some datapacks, and my initial intent was to react to the event, replace loots with items generated from my custom logic when the key matched some condition (namespace of the datapack, prefix...), then wipe the datapack's loot tables folder, just to make sure they'll never get generated "by mistake" if the plugin failed to overwrite it. However, I realized that this wasn't possible to get the loot table key anymore once I deleted the real loot tables...
Okay the issue is the LootTable in the event its from extra value added to NMS LootTable this is created when the loot tables are validated (the loot tables register in the server) in this case a random loot table was not register then not has that extra data and the event can return null...
maybe can fix that when try to get the loottable and check that case for create the missing extra data...