This commit is contained in:
Intege-rs
2026-01-24 07:55:36 -05:00
commit 7a77188758
5298 changed files with 723645 additions and 0 deletions

View File

@@ -0,0 +1,82 @@
package com.hypixel.fastutil;
import java.util.Collection;
public interface FastCollection<E> extends Collection<E> {
void forEachWithFloat(FastCollection.FastConsumerF<? super E> var1, float var2);
void forEachWithInt(FastCollection.FastConsumerI<? super E> var1, int var2);
void forEachWithLong(FastCollection.FastConsumerL<? super E> var1, long var2);
<A, B, C, D> void forEach(
FastCollection.FastConsumerD9<? super E, A, B, C, D> var1,
A var2,
double var3,
double var5,
double var7,
double var9,
double var11,
double var13,
double var15,
double var17,
double var19,
B var21,
C var22,
D var23
);
<A, B, C, D> void forEach(
FastCollection.FastConsumerD6<? super E, A, B, C, D> var1,
A var2,
double var3,
double var5,
double var7,
double var9,
double var11,
double var13,
B var15,
C var16,
D var17
);
@FunctionalInterface
public interface FastConsumerD6<A, B, C, D, E> {
void accept(A var1, B var2, double var3, double var5, double var7, double var9, double var11, double var13, C var15, D var16, E var17);
}
@FunctionalInterface
public interface FastConsumerD9<A, B, C, D, E> {
void accept(
A var1,
B var2,
double var3,
double var5,
double var7,
double var9,
double var11,
double var13,
double var15,
double var17,
double var19,
C var21,
D var22,
E var23
);
}
@FunctionalInterface
public interface FastConsumerF<A> {
void accept(A var1, float var2);
}
@FunctionalInterface
public interface FastConsumerI<A> {
void accept(A var1, int var2);
}
@FunctionalInterface
public interface FastConsumerL<A> {
void accept(A var1, long var2);
}
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.bytes;
@FunctionalInterface
public interface Byte2ByteOperator {
byte apply(byte var1, byte var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.bytes;
@FunctionalInterface
public interface Byte2CharOperator {
char apply(byte var1, char var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.bytes;
@FunctionalInterface
public interface Byte2DoubleOperator {
double apply(byte var1, double var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.bytes;
@FunctionalInterface
public interface Byte2FloatOperator {
float apply(byte var1, float var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.bytes;
@FunctionalInterface
public interface Byte2IntOperator {
int apply(byte var1, int var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.bytes;
@FunctionalInterface
public interface Byte2LongOperator {
long apply(byte var1, long var2);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.bytes;
@FunctionalInterface
public interface Byte2ObjectOperator<V> {
V apply(byte var1, V var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.bytes;
@FunctionalInterface
public interface Byte2ShortOperator {
short apply(byte var1, short var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.chars;
@FunctionalInterface
public interface Char2ByteOperator {
byte apply(char var1, byte var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.chars;
@FunctionalInterface
public interface Char2CharOperator {
char apply(char var1, char var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.chars;
@FunctionalInterface
public interface Char2DoubleOperator {
double apply(char var1, double var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.chars;
@FunctionalInterface
public interface Char2FloatOperator {
float apply(char var1, float var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.chars;
@FunctionalInterface
public interface Char2IntOperator {
int apply(char var1, int var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.chars;
@FunctionalInterface
public interface Char2LongOperator {
long apply(char var1, long var2);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.chars;
@FunctionalInterface
public interface Char2ObjectOperator<V> {
V apply(char var1, V var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.chars;
@FunctionalInterface
public interface Char2ShortOperator {
short apply(char var1, short var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.doubles;
@FunctionalInterface
public interface Double2ByteOperator {
byte apply(double var1, byte var3);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.doubles;
@FunctionalInterface
public interface Double2CharOperator {
char apply(double var1, char var3);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.doubles;
@FunctionalInterface
public interface Double2DoubleOperator {
double apply(double var1, double var3);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.doubles;
@FunctionalInterface
public interface Double2FloatOperator {
float apply(double var1, float var3);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.doubles;
@FunctionalInterface
public interface Double2IntOperator {
int apply(double var1, int var3);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.doubles;
@FunctionalInterface
public interface Double2LongOperator {
long apply(double var1, long var3);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.doubles;
@FunctionalInterface
public interface Double2ObjectOperator<V> {
V apply(double var1, V var3);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.doubles;
@FunctionalInterface
public interface Double2ShortOperator {
short apply(double var1, short var3);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.floats;
@FunctionalInterface
public interface Float2ByteOperator {
byte apply(float var1, byte var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.floats;
@FunctionalInterface
public interface Float2CharOperator {
char apply(float var1, char var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.floats;
@FunctionalInterface
public interface Float2DoubleOperator {
double apply(float var1, double var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.floats;
@FunctionalInterface
public interface Float2FloatOperator {
float apply(float var1, float var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.floats;
@FunctionalInterface
public interface Float2IntOperator {
int apply(float var1, int var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.floats;
@FunctionalInterface
public interface Float2LongOperator {
long apply(float var1, long var2);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.floats;
@FunctionalInterface
public interface Float2ObjectOperator<V> {
V apply(float var1, V var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.floats;
@FunctionalInterface
public interface Float2ShortOperator {
short apply(float var1, short var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.ints;
@FunctionalInterface
public interface Int2ByteOperator {
byte apply(int var1, byte var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.ints;
@FunctionalInterface
public interface Int2CharOperator {
char apply(int var1, char var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.ints;
@FunctionalInterface
public interface Int2DoubleOperator {
double apply(int var1, double var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.ints;
@FunctionalInterface
public interface Int2FloatOperator {
float apply(int var1, float var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.ints;
@FunctionalInterface
public interface Int2IntOperator {
int apply(int var1, int var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.ints;
@FunctionalInterface
public interface Int2LongOperator {
long apply(int var1, long var2);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.ints;
@FunctionalInterface
public interface Int2ObjectOperator<V> {
V apply(int var1, V var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.ints;
@FunctionalInterface
public interface Int2ShortOperator {
short apply(int var1, short var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.longs;
@FunctionalInterface
public interface Long2ByteOperator {
byte apply(long var1, byte var3);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.longs;
@FunctionalInterface
public interface Long2CharOperator {
char apply(long var1, char var3);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.longs;
@FunctionalInterface
public interface Long2DoubleOperator {
double apply(long var1, double var3);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.longs;
@FunctionalInterface
public interface Long2FloatOperator {
float apply(long var1, float var3);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.longs;
@FunctionalInterface
public interface Long2IntOperator {
int apply(long var1, int var3);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.longs;
@FunctionalInterface
public interface Long2LongOperator {
long apply(long var1, long var3);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.longs;
@FunctionalInterface
public interface Long2ObjectOperator<V> {
V apply(long var1, V var3);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.longs;
@FunctionalInterface
public interface Long2ShortOperator {
short apply(long var1, short var3);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.shorts;
@FunctionalInterface
public interface Short2ByteOperator {
byte apply(short var1, byte var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.shorts;
@FunctionalInterface
public interface Short2CharOperator {
char apply(short var1, char var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.shorts;
@FunctionalInterface
public interface Short2DoubleOperator {
double apply(short var1, double var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.shorts;
@FunctionalInterface
public interface Short2FloatOperator {
float apply(short var1, float var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.shorts;
@FunctionalInterface
public interface Short2IntOperator {
int apply(short var1, int var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.shorts;
@FunctionalInterface
public interface Short2LongOperator {
long apply(short var1, long var2);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.shorts;
@FunctionalInterface
public interface Short2ObjectOperator<V> {
V apply(short var1, V var2);
}

View File

@@ -0,0 +1,6 @@
package com.hypixel.fastutil.shorts;
@FunctionalInterface
public interface Short2ShortOperator {
short apply(short var1, short var2);
}

View File

@@ -0,0 +1,18 @@
package com.hypixel.fastutil.util;
public class SneakyThrow {
public SneakyThrow() {
}
public static RuntimeException sneakyThrow(Throwable t) {
if (t == null) {
throw new NullPointerException("t");
} else {
return sneakyThrow0(t);
}
}
private static <T extends Throwable> T sneakyThrow0(Throwable t) throws T {
throw t;
}
}

View File

@@ -0,0 +1,55 @@
package com.hypixel.fastutil.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.concurrent.ThreadLocalRandom;
import sun.misc.Unsafe;
public class TLRUtil {
private static final Unsafe UNSAFE;
private static final long PROBE;
public TLRUtil() {
}
public static void localInit() {
ThreadLocalRandom.current();
}
public static int getProbe() {
return UNSAFE.getInt(Thread.currentThread(), PROBE);
}
public static int advanceProbe(int probe) {
probe ^= probe << 13;
probe ^= probe >>> 17;
probe ^= probe << 5;
UNSAFE.putInt(Thread.currentThread(), PROBE, probe);
return probe;
}
static {
Unsafe instance;
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
instance = (Unsafe)field.get(null);
} catch (Exception var5) {
try {
Constructor<Unsafe> c = Unsafe.class.getDeclaredConstructor();
c.setAccessible(true);
instance = c.newInstance();
} catch (Exception var4) {
throw SneakyThrow.sneakyThrow(var4);
}
}
UNSAFE = instance;
try {
PROBE = UNSAFE.objectFieldOffset(Thread.class.getDeclaredField("threadLocalRandomProbe"));
} catch (NoSuchFieldException var3) {
throw SneakyThrow.sneakyThrow(var3);
}
}
}

View File

@@ -0,0 +1,59 @@
package com.hypixel.hytale;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.logger.backend.HytaleFileHandler;
import com.hypixel.hytale.logger.backend.HytaleLoggerBackend;
import com.hypixel.hytale.logger.sentry.SkipSentryException;
import com.hypixel.hytale.server.core.HytaleServer;
import com.hypixel.hytale.server.core.HytaleServerConfig;
import com.hypixel.hytale.server.core.Options;
import io.sentry.Sentry;
import java.util.Map.Entry;
import java.util.logging.Level;
public class LateMain {
public LateMain() {
}
public static void lateMain(String[] args) {
try {
if (!Options.parse(args)) {
HytaleLogger.init();
HytaleFileHandler.INSTANCE.enable();
HytaleLogger.replaceStd();
HytaleLoggerBackend.LOG_LEVEL_LOADER = name -> {
for (Entry<String, Level> e : Options.getOptionSet().valuesOf(Options.LOG_LEVELS)) {
if (name.equals(e.getKey())) {
return e.getValue();
}
}
HytaleServer hytaleServer = HytaleServer.get();
if (hytaleServer != null) {
HytaleServerConfig config = hytaleServer.getConfig();
if (config != null) {
Level configLevel = config.getLogLevels().get(name);
if (configLevel != null) {
return configLevel;
}
}
}
return Options.getOptionSet().has(Options.SHUTDOWN_AFTER_VALIDATE) ? Level.WARNING : null;
};
if (Options.getOptionSet().has(Options.SHUTDOWN_AFTER_VALIDATE)) {
HytaleLoggerBackend.reloadLogLevels();
}
new HytaleServer();
}
} catch (Throwable var2) {
if (!SkipSentryException.hasSkipSentry(var2)) {
Sentry.captureException(var2);
}
var2.printStackTrace();
throw new RuntimeException("Failed to create HytaleServer", var2);
}
}
}

View File

@@ -0,0 +1,78 @@
package com.hypixel.hytale;
import com.hypixel.hytale.plugin.early.EarlyPluginLoader;
import com.hypixel.hytale.plugin.early.TransformingClassLoader;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Locale;
import javax.annotation.Nonnull;
public final class Main {
public Main() {
}
public static void main(String[] args) {
Locale.setDefault(Locale.ENGLISH);
System.setProperty("java.awt.headless", "true");
System.setProperty("file.encoding", "UTF-8");
EarlyPluginLoader.loadEarlyPlugins(args);
if (EarlyPluginLoader.hasTransformers()) {
launchWithTransformingClassLoader(args);
} else {
LateMain.lateMain(args);
}
}
private static void launchWithTransformingClassLoader(@Nonnull String[] args) {
try {
URL[] urls = getClasspathUrls();
ClassLoader appClassLoader = Main.class.getClassLoader();
TransformingClassLoader transformingClassLoader = new TransformingClassLoader(
urls, EarlyPluginLoader.getTransformers(), appClassLoader.getParent(), appClassLoader
);
Thread.currentThread().setContextClassLoader(transformingClassLoader);
Class<?> lateMainClass = transformingClassLoader.loadClass("com.hypixel.hytale.LateMain");
Method mainMethod = lateMainClass.getMethod("lateMain", String[].class);
mainMethod.invoke(null, args);
} catch (NoSuchMethodException | IllegalAccessException | ClassNotFoundException var6) {
throw new RuntimeException("Failed to launch with transforming classloader", var6);
} catch (InvocationTargetException var7) {
Throwable cause = var7.getCause();
if (cause instanceof RuntimeException re) {
throw re;
} else if (cause instanceof Error err) {
throw err;
} else {
throw new RuntimeException("LateMain.lateMain() threw an exception", cause);
}
}
}
private static URL[] getClasspathUrls() {
if (Main.class.getClassLoader() instanceof URLClassLoader urlClassLoader) {
return urlClassLoader.getURLs();
} else {
ObjectArrayList<URL> urls = new ObjectArrayList<>();
String classpath = System.getProperty("java.class.path");
if (classpath != null && !classpath.isEmpty()) {
for (String pathStr : classpath.split(System.getProperty("path.separator"))) {
try {
Path path = Path.of(pathStr);
if (Files.exists(path)) {
urls.add(path.toUri().toURL());
}
} catch (Exception var8) {
System.err.println("[EarlyPlugin] Failed to parse classpath entry: " + pathStr);
}
}
}
return urls.toArray(URL[]::new);
}
}
}

View File

@@ -0,0 +1,11 @@
package com.hypixel.hytale.assetstore;
public class AssetConstants {
public static final int EXPECTED_CHILDREN_PER_ASSET = 3;
public static final int EXPECTED_ASSETS_PER_PATH = 1;
public static final int EXPECTED_VALUES_PER_TAG = 3;
public static final int EXPECTED_ASSETS_PER_TAG = 3;
public AssetConstants() {
}
}

View File

@@ -0,0 +1,279 @@
package com.hypixel.hytale.assetstore;
import com.hypixel.hytale.assetstore.map.JsonAssetWithMap;
import com.hypixel.hytale.codec.ExtraInfo;
import com.hypixel.hytale.common.util.ArrayUtil;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.ints.IntSets;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class AssetExtraInfo<K> extends ExtraInfo {
@Nullable
private final Path assetPath;
private final AssetExtraInfo.Data data;
public AssetExtraInfo(AssetExtraInfo.Data data) {
super(Integer.MAX_VALUE, AssetValidationResults::new);
this.assetPath = null;
this.data = data;
}
public AssetExtraInfo(Path assetPath, AssetExtraInfo.Data data) {
super(Integer.MAX_VALUE, AssetValidationResults::new);
this.assetPath = assetPath;
this.data = data;
}
@Nonnull
public String generateKey() {
return "*" + this.getKey() + "_" + this.peekKey('_');
}
public K getKey() {
return (K)this.getData().getKey();
}
@Nullable
public Path getAssetPath() {
return this.assetPath;
}
public AssetExtraInfo.Data getData() {
return this.data;
}
@Override
public void appendDetailsTo(@Nonnull StringBuilder sb) {
sb.append("Id: ").append(this.getKey()).append("\n");
if (this.assetPath != null) {
sb.append("Path: ").append(this.assetPath).append("\n");
}
}
public AssetValidationResults getValidationResults() {
return (AssetValidationResults)super.getValidationResults();
}
@Nonnull
@Override
public String toString() {
return "AssetExtraInfo{assetPath=" + this.assetPath + ", data=" + this.data + "} " + super.toString();
}
public static class Data {
public static final char TAG_VALUE_SEPARATOR = '=';
private Map<Class<? extends JsonAssetWithMap>, List<Object>> containedAssets;
private Map<Class<? extends JsonAssetWithMap>, List<RawAsset<Object>>> containedRawAssets;
@Nullable
private AssetExtraInfo.Data containerData;
private Class<? extends JsonAsset<?>> assetClass;
private Object key;
private Object parentKey;
private final Map<String, String[]> rawTags = new HashMap<>(0);
private final Int2ObjectMap<IntSet> tagStorage = new Int2ObjectOpenHashMap<>(0);
private final Int2ObjectMap<IntSet> unmodifiableTagStorage = new Int2ObjectOpenHashMap<>(0);
private final IntSet expandedTagStorage = new IntOpenHashSet(0);
private final IntSet unmodifiableExpandedTagStorage = IntSets.unmodifiable(this.expandedTagStorage);
public <K> Data(Class<? extends JsonAsset<K>> assetClass, K key, K parentKey) {
this.assetClass = assetClass;
this.key = key;
this.parentKey = parentKey;
}
public <K> Data(@Nullable AssetExtraInfo.Data containerData, Class<? extends JsonAsset<K>> aClass, K key, K parentKey, boolean inheritContainerTags) {
this(aClass, key, parentKey);
this.containerData = containerData;
if (containerData != null && inheritContainerTags) {
this.putTags(containerData.rawTags);
}
}
public Class<? extends JsonAsset<?>> getAssetClass() {
return this.assetClass;
}
public Object getKey() {
return this.key;
}
public Object getParentKey() {
return this.parentKey;
}
@Nonnull
public AssetExtraInfo.Data getRootContainerData() {
AssetExtraInfo.Data temp = this;
while (temp.containerData != null) {
temp = temp.containerData;
}
return temp;
}
@Nullable
public AssetExtraInfo.Data getContainerData() {
return this.containerData;
}
@Nullable
public <K> K getContainerKey(Class<? extends JsonAsset<K>> aClass) {
if (this.containerData == null) {
return null;
} else {
return (K)(this.containerData.assetClass.equals(aClass) ? this.containerData.key : this.containerData.getContainerKey(aClass));
}
}
public void putTags(@Nonnull Map<String, String[]> tags) {
for (Entry<String, String[]> entry : tags.entrySet()) {
String tag = entry.getKey().intern();
this.rawTags.merge(tag, entry.getValue(), ArrayUtil::combine);
IntSet tagIndexes = this.ensureTag(tag);
for (String value : entry.getValue()) {
tagIndexes.add(AssetRegistry.getOrCreateTagIndex(value));
this.ensureTag(value);
this.rawTags.putIfAbsent(value, ArrayUtil.EMPTY_STRING_ARRAY);
String valueTag = (tag + "=" + value).intern();
this.rawTags.putIfAbsent(valueTag, ArrayUtil.EMPTY_STRING_ARRAY);
this.ensureTag(valueTag);
}
}
}
@Nonnull
public Map<String, String[]> getRawTags() {
return Collections.unmodifiableMap(this.rawTags);
}
@Nonnull
public Int2ObjectMap<IntSet> getTags() {
return Int2ObjectMaps.unmodifiable(this.unmodifiableTagStorage);
}
@Nonnull
public IntSet getExpandedTagIndexes() {
return this.unmodifiableExpandedTagStorage;
}
public IntSet getTag(int tagIndex) {
return this.unmodifiableTagStorage.getOrDefault(tagIndex, IntSets.EMPTY_SET);
}
public <K, T extends JsonAssetWithMap<K, M>, M extends AssetMap<K, T>> void addContainedAsset(Class<T> assetClass, T asset) {
if (this.containedAssets == null) {
this.containedAssets = new HashMap<>();
}
this.containedAssets.computeIfAbsent(assetClass, k -> new ArrayList<>()).add(asset);
}
public <K, T extends JsonAssetWithMap<K, M>, M extends AssetMap<K, T>> void addContainedAsset(Class<T> assetClass, RawAsset<K> rawAsset) {
if (this.containedRawAssets == null) {
this.containedRawAssets = new HashMap<>();
}
this.containedRawAssets.computeIfAbsent(assetClass, k -> new ArrayList<>()).add(rawAsset);
}
public <K> void fetchContainedAssets(K key, @Nonnull Map<Class<? extends JsonAssetWithMap>, Map<K, List<Object>>> containedAssets) {
if (this.containedAssets != null) {
for (Entry<Class<? extends JsonAssetWithMap>, List<Object>> entry : this.containedAssets.entrySet()) {
containedAssets.computeIfAbsent(entry.getKey(), k -> new HashMap<>()).computeIfAbsent(key, k -> new ArrayList<>(3)).addAll(entry.getValue());
}
}
}
public <K> void fetchContainedRawAssets(K key, @Nonnull Map<Class<? extends JsonAssetWithMap>, Map<K, List<RawAsset<Object>>>> containedAssets) {
if (this.containedRawAssets != null) {
for (Entry<Class<? extends JsonAssetWithMap>, List<RawAsset<Object>>> entry : this.containedRawAssets.entrySet()) {
containedAssets.computeIfAbsent(entry.getKey(), k -> new HashMap<>()).computeIfAbsent(key, k -> new ArrayList<>(3)).addAll(entry.getValue());
}
}
}
public <K, T extends JsonAssetWithMap<K, M>, M extends AssetMap<K, T>> boolean containsAsset(Class<T> tClass, K key) {
if (this.containedAssets != null) {
List<T> assets = (List<T>)this.containedAssets.get(tClass);
if (assets != null) {
Function<T, K> keyFunction = AssetRegistry.<K, T, M>getAssetStore(tClass).getKeyFunction();
for (T asset : assets) {
if (key.equals(keyFunction.apply(asset))) {
return true;
}
}
}
}
if (this.containedRawAssets != null) {
List<RawAsset<T>> rawAssets = (List<RawAsset<T>>)this.containedRawAssets.get(tClass);
if (rawAssets != null) {
for (RawAsset<T> rawAsset : rawAssets) {
if (key.equals(rawAsset.getKey())) {
return true;
}
}
}
}
return false;
}
public void loadContainedAssets(boolean reloading) {
if (this.containedAssets != null) {
for (Entry<Class<? extends JsonAssetWithMap>, List<Object>> entry : this.containedAssets.entrySet()) {
AssetRegistry.getAssetStore(entry.getKey()).loadAssets("Hytale:Hytale", entry.getValue(), AssetUpdateQuery.DEFAULT, reloading);
}
}
if (this.containedRawAssets != null) {
for (Entry<Class<? extends JsonAssetWithMap>, List<RawAsset<Object>>> entry : this.containedRawAssets.entrySet()) {
AssetRegistry.getAssetStore(entry.getKey()).loadBuffersWithKeys("Hytale:Hytale", entry.getValue(), AssetUpdateQuery.DEFAULT, reloading);
}
}
}
@Nonnull
private IntSet ensureTag(@Nonnull String tag) {
int idx = AssetRegistry.getOrCreateTagIndex(tag);
this.expandedTagStorage.add(idx);
return this.tagStorage.computeIfAbsent(idx, k -> {
IntSet set = new IntOpenHashSet(3);
this.unmodifiableTagStorage.put(k, IntSets.unmodifiable(set));
return set;
});
}
@Nonnull
@Override
public String toString() {
return "Data{containedAssets="
+ this.containedRawAssets
+ ", rawTags="
+ this.rawTags
+ ", parent="
+ this.containerData
+ ", assetClass="
+ this.assetClass
+ ", key="
+ this.key
+ "}";
}
}
}

View File

@@ -0,0 +1,4 @@
package com.hypixel.hytale.assetstore;
public interface AssetHolder<K> {
}

View File

@@ -0,0 +1,30 @@
package com.hypixel.hytale.assetstore;
import com.hypixel.hytale.codec.schema.SchemaContext;
import com.hypixel.hytale.codec.schema.config.Schema;
import com.hypixel.hytale.codec.validation.ValidationResults;
import com.hypixel.hytale.codec.validation.Validator;
import java.util.function.Supplier;
import javax.annotation.Nonnull;
public class AssetKeyValidator<K> implements Validator<K> {
private final Supplier<AssetStore<K, ?, ?>> store;
public AssetKeyValidator(Supplier<AssetStore<K, ?, ?>> store) {
this.store = store;
}
public AssetStore<K, ?, ?> getStore() {
return this.store.get();
}
@Override
public void accept(K k, @Nonnull ValidationResults results) {
this.store.get().validate(k, results, results.getExtraInfo());
}
@Override
public void updateSchema(SchemaContext context, @Nonnull Schema target) {
target.setHytaleAssetRef(this.store.get().getAssetClass().getSimpleName());
}
}

View File

@@ -0,0 +1,58 @@
package com.hypixel.hytale.assetstore;
import com.hypixel.hytale.assetstore.map.JsonAssetWithMap;
import java.nio.file.Path;
import java.util.Map;
import java.util.Set;
public class AssetLoadResult<K, T> {
private final Map<K, T> loadedAssets;
private final Map<K, Path> loadedKeyToPathMap;
private final Set<K> failedToLoadKeys;
private final Set<Path> failedToLoadPaths;
private final Map<Class<? extends JsonAssetWithMap>, AssetLoadResult> childAssetResults;
public AssetLoadResult(
Map<K, T> loadedAssets,
Map<K, Path> loadedKeyToPathMap,
Set<K> failedToLoadKeys,
Set<Path> failedToLoadPaths,
Map<Class<? extends JsonAssetWithMap>, AssetLoadResult> childAssetResults
) {
this.loadedAssets = loadedAssets;
this.loadedKeyToPathMap = loadedKeyToPathMap;
this.failedToLoadKeys = failedToLoadKeys;
this.failedToLoadPaths = failedToLoadPaths;
this.childAssetResults = childAssetResults;
}
public Map<K, T> getLoadedAssets() {
return this.loadedAssets;
}
public Map<K, Path> getLoadedKeyToPathMap() {
return this.loadedKeyToPathMap;
}
public Set<K> getFailedToLoadKeys() {
return this.failedToLoadKeys;
}
public Set<Path> getFailedToLoadPaths() {
return this.failedToLoadPaths;
}
public boolean hasFailed() {
if (this.failedToLoadKeys.isEmpty() && this.failedToLoadPaths.isEmpty()) {
for (AssetLoadResult result : this.childAssetResults.values()) {
if (result.hasFailed()) {
return true;
}
}
return false;
} else {
return true;
}
}
}

View File

@@ -0,0 +1,58 @@
package com.hypixel.hytale.assetstore;
import com.hypixel.hytale.assetstore.codec.AssetCodec;
import it.unimi.dsi.fastutil.ints.IntSet;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public abstract class AssetMap<K, T extends JsonAsset<K>> {
public AssetMap() {
}
@Nullable
public abstract T getAsset(K var1);
@Nullable
public abstract T getAsset(@Nonnull String var1, K var2);
@Nullable
public abstract Path getPath(K var1);
@Nullable
public abstract String getAssetPack(K var1);
public abstract Set<K> getKeys(Path var1);
public abstract Set<K> getChildren(K var1);
public abstract int getAssetCount();
public abstract Map<K, T> getAssetMap();
public abstract Map<K, Path> getPathMap(@Nonnull String var1);
public abstract Set<K> getKeysForTag(int var1);
public abstract IntSet getTagIndexes();
public abstract int getTagCount();
protected abstract void clear();
protected abstract void putAll(@Nonnull String var1, AssetCodec<K, T> var2, Map<K, T> var3, Map<K, Path> var4, Map<K, Set<K>> var5);
protected abstract Set<K> remove(Set<K> var1);
protected abstract Set<K> remove(@Nonnull String var1, Set<K> var2, List<Entry<String, Object>> var3);
public boolean requireReplaceOnRemove() {
return false;
}
public abstract Set<K> getKeysForPack(@Nonnull String var1);
}

View File

@@ -0,0 +1,79 @@
package com.hypixel.hytale.assetstore;
import com.hypixel.hytale.common.plugin.PluginManifest;
import java.nio.file.FileSystem;
import java.nio.file.Path;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class AssetPack {
@Nonnull
private final String name;
@Nonnull
private final Path root;
@Nullable
private final FileSystem fileSystem;
private final boolean isImmutable;
private final PluginManifest manifest;
private final Path packLocation;
public AssetPack(Path packLocation, @Nonnull String name, @Nonnull Path root, @Nullable FileSystem fileSystem, boolean isImmutable, PluginManifest manifest) {
this.name = name;
this.root = root;
this.fileSystem = fileSystem;
this.isImmutable = isImmutable;
this.manifest = manifest;
this.packLocation = packLocation;
}
@Nonnull
public String getName() {
return this.name;
}
@Nonnull
public Path getRoot() {
return this.root;
}
@Nullable
public FileSystem getFileSystem() {
return this.fileSystem;
}
public PluginManifest getManifest() {
return this.manifest;
}
public boolean isImmutable() {
return this.isImmutable;
}
public Path getPackLocation() {
return this.packLocation;
}
@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
} else if (o != null && this.getClass() == o.getClass()) {
AssetPack assetPack = (AssetPack)o;
return !this.name.equals(assetPack.name) ? false : this.root.equals(assetPack.root);
} else {
return false;
}
}
@Override
public int hashCode() {
int result = this.name.hashCode();
return 31 * result + this.root.hashCode();
}
@Nonnull
@Override
public String toString() {
return "AssetPack{name='" + this.name + "', root=" + this.root + ", fileSystem=" + this.fileSystem + "}";
}
}

View File

@@ -0,0 +1,39 @@
package com.hypixel.hytale.assetstore;
import com.hypixel.hytale.assetstore.map.JsonAssetWithMap;
import java.util.Collections;
import java.util.Set;
import javax.annotation.Nonnull;
public class AssetReferences<CK, C extends JsonAssetWithMap<CK, ?>> {
private final Class<C> parentAssetClass;
private final Set<CK> parentKeys;
public AssetReferences(Class<C> parentAssetClass, Set<CK> parentKeys) {
this.parentAssetClass = parentAssetClass;
this.parentKeys = parentKeys;
}
public Class<C> getParentAssetClass() {
return this.parentAssetClass;
}
public Set<CK> getParentKeys() {
return this.parentKeys;
}
public <T extends JsonAssetWithMap<K, ?>, K> void addChildAssetReferences(Class<T> tClass, K childKey) {
Class parentAssetClass = this.parentAssetClass;
AssetStore<CK, C, ?> assetStore = AssetRegistry.getAssetStore(parentAssetClass);
for (CK parentKey : this.parentKeys) {
assetStore.addChildAssetReferences(parentKey, tClass, Collections.singleton(childKey));
}
}
@Nonnull
@Override
public String toString() {
return "AssetReferences{parentAssetClass=" + this.parentAssetClass + ", parentKeys=" + this.parentKeys + "}";
}
}

View File

@@ -0,0 +1,145 @@
package com.hypixel.hytale.assetstore;
import com.hypixel.hytale.assetstore.event.RegisterAssetStoreEvent;
import com.hypixel.hytale.assetstore.event.RemoveAssetStoreEvent;
import com.hypixel.hytale.assetstore.map.JsonAssetWithMap;
import com.hypixel.hytale.event.IEventDispatcher;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.StampedLock;
import javax.annotation.Nonnull;
public class AssetRegistry {
public static final ReadWriteLock ASSET_LOCK = new ReentrantReadWriteLock();
public static boolean HAS_INIT = false;
public static final int TAG_NOT_FOUND = Integer.MIN_VALUE;
private static final Map<Class<? extends JsonAssetWithMap>, AssetStore<?, ?, ?>> storeMap = new HashMap<>();
private static final Map<Class<? extends JsonAssetWithMap>, AssetStore<?, ?, ?>> storeMapUnmodifiable = Collections.unmodifiableMap(storeMap);
private static final AtomicInteger NEXT_TAG_INDEX = new AtomicInteger();
private static final StampedLock TAG_LOCK = new StampedLock();
private static final Object2IntMap<String> TAG_MAP = new Object2IntOpenHashMap<>();
private static final Object2IntMap<String> CLIENT_TAG_MAP = new Object2IntOpenHashMap<>();
public AssetRegistry() {
}
@Nonnull
public static Map<Class<? extends JsonAssetWithMap>, AssetStore<?, ?, ?>> getStoreMap() {
return storeMapUnmodifiable;
}
public static <K, T extends JsonAssetWithMap<K, M>, M extends AssetMap<K, T>> AssetStore<K, T, M> getAssetStore(Class<T> tClass) {
return (AssetStore<K, T, M>)storeMap.get(tClass);
}
@Nonnull
public static <K, T extends JsonAssetWithMap<K, M>, M extends AssetMap<K, T>, S extends AssetStore<K, T, M>> S register(@Nonnull S assetStore) {
ASSET_LOCK.writeLock().lock();
try {
if (storeMap.putIfAbsent(assetStore.getAssetClass(), assetStore) != null) {
throw new IllegalArgumentException("Asset Store already exists for " + assetStore.getAssetClass());
}
} finally {
ASSET_LOCK.writeLock().unlock();
}
IEventDispatcher<RegisterAssetStoreEvent, RegisterAssetStoreEvent> dispatch = assetStore.getEventBus().dispatchFor(RegisterAssetStoreEvent.class);
if (dispatch.hasListener()) {
dispatch.dispatch(new RegisterAssetStoreEvent(assetStore));
}
return assetStore;
}
public static <K, T extends JsonAssetWithMap<K, M>, M extends AssetMap<K, T>, S extends AssetStore<K, T, M>> void unregister(@Nonnull S assetStore) {
ASSET_LOCK.writeLock().lock();
try {
storeMap.remove(assetStore.getAssetClass());
} finally {
ASSET_LOCK.writeLock().unlock();
}
IEventDispatcher<RemoveAssetStoreEvent, RemoveAssetStoreEvent> dispatch = assetStore.getEventBus().dispatchFor(RemoveAssetStoreEvent.class);
if (dispatch.hasListener()) {
dispatch.dispatch(new RemoveAssetStoreEvent(assetStore));
}
}
public static int getTagIndex(@Nonnull String tag) {
if (tag == null) {
throw new IllegalArgumentException("tag can't be null!");
} else {
long stamp = TAG_LOCK.readLock();
int var3;
try {
var3 = TAG_MAP.getInt(tag);
} finally {
TAG_LOCK.unlockRead(stamp);
}
return var3;
}
}
public static int getOrCreateTagIndex(@Nonnull String tag) {
if (tag == null) {
throw new IllegalArgumentException("tag can't be null!");
} else {
long stamp = TAG_LOCK.writeLock();
int var3;
try {
var3 = TAG_MAP.computeIfAbsent(tag.intern(), k -> NEXT_TAG_INDEX.getAndIncrement());
} finally {
TAG_LOCK.unlockWrite(stamp);
}
return var3;
}
}
public static boolean registerClientTag(@Nonnull String tag) {
if (tag == null) {
throw new IllegalArgumentException("tag can't be null!");
} else {
long stamp = TAG_LOCK.writeLock();
boolean var3;
try {
var3 = CLIENT_TAG_MAP.put(tag, TAG_MAP.computeIfAbsent(tag, k -> NEXT_TAG_INDEX.getAndIncrement())) == Integer.MIN_VALUE;
} finally {
TAG_LOCK.unlockWrite(stamp);
}
return var3;
}
}
@Nonnull
public static Object2IntMap<String> getClientTags() {
long stamp = TAG_LOCK.readLock();
Object2IntOpenHashMap var2;
try {
var2 = new Object2IntOpenHashMap<>(CLIENT_TAG_MAP);
} finally {
TAG_LOCK.unlockRead(stamp);
}
return var2;
}
static {
TAG_MAP.defaultReturnValue(Integer.MIN_VALUE);
CLIENT_TAG_MAP.defaultReturnValue(Integer.MIN_VALUE);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,178 @@
package com.hypixel.hytale.assetstore;
import javax.annotation.Nonnull;
public class AssetUpdateQuery {
public static final AssetUpdateQuery DEFAULT = new AssetUpdateQuery(AssetUpdateQuery.RebuildCache.DEFAULT);
public static final AssetUpdateQuery DEFAULT_NO_REBUILD = new AssetUpdateQuery(AssetUpdateQuery.RebuildCache.NO_REBUILD);
private final boolean disableAssetCompare;
private final AssetUpdateQuery.RebuildCache rebuildCache;
public AssetUpdateQuery(boolean disableAssetCompare, AssetUpdateQuery.RebuildCache rebuildCache) {
this.disableAssetCompare = disableAssetCompare;
this.rebuildCache = rebuildCache;
}
public AssetUpdateQuery(AssetUpdateQuery.RebuildCache rebuildCache) {
this(AssetStore.DISABLE_ASSET_COMPARE, rebuildCache);
}
public boolean isDisableAssetCompare() {
return this.disableAssetCompare;
}
@Nonnull
public AssetUpdateQuery.RebuildCache getRebuildCache() {
return this.rebuildCache;
}
@Nonnull
@Override
public String toString() {
return "AssetUpdateQuery{rebuildCache=" + this.rebuildCache + "}";
}
public static class RebuildCache {
public static final AssetUpdateQuery.RebuildCache DEFAULT = new AssetUpdateQuery.RebuildCache(true, true, true, true, true, true);
public static final AssetUpdateQuery.RebuildCache NO_REBUILD = new AssetUpdateQuery.RebuildCache(false, false, false, false, false, false);
private final boolean blockTextures;
private final boolean models;
private final boolean modelTextures;
private final boolean mapGeometry;
private final boolean itemIcons;
private final boolean commonAssetsRebuild;
public RebuildCache(boolean blockTextures, boolean models, boolean modelTextures, boolean mapGeometry, boolean itemIcons, boolean commonAssetsRebuild) {
this.blockTextures = blockTextures;
this.models = models;
this.modelTextures = modelTextures;
this.mapGeometry = mapGeometry;
this.itemIcons = itemIcons;
this.commonAssetsRebuild = commonAssetsRebuild;
}
public boolean isBlockTextures() {
return this.blockTextures;
}
public boolean isModels() {
return this.models;
}
public boolean isModelTextures() {
return this.modelTextures;
}
public boolean isMapGeometry() {
return this.mapGeometry;
}
public boolean isItemIcons() {
return this.itemIcons;
}
public boolean isCommonAssetsRebuild() {
return this.commonAssetsRebuild;
}
@Nonnull
public AssetUpdateQuery.RebuildCacheBuilder toBuilder() {
return new AssetUpdateQuery.RebuildCacheBuilder(
this.blockTextures, this.models, this.modelTextures, this.mapGeometry, this.itemIcons, this.commonAssetsRebuild
);
}
@Nonnull
public static AssetUpdateQuery.RebuildCacheBuilder builder() {
return new AssetUpdateQuery.RebuildCacheBuilder();
}
@Nonnull
@Override
public String toString() {
return "RebuildCache{blockTextures="
+ this.blockTextures
+ ", models="
+ this.models
+ ", modelTextures="
+ this.modelTextures
+ ", mapGeometry="
+ this.mapGeometry
+ ", icons="
+ this.itemIcons
+ ", commonAssetsRebuild="
+ this.commonAssetsRebuild
+ "}";
}
}
public static class RebuildCacheBuilder {
private boolean blockTextures;
private boolean models;
private boolean modelTextures;
private boolean mapGeometry;
private boolean itemIcons;
private boolean commonAssetsRebuild;
RebuildCacheBuilder() {
}
RebuildCacheBuilder(boolean blockTextures, boolean models, boolean modelTextures, boolean mapGeometry, boolean itemIcons, boolean commonAssetsRebuild) {
this.blockTextures = blockTextures;
this.models = models;
this.modelTextures = modelTextures;
this.mapGeometry = mapGeometry;
this.itemIcons = itemIcons;
this.commonAssetsRebuild = commonAssetsRebuild;
}
public void setBlockTextures(boolean blockTextures) {
this.blockTextures = blockTextures;
}
public void setModels(boolean models) {
this.models = models;
}
public void setModelTextures(boolean modelTextures) {
this.modelTextures = modelTextures;
}
public void setMapGeometry(boolean mapGeometry) {
this.mapGeometry = mapGeometry;
}
public void setItemIcons(boolean itemIcons) {
this.itemIcons = itemIcons;
}
public void setCommonAssetsRebuild(boolean commonAssetsRebuild) {
this.commonAssetsRebuild = commonAssetsRebuild;
}
@Nonnull
public AssetUpdateQuery.RebuildCache build() {
return new AssetUpdateQuery.RebuildCache(
this.blockTextures, this.models, this.modelTextures, this.mapGeometry, this.itemIcons, this.commonAssetsRebuild
);
}
@Nonnull
@Override
public String toString() {
return "RebuildCache{blockTextures="
+ this.blockTextures
+ ", models="
+ this.models
+ ", modelTextures="
+ this.modelTextures
+ ", mapGeometry="
+ this.mapGeometry
+ ", icons="
+ this.itemIcons
+ ", commonAssetsRebuild="
+ this.commonAssetsRebuild
+ "}";
}
}
}

View File

@@ -0,0 +1,77 @@
package com.hypixel.hytale.assetstore;
import com.hypixel.hytale.codec.ExtraInfo;
import com.hypixel.hytale.codec.validation.ValidationResults;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.logger.backend.HytaleLoggerBackend;
import com.hypixel.hytale.logger.util.GithubMessageUtil;
import java.nio.file.Path;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.checkerframework.checker.nullness.compatqual.NonNullDecl;
public class AssetValidationResults extends ValidationResults {
private Set<Class<? extends JsonAsset>> disabledMissingAssetClasses;
public AssetValidationResults(ExtraInfo extraInfo) {
super(extraInfo);
}
public void handleMissingAsset(String field, @Nonnull Class<? extends JsonAsset> assetType, Object assetId) {
if (this.disabledMissingAssetClasses == null || !this.disabledMissingAssetClasses.contains(assetType)) {
throw new MissingAssetException(field, assetType, assetId);
}
}
public void handleMissingAsset(String field, @Nonnull Class<? extends JsonAsset> assetType, Object assetId, String extra) {
if (this.disabledMissingAssetClasses == null || !this.disabledMissingAssetClasses.contains(assetType)) {
throw new MissingAssetException(field, assetType, assetId, extra);
}
}
public void disableMissingAssetFor(Class<? extends JsonAsset> assetType) {
if (this.disabledMissingAssetClasses == null) {
this.disabledMissingAssetClasses = new HashSet<>();
}
this.disabledMissingAssetClasses.add(assetType);
}
@Override
public void logOrThrowValidatorExceptions(@NonNullDecl HytaleLogger logger, @NonNullDecl String msg) {
this.logOrThrowValidatorExceptions(logger, msg, null, 0);
}
public void logOrThrowValidatorExceptions(@NonNullDecl HytaleLogger logger, @NonNullDecl String msg, @Nullable Path path, int lineOffset) {
if (GithubMessageUtil.isGithub() && this.validatorExceptions != null && !this.validatorExceptions.isEmpty()) {
for (ValidationResults.ValidatorResultsHolder holder : this.validatorExceptions) {
String file = "unknown";
if (path == null && this.extraInfo instanceof AssetExtraInfo<?> assetExtraInfo) {
path = assetExtraInfo.getAssetPath();
}
if (path != null) {
file = path.toString();
}
for (ValidationResults.ValidationResult result : holder.results()) {
HytaleLoggerBackend.rawLog(
switch (result.result()) {
case SUCCESS -> "";
case WARNING -> holder.line() == -1
? GithubMessageUtil.messageWarning(file, result.reason())
: GithubMessageUtil.messageWarning(file, holder.line() + lineOffset, holder.column(), result.reason());
case FAIL -> holder.line() == -1
? GithubMessageUtil.messageError(file, result.reason())
: GithubMessageUtil.messageError(file, holder.line() + lineOffset, holder.column(), result.reason());
}
);
}
}
}
super.logOrThrowValidatorExceptions(logger, msg);
}
}

View File

@@ -0,0 +1,50 @@
package com.hypixel.hytale.assetstore;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class DecodedAsset<K, T extends JsonAsset<K>> implements AssetHolder<K> {
private final K key;
private final T asset;
public DecodedAsset(K key, T asset) {
this.key = key;
this.asset = asset;
}
public K getKey() {
return this.key;
}
public T getAsset() {
return this.asset;
}
@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
} else if (o != null && this.getClass() == o.getClass()) {
DecodedAsset<?, ?> that = (DecodedAsset<?, ?>)o;
if (this.key != null ? this.key.equals(that.key) : that.key == null) {
return this.asset != null ? this.asset.equals(that.asset) : that.asset == null;
} else {
return false;
}
} else {
return false;
}
}
@Override
public int hashCode() {
int result = this.key != null ? this.key.hashCode() : 0;
return 31 * result + (this.asset != null ? this.asset.hashCode() : 0);
}
@Nonnull
@Override
public String toString() {
return "DecodedAsset{key=" + this.key + ", asset=" + this.asset + "}";
}
}

View File

@@ -0,0 +1,5 @@
package com.hypixel.hytale.assetstore;
public interface JsonAsset<K> {
K getId();
}

View File

@@ -0,0 +1,55 @@
package com.hypixel.hytale.assetstore;
import com.hypixel.hytale.codec.ExtraInfo;
import com.hypixel.hytale.codec.validation.ValidationResults;
import javax.annotation.Nonnull;
public class MissingAssetException extends RuntimeException {
private String field;
private Class<? extends JsonAsset> assetType;
private Object assetId;
public MissingAssetException(String field, @Nonnull Class<? extends JsonAsset> assetType, Object assetId) {
super("Missing asset '" + assetId + "' of type " + assetType.getSimpleName() + " for field '" + field + "'!");
this.field = field;
this.assetType = assetType;
this.assetId = assetId;
}
public MissingAssetException(String field, @Nonnull Class<? extends JsonAsset> assetType, Object assetId, String extra) {
super("Missing asset '" + assetId + "' of type " + assetType.getSimpleName() + " for field '" + field + "'! " + extra);
this.field = field;
this.assetType = assetType;
this.assetId = assetId;
}
public String getField() {
return this.field;
}
public Class<? extends JsonAsset> getAssetType() {
return this.assetType;
}
public Object getAssetId() {
return this.assetId;
}
public static void handle(@Nonnull ExtraInfo extraInfo, String field, @Nonnull Class<? extends JsonAsset> assetType, Object assetId) {
ValidationResults validationResults = extraInfo.getValidationResults();
if (validationResults instanceof AssetValidationResults) {
((AssetValidationResults)validationResults).handleMissingAsset(field, assetType, assetId);
} else {
throw new MissingAssetException(field, assetType, assetId);
}
}
public static void handle(@Nonnull ExtraInfo extraInfo, String field, @Nonnull Class<? extends JsonAsset> assetType, Object assetId, String extra) {
ValidationResults validationResults = extraInfo.getValidationResults();
if (validationResults instanceof AssetValidationResults) {
((AssetValidationResults)validationResults).handleMissingAsset(field, assetType, assetId, extra);
} else {
throw new MissingAssetException(field, assetType, assetId, extra);
}
}
}

View File

@@ -0,0 +1,153 @@
package com.hypixel.hytale.assetstore;
import com.hypixel.hytale.assetstore.codec.ContainedAssetCodec;
import com.hypixel.hytale.assetstore.map.JsonAssetWithMap;
import com.hypixel.hytale.codec.util.RawJsonReader;
import java.io.IOException;
import java.nio.file.Path;
import java.util.function.Supplier;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNullableByDefault;
@ParametersAreNullableByDefault
public class RawAsset<K> implements AssetHolder<K> {
private final Path parentPath;
@Nullable
private final K key;
private final int lineOffset;
private final boolean parentKeyResolved;
@Nullable
private final K parentKey;
@Nullable
private final Path path;
@Nullable
private final char[] buffer;
@Nullable
private final AssetExtraInfo.Data containerData;
@Nonnull
private final ContainedAssetCodec.Mode containedAssetMode;
public RawAsset(K key, Path path) {
this.key = key;
this.lineOffset = 0;
this.parentKeyResolved = false;
this.parentKey = null;
this.path = path;
this.parentPath = null;
this.buffer = null;
this.containerData = null;
this.containedAssetMode = ContainedAssetCodec.Mode.NONE;
}
public RawAsset(
Path parentPath,
K key,
K parentKey,
int lineOffset,
char[] buffer,
AssetExtraInfo.Data containerData,
@Nonnull ContainedAssetCodec.Mode containedAssetMode
) {
this.key = key;
this.lineOffset = lineOffset;
this.parentKeyResolved = true;
this.parentKey = parentKey;
this.path = null;
this.parentPath = parentPath;
this.buffer = buffer;
this.containerData = containerData;
this.containedAssetMode = containedAssetMode;
}
private RawAsset(
K key,
boolean parentKeyResolved,
K parentKey,
Path path,
char[] buffer,
AssetExtraInfo.Data containerData,
@Nonnull ContainedAssetCodec.Mode containedAssetMode
) {
this.key = key;
this.lineOffset = 0;
this.parentKeyResolved = parentKeyResolved;
this.parentKey = parentKey;
this.path = path;
this.parentPath = null;
this.buffer = buffer;
this.containerData = containerData;
this.containedAssetMode = containedAssetMode;
}
@Nullable
public K getKey() {
return this.key;
}
public boolean isParentKeyResolved() {
return this.parentKeyResolved;
}
@Nullable
public K getParentKey() {
return this.parentKey;
}
@Nullable
public Path getPath() {
return this.path;
}
public Path getParentPath() {
return this.parentPath;
}
public int getLineOffset() {
return this.lineOffset;
}
public char[] getBuffer() {
return this.buffer;
}
@Nonnull
public ContainedAssetCodec.Mode getContainedAssetMode() {
return this.containedAssetMode;
}
@Nonnull
public RawJsonReader toRawJsonReader(@Nonnull Supplier<char[]> bufferSupplier) throws IOException {
return this.path != null ? RawJsonReader.fromPath(this.path, bufferSupplier.get()) : RawJsonReader.fromBuffer(this.buffer);
}
@Nonnull
public AssetExtraInfo.Data makeData(Class<? extends JsonAssetWithMap<K, ?>> aClass, K key, K parentKey) {
boolean inheritTags = switch (this.containedAssetMode) {
case INHERIT_ID, INHERIT_ID_AND_PARENT, INJECT_PARENT -> true;
case NONE, GENERATE_ID -> false;
};
return new AssetExtraInfo.Data(this.containerData, aClass, key, parentKey, inheritTags);
}
@Nonnull
public RawAsset<K> withResolveKeys(K key, K parentKey) {
return new RawAsset<>(key, true, parentKey, this.path, this.buffer, this.containerData, this.containedAssetMode);
}
@Nonnull
@Override
public String toString() {
return "RawAsset{key="
+ this.key
+ ", parentKeyResolved="
+ this.parentKeyResolved
+ ", parentKey="
+ this.parentKey
+ ", path="
+ this.path
+ ", buffer.length="
+ (this.buffer != null ? this.buffer.length : -1)
+ "}";
}
}

View File

@@ -0,0 +1,225 @@
package com.hypixel.hytale.assetstore.codec;
import com.hypixel.hytale.assetstore.AssetExtraInfo;
import com.hypixel.hytale.assetstore.JsonAsset;
import com.hypixel.hytale.codec.Codec;
import com.hypixel.hytale.codec.KeyedCodec;
import com.hypixel.hytale.codec.builder.BuilderCodec;
import com.hypixel.hytale.codec.codecs.map.MapCodec;
import com.hypixel.hytale.codec.schema.SchemaContext;
import com.hypixel.hytale.codec.schema.config.ObjectSchema;
import com.hypixel.hytale.codec.schema.config.Schema;
import com.hypixel.hytale.codec.util.RawJsonReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class AssetBuilderCodec<K, T extends JsonAsset<K>> extends BuilderCodec<T> implements AssetCodec<K, T> {
public static final KeyedCodec<Map<String, String[]>> TAGS_CODEC = new KeyedCodec<>("Tags", new MapCodec<>(Codec.STRING_ARRAY, HashMap::new));
private static final String TAG_DOCUMENTATION = "Tags are a general way to describe an asset that can be interpreted by other systems in a way they see fit.\n\nFor example you could tag something with a **Material** tag with the values **Solid** and **Stone**, And another single tag **Ore**.\n\nTags will be expanded into a single list of tags automatically. Using the above example with **Material** and **Ore** the end result would be the following list of tags: **Ore**, **Material**, **Solid**, **Stone**, **Material=Solid** and **Material=Stone**.";
@Nonnull
protected final KeyedCodec<K> idCodec;
@Nonnull
protected final KeyedCodec<K> parentCodec;
protected final BiConsumer<T, K> idSetter;
protected final BiConsumer<T, AssetExtraInfo.Data> dataSetter;
@Nonnull
protected final Function<T, AssetExtraInfo.Data> dataGetter;
protected AssetBuilderCodec(@Nonnull AssetBuilderCodec.Builder<K, T> builder) {
super(builder);
this.idCodec = builder.idCodec;
this.parentCodec = new KeyedCodec<>("Parent", this.idCodec.getChildCodec());
this.idSetter = builder.idSetter;
this.dataSetter = builder.dataSetter;
this.dataGetter = builder.dataGetter;
}
@Nonnull
@Override
public KeyedCodec<K> getKeyCodec() {
return this.idCodec;
}
@Nonnull
@Override
public KeyedCodec<K> getParentCodec() {
return this.parentCodec;
}
@Override
public AssetExtraInfo.Data getData(T t) {
return this.dataGetter.apply(t);
}
@Override
public T decodeJsonAsset(@Nonnull RawJsonReader reader, @Nonnull AssetExtraInfo<K> extraInfo) throws IOException {
return this.decodeAndInheritJsonAsset(reader, null, extraInfo);
}
@Override
public T decodeAndInheritJsonAsset(@Nonnull RawJsonReader reader, @Nullable T parent, @Nonnull AssetExtraInfo<K> extraInfo) throws IOException {
T t = this.supplier.get();
this.dataSetter.accept(t, extraInfo.getData());
if (parent != null) {
this.inherit(t, parent, extraInfo);
}
this.decodeAndInheritJson0(reader, t, parent, extraInfo);
this.idSetter.accept(t, extraInfo.getKey());
this.afterDecodeAndValidate(t, extraInfo);
return t;
}
@Nonnull
@Override
public ObjectSchema toSchema(@Nonnull SchemaContext context) {
return this.toSchema(context, this.supplier.get());
}
@Nonnull
public ObjectSchema toSchema(@Nonnull SchemaContext context, @Nullable T def) {
ObjectSchema schema = super.toSchema(context, def);
KeyedCodec<K> parent = this.getParentCodec();
Schema parentSchema = parent.getChildCodec().toSchema(context);
parentSchema.setMarkdownDescription(
"When set this asset will inherit properties from the named asset.\n\nWhen inheriting from another **"
+ this.tClass.getSimpleName()
+ "** most properties will simply be copied from the parent asset to this asset. In the case where both child and parent provide a field the child field will simply replace the value provided by the parent, in the case of nested structures this will apply to the fields within the structure. In some cases the field may decide to act differently, for example: by merging the parent and child fields together."
);
Class<? super T> rootClass = this.tClass;
for (BuilderCodec<? super T> rootCodec = this; rootCodec.getParent() != null; rootClass = rootCodec.getInnerClass()) {
rootCodec = rootCodec.getParent();
}
parentSchema.setHytaleParent(new Schema.InheritSettings(rootClass.getSimpleName()));
LinkedHashMap<String, Schema> props = new LinkedHashMap<>();
props.put(parent.getKey(), parentSchema);
props.putAll(schema.getProperties());
schema.setProperties(props);
return schema;
}
@Nonnull
public static <K, T extends JsonAsset<K>> AssetBuilderCodec.Builder<K, T> builder(
Class<T> tClass,
Supplier<T> supplier,
Codec<K> idCodec,
BiConsumer<T, K> idSetter,
Function<T, K> idGetter,
BiConsumer<T, AssetExtraInfo.Data> dataSetter,
@Nonnull Function<T, AssetExtraInfo.Data> dataGetter
) {
return new AssetBuilderCodec.Builder<>(tClass, supplier, idCodec, idSetter, idGetter, dataSetter, dataGetter);
}
@Nonnull
public static <K, T extends JsonAsset<K>> AssetBuilderCodec.Builder<K, T> builder(
Class<T> tClass,
Supplier<T> supplier,
BuilderCodec<? super T> parentCodec,
Codec<K> idCodec,
BiConsumer<T, K> idSetter,
Function<T, K> idGetter,
BiConsumer<T, AssetExtraInfo.Data> dataSetter,
@Nonnull Function<T, AssetExtraInfo.Data> dataGetter
) {
return new AssetBuilderCodec.Builder<>(tClass, supplier, parentCodec, idCodec, idSetter, idGetter, dataSetter, dataGetter);
}
@Nonnull
public static <K, T extends JsonAsset<K>> AssetBuilderCodec<K, T> wrap(
@Nonnull BuilderCodec<T> codec,
Codec<K> idCodec,
BiConsumer<T, K> idSetter,
Function<T, K> idGetter,
BiConsumer<T, AssetExtraInfo.Data> dataSetter,
@Nonnull Function<T, AssetExtraInfo.Data> dataGetter
) {
return builder(codec.getInnerClass(), codec.getSupplier(), codec, idCodec, idSetter, idGetter, dataSetter, dataGetter)
.documentation(codec.getDocumentation())
.build();
}
public static class Builder<K, T extends JsonAsset<K>> extends BuilderCodec.BuilderBase<T, AssetBuilderCodec.Builder<K, T>> {
@Nonnull
protected final KeyedCodec<K> idCodec;
protected final BiConsumer<T, K> idSetter;
protected final BiConsumer<T, AssetExtraInfo.Data> dataSetter;
@Nonnull
protected final Function<T, AssetExtraInfo.Data> dataGetter;
public Builder(
Class<T> tClass,
Supplier<T> supplier,
Codec<K> idCodec,
BiConsumer<T, K> idSetter,
Function<T, K> idGetter,
BiConsumer<T, AssetExtraInfo.Data> dataSetter,
@Nonnull Function<T, AssetExtraInfo.Data> dataGetter
) {
super(tClass, supplier);
this.idCodec = new KeyedCodec<>("Id", idCodec);
this.idSetter = idSetter;
this.dataSetter = dataSetter;
this.dataGetter = dataGetter;
this.<Map<String, String[]>>appendInherited(AssetBuilderCodec.TAGS_CODEC, (t, tags) -> dataGetter.apply(t).putTags(tags), t -> {
AssetExtraInfo.Data data = dataGetter.apply(t);
return data != null ? data.getRawTags() : null;
}, (t, parent) -> {
AssetExtraInfo.Data data = dataGetter.apply(t);
AssetExtraInfo.Data parentData = dataGetter.apply(parent);
if (data != null && parentData != null) {
data.putTags(parentData.getRawTags());
}
})
.documentation(
"Tags are a general way to describe an asset that can be interpreted by other systems in a way they see fit.\n\nFor example you could tag something with a **Material** tag with the values **Solid** and **Stone**, And another single tag **Ore**.\n\nTags will be expanded into a single list of tags automatically. Using the above example with **Material** and **Ore** the end result would be the following list of tags: **Ore**, **Material**, **Solid**, **Stone**, **Material=Solid** and **Material=Stone**."
)
.add();
}
public Builder(
Class<T> tClass,
Supplier<T> supplier,
BuilderCodec<? super T> parentCodec,
Codec<K> idCodec,
BiConsumer<T, K> idSetter,
Function<T, K> idGetter,
BiConsumer<T, AssetExtraInfo.Data> dataSetter,
@Nonnull Function<T, AssetExtraInfo.Data> dataGetter
) {
super(tClass, supplier, parentCodec);
this.idCodec = new KeyedCodec<>("Id", idCodec);
this.idSetter = idSetter;
this.dataSetter = dataSetter;
this.dataGetter = dataGetter;
this.<Map<String, String[]>>appendInherited(AssetBuilderCodec.TAGS_CODEC, (t, tags) -> dataGetter.apply(t).putTags(tags), t -> {
AssetExtraInfo.Data data = dataGetter.apply(t);
return data != null ? data.getRawTags() : null;
}, (t, parent) -> {
AssetExtraInfo.Data data = dataGetter.apply(t);
AssetExtraInfo.Data parentData = dataGetter.apply(parent);
if (data != null && parentData != null) {
data.putTags(parentData.getRawTags());
}
})
.documentation(
"Tags are a general way to describe an asset that can be interpreted by other systems in a way they see fit.\n\nFor example you could tag something with a **Material** tag with the values **Solid** and **Stone**, And another single tag **Ore**.\n\nTags will be expanded into a single list of tags automatically. Using the above example with **Material** and **Ore** the end result would be the following list of tags: **Ore**, **Material**, **Solid**, **Stone**, **Material=Solid** and **Material=Stone**."
)
.add();
}
@Nonnull
public AssetBuilderCodec<K, T> build() {
return new AssetBuilderCodec<>(this);
}
}
}

View File

@@ -0,0 +1,23 @@
package com.hypixel.hytale.assetstore.codec;
import com.hypixel.hytale.assetstore.AssetExtraInfo;
import com.hypixel.hytale.assetstore.JsonAsset;
import com.hypixel.hytale.codec.InheritCodec;
import com.hypixel.hytale.codec.KeyedCodec;
import com.hypixel.hytale.codec.util.RawJsonReader;
import com.hypixel.hytale.codec.validation.ValidatableCodec;
import java.io.IOException;
import javax.annotation.Nullable;
public interface AssetCodec<K, T extends JsonAsset<K>> extends InheritCodec<T>, ValidatableCodec<T> {
KeyedCodec<K> getKeyCodec();
KeyedCodec<K> getParentCodec();
@Nullable
AssetExtraInfo.Data getData(T var1);
T decodeJsonAsset(RawJsonReader var1, AssetExtraInfo<K> var2) throws IOException;
T decodeAndInheritJsonAsset(RawJsonReader var1, T var2, AssetExtraInfo<K> var3) throws IOException;
}

View File

@@ -0,0 +1,308 @@
package com.hypixel.hytale.assetstore.codec;
import com.hypixel.hytale.assetstore.AssetExtraInfo;
import com.hypixel.hytale.assetstore.JsonAsset;
import com.hypixel.hytale.codec.Codec;
import com.hypixel.hytale.codec.ExtraInfo;
import com.hypixel.hytale.codec.KeyedCodec;
import com.hypixel.hytale.codec.builder.BuilderCodec;
import com.hypixel.hytale.codec.exception.CodecException;
import com.hypixel.hytale.codec.lookup.ACodecMapCodec;
import com.hypixel.hytale.codec.lookup.Priority;
import com.hypixel.hytale.codec.lookup.StringCodecMapCodec;
import com.hypixel.hytale.codec.schema.SchemaContext;
import com.hypixel.hytale.codec.schema.config.ObjectSchema;
import com.hypixel.hytale.codec.schema.config.Schema;
import com.hypixel.hytale.codec.util.RawJsonReader;
import java.io.IOException;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.bson.BsonDocument;
import org.bson.BsonValue;
public class AssetCodecMapCodec<K, T extends JsonAsset<K>> extends StringCodecMapCodec<T, AssetBuilderCodec<K, T>> implements AssetCodec<K, T> {
@Nonnull
protected final KeyedCodec<K> idCodec;
@Nonnull
protected final KeyedCodec<K> parentCodec;
protected final BiConsumer<T, K> idSetter;
protected final Function<T, K> idGetter;
protected final BiConsumer<T, AssetExtraInfo.Data> dataSetter;
protected final Function<T, AssetExtraInfo.Data> dataGetter;
public AssetCodecMapCodec(
Codec<K> idCodec,
BiConsumer<T, K> idSetter,
Function<T, K> idGetter,
BiConsumer<T, AssetExtraInfo.Data> dataSetter,
Function<T, AssetExtraInfo.Data> dataGetter
) {
super("Type");
this.idCodec = new KeyedCodec<>("Id", idCodec);
this.parentCodec = new KeyedCodec<>("Parent", idCodec);
this.idSetter = idSetter;
this.idGetter = idGetter;
this.dataSetter = dataSetter;
this.dataGetter = dataGetter;
}
public AssetCodecMapCodec(
String key,
Codec<K> idCodec,
BiConsumer<T, K> idSetter,
Function<T, K> idGetter,
BiConsumer<T, AssetExtraInfo.Data> dataSetter,
Function<T, AssetExtraInfo.Data> dataGetter
) {
super(key);
this.idCodec = new KeyedCodec<>("Id", idCodec);
this.parentCodec = new KeyedCodec<>("Parent", idCodec);
this.idSetter = idSetter;
this.idGetter = idGetter;
this.dataSetter = dataSetter;
this.dataGetter = dataGetter;
}
public AssetCodecMapCodec(
Codec<K> idCodec,
BiConsumer<T, K> idSetter,
Function<T, K> idGetter,
BiConsumer<T, AssetExtraInfo.Data> dataSetter,
Function<T, AssetExtraInfo.Data> dataGetter,
boolean allowDefault
) {
super("Type", allowDefault);
this.idCodec = new KeyedCodec<>("Id", idCodec);
this.parentCodec = new KeyedCodec<>("Parent", idCodec);
this.idSetter = idSetter;
this.idGetter = idGetter;
this.dataSetter = dataSetter;
this.dataGetter = dataGetter;
}
public AssetCodecMapCodec(
String key,
Codec<K> idCodec,
BiConsumer<T, K> idSetter,
Function<T, K> idGetter,
BiConsumer<T, AssetExtraInfo.Data> dataSetter,
Function<T, AssetExtraInfo.Data> dataGetter,
boolean allowDefault
) {
super(key, allowDefault);
this.idCodec = new KeyedCodec<>("Id", idCodec);
this.parentCodec = new KeyedCodec<>("Parent", idCodec);
this.idSetter = idSetter;
this.idGetter = idGetter;
this.dataSetter = dataSetter;
this.dataGetter = dataGetter;
}
@Nonnull
@Override
public KeyedCodec<K> getKeyCodec() {
return this.idCodec;
}
@Nonnull
@Override
public KeyedCodec<K> getParentCodec() {
return this.parentCodec;
}
@Override
public AssetExtraInfo.Data getData(T t) {
return this.dataGetter.apply(t);
}
@Nonnull
public AssetCodecMapCodec<K, T> register(@Nonnull String id, Class<? extends T> aClass, BuilderCodec<? extends T> codec) {
return this.register(Priority.NORMAL, id, aClass, codec);
}
@Nonnull
public AssetCodecMapCodec<K, T> register(@Nonnull Priority priority, @Nonnull String id, Class<? extends T> aClass, BuilderCodec<? extends T> codec) {
AssetBuilderCodec<K, T> assetCodec = AssetBuilderCodec.wrap(
(BuilderCodec<T>)codec, this.idCodec.getChildCodec(), this.idSetter, this.idGetter, this.dataSetter, this.dataGetter
);
super.register(priority, id, aClass, assetCodec);
return this;
}
public T decodeAndInherit(@Nonnull BsonDocument document, T parent, ExtraInfo extraInfo) {
BsonValue id = document.get(this.key);
AssetBuilderCodec<K, T> codec = this.idToCodec.get(id == null ? null : id.asString().getValue());
if (codec == null) {
AssetBuilderCodec<K, T> defaultCodec = this.getDefaultCodec();
if (defaultCodec == null) {
throw new ACodecMapCodec.UnknownIdException("No codec registered with for '" + this.key + "': " + id);
} else {
return defaultCodec.decodeAndInherit(document, parent, extraInfo);
}
} else {
return codec.decodeAndInherit(document, parent, extraInfo);
}
}
public void decodeAndInherit(@Nonnull BsonDocument document, T t, T parent, ExtraInfo extraInfo) {
BsonValue id = document.get(this.key);
AssetBuilderCodec<K, T> codec = this.idToCodec.get(id == null ? null : id.asString().getValue());
if (codec == null) {
AssetBuilderCodec<K, T> defaultCodec = this.getDefaultCodec();
if (defaultCodec == null) {
throw new ACodecMapCodec.UnknownIdException("No codec registered with for '" + this.key + "': " + id);
} else {
defaultCodec.decodeAndInherit(document, t, parent, extraInfo);
}
} else {
codec.decodeAndInherit(document, t, parent, extraInfo);
}
}
public T decodeAndInheritJson(@Nonnull RawJsonReader reader, @Nullable T parent, @Nonnull ExtraInfo extraInfo) throws IOException {
reader.mark();
String id = null;
if (RawJsonReader.seekToKey(reader, this.key)) {
id = reader.readString();
} else if (parent != null) {
id = this.getIdFor((Class<? extends T>)parent.getClass());
}
reader.reset();
extraInfo.ignoreUnusedKey(this.key);
JsonAsset var7;
try {
AssetBuilderCodec<K, T> codec = id == null ? null : this.idToCodec.get(id);
if (codec != null) {
return codec.decodeAndInheritJson(reader, parent, extraInfo);
}
AssetBuilderCodec<K, T> defaultCodec = this.getDefaultCodec();
if (defaultCodec == null) {
throw new ACodecMapCodec.UnknownIdException("No codec registered with for '" + this.key + "': " + id);
}
var7 = defaultCodec.decodeAndInheritJson(reader, parent, extraInfo);
} finally {
extraInfo.popIgnoredUnusedKey();
}
return (T)var7;
}
public void decodeAndInheritJson(@Nonnull RawJsonReader reader, T t, @Nullable T parent, @Nonnull ExtraInfo extraInfo) throws IOException {
reader.mark();
String id = null;
if (RawJsonReader.seekToKey(reader, this.key)) {
id = reader.readString();
} else if (parent != null) {
id = this.getIdFor((Class<? extends T>)parent.getClass());
}
reader.reset();
extraInfo.ignoreUnusedKey(this.key);
try {
AssetBuilderCodec<K, T> codec = id == null ? null : this.idToCodec.get(id);
if (codec != null) {
codec.decodeAndInheritJson(reader, t, parent, extraInfo);
return;
}
AssetBuilderCodec<K, T> defaultCodec = this.getDefaultCodec();
if (defaultCodec == null) {
throw new ACodecMapCodec.UnknownIdException("No codec registered with for '" + this.key + "': " + id);
}
defaultCodec.decodeAndInheritJson(reader, t, parent, extraInfo);
} finally {
extraInfo.popIgnoredUnusedKey();
}
}
@Override
public T decodeJsonAsset(@Nonnull RawJsonReader reader, @Nonnull AssetExtraInfo<K> extraInfo) throws IOException {
return this.decodeAndInheritJsonAsset(reader, null, extraInfo);
}
@Override
public T decodeAndInheritJsonAsset(@Nonnull RawJsonReader reader, @Nullable T parent, @Nonnull AssetExtraInfo<K> extraInfo) throws IOException {
reader.mark();
String id = null;
if (RawJsonReader.seekToKey(reader, this.key)) {
id = reader.readString();
} else if (parent != null) {
id = this.getIdFor((Class<? extends T>)parent.getClass());
}
reader.reset();
extraInfo.ignoreUnusedKey(this.key);
JsonAsset var8;
try {
AssetBuilderCodec<K, T> codec = id == null ? null : this.idToCodec.get(id);
if (codec == null) {
AssetBuilderCodec<K, T> defaultCodec = this.getDefaultCodec();
if (defaultCodec == null) {
throw new ACodecMapCodec.UnknownIdException("No codec registered with for '" + this.key + "': " + id);
}
codec = defaultCodec;
}
Supplier<T> supplier = codec.getSupplier();
if (supplier == null) {
throw new CodecException(
"This BuilderCodec is for an abstract or direct codec. To use this codec you must specify an existing object to decode into."
);
}
T t = supplier.get();
this.dataSetter.accept(t, extraInfo.getData());
if (parent != null) {
codec.inherit(t, parent, extraInfo);
}
codec.decodeAndInheritJson0(reader, t, parent, extraInfo);
this.idSetter.accept(t, extraInfo.getKey());
codec.afterDecodeAndValidate(t, extraInfo);
var8 = t;
} finally {
extraInfo.popIgnoredUnusedKey();
}
return (T)var8;
}
@Nonnull
@Override
public Schema toSchema(@Nonnull SchemaContext context) {
Schema schema = super.toSchema(context);
schema.getHytaleSchemaTypeField().setParentPropertyKey(this.parentCodec.getKey());
return schema;
}
@Override
protected void mutateChildSchema(String key, @Nonnull SchemaContext context, BuilderCodec<? extends T> c, @Nonnull ObjectSchema objectSchema) {
super.mutateChildSchema(key, context, c, objectSchema);
AssetBuilderCodec<K, T> def = this.getDefaultCodec();
if (!this.allowDefault || def != c) {
Schema idField = new Schema();
idField.setRequired(this.key);
Schema parentField = new Schema();
parentField.setRequired(this.parentCodec.getKey());
AssetBuilderCodec<K, T> bc = (AssetBuilderCodec<K, T>)c;
Schema parentSchema = objectSchema.getProperties().get(bc.getParentCodec().getKey());
if (parentSchema != null) {
Schema.InheritSettings settings = parentSchema.getHytaleParent();
settings.setMapKey(this.key);
settings.setMapKeyValue(key);
objectSchema.setOneOf(idField, parentField);
}
}
}
}

View File

@@ -0,0 +1,234 @@
package com.hypixel.hytale.assetstore.codec;
import com.hypixel.hytale.assetstore.AssetExtraInfo;
import com.hypixel.hytale.assetstore.AssetMap;
import com.hypixel.hytale.assetstore.AssetRegistry;
import com.hypixel.hytale.assetstore.AssetStore;
import com.hypixel.hytale.assetstore.RawAsset;
import com.hypixel.hytale.assetstore.map.JsonAssetWithMap;
import com.hypixel.hytale.codec.Codec;
import com.hypixel.hytale.codec.ExtraInfo;
import com.hypixel.hytale.codec.KeyedCodec;
import com.hypixel.hytale.codec.schema.SchemaContext;
import com.hypixel.hytale.codec.schema.config.Schema;
import com.hypixel.hytale.codec.util.RawJsonReader;
import com.hypixel.hytale.codec.validation.ValidatableCodec;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Set;
import java.util.function.Function;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.bson.BsonValue;
public class ContainedAssetCodec<K, T extends JsonAssetWithMap<K, M>, M extends AssetMap<K, T>> implements Codec<K>, ValidatableCodec<K> {
private static final boolean DISABLE_DIRECT_LOADING = true;
private final Class<T> assetClass;
private final AssetCodec<K, T> codec;
@Nonnull
private final ContainedAssetCodec.Mode mode;
private final Function<AssetExtraInfo<K>, K> keyGenerator;
public ContainedAssetCodec(Class<T> assetClass, AssetCodec<K, T> codec) {
this(assetClass, codec, ContainedAssetCodec.Mode.GENERATE_ID);
}
public ContainedAssetCodec(Class<T> assetClass, AssetCodec<K, T> codec, @Nonnull ContainedAssetCodec.Mode mode) {
this(assetClass, codec, mode, assetExtraInfo -> AssetRegistry.<K, T, M>getAssetStore(assetClass).transformKey(assetExtraInfo.generateKey()));
}
public ContainedAssetCodec(Class<T> assetClass, AssetCodec<K, T> codec, @Nonnull ContainedAssetCodec.Mode mode, Function<AssetExtraInfo<K>, K> keyGenerator) {
if (mode == ContainedAssetCodec.Mode.NONE) {
throw new UnsupportedOperationException("Contained asset mode can't be NONE!");
} else {
this.assetClass = assetClass;
this.codec = codec;
this.mode = mode;
this.keyGenerator = keyGenerator;
}
}
public Class<T> getAssetClass() {
return this.assetClass;
}
@Nullable
@Override
public K decode(@Nonnull BsonValue bsonValue, ExtraInfo extraInfo) {
if (!(extraInfo instanceof AssetExtraInfo<K> assetExtraInfo)) {
throw new UnsupportedOperationException("Unable to decode asset from codec used outside of an AssetStore");
} else if (bsonValue.isString()) {
return this.codec.getKeyCodec().getChildCodec().decode(bsonValue, extraInfo);
} else {
KeyedCodec<K> parentCodec = this.codec.getParentCodec();
K parentId = parentCodec != null ? parentCodec.getOrNull(bsonValue.asDocument(), extraInfo) : null;
AssetStore<K, T, M> assetStore = AssetRegistry.getAssetStore(this.assetClass);
K id;
switch (this.mode) {
case GENERATE_ID: {
id = this.keyGenerator.apply(assetExtraInfo);
boolean inheritContainerTags = false;
break;
}
case INHERIT_ID: {
id = assetStore.transformKey(assetExtraInfo.getKey());
boolean inheritContainerTags = true;
break;
}
case INHERIT_ID_AND_PARENT: {
id = assetStore.transformKey(assetExtraInfo.getKey());
if (parentId == null) {
Object thisAssetParentId = assetExtraInfo.getData().getParentKey();
if (thisAssetParentId != null) {
parentId = assetStore.transformKey(thisAssetParentId);
}
}
boolean inheritContainerTags = true;
break;
}
case INJECT_PARENT: {
id = this.keyGenerator.apply(assetExtraInfo);
if (parentId == null && !assetExtraInfo.getKey().equals(id)) {
parentId = assetExtraInfo.getKey();
}
boolean inheritContainerTags = true;
break;
}
default:
throw new UnsupportedOperationException("Contained asset mode can't be NONE!");
}
T parent = parentId != null ? assetStore.getAssetMap().getAsset(parentId) : null;
if (parentId != null && parent != null) {
}
char[] clone = bsonValue.asDocument().toJson().toCharArray();
Path path = assetExtraInfo.getAssetPath();
assetExtraInfo.getData().addContainedAsset(this.assetClass, new RawAsset<>(path, id, parentId, 0, clone, assetExtraInfo.getData(), this.mode));
return id;
}
}
@Override
public BsonValue encode(@Nonnull K key, ExtraInfo extraInfo) {
if (key.toString().startsWith("*")) {
T asset = (T)AssetRegistry.<K, T, M>getAssetStore(this.assetClass).getAssetMap().getAsset(key);
if (asset != null) {
return this.codec.encode(asset, extraInfo);
}
}
return this.codec.getKeyCodec().getChildCodec().encode(key, extraInfo);
}
@Nullable
@Override
public K decodeJson(@Nonnull RawJsonReader reader, ExtraInfo extraInfo) throws IOException {
if (!(extraInfo instanceof AssetExtraInfo<K> assetExtraInfo)) {
throw new UnsupportedOperationException("Unable to decode asset from codec used outside of an AssetStore");
} else {
int lineStart = reader.getLine() - 1;
if (reader.peekFor('"')) {
return this.codec.getKeyCodec().getChildCodec().decodeJson(reader, extraInfo);
} else {
reader.mark();
K parentId = null;
boolean needsSkip = false;
KeyedCodec<K> parentCodec = this.codec.getParentCodec();
if (parentCodec != null && RawJsonReader.seekToKey(reader, parentCodec.getKey())) {
parentId = parentCodec.getChildCodec().decodeJson(reader, extraInfo);
needsSkip = true;
}
AssetStore<K, T, M> assetStore = AssetRegistry.getAssetStore(this.assetClass);
K id;
switch (this.mode) {
case GENERATE_ID: {
id = this.keyGenerator.apply(assetExtraInfo);
boolean inheritContainerTags = false;
break;
}
case INHERIT_ID: {
id = assetStore.transformKey(assetExtraInfo.getKey());
boolean inheritContainerTags = true;
break;
}
case INHERIT_ID_AND_PARENT: {
id = assetStore.transformKey(assetExtraInfo.getKey());
if (parentId == null) {
Object thisAssetParentId = assetExtraInfo.getData().getParentKey();
if (thisAssetParentId != null) {
parentId = assetStore.transformKey(thisAssetParentId);
}
}
boolean inheritContainerTags = true;
break;
}
case INJECT_PARENT: {
id = this.keyGenerator.apply(assetExtraInfo);
if (parentId == null && !assetExtraInfo.getKey().equals(id)) {
parentId = assetExtraInfo.getKey();
}
boolean inheritContainerTags = true;
break;
}
default:
throw new UnsupportedOperationException("Contained asset mode can't be NONE!");
}
T parent = parentId != null ? assetStore.getAssetMap().getAsset(parentId) : null;
if (parentId != null && parent != null) {
}
if (needsSkip) {
reader.skipObjectContinued();
}
char[] clone = reader.cloneMark();
reader.unmark();
Path path = assetExtraInfo.getAssetPath();
assetExtraInfo.getData()
.addContainedAsset(this.assetClass, new RawAsset<>(path, id, parentId, lineStart, clone, assetExtraInfo.getData(), this.mode));
return id;
}
}
}
@Nonnull
@Override
public Schema toSchema(@Nonnull SchemaContext context) {
Schema keySchema = context.refDefinition(this.codec.getKeyCodec().getChildCodec());
keySchema.setTitle("Reference to " + this.assetClass.getSimpleName());
Schema nestedSchema = context.refDefinition(this.codec);
Schema s = Schema.anyOf(keySchema, nestedSchema);
s.setHytaleAssetRef(this.assetClass.getSimpleName());
return s;
}
@Override
public void validate(K k, @Nonnull ExtraInfo extraInfo) {
AssetRegistry.<K, T, M>getAssetStore(this.assetClass).validate(k, extraInfo.getValidationResults(), extraInfo);
}
@Override
public void validateDefaults(ExtraInfo extraInfo, @Nonnull Set<Codec<?>> tested) {
if (tested.add(this)) {
;
}
}
public static enum Mode {
NONE,
GENERATE_ID,
INHERIT_ID,
INHERIT_ID_AND_PARENT,
INJECT_PARENT;
private Mode() {
}
}
}

View File

@@ -0,0 +1,58 @@
package com.hypixel.hytale.assetstore.event;
import com.hypixel.hytale.event.IEvent;
import java.nio.file.Path;
import java.util.List;
import javax.annotation.Nonnull;
public abstract class AssetMonitorEvent<T> implements IEvent<T> {
@Nonnull
private final List<Path> createdOrModifiedFilesToLoad;
@Nonnull
private final List<Path> removedFilesToUnload;
@Nonnull
private final List<Path> createdOrModifiedDirectories;
@Nonnull
private final List<Path> removedFilesAndDirectories;
@Nonnull
private final String assetPack;
public AssetMonitorEvent(
@Nonnull String assetPack,
@Nonnull List<Path> createdOrModified,
@Nonnull List<Path> removed,
@Nonnull List<Path> createdDirectories,
@Nonnull List<Path> removedDirectories
) {
this.assetPack = assetPack;
this.createdOrModifiedFilesToLoad = createdOrModified;
this.removedFilesToUnload = removed;
this.createdOrModifiedDirectories = createdDirectories;
this.removedFilesAndDirectories = removedDirectories;
}
@Nonnull
public String getAssetPack() {
return this.assetPack;
}
@Nonnull
public List<Path> getCreatedOrModifiedFilesToLoad() {
return this.createdOrModifiedFilesToLoad;
}
@Nonnull
public List<Path> getRemovedFilesToUnload() {
return this.removedFilesToUnload;
}
@Nonnull
public List<Path> getRemovedFilesAndDirectories() {
return this.removedFilesAndDirectories;
}
@Nonnull
public List<Path> getCreatedOrModifiedDirectories() {
return this.createdOrModifiedDirectories;
}
}

View File

@@ -0,0 +1,25 @@
package com.hypixel.hytale.assetstore.event;
import com.hypixel.hytale.assetstore.AssetStore;
import com.hypixel.hytale.event.IEvent;
import javax.annotation.Nonnull;
public abstract class AssetStoreEvent<KeyType> implements IEvent<KeyType> {
@Nonnull
private final AssetStore<?, ?, ?> assetStore;
public AssetStoreEvent(@Nonnull AssetStore<?, ?, ?> assetStore) {
this.assetStore = assetStore;
}
@Nonnull
public AssetStore<?, ?, ?> getAssetStore() {
return this.assetStore;
}
@Nonnull
@Override
public String toString() {
return "AssetStoreEvent{assetStore=" + this.assetStore + "}";
}
}

View File

@@ -0,0 +1,34 @@
package com.hypixel.hytale.assetstore.event;
import com.hypixel.hytale.assetstore.AssetStore;
import java.nio.file.Path;
import java.util.List;
import javax.annotation.Nonnull;
public class AssetStoreMonitorEvent extends AssetMonitorEvent<Void> {
@Nonnull
private final AssetStore<?, ?, ?> assetStore;
public AssetStoreMonitorEvent(
@Nonnull String assetPack,
@Nonnull AssetStore<?, ?, ?> assetStore,
@Nonnull List<Path> createdOrModified,
@Nonnull List<Path> removed,
@Nonnull List<Path> createdOrModifiedDirectories,
@Nonnull List<Path> removedDirectories
) {
super(assetPack, createdOrModified, removed, createdOrModifiedDirectories, removedDirectories);
this.assetStore = assetStore;
}
@Nonnull
public AssetStore<?, ?, ?> getAssetStore() {
return this.assetStore;
}
@Nonnull
@Override
public String toString() {
return "AssetMonitorEvent{assetStore=" + this.assetStore + "}";
}
}

View File

@@ -0,0 +1,9 @@
package com.hypixel.hytale.assetstore.event;
import com.hypixel.hytale.assetstore.JsonAsset;
import com.hypixel.hytale.event.IEvent;
public abstract class AssetsEvent<K, T extends JsonAsset<K>> implements IEvent<Class<T>> {
public AssetsEvent() {
}
}

View File

@@ -0,0 +1,201 @@
package com.hypixel.hytale.assetstore.event;
import com.hypixel.hytale.assetstore.AssetExtraInfo;
import com.hypixel.hytale.assetstore.AssetMap;
import com.hypixel.hytale.assetstore.AssetRegistry;
import com.hypixel.hytale.assetstore.AssetStore;
import com.hypixel.hytale.assetstore.map.JsonAssetWithMap;
import com.hypixel.hytale.common.util.FormatUtil;
import com.hypixel.hytale.event.IProcessedEvent;
import com.hypixel.hytale.logger.HytaleLogger;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import javax.annotation.Nonnull;
public class GenerateAssetsEvent<K, T extends JsonAssetWithMap<K, M>, M extends AssetMap<K, T>> extends AssetsEvent<K, T> implements IProcessedEvent {
private final Class<T> tClass;
private final M assetMap;
@Nonnull
private final Map<K, T> loadedAssets;
private final Map<K, Set<K>> assetChildren;
@Nonnull
private final Map<K, T> unmodifiableLoadedAssets;
private final Map<K, T> addedAssets = new ConcurrentHashMap<>();
private final Map<K, Set<K>> addedAssetChildren = new ConcurrentHashMap<>();
private final Map<Class<? extends JsonAssetWithMap<?, ?>>, Map<?, Set<K>>> addedChildAssetsMap = new ConcurrentHashMap<>();
private long before;
public GenerateAssetsEvent(Class<T> tClass, M assetMap, @Nonnull Map<K, T> loadedAssets, Map<K, Set<K>> assetChildren) {
this.tClass = tClass;
this.assetMap = assetMap;
this.loadedAssets = loadedAssets;
this.assetChildren = assetChildren;
this.unmodifiableLoadedAssets = Collections.unmodifiableMap(loadedAssets);
this.before = System.nanoTime();
}
public Class<T> getAssetClass() {
return this.tClass;
}
@Nonnull
public Map<K, T> getLoadedAssets() {
return this.unmodifiableLoadedAssets;
}
public M getAssetMap() {
return this.assetMap;
}
public void addChildAsset(K childKey, T asset, @Nonnull K parent) {
if (!this.loadedAssets.containsKey(parent) && this.assetMap.getAsset(parent) == null) {
throw new IllegalArgumentException("Parent '" + parent + "' doesn't exist!");
} else if (parent.equals(childKey)) {
throw new IllegalArgumentException("Unable to to add asset '" + parent + "' because it is its own parent!");
} else {
AssetStore<K, T, M> assetStore = AssetRegistry.getAssetStore(this.tClass);
AssetExtraInfo<K> extraInfo = new AssetExtraInfo<>(assetStore.getCodec().getData(asset));
assetStore.getCodec().validate(asset, extraInfo);
extraInfo.getValidationResults().logOrThrowValidatorExceptions(assetStore.getLogger());
this.addedAssets.put(childKey, asset);
this.addedAssetChildren.computeIfAbsent(parent, k -> new HashSet<>()).add(childKey);
}
}
@SafeVarargs
public final void addChildAsset(K childKey, T asset, @Nonnull K... parents) {
for (int i = 0; i < parents.length; i++) {
K parent = parents[i];
if (!this.loadedAssets.containsKey(parent) && this.assetMap.getAsset(parent) == null) {
throw new IllegalArgumentException("Parent at " + i + " '" + parent + "' doesn't exist!");
}
if (parent.equals(childKey)) {
throw new IllegalArgumentException("Unable to to add asset '" + parent + "' because it is its own parent!");
}
}
AssetStore<K, T, M> assetStore = AssetRegistry.getAssetStore(this.tClass);
AssetExtraInfo<K> extraInfo = new AssetExtraInfo<>(assetStore.getCodec().getData(asset));
assetStore.getCodec().validate(asset, extraInfo);
extraInfo.getValidationResults().logOrThrowValidatorExceptions(assetStore.getLogger());
this.addedAssets.put(childKey, asset);
for (K parentx : parents) {
this.addedAssetChildren.computeIfAbsent(parentx, k -> new HashSet<>()).add(childKey);
}
}
public <P extends JsonAssetWithMap<PK, ?>, PK> void addChildAssetWithReference(K childKey, T asset, Class<P> parentAssetClass, @Nonnull PK parentKey) {
if (AssetRegistry.<PK, T, AssetMap<PK, T>>getAssetStore(parentAssetClass).getAssetMap().getAsset(parentKey) == null) {
throw new IllegalArgumentException("Parent '" + parentKey + "' from " + parentAssetClass + " doesn't exist!");
} else if (parentKey.equals(childKey)) {
throw new IllegalArgumentException("Unable to to add asset '" + parentKey + "' because it is its own parent!");
} else {
AssetStore<K, T, M> assetStore = AssetRegistry.getAssetStore(this.tClass);
AssetExtraInfo<K> extraInfo = new AssetExtraInfo<>(assetStore.getCodec().getData(asset));
assetStore.getCodec().validate(asset, extraInfo);
extraInfo.getValidationResults().logOrThrowValidatorExceptions(assetStore.getLogger());
this.addedAssets.put(childKey, asset);
((Map<PK, Set<K>>)this.addedChildAssetsMap
.computeIfAbsent(parentAssetClass, k -> new ConcurrentHashMap<>()))
.computeIfAbsent(parentKey, k -> new HashSet())
.add(childKey);
}
}
public void addChildAssetWithReferences(K childKey, T asset, @Nonnull GenerateAssetsEvent.ParentReference<?, ?>... parents) {
for (int i = 0; i < parents.length; i++) {
GenerateAssetsEvent.ParentReference<?, ?> parent = parents[i];
if (AssetRegistry.getAssetStore(parent.getParentAssetClass()).getAssetMap().getAsset((K)parent.getParentKey()) == null) {
throw new IllegalArgumentException("Parent at " + i + " '" + parent + "' doesn't exist!");
}
if (parent.parentKey.equals(childKey)) {
throw new IllegalArgumentException("Unable to to add asset '" + parent.parentKey + "' because it is its own parent!");
}
}
AssetStore<K, T, M> assetStore = AssetRegistry.getAssetStore(this.tClass);
AssetExtraInfo<K> extraInfo = new AssetExtraInfo<>(assetStore.getCodec().getData(asset));
assetStore.getCodec().validate(asset, extraInfo);
extraInfo.getValidationResults().logOrThrowValidatorExceptions(assetStore.getLogger());
this.addedAssets.put(childKey, asset);
for (GenerateAssetsEvent.ParentReference<?, ?> parentx : parents) {
((Map<Object, Set<K>>)this.addedChildAssetsMap
.computeIfAbsent((Class<? extends JsonAssetWithMap<?, ?>>)parentx.parentAssetClass, k -> new ConcurrentHashMap<>()))
.computeIfAbsent(parentx.parentKey, k -> new HashSet())
.add(childKey);
}
}
@Override
public void processEvent(@Nonnull String hookName) {
HytaleLogger.getLogger()
.at(Level.INFO)
.log(
"Generated %d of %s from %s in %s",
this.addedAssets.size(),
this.tClass.getSimpleName(),
hookName,
FormatUtil.nanosToString(System.nanoTime() - this.before)
);
this.loadedAssets.putAll(this.addedAssets);
this.addedAssets.clear();
for (Entry<K, Set<K>> entry : this.addedAssetChildren.entrySet()) {
K parent = entry.getKey();
this.assetChildren.computeIfAbsent(parent, kx -> ConcurrentHashMap.newKeySet()).addAll(entry.getValue());
}
this.addedAssetChildren.clear();
for (Entry<Class<? extends JsonAssetWithMap<?, ?>>, Map<?, Set<K>>> entry : this.addedChildAssetsMap.entrySet()) {
Class k = entry.getKey();
AssetStore assetStore = AssetRegistry.getAssetStore(k);
for (Entry<?, Set<K>> childEntry : entry.getValue().entrySet()) {
assetStore.addChildAssetReferences(childEntry.getKey(), this.tClass, childEntry.getValue());
}
}
this.addedChildAssetsMap.clear();
this.before = System.nanoTime();
}
@Nonnull
@Override
public String toString() {
return "GenerateAssetsEvent{tClass=" + this.tClass + ", loadedAssets.size()=" + this.loadedAssets.size() + ", " + super.toString() + "}";
}
public static class ParentReference<P extends JsonAssetWithMap<PK, ?>, PK> {
private final Class<P> parentAssetClass;
private final PK parentKey;
public ParentReference(Class<P> parentAssetClass, PK parentKey) {
this.parentAssetClass = parentAssetClass;
this.parentKey = parentKey;
}
public Class<P> getParentAssetClass() {
return this.parentAssetClass;
}
public PK getParentKey() {
return this.parentKey;
}
@Nonnull
@Override
public String toString() {
return "ParentReference{parentAssetClass=" + this.parentAssetClass + ", parentKey=" + this.parentKey + "}";
}
}
}

View File

@@ -0,0 +1,56 @@
package com.hypixel.hytale.assetstore.event;
import com.hypixel.hytale.assetstore.AssetMap;
import com.hypixel.hytale.assetstore.AssetUpdateQuery;
import com.hypixel.hytale.assetstore.JsonAsset;
import java.util.Collections;
import java.util.Map;
import javax.annotation.Nonnull;
public class LoadedAssetsEvent<K, T extends JsonAsset<K>, M extends AssetMap<K, T>> extends AssetsEvent<K, T> {
@Nonnull
private final Class<T> tClass;
@Nonnull
private final M assetMap;
@Nonnull
private final Map<K, T> loadedAssets;
private final boolean initial;
@Nonnull
private final AssetUpdateQuery query;
public LoadedAssetsEvent(@Nonnull Class<T> tClass, @Nonnull M assetMap, @Nonnull Map<K, T> loadedAssets, boolean initial, @Nonnull AssetUpdateQuery query) {
this.tClass = tClass;
this.assetMap = assetMap;
this.loadedAssets = Collections.unmodifiableMap(loadedAssets);
this.initial = initial;
this.query = query;
}
public Class<T> getAssetClass() {
return this.tClass;
}
public M getAssetMap() {
return this.assetMap;
}
@Nonnull
public Map<K, T> getLoadedAssets() {
return this.loadedAssets;
}
public boolean isInitial() {
return this.initial;
}
@Nonnull
public AssetUpdateQuery getQuery() {
return this.query;
}
@Nonnull
@Override
public String toString() {
return "LoadedAssetsEvent{loadedAssets=" + this.loadedAssets + ", initial=" + this.initial + ", query=" + this.query + "} " + super.toString();
}
}

View File

@@ -0,0 +1,10 @@
package com.hypixel.hytale.assetstore.event;
import com.hypixel.hytale.assetstore.AssetStore;
import javax.annotation.Nonnull;
public class RegisterAssetStoreEvent extends AssetStoreEvent<Void> {
public RegisterAssetStoreEvent(@Nonnull AssetStore<?, ?, ?> assetStore) {
super(assetStore);
}
}

View File

@@ -0,0 +1,10 @@
package com.hypixel.hytale.assetstore.event;
import com.hypixel.hytale.assetstore.AssetStore;
import javax.annotation.Nonnull;
public class RemoveAssetStoreEvent extends AssetStoreEvent<Void> {
public RemoveAssetStoreEvent(@Nonnull AssetStore<?, ?, ?> assetStore) {
super(assetStore);
}
}

View File

@@ -0,0 +1,45 @@
package com.hypixel.hytale.assetstore.event;
import com.hypixel.hytale.assetstore.AssetMap;
import com.hypixel.hytale.assetstore.JsonAsset;
import java.util.Collections;
import java.util.Set;
import javax.annotation.Nonnull;
public class RemovedAssetsEvent<K, T extends JsonAsset<K>, M extends AssetMap<K, T>> extends AssetsEvent<K, T> {
private final Class<T> tClass;
private final M assetMap;
@Nonnull
private final Set<K> removedAssets;
private final boolean replaced;
public RemovedAssetsEvent(Class<T> tClass, M assetMap, @Nonnull Set<K> removedAssets, boolean replaced) {
this.tClass = tClass;
this.assetMap = assetMap;
this.removedAssets = Collections.unmodifiableSet(removedAssets);
this.replaced = replaced;
}
public Class<T> getAssetClass() {
return this.tClass;
}
public M getAssetMap() {
return this.assetMap;
}
@Nonnull
public Set<K> getRemovedAssets() {
return this.removedAssets;
}
public boolean isReplaced() {
return this.replaced;
}
@Nonnull
@Override
public String toString() {
return "RemovedAssetsEvent{removedAssets=" + this.removedAssets + ", replaced=" + this.replaced + "} " + super.toString();
}
}

View File

@@ -0,0 +1,78 @@
package com.hypixel.hytale.assetstore.iterator;
import com.hypixel.hytale.assetstore.AssetMap;
import com.hypixel.hytale.assetstore.AssetRegistry;
import com.hypixel.hytale.assetstore.AssetStore;
import com.hypixel.hytale.assetstore.JsonAsset;
import com.hypixel.hytale.assetstore.map.JsonAssetWithMap;
import java.io.Closeable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class AssetStoreIterator implements Iterator<AssetStore<?, ?, ?>>, Closeable {
@Nonnull
private final List<AssetStore<?, ?, ?>> list;
public AssetStoreIterator(@Nonnull Collection<AssetStore<?, ?, ?>> values) {
this.list = new ArrayList<>(values);
}
@Override
public boolean hasNext() {
return !this.list.isEmpty();
}
@Nullable
public AssetStore<?, ?, ?> next() {
Iterator<AssetStore<?, ?, ?>> iterator = this.list.iterator();
while (iterator.hasNext()) {
AssetStore<?, ? extends JsonAssetWithMap<?, ? extends AssetMap<?, ?>>, ? extends AssetMap<?, ? extends JsonAssetWithMap<?, ?>>> assetStore = (AssetStore<?, ? extends JsonAssetWithMap<?, ? extends AssetMap<?, ?>>, ? extends AssetMap<?, ? extends JsonAssetWithMap<?, ?>>>)iterator.next();
if (!this.isWaitingForDependencies(assetStore)) {
iterator.remove();
return assetStore;
}
}
return null;
}
public int size() {
return this.list.size();
}
public boolean isWaitingForDependencies(@Nonnull AssetStore<?, ?, ?> assetStore) {
for (Class<? extends JsonAsset<?>> aClass : assetStore.getLoadsAfter()) {
AssetStore otherStore = AssetRegistry.getAssetStore(aClass);
if (otherStore == null) {
throw new IllegalArgumentException("Unable to find asset store: " + aClass);
}
if (this.list.contains(otherStore)) {
return true;
}
}
return false;
}
public boolean isBeingWaitedFor(@Nonnull AssetStore<?, ?, ?> assetStore) {
Class<? extends JsonAssetWithMap<?, ? extends AssetMap<?, ?>>> assetClass = (Class<? extends JsonAssetWithMap<?, ? extends AssetMap<?, ?>>>)assetStore.getAssetClass();
for (AssetStore<?, ?, ?> store : this.list) {
if (store.getLoadsAfter().contains(assetClass)) {
return true;
}
}
return false;
}
@Override
public void close() {
}
}

View File

@@ -0,0 +1,39 @@
package com.hypixel.hytale.assetstore.iterator;
import com.hypixel.hytale.assetstore.AssetRegistry;
import com.hypixel.hytale.assetstore.AssetStore;
import com.hypixel.hytale.assetstore.JsonAsset;
import java.util.Collection;
import javax.annotation.Nonnull;
public class CircularDependencyException extends RuntimeException {
public CircularDependencyException(@Nonnull Collection<AssetStore<?, ?, ?>> values, @Nonnull AssetStoreIterator iterator) {
super(makeMessage(values, iterator));
}
@Nonnull
protected static String makeMessage(@Nonnull Collection<AssetStore<?, ?, ?>> values, @Nonnull AssetStoreIterator iterator) {
StringBuilder sb = new StringBuilder(
"Failed to process any stores there must be a circular dependency! " + values + ", " + iterator.size() + "\nWaiting for Asset Stores:\n"
);
for (AssetStore<?, ?, ?> store : values) {
if (iterator.isWaitingForDependencies(store)) {
sb.append(store.getAssetClass()).append("\n");
for (Class<? extends JsonAsset<?>> aClass : store.getLoadsAfter()) {
AssetStore otherStore = AssetRegistry.getAssetStore(aClass);
if (otherStore == null) {
throw new IllegalArgumentException("Unable to find asset store: " + aClass);
}
if (iterator.isWaitingForDependencies(otherStore)) {
sb.append("\t- ").append(otherStore.getAssetClass()).append("\n");
}
}
}
}
return sb.toString();
}
}

View File

@@ -0,0 +1,61 @@
package com.hypixel.hytale.assetstore.map;
import com.hypixel.fastutil.ints.Int2ObjectConcurrentHashMap;
import com.hypixel.hytale.assetstore.AssetExtraInfo;
import com.hypixel.hytale.assetstore.JsonAsset;
import com.hypixel.hytale.assetstore.codec.AssetCodec;
import it.unimi.dsi.fastutil.ints.IntIterator;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.ints.IntSets;
import java.util.Map;
import javax.annotation.Nonnull;
public abstract class AssetMapWithIndexes<K, T extends JsonAsset<K>> extends DefaultAssetMap<K, T> {
public static final int NOT_FOUND = Integer.MIN_VALUE;
protected final Int2ObjectConcurrentHashMap<IntSet> indexedTagStorage = new Int2ObjectConcurrentHashMap<>();
protected final Int2ObjectConcurrentHashMap<IntSet> unmodifiableIndexedTagStorage = new Int2ObjectConcurrentHashMap<>();
public AssetMapWithIndexes() {
}
@Override
protected void clear() {
super.clear();
this.indexedTagStorage.clear();
this.unmodifiableIndexedTagStorage.clear();
}
public IntSet getIndexesForTag(int index) {
return this.unmodifiableIndexedTagStorage.getOrDefault(index, IntSets.EMPTY_SET);
}
@Override
protected void putAssetTags(AssetCodec<K, T> codec, Map<K, T> loadedAssets) {
}
protected void putAssetTag(@Nonnull AssetCodec<K, T> codec, K key, int index, T value) {
AssetExtraInfo.Data data = codec.getData(value);
if (data != null) {
IntIterator iterator = data.getExpandedTagIndexes().iterator();
while (iterator.hasNext()) {
int tag = iterator.nextInt();
this.putAssetTag(key, index, tag);
}
}
}
protected void putAssetTag(K key, int index, int tag) {
this.putAssetTag(key, tag);
this.indexedTagStorage.computeIfAbsent(tag, k -> {
IntSet set = Int2ObjectConcurrentHashMap.newKeySet(3);
this.unmodifiableIndexedTagStorage.put(k, IntSets.unmodifiable(set));
return set;
}).add(index);
}
@Override
public boolean requireReplaceOnRemove() {
return true;
}
}

Some files were not shown because too many files have changed in this diff Show More