// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.server.core.modules.entitystats;

import java.util.HashMap;
import com.hypixel.hytale.server.core.modules.entitystats.modifier.StaticModifier;
import com.hypixel.hytale.protocol.ChangeStatBehaviour;
import com.hypixel.hytale.protocol.ValueType;
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
import java.util.Iterator;
import it.unimi.dsi.fastutil.floats.FloatArrayList;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import com.hypixel.hytale.protocol.EntityStatOp;
import java.util.logging.Level;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.server.core.modules.entitystats.modifier.Modifier;
import com.hypixel.hytale.assetstore.map.IndexedLookupTableAssetMap;
import java.util.Arrays;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import com.hypixel.hytale.server.core.modules.entitystats.asset.EntityStatType;
import javax.annotation.Nullable;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import com.hypixel.hytale.common.util.ArrayUtil;
import com.hypixel.hytale.component.ComponentType;
import it.unimi.dsi.fastutil.floats.FloatList;
import com.hypixel.hytale.protocol.EntityStatUpdate;
import java.util.List;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import javax.annotation.Nonnull;
import java.util.Map;
import com.hypixel.hytale.codec.builder.BuilderCodec;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.Component;

public class EntityStatMap implements Component<EntityStore>
{
    public static final int VERSION = 5;
    public static final BuilderCodec<EntityStatMap> CODEC;
    private Map<String, EntityStatValue> unknown;
    @Nonnull
    private EntityStatValue[] values;
    float[] tempRegenerationValues;
    public final Int2ObjectMap<List<EntityStatUpdate>> selfUpdates;
    public final Int2ObjectMap<FloatList> selfStatValues;
    public final Int2ObjectMap<List<EntityStatUpdate>> otherUpdates;
    protected boolean isSelfNetworkOutdated;
    protected boolean isNetworkOutdated;
    
    public static ComponentType<EntityStore, EntityStatMap> getComponentType() {
        return EntityStatsModule.get().getEntityStatMapComponentType();
    }
    
    public EntityStatMap() {
        this.values = EntityStatValue.EMPTY_ARRAY;
        this.tempRegenerationValues = ArrayUtil.EMPTY_FLOAT_ARRAY;
        this.selfUpdates = new Int2ObjectOpenHashMap<List<EntityStatUpdate>>();
        this.selfStatValues = new Int2ObjectOpenHashMap<FloatList>();
        this.otherUpdates = new Int2ObjectOpenHashMap<List<EntityStatUpdate>>();
    }
    
    public int size() {
        return this.values.length;
    }
    
    @Nullable
    public EntityStatValue get(final int index) {
        if (index >= this.values.length) {
            return null;
        }
        return this.values[index];
    }
    
    @Deprecated
    @Nullable
    public EntityStatValue get(final String entityStat) {
        return this.get(EntityStatType.getAssetMap().getIndex(entityStat));
    }
    
    public void update() {
        final IndexedLookupTableAssetMap<String, EntityStatType> assetMap = EntityStatType.getAssetMap();
        for (int index = 0; index < this.values.length; ++index) {
            final EntityStatType asset = assetMap.getAsset(index);
            final EntityStatValue value = this.values[index];
            if (value != null) {
                if (asset.isUnknown()) {
                    if (this.unknown == null) {
                        this.unknown = new Object2ObjectOpenHashMap<String, EntityStatValue>();
                    }
                    this.unknown.put(asset.getId(), value);
                    this.values[index] = new EntityStatValue(index, asset);
                }
                else if (value.synchronizeAsset(index, asset)) {
                    this.addInitChange(index, value);
                }
            }
        }
        final int assetCount = assetMap.getNextIndex();
        final int oldLength = this.values.length;
        if (oldLength <= assetCount) {
            this.values = Arrays.copyOf(this.values, assetCount);
            for (int index2 = oldLength; index2 < assetCount; ++index2) {
                final EntityStatType asset2 = assetMap.getAsset(index2);
                if (asset2.isUnknown()) {
                    final EntityStatValue[] values = this.values;
                    final int n = index2;
                    final EntityStatValue entityStatValue = new EntityStatValue(index2, asset2);
                    values[n] = entityStatValue;
                    final EntityStatValue value2 = entityStatValue;
                    this.addInitChange(index2, value2);
                }
                else {
                    EntityStatValue value2 = (this.unknown == null) ? null : this.unknown.remove(asset2.getId());
                    if (value2 != null) {
                        value2.synchronizeAsset(index2, asset2);
                        this.addInitChange(index2, this.values[index2] = value2);
                    }
                    else {
                        final EntityStatValue[] values2 = this.values;
                        final int n2 = index2;
                        final EntityStatValue entityStatValue2 = new EntityStatValue(index2, asset2);
                        values2[n2] = entityStatValue2;
                        value2 = entityStatValue2;
                        this.addInitChange(index2, value2);
                    }
                }
            }
        }
    }
    
