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

Additional Dropped Item Elements #7270

Open
wants to merge 19 commits into
base: dev/feature
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 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
63 changes: 63 additions & 0 deletions src/main/java/ch/njol/skript/bukkitutil/UUIDUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package ch.njol.skript.bukkitutil;

import ch.njol.util.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.UUID;

/**
* Utility class for quick {@link UUID} methods.
*/
public class UUIDUtils {
TheAbsolutionism marked this conversation as resolved.
Show resolved Hide resolved

/**
* Converts {@code object} into a UUID if possible
* @param object
* @return The resulting {@link UUID}
*/
public static @Nullable UUID asUUID(@NotNull Object object) {
if (object instanceof OfflinePlayer offlinePlayer) {
return offlinePlayer.getUniqueId();
} else if (object instanceof Entity entity) {
return entity.getUniqueId();
} else if (object instanceof String string && StringUtils.containsAny(string, "-")) {
try {
return UUID.fromString(string);
} catch (Exception ignored) {}
} else if (object instanceof UUID uuid) {
return uuid;
}
return null;
}

/**
* Get the {@link Entity} or {@link OfflinePlayer} the {@code uuid} belongs to.
* Will return an {@link OfflinePlayer} regardless if the player exists.
* @param uuid The {@link UUID}
* @return The resulting {@link Entity} or {@link OfflinePlayer}
*/
public static @Nullable Object fromUUID(@NotNull UUID uuid) {
return fromUUID(uuid, false);
}

/**
* Get the {@link Entity} or {@link OfflinePlayer} the {@code uuid} belongs to.
* @param uuid The {@link UUID}
* @param restrictOffline If the {@link OfflinePlayer} needs to have played the server.
* @return The resulting {@link Entity} or {@link OfflinePlayer}
*/
public static @Nullable Object fromUUID(@NotNull UUID uuid, boolean restrictOffline) {
Entity checkEntity = Bukkit.getEntity(uuid);
if (checkEntity != null)
return checkEntity;
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid);
if (!restrictOffline || (restrictOffline && offlinePlayer.hasPlayedBefore()))
return offlinePlayer;
return null;
}

}
34 changes: 34 additions & 0 deletions src/main/java/ch/njol/skript/conditions/CondItemDespawn.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package ch.njol.skript.conditions;

import ch.njol.skript.conditions.base.PropertyCondition;
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 org.bukkit.entity.Item;

@Name("Will Despawn")
@Description("Checks if the dropped item will be despawned naturally through Minecraft's timer.")
@Examples({
"if all dropped items can despawn naturally:",
"\tprevent all dropped items from naturally despawning"
})
@Since("INSERT VERSION")
public class CondItemDespawn extends PropertyCondition<Item> {

static {
PropertyCondition.register(CondItemDespawn.class, PropertyType.WILL, "(despawn naturally|naturally despawn)", "itementities");
PropertyCondition.register(CondItemDespawn.class, PropertyType.CAN, "(despawn naturally|naturally despawn)", "itementities");
TheAbsolutionism marked this conversation as resolved.
Show resolved Hide resolved
}

@Override
public boolean check(Item item) {
return !item.isUnlimitedLifetime();
}

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

}
68 changes: 36 additions & 32 deletions src/main/java/ch/njol/skript/conditions/base/PropertyCondition.java
TheAbsolutionism marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
package ch.njol.skript.conditions.base;

import ch.njol.skript.lang.SyntaxStringBuilder;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;

