Fix some issues with java 9 / reflection

This commit is contained in:
Jesse Boyd 2018-08-16 19:56:31 +10:00
parent 8de1fff263
commit 2172ebba83
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
12 changed files with 357 additions and 170 deletions

View File

@ -231,9 +231,8 @@ public class BukkitChunk_All extends IntFaweChunk<Chunk, BukkitQueue_All> {
int xx = bx + x; int xx = bx + x;
BlockTypes type = BlockTypes.getFromStateId(combined); BlockTypes type = BlockTypes.getFromStateId(combined);
if (type == BlockTypes.__RESERVED__) continue;
switch (type) { switch (type) {
case __RESERVED__:
continue;
case AIR: case AIR:
case CAVE_AIR: case CAVE_AIR:
case VOID_AIR: case VOID_AIR:
@ -280,9 +279,8 @@ public class BukkitChunk_All extends IntFaweChunk<Chunk, BukkitQueue_All> {
int j = place ? index : 4095 - index; int j = place ? index : 4095 - index;
int combined = newArray[j]; int combined = newArray[j];
BlockTypes type = BlockTypes.getFromStateId(combined); BlockTypes type = BlockTypes.getFromStateId(combined);
if (type == BlockTypes.__RESERVED__) continue;
switch (type) { switch (type) {
case __RESERVED__:
continue;
case AIR: case AIR:
case CAVE_AIR: case CAVE_AIR:
case VOID_AIR: case VOID_AIR:

View File

@ -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<BlockState[]>() {
@Override
public void run(BlockState[] value) {
this.value = world.getChunkAt(x, z).getTileEntities(b);
}
});
}
@Override @Override
public boolean isLoaded() { public boolean isLoaded() {
return world.isChunkLoaded(x, z); return world.isChunkLoaded(x, z);

View File

@ -6,11 +6,8 @@ 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.registry.InputParser; import com.sk89q.worldedit.internal.registry.InputParser;
import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.util.command.Dispatcher;
import java.util.AbstractMap;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public abstract class FaweParser<T> extends InputParser<T> { public abstract class FaweParser<T> extends InputParser<T> {
protected FaweParser(WorldEdit worldEdit) { protected FaweParser(WorldEdit worldEdit) {
@ -98,6 +95,7 @@ public abstract class FaweParser<T> extends InputParser<T> {
args.add(arg); args.add(arg);
command = full.substring(0, startPos); command = full.substring(0, startPos);
} }
Collections.reverse(args);
ParseEntry entry = new ParseEntry(full, command, i > 0 ? and.get(i - 1) : false); ParseEntry entry = new ParseEntry(full, command, i > 0 ? and.get(i - 1) : false);
keys.add(new AbstractMap.SimpleEntry<>(entry, args)); keys.add(new AbstractMap.SimpleEntry<>(entry, args));
} }

View File

@ -449,8 +449,10 @@ public class Config {
*/ */
private void setAccessible(Field field) throws NoSuchFieldException, IllegalAccessException { private void setAccessible(Field field) throws NoSuchFieldException, IllegalAccessException {
field.setAccessible(true); field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers"); if (Modifier.isFinal(field.getModifiers())) {
modifiersField.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
}
} }
} }

View File

@ -28,7 +28,11 @@ public class ReflectionUtils {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T extends Enum<?>> T addEnum(Class<T> enumType, String enumName) { public static <T extends Enum<?>> T addEnum(Class<T> 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 extends Enum<?>> T addEnum(Class<T> enumType, String enumName, Class<?>[] additionalTypes, Object[] additionalValues) { public static <T extends Enum<?>> T addEnum(Class<T> enumType, String enumName, Class<?>[] additionalTypes, Object[] additionalValues) {
@ -145,13 +149,15 @@ public class ReflectionUtils {
// next we change the modifier in the Field instance to // next we change the modifier in the Field instance to
// not be final anymore, thus tricking reflection into // not be final anymore, thus tricking reflection into
// letting us modify the static final field // letting us modify the static final field
Field modifiersField = Field.class.getDeclaredField("modifiers"); if (Modifier.isFinal(field.getModifiers())) {
modifiersField.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers");
int modifiers = modifiersField.getInt(field); modifiersField.setAccessible(true);
int modifiers = modifiersField.getInt(field);
// blank out the final bit in the modifiers int // blank out the final bit in the modifiers int
modifiers &= ~Modifier.FINAL; modifiers &= ~Modifier.FINAL;
modifiersField.setInt(field, modifiers); modifiersField.setInt(field, modifiers);
}
try { try {
FieldAccessor fa = ReflectionFactory.getReflectionFactory().newFieldAccessor(field, false); FieldAccessor fa = ReflectionFactory.getReflectionFactory().newFieldAccessor(field, false);

View File

@ -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 extends Enum<?>> T addEnum(Class<T> 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 <T extends Enum<?>> void clearEnum(Class<T> 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
}
}

View File

@ -13,7 +13,7 @@ public class SolidBlockMask extends BlockTypeMask {
public static boolean[] getTypes() { public static boolean[] getTypes() {
boolean[] types = new boolean[BlockTypes.size()]; boolean[] types = new boolean[BlockTypes.size()];
for (BlockTypes type : BlockTypes.values) { for (BlockTypes type : BlockTypes.values) {
types[type.ordinal()] = type.getMaterial().isSolid(); types[type.getInternalId()] = type.getMaterial().isSolid();
} }
return types; return types;
} }

View File

@ -652,109 +652,111 @@ public enum BlockTypes implements BlockType {
Instance 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<AbstractProperty> propertiesList;
private final Map<String, AbstractProperty> propertiesMap;
private final Set<AbstractProperty> 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<String, ? extends Property> 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<String, AbstractProperty> propMap = new HashMap<>();
private final String id; int bitOffset = 0;
private final BlockState defaultState; for (Map.Entry<String, ? extends Property> 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; maxInternalStateId += (property.getValues().size() << bitOffset);
private final AbstractProperty[] propertiesArr; }
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<AbstractProperty> propertiesList; this.blockMaterial = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry().getMaterial(type);
private final Map<String, AbstractProperty> propertiesMap; this.itemType = ItemTypes.get(type);
private final Set<AbstractProperty> propertiesSet;
private final BlockMaterial blockMaterial; if (propertyString != null) {
private final int permutations; this.defaultState = new BlockState(parseProperties(propertyString, propertiesMap));
} else {
this.defaultState = new BlockState(internalId);
}
}
@Deprecated public static final int BIT_OFFSET; // Used internally private int parseProperties(String properties, Map<String, AbstractProperty> propertyMap) {
@Deprecated public static final int BIT_MASK; // Used internally int id = internalId;
for (String keyPair : properties.split(",")) {
private BlockState[] states; String[] split = keyPair.split("=");
String name = split[0];
BlockTypes() { String value = split[1];
id = "minecraft:" + name().toLowerCase(); AbstractProperty btp = propertyMap.get(name);
itemType = null; id = btp.modify(id, btp.getValueFor(value));
defaultState = null; }
propertiesMapArr = null; return id;
propertiesArr = null; }
propertiesList = null;
propertiesMap = null;
propertiesSet = null;
blockMaterial = null;
permutations = 0;
} }
BlockTypes(String id) { private final String id;
if (id == null) id = "minecraft:" + name().toLowerCase(); private final Settings settings;
// 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;
int maxInternalStateId = 0; BlockTypes() {
Map<String, ? extends Property> properties = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry().getProperties(this); if (name().indexOf(':') == -1) id = "minecraft:" + name().toLowerCase();
if (!properties.isEmpty()) { else id = name().toLowerCase();
// Ensure the properties are registered settings = null;
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<String, AbstractProperty> propMap = new HashMap<>();
int bitOffset = 0; private void init(String id, int internalId) {
for (Map.Entry<String, ? extends Property> entry : properties.entrySet()) { try {
PropertyKey key = PropertyKey.getOrCreate(entry.getKey()); ReflectionUtils.setFailsafeFieldValue(BlockTypes.class.getDeclaredField("settings"), this, new Settings(this, id, internalId));
AbstractProperty property = ((AbstractProperty) entry.getValue()).withOffset(bitOffset); } catch (Throwable e) {
this.propertiesMapArr[key.ordinal()] = property; throw new RuntimeException(e);
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());
} }
} }
public BlockState withPropertyId(int propertyId) { public BlockState withPropertyId(int propertyId) {
if (propertiesArr.length == 0) return defaultState; if (settings.propertiesArr.length == 0) return settings.defaultState;
BlockState[] tmp = states; BlockState[] tmp = settings.states;
if (tmp == null) { if (tmp == null) {
synchronized (this) { synchronized (this) {
if ((tmp = states) == null) { if ((tmp = settings.states) == null) {
tmp = states = new BlockState[getMaxStateId() + 1]; tmp = settings.states = new BlockState[getMaxStateId() + 1];
tmp[defaultState.getInternalPropertiesId()] = defaultState; tmp[settings.defaultState.getInternalPropertiesId()] = settings.defaultState;
} }
} }
} }
@ -771,12 +773,12 @@ public enum BlockTypes implements BlockType {
@Deprecated @Deprecated
public int getMaxStateId() { public int getMaxStateId() {
return permutations; return settings.permutations;
} }
@Override @Override
public boolean apply(Extent extent, Vector get, Vector set) throws WorldEditException { 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) { public Mask toMask(Extent extent) {
@ -817,7 +819,15 @@ public enum BlockTypes implements BlockType {
* @return * @return
*/ */
public BlockState withProperties(String properties) { 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 @Deprecated
public Map<String, ? extends Property> getPropertyMap() { public Map<String, ? extends Property> getPropertyMap() {
return this.propertiesMap; return this.settings.propertiesMap;
} }
/** /**
@ -837,12 +847,12 @@ public enum BlockTypes implements BlockType {
*/ */
@Deprecated @Deprecated
public List<? extends Property> getProperties() { public List<? extends Property> getProperties() {
return this.propertiesList; return this.settings.propertiesList;
} }
@Deprecated @Deprecated
public Set<? extends Property> getPropertiesSet() { public Set<? extends Property> getPropertiesSet() {
return this.propertiesSet; return this.settings.propertiesSet;
} }
/** /**
@ -853,17 +863,17 @@ public enum BlockTypes implements BlockType {
*/ */
@Deprecated @Deprecated
public <V> Property<V> getProperty(String name) { public <V> Property<V> getProperty(String name) {
return this.propertiesMap.get(name); return this.settings.propertiesMap.get(name);
} }
public boolean hasProperty(PropertyKey key) { public boolean hasProperty(PropertyKey key) {
int ordinal = key.ordinal(); 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 <V> Property<V> getProperty(PropertyKey key) { public <V> Property<V> getProperty(PropertyKey key) {
try { try {
return this.propertiesMapArr[key.ordinal()]; return this.settings.propertiesMapArr[key.ordinal()];
} catch (IndexOutOfBoundsException ignore) { } catch (IndexOutOfBoundsException ignore) {
return null; return null;
} }
@ -875,7 +885,7 @@ public enum BlockTypes implements BlockType {
* @return The default state * @return The default state
*/ */
public BlockState getDefaultState() { public BlockState getDefaultState() {
return this.defaultState; return this.settings.defaultState;
} }
/** /**
@ -894,7 +904,7 @@ public enum BlockTypes implements BlockType {
*/ */
@Nullable @Nullable
public ItemType getItemType() { public ItemType getItemType() {
return itemType; return settings.itemType;
} }
/** /**
@ -903,19 +913,7 @@ public enum BlockTypes implements BlockType {
* @return The material * @return The material
*/ */
public BlockMaterial getMaterial() { public BlockMaterial getMaterial() {
return this.blockMaterial; return this.settings.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;
} }
/** /**
@ -926,7 +924,7 @@ public enum BlockTypes implements BlockType {
* @return internal id * @return internal id
*/ */
public int getInternalId() { public int getInternalId() {
return this.ordinal(); return this.settings.internalId;
} }
@Override @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<String, BlockTypes> $REGISTRY = new HashMap<>(); private static final Map<String, BlockTypes> $REGISTRY = new HashMap<>();
private static int $LENGTH;
public static final BlockTypes[] values; public static final BlockTypes[] values;
static { static {
@ -948,6 +951,7 @@ public enum BlockTypes implements BlockType {
Map<String, String> blockMap = blocks.stream().collect(Collectors.toMap(item -> item.charAt(item.length() - 1) == ']' ? item.substring(0, item.indexOf('[')) : item, item -> item)); Map<String, String> blockMap = blocks.stream().collect(Collectors.toMap(item -> item.charAt(item.length() - 1) == ']' ? item.substring(0, item.indexOf('[')) : item, item -> item));
BlockTypes[] oldValues = BlockTypes.values(); BlockTypes[] oldValues = BlockTypes.values();
$LENGTH = oldValues.length;
int size = blockMap.size(); int size = blockMap.size();
for (BlockTypes type : oldValues) { for (BlockTypes type : oldValues) {
if (!blockMap.containsKey(type.getId())) size++; if (!blockMap.containsKey(type.getId())) size++;
@ -959,12 +963,14 @@ public enum BlockTypes implements BlockType {
BIT_OFFSET = MathMan.log2nlz(size); BIT_OFFSET = MathMan.log2nlz(size);
BIT_MASK = ((1 << BIT_OFFSET) - 1); BIT_MASK = ((1 << BIT_OFFSET) - 1);
LinkedHashSet<BlockTypes> newValues = new LinkedHashSet<>(Arrays.asList(oldValues));
for (BlockTypes type : oldValues) { for (BlockTypes type : oldValues) {
String block = blockMap.getOrDefault(type.getId(), type.getId()); String block = blockMap.getOrDefault(type.getId(), type.getId());
register(block); BlockTypes registered = register(block);
if (!newValues.contains(registered)) newValues.add(registered);
} }
// Cache the values // Cache the values
values = values(); values = newValues.toArray(new BlockTypes[newValues.size()]);
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
throw new RuntimeException(e); throw new RuntimeException(e);
@ -995,17 +1001,14 @@ public enum BlockTypes implements BlockType {
try { try {
existing = valueOf(enumName.toUpperCase()); existing = valueOf(enumName.toUpperCase());
} catch (IllegalArgumentException ignore) {} } catch (IllegalArgumentException ignore) {}
if (existing == null) {
Class[] paramTypes = new Class[]{String.class}; existing = ReflectionUtils.addEnum(BlockTypes.class, enumName);
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);
} }
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); if (typeName.startsWith("minecraft:")) $REGISTRY.put(typeName.substring(10), existing);
$REGISTRY.put(typeName, existing); $REGISTRY.put(typeName, existing);
return existing; return existing;

View File

@ -32,4 +32,7 @@ public interface EntityType {
default String getName() { default String getName() {
return getId(); return getId();
} }
@Deprecated
public int getInternalId();
} }

View File

@ -30,9 +30,7 @@ import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.registry.LegacyMapper; import com.sk89q.worldedit.world.registry.LegacyMapper;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collection; import java.util.*;
import java.util.HashMap;
import java.util.Map;
public enum EntityTypes implements EntityType { public enum EntityTypes implements EntityType {
/* /*
@ -40,6 +38,7 @@ public enum EntityTypes implements EntityType {
Replaced at runtime by the entity registry Replaced at runtime by the entity registry
----------------------------------------------------- -----------------------------------------------------
*/ */
__RESERVED__,
AREA_EFFECT_CLOUD, AREA_EFFECT_CLOUD,
ARMOR_STAND, ARMOR_STAND,
ARROW, ARROW,
@ -139,6 +138,7 @@ public enum EntityTypes implements EntityType {
; ;
private String id; private String id;
private int internalId;
EntityTypes() { EntityTypes() {
this(null); this(null);
@ -151,6 +151,7 @@ public enum EntityTypes implements EntityType {
id = "minecraft:" + id; id = "minecraft:" + id;
} }
this.id = id; this.id = id;
this.internalId = ordinal();
} }
@Override @Override
@ -163,6 +164,11 @@ public enum EntityTypes implements EntityType {
return getId(); return getId();
} }
@Override
public int getInternalId() {
return internalId;
}
/* /*
----------------------------------------------------- -----------------------------------------------------
Static Initializer Static Initializer
@ -237,19 +243,23 @@ public enum EntityTypes implements EntityType {
} }
private static final Map<String, EntityTypes> $REGISTRY = new HashMap<>(); private static final Map<String, EntityTypes> $REGISTRY = new HashMap<>();
private static int $LENGTH;
public static final EntityTypes[] values; public static final EntityTypes[] values;
static { static {
try { try {
Collection<String> ents = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getEntityRegistry().registerEntities(); Collection<String> ents = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getEntityRegistry().registerEntities();
EntityTypes[] oldValues = values();
$LENGTH = oldValues.length;
LinkedHashSet<EntityTypes> newValues = new LinkedHashSet<>(Arrays.asList(oldValues));
if (!ents.isEmpty()) { // No types found - use defaults if (!ents.isEmpty()) { // No types found - use defaults
for (String ent : ents) { for (String ent : ents) {
register(ent); EntityTypes registered = register(ent);
if (!newValues.contains(registered)) newValues.add(registered);
} }
} }
// Cache the values // Cache the values
values = values(); values = newValues.toArray(new EntityTypes[newValues.size()]);
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
throw new RuntimeException(e); throw new RuntimeException(e);
@ -264,11 +274,12 @@ public enum EntityTypes implements EntityType {
// Check existing // Check existing
EntityTypes existing = null; EntityTypes existing = null;
try { existing = valueOf(enumName.toUpperCase()); } catch (IllegalArgumentException ignore) {} try { existing = valueOf(enumName.toUpperCase()); } catch (IllegalArgumentException ignore) {}
if (existing != null) { if (existing == null) {
// TODO additional registration existing = ReflectionUtils.addEnum(EntityTypes.class, enumName);
} else { }
// Create it int internalId = existing.ordinal();
existing = ReflectionUtils.addEnum(EntityTypes.class, enumName, new Class[]{String.class}, new Object[]{id}); if (internalId == 0 && existing != __RESERVED__) {
existing.internalId = $LENGTH++;
} }
if (typeName.startsWith("minecraft:")) $REGISTRY.put(typeName.substring(10), existing); if (typeName.startsWith("minecraft:")) $REGISTRY.put(typeName.substring(10), existing);
$REGISTRY.put(typeName, existing); $REGISTRY.put(typeName, existing);

View File

@ -34,9 +34,7 @@ import com.sk89q.worldedit.world.registry.LegacyMapper;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.Collection; import java.util.*;
import java.util.HashMap;
import java.util.Map;
public enum ItemTypes implements ItemType { public enum ItemTypes implements ItemType {
/* /*
@ -45,6 +43,7 @@ public enum ItemTypes implements ItemType {
----------------------------------------------------- -----------------------------------------------------
*/ */
__RESERVED__,
ACACIA_BOAT, ACACIA_BOAT,
ACACIA_BUTTON, ACACIA_BUTTON,
ACACIA_DOOR, ACACIA_DOOR,
@ -842,6 +841,7 @@ public enum ItemTypes implements ItemType {
private BlockTypes blockType; private BlockTypes blockType;
private final String id; private final String id;
private final BaseItem defaultState; private final BaseItem defaultState;
private int internalId;
ItemTypes() { ItemTypes() {
this(null); this(null);
@ -855,6 +855,7 @@ public enum ItemTypes implements ItemType {
} }
this.id = id; this.id = id;
this.defaultState = new BaseItemStack(this, 1); this.defaultState = new BaseItemStack(this, 1);
this.internalId = ordinal();
} }
private void setBlockType(BlockTypes type) { private void setBlockType(BlockTypes type) {
@ -872,7 +873,7 @@ public enum ItemTypes implements ItemType {
@Deprecated @Deprecated
public int getInternalId() { public int getInternalId() {
return ordinal(); return this.internalId;
} }
/** /**
@ -920,19 +921,23 @@ public enum ItemTypes implements ItemType {
----------------------------------------------------- -----------------------------------------------------
*/ */
private static final Map<String, ItemTypes> $REGISTRY = new HashMap<>(); private static final Map<String, ItemTypes> $REGISTRY = new HashMap<>();
private static int $LENGTH;
public static final ItemTypes[] values; public static final ItemTypes[] values;
static { static {
try { try {
Collection<String> items = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getItemRegistry().registerItems(); Collection<String> items = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getItemRegistry().registerItems();
ItemTypes[] oldValues = values();
$LENGTH = oldValues.length;
LinkedHashSet<ItemTypes> newValues = new LinkedHashSet<>(Arrays.asList(oldValues));
if (!items.isEmpty()) { // No types found - use defaults if (!items.isEmpty()) { // No types found - use defaults
for (String item : items) { for (String item : items) {
register(item); ItemTypes registered = register(item);
if (!newValues.contains(registered)) newValues.add(registered);
} }
} }
// Cache the values // Cache the values
values = values(); values = newValues.toArray(new ItemTypes[newValues.size()]);
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
throw new RuntimeException(e); throw new RuntimeException(e);
@ -964,11 +969,12 @@ public enum ItemTypes implements ItemType {
// Check existing // Check existing
ItemTypes existing = null; ItemTypes existing = null;
try { existing = valueOf(enumName.toUpperCase()); } catch (IllegalArgumentException ignore) {} try { existing = valueOf(enumName.toUpperCase()); } catch (IllegalArgumentException ignore) {}
if (existing != null) { if (existing == null) {
// TODO additional registration existing = ReflectionUtils.addEnum(ItemTypes.class, enumName);
} else { }
// Create it int internalId = existing.ordinal();
existing = ReflectionUtils.addEnum(ItemTypes.class, enumName, new Class[]{String.class}, new Object[]{id}); if (internalId == 0 && existing != __RESERVED__) {
existing.internalId = $LENGTH++;
} }
if (typeName.startsWith("minecraft:")) $REGISTRY.put(typeName.substring(10), existing); if (typeName.startsWith("minecraft:")) $REGISTRY.put(typeName.substring(10), existing);
$REGISTRY.put(typeName, existing); $REGISTRY.put(typeName, existing);