Merge remote-tracking branch 'upstream/main'

# Conflicts:
#	build.gradle.kts
#	settings.gradle.kts
#	worldedit-bukkit/build.gradle.kts
This commit is contained in:
2024-11-27 23:59:14 +01:00
783 changed files with 30462 additions and 15592 deletions

View File

@ -12,7 +12,7 @@ applyPlatformAndCoreConfiguration()
dependencies {
constraints {
implementation(libs.snakeyaml) {
version { strictly("2.0") }
version { strictly("2.2") }
because("Bukkit provides SnakeYaml")
}
}
@ -46,7 +46,6 @@ dependencies {
implementation(libs.findbugs)
implementation(libs.rhino)
compileOnly(libs.adventureApi)
compileOnlyApi(libs.adventureNbt)
compileOnlyApi(libs.adventureMiniMessage)
implementation(libs.zstd) { isTransitive = false }
compileOnly(libs.paster)
@ -56,10 +55,10 @@ dependencies {
antlr(libs.antlr4)
implementation(libs.antlr4Runtime)
implementation(libs.jsonSimple) { isTransitive = false }
implementation(platform(libs.linBus.bom))
// Tests
testRuntimeOnly(libs.log4jCore)
testImplementation(libs.adventureNbt)
testImplementation(libs.parallelgzip)
}

View File

@ -1,16 +1,12 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm") version "1.8.20"
kotlin("jvm") version "1.9.23"
application
}
applyCommonConfiguration()
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "17"
}
application.mainClass.set("com.sk89q.worldedit.internal.util.DocumentationPrinter")
tasks.named<JavaExec>("run") {
workingDir = rootProject.projectDir

View File

@ -125,7 +125,7 @@ public class MobSpawnerBlock extends BaseBlock {
@Override
public CompoundTag getNbtData() {
Map<String, Tag> values = new HashMap<>();
Map<String, Tag<?, ?>> values = new HashMap<>();
values.put("Delay", new ShortTag(delay));
values.put("SpawnCount", new ShortTag(spawnCount));
values.put("SpawnRange", new ShortTag(spawnRange));
@ -170,7 +170,7 @@ public class MobSpawnerBlock extends BaseBlock {
return;
}
Map<String, Tag> values = rootTag.getValue();
Map<String, Tag<?, ?>> values = rootTag.getValue();
Tag t = values.get("id");
if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals(getNbtId())) {

View File

@ -104,7 +104,7 @@ public class SignBlock extends BaseBlock {
@Override
public CompoundTag getNbtData() {
Map<String, Tag> values = new HashMap<>();
Map<String, Tag<?, ?>> values = new HashMap<>();
if (isLegacy()) {
values.put("Text1", new StringTag(text[0]));
values.put("Text2", new StringTag(text[1]));
@ -112,7 +112,7 @@ public class SignBlock extends BaseBlock {
values.put("Text4", new StringTag(text[3]));
} else {
ListTag messages = new ListTag(StringTag.class, Arrays.stream(text).map(StringTag::new).collect(Collectors.toList()));
Map<String, Tag> frontTextTag = new HashMap<>();
Map<String, Tag<?, ?>> frontTextTag = new HashMap<>();
frontTextTag.put("messages", messages);
values.put("front_text", new CompoundTag(frontTextTag));
}
@ -125,9 +125,9 @@ public class SignBlock extends BaseBlock {
return;
}
Map<String, Tag> values = rootTag.getValue();
Map<String, Tag<?, ?>> values = rootTag.getValue();
Tag t;
Tag<?, ?> t;
text = new String[]{EMPTY, EMPTY, EMPTY, EMPTY};

View File

@ -100,8 +100,8 @@ public class SkullBlock extends BaseBlock {
@Override
public CompoundTag getNbtData() {
Map<String, Tag> values = new HashMap<>();
Map<String, Tag> inner = new HashMap<>();
Map<String, Tag<?, ?>> values = new HashMap<>();
Map<String, Tag<?, ?>> inner = new HashMap<>();
inner.put("Name", new StringTag(owner));
values.put(DeprecationUtil.getHeadOwnerKey(), new CompoundTag(inner));
return new CompoundTag(values);
@ -113,7 +113,7 @@ public class SkullBlock extends BaseBlock {
return;
}
Map<String, Tag> values = rootTag.getValue();
Map<String, Tag<?, ?>> values = rootTag.getValue();
Tag t;

View File

@ -2,6 +2,7 @@ package com.fastasyncworldedit.core;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.internal.exception.FaweException;
import com.fastasyncworldedit.core.limit.FaweLimit;
import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
import com.fastasyncworldedit.core.util.CachedTextureUtil;
import com.fastasyncworldedit.core.util.CleanTextureUtil;
@ -13,8 +14,8 @@ import com.fastasyncworldedit.core.util.TaskManager;
import com.fastasyncworldedit.core.util.TextureUtil;
import com.fastasyncworldedit.core.util.WEManager;
import com.fastasyncworldedit.core.util.task.KeyQueuedExecutorService;
import com.fastasyncworldedit.core.util.task.UUIDKeyQueuedThreadFactory;
import com.github.luben.zstd.Zstd;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import net.jpountz.lz4.LZ4Factory;
@ -36,46 +37,43 @@ import java.lang.management.MemoryUsage;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* [ WorldEdit action]
* |
* \|/
* [ WorldEdit action ]
* <br>
* [ EditSession ] - The change is processed (area restrictions, change limit, block type)
* |
* \|/
* [Block change] - A block change from some location
* |
* \|/
* <br>
* [ Block change ] - A block change from some location
* <br>
* [ Set Queue ] - The SetQueue manages the implementation specific queue
* |
* \|/
* <br>
* [ Fawe Queue] - A queue of chunks - check if the queue has the chunk for a change
* |
* \|/
* <br>
* [ Fawe Chunk Implementation ] - Otherwise create a new FaweChunk object which is a wrapper around the Chunk object
* |
* \|/
* <br>
* [ Execution ] - When done, the queue then sets the blocks for the chunk, performs lighting updates and sends the chunk packet to the clients
* <p>
* Why it's faster:
* - The chunk is modified directly rather than through the API
* \ Removes some overhead, and means some processing can be done async
* - Lighting updates are performed on the chunk level rather than for every block
* \ e.g., A blob of stone: only the visible blocks need to have the lighting calculated
* - Block changes are sent with a chunk packet
* \ A chunk packet is generally quicker to create and smaller for large world edits
* - No physics updates
* \ Physics updates are slow, and are usually performed on each block
* - Block data shortcuts
* \ Some known blocks don't need to have the data set or accessed (e.g., air is never going to have data)
* - Remove redundant extents
* \ Up to 11 layers of extents can be removed
* - History bypassing
* \ FastMode bypasses history and means blocks in the world don't need to be checked and recorded
* <br> The chunk is modified directly rather than through the API
* - Removes some overhead, and means some processing can be done async
* <br> Lighting updates are performed on the chunk level rather than for every block
* - e.g., A blob of stone: only the visible blocks need to have the lighting calculated
* <br> Block changes are sent with a chunk packet
* - A chunk packet is generally quicker to create and smaller for large world edits
* <br> No physics updates
* - Physics updates are slow, and are usually performed on each block
* <br> Block data shortcuts
* - Some known blocks don't need to have the data set or accessed (e.g., air is never going to have data)
* <br> Remove redundant extents
* - Up to 11 layers of extents can be removed
* <br> History bypassing
* - FastMode bypasses history and means blocks in the world don't need to be checked and recorded
*/
public class Fawe {
@ -91,7 +89,7 @@ public class Fawe {
* The platform specific implementation.
*/
private final IFawe implementation;
private final KeyQueuedExecutorService<UUID> clipboardExecutor;
private final KeyQueuedExecutorService<UUID> uuidKeyQueuedExecutorService;
private FaweVersion version;
private TextureUtil textures;
private QueueHandler queueHandler;
@ -105,6 +103,8 @@ public class Fawe {
* Implementation dependent stuff
*/
this.setupConfigs();
FaweLimit.MAX.CONFIRM_LARGE =
Settings.settings().LIMITS.get("default").CONFIRM_LARGE || Settings.settings().GENERAL.LIMIT_UNLIMITED_CONFIRMS;
TaskManager.IMP = this.implementation.getTaskManager();
TaskManager.taskManager().async(() -> {
@ -137,14 +137,13 @@ public class Fawe {
}, 0);
TaskManager.taskManager().repeat(timer, 1);
clipboardExecutor = new KeyQueuedExecutorService<>(new ThreadPoolExecutor(
uuidKeyQueuedExecutorService = new KeyQueuedExecutorService<>(new ThreadPoolExecutor(
1,
Settings.settings().QUEUE.PARALLEL_THREADS,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(),
new ThreadFactoryBuilder().setNameFormat("fawe-clipboard-%d").build()
new UUIDKeyQueuedThreadFactory()
));
}
@ -362,6 +361,18 @@ public class Fawe {
Settings.settings().QUEUE.PARALLEL_THREADS
);
}
if (Settings.settings().HISTORY.DELETE_DISK_ON_LOGOUT && Settings.settings().HISTORY.USE_DATABASE) {
LOGGER.warn("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
LOGGER.warn("!!! !!!");
LOGGER.warn("!!! Using history database whilst deleting disk history! !!!");
LOGGER.warn("!!! You will not be able to rollback edits after a user logs !!!");
LOGGER.warn("!!! out, recommended to disable delete-disk-on-logout if you !!!");
LOGGER.warn("!!! you want to have full history rollback functionality. !!!");
LOGGER.warn("!!! Disable use-database if you do not need to have rollback !!!");
LOGGER.warn("!!! functionality and wish to disable this warning. !!!");
LOGGER.warn("!!! !!!");
LOGGER.warn("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
try {
byte[] in = new byte[0];
byte[] compressed = LZ4Factory.fastestJavaInstance().fastCompressor().compress(in);
@ -448,9 +459,58 @@ public class Fawe {
*
* @return Executor used for clipboard IO if clipboard on disk is enabled or null
* @since 2.6.2
* @deprecated Use any of {@link Fawe#submitUUIDKeyQueuedTask(UUID, Runnable)},
* {@link Fawe#submitUUIDKeyQueuedTask(UUID, Runnable, Object)}, {@link Fawe#submitUUIDKeyQueuedTask(UUID, Callable)}
* to ensure if a thread is already a UUID-queued thread, the task is immediately run
*/
@Deprecated(forRemoval = true, since = "2.12.1")
public KeyQueuedExecutorService<UUID> getClipboardExecutor() {
return this.clipboardExecutor;
return this.uuidKeyQueuedExecutorService;
}
/**
* Submit a task to the UUID key-queued executor
*
* @return Future representing the tank
* @since 2.12.1
*/
public Future<?> submitUUIDKeyQueuedTask(UUID uuid, Runnable runnable) {
if (Thread.currentThread() instanceof UUIDKeyQueuedThreadFactory.UUIDKeyQueuedThread) {
runnable.run();
return CompletableFuture.completedFuture(null);
}
return this.uuidKeyQueuedExecutorService.submit(uuid, runnable);
}
/**
* Submit a task to the UUID key-queued executor
*
* @return Future representing the tank
* @since 2.12.1
*/
public <T> Future<T> submitUUIDKeyQueuedTask(UUID uuid, Runnable runnable, T result) {
if (Thread.currentThread() instanceof UUIDKeyQueuedThreadFactory.UUIDKeyQueuedThread) {
runnable.run();
return CompletableFuture.completedFuture(result);
}
return this.uuidKeyQueuedExecutorService.submit(uuid, runnable, result);
}
/**
* Submit a task to the UUID key-queued executor
*
* @return Future representing the tank
* @since 2.12.1
*/
public <T> Future<T> submitUUIDKeyQueuedTask(UUID uuid, Callable<T> callable) {
if (Thread.currentThread() instanceof UUIDKeyQueuedThreadFactory.UUIDKeyQueuedThread) {
try {
return CompletableFuture.completedFuture(callable.call());
} catch (Throwable t) {
return CompletableFuture.failedFuture(t);
}
}
return this.uuidKeyQueuedExecutorService.submit(uuid, callable);
}
}

View File

@ -116,7 +116,10 @@ public class FaweAPI {
* @param file the file to load
* @return a clipboard containing the schematic
* @see ClipboardFormat
* @deprecated Opens streams that are not then closed. Use {@link ClipboardFormats#findByFile(File)} and its relevant
* methods to allow closing created streams/closing the reader (which will close the stream(s))
*/
@Deprecated(forRemoval = true, since = "2.11.1")
public static Clipboard load(File file) throws IOException {
return ClipboardFormats.findByFile(file).load(file);
}
@ -339,11 +342,11 @@ public class FaweAPI {
final BlockVector3 bot = selection.getMinimumPoint();
final BlockVector3 top = selection.getMaximumPoint();
final int minX = bot.getBlockX() >> 4;
final int minZ = bot.getBlockZ() >> 4;
final int minX = bot.x() >> 4;
final int minZ = bot.z() >> 4;
final int maxX = top.getBlockX() >> 4;
final int maxZ = top.getBlockZ() >> 4;
final int maxX = top.x() >> 4;
final int maxZ = top.z() >> 4;
int count = 0;

View File

@ -18,6 +18,7 @@ import com.fastasyncworldedit.core.util.collection.CleanableThreadLocal;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.sk89q.jnbt.ByteArrayTag;
import com.sk89q.jnbt.ByteTag;
import com.sk89q.jnbt.CompoundTag;
@ -48,7 +49,6 @@ import java.util.Map.Entry;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@ -60,16 +60,17 @@ import java.util.function.Supplier;
import static com.google.common.base.Preconditions.checkNotNull;
public enum FaweCache implements Trimable {
/**
* @deprecated Use {@link #INSTANCE} to get an instance.
*/
@Deprecated(forRemoval = true, since = "2.0.0")
IMP,
/**
* @since 2.0.0
*/
INSTANCE;
/**
* @deprecated Use {@link #INSTANCE} to get an instance.
*/
@Deprecated(forRemoval = true, since = "2.0.0")
public static final FaweCache IMP = INSTANCE;
private static final Logger LOGGER = LogManagerCompat.getLogger();
public final int BLOCKS_PER_LAYER = 4096;
@ -191,17 +192,22 @@ public enum FaweCache implements Trimable {
Type.OUTSIDE_REGION
);
public static final FaweException MAX_CHECKS = new FaweException(
Caption.of("fawe.cancel.reason.max" + ".checks"),
Caption.of("fawe.cancel.reason.max.checks"),
Type.MAX_CHECKS,
true
);
public static final FaweException MAX_FAILS = new FaweException(
Caption.of("fawe.cancel.reason.max.fails"),
Type.MAX_CHECKS,
true
);
public static final FaweException MAX_CHANGES = new FaweException(
Caption.of("fawe.cancel.reason.max" + ".changes"),
Caption.of("fawe.cancel.reason.max.changes"),
Type.MAX_CHANGES,
false
);
public static final FaweException LOW_MEMORY = new FaweException(
Caption.of("fawe.cancel.reason.low" + ".memory"),
Caption.of("fawe.cancel.reason.low.memory"),
Type.LOW_MEMORY,
false
);
@ -531,7 +537,7 @@ public enum FaweCache implements Trimable {
}
public CompoundTag asTag(Map<String, Object> value) {
HashMap<String, Tag> map = new HashMap<>();
HashMap<String, Tag<?, ?>> map = new HashMap<>();
for (Map.Entry<String, Object> entry : value.entrySet()) {
Object child = entry.getValue();
Tag tag = asTag(child);
@ -611,12 +617,38 @@ public enum FaweCache implements Trimable {
/*
Thread stuff
*/
/**
* Create a new blocking executor with default name and FaweCache logger
*
* @return new blocking executor
*/
public ThreadPoolExecutor newBlockingExecutor() {
return newBlockingExecutor("FAWE Blocking Executor - %d");
}
/**
* Create a new blocking executor with specified name and FaweCache logger
*
* @return new blocking executor
* @since 2.9.0
*/
public ThreadPoolExecutor newBlockingExecutor(String name) {
return newBlockingExecutor(name, LOGGER);
}
/**
* Create a new blocking executor with specified name and logger
*
* @return new blocking executor
* @since 2.9.0
*/
public ThreadPoolExecutor newBlockingExecutor(String name, Logger logger) {
int nThreads = Settings.settings().QUEUE.PARALLEL_THREADS;
ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(nThreads, true);
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS, queue,
Executors.defaultThreadFactory(),
new ThreadFactoryBuilder().setNameFormat(name).build(),
new ThreadPoolExecutor.CallerRunsPolicy()
) {
@ -651,10 +683,10 @@ public enum FaweCache implements Trimable {
int hash = throwable.getMessage() != null ? throwable.getMessage().hashCode() : 0;
if (hash != lastException) {
lastException = hash;
LOGGER.catching(throwable);
logger.catching(throwable);
count = 0;
} else if (count < Settings.settings().QUEUE.PARALLEL_THREADS) {
LOGGER.warn(throwable.getMessage());
logger.warn(throwable.getMessage());
count++;
}
}
@ -664,10 +696,10 @@ public enum FaweCache implements Trimable {
private void handleFaweException(FaweException e) {
FaweException.Type type = e.getType();
if (e.getType() == FaweException.Type.OTHER) {
LOGGER.catching(e);
logger.catching(e);
} else if (!faweExceptionReasonsUsed[type.ordinal()]) {
faweExceptionReasonsUsed[type.ordinal()] = true;
LOGGER.warn("FaweException: " + e.getMessage());
logger.warn("FaweException: " + e.getMessage());
}
}
};

View File

@ -50,9 +50,9 @@ public class BlendBall implements Brush {
final int outsetSize = (int) (size + 1);
double brushSizeSquared = size * size;
int tx = position.getBlockX();
int ty = position.getBlockY();
int tz = position.getBlockZ();
int tx = position.x();
int ty = position.y();
int tz = position.z();
int[] frequency = new int[BlockTypes.size()];

View File

@ -81,9 +81,9 @@ public class CatenaryBrush implements Brush, ResettableTool {
return pos1.add(pos2).divide(2).toBlockPoint();
}
double curveLen = pos1.distance(pos2) * lenPercent;
double dy = pos2.getY() - pos1.getY();
double dx = pos2.getX() - pos1.getX();
double dz = pos2.getZ() - pos1.getZ();
double dy = pos2.y() - pos1.y();
double dx = pos2.x() - pos1.x();
double dz = pos2.z() - pos1.z();
double dh = Math.sqrt(dx * dx + dz * dz);
double g = Math.sqrt(curveLen * curveLen - dy * dy) / 2;
double a = 0.00001;

View File

@ -54,9 +54,9 @@ public class CommandBrush implements Brush {
position.subtract(radius, radius, radius),
position.add(radius, radius, radius)
);
String replaced = command.replace("{x}", Integer.toString(position.getBlockX()))
.replace("{y}", Integer.toString(position.getBlockY()))
.replace("{z}", Integer.toString(position.getBlockZ()))
String replaced = command.replace("{x}", Integer.toString(position.x()))
.replace("{y}", Integer.toString(position.y()))
.replace("{z}", Integer.toString(position.z()))
.replace("{world}", editSession.getWorld().getName())
.replace("{size}", Integer.toString(radius));

View File

@ -65,11 +65,11 @@ public class CopyPastaBrush implements Brush, ResettableTool {
mask = Masks.alwaysTrue();
}
final ResizableClipboardBuilder builder = new ResizableClipboardBuilder(editSession.getWorld());
final int minY = position.getBlockY();
final int minY = position.y();
mask = new AbstractDelegateMask(mask) {
@Override
public boolean test(BlockVector3 vector) {
if (super.test(vector) && vector.getBlockY() >= minY) {
if (super.test(vector) && vector.y() >= minY) {
BaseBlock block = editSession.getFullBlock(vector);
if (!block.getBlockType().getMaterial().isAir()) {
builder.add(vector, BlockTypes.AIR.getDefaultState().toBaseBlock(), block);
@ -91,7 +91,7 @@ public class CopyPastaBrush implements Brush, ResettableTool {
newClipboard.setOrigin(position);
ClipboardHolder holder = new ClipboardHolder(newClipboard);
session.setClipboard(holder);
int blocks = builder.size();
long blocks = builder.longSize();
player.print(Caption.of("fawe.worldedit.copy.command.copy", blocks));
} else {
AffineTransform transform = null;

View File

@ -63,15 +63,15 @@ public class ErodeBrush implements Brush {
Clipboard buffer1 = new CPUOptimizedClipboard(region);
Clipboard buffer2 = new CPUOptimizedClipboard(region);
final int bx = target.getBlockX();
final int by = target.getBlockY();
final int bz = target.getBlockZ();
final int bx = target.x();
final int by = target.y();
final int bz = target.z();
for (int x = -brushSize, relx = 0; x <= brushSize; x++, relx++) {
for (int x = -brushSize, relx = 0; x <= brushSize && relx < buffer1.getWidth(); x++, relx++) {
int x0 = x + bx;
for (int y = -brushSize, rely = 0; y <= brushSize; y++, rely++) {
for (int y = -brushSize, rely = 0; y <= brushSize && rely < buffer1.getHeight(); y++, rely++) {
int y0 = y + by;
for (int z = -brushSize, relz = 0; z <= brushSize; z++, relz++) {
for (int z = -brushSize, relz = 0; z <= brushSize && relz < buffer1.getLength(); z++, relz++) {
int z0 = z + bz;
BlockState state = es.getBlock(x0, y0, z0);
buffer1.setBlock(relx, rely, relz, state);
@ -106,7 +106,7 @@ public class ErodeBrush implements Brush {
for (BlockVector3 pos : finalBuffer) {
BlockState block = pos.getBlock(finalBuffer);
es.setBlock(pos.getX() + bx - brushSize, pos.getY() + by - brushSize, pos.getZ() + bz - brushSize, block);
es.setBlock(pos.x() + bx - brushSize, pos.y() + by - brushSize, pos.z() + bz - brushSize, block);
}
}
@ -115,11 +115,11 @@ public class ErodeBrush implements Brush {
Clipboard current, Clipboard target
) {
int[] frequency = null;
for (int x = -brushSize, relx = 0; x <= brushSize; x++, relx++) {
for (int x = -brushSize, relx = 0; x <= brushSize && relx < target.getWidth(); x++, relx++) {
int x2 = x * x;
for (int z = -brushSize, relz = 0; z <= brushSize; z++, relz++) {
for (int z = -brushSize, relz = 0; z <= brushSize && relz < target.getLength(); z++, relz++) {
int x2y2 = x2 + z * z;
for (int y = -brushSize, rely = 0; y <= brushSize; y++, rely++) {
for (int y = -brushSize, rely = 0; y <= brushSize && rely < target.getHeight(); y++, rely++) {
int cube = x2y2 + y * y;
target.setBlock(relx, rely, relz, current.getBlock(relx, rely, relz));
if (cube >= brushSizeSquared) {
@ -139,9 +139,9 @@ public class ErodeBrush implements Brush {
int highest = 1;
for (BlockVector3 offs : FACES_TO_CHECK) {
BaseBlock next = current.getFullBlock(
relx + offs.getBlockX(),
rely + offs.getBlockY(),
relz + offs.getBlockZ()
relx + offs.x(),
rely + offs.y(),
relz + offs.z()
);
if (!next.getBlockType().getMaterial().isMovementBlocker()) {
continue;
@ -166,11 +166,11 @@ public class ErodeBrush implements Brush {
Clipboard current, Clipboard target
) {
int[] frequency = null;
for (int x = -brushSize, relx = 0; x <= brushSize; x++, relx++) {
for (int x = -brushSize, relx = 0; x <= brushSize && relx < target.getWidth(); x++, relx++) {
int x2 = x * x;
for (int z = -brushSize, relz = 0; z <= brushSize; z++, relz++) {
for (int z = -brushSize, relz = 0; z <= brushSize && relz < target.getLength(); z++, relz++) {
int x2y2 = x2 + z * z;
for (int y = -brushSize, rely = 0; y <= brushSize; y++, rely++) {
for (int y = -brushSize, rely = 0; y <= brushSize && rely < target.getHeight(); y++, rely++) {
int cube = x2y2 + y * y;
target.setBlock(relx, rely, relz, current.getBlock(relx, rely, relz));
if (cube >= brushSizeSquared) {
@ -190,9 +190,9 @@ public class ErodeBrush implements Brush {
int total = 0;
for (BlockVector3 offs : FACES_TO_CHECK) {
BaseBlock next = current.getFullBlock(
relx + offs.getBlockX(),
rely + offs.getBlockY(),
relz + offs.getBlockZ()
relx + offs.x(),
rely + offs.y(),
relz + offs.z()
);
if (next.getMaterial().isMovementBlocker()) {
continue;

View File

@ -12,9 +12,9 @@ public class FallingSphere implements Brush {
@Override
public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws
MaxChangedBlocksException {
int px = position.getBlockX();
int py = position.getBlockY();
int pz = position.getBlockZ();
int px = position.x();
int py = position.y();
int pz = position.z();
int maxY = editSession.getMaxY();
int minY = editSession.getMinY();

View File

@ -53,7 +53,7 @@ public class HeightBrush implements Brush {
try {
heightMap = ScalableHeightMap.fromPNG(stream);
} catch (IOException e) {
throw new FaweException(Caption.of("fawe.worldedit.brush.brush.height.invalid"));
throw new FaweException(Caption.of("fawe.worldedit.brush.brush.height.invalid", e.getMessage()));
}
} else if (clipboard != null) {
heightMap = ScalableHeightMap.fromClipboard(clipboard, minY, maxY);

View File

@ -14,7 +14,6 @@ import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.util.Location;
@ -25,7 +24,6 @@ import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockState;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.util.Iterator;
@ -74,10 +72,15 @@ public class InspectBrush extends BrushTool {
return false;
}
try {
BlockVector3 target = getTarget(player, rightClick).toBlockPoint();
final int x = target.getBlockX();
final int y = target.getBlockY();
final int z = target.getBlockZ();
Vector3 targetVector = getTarget(player, rightClick);
if (targetVector == null) {
player.print(Caption.of("worldedit.tool.no-block"));
return true;
}
BlockVector3 target = targetVector.toBlockPoint();
final int x = target.x();
final int y = target.y();
final int z = target.z();
World world = player.getWorld();
RollbackDatabase db = DBHandler.dbHandler().getDatabase(world);
int count = 0;

View File

@ -24,7 +24,8 @@ public record PopulateSchem(Mask mask, List<ClipboardHolder> clipboards, int rar
CuboidRegion cuboid = new CuboidRegion(
editSession.getWorld(),
position.subtract(size1, size1, size1),
position.add(size1, size1, size1)
position.add(size1, size1, size1),
true
);
try {
editSession.addSchems(cuboid, mask, clipboards, rarity, randomRotate);

View File

@ -35,7 +35,7 @@ public record RecurseBrush(boolean dfs) implements Brush {
DFSRecursiveVisitor visitor = new DFSRecursiveVisitor(mask, replace, Integer.MAX_VALUE, Integer.MAX_VALUE) {
@Override
public boolean isVisitable(BlockVector3 from, BlockVector3 to) {
int y = to.getBlockY();
int y = to.y();
return y < maxY && radMask.test(to) && super.isVisitable(from, to);
}
};
@ -45,7 +45,7 @@ public record RecurseBrush(boolean dfs) implements Brush {
RecursiveVisitor visitor = new RecursiveVisitor(mask, replace, radius, editSession.getMinY(), editSession.getMaxY()) {
@Override
public boolean isVisitable(BlockVector3 from, BlockVector3 to) {
int y = to.getBlockY();
int y = to.y();
return y < maxY && super.isVisitable(from, to);
}
};

View File

@ -19,15 +19,15 @@ public record RockBrush(double amplitude, double frequency, Vector3 radius) impl
double seedY = ThreadLocalRandom.current().nextDouble();
double seedZ = ThreadLocalRandom.current().nextDouble();
int px = position.getBlockX();
int py = position.getBlockY();
int pz = position.getBlockZ();
int px = position.x();
int py = position.y();
int pz = position.z();
double distort = this.frequency / size;
double modX = 1D / radius.getX();
double modY = 1D / radius.getY();
double modZ = 1D / radius.getZ();
double modX = 1D / radius.x();
double modY = 1D / radius.y();
double modZ = 1D / radius.z();
int radiusSqr = (int) (size * size);
int sizeInt = (int) size * 2;

View File

@ -5,6 +5,7 @@ import com.fastasyncworldedit.core.function.mask.RadiusMask;
import com.fastasyncworldedit.core.function.mask.SurfaceMask;
import com.fastasyncworldedit.core.math.BlockVectorSet;
import com.fastasyncworldedit.core.math.LocalBlockVectorSet;
import com.fastasyncworldedit.core.util.collection.BlockVector3Set;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.command.tool.brush.Brush;
@ -64,16 +65,17 @@ public class ScatterBrush implements Brush {
length = 1;
visited.add(position);
}
LocalBlockVectorSet placed = new LocalBlockVectorSet();
placed.setOffset(position.getX(), position.getZ());
BlockVector3 patternSize = pattern.size();
BlockVector3Set placed = BlockVector3Set.getAppropriateVectorSet(patternSize.add(distance, distance, distance));
placed.setOffset(position.x(), position.y(), position.z());
int maxFails = 1000;
for (int i = 0; i < count; i++) {
int index = ThreadLocalRandom.current().nextInt(length);
BlockVector3 pos = visited.get(index);
if (pos != null && canApply(pos)) {
int x = pos.getBlockX();
int y = pos.getBlockY();
int z = pos.getBlockZ();
int x = pos.x();
int y = pos.y();
int z = pos.z();
if (placed.containsRadius(x, y, z, distance)) {
if (maxFails-- <= 0) {
break;
@ -88,7 +90,20 @@ public class ScatterBrush implements Brush {
finish(editSession, placed, position, pattern, size);
}
/**
* @deprecated Use {@link ScatterBrush#finish(EditSession, BlockVector3Set, BlockVector3, Pattern, double)}
*/
@Deprecated(forRemoval = true, since = "2.9.2")
public void finish(EditSession editSession, LocalBlockVectorSet placed, BlockVector3 pos, Pattern pattern, double size) {
finish(editSession, (BlockVector3Set) placed, pos, pattern, size);
}
/**
* Complete the scatter brush process.
*
* @since 2.9.2
*/
public void finish(EditSession editSession, BlockVector3Set placed, BlockVector3 pos, Pattern pattern, double size) {
}
public boolean canApply(BlockVector3 pos) {
@ -99,8 +114,23 @@ public class ScatterBrush implements Brush {
return surface.direction(pt);
}
/**
* @deprecated Use {@link ScatterBrush#apply(EditSession, BlockVector3Set, BlockVector3, Pattern, double)}
*/
@Deprecated(forRemoval = true, since = "2.9.2")
public void apply(EditSession editSession, LocalBlockVectorSet placed, BlockVector3 pt, Pattern p, double size) throws
MaxChangedBlocksException {
apply(editSession, (BlockVector3Set) placed, pt, p, size);
}
/**
* Apply the scatter brush to a given position
*
* @since 2.9.2
*/
public void apply(EditSession editSession, BlockVector3Set placed, BlockVector3 pt, Pattern p, double size) throws
MaxChangedBlocksException {
editSession.setBlock(pt, p);
}

View File

@ -45,9 +45,9 @@ public class ScatterCommand extends ScatterBrush {
position.subtract(radius, radius, radius),
position.add(radius, radius, radius)
);
String replaced = command.replace("{x}", Integer.toString(position.getBlockX()))
.replace("{y}", Integer.toString(position.getBlockY()))
.replace("{z}", Integer.toString(position.getBlockZ()))
String replaced = command.replace("{x}", Integer.toString(position.x()))
.replace("{y}", Integer.toString(position.y()))
.replace("{z}", Integer.toString(position.z()))
.replace("{world}", editSession.getWorld().getName())
.replace("{size}", Integer.toString(radius));

View File

@ -16,9 +16,9 @@ public class ScatterOverlayBrush extends ScatterBrush {
@Override
public void apply(EditSession editSession, LocalBlockVectorSet placed, BlockVector3 pt, Pattern p, double size) throws
MaxChangedBlocksException {
final int x = pt.getBlockX();
final int y = pt.getBlockY();
final int z = pt.getBlockZ();
final int x = pt.x();
final int y = pt.y();
final int z = pt.z();
BlockVector3 dir = getDirection(pt);
if (dir == null) {
getDir:
@ -37,7 +37,7 @@ public class ScatterOverlayBrush extends ScatterBrush {
return;
}
}
editSession.setBlock(x + dir.getBlockX(), y + dir.getBlockY(), z + dir.getBlockZ(), p);
editSession.setBlock(x + dir.x(), y + dir.y(), z + dir.z(), p);
}
}

View File

@ -3,6 +3,7 @@ package com.fastasyncworldedit.core.command.tool.brush;
import com.fastasyncworldedit.core.function.mask.SurfaceMask;
import com.fastasyncworldedit.core.math.LocalBlockVectorSet;
import com.fastasyncworldedit.core.math.MutableBlockVector3;
import com.fastasyncworldedit.core.util.collection.BlockVector3Set;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.function.mask.Mask;
@ -24,7 +25,7 @@ public class ShatterBrush extends ScatterBrush {
@Override
public void apply(
final EditSession editSession,
final LocalBlockVectorSet placed,
final BlockVector3Set placed,
final BlockVector3 position,
Pattern p,
double size
@ -34,7 +35,7 @@ public class ShatterBrush extends ScatterBrush {
@Override
public void finish(
EditSession editSession,
LocalBlockVectorSet placed,
BlockVector3Set placed,
final BlockVector3 position,
Pattern pattern,
double size
@ -79,13 +80,13 @@ public class ShatterBrush extends ScatterBrush {
}
for (int i1 = 0; i1 < BreadthFirstSearch.DIAGONAL_DIRECTIONS.length; i1++) {
BlockVector3 direction = BreadthFirstSearch.DIAGONAL_DIRECTIONS[i1];
int x2 = x + direction.getBlockX();
int y2 = y + direction.getBlockY();
int z2 = z + direction.getBlockZ();
int x2 = x + direction.x();
int y2 = y + direction.y();
int z2 = z + direction.z();
// Check boundary
int dx = position.getBlockX() - x2;
int dy = position.getBlockY() - y2;
int dz = position.getBlockZ() - z2;
int dx = position.x() - x2;
int dy = position.y() - y2;
int dz = position.z() - z2;
int dSqr = (dx * dx) + (dy * dy) + (dz * dz);
if (dSqr <= radius2) {
BlockVector3 bv = mutable.setComponents(x2, y2, z2);

View File

@ -130,9 +130,9 @@ public class SplineBrush implements Brush, ResettableTool {
private Vector3 getCentroid(Collection<BlockVector3> points) {
MutableVector3 sum = new MutableVector3();
for (BlockVector3 p : points) {
sum.mutX(sum.getX() + p.getX());
sum.mutY(sum.getY() + p.getY());
sum.mutZ(sum.getZ() + p.getZ());
sum.mutX(sum.x() + p.x());
sum.mutY(sum.y() + p.y());
sum.mutZ(sum.z() + p.z());
}
return sum.multiply(1.0 / points.size());
}

View File

@ -38,16 +38,16 @@ public class SurfaceSpline implements Brush {
int minY = editSession.getMinY();
if (path.isEmpty() || !pos.equals(path.get(path.size() - 1))) {
int max = editSession.getNearestSurfaceTerrainBlock(
pos.getBlockX(),
pos.getBlockZ(),
pos.getBlockY(),
pos.x(),
pos.z(),
pos.y(),
minY,
maxY
);
if (max == -1) {
return;
}
path.add(BlockVector3.at(pos.getBlockX(), max, pos.getBlockZ()));
path.add(BlockVector3.at(pos.x(), max, pos.z()));
if (editSession.getActor() != null) {
editSession.getActor().print(Caption.of("fawe.worldedit.brush.spline.primary.2"));
}
@ -69,9 +69,9 @@ public class SurfaceSpline implements Brush {
LocalBlockVectorSet vset = new LocalBlockVectorSet();
for (double loop = 0; loop <= 1; loop += 1D / splinelength / quality) {
final Vector3 tipv = interpol.getPosition(loop);
final int tipx = MathMan.roundInt(tipv.getX());
final int tipz = (int) tipv.getZ();
int tipy = MathMan.roundInt(tipv.getY());
final int tipx = MathMan.roundInt(tipv.x());
final int tipz = (int) tipv.z();
int tipy = MathMan.roundInt(tipv.y());
tipy = editSession.getNearestSurfaceTerrainBlock(tipx, tipz, tipy, minY, maxY, Integer.MIN_VALUE, Integer.MAX_VALUE);
if (tipy == Integer.MIN_VALUE || tipy == Integer.MAX_VALUE) {
continue;
@ -88,15 +88,15 @@ public class SurfaceSpline implements Brush {
LocalBlockVectorSet newSet = new LocalBlockVectorSet();
final int ceilrad = (int) Math.ceil(radius);
for (BlockVector3 v : vset) {
final int tipx = v.getBlockX();
final int tipz = v.getBlockZ();
final int tipx = v.x();
final int tipz = v.z();
for (int loopx = tipx - ceilrad; loopx <= tipx + ceilrad; loopx++) {
for (int loopz = tipz - ceilrad; loopz <= tipz + ceilrad; loopz++) {
if (MathMan.hypot2(loopx - tipx, 0, loopz - tipz) <= radius2) {
int y = editSession.getNearestSurfaceTerrainBlock(
loopx,
loopz,
v.getBlockY(),
v.y(),
minY,
maxY,
Integer.MIN_VALUE,

View File

@ -51,6 +51,7 @@ public abstract class Scroll implements ScrollTool {
parserContext.setActor(player);
parserContext.setWorld(player.getWorld());
parserContext.setSession(session);
parserContext.setTryLegacy(player.getLimit().ALLOW_LEGACY);
switch (mode) {
case CLIPBOARD:
if (arguments.size() != 2) {

View File

@ -13,7 +13,7 @@ public class ScrollRange extends Scroll {
@Override
public boolean increment(Player player, int amount) {
int max = WorldEdit.getInstance().getConfiguration().maxBrushRadius;
int max = player.getLimit().MAX_BRUSH_RADIUS;
int newSize = MathMan.wrap(getTool().getRange() + amount, (int) (getTool().getSize() + 1), max);
getTool().setRange(newSize);
return true;

View File

@ -12,7 +12,7 @@ public class ScrollSize extends Scroll {
@Override
public boolean increment(Player player, int amount) {
int max = WorldEdit.getInstance().getConfiguration().maxRadius;
int max = player.getLimit().MAX_RADIUS;
double newSize = Math.max(0, Math.min(max == -1 ? 4095 : max, getTool().getSize() + amount));
getTool().setSize(newSize);
return true;

View File

@ -83,7 +83,7 @@ public class ClipboardSpline extends Spline {
Region region = clipboard.getRegion();
BlockVector3 origin = clipboard.getOrigin();
// center = region.getCenter().setY(origin.getY() - 1);
center = region.getCenter().withY(origin.getY() - 1).toBlockPoint();
center = region.getCenter().withY(origin.y() - 1).toBlockPoint();
this.centerOffset = center.subtract(center.round());
this.center = center.subtract(centerOffset);
this.transform = transform;
@ -108,15 +108,15 @@ public class ClipboardSpline extends Spline {
clipboardHolder.setTransform(transform);
BlockVector3 functionOffset = target.subtract(clipboard.getOrigin());
final int offX = functionOffset.getBlockX();
final int offY = functionOffset.getBlockY();
final int offZ = functionOffset.getBlockZ();
final int offX = functionOffset.x();
final int offY = functionOffset.y();
final int offZ = functionOffset.z();
Operation operation = clipboardHolder
.createPaste(editSession)
.to(target)
.ignoreAirBlocks(true)
.filter(v -> buffer.add(v.getBlockX() + offX, v.getBlockY() + offY, v.getBlockZ() + offZ))
.filter(v -> buffer.add(v.x() + offX, v.y() + offY, v.z() + offZ))
.build();
Operations.completeLegacy(operation);

View File

@ -121,7 +121,7 @@ public abstract class Spline {
* 2 dimensional "cross" product. cross2D(v1, v2) = |v1|*|v2|*sin(theta) or v1 X v2 taking Y to be 0
*/
private double cross2D(Vector2 v1, Vector2 v2) {
return v1.getX() * v2.getZ() - v2.getX() * v1.getZ();
return v1.x() * v2.z() - v2.x() * v1.z();
}
/**
@ -144,7 +144,7 @@ public abstract class Spline {
// Calculate rotation from spline
Vector3 deriv = interpolation.get1stDerivative(position);
Vector2 deriv2D = Vector2.at(deriv.getX(), deriv.getZ()).normalize();
Vector2 deriv2D = Vector2.at(deriv.x(), deriv.z()).normalize();
double angle = Math.toDegrees(
-Math.atan2(cross2D(direction, deriv2D), direction.dot(deriv2D))
);

View File

@ -79,13 +79,13 @@ public class SweepBrush implements Brush, ResettableTool {
Clipboard clipboard = holder.getClipboard();
BlockVector3 dimensions = clipboard.getDimensions();
double quality = Math.max(dimensions.getBlockX(), dimensions.getBlockZ());
double quality = Math.max(dimensions.x(), dimensions.z());
AffineTransform transform = new AffineTransform();
ClipboardSpline spline = new ClipboardSpline(editSession, holder, interpol, transform, nodes.size());
if (dimensions.getBlockX() > dimensions.getBlockZ()) {
if (dimensions.x() > dimensions.z()) {
spline.setDirection(Vector2.at(0, 1));
}

View File

@ -2,9 +2,11 @@ package com.fastasyncworldedit.core.configuration;
import com.fastasyncworldedit.core.configuration.file.YamlConfiguration;
import com.fastasyncworldedit.core.util.StringMan;
import com.sk89q.util.StringUtil;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nullable;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.PrintWriter;
@ -14,8 +16,11 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
@ -27,8 +32,16 @@ public class Config {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private final Map<String, Object> removedKeyVals = new HashMap<>();
@Nullable
private Map<String, Map.Entry<String, Object>> copyTo = new HashMap<>();
private boolean performCopyTo = false;
private List<String> existingMigrateNodes = null;
public Config() {
save(new PrintWriter(new ByteArrayOutputStream(0)), getClass(), this, 0);
// This is now definitely required as the save -> load -> save order means the @CopiedFrom annotated fields work
save(new PrintWriter(new ByteArrayOutputStream(0)), getClass(), this, 0, null);
performCopyTo = true;
}
/**
@ -43,7 +56,8 @@ public class Config {
try {
return (T) field.get(instance);
} catch (IllegalAccessException e) {
e.printStackTrace();
LOGGER.error("Failed to get config option: {}", key, e);
return null;
}
}
}
@ -53,11 +67,12 @@ public class Config {
/**
* Set the value of a specific node. Probably throws some error if you supply non existing keys or invalid values.
* This should only be called during loading of a config file
*
* @param key config node
* @param value value
*/
private void set(String key, Object value, Class<?> root) {
private void setLoadedNode(String key, Object value, Class<?> root) {
String[] split = key.split("\\.");
Object instance = getInstance(split, root);
if (instance != null) {
@ -67,6 +82,20 @@ public class Config {
if (field.getAnnotation(Final.class) != null) {
return;
}
if (copyTo != null) {
copyTo.remove(key); // Remove if the config field is already written
final Object finalValue = value;
copyTo.replaceAll((copyToNode, entry) -> {
if (!key.equals(entry.getKey())) {
return entry;
}
return new AbstractMap.SimpleEntry<>(key, finalValue);
});
}
Migrate migrate = field.getAnnotation(Migrate.class);
if (migrate != null) {
existingMigrateNodes.add(migrate.value());
}
if (field.getType() == String.class && !(value instanceof String)) {
value = value + "";
}
@ -74,25 +103,38 @@ public class Config {
field.set(instance, value);
return;
} catch (Throwable e) {
e.printStackTrace();
LOGGER.error("Failed to set config option: {}", key);
}
}
}
LOGGER.error("Failed to set config option: {}: {} | {} | {}.yml", key, value, instance, root.getSimpleName());
removedKeyVals.put(key, value);
LOGGER.warn(
"Failed to set config option: {}: {} | {} | {}.yml. This is likely because it was removed or was set with an " +
"invalid value.",
key,
value,
instance,
root.getSimpleName()
);
}
public boolean load(File file) {
if (!file.exists()) {
return false;
}
existingMigrateNodes = new ArrayList<>();
YamlConfiguration yml = YamlConfiguration.loadConfiguration(file);
for (String key : yml.getKeys(true)) {
Object value = yml.get(key);
if (value instanceof MemorySection) {
continue;
}
set(key, value, getClass());
setLoadedNode(key, value, getClass());
}
for (String node : existingMigrateNodes) {
removedKeyVals.remove(node);
}
existingMigrateNodes = null;
return true;
}
@ -110,10 +152,10 @@ public class Config {
}
PrintWriter writer = new PrintWriter(file);
Object instance = this;
save(writer, getClass(), instance, 0);
save(writer, getClass(), instance, 0, null);
writer.close();
} catch (Throwable e) {
e.printStackTrace();
LOGGER.error("Failed to save config file: {}", file, e);
}
}
@ -166,6 +208,32 @@ public class Config {
}
/**
* Indicates that a field should be migrated from a node that is deleted
*
* @since 2.10.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Migrate {
String value();
}
/**
* Indicates that a field's default value should match another input if the config is otherwise already generated
*
* @since 2.11.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface CopiedFrom {
String value();
}
@Ignore // This is not part of the config
public static class ConfigBlock<T> {
@ -218,11 +286,10 @@ public class Config {
return value != null ? value.toString() : "null";
}
private void save(PrintWriter writer, Class<?> clazz, final Object instance, int indent) {
private void save(PrintWriter writer, Class<?> clazz, final Object instance, int indent, String parentNode) {
try {
String CTRF = System.lineSeparator();
String spacing = StringMan.repeat(" ", indent);
HashMap<Class<?>, Object> instances = new HashMap<>();
for (Field field : clazz.getFields()) {
if (field.getAnnotation(Ignore.class) != null) {
continue;
@ -239,31 +306,26 @@ public class Config {
}
if (current == ConfigBlock.class) {
current = (Class<?>) ((ParameterizedType) (field.getGenericType())).getActualTypeArguments()[0];
comment = current.getAnnotation(Comment.class);
if (comment != null) {
for (String commentLine : comment.value()) {
writer.write(spacing + "# " + commentLine + CTRF);
}
}
BlockName blockNames = current.getAnnotation(BlockName.class);
if (blockNames != null) {
writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF);
ConfigBlock configBlock = (ConfigBlock) field.get(instance);
if (configBlock == null || configBlock.getInstances().isEmpty()) {
configBlock = new ConfigBlock();
field.set(instance, configBlock);
for (String blockName : blockNames.value()) {
configBlock.put(blockName, current.getDeclaredConstructor().newInstance());
}
}
// Save each instance
for (Map.Entry<String, Object> entry : ((Map<String, Object>) configBlock.getRaw()).entrySet()) {
String key = entry.getKey();
writer.write(spacing + " " + toNodeName(key) + ":" + CTRF);
save(writer, current, entry.getValue(), indent + 4);
}
}
handleConfigBlockSave(writer, instance, indent, field, spacing, CTRF, current, parentNode);
continue;
} else if (!removedKeyVals.isEmpty()) {
Migrate migrate = field.getAnnotation(Migrate.class);
Object value;
if (migrate != null && (value = removedKeyVals.remove(migrate.value())) != null) {
field.set(instance, value);
}
}
CopiedFrom copiedFrom;
if (copyTo != null && (copiedFrom = field.getAnnotation(CopiedFrom.class)) != null) {
String node = toNodeName(field.getName());
node = parentNode == null ? node : parentNode + "." + node;
Map.Entry<String, Object> entry = copyTo.remove(node);
Object copiedVal;
if (entry == null) {
copyTo.put(node, new AbstractMap.SimpleEntry<>(copiedFrom.value(), null));
} else if ((copiedVal = entry.getValue()) != null) {
field.set(instance, copiedVal);
}
}
Create create = field.getAnnotation(Create.class);
if (create != null) {
@ -278,12 +340,12 @@ public class Config {
writer.write(spacing + "# " + commentLine + CTRF);
}
}
writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF);
String node = toNodeName(current.getSimpleName());
writer.write(spacing + node + ":" + CTRF);
if (value == null) {
field.set(instance, value = current.getDeclaredConstructor().newInstance());
instances.put(current, value);
}
save(writer, current, value, indent + 2);
save(writer, current, value, indent + 2, parentNode == null ? node : parentNode + "." + node);
} else {
writer.write(spacing + toNodeName(field.getName() + ": ") + toYamlString(
field.get(instance),
@ -292,7 +354,48 @@ public class Config {
}
}
} catch (Throwable e) {
e.printStackTrace();
LOGGER.error("Failed to save config file", e);
}
if (parentNode == null && performCopyTo) {
performCopyTo = false;
copyTo = null;
}
}
private <T> void handleConfigBlockSave(
PrintWriter writer,
Object instance,
int indent,
Field field,
String spacing,
String CTRF,
Class<T> current,
String parentNode
) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
Comment comment = current.getAnnotation(Comment.class);
if (comment != null) {
for (String commentLine : comment.value()) {
writer.write(spacing + "# " + commentLine + CTRF);
}
}
BlockName blockNames = current.getAnnotation(BlockName.class);
if (blockNames != null) {
String node = toNodeName(current.getSimpleName());
writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF);
ConfigBlock<T> configBlock = (ConfigBlock<T>) field.get(instance);
if (configBlock == null || configBlock.getInstances().isEmpty()) {
configBlock = new ConfigBlock<>();
field.set(instance, configBlock);
for (String blockName : blockNames.value()) {
configBlock.put(blockName, current.getDeclaredConstructor().newInstance());
}
}
// Save each instance
for (Map.Entry<String, T> entry : configBlock.getRaw().entrySet()) {
String key = entry.getKey();
writer.write(spacing + " " + toNodeName(key) + ":" + CTRF);
save(writer, current, entry.getValue(), indent + 4, parentNode == null ? node : parentNode + "." + node);
}
}
}
@ -311,7 +414,7 @@ public class Config {
return field;
} catch (Throwable ignored) {
LOGGER.warn(
"Invalid config field: {} for {}",
"Invalid config field: {} for {}. It is possible this is because it has been removed.",
StringMan.join(split, "."),
toNodeName(instance.getClass().getSimpleName())
);
@ -379,7 +482,7 @@ public class Config {
return null;
}
} catch (Throwable e) {
e.printStackTrace();
LOGGER.error("Failed retrieving instance for config node: {}", StringUtil.joinString(split, "."), e);
}
return null;
}

View File

@ -2,6 +2,7 @@ package com.fastasyncworldedit.core.configuration;
import com.fastasyncworldedit.core.limit.FaweLimit;
import com.fastasyncworldedit.core.limit.PropertyRemap;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.world.block.BlockTypesCache;
@ -19,14 +20,14 @@ import java.util.stream.Stream;
public class Settings extends Config {
@Ignore
static Settings INSTANCE = new Settings();
/**
* @deprecated Use {@link #settings()} instead to get an instance.
*/
@Ignore
@Deprecated(forRemoval = true, since = "2.0.0")
public static final Settings IMP = new Settings();
@Ignore
static Settings INSTANCE = new Settings();
public static final Settings IMP = INSTANCE;
@Ignore
public boolean PROTOCOL_SUPPORT_FIX = false;
@Comment("These first 6 aren't configurable") // This is a comment
@ -79,6 +80,8 @@ public class Settings extends Config {
@Create
public REGION_RESTRICTIONS_OPTIONS REGION_RESTRICTIONS_OPTIONS;
@Create
public GENERAL GENERAL;
@Create
public ConfigBlock<LIMITS> LIMITS;
private Settings() {
@ -102,7 +105,7 @@ public class Settings extends Config {
public FaweLimit getLimit(Actor actor) {
FaweLimit limit;
if (actor.hasPermission("fawe.bypass") || actor.hasPermission("fawe.limit.unlimited")) {
if (actor.hasPermission("fawe.limit.unlimited")) {
return FaweLimit.MAX.copy();
}
limit = new FaweLimit();
@ -120,31 +123,55 @@ public class Settings extends Config {
limit.MAX_ACTIONS,
newLimit.MAX_ACTIONS != -1 ? newLimit.MAX_ACTIONS : Integer.MAX_VALUE
);
limit.MAX_CHANGES = Math.max(
limit.MAX_CHANGES,
limit.MAX_CHANGES.set(Math.max(
limit.MAX_CHANGES.get(),
newLimit.MAX_CHANGES != -1 ? newLimit.MAX_CHANGES : Long.MAX_VALUE
);
limit.MAX_BLOCKSTATES = Math.max(
limit.MAX_BLOCKSTATES,
));
limit.MAX_BLOCKSTATES.set(Math.max(
limit.MAX_BLOCKSTATES.get(),
newLimit.MAX_BLOCKSTATES != -1 ? newLimit.MAX_BLOCKSTATES : Integer.MAX_VALUE
);
limit.MAX_CHECKS = Math.max(
limit.MAX_CHECKS,
));
limit.MAX_CHECKS.set(Math.max(
limit.MAX_CHECKS.get(),
newLimit.MAX_CHECKS != -1 ? newLimit.MAX_CHECKS : Long.MAX_VALUE
);
limit.MAX_ENTITIES = Math.max(
limit.MAX_ENTITIES,
));
limit.MAX_ENTITIES.set(Math.max(
limit.MAX_ENTITIES.get(),
newLimit.MAX_ENTITIES != -1 ? newLimit.MAX_ENTITIES : Integer.MAX_VALUE
);
limit.MAX_FAILS = Math.max(limit.MAX_FAILS, newLimit.MAX_FAILS != -1 ? newLimit.MAX_FAILS : Integer.MAX_VALUE);
limit.MAX_ITERATIONS = Math.max(
limit.MAX_ITERATIONS,
));
limit.MAX_FAILS.set(Math.max(
limit.MAX_FAILS.get(),
newLimit.MAX_FAILS != -1 ? newLimit.MAX_FAILS : Integer.MAX_VALUE
));
limit.MAX_ITERATIONS.set(Math.max(
limit.MAX_ITERATIONS.get(),
newLimit.MAX_ITERATIONS != -1 ? newLimit.MAX_ITERATIONS : Integer.MAX_VALUE
));
limit.MAX_RADIUS = Math.max(limit.MAX_RADIUS, newLimit.MAX_RADIUS != -1 ? newLimit.MAX_RADIUS : Integer.MAX_VALUE);
limit.MAX_SUPER_PICKAXE_SIZE = Math.max(
limit.MAX_SUPER_PICKAXE_SIZE,
newLimit.MAX_SUPER_PICKAXE_SIZE != -1 ? newLimit.MAX_SUPER_PICKAXE_SIZE : Integer.MAX_VALUE
);
limit.MAX_BRUSH_RADIUS = Math.max(
limit.MAX_BRUSH_RADIUS,
newLimit.MAX_BRUSH_RADIUS != -1 ? newLimit.MAX_BRUSH_RADIUS : Integer.MAX_VALUE
);
limit.MAX_BUTCHER_RADIUS = Math.max(
limit.MAX_BUTCHER_RADIUS,
newLimit.MAX_BUTCHER_RADIUS != -1 ? newLimit.MAX_BUTCHER_RADIUS : Integer.MAX_VALUE
);
limit.MAX_HISTORY = Math.max(
limit.MAX_HISTORY,
newLimit.MAX_HISTORY_MB != -1 ? newLimit.MAX_HISTORY_MB : Integer.MAX_VALUE
);
limit.SCHEM_FILE_NUM_LIMIT = Math.max(
limit.SCHEM_FILE_NUM_LIMIT,
newLimit.SCHEM_FILE_NUM_LIMIT != -1 ? newLimit.SCHEM_FILE_NUM_LIMIT : Integer.MAX_VALUE
);
limit.SCHEM_FILE_SIZE_LIMIT = Math.max(
limit.SCHEM_FILE_SIZE_LIMIT,
newLimit.SCHEM_FILE_SIZE_LIMIT != -1 ? newLimit.SCHEM_FILE_SIZE_LIMIT : Integer.MAX_VALUE
);
limit.MAX_EXPRESSION_MS = Math.max(
limit.MAX_EXPRESSION_MS,
newLimit.MAX_EXPRESSION_MS != -1 ? newLimit.MAX_EXPRESSION_MS : Integer.MAX_VALUE
@ -166,6 +193,7 @@ public class Settings extends Config {
}
}
limit.UNIVERSAL_DISALLOWED_BLOCKS &= newLimit.UNIVERSAL_DISALLOWED_BLOCKS;
limit.ALLOW_LEGACY &= newLimit.ALLOW_LEGACY;
if (limit.DISALLOWED_BLOCKS == null) {
limit.DISALLOWED_BLOCKS = newLimit.DISALLOWED_BLOCKS.isEmpty() ? Collections.emptySet() : new HashSet<>(
@ -342,6 +370,14 @@ public class Settings extends Config {
public int MAX_ITERATIONS = 1000;
@Comment("Max allowed entities (e.g. cows)")
public int MAX_ENTITIES = 1337;
@Comment("Max allowed radius (e.g. for //sphere)")
public int MAX_RADIUS = LocalConfiguration.MAX_RADIUS;
@Comment("Max allowed superpickaxe size")
public int MAX_SUPER_PICKAXE_SIZE = LocalConfiguration.MAX_SUPER_RADIUS;
@Comment("Max allowed brush radius")
public int MAX_BRUSH_RADIUS = LocalConfiguration.MAX_BRUSH_RADIUS;
@Comment("Max allowed butcher radius")
public int MAX_BUTCHER_RADIUS = LocalConfiguration.MAX_BUTCHER_RADIUS;
@Comment({
"Blockstates include Banner, Beacon, BrewingStand, Chest, CommandBlock, ",
"CreatureSpawner, Dispenser, Dropper, EndGateway, Furnace, Hopper, Jukebox, ",
@ -353,6 +389,18 @@ public class Settings extends Config {
" - History on disk or memory will be deleted",
})
public int MAX_HISTORY_MB = -1;
@Comment({
"Sets a maximum limit (in kb) for the size of a player's schematics directory (per-player mode only)",
"Set to -1 to disable"
})
@Migrate("experimental.per-player-file-size-limit")
public int SCHEM_FILE_SIZE_LIMIT = -1;
@Comment({
"Sets a maximum limit for the amount of schematics in a player's schematics directory (per-player mode only)",
"Set to -1 to disable"
})
@Migrate("experimental.per-player-file-num-limit")
public int SCHEM_FILE_NUM_LIMIT = -1;
@Comment("Maximum time in milliseconds //calc can execute")
public int MAX_EXPRESSION_MS = 50;
@Comment({
@ -394,12 +442,17 @@ public class Settings extends Config {
" - If fast-placement is disabled, this may cause edits to be slower."
})
public boolean UNIVERSAL_DISALLOWED_BLOCKS = true;
@Comment({
"If legacy, mumerical, blocks IDs should be able to be used (i.e. 12:2),"
})
public boolean ALLOW_LEGACY = true;
@Comment({
"List of blocks to deny use of. Can be either an entire block type or a block with a specific property value.",
"Where block properties are specified, any blockstate with the property will be disallowed (e.g. all directions",
"of a waterlogged fence). For blocking/remapping of all occurrences of a property like waterlogged, see",
"remap-properties below.",
"To generate a blank list, substitute the default content with a set of square brackets [] instead.",
"The 'worldedit.anyblock' permission is not considered here.",
"Example block property blocking:",
" - \"minecraft:conduit[waterlogged=true]\"",
" - \"minecraft:piston[extended=false,facing=west]\"",
@ -472,6 +525,9 @@ public class Settings extends Config {
public int DELETE_AFTER_DAYS = 7;
@Comment("Delete history in memory on logout (does not effect disk)")
public boolean DELETE_ON_LOGOUT = true;
@Comment("Delete history on disk on logout")
@CopiedFrom("history.delete-on-logout")
public boolean DELETE_DISK_ON_LOGOUT = false;
@Comment({
"If history should be enabled by default for plugins using WorldEdit:",
" - It is faster to have disabled",
@ -510,7 +566,7 @@ public class Settings extends Config {
" - A larger value will use slightly less CPU time",
" - A smaller value will reduce memory usage",
" - A value too small may break some operations (deform?)",
" - Values smaller than the configurated parallel-threads are not accepted",
" - Values smaller than the configured parallel-threads are not accepted",
" - It is recommended this option be at least 4x greater than parallel-threads"
})
@ -543,12 +599,6 @@ public class Settings extends Config {
})
public boolean POOL = true;
@Comment({
"When using fastmode do not bother to tick existing/placed blocks/fluids",
"Only works in versions up to 1.17.1"
})
public boolean NO_TICK_FASTMODE = true;
public static class PROGRESS {
@Comment({"Display constant titles about the progress of a user's edit",
@ -574,6 +624,13 @@ public class Settings extends Config {
})
public static class EXPERIMENTAL {
@Comment({
"Undo operation batch size",
" - The size defines the number of changes read at once.",
" - Larger numbers might reduce overhead but increase latency for edits with only few changes.",
" - 0 means undo operations are not batched."})
public int UNDO_BATCH_SIZE = 128;
@Comment({
"[UNSAFE] Directly modify the region files. (OBSOLETE - USE ANVIL COMMANDS)",
" - IMPROPER USE CAN CAUSE WORLD CORRUPTION!",
@ -621,16 +678,9 @@ public class Settings extends Config {
public boolean ALLOW_TICK_FLUIDS = false;
@Comment({
"Sets a maximum limit (in kb) for the size of a player's schematics directory (per-player mode only)",
"Set to -1 to disable"
"Whether FAWE should use the incubator Vector API to accelerate some operations"
})
public int PER_PLAYER_FILE_SIZE_LIMIT = -1;
@Comment({
"Sets a maximum limit for the amount of schematics in a player's schematics directory (per-player mode only)",
"Set to -1 to disable"
})
public int PER_PLAYER_FILE_NUM_LIMIT = -1;
public boolean USE_VECTOR_API = false;
}
@ -640,6 +690,13 @@ public class Settings extends Config {
@Comment({"The web interface for clipboards", " - All schematics are anonymous and private", " - Downloads can be deleted by the user", " - Supports clipboard uploads, downloads and saves",})
public String URL = "https://schem.intellectualsites.com/fawe/";
@Comment({"The url of the backend server (Arkitektonika)"})
public String ARKITEKTONIKA_BACKEND_URL = "https://api.schematic.cloud/";
@Comment({"The url used to generate a download link from.", "{key} will be replaced with the generated key"})
public String ARKITEKTONIKA_DOWNLOAD_URL = "https://schematic.cloud/download/{key}";
@Comment({"The url used to generate a deletion link from.", "{key} will be replaced with the generated key"})
public String ARKITEKTONIKA_DELETE_URL = "https://schematic.cloud/delete/{key}";
@Comment("The maximum amount of time in seconds the plugin can attempt to load images for.")
public int MAX_IMAGE_LOAD_TIME = 5;
@ -720,6 +777,13 @@ public class Settings extends Config {
" - Requires clipboard.use-disk to be enabled"
})
public boolean SAVE_CLIPBOARD_NBT_TO_DISK = true;
@Comment({
"Apply a file lock on the clipboard file (only relevant if clipboad.on-disk is enabled)",
" - Prevents other processes using the file whilst in use by FAWE",
" - This extends to other servers, useful if you have multiple servers using a unified clipboard folder",
" - May run into issues where a file lock is not correctly lifted"
})
public boolean LOCK_CLIPBOARD_FILE = false;
}
@ -742,4 +806,18 @@ public class Settings extends Config {
}
public static class GENERAL {
@Comment({
"If the player should be relocated/unstuck when a generation command would bury them",
})
public boolean UNSTUCK_ON_GENERATE = true;
@Comment({
"If unlimited limits should still require /confirm on large. Defaults to limits.default.confirm-large otherwise."
})
public boolean LIMIT_UNLIMITED_CONFIRMS = true;
}
}

View File

@ -68,6 +68,7 @@ public class YamlConfiguration extends FileConfiguration {
LOGGER.error("Could not read {}\n" + "Renamed to {}", file, dest.getAbsolutePath(), ex);
} catch (final IOException e) {
e.printStackTrace();
ex.printStackTrace();
}
}

View File

@ -13,7 +13,7 @@ public class DBHandler {
* @deprecated Use {@link #dbHandler()} instead.
*/
@Deprecated(forRemoval = true, since = "2.0.0")
public static final DBHandler IMP = new DBHandler();
public static final DBHandler IMP = dbHandler();
private static final Logger LOGGER = LogManagerCompat.getLogger();
private static DBHandler INSTANCE;
private final Map<World, RollbackDatabase> databases = new ConcurrentHashMap<>(8, 0.9f, 1);

View File

@ -64,26 +64,47 @@ public class RollbackDatabase extends AsyncNotifyQueue {
public Future<Boolean> init() {
return call(() -> {
try (PreparedStatement stmt = connection.prepareStatement("CREATE TABLE IF NOT EXISTS`" + this.prefix +
"edits` (`player` BLOB(16) NOT NULL,`id` INT NOT NULL, `time` INT NOT NULL,`x1`" +
"INT NOT NULL,`x2` INT NOT NULL,`z1` INT NOT NULL,`z2` INT NOT NULL,`y1`" +
"INT NOT NULL, `y2` INT NOT NULL, `size` INT NOT NULL, `command` VARCHAR, PRIMARY KEY (player, id))")) {
"_edits` (`player` BLOB(16) NOT NULL,`id` INT NOT NULL, `time` INT NOT NULL,`x1` " +
"INT NOT NULL,`x2` INT NOT NULL,`z1` INT NOT NULL,`z2` INT NOT NULL,`y1` " +
"INT NOT NULL, `y2` INT NOT NULL, `size` BIGINT NOT NULL, `command` VARCHAR, PRIMARY KEY (player, id))")) {
stmt.executeUpdate();
}
try (PreparedStatement stmt = connection.prepareStatement("ALTER TABLE`" + this.prefix + "edits` ADD COLUMN `command` VARCHAR")) {
String alterTablePrefix = "ALTER TABLE`" + this.prefix + "edits` ";
try (PreparedStatement stmt =
connection.prepareStatement(alterTablePrefix + "ADD COLUMN `command` VARCHAR")) {
stmt.executeUpdate();
} catch (SQLException ignored) {
} // Already updated
try (PreparedStatement stmt = connection.prepareStatement("ALTER TABLE`" + this.prefix + "edits` ADD SIZE INT DEFAULT 0 NOT NULL")) {
try (PreparedStatement stmt =
connection.prepareStatement(alterTablePrefix + "ADD COLUMN `size` BIGINT DEFAULT 0 NOT NULL")) {
stmt.executeUpdate();
} catch (SQLException ignored) {
} // Already updated
boolean migrated = false;
try (PreparedStatement stmt =
connection.prepareStatement("INSERT INTO `" + this.prefix + "_edits` " +
"(player, id, time, x1, x2, z1, z2, y1, y2, size, command) " +
"SELECT player, id, time, x1, x2, z1, z2, y1, y2, size, command " +
"FROM `" + this.prefix + "edits`")) {
stmt.executeUpdate();
migrated = true;
} catch (SQLException ignored) {
} // Already updated
if (migrated) {
try (PreparedStatement stmt = connection.prepareStatement("DROP TABLE `" + this.prefix + "edits`")) {
stmt.executeUpdate();
}
}
return true;
});
}
public Future<Integer> delete(UUID uuid, int id) {
return call(() -> {
try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix + "edits` WHERE `player`=? AND `id`=?")) {
try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix + "_edits` WHERE `player`=? " +
"AND `id`=?")) {
stmt.setBytes(1, toBytes(uuid));
stmt.setInt(2, id);
return stmt.executeUpdate();
@ -94,7 +115,7 @@ public class RollbackDatabase extends AsyncNotifyQueue {
public Future<RollbackOptimizedHistory> getEdit(@Nonnull UUID uuid, int id) {
return call(() -> {
try (PreparedStatement stmt = connection.prepareStatement("SELECT * FROM`" + this.prefix +
"edits` WHERE `player`=? AND `id`=?")) {
"_edits` WHERE `player`=? AND `id`=?")) {
stmt.setBytes(1, toBytes(uuid));
stmt.setInt(2, id);
ResultSet result = stmt.executeQuery();
@ -119,7 +140,7 @@ public class RollbackDatabase extends AsyncNotifyQueue {
CuboidRegion region = new CuboidRegion(BlockVector3.at(x1, y1, z1), BlockVector3.at(x2, y2, z2));
long time = result.getInt("time") * 1000L;
long size = result.getInt("size");
long size = result.getLong("size");
String command = result.getString("command");
@ -135,7 +156,7 @@ public class RollbackDatabase extends AsyncNotifyQueue {
long now = System.currentTimeMillis() / 1000;
final int then = (int) (now - diff);
return call(() -> {
try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix + "edits` WHERE `time`<?")) {
try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix + "_edits` WHERE `time`<?")) {
stmt.setInt(1, then);
return stmt.executeUpdate();
}
@ -159,23 +180,33 @@ public class RollbackDatabase extends AsyncNotifyQueue {
Future<Integer> future = call(() -> {
try {
int count = 0;
String stmtStr = ascending ? uuid == null ? "SELECT * FROM`" + this.prefix + "edits` WHERE `time`>? AND `x2`>=? AND" +
" `x1`<=? AND `z2`>=? AND `z1`<=? AND `y2`>=? AND `y1`<=? ORDER BY `time` , `id`" :
"SELECT * FROM`" + this.prefix + "edits` WHERE `time`>? AND" +
" `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND `y2`>=? AND `y1`<=? AND `player`=? ORDER BY `time` ASC, `id` ASC" :
uuid == null ? "SELECT * FROM`" + this.prefix + "edits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND `z2`>=? " +
"AND `z1`<=? AND `y2`>=? AND `y1`<=? ORDER BY `time` DESC, `id` DESC" :
"SELECT * FROM`" + this.prefix + "edits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND" +
" `z2`>=? AND `z1`<=? AND `y2`>=? AND `y1`<=? AND `player`=? ORDER BY `time` DESC, `id` DESC";
try (PreparedStatement stmt = connection.prepareStatement(stmtStr)) {
String stmtStr = """
SELECT * FROM `%s_edits`
WHERE `time` > ?
AND `x2` >= ?
AND `x1` <= ?
AND `z2` >= ?
AND `z1` <= ?
AND `y2` >= ?
AND `y1` <= ?
""";
if (uuid != null) {
stmtStr += "\n AND `player`= ?";
}
if (ascending) {
stmtStr += "\n ORDER BY `time` ASC, `id` ASC";
} else {
stmtStr += "\n ORDER BY `time` DESC, `id` DESC";
}
try (PreparedStatement stmt = connection.prepareStatement(stmtStr.formatted(this.prefix))) {
stmt.setInt(1, (int) (minTime / 1000));
stmt.setInt(2, pos1.getBlockX());
stmt.setInt(3, pos2.getBlockX());
stmt.setInt(4, pos1.getBlockZ());
stmt.setInt(5, pos2.getBlockZ());
stmt.setInt(2, pos1.x());
stmt.setInt(3, pos2.x());
stmt.setInt(4, pos1.z());
stmt.setInt(5, pos2.z());
// Keep 128 offset for backwards-compatibility
stmt.setInt(6, pos1.getBlockY() - 128);
stmt.setInt(7, pos2.getBlockY() - 128);
stmt.setInt(6, pos1.y() - 128);
stmt.setInt(7, pos2.y() - 128);
if (uuid != null) {
byte[] uuidBytes = toBytes(uuid);
stmt.setBytes(8, uuidBytes);
@ -192,21 +223,22 @@ public class RollbackDatabase extends AsyncNotifyQueue {
}
if (delete && uuid != null) {
try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix +
"edits` WHERE `player`=? AND `time`>? AND `x2`>=? AND `x1`<=? AND `y2`>=? AND `y1`<=? AND `z2`>=? AND `z1`<=?")) {
stmt.setInt(1, (int) (minTime / 1000));
stmt.setInt(2, pos1.getBlockX());
stmt.setInt(3, pos2.getBlockX());
stmt.setInt(4, pos1.getBlockZ());
stmt.setInt(5, pos2.getBlockZ());
// Keep 128 offset for backwards-compatibility
stmt.setInt(6, pos1.getBlockY() - 128);
stmt.setInt(7, pos2.getBlockY() - 128);
"_edits` WHERE `player`=? AND `time`>? AND `x2`>=? AND `x1`<=? AND `y2`>=? AND `y1`<=? AND `z2`>=? " +
"AND `z1`<=?")) {
byte[] uuidBytes = ByteBuffer
.allocate(16)
.putLong(uuid.getMostSignificantBits())
.putLong(uuid.getLeastSignificantBits())
.array();
stmt.setBytes(8, uuidBytes);
stmt.setBytes(1, uuidBytes);
stmt.setInt(2, (int) (minTime / 1000));
stmt.setInt(3, pos1.x());
stmt.setInt(4, pos2.x());
stmt.setInt(5, pos1.z());
stmt.setInt(6, pos2.z());
// Keep 128 offset for backwards-compatibility
stmt.setInt(7, pos1.y() - 128);
stmt.setInt(8, pos2.y() - 128);
}
}
return count;
@ -239,7 +271,7 @@ public class RollbackDatabase extends AsyncNotifyQueue {
RollbackOptimizedHistory[] copy = IntStream.range(0, size)
.mapToObj(i -> historyChanges.poll()).toArray(RollbackOptimizedHistory[]::new);
try (PreparedStatement stmt = connection.prepareStatement("INSERT OR REPLACE INTO`" + this.prefix + "edits`" +
try (PreparedStatement stmt = connection.prepareStatement("INSERT OR REPLACE INTO`" + this.prefix + "_edits`" +
" (`player`,`id`,`time`,`x1`,`x2`,`z1`,`z2`,`y1`,`y2`,`command`,`size`) VALUES(?,?,?,?,?,?,?,?,?,?,?)")) {
// `player`,`id`,`time`,`x1`,`x2`,`z1`,`z2`,`y1`,`y2`,`command`,`size`) VALUES(?,?,?,?,?,?,?,?,?,?,?)"
for (RollbackOptimizedHistory change : copy) {
@ -252,15 +284,15 @@ public class RollbackDatabase extends AsyncNotifyQueue {
BlockVector3 pos1 = change.getMinimumPoint();
BlockVector3 pos2 = change.getMaximumPoint();
stmt.setInt(4, pos1.getX());
stmt.setInt(5, pos2.getX());
stmt.setInt(6, pos1.getZ());
stmt.setInt(7, pos2.getZ());
stmt.setInt(4, pos1.x());
stmt.setInt(5, pos2.x());
stmt.setInt(6, pos1.z());
stmt.setInt(7, pos2.z());
// Keep 128 offset for backwards-compatibility
stmt.setInt(8, pos1.getY() - 128);
stmt.setInt(9, pos2.getY() - 128);
stmt.setInt(8, pos1.y() - 128);
stmt.setInt(9, pos2.y() - 128);
stmt.setString(10, change.getCommand());
stmt.setInt(11, change.size());
stmt.setLong(11, change.longSize());
stmt.executeUpdate();
stmt.clearParameters();
}

View File

@ -3,25 +3,25 @@ package com.fastasyncworldedit.core.entity;
import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.util.TaskManager;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.world.entity.EntityType;
import org.enginehub.linbus.tree.LinCompoundTag;
import javax.annotation.Nullable;
import java.util.function.Supplier;
public class LazyBaseEntity extends BaseEntity {
private Supplier<CompoundBinaryTag> saveTag;
private Supplier<LinCompoundTag> saveTag;
public LazyBaseEntity(EntityType type, Supplier<CompoundBinaryTag> saveTag) {
public LazyBaseEntity(EntityType type, Supplier<LinCompoundTag> saveTag) {
super(type);
this.saveTag = saveTag;
}
@Nullable
@Override
public CompoundBinaryTag getNbt() {
Supplier<CompoundBinaryTag> tmp = saveTag;
public LinCompoundTag getNbt() {
Supplier<LinCompoundTag> tmp = saveTag;
if (tmp != null) {
saveTag = null;
if (Fawe.isMainThread()) {

View File

@ -0,0 +1,30 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.fastasyncworldedit.core.exception;
/**
* Thrown when a maximum radius for a brush is reached.
*/
public class BrushRadiusLimitException extends RadiusLimitException {
public BrushRadiusLimitException(int maxBrushRadius) {
super(maxBrushRadius);
}
}

View File

@ -0,0 +1,17 @@
package com.fastasyncworldedit.core.exception;
import com.sk89q.worldedit.WorldEditException;
public class OutsideWorldBoundsException extends WorldEditException {
private final int y;
public OutsideWorldBoundsException(int y) {
this.y = y;
}
public int y() {
return y;
}
}

View File

@ -0,0 +1,41 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.fastasyncworldedit.core.exception;
import com.sk89q.worldedit.WorldEditException;
/**
* Thrown when a maximum radius is reached, such as, for example,
* in the case of a sphere command.
*/
public class RadiusLimitException extends WorldEditException {
private final int maxRadius;
public RadiusLimitException(int maxRadius) {
this.maxRadius = maxRadius;
}
public int getMaxRadius() {
return maxRadius;
}
//FAWE end
}

View File

@ -21,22 +21,17 @@ import com.sk89q.worldedit.internal.registry.AbstractFactory;
import com.sk89q.worldedit.internal.registry.InputParser;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import java.util.ArrayList;
import java.util.List;
public class TransformFactory extends AbstractFactory<ResettableExtent> {
private final RichTransformParser richTransformParser;
/**
* Create a new factory.
*
* @param worldEdit the WorldEdit instance
*/
public TransformFactory(WorldEdit worldEdit) {
super(worldEdit, new NullTransformParser(worldEdit));
richTransformParser = new RichTransformParser(worldEdit);
super(worldEdit, new NullTransformParser(worldEdit), new RichTransformParser(worldEdit));
// split and parse each sub-transform
register(new RandomTransformParser(worldEdit));
@ -51,68 +46,7 @@ public class TransformFactory extends AbstractFactory<ResettableExtent> {
}
@Override
public ResettableExtent parseFromInput(String input, ParserContext context) throws InputParseException {
List<ResettableExtent> transforms = new ArrayList<>();
for (String component : input.split(" ")) {
if (component.isEmpty()) {
continue;
}
ResettableExtent match = richTransformParser.parseFromInput(component, context);
if (match != null) {
transforms.add(match);
continue;
}
parseFromParsers(context, transforms, component);
}
return getResettableExtent(input, transforms);
}
private void parseFromParsers(
final ParserContext context,
final List<ResettableExtent> transforms,
final String component
) {
ResettableExtent match = null;
for (InputParser<ResettableExtent> parser : getParsers()) {
match = parser.parseFromInput(component, context);
if (match != null) {
break;
}
}
if (match == null) {
throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(component)));
}
transforms.add(match);
}
/**
* Parses a transform without considering parsing through the {@link RichTransformParser}, therefore not accepting
* "richer" parsing where &amp; and , are used. Exists to prevent stack overflows.
*
* @param input input string
* @param context input context
* @return parsed result
* @throws InputParseException if no result found
*/
public ResettableExtent parseWithoutRich(String input, ParserContext context) throws InputParseException {
List<ResettableExtent> transforms = new ArrayList<>();
for (String component : input.split(" ")) {
if (component.isEmpty()) {
continue;
}
parseFromParsers(context, transforms, component);
}
return getResettableExtent(input, transforms);
}
private ResettableExtent getResettableExtent(final String input, final List<ResettableExtent> transforms) {
protected ResettableExtent getParsed(final String input, final List<ResettableExtent> transforms) {
switch (transforms.size()) {
case 0:
throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input)));

View File

@ -37,14 +37,14 @@ public abstract class FaweParser<T> extends InputParser<T> implements AliasedPar
for (int i = 0; i < toParse.length(); i++) {
char c = toParse.charAt(i);
switch (c) {
case ',', '&' -> {
case ',', '&', ' ' -> {
if (expression) {
continue;
}
String result = toParse.substring(last, i);
if (!result.isEmpty()) {
inputs.add(result);
and.add(c == '&');
and.add(c == '&' || c == ' ');
} else {
throw new InputParseException(Caption.of("fawe.error.parse.invalid-dangling-character", c));
}

View File

@ -53,7 +53,7 @@ public abstract class RichParser<E> extends InputParser<E> implements AliasedPar
}
@Nonnull
private Function<String, Stream<? extends String>> extractArguments(String input) {
private Function<String, Stream<? extends String>> extractArguments(String input, ParserContext context) {
return prefix -> {
if (input.length() > prefix.length() && input.startsWith(prefix + "[")) {
// input already contains argument(s) -> extract them
@ -65,7 +65,7 @@ public abstract class RichParser<E> extends InputParser<E> implements AliasedPar
}
String previous = prefix + builder;
// read the suggestions for the last argument
return getSuggestions(strings[strings.length - 1], strings.length - 1)
return getSuggestions(strings[strings.length - 1], strings.length - 1, context)
.map(suggestion -> previous + "[" + suggestion);
} else {
return Stream.of(prefix);
@ -95,7 +95,7 @@ public abstract class RichParser<E> extends InputParser<E> implements AliasedPar
public Stream<String> getSuggestions(String input) {
return Arrays.stream(this.prefixes)
.filter(validPrefix(input))
.flatMap(extractArguments(input));
.flatMap(extractArguments(input, new ParserContext()));
}
@Override
@ -122,8 +122,25 @@ public abstract class RichParser<E> extends InputParser<E> implements AliasedPar
* @param argumentInput the already provided input for the argument at the given index.
* @param index the index of the argument to get suggestions for.
* @return a stream of suggestions matching the given input for the argument at the given index.
*
* @deprecated Use the version that takes a {@link ParserContext}, {@link #getSuggestions(String, int, ParserContext)}
*/
protected abstract Stream<String> getSuggestions(String argumentInput, int index);
@Deprecated
protected Stream<String> getSuggestions(String argumentInput, int index) {
return Stream.empty();
}
/**
* Returns a stream of suggestions for the argument at the given index.
*
* @param argumentInput the already provided input for the argument at the given index.
* @param index the index of the argument to get suggestions for.
* @param context the context which may optionally be provided by a parser.
* @return a stream of suggestions matching the given input for the argument at the given index.
*/
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
return getSuggestions(argumentInput, index);
}
/**
* Parses the already split arguments.

View File

@ -0,0 +1,72 @@
package com.fastasyncworldedit.core.extension.factory.parser.common;
import com.fastasyncworldedit.core.configuration.Caption;
import com.fastasyncworldedit.core.extent.inventory.SlottableBlockBag;
import com.fastasyncworldedit.core.limit.FaweLimit;
import com.google.common.collect.ImmutableList;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.input.DisallowedUsageException;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.internal.registry.SimpleInputParser;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.world.block.BlockType;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public abstract class HotbarParser<T> extends SimpleInputParser<T> {
private final List<String> aliases = ImmutableList.of("#hotbar");
protected HotbarParser(final WorldEdit worldEdit) {
super(worldEdit);
}
@Override
public List<String> getMatchedAliases() {
return aliases;
}
protected List<BlockType> getBlockTypes(ParserContext context) {
Player player = context.requirePlayer();
BlockBag bag = player.getInventoryBlockBag();
if (!(bag instanceof final SlottableBlockBag slottable)) {
// Matches DefaultBlockParser
throw new InputParseException(Caption.of("fawe.error.unsupported"));
}
List<BlockType> types = new ArrayList<>();
FaweLimit limit = player.getLimit();
boolean anyBlock = player.hasPermission("worldedit.anyblock");
for (int slot = 0; slot < 9; slot++) {
BaseItem item = slottable.getItem(slot);
if (item != null && item.getType().hasBlockType()) {
BlockType type = item.getType().getBlockType();
if (!anyBlock && worldEdit.getConfiguration().disallowedBlocks.contains(type.id().toLowerCase(Locale.ROOT))) {
throw new DisallowedUsageException(Caption.of(
"worldedit.error.disallowed-block",
TextComponent.of(type.getId())
));
}
if (!limit.isUnlimited()) {
if (limit.DISALLOWED_BLOCKS.contains(type.id().toLowerCase(Locale.ROOT))) {
throw new DisallowedUsageException(Caption.of(
"fawe.error.limit.disallowed-block",
TextComponent.of(type.getId())
));
}
}
types.add(type);
}
}
if (types.isEmpty()) {
throw new InputParseException(Caption.of("fawe.error.no-valid-on-hotbar"));
}
return types;
}
}

View File

@ -19,9 +19,9 @@ public class AdjacentMaskParser extends RichParser<Mask> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index == 0) {
return worldEdit.getMaskFactory().getSuggestions(argumentInput).stream();
return worldEdit.getMaskFactory().getSuggestions(argumentInput, context).stream();
} else if (index == 1 || index == 2) {
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
}

View File

@ -22,7 +22,7 @@ public class AngleMaskParser extends RichParser<Mask> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index == 0 || index == 1) {
return SuggestionHelper.suggestPositiveDoubles(argumentInput).flatMap(s -> Stream.of(s, s + "d"));
} else if (index > 1 && index <= 1 + flags.length) {

View File

@ -18,9 +18,9 @@ public class BesideMaskParser extends RichParser<Mask> {
}
@Override
protected Stream<String> getSuggestions(final String argumentInput, final int index) {
protected Stream<String> getSuggestions(final String argumentInput, final int index, ParserContext context) {
if (index == 0) {
return worldEdit.getMaskFactory().getSuggestions(argumentInput).stream();
return worldEdit.getMaskFactory().getSuggestions(argumentInput, context).stream();
} else if (index == 1 || index == 2) {
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
}

View File

@ -22,7 +22,7 @@ public class ExtremaMaskParser extends RichParser<Mask> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index == 0 || index == 1) {
return SuggestionHelper.suggestPositiveDoubles(argumentInput).flatMap(s -> Stream.of(s, s + "d"));
} else if (index > 1 && index <= 1 + flags.length) {

View File

@ -0,0 +1,20 @@
package com.fastasyncworldedit.core.extension.factory.parser.mask;
import com.fastasyncworldedit.core.extension.factory.parser.common.HotbarParser;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.function.mask.BlockTypeMask;
import com.sk89q.worldedit.function.mask.Mask;
public class HotbarMaskParser extends HotbarParser<Mask> {
public HotbarMaskParser(WorldEdit worldEdit) {
super(worldEdit);
}
@Override
public Mask parseFromSimpleInput(String input, ParserContext context) {
return new BlockTypeMask(context.getExtent(), getBlockTypes(context));
}
}

View File

@ -22,7 +22,7 @@ public class ROCAngleMaskParser extends RichParser<Mask> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index == 0 || index == 1) {
return SuggestionHelper.suggestPositiveDoubles(argumentInput).flatMap(s -> Stream.of(s, s + "d"));
} else if (index > 1 && index <= 1 + flags.length) {

View File

@ -18,7 +18,7 @@ public class RadiusMaskParser extends RichParser<Mask> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index == 0 || index == 1) {
return SuggestionHelper.suggestPositiveIntegers(argumentInput);
}

View File

@ -4,7 +4,7 @@ import com.fastasyncworldedit.core.command.SuggestInputParseException;
import com.fastasyncworldedit.core.configuration.Caption;
import com.fastasyncworldedit.core.extension.factory.parser.FaweParser;
import com.fastasyncworldedit.core.function.mask.BlockMaskBuilder;
import com.fastasyncworldedit.core.function.mask.MaskUnion;
import com.sk89q.worldedit.function.mask.MaskUnion;
import com.fastasyncworldedit.core.util.StringMan;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.worldedit.WorldEdit;
@ -97,11 +97,11 @@ public class RichMaskParser extends FaweParser<Mask> {
)),
() -> {
if (full.length() == 1) {
return new ArrayList<>(worldEdit.getMaskFactory().getSuggestions(""));
return new ArrayList<>(worldEdit.getMaskFactory().getSuggestions("", context));
}
return new ArrayList<>(worldEdit
.getMaskFactory()
.getSuggestions(command.toLowerCase(Locale.ROOT)));
.getSuggestions(command.toLowerCase(Locale.ROOT), context));
}
);
}
@ -143,7 +143,7 @@ public class RichMaskParser extends FaweParser<Mask> {
int end = command.lastIndexOf(']');
mask = parseFromInput(command.substring(1, end == -1 ? command.length() : end), context);
} else {
BlockMaskBuilder builder = new BlockMaskBuilder();
BlockMaskBuilder builder = new BlockMaskBuilder(context);
try {
builder.addRegex(full);
} catch (InputParseException ignored) {
@ -164,11 +164,11 @@ public class RichMaskParser extends FaweParser<Mask> {
)),
() -> {
if (full.length() == 1) {
return new ArrayList<>(worldEdit.getMaskFactory().getSuggestions(""));
return new ArrayList<>(worldEdit.getMaskFactory().getSuggestions("", context));
}
return new ArrayList<>(worldEdit
.getMaskFactory()
.getSuggestions(command.toLowerCase(Locale.ROOT)));
.getSuggestions(command.toLowerCase(Locale.ROOT), context));
}
);
}

View File

@ -24,12 +24,12 @@ public class RichOffsetMaskParser extends RichParser<Mask> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index < 3) {
return SuggestionHelper.suggestPositiveIntegers(argumentInput);
}
if (index == 3) {
return worldEdit.getMaskFactory().getSuggestions(argumentInput).stream();
return worldEdit.getMaskFactory().getSuggestions(argumentInput, context).stream();
}
return Stream.empty();
}

View File

@ -20,7 +20,7 @@ public class SimplexMaskParser extends RichParser<Mask> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index < 3) {
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
}

View File

@ -23,7 +23,7 @@ public class SurfaceAngleMaskParser extends RichParser<Mask> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index <= 2) {
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
}

View File

@ -25,7 +25,7 @@ public class AngleColorPatternParser extends RichParser<Pattern> {
}
@Override
public Stream<String> getSuggestions(String argumentInput, int index) {
public Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index != 0) {
return Stream.empty();
}

View File

@ -25,7 +25,7 @@ public class AverageColorPatternParser extends RichParser<Pattern> {
}
@Override
public Stream<String> getSuggestions(String argumentInput, int index) {
public Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index > 4) {
return Stream.empty();
}

View File

@ -54,7 +54,7 @@ public class BiomePatternParser extends RichParser<Pattern> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index == 0) {
return BiomeType.REGISTRY.getSuggestions(argumentInput);
}

View File

@ -26,9 +26,9 @@ public class BufferedPattern2DParser extends RichParser<Pattern> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index == 0) {
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
}
return Stream.empty();
}

View File

@ -26,9 +26,9 @@ public class BufferedPatternParser extends RichParser<Pattern> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index == 0) {
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
}
return Stream.empty();
}

View File

@ -26,7 +26,7 @@ public class ColorPatternParser extends RichParser<Pattern> {
}
@Override
public Stream<String> getSuggestions(String argumentInput, int index) {
public Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index > 4) {
return Stream.empty();
}

View File

@ -25,7 +25,7 @@ public class DesaturatePatternParser extends RichParser<Pattern> {
}
@Override
public Stream<String> getSuggestions(String argumentInput, int index) {
public Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index == 0) {
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
}

View File

@ -0,0 +1,26 @@
package com.fastasyncworldedit.core.extension.factory.parser.pattern;
import com.fastasyncworldedit.core.extension.factory.parser.common.HotbarParser;
import com.fastasyncworldedit.core.math.random.TrueRandom;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.pattern.RandomPattern;
import com.sk89q.worldedit.world.block.BlockType;
public class HotbarPatternParser extends HotbarParser<Pattern> {
public HotbarPatternParser(WorldEdit worldEdit) {
super(worldEdit);
}
@Override
public Pattern parseFromSimpleInput(String input, ParserContext context) {
RandomPattern random = new RandomPattern(new TrueRandom());
for (BlockType type : getBlockTypes(context)) {
random.add(type, 1);
}
return random;
}
}

View File

@ -2,7 +2,7 @@ package com.fastasyncworldedit.core.extension.factory.parser.pattern;
import com.fastasyncworldedit.core.configuration.Caption;
import com.fastasyncworldedit.core.extension.factory.parser.RichParser;
import com.fastasyncworldedit.core.function.pattern.Linear2DBlockPattern;
import com.fastasyncworldedit.core.math.random.Linear2DRandom;
import com.google.common.base.Preconditions;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.util.SuggestionHelper;
@ -14,7 +14,6 @@ import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import javax.annotation.Nonnull;
import java.util.Set;
import java.util.stream.Stream;
public class Linear2DPatternParser extends RichParser<Pattern> {
@ -29,9 +28,9 @@ public class Linear2DPatternParser extends RichParser<Pattern> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
return switch (index) {
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
case 1, 2 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
default -> Stream.empty();
};
@ -59,9 +58,8 @@ public class Linear2DPatternParser extends RichParser<Pattern> {
zScale = Integer.parseInt(arguments[2]);
Preconditions.checkArgument(zScale != 0);
}
if (inner instanceof RandomPattern) {
Set<Pattern> patterns = ((RandomPattern) inner).getPatterns();
return new Linear2DBlockPattern(patterns.toArray(new Pattern[0]), xScale, zScale);
if (inner instanceof RandomPattern rp) {
return new RandomPattern(new Linear2DRandom(xScale, zScale), rp);
}
throw new InputParseException(TextComponent.of("Pattern " + inner.getClass().getSimpleName()
+ " cannot be used with " + getPrefix()));

View File

@ -2,7 +2,7 @@ package com.fastasyncworldedit.core.extension.factory.parser.pattern;
import com.fastasyncworldedit.core.configuration.Caption;
import com.fastasyncworldedit.core.extension.factory.parser.RichParser;
import com.fastasyncworldedit.core.function.pattern.Linear3DBlockPattern;
import com.fastasyncworldedit.core.math.random.Linear3DRandom;
import com.google.common.base.Preconditions;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.util.SuggestionHelper;
@ -14,7 +14,6 @@ import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import javax.annotation.Nonnull;
import java.util.Set;
import java.util.stream.Stream;
public class Linear3DPatternParser extends RichParser<Pattern> {
@ -29,9 +28,9 @@ public class Linear3DPatternParser extends RichParser<Pattern> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
return switch (index) {
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
case 1, 2, 3 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
default -> Stream.empty();
};
@ -64,9 +63,8 @@ public class Linear3DPatternParser extends RichParser<Pattern> {
zScale = Integer.parseInt(arguments[3]);
Preconditions.checkArgument(zScale != 0);
}
if (inner instanceof RandomPattern) {
Set<Pattern> patterns = ((RandomPattern) inner).getPatterns();
return new Linear3DBlockPattern(patterns.toArray(new Pattern[0]), xScale, yScale, zScale);
if (inner instanceof RandomPattern rp) {
return new RandomPattern(new Linear3DRandom(xScale, yScale, zScale), rp);
}
throw new InputParseException(TextComponent.of("Pattern " + inner.getClass().getSimpleName()
+ " cannot be used with " + getPrefix()));

View File

@ -28,9 +28,9 @@ public class LinearPatternParser extends RichParser<Pattern> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
return switch (index) {
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
case 1, 2, 3 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
default -> Stream.empty();
};

View File

@ -25,10 +25,10 @@ public class MaskedPatternParser extends RichParser<Pattern> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
return switch (index) {
case 0 -> this.worldEdit.getMaskFactory().getSuggestions(argumentInput).stream();
case 1, 2 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
case 0 -> this.worldEdit.getMaskFactory().getSuggestions(argumentInput, context).stream();
case 1, 2 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
default -> Stream.empty();
};
}

View File

@ -24,9 +24,9 @@ public class NoXPatternParser extends RichParser<Pattern> {
}
@Override
public Stream<String> getSuggestions(String argumentInput, int index) {
public Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index == 0) {
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
}
return Stream.empty();
}

View File

@ -24,9 +24,9 @@ public class NoYPatternParser extends RichParser<Pattern> {
}
@Override
public Stream<String> getSuggestions(String argumentInput, int index) {
public Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index == 0) {
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
}
return Stream.empty();
}

View File

@ -24,9 +24,9 @@ public class NoZPatternParser extends RichParser<Pattern> {
}
@Override
public Stream<String> getSuggestions(String argumentInput, int index) {
public Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index == 0) {
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
}
return Stream.empty();
}

View File

@ -36,12 +36,12 @@ public abstract class NoisePatternParser extends RichParser<Pattern> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index == 0) {
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
}
if (index == 1) {
return worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
return worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
}
return Stream.empty();
}

View File

@ -25,9 +25,9 @@ public class OffsetPatternParser extends RichParser<Pattern> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
return switch (index) {
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
case 1, 2, 3 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
default -> Stream.empty();
};

View File

@ -4,6 +4,7 @@ import com.fastasyncworldedit.core.configuration.Caption;
import com.fastasyncworldedit.core.extension.factory.parser.RichParser;
import com.fastasyncworldedit.core.extent.clipboard.MultiClipboardHolder;
import com.fastasyncworldedit.core.function.pattern.RandomFullClipboardPattern;
import com.google.common.base.Function;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.util.SuggestionHelper;
import com.sk89q.worldedit.extension.input.InputParseException;
@ -33,7 +34,7 @@ public class RandomFullClipboardPatternParser extends RichParser<Pattern> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
switch (index) {
case 0:
if (argumentInput.equals("#") || argumentInput.equals("#c")) {

View File

@ -25,9 +25,9 @@ public class RandomOffsetPatternParser extends RichParser<Pattern> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
return switch (index) {
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
case 1, 2, 3 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
default -> Stream.empty();
};

View File

@ -24,9 +24,9 @@ public class RelativePatternParser extends RichParser<Pattern> {
}
@Override
public Stream<String> getSuggestions(String argumentInput, int index) {
public Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index == 0) {
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
}
return Stream.empty();
}

View File

@ -25,7 +25,7 @@ public class SaturatePatternParser extends RichParser<Pattern> {
}
@Override
public Stream<String> getSuggestions(String argumentInput, int index) {
public Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index > 3) {
return Stream.empty();
}

View File

@ -25,9 +25,9 @@ public class SolidRandomOffsetPatternParser extends RichParser<Pattern> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
return switch (index) {
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
case 1, 2, 3 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
default -> Stream.empty();
};

View File

@ -25,9 +25,9 @@ public class SurfaceRandomOffsetPatternParser extends RichParser<Pattern> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
return switch (index) {
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
case 1 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
default -> Stream.empty();
};

View File

@ -28,7 +28,7 @@ public class TypeSwapPatternParser extends RichParser<Pattern> {
}
@Override
public Stream<String> getSuggestions(String argumentInput, int index) {
public Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index > 2) {
return Stream.empty();
}

View File

@ -23,9 +23,9 @@ public class Linear3DTransformParser extends RichParser<ResettableExtent> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index == 0) {
return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream();
return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream();
}
return Stream.empty();
}

View File

@ -23,9 +23,9 @@ public class LinearTransformParser extends RichParser<ResettableExtent> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index == 0) {
return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream();
return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream();
}
return Stream.empty();
}

View File

@ -26,11 +26,11 @@ public class OffsetTransformParser extends RichParser<ResettableExtent> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index < 3) {
return SuggestionHelper.suggestPositiveIntegers(argumentInput);
} else if (index == 3) {
return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream();
return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream();
}
return Stream.empty();
}

View File

@ -24,11 +24,11 @@ public class PatternTransformParser extends RichParser<ResettableExtent> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index == 0) {
return worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
return worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
} else if (index == 1) {
return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream();
return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream();
}
return Stream.empty();
}

View File

@ -25,12 +25,12 @@ public class RotateTransformParser extends RichParser<ResettableExtent> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index < 3) {
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
}
if (index == 3) {
return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream();
return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream();
}
return Stream.empty();
}

View File

@ -24,11 +24,11 @@ public class ScaleTransformParser extends RichParser<ResettableExtent> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index < 3) {
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
} else if (index == 3) {
return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream();
return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream();
}
return Stream.empty();
}

View File

@ -24,11 +24,11 @@ public class SpreadTransformParser extends RichParser<ResettableExtent> {
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
if (index < 3) {
return SuggestionHelper.suggestPositiveIntegers(argumentInput);
} else if (index == 3) {
return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream();
return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream();
}
return Stream.empty();
}

View File

@ -200,6 +200,7 @@ public class ConsumeBindings extends Bindings {
public BaseBlock baseBlock(Actor actor, String argument) {
ParserContext parserContext = new ParserContext();
parserContext.setActor(actor);
parserContext.setTryLegacy(actor.getLimit().ALLOW_LEGACY);
if (actor instanceof Entity) {
Extent extent = ((Entity) actor).getExtent();
if (extent instanceof World) {

View File

@ -0,0 +1,7 @@
package com.fastasyncworldedit.core.extension.platform.binding;
import com.sk89q.worldedit.EditSession;
public record EditSessionHolder(EditSession session) {
}

View File

@ -3,7 +3,11 @@ package com.fastasyncworldedit.core.extension.platform.binding;
import com.fastasyncworldedit.core.configuration.Caption;
import com.fastasyncworldedit.core.database.DBHandler;
import com.fastasyncworldedit.core.database.RollbackDatabase;
import com.fastasyncworldedit.core.extent.LimitExtent;
import com.fastasyncworldedit.core.extent.processor.ExtentBatchProcessorHolder;
import com.fastasyncworldedit.core.internal.exception.FaweException;
import com.fastasyncworldedit.core.regions.FaweMaskManager;
import com.fastasyncworldedit.core.util.ExtentTraverser;
import com.fastasyncworldedit.core.util.TextureUtil;
import com.fastasyncworldedit.core.util.image.ImageUtil;
import com.sk89q.worldedit.EditSession;
@ -11,6 +15,7 @@ import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.argument.Arguments;
import com.sk89q.worldedit.command.util.annotation.AllowedRegion;
import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.platform.Actor;
@ -25,6 +30,7 @@ import org.enginehub.piston.inject.Key;
import org.enginehub.piston.util.ValueProvider;
import java.awt.image.BufferedImage;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Optional;
@ -52,11 +58,33 @@ public class ProvideBindings extends Bindings {
@Binding
public EditSession editSession(LocalSession localSession, Actor actor, InjectedValueAccess context) {
Method commandMethod =
context.injectedValue(Key.of(InjectedValueStore.class)).get().injectedValue(Key.of(Method.class)).get();
Arguments arguments = context.injectedValue(Key.of(Arguments.class)).orElse(null);
String command = arguments == null ? null : arguments.get();
EditSession editSession = localSession.createEditSession(actor, command);
editSession.enableStandardMode();
Request.request().setEditSession(editSession);
boolean synchronousSetting = commandMethod.getAnnotation(SynchronousSettingExpected.class) != null;
EditSessionHolder holder = context.injectedValue(Key.of(EditSessionHolder.class)).orElse(null);
EditSession editSession = holder != null ? holder.session() : null;
if (editSession == null) {
editSession = localSession.createEditSession(actor, command);
editSession.enableStandardMode();
} else {
LimitExtent limitExtent = new ExtentTraverser<>(editSession).findAndGet(LimitExtent.class);
if (limitExtent != null) {
limitExtent.setProcessing(!synchronousSetting);
if (!synchronousSetting) {
ExtentBatchProcessorHolder processorHolder = new ExtentTraverser<>(editSession).findAndGet(
ExtentBatchProcessorHolder.class);
if (processorHolder != null) {
processorHolder.addProcessor(limitExtent);
} else {
throw new FaweException(Caption.of("fawe.error.no-process-non-synchronous-edit"));
}
}
}
Request.request().setEditSession(editSession);
}
return editSession;
}

View File

@ -24,7 +24,7 @@ public class BlockTranslateExtent extends AbstractDelegateExtent {
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 location, T block) throws WorldEditException {
return getExtent().setBlock(location.getX() + dx, location.getY() + dy, location.getZ() + dz, block);
return getExtent().setBlock(location.x() + dx, location.y() + dy, location.z() + dz, block);
}
@Override
@ -49,7 +49,7 @@ public class BlockTranslateExtent extends AbstractDelegateExtent {
@Override
public BlockState getBlock(BlockVector3 location) {
return getBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ());
return getBlock(location.x(), location.y(), location.z());
}
@Override

View File

@ -101,7 +101,7 @@ public class DisallowedBlocksExtent extends AbstractDelegateExtent implements IB
@SuppressWarnings("unchecked")
private <B extends BlockStateHolder<B>> B checkBlock(B block) {
if (blockedBlocks != null) {
if (blockedBlocks.contains(block.getBlockType().getId())) {
if (blockedBlocks.contains(block.getBlockType().id())) {
return (B) (block instanceof BlockState ? RESERVED : RESERVED.toBaseBlock()); // set to reserved/empty
}
}
@ -140,7 +140,7 @@ public class DisallowedBlocksExtent extends AbstractDelegateExtent implements IB
}
BlockState state = BlockTypesCache.states[block];
if (blockedBlocks != null) {
if (blockedBlocks.contains(state.getBlockType().getId())) {
if (blockedBlocks.contains(state.getBlockType().id())) {
blocks[i] = BlockTypesCache.ReservedIDs.__RESERVED__;
continue;
}

View File

@ -64,11 +64,11 @@ public abstract class FaweRegionExtent extends ResettableExtent implements IBatc
@Override
public final boolean contains(BlockVector3 p) {
return contains(p.getBlockX(), p.getBlockY(), p.getBlockZ());
return contains(p.x(), p.y(), p.z());
}
public final boolean contains(BlockVector2 p) {
return contains(p.getBlockX(), p.getBlockZ());
return contains(p.x(), p.z());
}
@Override
@ -96,12 +96,12 @@ public abstract class FaweRegionExtent extends ResettableExtent implements IBatc
@Override
public BiomeType getBiome(BlockVector3 position) {
return getBiomeType(position.getX(), position.getY(), position.getZ());
return getBiomeType(position.x(), position.y(), position.z());
}
@Override
public BiomeType getBiomeType(int x, int y, int z) {
if (!contains(x, z)) {
if (!contains(x, y, z)) {
if (!limit.MAX_FAILS()) {
WEManager.weManager().cancelEditSafe(this, FaweCache.OUTSIDE_REGION);
}
@ -112,7 +112,7 @@ public abstract class FaweRegionExtent extends ResettableExtent implements IBatc
@Override
public BaseBlock getFullBlock(BlockVector3 position) {
return getFullBlock(position.getX(), position.getY(), position.getZ());
return getFullBlock(position.x(), position.y(), position.z());
}
@Override
@ -128,7 +128,7 @@ public abstract class FaweRegionExtent extends ResettableExtent implements IBatc
@Override
public BlockState getBlock(BlockVector3 position) {
return getBlock(position.getX(), position.getY(), position.getZ());
return getBlock(position.x(), position.y(), position.z());
}
@Override

View File

@ -6,12 +6,11 @@ import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet;
import com.fastasyncworldedit.core.regions.RegionWrapper;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
public class HeightBoundExtent extends FaweRegionExtent {
@ -50,7 +49,8 @@ public class HeightBoundExtent extends FaweRegionExtent {
@Override
public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) {
if (trimY(set, min, max, true) | trimNBT(set, this::contains)) {
BlockVector3 chunkPos = chunk.getChunkBlockCoord().withY(0);
if (trimY(set, min, max, true) | trimNBT(set, this::contains, pos -> this.contains(pos.add(chunkPos)))) {
return set;
}
return null;

View File

@ -2,6 +2,7 @@ package com.fastasyncworldedit.core.extent;
import com.fastasyncworldedit.core.history.changeset.AbstractChangeSet;
import com.fastasyncworldedit.core.math.MutableBlockVector3;
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
@ -66,7 +67,7 @@ public class HistoryExtent extends AbstractDelegateExtent {
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block) throws WorldEditException {
return setBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ(), block);
return setBlock(location.x(), location.y(), location.z(), block);
}
@Nullable
@ -74,7 +75,7 @@ public class HistoryExtent extends AbstractDelegateExtent {
public Entity createEntity(Location location, BaseEntity state) {
final Entity entity = super.createEntity(location, state);
if (state != null) {
this.changeSet.addEntityCreate(state.getNbtData());
this.changeSet.addEntityCreate(FaweCompoundTag.of(state.getNbt()));
}
return entity;
}
@ -84,7 +85,7 @@ public class HistoryExtent extends AbstractDelegateExtent {
public Entity createEntity(Location location, BaseEntity state, UUID uuid) {
final Entity entity = super.createEntity(location, state, uuid);
if (state != null) {
this.changeSet.addEntityCreate(state.getNbtData());
this.changeSet.addEntityCreate(FaweCompoundTag.of(state.getNbt()));
}
return entity;
}
@ -110,8 +111,8 @@ public class HistoryExtent extends AbstractDelegateExtent {
@Override
public boolean setBiome(BlockVector3 position, BiomeType newBiome) {
BiomeType oldBiome = this.getBiome(position);
if (!oldBiome.getId().equals(newBiome.getId())) {
this.changeSet.addBiomeChange(position.getBlockX(), position.getBlockY(), position.getBlockZ(), oldBiome, newBiome);
if (!oldBiome.id().equals(newBiome.id())) {
this.changeSet.addBiomeChange(position.x(), position.y(), position.z(), oldBiome, newBiome);
return getExtent().setBiome(position, newBiome);
} else {
return false;
@ -121,7 +122,7 @@ public class HistoryExtent extends AbstractDelegateExtent {
@Override
public boolean setBiome(int x, int y, int z, BiomeType newBiome) {
BiomeType oldBiome = this.getBiome(mutable.setComponents(x, y, z));
if (!oldBiome.getId().equals(newBiome.getId())) {
if (!oldBiome.id().equals(newBiome.id())) {
this.changeSet.addBiomeChange(x, y, z, oldBiome, newBiome);
return getExtent().setBiome(x, y, z, newBiome);
} else {
@ -154,11 +155,10 @@ public class HistoryExtent extends AbstractDelegateExtent {
@Override
public boolean remove() {
final Location location = this.entity.getLocation();
final BaseEntity state = this.entity.getState();
final boolean success = this.entity.remove();
if (state != null && success) {
HistoryExtent.this.changeSet.addEntityRemove(state.getNbtData());
HistoryExtent.this.changeSet.addEntityRemove(FaweCompoundTag.of(state.getNbt()));
}
return success;
}

View File

@ -1,11 +1,15 @@
package com.fastasyncworldedit.core.extent;
import com.fastasyncworldedit.core.extent.filter.block.ExtentFilterBlock;
import com.fastasyncworldedit.core.function.generator.GenBase;
import com.fastasyncworldedit.core.function.generator.Resource;
import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
import com.fastasyncworldedit.core.internal.exception.FaweException;
import com.fastasyncworldedit.core.limit.FaweLimit;
import com.fastasyncworldedit.core.queue.Filter;
import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IChunk;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet;
import com.fastasyncworldedit.core.util.ExtentTraverser;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEditException;
@ -17,7 +21,6 @@ import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.formatting.text.Component;
@ -37,18 +40,22 @@ import java.util.Set;
import java.util.UUID;
import java.util.function.Consumer;
public class LimitExtent extends AbstractDelegateExtent {
public class LimitExtent extends AbstractDelegateExtent implements IBatchProcessor {
private final FaweLimit limit;
private final boolean[] faweExceptionReasonsUsed = new boolean[FaweException.Type.values().length];
private final Consumer<Component> onErrorMessage;
private final int chunk_size;
private boolean processing;
/**
* Create a new instance.
*
* @param extent the extent
* @param limit the limit
* @deprecated Use {@link LimitExtent#LimitExtent(Extent, FaweLimit, Consumer, boolean)}
*/
@Deprecated(forRemoval = true, since = "2.12.0")
public LimitExtent(Extent extent, FaweLimit limit) {
this(extent, limit, c -> {
});
@ -60,11 +67,33 @@ public class LimitExtent extends AbstractDelegateExtent {
* @param extent the extent
* @param limit the limit
* @param onErrorMessage consumer to handle a component generated by exceptions
* @deprecated Use {@link LimitExtent#LimitExtent(Extent, FaweLimit, Consumer, boolean)}
*/
@Deprecated(forRemoval = true, since = "2.12.0")
public LimitExtent(Extent extent, FaweLimit limit, Consumer<Component> onErrorMessage) {
this(extent, limit, onErrorMessage, false);
}
/**
* Create a new instance.
*
* @param extent the extent
* @param limit the limit
* @param onErrorMessage consumer to handle a component generated by exceptions
* @param processing if this limit extent is expected to be processing
* @since 2.12.0
*/
public LimitExtent(
Extent extent,
FaweLimit limit,
Consumer<Component> onErrorMessage,
boolean processing
) {
super(extent);
this.limit = limit;
this.onErrorMessage = onErrorMessage;
this.chunk_size = 16 * 16 * (extent.getMaxY() - extent.getMinY());
this.processing = processing;
}
private void handleException(FaweException e) {
@ -81,7 +110,7 @@ public class LimitExtent extends AbstractDelegateExtent {
public List<? extends Entity> getEntities(Region region) {
limit.THROW_MAX_CHECKS(region.getVolume());
try {
return super.getEntities(region);
return extent.getEntities(region);
} catch (FaweException e) {
handleException(e);
return Collections.emptyList();
@ -92,7 +121,7 @@ public class LimitExtent extends AbstractDelegateExtent {
public List<? extends Entity> getEntities() {
limit.THROW_MAX_CHECKS();
try {
return super.getEntities();
return extent.getEntities();
} catch (FaweException e) {
handleException(e);
return Collections.emptyList();
@ -105,7 +134,7 @@ public class LimitExtent extends AbstractDelegateExtent {
limit.THROW_MAX_CHANGES();
limit.THROW_MAX_ENTITIES();
try {
return super.createEntity(location, entity);
return extent.createEntity(location, entity);
} catch (FaweException e) {
handleException(e);
return null;
@ -118,7 +147,7 @@ public class LimitExtent extends AbstractDelegateExtent {
limit.THROW_MAX_CHANGES();
limit.THROW_MAX_ENTITIES();
try {
return super.createEntity(location, entity, uuid);
return extent.createEntity(location, entity, uuid);
} catch (FaweException e) {
handleException(e);
return null;
@ -130,7 +159,7 @@ public class LimitExtent extends AbstractDelegateExtent {
limit.THROW_MAX_CHANGES();
limit.THROW_MAX_ENTITIES();
try {
super.removeEntity(x, y, z, uuid);
extent.removeEntity(x, y, z, uuid);
} catch (FaweException e) {
handleException(e);
}
@ -138,9 +167,9 @@ public class LimitExtent extends AbstractDelegateExtent {
@Override
public boolean regenerateChunk(int x, int z, @Nullable BiomeType type, @Nullable Long seed) {
limit.THROW_MAX_CHANGES(Character.MAX_VALUE);
limit.THROW_MAX_CHANGES(chunk_size);
try {
return super.regenerateChunk(x, z, type, seed);
return extent.regenerateChunk(x, z, type, seed);
} catch (FaweException e) {
handleException(e);
return false;
@ -151,7 +180,7 @@ public class LimitExtent extends AbstractDelegateExtent {
public int getHighestTerrainBlock(int x, int z, int minY, int maxY) {
limit.THROW_MAX_CHECKS(maxY - minY + 1);
try {
return super.getHighestTerrainBlock(x, z, minY, maxY);
return extent.getHighestTerrainBlock(x, z, minY, maxY);
} catch (FaweException e) {
handleException(e);
return minY;
@ -162,7 +191,7 @@ public class LimitExtent extends AbstractDelegateExtent {
public int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) {
limit.THROW_MAX_CHECKS(maxY - minY + 1);
try {
return super.getHighestTerrainBlock(x, z, minY, maxY, filter);
return extent.getHighestTerrainBlock(x, z, minY, maxY, filter);
} catch (FaweException e) {
handleException(e);
return minY;
@ -173,7 +202,7 @@ public class LimitExtent extends AbstractDelegateExtent {
public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
limit.THROW_MAX_CHECKS(maxY - minY + 1);
try {
return super.getNearestSurfaceLayer(x, z, y, minY, maxY);
return extent.getNearestSurfaceLayer(x, z, y, minY, maxY);
} catch (FaweException e) {
handleException(e);
return minY;
@ -184,7 +213,7 @@ public class LimitExtent extends AbstractDelegateExtent {
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) {
limit.THROW_MAX_CHECKS(maxY - minY + 1);
try {
return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir);
return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir);
} catch (FaweException e) {
handleException(e);
return minY;
@ -195,7 +224,7 @@ public class LimitExtent extends AbstractDelegateExtent {
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) {
limit.THROW_MAX_CHECKS(maxY - minY + 1);
try {
return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY);
return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY);
} catch (FaweException e) {
handleException(e);
return minY;
@ -206,7 +235,7 @@ public class LimitExtent extends AbstractDelegateExtent {
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) {
limit.THROW_MAX_CHECKS(maxY - minY + 1);
try {
return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax);
return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax);
} catch (FaweException e) {
handleException(e);
return minY;
@ -217,7 +246,7 @@ public class LimitExtent extends AbstractDelegateExtent {
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) {
limit.THROW_MAX_CHECKS(maxY - minY + 1);
try {
return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask);
return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask);
} catch (FaweException e) {
handleException(e);
return minY;
@ -237,91 +266,47 @@ public class LimitExtent extends AbstractDelegateExtent {
) {
limit.THROW_MAX_CHECKS(maxY - minY + 1);
try {
return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir);
return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir);
} catch (FaweException e) {
handleException(e);
return minY;
}
}
@Override
public void addCaves(Region region) throws WorldEditException {
limit.THROW_MAX_CHECKS(region.getVolume());
limit.THROW_MAX_CHANGES(region.getVolume());
super.addCaves(region);
}
@Override
public void generate(Region region, GenBase gen) throws WorldEditException {
limit.THROW_MAX_CHECKS(region.getVolume());
limit.THROW_MAX_CHANGES(region.getVolume());
super.generate(region, gen);
}
@Override
public void addSchems(Region region, Mask mask, List<ClipboardHolder> clipboards, int rarity, boolean rotate) throws
WorldEditException {
limit.THROW_MAX_CHECKS(region.getVolume());
limit.THROW_MAX_CHANGES(region.getVolume());
super.addSchems(region, mask, clipboards, rarity, rotate);
}
@Override
public void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException {
limit.THROW_MAX_CHECKS(region.getVolume());
limit.THROW_MAX_CHANGES(region.getVolume());
super.spawnResource(region, gen, rarity, frequency);
}
@Override
public void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws
WorldEditException {
limit.THROW_MAX_CHECKS(region.getVolume());
limit.THROW_MAX_CHANGES(region.getVolume());
super.addOre(region, mask, material, size, frequency, rarity, minY, maxY);
}
@Override
public void addOres(Region region, Mask mask) throws WorldEditException {
limit.THROW_MAX_CHECKS(region.getVolume());
limit.THROW_MAX_CHANGES(region.getVolume());
super.addOres(region, mask);
}
@Override
public List<Countable<BlockType>> getBlockDistribution(Region region) {
limit.THROW_MAX_CHECKS(region.getVolume());
return super.getBlockDistribution(region);
return extent.getBlockDistribution(region);
}
@Override
public List<Countable<BlockState>> getBlockDistributionWithData(Region region) {
limit.THROW_MAX_CHECKS(region.getVolume());
return super.getBlockDistributionWithData(region);
return extent.getBlockDistributionWithData(region);
}
@Override
public int countBlocks(Region region, Set<BaseBlock> searchBlocks) {
limit.THROW_MAX_CHECKS(region.getVolume());
return super.countBlocks(region, searchBlocks);
return extent.countBlocks(region, searchBlocks);
}
@Override
public int countBlocks(Region region, Mask searchMask) {
limit.THROW_MAX_CHECKS(region.getVolume());
return super.countBlocks(region, searchMask);
return extent.countBlocks(region, searchMask);
}
@Override
public <B extends BlockStateHolder<B>> int setBlocks(Region region, B block) throws MaxChangedBlocksException {
limit.THROW_MAX_CHANGES(region.getVolume());
return super.setBlocks(region, block);
return extent.setBlocks(region, block);
}
@Override
public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException {
limit.THROW_MAX_CHANGES(region.getVolume());
return super.setBlocks(region, pattern);
return extent.setBlocks(region, pattern);
}
@Override
@ -329,41 +314,34 @@ public class LimitExtent extends AbstractDelegateExtent {
MaxChangedBlocksException {
limit.THROW_MAX_CHECKS(region.getVolume());
limit.THROW_MAX_CHANGES(region.getVolume());
return super.replaceBlocks(region, filter, replacement);
return extent.replaceBlocks(region, filter, replacement);
}
@Override
public int replaceBlocks(Region region, Set<BaseBlock> filter, Pattern pattern) throws MaxChangedBlocksException {
limit.THROW_MAX_CHECKS(region.getVolume());
limit.THROW_MAX_CHANGES(region.getVolume());
return super.replaceBlocks(region, filter, pattern);
return extent.replaceBlocks(region, filter, pattern);
}
@Override
public int replaceBlocks(Region region, Mask mask, Pattern pattern) throws MaxChangedBlocksException {
limit.THROW_MAX_CHECKS(region.getVolume());
limit.THROW_MAX_CHANGES(region.getVolume());
return super.replaceBlocks(region, mask, pattern);
}
@Override
public int center(Region region, Pattern pattern) throws MaxChangedBlocksException {
limit.THROW_MAX_CHECKS(region.getVolume());
limit.THROW_MAX_CHANGES(region.getVolume());
return super.center(region, pattern);
return extent.replaceBlocks(region, mask, pattern);
}
@Override
public int setBlocks(Set<BlockVector3> vset, Pattern pattern) {
limit.THROW_MAX_CHANGES(vset.size());
return super.setBlocks(vset, pattern);
return extent.setBlocks(vset, pattern);
}
@Override
public <T extends Filter> T apply(Region region, T filter, boolean full) {
limit.THROW_MAX_CHECKS(region.getVolume());
limit.THROW_MAX_CHANGES(region.getVolume());
return super.apply(region, filter, full);
return extent.apply(region, filter, full);
}
@Override
@ -373,12 +351,12 @@ public class LimitExtent extends AbstractDelegateExtent {
size = ((Collection<BlockVector3>) positions).size();
} else if (positions instanceof Region) {
BlockVector3 dim = ((Region) positions).getDimensions();
size = dim.getX() * dim.getY() * dim.getZ();
size = dim.x() * dim.y() * dim.z();
} else if (positions instanceof Extent) {
BlockVector3 min = ((Extent) positions).getMinimumPoint();
BlockVector3 max = ((Extent) positions).getMinimumPoint();
BlockVector3 dim = max.subtract(min).add(BlockVector3.ONE);
size = dim.getX() * dim.getY() * dim.getZ();
size = dim.x() * dim.y() * dim.z();
} else {
ExtentFilterBlock block = new ExtentFilterBlock(this);
for (BlockVector3 pos : positions) {
@ -393,14 +371,14 @@ public class LimitExtent extends AbstractDelegateExtent {
}
limit.THROW_MAX_CHECKS(size);
limit.THROW_MAX_CHANGES(size);
return super.apply(positions, filter);
return extent.apply(positions, filter);
}
@Override
public BlockState getBlock(BlockVector3 position) {
limit.THROW_MAX_CHECKS();
try {
return super.getBlock(position);
return extent.getBlock(position);
} catch (FaweException e) {
handleException(e);
return BlockTypes.AIR.getDefaultState();
@ -411,7 +389,7 @@ public class LimitExtent extends AbstractDelegateExtent {
public BlockState getBlock(int x, int y, int z) {
limit.THROW_MAX_CHECKS();
try {
return super.getBlock(x, y, z);
return extent.getBlock(x, y, z);
} catch (FaweException e) {
handleException(e);
return BlockTypes.AIR.getDefaultState();
@ -422,7 +400,7 @@ public class LimitExtent extends AbstractDelegateExtent {
public BaseBlock getFullBlock(BlockVector3 position) {
limit.THROW_MAX_CHECKS();
try {
return super.getFullBlock(position);
return extent.getFullBlock(position);
} catch (FaweException e) {
handleException(e);
return BlockTypes.AIR.getDefaultState().toBaseBlock();
@ -433,7 +411,7 @@ public class LimitExtent extends AbstractDelegateExtent {
public BaseBlock getFullBlock(int x, int y, int z) {
limit.THROW_MAX_CHECKS();
try {
return super.getFullBlock(x, y, z);
return extent.getFullBlock(x, y, z);
} catch (FaweException e) {
handleException(e);
return BlockTypes.AIR.getDefaultState().toBaseBlock();
@ -444,7 +422,7 @@ public class LimitExtent extends AbstractDelegateExtent {
public BiomeType getBiome(BlockVector3 position) {
limit.THROW_MAX_CHECKS();
try {
return super.getBiome(position);
return extent.getBiome(position);
} catch (FaweException e) {
handleException(e);
return BiomeTypes.FOREST;
@ -455,7 +433,7 @@ public class LimitExtent extends AbstractDelegateExtent {
public BiomeType getBiomeType(int x, int y, int z) {
limit.THROW_MAX_CHECKS();
try {
return super.getBiomeType(x, y, z);
return extent.getBiomeType(x, y, z);
} catch (FaweException e) {
handleException(e);
return BiomeTypes.FOREST;
@ -470,7 +448,7 @@ public class LimitExtent extends AbstractDelegateExtent {
limit.THROW_MAX_BLOCKSTATES();
}
try {
return super.setBlock(position, block);
return extent.setBlock(position, block);
} catch (FaweException e) {
handleException(e);
return false;
@ -484,7 +462,7 @@ public class LimitExtent extends AbstractDelegateExtent {
limit.THROW_MAX_BLOCKSTATES();
}
try {
return super.setBlock(x, y, z, block);
return extent.setBlock(x, y, z, block);
} catch (FaweException e) {
handleException(e);
return false;
@ -494,9 +472,9 @@ public class LimitExtent extends AbstractDelegateExtent {
@Override
public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
limit.THROW_MAX_CHANGES();
limit.MAX_BLOCKSTATES();
limit.THROW_MAX_BLOCKSTATES();
try {
return super.setTile(x, y, z, tile);
return extent.setTile(x, y, z, tile);
} catch (FaweException e) {
handleException(e);
return false;
@ -507,7 +485,7 @@ public class LimitExtent extends AbstractDelegateExtent {
public boolean setBiome(BlockVector3 position, BiomeType biome) {
limit.THROW_MAX_CHANGES();
try {
return super.setBiome(position, biome);
return extent.setBiome(position, biome);
} catch (FaweException e) {
handleException(e);
return false;
@ -518,11 +496,41 @@ public class LimitExtent extends AbstractDelegateExtent {
public boolean setBiome(int x, int y, int z, BiomeType biome) {
limit.THROW_MAX_CHANGES();
try {
return super.setBiome(x, y, z, biome);
return extent.setBiome(x, y, z, biome);
} catch (FaweException e) {
handleException(e);
return false;
}
}
public void setProcessing(boolean processing) {
this.processing = processing;
}
@Override
public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) {
if (!processing) {
return set;
}
int tiles = set.tiles().size();
int ents = set.entities().size() + set.getEntityRemoves().size();
limit.THROW_MAX_CHANGES(tiles + ents);
limit.THROW_MAX_BLOCKSTATES(tiles);
limit.THROW_MAX_ENTITIES(ents);
return set;
}
@Override
public Extent construct(final Extent child) {
if (extent != child) {
new ExtentTraverser<Extent>(this).setNext(child);
}
return this;
}
@Override
public ProcessorScope getScope() {
return ProcessorScope.READING_SET_BLOCKS;
}
}

View File

@ -38,9 +38,9 @@ public class PositionTransformExtent extends ResettableExtent {
if (min == null) {
min = pos;
}
mutable.mutX(pos.getX() - min.getX());
mutable.mutY(pos.getY() - min.getY());
mutable.mutZ(pos.getZ() - min.getZ());
mutable.mutX(pos.x() - min.x());
mutable.mutY(pos.y() - min.y());
mutable.mutZ(pos.z() - min.z());
MutableVector3 tmp = new MutableVector3(transform.apply(mutable.toVector3()));
return min.add(tmp.roundHalfUp().toBlockPoint());
}
@ -49,9 +49,9 @@ public class PositionTransformExtent extends ResettableExtent {
if (min == null) {
min = BlockVector3.at(x, y, z);
}
mutable.mutX(x - min.getX());
mutable.mutY(y - min.getY());
mutable.mutZ(z - min.getZ());
mutable.mutX(x - min.x());
mutable.mutY(y - min.y());
mutable.mutZ(z - min.z());
MutableVector3 tmp = new MutableVector3(transform.apply(mutable.toVector3()));
return min.add(tmp.roundHalfUp().toBlockPoint());
}
@ -73,10 +73,10 @@ public class PositionTransformExtent extends ResettableExtent {
@Override
public BiomeType getBiome(BlockVector3 position) {
mutable.mutX(position.getBlockX());
mutable.mutZ(position.getBlockZ());
mutable.mutY(position.getBlockY());
return super.getBiome(getPos(mutable.getX(), mutable.getY(), mutable.getZ()));
mutable.mutX(position.x());
mutable.mutZ(position.z());
mutable.mutY(position.y());
return super.getBiome(getPos(mutable.x(), mutable.y(), mutable.z()));
}
@Override
@ -92,10 +92,10 @@ public class PositionTransformExtent extends ResettableExtent {
@Override
public boolean setBiome(BlockVector3 position, BiomeType biome) {
mutable.mutX(position.getBlockX());
mutable.mutZ(position.getBlockZ());
mutable.mutY(position.getBlockY());
return super.setBiome(getPos(mutable.getX(), mutable.getY(), mutable.getZ()), biome);
mutable.mutX(position.x());
mutable.mutZ(position.z());
mutable.mutY(position.y());
return super.setBiome(getPos(mutable.x(), mutable.y(), mutable.z()), biome);
}
public void setTransform(Transform transform) {

View File

@ -80,12 +80,12 @@ public class ProcessedWEExtent extends AbstractDelegateExtent {
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block)
throws WorldEditException {
return setBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ(), block);
return setBlock(location.x(), location.y(), location.z(), block);
}
@Override
public BlockState getBlock(BlockVector3 location) {
return getBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ());
return getBlock(location.x(), location.y(), location.z());
}
@Override

View File

@ -41,8 +41,8 @@ public class SourceMaskExtent extends TemporalExtent {
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 location, T block) throws WorldEditException {
set(location.getBlockX(), location.getBlockY(), location.getBlockZ(), block);
return mask.test(location) && super.setBlock(location.getX(), location.getY(), location.getZ(), block);
set(location.x(), location.y(), location.z(), block);
return mask.test(location) && super.setBlock(location.x(), location.y(), location.z(), block);
}
@Override

View File

@ -2,14 +2,12 @@ package com.fastasyncworldedit.core.extent;
import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
import com.fastasyncworldedit.core.math.BlockVector3ChunkMap;
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IChunk;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet;
import com.fastasyncworldedit.core.util.ExtentTraverser;
import com.google.common.collect.ImmutableMap;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
@ -20,18 +18,17 @@ import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.NbtValued;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import org.enginehub.linbus.tree.LinCompoundTag;
import org.enginehub.linbus.tree.LinTag;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProcessor {
@ -77,79 +74,82 @@ public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProc
if (!(block instanceof BaseBlock localBlock)) {
return block;
}
if (!localBlock.hasNbtData()) {
final LinCompoundTag nbt = localBlock.getNbt();
if (nbt == null) {
return block;
}
CompoundTag nbt = localBlock.getNbtData();
Map<String, Tag> value = new HashMap<>(nbt.getValue());
LinCompoundTag.Builder nbtBuilder = nbt.toBuilder();
for (String key : strip) {
value.remove(key);
nbtBuilder.remove(key);
}
return (B) localBlock.toBaseBlock(new CompoundTag(value));
return (B) localBlock.toBaseBlock(nbtBuilder.build());
}
public <T extends NbtValued> T stripEntityNBT(T entity) {
if (!entity.hasNbtData()) {
LinCompoundTag nbt = entity.getNbt();
if (nbt == null) {
return entity;
}
CompoundTag nbt = entity.getNbtData();
Map<String, Tag> value = new HashMap<>(nbt.getValue());
LinCompoundTag.Builder nbtBuilder = nbt.toBuilder();
for (String key : strip) {
value.remove(key);
nbtBuilder.remove(key);
}
entity.setNbtData(new CompoundTag(value));
entity.setNbt(nbtBuilder.build());
return entity;
}
@Override
public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
Map<BlockVector3, CompoundTag> tiles = set.getTiles();
Set<CompoundTag> entities = set.getEntities();
Map<BlockVector3, FaweCompoundTag> tiles = set.tiles();
Collection<FaweCompoundTag> entities = set.entities();
if (tiles.isEmpty() && entities.isEmpty()) {
return set;
}
boolean isBv3ChunkMap = tiles instanceof BlockVector3ChunkMap;
for (final Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) {
ImmutableMap.Builder<String, Tag> map = ImmutableMap.builder();
final AtomicBoolean isStripped = new AtomicBoolean(false);
entry.getValue().getValue().forEach((k, v) -> {
if (strip.contains(k.toLowerCase())) {
isStripped.set(true);
} else {
map.put(k, v);
}
});
if (isStripped.get()) {
for (final var entry : tiles.entrySet()) {
FaweCompoundTag original = entry.getValue();
FaweCompoundTag result = stripNbt(original);
if (original != result) {
if (isBv3ChunkMap) {
// Replace existing value with stripped value
tiles.put(entry.getKey(), new CompoundTag(map.build()));
tiles.put(entry.getKey(), result);
} else {
entry.setValue(new CompoundTag(map.build()));
entry.setValue(result);
}
}
}
Set<CompoundTag> stripped = new HashSet<>();
Iterator<CompoundTag> iterator = entities.iterator();
Set<FaweCompoundTag> stripped = new HashSet<>();
Iterator<FaweCompoundTag> iterator = entities.iterator();
while (iterator.hasNext()) {
CompoundTag entity = iterator.next();
ImmutableMap.Builder<String, Tag> map = ImmutableMap.builder();
final AtomicBoolean isStripped = new AtomicBoolean(false);
entity.getValue().forEach((k, v) -> {
if (strip.contains(k.toUpperCase(Locale.ROOT))) {
isStripped.set(true);
} else {
map.put(k, v);
}
});
if (isStripped.get()) {
FaweCompoundTag original = iterator.next();
FaweCompoundTag result = stripNbt(original);
if (original != result) {
iterator.remove();
stripped.add(new CompoundTag(map.build()));
stripped.add(result);
}
}
set.getEntities().addAll(stripped);
// this relies on entities.addAll(...) not throwing an exception if empty+unmodifiable (=> stripped is empty too)
entities.addAll(stripped);
return set;
}
private FaweCompoundTag stripNbt(
FaweCompoundTag compoundTag
) {
LinCompoundTag.Builder builder = LinCompoundTag.builder();
boolean stripped = false;
for (var entry : compoundTag.linTag().value().entrySet()) {
String k = entry.getKey();
LinTag<?> v = entry.getValue();
if (strip.contains(k.toLowerCase(Locale.ROOT))) {
stripped = true;
} else {
builder.put(k, v);
}
}
return stripped ? FaweCompoundTag.of(builder.build()) : compoundTag;
}
@Nullable
@Override
public Extent construct(final Extent child) {

View File

@ -44,7 +44,7 @@ public class TemporalExtent extends PassthroughExtent {
@Override
public BlockState getBlock(BlockVector3 position) {
if (position.getX() == x && position.getY() == y && position.getZ() == z) {
if (position.x() == x && position.y() == y && position.z() == z) {
return block.toImmutableState();
}
return super.getBlock(position);
@ -60,7 +60,7 @@ public class TemporalExtent extends PassthroughExtent {
@Override
public BaseBlock getFullBlock(BlockVector3 position) {
if (position.getX() == x && position.getY() == y && position.getZ() == z) {
if (position.x() == x && position.y() == y && position.z() == z) {
if (block instanceof BaseBlock) {
return (BaseBlock) block;
} else {
@ -72,7 +72,7 @@ public class TemporalExtent extends PassthroughExtent {
@Override
public BiomeType getBiome(BlockVector3 position) {
if (position.getX() == bx && position.getZ() == bz) {
if (position.x() == bx && position.z() == bz) {
return biome;
}
return super.getBiome(position);

Some files were not shown because too many files have changed in this diff Show More