diff --git a/patches/minecraft/net/minecraft/client/multiplayer/WorldClient.java.patch b/patches/minecraft/net/minecraft/client/multiplayer/WorldClient.java.patch new file mode 100644 index 000000000..32aa14412 --- /dev/null +++ b/patches/minecraft/net/minecraft/client/multiplayer/WorldClient.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/client/multiplayer/WorldClient.java ++++ b/net/minecraft/client/multiplayer/WorldClient.java +@@ -81,6 +81,7 @@ + this.mapStorage = new SaveDataMemoryStorage(); + this.calculateInitialSkylight(); + this.calculateInitialWeather(); ++ this.initCapabilities(); + } + + public void tick() { diff --git a/patches/minecraft/net/minecraft/client/renderer/BufferBuilder.java.patch b/patches/minecraft/net/minecraft/client/renderer/BufferBuilder.java.patch index 1e8a9e818..5a93943a9 100644 --- a/patches/minecraft/net/minecraft/client/renderer/BufferBuilder.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/BufferBuilder.java.patch @@ -46,7 +46,7 @@ } + + public boolean isColorDisabled() { -+ return noColor; ++ return noColor; + } + + public void putBulkData(ByteBuffer buffer) { diff --git a/patches/minecraft/net/minecraft/client/renderer/block/model/IBakedModel.java.patch b/patches/minecraft/net/minecraft/client/renderer/block/model/IBakedModel.java.patch index f7f64756e..a16341fca 100644 --- a/patches/minecraft/net/minecraft/client/renderer/block/model/IBakedModel.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/block/model/IBakedModel.java.patch @@ -17,6 +17,6 @@ + * that should be applied to the GL state before rendering it (matrix may be null). + */ + default org.apache.commons.lang3.tuple.Pair handlePerspective(ItemCameraTransforms.TransformType cameraTransformType) { -+ return net.minecraftforge.client.ForgeHooksClient.handlePerspective(this, cameraTransformType); ++ return net.minecraftforge.client.ForgeHooksClient.handlePerspective(this, cameraTransformType); } +} diff --git a/patches/minecraft/net/minecraft/client/renderer/block/model/ModelBlock.java.patch b/patches/minecraft/net/minecraft/client/renderer/block/model/ModelBlock.java.patch index cbc402a12..ec55a1d33 100644 --- a/patches/minecraft/net/minecraft/client/renderer/block/model/ModelBlock.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/block/model/ModelBlock.java.patch @@ -73,7 +73,7 @@ private static BakedQuad func_209567_a(BlockPart p_209567_0_, BlockPartFace p_209567_1_, TextureAtlasSprite p_209567_2_, EnumFacing p_209567_3_, ModelRotation p_209567_4_, boolean p_209567_5_) { - return field_209572_h.func_199332_a(p_209567_0_.positionFrom, p_209567_0_.positionTo, p_209567_1_, p_209567_2_, p_209567_3_, p_209567_4_, p_209567_0_.partRotation, p_209567_5_, p_209567_0_.shade); -+ return makeBakedQuad(p_209567_0_, p_209567_1_, p_209567_2_, p_209567_3_, (net.minecraftforge.common.model.IModelState) p_209567_4_, p_209567_5_); ++ return makeBakedQuad(p_209567_0_, p_209567_1_, p_209567_2_, p_209567_3_, (net.minecraftforge.common.model.IModelState) p_209567_4_, p_209567_5_); } + public static BakedQuad makeBakedQuad(BlockPart p_209567_0_, BlockPartFace p_209567_1_, TextureAtlasSprite p_209567_2_, EnumFacing p_209567_3_, net.minecraftforge.common.model.IModelState p_209567_4_, boolean p_209567_5_) { diff --git a/patches/minecraft/net/minecraft/client/renderer/texture/TextureAtlasSprite.java.patch b/patches/minecraft/net/minecraft/client/renderer/texture/TextureAtlasSprite.java.patch index 41b3f964f..57d4d2521 100644 --- a/patches/minecraft/net/minecraft/client/renderer/texture/TextureAtlasSprite.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/texture/TextureAtlasSprite.java.patch @@ -8,6 +8,6 @@ + // Forge Start + + public int getPixelRGBA(int frameIndex, int x, int y) { -+ return this.field_195670_c[frameIndex].func_195709_a(x + this.field_195671_d[frameIndex] * this.width, y + this.field_195672_e[frameIndex] * this.height); ++ return this.field_195670_c[frameIndex].func_195709_a(x + this.field_195671_d[frameIndex] * this.width, y + this.field_195672_e[frameIndex] * this.height); } +} diff --git a/patches/minecraft/net/minecraft/client/renderer/vertex/VertexFormatElement.java.patch b/patches/minecraft/net/minecraft/client/renderer/vertex/VertexFormatElement.java.patch new file mode 100644 index 000000000..fdd24052d --- /dev/null +++ b/patches/minecraft/net/minecraft/client/renderer/vertex/VertexFormatElement.java.patch @@ -0,0 +1,21 @@ +--- a/net/minecraft/client/renderer/vertex/VertexFormatElement.java ++++ b/net/minecraft/client/renderer/vertex/VertexFormatElement.java +@@ -124,10 +124,17 @@ + NORMAL("Normal"), + COLOR("Vertex Color"), + UV("UV"), ++ // As of 1.8.8 - unused in vanilla; use GENERIC for now ++ @Deprecated + MATRIX("Bone Matrix"), ++ @Deprecated + BLEND_WEIGHT("Blend Weight"), +- PADDING("Padding"); ++ PADDING("Padding"), ++ GENERIC("Generic"); + ++ public void preDraw(VertexFormat format, int element, int stride, java.nio.ByteBuffer buffer) { net.minecraftforge.client.ForgeHooksClient.preDraw(this, format, element, stride, buffer); } ++ public void postDraw(VertexFormat format, int element, int stride, java.nio.ByteBuffer buffer) { net.minecraftforge.client.ForgeHooksClient.postDraw(this, format, element, stride, buffer); } ++ + private final String displayName; + + private EnumUsage(String displayNameIn) { diff --git a/patches/minecraft/net/minecraft/client/resources/Language.java.patch b/patches/minecraft/net/minecraft/client/resources/Language.java.patch new file mode 100644 index 000000000..63ec22498 --- /dev/null +++ b/patches/minecraft/net/minecraft/client/resources/Language.java.patch @@ -0,0 +1,25 @@ +--- a/net/minecraft/client/resources/Language.java ++++ b/net/minecraft/client/resources/Language.java +@@ -15,7 +15,13 @@ + this.region = regionIn; + this.name = nameIn; + this.bidirectional = bidirectionalIn; ++ String[] splitLangCode = name.split("_", 2); ++ if (splitLangCode.length == 1) { // Vanilla has some languages without underscores ++ this.javaLocale = new java.util.Locale(languageCode); ++ } else { ++ this.javaLocale = new java.util.Locale(splitLangCode[0], splitLangCode[1]); + } ++ } + + public String getLanguageCode() { + return this.languageCode; +@@ -44,4 +50,8 @@ + public int compareTo(Language p_compareTo_1_) { + return this.languageCode.compareTo(p_compareTo_1_.languageCode); + } ++ ++ // Forge: add access to Locale so modders can create correct string and number formatters ++ private final java.util.Locale javaLocale; ++ public java.util.Locale getJavaLocale() { return javaLocale; } + } diff --git a/patches/minecraft/net/minecraft/entity/Entity.java.patch b/patches/minecraft/net/minecraft/entity/Entity.java.patch new file mode 100644 index 000000000..16295c073 --- /dev/null +++ b/patches/minecraft/net/minecraft/entity/Entity.java.patch @@ -0,0 +1,28 @@ +--- a/net/minecraft/entity/Entity.java ++++ b/net/minecraft/entity/Entity.java +@@ -12,6 +12,7 @@ + import java.util.Random; + import java.util.Set; + import java.util.UUID; ++ + import javax.annotation.Nullable; + import net.minecraft.advancements.CriteriaTriggers; + import net.minecraft.block.Block; +@@ -97,7 +98,7 @@ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + +-public abstract class Entity implements INameable, ICommandSource { ++public abstract class Entity extends net.minecraftforge.common.capabilities.CapabilityProvider implements INameable, ICommandSource, net.minecraftforge.common.extensions.IForgeEntity { + protected static final Logger LOGGER = LogManager.getLogger(); + private static final List EMPTY_EQUIPMENT = Collections.emptyList(); + private static final AxisAlignedBB ZERO_AABB = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D); +@@ -221,6 +222,8 @@ + this.dataManager.register(SILENT, false); + this.dataManager.register(NO_GRAVITY, false); + this.entityInit(); ++ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.EntityEvent.EntityConstructing(this)); ++ this.gatherCapabilities(); + } + + public EntityType func_200600_R() { diff --git a/patches/minecraft/net/minecraft/item/Item.java.patch b/patches/minecraft/net/minecraft/item/Item.java.patch index 5fc08a2fc..f9fc9f068 100644 --- a/patches/minecraft/net/minecraft/item/Item.java.patch +++ b/patches/minecraft/net/minecraft/item/Item.java.patch @@ -1,11 +1,163 @@ --- a/net/minecraft/item/Item.java +++ b/net/minecraft/item/Item.java -@@ -50,7 +50,7 @@ +@@ -50,9 +50,9 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -public class Item implements IItemProvider { -+public class Item extends net.minecraftforge.registries.ForgeRegistryEntry implements IItemProvider { - public static final RegistryNamespaced REGISTRY = new RegistryNamespaced(); - public static final Map BLOCK_TO_ITEM = Maps.newHashMap(); +- public static final RegistryNamespaced REGISTRY = new RegistryNamespaced(); +- public static final Map BLOCK_TO_ITEM = Maps.newHashMap(); ++public class Item extends net.minecraftforge.registries.ForgeRegistryEntry implements IItemProvider, net.minecraftforge.common.extensions.IForgeItem { ++ public static final RegistryNamespaced REGISTRY = net.minecraftforge.registries.GameData.getWrapper(Item.class); ++ public static final Map BLOCK_TO_ITEM = net.minecraftforge.registries.GameData.getBlockItemMap(); private static final IItemPropertyGetter DAMAGED_GETTER = (p_210306_0_, p_210306_1_, p_210306_2_) -> { + return p_210306_0_.isItemDamaged() ? 1.0F : 0.0F; + }; +@@ -126,6 +126,10 @@ + this.containerItem = p_i48487_1_.field_200922_c; + this.maxDamage = p_i48487_1_.field_200921_b; + this.maxStackSize = p_i48487_1_.field_200920_a; ++ this.canRepair = p_i48487_1_.canRepair; ++ this.toolClasses.putAll(p_i48487_1_.toolClasses); ++ Object tmp = net.minecraftforge.fml.DistExecutor.callWhenOn(Dist.CLIENT, p_i48487_1_.teisr); ++ this.teisr = tmp == null ? null : () -> (net.minecraft.client.renderer.tileentity.TileEntityItemStackRenderer) tmp; + if (this.maxDamage > 0) { + this.addPropertyOverride(new ResourceLocation("damaged"), DAMAGED_GETTER); + this.addPropertyOverride(new ResourceLocation("damage"), DAMAGE_GETTER); +@@ -149,10 +153,12 @@ + return stack; + } + ++ @Deprecated // Use ItemStack sensitive version. + public final int getItemStackLimit() { + return this.maxStackSize; + } + ++ @Deprecated // Use ItemStack sensitive version. + public final int getMaxDamage() { + return this.maxDamage; + } +@@ -207,6 +213,7 @@ + return this.containerItem; + } + ++ @Deprecated // Use ItemStack sensitive version. + public boolean hasContainerItem() { + return this.containerItem != null; + } +@@ -263,7 +270,7 @@ + } + + public boolean isEnchantable(ItemStack stack) { +- return this.getItemStackLimit() == 1 && this.isDamageable(); ++ return this.getItemStackLimit(stack) == 1 && this.isDamageable(); + } + + @Nullable +@@ -280,8 +287,8 @@ + float f5 = MathHelper.sin(-f * ((float)Math.PI / 180F)); + float f6 = f3 * f4; + float f7 = f2 * f4; +- double d3 = 5.0D; +- Vec3d vec3d1 = vec3d.add((double)f6 * 5.0D, (double)f5 * 5.0D, (double)f7 * 5.0D); ++ double d3 = playerIn.getEntityAttribute(EntityPlayer.REACH_DISTANCE).getAttributeValue(); ++ Vec3d vec3d1 = vec3d.add((double)f6 * d3, (double)f5 * d3, (double)f7 * d3); + return worldIn.func_200259_a(vec3d, vec3d1, useLiquids ? RayTraceFluidMode.SOURCE_ONLY : RayTraceFluidMode.NEVER, false, false); + } + +@@ -297,6 +304,7 @@ + } + + protected boolean isInCreativeTab(ItemGroup targetTab) { ++ if (getCreativeTabs().stream().anyMatch(tab -> tab == targetTab)) return true; + ItemGroup itemgroup = this.getCreativeTab(); + return itemgroup != null && (targetTab == ItemGroup.SEARCH || targetTab == itemgroup); + } +@@ -310,10 +318,49 @@ + return false; + } + ++ @Deprecated // Use ItemStack sensitive version. + public Multimap getItemAttributeModifiers(EntityEquipmentSlot equipmentSlot) { + return HashMultimap.create(); + } + ++ /* ======================================== FORGE START =====================================*/ ++ ++ @Nullable ++ private final java.util.function.Supplier teisr; ++ ++ private final java.util.Map toolClasses = new java.util.HashMap(); ++ ++ protected final boolean canRepair; ++ ++ @Override ++ public boolean isRepairable() ++ { ++ return canRepair && isDamageable(); ++ } ++ ++ @Override ++ public java.util.Set getToolClasses(ItemStack stack) ++ { ++ return toolClasses.keySet(); ++ } ++ ++ @Override ++ public int getHarvestLevel(ItemStack stack, String toolClass, @Nullable EntityPlayer player, @Nullable IBlockState blockState) ++ { ++ Integer ret = toolClasses.get(toolClass); ++ return ret == null ? -1 : ret; ++ } ++ ++ @OnlyIn(Dist.CLIENT) ++ @Override ++ public final net.minecraft.client.renderer.tileentity.TileEntityItemStackRenderer getTileEntityItemStackRenderer() ++ { ++ net.minecraft.client.renderer.tileentity.TileEntityItemStackRenderer renderer = teisr != null ? teisr.get() : null; ++ return renderer != null ? renderer : net.minecraft.client.renderer.tileentity.TileEntityItemStackRenderer.instance; ++ } ++ ++ /* ======================================== FORGE END =====================================*/ ++ + public static void registerItems() { + registerItemBlock(Blocks.AIR, new ItemAir(Blocks.AIR, new Item.Builder())); + func_200879_a(Blocks.STONE, ItemGroup.BUILDING_BLOCKS); +@@ -1147,6 +1194,9 @@ + private Item field_200922_c; + private ItemGroup field_200923_d; + private EnumRarity field_208104_e = EnumRarity.COMMON; ++ private boolean canRepair = true; ++ private java.util.Map toolClasses = new java.util.HashMap(); ++ private java.util.function.Supplier> teisr; + + public Item.Builder func_200917_a(int p_200917_1_) { + if (this.field_200921_b > 0) { +@@ -1181,5 +1231,27 @@ + this.field_208104_e = p_208103_1_; + return this; + } ++ ++ public Item.Builder setNoRepair() { ++ canRepair = false; ++ return this; + } ++ ++ /** ++ * Sets or removes the harvest level for the specified tool class. ++ * ++ * @param toolClass Class ++ * @param level Harvest level: Wood: 0 Stone: 1 Iron: 2 Diamond: 3 Gold: 0 ++ */ ++ public void setHarvestLevel(String toolClass, int level) { ++ if (level < 0) ++ toolClasses.remove(toolClass); ++ else ++ toolClasses.put(toolClass, level); + } ++ ++ public void setTileEntityItemStackRenderer(java.util.function.Supplier> teisrSupplier) { ++ this.teisr = teisrSupplier; ++ } ++ } ++} diff --git a/patches/minecraft/net/minecraft/item/ItemStack.java.patch b/patches/minecraft/net/minecraft/item/ItemStack.java.patch new file mode 100644 index 000000000..3bd1c3fb5 --- /dev/null +++ b/patches/minecraft/net/minecraft/item/ItemStack.java.patch @@ -0,0 +1,302 @@ +--- a/net/minecraft/item/ItemStack.java ++++ b/net/minecraft/item/ItemStack.java +@@ -63,7 +63,7 @@ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + +-public final class ItemStack { ++public final class ItemStack extends net.minecraftforge.common.capabilities.CapabilityProvider implements net.minecraftforge.common.capabilities.ICapabilitySerializable { + private static final Logger field_199558_c = LogManager.getLogger(); + public static final ItemStack EMPTY = new ItemStack((Item)null); + public static final DecimalFormat DECIMALFORMAT = func_208306_D(); +@@ -79,6 +79,9 @@ + private BlockWorldState canPlaceOnCacheBlock; + private boolean canPlaceOnCacheResult; + ++ private net.minecraftforge.registries.IRegistryDelegate delegate; ++ private NBTTagCompound capNBT; ++ + private static DecimalFormat func_208306_D() { + DecimalFormat decimalformat = new DecimalFormat("#.##"); + decimalformat.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ROOT)); +@@ -89,10 +92,13 @@ + this(p_i48203_1_, 1); + } + +- public ItemStack(IItemProvider p_i48204_1_, int p_i48204_2_) { ++ public ItemStack(IItemProvider p_i48204_1_, int p_i48204_2_){ this(p_i48204_1_, p_i48204_2_, null); } ++ public ItemStack(IItemProvider p_i48204_1_, int p_i48204_2_, @Nullable NBTTagCompound capNBT) { ++ this.capNBT = capNBT; + this.item = p_i48204_1_ == null ? null : p_i48204_1_.func_199767_j(); + this.stackSize = p_i48204_2_; + this.updateEmptyState(); ++ this.forgeInit(); + } + + private void updateEmptyState() { +@@ -101,6 +107,7 @@ + } + + private ItemStack(NBTTagCompound compound) { ++ this.capNBT = compound.hasKey("ForgeCaps") ? compound.getCompoundTag("ForgeCaps") : null; + Item item = Item.REGISTRY.getObject(new ResourceLocation(compound.getString("id"))); + this.item = item == null ? Items.AIR : item; + this.stackSize = compound.getByte("Count"); +@@ -114,6 +121,7 @@ + } + + this.updateEmptyState(); ++ this.forgeInit(); + } + + public static ItemStack func_199557_a(NBTTagCompound p_199557_0_) { +@@ -128,7 +136,7 @@ + public boolean isEmpty() { + if (this == EMPTY) { + return true; +- } else if (this.getItem() != null && this.getItem() != Items.AIR) { ++ } else if (this.getItemRaw() != null && this.getItemRaw() != Items.AIR) { + return this.stackSize <= 0; + } else { + return true; +@@ -144,10 +152,11 @@ + } + + public Item getItem() { +- return this.isEmpty ? Items.AIR : this.item; ++ return this.isEmpty || this.delegate == null ? Items.AIR : this.delegate.get(); + } + + public EnumActionResult func_196084_a(ItemUseContext p_196084_1_) { ++ if (!p_196084_1_.field_196006_g.isRemote) return net.minecraftforge.common.ForgeHooks.onPlaceItemIntoWorld(p_196084_1_); + EntityPlayer entityplayer = p_196084_1_.func_195999_j(); + BlockPos blockpos = p_196084_1_.func_195995_a(); + BlockWorldState blockworldstate = new BlockWorldState(p_196084_1_.func_195991_k(), blockpos, false); +@@ -164,6 +173,23 @@ + } + } + ++ public EnumActionResult onItemUseFirst(ItemUseContext p_196084_1_) { ++ EntityPlayer entityplayer = p_196084_1_.func_195999_j(); ++ BlockPos blockpos = p_196084_1_.func_195995_a(); ++ BlockWorldState blockworldstate = new BlockWorldState(p_196084_1_.func_195991_k(), blockpos, false); ++ if (entityplayer != null && !entityplayer.capabilities.allowEdit && !this.func_206847_b(p_196084_1_.func_195991_k().func_205772_D(), blockworldstate)) { ++ return EnumActionResult.PASS; ++ } else { ++ Item item = this.getItem(); ++ EnumActionResult enumactionresult = item.onItemUseFirst(p_196084_1_); ++ if (entityplayer != null && enumactionresult == EnumActionResult.SUCCESS) { ++ entityplayer.addStat(StatList.OBJECT_USE_STATS.func_199076_b(item)); ++ } ++ ++ return enumactionresult; ++ } ++ } ++ + public float getDestroySpeed(IBlockState blockIn) { + return this.getItem().getDestroySpeed(this, blockIn); + } +@@ -183,12 +209,15 @@ + if (this.stackTagCompound != null) { + nbt.setTag("tag", this.stackTagCompound); + } +- ++ NBTTagCompound cnbt = this.serializeCaps(); ++ if (cnbt != null && !cnbt.isEmpty()) { ++ nbt.setTag("ForgeCaps", cnbt); ++ } + return nbt; + } + + public int getMaxStackSize() { +- return this.getItem().getItemStackLimit(); ++ return this.getItem().getItemStackLimit(this); + } + + public boolean isStackable() { +@@ -196,7 +225,7 @@ + } + + public boolean isItemStackDamageable() { +- if (!this.isEmpty && this.getItem().getMaxDamage() > 0) { ++ if (!this.isEmpty && this.getItem().getMaxDamage(this) > 0) { + NBTTagCompound nbttagcompound = this.getTagCompound(); + return nbttagcompound == null || !nbttagcompound.getBoolean("Unbreakable"); + } else { +@@ -205,19 +234,19 @@ + } + + public boolean isItemDamaged() { +- return this.isItemStackDamageable() && this.getItemDamage() > 0; ++ return this.isItemStackDamageable() && getItem().isDamaged(this); + } + +- public int getItemDamage() { +- return this.stackTagCompound == null ? 0 : this.stackTagCompound.getInteger("Damage"); ++ public int getItemDamage() { // TODO evaluate the necessity of this patch ++ return this.getItem().getDamage(this); + } + + public void func_196085_b(int p_196085_1_) { +- this.func_196082_o().setInteger("Damage", Math.max(0, p_196085_1_)); ++ getItem().setDamage(this, p_196085_1_); + } + + public int getMaxDamage() { +- return this.getItem().getMaxDamage(); ++ return this.getItem().getMaxDamage(this); + } + + public boolean attemptDamageItem(int amount, Random rand, @Nullable EntityPlayerMP damager) { +@@ -285,7 +314,7 @@ + } + + public boolean canHarvestBlock(IBlockState blockIn) { +- return this.getItem().canHarvestBlock(blockIn); ++ return this.getItem().canHarvestBlock(blockIn, this); + } + + public boolean interactWithEntity(EntityPlayer playerIn, EntityLivingBase entityIn, EnumHand hand) { +@@ -293,7 +322,7 @@ + } + + public ItemStack copy() { +- ItemStack itemstack = new ItemStack(this.getItem(), this.stackSize); ++ ItemStack itemstack = new ItemStack(this.getItem(), this.stackSize, this.serializeCaps()); + itemstack.setAnimationsToGo(this.getAnimationsToGo()); + if (this.stackTagCompound != null) { + itemstack.stackTagCompound = this.stackTagCompound.copy(); +@@ -309,7 +338,7 @@ + if (stackA.stackTagCompound == null && stackB.stackTagCompound != null) { + return false; + } else { +- return stackA.stackTagCompound == null || stackA.stackTagCompound.equals(stackB.stackTagCompound); ++ return stackA.stackTagCompound == null || stackA.stackTagCompound.equals(stackB.stackTagCompound) && stackA.areCapsCompatible(stackB); + } + } else { + return false; +@@ -332,7 +361,7 @@ + } else if (this.stackTagCompound == null && other.stackTagCompound != null) { + return false; + } else { +- return this.stackTagCompound == null || this.stackTagCompound.equals(other.stackTagCompound); ++ return this.stackTagCompound == null || this.stackTagCompound.equals(other.stackTagCompound) && this.areCapsCompatible(other); + } + } + +@@ -633,6 +662,7 @@ + } + } + ++ net.minecraftforge.event.ForgeEventFactory.onItemTooltip(this, playerIn, list, advanced); + return list; + } + +@@ -743,7 +773,7 @@ + } + } + } else { +- multimap = this.getItem().getItemAttributeModifiers(equipmentSlot); ++ multimap = this.getItem().getAttributeModifiers(equipmentSlot, this); + } + + return multimap; +@@ -874,4 +904,98 @@ + public void shrink(int quantity) { + this.grow(-quantity); + } ++ ++ // FORGE START ++ ++ public void deserializeNBT(NBTTagCompound nbt) ++ { ++ // TODO do this better while respecting new rules ++ final ItemStack itemStack = new ItemStack(nbt); ++ this.stackTagCompound = itemStack.stackTagCompound; ++ this.capNBT = itemStack.capNBT; + } ++ ++ public NBTTagCompound serializeNBT() ++ { ++ NBTTagCompound ret = new NBTTagCompound(); ++ this.writeToNBT(ret); ++ return ret; ++ } ++ ++ /** ++ * Set up forge's ItemStack additions. ++ */ ++ private void forgeInit() ++ { ++ Item item = getItemRaw(); ++ if (item != null) ++ { ++ this.delegate = item.delegate; ++ net.minecraftforge.common.capabilities.ICapabilityProvider provider = item.initCapabilities(this, this.capNBT); ++ this.gatherCapabilities(provider); ++ if (this.capNBT != null) deserializeCaps(this.capNBT); ++ } ++ } ++ ++ /** ++ * Internal call to get the actual item, not the delegate. ++ * In all other methods, FML replaces calls to this.item with the item delegate. ++ */ ++ @Nullable ++ private Item getItemRaw() ++ { ++ return this.item; ++ } ++ ++ /** ++ * Modeled after ItemStack.areItemStacksEqual ++ * Uses Item.getNBTShareTag for comparison instead of NBT and capabilities. ++ * Only used for comparing itemStacks that were transferred from server to client using Item.getNBTShareTag. ++ */ ++ public static boolean areItemStacksEqualUsingNBTShareTag(ItemStack stackA, ItemStack stackB) ++ { ++ if (stackA.isEmpty()) ++ return stackB.isEmpty(); ++ else ++ return !stackB.isEmpty() && stackA.isItemStackEqualUsingNBTShareTag(stackB); ++ } ++ ++ /** ++ * Modeled after ItemStack.isItemStackEqual ++ * Uses Item.getNBTShareTag for comparison instead of NBT and capabilities. ++ * Only used for comparing itemStacks that were transferred from server to client using Item.getNBTShareTag. ++ */ ++ private boolean isItemStackEqualUsingNBTShareTag(ItemStack other) ++ { ++ return this.stackSize == other.stackSize && this.getItem() == other.getItem() && areItemStackShareTagsEqual(this, other); ++ } ++ ++ /** ++ * Modeled after ItemStack.areItemStackTagsEqual ++ * Uses Item.getNBTShareTag for comparison instead of NBT and capabilities. ++ * Only used for comparing itemStacks that were transferred from server to client using Item.getNBTShareTag. ++ */ ++ public static boolean areItemStackShareTagsEqual(ItemStack stackA, ItemStack stackB) ++ { ++ NBTTagCompound shareTagA = stackA.getItem().getNBTShareTag(stackA); ++ NBTTagCompound shareTagB = stackB.getItem().getNBTShareTag(stackB); ++ if (shareTagA == null) ++ return shareTagB == null; ++ else ++ return shareTagB != null && shareTagA.equals(shareTagB); ++ } ++ ++ /** ++ * ++ * Should this item, when held, allow sneak-clicks to pass through to the underlying block? ++ * ++ * @param world The world ++ * @param pos Block position in world ++ * @param player The Player that is wielding the item ++ * @return ++ */ ++ public boolean doesSneakBypassUse(net.minecraft.world.IWorldReader world, BlockPos pos, EntityPlayer player) ++ { ++ return this.isEmpty() || this.getItem().doesSneakBypassUse(this, world, pos, player); ++ } ++} diff --git a/patches/minecraft/net/minecraft/tileentity/TileEntity.java.patch b/patches/minecraft/net/minecraft/tileentity/TileEntity.java.patch new file mode 100644 index 000000000..a378afcdf --- /dev/null +++ b/patches/minecraft/net/minecraft/tileentity/TileEntity.java.patch @@ -0,0 +1,23 @@ +--- a/net/minecraft/tileentity/TileEntity.java ++++ b/net/minecraft/tileentity/TileEntity.java +@@ -12,10 +12,11 @@ + import net.minecraft.world.World; + import net.minecraftforge.api.distmarker.Dist; + import net.minecraftforge.api.distmarker.OnlyIn; ++ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + +-public abstract class TileEntity { ++public abstract class TileEntity extends net.minecraftforge.common.capabilities.CapabilityProvider implements net.minecraftforge.common.extensions.IForgeTileEntity { + private static final Logger LOGGER = LogManager.getLogger(); + private final TileEntityType field_200663_e; + protected World world; +@@ -26,6 +27,7 @@ + + public TileEntity(TileEntityType p_i48289_1_) { + this.field_200663_e = p_i48289_1_; ++ this.gatherCapabilities(); + } + + @Nullable diff --git a/patches/minecraft/net/minecraft/village/Village.java.patch b/patches/minecraft/net/minecraft/village/Village.java.patch new file mode 100644 index 000000000..150a8cf78 --- /dev/null +++ b/patches/minecraft/net/minecraft/village/Village.java.patch @@ -0,0 +1,42 @@ +--- a/net/minecraft/village/Village.java ++++ b/net/minecraft/village/Village.java +@@ -30,7 +30,7 @@ + import net.minecraft.util.text.ITextComponent; + import net.minecraft.world.World; + +-public class Village { ++public class Village extends net.minecraftforge.common.capabilities.CapabilityProvider implements net.minecraftforge.common.extensions.IForgeVillage { + private World world; + private final List villageDoorInfoList = Lists.newArrayList(); + private BlockPos centerHelper = BlockPos.ORIGIN; +@@ -45,10 +45,12 @@ + private int numIronGolems; + + public Village() { ++ this.gatherCapabilities(); + } + + public Village(World worldIn) { + this.world = worldIn; ++ this.gatherCapabilities(); + } + + public void setWorld(World worldIn) { +@@ -364,7 +366,7 @@ + this.playerReputation.put(nbttagcompound1.getString("Name"), nbttagcompound1.getInteger("S")); + } + } +- ++ if (compound.hasKey("ForgeCaps")) this.deserializeCaps(compound.getCompoundTag("ForgeCaps")); + } + + public void writeVillageDataToNBT(NBTTagCompound compound) { +@@ -413,6 +415,8 @@ + } + + compound.setTag("Players", nbttaglist1); ++ NBTTagCompound capTag = this.serializeCaps(); ++ if (capTag != null) compound.setTag("ForgeCaps", capTag); + } + + public void endMatingSeason() { diff --git a/patches/minecraft/net/minecraft/world/World.java.patch b/patches/minecraft/net/minecraft/world/World.java.patch new file mode 100644 index 000000000..c7d1a79b7 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/World.java.patch @@ -0,0 +1,55 @@ +--- a/net/minecraft/world/World.java ++++ b/net/minecraft/world/World.java +@@ -68,10 +68,11 @@ + import net.minecraft.world.storage.WorldSavedDataStorage; + import net.minecraftforge.api.distmarker.Dist; + import net.minecraftforge.api.distmarker.OnlyIn; ++ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + +-public abstract class World implements IWorld, IWorldReader, AutoCloseable { ++public abstract class World extends net.minecraftforge.common.capabilities.CapabilityProvider implements IWorld, IWorldReader, AutoCloseable, net.minecraftforge.common.extensions.IForgeWorld { + protected static final Logger field_195596_d = LogManager.getLogger(); + private static final EnumFacing[] field_200007_a = EnumFacing.values(); + private int seaLevel = 63; +@@ -121,6 +122,7 @@ + this.provider = providerIn; + this.isRemote = client; + this.worldBorder = providerIn.createWorldBorder(); ++ perWorldStorage = new WorldSavedDataStorage((ISaveHandler)null); + } + + public IWorld init() { +@@ -2397,4 +2399,31 @@ + public abstract RecipeManager func_199532_z(); + + public abstract NetworkTagManager func_205772_D(); ++ ++ /* ======================================== FORGE START =====================================*/ ++ ++ private net.minecraftforge.common.util.WorldCapabilityData capabilityData; ++ ++ protected void initCapabilities() ++ { ++ net.minecraftforge.common.capabilities.ICapabilityProvider parent = provider.initCapabilities(); ++ this.gatherCapabilities(parent); ++ net.minecraftforge.common.util.WorldCapabilityData data = (net.minecraftforge.common.util.WorldCapabilityData)perWorldStorage.func_201067_a(net.minecraftforge.common.util.WorldCapabilityData::new, net.minecraftforge.common.util.WorldCapabilityData.ID); ++ if (data == null) ++ { ++ capabilityData = new net.minecraftforge.common.util.WorldCapabilityData(getCapabilities()); ++ perWorldStorage.setData(capabilityData.func_195925_e(), capabilityData); + } ++ else ++ { ++ capabilityData = data; ++ capabilityData.setCapabilities(provider, getCapabilities()); ++ } ++ } ++ ++ protected WorldSavedDataStorage perWorldStorage; //Moved to a getter to simulate final without being final so we can load in subclasses. ++ public WorldSavedDataStorage getPerWorldStorage() ++ { ++ return perWorldStorage; ++ } ++} diff --git a/patches/minecraft/net/minecraft/world/WorldServer.java.patch b/patches/minecraft/net/minecraft/world/WorldServer.java.patch new file mode 100644 index 000000000..9d377fdf5 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/WorldServer.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/WorldServer.java ++++ b/net/minecraft/world/WorldServer.java +@@ -150,6 +150,7 @@ + this.getWorldBorder().setTransition(this.worldInfo.getBorderSize()); + } + ++ this.initCapabilities(); + return this; + } + diff --git a/patches/minecraft/net/minecraft/world/WorldServerMulti.java.patch b/patches/minecraft/net/minecraft/world/WorldServerMulti.java.patch new file mode 100644 index 000000000..8f54bcf59 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/WorldServerMulti.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/world/WorldServerMulti.java ++++ b/net/minecraft/world/WorldServerMulti.java +@@ -60,6 +60,7 @@ + this.villageCollection.setWorldsForAll(this); + } + ++ this.initCapabilities(); + return this; + } + diff --git a/patches/minecraft/net/minecraft/world/chunk/Chunk.java.patch b/patches/minecraft/net/minecraft/world/chunk/Chunk.java.patch new file mode 100644 index 000000000..434707fa0 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/chunk/Chunk.java.patch @@ -0,0 +1,19 @@ +--- a/net/minecraft/world/chunk/Chunk.java ++++ b/net/minecraft/world/chunk/Chunk.java +@@ -53,7 +53,7 @@ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + +-public class Chunk implements IChunk { ++public class Chunk extends net.minecraftforge.common.capabilities.CapabilityProvider implements IChunk, net.minecraftforge.common.extensions.IForgeChunk { + private static final Logger LOGGER = LogManager.getLogger(); + public static final ChunkSection NULL_BLOCK_STORAGE = null; + private final ChunkSection[] storageArrays; +@@ -125,6 +125,7 @@ + this.field_201621_s = p_i49379_6_; + this.field_205325_u = p_i49379_7_; + this.inhabitedTime = p_i49379_8_; ++ this.gatherCapabilities(); + } + + public Chunk(World p_i48703_1_, ChunkPrimer p_i48703_2_, int p_i48703_3_, int p_i48703_4_) { diff --git a/patches/minecraft/net/minecraft/world/chunk/storage/AnvilChunkLoader.java.patch b/patches/minecraft/net/minecraft/world/chunk/storage/AnvilChunkLoader.java.patch new file mode 100644 index 000000000..fad6efd86 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/chunk/storage/AnvilChunkLoader.java.patch @@ -0,0 +1,33 @@ +--- a/net/minecraft/world/chunk/storage/AnvilChunkLoader.java ++++ b/net/minecraft/world/chunk/storage/AnvilChunkLoader.java +@@ -445,7 +445,19 @@ + + compound.setTag("Heightmaps", nbttagcompound2); + compound.setTag("Structures", this.func_202160_a(chunkIn.x, chunkIn.z, chunkIn.func_201609_c(), chunkIn.func_201604_d())); ++ ++ if (chunkIn.getCapabilities() != null) ++ { ++ try ++ { ++ compound.setTag("ForgeCaps", chunkIn.getCapabilities().serializeNBT()); + } ++ catch (Exception exception) ++ { ++ org.apache.logging.log4j.LogManager.getLogger().error("A capability provider has thrown an exception trying to write state. It will not persist. Report this to the mod author", exception); ++ } ++ } ++ } + + private Chunk readChunkFromNBT(IWorld worldIn, NBTTagCompound compound) { + int i = compound.getInteger("xPos"); +@@ -511,6 +523,10 @@ + chunk.setModified(true); + } + ++ if (chunk.getCapabilities() != null && compound.hasKey("ForgeCaps")) { ++ chunk.getCapabilities().deserializeNBT(compound.getCompoundTag("ForgeCaps")); ++ } ++ + return chunk; + } + diff --git a/patches/minecraft/net/minecraft/world/dimension/Dimension.java.patch b/patches/minecraft/net/minecraft/world/dimension/Dimension.java.patch new file mode 100644 index 000000000..421ea7830 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/dimension/Dimension.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/dimension/Dimension.java ++++ b/net/minecraft/world/dimension/Dimension.java +@@ -13,7 +13,7 @@ + import net.minecraftforge.api.distmarker.Dist; + import net.minecraftforge.api.distmarker.OnlyIn; + +-public abstract class Dimension { ++public abstract class Dimension implements net.minecraftforge.common.extensions.IForgeDimension { + public static final float[] MOON_PHASE_FACTORS = new float[]{1.0F, 0.75F, 0.5F, 0.25F, 0.0F, 0.25F, 0.5F, 0.75F}; + protected World world; + protected boolean doesWaterVaporize; diff --git a/src/main/java/net/minecraftforge/client/CloudRenderer.java b/src/main/java/net/minecraftforge/client/CloudRenderer.java index feecd9c60..32f7c48ee 100644 --- a/src/main/java/net/minecraftforge/client/CloudRenderer.java +++ b/src/main/java/net/minecraftforge/client/CloudRenderer.java @@ -41,6 +41,7 @@ import net.minecraft.client.renderer.vertex.VertexBuffer; import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.entity.Entity; import net.minecraft.resources.IReloadableResourceManager; +import net.minecraft.resources.IResourceManager; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; diff --git a/src/main/java/net/minecraftforge/client/ForgeClientHandler.java b/src/main/java/net/minecraftforge/client/ForgeClientHandler.java index b347f036c..655c0e117 100644 --- a/src/main/java/net/minecraftforge/client/ForgeClientHandler.java +++ b/src/main/java/net/minecraftforge/client/ForgeClientHandler.java @@ -35,7 +35,8 @@ public class ForgeClientHandler // register model for the universal bucket, if it exists if (FluidRegistry.isUniversalBucketEnabled()) { - ModelLoader.setBucketModelDefinition(ForgeMod.getInstance().universalBucket); + // TODO no more mesh definitions, this should be implemented with overrides +// ModelLoader.setBucketModelDefinition(ForgeMod.getInstance().universalBucket); } } @@ -44,7 +45,7 @@ public class ForgeClientHandler { if (FluidRegistry.isUniversalBucketEnabled()) { - event.getItemColors().registerItemColorHandler(new FluidContainerColorer(), ForgeMod.getInstance().universalBucket); + event.getItemColors().func_199877_a(new FluidContainerColorer(), ForgeMod.getInstance().universalBucket); } } } diff --git a/src/main/java/net/minecraftforge/client/model/animation/AnimationItemOverrideList.java b/src/main/java/net/minecraftforge/client/model/animation/AnimationItemOverrideList.java index 97d692fd8..d83670948 100644 --- a/src/main/java/net/minecraftforge/client/model/animation/AnimationItemOverrideList.java +++ b/src/main/java/net/minecraftforge/client/model/animation/AnimationItemOverrideList.java @@ -67,22 +67,23 @@ public final class AnimationItemOverrideList extends ItemOverrideList @Override public IBakedModel func_209581_a(IBakedModel originalModel, ItemStack stack, @Nullable World world, @Nullable EntityLivingBase entity) { - IAnimationStateMachine asm = stack.getCapability(CapabilityAnimation.ANIMATION_CAPABILITY, null); - if (asm != null) - { - // TODO: caching? - if(world == null && entity != null) + return stack.getCapability(CapabilityAnimation.ANIMATION_CAPABILITY, null) + .map(asm -> { - world = entity.world; - } - if(world == null) - { - world = Minecraft.getMinecraft().world; - } - IModelState state = asm.apply(Animation.getWorldTime(world, Animation.getPartialTickTime())).getLeft(); + World w = world; + // TODO caching? + if(w == null && entity != null) + { + w = entity.world; + } + if(world == null) + { + w = Minecraft.getMinecraft().world; + } + return asm.apply(Animation.getWorldTime(world, Animation.getPartialTickTime())).getLeft(); + }) // TODO where should uvlock data come from? - return model.bake(ModelLoader.defaultModelGetter(), bakedTextureGetter, new ModelStateComposition(state, this.state), false, format); - } - return super.func_209581_a(originalModel, stack, world, entity); + .map(state -> model.bake(ModelLoader.defaultModelGetter(), bakedTextureGetter, new ModelStateComposition(state, this.state), false, format)) + .orElseGet(() -> super.func_209581_a(originalModel, stack, world, entity)); } } diff --git a/src/main/java/net/minecraftforge/client/model/animation/AnimationModelBase.java b/src/main/java/net/minecraftforge/client/model/animation/AnimationModelBase.java index 8af0d3881..de3a511bf 100644 --- a/src/main/java/net/minecraftforge/client/model/animation/AnimationModelBase.java +++ b/src/main/java/net/minecraftforge/client/model/animation/AnimationModelBase.java @@ -42,11 +42,8 @@ import net.minecraftforge.client.model.pipeline.VertexLighterFlat; import net.minecraftforge.client.model.pipeline.VertexBufferConsumer; import net.minecraftforge.common.animation.Event; import net.minecraftforge.common.animation.IEventHandler; -import net.minecraftforge.common.model.IModelState; import net.minecraftforge.common.model.animation.CapabilityAnimation; -import net.minecraftforge.common.model.animation.IAnimationStateMachine; -import org.apache.commons.lang3.tuple.Pair; import org.lwjgl.opengl.GL11; /** @@ -69,17 +66,18 @@ public class AnimationModelBase extends ModelBase implements I @Override public void render(Entity entity, float limbSwing, float limbSwingSpeed, float timeAlive, float yawHead, float rotationPitch, float scale) { - IAnimationStateMachine capability = entity.getCapability(CapabilityAnimation.ANIMATION_CAPABILITY, null); - if (capability == null) - { - return; - } - Pair> pair = capability.apply(timeAlive / 20); - handleEvents((T)entity, timeAlive / 20, pair.getRight()); - IUnbakedModel model = ModelLoaderRegistry.getModelOrMissing(modelLocation); - // TODO where should uvlock data come from? - IBakedModel bakedModel = model.bake(ModelLoader.defaultModelGetter(), ModelLoader.defaultTextureGetter(), pair.getLeft(), false, DefaultVertexFormats.ITEM); + entity.getCapability(CapabilityAnimation.ANIMATION_CAPABILITY, null) + .map(cap -> cap.apply(timeAlive / 20)) + .map(pair -> { + handleEvents((T) entity, timeAlive / 20, pair.getRight()); + IUnbakedModel unbaked = ModelLoaderRegistry.getModelOrMissing(modelLocation); + // TODO where should uvlock data come from? + return unbaked.bake(ModelLoader.defaultModelGetter(), ModelLoader.defaultTextureGetter(), pair.getLeft(), false, DefaultVertexFormats.ITEM); + }).ifPresent(model -> drawModel(model, entity)); + } + private void drawModel(IBakedModel bakedModel, Entity entity) + { BlockPos pos = new BlockPos(entity.posX, entity.posY + entity.height, entity.posZ); RenderHelper.disableStandardItemLighting(); @@ -109,7 +107,7 @@ public class AnimationModelBase extends ModelBase implements I } for(EnumFacing side : EnumFacing.values()) { - random.setSeed(42); + random.setSeed(42); quads = bakedModel.func_200117_a(null, side, random); if(!quads.isEmpty()) { diff --git a/src/main/java/net/minecraftforge/client/model/animation/AnimationTESR.java b/src/main/java/net/minecraftforge/client/model/animation/AnimationTESR.java index ea97d2a1e..f45614520 100644 --- a/src/main/java/net/minecraftforge/client/model/animation/AnimationTESR.java +++ b/src/main/java/net/minecraftforge/client/model/animation/AnimationTESR.java @@ -30,6 +30,7 @@ import net.minecraft.world.IWorldReader; import net.minecraftforge.client.MinecraftForgeClient; import net.minecraftforge.common.animation.Event; import net.minecraftforge.common.animation.IEventHandler; +import net.minecraftforge.common.capabilities.OptionalCapabilityInstance; import net.minecraftforge.common.model.IModelState; import net.minecraftforge.common.model.animation.CapabilityAnimation; import net.minecraftforge.common.model.animation.IAnimationStateMachine; @@ -50,7 +51,8 @@ public class AnimationTESR extends FastTESR implements @Override public void renderTileEntityFast(T te, double x, double y, double z, float partialTick, int breakStage, BufferBuilder renderer) { - if(!te.hasCapability(CapabilityAnimation.ANIMATION_CAPABILITY, null)) + OptionalCapabilityInstance cap = te.getCapability(CapabilityAnimation.ANIMATION_CAPABILITY); + if(!cap.isPresent()) { return; } @@ -60,7 +62,7 @@ public class AnimationTESR extends FastTESR implements IBlockState state = world.getBlockState(pos); if(state.getBlock().getBlockState().getProperties().contains(Properties.StaticProperty)) { - state = state.withProperty(Properties.StaticProperty, false); + state = state.func_206870_a(Properties.StaticProperty, false); } if(state instanceof IExtendedBlockState) { @@ -68,20 +70,19 @@ public class AnimationTESR extends FastTESR implements if(exState.getUnlistedNames().contains(Properties.AnimationProperty)) { float time = Animation.getWorldTime(getWorld(), partialTick); - IAnimationStateMachine capability = te.getCapability(CapabilityAnimation.ANIMATION_CAPABILITY, null); - if (capability != null) - { - Pair> pair = capability.apply(time); - handleEvents(te, time, pair.getRight()); + cap + .map(asm -> asm.apply(time)) + .ifPresent(pair -> { + handleEvents(te, time, pair.getRight()); - // TODO: caching? - IBakedModel model = blockRenderer.getBlockModelShapes().getModelForState(exState.getClean()); - exState = exState.withProperty(Properties.AnimationProperty, pair.getLeft()); + // TODO: caching? + IBakedModel model = blockRenderer.getBlockModelShapes().getModelForState(exState.getClean()); + IExtendedBlockState animState = exState.withProperty(Properties.AnimationProperty, pair.getLeft()); - renderer.setTranslation(x - pos.getX(), y - pos.getY(), z - pos.getZ()); + renderer.setTranslation(x - pos.getX(), y - pos.getY(), z - pos.getZ()); - blockRenderer.getBlockModelRenderer().func_199324_a(world, model, exState, pos, renderer, false, new Random(), 42); - } + blockRenderer.getBlockModelRenderer().func_199324_a(world, model, animState, pos, renderer, false, new Random(), 42); + }); } } } diff --git a/src/main/java/net/minecraftforge/client/resource/IResourceType.java b/src/main/java/net/minecraftforge/client/resource/IResourceType.java index 44feb8c46..ce72df31f 100644 --- a/src/main/java/net/minecraftforge/client/resource/IResourceType.java +++ b/src/main/java/net/minecraftforge/client/resource/IResourceType.java @@ -19,13 +19,13 @@ package net.minecraftforge.client.resource; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; /** * Represents a generic type of reloadable resource. Used for resource reload filtering. */ -@SideOnly(Side.CLIENT) +@OnlyIn(Dist.CLIENT) public interface IResourceType { } diff --git a/src/main/java/net/minecraftforge/client/resource/ReloadRequirements.java b/src/main/java/net/minecraftforge/client/resource/ReloadRequirements.java index bb11eaf58..5412b7553 100644 --- a/src/main/java/net/minecraftforge/client/resource/ReloadRequirements.java +++ b/src/main/java/net/minecraftforge/client/resource/ReloadRequirements.java @@ -22,15 +22,15 @@ package net.minecraftforge.client.resource; import java.util.Set; import java.util.function.Predicate; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; - import com.google.common.collect.Sets; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + /** * Holds methods to create standard predicates to select {@link IResourceType}s that should be reloaded. */ -@SideOnly(Side.CLIENT) +@OnlyIn(Dist.CLIENT) public final class ReloadRequirements { /** diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index 79094c3d1..3a2437458 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -79,6 +79,7 @@ import net.minecraft.item.ItemPotion; import net.minecraft.item.ItemSpade; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemTippedArrow; +import net.minecraft.item.ItemUseContext; import net.minecraft.item.crafting.IRecipe; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; @@ -867,8 +868,11 @@ public class ForgeHooks return event.isCanceled() ? -1 : event.getExpToDrop(); } - public static EnumActionResult onPlaceItemIntoWorld(@Nonnull ItemStack itemstack, @Nonnull EntityPlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side, float hitX, float hitY, float hitZ, @Nonnull EnumHand hand) + public static EnumActionResult onPlaceItemIntoWorld(@Nonnull ItemUseContext context) { + ItemStack itemstack = context.func_195996_i(); + World world = context.func_195991_k(); + // handle all placement events here int meta = itemstack.getItemDamage(); int size = itemstack.getCount(); @@ -883,7 +887,7 @@ public class ForgeHooks world.captureBlockSnapshots = true; } - EnumActionResult ret = itemstack.getItem().onItemUse(player, world, pos, hand, side, hitX, hitY, hitZ); + EnumActionResult ret = itemstack.getItem().func_195939_a(context); world.captureBlockSnapshots = false; if (ret == EnumActionResult.SUCCESS) @@ -902,12 +906,16 @@ public class ForgeHooks world.capturedBlockSnapshots.clear(); // make sure to set pre-placement item data for event - itemstack.setItemDamage(meta); + itemstack.func_196085_b(meta); itemstack.setCount(size); if (nbt != null) { itemstack.setTagCompound(nbt); } + + EntityPlayer player = context.func_195999_j(); + EnumFacing side = context.func_196000_l(); + if (blockSnapshots.size() > 1) { placeEvent = ForgeEventFactory.onPlayerMultiBlockPlace(player, blockSnapshots, side, hand); @@ -931,7 +939,7 @@ public class ForgeHooks else { // Change the stack to its new content - itemstack.setItemDamage(newMeta); + itemstack.func_196085_b(newMeta); itemstack.setCount(newSize); if (nbt != null) { diff --git a/src/main/java/net/minecraftforge/common/capabilities/Capability.java b/src/main/java/net/minecraftforge/common/capabilities/Capability.java index 8a5622183..086161d1a 100644 --- a/src/main/java/net/minecraftforge/common/capabilities/Capability.java +++ b/src/main/java/net/minecraftforge/common/capabilities/Capability.java @@ -135,17 +135,6 @@ public class Capability } } - /** - * Use this inside ICapabilityProvider.getCapability to avoid unchecked cast warnings. - * Example: return SOME_CAPABILITY.cast(instance); - * Use with caution; - */ - @SuppressWarnings("unchecked") - public R cast(T instance) - { - return (R)instance; - } - // INTERNAL private final String name; private final IStorage storage; diff --git a/src/main/java/net/minecraftforge/common/capabilities/CapabilityDispatcher.java b/src/main/java/net/minecraftforge/common/capabilities/CapabilityDispatcher.java index 881ff6ed5..142d8af8c 100644 --- a/src/main/java/net/minecraftforge/common/capabilities/CapabilityDispatcher.java +++ b/src/main/java/net/minecraftforge/common/capabilities/CapabilityDispatcher.java @@ -20,11 +20,14 @@ package net.minecraftforge.common.capabilities; import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + import java.util.List; import java.util.Map; import com.google.common.collect.Lists; +import mcp.MethodsReturnNonnullByDefault; import net.minecraft.nbt.INBTBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumFacing; @@ -41,6 +44,8 @@ import net.minecraftforge.common.util.INBTSerializable; * Internally the handlers are baked into arrays for fast iteration. * The ResourceLocations will be used for the NBT Key when serializing. */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault public final class CapabilityDispatcher implements INBTSerializable, ICapabilityProvider { private ICapabilityProvider[] caps; @@ -87,7 +92,7 @@ public final class CapabilityDispatcher implements INBTSerializable OptionalCapabilityInstance getCapability(Capability cap, EnumFacing side) + public OptionalCapabilityInstance getCapability(Capability cap, @Nullable EnumFacing side) { for (ICapabilityProvider c : caps) { @@ -122,7 +127,7 @@ public final class CapabilityDispatcher implements INBTSerializable OptionalCapabilityInstance getCapability(@Nonnull Capability cap, @Nullable EnumFacing side) + { + final CapabilityDispatcher disp = getCapabilities(); + return disp == null ? OptionalCapabilityInstance.empty() : disp.getCapability(cap, side); + } +} diff --git a/src/main/java/net/minecraftforge/common/capabilities/NonNullConsumer.java b/src/main/java/net/minecraftforge/common/capabilities/NonNullConsumer.java new file mode 100644 index 000000000..455149b9f --- /dev/null +++ b/src/main/java/net/minecraftforge/common/capabilities/NonNullConsumer.java @@ -0,0 +1,29 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2018. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.common.capabilities; + +import javax.annotation.Nonnull; + +//Exactly like Consumer, except there IS a contract that the parameter must not be null. +@FunctionalInterface +public interface NonNullConsumer +{ + void accept(@Nonnull T t); +} diff --git a/src/main/java/net/minecraftforge/common/capabilities/OptionalCapabilityInstance.java b/src/main/java/net/minecraftforge/common/capabilities/OptionalCapabilityInstance.java index 082d1933c..adb84861b 100644 --- a/src/main/java/net/minecraftforge/common/capabilities/OptionalCapabilityInstance.java +++ b/src/main/java/net/minecraftforge/common/capabilities/OptionalCapabilityInstance.java @@ -28,6 +28,14 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; + +import mcp.MethodsReturnNonnullByDefault; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault public class OptionalCapabilityInstance { private final NonNullSupplier supplier; @@ -35,7 +43,7 @@ public class OptionalCapabilityInstance private Set>> listeners = new HashSet<>(); private boolean isValid = true; - private static final OptionalCapabilityInstance EMPTY = new OptionalCapabilityInstance<>(null); + private static final @Nonnull OptionalCapabilityInstance EMPTY = new OptionalCapabilityInstance<>(null); @SuppressWarnings("unchecked") public static OptionalCapabilityInstance empty() @@ -49,17 +57,17 @@ public class OptionalCapabilityInstance return (OptionalCapabilityInstance)this; } - private OptionalCapabilityInstance(NonNullSupplier instanceSupplier) + private OptionalCapabilityInstance(@Nullable NonNullSupplier instanceSupplier) { this.supplier = instanceSupplier; } - public static OptionalCapabilityInstance of(final NonNullSupplier instanceSupplier) + public static OptionalCapabilityInstance of(final @Nullable NonNullSupplier instanceSupplier) { - return new OptionalCapabilityInstance<>(instanceSupplier); + return instanceSupplier == null ? EMPTY.cast() : new OptionalCapabilityInstance<>(instanceSupplier); } - private T getValue() + private @Nullable T getValue() { if (!isValid) return null; @@ -103,10 +111,11 @@ public class OptionalCapabilityInstance * @throws NullPointerException if mod object is present and {@code consumer} is * null */ - public void ifPresent(Consumer consumer) + public void ifPresent(NonNullConsumer consumer) { - if (isValid && getValue() != null) - consumer.accept(getValue()); + T val = getValue(); + if (isValid && val != null) + consumer.accept(val); } /** @@ -148,30 +157,6 @@ public class OptionalCapabilityInstance return isPresent() ? OptionalCapabilityInstance.of(()->mapper.apply(getValue())) : empty(); } - /** - * If a value is present, apply the provided {@code Optional}-bearing - * mapping function to it, return that result, otherwise return an empty - * {@code Optional}. This method is similar to {@link #map(Function)}, - * but the provided mapper is one whose result is already an {@code Optional}, - * and if invoked, {@code flatMap} does not wrap it with an additional - * {@code Optional}. - * - * @param The type parameter to the {@code Optional} returned by - * @param mapper a mapping function to apply to the mod object, if present - * the mapping function - * @return the result of applying an {@code Optional}-bearing mapping - * function to the value of this {@code Optional}, if a value is present, - * otherwise an empty {@code Optional} - * @throws NullPointerException if the mapping function is null or returns - * a null result - */ - public OptionalCapabilityInstance flatMap(Function> mapper) - {//I am not sure this is valid, or how to handle this, it's just a copy pasta from Optional. I dont think its needed. Returning a null supplier is bad - Objects.requireNonNull(mapper); - final U value = map(mapper).orElse(Optional.empty()).orElse(null); // To keep the non-null contract we have to evaluate right now. Should we allow this function at all? - return value != null ? OptionalCapabilityInstance.of(() -> value) : OptionalCapabilityInstance.empty(); - } - /** * Return the mod object if present, otherwise return {@code other}. * @@ -181,7 +166,8 @@ public class OptionalCapabilityInstance */ public T orElse(T other) { - return getValue() != null ? getValue() : other; + T val = getValue(); + return val != null ? val : other; } /** @@ -194,9 +180,10 @@ public class OptionalCapabilityInstance * @throws NullPointerException if mod object is not present and {@code other} is * null */ - public T orElseGet(Supplier other) + public T orElseGet(NonNullSupplier other) { - return getValue() != null ? getValue() : other.get(); + T val = getValue(); + return val != null ? val : other.get(); } /** @@ -217,8 +204,9 @@ public class OptionalCapabilityInstance */ public T orElseThrow(Supplier exceptionSupplier) throws X { - if (getValue() != null) - return getValue(); + T val = getValue(); + if (val != null) + return val; throw exceptionSupplier.get(); } diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeChunk.java b/src/main/java/net/minecraftforge/common/extensions/IForgeChunk.java new file mode 100644 index 000000000..8e46d4db6 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeChunk.java @@ -0,0 +1,8 @@ +package net.minecraftforge.common.extensions; + +import net.minecraftforge.common.capabilities.ICapabilityProvider; + +public interface IForgeChunk extends ICapabilityProvider +{ + +} diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeDimension.java b/src/main/java/net/minecraftforge/common/extensions/IForgeDimension.java new file mode 100644 index 000000000..78932a73c --- /dev/null +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeDimension.java @@ -0,0 +1,21 @@ +package net.minecraftforge.common.extensions; + +public interface IForgeDimension +{ + /** + * Called from {@link World#initCapabilities()}, to gather capabilities for this + * world. It's safe to access world here since this is called after world is + * registered. + * + * On server, called directly after mapStorage and world data such as Scoreboard + * and VillageCollection are initialized. On client, called when world is + * constructed, just before world load event is called. Note that this method is + * always called before the world load event. + * + * @return initial holder for capabilities on the world + */ + default net.minecraftforge.common.capabilities.ICapabilityProvider initCapabilities() + { + return null; + } +} diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeEntity.java b/src/main/java/net/minecraftforge/common/extensions/IForgeEntity.java new file mode 100644 index 000000000..15871f9e7 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeEntity.java @@ -0,0 +1,26 @@ +package net.minecraftforge.common.extensions; + +import net.minecraft.entity.Entity; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.capabilities.ICapabilitySerializable; + +public interface IForgeEntity extends ICapabilitySerializable +{ + default Entity getEntity() { return (Entity) this; } + + default void deserializeNBT(NBTTagCompound nbt) + { + getEntity().readFromNBT(nbt); + } + + default NBTTagCompound serializeNBT() + { + NBTTagCompound ret = new NBTTagCompound(); + String id = getEntity().getEntityString(); + if (id != null) + { + ret.setString("id", getEntity().getEntityString()); + } + return getEntity().writeToNBT(ret); + } +} diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeItem.java b/src/main/java/net/minecraftforge/common/extensions/IForgeItem.java new file mode 100644 index 000000000..b90506926 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeItem.java @@ -0,0 +1,758 @@ +package net.minecraftforge.common.extensions; + +import javax.annotation.Nullable; + +import com.google.common.collect.Multimap; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.ai.attributes.AttributeModifier; +import net.minecraft.entity.passive.EntityHorse; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.Items; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.IItemPropertyGetter; +import net.minecraft.item.Item; +import net.minecraft.item.ItemAxe; +import net.minecraft.item.ItemGroup; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemSword; +import net.minecraft.item.ItemUseContext; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.registry.RegistrySimple; +import net.minecraft.world.GameType; +import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +// TODO review most of the methods in this "patch" +public interface IForgeItem +{ + // Helpers for accessing Item data + default Item getItem() + { + return (Item) this; + } + + /** + * ItemStack sensitive version of getItemAttributeModifiers + */ + default Multimap getAttributeModifiers(EntityEquipmentSlot slot, ItemStack stack) + { + return getItem().getItemAttributeModifiers(slot); + } + + /** + * Called when a player drops the item into the world, returning false from this + * will prevent the item from being removed from the players inventory and + * spawning in the world + * + * @param player The player that dropped the item + * @param item The item stack, before the item is removed. + */ + default boolean onDroppedByPlayer(ItemStack item, EntityPlayer player) + { + return true; + } + + /** + * Allow the item one last chance to modify its name used for the tool highlight + * useful for adding something extra that can't be removed by a user in the + * displayed name, such as a mode of operation. + * + * @param item the ItemStack for the item. + * @param displayName the name that will be displayed unless it is changed in + * this method. + */ + default String getHighlightTip(ItemStack item, String displayName) + { + return displayName; + } + + /** + * This is called when the item is used, before the block is activated. + * + * @return Return PASS to allow vanilla handling, any other to skip normal code. + */ + default EnumActionResult onItemUseFirst(ItemUseContext context) + { + return EnumActionResult.PASS; + } + + /** + * Called by CraftingManager to determine if an item is reparable. + * + * @return True if reparable + */ + boolean isRepairable(); + + /** + * Override this method to change the NBT data being sent to the client. You + * should ONLY override this when you have no other choice, as this might change + * behavior client side! + * + * Note that this will sometimes be applied multiple times, the following MUST + * be supported: Item item = stack.getItem(); NBTTagCompound nbtShare1 = + * item.getNBTShareTag(stack); stack.setTagCompound(nbtShare1); NBTTagCompound + * nbtShare2 = item.getNBTShareTag(stack); assert nbtShare1.equals(nbtShare2); + * + * @param stack The stack to send the NBT tag for + * @return The NBT tag + */ + @Nullable + default NBTTagCompound getNBTShareTag(ItemStack stack) + { + return stack.getTagCompound(); + } + + /** + * Override this method to decide what to do with the NBT data received from + * getNBTShareTag(). + * + * @param stack The stack that received NBT + * @param nbt Received NBT, can be null + */ + default void readNBTShareTag(ItemStack stack, @Nullable NBTTagCompound nbt) + { + stack.setTagCompound(nbt); + } + + /** + * Called before a block is broken. Return true to prevent default block + * harvesting. + * + * Note: In SMP, this is called on both client and server sides! + * + * @param itemstack The current ItemStack + * @param pos Block's position in world + * @param player The Player that is wielding the item + * @return True to prevent harvesting, false to continue as normal + */ + default boolean onBlockStartBreak(ItemStack itemstack, BlockPos pos, EntityPlayer player) + { + return false; + } + + /** + * Called each tick while using an item. + * + * @param stack The Item being used + * @param player The Player using the item + * @param count The amount of time in tick the item has been used for + * continuously + */ + default void onUsingTick(ItemStack stack, EntityLivingBase player, int count) + { + } + + /** + * Called when the player Left Clicks (attacks) an entity. Processed before + * damage is done, if return value is true further processing is canceled and + * the entity is not attacked. + * + * @param stack The Item being used + * @param player The player that is attacking + * @param entity The entity being attacked + * @return True to cancel the rest of the interaction. + */ + default boolean onLeftClickEntity(ItemStack stack, EntityPlayer player, Entity entity) + { + return false; + } + + /** + * ItemStack sensitive version of getContainerItem. Returns a full ItemStack + * instance of the result. + * + * @param itemStack The current ItemStack + * @return The resulting ItemStack + */ + default ItemStack getContainerItem(ItemStack itemStack) + { + if (!hasContainerItem(itemStack)) + { + return ItemStack.EMPTY; + } + return new ItemStack(getItem().getContainerItem()); + } + + /** + * ItemStack sensitive version of hasContainerItem + * + * @param stack The current item stack + * @return True if this item has a 'container' + */ + default boolean hasContainerItem(ItemStack stack) + { + return getItem().hasContainerItem(); + } + + /** + * Retrieves the normal 'lifespan' of this item when it is dropped on the ground + * as a EntityItem. This is in ticks, standard result is 6000, or 5 mins. + * + * @param itemStack The current ItemStack + * @param world The world the entity is in + * @return The normal lifespan in ticks. + */ + default int getEntityLifespan(ItemStack itemStack, World world) + { + return 6000; + } + + /** + * Determines if this Item has a special entity for when they are in the world. + * Is called when a EntityItem is spawned in the world, if true and + * Item#createCustomEntity returns non null, the EntityItem will be destroyed + * and the new Entity will be added to the world. + * + * @param stack The current item stack + * @return True of the item has a custom entity, If true, + * Item#createCustomEntity will be called + */ + default boolean hasCustomEntity(ItemStack stack) + { + return false; + } + + /** + * This function should return a new entity to replace the dropped item. + * Returning null here will not kill the EntityItem and will leave it to + * function normally. Called when the item it placed in a world. + * + * @param world The world object + * @param location The EntityItem object, useful for getting the position of + * the entity + * @param itemstack The current item stack + * @return A new Entity object to spawn or null + */ + @Nullable + default Entity createEntity(World world, Entity location, ItemStack itemstack) + { + return null; + } + + /** + * Called by the default implemetation of EntityItem's onUpdate method, allowing + * for cleaner control over the update of the item without having to write a + * subclass. + * + * @param entityItem The entity Item + * @return Return true to skip any further update code. + */ + default boolean onEntityItemUpdate(net.minecraft.entity.item.EntityItem entityItem) + { + return false; + } + + /** + * Gets a list of tabs that items belonging to this class can display on, + * combined properly with getSubItems allows for a single item to span many + * sub-items across many tabs. + * + * @return A list of all tabs that this item could possibly be one. + */ + default java.util.Collection getCreativeTabs() + { + return java.util.Collections.singletonList(getItem().getCreativeTab()); + } + + /** + * Determines the base experience for a player when they remove this item from a + * furnace slot. This number must be between 0 and 1 for it to be valid. This + * number will be multiplied by the stack size to get the total experience. + * + * @param item The item stack the player is picking up. + * @return The amount to award for each item. + */ + default float getSmeltingExperience(ItemStack item) + { + return -1; // -1 will default to the old lookups. + } + + /** + * + * Should this item, when held, allow sneak-clicks to pass through to the + * underlying block? + * + * @param world The world + * @param pos Block position in world + * @param player The Player that is wielding the item + * @return + */ + default boolean doesSneakBypassUse(ItemStack stack, net.minecraft.world.IWorldReader world, BlockPos pos, EntityPlayer player) + { + return false; + } + + /** + * Called to tick armor in the armor slot. Override to do something + */ + default void onArmorTick(World world, EntityPlayer player, ItemStack itemStack) + { + } + + /** + * Determines if the specific ItemStack can be placed in the specified armor + * slot, for the entity. + * + * TODO: Change name to canEquip in 1.13? + * + * @param stack The ItemStack + * @param armorType Armor slot to be verified. + * @param entity The entity trying to equip the armor + * @return True if the given ItemStack can be inserted in the slot + */ + default boolean isValidArmor(ItemStack stack, EntityEquipmentSlot armorType, Entity entity) + { + return net.minecraft.entity.EntityLiving.getSlotForItemStack(stack) == armorType; + } + + /** + * Override this to set a non-default armor slot for an ItemStack, but do + * not use this to get the armor slot of said stack; for that, use + * {@link net.minecraft.entity.EntityLiving#getSlotForItemStack(ItemStack)}. + * + * @param stack the ItemStack + * @return the armor slot of the ItemStack, or {@code null} to let the default + * vanilla logic as per {@code EntityLiving.getSlotForItemStack(stack)} + * decide + */ + @Nullable + default EntityEquipmentSlot getEquipmentSlot(ItemStack stack) + { + return null; + } + + /** + * Allow or forbid the specific book/item combination as an anvil enchant + * + * @param stack The item + * @param book The book + * @return if the enchantment is allowed + */ + default boolean isBookEnchantable(ItemStack stack, ItemStack book) + { + return true; + } + + /** + * Called by RenderBiped and RenderPlayer to determine the armor texture that + * should be use for the currently equipped item. This will only be called on + * instances of ItemArmor. + * + * Returning null from this function will use the default value. + * + * @param stack ItemStack for the equipped armor + * @param entity The entity wearing the armor + * @param slot The slot the armor is in + * @param type The subtype, can be null or "overlay" + * @return Path of texture to bind, or null to use default + */ + @Nullable + default String getArmorTexture(ItemStack stack, Entity entity, EntityEquipmentSlot slot, String type) + { + return null; + } + + /** + * Returns the font renderer used to render tooltips and overlays for this item. + * Returning null will use the standard font renderer. + * + * @param stack The current item stack + * @return A instance of FontRenderer or null to use default + */ + @OnlyIn(Dist.CLIENT) + @Nullable + default net.minecraft.client.gui.FontRenderer getFontRenderer(ItemStack stack) + { + return null; + } + + /** + * Override this method to have an item handle its own armor rendering. + * + * @param entityLiving The entity wearing the armor + * @param itemStack The itemStack to render the model of + * @param armorSlot The slot the armor is in + * @param _default Original armor model. Will have attributes set. + * @return A ModelBiped to render instead of the default + */ + @OnlyIn(Dist.CLIENT) + @Nullable + default net.minecraft.client.renderer.entity.model.ModelBiped getArmorModel(EntityLivingBase entityLiving, ItemStack itemStack, + EntityEquipmentSlot armorSlot, net.minecraft.client.renderer.entity.model.ModelBiped _default) + { + return null; + } + + /** + * Called when a entity tries to play the 'swing' animation. + * + * @param entityLiving The entity swinging the item. + * @param stack The Item stack + * @return True to cancel any further processing by EntityLiving + */ + default boolean onEntitySwing(EntityLivingBase entityLiving, ItemStack stack) + { + return false; + } + + /** + * Called when the client starts rendering the HUD, for whatever item the player + * currently has as a helmet. This is where pumpkins would render there overlay. + * + * @param stack The ItemStack that is equipped + * @param player Reference to the current client entity + * @param resolution Resolution information about the current viewport and + * configured GUI Scale + * @param partialTicks Partial ticks for the renderer, useful for interpolation + */ + @OnlyIn(Dist.CLIENT) + default void renderHelmetOverlay(ItemStack stack, EntityPlayer player, int width, int height, float partialTicks) + { + } + + /** + * Return the itemDamage represented by this ItemStack. Defaults to the Damage + * entry in the stack NBT, but can be overridden here for other sources. + * + * @param stack The itemstack that is damaged + * @return the damage value + */ + default int getDamage(ItemStack stack) + { + return !stack.hasTagCompound() ? 0 : stack.getTagCompound().getInteger("Damage"); + } + + /** + * Determines if the durability bar should be rendered for this item. Defaults + * to vanilla stack.isDamaged behavior. But modders can use this for any data + * they wish. + * + * @param stack The current Item Stack + * @return True if it should render the 'durability' bar. + */ + default boolean showDurabilityBar(ItemStack stack) + { + return stack.isItemDamaged(); + } + + /** + * Queries the percentage of the 'Durability' bar that should be drawn. + * + * @param stack The current ItemStack + * @return 0.0 for 100% (no damage / full bar), 1.0 for 0% (fully damaged / + * empty bar) + */ + default double getDurabilityForDisplay(ItemStack stack) + { + return (double) stack.getItemDamage() / (double) stack.getMaxDamage(); + } + + /** + * Returns the packed int RGB value used to render the durability bar in the + * GUI. Defaults to a value based on the hue scaled based on + * {@link #getDurabilityForDisplay}, but can be overriden. + * + * @param stack Stack to get durability from + * @return A packed RGB value for the durability colour (0x00RRGGBB) + */ + default int getRGBDurabilityForDisplay(ItemStack stack) + { + return MathHelper.hsvToRGB(Math.max(0.0F, (float) (1.0F - getDurabilityForDisplay(stack))) / 3.0F, 1.0F, 1.0F); + } + + /** + * Return the maxDamage for this ItemStack. Defaults to the maxDamage field in + * this item, but can be overridden here for other sources such as NBT. + * + * @param stack The itemstack that is damaged + * @return the damage value + */ + default int getMaxDamage(ItemStack stack) + { + return getItem().getMaxDamage(); + } + + /** + * Return if this itemstack is damaged. Note only called if + * {@link #isDamageable()} is true. + * + * @param stack the stack + * @return if the stack is damaged + */ + default boolean isDamaged(ItemStack stack) + { + return stack.getItemDamage() > 0; + } + + /** + * Set the damage for this itemstack. Note, this method is responsible for zero + * checking. + * + * @param stack the stack + * @param damage the new damage value + */ + default void setDamage(ItemStack stack, int damage) + { + stack.func_196082_o().setInteger("Damage", Math.max(0, damage)); + } + + /** + * Checked from + * {@link net.minecraft.client.multiplayer.PlayerControllerMP#onPlayerDestroyBlock(BlockPos pos) + * PlayerControllerMP.onPlayerDestroyBlock()} when a creative player left-clicks + * a block with this item. Also checked from + * {@link net.minecraftforge.common.ForgeHooks#onBlockBreakEvent(World, GameType, EntityPlayerMP, BlockPos) + * ForgeHooks.onBlockBreakEvent()} to prevent sending an event. + * + * @return true if the given player can destroy specified block in creative mode + * with this item + */ + default boolean canDestroyBlockInCreative(World world, BlockPos pos, ItemStack stack, EntityPlayer player) + { + return !(this instanceof ItemSword); + } + + /** + * ItemStack sensitive version of {@link #canHarvestBlock(IBlockState)} + * + * @param state The block trying to harvest + * @param stack The itemstack used to harvest the block + * @return true if can harvest the block + */ + default boolean canHarvestBlock(IBlockState state, ItemStack stack) + { + return getItem().canHarvestBlock(state); + } + + /** + * Gets the maximum number of items that this stack should be able to hold. This + * is a ItemStack (and thus NBT) sensitive version of Item.getItemStackLimit() + * + * @param stack The ItemStack + * @return The maximum number this item can be stacked to + */ + default int getItemStackLimit(ItemStack stack) + { + return getItem().getItemStackLimit(); + } + + java.util.Set getToolClasses(ItemStack stack); + + /** + * Queries the harvest level of this item stack for the specified tool class, + * Returns -1 if this tool is not of the specified type + * + * @param stack This item stack instance + * @param toolClass Tool Class + * @param player The player trying to harvest the given blockstate + * @param blockState The block to harvest + * @return Harvest level, or -1 if not the specified tool type. + */ + int getHarvestLevel(ItemStack stack, String toolClass, @Nullable EntityPlayer player, @Nullable IBlockState blockState); + + /** + * ItemStack sensitive version of getItemEnchantability + * + * @param stack The ItemStack + * @return the item echantability value + */ + default int getItemEnchantability(ItemStack stack) + { + return getItem().getItemEnchantability(); + } + + /** + * Checks whether an item can be enchanted with a certain enchantment. This + * applies specifically to enchanting an item in the enchanting table and is + * called when retrieving the list of possible enchantments for an item. + * Enchantments may additionally (or exclusively) be doing their own checks in + * {@link net.minecraft.enchantment.Enchantment#canApplyAtEnchantingTable(ItemStack)}; + * check the individual implementation for reference. By default this will check + * if the enchantment type is valid for this item type. + * + * @param stack the item stack to be enchanted + * @param enchantment the enchantment to be applied + * @return true if the enchantment can be applied to this item + */ + default boolean canApplyAtEnchantingTable(ItemStack stack, net.minecraft.enchantment.Enchantment enchantment) + { + return enchantment.type.canEnchantItem(stack.getItem()); + } + + /** + * Whether this Item can be used as a payment to activate the vanilla beacon. + * + * @param stack the ItemStack + * @return true if this Item can be used + */ + default boolean isBeaconPayment(ItemStack stack) + { + return this == Items.EMERALD || this == Items.DIAMOND || this == Items.GOLD_INGOT || this == Items.IRON_INGOT; + } + + /** + * Determine if the player switching between these two item stacks + * + * @param oldStack The old stack that was equipped + * @param newStack The new stack + * @param slotChanged If the current equipped slot was changed, Vanilla does not + * play the animation if you switch between two slots that + * hold the exact same item. + * @return True to play the item change animation + */ + default boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) + { + return !oldStack.equals(newStack); // !ItemStack.areItemStacksEqual(oldStack, newStack); + } + + /** + * Called when the player is mining a block and the item in his hand changes. + * Allows to not reset blockbreaking if only NBT or similar changes. + * + * @param oldStack The old stack that was used for mining. Item in players main + * hand + * @param newStack The new stack + * @return True to reset block break progress + */ + default boolean shouldCauseBlockBreakReset(ItemStack oldStack, ItemStack newStack) + { + return !(newStack.getItem() == oldStack.getItem() && ItemStack.areItemStackTagsEqual(newStack, oldStack) + && (newStack.isItemStackDamageable() || newStack.getItemDamage() == oldStack.getItemDamage())); + } + + /** + * Called to get the Mod ID of the mod that *created* the ItemStack, instead of + * the real Mod ID that *registered* it. + * + * For example the Forge Universal Bucket creates a subitem for each modded + * fluid, and it returns the modded fluid's Mod ID here. + * + * Mods that register subitems for other mods can override this. Informational + * mods can call it to show the mod that created the item. + * + * @param itemStack the ItemStack to check + * @return the Mod ID for the ItemStack, or null when there is no specially + * associated mod and {@link #getRegistryName()} would return null. + */ + @Nullable + default String getCreatorModId(ItemStack itemStack) + { + return net.minecraftforge.common.ForgeHooks.getDefaultCreatorModId(itemStack); + } + + /** + * Called from ItemStack.setItem, will hold extra data for the life of this + * ItemStack. Can be retrieved from stack.getCapabilities() The NBT can be null + * if this is not called from readNBT or if the item the stack is changing FROM + * is different then this item, or the previous item had no capabilities. + * + * This is called BEFORE the stacks item is set so you can use stack.getItem() + * to see the OLD item. Remember that getItem CAN return null. + * + * @param stack The ItemStack + * @param nbt NBT of this item serialized, or null. + * @return A holder instance associated with this ItemStack where you can hold + * capabilities for the life of this item. + */ + @Nullable + default net.minecraftforge.common.capabilities.ICapabilityProvider initCapabilities(ItemStack stack, @Nullable NBTTagCompound nbt) + { + return null; + } + + default com.google.common.collect.ImmutableMap getAnimationParameters(final ItemStack stack, + final World world, final EntityLivingBase entity) + { + com.google.common.collect.ImmutableMap.Builder builder = com.google.common.collect.ImmutableMap + .builder(); + for (ResourceLocation location : ((RegistrySimple) getItem().properties).getKeys()) + { + final IItemPropertyGetter parameter = getItem().properties.getObject(location); + builder.put(location.toString(), input -> parameter.call(stack, world, entity)); + } + return builder.build(); + } + + /** + * Can this Item disable a shield + * + * @param stack The ItemStack + * @param shield The shield in question + * @param entity The EntityLivingBase holding the shield + * @param attacker The EntityLivingBase holding the ItemStack + * @retrun True if this ItemStack can disable the shield in question. + */ + default boolean canDisableShield(ItemStack stack, ItemStack shield, EntityLivingBase entity, EntityLivingBase attacker) + { + return this instanceof ItemAxe; + } + + /** + * Is this Item a shield + * + * @param stack The ItemStack + * @param entity The Entity holding the ItemStack + * @return True if the ItemStack is considered a shield + */ + default boolean isShield(ItemStack stack, @Nullable EntityLivingBase entity) + { + return stack.getItem() == Items.SHIELD; + } + + /** + * @return the fuel burn time for this itemStack in a furnace. Return 0 to make + * it not act as a fuel. Return -1 to let the default vanilla logic + * decide. + */ + default int getItemBurnTime(ItemStack itemStack) + { + return -1; + } + + /** + * Returns an enum constant of type {@code HorseArmorType}. The returned enum + * constant will be used to determine the armor value and texture of this item + * when equipped. + * + * @param stack the armor stack + * @return an enum constant of type {@code HorseArmorType}. Return + * HorseArmorType.NONE if this is not horse armor + */ + default net.minecraft.entity.passive.HorseArmorType getHorseArmorType(ItemStack stack) + { + return net.minecraft.entity.passive.HorseArmorType.getByItem(stack.getItem()); + } + + default String getHorseArmorTexture(net.minecraft.entity.EntityLiving wearer, ItemStack stack) + { + return getHorseArmorType(stack).getTextureName(); + } + + /** + * Called every tick from {@link EntityHorse#onUpdate()} on the item in the + * armor slot. + * + * @param world the world the horse is in + * @param horse the horse wearing this armor + * @param armor the armor itemstack + */ + default void onHorseArmorTick(World world, net.minecraft.entity.EntityLiving horse, ItemStack armor) + { + } + + /** + * @return This Item's renderer, or the default instance if it does not have + * one. + */ + @OnlyIn(Dist.CLIENT) + net.minecraft.client.renderer.tileentity.TileEntityItemStackRenderer getTileEntityItemStackRenderer(); +} diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeTileEntity.java b/src/main/java/net/minecraftforge/common/extensions/IForgeTileEntity.java new file mode 100644 index 000000000..aacf7787e --- /dev/null +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeTileEntity.java @@ -0,0 +1,24 @@ +package net.minecraftforge.common.extensions; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.capabilities.ICapabilitySerializable; + +public interface IForgeTileEntity extends ICapabilitySerializable +{ + default TileEntity getTileEntity() { return (TileEntity) this; } + + @Override + default void deserializeNBT(NBTTagCompound nbt) + { + getTileEntity().readFromNBT(nbt); + } + + @Override + default NBTTagCompound serializeNBT() + { + NBTTagCompound ret = new NBTTagCompound(); + getTileEntity().writeToNBT(ret); + return ret; + } +} diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeVillage.java b/src/main/java/net/minecraftforge/common/extensions/IForgeVillage.java new file mode 100644 index 000000000..22fbbacee --- /dev/null +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeVillage.java @@ -0,0 +1,27 @@ +package net.minecraftforge.common.extensions; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.village.Village; +import net.minecraftforge.common.capabilities.ICapabilitySerializable; + +public interface IForgeVillage extends ICapabilitySerializable +{ + default Village getVillage() + { + return (Village) this; + } + + @Override + default void deserializeNBT(NBTTagCompound nbt) + { + getVillage().readVillageDataFromNBT(nbt); + } + + @Override + default NBTTagCompound serializeNBT() + { + NBTTagCompound ret = new NBTTagCompound(); + getVillage().writeVillageDataToNBT(ret); + return ret; + } +} diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeWorld.java b/src/main/java/net/minecraftforge/common/extensions/IForgeWorld.java new file mode 100644 index 000000000..59b12bdc9 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeWorld.java @@ -0,0 +1,8 @@ +package net.minecraftforge.common.extensions; + +import net.minecraftforge.common.capabilities.ICapabilityProvider; + +public interface IForgeWorld extends ICapabilityProvider +{ + +} diff --git a/src/main/java/net/minecraftforge/common/model/animation/CapabilityAnimation.java b/src/main/java/net/minecraftforge/common/model/animation/CapabilityAnimation.java index 635e4fa3a..f03e9cab3 100644 --- a/src/main/java/net/minecraftforge/common/model/animation/CapabilityAnimation.java +++ b/src/main/java/net/minecraftforge/common/model/animation/CapabilityAnimation.java @@ -60,14 +60,14 @@ public class CapabilityAnimation } @Override - @Nullable + @Nonnull public OptionalCapabilityInstance getCapability(@Nonnull Capability capability, @Nullable EnumFacing facing) { if(capability == ANIMATION_CAPABILITY) { - return ANIMATION_CAPABILITY.cast(asm); + return OptionalCapabilityInstance.of(() -> asm).cast(); } - return null; + return OptionalCapabilityInstance.empty(); } } } diff --git a/src/main/java/net/minecraftforge/common/property/Properties.java b/src/main/java/net/minecraftforge/common/property/Properties.java index 0a3c649a8..e9941e61d 100644 --- a/src/main/java/net/minecraftforge/common/property/Properties.java +++ b/src/main/java/net/minecraftforge/common/property/Properties.java @@ -19,8 +19,8 @@ package net.minecraftforge.common.property; -import net.minecraft.block.properties.IProperty; -import net.minecraft.block.properties.PropertyBool; +import net.minecraft.state.BooleanProperty; +import net.minecraft.state.IProperty; import net.minecraftforge.common.model.IModelState; public class Properties @@ -28,7 +28,7 @@ public class Properties /** * Property indicating if the model should be rendered in the static renderer or in the TESR. AnimationTESR sets it to false. */ - public static final PropertyBool StaticProperty = PropertyBool.create("static"); + public static final BooleanProperty StaticProperty = BooleanProperty.create("static"); /** * Property holding the IModelState used for animating the model in the TESR. diff --git a/src/main/java/net/minecraftforge/common/util/WorldCapabilityData.java b/src/main/java/net/minecraftforge/common/util/WorldCapabilityData.java index 04c925da4..43b21de11 100644 --- a/src/main/java/net/minecraftforge/common/util/WorldCapabilityData.java +++ b/src/main/java/net/minecraftforge/common/util/WorldCapabilityData.java @@ -19,8 +19,10 @@ package net.minecraftforge.common.util; +import javax.annotation.Nullable; + import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.world.WorldProvider; +import net.minecraft.world.dimension.Dimension; import net.minecraft.world.storage.WorldSavedData; public class WorldCapabilityData extends WorldSavedData @@ -35,7 +37,7 @@ public class WorldCapabilityData extends WorldSavedData super(name); } - public WorldCapabilityData(INBTSerializable serializable) + public WorldCapabilityData(@Nullable INBTSerializable serializable) { super(ID); this.serializable = serializable; @@ -66,7 +68,7 @@ public class WorldCapabilityData extends WorldSavedData return true; } - public void setCapabilities(WorldProvider provider, INBTSerializable capabilities) + public void setCapabilities(Dimension provider, INBTSerializable capabilities) { this.serializable = capabilities; if (this.capNBT != null && serializable != null) diff --git a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java index 73b86a3c2..98f91cbf8 100644 --- a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java +++ b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java @@ -328,9 +328,9 @@ public class ForgeEventFactory return event.getNewState(); } - public static ItemTooltipEvent onItemTooltip(ItemStack itemStack, @Nullable EntityPlayer entityPlayer, List toolTip, ITooltipFlag flags) + public static ItemTooltipEvent onItemTooltip(ItemStack itemStack, @Nullable EntityPlayer entityPlayer, List list, ITooltipFlag flags) { - ItemTooltipEvent event = new ItemTooltipEvent(itemStack, entityPlayer, toolTip, flags); + ItemTooltipEvent event = new ItemTooltipEvent(itemStack, entityPlayer, list, flags); MinecraftForge.EVENT_BUS.post(event); return event; } @@ -624,41 +624,18 @@ public class ForgeEventFactory { return MinecraftForge.EVENT_BUS.post(new RenderBlockOverlayEvent(player, renderPartialTicks, type, block, pos)); } - + @Nullable - public static CapabilityDispatcher gatherCapabilities(TileEntity tileEntity) + public static CapabilityDispatcher gatherCapabilities(Class type, T provider) { - return gatherCapabilities(new AttachCapabilitiesEvent(TileEntity.class, tileEntity), null); + return gatherCapabilities(type, provider, null); } - + + @SuppressWarnings("unchecked") @Nullable - public static CapabilityDispatcher gatherCapabilities(Entity entity) + public static CapabilityDispatcher gatherCapabilities(Class type, T provider, @Nullable ICapabilityProvider parent) { - return gatherCapabilities(new AttachCapabilitiesEvent(Entity.class, entity), null); - } - - @Nullable - public static CapabilityDispatcher gatherCapabilities(Village village) - { - return gatherCapabilities(new AttachCapabilitiesEvent(Village.class, village), null); - } - - @Nullable - public static CapabilityDispatcher gatherCapabilities(ItemStack stack, ICapabilityProvider parent) - { - return gatherCapabilities(new AttachCapabilitiesEvent(ItemStack.class, stack), parent); - } - - @Nullable - public static CapabilityDispatcher gatherCapabilities(World world, ICapabilityProvider parent) - { - return gatherCapabilities(new AttachCapabilitiesEvent(World.class, world), parent); - } - - @Nullable - public static CapabilityDispatcher gatherCapabilities(Chunk chunk) - { - return gatherCapabilities(new AttachCapabilitiesEvent(Chunk.class, chunk), null); + return gatherCapabilities(new AttachCapabilitiesEvent((Class) type, provider), parent); } @Nullable diff --git a/src/main/java/net/minecraftforge/event/entity/player/ItemTooltipEvent.java b/src/main/java/net/minecraftforge/event/entity/player/ItemTooltipEvent.java index 34d522cab..6af9ba6fc 100644 --- a/src/main/java/net/minecraftforge/event/entity/player/ItemTooltipEvent.java +++ b/src/main/java/net/minecraftforge/event/entity/player/ItemTooltipEvent.java @@ -25,6 +25,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; +import net.minecraft.util.text.ITextComponent; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -34,17 +35,17 @@ public class ItemTooltipEvent extends PlayerEvent private final ITooltipFlag flags; @Nonnull private final ItemStack itemStack; - private final List toolTip; + private final List toolTip; /** * This event is fired in {@link ItemStack#getTooltip(EntityPlayer, ITooltipFlag)}, which in turn is called from it's respective GUIContainer. * Tooltips are also gathered with a null entityPlayer during startup by {@link Minecraft#populateSearchTreeManager()}. */ - public ItemTooltipEvent(@Nonnull ItemStack itemStack, @Nullable EntityPlayer entityPlayer, List toolTip, ITooltipFlag flags) + public ItemTooltipEvent(@Nonnull ItemStack itemStack, @Nullable EntityPlayer entityPlayer, List list, ITooltipFlag flags) { super(entityPlayer); this.itemStack = itemStack; - this.toolTip = toolTip; + this.toolTip = list; this.flags = flags; } @@ -68,7 +69,7 @@ public class ItemTooltipEvent extends PlayerEvent /** * The {@link ItemStack} tooltip. */ - public List getToolTip() + public List getToolTip() { return toolTip; } diff --git a/src/main/java/net/minecraftforge/fluids/FluidUtil.java b/src/main/java/net/minecraftforge/fluids/FluidUtil.java index b741355b2..608c99955 100644 --- a/src/main/java/net/minecraftforge/fluids/FluidUtil.java +++ b/src/main/java/net/minecraftforge/fluids/FluidUtil.java @@ -24,7 +24,6 @@ import javax.annotation.Nullable; import com.google.common.base.Preconditions; import net.minecraft.block.Block; -import net.minecraft.block.BlockLiquid; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.player.EntityPlayer; @@ -40,6 +39,7 @@ import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.common.ForgeMod; +import net.minecraftforge.common.capabilities.OptionalCapabilityInstance; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandlerItem; @@ -74,8 +74,7 @@ public class FluidUtil Preconditions.checkNotNull(world); Preconditions.checkNotNull(pos); - IFluidHandler blockFluidHandler = getFluidHandler(world, pos, side); - return blockFluidHandler != null && interactWithFluidHandler(player, hand, blockFluidHandler); + return getFluidHandler(world, pos, side).map(handler -> interactWithFluidHandler(player, hand, handler)).orElse(false); } /** @@ -98,21 +97,23 @@ public class FluidUtil ItemStack heldItem = player.getHeldItem(hand); if (!heldItem.isEmpty()) { - IItemHandler playerInventory = player.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null); - if (playerInventory != null) - { - FluidActionResult fluidActionResult = tryFillContainerAndStow(heldItem, handler, playerInventory, Integer.MAX_VALUE, player, true); - if (!fluidActionResult.isSuccess()) - { - fluidActionResult = tryEmptyContainerAndStow(heldItem, handler, playerInventory, Integer.MAX_VALUE, player, true); - } - - if (fluidActionResult.isSuccess()) - { - player.setHeldItem(hand, fluidActionResult.getResult()); - return true; - } - } + return player.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) + .map(playerInventory -> { + + FluidActionResult fluidActionResult = tryFillContainerAndStow(heldItem, handler, playerInventory, Integer.MAX_VALUE, player, true); + if (!fluidActionResult.isSuccess()) + { + fluidActionResult = tryEmptyContainerAndStow(heldItem, handler, playerInventory, Integer.MAX_VALUE, player, true); + } + + if (fluidActionResult.isSuccess()) + { + player.setHeldItem(hand, fluidActionResult.getResult()); + return true; + } + return false; + }) + .orElse(false); } return false; } @@ -133,31 +134,31 @@ public class FluidUtil public static FluidActionResult tryFillContainer(@Nonnull ItemStack container, IFluidHandler fluidSource, int maxAmount, @Nullable EntityPlayer player, boolean doFill) { ItemStack containerCopy = ItemHandlerHelper.copyStackWithSize(container, 1); // do not modify the input - IFluidHandlerItem containerFluidHandler = getFluidHandler(containerCopy); - if (containerFluidHandler != null) - { - FluidStack simulatedTransfer = tryFluidTransfer(containerFluidHandler, fluidSource, maxAmount, false); - if (simulatedTransfer != null) - { - if (doFill) - { - tryFluidTransfer(containerFluidHandler, fluidSource, maxAmount, true); - if (player != null) + return getFluidHandler(containerCopy) + .map(containerFluidHandler -> { + FluidStack simulatedTransfer = tryFluidTransfer(containerFluidHandler, fluidSource, maxAmount, false); + if (simulatedTransfer != null) { - SoundEvent soundevent = simulatedTransfer.getFluid().getFillSound(simulatedTransfer); - player.world.playSound(null, player.posX, player.posY + 0.5, player.posZ, soundevent, SoundCategory.BLOCKS, 1.0F, 1.0F); + if (doFill) + { + tryFluidTransfer(containerFluidHandler, fluidSource, maxAmount, true); + if (player != null) + { + SoundEvent soundevent = simulatedTransfer.getFluid().getFillSound(simulatedTransfer); + player.world.playSound(null, player.posX, player.posY + 0.5, player.posZ, soundevent, SoundCategory.BLOCKS, 1.0F, 1.0F); + } + } + else + { + containerFluidHandler.fill(simulatedTransfer, true); + } + + ItemStack resultContainer = containerFluidHandler.getContainer(); + return new FluidActionResult(resultContainer); } - } - else - { - containerFluidHandler.fill(simulatedTransfer, true); - } - - ItemStack resultContainer = containerFluidHandler.getContainer(); - return new FluidActionResult(resultContainer); - } - } - return FluidActionResult.FAILURE; + return FluidActionResult.FAILURE; + }) + .orElse(FluidActionResult.FAILURE); } /** @@ -177,35 +178,35 @@ public class FluidUtil public static FluidActionResult tryEmptyContainer(@Nonnull ItemStack container, IFluidHandler fluidDestination, int maxAmount, @Nullable EntityPlayer player, boolean doDrain) { ItemStack containerCopy = ItemHandlerHelper.copyStackWithSize(container, 1); // do not modify the input - IFluidHandlerItem containerFluidHandler = getFluidHandler(containerCopy); - if (containerFluidHandler != null) - { - if (doDrain) - { - FluidStack transfer = tryFluidTransfer(fluidDestination, containerFluidHandler, maxAmount, true); - if (transfer != null) - { - if (player != null) + return getFluidHandler(containerCopy) + .map(containerFluidHandler -> { + if (doDrain) { - SoundEvent soundevent = transfer.getFluid().getEmptySound(transfer); - player.world.playSound(null, player.posX, player.posY + 0.5, player.posZ, soundevent, SoundCategory.BLOCKS, 1.0F, 1.0F); + FluidStack transfer = tryFluidTransfer(fluidDestination, containerFluidHandler, maxAmount, true); + if (transfer != null) + { + if (player != null) + { + SoundEvent soundevent = transfer.getFluid().getEmptySound(transfer); + player.world.playSound(null, player.posX, player.posY + 0.5, player.posZ, soundevent, SoundCategory.BLOCKS, 1.0F, 1.0F); + } + ItemStack resultContainer = containerFluidHandler.getContainer(); + return new FluidActionResult(resultContainer); + } } - ItemStack resultContainer = containerFluidHandler.getContainer(); - return new FluidActionResult(resultContainer); - } - } - else - { - FluidStack simulatedTransfer = tryFluidTransfer(fluidDestination, containerFluidHandler, maxAmount, false); - if (simulatedTransfer != null) - { - containerFluidHandler.drain(simulatedTransfer, true); - ItemStack resultContainer = containerFluidHandler.getContainer(); - return new FluidActionResult(resultContainer); - } - } - } - return FluidActionResult.FAILURE; + else + { + FluidStack simulatedTransfer = tryFluidTransfer(fluidDestination, containerFluidHandler, maxAmount, false); + if (simulatedTransfer != null) + { + containerFluidHandler.drain(simulatedTransfer, true); + ItemStack resultContainer = containerFluidHandler.getContainer(); + return new FluidActionResult(resultContainer); + } + } + return FluidActionResult.FAILURE; + }) + .orElse(FluidActionResult.FAILURE); } /** @@ -478,47 +479,30 @@ public class FluidUtil * You can't fill or drain multiple items at once, if you do then liquid is multiplied or destroyed. * * Vanilla buckets will be converted to universal buckets if they are enabled. - * - * Returns null if the itemStack passed in does not have a fluid handler. */ - @Nullable - public static IFluidHandlerItem getFluidHandler(@Nonnull ItemStack itemStack) + public static OptionalCapabilityInstance getFluidHandler(@Nonnull ItemStack itemStack) { - if (itemStack.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, null)) - { - return itemStack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, null); - } - else - { - return null; - } + return itemStack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY); } /** * Helper method to get the fluid contained in an itemStack */ - @Nullable - public static FluidStack getFluidContained(@Nonnull ItemStack container) + public static OptionalCapabilityInstance getFluidContained(@Nonnull ItemStack container) { if (!container.isEmpty()) { container = ItemHandlerHelper.copyStackWithSize(container, 1); - IFluidHandlerItem fluidHandler = getFluidHandler(container); - if (fluidHandler != null) - { - return fluidHandler.drain(Integer.MAX_VALUE, false); - } + return getFluidHandler(container) + .map(handler -> handler.drain(Integer.MAX_VALUE, false)); } - return null; + return OptionalCapabilityInstance.empty(); } /** * Helper method to get an IFluidHandler for at a block position. - * - * Returns null if there is no valid fluid handler. */ - @Nullable - public static IFluidHandler getFluidHandler(World world, BlockPos blockPos, @Nullable EnumFacing side) + public static OptionalCapabilityInstance getFluidHandler(World world, BlockPos blockPos, @Nullable EnumFacing side) { IBlockState state = world.getBlockState(blockPos); Block block = state.getBlock(); @@ -526,21 +510,21 @@ public class FluidUtil if (block.hasTileEntity(state)) { TileEntity tileEntity = world.getTileEntity(blockPos); - if (tileEntity != null && tileEntity.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, side)) + if (tileEntity != null) { return tileEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, side); } - } + }/* TODO fluids blocks? if (block instanceof IFluidBlock) { - return new FluidBlockWrapper((IFluidBlock) block, world, blockPos); + return OptionalCapabilityInstance.of(() -> new FluidBlockWrapper((IFluidBlock) block, world, blockPos)); } else if (block instanceof BlockLiquid) { - return new BlockLiquidWrapper((BlockLiquid) block, world, blockPos); + return OptionalCapabilityInstance.of(() -> new BlockLiquidWrapper((BlockLiquid) block, world, blockPos)); } - - return null; +*/ + return OptionalCapabilityInstance.empty(); } /** @@ -565,6 +549,7 @@ public class FluidUtil IBlockState state = worldIn.getBlockState(pos); Block block = state.getBlock(); + /* TODO fluid blocks? if (block instanceof IFluidBlock || block instanceof BlockLiquid) { IFluidHandler targetFluidHandler = getFluidHandler(worldIn, pos, side); @@ -572,7 +557,7 @@ public class FluidUtil { return tryFillContainer(emptyContainer, targetFluidHandler, Integer.MAX_VALUE, playerIn, true); } - } + }*/ return FluidActionResult.FAILURE; } @@ -591,12 +576,11 @@ public class FluidUtil public static FluidActionResult tryPlaceFluid(@Nullable EntityPlayer player, World world, BlockPos pos, @Nonnull ItemStack container, FluidStack resource) { ItemStack containerCopy = ItemHandlerHelper.copyStackWithSize(container, 1); // do not modify the input - IFluidHandlerItem containerFluidHandler = getFluidHandler(containerCopy); - if (containerFluidHandler != null && tryPlaceFluid(player, world, pos, containerFluidHandler, resource)) - { - return new FluidActionResult(containerFluidHandler.getContainer()); - } - return FluidActionResult.FAILURE; + return getFluidHandler(containerCopy) + .filter(handler -> tryPlaceFluid(player, world, pos, handler, resource)) + .map(IFluidHandlerItem::getContainer) + .map(FluidActionResult::new) + .orElse(FluidActionResult.FAILURE); } /** @@ -674,7 +658,7 @@ public class FluidUtil */ private static IFluidHandler getFluidBlockHandler(Fluid fluid, World world, BlockPos pos) { - Block block = fluid.getBlock(); + Block block = fluid.getBlock();/* TODO fluid blocks? if (block instanceof IFluidBlock) { return new FluidBlockWrapper((IFluidBlock) block, world, pos); @@ -683,7 +667,7 @@ public class FluidUtil { return new BlockLiquidWrapper((BlockLiquid) block, world, pos); } - else + else*/ { return new BlockWrapper(block, world, pos); } @@ -724,7 +708,7 @@ public class FluidUtil { Fluid fluid = fluidStack.getFluid(); - if (fluidStack.tag == null || fluidStack.tag.hasNoTags()) + if (fluidStack.tag == null || fluidStack.tag.isEmpty()) { if (fluid == FluidRegistry.WATER) { diff --git a/src/main/resources/forge_at.cfg b/src/main/resources/forge_at.cfg index 5d3f0ab51..af8464c64 100644 --- a/src/main/resources/forge_at.cfg +++ b/src/main/resources/forge_at.cfg @@ -16,6 +16,9 @@ public net.minecraft.block.BlockFire func_176534_d(Lnet/minecraft/block/Block;)I # Item public net.minecraft.item.Item func_77656_e(I)Lnet.minecraft.item.Item; #setMaxDamage public net.minecraft.item.Item func_77627_a(Z)Lnet.minecraft.item.Item; #setHasSubtypes +public net.minecraft.item.Item field_185051_m # properties +# Entity +public net.minecraft.entity.Entity func_70022_Q()Ljava/lang/String; # getEntityString # EntityPlayer public net.minecraft.entity.player.EntityPlayer func_71053_j()V #closeScreen # EntityTrackerEntry