    @Nullable
    public Modifier getModifier(final int index, final String key) {
        final EntityStatValue entityStatValue = this.get(index);
        if (entityStatValue == null) {
            HytaleLogger.getLogger().at(Level.WARNING).log("No EntityStatValue found for index: " + index);
            return null;
        }
        return (entityStatValue.getModifiers() != null) ? entityStatValue.getModifiers().get(key) : null;
    }
    
    @Nullable
    public Modifier putModifier(final int index, final String key, final Modifier modifier) {
        return this.putModifier(Predictable.NONE, index, key, modifier);
    }
    
    @Nullable
    public Modifier putModifier(final Predictable predictable, final int index, final String key, final Modifier modifier) {
        final EntityStatValue entityStatValue = this.get(index);
        if (entityStatValue == null) {
            HytaleLogger.getLogger().at(Level.WARNING).log("No EntityStatValue found for index: " + index);
            return null;
        }
        final float previousValue = entityStatValue.get();
        final Modifier previous = entityStatValue.putModifier(key, modifier);
        this.addChange(predictable, index, EntityStatOp.PutModifier, previousValue, key, modifier);
        return previous;
    }
    
    @Nullable
    public Modifier removeModifier(final int index, final String key) {
        return this.removeModifier(Predictable.NONE, index, key);
    }
    
    @Nullable
    public Modifier removeModifier(final Predictable predictable, final int index, final String key) {
        final EntityStatValue entityStatValue = this.get(index);
        if (entityStatValue == null) {
            HytaleLogger.getLogger().at(Level.WARNING).log("No EntityStatValue found for index: " + index);
            return null;
        }
        final float previousValue = entityStatValue.get();
        final Modifier previous = entityStatValue.removeModifier(key);
        if (previous != null) {
            this.addChange(predictable, index, EntityStatOp.RemoveModifier, previousValue, key, null);
        }
        return previous;
    }
    
    public float setStatValue(final int index, final float newValue) {
        return this.setStatValue(Predictable.NONE, index, newValue);
    }
    
    public float setStatValue(final Predictable predictable, final int index, final float newValue) {
        final EntityStatValue entityStatValue = this.get(index);
        if (entityStatValue == null) {
            HytaleLogger.getLogger().at(Level.WARNING).log("No EntityStatValue found for index: " + index);
            return 0.0f;
        }
        final float currentValue = entityStatValue.get();
        final float ret = entityStatValue.set(newValue);
        if (predictable != Predictable.NONE || newValue != currentValue) {
            this.addChange(predictable, index, EntityStatOp.Set, currentValue, newValue);
        }
        return ret;
    }
    
    public float addStatValue(final int index, final float amount) {
        return this.addStatValue(Predictable.NONE, index, amount);
    }
    
    public float addStatValue(final Predictable predictable, final int index, final float amount) {
        final EntityStatValue entityStatValue = this.get(index);
        if (entityStatValue == null) {
            HytaleLogger.getLogger().at(Level.WARNING).log("No EntityStatValue found for index: " + index);
            return 0.0f;
        }
        final float currentValue = entityStatValue.get();
        final float ret = entityStatValue.set(currentValue + amount);
        if (predictable != Predictable.NONE || ret != currentValue) {
            this.addChange(predictable, index, EntityStatOp.Add, currentValue, amount);
        }
        return ret;
    }
    
    public float subtractStatValue(final int index, final float amount) {
        return this.addStatValue(index, -amount);
    }
    
    public float subtractStatValue(final Predictable predictable, final int index, final float amount) {
        return this.addStatValue(predictable, index, -amount);
    }
    
    public float minimizeStatValue(final int index) {
        return this.minimizeStatValue(Predictable.NONE, index);
    }
    
    public float minimizeStatValue(final Predictable predictable, final int index) {
        final EntityStatValue entityStatValue = this.get(index);
        if (entityStatValue == null) {
            HytaleLogger.getLogger().at(Level.WARNING).log("No EntityStatValue found for index: " + index);
            return 0.0f;
        }
        final float previousValue = entityStatValue.get();
        final float ret = entityStatValue.set(entityStatValue.getMin());
        this.addChange(predictable, index, EntityStatOp.Minimize, previousValue, 0.0f);
        return ret;
    }
    
