Port capability patches to 1.13 and refactor to new system (#5134)

* resource package and misc leftover rendering stuff

* Port Item and ItemStack patches

* Extract most item patches to interface

* Refactor Item#setNoRepair to be part of Item.Builder

* Adapt AnimationItemOverrideList to new cap system

* Improve null contract of OptionalCapabilityInstance

* Remove Capability.cast

* Update CapabilityAnimation to new cap system

* Remove OptionalCapabilityInstance#flatMap and add NonNullConsumer

* Add capability patch to Entity, not everything yet

* Fix Entity patch and add missing methods to IForgeEntity

* Fix null contract of CapabilityDispatcher

* Add TileEntity caps

* Adapt FluidUtil to new cap system

* Add world caps

* Add chunk caps

* Clean up cap patches

* Replace all tabs with spaces

* Move builder methods on Item to Item.Builder

Whitepsace fix

* Sided stuff take 2

* Prevent OptionalCapabilityInstance creating additional empty instances

* Cache getCapability result in AnimationTESR

* Fix imports in TileEntity patch

* Pull out cap code to base class, add village caps
This commit is contained in:
tterrag 2018-09-09 17:27:15 -04:00 committed by GitHub
parent f851b37aa0
commit 334d925972
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
45 changed files with 1967 additions and 266 deletions

View file

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

View file

@ -46,7 +46,7 @@
} }
+ +
+ public boolean isColorDisabled() { + public boolean isColorDisabled() {
+ return noColor; + return noColor;
+ } + }
+ +
+ public void putBulkData(ByteBuffer buffer) { + public void putBulkData(ByteBuffer buffer) {

View file

@ -17,6 +17,6 @@
+ * that should be applied to the GL state before rendering it (matrix may be null). + * that should be applied to the GL state before rendering it (matrix may be null).
+ */ + */
+ default org.apache.commons.lang3.tuple.Pair<? extends IBakedModel, javax.vecmath.Matrix4f> handlePerspective(ItemCameraTransforms.TransformType cameraTransformType) { + default org.apache.commons.lang3.tuple.Pair<? extends IBakedModel, javax.vecmath.Matrix4f> handlePerspective(ItemCameraTransforms.TransformType cameraTransformType) {
+ return net.minecraftforge.client.ForgeHooksClient.handlePerspective(this, cameraTransformType); + return net.minecraftforge.client.ForgeHooksClient.handlePerspective(this, cameraTransformType);
} }
+} +}

View file

@ -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_) { 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 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_) { + 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_) {

View file

@ -8,6 +8,6 @@
+ // Forge Start + // Forge Start
+ +
+ public int getPixelRGBA(int frameIndex, int x, int y) { + 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);
} }
+} +}

View file

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

View file

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

View file

@ -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<ItemStack> EMPTY_EQUIPMENT = Collections.<ItemStack>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() {

View file

@ -1,11 +1,163 @@
--- a/net/minecraft/item/Item.java --- a/net/minecraft/item/Item.java
+++ b/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.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.api.distmarker.OnlyIn;
-public class Item implements IItemProvider { -public class Item implements IItemProvider {
+public class Item extends net.minecraftforge.registries.ForgeRegistryEntry<Item> implements IItemProvider { - public static final RegistryNamespaced<ResourceLocation, Item> REGISTRY = new RegistryNamespaced<ResourceLocation, Item>();
public static final RegistryNamespaced<ResourceLocation, Item> REGISTRY = new RegistryNamespaced<ResourceLocation, Item>(); - public static final Map<Block, Item> BLOCK_TO_ITEM = Maps.<Block, Item>newHashMap();
public static final Map<Block, Item> BLOCK_TO_ITEM = Maps.<Block, Item>newHashMap(); +public class Item extends net.minecraftforge.registries.ForgeRegistryEntry<Item> implements IItemProvider, net.minecraftforge.common.extensions.IForgeItem {
+ public static final RegistryNamespaced<ResourceLocation, Item> REGISTRY = net.minecraftforge.registries.GameData.getWrapper(Item.class);
+ public static final Map<Block, Item> BLOCK_TO_ITEM = net.minecraftforge.registries.GameData.getBlockItemMap();
private static final IItemPropertyGetter DAMAGED_GETTER = (p_210306_0_, p_210306_1_, p_210306_2_) -> { 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<String, AttributeModifier> getItemAttributeModifiers(EntityEquipmentSlot equipmentSlot) {
return HashMultimap.<String, AttributeModifier>create();
}
+ /* ======================================== FORGE START =====================================*/
+
+ @Nullable
+ private final java.util.function.Supplier<net.minecraft.client.renderer.tileentity.TileEntityItemStackRenderer> teisr;
+
+ private final java.util.Map<String, Integer> toolClasses = new java.util.HashMap<String, Integer>();
+
+ protected final boolean canRepair;
+
+ @Override
+ public boolean isRepairable()
+ {
+ return canRepair && isDamageable();
+ }
+
+ @Override
+ public java.util.Set<String> 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<String, Integer> toolClasses = new java.util.HashMap<String, Integer>();
+ private java.util.function.Supplier<java.util.concurrent.Callable<net.minecraft.client.renderer.tileentity.TileEntityItemStackRenderer>> 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<java.util.concurrent.Callable<net.minecraft.client.renderer.tileentity.TileEntityItemStackRenderer>> teisrSupplier) {
+ this.teisr = teisrSupplier;
+ }
+ }
+}

View file

@ -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<NBTTagCompound> {
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<Item> 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);
+ }
+}

View file

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

View file

@ -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<VillageDoorInfo> villageDoorInfoList = Lists.<VillageDoorInfo>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() {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -41,6 +41,7 @@ import net.minecraft.client.renderer.vertex.VertexBuffer;
import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.resources.IReloadableResourceManager; import net.minecraft.resources.IReloadableResourceManager;
import net.minecraft.resources.IResourceManager;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;

View file

@ -35,7 +35,8 @@ public class ForgeClientHandler
// register model for the universal bucket, if it exists // register model for the universal bucket, if it exists
if (FluidRegistry.isUniversalBucketEnabled()) 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()) if (FluidRegistry.isUniversalBucketEnabled())
{ {
event.getItemColors().registerItemColorHandler(new FluidContainerColorer(), ForgeMod.getInstance().universalBucket); event.getItemColors().func_199877_a(new FluidContainerColorer(), ForgeMod.getInstance().universalBucket);
} }
} }
} }

