Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preventing NPE caused by creation of PlayerProfile from OfflinePlayer #7091

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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(), ""));
TheLimeGlass marked this conversation as resolved.
Show resolved Hide resolved
} 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(), ""));
TheLimeGlass marked this conversation as resolved.
Show resolved Hide resolved
} else {
//noinspection deprecation
skull.setOwner("");
}
skull.update(true, false);
}
}

Expand Down