Expand Down Expand Up @@ -107,28 +108,29 @@ public static void register(Class<? extends Condition> condition, PropertyType p
throw new SkriptAPIException("The type argument must not contain any '%'s");

switch (propertyType) {
case BE:
case BE -> {
Skript.registerCondition(condition, ConditionType.PROPERTY,
"%" + type + "% (is|are) " + property,
"%" + type + "% (isn't|is not|aren't|are not) " + property);
break;
case CAN:
"%" + type + "% (is|are) " + property,
"%" + type + "% (isn't|is not|aren't|are not) " + property);
}
case CAN -> {
Skript.registerCondition(condition, ConditionType.PROPERTY,
"%" + type + "% can " + property,
"%" + type + "% (can't|cannot|can not) " + property);
break;
case HAVE:
"%" + type + "% can " + property,
"%" + type + "% (can't|cannot|can not) " + property);
}
case HAVE -> {
Skript.registerCondition(condition, ConditionType.PROPERTY,
"%" + type + "% (has|have) " + property,
"%" + type + "% (doesn't|does not|do not|don't) have " + property);
break;
case WILL:
"%" + type + "% (has|have) " + property,
"%" + type + "% (doesn't|does not|do not|don't) have " + property);
}
case WILL -> {
Skript.registerCondition(condition,
"%" + type + "% will " + property,
"%" + type + "% (will (not|neither)|won't) " + property);
break;
default:
"%" + type + "% will " + property,
"%" + type + "% (will (not|neither)|won't) " + property);
}
default -> {
assert false;
}
}
}

Expand Down Expand Up @@ -168,25 +170,27 @@ public String toString(@Nullable Event event, boolean debug) {
return toString(this, getPropertyType(), event, debug, expr, getPropertyName());
}

public static String toString(Condition condition, PropertyType propertyType, @Nullable Event event,
boolean debug, Expression<?> expr, String property) {
switch (propertyType) {
case BE:
return expr.toString(event, debug) + (expr.isSingle() ? " is " : " are ") + (condition.isNegated() ? "not " : "") + property;
case CAN:
return expr.toString(event, debug) + (condition.isNegated() ? " can't " : " can ") + property;
case HAVE:
public static String toString(Condition condition, PropertyType propertyType, @Nullable Event event, boolean debug, Expression<?> expr, String property) {
SyntaxStringBuilder builder = new SyntaxStringBuilder(event, debug);
builder.append(expr);
builder.append(switch (propertyType) {
case BE -> (expr.isSingle() ? "is " : "are ") + (condition.isNegated() ? "not" : "");
case CAN -> (condition.isNegated() ? "can't" : "can");
case HAVE -> {
if (expr.isSingle()) {
return expr.toString(event, debug) + (condition.isNegated() ? " doesn't have " : " has ") + property;
yield (condition.isNegated() ? "doesn't have" : "has");
} else {
return expr.toString(event, debug) + (condition.isNegated() ? " don't have " : " have ") + property;
yield (condition.isNegated() ? "don't have" : "have");
}
case WILL:
return expr.toString(event, debug) + (condition.isNegated() ? " won't " : " will ") + "be " + property;
default:
}
case WILL -> (condition.isNegated() ? "won't " : "will ") + "be";
default -> {
assert false;
return null;
}
yield null;
}
});
builder.append(property);
return builder.toString();
}

}
62 changes: 62 additions & 0 deletions src/main/java/ch/njol/skript/effects/EffItemDespawn.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package ch.njol.skript.effects;

import ch.njol.skript.Skript;
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.lang.Effect;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.skript.lang.SyntaxStringBuilder;
import ch.njol.util.Kleenean;
import org.bukkit.entity.Item;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;

@Name("Item Despawn")
@Description("Prevent a dropped item from naturally despawning through Minecraft's timer.")
@Examples({
"prevent all dropped items from naturally despawning",
"allow all dropped items to naturally despawn"
})
@Since("INSERT VERSION")
public class EffItemDespawn extends Effect {

static {
Skript.registerEffect(EffItemDespawn.class,
"(prevent|disallow) %itementities% from (naturally despawning|despawning naturally)",
"allow natural despawning of %itementities%",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say there should be a corresponding
(prevent|disallow) natural despawning of %itementities%

I'm also wondering if natural should be optional, as in prevent despawning of %itementities% (not 100% sure on that)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know

"allow %itementities% to (naturally despawn|despawn naturally)");
}

private Expression<Item> entities;
private boolean prevent;

@Override
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
prevent = matchedPattern == 0;
//noinspection unchecked
entities = (Expression<Item>) exprs[0];
return true;
}

