mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-08-16 08:15:50 +00:00
Merge branch 'dev' into feat/kts
# Conflicts: # core/src/main/java/com/volmit/iris/core/project/SchemaBuilder.java # gradle/libs.versions.toml
This commit is contained in:
commit
768e569400
@ -1,4 +1,4 @@
|
||||
import io.github.slimjar.func.slimjar
|
||||
import io.github.slimjar.func.slimjarHelper
|
||||
import io.github.slimjar.resolver.data.Mirror
|
||||
import org.ajoberstar.grgit.Grgit
|
||||
import java.net.URI
|
||||
@ -69,7 +69,7 @@ dependencies {
|
||||
compileOnly(libs.multiverseCore)
|
||||
|
||||
// Shaded
|
||||
implementation(slimjar())
|
||||
implementation(slimjarHelper("spigot"))
|
||||
|
||||
// Dynamically Loaded
|
||||
slim(libs.paralithic)
|
||||
|
@ -435,7 +435,7 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
|
||||
public Iris() {
|
||||
instance = this;
|
||||
SlimJar.load(getDataFolder("cache", "libraries"));
|
||||
SlimJar.load();
|
||||
}
|
||||
|
||||
private void enable() {
|
||||
|
@ -39,7 +39,7 @@ import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.parallel.BurstExecutor;
|
||||
import com.volmit.iris.util.parallel.MultiBurst;
|
||||
import com.volmit.iris.util.reflect.OldEnum;
|
||||
import com.volmit.iris.util.reflect.KeyedType;
|
||||
import com.volmit.iris.util.scheduling.ChronoLatch;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import lombok.Data;
|
||||
@ -356,14 +356,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
||||
this.imageLoader = registerLoader(IrisImage.class);
|
||||
this.scriptLoader = registerLoader(IrisScript.class);
|
||||
this.matterObjectLoader = registerLoader(IrisMatterObject.class);
|
||||
if (OldEnum.exists()) {
|
||||
builder.registerTypeAdapterFactory(new TypeAdapterFactory() {
|
||||
@Override
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
|
||||
return (TypeAdapter<T>) OldEnum.create(type.getRawType());
|
||||
}
|
||||
});
|
||||
}
|
||||
builder.registerTypeAdapterFactory(KeyedType::createTypeAdapter);
|
||||
|
||||
gson = builder.create();
|
||||
dimensionLoader.streamAll()
|
||||
|
@ -31,7 +31,7 @@ import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.data.B;
|
||||
import com.volmit.iris.util.json.JSONArray;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.reflect.OldEnum;
|
||||
import com.volmit.iris.util.reflect.KeyedType;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -338,10 +338,10 @@ public class SchemaBuilder {
|
||||
prop.put("$ref", "#/definitions/" + key);
|
||||
description.add(SYMBOL_TYPE__N + " Must be a valid Potion Effect Type (use ctrl+space for auto complete!)");
|
||||
|
||||
} else if (KeyedType.isKeyed(k.getType())) {
|
||||
fancyType = addEnum(k.getType(), prop, description, KeyedType.values(k.getType()), Function.identity());
|
||||
} else if (k.getType().isEnum()) {
|
||||
fancyType = addEnum(k.getType(), prop, description, k.getType().getEnumConstants(), o -> ((Enum<?>) o).name());
|
||||
} else if (OldEnum.isOldEnum(k.getType())) {
|
||||
fancyType = addEnum(k.getType(), prop, description, OldEnum.values(k.getType()), OldEnum::name);
|
||||
}
|
||||
}
|
||||
case "object" -> {
|
||||
@ -506,10 +506,10 @@ public class SchemaBuilder {
|
||||
items.put("$ref", "#/definitions/" + key);
|
||||
prop.put("items", items);
|
||||
description.add(SYMBOL_TYPE__N + " Must be a valid Potion Effect Type (use ctrl+space for auto complete!)");
|
||||
} else if (KeyedType.isKeyed(t.type())) {
|
||||
fancyType = addEnumList(prop, description, t, KeyedType.values(t.type()), Function.identity());
|
||||
} else if (t.type().isEnum()) {
|
||||
fancyType = addEnumList(prop, description, t, t.type().getEnumConstants(), o -> ((Enum<?>) o).name());
|
||||
} else if (OldEnum.isOldEnum(t.type())) {
|
||||
fancyType = addEnumList(prop, description, t, OldEnum.values(t.type()), OldEnum::name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -552,7 +552,7 @@ public class SchemaBuilder {
|
||||
if (present) d.add(" ");
|
||||
if (value instanceof List) {
|
||||
d.add(SYMBOL_LIMIT__N + " Default Value is an empty list");
|
||||
} else if (!cl.isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(cl.isEnum()) && !OldEnum.isOldEnum(cl)) {
|
||||
} else if (!cl.isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(cl.isEnum()) && !KeyedType.isKeyed(cl)) {
|
||||
d.add(SYMBOL_LIMIT__N + " Default Value is a default object (create this object to see default properties)");
|
||||
} else {
|
||||
d.add(SYMBOL_LIMIT__N + " Default Value is " + value);
|
||||
@ -606,7 +606,7 @@ public class SchemaBuilder {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String addEnumList(JSONObject prop, KList<String> description, ArrayType t, Object[] values, Function<Object, String> function) {
|
||||
private <T> String addEnumList(JSONObject prop, KList<String> description, ArrayType t, T[] values, Function<T, String> function) {
|
||||
JSONObject items = new JSONObject();
|
||||
var s = addEnum(t.type(), items, description, values, function);
|
||||
prop.put("items", items);
|
||||
@ -615,10 +615,10 @@ public class SchemaBuilder {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String addEnum(Class<?> type, JSONObject prop, KList<String> description, Object[] values, Function<Object, String> function) {
|
||||
private <T> String addEnum(Class<?> type, JSONObject prop, KList<String> description, T[] values, Function<T, String> function) {
|
||||
JSONArray a = new JSONArray();
|
||||
boolean advanced = type.isAnnotationPresent(Desc.class);
|
||||
for (Object gg : values) {
|
||||
for (T gg : values) {
|
||||
if (advanced) {
|
||||
try {
|
||||
JSONObject j = new JSONObject();
|
||||
@ -664,7 +664,7 @@ public class SchemaBuilder {
|
||||
return "boolean";
|
||||
}
|
||||
|
||||
if (c.equals(String.class) || c.isEnum() || OldEnum.isOldEnum(c) || c.equals(Enchantment.class) || c.equals(PotionEffectType.class)) {
|
||||
if (c.equals(String.class) || c.isEnum() || KeyedType.isKeyed(c)) {
|
||||
return "string";
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,137 @@
|
||||
package com.volmit.iris.util.data.registry;
|
||||
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import lombok.NonNull;
|
||||
import org.bukkit.Keyed;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Registry;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public interface KeyedRegistry<T> {
|
||||
@NonNull Map<NamespacedKey, T> map();
|
||||
|
||||
@Nullable T get(@NonNull NamespacedKey key);
|
||||
@Nullable NamespacedKey keyOf(@NonNull T value);
|
||||
|
||||
default boolean isEmpty() {
|
||||
return map().isEmpty();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
default Optional<T> find(@NonNull String @NonNull ... keys) {
|
||||
if (keys.length == 0) throw new IllegalArgumentException("Need at least one key");
|
||||
for (final String key : keys) {
|
||||
final T t = get(NamespacedKey.minecraft(key));
|
||||
if (t != null) {
|
||||
return Optional.of(t);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
default Optional<T> find(@NonNull NamespacedKey @NonNull ... keys) {
|
||||
if (keys.length == 0) throw new IllegalArgumentException("Need at least one key");
|
||||
for (final NamespacedKey key : keys) {
|
||||
final T t = get(key);
|
||||
if (t != null) {
|
||||
return Optional.of(t);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Contract(value = "null -> null; !null -> new", pure = true)
|
||||
static <T> KeyedRegistry<T> wrapped(Map<NamespacedKey, T> map) {
|
||||
if (map == null) return null;
|
||||
return new MappedRegistry<>(map);
|
||||
}
|
||||
|
||||
@Contract(value = "null -> null; !null -> new", pure = true)
|
||||
static <T extends Keyed> KeyedRegistry<T> wrapped(Registry<T> registry) {
|
||||
if (registry == null) return null;
|
||||
return new BukkitRegistry<>(registry);
|
||||
}
|
||||
|
||||
@Contract(value = "_ -> new", pure = true)
|
||||
static <T> KeyedRegistry<T> wrapped(@NonNull Collection<@NonNull KeyedRegistry<T>> registries) {
|
||||
return new CompoundRegistry<>(registries);
|
||||
}
|
||||
|
||||
|
||||
record MappedRegistry<T>(Map<NamespacedKey, T> map) implements KeyedRegistry<T> {
|
||||
@Override
|
||||
public @Nullable T get(@NonNull NamespacedKey key) {
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable NamespacedKey keyOf(@NonNull T value) {
|
||||
return map.entrySet().stream()
|
||||
.filter(e -> e.getValue().equals(value))
|
||||
.map(Map.Entry::getKey)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
record BukkitRegistry<T extends Keyed>(Registry<T> registry) implements KeyedRegistry<T> {
|
||||
@Override
|
||||
public @NonNull Map<NamespacedKey, T> map() {
|
||||
return registry.stream().collect(Collectors.toMap(Keyed::getKey, Function.identity()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable T get(@NonNull NamespacedKey key) {
|
||||
return registry.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull NamespacedKey keyOf(@NonNull T value) {
|
||||
return value.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
record CompoundRegistry<T>(Collection<KeyedRegistry<T>> registries) implements KeyedRegistry<T> {
|
||||
@Override
|
||||
public @NonNull Map<NamespacedKey, T> map() {
|
||||
final KMap<NamespacedKey, T> m = new KMap<>();
|
||||
for (final KeyedRegistry<T> registry : registries) {
|
||||
m.put(registry.map());
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable T get(@NonNull NamespacedKey key) {
|
||||
for (final KeyedRegistry<T> registry : registries) {
|
||||
final T t = registry.get(key);
|
||||
if (t != null) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable NamespacedKey keyOf(@NonNull T value) {
|
||||
for (final KeyedRegistry<T> registry : registries) {
|
||||
final NamespacedKey key = registry.keyOf(value);
|
||||
if (key != null) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return registries.isEmpty() || registries.stream().allMatch(KeyedRegistry::isEmpty);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.volmit.iris.util.data.registry;
|
||||
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import lombok.NonNull;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class RegistryTypeAdapter<T> extends TypeAdapter<T> {
|
||||
private final KeyedRegistry<T> registry;
|
||||
|
||||
private RegistryTypeAdapter(KeyedRegistry<T> type) {
|
||||
this.registry = type;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static <T> RegistryTypeAdapter<T> of(@NonNull Class<T> type) {
|
||||
final var registry = RegistryUtil.lookup(type);
|
||||
return registry.isEmpty() ? null : new RegistryTypeAdapter<>(registry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter out, T value) throws IOException {
|
||||
if (value == null) {
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
|
||||
final var key = registry.keyOf(value);
|
||||
if (key == null) out.nullValue();
|
||||
else out.value(key.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read(JsonReader in) throws IOException {
|
||||
final NamespacedKey key = NamespacedKey.fromString(in.nextString());
|
||||
return key == null ? null : registry.get(key);
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@ package com.volmit.iris.util.data.registry;
|
||||
|
||||
import com.volmit.iris.core.nms.container.Pair;
|
||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import lombok.NonNull;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Keyed;
|
||||
@ -13,116 +15,78 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.volmit.iris.util.data.registry.KeyedRegistry.wrapped;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class RegistryUtil {
|
||||
private static final AtomicCache<RegistryLookup> registryLookup = new AtomicCache<>();
|
||||
private static final Map<Class<?>, Map<NamespacedKey, Keyed>> KEYED_REGISTRY = new HashMap<>();
|
||||
private static final Map<Class<?>, Map<NamespacedKey, Object>> ENUM_REGISTRY = new HashMap<>();
|
||||
private static final Map<Class<?>, Registry<Keyed>> REGISTRY = new HashMap<>();
|
||||
private static final KMap<Class<?>, KeyedRegistry<Object>> CACHE = new KMap<>();
|
||||
|
||||
@NonNull
|
||||
public static <T> T find(@NonNull Class<T> typeClass, @NonNull String... keys) {
|
||||
return find(typeClass, defaultLookup(), keys);
|
||||
return find(typeClass, Arrays.stream(keys).map(NamespacedKey::minecraft).toArray(NamespacedKey[]::new));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static <T> T find(@NonNull Class<T> typeClass, @Nullable Lookup<T> lookup, @NonNull String... keys) {
|
||||
return find(typeClass, lookup, Arrays.stream(keys).map(NamespacedKey::minecraft).toArray(NamespacedKey[]::new));
|
||||
}
|
||||
|
||||
public static <T> T find(@NonNull Class<T> typeClass, @NonNull NamespacedKey... keys) {
|
||||
return find(typeClass, defaultLookup(), keys);
|
||||
return lookup(typeClass).find(keys).orElseThrow(() -> new IllegalArgumentException("No element found for keys: " + Arrays.toString(keys)));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static <T> T find(@NonNull Class<T> typeClass, @Nullable Lookup<T> lookup, @NonNull NamespacedKey... keys) {
|
||||
if (keys.length == 0) throw new IllegalArgumentException("Need at least one key");
|
||||
Registry<Keyed> registry = null;
|
||||
if (Keyed.class.isAssignableFrom(typeClass)) {
|
||||
registry = getRegistry(typeClass.asSubclass(Keyed.class));
|
||||
}
|
||||
if (registry == null) {
|
||||
registry = REGISTRY.computeIfAbsent(typeClass, t -> Arrays.stream(Registry.class.getDeclaredFields())
|
||||
.filter(field -> Modifier.isStatic(field.getModifiers()) && Modifier.isPublic(field.getModifiers()))
|
||||
.filter(field -> Registry.class.isAssignableFrom(field.getType()))
|
||||
.filter(field -> ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0].equals(t))
|
||||
.map(field -> {
|
||||
try {
|
||||
return (Registry<Keyed>) field.get(null);
|
||||
} catch (IllegalAccessException e) {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst()
|
||||
.orElse(null));
|
||||
}
|
||||
public static <T> KeyedRegistry<T> lookup(@NonNull Class<T> typeClass) {
|
||||
return (KeyedRegistry<T>) CACHE.computeIfAbsent(typeClass, $ -> {
|
||||
final var registries = new KList<KeyedRegistry<Object>>();
|
||||
if (Keyed.class.isAssignableFrom(typeClass)) {
|
||||
var bukkit = wrapped(getRegistry(typeClass.asSubclass(Keyed.class)));
|
||||
if (bukkit == null) {
|
||||
bukkit = Arrays.stream(Registry.class.getDeclaredFields())
|
||||
.filter(field -> Modifier.isStatic(field.getModifiers()) && Modifier.isPublic(field.getModifiers()))
|
||||
.filter(field -> Registry.class.isAssignableFrom(field.getType()))
|
||||
.filter(field -> ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0].equals(typeClass))
|
||||
.map(field -> {
|
||||
try {
|
||||
return (Registry<Keyed>) field.get(null);
|
||||
} catch (IllegalAccessException e) {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst()
|
||||
.map(KeyedRegistry::wrapped)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
if (registry != null) {
|
||||
for (NamespacedKey key : keys) {
|
||||
Keyed value = registry.get(key);
|
||||
if (value != null)
|
||||
return (T) value;
|
||||
registries.addNonNull((KeyedRegistry<Object>) (Object) bukkit);
|
||||
}
|
||||
}
|
||||
registries.add(getKeyedValues(typeClass));
|
||||
registries.add(getEnumValues(typeClass));
|
||||
|
||||
if (lookup != null)
|
||||
return lookup.find(typeClass, keys);
|
||||
throw new IllegalArgumentException("No element found for keys: " + Arrays.toString(keys));
|
||||
return wrapped(registries);
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static <T> T findByField(@NonNull Class<T> typeClass, @NonNull NamespacedKey... keys) {
|
||||
var values = KEYED_REGISTRY.computeIfAbsent(typeClass, RegistryUtil::getKeyedValues);
|
||||
for (NamespacedKey key : keys) {
|
||||
var value = values.get(key);
|
||||
if (value != null)
|
||||
return (T) value;
|
||||
}
|
||||
throw new IllegalArgumentException("No element found for keys: " + Arrays.toString(keys));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static <T> T findByEnum(@NonNull Class<T> typeClass, @NonNull NamespacedKey... keys) {
|
||||
var values = ENUM_REGISTRY.computeIfAbsent(typeClass, RegistryUtil::getEnumValues);
|
||||
for (NamespacedKey key : keys) {
|
||||
var value = values.get(key);
|
||||
if (value != null)
|
||||
return (T) value;
|
||||
}
|
||||
throw new IllegalArgumentException("No element found for keys: " + Arrays.toString(keys));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static <T> Lookup<T> defaultLookup() {
|
||||
return Lookup.combine(RegistryUtil::findByField, RegistryUtil::findByEnum);
|
||||
}
|
||||
|
||||
private static Map<NamespacedKey, Keyed> getKeyedValues(@NonNull Class<?> typeClass) {
|
||||
return Arrays.stream(typeClass.getDeclaredFields())
|
||||
private static KeyedRegistry<Object> getKeyedValues(@NonNull Class<?> typeClass) {
|
||||
return wrapped(Arrays.stream(typeClass.getDeclaredFields())
|
||||
.filter(field -> Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers()))
|
||||
.filter(field -> Keyed.class.isAssignableFrom(field.getType()))
|
||||
.map(field -> {
|
||||
try {
|
||||
return (Keyed) field.get(null);
|
||||
final var value = (Keyed) field.get(null);
|
||||
return new Pair<>(value.getKey(), value);
|
||||
} catch (Throwable e) {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toMap(Keyed::getKey, Function.identity()));
|
||||
.collect(Collectors.toMap(Pair::getA, Pair::getB)));
|
||||
}
|
||||
|
||||
private static Map<NamespacedKey, Object> getEnumValues(@NonNull Class<?> typeClass) {
|
||||
return Arrays.stream(typeClass.getDeclaredFields())
|
||||
private static KeyedRegistry<Object> getEnumValues(@NonNull Class<?> typeClass) {
|
||||
return wrapped(Arrays.stream(typeClass.getDeclaredFields())
|
||||
.filter(field -> Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers()))
|
||||
.filter(field -> typeClass.isAssignableFrom(field.getType()))
|
||||
.map(field -> {
|
||||
@ -133,28 +97,10 @@ public class RegistryUtil {
|
||||
}
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toMap(Pair::getA, Pair::getB));
|
||||
.collect(Collectors.toMap(Pair::getA, Pair::getB)));
|
||||
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Lookup<T> {
|
||||
@NonNull
|
||||
T find(@NonNull Class<T> typeClass, @NonNull NamespacedKey... keys);
|
||||
|
||||
static <T> Lookup<T> combine(@NonNull Lookup<T>... lookups) {
|
||||
if (lookups.length == 0) throw new IllegalArgumentException("Need at least one lookup");
|
||||
return (typeClass, keys) -> {
|
||||
for (Lookup<T> lookup : lookups) {
|
||||
try {
|
||||
return lookup.find(typeClass, keys);
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
}
|
||||
throw new IllegalArgumentException("No element found for keys: " + Arrays.toString(keys));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static <T extends Keyed> Registry<T> getRegistry(@NotNull Class<T> type) {
|
||||
RegistryLookup lookup = registryLookup.aquire(() -> {
|
||||
|
@ -2,34 +2,34 @@ package com.volmit.iris.util.matter.slices;
|
||||
|
||||
import com.volmit.iris.util.data.palette.Palette;
|
||||
import com.volmit.iris.util.matter.Sliced;
|
||||
import com.volmit.iris.util.matter.slices.container.JigsawPieceContainer;
|
||||
import com.volmit.iris.util.matter.slices.container.JigsawStructureContainer;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
@Sliced
|
||||
public class JigsawStructureMatter extends RawMatter<JigsawPieceContainer> {
|
||||
public class JigsawStructureMatter extends RawMatter<JigsawStructureContainer> {
|
||||
public JigsawStructureMatter() {
|
||||
this(1,1,1);
|
||||
}
|
||||
|
||||
public JigsawStructureMatter(int width, int height, int depth) {
|
||||
super(width, height, depth, JigsawPieceContainer.class);
|
||||
super(width, height, depth, JigsawStructureContainer.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Palette<JigsawPieceContainer> getGlobalPalette() {
|
||||
public Palette<JigsawStructureContainer> getGlobalPalette() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNode(JigsawPieceContainer b, DataOutputStream dos) throws IOException {
|
||||
public void writeNode(JigsawStructureContainer b, DataOutputStream dos) throws IOException {
|
||||
dos.writeUTF(b.getLoadKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JigsawPieceContainer readNode(DataInputStream din) throws IOException {
|
||||
return new JigsawPieceContainer(din.readUTF());
|
||||
public JigsawStructureContainer readNode(DataInputStream din) throws IOException {
|
||||
return new JigsawStructureContainer(din.readUTF());
|
||||
}
|
||||
}
|
||||
|
@ -1,124 +1,69 @@
|
||||
package com.volmit.iris.util.misc;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.nms.container.Pair;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import io.github.slimjar.app.builder.ApplicationBuilder;
|
||||
import io.github.slimjar.injector.loader.IsolatedInjectableClassLoader;
|
||||
import io.github.slimjar.app.builder.SpigotApplicationBuilder;
|
||||
import io.github.slimjar.injector.loader.factory.InjectableFactory;
|
||||
import io.github.slimjar.logging.ProcessLogger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static com.volmit.iris.Iris.instance;
|
||||
|
||||
public class SlimJar {
|
||||
private static final String NAME = "Iris";
|
||||
private static final Logger LOGGER = Logger.getLogger(NAME);
|
||||
private static final boolean DEBUG = Boolean.getBoolean("iris.debug-slimjar");
|
||||
private static final boolean DISABLE_REMAPPER = Boolean.getBoolean("iris.disable-remapper");
|
||||
|
||||
private static final ReentrantLock lock = new ReentrantLock();
|
||||
private static final AtomicBoolean loaded = new AtomicBoolean();
|
||||
|
||||
public static void load(@Nullable File localRepository) {
|
||||
public static void load() {
|
||||
if (loaded.get()) return;
|
||||
lock.lock();
|
||||
|
||||
try {
|
||||
if (loaded.getAndSet(true)) return;
|
||||
if (localRepository == null) {
|
||||
localRepository = new File(".iris/libraries");
|
||||
final var downloadPath = instance.getDataFolder("cache", "libraries").toPath();
|
||||
final var logger = instance.getLogger();
|
||||
|
||||
logger.info("Loading libraries...");
|
||||
try {
|
||||
new SpigotApplicationBuilder(instance)
|
||||
.downloadDirectoryPath(downloadPath)
|
||||
.debug(DEBUG)
|
||||
.remap(!DISABLE_REMAPPER)
|
||||
.build();
|
||||
} catch (Throwable e) {
|
||||
Iris.warn("Failed to inject the library loader, falling back to application builder");
|
||||
ApplicationBuilder.appending(instance.getName())
|
||||
.injectableFactory(InjectableFactory.selecting(InjectableFactory.ERROR, InjectableFactory.INJECTABLE, InjectableFactory.WRAPPED, InjectableFactory.UNSAFE))
|
||||
.downloadDirectoryPath(downloadPath)
|
||||
.logger(new ProcessLogger() {
|
||||
@Override
|
||||
public void info(@NotNull String message, @Nullable Object... args) {
|
||||
if (!DEBUG) return;
|
||||
instance.getLogger().info(message.formatted(args));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(@NotNull String message, @Nullable Object... args) {
|
||||
instance.getLogger().severe(message.formatted(args));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(@NotNull String message, @Nullable Object... args) {
|
||||
if (!DEBUG) return;
|
||||
instance.getLogger().info(message.formatted(args));
|
||||
}
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
LOGGER.info("Loading libraries...");
|
||||
load(localRepository.toPath(), new ProcessLogger() {
|
||||
@Override
|
||||
public void info(@NotNull String message, @Nullable Object... args) {
|
||||
if (!DEBUG) return;
|
||||
LOGGER.info(message.formatted(args));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(@NotNull String message, @Nullable Object... args) {
|
||||
LOGGER.severe(message.formatted(args));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(@NotNull String message, @Nullable Object... args) {
|
||||
if (!DEBUG) return;
|
||||
LOGGER.info(message.formatted(args));
|
||||
}
|
||||
});
|
||||
LOGGER.info("Libraries loaded successfully!");
|
||||
logger.info("Libraries loaded successfully!");
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private static void load(Path downloadPath, ProcessLogger logger) {
|
||||
try {
|
||||
loadSpigot(downloadPath, logger);
|
||||
} catch (Throwable e) {
|
||||
Iris.warn("Failed to inject the library loader, falling back to application builder");
|
||||
ApplicationBuilder.appending(NAME)
|
||||
.injectableFactory(InjectableFactory.selecting(InjectableFactory.ERROR, InjectableFactory.INJECTABLE, InjectableFactory.WRAPPED, InjectableFactory.UNSAFE))
|
||||
.downloadDirectoryPath(downloadPath)
|
||||
.logger(logger)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadSpigot(Path downloadPath, ProcessLogger logger) throws Throwable {
|
||||
var current = SlimJar.class.getClassLoader();
|
||||
var libraryLoaderField = current.getClass().getDeclaredField("libraryLoader");
|
||||
libraryLoaderField.setAccessible(true);
|
||||
if (!ClassLoader.class.isAssignableFrom(libraryLoaderField.getType())) throw new IllegalStateException("Failed to find library loader");
|
||||
final var libraryLoader = (ClassLoader) libraryLoaderField.get(current);
|
||||
|
||||
final var pair = findRemapper();
|
||||
final var remapper = pair.getA();
|
||||
final var factory = pair.getB();
|
||||
final var classpath = new KList<URL>();
|
||||
|
||||
ApplicationBuilder.injecting(NAME, classpath::add)
|
||||
.downloadDirectoryPath(downloadPath)
|
||||
.logger(logger)
|
||||
.build();
|
||||
|
||||
final var urls = remapper.andThen(KList::new)
|
||||
.apply(classpath.convertNasty(url -> Path.of(url.toURI())))
|
||||
.convertNasty(path -> path.toUri().toURL())
|
||||
.toArray(URL[]::new);
|
||||
libraryLoaderField.set(current, factory.apply(urls, libraryLoader == null ? current.getParent() : libraryLoader));
|
||||
}
|
||||
|
||||
private static Pair<Function<List<Path>, List<Path>>, BiFunction<URL[], ClassLoader, URLClassLoader>> findRemapper() {
|
||||
Function<List<Path>, List<Path>> mapper = null;
|
||||
BiFunction<URL[], ClassLoader, URLClassLoader> factory = null;
|
||||
if (!DISABLE_REMAPPER) {
|
||||
try {
|
||||
var libraryLoader = Class.forName("org.bukkit.plugin.java.LibraryLoader");
|
||||
var mapperField = libraryLoader.getDeclaredField("REMAPPER");
|
||||
var factoryField = libraryLoader.getDeclaredField("LIBRARY_LOADER_FACTORY");
|
||||
mapperField.setAccessible(true);
|
||||
factoryField.setAccessible(true);
|
||||
mapper = (Function<List<Path>, List<Path>>) mapperField.get(null);
|
||||
factory = (BiFunction<URL[], ClassLoader, URLClassLoader>) factoryField.get(null);
|
||||
} catch (Throwable ignored) {}
|
||||
}
|
||||
|
||||
if (mapper == null) mapper = Function.identity();
|
||||
if (factory == null) factory = (urls, parent) -> new IsolatedInjectableClassLoader(urls, List.of(), parent);
|
||||
return new Pair<>(mapper, factory);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
package com.volmit.iris.util.reflect;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.volmit.iris.util.data.registry.RegistryTypeAdapter;
|
||||
import com.volmit.iris.util.data.registry.RegistryUtil;
|
||||
import org.bukkit.Keyed;
|
||||
|
||||
public class KeyedType {
|
||||
private static final boolean KEYED_ENABLED = Boolean.getBoolean("iris.keyed-types");
|
||||
private static final boolean KEYED_LENIENT = Boolean.getBoolean("iris.keyed-lenient");
|
||||
|
||||
public static String[] values(Class<?> type) {
|
||||
if (!isKeyed(type)) return new String[0];
|
||||
if (!KEYED_ENABLED) return OldEnum.values(type);
|
||||
return RegistryUtil.lookup(type)
|
||||
.map()
|
||||
.keySet()
|
||||
.stream()
|
||||
.map(Object::toString)
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
public static boolean isKeyed(Class<?> type) {
|
||||
if (KEYED_ENABLED) {
|
||||
if (KEYED_LENIENT) return !RegistryUtil.lookup(type).isEmpty();
|
||||
else return Keyed.class.isAssignableFrom(type);
|
||||
} else return OldEnum.isOldEnum(type);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> TypeAdapter<T> createTypeAdapter(Gson gson, TypeToken<T> type) {
|
||||
if (!isKeyed(type.getRawType())) return null;
|
||||
return (TypeAdapter<T>) (KEYED_ENABLED ? RegistryTypeAdapter.of(type.getRawType()) : OldEnum.create(type.getRawType()));
|
||||
}
|
||||
}
|
@ -1,20 +1,22 @@
|
||||
package com.volmit.iris.util.reflect;
|
||||
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
@Deprecated(since = "3.7.1")
|
||||
public class OldEnum {
|
||||
|
||||
private static final Class<?> oldEnum;
|
||||
private static final Method name;
|
||||
private static final MethodHandle name;
|
||||
|
||||
public static boolean exists() {
|
||||
return oldEnum != null;
|
||||
@ -25,11 +27,16 @@ public class OldEnum {
|
||||
}
|
||||
|
||||
public static <T> T valueOf(Class<? extends T> c, String name) {
|
||||
try {
|
||||
return (T) c.getDeclaredField(name).get(null);
|
||||
} catch (Throwable e) {
|
||||
return null;
|
||||
return valueOf(c, name, name.replace(".", "_"));
|
||||
}
|
||||
|
||||
public static <T> T valueOf(Class<? extends T> c, String... names) {
|
||||
for (final String name : names) {
|
||||
try {
|
||||
return (T) c.getDeclaredField(name).get(null);
|
||||
} catch (Throwable ignored) {}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String name(Object o) {
|
||||
@ -40,20 +47,20 @@ public class OldEnum {
|
||||
}
|
||||
}
|
||||
|
||||
public static Object[] values(Class<?> clazz) {
|
||||
if (!isOldEnum(clazz)) return new Object[0];
|
||||
public static String[] values(Class<?> clazz) {
|
||||
if (!isOldEnum(clazz)) return new String[0];
|
||||
return Arrays.stream(clazz.getDeclaredFields())
|
||||
.filter(f -> Modifier.isStatic(f.getModifiers()))
|
||||
.filter(f -> Modifier.isFinal(f.getModifiers()))
|
||||
.map(f -> {
|
||||
try {
|
||||
return f.get(null);
|
||||
return name(f.get(null));
|
||||
} catch (Throwable ignored) {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.toArray();
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
public static <T> TypeAdapter<T> create(Class<? extends T> type) {
|
||||
@ -76,10 +83,10 @@ public class OldEnum {
|
||||
|
||||
static {
|
||||
Class<?> clazz = null;
|
||||
Method method = null;
|
||||
MethodHandle method = null;
|
||||
try {
|
||||
clazz = Class.forName("org.bukkit.util.OldEnum");
|
||||
method = clazz.getDeclaredMethod("name");
|
||||
method = MethodHandles.lookup().findVirtual(clazz, "name", MethodType.methodType(String.class));
|
||||
} catch (Throwable ignored) {}
|
||||
|
||||
if (clazz == null || method == null) {
|
||||
|
@ -5,7 +5,7 @@
|
||||
[versions]
|
||||
# Plugins
|
||||
shadow = "9.0.0-rc1" # https://plugins.gradle.org/plugin/com.gradleup.shadow
|
||||
slimjar = "2.1.4" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar
|
||||
slimjar = "2.1.5" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar
|
||||
download = "5.6.0" # https://plugins.gradle.org/plugin/de.undercouch.download
|
||||
runPaper = "2.3.1" # https://plugins.gradle.org/plugin/xyz.jpenilla.run-paper
|
||||
sentryPlugin = "5.8.0" # https://github.com/getsentry/sentry-android-gradle-plugin
|
||||
@ -15,8 +15,8 @@ grgit = "5.3.2" # https://github.com/ajoberstar/grgit
|
||||
lombok = "1.18.38"
|
||||
spigot = "1.20.1-R0.1-SNAPSHOT" # https://hub.spigotmc.org/nexus/repository/snapshots/org/spigotmc/spigot-api/maven-metadata.xml
|
||||
log4j = "2.19.0" # https://central.sonatype.com/artifact/org.apache.logging.log4j/log4j-api
|
||||
adventure-api = "4.23.0" # https://github.com/KyoriPowered/adventure
|
||||
adventure-platform = "4.4.0" # https://github.com/KyoriPowered/adventure-platform
|
||||
adventure-api = "4.24.0" # https://github.com/KyoriPowered/adventure
|
||||
adventure-platform = "4.4.1" # https://github.com/KyoriPowered/adventure-platform
|
||||
|
||||
annotations = "26.0.2" # https://central.sonatype.com/artifact/org.jetbrains/annotations
|
||||
paralithic = "0.8.1" # https://github.com/PolyhedralDev/Paralithic/
|
||||
|
Loading…
x
Reference in New Issue
Block a user