View file

@ -67,22 +67,23 @@ public final class AnimationItemOverrideList extends ItemOverrideList
@Override @Override
public IBakedModel func_209581_a(IBakedModel originalModel, ItemStack stack, @Nullable World world, @Nullable EntityLivingBase entity) public IBakedModel func_209581_a(IBakedModel originalModel, ItemStack stack, @Nullable World world, @Nullable EntityLivingBase entity)
{ {
IAnimationStateMachine asm = stack.getCapability(CapabilityAnimation.ANIMATION_CAPABILITY, null); return stack.getCapability(CapabilityAnimation.ANIMATION_CAPABILITY, null)
if (asm != null) .map(asm ->
{
// TODO: caching?
if(world == null && entity != null)
{ {
world = entity.world; World w = world;
} // TODO caching?
if(world == null) if(w == null && entity != null)
{ {
world = Minecraft.getMinecraft().world; w = entity.world;
} }
IModelState state = asm.apply(Animation.getWorldTime(world, Animation.getPartialTickTime())).getLeft(); if(world == null)
{
w = Minecraft.getMinecraft().world;
}
return asm.apply(Animation.getWorldTime(world, Animation.getPartialTickTime())).getLeft();
})
// TODO where should uvlock data come from? // TODO where should uvlock data come from?
return model.bake(ModelLoader.defaultModelGetter(), bakedTextureGetter, new ModelStateComposition(state, this.state), false, format); .map(state -> model.bake(ModelLoader.defaultModelGetter(), bakedTextureGetter, new ModelStateComposition(state, this.state), false, format))
} .orElseGet(() -> super.func_209581_a(originalModel, stack, world, entity));
return super.func_209581_a(originalModel, stack, world, entity);
} }
} }

View file

