diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All.java index 3adc0d9a9..9839fda48 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All.java @@ -231,9 +231,8 @@ public class BukkitChunk_All extends IntFaweChunk { int xx = bx + x; BlockTypes type = BlockTypes.getFromStateId(combined); + if (type == BlockTypes.__RESERVED__) continue; switch (type) { - case __RESERVED__: - continue; case AIR: case CAVE_AIR: case VOID_AIR: @@ -280,9 +279,8 @@ public class BukkitChunk_All extends IntFaweChunk { int j = place ? index : 4095 - index; int combined = newArray[j]; BlockTypes type = BlockTypes.getFromStateId(combined); + if (type == BlockTypes.__RESERVED__) continue; switch (type) { - case __RESERVED__: - continue; case AIR: case CAVE_AIR: case VOID_AIR: diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncChunk.java index 370baa38c..e4e8037ba 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncChunk.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncChunk.java @@ -130,6 +130,19 @@ public class AsyncChunk implements Chunk { }); } + @Override + public BlockState[] getTileEntities(boolean b) { + if (!isLoaded()) { + return new BlockState[0]; + } + return TaskManager.IMP.sync(new RunnableVal() { + @Override + public void run(BlockState[] value) { + this.value = world.getChunkAt(x, z).getTileEntities(b); + } + }); + } + @Override public boolean isLoaded() { return world.isChunkLoaded(x, z); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/command/FaweParser.java b/worldedit-core/src/main/java/com/boydti/fawe/command/FaweParser.java index ea0903fee..0235e1f94 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/command/FaweParser.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/command/FaweParser.java @@ -6,11 +6,8 @@ import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.util.command.Dispatcher; -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; + +import java.util.*; public abstract class FaweParser extends InputParser { protected FaweParser(WorldEdit worldEdit) { @@ -98,6 +95,7 @@ public abstract class FaweParser extends InputParser { args.add(arg); command = full.substring(0, startPos); } + Collections.reverse(args); ParseEntry entry = new ParseEntry(full, command, i > 0 ? and.get(i - 1) : false); keys.add(new AbstractMap.SimpleEntry<>(entry, args)); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/config/Config.java b/worldedit-core/src/main/java/com/boydti/fawe/config/Config.java index d7232f333..c16ebc848 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/config/Config.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/config/Config.java @@ -449,8 +449,10 @@ public class Config { */ private void setAccessible(Field field) throws NoSuchFieldException, IllegalAccessException { field.setAccessible(true); - Field modifiersField = Field.class.getDeclaredField("modifiers"); - modifiersField.setAccessible(true); - modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + if (Modifier.isFinal(field.getModifiers())) { + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + } } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils.java b/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils.java index 415f0e674..50e66803d 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils.java @@ -28,7 +28,11 @@ public class ReflectionUtils { @SuppressWarnings("unchecked") public static > T addEnum(Class enumType, String enumName) { - return addEnum(enumType, enumName, new Class[]{} , new Object[]{}); + try { + return addEnum(enumType, enumName, new Class[]{}, new Object[]{}); + } catch (Throwable ignore) { + return ReflectionUtils9.addEnum(enumType, enumName); + } } public static > T addEnum(Class enumType, String enumName, Class[] additionalTypes, Object[] additionalValues) { @@ -145,13 +149,15 @@ public class ReflectionUtils { // next we change the modifier in the Field instance to // not be final anymore, thus tricking reflection into // letting us modify the static final field - Field modifiersField = Field.class.getDeclaredField("modifiers"); - modifiersField.setAccessible(true); - int modifiers = modifiersField.getInt(field); + if (Modifier.isFinal(field.getModifiers())) { + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + int modifiers = modifiersField.getInt(field); - // blank out the final bit in the modifiers int - modifiers &= ~Modifier.FINAL; - modifiersField.setInt(field, modifiers); + // blank out the final bit in the modifiers int + modifiers &= ~Modifier.FINAL; + modifiersField.setInt(field, modifiers); + } try { FieldAccessor fa = ReflectionFactory.getReflectionFactory().newFieldAccessor(field, false); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils9.java b/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils9.java new file mode 100644 index 000000000..e054de7a3 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils9.java @@ -0,0 +1,147 @@ +package com.boydti.fawe.util; + +import sun.misc.Unsafe; + +import java.lang.reflect.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class ReflectionUtils9 { + public static > T addEnum(Class enumType, String enumName) { + + // 0. Sanity checks + if (!Enum.class.isAssignableFrom(enumType)) { + throw new RuntimeException("class " + enumType + " is not an instance of Enum"); + } + // 1. Lookup "$VALUES" holder in enum class and get previous enum instances + Field valuesField = null; + Field[] fields = enumType.getDeclaredFields(); + for (Field field : fields) { + if (field.getName().contains("$VALUES")) { + valuesField = field; + break; + } + } + AccessibleObject.setAccessible(new Field[]{valuesField}, true); + + try { + + // 2. Copy it + T[] previousValues = (T[]) valuesField.get(enumType); + List values = new ArrayList(Arrays.asList(previousValues)); + + // 3. build new enum + T newValue = (T) makeEnum(enumType, // The target enum class + enumName, // THE NEW ENUM INSTANCE TO BE DYNAMICALLY ADDED + values.size()); // can be used to pass values to the enum constuctor + + // 4. add new value + values.add(newValue); + + // 5. Set new values field + try { + setFailsafeFieldValue(valuesField, null, + values.toArray((T[]) Array.newInstance(enumType, 0))); + } catch (Throwable e) { + Field ordinalField = Enum.class.getDeclaredField("ordinal"); + setFailsafeFieldValue(ordinalField, newValue, 0); + } + + // 6. Clean enum cache + cleanEnumCache(enumType); + return newValue; + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e.getMessage(), e); + } + } + + public static > void clearEnum(Class enumType) { + // 0. Sanity checks + if (!Enum.class.isAssignableFrom(enumType)) { + throw new RuntimeException("class " + enumType + " is not an instance of Enum"); + } + // 1. Lookup "$VALUES" holder in enum class and get previous enum instances + Field valuesField = null; + Field[] fields = enumType.getDeclaredFields(); + for (Field field : fields) { + if (field.getName().contains("$VALUES")) { + valuesField = field; + break; + } + } + AccessibleObject.setAccessible(new Field[]{valuesField}, true); + try { + setFailsafeFieldValue(valuesField, null, Array.newInstance(enumType, 0)); + // 6. Clean enum cache + cleanEnumCache(enumType); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e.getMessage(), e); + } + } + + public static Object makeEnum(Class enumClass, String value, int ordinal) throws Exception { + Constructor constructor = Unsafe.class.getDeclaredConstructors()[0]; + constructor.setAccessible(true); + Unsafe unsafe = (Unsafe) constructor.newInstance(); + Object instance = unsafe.allocateInstance(enumClass); + + Field ordinalField = Enum.class.getDeclaredField("ordinal"); + setFailsafeFieldValue(ordinalField, instance, 0); + + Field nameField = Enum.class.getDeclaredField("name"); + setFailsafeFieldValue(nameField, instance, value); + + return instance; + } + + public static void setFailsafeFieldValue(Field field, Object target, Object value) + throws NoSuchFieldException, IllegalAccessException { + + // let's make the field accessible + field.setAccessible(true); + + // next we change the modifier in the Field instance to + // not be final anymore, thus tricking reflection into + // letting us modify the static final field + if (Modifier.isFinal(field.getModifiers())) { + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + int modifiers = modifiersField.getInt(field); + + // blank out the final bit in the modifiers int + modifiers &= ~Modifier.FINAL; + modifiersField.setInt(field, modifiers); + } + + try { + System.out.println("Target " + target + " | " + field.getName()); + if (target == null) field.set(null, value); + else field.set(target, value); + +// FieldAccessor fa = ReflectionFactory.getReflectionFactory().newFieldAccessor(field, false); +// fa.set(target, value); + } catch (NoSuchMethodError error) { + field.set(target, value); + } + } + + private static void blankField(Class enumClass, String fieldName) + throws NoSuchFieldException, IllegalAccessException { + for (Field field : Class.class.getDeclaredFields()) { + if (field.getName().contains(fieldName)) { + AccessibleObject.setAccessible(new Field[]{field}, true); + setFailsafeFieldValue(field, enumClass, null); + break; + } + } + } + + private static void cleanEnumCache(Class enumClass) + throws NoSuchFieldException, IllegalAccessException { + blankField(enumClass, "enumConstantDirectory"); // Sun (Oracle?!?) JDK 1.5/6 + blankField(enumClass, "enumConstants"); // IBM JDK + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java index 41c8bf051..67b30b9cd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/SolidBlockMask.java @@ -13,7 +13,7 @@ public class SolidBlockMask extends BlockTypeMask { public static boolean[] getTypes() { boolean[] types = new boolean[BlockTypes.size()]; for (BlockTypes type : BlockTypes.values) { - types[type.ordinal()] = type.getMaterial().isSolid(); + types[type.getInternalId()] = type.getMaterial().isSolid(); } return types; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java index 64e116542..fb4aa4f0b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java @@ -652,109 +652,111 @@ public enum BlockTypes implements BlockType { Instance ----------------------------------------------------- */ + private final static class Settings { + private final int internalId; + private final ItemTypes itemType; + private final BlockState defaultState; + private final AbstractProperty[] propertiesMapArr; + private final AbstractProperty[] propertiesArr; + private final List propertiesList; + private final Map propertiesMap; + private final Set propertiesSet; + private final BlockMaterial blockMaterial; + private final int permutations; + private BlockState[] states; + Settings(BlockTypes type, String id, int internalId) { + this.internalId = internalId; + String propertyString = null; + int propI = id.indexOf('['); + if (propI != -1) { + propertyString = id.substring(propI + 1, id.length() - 1); + } - private final ItemTypes itemType; + int maxInternalStateId = 0; + Map properties = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry().getProperties(type); + if (!properties.isEmpty()) { + // Ensure the properties are registered + int maxOrdinal = 0; + for (String key : properties.keySet()) { + maxOrdinal = Math.max(PropertyKey.getOrCreate(key).ordinal(), maxOrdinal); + } + this.propertiesMapArr = new AbstractProperty[maxOrdinal + 1]; + int prop_arr_i = 0; + this.propertiesArr = new AbstractProperty[properties.size()]; + HashMap propMap = new HashMap<>(); - private final String id; - private final BlockState defaultState; + int bitOffset = 0; + for (Map.Entry entry : properties.entrySet()) { + PropertyKey key = PropertyKey.getOrCreate(entry.getKey()); + AbstractProperty property = ((AbstractProperty) entry.getValue()).withOffset(bitOffset); + this.propertiesMapArr[key.ordinal()] = property; + this.propertiesArr[prop_arr_i++] = property; + propMap.put(entry.getKey(), property); + bitOffset += property.getNumBits(); - private final AbstractProperty[] propertiesMapArr; - private final AbstractProperty[] propertiesArr; + maxInternalStateId += (property.getValues().size() << bitOffset); + } + this.propertiesList = Arrays.asList(this.propertiesArr); + this.propertiesMap = Collections.unmodifiableMap(propMap); + this.propertiesSet = new LinkedHashSet<>(this.propertiesMap.values()); + } else { + this.propertiesMapArr = new AbstractProperty[0]; + this.propertiesArr = this.propertiesMapArr; + this.propertiesList = Collections.emptyList(); + this.propertiesMap = Collections.emptyMap(); + this.propertiesSet = Collections.emptySet(); + } + this.permutations = maxInternalStateId; - private final List propertiesList; - private final Map propertiesMap; - private final Set propertiesSet; + this.blockMaterial = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry().getMaterial(type); + this.itemType = ItemTypes.get(type); - private final BlockMaterial blockMaterial; - private final int permutations; + if (propertyString != null) { + this.defaultState = new BlockState(parseProperties(propertyString, propertiesMap)); + } else { + this.defaultState = new BlockState(internalId); + } + } - @Deprecated public static final int BIT_OFFSET; // Used internally - @Deprecated public static final int BIT_MASK; // Used internally - - private BlockState[] states; - - BlockTypes() { - id = "minecraft:" + name().toLowerCase(); - itemType = null; - defaultState = null; - propertiesMapArr = null; - propertiesArr = null; - propertiesList = null; - propertiesMap = null; - propertiesSet = null; - blockMaterial = null; - permutations = 0; + private int parseProperties(String properties, Map propertyMap) { + int id = internalId; + for (String keyPair : properties.split(",")) { + String[] split = keyPair.split("="); + String name = split[0]; + String value = split[1]; + AbstractProperty btp = propertyMap.get(name); + id = btp.modify(id, btp.getValueFor(value)); + } + return id; + } } - BlockTypes(String id) { - if (id == null) id = "minecraft:" + name().toLowerCase(); - // If it has no namespace, assume minecraft. - else if (!id.contains(":")) { - id = "minecraft:" + id; - } - String propertyString = null; - int propI = id.indexOf('['); - if (propI != -1) { - propertyString = id.substring(propI + 1, id.length() - 1); - id = id.substring(0, propI); - } - this.id = id; + private final String id; + private final Settings settings; - int maxInternalStateId = 0; - Map properties = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry().getProperties(this); - if (!properties.isEmpty()) { - // Ensure the properties are registered - int maxOrdinal = 0; - for (String key : properties.keySet()) { - maxOrdinal = Math.max(PropertyKey.getOrCreate(key).ordinal(), maxOrdinal); - } - this.propertiesMapArr = new AbstractProperty[maxOrdinal + 1]; - int prop_arr_i = 0; - this.propertiesArr = new AbstractProperty[properties.size()]; - HashMap propMap = new HashMap<>(); + BlockTypes() { + if (name().indexOf(':') == -1) id = "minecraft:" + name().toLowerCase(); + else id = name().toLowerCase(); + settings = null; + } - int bitOffset = 0; - for (Map.Entry entry : properties.entrySet()) { - PropertyKey key = PropertyKey.getOrCreate(entry.getKey()); - AbstractProperty property = ((AbstractProperty) entry.getValue()).withOffset(bitOffset); - this.propertiesMapArr[key.ordinal()] = property; - this.propertiesArr[prop_arr_i++] = property; - propMap.put(entry.getKey(), property); - bitOffset += property.getNumBits(); - - maxInternalStateId += (property.getValues().size() << bitOffset); - } - this.propertiesList = Arrays.asList(this.propertiesArr); - this.propertiesMap = Collections.unmodifiableMap(propMap); - this.propertiesSet = new LinkedHashSet<>(this.propertiesMap.values()); - } else { - this.propertiesMapArr = new AbstractProperty[0]; - this.propertiesArr = this.propertiesMapArr; - this.propertiesList = Collections.emptyList(); - this.propertiesMap = Collections.emptyMap(); - this.propertiesSet = Collections.emptySet(); - } - this.permutations = maxInternalStateId; - - this.blockMaterial = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry().getMaterial(this); - this.itemType = ItemTypes.get(this); - - if (propertyString != null) { - this.defaultState = new BlockState(parseProperties(propertyString)); - } else { - this.defaultState = new BlockState(this.getInternalId()); + private void init(String id, int internalId) { + try { + ReflectionUtils.setFailsafeFieldValue(BlockTypes.class.getDeclaredField("settings"), this, new Settings(this, id, internalId)); + } catch (Throwable e) { + throw new RuntimeException(e); } } public BlockState withPropertyId(int propertyId) { - if (propertiesArr.length == 0) return defaultState; - BlockState[] tmp = states; + if (settings.propertiesArr.length == 0) return settings.defaultState; + BlockState[] tmp = settings.states; if (tmp == null) { synchronized (this) { - if ((tmp = states) == null) { - tmp = states = new BlockState[getMaxStateId() + 1]; - tmp[defaultState.getInternalPropertiesId()] = defaultState; + if ((tmp = settings.states) == null) { + tmp = settings.states = new BlockState[getMaxStateId() + 1]; + tmp[settings.defaultState.getInternalPropertiesId()] = settings.defaultState; } } } @@ -771,12 +773,12 @@ public enum BlockTypes implements BlockType { @Deprecated public int getMaxStateId() { - return permutations; + return settings.permutations; } @Override public boolean apply(Extent extent, Vector get, Vector set) throws WorldEditException { - return extent.setBlock(set, this.defaultState); + return extent.setBlock(set, this.settings.defaultState); } public Mask toMask(Extent extent) { @@ -817,7 +819,15 @@ public enum BlockTypes implements BlockType { * @return */ public BlockState withProperties(String properties) { - return withStateId(parseProperties(properties)); + int id = getInternalId(); + for (String keyPair : properties.split(",")) { + String[] split = keyPair.split("="); + String name = split[0]; + String value = split[1]; + AbstractProperty btp = settings.propertiesMap.get(name); + id = btp.modify(id, btp.getValueFor(value)); + } + return withStateId(id); } /** @@ -827,7 +837,7 @@ public enum BlockTypes implements BlockType { */ @Deprecated public Map getPropertyMap() { - return this.propertiesMap; + return this.settings.propertiesMap; } /** @@ -837,12 +847,12 @@ public enum BlockTypes implements BlockType { */ @Deprecated public List getProperties() { - return this.propertiesList; + return this.settings.propertiesList; } @Deprecated public Set getPropertiesSet() { - return this.propertiesSet; + return this.settings.propertiesSet; } /** @@ -853,17 +863,17 @@ public enum BlockTypes implements BlockType { */ @Deprecated public Property getProperty(String name) { - return this.propertiesMap.get(name); + return this.settings.propertiesMap.get(name); } public boolean hasProperty(PropertyKey key) { int ordinal = key.ordinal(); - return this.propertiesMapArr.length > ordinal ? this.propertiesMapArr[ordinal] != null : false; + return this.settings.propertiesMapArr.length > ordinal ? this.settings.propertiesMapArr[ordinal] != null : false; } public Property getProperty(PropertyKey key) { try { - return this.propertiesMapArr[key.ordinal()]; + return this.settings.propertiesMapArr[key.ordinal()]; } catch (IndexOutOfBoundsException ignore) { return null; } @@ -875,7 +885,7 @@ public enum BlockTypes implements BlockType { * @return The default state */ public BlockState getDefaultState() { - return this.defaultState; + return this.settings.defaultState; } /** @@ -894,7 +904,7 @@ public enum BlockTypes implements BlockType { */ @Nullable public ItemType getItemType() { - return itemType; + return settings.itemType; } /** @@ -903,19 +913,7 @@ public enum BlockTypes implements BlockType { * @return The material */ public BlockMaterial getMaterial() { - return this.blockMaterial; - } - - protected int parseProperties(String properties) { - int id = this.getInternalId(); - for (String keyPair : properties.split(",")) { - String[] split = keyPair.split("="); - String name = split[0]; - String value = split[1]; - AbstractProperty btp = (AbstractProperty) getProperty(name); - id = btp.modify(id, btp.getValueFor(value)); - } - return id; + return this.settings.blockMaterial; } /** @@ -926,7 +924,7 @@ public enum BlockTypes implements BlockType { * @return internal id */ public int getInternalId() { - return this.ordinal(); + return this.settings.internalId; } @Override @@ -935,11 +933,16 @@ public enum BlockTypes implements BlockType { } /* - ----------------------------------------------------- - Static Initializer - ----------------------------------------------------- - */ + ----------------------------------------------------- + Static Initializer + ----------------------------------------------------- + */ + + @Deprecated public static final int BIT_OFFSET; // Used internally + @Deprecated public static final int BIT_MASK; // Used internally + private static final Map $REGISTRY = new HashMap<>(); + private static int $LENGTH; public static final BlockTypes[] values; static { @@ -948,6 +951,7 @@ public enum BlockTypes implements BlockType { Map blockMap = blocks.stream().collect(Collectors.toMap(item -> item.charAt(item.length() - 1) == ']' ? item.substring(0, item.indexOf('[')) : item, item -> item)); BlockTypes[] oldValues = BlockTypes.values(); + $LENGTH = oldValues.length; int size = blockMap.size(); for (BlockTypes type : oldValues) { if (!blockMap.containsKey(type.getId())) size++; @@ -959,12 +963,14 @@ public enum BlockTypes implements BlockType { BIT_OFFSET = MathMan.log2nlz(size); BIT_MASK = ((1 << BIT_OFFSET) - 1); + LinkedHashSet newValues = new LinkedHashSet<>(Arrays.asList(oldValues)); for (BlockTypes type : oldValues) { String block = blockMap.getOrDefault(type.getId(), type.getId()); - register(block); + BlockTypes registered = register(block); + if (!newValues.contains(registered)) newValues.add(registered); } // Cache the values - values = values(); + values = newValues.toArray(new BlockTypes[newValues.size()]); } catch (Throwable e) { e.printStackTrace(); throw new RuntimeException(e); @@ -995,17 +1001,14 @@ public enum BlockTypes implements BlockType { try { existing = valueOf(enumName.toUpperCase()); } catch (IllegalArgumentException ignore) {} - - Class[] paramTypes = new Class[]{String.class}; - Object[] args = new Object[]{id}; - - if (existing != null) { - // Load values - ReflectionUtils.copyEnum(existing, enumName, paramTypes, args); - } else { - // Create it - existing = ReflectionUtils.addEnum(BlockTypes.class, enumName, paramTypes, args); + if (existing == null) { + existing = ReflectionUtils.addEnum(BlockTypes.class, enumName); } + int internalId = existing.ordinal(); + if (internalId == 0 && existing != __RESERVED__) { + internalId = $LENGTH++; + } + existing.init(id, internalId); if (typeName.startsWith("minecraft:")) $REGISTRY.put(typeName.substring(10), existing); $REGISTRY.put(typeName, existing); return existing; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java index b9f898fd5..fbd0d6a64 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java @@ -32,4 +32,7 @@ public interface EntityType { default String getName() { return getId(); } + + @Deprecated + public int getInternalId(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java index 9fdfcfd89..3f502425d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java @@ -30,9 +30,7 @@ import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.registry.LegacyMapper; import javax.annotation.Nullable; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; +import java.util.*; public enum EntityTypes implements EntityType { /* @@ -40,6 +38,7 @@ public enum EntityTypes implements EntityType { Replaced at runtime by the entity registry ----------------------------------------------------- */ + __RESERVED__, AREA_EFFECT_CLOUD, ARMOR_STAND, ARROW, @@ -139,6 +138,7 @@ public enum EntityTypes implements EntityType { ; private String id; + private int internalId; EntityTypes() { this(null); @@ -151,6 +151,7 @@ public enum EntityTypes implements EntityType { id = "minecraft:" + id; } this.id = id; + this.internalId = ordinal(); } @Override @@ -163,6 +164,11 @@ public enum EntityTypes implements EntityType { return getId(); } + @Override + public int getInternalId() { + return internalId; + } + /* ----------------------------------------------------- Static Initializer @@ -237,19 +243,23 @@ public enum EntityTypes implements EntityType { } private static final Map $REGISTRY = new HashMap<>(); - + private static int $LENGTH; public static final EntityTypes[] values; static { try { Collection ents = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getEntityRegistry().registerEntities(); + EntityTypes[] oldValues = values(); + $LENGTH = oldValues.length; + LinkedHashSet newValues = new LinkedHashSet<>(Arrays.asList(oldValues)); if (!ents.isEmpty()) { // No types found - use defaults for (String ent : ents) { - register(ent); + EntityTypes registered = register(ent); + if (!newValues.contains(registered)) newValues.add(registered); } } // Cache the values - values = values(); + values = newValues.toArray(new EntityTypes[newValues.size()]); } catch (Throwable e) { e.printStackTrace(); throw new RuntimeException(e); @@ -264,11 +274,12 @@ public enum EntityTypes implements EntityType { // Check existing EntityTypes existing = null; try { existing = valueOf(enumName.toUpperCase()); } catch (IllegalArgumentException ignore) {} - if (existing != null) { - // TODO additional registration - } else { - // Create it - existing = ReflectionUtils.addEnum(EntityTypes.class, enumName, new Class[]{String.class}, new Object[]{id}); + if (existing == null) { + existing = ReflectionUtils.addEnum(EntityTypes.class, enumName); + } + int internalId = existing.ordinal(); + if (internalId == 0 && existing != __RESERVED__) { + existing.internalId = $LENGTH++; } if (typeName.startsWith("minecraft:")) $REGISTRY.put(typeName.substring(10), existing); $REGISTRY.put(typeName, existing); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java index 00c6ff186..28c0f5dc6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java @@ -34,9 +34,7 @@ import com.sk89q.worldedit.world.registry.LegacyMapper; import javax.annotation.Nullable; import java.lang.reflect.Field; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; +import java.util.*; public enum ItemTypes implements ItemType { /* @@ -45,6 +43,7 @@ public enum ItemTypes implements ItemType { ----------------------------------------------------- */ + __RESERVED__, ACACIA_BOAT, ACACIA_BUTTON, ACACIA_DOOR, @@ -842,6 +841,7 @@ public enum ItemTypes implements ItemType { private BlockTypes blockType; private final String id; private final BaseItem defaultState; + private int internalId; ItemTypes() { this(null); @@ -855,6 +855,7 @@ public enum ItemTypes implements ItemType { } this.id = id; this.defaultState = new BaseItemStack(this, 1); + this.internalId = ordinal(); } private void setBlockType(BlockTypes type) { @@ -872,7 +873,7 @@ public enum ItemTypes implements ItemType { @Deprecated public int getInternalId() { - return ordinal(); + return this.internalId; } /** @@ -920,19 +921,23 @@ public enum ItemTypes implements ItemType { ----------------------------------------------------- */ private static final Map $REGISTRY = new HashMap<>(); - + private static int $LENGTH; public static final ItemTypes[] values; static { try { Collection items = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getItemRegistry().registerItems(); + ItemTypes[] oldValues = values(); + $LENGTH = oldValues.length; + LinkedHashSet newValues = new LinkedHashSet<>(Arrays.asList(oldValues)); if (!items.isEmpty()) { // No types found - use defaults for (String item : items) { - register(item); + ItemTypes registered = register(item); + if (!newValues.contains(registered)) newValues.add(registered); } } // Cache the values - values = values(); + values = newValues.toArray(new ItemTypes[newValues.size()]); } catch (Throwable e) { e.printStackTrace(); throw new RuntimeException(e); @@ -964,11 +969,12 @@ public enum ItemTypes implements ItemType { // Check existing ItemTypes existing = null; try { existing = valueOf(enumName.toUpperCase()); } catch (IllegalArgumentException ignore) {} - if (existing != null) { - // TODO additional registration - } else { - // Create it - existing = ReflectionUtils.addEnum(ItemTypes.class, enumName, new Class[]{String.class}, new Object[]{id}); + if (existing == null) { + existing = ReflectionUtils.addEnum(ItemTypes.class, enumName); + } + int internalId = existing.ordinal(); + if (internalId == 0 && existing != __RESERVED__) { + existing.internalId = $LENGTH++; } if (typeName.startsWith("minecraft:")) $REGISTRY.put(typeName.substring(10), existing); $REGISTRY.put(typeName, existing); diff --git a/worldedit-core/src/main/resources/darwin/x86_64/liblz4-java.dylib b/worldedit-core/src/main/resources/darwin/x86_64/liblz4-java.dylib new file mode 100644 index 000000000..9d5cc0e58 Binary files /dev/null and b/worldedit-core/src/main/resources/darwin/x86_64/liblz4-java.dylib differ