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( );
|
||||
SHEEP = new FMilkType( "sheep" , EntitySheep.class );
|
||||
PIG = new FMilkType( "pig" , EntityPig.class );
|
||||
HORSE = new FMilkType( "horse" , EntityHorse.class )
|
||||
.setExtraCheck( a -> ( (EntityHorse) a ).getType( ) == HorseType.HORSE );
|
||||
PIG = new FMilkType( "pig" , EntityPig.class ) //
|
||||
.setPeriod( 48000 );
|
||||
HORSE = new FMilkType( "horse" , EntityHorse.class ) //
|
||||
.setExtraCheck( a -> ( (EntityHorse) a ).getType( ) == HorseType.HORSE ) //
|
||||
.setPeriod( 24000 );
|
||||
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 Class< ? extends EntityAnimal > animal;
|
||||
public final Item bucket;
|
||||
private int period = 12000;
|
||||
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 )
|
||||
{
|
||||
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;
|
||||
|
||||
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
||||
|
||||
|
||||
public class Food
|
||||
{
|
||||
|
||||
static {
|
||||
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 net.minecraft.block.Block;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemBlock;
|
||||
import net.minecraft.util.IThreadListener;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.WorldServer;
|
||||
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.IForgeRegistryEntry;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
|
||||
|
||||
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_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( )
|
||||
{
|
||||
for ( final Map.Entry< Item , Boolean > entry : URegistry.ITEMS.entrySet( ) ) {
|
||||
|
|
Reference in a new issue