@ -42,11 +42,8 @@ import net.minecraftforge.client.model.pipeline.VertexLighterFlat;
import net.minecraftforge.client.model.pipeline.VertexBufferConsumer; import net.minecraftforge.client.model.pipeline.VertexBufferConsumer;
import net.minecraftforge.common.animation.Event; import net.minecraftforge.common.animation.Event;
import net.minecraftforge.common.animation.IEventHandler; 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.CapabilityAnimation;
import net.minecraftforge.common.model.animation.IAnimationStateMachine;
import org.apache.commons.lang3.tuple.Pair;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
/** /**
@ -69,17 +66,18 @@ public class AnimationModelBase<T extends Entity> extends ModelBase implements I
@Override @Override
public void render(Entity entity, float limbSwing, float limbSwingSpeed, float timeAlive, float yawHead, float rotationPitch, float scale) 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); entity.getCapability(CapabilityAnimation.ANIMATION_CAPABILITY, null)
if (capability == null) .map(cap -> cap.apply(timeAlive / 20))
{ .map(pair -> {
return; handleEvents((T) entity, timeAlive / 20, pair.getRight());
} IUnbakedModel unbaked = ModelLoaderRegistry.getModelOrMissing(modelLocation);
Pair<IModelState, Iterable<Event>> pair = capability.apply(timeAlive / 20); // TODO where should uvlock data come from?
handleEvents((T)entity, timeAlive / 20, pair.getRight()); return unbaked.bake(ModelLoader.defaultModelGetter(), ModelLoader.defaultTextureGetter(), pair.getLeft(), false, DefaultVertexFormats.ITEM);
IUnbakedModel model = ModelLoaderRegistry.getModelOrMissing(modelLocation); }).ifPresent(model -> drawModel(model, entity));
// TODO where should uvlock data come from? }
IBakedModel bakedModel = model.bake(ModelLoader.defaultModelGetter(), ModelLoader.defaultTextureGetter(), pair.getLeft(), false, DefaultVertexFormats.ITEM);
private void drawModel(IBakedModel bakedModel, Entity entity)
{
BlockPos pos = new BlockPos(entity.posX, entity.posY + entity.height, entity.posZ); BlockPos pos = new BlockPos(entity.posX, entity.posY + entity.height, entity.posZ);
RenderHelper.disableStandardItemLighting(); RenderHelper.disableStandardItemLighting();
@ -109,7 +107,7 @@ public class AnimationModelBase<T extends Entity> extends ModelBase implements I
} }
for(EnumFacing side : EnumFacing.values()) for(EnumFacing side : EnumFacing.values())
{ {
random.setSeed(42); random.setSeed(42);
quads = bakedModel.func_200117_a(null, side, random); quads = bakedModel.func_200117_a(null, side, random);
if(!quads.isEmpty()) if(!quads.isEmpty())
{ {

View file

@ -30,6 +30,7 @@ import net.minecraft.world.IWorldReader;
import net.minecraftforge.client.MinecraftForgeClient; import net.minecraftforge.client.MinecraftForgeClient;
import net.minecraftforge.common.animation.Event; import net.minecraftforge.common.animation.Event;
import net.minecraftforge.common.animation.IEventHandler; import net.minecraftforge.common.animation.IEventHandler;
import net.minecraftforge.common.capabilities.OptionalCapabilityInstance;
import net.minecraftforge.common.model.IModelState; import net.minecraftforge.common.model.IModelState;
import net.minecraftforge.common.model.animation.CapabilityAnimation; import net.minecraftforge.common.model.animation.CapabilityAnimation;
import net.minecraftforge.common.model.animation.IAnimationStateMachine; import net.minecraftforge.common.model.animation.IAnimationStateMachine;
@ -50,7 +51,8 @@ public class AnimationTESR<T extends TileEntity> extends FastTESR<T> implements
@Override @Override
public void renderTileEntityFast(T te, double x, double y, double z, float partialTick, int breakStage, BufferBuilder renderer) 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<IAnimationStateMachine> cap = te.getCapability(CapabilityAnimation.ANIMATION_CAPABILITY);
if(!cap.isPresent())
{ {
return; return;
} }
@ -60,7 +62,7 @@ public class AnimationTESR<T extends TileEntity> extends FastTESR<T> implements
IBlockState state = world.getBlockState(pos); IBlockState state = world.getBlockState(pos);
if(state.getBlock().getBlockState().getProperties().contains(Properties.StaticProperty)) 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) if(state instanceof IExtendedBlockState)
{ {
@ -68,20 +70,19 @@ public class AnimationTESR<T extends TileEntity> extends FastTESR<T> implements
if(exState.getUnlistedNames().contains(Properties.AnimationProperty)) if(exState.getUnlistedNames().contains(Properties.AnimationProperty))
{ {
float time = Animation.getWorldTime(getWorld(), partialTick); float time = Animation.getWorldTime(getWorld(), partialTick);
IAnimationStateMachine capability = te.getCapability(CapabilityAnimation.ANIMATION_CAPABILITY, null); cap
if (capability != null) .map(asm -> asm.apply(time))
{ .ifPresent(pair -> {
Pair<IModelState, Iterable<Event>> pair = capability.apply(time); handleEvents(te, time, pair.getRight());
handleEvents(te, time, pair.getRight());
// TODO: caching? // TODO: caching?
IBakedModel model = blockRenderer.getBlockModelShapes().getModelForState(exState.getClean()); IBakedModel model = blockRenderer.getBlockModelShapes().getModelForState(exState.getClean());
exState = exState.withProperty(Properties.AnimationProperty, pair.getLeft()); 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);
} });
} }
} }
} }

View file

@ -19,13 +19,13 @@
package net.minecraftforge.client.resource; package net.minecraftforge.client.resource;
import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.api.distmarker.OnlyIn;
/** /**
* Represents a generic type of reloadable resource. Used for resource reload filtering. * Represents a generic type of reloadable resource. Used for resource reload filtering.
*/ */
@SideOnly(Side.CLIENT) @OnlyIn(Dist.CLIENT)
public interface IResourceType public interface IResourceType
{ {
} }

View file

