Telesphoreo 2024-03-16 14:34:54 -05:00
commit c259540f86
No known key found for this signature in database
GPG Key ID: 9D1991811E093C02
38 changed files with 251 additions and 121 deletions

View File

@ -33,9 +33,6 @@
"Renovate" "Renovate"
], ],
"rebaseWhen" : "conflicted", "rebaseWhen" : "conflicted",
"schedule" : [
"on the first day of the month"
],
"customManagers" : [ "customManagers" : [
{ {
"customType" : "regex", "customType" : "regex",

View File

@ -11,7 +11,7 @@ jobs:
- name: Checkout Repository - name: Checkout Repository
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Validate Gradle Wrapper - name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1 uses: gradle/wrapper-validation-action@v2
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:

View File

@ -11,7 +11,7 @@ jobs:
- name: Checkout Repository - name: Checkout Repository
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Validate Gradle Wrapper - name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1 uses: gradle/wrapper-validation-action@v2
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:

View File

@ -12,6 +12,6 @@ jobs:
if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }} if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: release-drafter/release-drafter@v5 - uses: release-drafter/release-drafter@v6
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -9,7 +9,7 @@ jobs:
- name: Checkout Repository - name: Checkout Repository
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Validate Gradle Wrapper - name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1 uses: gradle/wrapper-validation-action@v2
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:

View File

@ -7,7 +7,7 @@ import xyz.jpenilla.runpaper.task.RunServer
plugins { plugins {
id("io.github.gradle-nexus.publish-plugin") version "1.3.0" id("io.github.gradle-nexus.publish-plugin") version "1.3.0"
id("xyz.jpenilla.run-paper") version "2.2.2" id("xyz.jpenilla.run-paper") version "2.2.3"
} }
if (!File("$rootDir/.git").exists()) { if (!File("$rootDir/.git").exists()) {
@ -34,7 +34,7 @@ logger.lifecycle("""
******************************************* *******************************************
""") """)
var rootVersion by extra("2.8.5") var rootVersion by extra("2.9.2")
var snapshot by extra("SNAPSHOT") var snapshot by extra("SNAPSHOT")
var revision: String by extra("") var revision: String by extra("")
var buildNumber by extra("") var buildNumber by extra("")

View File

@ -22,7 +22,7 @@ val properties = Properties().also { props ->
dependencies { dependencies {
implementation(gradleApi()) implementation(gradleApi())
implementation("org.ajoberstar.grgit:grgit-gradle:5.2.1") implementation("org.ajoberstar.grgit:grgit-gradle:5.2.2")
implementation("com.github.johnrengelman:shadow:8.1.1") implementation("com.github.johnrengelman:shadow:8.1.1")
implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.11") implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.11")
} }

View File

@ -14,14 +14,14 @@ mapmanager = "1.8.0-SNAPSHOT"
griefprevention = "17.0.0" griefprevention = "17.0.0"
griefdefender = "2.1.0-SNAPSHOT" griefdefender = "2.1.0-SNAPSHOT"
residence = "4.5._13.1" residence = "4.5._13.1"
towny = "0.100.1.5" towny = "0.100.1.20"
plotsquared = "7.3.1" plotsquared = "7.3.6"
# Third party # Third party
bstats = "3.0.2" bstats = "3.0.2"
sparsebitset = "1.3" sparsebitset = "1.3"
parallelgzip = "1.0.5" parallelgzip = "1.0.5"
adventure = "4.15.0" adventure = "4.16.0"
adventure-bukkit = "4.3.2" adventure-bukkit = "4.3.2"
checkerqual = "3.42.0" checkerqual = "3.42.0"
truezip = "6.8.4" truezip = "6.8.4"
@ -43,10 +43,10 @@ serverlib = "2.3.4"
## Internal ## Internal
text-adapter = "3.0.6" text-adapter = "3.0.6"
text = "3.0.4" text = "3.0.4"
piston = "0.5.7" piston = "0.5.8"
# Tests # Tests
mockito = "5.9.0" mockito = "5.11.0"
# Gradle plugins # Gradle plugins
pluginyml = "0.6.0" pluginyml = "0.6.0"

View File

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

20
gradlew.bat vendored
View File

@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute if %ERRORLEVEL% equ 0 goto execute
echo. echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. echo location of your Java installation. 1>&2
goto fail goto fail
@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute if exist "%JAVA_EXE%" goto execute
echo. echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. echo location of your Java installation. 1>&2
goto fail goto fail

View File

@ -178,7 +178,7 @@ tasks.named<ShadowJar>("shadowJar") {
include(dependency("org.lz4:lz4-java:1.8.0")) include(dependency("org.lz4:lz4-java:1.8.0"))
} }
relocate("net.kyori", "com.fastasyncworldedit.core.adventure") { relocate("net.kyori", "com.fastasyncworldedit.core.adventure") {
include(dependency("net.kyori:adventure-nbt:4.15.0")) include(dependency("net.kyori:adventure-nbt:4.16.0"))
} }
relocate("com.zaxxer", "com.fastasyncworldedit.core.math") { relocate("com.zaxxer", "com.fastasyncworldedit.core.math") {
include(dependency("com.zaxxer:SparseBitSet:1.3")) include(dependency("com.zaxxer:SparseBitSet:1.3"))

View File

@ -163,13 +163,22 @@ public class WorldGuardFeature extends BukkitMaskManager implements Listener {
final Location location = player.getLocation(); final Location location = player.getLocation();
final Set<ProtectedRegion> regions = this.getRegions(localplayer, location, isWhitelist); final Set<ProtectedRegion> regions = this.getRegions(localplayer, location, isWhitelist);
if (!regions.isEmpty()) { if (!regions.isEmpty()) {
RegionManager manager = WorldGuard
.getInstance()
.getPlatform()
.getRegionContainer()
.get(BukkitAdapter.adapt(location.getWorld()));
if (manager == null) {
return null;
}
Set<Region> result = new HashSet<>(); Set<Region> result = new HashSet<>();
for (ProtectedRegion myRegion : regions) { for (ProtectedRegion myRegion : regions) {
if (myRegion.getId().equals("__global__")) { if (myRegion.getId().equals("__global__")) {
return new FaweMask(RegionWrapper.GLOBAL()) { return new FaweMask(RegionWrapper.GLOBAL()) {
@Override @Override
public boolean isValid(com.sk89q.worldedit.entity.Player player, MaskType type) { public boolean isValid(com.sk89q.worldedit.entity.Player player, MaskType type) {
return isAllowed(worldguard.wrapPlayer(BukkitAdapter.adapt(player)), myRegion); return manager.hasRegion(myRegion.getId())
&& isAllowed(worldguard.wrapPlayer(BukkitAdapter.adapt(player)), myRegion);
} }
}; };
} else { } else {
@ -185,7 +194,7 @@ public class WorldGuardFeature extends BukkitMaskManager implements Listener {
public boolean isValid(com.sk89q.worldedit.entity.Player player, MaskType type) { public boolean isValid(com.sk89q.worldedit.entity.Player player, MaskType type) {
final LocalPlayer localplayer = worldguard.wrapPlayer(BukkitAdapter.adapt(player)); final LocalPlayer localplayer = worldguard.wrapPlayer(BukkitAdapter.adapt(player));
for (ProtectedRegion myRegion : regions) { for (ProtectedRegion myRegion : regions) {
if (!isAllowed(localplayer, myRegion)) { if (!manager.hasRegion(myRegion.getId()) || !isAllowed(localplayer, myRegion)) {
return false; return false;
} }
} }

View File

@ -626,7 +626,7 @@ public enum FaweCache implements Trimable {
* Create a new blocking executor with specified name and FaweCache logger * Create a new blocking executor with specified name and FaweCache logger
* *
* @return new blocking executor * @return new blocking executor
* @since TODO * @since 2.9.0
*/ */
public ThreadPoolExecutor newBlockingExecutor(String name) { public ThreadPoolExecutor newBlockingExecutor(String name) {
return newBlockingExecutor(name, LOGGER); return newBlockingExecutor(name, LOGGER);
@ -636,7 +636,7 @@ public enum FaweCache implements Trimable {
* Create a new blocking executor with specified name and logger * Create a new blocking executor with specified name and logger
* *
* @return new blocking executor * @return new blocking executor
* @since TODO * @since 2.9.0
*/ */
public ThreadPoolExecutor newBlockingExecutor(String name, Logger logger) { public ThreadPoolExecutor newBlockingExecutor(String name, Logger logger) {
int nThreads = Settings.settings().QUEUE.PARALLEL_THREADS; int nThreads = Settings.settings().QUEUE.PARALLEL_THREADS;

View File

@ -159,18 +159,23 @@ public class RollbackDatabase extends AsyncNotifyQueue {
Future<Integer> future = call(() -> { Future<Integer> future = call(() -> {
try { try {
int count = 0; int count = 0;
String stmtStr; String stmtStr = """
SELECT * FROM `%sedits`
WHERE `time` > ?
AND `x2` >= ?
AND `x1` <= ?
AND `z2` >= ?
AND `z1` <= ?
AND `y2` >= ?
AND `y1` <= ?
""";
if (uuid != null) {
stmtStr += "\n AND `player`= ?";
}
if (ascending) { if (ascending) {
if (uuid == null) { stmtStr += "\n ORDER BY `time` ASC, `id` ASC";
stmtStr = "SELECT * FROM`%sedits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND " +
"`y2`>=? AND `y1`<=? ORDER BY `time` , `id`";
} else {
stmtStr = "SELECT * FROM`%sedits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND " +
"`y2`>=? AND `y1`<=? AND `player`=? ORDER BY `time` ASC, `id` ASC";
}
} else { } else {
stmtStr = "SELECT * FROM`%sedits` WHERE `time`>? AND `x2`>=? AND `x1`<=? AND `z2`>=? AND `z1`<=? AND " + stmtStr += "\n ORDER BY `time` DESC, `id` DESC";
"`y2`>=? AND `y1`<=? AND `player`=? ORDER BY `time` DESC, `id` DESC";
} }
try (PreparedStatement stmt = connection.prepareStatement(stmtStr.formatted(this.prefix))) { try (PreparedStatement stmt = connection.prepareStatement(stmtStr.formatted(this.prefix))) {
stmt.setInt(1, (int) (minTime / 1000)); stmt.setInt(1, (int) (minTime / 1000));

View File

@ -53,7 +53,7 @@ public abstract class RichParser<E> extends InputParser<E> implements AliasedPar
} }
@Nonnull @Nonnull
private Function<String, Stream<? extends String>> extractArguments(String input) { private Function<String, Stream<? extends String>> extractArguments(String input, ParserContext context) {
return prefix -> { return prefix -> {
if (input.length() > prefix.length() && input.startsWith(prefix + "[")) { if (input.length() > prefix.length() && input.startsWith(prefix + "[")) {
// input already contains argument(s) -> extract them // 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; String previous = prefix + builder;
// read the suggestions for the last argument // 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); .map(suggestion -> previous + "[" + suggestion);
} else { } else {
return Stream.of(prefix); return Stream.of(prefix);
@ -95,7 +95,7 @@ public abstract class RichParser<E> extends InputParser<E> implements AliasedPar
public Stream<String> getSuggestions(String input) { public Stream<String> getSuggestions(String input) {
return Arrays.stream(this.prefixes) return Arrays.stream(this.prefixes)
.filter(validPrefix(input)) .filter(validPrefix(input))
.flatMap(extractArguments(input)); .flatMap(extractArguments(input, new ParserContext()));
} }
@Override @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 argumentInput the already provided input for the argument at the given index.
* @param index the index of the argument to get suggestions for. * @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. * @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. * Parses the already split arguments.

View File

@ -97,11 +97,11 @@ public class RichMaskParser extends FaweParser<Mask> {
)), )),
() -> { () -> {
if (full.length() == 1) { if (full.length() == 1) {
return new ArrayList<>(worldEdit.getMaskFactory().getSuggestions("")); return new ArrayList<>(worldEdit.getMaskFactory().getSuggestions("", context));
} }
return new ArrayList<>(worldEdit return new ArrayList<>(worldEdit
.getMaskFactory() .getMaskFactory()
.getSuggestions(command.toLowerCase(Locale.ROOT))); .getSuggestions(command.toLowerCase(Locale.ROOT), context));
} }
); );
} }
@ -164,11 +164,11 @@ public class RichMaskParser extends FaweParser<Mask> {
)), )),
() -> { () -> {
if (full.length() == 1) { if (full.length() == 1) {
return new ArrayList<>(worldEdit.getMaskFactory().getSuggestions("")); return new ArrayList<>(worldEdit.getMaskFactory().getSuggestions("", context));
} }
return new ArrayList<>(worldEdit return new ArrayList<>(worldEdit
.getMaskFactory() .getMaskFactory()
.getSuggestions(command.toLowerCase(Locale.ROOT))); .getSuggestions(command.toLowerCase(Locale.ROOT), context));
} }
); );
} }

View File

@ -12,6 +12,10 @@ import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
/**
* @deprecated Unused internal, will be removed in v3
*/
@Deprecated(forRemoval = true, since = "TODO")
public class TransformExtent extends BlockTransformExtent { public class TransformExtent extends BlockTransformExtent {
private final MutableVector3 mutable1 = new MutableVector3(); private final MutableVector3 mutable1 = new MutableVector3();

View File

@ -18,6 +18,7 @@ import com.fastasyncworldedit.core.queue.Filter;
import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueChunk;
import com.fastasyncworldedit.core.queue.IQueueExtent; import com.fastasyncworldedit.core.queue.IQueueExtent;
import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.mask.BlockMask;
import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.ExistingBlockMask;
@ -45,6 +46,7 @@ import java.util.stream.IntStream;
public class ParallelQueueExtent extends PassthroughExtent { public class ParallelQueueExtent extends PassthroughExtent {
private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final ThreadLocal<Extent> extents = new ThreadLocal<>();
private final World world; private final World world;
private final QueueHandler handler; private final QueueHandler handler;
@ -73,10 +75,36 @@ public class ParallelQueueExtent extends PassthroughExtent {
this.fastmode = fastmode; this.fastmode = fastmode;
} }
/**
* Removes the extent currently associated with the calling thread.
*/
public static void clearCurrentExtent() {
extents.remove();
}
/**
* Sets the extent associated with the calling thread.
*/
public static void setCurrentExtent(Extent extent) {
extents.set(extent);
}
private void enter(Extent extent) {
setCurrentExtent(extent);
}
private void exit() {
clearCurrentExtent();
}
@Override @Override
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
public IQueueExtent<IQueueChunk> getExtent() { public IQueueExtent<IQueueChunk> getExtent() {
return (IQueueExtent<IQueueChunk>) super.getExtent(); Extent extent = extents.get();
if (extent == null) {
extent = super.getExtent();
}
return (IQueueExtent<IQueueChunk>) extent;
} }
@Override @Override
@ -103,9 +131,12 @@ public class ParallelQueueExtent extends PassthroughExtent {
// Get a pool, to operate on the chunks in parallel // Get a pool, to operate on the chunks in parallel
final int size = Math.min(chunks.size(), Settings.settings().QUEUE.PARALLEL_THREADS); final int size = Math.min(chunks.size(), Settings.settings().QUEUE.PARALLEL_THREADS);
if (size <= 1 && chunksIter.hasNext()) { if (size <= 1) {
BlockVector2 pos = chunksIter.next(); // if PQE is ever used with PARALLEL_THREADS = 1, or only one chunk is edited, just run sequentially
getExtent().apply(null, filter, region, pos.getX(), pos.getZ(), full); while (chunksIter.hasNext()) {
BlockVector2 pos = chunksIter.next();
getExtent().apply(null, filter, region, pos.getX(), pos.getZ(), full);
}
} else { } else {
final ForkJoinTask[] tasks = IntStream.range(0, size).mapToObj(i -> handler.submit(() -> { final ForkJoinTask[] tasks = IntStream.range(0, size).mapToObj(i -> handler.submit(() -> {
try { try {
@ -114,6 +145,7 @@ public class ParallelQueueExtent extends PassthroughExtent {
final SingleThreadQueueExtent queue = (SingleThreadQueueExtent) getNewQueue(); final SingleThreadQueueExtent queue = (SingleThreadQueueExtent) getNewQueue();
queue.setFastMode(fastmode); queue.setFastMode(fastmode);
queue.setFaweExceptionArray(faweExceptionReasonsUsed); queue.setFaweExceptionArray(faweExceptionReasonsUsed);
enter(queue);
synchronized (queue) { synchronized (queue) {
try { try {
ChunkFilterBlock block = null; ChunkFilterBlock block = null;
@ -154,6 +186,8 @@ public class ParallelQueueExtent extends PassthroughExtent {
exceptionCount++; exceptionCount++;
LOGGER.warn(message); LOGGER.warn(message);
} }
} finally {
exit();
} }
})).toArray(ForkJoinTask[]::new); })).toArray(ForkJoinTask[]::new);
// Join filters // Join filters

View File

@ -408,7 +408,7 @@ public abstract class QueueHandler implements Trimable, Runnable {
* Sets the current thread's {@link IQueueExtent} instance in the queue pool to null. * Sets the current thread's {@link IQueueExtent} instance in the queue pool to null.
*/ */
public void unCache() { public void unCache() {
queuePool.set(null); queuePool.remove();
} }
private IQueueExtent<IQueueChunk> pool() { private IQueueExtent<IQueueChunk> pool() {

View File

@ -9,7 +9,6 @@ import com.fastasyncworldedit.core.extent.processor.EmptyBatchProcessor;
import com.fastasyncworldedit.core.extent.processor.ExtentBatchProcessorHolder; import com.fastasyncworldedit.core.extent.processor.ExtentBatchProcessorHolder;
import com.fastasyncworldedit.core.extent.processor.ProcessorScope; import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
import com.fastasyncworldedit.core.internal.exception.FaweException; import com.fastasyncworldedit.core.internal.exception.FaweException;
import com.fastasyncworldedit.core.queue.IChunk;
import com.fastasyncworldedit.core.queue.IChunkCache; import com.fastasyncworldedit.core.queue.IChunkCache;
import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.IChunkSet;
@ -48,11 +47,9 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
private static final Logger LOGGER = LogManagerCompat.getLogger(); private static final Logger LOGGER = LogManagerCompat.getLogger();
// Pool discarded chunks for reuse (can safely be cleared by another thread)
// private static final ConcurrentLinkedQueue<IChunk> CHUNK_POOL = new ConcurrentLinkedQueue<>();
// Chunks currently being queued / worked on // Chunks currently being queued / worked on
private final Long2ObjectLinkedOpenHashMap<IQueueChunk> chunks = new Long2ObjectLinkedOpenHashMap<>(); private final Long2ObjectLinkedOpenHashMap<IQueueChunk<?>> chunks = new Long2ObjectLinkedOpenHashMap<>();
private final ConcurrentLinkedQueue<Future> submissions = new ConcurrentLinkedQueue<>(); private final ConcurrentLinkedQueue<Future<?>> submissions = new ConcurrentLinkedQueue<>();
private final ReentrantLock getChunkLock = new ReentrantLock(); private final ReentrantLock getChunkLock = new ReentrantLock();
private World world = null; private World world = null;
private int minY = 0; private int minY = 0;
@ -142,12 +139,10 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
if (!this.initialized) { if (!this.initialized) {
return; return;
} }
if (!this.chunks.isEmpty()) { getChunkLock.lock();
getChunkLock.lock(); try {
for (IChunk chunk : this.chunks.values()) {
chunk.recycle();
}
this.chunks.clear(); this.chunks.clear();
} finally {
getChunkLock.unlock(); getChunkLock.unlock();
} }
this.enabledQueue = true; this.enabledQueue = true;
@ -234,7 +229,6 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
} }
} }
if (chunk.isEmpty()) { if (chunk.isEmpty()) {
chunk.recycle();
Future result = Futures.immediateFuture(null); Future result = Futures.immediateFuture(null);
return (V) result; return (V) result;
} }

View File

@ -1,7 +1,5 @@
package com.fastasyncworldedit.core.queue.implementation.chunk; package com.fastasyncworldedit.core.queue.implementation.chunk;
import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock; import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock;
import com.fastasyncworldedit.core.extent.processor.EmptyBatchProcessor; import com.fastasyncworldedit.core.extent.processor.EmptyBatchProcessor;
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
@ -11,36 +9,34 @@ import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.IChunkSet;
import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueChunk;
import com.fastasyncworldedit.core.queue.IQueueExtent; import com.fastasyncworldedit.core.queue.IQueueExtent;
import com.fastasyncworldedit.core.queue.Pool; import com.fastasyncworldedit.core.queue.implementation.ParallelQueueExtent;
import com.fastasyncworldedit.core.util.MemUtil; import com.fastasyncworldedit.core.util.MemUtil;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
/** /**
* An abstract {@link IChunk} class that implements basic get/set blocks. * An abstract {@link IChunk} class that implements basic get/set blocks.
*/ */
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> { public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final Pool<ChunkHolder> POOL = FaweCache.INSTANCE.registerPool(
ChunkHolder.class,
ChunkHolder::new,
Settings.settings().QUEUE.POOL
);
public static ChunkHolder newInstance() { public static ChunkHolder newInstance() {
return POOL.poll(); return new ChunkHolder();
} }
private volatile IChunkGet chunkExisting; // The existing chunk (e.g. a clipboard, or the world, before changes) private volatile IChunkGet chunkExisting; // The existing chunk (e.g. a clipboard, or the world, before changes)
@ -63,16 +59,12 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
this.delegate = delegate; this.delegate = delegate;
} }
private static final AtomicBoolean recycleWarning = new AtomicBoolean(false);
@Override @Override
public synchronized void recycle() { public void recycle() {
delegate = NULL; if (!recycleWarning.getAndSet(true)) {
if (chunkSet != null) { LOGGER.warn("ChunkHolder should not be recycled.", new Exception());
chunkSet.recycle();
chunkSet = null;
} }
chunkExisting = null;
extent = null;
POOL.offer(this);
} }
public long initAge() { public long initAge() {
@ -1018,7 +1010,6 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
// Do nothing // Do nothing
}); });
} }
recycle();
return null; return null;
} }
@ -1031,6 +1022,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
IChunkGet get = getOrCreateGet(); IChunkGet get = getOrCreateGet();
try { try {
get.lockCall(); get.lockCall();
trackExtent();
boolean postProcess = !(getExtent().getPostProcessor() instanceof EmptyBatchProcessor); boolean postProcess = !(getExtent().getPostProcessor() instanceof EmptyBatchProcessor);
final int copyKey = get.setCreateCopy(postProcess); final int copyKey = get.setCreateCopy(postProcess);
final IChunkSet iChunkSet = getExtent().processSet(this, get, set); final IChunkSet iChunkSet = getExtent().processSet(this, get, set);
@ -1046,11 +1038,24 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
return get.call(set, finalizer); return get.call(set, finalizer);
} finally { } finally {
get.unlockCall(); get.unlockCall();
untrackExtent();
} }
} }
return null; return null;
} }
// "call" can be called by QueueHandler#blockingExecutor. In such case, we still want the other thread
// to use this SingleThreadQueueExtent. Otherwise, many threads might end up locking on **one** STQE.
// This way, locking is spread across multiple STQEs, allowing for better performance
private void trackExtent() {
ParallelQueueExtent.setCurrentExtent(extent);
}
private void untrackExtent() {
ParallelQueueExtent.clearCurrentExtent();
}
/** /**
* Get the extent this chunk is in. * Get the extent this chunk is in.
*/ */

View File

@ -33,7 +33,7 @@ public abstract class RandomCollection<T> {
public static <T> RandomCollection<T> of(Map<T, Double> weights, SimpleRandom random) { public static <T> RandomCollection<T> of(Map<T, Double> weights, SimpleRandom random) {
checkNotNull(random); checkNotNull(random);
return FastRandomCollection.create(weights, random) return FastRandomCollection.create(weights, random)
.orElse(new SimpleRandomCollection<>(weights, random)); .orElseGet(() -> new SimpleRandomCollection<>(weights, random));
} }
public void setRandom(SimpleRandom random) { public void setRandom(SimpleRandom random) {

View File

@ -32,6 +32,7 @@ import com.fastasyncworldedit.core.internal.io.FaweOutputStream;
import com.fastasyncworldedit.core.limit.FaweLimit; import com.fastasyncworldedit.core.limit.FaweLimit;
import com.fastasyncworldedit.core.util.BrushCache; import com.fastasyncworldedit.core.util.BrushCache;
import com.fastasyncworldedit.core.util.MainUtil; import com.fastasyncworldedit.core.util.MainUtil;
import com.fastasyncworldedit.core.util.MaskTraverser;
import com.fastasyncworldedit.core.util.StringMan; import com.fastasyncworldedit.core.util.StringMan;
import com.fastasyncworldedit.core.util.TaskManager; import com.fastasyncworldedit.core.util.TaskManager;
import com.fastasyncworldedit.core.util.TextureHolder; import com.fastasyncworldedit.core.util.TextureHolder;
@ -53,6 +54,7 @@ import com.sk89q.worldedit.command.tool.Tool;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Locatable; import com.sk89q.worldedit.extension.platform.Locatable;
import com.sk89q.worldedit.extent.NullExtent;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.extent.inventory.BlockBag;
@ -594,6 +596,9 @@ public class LocalSession implements TextureHolder {
long size = MainUtil.getSize(item); long size = MainUtil.getSize(item);
historySize -= size; historySize -= size;
} }
// free the mask from any remaining references to e.g. extents
// if used again
new MaskTraverser(mask).reset(NullExtent.INSTANCE);
} finally { } finally {
historyWriteLock.unlock(); historyWriteLock.unlock();
} }

View File

@ -113,8 +113,7 @@ public class FactoryConverter<T> implements ArgumentConverter<T> {
); );
} }
@Override private ParserContext createContext(InjectedValueAccess context) {
public ConversionResult<T> convert(String argument, InjectedValueAccess context) {
Actor actor = context.injectedValue(Key.of(Actor.class)) Actor actor = context.injectedValue(Key.of(Actor.class))
.orElseThrow(() -> new IllegalStateException("No actor")); .orElseThrow(() -> new IllegalStateException("No actor"));
LocalSession session = WorldEdit.getInstance().getSessionManager().get(actor); LocalSession session = WorldEdit.getInstance().getSessionManager().get(actor);
@ -139,6 +138,13 @@ public class FactoryConverter<T> implements ArgumentConverter<T> {
contextTweaker.accept(parserContext); contextTweaker.accept(parserContext);
} }
return parserContext;
}
@Override
public ConversionResult<T> convert(String argument, InjectedValueAccess context) {
ParserContext parserContext = createContext(context);
try { try {
return SuccessfulConversion.fromSingle( return SuccessfulConversion.fromSingle(
factoryExtractor.apply(worldEdit).parseFromInput(argument, parserContext) factoryExtractor.apply(worldEdit).parseFromInput(argument, parserContext)
@ -150,7 +156,9 @@ public class FactoryConverter<T> implements ArgumentConverter<T> {
@Override @Override
public List<String> getSuggestions(String input, InjectedValueAccess context) { public List<String> getSuggestions(String input, InjectedValueAccess context) {
return factoryExtractor.apply(worldEdit).getSuggestions(input); ParserContext parserContext = createContext(context);
return factoryExtractor.apply(worldEdit).getSuggestions(input, parserContext);
} }
@Override @Override

View File

@ -127,13 +127,13 @@ public final class MaskFactory extends AbstractFactory<Mask> {
} }
@Override @Override
public List<String> getSuggestions(String input) { public List<String> getSuggestions(String input, final ParserContext parserContext) {
final String[] split = input.split(" "); final String[] split = input.split(" ");
if (split.length > 1) { if (split.length > 1) {
String prev = input.substring(0, input.lastIndexOf(" ")) + " "; String prev = input.substring(0, input.lastIndexOf(" ")) + " ";
return super.getSuggestions(split[split.length - 1]).stream().map(s -> prev + s).collect(Collectors.toList()); return super.getSuggestions(split[split.length - 1], parserContext).stream().map(s -> prev + s).collect(Collectors.toList());
} }
return super.getSuggestions(input); return super.getSuggestions(input, parserContext);
} }
@Override @Override

View File

@ -91,9 +91,7 @@ public class AbstractDelegateExtent implements Extent {
@Override @Override
public BlockState getBlock(BlockVector3 position) { public BlockState getBlock(BlockVector3 position) {
//FAWE start - return coordinates return extent.getBlock(position);
return extent.getBlock(position.getX(), position.getY(), position.getZ());
//FAWE end
} }
@Override @Override
@ -103,9 +101,7 @@ public class AbstractDelegateExtent implements Extent {
@Override @Override
public BaseBlock getFullBlock(BlockVector3 position) { public BaseBlock getFullBlock(BlockVector3 position) {
//FAWE start - return coordinates return extent.getFullBlock(position);
return extent.getFullBlock(position.getX(), position.getY(), position.getZ());
//FAWE end
} }
//FAWE start //FAWE start
@ -117,9 +113,7 @@ public class AbstractDelegateExtent implements Extent {
@Override @Override
public BaseBlock getFullBlock(int x, int y, int z) { public BaseBlock getFullBlock(int x, int y, int z) {
//FAWE start - return coordinates
return extent.getFullBlock(x, y, z); return extent.getFullBlock(x, y, z);
//FAWE end
} }
@Override @Override
@ -375,9 +369,7 @@ public class AbstractDelegateExtent implements Extent {
@Override @Override
public BiomeType getBiome(BlockVector3 position) { public BiomeType getBiome(BlockVector3 position) {
//FAWE start - switch top x,y,z return extent.getBiome(position);
return extent.getBiomeType(position.getX(), position.getY(), position.getZ());
//FAWE end
} }
//FAWE start //FAWE start
@ -420,9 +412,7 @@ public class AbstractDelegateExtent implements Extent {
@Override @Override
public <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 position, T block) public <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 position, T block)
throws WorldEditException { throws WorldEditException {
//FAWE start - switch to x,y,z return extent.setBlock(position, block);
return extent.setBlock(position.getX(), position.getY(), position.getZ(), block);
//FAWE end
} }
//FAWE start //FAWE start
@ -447,9 +437,7 @@ public class AbstractDelegateExtent implements Extent {
@Override @Override
public boolean setBiome(BlockVector3 position, BiomeType biome) { public boolean setBiome(BlockVector3 position, BiomeType biome) {
//FAWE start - switch to x,y,z return extent.setBiome(position, biome);
return extent.setBiome(position.getX(), position.getY(), position.getZ(), biome);
//FAWE end
} }
//FAWE start //FAWE start

View File

@ -27,7 +27,7 @@ import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import java.util.HashMap; import java.util.LinkedHashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -41,7 +41,7 @@ public class RandomPattern extends AbstractPattern {
//FAWE start - SimpleRandom > Random, LHS<P> > List //FAWE start - SimpleRandom > Random, LHS<P> > List
private final SimpleRandom random; private final SimpleRandom random;
private Map<Pattern, Double> weights = new HashMap<>(); private Map<Pattern, Double> weights = new LinkedHashMap<>();
private RandomCollection<Pattern> collection; private RandomCollection<Pattern> collection;
private LinkedHashSet<Pattern> patterns = new LinkedHashSet<>(); private LinkedHashSet<Pattern> patterns = new LinkedHashSet<>();
//FAWE end //FAWE end

View File

@ -24,6 +24,7 @@ import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.antlr.ExpressionLexer; import com.sk89q.worldedit.antlr.ExpressionLexer;
import com.sk89q.worldedit.antlr.ExpressionParser; import com.sk89q.worldedit.antlr.ExpressionParser;
import com.sk89q.worldedit.internal.expression.invoke.ExpressionCompiler; import com.sk89q.worldedit.internal.expression.invoke.ExpressionCompiler;
import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment;
import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.CommonTokenStream;
@ -199,7 +200,9 @@ public class Expression implements Cloneable {
//FAWE start //FAWE start
public Expression clone() { public Expression clone() {
return new Expression(initialExpression, new HashSet<>(providedSlots)); Expression expression = new Expression(initialExpression, new HashSet<>(providedSlots));
expression.setEnvironment(getEnvironment().clone());
return expression;
} }
//FAWE end //FAWE end

View File

@ -22,7 +22,7 @@ package com.sk89q.worldedit.internal.expression;
/** /**
* Represents a way to access blocks in a world. Has to accept non-rounded coordinates. * Represents a way to access blocks in a world. Has to accept non-rounded coordinates.
*/ */
public interface ExpressionEnvironment { public interface ExpressionEnvironment extends Cloneable {
int getBlockType(double x, double y, double z); int getBlockType(double x, double y, double z);
@ -36,4 +36,7 @@ public interface ExpressionEnvironment {
int getBlockDataRel(double x, double y, double z); int getBlockDataRel(double x, double y, double z);
// FAWE start
ExpressionEnvironment clone();
// FAWE end
} }

View File

@ -96,9 +96,14 @@ public abstract class AbstractFactory<E> {
throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input))); throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input)));
} }
@Deprecated
public List<String> getSuggestions(String input) { public List<String> getSuggestions(String input) {
return getSuggestions(input, new ParserContext());
}
public List<String> getSuggestions(String input, ParserContext context) {
return parsers.stream().flatMap( return parsers.stream().flatMap(
p -> p.getSuggestions(input) p -> p.getSuggestions(input, context)
).collect(Collectors.toList()); ).collect(Collectors.toList());
} }

View File

@ -45,9 +45,22 @@ public abstract class InputParser<E> {
* Gets a stream of suggestions of input to this parser. * Gets a stream of suggestions of input to this parser.
* *
* @return a stream of suggestions * @return a stream of suggestions
* @deprecated Use the version that takes a {@link ParserContext}, {@link #getSuggestions(String, ParserContext)}
*/ */
@Deprecated
public Stream<String> getSuggestions(String input) { public Stream<String> getSuggestions(String input) {
return Stream.empty(); return Stream.empty();
} }
/**
* Gets a stream of suggestions of input to this parser.
*
* @param input The string input
* @param context The parser context
*
* @return a stream of suggestions
*/
public Stream<String> getSuggestions(String input, ParserContext context) {
return getSuggestions(input);
}
} }

View File

@ -141,7 +141,7 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion {
*/ */
public void setRadius(Vector2 radius) { public void setRadius(Vector2 radius) {
this.radius = radius.add(0.5, 0.5); this.radius = radius.add(0.5, 0.5);
this.radiusInverse = Vector2.ONE.divide(radius); this.radiusInverse = Vector2.ONE.divide(this.radius);
} }
/** /**
@ -413,11 +413,12 @@ public class CylinderRegion extends AbstractRegion implements FlatRegion {
final IChunk chunk, final Filter filter, final ChunkFilterBlock block, final IChunk chunk, final Filter filter, final ChunkFilterBlock block,
final IChunkGet get, final IChunkSet set, boolean full final IChunkGet get, final IChunkSet set, boolean full
) { ) {
int bcx = chunk.getX() >> 4; int bcx = chunk.getX() << 4;
int bcz = chunk.getZ() >> 4; int bcz = chunk.getZ() << 4;
int tcx = bcx + 15; int tcx = bcx + 15;
int tcz = bcz + 15; int tcz = bcz + 15;
if (contains(bcx, bcz) && contains(tcx, tcz)) { // must contain all 4 corners for fast path
if (contains(bcx, bcz) && contains(tcx, tcz) && contains(bcx, tcz) && contains(tcx, bcz)) {
filter(chunk, filter, block, get, set, minY, maxY, full); filter(chunk, filter, block, get, set, minY, maxY, full);
return; return;
} }

View File

@ -28,6 +28,8 @@ import com.sk89q.worldedit.math.Vector3;
public class WorldEditExpressionEnvironment implements ExpressionEnvironment { public class WorldEditExpressionEnvironment implements ExpressionEnvironment {
private static final Vector3 BLOCK_CENTER_OFFSET = Vector3.at(0.5, 0.5, 0.5);
private final Vector3 unit; private final Vector3 unit;
private final Vector3 zero2; private final Vector3 zero2;
//FAWE start - MutableVector3 //FAWE start - MutableVector3
@ -42,7 +44,7 @@ public class WorldEditExpressionEnvironment implements ExpressionEnvironment {
public WorldEditExpressionEnvironment(Extent extent, Vector3 unit, Vector3 zero) { public WorldEditExpressionEnvironment(Extent extent, Vector3 unit, Vector3 zero) {
this.extent = extent; this.extent = extent;
this.unit = unit; this.unit = unit;
this.zero2 = zero.add(0.5, 0.5, 0.5); this.zero2 = zero.add(BLOCK_CENTER_OFFSET);
} }
public BlockVector3 toWorld(double x, double y, double z) { public BlockVector3 toWorld(double x, double y, double z) {
@ -94,10 +96,13 @@ public class WorldEditExpressionEnvironment implements ExpressionEnvironment {
public Vector3 toWorldRel(double x, double y, double z) { public Vector3 toWorldRel(double x, double y, double z) {
return current.add(x, y, z); return current.add(x, y, z);
} }
public WorldEditExpressionEnvironment clone() {
return new WorldEditExpressionEnvironment(extent, unit, zero2.subtract(BLOCK_CENTER_OFFSET));
}
//FAWe end //FAWe end
public void setCurrentBlock(Vector3 current) { public void setCurrentBlock(Vector3 current) {
this.current = current; this.current = current;
} }
} }

View File

@ -23,6 +23,8 @@ import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes;
/** /**
* Utility methods for Google's GSON library. * Utility methods for Google's GSON library.
@ -41,6 +43,7 @@ public final class GsonUtil {
GsonBuilder gsonBuilder = new GsonBuilder(); GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Vector3.class, new VectorAdapter()); gsonBuilder.registerTypeAdapter(Vector3.class, new VectorAdapter());
gsonBuilder.registerTypeAdapter(BlockVector3.class, new BlockVectorAdapter()); gsonBuilder.registerTypeAdapter(BlockVector3.class, new BlockVectorAdapter());
gsonBuilder.registerTypeAdapter(ItemType.class, new ItemTypeAdapter());
return gsonBuilder; return gsonBuilder;
} }

View File

@ -0,0 +1,26 @@
package com.sk89q.worldedit.util.gson;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes;
import java.lang.reflect.Type;
public final class ItemTypeAdapter implements JsonDeserializer<ItemType> {
@Override
public ItemType deserialize(JsonElement json, Type type, JsonDeserializationContext cont) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
String id = jsonObject.get("id").getAsString();
ItemType itemType = ItemTypes.get(id);
if (itemType == null) {
throw new JsonParseException("Could not parse item type `" + id + "`");
}
return itemType;
}
}

View File

@ -79,7 +79,7 @@ public class ItemType implements RegistryItem, Keyed {
} }
//FAWE start //FAWE start
private int internalId; private transient int internalId;
@Override @Override
public void setInternalId(int internalId) { public void setInternalId(int internalId) {

View File

@ -114,6 +114,11 @@ class BaseExpressionTest {
public int getBlockDataRel(double x, double y, double z) { public int getBlockDataRel(double x, double y, double z) {
return (int) y * 100; return (int) y * 100;
} }
@Override
public ExpressionEnvironment clone() {
return this;
}
}); });
return expression.evaluate(); return expression.evaluate();

View File

@ -28,7 +28,7 @@ dependencies {
}) })
api("org.apache.logging.log4j:log4j-api") api("org.apache.logging.log4j:log4j-api")
api("org.bstats:bstats-sponge:1.7") api("org.bstats:bstats-sponge:1.7")
testImplementation("org.mockito:mockito-core:5.9.0") testImplementation("org.mockito:mockito-core:5.11.0")
} }
<<<<<<< HEAD <<<<<<< HEAD