    public float maximizeStatValue(final int index) {
        return this.maximizeStatValue(Predictable.NONE, index);
    }
    
    public float maximizeStatValue(final Predictable predictable, final int index) {
        final EntityStatValue entityStatValue = this.get(index);
        if (entityStatValue == null) {
            HytaleLogger.getLogger().at(Level.WARNING).log("No EntityStatValue found for index: " + index);
            return 0.0f;
        }
        final float previousValue = entityStatValue.get();
        final float ret = entityStatValue.set(entityStatValue.getMax());
        this.addChange(predictable, index, EntityStatOp.Maximize, previousValue, 0.0f);
        return ret;
    }
    
    public float resetStatValue(final int index) {
        return this.resetStatValue(Predictable.NONE, index);
    }
    
    public float resetStatValue(final Predictable predictable, final int index) {
        final EntityStatType entityStatType = EntityStatType.getAssetMap().getAsset(index);
        if (entityStatType == null) {
            HytaleLogger.getLogger().at(Level.WARNING).log("No EntityStatType found for index: " + index);
            return 0.0f;
        }
        final EntityStatValue entityStatValue = this.get(index);
        if (entityStatValue == null) {
            HytaleLogger.getLogger().at(Level.WARNING).log("No EntityStatValue found for index: " + index);
            return 0.0f;
        }
        final float previousValue = entityStatValue.get();
        float ret = 0.0f;
        switch (entityStatType.getResetBehavior()) {
            case InitialValue: {
                ret = entityStatValue.set(entityStatType.getInitialValue());
                break;
            }
            case MaxValue: {
                ret = entityStatValue.set(entityStatValue.getMax());
                break;
            }
            default: {
                ret = 0.0f;
                break;
            }
        }
        this.addChange(predictable, index, EntityStatOp.Reset, previousValue, 0.0f);
        return ret;
    }
    
    @Nonnull
    public Int2ObjectMap<List<EntityStatUpdate>> getSelfUpdates() {
        return this.selfUpdates;
    }
    
    @Nonnull
    public Int2ObjectMap<FloatList> getSelfStatValues() {
        return this.selfStatValues;
    }
    
    @Nonnull
    public Int2ObjectMap<EntityStatUpdate[]> consumeSelfUpdates() {
        return this.updatesToProtocol(this.selfUpdates);
    }
    
    public void clearUpdates() {
        this.selfUpdates.values().forEach(List::clear);
        this.selfStatValues.values().forEach(List::clear);
        this.otherUpdates.values().forEach(List::clear);
    }
    
    @Nonnull
    public Int2ObjectMap<EntityStatUpdate[]> consumeOtherUpdates() {
        return this.updatesToProtocol(this.otherUpdates);
    }
    
    @Nonnull
    private Int2ObjectOpenHashMap<EntityStatUpdate[]> updatesToProtocol(@Nonnull final Int2ObjectMap<List<EntityStatUpdate>> localUpdates) {
        final Int2ObjectOpenHashMap<EntityStatUpdate[]> updates = new Int2ObjectOpenHashMap<EntityStatUpdate[]>(localUpdates.size());
        final ObjectIterator<Int2ObjectMap.Entry<List<EntityStatUpdate>>> iterator = Int2ObjectMaps.fastIterator(localUpdates);
        while (iterator.hasNext()) {
            final Int2ObjectMap.Entry<List<EntityStatUpdate>> e = iterator.next();
            if (e.getValue().isEmpty()) {
                continue;
            }
            updates.put(e.getIntKey(), (EntityStatUpdate[])e.getValue().toArray(EntityStatUpdate[]::new));
        }
        return updates;
    }
    
    @Nonnull
    public Int2ObjectMap<EntityStatUpdate[]> createInitUpdate(final boolean all) {
        final Int2ObjectOpenHashMap<EntityStatUpdate[]> updates = new Int2ObjectOpenHashMap<EntityStatUpdate[]>(this.size());
        for (int i = 0; i < this.size(); ++i) {
            final EntityStatValue stat = this.get(i);
            if (stat != null) {
                if (EntityStatType.getAssetMap().getAsset(i).isShared() || all) {
                    updates.put(i, new EntityStatUpdate[] { makeInitChange(stat) });
                }
            }
        }
        return updates;
    }
    
