mirror of
https://gitlab.com/phoenix-dvpmt/mmoitems.git
synced 2024-12-22 04:37:42 +01:00
Fixed subtypes of SKIN
This commit is contained in:
parent
8f20edde22
commit
dd9cdc34bc
@ -106,7 +106,9 @@ public class ItemSkin extends UseItem {
|
||||
* in the target item so that if deskined, it can be retrieved
|
||||
* and given back to the player.
|
||||
*/
|
||||
public static final String SKIN_ID_TAG = "MMOITEMS_SKIN_ID";
|
||||
public static final String
|
||||
SKIN_ID_TAG = "MMOITEMS_SKIN_ID",
|
||||
SKIN_TYPE_TAG = "MMOITEMS_SKIN_TYPE";
|
||||
|
||||
/**
|
||||
* Applies the skin information from a skin consumable onto any item.
|
||||
@ -126,9 +128,10 @@ public class ItemSkin extends UseItem {
|
||||
final NBTItem nbtSkin = volSkin.getNBT();
|
||||
|
||||
// Apply skin ID to new item
|
||||
@Nullable String appliedSkinId = volSkin.getNBT().getString(SKIN_ID_TAG);
|
||||
appliedSkinId = MMOUtils.isNonEmpty(appliedSkinId) ? appliedSkinId : nbtSkin.getString("MMOITEMS_ITEM_ID");
|
||||
final String appliedSkinId = MMOUtils.requireNonEmptyElse(volSkin.getNBT().getString(SKIN_ID_TAG), nbtSkin.getString("MMOITEMS_ITEM_ID"));
|
||||
final String appliedTypeId = MMOUtils.requireNonEmptyElse(volSkin.getNBT().getString(SKIN_TYPE_TAG), nbtSkin.getString("MMOITEMS_ITEM_TYPE"));
|
||||
target.addTag(new ItemTag(SKIN_ID_TAG, appliedSkinId));
|
||||
target.addTag(new ItemTag(SKIN_TYPE_TAG, appliedTypeId));
|
||||
|
||||
// Custom model data
|
||||
if (nbtSkin.getInteger("CustomModelData") != 0)
|
||||
|
@ -4,13 +4,13 @@ import com.google.gson.JsonObject;
|
||||
import io.lumine.mythic.lib.api.item.ItemTag;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.api.util.SmartGive;
|
||||
import io.lumine.mythic.lib.util.annotation.BackwardsCompatibility;
|
||||
import io.lumine.mythic.lib.version.VersionMaterial;
|
||||
import net.Indyuce.mmoitems.ItemStats;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.interaction.ItemSkin;
|
||||
import net.Indyuce.mmoitems.util.MMOUtils;
|
||||
import net.Indyuce.mmoitems.api.Type;
|
||||
import net.Indyuce.mmoitems.api.interaction.Consumable;
|
||||
import net.Indyuce.mmoitems.api.interaction.ItemSkin;
|
||||
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
|
||||
import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
@ -19,6 +19,8 @@ import net.Indyuce.mmoitems.stat.data.ParticleData;
|
||||
import net.Indyuce.mmoitems.stat.data.SkullTextureData;
|
||||
import net.Indyuce.mmoitems.stat.type.BooleanStat;
|
||||
import net.Indyuce.mmoitems.stat.type.ConsumableItemInteraction;
|
||||
import net.Indyuce.mmoitems.util.MMOUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -30,77 +32,94 @@ import org.bukkit.inventory.meta.LeatherArmorMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class CanDeskin extends BooleanStat implements ConsumableItemInteraction {
|
||||
public CanDeskin() {
|
||||
super("CAN_DESKIN", Material.LEATHER, "Can Deskin?",
|
||||
new String[] { "Players can deskin their item", "and get their skin back", "from the item." }, new String[] { "consumable" });
|
||||
}
|
||||
public CanDeskin() {
|
||||
super("CAN_DESKIN", Material.LEATHER, "Can Deskin?",
|
||||
new String[]{"Players can deskin their item", "and get their skin back", "from the item."}, new String[]{"consumable"});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleConsumableEffect(@NotNull InventoryClickEvent event, @NotNull PlayerData playerData, @NotNull Consumable consumable, @NotNull NBTItem target, Type targetType) {
|
||||
final String skinId = target.getString(ItemSkin.SKIN_ID_TAG);
|
||||
Player player = playerData.getPlayer();
|
||||
@Override
|
||||
public boolean handleConsumableEffect(@NotNull InventoryClickEvent event, @NotNull PlayerData playerData, @NotNull Consumable consumable, @NotNull NBTItem target, Type targetType) {
|
||||
final String skinId = target.getString(ItemSkin.SKIN_ID_TAG);
|
||||
Player player = playerData.getPlayer();
|
||||
|
||||
if (consumable.getNBTItem().getBoolean("MMOITEMS_CAN_DESKIN") && !skinId.isEmpty()) {
|
||||
if (consumable.getNBTItem().getBoolean("MMOITEMS_CAN_DESKIN") && !skinId.isEmpty()) {
|
||||
|
||||
// Set target item to default skin
|
||||
String targetItemId = target.getString("MMOITEMS_ITEM_ID");
|
||||
target.removeTag(ItemSkin.SKIN_ID_TAG);
|
||||
// Set target item to default skin
|
||||
String targetItemId = target.getString("MMOITEMS_ITEM_ID");
|
||||
target.removeTag(ItemSkin.SKIN_ID_TAG);
|
||||
|
||||
MMOItemTemplate targetTemplate = MMOItems.plugin.getTemplates().getTemplateOrThrow(targetType, targetItemId);
|
||||
MMOItem originalMmoitem = targetTemplate.newBuilder(playerData.getRPG()).build();
|
||||
ItemStack originalItem = targetTemplate.newBuilder(playerData.getRPG()).build().newBuilder().build();
|
||||
MMOItemTemplate targetTemplate = MMOItems.plugin.getTemplates().getTemplateOrThrow(targetType, targetItemId);
|
||||
MMOItem originalMmoitem = targetTemplate.newBuilder(playerData.getRPG()).build();
|
||||
ItemStack originalItem = targetTemplate.newBuilder(playerData.getRPG()).build().newBuilder().build();
|
||||
|
||||
int originalCustomModelData = originalItem.getItemMeta().hasCustomModelData() ? originalItem.getItemMeta().getCustomModelData() : -1;
|
||||
if (originalCustomModelData != -1)
|
||||
target.addTag(new ItemTag("CustomModelData", originalCustomModelData));
|
||||
else
|
||||
target.removeTag("CustomModelData");
|
||||
int originalCustomModelData = originalItem.getItemMeta().hasCustomModelData() ? originalItem.getItemMeta().getCustomModelData() : -1;
|
||||
if (originalCustomModelData != -1)
|
||||
target.addTag(new ItemTag("CustomModelData", originalCustomModelData));
|
||||
else
|
||||
target.removeTag("CustomModelData");
|
||||
|
||||
if (originalMmoitem.hasData(ItemStats.ITEM_PARTICLES)) {
|
||||
JsonObject itemParticles = ((ParticleData) originalMmoitem.getData(ItemStats.ITEM_PARTICLES)).toJson();
|
||||
target.addTag(new ItemTag("MMOITEMS_ITEM_PARTICLES", itemParticles.toString()));
|
||||
} else
|
||||
target.removeTag("MMOITEMS_ITEM_PARTICLES");
|
||||
if (originalMmoitem.hasData(ItemStats.ITEM_PARTICLES)) {
|
||||
JsonObject itemParticles = ((ParticleData) originalMmoitem.getData(ItemStats.ITEM_PARTICLES)).toJson();
|
||||
target.addTag(new ItemTag("MMOITEMS_ITEM_PARTICLES", itemParticles.toString()));
|
||||
} else
|
||||
target.removeTag("MMOITEMS_ITEM_PARTICLES");
|
||||
|
||||
ItemStack targetItem = target.toItem();
|
||||
ItemMeta targetItemMeta = targetItem.getItemMeta();
|
||||
ItemMeta originalItemMeta = originalItem.getItemMeta();
|
||||
ItemStack targetItem = target.toItem();
|
||||
ItemMeta targetItemMeta = targetItem.getItemMeta();
|
||||
ItemMeta originalItemMeta = originalItem.getItemMeta();
|
||||
|
||||
if (targetItemMeta.isUnbreakable()) {
|
||||
targetItemMeta.setUnbreakable(originalItemMeta.isUnbreakable());
|
||||
if (targetItemMeta instanceof Damageable && originalItemMeta instanceof Damageable)
|
||||
((Damageable) targetItemMeta).setDamage(((Damageable) originalItemMeta).getDamage());
|
||||
}
|
||||
if (targetItemMeta.isUnbreakable()) {
|
||||
targetItemMeta.setUnbreakable(originalItemMeta.isUnbreakable());
|
||||
if (targetItemMeta instanceof Damageable && originalItemMeta instanceof Damageable)
|
||||
((Damageable) targetItemMeta).setDamage(((Damageable) originalItemMeta).getDamage());
|
||||
}
|
||||
|
||||
if (targetItemMeta instanceof LeatherArmorMeta && originalItemMeta instanceof LeatherArmorMeta)
|
||||
((LeatherArmorMeta) targetItemMeta).setColor(((LeatherArmorMeta) originalItemMeta).getColor());
|
||||
if (targetItemMeta instanceof LeatherArmorMeta && originalItemMeta instanceof LeatherArmorMeta)
|
||||
((LeatherArmorMeta) targetItemMeta).setColor(((LeatherArmorMeta) originalItemMeta).getColor());
|
||||
|
||||
if (target.hasTag("SkullOwner") && (targetItem.getType() == VersionMaterial.PLAYER_HEAD.toMaterial())
|
||||
&& (originalItem.getType() == VersionMaterial.PLAYER_HEAD.toMaterial())) {
|
||||
try {
|
||||
Field profileField = targetItemMeta.getClass().getDeclaredField("profile");
|
||||
profileField.setAccessible(true);
|
||||
profileField.set(targetItemMeta, ((SkullTextureData) originalMmoitem.getData(ItemStats.SKULL_TEXTURE)).getGameProfile());
|
||||
} catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
|
||||
MMOItems.plugin.getLogger().warning("Could not read skull texture");
|
||||
}
|
||||
}
|
||||
if (target.hasTag("SkullOwner") && (targetItem.getType() == VersionMaterial.PLAYER_HEAD.toMaterial())
|
||||
&& (originalItem.getType() == VersionMaterial.PLAYER_HEAD.toMaterial())) {
|
||||
try {
|
||||
Field profileField = targetItemMeta.getClass().getDeclaredField("profile");
|
||||
profileField.setAccessible(true);
|
||||
profileField.set(targetItemMeta, ((SkullTextureData) originalMmoitem.getData(ItemStats.SKULL_TEXTURE)).getGameProfile());
|
||||
} catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
|
||||
MMOItems.plugin.getLogger().warning("Could not read skull texture");
|
||||
}
|
||||
}
|
||||
|
||||
// Update deskined item
|
||||
final ItemStack updated = target.getItem();
|
||||
updated.setItemMeta(targetItemMeta);
|
||||
updated.setType(originalItem.getType());
|
||||
// Update deskined item
|
||||
final ItemStack updated = target.getItem();
|
||||
updated.setItemMeta(targetItemMeta);
|
||||
updated.setType(originalItem.getType());
|
||||
|
||||
// Give back skin item
|
||||
MMOItemTemplate template = MMOItems.plugin.getTemplates().getTemplateOrThrow(Type.SKIN, skinId);
|
||||
MMOItem mmoitem = template.newBuilder(playerData.getRPG()).build();
|
||||
new SmartGive(player).give(mmoitem.newBuilder().build());
|
||||
// Give back the skin item
|
||||
try {
|
||||
|
||||
Message.SKIN_REMOVED.format(ChatColor.YELLOW, "#item#", MMOUtils.getDisplayName(targetItem)).send(player);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Try to find the skin item.
|
||||
// This is for backwards compatibility as cases with SKIN subtypes were not handled
|
||||
// in the past, inducing an unfixable data loss for item skins applied onto items
|
||||
@BackwardsCompatibility(version = "unknown") final String skinTypeId = target.getString(ItemSkin.SKIN_TYPE_TAG);
|
||||
final Type type = Objects.requireNonNullElse(Type.get(skinTypeId), Type.SKIN);
|
||||
Validate.notNull(type, "Could not find item type of applied skin");
|
||||
final MMOItemTemplate template = MMOItems.plugin.getTemplates().getTemplateOrThrow(Type.SKIN, skinId);
|
||||
Validate.notNull(template, "Could not find item template of applied skin");
|
||||
|
||||
// Item found, giving it to the player
|
||||
final MMOItem mmoitem = template.newBuilder(playerData.getRPG()).build();
|
||||
new SmartGive(player).give(mmoitem.newBuilder().build());
|
||||
} catch (Exception exception) {
|
||||
MMOItems.plugin.getLogger().log(Level.INFO, "Could not retrieve item skin with ID '" + skinId + "' for player " + playerData.getUniqueId());
|
||||
// No luck :(
|
||||
}
|
||||
|
||||
Message.SKIN_REMOVED.format(ChatColor.YELLOW, "#item#", MMOUtils.getDisplayName(targetItem)).send(player);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package net.Indyuce.mmoitems.stat.data;
|
||||
|
||||
import io.lumine.mythic.lib.api.item.ItemTag;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import net.Indyuce.mmoitems.api.interaction.ItemSkin;
|
||||
import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
|
||||
import net.Indyuce.mmoitems.stat.data.type.Mergeable;
|
||||
import net.Indyuce.mmoitems.stat.data.type.StatData;
|
||||
@ -12,123 +13,144 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class StoredTagsData implements StatData, Mergeable<StoredTagsData> {
|
||||
private final List<ItemTag> tags = new ArrayList<>();
|
||||
private final List<ItemTag> tags = new ArrayList<>();
|
||||
|
||||
private static final List<String> IGNORED_TAGS = Arrays.asList(
|
||||
"Unbreakable", "BlockEntityTag", "display", "Enchantments", "HideFlags", "Damage",
|
||||
"AttributeModifiers", "SkullOwner", "CanDestroy", "PickupDelay", "Age");
|
||||
private static final List<String> IGNORED_TAGS = Arrays.asList(
|
||||
"Unbreakable", "BlockEntityTag", "display", "Enchantments", "HideFlags", "Damage",
|
||||
"AttributeModifiers", "SkullOwner", "CanDestroy", "PickupDelay", "Age");
|
||||
|
||||
@Deprecated
|
||||
private static final List<String> SAVED_MMOITEMS_TAGS = Arrays.asList(
|
||||
"MMOITEMS_SKIN_ID");
|
||||
/**
|
||||
* TODO Make this list publically accessible to other plugins
|
||||
*/
|
||||
@Deprecated
|
||||
private static final List<String> SAVED_MMOITEMS_TAGS = Arrays.asList(
|
||||
ItemSkin.SKIN_ID_TAG,
|
||||
ItemSkin.SKIN_TYPE_TAG);
|
||||
|
||||
@Deprecated
|
||||
public StoredTagsData(ItemStack stack) {
|
||||
this(NBTItem.get(stack));
|
||||
}
|
||||
@Deprecated
|
||||
public StoredTagsData(ItemStack stack) {
|
||||
this(NBTItem.get(stack));
|
||||
}
|
||||
|
||||
public StoredTagsData(List<ItemTag> tgs) { tags.addAll(tgs); }
|
||||
public StoredTagsData(List<ItemTag> tgs) {
|
||||
tags.addAll(tgs);
|
||||
}
|
||||
|
||||
public StoredTagsData(NBTItem nbt) {
|
||||
for (String tag : nbt.getTags()) {
|
||||
public StoredTagsData(NBTItem nbt) {
|
||||
for (String tag : nbt.getTags()) {
|
||||
|
||||
// Usually ignore mmoitems
|
||||
if (tag.startsWith("MMOITEMS_") && !SAVED_MMOITEMS_TAGS.contains(tag))
|
||||
// Usually ignore mmoitems
|
||||
if (tag.startsWith("MMOITEMS_") && !SAVED_MMOITEMS_TAGS.contains(tag))
|
||||
|
||||
// Must be handled by its respective stat.
|
||||
continue;
|
||||
// Must be handled by its respective stat.
|
||||
continue;
|
||||
|
||||
// Any vanilla or MMOItem tag should be ignored as those are
|
||||
// automatically handled. Same for the History stat ones.
|
||||
if (IGNORED_TAGS.contains(tag) || tag.startsWith(ItemStackBuilder.history_keyword))
|
||||
continue;
|
||||
// Any vanilla or MMOItem tag should be ignored as those are
|
||||
// automatically handled. Same for the History stat ones.
|
||||
if (IGNORED_TAGS.contains(tag) || tag.startsWith(ItemStackBuilder.history_keyword))
|
||||
continue;
|
||||
|
||||
// As more methods are added we can add more types here
|
||||
switch (getTagType(nbt.getTypeId(tag))) {
|
||||
case "double":
|
||||
tags.add(new ItemTag(tag, nbt.getDouble(tag)));
|
||||
break;
|
||||
case "int":
|
||||
tags.add(new ItemTag(tag, nbt.getInteger(tag)));
|
||||
break;
|
||||
case "byte":
|
||||
tags.add(new ItemTag(tag, nbt.getBoolean(tag)));
|
||||
break;
|
||||
case "string":
|
||||
tags.add(new ItemTag(tag, nbt.getString(tag)));
|
||||
break;
|
||||
// default:
|
||||
// tags.add(new ItemTag(tag, "UNSUPPORTED TAG TYPE!"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addTag(ItemTag tag) {
|
||||
tags.add(tag);
|
||||
}
|
||||
// As more methods are added we can add more types here
|
||||
switch (getTagType(nbt.getTypeId(tag))) {
|
||||
case "double":
|
||||
tags.add(new ItemTag(tag, nbt.getDouble(tag)));
|
||||
break;
|
||||
case "int":
|
||||
tags.add(new ItemTag(tag, nbt.getInteger(tag)));
|
||||
break;
|
||||
case "byte":
|
||||
tags.add(new ItemTag(tag, nbt.getBoolean(tag)));
|
||||
break;
|
||||
case "string":
|
||||
tags.add(new ItemTag(tag, nbt.getString(tag)));
|
||||
break;
|
||||
// default:
|
||||
// tags.add(new ItemTag(tag, "UNSUPPORTED TAG TYPE!"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<ItemTag> getTags() {
|
||||
return tags;
|
||||
}
|
||||
public void addTag(ItemTag tag) {
|
||||
tags.add(tag);
|
||||
}
|
||||
|
||||
private String getTagType(int id) {
|
||||
switch (id) {
|
||||
case 0:
|
||||
return "end";
|
||||
case 1:
|
||||
return "byte";
|
||||
case 2:
|
||||
return "short";
|
||||
case 3:
|
||||
return "int";
|
||||
case 4:
|
||||
return "long";
|
||||
case 5:
|
||||
return "float";
|
||||
case 6:
|
||||
return "double";
|
||||
case 7:
|
||||
return "bytearray";
|
||||
case 8:
|
||||
return "string";
|
||||
case 9:
|
||||
return "list";
|
||||
case 10:
|
||||
return "compound";
|
||||
case 11:
|
||||
return "intarray";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
public List<ItemTag> getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void merge(StoredTagsData data) {
|
||||
tags.addAll(data.tags);
|
||||
}
|
||||
private String getTagType(int id) {
|
||||
switch (id) {
|
||||
case 0:
|
||||
return "end";
|
||||
case 1:
|
||||
return "byte";
|
||||
case 2:
|
||||
return "short";
|
||||
case 3:
|
||||
return "int";
|
||||
case 4:
|
||||
return "long";
|
||||
case 5:
|
||||
return "float";
|
||||
case 6:
|
||||
return "double";
|
||||
case 7:
|
||||
return "bytearray";
|
||||
case 8:
|
||||
return "string";
|
||||
case 9:
|
||||
return "list";
|
||||
case 10:
|
||||
return "compound";
|
||||
case 11:
|
||||
return "intarray";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredTagsData cloneData() { return new StoredTagsData(getTags()); }
|
||||
@Override
|
||||
public void merge(StoredTagsData data) {
|
||||
tags.addAll(data.tags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return tags.isEmpty();
|
||||
}
|
||||
@Override
|
||||
public StoredTagsData cloneData() {
|
||||
return new StoredTagsData(getTags());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof StoredTagsData)) { return false; }
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return tags.isEmpty();
|
||||
}
|
||||
|
||||
if (((StoredTagsData) obj).getTags().size() != getTags().size()) { return false; }
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof StoredTagsData)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ItemTag tag : ((StoredTagsData) obj).getTags()) {
|
||||
if (((StoredTagsData) obj).getTags().size() != getTags().size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tag == null) { continue; }
|
||||
for (ItemTag tag : ((StoredTagsData) obj).getTags()) {
|
||||
|
||||
boolean unmatched = true;
|
||||
for (ItemTag tg : getTags()) {
|
||||
if (tag.equals(tg)) { unmatched = false; break; } }
|
||||
if (unmatched) { return false; } }
|
||||
return true;
|
||||
}
|
||||
if (tag == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean unmatched = true;
|
||||
for (ItemTag tg : getTags()) {
|
||||
if (tag.equals(tg)) {
|
||||
unmatched = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (unmatched) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -57,6 +57,11 @@ public class MMOUtils {
|
||||
return str != null && !str.isEmpty();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String requireNonEmptyElse(@Nullable String str, @NotNull String fallback) {
|
||||
return isNonEmpty(str) ? str : Objects.requireNonNull(fallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The skull texture URL from a given player head
|
||||
*/
|
||||
@ -87,8 +92,8 @@ public class MMOUtils {
|
||||
* - for item upgrading TODO
|
||||
* - item repairing
|
||||
*
|
||||
* @param ref1 First reference
|
||||
* @param ref2 Second reference
|
||||
* @param ref1 First reference
|
||||
* @param ref2 Second reference
|
||||
* @return If items can interact
|
||||
*/
|
||||
public static boolean checkReference(@Nullable String ref1, @Nullable String ref2) {
|
||||
|
Loading…
Reference in New Issue
Block a user