@ -22,15 +22,15 @@ package net.minecraftforge.client.resource;
import java.util.Set; import java.util.Set;
import java.util.function.Predicate; import java.util.function.Predicate;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import com.google.common.collect.Sets; 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. * 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 public final class ReloadRequirements
{ {
/** /**

View file

@ -79,6 +79,7 @@ import net.minecraft.item.ItemPotion;
import net.minecraft.item.ItemSpade; import net.minecraft.item.ItemSpade;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemTippedArrow; import net.minecraft.item.ItemTippedArrow;
import net.minecraft.item.ItemUseContext;
import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.IRecipe;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagList;
@ -867,8 +868,11 @@ public class ForgeHooks
return event.isCanceled() ? -1 : event.getExpToDrop(); 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 // handle all placement events here
int meta = itemstack.getItemDamage(); int meta = itemstack.getItemDamage();
int size = itemstack.getCount(); int size = itemstack.getCount();
@ -883,7 +887,7 @@ public class ForgeHooks
world.captureBlockSnapshots = true; 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; world.captureBlockSnapshots = false;
if (ret == EnumActionResult.SUCCESS) if (ret == EnumActionResult.SUCCESS)
@ -902,12 +906,16 @@ public class ForgeHooks
world.capturedBlockSnapshots.clear(); world.capturedBlockSnapshots.clear();
// make sure to set pre-placement item data for event // make sure to set pre-placement item data for event
itemstack.setItemDamage(meta); itemstack.func_196085_b(meta);
itemstack.setCount(size); itemstack.setCount(size);
if (nbt != null) if (nbt != null)
{ {
itemstack.setTagCompound(nbt); itemstack.setTagCompound(nbt);
} }
EntityPlayer player = context.func_195999_j();
EnumFacing side = context.func_196000_l();
if (blockSnapshots.size() > 1) if (blockSnapshots.size() > 1)
{ {
placeEvent = ForgeEventFactory.onPlayerMultiBlockPlace(player, blockSnapshots, side, hand); placeEvent = ForgeEventFactory.onPlayerMultiBlockPlace(player, blockSnapshots, side, hand);
@ -931,7 +939,7 @@ public class ForgeHooks
else else
{ {
// Change the stack to its new content // Change the stack to its new content
itemstack.setItemDamage(newMeta); itemstack.func_196085_b(newMeta);
itemstack.setCount(newSize); itemstack.setCount(newSize);
if (nbt != null) if (nbt != null)
{ {

View file

@ -135,17 +135,6 @@ public class Capability<T>
} }
} }
/**
* Use this inside ICapabilityProvider.getCapability to avoid unchecked cast warnings.
* Example: return SOME_CAPABILITY.cast(instance);
* Use with caution;
*/
@SuppressWarnings("unchecked")
public <R> R cast(T instance)
{
return (R)instance;
}
// INTERNAL // INTERNAL
private final String name; private final String name;
private final IStorage<T> storage; private final IStorage<T> storage;

View file

@ -20,11 +20,14 @@
package net.minecraftforge.common.capabilities; package net.minecraftforge.common.capabilities;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.nbt.INBTBase; import net.minecraft.nbt.INBTBase;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing; 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. * Internally the handlers are baked into arrays for fast iteration.
* The ResourceLocations will be used for the NBT Key when serializing. * The ResourceLocations will be used for the NBT Key when serializing.
*/ */
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public final class CapabilityDispatcher implements INBTSerializable<NBTTagCompound>, ICapabilityProvider public final class CapabilityDispatcher implements INBTSerializable<NBTTagCompound>, ICapabilityProvider
{ {
private ICapabilityProvider[] caps; private ICapabilityProvider[] caps;
@ -87,7 +92,7 @@ public final class CapabilityDispatcher implements INBTSerializable<NBTTagCompou
@Override @Override
public <T> OptionalCapabilityInstance<T> getCapability(Capability<T> cap, EnumFacing side) public <T> OptionalCapabilityInstance<T> getCapability(Capability<T> cap, @Nullable EnumFacing side)
{ {
for (ICapabilityProvider c : caps) for (ICapabilityProvider c : caps)
{ {
@ -122,7 +127,7 @@ public final class CapabilityDispatcher implements INBTSerializable<NBTTagCompou
} }
} }
public boolean areCompatible(CapabilityDispatcher other) //Called from ItemStack to compare equality. public boolean areCompatible(@Nullable CapabilityDispatcher other) //Called from ItemStack to compare equality.
{ // Only compares serializeable caps. { // Only compares serializeable caps.
if (other == null) return this.writers.length == 0; // Done this way so we can do some pre-checks before doing the costly NBT serialization and compare if (other == null) return this.writers.length == 0; // Done this way so we can do some pre-checks before doing the costly NBT serialization and compare
if (this.writers.length == 0) return other.writers.length == 0; if (this.writers.length == 0) return other.writers.length == 0;

View file

@ -0,0 +1,100 @@
/*
* 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;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.event.ForgeEventFactory;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public abstract class CapabilityProvider implements ICapabilityProvider
{
private @Nullable CapabilityDispatcher capabilities;
protected final void gatherCapabilities() { gatherCapabilities(null); }
protected final void gatherCapabilities(@Nullable ICapabilityProvider parent)
{
this.capabilities = ForgeEventFactory.gatherCapabilities(getClass(), this, parent);
}
protected final @Nullable CapabilityDispatcher getCapabilities()
{
return this.capabilities;
}
public final boolean areCapsCompatible(CapabilityProvider other)
{
return areCapsCompatible(other.getCapabilities());
}
public final boolean areCapsCompatible(@Nullable CapabilityDispatcher other)
{
final CapabilityDispatcher disp = getCapabilities();
if (disp == null)
{
if (other == null)
{
return true;
}
else
{
return other.areCompatible(null);
}
}
else
{
return disp.areCompatible(other);
}
}
protected final @Nullable NBTTagCompound serializeCaps()
{
final CapabilityDispatcher disp = getCapabilities();
if (disp != null)
{
return disp.serializeNBT();
}
return null;
}
protected final void deserializeCaps(NBTTagCompound tag)
{
final CapabilityDispatcher disp = getCapabilities();
if (disp != null)
{
disp.deserializeNBT(tag);
}
}
@Override
@Nonnull
public <T> OptionalCapabilityInstance<T> getCapability(@Nonnull Capability<T> cap, @Nullable EnumFacing side)
{
final CapabilityDispatcher disp = getCapabilities();
return disp == null ? OptionalCapabilityInstance.empty() : disp.getCapability(cap, side);
}
}

View file

@ -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<T>
{
void accept(@Nonnull T t);
}

View file

@ -28,6 +28,14 @@ import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.function.Supplier; 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<T> public class OptionalCapabilityInstance<T>
{ {
private final NonNullSupplier<T> supplier; private final NonNullSupplier<T> supplier;
@ -35,7 +43,7 @@ public class OptionalCapabilityInstance<T>
private Set<Consumer<OptionalCapabilityInstance<T>>> listeners = new HashSet<>(); private Set<Consumer<OptionalCapabilityInstance<T>>> listeners = new HashSet<>();
private boolean isValid = true; private boolean isValid = true;
private static final OptionalCapabilityInstance<Void> EMPTY = new OptionalCapabilityInstance<>(null); private static final @Nonnull OptionalCapabilityInstance<Void> EMPTY = new OptionalCapabilityInstance<>(null);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> OptionalCapabilityInstance<T> empty() public static <T> OptionalCapabilityInstance<T> empty()
@ -49,17 +57,17 @@ public class OptionalCapabilityInstance<T>
return (OptionalCapabilityInstance<X>)this; return (OptionalCapabilityInstance<X>)this;
} }
private OptionalCapabilityInstance(NonNullSupplier<T> instanceSupplier) private OptionalCapabilityInstance(@Nullable NonNullSupplier<T> instanceSupplier)
{ {
this.supplier = instanceSupplier; this.supplier = instanceSupplier;
} }
public static <T> OptionalCapabilityInstance<T> of(final NonNullSupplier<T> instanceSupplier) public static <T> OptionalCapabilityInstance<T> of(final @Nullable NonNullSupplier<T> instanceSupplier)
{ {
return new OptionalCapabilityInstance<>(instanceSupplier); return instanceSupplier == null ? EMPTY.cast() : new OptionalCapabilityInstance<>(instanceSupplier);
} }
private T getValue() private @Nullable T getValue()
{ {
if (!isValid) if (!isValid)
return null; return null;
@ -103,10 +111,11 @@ public class OptionalCapabilityInstance<T>
* @throws NullPointerException if mod object is present and {@code consumer} is * @throws NullPointerException if mod object is present and {@code consumer} is
* null * null
*/ */
public void ifPresent(Consumer<? super T> consumer) public void ifPresent(NonNullConsumer<? super T> consumer)
{ {
if (isValid && getValue() != null) T val = getValue();
consumer.accept(getValue()); if (isValid && val != null)
consumer.accept(val);
} }
/** /**
@ -148,30 +157,6 @@ public class OptionalCapabilityInstance<T>
return isPresent() ? OptionalCapabilityInstance.of(()->mapper.apply(getValue())) : empty(); 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 <U> 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<U> OptionalCapabilityInstance<U> flatMap(Function<? super T, Optional<U>> 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}. * Return the mod object if present, otherwise return {@code other}.
* *
@ -181,7 +166,8 @@ public class OptionalCapabilityInstance<T>
*/ */
public T orElse(T other) 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<T>
* @throws NullPointerException if mod object is not present and {@code other} is * @throws NullPointerException if mod object is not present and {@code other} is
* null * null
*/ */
public T orElseGet(Supplier<? extends T> other) public T orElseGet(NonNullSupplier<? extends T> other)
{ {
return getValue() != null ? getValue() : other.get(); T val = getValue();
return val != null ? val : other.get();
} }
/** /**
@ -217,8 +204,9 @@ public class OptionalCapabilityInstance<T>
*/ */
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X
{ {
if (getValue() != null) T val = getValue();
return getValue(); if (val != null)
return val;
throw exceptionSupplier.get(); throw exceptionSupplier.get();
} }

View file

@ -0,0 +1,8 @@
package net.minecraftforge.common.extensions;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
public interface IForgeChunk extends ICapabilityProvider
{
}

View file

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

View file

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

View file

@ -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<String, AttributeModifier> 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<ItemGroup> 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 <em>do
* not use this to get the armor slot of said stack; for that, use
* {@link net.minecraft.entity.EntityLiving#getSlotForItemStack(ItemStack)}.</em>
*
* @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<String> 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<String, net.minecraftforge.common.animation.ITimeValue> getAnimationParameters(final ItemStack stack,
final World world, final EntityLivingBase entity)
{
com.google.common.collect.ImmutableMap.Builder<String, net.minecraftforge.common.animation.ITimeValue> builder = com.google.common.collect.ImmutableMap
.builder();
for (ResourceLocation location : ((RegistrySimple<ResourceLocation, IItemPropertyGetter>) 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();
}

View file

@ -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<NBTTagCompound>
{
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;
}
}

View file

@ -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<NBTTagCompound>
{
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;
}
}

View file

@ -0,0 +1,8 @@
package net.minecraftforge.common.extensions;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
public interface IForgeWorld extends ICapabilityProvider
{
}

View file

@ -60,14 +60,14 @@ public class CapabilityAnimation
} }
@Override @Override
@Nullable @Nonnull
public <T> OptionalCapabilityInstance<T> getCapability(@Nonnull Capability<T> capability, @Nullable EnumFacing facing) public <T> OptionalCapabilityInstance<T> getCapability(@Nonnull Capability<T> capability, @Nullable EnumFacing facing)
{ {
if(capability == ANIMATION_CAPABILITY) if(capability == ANIMATION_CAPABILITY)
{ {
return ANIMATION_CAPABILITY.cast(asm); return OptionalCapabilityInstance.of(() -> asm).cast();
} }
return null; return OptionalCapabilityInstance.empty();
} }
} }
} }