    public boolean consumeSelfNetworkOutdated() {
        final boolean temp = this.isSelfNetworkOutdated;
        this.isSelfNetworkOutdated = false;
        return temp;
    }
    
    public boolean consumeNetworkOutdated() {
        final boolean temp = this.isNetworkOutdated;
        this.isNetworkOutdated = false;
        return temp;
    }
    
    private void addInitChange(final int index, @Nonnull final EntityStatValue value) {
        this.addChange(Predictable.NONE, index, EntityStatOp.Init, value.get(), value.get(), value.getModifiers());
    }
    
    private void addChange(final Predictable predictable, final int index, @Nonnull final EntityStatOp op, final float previousValue, final float value) {
        this.addChange(predictable, index, op, previousValue, value, null);
    }
    
    private void addChange(final Predictable predictable, final int index, @Nonnull final EntityStatOp op, final float previousValue, final float value, final Map<String, Modifier> modifierMap) {
        final EntityStatType statType = EntityStatType.getAssetMap().getAsset(index);
        if (statType.isShared()) {
            final boolean isPredictable = predictable == Predictable.ALL;
            final List<EntityStatUpdate> other = this.otherUpdates.computeIfAbsent(index, v -> new ObjectArrayList());
            this.tryMergeUpdate(other, op, value, modifierMap, isPredictable);
            this.isNetworkOutdated = true;
        }
        final boolean isPredictable = predictable != Predictable.NONE;
        final List<EntityStatUpdate> self = this.selfUpdates.computeIfAbsent(index, v -> new ObjectArrayList());
        final FloatList values = this.selfStatValues.computeIfAbsent(index, v -> new FloatArrayList());
        if (this.tryMergeUpdate(self, op, value, modifierMap, isPredictable)) {
            values.set(values.size() - 1, this.get(index).get());
            return;
        }
        values.add(previousValue);
        values.add(this.get(index).get());
        this.isSelfNetworkOutdated = true;
    }
    
    private void addChange(final Predictable predictable, final int index, final EntityStatOp op, final float previousValue, final String key, @Nullable final Modifier modifier) {
        final EntityStatType statType = EntityStatType.getAssetMap().getAsset(index);
        final com.hypixel.hytale.protocol.Modifier modifierPacket = (modifier != null) ? modifier.toPacket() : null;
        if (statType.isShared()) {
            final boolean isPredictable = predictable == Predictable.ALL;
            final List<EntityStatUpdate> other = this.otherUpdates.computeIfAbsent(index, v -> new ObjectArrayList());
            other.add(new EntityStatUpdate(op, isPredictable, 0.0f, null, key, modifierPacket));
            this.isNetworkOutdated = true;
        }
        final boolean isPredictable = predictable != Predictable.NONE;
        final List<EntityStatUpdate> self = this.selfUpdates.computeIfAbsent(index, v -> new ObjectArrayList());
        self.add(new EntityStatUpdate(op, isPredictable, 0.0f, null, key, modifierPacket));
        final FloatList values = this.selfStatValues.computeIfAbsent(index, v -> new FloatArrayList());
        values.add(previousValue);
        values.add(this.get(index).get());
        this.isSelfNetworkOutdated = true;
    }
    
    private boolean tryMergeUpdate(@Nonnull final List<EntityStatUpdate> updates, @Nonnull final EntityStatOp op, final float value, @Nullable final Map<String, Modifier> modifierMap, final boolean isPredictable) {
        final EntityStatUpdate last = updates.isEmpty() ? null : updates.getLast();
        switch (op) {
            case Init: {
                if (!isPredictable && last != null && !last.predictable && last.op == EntityStatOp.Init) {
                    last.value = value;
                    return true;
                }
                Map<String, com.hypixel.hytale.protocol.Modifier> modifiers = null;
                if (modifierMap != null) {
                    modifiers = new Object2ObjectOpenHashMap<String, com.hypixel.hytale.protocol.Modifier>();
                    for (final Map.Entry<String, Modifier> e : modifierMap.entrySet()) {
                        modifiers.put(e.getKey(), e.getValue().toPacket());
                    }
                }
                updates.add(new EntityStatUpdate(op, isPredictable, value, modifiers, null, null));
                return false;
            }
            case Remove: {
                updates.add(new EntityStatUpdate(op, isPredictable, 0.0f, null, null, null));
                break;
            }
            case Add: {
                if (!isPredictable && last != null && !last.predictable && (last.op == EntityStatOp.Init || last.op == EntityStatOp.Add || last.op == EntityStatOp.Set)) {
                    final EntityStatUpdate entityStatUpdate = last;
                    entityStatUpdate.value += value;
                    return true;
                }
                updates.add(new EntityStatUpdate(op, isPredictable, value, null, null, null));
                return false;
            }
            case Set:
            case Minimize:
            case Maximize:
            case Reset: {
                if (!isPredictable && last != null && !last.predictable && last.op != EntityStatOp.Remove) {
                    if (last.op != EntityStatOp.Init) {
                        last.op = op;
                    }
                    last.value = value;
                    return true;
                }
                updates.add(new EntityStatUpdate(op, isPredictable, value, null, null, null));
                return false;
            }
        }
        return false;
    }
    
