diff --git a/src/main/java/ch/njol/skript/expressions/ExprLastDeathLocation.java b/src/main/java/ch/njol/skript/expressions/ExprLastDeathLocation.java new file mode 100644 index 00000000000..14adad782d4 --- /dev/null +++ b/src/main/java/ch/njol/skript/expressions/ExprLastDeathLocation.java @@ -0,0 +1,66 @@ +package ch.njol.skript.expressions; + +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.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +@Name("Last Death Location") +@Description({ + "Gets the last death location of a player, or offline player, if available.", + "Can also be set, reset, and deleted if the player is online." +}) +@Examples({ + "set {_loc} to the last death location of player", + "teleport player to last death location of (random element out of all players)" +}) +@Since("INSERT VERSION") +public class ExprLastDeathLocation extends SimplePropertyExpression { + + static { + register(ExprLastDeathLocation.class, Location.class, "[last] death location[s]", "offlineplayers"); + } + + @Override + public @Nullable Location convert(OfflinePlayer offlinePlayer) { + return offlinePlayer instanceof Player player + ? player.getLastDeathLocation() + : offlinePlayer.getLastDeathLocation(); + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + return switch (mode) { + case SET, RESET, DELETE -> CollectionUtils.array(Location.class); + default -> null; + }; + } + + @Override + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + Location loc = (delta != null && delta[0] instanceof Location location) ? location : null; + for (OfflinePlayer offlinePlayer : getExpr().getArray(event)) { + if (offlinePlayer instanceof Player player) + player.setLastDeathLocation(loc); + } + } + + @Override + protected String getPropertyName() { + return "last death location"; + } + + @Override + public Class getReturnType() { + return Location.class; + } + +} diff --git a/src/test/java/org/skriptlang/skript/test/tests/syntaxes/expressions/ExprLastDeathLocationTest.java b/src/test/java/org/skriptlang/skript/test/tests/syntaxes/expressions/ExprLastDeathLocationTest.java new file mode 100644 index 00000000000..40706ac0591 --- /dev/null +++ b/src/test/java/org/skriptlang/skript/test/tests/syntaxes/expressions/ExprLastDeathLocationTest.java @@ -0,0 +1,75 @@ +package org.skriptlang.skript.test.tests.syntaxes.expressions; + +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.TriggerItem; +import ch.njol.skript.lang.util.ContextlessEvent; +import ch.njol.skript.test.runner.SkriptJUnitTest; +import ch.njol.skript.variables.Variables; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.easymock.EasyMock; +import org.easymock.IArgumentMatcher; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class ExprLastDeathLocationTest extends SkriptJUnitTest { + + private Player player; + private Effect get, set; + + @Before + public void setup() { + player = EasyMock.niceMock(Player.class); + set = Effect.parse("set last death location of {_player} to {_location}", null); + get = Effect.parse("set {_loc} to last death location of {_player}", null); + } + + @Test + public void test() { + if (get == null) + Assert.fail("Get statement was null"); + if (set == null) + Assert.fail("Set statement was null"); + + Location location = new Location(Bukkit.getWorld("world"), 0, 0, 0); + + ContextlessEvent event = ContextlessEvent.get(); + Variables.setVariable("player", player, event, true); + Variables.setVariable("location", location, event, true); + + player.setLastDeathLocation(locationMatcher(location)); + EasyMock.expectLastCall(); + EasyMock.replay(player); + TriggerItem.walk(set, event); + EasyMock.verify(player); + + EasyMock.resetToNice(player); + + EasyMock.expect(player.getLastDeathLocation()).andReturn(location); + EasyMock.replay(player); + TriggerItem.walk(get, event); + EasyMock.verify(player); + } + + private T locationMatcher(Location expectedLoc) { + EasyMock.reportMatcher(new IArgumentMatcher() { + @Override + public boolean matches(Object argument) { + if (argument instanceof Location location) { + return location.equals(expectedLoc); + } + return false; + } + + @Override + public void appendTo(StringBuffer buffer) { + buffer.append("[location matcher]"); + } + }); + + return null; + } + +}