@Override
protected void execute(Event event) {
for (Item item : entities.getArray(event)) {
item.setUnlimitedLifetime(prevent);
}
}

@Override
public String toString(@Nullable Event event, boolean debug) {
SyntaxStringBuilder builder = new SyntaxStringBuilder(event, debug);
if (prevent) {
builder.append("prevent", entities, "from naturally despawning");
} else {
builder.append("allow", entities, "to naturally despawn");
}
return builder.toString();
}

}
107 changes: 107 additions & 0 deletions src/main/java/ch/njol/skript/expressions/ExprEntityOwner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package ch.njol.skript.expressions;

import ch.njol.skript.Skript;
import ch.njol.skript.bukkitutil.UUIDUtils;
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.skript.lang.ExpressionType;
import ch.njol.util.coll.CollectionUtils;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Item;
import org.bukkit.entity.Tameable;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;

import java.util.UUID;

@Name("Entity Owner")
@Description({
"The owner of a tameable entity (i.e. horse or wolf) or a dropped item.",
"Getting the owner of a dropped item will only return a loaded entity or a player that has played before. "
+ "If the entity was killed, or the player has never played before, will return null.",
TheAbsolutionism marked this conversation as resolved.
Show resolved Hide resolved
"Setting the owner of a dropped item means only that entity or player can pick it up. "
+ "This is UUID based, so it can also be set to a specific UUID.",
"Dropping an item does not automatically make the entity or player the owner."
})
@Examples({
"set owner of target entity to player",
"delete owner of target entity",
"set {_t} to uuid of tamer of target entity",
"",
"set the owner of all dropped items to player"
})
@Since("2.5, INSERT VERSION (dropped items)")
public class ExprEntityOwner extends SimplePropertyExpression<Entity, Object> {

static {
Skript.registerExpression(ExprEntityOwner.class, Object.class, ExpressionType.PROPERTY,
"[the] (owner|tamer) of %livingentities%",
"%livingentities%'[s] (owner|tamer)",
"[the] [dropped item] owner of %itementities%",
"%itementities%'[s] [dropped item] owner");
TheAbsolutionism marked this conversation as resolved.
Show resolved Hide resolved
}

@Override
public @Nullable Object convert(Entity entity) {
if (entity instanceof Tameable tameable && tameable.isTamed()) {
return tameable.getOwner();
} else if (entity instanceof Item item) {
UUID uuid = item.getOwner();
if (uuid == null)
return null;
return UUIDUtils.fromUUID(uuid, true);
}
return null;
}

@Override
public Class<?> @Nullable [] acceptChange(ChangeMode mode) {
return switch (mode) {
case SET, DELETE, RESET -> CollectionUtils.array(OfflinePlayer.class, Entity.class, String.class);
default -> null;
};
}

@Override
public void change(Event event, Object @Nullable [] delta, ChangeMode mode) {
UUID newId = null;
OfflinePlayer newPlayer = null;
if (delta != null) {
if (delta[0] instanceof OfflinePlayer offlinePlayer) {
newPlayer = offlinePlayer;
newId = offlinePlayer.getUniqueId();
} else {
newId = UUIDUtils.asUUID(delta[0]);
}
}

for (Entity entity : getExpr().getArray(event)) {
if (entity instanceof Tameable tameable) {
tameable.setOwner(newPlayer);
} else if (entity instanceof Item item) {
item.setOwner(newId);
}
}
}

@Override
public Class<Object> getReturnType() {
TheAbsolutionism marked this conversation as resolved.
Show resolved Hide resolved
return Object.class;
}

@Override
public Class<?>[] possibleReturnTypes() {
return CollectionUtils.array(Entity.class, OfflinePlayer.class);
}

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

}
Loading
Loading