View file

@ -19,8 +19,8 @@
package net.minecraftforge.common.property; package net.minecraftforge.common.property;
import net.minecraft.block.properties.IProperty; import net.minecraft.state.BooleanProperty;
import net.minecraft.block.properties.PropertyBool; import net.minecraft.state.IProperty;
import net.minecraftforge.common.model.IModelState; import net.minecraftforge.common.model.IModelState;
public class Properties 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. * 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. * Property holding the IModelState used for animating the model in the TESR.

View file

@ -19,8 +19,10 @@
package net.minecraftforge.common.util; package net.minecraftforge.common.util;
import javax.annotation.Nullable;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.WorldProvider; import net.minecraft.world.dimension.Dimension;
import net.minecraft.world.storage.WorldSavedData; import net.minecraft.world.storage.WorldSavedData;
public class WorldCapabilityData extends WorldSavedData public class WorldCapabilityData extends WorldSavedData
@ -35,7 +37,7 @@ public class WorldCapabilityData extends WorldSavedData
super(name); super(name);
} }
public WorldCapabilityData(INBTSerializable<NBTTagCompound> serializable) public WorldCapabilityData(@Nullable INBTSerializable<NBTTagCompound> serializable)
{ {
super(ID); super(ID);
this.serializable = serializable; this.serializable = serializable;
@ -66,7 +68,7 @@ public class WorldCapabilityData extends WorldSavedData
return true; return true;
} }
public void setCapabilities(WorldProvider provider, INBTSerializable<NBTTagCompound> capabilities) public void setCapabilities(Dimension provider, INBTSerializable<NBTTagCompound> capabilities)
{ {
this.serializable = capabilities; this.serializable = capabilities;
if (this.capNBT != null && serializable != null) if (this.capNBT != null && serializable != null)

View file

@ -328,9 +328,9 @@ public class ForgeEventFactory
return event.getNewState(); return event.getNewState();
} }
public static ItemTooltipEvent onItemTooltip(ItemStack itemStack, @Nullable EntityPlayer entityPlayer, List<String> toolTip, ITooltipFlag flags) public static ItemTooltipEvent onItemTooltip(ItemStack itemStack, @Nullable EntityPlayer entityPlayer, List<ITextComponent> list, ITooltipFlag flags)
{ {
ItemTooltipEvent event = new ItemTooltipEvent(itemStack, entityPlayer, toolTip, flags); ItemTooltipEvent event = new ItemTooltipEvent(itemStack, entityPlayer, list, flags);
MinecraftForge.EVENT_BUS.post(event); MinecraftForge.EVENT_BUS.post(event);
return event; return event;
} }
@ -624,41 +624,18 @@ public class ForgeEventFactory
{ {
return MinecraftForge.EVENT_BUS.post(new RenderBlockOverlayEvent(player, renderPartialTicks, type, block, pos)); return MinecraftForge.EVENT_BUS.post(new RenderBlockOverlayEvent(player, renderPartialTicks, type, block, pos));
} }
@Nullable @Nullable
public static CapabilityDispatcher gatherCapabilities(TileEntity tileEntity) public static <T extends ICapabilityProvider> CapabilityDispatcher gatherCapabilities(Class<? extends T> type, T provider)
{ {
return gatherCapabilities(new AttachCapabilitiesEvent<TileEntity>(TileEntity.class, tileEntity), null); return gatherCapabilities(type, provider, null);
} }
@SuppressWarnings("unchecked")
@Nullable @Nullable
public static CapabilityDispatcher gatherCapabilities(Entity entity) public static <T extends ICapabilityProvider> CapabilityDispatcher gatherCapabilities(Class<? extends T> type, T provider, @Nullable ICapabilityProvider parent)
{ {
return gatherCapabilities(new AttachCapabilitiesEvent<Entity>(Entity.class, entity), null); return gatherCapabilities(new AttachCapabilitiesEvent<T>((Class<T>) type, provider), parent);
}
@Nullable
public static CapabilityDispatcher gatherCapabilities(Village village)
{
return gatherCapabilities(new AttachCapabilitiesEvent<Village>(Village.class, village), null);
}
@Nullable
public static CapabilityDispatcher gatherCapabilities(ItemStack stack, ICapabilityProvider parent)
{
return gatherCapabilities(new AttachCapabilitiesEvent<ItemStack>(ItemStack.class, stack), parent);
}
@Nullable
public static CapabilityDispatcher gatherCapabilities(World world, ICapabilityProvider parent)
{
return gatherCapabilities(new AttachCapabilitiesEvent<World>(World.class, world), parent);
}
@Nullable
public static CapabilityDispatcher gatherCapabilities(Chunk chunk)
{
return gatherCapabilities(new AttachCapabilitiesEvent<Chunk>(Chunk.class, chunk), null);
} }
@Nullable @Nullable

