package choonster.testmod3.capability.pigspawner; import choonster.testmod3.Logger; import choonster.testmod3.TestMod3; import choonster.testmod3.api.capability.pigspawner.IPigSpawner; import choonster.testmod3.api.capability.pigspawner.IPigSpawnerFinite; import choonster.testmod3.api.capability.pigspawner.IPigSpawnerInteractable; import choonster.testmod3.capability.CapabilityContainerListenerManager; import choonster.testmod3.capability.CapabilityProviderSerializable; import choonster.testmod3.util.CapabilityUtils; import choonster.testmod3.util.DebugUtil; import net.minecraft.block.Block; import net.minecraft.command.ICommandSender; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.Style; import net.minecraft.util.text.TextFormatting; import net.minecraft.world.World; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.CapabilityInject; import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.event.AttachCapabilitiesEvent; import net.minecraftforge.event.entity.player.ItemTooltipEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; import javax.annotation.Nullable; import java.util.List; import java.util.stream.Collectors; /** * Capability for {@link IPigSpawner}. * * @author Choonster */ public final class CapabilityPigSpawner { /** * The {@link Capability} instance. */ @CapabilityInject(IPigSpawner.class) public static final Capability<IPigSpawner> PIG_SPAWNER_CAPABILITY = null; /** * The default {@link EnumFacing} to use for this capability. */ public static final EnumFacing DEFAULT_FACING = null; /** * The ID of the capability. */ public static final ResourceLocation ID = new ResourceLocation(TestMod3.MODID, "PigPower"); public static final Marker LOG_MARKER = MarkerManager.getMarker("PIG_SPAWNER", Logger.MOD_MARKER); /** * Register the capability. */ public static void register() { CapabilityManager.INSTANCE.register(IPigSpawner.class, new Capability.IStorage<IPigSpawner>() { @Override public NBTBase writeNBT(final Capability<IPigSpawner> capability, final IPigSpawner instance, final EnumFacing side) { final NBTTagCompound tagCompound = new NBTTagCompound(); if (instance instanceof IPigSpawnerFinite) { tagCompound.setInteger("NumPigs", ((IPigSpawnerFinite) instance).getNumPigs()); } return tagCompound; } @Override public void readNBT(final Capability<IPigSpawner> capability, final IPigSpawner instance, final EnumFacing side, final NBTBase nbt) { if (instance instanceof IPigSpawnerFinite) { final IPigSpawnerFinite pigSpawnerFinite = (IPigSpawnerFinite) instance; final NBTTagCompound tagCompound = (NBTTagCompound) nbt; Logger.debug(LOG_MARKER, DebugUtil.getStackTrace(10), "Reading finite pig spawner from NBT: %s (Current: %d, New: %d)", instance, pigSpawnerFinite.getNumPigs(), tagCompound.getInteger("NumPigs")); pigSpawnerFinite.setNumPigs(tagCompound.getInteger("NumPigs")); } } }, () -> new PigSpawnerFinite(20)); CapabilityContainerListenerManager.registerListenerFactory(ContainerListenerPigSpawnerFinite::new); } /** * Get the {@link IPigSpawner} from the specified {@link ItemStack}'s capabilities, if any. * * @param itemStack The ItemStack * @return The IPigSpawner, or null if there isn't one */ @Nullable public static IPigSpawner getPigSpawner(final ItemStack itemStack) { return CapabilityUtils.getCapability(itemStack, PIG_SPAWNER_CAPABILITY, DEFAULT_FACING); } /** * Create a provider for the default {@link IPigSpawner} instance. * * @return The provider */ public static ICapabilityProvider createProvider() { return new CapabilityProviderSerializable<>(PIG_SPAWNER_CAPABILITY, DEFAULT_FACING); } /** * Create a provider for the specified {@link IPigSpawner} instance. * * @param pigSpawner The IPigSpawner * @return The provider */ public static ICapabilityProvider createProvider(final IPigSpawner pigSpawner) { return new CapabilityProviderSerializable<>(PIG_SPAWNER_CAPABILITY, DEFAULT_FACING, pigSpawner); } /** * Event handler for the {@link IPigSpawner} capability. */ @Mod.EventBusSubscriber private static class EventHandler { /** * Attach the {@link IPigSpawner} capability to vanilla items. * * @param event The event */ @SubscribeEvent public static void attachCapabilities(final AttachCapabilitiesEvent<ItemStack> event) { if (event.getObject().getItem() == Items.CLAY_BALL) { event.addCapability(ID, createProvider()); } } /** * Spawn a pig at the specified position. * <p> * If there's an {@link IPigSpawnerInteractable}, call {@link IPigSpawnerInteractable#interact} on it. * * @param pigSpawner The pig spawner * @param world The World * @param x The x position to spawn the pig at * @param y The y position to spawn the pig at * @param z The z position to spawn the pig at * @param interactable The IPigSpawnerInteractable, if any * @param interactablePos The position of the IPigSpawnerInteractable * @param iCommandSender The ICommandSender, if any * @return Was any action taken? */ private static boolean trySpawnPig(final IPigSpawner pigSpawner, final World world, final double x, final double y, final double z, @Nullable final IPigSpawnerInteractable interactable, final BlockPos interactablePos, @Nullable final ICommandSender iCommandSender) { if (world.isRemote) return false; boolean actionTaken = false; boolean shouldSpawnPig = true; if (interactable != null) { shouldSpawnPig = !interactable.interact(pigSpawner, world, interactablePos, iCommandSender); actionTaken = true; } if (shouldSpawnPig && pigSpawner.canSpawnPig(world, x, y, z)) { pigSpawner.spawnPig(world, x, y, z); actionTaken = true; } return actionTaken; } /** * Spawn a pig when a player right clicks a block with an item that has the {@link IPigSpawner} capability. * <p> * If the block implements {@link IPigSpawnerInteractable}, call {@link IPigSpawnerInteractable#interact} on it. * * @param event The event */ @SubscribeEvent public static void playerInteract(final PlayerInteractEvent.RightClickBlock event) { final EnumFacing facing = event.getFace(); assert facing != null; final BlockPos spawnPos = event.getPos().offset(facing); final double x = spawnPos.getX() + 0.5, y = spawnPos.getY() + 0.5, z = spawnPos.getZ() + 0.5; final World world = event.getWorld(); final Block block = world.getBlockState(event.getPos()).getBlock(); final IPigSpawnerInteractable interactable = block instanceof IPigSpawnerInteractable ? (IPigSpawnerInteractable) block : null; final EntityPlayer player = event.getEntityPlayer(); final IPigSpawner pigSpawner = getPigSpawner(event.getItemStack()); if (pigSpawner != null) { trySpawnPig(pigSpawner, world, x, y, z, interactable, event.getPos(), player); } } /** * Spawn a pig when a player right clicks an entity with an item that has the {@link IPigSpawner} capability. * <p> * If the entity implements {@link IPigSpawnerInteractable}, call {@link IPigSpawnerInteractable#interact} on it. * * @param event The event */ @SubscribeEvent public static void entityInteract(final PlayerInteractEvent.EntityInteract event) { final World world = event.getEntityPlayer().getEntityWorld(); final Entity target = event.getTarget(); final double x = target.posX, y = target.posY, z = target.posZ; final IPigSpawnerInteractable interactable = target instanceof IPigSpawnerInteractable ? (IPigSpawnerInteractable) target : null; final EnumHand hand = event.getHand(); final IPigSpawner pigSpawner = getPigSpawner(event.getEntityPlayer().getHeldItem(hand)); if (pigSpawner != null) { trySpawnPig(pigSpawner, world, x, y, z, interactable, target.getPosition(), event.getEntityPlayer()); } } /** * Add the {@link IPigSpawner}'s tooltip lines to the tooltip if the item has the {@link IPigSpawner} capability * * @param event The event */ @SubscribeEvent public static void itemTooltip(final ItemTooltipEvent event) { final IPigSpawner pigSpawner = getPigSpawner(event.getItemStack()); if (pigSpawner == null) return; final Style style = new Style().setColor(TextFormatting.LIGHT_PURPLE); final List<ITextComponent> chatComponents = pigSpawner.getTooltipLines(); final List<String> tooltipLines = chatComponents.stream() .map(iTextComponent -> iTextComponent.setStyle(style)) .map(ITextComponent::getFormattedText) .collect(Collectors.toList()); event.getToolTip().add(""); event.getToolTip().addAll(tooltipLines); } } }