From 2172ebba8388e7e1cd255500b56d938c34d0f31f Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Thu, 16 Aug 2018 19:56:31 +1000 Subject: [PATCH] Fix some issues with java 9 / reflection --- .../fawe/bukkit/v0/BukkitChunk_All.java | 6 +- .../fawe/bukkit/wrapper/AsyncChunk.java | 13 + .../com/boydti/fawe/command/FaweParser.java | 8 +- .../java/com/boydti/fawe/config/Config.java | 8 +- .../com/boydti/fawe/util/ReflectionUtils.java | 20 +- .../boydti/fawe/util/ReflectionUtils9.java | 147 ++++++++++ .../function/mask/SolidBlockMask.java | 2 +- .../worldedit/world/block/BlockTypes.java | 257 +++++++++--------- .../worldedit/world/entity/EntityType.java | 3 + .../worldedit/world/entity/EntityTypes.java | 33 ++- .../sk89q/worldedit/world/item/ItemTypes.java | 30 +- .../resources/darwin/x86_64/liblz4-java.dylib | Bin 0 -> 47188 bytes 12 files changed, 357 insertions(+), 170 deletions(-) create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils9.java create mode 100644 worldedit-core/src/main/resources/darwin/x86_64/liblz4-java.dylib 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 0000000000000000000000000000000000000000..9d5cc0e58e3a99ce201dae544636959c8bfdccd6 GIT binary patch literal 47188 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 M8J~N32OwAeZ}C<7HUIzs literal 0 HcmV?d00001