View file

@ -25,6 +25,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.util.ITooltipFlag; import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.text.ITextComponent;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -34,17 +35,17 @@ public class ItemTooltipEvent extends PlayerEvent
private final ITooltipFlag flags; private final ITooltipFlag flags;
@Nonnull @Nonnull
private final ItemStack itemStack; private final ItemStack itemStack;
private final List<String> toolTip; private final List<ITextComponent> toolTip;
/** /**
* This event is fired in {@link ItemStack#getTooltip(EntityPlayer, ITooltipFlag)}, which in turn is called from it's respective GUIContainer. * 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()}. * Tooltips are also gathered with a null entityPlayer during startup by {@link Minecraft#populateSearchTreeManager()}.
*/ */
public ItemTooltipEvent(@Nonnull ItemStack itemStack, @Nullable EntityPlayer entityPlayer, List<String> toolTip, ITooltipFlag flags) public ItemTooltipEvent(@Nonnull ItemStack itemStack, @Nullable EntityPlayer entityPlayer, List<ITextComponent> list, ITooltipFlag flags)
{ {
super(entityPlayer); super(entityPlayer);
this.itemStack = itemStack; this.itemStack = itemStack;
this.toolTip = toolTip; this.toolTip = list;
this.flags = flags; this.flags = flags;
} }
@ -68,7 +69,7 @@ public class ItemTooltipEvent extends PlayerEvent
/** /**
* The {@link ItemStack} tooltip. * The {@link ItemStack} tooltip.
*/ */
public List<String> getToolTip() public List<ITextComponent> getToolTip()
{ {
return toolTip; return toolTip;
} }

