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

Add support for spawning dropped items #6746

Merged
merged 5 commits into from
May 31, 2024
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
126 changes: 83 additions & 43 deletions src/main/java/ch/njol/skript/entity/DroppedItemData.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,16 @@
*/
package ch.njol.skript.entity;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.function.Consumer;

import ch.njol.skript.Skript;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Item;
import org.bukkit.inventory.ItemStack;
import org.eclipse.jdt.annotation.Nullable;

import ch.njol.skript.aliases.ItemType;
import ch.njol.skript.lang.Literal;
Expand All @@ -32,71 +37,76 @@
import ch.njol.skript.localization.Noun;
import ch.njol.skript.registrations.Classes;
import ch.njol.util.coll.CollectionUtils;
import org.jetbrains.annotations.Nullable;

/**
* @author Peter Güttinger
*/
public class DroppedItemData extends EntityData<Item> {

private static final boolean HAS_JAVA_CONSUMER_DROP = Skript.methodExists(World.class, "dropItem", Location.class, ItemStack.class, Consumer.class);
private static @Nullable Method BUKKIT_CONSUMER_DROP;

static {
EntityData.register(DroppedItemData.class, "dropped item", Item.class, "dropped item");

try {
BUKKIT_CONSUMER_DROP = World.class.getDeclaredMethod("dropItem", Location.class, ItemStack.class, org.bukkit.util.Consumer.class);
} catch (NoSuchMethodException | SecurityException ignored) {}
}

private final static Adjective m_adjective = new Adjective("entities.dropped item.adjective");

@Nullable
private ItemType[] types;

private ItemType @Nullable [] types;

public DroppedItemData() {}

public DroppedItemData(@Nullable ItemType[] types) {
public DroppedItemData(ItemType @Nullable [] types) {
this.types = types;
}

@Override
protected boolean init(final Literal<?>[] exprs, final int matchedPattern, final ParseResult parseResult) {
if (exprs.length > 0 && exprs[0] != null)
types = (ItemType[]) exprs[0].getAll();
protected boolean init(Literal<?>[] expressions, int matchedPattern, ParseResult parseResult) {
if (expressions.length > 0 && expressions[0] != null)
types = (ItemType[]) expressions[0].getAll();
return true;
}

@Override
protected boolean init(final @Nullable Class<? extends Item> c, final @Nullable Item e) {
if (e != null) {
final ItemStack i = e.getItemStack();
protected boolean init(@Nullable Class<? extends Item> clazz, @Nullable Item itemEntity) {
if (itemEntity != null) {
final ItemStack i = itemEntity.getItemStack();
types = new ItemType[] {new ItemType(i)};
}
return true;
}

@Override
protected boolean match(final Item entity) {
protected boolean match(Item entity) {
if (types != null) {
for (final ItemType t : types) {
for (ItemType t : types) {
if (t.isOfType(entity.getItemStack()))
return true;
}
return false;
} else {
return true;
}
return true;
}

@Override
public void set(final Item entity) {
if (types == null)
return;
final ItemType t = CollectionUtils.getRandom(types);
assert t != null;
ItemStack stack = t.getItem().getRandom();
if (stack != null)
entity.setItemStack(stack);
entity.setItemStack(stack);
}

@Override
public boolean isSupertypeOf(final EntityData<?> e) {
if (!(e instanceof DroppedItemData))
public boolean isSupertypeOf(EntityData<?> otherData) {
if (!(otherData instanceof DroppedItemData))
return false;
final DroppedItemData d = (DroppedItemData) e;
DroppedItemData otherItemData = (DroppedItemData) otherData;
if (types != null)
return d.types != null && ItemType.isSubset(types, d.types);
return otherItemData.types != null && ItemType.isSubset(types, otherItemData.types);
return true;
}

Expand All @@ -111,36 +121,66 @@ public EntityData getSuperType() {
}

@Override
public String toString(final int flags) {
final ItemType[] types = this.types;
public String toString(int flags) {
if (types == null)
return super.toString(flags);
final StringBuilder b = new StringBuilder();
b.append(Noun.getArticleWithSpace(types[0].getTypes().get(0).getGender(), flags));
b.append(m_adjective.toString(types[0].getTypes().get(0).getGender(), flags));
b.append(" ");
b.append(Classes.toString(types, flags & Language.NO_ARTICLE_MASK, false));
return "" + b.toString();
int gender = types[0].getTypes().get(0).getGender();
return Noun.getArticleWithSpace(gender, flags) +
m_adjective.toString(gender, flags) +
" " +
Classes.toString(types, flags & Language.NO_ARTICLE_MASK, false);
}

// return ItemType.serialize(types);

@Override
@Deprecated
protected boolean deserialize(final String s) {
protected boolean deserialize(String s) {
throw new UnsupportedOperationException("old serialization is no longer supported");
// if (s.isEmpty())
// return true;
// types = ItemType.deserialize(s);
// return types != null;
}

@Override
protected boolean equals_i(final EntityData<?> obj) {
if (!(obj instanceof DroppedItemData))
protected boolean equals_i(EntityData<?> otherData) {
if (!(otherData instanceof DroppedItemData))
return false;
return Arrays.equals(types, ((DroppedItemData) obj).types);
return Arrays.equals(types, ((DroppedItemData) otherData).types);
}


@Override
public boolean canSpawn(@Nullable World world) {
return types != null && types.length > 0 && world != null;
}

@Override
public @Nullable Item spawn(Location location, @Nullable Consumer<Item> consumer) {
World world = location.getWorld();
if (!canSpawn(world))
return null;
assert types != null && types.length > 0;

final ItemType itemType = CollectionUtils.getRandom(types);
assert itemType != null;
ItemStack stack = itemType.getItem().getRandom();

Item item;
if (consumer == null) {
item = world.dropItem(location, stack);
} else if (HAS_JAVA_CONSUMER_DROP) {
item = world.dropItem(location, stack, consumer);
} else if (BUKKIT_CONSUMER_DROP != null) {
try {
// noinspection deprecation
item = (Item) BUKKIT_CONSUMER_DROP.invoke(world, location, stack, (org.bukkit.util.Consumer<Item>) consumer::accept);
} catch (InvocationTargetException | IllegalAccessException e) {
if (Skript.testing())
Skript.exception(e, "Can't spawn " + this.getName());
return null;
}
} else {
item = world.dropItem(location, stack);
consumer.accept(item);
}
return item;
}

@Override
protected int hashCode_i() {
return Arrays.hashCode(types);
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/ch/njol/skript/sections/EffSecSpawn.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;

import ch.njol.skript.doc.RequiredPlugins;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.event.Event;
Expand Down Expand Up @@ -58,9 +59,9 @@
"spawn 3 creepers at the targeted block",
"spawn a ghast 5 meters above the player",
"spawn a zombie at the player:",
"\tset name of the zombie to \"\""
"\tset name of the zombie to \"\""
})
@Since("1.0, 2.6.1 (with section)")
@Since("1.0, 2.6.1 (with section), INSERT VERSION (dropped items)")
public class EffSecSpawn extends EffectSection {

public static class SpawnEvent extends Event {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
test "spawn dropped item":
spawn dropped stone at spawn of world "world":
set {_e} to entity
assert {_e} is set with "failed to spawn dropped stone"
delete entity within {_e}

sovdeeth marked this conversation as resolved.
Show resolved Hide resolved
spawn dropped item at spawn of world "world":
set {_e2} to entity
assert {_e2} is not set with "spawned `dropped item` despite undefined item type"
sovdeeth marked this conversation as resolved.
Show resolved Hide resolved