2013-05-23 01:01:19 -04:00
package net.minecraftforge.fluids ;
import java.util.Arrays ;
import java.util.HashMap ;
import java.util.HashSet ;
import java.util.List ;
import java.util.Map ;
import java.util.Set ;
2014-01-29 18:34:23 -08:00
import com.google.common.collect.Maps ;
import com.google.common.collect.Sets ;
2015-04-10 20:09:58 -04:00
import cpw.mods.fml.common.FMLLog ;
2013-12-16 20:18:48 -05:00
import cpw.mods.fml.common.eventhandler.Event ;
2013-12-12 23:32:18 -08:00
import net.minecraft.init.Items ;
2013-05-23 01:01:19 -04:00
import net.minecraft.item.Item ;
import net.minecraft.item.ItemStack ;
import net.minecraftforge.common.MinecraftForge ;
/**
* Register simple items that contain fluids here. Useful for buckets, bottles, and things that have
* ID/metadata mappings.
2015-04-05 16:13:17 -04:00
*
2013-05-23 01:01:19 -04:00
* For more complex items, use {@link IFluidContainerItem} instead.
2015-04-05 16:13:17 -04:00
*
2013-05-23 01:01:19 -04:00
* @author King Lemming
2015-04-05 16:13:17 -04:00
*
2013-05-23 01:01:19 -04:00
*/
2013-07-16 21:40:49 -07:00
public abstract class FluidContainerRegistry
{
2015-04-05 16:13:17 -04:00
// Holder object that implements HashCode for an ItemStack,
// the local maps are not guaranteed to have the same internal generic structure,
2014-01-29 18:34:23 -08:00
// but the external interface for checking ItemStacks will still exist.
private static class ContainerKey
{
ItemStack container ;
2015-03-25 01:27:15 -04:00
FluidStack stack ;
2014-01-29 18:34:23 -08:00
private ContainerKey ( ItemStack container )
{
this . container = container ;
}
2015-03-25 01:27:15 -04:00
private ContainerKey ( ItemStack container , FluidStack stack )
2014-01-29 18:34:23 -08:00
{
this ( container );
2015-03-25 01:27:15 -04:00
this . stack = stack ;
2014-01-29 18:34:23 -08:00
}
@Override
public int hashCode ()
{
int code = 1 ;
2014-02-23 16:56:16 -08:00
code = 31 * code + container . getItem (). hashCode ();
2014-01-29 18:34:23 -08:00
code = 31 * code + container . getItemDamage ();
2015-03-25 01:27:15 -04:00
if ( stack != null )
2015-04-10 16:38:45 -04:00
code = 31 * code + stack . fluid . hashCode ();
2014-01-29 18:34:23 -08:00
return code ;
}
2014-03-10 22:51:31 -07:00
@Override
public boolean equals ( Object o )
{
2014-03-10 23:27:30 -07:00
if ( ! ( o instanceof ContainerKey )) return false ;
ContainerKey ck = ( ContainerKey ) o ;
if ( container . getItem () != ck . container . getItem ()) return false ;
if ( container . getItemDamage () != ck . container . getItemDamage ()) return false ;
2015-03-25 01:27:15 -04:00
if ( stack == null && ck . stack != null ) return false ;
if ( stack != null && ck . stack == null ) return false ;
if ( stack == null && ck . stack == null ) return true ;
if ( stack . fluid != ck . stack . fluid ) return false ;
2014-03-10 23:27:30 -07:00
return true ;
2014-03-10 22:51:31 -07:00
}
2014-01-29 18:34:23 -08:00
}
private static Map < ContainerKey , FluidContainerData > containerFluidMap = Maps . newHashMap ();
private static Map < ContainerKey , FluidContainerData > filledContainerMap = Maps . newHashMap ();
private static Set < ContainerKey > emptyContainers = Sets . newHashSet ();
2013-05-23 01:01:19 -04:00
public static final int BUCKET_VOLUME = 1000 ;
2013-12-12 23:32:18 -08:00
public static final ItemStack EMPTY_BUCKET = new ItemStack ( Items . bucket );
public static final ItemStack EMPTY_BOTTLE = new ItemStack ( Items . glass_bottle );
private static final ItemStack NULL_EMPTYCONTAINER = new ItemStack ( Items . bucket );
2013-05-23 01:01:19 -04:00
2013-07-16 21:40:49 -07:00
static
{
2013-12-12 23:32:18 -08:00
registerFluidContainer ( FluidRegistry . WATER , new ItemStack ( Items . water_bucket ), EMPTY_BUCKET );
registerFluidContainer ( FluidRegistry . LAVA , new ItemStack ( Items . lava_bucket ), EMPTY_BUCKET );
registerFluidContainer ( FluidRegistry . WATER , new ItemStack ( Items . potionitem ), EMPTY_BOTTLE );
2013-05-23 01:01:19 -04:00
}
2013-07-16 21:40:49 -07:00
private FluidContainerRegistry (){}
2013-05-23 01:01:19 -04:00
/**
* Register a new fluid containing item.
2015-04-05 16:13:17 -04:00
*
2013-05-23 01:01:19 -04:00
* @param stack
* FluidStack containing the type and amount of the fluid stored in the item.
* @param filledContainer
* ItemStack representing the container when it is full.
* @param emptyContainer
* ItemStack representing the container when it is empty.
* @return True if container was successfully registered; false if it already is.
2014-01-29 18:34:23 -08:00
*/
2013-07-16 21:40:49 -07:00
public static boolean registerFluidContainer ( FluidStack stack , ItemStack filledContainer , ItemStack emptyContainer )
{
2013-05-23 01:01:19 -04:00
return registerFluidContainer ( new FluidContainerData ( stack , filledContainer , emptyContainer ));
}
/**
* Register a new fluid containing item. The item is assumed to hold 1000 mB of fluid. Also
* registers the Fluid if possible.
2015-04-05 16:13:17 -04:00
*
2013-05-23 01:01:19 -04:00
* @param fluid
* Fluid type that is stored in the item.
* @param filledContainer
* ItemStack representing the container when it is full.
* @param emptyContainer
* ItemStack representing the container when it is empty.
2015-04-10 20:09:58 -04:00
* @return True if container was successfully registered; false if it already is, or an invalid parameter was passed.
2014-01-29 18:34:23 -08:00
*/
2013-07-16 21:40:49 -07:00
public static boolean registerFluidContainer ( Fluid fluid , ItemStack filledContainer , ItemStack emptyContainer )
{
if ( ! FluidRegistry . isFluidRegistered ( fluid ))
{
2013-05-23 01:01:19 -04:00
FluidRegistry . registerFluid ( fluid );
}
return registerFluidContainer ( new FluidStack ( fluid , BUCKET_VOLUME ), filledContainer , emptyContainer );
}
/**
* Register a new fluid containing item that does not have an empty container.
2015-04-05 16:13:17 -04:00
*
2013-05-23 01:01:19 -04:00
* @param stack
* FluidStack containing the type and amount of the fluid stored in the item.
* @param filledContainer
* ItemStack representing the container when it is full.
2015-04-10 20:09:58 -04:00
* @return True if container was successfully registered; false if it already is, or an invalid parameter was passed.
2014-01-29 18:34:23 -08:00
*/
2013-07-16 21:40:49 -07:00
public static boolean registerFluidContainer ( FluidStack stack , ItemStack filledContainer )
{
2013-05-23 01:01:19 -04:00
return registerFluidContainer ( new FluidContainerData ( stack , filledContainer , null , true ));
}
/**
* Register a new fluid containing item that does not have an empty container. The item is
* assumed to hold 1000 mB of fluid. Also registers the Fluid if possible.
2015-04-05 16:13:17 -04:00
*
2013-05-23 01:01:19 -04:00
* @param fluid
* Fluid type that is stored in the item.
* @param filledContainer
* ItemStack representing the container when it is full.
2015-04-10 20:09:58 -04:00
* @return True if container was successfully registered; false if it already is, or an invalid parameter was passed.
2014-01-29 18:34:23 -08:00
*/
2013-07-16 21:40:49 -07:00
public static boolean registerFluidContainer ( Fluid fluid , ItemStack filledContainer )
{
if ( ! FluidRegistry . isFluidRegistered ( fluid ))
{
2013-05-23 01:01:19 -04:00
FluidRegistry . registerFluid ( fluid );
}
return registerFluidContainer ( new FluidStack ( fluid , BUCKET_VOLUME ), filledContainer );
}
/**
* Register a new fluid containing item.
2015-04-05 16:13:17 -04:00
*
2013-05-23 01:01:19 -04:00
* @param data
* See {@link FluidContainerData}.
2015-04-10 20:09:58 -04:00
* @return True if container was successfully registered; false if it already is, or an invalid parameter was passed.
2014-01-29 18:34:23 -08:00
*/
2013-07-16 21:40:49 -07:00
public static boolean registerFluidContainer ( FluidContainerData data )
{
2015-04-10 20:09:58 -04:00
if ( isFilledContainer ( data . filledContainer ) || data . filledContainer == null )
2013-07-16 21:40:49 -07:00
{
2013-05-23 01:01:19 -04:00
return false ;
}
2015-04-10 20:09:58 -04:00
if ( data . fluid == null || data . fluid . getFluid () == null )
{
FMLLog . bigWarning ( "Invalid registration attempt for a fluid container item %s (type %s) has occurred. The registration has been denied to prevent crashes. The mod responsible for the registration needs to correct this." , data . filledContainer . getItem (). getUnlocalizedName ( data . filledContainer ));
return false ;
}
2014-01-29 18:34:23 -08:00
containerFluidMap . put ( new ContainerKey ( data . filledContainer ), data );
2013-05-23 01:01:19 -04:00
2013-08-28 22:16:59 -04:00
if ( data . emptyContainer != null && data . emptyContainer != NULL_EMPTYCONTAINER )
2013-07-16 21:40:49 -07:00
{
2014-01-29 18:34:23 -08:00
filledContainerMap . put ( new ContainerKey ( data . emptyContainer , data . fluid ), data );
emptyContainers . add ( new ContainerKey ( data . emptyContainer ));
2013-05-23 01:01:19 -04:00
}
2013-07-16 21:40:49 -07:00
2013-05-23 01:01:19 -04:00
MinecraftForge . EVENT_BUS . post ( new FluidContainerRegisterEvent ( data ));
return true ;
}
/**
* Determines the fluid type and amount inside a container.
2015-04-05 16:13:17 -04:00
*
2013-05-23 01:01:19 -04:00
* @param container
* The fluid container.
* @return FluidStack representing stored fluid.
2014-01-29 18:34:23 -08:00
*/
2013-07-16 21:40:49 -07:00
public static FluidStack getFluidForFilledItem ( ItemStack container )
{
if ( container == null )
{
2013-05-23 01:01:19 -04:00
return null ;
}
2013-07-16 21:40:49 -07:00
2014-01-29 18:34:23 -08:00
FluidContainerData data = containerFluidMap . get ( new ContainerKey ( container ));
2013-05-23 01:01:19 -04:00
return data == null ? null : data . fluid . copy ();
}
/**
* Attempts to fill an empty container with a fluid.
2015-04-05 16:13:17 -04:00
*
2013-05-23 01:01:19 -04:00
* NOTE: Returns null on fail, NOT the empty container.
2015-04-05 16:13:17 -04:00
*
2013-05-23 01:01:19 -04:00
* @param fluid
* FluidStack containing the type and amount of fluid to fill.
* @param container
* ItemStack representing the empty container.
* @return Filled container if successful, otherwise null.
2014-01-29 18:34:23 -08:00
*/
2013-07-16 21:40:49 -07:00
public static ItemStack fillFluidContainer ( FluidStack fluid , ItemStack container )
{
if ( container == null || fluid == null )
{
2013-05-23 01:01:19 -04:00
return null ;
}
2013-07-16 21:40:49 -07:00
2014-01-29 18:34:23 -08:00
FluidContainerData data = filledContainerMap . get ( new ContainerKey ( container , fluid ));
2013-07-16 21:40:49 -07:00
if ( data != null && fluid . amount >= data . fluid . amount )
{
2013-05-23 01:01:19 -04:00
return data . filledContainer . copy ();
}
return null ;
}
2014-07-29 23:16:32 +02:00
/**
* Attempts to empty a full container.
2015-04-05 16:13:17 -04:00
*
2014-07-29 23:16:32 +02:00
* @param container
* ItemStack representing the full container.
* @return Empty container if successful, otherwise null.
*/
public static ItemStack drainFluidContainer ( ItemStack container )
{
if ( container == null )
{
return null ;
}
FluidContainerData data = containerFluidMap . get ( new ContainerKey ( container ));
if ( data != null )
{
return data . emptyContainer . copy ();
}
return null ;
}
/**
* Determines the capacity of a full container.
2015-04-05 16:13:17 -04:00
*
2014-07-29 23:16:32 +02:00
* @param container
* The full container.
* @return The containers capacity, or 0 if the ItemStack does not represent
* a registered container.
*/
public static int getContainerCapacity ( ItemStack container )
{
return getContainerCapacity ( null , container );
}
/**
* Determines the capacity of a container.
2015-04-05 16:13:17 -04:00
*
2014-07-29 23:16:32 +02:00
* @param fluid
* FluidStack containing the type of fluid the capacity should be
* determined for (ignored for full containers).
* @param container
* The container (full or empty).
* @return The containers capacity, or 0 if the ItemStack does not represent
* a registered container or the FluidStack is not registered with
* the empty container.
*/
public static int getContainerCapacity ( FluidStack fluid , ItemStack container )
{
if ( container == null )
{
return 0 ;
}
FluidContainerData data = containerFluidMap . get ( new ContainerKey ( container ));
if ( data != null )
{
return data . fluid . amount ;
}
if ( fluid != null )
{
data = filledContainerMap . get ( new ContainerKey ( container , fluid ));
if ( data != null )
{
return data . fluid . amount ;
}
}
return 0 ;
}
2013-05-23 01:01:19 -04:00
/**
* Determines if a container holds a specific fluid.
2014-01-29 18:34:23 -08:00
*/
2013-07-16 21:40:49 -07:00
public static boolean containsFluid ( ItemStack container , FluidStack fluid )
{
if ( container == null || fluid == null )
{
2013-05-23 01:01:19 -04:00
return false ;
}
2013-07-16 21:40:49 -07:00
2014-02-10 15:29:36 -08:00
FluidContainerData data = containerFluidMap . get ( new ContainerKey ( container ));
return data == null ? false : data . fluid . containsFluid ( fluid );
2013-05-23 01:01:19 -04:00
}
2013-07-16 21:40:49 -07:00
public static boolean isBucket ( ItemStack container )
{
if ( container == null )
{
2013-05-23 01:01:19 -04:00
return false ;
}
2013-07-16 21:40:49 -07:00
if ( container . isItemEqual ( EMPTY_BUCKET ))
{
2013-05-23 01:01:19 -04:00
return true ;
}
2013-07-16 21:40:49 -07:00
2014-01-29 18:34:23 -08:00
FluidContainerData data = containerFluidMap . get ( new ContainerKey ( container ));
2013-05-23 01:01:19 -04:00
return data != null && data . emptyContainer . isItemEqual ( EMPTY_BUCKET );
}
2013-07-16 21:40:49 -07:00
public static boolean isContainer ( ItemStack container )
{
2013-05-23 01:01:19 -04:00
return isEmptyContainer ( container ) || isFilledContainer ( container );
}
2013-07-16 21:40:49 -07:00
public static boolean isEmptyContainer ( ItemStack container )
{
2014-01-29 18:34:23 -08:00
return container != null && emptyContainers . contains ( new ContainerKey ( container ));
2013-05-23 01:01:19 -04:00
}
2013-07-16 21:40:49 -07:00
public static boolean isFilledContainer ( ItemStack container )
{
2013-05-23 01:01:19 -04:00
return container != null && getFluidForFilledItem ( container ) != null ;
}
2013-07-16 21:40:49 -07:00
public static FluidContainerData [] getRegisteredFluidContainerData ()
{
2013-07-08 18:54:03 -07:00
return containerFluidMap . values (). toArray ( new FluidContainerData [ containerFluidMap . size () ] );
2013-05-23 01:01:19 -04:00
}
/**
* Wrapper class for the registry entries. Ensures that none of the attempted registrations
* contain null references unless permitted.
2014-01-29 18:34:23 -08:00
*/
2013-07-16 21:40:49 -07:00
public static class FluidContainerData
{
2013-05-23 01:01:19 -04:00
public final FluidStack fluid ;
public final ItemStack filledContainer ;
public final ItemStack emptyContainer ;
2013-07-16 21:40:49 -07:00
public FluidContainerData ( FluidStack stack , ItemStack filledContainer , ItemStack emptyContainer )
{
2013-05-23 01:01:19 -04:00
this ( stack , filledContainer , emptyContainer , false );
}
2013-07-16 21:40:49 -07:00
public FluidContainerData ( FluidStack stack , ItemStack filledContainer , ItemStack emptyContainer , boolean nullEmpty )
{
2013-05-23 01:01:19 -04:00
this . fluid = stack ;
this . filledContainer = filledContainer ;
2013-08-28 22:16:59 -04:00
this . emptyContainer = emptyContainer == null ? NULL_EMPTYCONTAINER : emptyContainer ;
2013-05-23 01:01:19 -04:00
2013-07-16 21:40:49 -07:00
if ( stack == null || filledContainer == null || emptyContainer == null && ! nullEmpty )
{
2013-05-23 01:01:19 -04:00
throw new RuntimeException ( "Invalid FluidContainerData - a parameter was null." );
}
}
2013-07-16 21:40:49 -07:00
public FluidContainerData copy ()
{
2013-05-23 01:01:19 -04:00
return new FluidContainerData ( fluid , filledContainer , emptyContainer , true );
}
}
2013-07-16 21:40:49 -07:00
public static class FluidContainerRegisterEvent extends Event
{
2013-05-23 01:01:19 -04:00
public final FluidContainerData data ;
2013-07-16 21:40:49 -07:00
public FluidContainerRegisterEvent ( FluidContainerData data )
{
2013-05-23 01:01:19 -04:00
this . data = data . copy ();
}
}
}