    public void processStatChanges(final Predictable predictable, @Nonnull final Int2FloatMap entityStats, final ValueType valueType, @Nonnull final ChangeStatBehaviour changeStatBehaviour) {
        for (final Int2FloatMap.Entry entry : entityStats.int2FloatEntrySet()) {
            final int statIndex = entry.getIntKey();
            float amount = entry.getFloatValue();
            if (valueType == ValueType.Percent) {
                final EntityStatValue stat = this.get(statIndex);
                if (stat == null) {
                    continue;
                }
                amount = amount * (stat.getMax() - stat.getMin()) / 100.0f;
            }
            switch (changeStatBehaviour) {
                case Set: {
                    this.setStatValue(predictable, statIndex, amount);
                    continue;
                }
                case Add: {
                    this.addStatValue(predictable, statIndex, amount);
                    continue;
                }
            }
        }
    }
    
    @Nonnull
    @Override
    public String toString() {
        return "EntityStatMap{unknown=" + String.valueOf(this.unknown) + "values=" + Arrays.toString(this.values);
    }
    
    @Nonnull
    @Override
    public EntityStatMap clone() {
        final EntityStatMap map = new EntityStatMap();
        map.unknown = this.unknown;
        map.update();
        for (int i = 0; i < this.values.length; ++i) {
            map.values[i].set(this.values[i].get());
        }
        map.selfUpdates.putAll((Map<?, ?>)this.selfUpdates);
        map.selfStatValues.putAll((Map<?, ?>)this.selfStatValues);
        map.otherUpdates.putAll((Map<?, ?>)this.otherUpdates);
        return map;
    }
    
    @Nonnull
    private static EntityStatUpdate makeInitChange(@Nonnull final EntityStatValue value) {
        Map<String, com.hypixel.hytale.protocol.Modifier> modifiers = null;
        if (value.getModifiers() != null) {
            modifiers = new Object2ObjectOpenHashMap<String, com.hypixel.hytale.protocol.Modifier>();
            for (final Map.Entry<String, Modifier> e : value.getModifiers().entrySet()) {
                modifiers.put(e.getKey(), e.getValue().toPacket());
            }
        }
        return new EntityStatUpdate(EntityStatOp.Init, false, value.get(), modifiers, null, null);
    }
    
    public static Int2ObjectMap<com.hypixel.hytale.protocol.Modifier[]> toPacket(@Nullable final Int2ObjectMap<StaticModifier[]> modifiers) {
        if (modifiers == null) {
            return null;
        }
        final Int2ObjectOpenHashMap<com.hypixel.hytale.protocol.Modifier[]> packet = new Int2ObjectOpenHashMap<com.hypixel.hytale.protocol.Modifier[]>(modifiers.size());
        for (final Int2ObjectMap.Entry<StaticModifier[]> e : modifiers.int2ObjectEntrySet()) {
            final com.hypixel.hytale.protocol.Modifier[] out = new com.hypixel.hytale.protocol.Modifier[((StaticModifier[])e.getValue()).length];
            for (int i = 0; i < out.length; ++i) {
                out[i] = ((StaticModifier[])e.getValue())[i].toPacket();
            }
            packet.put(e.getIntKey(), out);
        }
        return packet;
    }
    
