Java tutorial
/* * This file is part of Unlit Torch. * * Unlit Torch is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Unlit Torch is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Unlit Torch. If not, see <http://www.gnu.org/licenses/>. */ package com.github.pelepmc.unlittorch; import static com.github.pelepmc.unlittorch.TorchBlock.UNLIT; import static com.github.pelepmc.unlittorch.UnlitTorch.MOD_ID; import static net.minecraft.init.SoundEvents.BLOCK_FIRE_AMBIENT; import static net.minecraft.init.SoundEvents.BLOCK_LAVA_EXTINGUISH; import static net.minecraft.util.SoundCategory.BLOCKS; import static net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.client.resources.I18n; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Blocks; import net.minecraft.item.EnumAction; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; import net.minecraft.util.ActionResult; import net.minecraft.util.EnumActionResult; 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.math.MathHelper; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.event.entity.player.ItemTooltipEvent; import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandlerModifiable; import java.util.List; public final class TorchItem extends ItemBlock { public static final int LIT_METADATA = 0; public static final int UNLIT_METADATA = 1; public static final ResourceLocation IGNITING_PROPERTY_KEY = new ResourceLocation("igniting"); TorchItem(Block block) { super(block); setHasSubtypes(true); addPropertyOverride(IGNITING_PROPERTY_KEY, (stack, world, entity) -> entity != null && entity.isHandActive() && entity.getActiveItemStack() == stack ? 1.0f : 0.0f); } private static final int UPDATE_INTERVAL = 25; @Override public void onUpdate(ItemStack stack, World world, Entity entity, int slot, boolean held) { if (world.isRemote || world.getTotalWorldTime() % UPDATE_INTERVAL != 0) return; IItemHandler handler = entity.getCapability(ITEM_HANDLER_CAPABILITY, null); if (!(handler instanceof IItemHandlerModifiable)) return; if (entity instanceof EntityPlayer && ((EntityPlayer) entity).capabilities.isCreativeMode) return; IItemHandlerModifiable inventory = (IItemHandlerModifiable) handler; if (stack.getMetadata() == LIT_METADATA && entity.isWet()) { for (int i = 0; i < inventory.getSlots(); i++) { stack = inventory.getStackInSlot(i); if (stack != null && stack.getItem() == this && stack.stackSize != 0) { stack = stack.copy(); stack.setItemDamage(UNLIT_METADATA); inventory.setStackInSlot(i, stack); } } playDousingSound(entity.worldObj, entity.posX, entity.posY + entity.getEyeHeight(), entity.posZ); } else if (stack.getMetadata() == UNLIT_METADATA && entity.isBurning()) { for (int i = 0; i < inventory.getSlots(); i++) { stack = inventory.getStackInSlot(i); if (stack != null && stack.getItem() == this && stack.stackSize != 0) { stack = stack.copy(); stack.setItemDamage(LIT_METADATA); inventory.setStackInSlot(i, stack); } } playIgnitingSound(entity.worldObj, entity.posX, entity.posY + entity.getEyeHeight(), entity.posZ); } } @Override public boolean onEntityItemUpdate(EntityItem entity) { if (entity.worldObj.isRemote) return false; ItemStack stack = entity.getEntityItem(); if (stack.getItem() != this) return false; if (stack.getMetadata() == LIT_METADATA && entity.isWet()) { stack.setItemDamage(UNLIT_METADATA); playDousingSound(entity.worldObj, entity.posX, entity.posY + entity.getEyeHeight(), entity.posZ); } else if (stack.getMetadata() == UNLIT_METADATA && entity.isBurning()) { stack.setItemDamage(LIT_METADATA); playIgnitingSound(entity.worldObj, entity.posX, entity.posY + entity.getEyeHeight(), entity.posZ); } return false; } @Override public EnumActionResult onItemUseFirst(ItemStack stack, EntityPlayer player, World world, BlockPos position, EnumFacing side, float localX, float localY, float localZ, EnumHand hand) { if (player.isSneaking() || stack == null) return EnumActionResult.PASS; IBlockState state = world.getBlockState(position); if (state.getBlock() != getBlock()) return EnumActionResult.PASS; if ((stack.getMetadata() == UNLIT_METADATA && !state.getValue(UNLIT)) || (stack.getMetadata() == LIT_METADATA && state.getValue(UNLIT))) { player.setActiveHand(hand); return EnumActionResult.FAIL; } return EnumActionResult.PASS; } @Override public ActionResult<ItemStack> onItemRightClick(ItemStack stack, World world, EntityPlayer player, EnumHand hand) { player.setActiveHand(hand); return new ActionResult<>(EnumActionResult.FAIL, stack); } private static final int USE_DURATION = 72000; private static final int MAX_IGNITION_DELAY = 30; private static final int COOLDOWN_DURATION = 10; @Override public void onUsingTick(ItemStack stack, EntityLivingBase entity, int count) { if (count == USE_DURATION || count % MAX_IGNITION_DELAY != 0) return; World world = entity.worldObj; RayTraceResult result = rayTrace(world, entity, true); if (result == null || result.typeOfHit != RayTraceResult.Type.BLOCK) return; IBlockState state = world.getBlockState(result.getBlockPos()); if (state.getBlock() != getBlock()) return; if (stack.getMetadata() == UNLIT_METADATA && !state.getValue(UNLIT)) { if (entity instanceof EntityPlayer) ((EntityPlayer) entity).getCooldownTracker().setCooldown(this, COOLDOWN_DURATION); stack.setItemDamage(LIT_METADATA); playIgnitingSound(world, entity.posX, entity.posY + entity.getEyeHeight(), entity.posZ); } else if (stack.getMetadata() == LIT_METADATA && state.getValue(UNLIT)) { if (entity instanceof EntityPlayer) ((EntityPlayer) entity).getCooldownTracker().setCooldown(this, COOLDOWN_DURATION); BlockPos position = result.getBlockPos(); world.setBlockState(position, state.withProperty(UNLIT, false)); playIgnitingSound(world, position.getX() + 0.5d, position.getY() + 0.5d, position.getZ() + 0.5d); } } private static final float DEGREES_TO_RADIANS = (float) Math.PI / 180.0f; private RayTraceResult rayTrace(World world, Entity entity, boolean includeLiquids) { float pitch = entity.rotationPitch; float yaw = entity.rotationYaw; float scale = -MathHelper.cos(-pitch * DEGREES_TO_RADIANS); float unitX = MathHelper.sin(-yaw * DEGREES_TO_RADIANS - (float) Math.PI) * scale; float unitY = MathHelper.sin(-pitch * DEGREES_TO_RADIANS); float unitZ = MathHelper.cos(-yaw * DEGREES_TO_RADIANS - (float) Math.PI) * scale; double reach = entity instanceof EntityPlayerMP ? ((EntityPlayerMP) entity).interactionManager.getBlockReachDistance() : 5.0d; Vec3d start = new Vec3d(entity.posX, entity.posY + entity.getEyeHeight(), entity.posZ); Vec3d end = start.addVector(unitX * reach, unitY * reach, unitZ * reach); return world.rayTraceBlocks(start, end, includeLiquids, !includeLiquids, false); } @Override public int getMaxItemUseDuration(ItemStack stack) { return USE_DURATION; } @Override public EnumAction getItemUseAction(ItemStack stack) { return EnumAction.BLOCK; } @Override public int getMetadata(int damage) { return damage; } @SideOnly(Side.CLIENT) @Override public void getSubItems(Item item, CreativeTabs tab, List<ItemStack> items) { items.add(new ItemStack(this, 1, LIT_METADATA)); items.add(new ItemStack(this, 1, UNLIT_METADATA)); } private static final String LIT_UNLOCALIZED_NAME = "tile.torch"; // use minecraft's existing localization private static final String UNLIT_UNLOCALIZED_NAME = "tile." + MOD_ID + ".torch.unlit"; @Override public String getUnlocalizedName(ItemStack stack) { return stack.getMetadata() == UNLIT_METADATA ? UNLIT_UNLOCALIZED_NAME : LIT_UNLOCALIZED_NAME; } private static void playDousingSound(World world, double x, double y, double z) { world.playSound(null, x, y, z, BLOCK_LAVA_EXTINGUISH, BLOCKS, 0.4f + (0.15f * itemRand.nextFloat()), 1.0f); } private static void playIgnitingSound(World world, double x, double y, double z) { world.playSound(null, x, y, z, BLOCK_FIRE_AMBIENT, BLOCKS, 0.9f + itemRand.nextFloat(), 0.6f); } private static final String TOOLTIP_KEY = "item." + MOD_ID + ".torch.tooltip.unmodded"; @SideOnly(Side.CLIENT) @SubscribeEvent(priority = EventPriority.LOWEST) public void addTooltip(ItemTooltipEvent event) { if (!event.isCanceled()) { Item item = event.getItemStack().getItem(); if (item instanceof ItemBlock && ((ItemBlock) item).getBlock() == Blocks.TORCH) event.getToolTip().add(I18n.format(TOOLTIP_KEY)); } } }