Bypass Bukkit in more situations (#532)

* Bypass Bukkit in more situations

* Use orElseGet

* Apply the same optimisation in the reverse BlockData adapter, and use lambdas instead of AIC

* Remove bukkit type checks

* Improve reliability of fallbacks
This commit is contained in:
Matthew Miller 2019-11-15 12:02:46 +10:00 committed by GitHub
parent 89bc664f69
commit 77ef0ae417
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 24 deletions

View File

@ -21,7 +21,6 @@ package com.sk89q.worldedit.bukkit;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Function;
import com.sk89q.worldedit.NotABlockException; import com.sk89q.worldedit.NotABlockException;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
@ -29,6 +28,7 @@ import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
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.util.Location; import com.sk89q.worldedit.util.Location;
@ -45,6 +45,8 @@ import com.sk89q.worldedit.world.gamemode.GameMode;
import com.sk89q.worldedit.world.gamemode.GameModes; import com.sk89q.worldedit.world.gamemode.GameModes;
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 it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
@ -52,6 +54,7 @@ import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import java.util.EnumMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@ -349,18 +352,19 @@ public class BukkitAdapter {
return org.bukkit.entity.EntityType.fromName(entityType.getId().substring(10)); return org.bukkit.entity.EntityType.fromName(entityType.getId().substring(10));
} }
private static EnumMap<Material, BlockType> materialBlockTypeCache = new EnumMap<>(Material.class);
private static EnumMap<Material, ItemType> materialItemTypeCache = new EnumMap<>(Material.class);
/** /**
* Converts a Material to a BlockType * Converts a Material to a BlockType
* *
* @param material The material * @param material The material
* @return The blocktype * @return The blocktype
*/ */
@Nullable
public static BlockType asBlockType(Material material) { public static BlockType asBlockType(Material material) {
checkNotNull(material); checkNotNull(material);
if (!material.isBlock()) { return materialBlockTypeCache.computeIfAbsent(material, input -> BlockTypes.get(material.getKey().toString()));
throw new IllegalArgumentException(material.getKey().toString() + " is not a block!");
}
return BlockTypes.get(material.getKey().toString());
} }
/** /**
@ -369,15 +373,14 @@ public class BukkitAdapter {
* @param material The material * @param material The material
* @return The itemtype * @return The itemtype
*/ */
@Nullable
public static ItemType asItemType(Material material) { public static ItemType asItemType(Material material) {
checkNotNull(material); checkNotNull(material);
if (!material.isItem()) { return materialItemTypeCache.computeIfAbsent(material, input -> ItemTypes.get(material.getKey().toString()));
throw new IllegalArgumentException(material.getKey().toString() + " is not an item!");
}
return ItemTypes.get(material.getKey().toString());
} }
private static Map<String, BlockState> blockStateCache = new HashMap<>(); private static Int2ObjectMap<BlockState> blockStateCache = new Int2ObjectOpenHashMap<>();
private static Map<String, BlockState> blockStateStringCache = new HashMap<>();
/** /**
* Create a WorldEdit BlockState from a Bukkit BlockData * Create a WorldEdit BlockState from a Bukkit BlockData
@ -387,21 +390,32 @@ public class BukkitAdapter {
*/ */
public static BlockState adapt(BlockData blockData) { public static BlockState adapt(BlockData blockData) {
checkNotNull(blockData); checkNotNull(blockData);
return blockStateCache.computeIfAbsent(blockData.getAsString(), new Function<String, BlockState>() {
@Nullable if (WorldEditPlugin.getInstance().getBukkitImplAdapter() == null) {
@Override return blockStateStringCache.computeIfAbsent(blockData.getAsString(), input -> {
public BlockState apply(@Nullable String input) {
try { try {
return WorldEdit.getInstance().getBlockFactory().parseFromInput(input, TO_BLOCK_CONTEXT).toImmutableState(); return WorldEdit.getInstance().getBlockFactory().parseFromInput(input, TO_BLOCK_CONTEXT).toImmutableState();
} catch (InputParseException e) { } catch (InputParseException e) {
e.printStackTrace(); e.printStackTrace();
return null; return null;
} }
} });
}); } else {
return blockStateCache.computeIfAbsent(
WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBlockStateId(blockData).orElseGet(
() -> blockData.getAsString().hashCode()
), input -> {
try {
return WorldEdit.getInstance().getBlockFactory().parseFromInput(blockData.getAsString(), TO_BLOCK_CONTEXT).toImmutableState();
} catch (InputParseException e) {
e.printStackTrace();
return null;
}
});
}
} }
private static Map<String, BlockData> blockDataCache = new HashMap<>(); private static Int2ObjectMap<BlockData> blockDataCache = new Int2ObjectOpenHashMap<>();
/** /**
* Create a Bukkit BlockData from a WorldEdit BlockStateHolder * Create a Bukkit BlockData from a WorldEdit BlockStateHolder
@ -411,13 +425,9 @@ public class BukkitAdapter {
*/ */
public static <B extends BlockStateHolder<B>> BlockData adapt(B block) { public static <B extends BlockStateHolder<B>> BlockData adapt(B block) {
checkNotNull(block); checkNotNull(block);
return blockDataCache.computeIfAbsent(block.getAsString(), new Function<String, BlockData>() { // Should never not have an ID for this BlockState.
@Nullable int cacheKey = BlockStateIdAccess.getBlockStateId(block.toImmutableState()).orElseGet(block::hashCode);
@Override return blockDataCache.computeIfAbsent(cacheKey, input -> Bukkit.createBlockData(block.getAsString())).clone();
public BlockData apply(@Nullable String input) {
return Bukkit.createBlockData(block.getAsString());
}
}).clone();
} }
/** /**

View File

@ -33,6 +33,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockType;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@ -175,6 +176,9 @@ public interface BukkitImplAdapter {
*/ */
BaseItemStack adapt(ItemStack itemStack); BaseItemStack adapt(ItemStack itemStack);
default OptionalInt getInternalBlockStateId(BlockData data) {
return OptionalInt.empty();
}
/** /**
* Retrieve the internal ID for a given state, if possible. * Retrieve the internal ID for a given state, if possible.