// Path: src/main/java/net/darkhax/darkutils/DarkUtils.java
// @Mod(DarkUtils.MOD_ID)
// public class DarkUtils {
//     
//     public static final String MOD_ID = "darkutils";
//     
//     public static final String MOD_NAME = "Dark Utilities";
//     
//     public static final Logger LOG = LogManager.getLogger(MOD_NAME);
//     
//     public static final ItemGroup ITEM_GROUP = new ItemGroupBase(MOD_ID, () -> new ItemStack(DarkUtils.content.vectorPlate));
//     
//     public static final NetworkHelper NETWORK = new NetworkHelper(new ResourceLocation(MOD_ID, "main"), "2.0.X");
//     
//     public static RegistryHelper registry;
//     
//     public static Content content;
//     
//     public static AddonManager addons;
//     
//     public DarkUtils() {
//         
//         registry = DistExecutor.runForDist( () -> () -> new RegistryHelperClient(MOD_ID, LOG, ITEM_GROUP), () -> () -> new RegistryHelper(MOD_ID, LOG, ITEM_GROUP));
//         content = DistExecutor.runForDist( () -> () -> new ContentClient(registry), () -> () -> new Content(registry));
//         NETWORK.registerEnqueuedMessage(MessageSyncCrucibleType.class, NetworkHandlerServer::encodeStageMessage, t -> NetworkHandlerClient.decodeStageMessage(t), (t, u) -> NetworkHandlerClient.processSyncStagesMessage(t, u));
//         registry.initialize(FMLJavaModLoadingContext.get().getModEventBus());
//         
//         // Addons
//         addons = new AddonManager();
//     }
// }


import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import javax.annotation.Nullable;
import net.darkhax.darkutils.DarkUtils;
import net.minecraft.block.BlockState;
import net.minecraft.entity.monster.SlimeEntity;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.world.World;
package net.darkhax.darkutils.features.slimecrucible;




public class SlimeCrucibleType {
    
    /**
     * An internal map that holds all known slime types. Entries will be added to this map
     * automatically when they are constructed. To retrieve an entry use
     * {@link #getType(ResourceLocation)}.
     */
    private static final Map<ResourceLocation, SlimeCrucibleType> REGISTRY_MAP = new HashMap<>();
    
    /**
     * Gets the ID of the entity. This is used for serialization of types in recipes.
     */
    private final ResourceLocation id;
    
    /**
     * The sound event to play when an item is crafted by a crucible of the type.
     */
    private final SoundEvent craftingSound;
    
    /**
     * The sound event to play when a slime is fed a food it likes, or whenever the slime is
     * happy.
     */
    private final SoundEvent happySound;
    
    /**
     * The default name for the crucible's container GUI.
     */
    private final ITextComponent containerName;
    
    /**
     * The name of the material generated by the slime crucible.
     */
    private final ITextComponent materialName;
    
    /**
     * The maximum number of slime that can be held by a crucible.
     */
    private final int maxSlimePoints;
    
    /**
     * A color used in the slime crucible when the mouse is over a potential recipe.
     */
    private final int overlayColor;
    
    /**
     * A function that is used to build the slime in the crucible. This is primarily used on
     * the client for the tile entity renderer but can safely be used on both sides.
     */
    private final Function<World, SlimeEntity> entityBuilder;
    
    public SlimeCrucibleType(ResourceLocation id, int maxSlimePoints, Function<World, SlimeEntity> entityBuilder, SoundEvent craftingSound, SoundEvent happySound, int overlayColor) {
        
        this.id = id;
        this.maxSlimePoints = maxSlimePoints;
        this.entityBuilder = entityBuilder;
        this.craftingSound = craftingSound;
        this.happySound = happySound;
        this.overlayColor = overlayColor;
        this.containerName = new TranslationTextComponent("container." + id.getNamespace() + ".slime_crucible." + id.getPath());
        this.materialName = new TranslationTextComponent("tooltips." + id.getNamespace() + ".slime_crucible.material." + id.getPath());
        REGISTRY_MAP.put(id, this);
    }
    
    /**
     * Gets the registry name used by the slime type. This should be usable with
     * {@link #getType(ResourceLocation)} to provide the same object.
     * 
     * @return The registry name for the slime type.
     */
    public ResourceLocation getRegistryName () {
        
        return this.id;
    }
    
