Skip to content

Commit

Permalink
Preventing NPE caused by creation of PlayerProfile from OfflinePlayer (
Browse files Browse the repository at this point in the history
  • Loading branch information
Pesekjak authored Oct 1, 2024
1 parent cb6d995 commit 875a39b
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 104 deletions.
54 changes: 25 additions & 29 deletions src/main/java/ch/njol/skript/aliases/ItemType.java
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*
* Copyright Peter Güttinger, SkriptLang team and contributors
*/
package ch.njol.skript.aliases;

import ch.njol.skript.aliases.ItemData.OldItemData;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
29 changes: 29 additions & 0 deletions src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
67 changes: 13 additions & 54 deletions src/main/java/ch/njol/skript/expressions/ExprSkull.java
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*
* 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<Object, ItemType> {
public class ExprSkull extends SimplePropertyExpression<OfflinePlayer, ItemType> {

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<? extends ItemType> getReturnType() {
return ItemType.class;
}

@Override
protected String getPropertyName() {
return "skull";
}

}
35 changes: 14 additions & 21 deletions src/main/java/ch/njol/skript/expressions/ExprSkullOwner.java
Original file line number Diff line number Diff line change
@@ -1,30 +1,14 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
* 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;
import ch.njol.skript.doc.Name;
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;
Expand Down Expand Up @@ -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);
}
}

Expand Down

0 comments on commit 875a39b

Please sign in to comment.