Only synchronise tree generation at the very lowest level (#1788)

* Only synchronise tree generation at the very lowest level
 - Fixes #1681

* Perform the generate inside try-finally and actually use the resultant copied map to place blocks to the editsession

* Check result of generateTree and return null if failed
This commit is contained in:
Jordan 2022-06-13 08:05:18 +01:00 committed by GitHub
parent 02a6bb9b27
commit 63f031b01a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 85 additions and 66 deletions

View File

@ -10,6 +10,7 @@ import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
import com.fastasyncworldedit.core.util.NbtUtils; import com.fastasyncworldedit.core.util.NbtUtils;
import com.fastasyncworldedit.core.util.TaskManager;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
@ -561,16 +562,26 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
); // bukkit skips the feature gen which does this offset normally, so we have to add it back ); // bukkit skips the feature gen which does this offset normally, so we have to add it back
} }
ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle();
final BlockVector3 finalBlockVector = blockVector3;
// Sync to main thread to ensure no clashes occur
Map<BlockPos, CraftBlockState> placed = TaskManager.taskManager().sync(() -> {
serverLevel.captureTreeGeneration = true; serverLevel.captureTreeGeneration = true;
serverLevel.captureBlockStates = true; serverLevel.captureBlockStates = true;
boolean grownTree = bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, blockVector3), bukkitType); try {
if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) {
return null;
}
return ImmutableMap.copyOf(serverLevel.capturedBlockStates);
} finally {
serverLevel.captureBlockStates = false; serverLevel.captureBlockStates = false;
serverLevel.captureTreeGeneration = false; serverLevel.captureTreeGeneration = false;
if (!grownTree) {
serverLevel.capturedBlockStates.clear(); serverLevel.capturedBlockStates.clear();
}
});
if (placed == null || placed.isEmpty()) {
return false; return false;
} else { }
for (CraftBlockState craftBlockState : serverLevel.capturedBlockStates.values()) { for (CraftBlockState craftBlockState : placed.values()) {
if (craftBlockState == null || craftBlockState.getType() == Material.AIR) { if (craftBlockState == null || craftBlockState.getType() == Material.AIR) {
continue; continue;
} }
@ -578,11 +589,8 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData()) BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData())
); );
} }
serverLevel.capturedBlockStates.clear();
return true; return true;
} }
}
@Override @Override
public List<org.bukkit.entity.Entity> getEntities(org.bukkit.World world) { public List<org.bukkit.entity.Entity> getEntities(org.bukkit.World world) {

View File

@ -10,6 +10,7 @@ import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
import com.fastasyncworldedit.core.util.NbtUtils; import com.fastasyncworldedit.core.util.NbtUtils;
import com.fastasyncworldedit.core.util.TaskManager;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
@ -553,16 +554,26 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
); // bukkit skips the feature gen which does this offset normally, so we have to add it back ); // bukkit skips the feature gen which does this offset normally, so we have to add it back
} }
ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle();
final BlockVector3 finalBlockVector = blockVector3;
// Sync to main thread to ensure no clashes occur
Map<BlockPos, CraftBlockState> placed = TaskManager.taskManager().sync(() -> {
serverLevel.captureTreeGeneration = true; serverLevel.captureTreeGeneration = true;
serverLevel.captureBlockStates = true; serverLevel.captureBlockStates = true;
boolean grownTree = bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, blockVector3), bukkitType); try {
if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) {
return null;
}
return ImmutableMap.copyOf(serverLevel.capturedBlockStates);
} finally {
serverLevel.captureBlockStates = false; serverLevel.captureBlockStates = false;
serverLevel.captureTreeGeneration = false; serverLevel.captureTreeGeneration = false;
if (!grownTree) {
serverLevel.capturedBlockStates.clear(); serverLevel.capturedBlockStates.clear();
}
});
if (placed == null || placed.isEmpty()) {
return false; return false;
} else { }
for (CraftBlockState craftBlockState : serverLevel.capturedBlockStates.values()) { for (CraftBlockState craftBlockState : placed.values()) {
if (craftBlockState == null || craftBlockState.getType() == Material.AIR) { if (craftBlockState == null || craftBlockState.getType() == Material.AIR) {
continue; continue;
} }
@ -570,11 +581,8 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData()) BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData())
); );
} }
serverLevel.capturedBlockStates.clear();
return true; return true;
} }
}
@Override @Override
public List<org.bukkit.entity.Entity> getEntities(org.bukkit.World world) { public List<org.bukkit.entity.Entity> getEntities(org.bukkit.World world) {

View File

@ -10,6 +10,7 @@ import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
import com.fastasyncworldedit.core.util.NbtUtils; import com.fastasyncworldedit.core.util.NbtUtils;
import com.fastasyncworldedit.core.util.TaskManager;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
@ -554,16 +555,26 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
); // bukkit skips the feature gen which does this offset normally, so we have to add it back ); // bukkit skips the feature gen which does this offset normally, so we have to add it back
} }
ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle();
final BlockVector3 finalBlockVector = blockVector3;
// Sync to main thread to ensure no clashes occur
Map<BlockPos, CraftBlockState> placed = TaskManager.taskManager().sync(() -> {
serverLevel.captureTreeGeneration = true; serverLevel.captureTreeGeneration = true;
serverLevel.captureBlockStates = true; serverLevel.captureBlockStates = true;
boolean grownTree = bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, blockVector3), bukkitType); try {
if (!bukkitWorld.generateTree(BukkitAdapter.adapt(bukkitWorld, finalBlockVector), bukkitType)) {
return null;
}
return ImmutableMap.copyOf(serverLevel.capturedBlockStates);
} finally {
serverLevel.captureBlockStates = false; serverLevel.captureBlockStates = false;
serverLevel.captureTreeGeneration = false; serverLevel.captureTreeGeneration = false;
if (!grownTree) {
serverLevel.capturedBlockStates.clear(); serverLevel.capturedBlockStates.clear();
}
});
if (placed == null || placed.isEmpty()) {
return false; return false;
} else { }
for (CraftBlockState craftBlockState : serverLevel.capturedBlockStates.values()) { for (CraftBlockState craftBlockState : placed.values()) {
if (craftBlockState == null || craftBlockState.getType() == Material.AIR) { if (craftBlockState == null || craftBlockState.getType() == Material.AIR) {
continue; continue;
} }
@ -571,11 +582,8 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData()) BukkitAdapter.adapt(((org.bukkit.block.BlockState) craftBlockState).getBlockData())
); );
} }
serverLevel.capturedBlockStates.clear();
return true; return true;
} }
}
@Override @Override
public List<org.bukkit.entity.Entity> getEntities(org.bukkit.World world) { public List<org.bukkit.entity.Entity> getEntities(org.bukkit.World world) {

View File

@ -24,7 +24,6 @@ import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.internal.exception.FaweException; import com.fastasyncworldedit.core.internal.exception.FaweException;
import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
import com.fastasyncworldedit.core.util.TaskManager;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
@ -334,9 +333,7 @@ public class BukkitWorld extends AbstractWorld {
@Override @Override
public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 pt) { public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 pt) {
//FAWE start - allow tree commands to be undone and obey region restrictions //FAWE start - allow tree commands to be undone and obey region restrictions
return TaskManager.taskManager().sync(() -> WorldEditPlugin.getInstance().getBukkitImplAdapter().generateTree(type, editSession, pt, return WorldEditPlugin.getInstance().getBukkitImplAdapter().generateTree(type, editSession, pt, getWorld());
getWorld()
));
//FAWE end //FAWE end
} }

View File

@ -77,7 +77,7 @@ public class FaweAPI {
* </p> * </p>
* *
* @param world The name of the world * @param world The name of the world
* @param autoQueue If it should start dispatching before you enqueue it. * @param autoQueue If it should start dispatching before you close/flush it.
* @return the queue extent * @return the queue extent
*/ */
public static IQueueExtent<IQueueChunk> createQueue(World world, boolean autoQueue) { public static IQueueExtent<IQueueChunk> createQueue(World world, boolean autoQueue) {

View File

@ -273,13 +273,11 @@ public class WorldWrapper extends AbstractWorld {
@Override @Override
public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 position) throws public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 position) throws
MaxChangedBlocksException { MaxChangedBlocksException {
return TaskManager.taskManager().sync(() -> {
try { try {
return parent.generateTree(type, editSession, position); return parent.generateTree(type, editSession, position);
} catch (MaxChangedBlocksException e) { } catch (MaxChangedBlocksException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
});
} }
@Override @Override