    /**
     * Creates the slime entity represented by this type. Note that ALL is an internal type
     * used for matching and will try to crash if you call this on it.
     * 
     * @param world An instance of the world. The entity will not be spawned into the world,
     *        but is required for constructing entity objects.
     * @return A slime entity that this type represents.
     */
    public SlimeEntity createSlime (World world) {
        
        if (this.entityBuilder == null) {
            
// Path: src/main/java/net/darkhax/darkutils/DarkUtils.java
// @Mod(DarkUtils.MOD_ID)
// public class DarkUtils {
//     
//     public static final String MOD_ID = "darkutils";
//     
//     public static final String MOD_NAME = "Dark Utilities";
//     
//     public static final Logger LOG = LogManager.getLogger(MOD_NAME);
//     
//     public static final ItemGroup ITEM_GROUP = new ItemGroupBase(MOD_ID, () -> new ItemStack(DarkUtils.content.vectorPlate));
//     
//     public static final NetworkHelper NETWORK = new NetworkHelper(new ResourceLocation(MOD_ID, "main"), "2.0.X");
//     
//     public static RegistryHelper registry;
//     
//     public static Content content;
//     
//     public static AddonManager addons;
//     
//     public DarkUtils() {
//         
//         registry = DistExecutor.runForDist( () -> () -> new RegistryHelperClient(MOD_ID, LOG, ITEM_GROUP), () -> () -> new RegistryHelper(MOD_ID, LOG, ITEM_GROUP));
//         content = DistExecutor.runForDist( () -> () -> new ContentClient(registry), () -> () -> new Content(registry));
//         NETWORK.registerEnqueuedMessage(MessageSyncCrucibleType.class, NetworkHandlerServer::encodeStageMessage, t -> NetworkHandlerClient.decodeStageMessage(t), (t, u) -> NetworkHandlerClient.processSyncStagesMessage(t, u));
//         registry.initialize(FMLJavaModLoadingContext.get().getModEventBus());
//         
//         // Addons
//         addons = new AddonManager();
//     }
// }


// Path: src/main/java/net/darkhax/darkutils/features/slimecrucible/SlimeCrucibleType.java
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import javax.annotation.Nullable;
import net.darkhax.darkutils.DarkUtils;
import net.minecraft.block.BlockState;
import net.minecraft.entity.monster.SlimeEntity;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.world.World;

package net.darkhax.darkutils.features.slimecrucible;




public class SlimeCrucibleType {
    
    /**
     * An internal map that holds all known slime types. Entries will be added to this map
     * automatically when they are constructed. To retrieve an entry use
     * {@link #getType(ResourceLocation)}.
     */
    private static final Map<ResourceLocation, SlimeCrucibleType> REGISTRY_MAP = new HashMap<>();
    
    /**
     * Gets the ID of the entity. This is used for serialization of types in recipes.
     */
    private final ResourceLocation id;
    
    /**
     * The sound event to play when an item is crafted by a crucible of the type.
     */
    private final SoundEvent craftingSound;
    
    /**
     * The sound event to play when a slime is fed a food it likes, or whenever the slime is
     * happy.
     */
    private final SoundEvent happySound;
    
    /**
     * The default name for the crucible's container GUI.
     */
    private final ITextComponent containerName;
    
    /**
     * The name of the material generated by the slime crucible.
     */
    private final ITextComponent materialName;
    
    /**
     * The maximum number of slime that can be held by a crucible.
     */
    private final int maxSlimePoints;
    
    /**
     * A color used in the slime crucible when the mouse is over a potential recipe.
     */
    private final int overlayColor;
    
    /**
     * A function that is used to build the slime in the crucible. This is primarily used on
     * the client for the tile entity renderer but can safely be used on both sides.
     */
    private final Function<World, SlimeEntity> entityBuilder;
    
    public SlimeCrucibleType(ResourceLocation id, int maxSlimePoints, Function<World, SlimeEntity> entityBuilder, SoundEvent craftingSound, SoundEvent happySound, int overlayColor) {
        
        this.id = id;
        this.maxSlimePoints = maxSlimePoints;
        this.entityBuilder = entityBuilder;
        this.craftingSound = craftingSound;
        this.happySound = happySound;
        this.overlayColor = overlayColor;
        this.containerName = new TranslationTextComponent("container." + id.getNamespace() + ".slime_crucible." + id.getPath());
        this.materialName = new TranslationTextComponent("tooltips." + id.getNamespace() + ".slime_crucible.material." + id.getPath());
        REGISTRY_MAP.put(id, this);
    }
    
    /**
     * Gets the registry name used by the slime type. This should be usable with
     * {@link #getType(ResourceLocation)} to provide the same object.
     * 
     * @return The registry name for the slime type.
     */
    public ResourceLocation getRegistryName () {
        
        return this.id;
    }
    
    /**
     * Creates the slime entity represented by this type. Note that ALL is an internal type
     * used for matching and will try to crash if you call this on it.
     * 
     * @param world An instance of the world. The entity will not be spawned into the world,
     *        but is required for constructing entity objects.
     * @return A slime entity that this type represents.
     */
    public SlimeEntity createSlime (World world) {
        
        if (this.entityBuilder == null) {
            
            throw new IllegalArgumentException(this == DarkUtils.content.crucibleTypeAll ? "Someone tried to create an instance of the ALL slime type. This is an unsupported operation." : "The slime type " + this.id + " does not have an entityBuilder. This is not allowed.");