Milking can't be done too often

Period depends on animal type.
This commit is contained in:
Emmanuel BENOîT 2016-06-18 14:48:27 +02:00
parent 444e020ae0
commit 8ed83d6629
6 changed files with 350 additions and 75 deletions

View file

@ -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 );

View 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;
}
}

View file

@ -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 );
}
}
}

View file

@ -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( );
} }

View 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
}
}

View file

@ -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( ) ) {