View file

@ -24,7 +24,6 @@ import javax.annotation.Nullable;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockLiquid;
import net.minecraft.block.material.Material; import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
@ -40,6 +39,7 @@ import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.common.ForgeMod; import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.common.capabilities.OptionalCapabilityInstance;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandlerItem; import net.minecraftforge.fluids.capability.IFluidHandlerItem;
@ -74,8 +74,7 @@ public class FluidUtil
Preconditions.checkNotNull(world); Preconditions.checkNotNull(world);
Preconditions.checkNotNull(pos); Preconditions.checkNotNull(pos);
IFluidHandler blockFluidHandler = getFluidHandler(world, pos, side); return getFluidHandler(world, pos, side).map(handler -> interactWithFluidHandler(player, hand, handler)).orElse(false);
return blockFluidHandler != null && interactWithFluidHandler(player, hand, blockFluidHandler);
} }
/** /**
@ -98,21 +97,23 @@ public class FluidUtil
ItemStack heldItem = player.getHeldItem(hand); ItemStack heldItem = player.getHeldItem(hand);
if (!heldItem.isEmpty()) if (!heldItem.isEmpty())
{ {
IItemHandler playerInventory = player.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null); return player.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
if (playerInventory != null) .map(playerInventory -> {
{
FluidActionResult fluidActionResult = tryFillContainerAndStow(heldItem, handler, playerInventory, Integer.MAX_VALUE, player, true); FluidActionResult fluidActionResult = tryFillContainerAndStow(heldItem, handler, playerInventory, Integer.MAX_VALUE, player, true);
if (!fluidActionResult.isSuccess()) if (!fluidActionResult.isSuccess())
{ {
fluidActionResult = tryEmptyContainerAndStow(heldItem, handler, playerInventory, Integer.MAX_VALUE, player, true); fluidActionResult = tryEmptyContainerAndStow(heldItem, handler, playerInventory, Integer.MAX_VALUE, player, true);
} }
if (fluidActionResult.isSuccess()) if (fluidActionResult.isSuccess())
{ {
player.setHeldItem(hand, fluidActionResult.getResult()); player.setHeldItem(hand, fluidActionResult.getResult());
return true; return true;
} }
} return false;
})
.orElse(false);
} }
return 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) 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 ItemStack containerCopy = ItemHandlerHelper.copyStackWithSize(container, 1); // do not modify the input
IFluidHandlerItem containerFluidHandler = getFluidHandler(containerCopy); return getFluidHandler(containerCopy)
if (containerFluidHandler != null) .map(containerFluidHandler -> {
{ FluidStack simulatedTransfer = tryFluidTransfer(containerFluidHandler, fluidSource, maxAmount, false);
FluidStack simulatedTransfer = tryFluidTransfer(containerFluidHandler, fluidSource, maxAmount, false); if (simulatedTransfer != null)
if (simulatedTransfer != null)
{
if (doFill)
{
tryFluidTransfer(containerFluidHandler, fluidSource, maxAmount, true);
if (player != null)
{ {
SoundEvent soundevent = simulatedTransfer.getFluid().getFillSound(simulatedTransfer); if (doFill)
player.world.playSound(null, player.posX, player.posY + 0.5, player.posZ, soundevent, SoundCategory.BLOCKS, 1.0F, 1.0F); {
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);
} }
} return FluidActionResult.FAILURE;
else })
{ .orElse(FluidActionResult.FAILURE);
containerFluidHandler.fill(simulatedTransfer, true);
}
ItemStack resultContainer = containerFluidHandler.getContainer();
return new FluidActionResult(resultContainer);
}
}
return 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) 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 ItemStack containerCopy = ItemHandlerHelper.copyStackWithSize(container, 1); // do not modify the input
IFluidHandlerItem containerFluidHandler = getFluidHandler(containerCopy); return getFluidHandler(containerCopy)
if (containerFluidHandler != null) .map(containerFluidHandler -> {
{ if (doDrain)
if (doDrain)
{
FluidStack transfer = tryFluidTransfer(fluidDestination, containerFluidHandler, maxAmount, true);
if (transfer != null)
{
if (player != null)
{ {
SoundEvent soundevent = transfer.getFluid().getEmptySound(transfer); FluidStack transfer = tryFluidTransfer(fluidDestination, containerFluidHandler, maxAmount, true);
player.world.playSound(null, player.posX, player.posY + 0.5, player.posZ, soundevent, SoundCategory.BLOCKS, 1.0F, 1.0F); 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(); else
return new FluidActionResult(resultContainer); {
} FluidStack simulatedTransfer = tryFluidTransfer(fluidDestination, containerFluidHandler, maxAmount, false);
} if (simulatedTransfer != null)
else {
{ containerFluidHandler.drain(simulatedTransfer, true);
FluidStack simulatedTransfer = tryFluidTransfer(fluidDestination, containerFluidHandler, maxAmount, false); ItemStack resultContainer = containerFluidHandler.getContainer();
if (simulatedTransfer != null) return new FluidActionResult(resultContainer);
{ }
containerFluidHandler.drain(simulatedTransfer, true); }
ItemStack resultContainer = containerFluidHandler.getContainer(); return FluidActionResult.FAILURE;
return new FluidActionResult(resultContainer); })
} .orElse(FluidActionResult.FAILURE);
}
}
return 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. * 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. * 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 OptionalCapabilityInstance<IFluidHandlerItem> getFluidHandler(@Nonnull ItemStack itemStack)
public static IFluidHandlerItem getFluidHandler(@Nonnull ItemStack itemStack)
{ {
if (itemStack.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, null)) return itemStack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY);
{
return itemStack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, null);
}
else
{
return null;
}
} }
/** /**
* Helper method to get the fluid contained in an itemStack * Helper method to get the fluid contained in an itemStack
*/ */
@Nullable public static OptionalCapabilityInstance<FluidStack> getFluidContained(@Nonnull ItemStack container)
public static FluidStack getFluidContained(@Nonnull ItemStack container)
{ {
if (!container.isEmpty()) if (!container.isEmpty())
{ {
container = ItemHandlerHelper.copyStackWithSize(container, 1); container = ItemHandlerHelper.copyStackWithSize(container, 1);
IFluidHandlerItem fluidHandler = getFluidHandler(container); return getFluidHandler(container)
if (fluidHandler != null) .map(handler -> handler.drain(Integer.MAX_VALUE, false));
{
return fluidHandler.drain(Integer.MAX_VALUE, false);
}
} }
return null; return OptionalCapabilityInstance.empty();
} }
/** /**
* Helper method to get an IFluidHandler for at a block position. * Helper method to get an IFluidHandler for at a block position.
*
* Returns null if there is no valid fluid handler.
*/ */
@Nullable public static OptionalCapabilityInstance<IFluidHandler> getFluidHandler(World world, BlockPos blockPos, @Nullable EnumFacing side)
public static IFluidHandler getFluidHandler(World world, BlockPos blockPos, @Nullable EnumFacing side)
{ {
IBlockState state = world.getBlockState(blockPos); IBlockState state = world.getBlockState(blockPos);
Block block = state.getBlock(); Block block = state.getBlock();
@ -526,21 +510,21 @@ public class FluidUtil
if (block.hasTileEntity(state)) if (block.hasTileEntity(state))
{ {
TileEntity tileEntity = world.getTileEntity(blockPos); 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); return tileEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, side);
} }
} }/* TODO fluids blocks?
if (block instanceof IFluidBlock) 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) 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); IBlockState state = worldIn.getBlockState(pos);
Block block = state.getBlock(); Block block = state.getBlock();
/* TODO fluid blocks?
if (block instanceof IFluidBlock || block instanceof BlockLiquid) if (block instanceof IFluidBlock || block instanceof BlockLiquid)
{ {
IFluidHandler targetFluidHandler = getFluidHandler(worldIn, pos, side); IFluidHandler targetFluidHandler = getFluidHandler(worldIn, pos, side);
@ -572,7 +557,7 @@ public class FluidUtil
{ {
return tryFillContainer(emptyContainer, targetFluidHandler, Integer.MAX_VALUE, playerIn, true); return tryFillContainer(emptyContainer, targetFluidHandler, Integer.MAX_VALUE, playerIn, true);
} }
} }*/
return FluidActionResult.FAILURE; 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) 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 ItemStack containerCopy = ItemHandlerHelper.copyStackWithSize(container, 1); // do not modify the input
IFluidHandlerItem containerFluidHandler = getFluidHandler(containerCopy); return getFluidHandler(containerCopy)
if (containerFluidHandler != null && tryPlaceFluid(player, world, pos, containerFluidHandler, resource)) .filter(handler -> tryPlaceFluid(player, world, pos, handler, resource))
{ .map(IFluidHandlerItem::getContainer)
return new FluidActionResult(containerFluidHandler.getContainer()); .map(FluidActionResult::new)
} .orElse(FluidActionResult.FAILURE);
return FluidActionResult.FAILURE;
} }
/** /**
@ -674,7 +658,7 @@ public class FluidUtil
*/ */
private static IFluidHandler getFluidBlockHandler(Fluid fluid, World world, BlockPos pos) 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) if (block instanceof IFluidBlock)
{ {
return new FluidBlockWrapper((IFluidBlock) block, world, pos); return new FluidBlockWrapper((IFluidBlock) block, world, pos);
@ -683,7 +667,7 @@ public class FluidUtil
{ {
return new BlockLiquidWrapper((BlockLiquid) block, world, pos); return new BlockLiquidWrapper((BlockLiquid) block, world, pos);
} }
else else*/
{ {
return new BlockWrapper(block, world, pos); return new BlockWrapper(block, world, pos);
} }
@ -724,7 +708,7 @@ public class FluidUtil
{ {
Fluid fluid = fluidStack.getFluid(); Fluid fluid = fluidStack.getFluid();
if (fluidStack.tag == null || fluidStack.tag.hasNoTags()) if (fluidStack.tag == null || fluidStack.tag.isEmpty())
{ {
if (fluid == FluidRegistry.WATER) if (fluid == FluidRegistry.WATER)
{ {

View file

@ -16,6 +16,9 @@ public net.minecraft.block.BlockFire func_176534_d(Lnet/minecraft/block/Block;)I
# Item # Item
public net.minecraft.item.Item func_77656_e(I)Lnet.minecraft.item.Item; #setMaxDamage 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 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 # EntityPlayer
public net.minecraft.entity.player.EntityPlayer func_71053_j()V #closeScreen public net.minecraft.entity.player.EntityPlayer func_71053_j()V #closeScreen
# EntityTrackerEntry # EntityTrackerEntry