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;
publicclassAssetBuilderCodec<K, T extendsJsonAsset<K>> extendsBuilderCodec<T> implementsAssetCodec<K, T> {
publicstaticfinal KeyedCodec<Map<String, String[]>> TAGS_CODEC;
privatestaticfinalStringTAG_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**.";
@Nonnullprotectedfinal KeyedCodec<K> idCodec;
@Nonnullprotectedfinal KeyedCodec<K> parentCodec;
protectedfinal BiConsumer<T, K> idSetter;
protectedfinal BiConsumer<T, AssetExtraInfo.Data> dataSetter;
@Nonnullprotectedfinal Function<T, AssetExtraInfo.Data> dataGetter;
protectedAssetBuilderCodec(@Nonnull Builder<K, T> builder) {
super(builder);
this.idCodec = builder.idCodec;
this.parentCodec = newKeyedCodec<K>("Parent", this.idCodec.getChildCodec());
this.idSetter = builder.idSetter;
this.dataSetter = builder.dataSetter;
this.dataGetter = builder.dataGetter;
}
@Nonnullpublic KeyedCodec<K> getKeyCodec() {
returnthis.idCodec;
}
@Nonnullpublic KeyedCodec<K> getParentCodec() {
returnthis.parentCodec;
}
public AssetExtraInfo.Data getData(T t) {
return (AssetExtraInfo.Data)this.dataGetter.apply(t);
}
public T decodeJsonAsset(@Nonnull RawJsonReader reader, @Nonnull AssetExtraInfo<K> extraInfo)throws IOException {
return (T)this.decodeAndInheritJsonAsset(reader, (JsonAsset)null, extraInfo);
}
public T decodeAndInheritJsonAsset(@Nonnull RawJsonReader reader, @Nullable T parent, @Nonnull AssetExtraInfo<K> extraInfo)throws IOException {
Tt= (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;
}
@Nonnullpublic ObjectSchema toSchema(@Nonnull SchemaContext context) {
returnthis.toSchema(context, (JsonAsset)this.supplier.get());
}
@Nonnullpublic ObjectSchema toSchema(@Nonnull SchemaContext context, @Nullable T def) {
ObjectSchemaschema=super.toSchema(context, def);
KeyedCodec<K> parent = this.getParentCodec();
SchemaparentSchema= 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(newSchema.InheritSettings(rootClass.getSimpleName()));
LinkedHashMap<String, Schema> props = newLinkedHashMap();
props.put(parent.getKey(), parentSchema);
props.putAll(schema.getProperties());
schema.setProperties(props);
return schema;
}
@Nonnullpublicstatic <K, T extendsJsonAsset<K>> 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) {
returnnewBuilder<K, T>(tClass, supplier, idCodec, idSetter, idGetter, dataSetter, dataGetter);
}
@Nonnullpublicstatic <K, T extendsJsonAsset<K>> 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) {
returnnewBuilder<K, T>(tClass, supplier, parentCodec, idCodec, idSetter, idGetter, dataSetter, dataGetter);
}
@Nonnullpublicstatic <K, T extendsJsonAsset<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)builder(codec.getInnerClass(), codec.getSupplier(), codec, idCodec, idSetter, idGetter, dataSetter, dataGetter).documentation(codec.getDocumentation())).build();
}
static {
TAGS_CODEC = newKeyedCodec<Map<String, String[]>>("Tags", newMapCodec(Codec.STRING_ARRAY, HashMap::new));
}
publicstaticclassBuilder<K, T extendsJsonAsset<K>> extendsBuilderCodec.BuilderBase<T, Builder<K, T>> {
@Nonnullprotectedfinal KeyedCodec<K> idCodec;
protectedfinal BiConsumer<T, K> idSetter;
protectedfinal BiConsumer<T, AssetExtraInfo.Data> dataSetter;
@Nonnullprotectedfinal Function<T, AssetExtraInfo.Data> dataGetter;
publicBuilder(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 = newKeyedCodec<K>("Id", idCodec);
this.idSetter = idSetter;
this.dataSetter = dataSetter;
this.dataGetter = dataGetter;
this.appendInherited(AssetBuilderCodec.TAGS_CODEC, (t, tags) -> ((AssetExtraInfo.Data)dataGetter.apply(t)).putTags(tags), (t) -> {
AssetExtraInfo.Datadata= (AssetExtraInfo.Data)dataGetter.apply(t);
return data != null ? data.getRawTags() : null;
}, (t, parent) -> {
AssetExtraInfo.Datadata= (AssetExtraInfo.Data)dataGetter.apply(t);
AssetExtraInfo.DataparentData= (AssetExtraInfo.Data)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();
}
publicBuilder(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 = newKeyedCodec<K>("Id", idCodec);
this.idSetter = idSetter;
this.dataSetter = dataSetter;
this.dataGetter = dataGetter;
this.appendInherited(AssetBuilderCodec.TAGS_CODEC, (t, tags) -> ((AssetExtraInfo.Data)dataGetter.apply(t)).putTags(tags), (t) -> {
AssetExtraInfo.Datadata= (AssetExtraInfo.Data)dataGetter.apply(t);
return data != null ? data.getRawTags() : null;
}, (t, parent) -> {
AssetExtraInfo.Datadata= (AssetExtraInfo.Data)dataGetter.apply(t);
AssetExtraInfo.DataparentData= (AssetExtraInfo.Data)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();
}
@Nonnullpublic AssetBuilderCodec<K, T> build() {
returnnewAssetBuilderCodec<K, T>(this);
}
}
}