Skip to content

Commit baec56d

Browse files
committed
feat: implement "mutable" transform holder for random rotations
- also implement random rotation to schematic loadall - "mutable" transform allows random rotation of schematics outside of clipboard brush - fixes #3129
1 parent 20aa729 commit baec56d

File tree

11 files changed

+145
-19
lines changed

11 files changed

+145
-19
lines changed

worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MultiClipboardHolder.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,20 @@
33
import com.sk89q.worldedit.extent.clipboard.Clipboard;
44
import com.sk89q.worldedit.session.ClipboardHolder;
55

6+
import javax.annotation.Nonnull;
67
import java.io.IOException;
78
import java.net.URI;
89
import java.util.ArrayList;
910
import java.util.HashSet;
11+
import java.util.Iterator;
1012
import java.util.List;
1113
import java.util.Set;
1214
import java.util.UUID;
1315
import java.util.concurrent.ThreadLocalRandom;
1416

1517
import static com.google.common.base.Preconditions.checkNotNull;
1618

17-
public class MultiClipboardHolder extends URIClipboardHolder {
19+
public class MultiClipboardHolder extends URIClipboardHolder implements Iterable<URIClipboardHolder> {
1820

1921
private final List<URIClipboardHolder> holders;
2022
private Clipboard[] cached;
@@ -194,4 +196,9 @@ public void flush() {
194196
}
195197
}
196198

199+
@Override
200+
public @Nonnull Iterator<URIClipboardHolder> iterator() {
201+
return holders.iterator();
202+
}
203+
197204
}

worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/SchemGen.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ public boolean spawn(Random random, int x, int z) throws WorldEditException {
9292
if (transform.isIdentity()) {
9393
clipboard.paste(extent, mutable, false);
9494
} else {
95+
transform.mutate();
9596
clipboard.paste(extent, mutable, false, transform);
9697
}
9798
mutable.mutY(y);

worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/RandomFullClipboardPattern.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws W
6767
if (newTransform.isIdentity()) {
6868
clipboard.paste(extent, set, false);
6969
} else {
70+
newTransform.mutate();
7071
clipboard.paste(extent, set, false, newTransform);
7172
}
7273
return true;
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package com.fastasyncworldedit.core.math.transform;
2+
3+
import com.sk89q.worldedit.math.Vector3;
4+
import com.sk89q.worldedit.math.transform.Transform;
5+
6+
import java.util.function.Function;
7+
8+
/**
9+
* Applies an operation on a {@link Transform} when {@link MutatingOperationTransformHolder#mutate()} is called. Typically at
10+
* the start of an operation.
11+
*
12+
* @param <T> transform to mutate type
13+
* @since TODO
14+
*/
15+
public class MutatingOperationTransformHolder<T extends Transform> implements Transform {
16+
17+
private final Function<? super T, ? extends T> operation;
18+
private T transform;
19+
20+
/**
21+
* Construct new instance
22+
*
23+
* @param transform transform to mutate
24+
* @since TODO
25+
*/
26+
public MutatingOperationTransformHolder(T transform, Function<? super T, ? extends T> operation) {
27+
this.transform = transform;
28+
this.operation = operation;
29+
}
30+
31+
/**
32+
* Apply the mutator to the transform
33+
*
34+
* @since TODO
35+
*/
36+
public void mutate() {
37+
if (operation != null) {
38+
transform = operation.apply(transform);
39+
}
40+
}
41+
42+
@Override
43+
public boolean isIdentity() {
44+
return transform.isIdentity();
45+
}
46+
47+
@Override
48+
public Vector3 apply(final Vector3 input) {
49+
return transform.apply(input);
50+
}
51+
52+
@Override
53+
public Transform inverse() {
54+
return transform.inverse();
55+
}
56+
57+
@Override
58+
public Transform combine(final Transform other) {
59+
return transform.combine(other);
60+
}
61+
62+
}

worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ public void run(OutputStream out) {
404404
final Clipboard target;
405405
// If we have a transform, bake it into the copy
406406
if (!transform.isIdentity()) {
407+
transform.mutate();
407408
target = clipboard.transform(transform);
408409
} else {
409410
target = clipboard;
@@ -472,9 +473,10 @@ public void place(
472473
Region region = clipboard.getRegion().clone();
473474
if (selectPasted || onlySelect || removeEntities) {
474475
BlockVector3 clipboardOffset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin());
475-
BlockVector3 realTo = to.add(holder.getTransform().apply(clipboardOffset.toVector3()).toBlockPoint());
476-
BlockVector3 max = realTo.add(holder
477-
.getTransform()
476+
Transform transform = holder.getTransform();
477+
transform.mutate();
478+
BlockVector3 realTo = to.add(transform.apply(clipboardOffset.toVector3()).toBlockPoint());
479+
BlockVector3 max = realTo.add(transform
478480
.apply(region.getMaximumPoint().subtract(region.getMinimumPoint()).toVector3())
479481
.toBlockPoint());
480482
if (removeEntities) {
@@ -564,6 +566,7 @@ public void paste(
564566

565567
if (selectPasted || onlySelect || removeEntities) {
566568
BlockVector3 clipboardOffset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin());
569+
holder.getTransform().mutate(); //FAWE: mutate transform
567570
Vector3 realTo = to.toVector3().add(holder.getTransform().apply(clipboardOffset.toVector3()));
568571
Vector3 max = realTo.add(holder
569572
.getTransform()

worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
import com.fastasyncworldedit.core.event.extent.ActorSaveClipboardEvent;
2525
import com.fastasyncworldedit.core.extent.clipboard.MultiClipboardHolder;
2626
import com.fastasyncworldedit.core.extent.clipboard.URIClipboardHolder;
27-
import com.fastasyncworldedit.core.extent.clipboard.io.schematic.MinecraftStructure;
27+
import com.fastasyncworldedit.core.math.transform.MutatingOperationTransformHolder;
2828
import com.fastasyncworldedit.core.util.MainUtil;
2929
import com.google.common.collect.Multimap;
3030
import com.sk89q.worldedit.LocalConfiguration;
@@ -158,9 +158,11 @@ public void loadall(
158158
@Arg(desc = "File name.")
159159
String filename,
160160
@Switch(name = 'o', desc = "Overwrite/replace existing clipboard(s)")
161-
boolean overwrite
162-
// @Switch(name = 'r', desc = "Apply random rotation") <- not implemented below.
163-
// boolean randomRotate
161+
boolean overwrite,
162+
@Switch(name = 'r', desc = "Apply random rotation (static by default)")
163+
boolean randomRotate,
164+
@Switch(name = 'd', desc = "Random rotation is dynamic, changing each use")
165+
boolean dynamicRandom
164166
) throws FilenameException {
165167
final ClipboardFormat format = ClipboardFormats.findByAlias(formatName);
166168
if (format == null) {
@@ -169,19 +171,44 @@ public void loadall(
169171
}
170172
try {
171173
MultiClipboardHolder all = ClipboardFormats.loadAllFromInput(actor, filename, null, true);
172-
if (all != null) {
173-
if (overwrite) {
174-
session.setClipboard(all);
175-
} else {
176-
session.addClipboard(all);
177-
}
174+
if (all == null) {
178175
actor.print(Caption.of("fawe.worldedit.schematic.schematic.loaded", filename));
176+
return;
177+
}
178+
if (randomRotate) {
179+
for (ClipboardHolder holder : all) {
180+
setRandomRotateTransform(dynamicRandom, holder);
181+
}
182+
setRandomRotateTransform(dynamicRandom, all);
183+
}
184+
if (overwrite) {
185+
session.setClipboard(all);
186+
} else {
187+
session.addClipboard(all);
179188
}
189+
actor.print(Caption.of("fawe.worldedit.schematic.schematic.loaded", filename));
180190
} catch (IOException e) {
181191
throw new RuntimeException(e);
182192
}
183193
}
184194

195+
private static void setRandomRotateTransform(boolean dynamicRandom, ClipboardHolder holder) {
196+
if (dynamicRandom) {
197+
MutatingOperationTransformHolder<AffineTransform> mutating = new MutatingOperationTransformHolder<>(
198+
new AffineTransform(), t -> {
199+
int rotate = 90 * ThreadLocalRandom.current().nextInt(4);
200+
return t.rotateY(rotate);
201+
}
202+
);
203+
holder.setTransform(mutating);
204+
} else {
205+
AffineTransform transform = new AffineTransform();
206+
int rotate = 90 * ThreadLocalRandom.current().nextInt(4);
207+
transform = transform.rotateY(rotate);
208+
holder.setTransform(transform);
209+
}
210+
}
211+
185212
@Command(
186213
name = "clear",
187214
desc = "Clear your clipboard"
@@ -319,7 +346,9 @@ public void load(
319346
@Arg(desc = "Format name.", def = "")
320347
String formatName,
321348
@Switch(name = 'r', desc = "Apply random rotation to the clipboard")
322-
boolean randomRotate
349+
boolean randomRotate,
350+
@Switch(name = 'd', desc = "Random rotation is dynamic, changing each use")
351+
boolean dynamicRandom
323352
//FAWE end
324353
) throws FilenameException {
325354
LocalConfiguration config = worldEdit.getConfiguration();
@@ -435,10 +464,7 @@ public void load(
435464
closer.register(in);
436465
format.hold(actor, uri, in);
437466
if (randomRotate) {
438-
AffineTransform transform = new AffineTransform();
439-
int rotate = 90 * ThreadLocalRandom.current().nextInt(4);
440-
transform = transform.rotateY(rotate);
441-
session.getClipboard().setTransform(transform);
467+
setRandomRotateTransform(dynamicRandom, session.getClipboard());
442468
}
443469
actor.print(Caption.of("fawe.worldedit.schematic.schematic.loaded", filename));
444470
} catch (IllegalArgumentException e) {
@@ -889,6 +915,7 @@ private abstract static class SchematicOutputTask<T> implements Callable<T> {
889915
protected void writeToOutputStream(OutputStream outputStream) throws IOException, WorldEditException {
890916
Clipboard clipboard = holder.getClipboard();
891917
Transform transform = holder.getTransform();
918+
transform.mutate(); //FAWE: mutate transform
892919
Clipboard target = clipboard.transform(transform);
893920

894921
try (Closer closer = Closer.create()) {
@@ -928,6 +955,7 @@ public Void call() throws Exception {
928955
Clipboard target;
929956

930957
//FAWE start
958+
transform.mutate();
931959
boolean checkFilesize = Settings.settings().PATHS.PER_PLAYER_SCHEMATICS
932960
&& actor.getLimit().SCHEM_FILE_SIZE_LIMIT > -1;
933961

worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ public static void register(WorldEdit worldEdit, CommandManager commandManager)
9898
try {
9999
ClipboardHolder holder = context.getSession().getClipboard();
100100
Transform transform = holder.getTransform();
101+
transform.mutate(); //FAWE: mutate transform
101102
Extent target;
102103
if (transform.isIdentity()) {
103104
target = holder.getClipboard();

worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ public void build(EditSession editSession, BlockVector3 position, Pattern patter
9090
int rotate = 90 * ThreadLocalRandom.current().nextInt(4);
9191
transform = ((AffineTransform) transform).rotateY(rotate);
9292
if (originalTransform != null) {
93+
originalTransform.mutate();
9394
transform = originalTransform.combine(transform);
9495
}
9596
}

worldedit-core/src/main/java/com/sk89q/worldedit/math/transform/CombinedTransform.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,11 @@ public Transform combine(Transform other) {
9696
}
9797
}
9898

99+
@Override
100+
public void mutate() {
101+
for (Transform transform : transforms) {
102+
transform.mutate();
103+
}
104+
}
105+
99106
}

worldedit-core/src/main/java/com/sk89q/worldedit/math/transform/Transform.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,18 @@ public interface Transform {
5858
*/
5959
Transform combine(Transform other);
6060

61+
//FAWE start- mutating transforms
62+
63+
/**
64+
* Perform a mutation on this transform, if supported. Else, does nothing. This mutation will depend on the specific
65+
* transform implementation.
66+
* <p>
67+
* Implementation detail: it may be possible for this method to be called multiple times before an operation actually occurs.
68+
*
69+
* @since TODO
70+
*/
71+
default void mutate() {
72+
}
73+
//FAWE end
74+
6175
}

0 commit comments

Comments
 (0)