Performance improvement based on case study by @me4502

This commit is contained in:
MattBDev 2020-03-19 13:08:25 -04:00
parent 2e1c0c83f5
commit 9f07894f28
14 changed files with 106 additions and 65 deletions

View File

@ -22,14 +22,8 @@ package com.sk89q.worldedit.bukkit;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.Fawe; import com.boydti.fawe.Fawe;
import com.boydti.fawe.beta.IBlocks;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.beta.implementation.packet.ChunkPacket; import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
import com.boydti.fawe.bukkit.FaweBukkit;
import com.boydti.fawe.bukkit.adapter.mc1_14.BukkitGetBlocks_1_14;
import com.boydti.fawe.config.Settings;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
@ -39,7 +33,6 @@ import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.history.change.BlockChange;
import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
@ -52,6 +45,7 @@ import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.weather.WeatherType; import com.sk89q.worldedit.world.weather.WeatherType;
import com.sk89q.worldedit.world.weather.WeatherTypes; import com.sk89q.worldedit.world.weather.WeatherTypes;
import io.papermc.lib.PaperLib;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
@ -60,10 +54,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.function.Supplier;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import io.papermc.lib.PaperLib;
import org.bukkit.Effect; import org.bukkit.Effect;
import org.bukkit.TreeType; import org.bukkit.TreeType;
import org.bukkit.World; import org.bukkit.World;
@ -191,8 +182,14 @@ public class BukkitWorld extends AbstractWorld {
@Override @Override
public boolean regenerate(Region region, EditSession editSession) { public boolean regenerate(Region region, EditSession editSession) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
if (adapter != null) { try {
return adapter.regenerate(getWorld(), region, null, null, editSession); if (adapter != null) {
return adapter.regenerate(getWorld(), region, null, null, editSession);
} else {
throw new UnsupportedOperationException("Missing BukkitImplAdapater for this version.");
}
} catch (Exception e) {
logger.warn("Regeneration via adapter failed.", e);
} }
/* /*
BaseBlock[] history = new BaseBlock[16 * 16 * (getMaxY() + 1)]; BaseBlock[] history = new BaseBlock[16 * 16 * (getMaxY() + 1)];
@ -336,15 +333,13 @@ public class BukkitWorld extends AbstractWorld {
@Override @Override
public void checkLoadedChunk(BlockVector3 pt) { public void checkLoadedChunk(BlockVector3 pt) {
World world = getWorld(); World world = getWorld();
if (!world.isChunkLoaded(pt.getBlockX() >> 4, pt.getBlockZ() >> 4)) { int X = pt.getBlockX() >> 4;
int X = pt.getBlockX() >> 4; int Z = pt.getBlockZ() >> 4;
int Z = pt.getBlockZ() >> 4; if (Fawe.isMainThread()) {
if (Fawe.isMainThread()) { world.getChunkAt(X, Z);
world.getChunkAt(X, Z); } else {
} else if (!world.isChunkLoaded(X, Z)) { PaperLib.getChunkAtAsync(world, X, Z, true);
PaperLib.getChunkAtAsync(world,X, Z, true); }
}
}
} }
@Override @Override

View File

@ -658,10 +658,10 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
= WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getCommandManager().getCommand(label); = WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getCommandManager().getCommand(label);
if (!command.isPresent()) return; if (!command.isPresent()) return;
CommandSuggestionEvent suggestEvent = new CommandSuggestionEvent(wrapCommandSender(event.getSender()), event.getBuffer()); CommandSuggestionEvent suggestEvent = new CommandSuggestionEvent(wrapCommandSender(event.getSender()), buffer);
getWorldEdit().getEventBus().post(suggestEvent); getWorldEdit().getEventBus().post(suggestEvent);
event.setCompletions(CommandUtil.fixSuggestions(event.getBuffer(), suggestEvent.getSuggestions())); event.setCompletions(CommandUtil.fixSuggestions(buffer, suggestEvent.getSuggestions()));
event.setHandled(true); event.setHandled(true);
} }
} }

View File

@ -108,12 +108,13 @@ public class DefaultProgressTracker implements BiConsumer<DefaultProgressTracker
} }
public void sendTask() { public void sendTask() {
String queue = StringMan.padRight("" + totalQueue, 3); String queue = StringMan.padRight(String.valueOf(totalQueue), 3);
String dispatch = StringMan.padLeft("" + amountDispatch, 3); String dispatch = StringMan.padLeft(String.valueOf(amountDispatch), 3);
int total = amountDispatch != 0 ? amountDispatch : amountQueue; int total = amountDispatch != 0 ? amountDispatch : amountQueue;
int speed = total != 0 ? (int) (total / Math.max((System.currentTimeMillis() - start) / 1000d, 1)) : 0; int speed = total != 0 ? (int) (total / Math.max((System.currentTimeMillis() - start) / 1000d, 1)) : 0;
String speedStr = StringMan.padRight("" + speed, 3); String speedStr = StringMan.padRight(String.valueOf(speed), 3);
String percent = StringMan.padRight("" + (amountDispatch != 0 ? (amountDispatch * 100) / totalQueue : 0), 3); String percent = StringMan.padRight(
String.valueOf(amountDispatch != 0 ? (amountDispatch * 100) / totalQueue : 0), 3);
int remaining = speed != 0 ? amountQueue / speed : -1; int remaining = speed != 0 ? amountQueue / speed : -1;
sendTile(TextComponent.empty(), Caption.of("fawe.progress.progress.message", queue, dispatch, percent, StringMan.padLeft("" + speed, 3), StringMan.padLeft("" + remaining, 3))); sendTile(TextComponent.empty(), Caption.of("fawe.progress.progress.message", queue, dispatch, percent, StringMan.padLeft("" + speed, 3), StringMan.padLeft("" + remaining, 3)));
} }

View File

@ -15,6 +15,7 @@ import com.sk89q.worldedit.regions.AbstractRegion;
import com.sk89q.worldedit.regions.RegionOperationException; import com.sk89q.worldedit.regions.RegionOperationException;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import java.util.Iterator; import java.util.Iterator;
import org.jetbrains.annotations.NotNull;
public class FuzzyRegion extends AbstractRegion { public class FuzzyRegion extends AbstractRegion {
@ -56,6 +57,7 @@ public class FuzzyRegion extends AbstractRegion {
Operations.completeBlindly(search); Operations.completeBlindly(search);
} }
@NotNull
@Override @Override
public Iterator<BlockVector3> iterator() { public Iterator<BlockVector3> iterator() {
return set.iterator(); return set.iterator();

View File

@ -249,9 +249,9 @@ public class PolyhedralRegion extends AbstractRegion {
for (int i = 0; i < triangles.size(); ++i) { for (int i = 0; i < triangles.size(); ++i) {
final Triangle triangle = triangles.get(i); final Triangle triangle = triangles.get(i);
final BlockVector3 v0 = change.add(triangle.getVertex(0).toBlockPoint()); final BlockVector3 v0 = change.add(triangle.getVertex(0));
final BlockVector3 v1 = change.add(triangle.getVertex(1).toBlockPoint()); final BlockVector3 v1 = change.add(triangle.getVertex(1));
final BlockVector3 v2 = change.add(triangle.getVertex(2).toBlockPoint()); final BlockVector3 v2 = change.add(triangle.getVertex(2));
triangles.set(i, new Triangle(v0, v1, v2)); triangles.set(i, new Triangle(v0, v1, v2));
} }

View File

@ -62,8 +62,8 @@ public class Triangle {
return StringMan.getString(verts); return StringMan.getString(verts);
} }
public Vector3 getVertex(int index) { public BlockVector3 getVertex(int index) {
return Vector3.at(verts[index][0], verts[index][1], verts[index][2]); return BlockVector3.at(verts[index][0], verts[index][1], verts[index][2]);
} }
public boolean contains(BlockVector3 pos) { public boolean contains(BlockVector3 pos) {

View File

@ -40,7 +40,6 @@ import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.eventbus.EventBus; import com.sk89q.worldedit.util.eventbus.EventBus;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import java.util.UUID; import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -76,7 +75,7 @@ public class EditSessionBuilder {
* *
* @param world A world must be provided for all EditSession(s) * @param world A world must be provided for all EditSession(s)
*/ */
public EditSessionBuilder(@Nonnull World world) { public EditSessionBuilder(@NotNull World world) {
checkNotNull(world); checkNotNull(world);
this.world = world; this.world = world;
this.worldName = world.getName(); this.worldName = world.getName();
@ -88,7 +87,7 @@ public class EditSessionBuilder {
this.worldName = worldName; this.worldName = worldName;
} }
public EditSessionBuilder(@Nonnull String worldName) { public EditSessionBuilder(@NotNull String worldName) {
checkNotNull(worldName); checkNotNull(worldName);
this.worldName = worldName; this.worldName = worldName;
this.world = FaweAPI.getWorld(worldName); this.world = FaweAPI.getWorld(worldName);
@ -108,7 +107,7 @@ public class EditSessionBuilder {
return limit(FaweLimit.MAX.copy()); return limit(FaweLimit.MAX.copy());
} }
public EditSessionBuilder limitUnprocessed(@Nonnull Player player) { public EditSessionBuilder limitUnprocessed(@NotNull Player player) {
checkNotNull(player); checkNotNull(player);
limitUnlimited(); limitUnlimited();
FaweLimit tmp = player.getLimit(); FaweLimit tmp = player.getLimit();

View File

@ -26,6 +26,7 @@ import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
import java.util.Optional; import java.util.Optional;
import javax.annotation.Nullable;
/** /**
* Base extent class for buffering changes between {@link #setBlock(BlockVector3, BlockStateHolder)} * Base extent class for buffering changes between {@link #setBlock(BlockVector3, BlockStateHolder)}
@ -51,17 +52,38 @@ public abstract class AbstractBufferingExtent extends AbstractDelegateExtent {
@Override @Override
public BlockState getBlock(BlockVector3 position) { public BlockState getBlock(BlockVector3 position) {
return getBufferedBlock(position) BaseBlock block = getBufferedFullBlock(position);
.map(BaseBlock::toImmutableState) if (block == null) {
.orElseGet(() -> super.getBlock(position)); return super.getBlock(position);
}
return block.toImmutableState();
} }
@Override @Override
public BaseBlock getFullBlock(BlockVector3 position) { public BaseBlock getFullBlock(BlockVector3 position) {
return getBufferedBlock(position) BaseBlock block = getBufferedFullBlock(position);
.orElseGet(() -> super.getFullBlock(position)); if (block == null) {
return super.getFullBlock(position);
}
return block;
} }
protected abstract Optional<BaseBlock> getBufferedBlock(BlockVector3 position); @Deprecated
protected Optional<BaseBlock> getBufferedBlock(BlockVector3 position) {
throw new IllegalStateException("Invalid BufferingExtent provided. Must override `getBufferedFullBlock(BlockVector3)`.");
}
//TODO make below abstract
/**
* Gets a block from the buffer, or null if not buffered.
*
* This **must** be overridden, and will be abstract in WorldEdit 8.
*
* @param position The position
* @return The buffered block, or null
*/
@Nullable
protected BaseBlock getBufferedFullBlock(BlockVector3 position) {
return getBufferedBlock(position).orElse(null);
}
} }

View File

@ -66,11 +66,11 @@ public class ExtentBuffer extends AbstractBufferingExtent {
} }
@Override @Override
protected Optional<BaseBlock> getBufferedBlock(BlockVector3 position) { protected BaseBlock getBufferedFullBlock(BlockVector3 position) {
if (mask.test(getExtent(), position)) { if (mask.test(position)) {
return Optional.of(buffer.computeIfAbsent(position, (pos -> getExtent().getFullBlock(pos)))); return buffer.computeIfAbsent(position, (pos -> getExtent().getFullBlock(pos)));
} }
return Optional.empty(); return null;
} }
@Override @Override

View File

@ -77,8 +77,8 @@ public class ChunkBatchingExtent extends AbstractBufferingExtent {
} }
@Override @Override
protected Optional<BaseBlock> getBufferedBlock(BlockVector3 position) { protected BaseBlock getBufferedFullBlock(BlockVector3 position) {
return Optional.ofNullable(blockMap.get(position)); return blockMap.get(position);
} }
@Override @Override
@ -94,8 +94,7 @@ public class ChunkBatchingExtent extends AbstractBufferingExtent {
@Override @Override
public Operation resume(RunContext run) throws WorldEditException { public Operation resume(RunContext run) throws WorldEditException {
if (iterator == null) { if (iterator == null) {
iterator = ImmutableSortedSet.copyOf(RegionOptimizedComparator.INSTANCE, iterator = blockMap.keySet().parallelStream().sorted(RegionOptimizedComparator.INSTANCE).iterator();
blockMap.keySet()).iterator();
} }
while (iterator.hasNext()) { while (iterator.hasNext()) {
BlockVector3 position = iterator.next(); BlockVector3 position = iterator.next();

View File

@ -247,11 +247,14 @@ public class MultiStageReorder extends AbstractBufferingExtent implements Reorde
} }
@Override @Override
protected Optional<BaseBlock> getBufferedBlock(BlockVector3 position) { protected BaseBlock getBufferedFullBlock(BlockVector3 position) {
return stages.values().stream() for (BlockMap<BaseBlock> blocks : stages.values()) {
.map(blocks -> blocks.get(position)) BaseBlock baseBlock = blocks.get(position);
.filter(Objects::nonNull) if (baseBlock != null) {
.findAny(); return baseBlock;
}
}
return null;
} }
@Override @Override

View File

@ -99,6 +99,9 @@ public final class BlockStateIdAccess {
*/ */
private BlockStateIdAccess() {
}
public static @Nullable BlockState getBlockStateById(int id) { public static @Nullable BlockState getBlockStateById(int id) {
return BlockState.getFromOrdinal(id); return BlockState.getFromOrdinal(id);
} }

View File

@ -32,11 +32,13 @@ import com.sk89q.worldedit.registry.NamespacedRegistry;
import com.sk89q.worldedit.registry.state.AbstractProperty; import com.sk89q.worldedit.registry.state.AbstractProperty;
import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.registry.state.PropertyKey; import com.sk89q.worldedit.registry.state.PropertyKey;
import com.sk89q.worldedit.util.concurrency.LazyReference;
import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.item.ItemTypes;
import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BlockMaterial;
import com.sk89q.worldedit.world.registry.LegacyMapper; import com.sk89q.worldedit.world.registry.LegacyMapper;
import java.util.function.Function;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -53,10 +55,12 @@ public class BlockType implements Keyed, Pattern {
private final String id; private final String id;
private final BlockTypesCache.Settings settings; private final BlockTypesCache.Settings settings;
/* private final LazyReference<FuzzyBlockState> emptyFuzzy
private final LazyReference<Integer> legacyId = LazyReference.from(() -> computeLgacy(0)); = LazyReference.from(() -> new FuzzyBlockState(this));
private final LazyReference<Integer> legacyId = LazyReference.from(() -> computeLegacy(0));
private final LazyReference<Integer> legacyData = LazyReference.from(() -> computeLegacy(1)); private final LazyReference<Integer> legacyData = LazyReference.from(() -> computeLegacy(1));
*/
private Integer legacyCombinedId; private Integer legacyCombinedId;
private boolean initItemType; private boolean initItemType;
private ItemType itemType; private ItemType itemType;
@ -67,6 +71,16 @@ public class BlockType implements Keyed, Pattern {
this.settings = new BlockTypesCache.Settings(this, id, internalId, states); this.settings = new BlockTypesCache.Settings(this, id, internalId, states);
} }
public BlockType(String id, Function<BlockState, BlockState> values) {
// If it has no namespace, assume minecraft.
if (!id.contains(":")) {
id = "minecraft:" + id;
}
this.id = id;
//TODO fix the line below
this.settings = new BlockTypesCache.Settings(this, id, 0, null);
}
@Deprecated @Deprecated
public int getMaxStateId() { public int getMaxStateId() {
return settings.permutations; return settings.permutations;
@ -179,13 +193,12 @@ public class BlockType implements Keyed, Pattern {
* *
* @return The default state * @return The default state
*/ */
public final BlockState getDefaultState() { public BlockState getDefaultState() {
return this.settings.defaultState; return this.settings.defaultState;
} }
@Deprecated
public FuzzyBlockState getFuzzyMatcher() { public FuzzyBlockState getFuzzyMatcher() {
return new FuzzyBlockState(this); return emptyFuzzy.getValue();
} }
/** /**

View File

@ -74,16 +74,16 @@ import java.util.concurrent.TimeUnit;
*/ */
@Plugin(id = SpongeWorldEdit.MOD_ID, name = "WorldEdit", @Plugin(id = SpongeWorldEdit.MOD_ID, name = "WorldEdit",
description = "WorldEdit is an easy-to-use in-game world editor for Minecraft", description = "WorldEdit is an easy-to-use in-game world editor for Minecraft",
url = "http://www.enginehub.org/worldedit") url = "https://enginehub.org/worldedit/")
public class SpongeWorldEdit { public class SpongeWorldEdit {
@Inject @Inject
private Logger logger; private Logger logger;
@Inject
private Metrics2 metrics; private Metrics2 metrics;
public static final String MOD_ID = "worldedit"; public static final String MOD_ID = "worldedit";
private static final int BSTATS_PLUGIN_ID = 3329;
private SpongePermissionsProvider provider; private SpongePermissionsProvider provider;
@ -109,8 +109,10 @@ public class SpongeWorldEdit {
@Inject @ConfigDir(sharedRoot = false) @Inject @ConfigDir(sharedRoot = false)
private File workingDir; private File workingDir;
public SpongeWorldEdit() { @Inject
public SpongeWorldEdit(Metrics2.Factory metricsFactory) {
inst = this; inst = this;
metrics = metricsFactory.make(BSTATS_PLUGIN_ID);
} }
@Listener @Listener
@ -166,7 +168,9 @@ public class SpongeWorldEdit {
@Listener @Listener
public void serverStopping(GameStoppingServerEvent event) { public void serverStopping(GameStoppingServerEvent event) {
WorldEdit.getInstance().getPlatformManager().unregister(platform); WorldEdit worldEdit = WorldEdit.getInstance();
worldEdit.getSessionManager().unload();
worldEdit.getPlatformManager().unregister(platform);
} }
@Listener @Listener