    static {
        // 
        // This method could not be decompiled.
        // 
        // Original Bytecode:
        // 
        //     2: invokedynamic   BootstrapMethod #12, get:()Ljava/util/function/Supplier;
        //     7: invokestatic    com/hypixel/hytale/codec/builder/BuilderCodec.builder:(Ljava/lang/Class;Ljava/util/function/Supplier;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //    10: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.legacyVersioned:()Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
        //    13: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //    16: iconst_5       
        //    17: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.codecVersion:(I)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
        //    20: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //    23: new             Lcom/hypixel/hytale/codec/KeyedCodec;
        //    26: dup            
        //    27: ldc_w           "Stats"
        //    30: new             Lcom/hypixel/hytale/codec/codecs/map/MapCodec;
        //    33: dup            
        //    34: getstatic       com/hypixel/hytale/server/core/modules/entitystats/EntityStatValue.CODEC:Lcom/hypixel/hytale/codec/builder/BuilderCodec;
        //    37: invokedynamic   BootstrapMethod #13, get:()Ljava/util/function/Supplier;
        //    42: iconst_0       
        //    43: invokespecial   com/hypixel/hytale/codec/codecs/map/MapCodec.<init>:(Lcom/hypixel/hytale/codec/Codec;Ljava/util/function/Supplier;Z)V
        //    46: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
        //    49: invokedynamic   BootstrapMethod #14, accept:()Ljava/util/function/BiConsumer;
        //    54: invokedynamic   BootstrapMethod #15, apply:()Ljava/util/function/Function;
        //    59: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
        //    62: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //    65: invokedynamic   BootstrapMethod #16, accept:()Ljava/util/function/Consumer;
        //    70: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.afterDecode:(Ljava/util/function/Consumer;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
        //    73: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
        //    76: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.build:()Lcom/hypixel/hytale/codec/builder/BuilderCodec;
        //    79: putstatic       com/hypixel/hytale/server/core/modules/entitystats/EntityStatMap.CODEC:Lcom/hypixel/hytale/codec/builder/BuilderCodec;
        //    82: return         
        // 
        // The error that occurred was:
        // 
        // java.lang.UnsupportedOperationException: The requested operation is not supported.
        //     at com.strobel.util.ContractUtils.unsupported(ContractUtils.java:27)
        //     at com.strobel.assembler.metadata.TypeReference.getRawType(TypeReference.java:284)
        //     at com.strobel.assembler.metadata.TypeReference.getRawType(TypeReference.java:279)
        //     at com.strobel.assembler.metadata.TypeReference.makeGenericType(TypeReference.java:154)
        //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitParameterizedType(TypeSubstitutionVisitor.java:225)
        //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitParameterizedType(TypeSubstitutionVisitor.java:25)
        //     at com.strobel.assembler.metadata.ParameterizedType.accept(ParameterizedType.java:103)
        //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visit(TypeSubstitutionVisitor.java:40)
        //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitMethod(TypeSubstitutionVisitor.java:314)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2611)
        //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
        //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:790)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2689)
        //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
        //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:790)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2689)
        //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
        //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1083)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
        //     at com.strobel.decompiler.ast.TypeAnalysis.runInference(TypeAnalysis.java:684)
        //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypesForVariables(TypeAnalysis.java:593)
        //     at com.strobel.decompiler.ast.TypeAnalysis.runInference(TypeAnalysis.java:405)
        //     at com.strobel.decompiler.ast.TypeAnalysis.run(TypeAnalysis.java:95)
        //     at com.strobel.decompiler.ast.AstOptimizer.optimize(AstOptimizer.java:109)
        //     at com.strobel.decompiler.ast.AstOptimizer.optimize(AstOptimizer.java:42)
        //     at com.strobel.decompiler.languages.java.ast.AstMethodBodyBuilder.createMethodBody(AstMethodBodyBuilder.java:206)
        //     at com.strobel.decompiler.languages.java.ast.AstMethodBodyBuilder.createMethodBody(AstMethodBodyBuilder.java:93)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createMethodBody(AstBuilder.java:868)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createMethod(AstBuilder.java:761)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.addTypeMembers(AstBuilder.java:638)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeCore(AstBuilder.java:605)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeNoCache(AstBuilder.java:195)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createType(AstBuilder.java:162)
        //     at com.strobel.decompiler.languages.java.ast.AstBuilder.addType(AstBuilder.java:137)
        //     at com.strobel.decompiler.languages.java.JavaLanguage.buildAst(JavaLanguage.java:71)
        //     at com.strobel.decompiler.languages.java.JavaLanguage.decompileType(JavaLanguage.java:59)
        //     at com.strobel.decompiler.DecompilerDriver.decompileType(DecompilerDriver.java:333)
        //     at com.strobel.decompiler.DecompilerDriver.decompileJar(DecompilerDriver.java:254)
        //     at com.strobel.decompiler.DecompilerDriver.main(DecompilerDriver.java:129)
        // 
        throw new IllegalStateException("An error occurred while decompiling this method.");
    }
    
    public enum Predictable
    {
        NONE, 
        SELF, 
        ALL;
    }
}
