Milking can't be done too often
Period depends on animal type.
This commit is contained in:
parent
444e020ae0
commit
8ed83d6629
6 changed files with 350 additions and 75 deletions
|
@ -32,11 +32,14 @@ public class FMilkType
|
||||||
|
|
||||||
COW = new FMilkType( );
|
COW = new FMilkType( );
|
||||||
SHEEP = new FMilkType( "sheep" , EntitySheep.class );
|
SHEEP = new FMilkType( "sheep" , EntitySheep.class );
|
||||||
PIG = new FMilkType( "pig" , EntityPig.class );
|
PIG = new FMilkType( "pig" , EntityPig.class ) //
|
||||||
HORSE = new FMilkType( "horse" , EntityHorse.class )
|
.setPeriod( 48000 );
|
||||||
.setExtraCheck( a -> ( (EntityHorse) a ).getType( ) == HorseType.HORSE );
|
HORSE = new FMilkType( "horse" , EntityHorse.class ) //
|
||||||
|
.setExtraCheck( a -> ( (EntityHorse) a ).getType( ) == HorseType.HORSE ) //
|
||||||
|
.setPeriod( 24000 );
|
||||||
DONKEY = new FMilkType( "donkey" , EntityHorse.class )
|
DONKEY = new FMilkType( "donkey" , EntityHorse.class )
|
||||||
.setExtraCheck( a -> ( (EntityHorse) a ).getType( ) == HorseType.DONKEY );
|
.setExtraCheck( a -> ( (EntityHorse) a ).getType( ) == HorseType.DONKEY ) //
|
||||||
|
.setPeriod( 36000 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,6 +52,7 @@ public class FMilkType
|
||||||
public final boolean isVanilla;
|
public final boolean isVanilla;
|
||||||
public final Class< ? extends EntityAnimal > animal;
|
public final Class< ? extends EntityAnimal > animal;
|
||||||
public final Item bucket;
|
public final Item bucket;
|
||||||
|
private int period = 12000;
|
||||||
private Predicate< EntityAnimal > extraCheck;
|
private Predicate< EntityAnimal > extraCheck;
|
||||||
|
|
||||||
|
|
||||||
|
@ -86,6 +90,19 @@ public class FMilkType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int getPeriod( )
|
||||||
|
{
|
||||||
|
return period;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public FMilkType setPeriod( int period )
|
||||||
|
{
|
||||||
|
this.period = period;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean check( final EntityAnimal animal )
|
public boolean check( final EntityAnimal animal )
|
||||||
{
|
{
|
||||||
return this.extraCheck == null || this.extraCheck.test( animal );
|
return this.extraCheck == null || this.extraCheck.test( animal );
|
||||||
|
|
273
src/java/mmm/food/FMilkable.java
Normal file
273
src/java/mmm/food/FMilkable.java
Normal file
|
@ -0,0 +1,273 @@
|
||||||
|
package mmm.food;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import mmm.Mmm;
|
||||||
|
import mmm.utils.I_UMessage;
|
||||||
|
import mmm.utils.URegistry;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.passive.EntityAnimal;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
|
import net.minecraft.init.Items;
|
||||||
|
import net.minecraft.init.SoundEvents;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.nbt.NBTBase;
|
||||||
|
import net.minecraft.nbt.NBTTagLong;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.common.capabilities.Capability;
|
||||||
|
import net.minecraftforge.common.capabilities.CapabilityInject;
|
||||||
|
import net.minecraftforge.common.capabilities.CapabilityManager;
|
||||||
|
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
|
||||||
|
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||||
|
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||||
|
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
|
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class FMilkable
|
||||||
|
{
|
||||||
|
|
||||||
|
@CapabilityInject( FMilkable.class )
|
||||||
|
public static final Capability< FMilkable > CAPABILITY = null;
|
||||||
|
|
||||||
|
public static final ResourceLocation ID = new ResourceLocation( Mmm.ID , "Milkable" );
|
||||||
|
|
||||||
|
// *************************************************************************************************************
|
||||||
|
|
||||||
|
public static class Storage
|
||||||
|
implements Capability.IStorage< FMilkable >
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NBTBase writeNBT( final Capability< FMilkable > capability , final FMilkable instance ,
|
||||||
|
final EnumFacing side )
|
||||||
|
{
|
||||||
|
return new NBTTagLong( instance.lastMilking );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readNBT( final Capability< FMilkable > capability , final FMilkable instance ,
|
||||||
|
final EnumFacing side , final NBTBase nbt )
|
||||||
|
{
|
||||||
|
instance.lastMilking = ( (NBTTagLong) nbt ).getLong( );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// *************************************************************************************************************
|
||||||
|
|
||||||
|
public static class Provider
|
||||||
|
implements ICapabilitySerializable< NBTBase >
|
||||||
|
{
|
||||||
|
|
||||||
|
private final FMilkable instance = FMilkable.CAPABILITY.getDefaultInstance( );
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasCapability( final Capability< ? > capability , final EnumFacing facing )
|
||||||
|
{
|
||||||
|
return capability == FMilkable.CAPABILITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public < T > T getCapability( final Capability< T > capability , final EnumFacing facing )
|
||||||
|
{
|
||||||
|
return capability == FMilkable.CAPABILITY ? FMilkable.CAPABILITY.cast( this.instance ) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NBTBase serializeNBT( )
|
||||||
|
{
|
||||||
|
return FMilkable.CAPABILITY.writeNBT( this.instance , null );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deserializeNBT( final NBTBase nbt )
|
||||||
|
{
|
||||||
|
FMilkable.CAPABILITY.readNBT( this.instance , null , nbt );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// *************************************************************************************************************
|
||||||
|
|
||||||
|
public static class Message
|
||||||
|
implements I_UMessage
|
||||||
|
{
|
||||||
|
private int entityId;
|
||||||
|
private long lastMilking;
|
||||||
|
|
||||||
|
|
||||||
|
public Message( )
|
||||||
|
{
|
||||||
|
// EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Message( final Entity entity )
|
||||||
|
{
|
||||||
|
this.entityId = entity.getEntityId( );
|
||||||
|
this.lastMilking = entity.getCapability( FMilkable.CAPABILITY , null ).getLastMilking( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fromBytes( final ByteBuf buf )
|
||||||
|
{
|
||||||
|
this.entityId = buf.readInt( );
|
||||||
|
this.lastMilking = buf.readLong( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toBytes( final ByteBuf buf )
|
||||||
|
{
|
||||||
|
buf.writeInt( this.entityId );
|
||||||
|
buf.writeLong( this.lastMilking );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SideOnly( Side.CLIENT )
|
||||||
|
public void handleOnClient( )
|
||||||
|
{
|
||||||
|
final Entity entity = Minecraft.getMinecraft( ).theWorld.getEntityByID( this.entityId );
|
||||||
|
if ( entity == null || !entity.hasCapability( FMilkable.CAPABILITY , null ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
entity.getCapability( FMilkable.CAPABILITY , null ).lastMilking = this.lastMilking;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// *************************************************************************************************************
|
||||||
|
|
||||||
|
public static class EventHandler
|
||||||
|
{
|
||||||
|
@SubscribeEvent
|
||||||
|
public void attachCapability( final AttachCapabilitiesEvent.Entity event )
|
||||||
|
{
|
||||||
|
if ( FMilkType.MILK_TYPES.containsKey( event.getEntity( ).getClass( ) ) ) {
|
||||||
|
event.addCapability( FMilkable.ID , new Provider( ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void startTracking( final PlayerEvent.StartTracking event )
|
||||||
|
{
|
||||||
|
final EntityPlayer player = event.getEntityPlayer( );
|
||||||
|
if ( player.getEntityWorld( ).isRemote ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Entity entity = event.getTarget( );
|
||||||
|
if ( entity.hasCapability( FMilkable.CAPABILITY , null ) ) {
|
||||||
|
URegistry.network.sendTo( new Message( entity ) , (EntityPlayerMP) player );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void handleMilking( final PlayerInteractEvent.EntityInteract event )
|
||||||
|
{
|
||||||
|
// We must be holding a bucket
|
||||||
|
final ItemStack heldStack = event.getItemStack( );
|
||||||
|
if ( heldStack == null || heldStack.getItem( ) != Items.BUCKET ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Are we targeting a potentially milk-producing animal?
|
||||||
|
final Entity target = event.getTarget( );
|
||||||
|
if ( !target.hasCapability( CAPABILITY , null ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can't milk baby animals
|
||||||
|
final EntityAnimal animal = (EntityAnimal) target;
|
||||||
|
if ( animal.isChild( ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find actual milk type
|
||||||
|
final Set< FMilkType > milkTypes = FMilkType.MILK_TYPES.get( animal.getClass( ) );
|
||||||
|
FMilkType milkType = null;
|
||||||
|
for ( final FMilkType type : milkTypes ) {
|
||||||
|
if ( type.check( animal ) ) {
|
||||||
|
milkType = type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( milkType == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// So yeah, we're definitely trying to milk something. Don't process any further, even
|
||||||
|
// if milking fails.
|
||||||
|
event.setCanceled( true );
|
||||||
|
|
||||||
|
// Make sure it's been long enough since the animal's last milking
|
||||||
|
final EntityPlayer player = event.getEntityPlayer( );
|
||||||
|
FMilkable milkable = animal.getCapability( CAPABILITY , null );
|
||||||
|
long curTime = player.worldObj.getTotalWorldTime( );
|
||||||
|
if ( curTime - milkable.lastMilking < milkType.getPeriod( ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
milkable.lastMilking = curTime;
|
||||||
|
|
||||||
|
// Send updates to players
|
||||||
|
if ( !player.worldObj.isRemote ) {
|
||||||
|
URegistry.network.sendToAll( new Message( animal ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actually milk the animal
|
||||||
|
if ( !milkType.isVanilla || player.capabilities.isCreativeMode ) {
|
||||||
|
final ItemStack bucket = new ItemStack( milkType.bucket );
|
||||||
|
if ( --heldStack.stackSize == 0 ) {
|
||||||
|
player.setHeldItem( event.getHand( ) , bucket );
|
||||||
|
} else if ( !player.inventory.addItemStackToInventory( bucket ) ) {
|
||||||
|
player.dropItem( bucket , false );
|
||||||
|
}
|
||||||
|
player.playSound( SoundEvents.ENTITY_COW_MILK , 1.0F , 1.0F );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *************************************************************************************************************
|
||||||
|
|
||||||
|
public static void register( )
|
||||||
|
{
|
||||||
|
CapabilityManager.INSTANCE.register( FMilkable.class , new Storage( ) , FMilkable::new );
|
||||||
|
MinecraftForge.EVENT_BUS.register( new EventHandler( ) );
|
||||||
|
URegistry.addClientMessage( Message.class );
|
||||||
|
}
|
||||||
|
|
||||||
|
// *************************************************************************************************************
|
||||||
|
|
||||||
|
private long lastMilking = -500000;
|
||||||
|
|
||||||
|
|
||||||
|
public long getLastMilking( )
|
||||||
|
{
|
||||||
|
return this.lastMilking;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setLastMilking( final long lastMilking )
|
||||||
|
{
|
||||||
|
this.lastMilking = lastMilking;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,65 +0,0 @@
|
||||||
package mmm.food;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import net.minecraft.entity.passive.EntityAnimal;
|
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
|
||||||
import net.minecraft.init.Items;
|
|
||||||
import net.minecraft.init.SoundEvents;
|
|
||||||
import net.minecraft.item.ItemStack;
|
|
||||||
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
|
||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class FMilkingHandler
|
|
||||||
{
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
public void handleMilking( final PlayerInteractEvent.EntityInteract event )
|
|
||||||
{
|
|
||||||
final ItemStack heldStack = event.getItemStack( );
|
|
||||||
if ( heldStack == null || heldStack.getItem( ) != Items.BUCKET ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Entity target = event.getTarget( );
|
|
||||||
if ( ! ( target instanceof EntityAnimal ) ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final EntityAnimal animal = (EntityAnimal) target;
|
|
||||||
if ( animal.isChild( ) ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !FMilkType.MILK_TYPES.containsKey( animal.getClass( ) ) ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Set< FMilkType > milkTypes = FMilkType.MILK_TYPES.get( animal.getClass( ) );
|
|
||||||
FMilkType milkType = null;
|
|
||||||
for ( final FMilkType type : milkTypes ) {
|
|
||||||
if ( type.check( animal ) ) {
|
|
||||||
milkType = type;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( milkType == null ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final EntityPlayer player = event.getEntityPlayer( );
|
|
||||||
if ( !milkType.isVanilla || player.capabilities.isCreativeMode ) {
|
|
||||||
final ItemStack bucket = new ItemStack( milkType.bucket );
|
|
||||||
if ( --heldStack.stackSize == 0 ) {
|
|
||||||
player.setHeldItem( event.getHand( ) , bucket );
|
|
||||||
} else if ( !player.inventory.addItemStackToInventory( bucket ) ) {
|
|
||||||
player.dropItem( bucket , false );
|
|
||||||
}
|
|
||||||
player.playSound( SoundEvents.ENTITY_COW_MILK , 1.0F , 1.0F );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,16 +1,11 @@
|
||||||
package mmm.food;
|
package mmm.food;
|
||||||
|
|
||||||
|
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class Food
|
public class Food
|
||||||
{
|
{
|
||||||
|
|
||||||
static {
|
static {
|
||||||
FMilkType.preInit( );
|
FMilkType.preInit( );
|
||||||
MinecraftForge.EVENT_BUS.register( new FMilkingHandler( ) );
|
FMilkable.register( );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
23
src/java/mmm/utils/I_UMessage.java
Normal file
23
src/java/mmm/utils/I_UMessage.java
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package mmm.utils;
|
||||||
|
|
||||||
|
|
||||||
|
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public interface I_UMessage
|
||||||
|
extends IMessage
|
||||||
|
{
|
||||||
|
|
||||||
|
default void handleOnClient( )
|
||||||
|
{
|
||||||
|
// EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
default void handleOnServer( )
|
||||||
|
{
|
||||||
|
// EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -9,18 +9,26 @@ import java.util.Map;
|
||||||
|
|
||||||
import mmm.Mmm;
|
import mmm.Mmm;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemBlock;
|
import net.minecraft.item.ItemBlock;
|
||||||
|
import net.minecraft.util.IThreadListener;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraft.world.WorldServer;
|
||||||
import net.minecraftforge.client.model.ModelLoader;
|
import net.minecraftforge.client.model.ModelLoader;
|
||||||
|
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
|
||||||
|
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
|
||||||
import net.minecraftforge.fml.common.registry.GameRegistry;
|
import net.minecraftforge.fml.common.registry.GameRegistry;
|
||||||
import net.minecraftforge.fml.common.registry.IForgeRegistryEntry;
|
import net.minecraftforge.fml.common.registry.IForgeRegistryEntry;
|
||||||
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class URegistry
|
public class URegistry
|
||||||
{
|
{
|
||||||
|
public static final SimpleNetworkWrapper network = new SimpleNetworkWrapper( Mmm.ID );
|
||||||
|
private static int nextPacketDiscriminator = 0;
|
||||||
|
|
||||||
private static final HashSet< I_URecipeRegistrar > RECIPE_REGISTRARS = new HashSet<>( );
|
private static final HashSet< I_URecipeRegistrar > RECIPE_REGISTRARS = new HashSet<>( );
|
||||||
private static final HashSet< I_UOreGenerationRegistrar > ORE_GEN_REGISTRARS = new HashSet<>( );
|
private static final HashSet< I_UOreGenerationRegistrar > ORE_GEN_REGISTRARS = new HashSet<>( );
|
||||||
|
@ -135,6 +143,30 @@ public class URegistry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void addClientMessage( final Class< ? extends I_UMessage > message )
|
||||||
|
{
|
||||||
|
URegistry.network.registerMessage( //
|
||||||
|
( final I_UMessage m , final MessageContext ctx ) -> {
|
||||||
|
final IThreadListener main = Minecraft.getMinecraft( );
|
||||||
|
main.addScheduledTask( ( ) -> m.handleOnClient( ) );
|
||||||
|
return null;
|
||||||
|
} , //
|
||||||
|
message , URegistry.nextPacketDiscriminator++ , Side.CLIENT );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void addServerMessage( final Class< ? extends I_UMessage > message )
|
||||||
|
{
|
||||||
|
URegistry.network.registerMessage( //
|
||||||
|
( final I_UMessage m , final MessageContext ctx ) -> {
|
||||||
|
final IThreadListener main = (WorldServer) ctx.getServerHandler( ).playerEntity.worldObj;
|
||||||
|
main.addScheduledTask( ( ) -> m.handleOnServer( ) );
|
||||||
|
return null;
|
||||||
|
} , //
|
||||||
|
message , URegistry.nextPacketDiscriminator++ , Side.SERVER );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void setupItemModels( )
|
public static void setupItemModels( )
|
||||||
{
|
{
|
||||||
for ( final Map.Entry< Item , Boolean > entry : URegistry.ITEMS.entrySet( ) ) {
|
for ( final Map.Entry< Item , Boolean > entry : URegistry.ITEMS.entrySet( ) ) {
|
||||||
|
|
Reference in a new issue