From 875a39bd181b44b28ead8ae10eb852da1d9da993 Mon Sep 17 00:00:00 2001 From: Pesek <42549665+Pesekjak@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:58:06 +0200 Subject: [PATCH] Preventing NPE caused by creation of PlayerProfile from OfflinePlayer (#7091) --- .../java/ch/njol/skript/aliases/ItemType.java | 54 +++++++-------- .../ch/njol/skript/bukkitutil/ItemUtils.java | 29 ++++++++ .../ch/njol/skript/expressions/ExprSkull.java | 67 ++++--------------- .../skript/expressions/ExprSkullOwner.java | 35 ++++------ 4 files changed, 81 insertions(+), 104 deletions(-) diff --git a/src/main/java/ch/njol/skript/aliases/ItemType.java b/src/main/java/ch/njol/skript/aliases/ItemType.java index 8b78d39229b..aa772d2b646 100644 --- a/src/main/java/ch/njol/skript/aliases/ItemType.java +++ b/src/main/java/ch/njol/skript/aliases/ItemType.java @@ -1,21 +1,3 @@ -/** - * This file is part of Skript. - * - * Skript is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Skript is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Skript. If not, see . - * - * Copyright Peter Güttinger, SkriptLang team and contributors - */ package ch.njol.skript.aliases; import ch.njol.skript.aliases.ItemData.OldItemData; @@ -41,6 +23,7 @@ import org.bukkit.Material; import org.bukkit.OfflinePlayer; import org.bukkit.Tag; +import org.bukkit.Bukkit; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.Skull; @@ -391,22 +374,35 @@ public boolean hasType() { */ public boolean setBlock(Block block, boolean applyPhysics) { for (int i = random.nextInt(types.size()); i < types.size(); i++) { - ItemData d = types.get(i); - Material blockType = ItemUtils.asBlock(d.type); + ItemData data = types.get(i); + Material blockType = ItemUtils.asBlock(data.type); + if (blockType == null) // Ignore items which cannot be placed continue; - if (BlockUtils.set(block, blockType, d.getBlockValues(), applyPhysics)) { - ItemMeta itemMeta = getItemMeta(); - if (itemMeta instanceof SkullMeta) { - OfflinePlayer offlinePlayer = ((SkullMeta) itemMeta).getOwningPlayer(); - if (offlinePlayer == null) - continue; - Skull skull = (Skull) block.getState(); + + if (!BlockUtils.set(block, blockType, data.getBlockValues(), applyPhysics)) + continue; + + ItemMeta itemMeta = getItemMeta(); + + if (itemMeta instanceof SkullMeta) { + OfflinePlayer offlinePlayer = ((SkullMeta) itemMeta).getOwningPlayer(); + if (offlinePlayer == null) + continue; + Skull skull = (Skull) block.getState(); + if (offlinePlayer.getName() != null) { skull.setOwningPlayer(offlinePlayer); - skull.update(false, applyPhysics); + } else if (ItemUtils.CAN_CREATE_PLAYER_PROFILE) { + //noinspection deprecation + skull.setOwnerProfile(Bukkit.createPlayerProfile(offlinePlayer.getUniqueId(), "")); + } else { + //noinspection deprecation + skull.setOwner(""); } - return true; + skull.update(false, applyPhysics); } + + return true; } return false; } diff --git a/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java b/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java index ced9f5a8367..a74a604664d 100644 --- a/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java +++ b/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java @@ -21,7 +21,9 @@ import ch.njol.skript.Skript; import ch.njol.skript.aliases.ItemType; import ch.njol.skript.util.slot.Slot; +import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.OfflinePlayer; import org.bukkit.Tag; import org.bukkit.TreeType; import org.bukkit.block.Block; @@ -32,9 +34,11 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.SkullMeta; import org.jetbrains.annotations.Nullable; import java.util.HashMap; +import java.util.UUID; /** * Miscellaneous static utility methods related to items. @@ -44,6 +48,7 @@ public class ItemUtils { public static final boolean HAS_MAX_DAMAGE = Skript.methodExists(Damageable.class, "getMaxDamage"); // Introduced in Paper 1.21 public static final boolean HAS_RESET = Skript.methodExists(Damageable.class, "resetDamage"); + public static final boolean CAN_CREATE_PLAYER_PROFILE = Skript.methodExists(Bukkit.class, "createPlayerProfile", UUID.class, String.class); /** * Gets damage/durability of an item, or 0 if it does not have damage. @@ -148,6 +153,30 @@ public static void setDamage(ItemType itemType, int damage) { } } + /** + * Sets the owner of a player head. + * @param skull player head item to modify + * @param player owner of the head + */ + public static void setHeadOwner(ItemType skull, OfflinePlayer player) { + ItemMeta meta = skull.getItemMeta(); + if (!(meta instanceof SkullMeta)) + return; + + SkullMeta skullMeta = (SkullMeta) meta; + + if (player.getName() != null) { + skullMeta.setOwningPlayer(player); + } else if (CAN_CREATE_PLAYER_PROFILE) { + //noinspection deprecation + skullMeta.setOwnerProfile(Bukkit.createPlayerProfile(player.getUniqueId(), "")); + } else { + skullMeta.setOwningPlayer(null); + } + + skull.setItemMeta(skullMeta); + } + /** * Gets a block material corresponding to given item material, which might * be the given material. If no block material is found, null is returned. diff --git a/src/main/java/ch/njol/skript/expressions/ExprSkull.java b/src/main/java/ch/njol/skript/expressions/ExprSkull.java index bce8422a76d..8b8c0e0e19b 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprSkull.java +++ b/src/main/java/ch/njol/skript/expressions/ExprSkull.java @@ -1,86 +1,45 @@ -/** - * This file is part of Skript. - * - * Skript is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Skript is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Skript. If not, see . - * - * Copyright Peter Güttinger, SkriptLang team and contributors - */ package ch.njol.skript.expressions; +import ch.njol.skript.bukkitutil.ItemUtils; import org.bukkit.Material; import org.bukkit.OfflinePlayer; -import org.bukkit.inventory.meta.SkullMeta; import org.jetbrains.annotations.Nullable; -import ch.njol.skript.Skript; -import ch.njol.skript.aliases.Aliases; import ch.njol.skript.aliases.ItemType; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Name; import ch.njol.skript.doc.Since; import ch.njol.skript.expressions.base.SimplePropertyExpression; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.SkriptParser.ParseResult; -import ch.njol.util.Kleenean; -/** - * @author Peter Güttinger - */ @Name("Player Skull") @Description("Gets a skull item representing a player. Skulls for other entities are provided by the aliases.") -@Examples({"give the victim's skull to the attacker", - "set the block at the entity to the entity's skull"}) +@Examples({ + "give the victim's skull to the attacker", + "set the block at the entity to the entity's skull" +}) @Since("2.0") -public class ExprSkull extends SimplePropertyExpression { - +public class ExprSkull extends SimplePropertyExpression { + static { register(ExprSkull.class, ItemType.class, "(head|skull)", "offlineplayers"); } - - /** - * In 2017, SkullMeta finally got a method that takes OfflinePlayer. - */ - private static final boolean newSkullOwner = Skript.methodExists(SkullMeta.class, "setOwningPlayer", OfflinePlayer.class); - - @Override - public boolean init(final Expression[] exprs, final int matchedPattern, final Kleenean isDelayed, final ParseResult parseResult) { - return super.init(exprs, matchedPattern, isDelayed, parseResult); - } - - @SuppressWarnings("deprecation") + @Override - @Nullable - public ItemType convert(final Object o) { + public @Nullable ItemType convert(OfflinePlayer player) { ItemType skull = new ItemType(Material.PLAYER_HEAD); - SkullMeta meta = (SkullMeta) skull.getItemMeta(); - if (newSkullOwner) - meta.setOwningPlayer((OfflinePlayer) o); - else - meta.setOwner(((OfflinePlayer) o).getName()); - skull.setItemMeta(meta); + ItemUtils.setHeadOwner(skull, player); return skull; } - + @Override public Class getReturnType() { return ItemType.class; } - + @Override protected String getPropertyName() { return "skull"; } - + } diff --git a/src/main/java/ch/njol/skript/expressions/ExprSkullOwner.java b/src/main/java/ch/njol/skript/expressions/ExprSkullOwner.java index ec80ad70793..bc102126022 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprSkullOwner.java +++ b/src/main/java/ch/njol/skript/expressions/ExprSkullOwner.java @@ -1,23 +1,6 @@ -/** - * This file is part of Skript. - * - * Skript is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Skript is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Skript. If not, see . - * - * Copyright Peter Güttinger, SkriptLang team and contributors - */ package ch.njol.skript.expressions; +import ch.njol.skript.bukkitutil.ItemUtils; import ch.njol.skript.classes.Changer.ChangeMode; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Examples; @@ -25,6 +8,7 @@ import ch.njol.skript.doc.Since; import ch.njol.skript.expressions.base.SimplePropertyExpression; import ch.njol.util.coll.CollectionUtils; +import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.block.Block; import org.bukkit.block.BlockState; @@ -66,11 +50,20 @@ public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { OfflinePlayer offlinePlayer = (OfflinePlayer) delta[0]; for (Block block : getExpr().getArray(event)) { BlockState state = block.getState(); - if (state instanceof Skull) { - Skull skull = (Skull) state; + if (!(state instanceof Skull)) + continue; + + Skull skull = (Skull) state; + if (offlinePlayer.getName() != null) { skull.setOwningPlayer(offlinePlayer); - skull.update(true, false); + } else if (ItemUtils.CAN_CREATE_PLAYER_PROFILE) { + //noinspection deprecation + skull.setOwnerProfile(Bukkit.createPlayerProfile(offlinePlayer.getUniqueId(), "")); + } else { + //noinspection deprecation + skull.setOwner(""); } + skull.update(true, false); } }