New Capability system allowing for more manageable world object features.
When combined with @Optional this should address all issues of soft dependancy on mods/apis. This also addresses the issue of dynamic functionality in TileEntities/Entities. Current capability providers: TileEntity, Entity, ItemStack Also added INBTSerializeable, a generic interface for game objects that can be written to/from NBT tags. Vanilla capabilities will be coming soon, mostly on request and review. So start requesting capabiliteis on vanilla/Forge features.
This commit is contained in:
parent
4672f7bab0
commit
17db34ae31
16 changed files with 988 additions and 44 deletions
|
@ -1,6 +1,15 @@
|
|||
--- ../src-base/minecraft/net/minecraft/entity/Entity.java
|
||||
+++ ../src-work/minecraft/net/minecraft/entity/Entity.java
|
||||
@@ -129,6 +129,14 @@
|
||||
@@ -49,7 +49,7 @@
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
-public abstract class Entity implements ICommandSender
|
||||
+public abstract class Entity implements ICommandSender, net.minecraftforge.common.capabilities.ICapabilitySerializable<NBTTagCompound>
|
||||
{
|
||||
private static final AxisAlignedBB field_174836_a = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D);
|
||||
private static int field_70152_a;
|
||||
@@ -129,6 +129,15 @@
|
||||
protected UUID field_96093_i;
|
||||
private final CommandResultStats field_174837_as;
|
||||
|
||||
|
@ -8,23 +17,25 @@
|
|||
+ private NBTTagCompound customEntityData;
|
||||
+ public boolean captureDrops = false;
|
||||
+ public java.util.ArrayList<EntityItem> capturedDrops = new java.util.ArrayList<EntityItem>();
|
||||
+ private UUID persistentID;
|
||||
+
|
||||
+ @Deprecated //ToDo: Move to Capabilities?
|
||||
+ protected java.util.HashMap<String, net.minecraftforge.common.IExtendedEntityProperties> extendedProperties = new java.util.HashMap<String, net.minecraftforge.common.IExtendedEntityProperties>();
|
||||
+ private net.minecraftforge.common.capabilities.CapabilityDispatcher capabilities;
|
||||
+
|
||||
public int func_145782_y()
|
||||
{
|
||||
return this.field_145783_c;
|
||||
@@ -172,6 +180,8 @@
|
||||
@@ -172,6 +181,9 @@
|
||||
this.field_70180_af.func_75682_a(2, "");
|
||||
this.field_70180_af.func_75682_a(4, Byte.valueOf((byte)0));
|
||||
this.func_70088_a();
|
||||
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.EntityEvent.EntityConstructing(this));
|
||||
+ for (net.minecraftforge.common.IExtendedEntityProperties props : extendedProperties.values()) props.init(this, p_i1582_1_);
|
||||
+ capabilities = net.minecraftforge.event.ForgeEventFactory.gatherCapabilities(this);
|
||||
}
|
||||
|
||||
protected abstract void func_70088_a();
|
||||
@@ -998,10 +1008,7 @@
|
||||
@@ -998,10 +1010,7 @@
|
||||
|
||||
if (block.func_149688_o() == p_70055_1_)
|
||||
{
|
||||
|
@ -36,7 +47,7 @@
|
|||
}
|
||||
else
|
||||
{
|
||||
@@ -1356,6 +1363,21 @@
|
||||
@@ -1356,6 +1365,23 @@
|
||||
p_70109_1_.func_74757_a("Silent", this.func_174814_R());
|
||||
}
|
||||
|
||||
|
@ -54,11 +65,13 @@
|
|||
+ t.printStackTrace();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (this.capabilities != null) p_70109_1_.func_74782_a("ForgeCaps", this.capabilities.serializeNBT());
|
||||
+
|
||||
this.func_70014_b(p_70109_1_);
|
||||
|
||||
if (this.field_70154_o != null)
|
||||
@@ -1438,6 +1460,28 @@
|
||||
@@ -1438,6 +1464,30 @@
|
||||
this.func_174805_g(p_70020_1_.func_74767_n("CustomNameVisible"));
|
||||
this.field_174837_as.func_179668_a(p_70020_1_);
|
||||
this.func_174810_b(p_70020_1_.func_74767_n("Silent"));
|
||||
|
@ -78,16 +91,18 @@
|
|||
+ }
|
||||
+ }
|
||||
+
|
||||
+ //Rawr, legacy code, Vanilla added a UUID, keep this so older maps will convert properly
|
||||
+ //Rawr, legacy code, Vanilla added a UUID, keep this so older maps will convert properly TODO: Remove in 1.9
|
||||
+ if (p_70020_1_.func_74764_b("PersistentIDMSB") && p_70020_1_.func_74764_b("PersistentIDLSB"))
|
||||
+ {
|
||||
+ this.field_96093_i = new UUID(p_70020_1_.func_74763_f("PersistentIDMSB"), p_70020_1_.func_74763_f("PersistentIDLSB"));
|
||||
+ }
|
||||
+
|
||||
+ if (this.capabilities != null && p_70020_1_.func_74764_b("ForgeCaps")) this.capabilities.deserializeNBT(p_70020_1_.func_74775_l("ForgeCaps"));
|
||||
+
|
||||
this.func_70037_a(p_70020_1_);
|
||||
|
||||
if (this.func_142008_O())
|
||||
@@ -1512,7 +1556,10 @@
|
||||
@@ -1512,7 +1562,10 @@
|
||||
{
|
||||
EntityItem entityitem = new EntityItem(this.field_70170_p, this.field_70165_t, this.field_70163_u + (double)p_70099_2_, this.field_70161_v, p_70099_1_);
|
||||
entityitem.func_174869_p();
|
||||
|
@ -99,7 +114,7 @@
|
|||
return entityitem;
|
||||
}
|
||||
else
|
||||
@@ -1655,6 +1702,7 @@
|
||||
@@ -1655,6 +1708,7 @@
|
||||
|
||||
public void func_70078_a(Entity p_70078_1_)
|
||||
{
|
||||
|
@ -107,7 +122,7 @@
|
|||
this.field_70149_e = 0.0D;
|
||||
this.field_70147_f = 0.0D;
|
||||
|
||||
@@ -1789,7 +1837,7 @@
|
||||
@@ -1789,7 +1843,7 @@
|
||||
|
||||
public boolean func_70115_ae()
|
||||
{
|
||||
|
@ -116,7 +131,7 @@
|
|||
}
|
||||
|
||||
public boolean func_70093_af()
|
||||
@@ -2092,7 +2140,7 @@
|
||||
@@ -2092,7 +2146,7 @@
|
||||
|
||||
public float func_180428_a(Explosion p_180428_1_, World p_180428_2_, BlockPos p_180428_3_, IBlockState p_180428_4_)
|
||||
{
|
||||
|
@ -125,7 +140,7 @@
|
|||
}
|
||||
|
||||
public boolean func_174816_a(Explosion p_174816_1_, World p_174816_2_, BlockPos p_174816_3_, IBlockState p_174816_4_, float p_174816_5_)
|
||||
@@ -2353,4 +2401,184 @@
|
||||
@@ -2353,4 +2407,209 @@
|
||||
|
||||
EnchantmentHelper.func_151385_b(p_174815_1_, p_174815_2_);
|
||||
}
|
||||
|
@ -308,5 +323,30 @@
|
|||
+ {
|
||||
+ return this instanceof EntityLivingBase;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasCapability(net.minecraftforge.common.capabilities.Capability<?> capability, net.minecraft.util.EnumFacing facing)
|
||||
+ {
|
||||
+ if (getCapability(capability, facing) != null)
|
||||
+ return true;
|
||||
+ return capabilities == null ? false : capabilities.hasCapability(capability, facing);
|
||||
+ }
|
||||
+
|
||||
+ public <T> T getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, net.minecraft.util.EnumFacing facing)
|
||||
+ {
|
||||
+ return capabilities == null ? null : capabilities.getCapability(capability, facing);
|
||||
+ }
|
||||
+
|
||||
+ public void deserializeNBT(NBTTagCompound nbt)
|
||||
+ {
|
||||
+ this.func_70020_e(nbt);
|
||||
+ }
|
||||
+
|
||||
+ public NBTTagCompound serializeNBT()
|
||||
+ {
|
||||
+ NBTTagCompound ret = new NBTTagCompound();
|
||||
+ ret.func_74778_a("id", this.func_70022_Q());
|
||||
+ this.func_70109_d(ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ /* ================================== Forge End =====================================*/
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
Vec3 vec31 = vec3.func_72441_c((double)f6 * d3, (double)f5 * d3, (double)f7 * d3);
|
||||
return p_77621_1_.func_147447_a(vec3, vec31, p_77621_3_, !p_77621_3_, false);
|
||||
}
|
||||
@@ -371,11 +380,641 @@
|
||||
@@ -371,11 +380,659 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -694,12 +694,30 @@
|
|||
+ if (delegate.getResourceName() != null) return delegate.getResourceName().toString();
|
||||
+ return registryName != null ? registryName.toString() : null;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * 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.
|
||||
+ */
|
||||
+ public net.minecraftforge.common.capabilities.ICapabilityProvider initCapabilities(ItemStack stack, NBTTagCompound nbt)
|
||||
+ {
|
||||
+ return null;
|
||||
+ }
|
||||
+ /* ======================================== FORGE END =====================================*/
|
||||
+
|
||||
public static void func_150900_l()
|
||||
{
|
||||
func_179214_a(Blocks.field_150348_b, (new ItemMultiTexture(Blocks.field_150348_b, Blocks.field_150348_b, new Function<ItemStack, String>()
|
||||
@@ -855,6 +1494,10 @@
|
||||
@@ -855,6 +1512,10 @@
|
||||
private final float field_78011_i;
|
||||
private final int field_78008_j;
|
||||
|
||||
|
@ -710,7 +728,7 @@
|
|||
private ToolMaterial(int p_i1874_3_, int p_i1874_4_, float p_i1874_5_, float p_i1874_6_, int p_i1874_7_)
|
||||
{
|
||||
this.field_78001_f = p_i1874_3_;
|
||||
@@ -889,9 +1532,36 @@
|
||||
@@ -889,9 +1550,36 @@
|
||||
return this.field_78008_j;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,35 @@
|
|||
--- ../src-base/minecraft/net/minecraft/item/ItemStack.java
|
||||
+++ ../src-work/minecraft/net/minecraft/item/ItemStack.java
|
||||
@@ -49,6 +49,7 @@
|
||||
@@ -35,7 +35,7 @@
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
-public final class ItemStack
|
||||
+public final class ItemStack implements net.minecraftforge.common.capabilities.ICapabilitySerializable<NBTTagCompound>
|
||||
{
|
||||
public static final DecimalFormat field_111284_a = new DecimalFormat("#.###");
|
||||
public int field_77994_a;
|
||||
@@ -49,6 +49,10 @@
|
||||
private Block field_179550_j;
|
||||
private boolean field_179551_k;
|
||||
|
||||
+ private net.minecraftforge.fml.common.registry.RegistryDelegate<Item> delegate;
|
||||
+ private net.minecraftforge.common.capabilities.CapabilityDispatcher capabilities;
|
||||
+ private NBTTagCompound capNBT;
|
||||
+
|
||||
public ItemStack(Block p_i1876_1_)
|
||||
{
|
||||
this((Block)p_i1876_1_, 1);
|
||||
@@ -80,7 +81,7 @@
|
||||
@@ -74,13 +78,15 @@
|
||||
this((Item)p_i1880_1_, p_i1880_2_, 0);
|
||||
}
|
||||
|
||||
- public ItemStack(Item p_i1881_1_, int p_i1881_2_, int p_i1881_3_)
|
||||
+ public ItemStack(Item p_i1881_1_, int p_i1881_2_, int p_i1881_3_) { this (p_i1881_1_, p_i1881_2_, p_i1881_3_, null); }
|
||||
+ public ItemStack(Item p_i1881_1_, int p_i1881_2_, int p_i1881_3_, NBTTagCompound capNBT)
|
||||
{
|
||||
+ this.capNBT = capNBT;
|
||||
this.field_179552_h = null;
|
||||
this.field_179553_i = false;
|
||||
this.field_179550_j = null;
|
||||
this.field_179551_k = false;
|
||||
|
@ -17,7 +38,7 @@
|
|||
this.field_77994_a = p_i1881_2_;
|
||||
this.field_77991_e = p_i1881_3_;
|
||||
|
||||
@@ -120,11 +121,12 @@
|
||||
@@ -120,11 +126,12 @@
|
||||
|
||||
public Item func_77973_b()
|
||||
{
|
||||
|
@ -31,8 +52,18 @@
|
|||
boolean flag = this.func_77973_b().func_180614_a(this, p_179546_1_, p_179546_2_, p_179546_3_, p_179546_4_, p_179546_5_, p_179546_6_, p_179546_7_);
|
||||
|
||||
if (flag)
|
||||
@@ -169,11 +171,11 @@
|
||||
@@ -162,19 +169,23 @@
|
||||
p_77955_1_.func_74782_a("tag", this.field_77990_d);
|
||||
}
|
||||
|
||||
+ if (this.capabilities != null) p_77955_1_.func_74782_a("ForgeCaps", this.capabilities.serializeNBT());
|
||||
+
|
||||
return p_77955_1_;
|
||||
}
|
||||
|
||||
public void func_77963_c(NBTTagCompound p_77963_1_)
|
||||
{
|
||||
+ this.capNBT = p_77963_1_.func_74764_b("ForgeCaps") ? p_77963_1_.func_74775_l("ForgeCaps") : null;
|
||||
if (p_77963_1_.func_150297_b("id", 8))
|
||||
{
|
||||
- this.field_151002_e = Item.func_111206_d(p_77963_1_.func_74779_i("id"));
|
||||
|
@ -43,9 +74,11 @@
|
|||
- this.field_151002_e = Item.func_150899_d(p_77963_1_.func_74765_d("id"));
|
||||
+ this.func_150996_a(Item.func_150899_d(p_77963_1_.func_74765_d("id")));
|
||||
}
|
||||
+ this.capNBT = null;
|
||||
|
||||
this.field_77994_a = p_77963_1_.func_74771_c("Count");
|
||||
@@ -197,7 +199,7 @@
|
||||
this.field_77991_e = p_77963_1_.func_74765_d("Damage");
|
||||
@@ -197,7 +208,7 @@
|
||||
|
||||
public int func_77976_d()
|
||||
{
|
||||
|
@ -54,7 +87,7 @@
|
|||
}
|
||||
|
||||
public boolean func_77985_e()
|
||||
@@ -207,7 +209,7 @@
|
||||
@@ -207,7 +218,7 @@
|
||||
|
||||
public boolean func_77984_f()
|
||||
{
|
||||
|
@ -63,7 +96,7 @@
|
|||
}
|
||||
|
||||
public boolean func_77981_g()
|
||||
@@ -217,32 +219,27 @@
|
||||
@@ -217,32 +228,27 @@
|
||||
|
||||
public boolean func_77951_h()
|
||||
{
|
||||
|
@ -101,7 +134,7 @@
|
|||
}
|
||||
|
||||
public boolean func_96631_a(int p_96631_1_, Random p_96631_2_)
|
||||
@@ -274,8 +271,8 @@
|
||||
@@ -274,8 +280,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,7 +145,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
@@ -334,7 +331,7 @@
|
||||
@@ -334,7 +340,7 @@
|
||||
|
||||
public boolean func_150998_b(Block p_150998_1_)
|
||||
{
|
||||
|
@ -121,7 +154,16 @@
|
|||
}
|
||||
|
||||
public boolean func_111282_a(EntityPlayer p_111282_1_, EntityLivingBase p_111282_2_)
|
||||
@@ -742,6 +739,7 @@
|
||||
@@ -344,7 +350,7 @@
|
||||
|
||||
public ItemStack func_77946_l()
|
||||
{
|
||||
- ItemStack itemstack = new ItemStack(this.field_151002_e, this.field_77994_a, this.field_77991_e);
|
||||
+ ItemStack itemstack = new ItemStack(this.field_151002_e, this.field_77994_a, this.field_77991_e, this.capabilities != null ? this.capabilities.serializeNBT() : null);
|
||||
|
||||
if (this.field_77990_d != null)
|
||||
{
|
||||
@@ -742,6 +748,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,7 +171,7 @@
|
|||
return list;
|
||||
}
|
||||
|
||||
@@ -852,7 +850,7 @@
|
||||
@@ -852,7 +859,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -138,11 +180,48 @@
|
|||
}
|
||||
|
||||
return multimap;
|
||||
@@ -860,6 +858,7 @@
|
||||
@@ -860,6 +867,17 @@
|
||||
|
||||
public void func_150996_a(Item p_150996_1_)
|
||||
{
|
||||
+ if (p_150996_1_ == this.field_151002_e && field_151002_e != null && this.capabilities != null) //Item Didn't change but refreshed
|
||||
+ {
|
||||
+ net.minecraftforge.common.capabilities.ICapabilityProvider parent = field_151002_e.initCapabilities(this, this.capabilities.serializeNBT());
|
||||
+ this.capabilities = net.minecraftforge.event.ForgeEventFactory.gatherCapabilities(field_151002_e, this, parent);
|
||||
+ }
|
||||
+ else if (p_150996_1_ != this.field_151002_e && p_150996_1_ != null) // Item Changed
|
||||
+ {
|
||||
+ net.minecraftforge.common.capabilities.ICapabilityProvider parent = p_150996_1_.initCapabilities(this, this.capNBT);
|
||||
+ this.capabilities = net.minecraftforge.event.ForgeEventFactory.gatherCapabilities(field_151002_e, this, parent);
|
||||
+ }
|
||||
+ this.delegate = p_150996_1_ != null ? p_150996_1_.delegate : null;
|
||||
this.field_151002_e = p_150996_1_;
|
||||
}
|
||||
|
||||
@@ -946,4 +964,26 @@
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+
|
||||
+ public boolean hasCapability(net.minecraftforge.common.capabilities.Capability<?> capability, net.minecraft.util.EnumFacing facing)
|
||||
+ {
|
||||
+ return this.capabilities == null ? false : this.capabilities.hasCapability(capability, facing);
|
||||
+ }
|
||||
+
|
||||
+ public <T> T getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, net.minecraft.util.EnumFacing facing)
|
||||
+ {
|
||||
+ return this.capabilities == null ? null : this.capabilities.getCapability(capability, facing);
|
||||
+ }
|
||||
+
|
||||
+ public void deserializeNBT(NBTTagCompound nbt)
|
||||
+ {
|
||||
+ this.func_77963_c(nbt);
|
||||
+ }
|
||||
+
|
||||
+ public NBTTagCompound serializeNBT()
|
||||
+ {
|
||||
+ NBTTagCompound ret = new NBTTagCompound();
|
||||
+ this.func_77955_b(ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
}
|
||||
|
|
|
@ -1,22 +1,33 @@
|
|||
--- ../src-base/minecraft/net/minecraft/tileentity/TileEntity.java
|
||||
+++ ../src-work/minecraft/net/minecraft/tileentity/TileEntity.java
|
||||
@@ -59,6 +59,7 @@
|
||||
@@ -17,7 +17,7 @@
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
-public abstract class TileEntity
|
||||
+public abstract class TileEntity implements net.minecraftforge.common.capabilities.ICapabilitySerializable<NBTTagCompound>
|
||||
{
|
||||
private static final Logger field_145852_a = LogManager.getLogger();
|
||||
private static Map < String, Class <? extends TileEntity >> field_145855_i = Maps. < String, Class <? extends TileEntity >> newHashMap();
|
||||
@@ -59,6 +59,8 @@
|
||||
public void func_145839_a(NBTTagCompound p_145839_1_)
|
||||
{
|
||||
this.field_174879_c = new BlockPos(p_145839_1_.func_74762_e("x"), p_145839_1_.func_74762_e("y"), p_145839_1_.func_74762_e("z"));
|
||||
+ if (p_145839_1_.func_74764_b("ForgeData")) this.customTileData = p_145839_1_.func_74775_l("ForgeData");
|
||||
+ if (this.capabilities != null && p_145839_1_.func_74764_b("ForgeCaps")) this.capabilities.deserializeNBT(p_145839_1_.func_74775_l("ForgeCaps"));
|
||||
}
|
||||
|
||||
public void func_145841_b(NBTTagCompound p_145841_1_)
|
||||
@@ -75,6 +76,7 @@
|
||||
@@ -75,6 +77,8 @@
|
||||
p_145841_1_.func_74768_a("x", this.field_174879_c.func_177958_n());
|
||||
p_145841_1_.func_74768_a("y", this.field_174879_c.func_177956_o());
|
||||
p_145841_1_.func_74768_a("z", this.field_174879_c.func_177952_p());
|
||||
+ if (this.customTileData != null) p_145841_1_.func_74782_a("ForgeData", this.customTileData);
|
||||
+ if (this.capabilities != null) p_145841_1_.func_74782_a("ForgeCaps", this.capabilities.serializeNBT());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,9 +84,10 @@
|
||||
@@ -82,9 +86,10 @@
|
||||
{
|
||||
TileEntity tileentity = null;
|
||||
|
||||
|
@ -28,7 +39,7 @@
|
|||
|
||||
if (oclass != null)
|
||||
{
|
||||
@@ -102,7 +105,17 @@
|
||||
@@ -102,7 +107,17 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -46,7 +57,7 @@
|
|||
}
|
||||
|
||||
return tileentity;
|
||||
@@ -134,7 +147,6 @@
|
||||
@@ -134,7 +149,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,7 +65,7 @@
|
|||
public double func_145835_a(double p_145835_1_, double p_145835_3_, double p_145835_5_)
|
||||
{
|
||||
double d0 = (double)this.field_174879_c.func_177958_n() + 0.5D - p_145835_1_;
|
||||
@@ -279,4 +291,146 @@
|
||||
@@ -279,4 +293,176 @@
|
||||
func_145826_a(TileEntityFlowerPot.class, "FlowerPot");
|
||||
func_145826_a(TileEntityBanner.class, "Banner");
|
||||
}
|
||||
|
@ -199,5 +210,35 @@
|
|||
+ public void onLoad()
|
||||
+ {
|
||||
+ // NOOP
|
||||
+ }
|
||||
+
|
||||
+ private net.minecraftforge.common.capabilities.CapabilityDispatcher capabilities;
|
||||
+ public TileEntity()
|
||||
+ {
|
||||
+ capabilities = net.minecraftforge.event.ForgeEventFactory.gatherCapabilities(this);
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasCapability(net.minecraftforge.common.capabilities.Capability<?> capability, net.minecraft.util.EnumFacing facing)
|
||||
+ {
|
||||
+ if (getCapability(capability, facing) != null)
|
||||
+ return true;
|
||||
+ return capabilities == null ? false : capabilities.hasCapability(capability, facing);
|
||||
+ }
|
||||
+
|
||||
+ public <T> T getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, net.minecraft.util.EnumFacing facing)
|
||||
+ {
|
||||
+ return capabilities == null ? null : capabilities.getCapability(capability, facing);
|
||||
+ }
|
||||
+
|
||||
+ public void deserializeNBT(NBTTagCompound nbt)
|
||||
+ {
|
||||
+ this.func_145839_a(nbt);
|
||||
+ }
|
||||
+
|
||||
+ public NBTTagCompound serializeNBT()
|
||||
+ {
|
||||
+ NBTTagCompound ret = new NBTTagCompound();
|
||||
+ this.func_145841_b(ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
package net.minecraftforge.common.capabilities;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
|
||||
/**
|
||||
* This is the core holder object Capabilities.
|
||||
* Each capability will have ONE instance of this class,
|
||||
* and it will the the one passed into the ICapabilityProvider functions.
|
||||
*
|
||||
* The CapabilityManager is in charge of creating this class.
|
||||
*/
|
||||
public class Capability<T>
|
||||
{
|
||||
public static interface IStorage<T>
|
||||
{
|
||||
/**
|
||||
* Serialize the capability instance to a NBTTag.
|
||||
* This allows for a central implementation of saving the data.
|
||||
*
|
||||
* It is important to note that it is up to the API defining
|
||||
* the capability what requirements the 'instance' value must have.
|
||||
*
|
||||
* Due to the possibility of manipulating internal data, some
|
||||
* implementations MAY require that the 'instance' be an instance
|
||||
* of the 'default' implementation.
|
||||
*
|
||||
* Review the API docs for more info.
|
||||
*
|
||||
* @param capability The Capability being stored.
|
||||
* @param instance An instance of that capabilities interface.
|
||||
* @param side The side of the object the instance is associated with.
|
||||
* @return a NBT holding the data. Null if no data needs to be stored.
|
||||
*/
|
||||
NBTBase writeNBT(Capability<T> capability, T instance, EnumFacing side);
|
||||
|
||||
/**
|
||||
* Read the capability instance from a NBT tag.
|
||||
*
|
||||
* This allows for a central implementation of saving the data.
|
||||
*
|
||||
* It is important to note that it is up to the API defining
|
||||
* the capability what requirements the 'instance' value must have.
|
||||
*
|
||||
* Due to the possibility of manipulating internal data, some
|
||||
* implementations MAY require that the 'instance' be an instance
|
||||
* of the 'default' implementation.
|
||||
*
|
||||
* Review the API docs for more info. *
|
||||
*
|
||||
* @param capability The Capability being stored.
|
||||
* @param instance An instance of that capabilities interface.
|
||||
* @param side The side of the object the instance is associated with.
|
||||
* @param A NBT holding the data. Must not be null, as doesn't make sense to call this function with nothing to read...
|
||||
*/
|
||||
void readNBT(Capability<T> capability, T instance, EnumFacing side, NBTBase nbt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The unique name of this capability, typically this is
|
||||
* the fully qualified class name for the target interface.
|
||||
*/
|
||||
public String getName() { return name; }
|
||||
/**
|
||||
* @return An instance of the default storage handler. You can safely use this store your default implementation in NBT.
|
||||
*/
|
||||
public IStorage<T> getStorage() { return storage; }
|
||||
|
||||
/**
|
||||
* A NEW instance of the default implementation.
|
||||
*
|
||||
* If it important to note that if you want to use the default storage
|
||||
* you may be required to use this exact implementation.
|
||||
* Refer to the owning API of the Capability in question.
|
||||
*
|
||||
* @return A NEW instance of the default implementation.
|
||||
*/
|
||||
public T getDefaultInstance()
|
||||
{
|
||||
try
|
||||
{
|
||||
return this.factory.call();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Throwables.propagate(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// INTERNAL
|
||||
private final String name;
|
||||
private final IStorage<T> storage;
|
||||
private final Callable<? extends T> factory;
|
||||
|
||||
Capability(String name, IStorage<T> storage, Callable<? extends T> factory)
|
||||
{
|
||||
this.name = name;
|
||||
this.storage = storage;
|
||||
this.factory = factory;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
package net.minecraftforge.common.capabilities;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.common.util.INBTSerializable;
|
||||
|
||||
/**
|
||||
* A high-speed implementation of a capability delegator.
|
||||
* This is used to wrap the results of the AttachCapabilitiesEvent.
|
||||
* It is HIGHLY recommended that you DO NOT use this approach unless
|
||||
* you MUST delegate to multiple providers instead just implement y
|
||||
* our handlers using normal if statements.
|
||||
*
|
||||
* Internally the handlers are baked into arrays for fast iteration.
|
||||
* The ResourceLocations will be used for the NBT Key when serializing.
|
||||
*/
|
||||
public final class CapabilityDispatcher implements INBTSerializable<NBTTagCompound>, ICapabilityProvider
|
||||
{
|
||||
private ICapabilityProvider[] caps;
|
||||
private INBTSerializable<NBTBase>[] writers;
|
||||
private String[] names;
|
||||
|
||||
public CapabilityDispatcher(Map<ResourceLocation, ICapabilityProvider> list)
|
||||
{
|
||||
this(list, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public CapabilityDispatcher(Map<ResourceLocation, ICapabilityProvider> list, ICapabilityProvider parent)
|
||||
{
|
||||
List<ICapabilityProvider> lstCaps = Lists.newArrayList();
|
||||
List<INBTSerializable<NBTBase>> lstWriters = Lists.newArrayList();
|
||||
List<String> lstNames = Lists.newArrayList();
|
||||
|
||||
if (parent != null) // Parents go first!
|
||||
{
|
||||
lstCaps.add(parent);
|
||||
if (parent instanceof INBTSerializable)
|
||||
{
|
||||
lstWriters.add((INBTSerializable<NBTBase>)parent);
|
||||
lstNames.add("Parent");
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<ResourceLocation, ICapabilityProvider> entry : list.entrySet())
|
||||
{
|
||||
ICapabilityProvider prov = entry.getValue();
|
||||
lstCaps.add(prov);
|
||||
if (prov instanceof INBTSerializable)
|
||||
{
|
||||
lstWriters.add((INBTSerializable<NBTBase>)prov);
|
||||
lstNames.add(entry.getKey().toString());
|
||||
}
|
||||
}
|
||||
|
||||
caps = lstCaps.toArray(new ICapabilityProvider[lstCaps.size()]);
|
||||
writers = lstWriters.toArray(new INBTSerializable[lstWriters.size()]);
|
||||
names = lstNames.toArray(new String[lstNames.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCapability(Capability<?> capability, EnumFacing facing)
|
||||
{
|
||||
for (ICapabilityProvider cap : caps)
|
||||
{
|
||||
if (cap.hasCapability(capability, facing))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getCapability(Capability<T> capability, EnumFacing facing)
|
||||
{
|
||||
for (ICapabilityProvider cap : caps)
|
||||
{
|
||||
T ret = cap.getCapability(capability, facing);
|
||||
if (ret != null)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTTagCompound serializeNBT()
|
||||
{
|
||||
NBTTagCompound nbt = new NBTTagCompound();
|
||||
for (int x = 0; x < writers.length; x++)
|
||||
{
|
||||
nbt.setTag(names[x], writers[x].serializeNBT());
|
||||
}
|
||||
return nbt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeNBT(NBTTagCompound nbt)
|
||||
{
|
||||
for (int x = 0; x < writers.length; x++)
|
||||
{
|
||||
if (nbt.hasKey(names[x]))
|
||||
{
|
||||
writers[x].deserializeNBT(nbt.getTag(names[x]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package net.minecraftforge.common.capabilities;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* When placed on a FIELD, the field will be set to an
|
||||
* instance of Capability once that capability is registered.
|
||||
* That field must be static and be able to hold a instance
|
||||
* of 'Capability'
|
||||
*
|
||||
* Example:
|
||||
* @CapabilityInject(IExampleCapability.class)
|
||||
* private static final Capability<IExampleCapability> TEST_CAP = null;
|
||||
*
|
||||
* When placed on a METHOD, the method will be invoked once the
|
||||
* capability is registered. This allows you to have a 'enable features'
|
||||
* callback. It MUST have one parameter of type 'Capability;
|
||||
*
|
||||
* Example:
|
||||
* @CapabilityInject(IExampleCapability.class)
|
||||
* private static void capRegistered(Capability<IExampleCapability> cap) {}
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
public @interface CapabilityInject
|
||||
{
|
||||
/**
|
||||
* The capability interface to listen for registration.
|
||||
* Note:
|
||||
* When reading annotations, DO NOT call this function as it will cause a hard dependency on the class.
|
||||
*/
|
||||
Class<?> value();
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
package net.minecraftforge.common.capabilities;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import net.minecraftforge.common.util.EnumHelper;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
import net.minecraftforge.fml.common.discovery.ASMDataTable;
|
||||
|
||||
public enum CapabilityManager
|
||||
{
|
||||
INSTANCE;
|
||||
|
||||
/**
|
||||
* Registers a capability to be consumed by others.
|
||||
* APIs who define the capability should call this.
|
||||
* To retrieve the Capability instance, use the @CapabilityInject annotation.
|
||||
*
|
||||
* @param type The Interface to be registered
|
||||
* @param storage A default implementation of the storage handler.
|
||||
* @param implementation A default implementation of the interface.
|
||||
*/
|
||||
public <T> void register(Class<T> type, Capability.IStorage<T> storage, final Class<? extends T> implementation)
|
||||
{
|
||||
Preconditions.checkArgument(implementation != null, "Attempted to register a capability with no default implementation");
|
||||
register(type, storage, new Callable<T>()
|
||||
{
|
||||
@Override
|
||||
public T call() throws Exception
|
||||
{
|
||||
try {
|
||||
return (T)implementation.newInstance();
|
||||
} catch (InstantiationException e) {
|
||||
Throwables.propagate(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
Throwables.propagate(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a capability to be consumed by others.
|
||||
* APIs who define the capability should call this.
|
||||
* To retrieve the Capability instance, use the @CapabilityInject annotation.
|
||||
*
|
||||
* @param type The Interface to be registered
|
||||
* @param storage A default implementation of the storage handler.
|
||||
* @param factor A Factory that will produce new instances of the default implementation.
|
||||
*/
|
||||
public <T> void register(Class<T> type, Capability.IStorage<T> storage, Callable<? extends T> factory)
|
||||
{
|
||||
Preconditions.checkArgument(type != null, "Attempted to register a capability with invalid type");
|
||||
Preconditions.checkArgument(storage != null, "Attempted to register a capability with no storage implementation");
|
||||
Preconditions.checkArgument(factory != null, "Attempted to register a capability with no default implementation factory");
|
||||
String realName = type.getName().intern();
|
||||
Preconditions.checkState(!providers.containsKey(realName), "Can not register a capability implementation multiple times: %s", realName);
|
||||
|
||||
Capability<T> cap = new Capability<T>(realName, storage, factory);
|
||||
providers.put(realName, cap);
|
||||
|
||||
List<Function<Capability<?>, Object>> list = callbacks.get(realName);
|
||||
if (list != null)
|
||||
{
|
||||
for (Function<Capability<?>, Object> func : list)
|
||||
{
|
||||
func.apply(cap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// INTERNAL
|
||||
private IdentityHashMap<String, Capability<?>> providers = Maps.newIdentityHashMap();
|
||||
private IdentityHashMap<String, List<Function<Capability<?>, Object>>> callbacks = Maps.newIdentityHashMap();
|
||||
public void injectCapabilities(ASMDataTable data)
|
||||
{
|
||||
for (ASMDataTable.ASMData entry : data.getAll(CapabilityInject.class.getName()))
|
||||
{
|
||||
final String targetClass = entry.getClassName();
|
||||
final String targetName = entry.getObjectName();
|
||||
Type type = (Type)entry.getAnnotationInfo().get("value");
|
||||
if (type == null)
|
||||
{
|
||||
FMLLog.log(Level.WARN, "Unable to inject capability at %s.%s (Invalid Annotation)", targetClass, targetName);
|
||||
}
|
||||
final String capabilityName = type.getInternalName().replace('/', '.').intern();
|
||||
|
||||
List<Function<Capability<?>, Object>> list = callbacks.get(capabilityName);
|
||||
if (list == null)
|
||||
{
|
||||
list = Lists.newArrayList();
|
||||
callbacks.put(capabilityName, list);
|
||||
}
|
||||
|
||||
if (entry.getObjectName().indexOf('(') > 0)
|
||||
{
|
||||
list.add(new Function<Capability<?>, Object>()
|
||||
{
|
||||
@Override
|
||||
public Object apply(Capability<?> input)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (Method mtd : Class.forName(targetClass).getDeclaredMethods())
|
||||
{
|
||||
if (targetName.equals(mtd.getName() + Type.getMethodDescriptor(mtd)))
|
||||
{
|
||||
if ((mtd.getModifiers() & Modifier.STATIC) != Modifier.STATIC)
|
||||
{
|
||||
FMLLog.log(Level.WARN, "Unable to inject capability %s at %s.%s (Non-Static)", capabilityName, targetClass, targetName);
|
||||
return null;
|
||||
}
|
||||
|
||||
mtd.setAccessible(true);
|
||||
mtd.invoke(null, input);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
FMLLog.log(Level.WARN, "Unable to inject capability %s at %s.%s (Method Not Found)", capabilityName, targetClass, targetName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
FMLLog.log(Level.WARN, e, "Unable to inject capability %s at %s.%s", capabilityName, targetClass, targetName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
list.add(new Function<Capability<?>, Object>()
|
||||
{
|
||||
@Override
|
||||
public Object apply(Capability<?> input)
|
||||
{
|
||||
try
|
||||
{
|
||||
Field field = Class.forName(targetClass).getDeclaredField(targetName);
|
||||
if ((field.getModifiers() & Modifier.STATIC) != Modifier.STATIC)
|
||||
{
|
||||
FMLLog.log(Level.WARN, "Unable to inject capability %s at %s.%s (Non-Static)", capabilityName, targetClass, targetName);
|
||||
return null;
|
||||
}
|
||||
EnumHelper.setFailsafeFieldValue(field, null, input);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
FMLLog.log(Level.WARN, e, "Unable to inject capability %s at %s.%s", capabilityName, targetClass, targetName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package net.minecraftforge.common.capabilities;
|
||||
|
||||
import net.minecraft.util.EnumFacing;
|
||||
|
||||
public interface ICapabilityProvider
|
||||
{
|
||||
/**
|
||||
* Determines if this object has support for the capability in question on the specific side.
|
||||
* The return value of this MIGHT change during runtime if this object gains or looses support
|
||||
* for a capability.
|
||||
*
|
||||
* Example:
|
||||
* A Pipe getting a cover placed on one side causing it loose the Inventory attachment function for that side.
|
||||
*
|
||||
* This is a light weight version of getCapability, intended for metadata uses.
|
||||
*
|
||||
* @param capability The capability to check
|
||||
* @param facing The Side to check from:
|
||||
* CAN BE NULL. Null is defined to represent 'internal' or 'self'
|
||||
* @return True if this object supports the capability.
|
||||
*/
|
||||
boolean hasCapability(Capability<?> capability, EnumFacing facing);
|
||||
|
||||
/**
|
||||
* Retrieves the handler for the capability requested on the specific side.
|
||||
* The return value CAN be null if the object does not support the capability.
|
||||
* The return value CAN be the same for multiple faces.
|
||||
*
|
||||
* @param capability The capability to check
|
||||
* @param facing The Side to check from:
|
||||
* CAN BE NULL. Null is defined to represent 'internal' or 'self'
|
||||
* @return True if this object supports the capability.
|
||||
*/
|
||||
<T> T getCapability(Capability<T> capability, EnumFacing facing);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package net.minecraftforge.common.capabilities;
|
||||
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraftforge.common.util.INBTSerializable;
|
||||
|
||||
//Just a mix of the two, useful in patches to lower the size.
|
||||
public interface ICapabilitySerializable<T extends NBTBase> extends ICapabilityProvider, INBTSerializable<T>{}
|
|
@ -0,0 +1,13 @@
|
|||
package net.minecraftforge.common.util;
|
||||
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
|
||||
/**
|
||||
* An interface designed to unify various things in the Minecraft
|
||||
* code base that can be serialized to and from a NBT tag.
|
||||
*/
|
||||
public interface INBTSerializable<T extends NBTBase>
|
||||
{
|
||||
T serializeNBT();
|
||||
void deserializeNBT(T nbt);
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
package net.minecraftforge.event;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
|
||||
/**
|
||||
* Fired whenever an object with Capabilities support {currently TileEntity/Item/Entity)
|
||||
* is created. Allowing for the attachment of arbitrary capability providers.
|
||||
*
|
||||
* Please note that as this is fired for ALL object creations efficient code is recommended.
|
||||
* And if possible use one of the sub-classes to filter your intended objects.
|
||||
*/
|
||||
public class AttachCapabilitiesEvent extends Event
|
||||
{
|
||||
private final Object obj;
|
||||
private final Map<ResourceLocation, ICapabilityProvider> caps = Maps.newLinkedHashMap();
|
||||
private final Map<ResourceLocation, ICapabilityProvider> view = Collections.unmodifiableMap(caps);
|
||||
public AttachCapabilitiesEvent(Object obj)
|
||||
{
|
||||
this.obj = obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the object that is being created, Not much state is set.
|
||||
*/
|
||||
public Object getObject()
|
||||
{
|
||||
return this.obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a capability to be attached to this object.
|
||||
* Keys MUST be unique, it is suggested that you set the domain to your mod ID.
|
||||
* If the capability is an instance of INBTSerializeable, this key will be used when serializing this capability.
|
||||
*
|
||||
* @param key The name of owner of this capability provider.
|
||||
* @param cap The capability provider
|
||||
*/
|
||||
public void addCapability(ResourceLocation key, ICapabilityProvider cap)
|
||||
{
|
||||
if (caps.containsKey(key))
|
||||
throw new IllegalStateException("Duplicate Capability Key: " + key + " " + cap);
|
||||
this.caps.put(key, cap);
|
||||
}
|
||||
|
||||
/**
|
||||
* A unmodifiable view of the capabilities that will be attached to this object.
|
||||
*/
|
||||
public Map<ResourceLocation, ICapabilityProvider> getCapabilities()
|
||||
{
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A version of the parent event which is only fired for Tile Entities.
|
||||
*/
|
||||
public static class TileEntity extends AttachCapabilitiesEvent
|
||||
{
|
||||
private final net.minecraft.tileentity.TileEntity te;
|
||||
public TileEntity(net.minecraft.tileentity.TileEntity te)
|
||||
{
|
||||
super(te);
|
||||
this.te = te;
|
||||
}
|
||||
public net.minecraft.tileentity.TileEntity getTileEntity()
|
||||
{
|
||||
return this.te;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of the parent event which is only fired for Entities.
|
||||
*/
|
||||
public static class Entity extends AttachCapabilitiesEvent
|
||||
{
|
||||
private final net.minecraft.entity.Entity entity;
|
||||
public Entity(net.minecraft.entity.Entity entity)
|
||||
{
|
||||
super(entity);
|
||||
this.entity = entity;
|
||||
}
|
||||
public net.minecraft.entity.Entity getEntity()
|
||||
{
|
||||
return this.entity;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of the parent event which is only fired for ItemStacks.
|
||||
*/
|
||||
public static class Item extends AttachCapabilitiesEvent
|
||||
{
|
||||
private final net.minecraft.item.ItemStack stack;
|
||||
private final net.minecraft.item.Item item;
|
||||
public Item(net.minecraft.item.Item item, net.minecraft.item.ItemStack stack)
|
||||
{
|
||||
super(item);
|
||||
this.item = item;
|
||||
this.stack = stack;
|
||||
}
|
||||
public net.minecraft.item.Item getItem()
|
||||
{
|
||||
return this.item;
|
||||
}
|
||||
public net.minecraft.item.ItemStack getItemStack()
|
||||
{
|
||||
return this.stack;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,7 +16,9 @@ import net.minecraft.entity.monster.EntityZombie;
|
|||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayer.EnumStatus;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.BlockPos;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
|
@ -33,6 +35,8 @@ import net.minecraftforge.client.event.ClientChatReceivedEvent;
|
|||
import net.minecraftforge.client.event.RenderBlockOverlayEvent;
|
||||
import net.minecraftforge.client.event.RenderBlockOverlayEvent.OverlayType;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.capabilities.CapabilityDispatcher;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.common.util.BlockSnapshot;
|
||||
import net.minecraftforge.event.brewing.PotionBrewEvent;
|
||||
import net.minecraftforge.event.entity.EntityEvent;
|
||||
|
@ -91,7 +95,7 @@ public class ForgeEventFactory
|
|||
MinecraftForge.EVENT_BUS.post(event);
|
||||
return event;
|
||||
}
|
||||
|
||||
|
||||
public static NeighborNotifyEvent onNeighborNotify(World world, BlockPos pos, IBlockState state, EnumSet<EnumFacing> notifiedSides)
|
||||
{
|
||||
NeighborNotifyEvent event = new NeighborNotifyEvent(world, pos, state, notifiedSides);
|
||||
|
@ -142,7 +146,7 @@ public class ForgeEventFactory
|
|||
MinecraftForge.EVENT_BUS.post(event);
|
||||
return event.getResult();
|
||||
}
|
||||
|
||||
|
||||
public static int getExperienceDrop(EntityLivingBase entity, EntityPlayer attackingPlayer, int originalExperience)
|
||||
{
|
||||
LivingExperienceDropEvent event = new LivingExperienceDropEvent(entity, attackingPlayer, originalExperience);
|
||||
|
@ -323,7 +327,7 @@ public class ForgeEventFactory
|
|||
MinecraftForge.EVENT_BUS.post(event);
|
||||
return event.name;
|
||||
}
|
||||
|
||||
|
||||
public static PlaySoundAtEntityEvent onPlaySoundAtEntity(Entity entity, String name, float volume, float pitch)
|
||||
{
|
||||
PlaySoundAtEntityEvent event = new PlaySoundAtEntityEvent(entity, name, volume, pitch);
|
||||
|
@ -362,18 +366,18 @@ public class ForgeEventFactory
|
|||
{
|
||||
return !MinecraftForge.EVENT_BUS.post(new EntityInteractEvent(player, entity));
|
||||
}
|
||||
|
||||
|
||||
public static boolean canMountEntity(Entity entityMounting, Entity entityBeingMounted, boolean isMounting)
|
||||
{
|
||||
boolean isCanceled = MinecraftForge.EVENT_BUS.post(new EntityMountEvent(entityMounting, entityBeingMounted, entityMounting.worldObj, isMounting));
|
||||
|
||||
|
||||
if(isCanceled)
|
||||
{
|
||||
entityMounting.setPositionAndRotation(entityMounting.posX, entityMounting.posY, entityMounting.posZ, entityMounting.prevRotationYaw, entityMounting.prevRotationPitch);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
public static EnumStatus onPlayerSleepInBed(EntityPlayer player, BlockPos pos)
|
||||
|
@ -392,7 +396,7 @@ public class ForgeEventFactory
|
|||
{
|
||||
MinecraftForge.EVENT_BUS.post(new PlayerFlyableFallEvent(player, distance, multiplier));
|
||||
}
|
||||
|
||||
|
||||
public static boolean onPlayerSpawnSet(EntityPlayer player, BlockPos pos, boolean forced) {
|
||||
return MinecraftForge.EVENT_BUS.post(new PlayerSetSpawnEvent(player, pos, forced));
|
||||
}
|
||||
|
@ -460,20 +464,40 @@ public class ForgeEventFactory
|
|||
{
|
||||
MinecraftForge.EVENT_BUS.post(new PotionBrewEvent.Post(brewingItemStacks));
|
||||
}
|
||||
|
||||
|
||||
public static boolean renderFireOverlay(EntityPlayer player, float renderPartialTicks)
|
||||
{
|
||||
return renderBlockOverlay(player, renderPartialTicks, OverlayType.FIRE, Blocks.fire.getDefaultState(), new BlockPos(player));
|
||||
}
|
||||
|
||||
|
||||
public static boolean renderWaterOverlay(EntityPlayer player, float renderPartialTicks)
|
||||
{
|
||||
return renderBlockOverlay(player, renderPartialTicks, OverlayType.WATER, Blocks.water.getDefaultState(), new BlockPos(player));
|
||||
}
|
||||
|
||||
|
||||
public static boolean renderBlockOverlay(EntityPlayer player, float renderPartialTicks, OverlayType type, IBlockState block, BlockPos pos)
|
||||
{
|
||||
return MinecraftForge.EVENT_BUS.post(new RenderBlockOverlayEvent(player, renderPartialTicks, type, block, pos));
|
||||
}
|
||||
|
||||
public static CapabilityDispatcher gatherCapabilities(TileEntity tileEntity)
|
||||
{
|
||||
return gatherCapabilities(new AttachCapabilitiesEvent.TileEntity(tileEntity), null);
|
||||
}
|
||||
|
||||
public static CapabilityDispatcher gatherCapabilities(Entity entity)
|
||||
{
|
||||
return gatherCapabilities(new AttachCapabilitiesEvent.Entity(entity), null);
|
||||
}
|
||||
|
||||
public static CapabilityDispatcher gatherCapabilities(Item item, ItemStack stack, ICapabilityProvider parent)
|
||||
{
|
||||
return gatherCapabilities(new AttachCapabilitiesEvent.Item(item, stack), parent);
|
||||
}
|
||||
|
||||
private static CapabilityDispatcher gatherCapabilities(AttachCapabilitiesEvent event, ICapabilityProvider parent)
|
||||
{
|
||||
MinecraftForge.EVENT_BUS.post(event);
|
||||
return event.getCapabilities().size() > 0 ? new CapabilityDispatcher(event.getCapabilities(), parent) : null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.util.Properties;
|
|||
import java.util.Set;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.common.capabilities.CapabilityManager;
|
||||
import net.minecraftforge.fml.common.LoaderState.ModState;
|
||||
import net.minecraftforge.fml.common.ModContainer.Disableable;
|
||||
import net.minecraftforge.fml.common.ProgressManager.ProgressBar;
|
||||
|
@ -551,6 +552,7 @@ public class Loader
|
|||
}
|
||||
ObjectHolderRegistry.INSTANCE.findObjectHolders(discoverer.getASMTable());
|
||||
ItemStackHolderInjector.INSTANCE.findHolders(discoverer.getASMTable());
|
||||
CapabilityManager.INSTANCE.injectCapabilities(discoverer.getASMTable());
|
||||
modController.distributeStateMessage(LoaderState.PREINITIALIZATION, discoverer.getASMTable(), canonicalConfigDir);
|
||||
ObjectHolderRegistry.INSTANCE.applyObjectHolders();
|
||||
ItemStackHolderInjector.INSTANCE.inject();
|
||||
|
|
|
@ -42,3 +42,4 @@ net/minecraft/server/management/ServerConfigurationManager.initializeConnectionT
|
|||
net/minecraft/item/ItemMonsterPlacer.spawnCreature(Lnet/minecraft/world/World;Ljava/lang/String;DDD)Lnet/minecraft/entity/Entity;=|p_77840_0_,name,p_77840_2_,p_77840_4_,p_77840_6_
|
||||
|
||||
net/minecraft/stats/StatList.mergeStatBases([Lnet/minecraft/stats/StatBase;Lnet/minecraft/block/Block;Lnet/minecraft/block/Block;Z)V=|p_151180_0_,p_151180_1_,p_151180_2_,useItemIds
|
||||
net/minecraft/item/ItemStack.<init>(Lnet/minecraft/item/Item;IILnet/minecraft/nbt/NBTTagCompound;)V=|p_i1881_1_,p_i1881_2_,p_i1881_3_,capNBT
|
||||
|
|
140
src/test/java/net/minecraftforge/test/TestCapabilityMod.java
Normal file
140
src/test/java/net/minecraftforge/test/TestCapabilityMod.java
Normal file
|
@ -0,0 +1,140 @@
|
|||
package net.minecraftforge.test;
|
||||
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.Capability.IStorage;
|
||||
import net.minecraftforge.common.capabilities.CapabilityInject;
|
||||
import net.minecraftforge.common.capabilities.CapabilityManager;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
|
||||
@Mod(modid="forge.testcapmod",version="1.0")
|
||||
public class TestCapabilityMod
|
||||
{
|
||||
// A Holder/Marker for if this capability is installed.
|
||||
// MUST be Static final doesn't matter but is suggested to prevent
|
||||
// you from overriding it elsewhere.
|
||||
// As Annotations and generic's are erased/unload at runtime this
|
||||
// does NOT create a hard dependency on the class.
|
||||
@CapabilityInject(IExampleCapability.class)
|
||||
private static final Capability<IExampleCapability> TEST_CAP = null;
|
||||
|
||||
@Mod.EventHandler
|
||||
public void preinit(FMLPreInitializationEvent evt)
|
||||
{
|
||||
// If you are a API, provide register your capability ASAP.
|
||||
// You MUST supply a default save handler and a default implementation
|
||||
// If you are a CONSUMER of the capability DO NOT register it. Only APIs should.
|
||||
CapabilityManager.INSTANCE.register(IExampleCapability.class, new Storage(), DefaultImpl.class);
|
||||
MinecraftForge.EVENT_BUS.register(this);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onInteract(PlayerInteractEvent event)
|
||||
{
|
||||
if (event.action != PlayerInteractEvent.Action.LEFT_CLICK_BLOCK) return;
|
||||
if (event.entityPlayer.getHeldItem() == null) return;
|
||||
if (event.entityPlayer.getHeldItem().getItem() != Items.stick) return;
|
||||
|
||||
// This is just a example of how to interact with the TE, note the strong type binding that getCapability has
|
||||
TileEntity te = event.world.getTileEntity(event.pos);
|
||||
if (te != null && te.hasCapability(TEST_CAP, event.face))
|
||||
{
|
||||
event.setCanceled(true);
|
||||
IExampleCapability inv = te.getCapability(TEST_CAP, event.face);
|
||||
System.out.println("Hi I'm a " + inv.getOwnerType());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Example of having this annotation on a method, this will be called when the capability is present.
|
||||
// You could do something like register event handlers to attach these capabilities to objects, or
|
||||
// setup your factory, who knows. Just figured i'd give you the power.
|
||||
@CapabilityInject(IExampleCapability.class)
|
||||
private static void capRegistered(Capability<IExampleCapability> cap)
|
||||
{
|
||||
System.out.println("IExampleCapability was registered wheeeeee!");
|
||||
}
|
||||
|
||||
// An example of how to attach a capability to an arbitrary Tile entity.
|
||||
// Note: Doing this IS NOT recommended for normal implementations.
|
||||
// If you control the TE it is HIGHLY recommend that you implement a fast
|
||||
// version of the has/getCapability functions yourself. So you have control
|
||||
// over everything yours being called first.
|
||||
@SubscribeEvent
|
||||
public void onTELoad(AttachCapabilitiesEvent.TileEntity event)
|
||||
{
|
||||
// Having the Provider implement the cap is not recomended as this creates a hard dep on the cap interface.
|
||||
// And doesnt allow for sidedness.
|
||||
// But as this is a example and we dont care about that here we go.
|
||||
class Provider implements ICapabilityProvider, IExampleCapability
|
||||
{
|
||||
private TileEntity te;
|
||||
|
||||
Provider(TileEntity te)
|
||||
{
|
||||
this.te = te;
|
||||
}
|
||||
@Override
|
||||
public boolean hasCapability(Capability<?> capability, EnumFacing facing)
|
||||
{
|
||||
return TEST_CAP != null && capability == TEST_CAP;
|
||||
}
|
||||
@SuppressWarnings("unchecked") //There isnt anything sane we can do about this.
|
||||
@Override
|
||||
public <T> T getCapability(Capability<T> capability, EnumFacing facing)
|
||||
{
|
||||
if (TEST_CAP != null && capability == TEST_CAP) return (T)this;
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String getOwnerType() {
|
||||
return te.getClass().getName();
|
||||
}
|
||||
}
|
||||
|
||||
//Attach it! The resource location MUST be unique it's recomneded that you tag it with your modid and what the cap is.
|
||||
event.addCapability(new ResourceLocation("TestCapabilityMod:DummyCap"), new Provider(event.getTileEntity()));
|
||||
}
|
||||
|
||||
// Capabilities SHOULD be interfaces, NOT concrete classes, this allows for
|
||||
// the most flexibility for the implementors.
|
||||
public static interface IExampleCapability
|
||||
{
|
||||
String getOwnerType();
|
||||
}
|
||||
|
||||
// Storage implementations are required, tho there is some flexibility here.
|
||||
// If you are the API provider you can also say that in order to use the default storage
|
||||
// the consumer MUST use the default impl, to allow you to access innards.
|
||||
// This is just a contract you will have to stipulate in the documentation of your cap.
|
||||
public static class Storage implements IStorage<IExampleCapability>
|
||||
{
|
||||
@Override
|
||||
public NBTBase writeNBT(Capability<IExampleCapability> capability, IExampleCapability instance, EnumFacing side) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readNBT(Capability<IExampleCapability> capability, IExampleCapability instance, EnumFacing side, NBTBase nbt) {
|
||||
}
|
||||
}
|
||||
|
||||
// You MUST also supply a default implementation.
|
||||
// This is to make life easier on consumers.
|
||||
public static class DefaultImpl implements IExampleCapability {
|
||||
@Override
|
||||
public String getOwnerType(){
|
||||
return "Default Implementation!";
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue