From 4fc62d98cb225b7e050a1d820858277ee8dda6e3 Mon Sep 17 00:00:00 2001 From: TomyLobo Date: Tue, 14 Mar 2023 03:13:00 +0100 Subject: [PATCH] Add new //placement types - //placement min - selection min X/Y/Z - //placement max - selection max X/Y/Z - //placement world - absolute world location - //placement here - This puts the placement position at the current player position. --- .../com/sk89q/worldedit/LocalSession.java | 4 ++ .../worldedit/command/GeneralCommands.java | 10 ++++ .../worldedit/session/PlacementType.java | 43 ++++++++++++++++ .../src/main/resources/lang/strings.json | 6 +++ .../com/sk89q/worldedit/LocalSessionTest.java | 5 ++ .../worldedit/session/PlacementTest.java | 5 ++ .../worldedit/session/PlacementTypeTest.java | 50 +++++++++++++++++++ 7 files changed, 123 insertions(+) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index e971fb766..e72775607 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -582,6 +582,10 @@ public Placement getPlacement() { * @param placement the placement. */ public void setPlacement(Placement placement) { + if (placement.getPlacementType() == PlacementType.HERE) { + throw new IllegalStateException("PlacementType.HERE cannot be used. Use PLAYER or WORLD instead."); + } + this.placement = placement; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java index 3d50bd0b1..05a89bd40 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java @@ -32,6 +32,7 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Locatable; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.RegionMaskingFilter; import com.sk89q.worldedit.function.block.ApplySideEffect; @@ -460,6 +461,15 @@ public void placement(Actor actor, LocalSession session, @Offset BlockVector3 offset) { offset = offset.multiply(multiplier); + if (placementType == PlacementType.HERE) { + if (!placementType.canBeUsedBy(actor)) { + actor.printError(TranslatableComponent.of("worldedit.toggleplace.not-locatable")); + return; + } + // Replace "//placement here" by "//placement " + placementType = PlacementType.WORLD; + offset = offset.add(((Locatable) actor).getBlockLocation().toVector().toBlockPoint()); + } placementImpl(actor, session, new Placement(placementType, offset)); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/PlacementType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/PlacementType.java index 2f4bd3f69..3d951a26a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/session/PlacementType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/PlacementType.java @@ -28,6 +28,13 @@ import static com.google.common.base.Preconditions.checkNotNull; public enum PlacementType { + WORLD("worldedit.toggleplace.world", "worldedit.toggleplace.world-offset") { + @Override + public BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException { + return BlockVector3.ZERO; + } + }, + PLAYER("worldedit.toggleplace.player", "worldedit.toggleplace.player-offset") { @Override public BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException { @@ -44,11 +51,47 @@ public boolean canBeUsedBy(Actor actor) { } }, + HERE(null, null) { + @Override + public BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException { + throw new IllegalStateException("PlacementType.HERE cannot be used. Use PLAYER or WORLD instead."); + } + + @Override + public boolean canBeUsedBy(Actor actor) { + return PLAYER.canBeUsedBy(actor); + } + + @Override + public String getTranslationKey() { + throw new IllegalStateException("PlacementType.HERE cannot be used. Use PLAYER or WORLD instead."); + } + + @Override + public String getTranslationKeyWithOffset() { + throw new IllegalStateException("PlacementType.HERE cannot be used. Use PLAYER or WORLD instead."); + } + }, + POS1("worldedit.toggleplace.pos1", "worldedit.toggleplace.pos1-offset") { @Override public BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException { return selector.getPrimaryPosition(); } + }, + + MIN("worldedit.toggleplace.min", "worldedit.toggleplace.min-offset") { + @Override + public BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException { + return selector.getRegion().getMinimumPoint(); + } + }, + + MAX("worldedit.toggleplace.max", "worldedit.toggleplace.max-offset") { + @Override + public BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException { + return selector.getRegion().getMaximumPoint(); + } }; private final String translationKey; diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index 7186a3f40..b6c4ed18b 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -72,6 +72,12 @@ "worldedit.toggleplace.pos1-offset": "Now placing at an offset of ({0}, {1}, {2}) from pos #1.", "worldedit.toggleplace.player": "Now placing at the block you stand in.", "worldedit.toggleplace.player-offset": "Now placing at an offset of ({0}, {1}, {2}) from the block you stand in.", + "worldedit.toggleplace.min": "Now placing at the minimum of the current selection.", + "worldedit.toggleplace.min-offset": "Now placing at an offset of ({0}, {1}, {2}) from the minimum of the current selection.", + "worldedit.toggleplace.max": "Now placing at the maximum of the current selection.", + "worldedit.toggleplace.max-offset": "Now placing at an offset of ({0}, {1}, {2}) from the maximum of the current selection.", + "worldedit.toggleplace.world": "Now placing at world origin.", + "worldedit.toggleplace.world-offset": "Now placing at ({0}, {1}, {2}).", "worldedit.toggleplace.not-locatable": "Cannot toggle placing in this context.", "worldedit.searchitem.too-short": "Enter a longer search string (len > 2).", "worldedit.searchitem.either-b-or-i": "You cannot use both the 'b' and 'i' flags simultaneously.", diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/LocalSessionTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/LocalSessionTest.java index 677c830ec..80802899e 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/LocalSessionTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/LocalSessionTest.java @@ -131,6 +131,11 @@ void testPlacementPlayer() throws Exception { @ParameterizedTest @EnumSource(PlacementType.class) void testPlacementGeneric(PlacementType placementType) throws Exception { + if (placementType == PlacementType.HERE) { + // HERE is a special case that's handled in command code and doesn't have an actual implementation + return; + } + final ActorSelectorLimits limits = ActorSelectorLimits.forActor(player); final RegionSelector regionSelector = session.getRegionSelector(world); diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/session/PlacementTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/session/PlacementTest.java index 1531836ea..abcbfd445 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/session/PlacementTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/session/PlacementTest.java @@ -50,6 +50,11 @@ void setUp() { @ParameterizedTest @EnumSource(PlacementType.class) void testPlacementGeneric(PlacementType placementType) throws Exception { + if (placementType == PlacementType.HERE) { + // HERE is a special case that's handled in command code and doesn't have an actual implementation + return; + } + final ActorSelectorLimits limits = mock(ActorSelectorLimits.class, Answers.RETURNS_SMART_NULLS); final RegionSelector regionSelector = new CuboidRegionSelector(); diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/session/PlacementTypeTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/session/PlacementTypeTest.java index 4159896e5..46eb92d64 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/session/PlacementTypeTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/session/PlacementTypeTest.java @@ -22,6 +22,7 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.World; @@ -38,6 +39,17 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; class PlacementTypeTest { + @Test + void testPlacementWORLD() throws Exception { + final RegionSelector regionSelector = mock(RegionSelector.class, Answers.RETURNS_SMART_NULLS); + final Player player = mock(Player.class, Answers.RETURNS_SMART_NULLS); + + assertEquals(BlockVector3.ZERO, PlacementType.WORLD.getPlacementPosition(regionSelector, player)); + + verifyNoInteractions(regionSelector); + verifyNoInteractions(player); + } + @Test void testPlacementPLAYER() throws Exception { final RegionSelector regionSelector = mock(RegionSelector.class, Answers.RETURNS_SMART_NULLS); @@ -70,4 +82,42 @@ void testPlacementPOS1() throws Exception { verifyNoMoreInteractions(regionSelector); verifyNoInteractions(actor); } + + @Test + void testPlacementMIN() throws Exception { + final Region region = mock(Region.class, Answers.RETURNS_SMART_NULLS); + final RegionSelector regionSelector = mock(RegionSelector.class, Answers.RETURNS_SMART_NULLS); + final Actor actor = mock(Actor.class, Answers.RETURNS_SMART_NULLS); + + final BlockVector3 min = BlockVector3.at(1337, 42, 23); + doReturn(min).when(region).getMinimumPoint(); + doReturn(region).when(regionSelector).getRegion(); + + assertEquals(min, PlacementType.MIN.getPlacementPosition(regionSelector, actor)); + + verify(region, times(1)).getMinimumPoint(); + verifyNoMoreInteractions(region); + verify(regionSelector, times(1)).getRegion(); + verifyNoMoreInteractions(regionSelector); + verifyNoInteractions(actor); + } + + @Test + void testPlacementMAX() throws Exception { + final Region region = mock(Region.class, Answers.RETURNS_SMART_NULLS); + final RegionSelector regionSelector = mock(RegionSelector.class, Answers.RETURNS_SMART_NULLS); + final Actor actor = mock(Actor.class, Answers.RETURNS_SMART_NULLS); + + final BlockVector3 max = BlockVector3.at(1337, 42, 23); + doReturn(max).when(region).getMaximumPoint(); + doReturn(region).when(regionSelector).getRegion(); + + assertEquals(max, PlacementType.MAX.getPlacementPosition(regionSelector, actor)); + + verify(region, times(1)).getMaximumPoint(); + verifyNoMoreInteractions(region); + verify(regionSelector, times(1)).getRegion(); + verifyNoMoreInteractions(regionSelector); + verifyNoInteractions(actor); + } }