Add Chunk capabilities (#4228)

This commit is contained in:
Erlend Åmdal 2017-10-03 05:24:11 +02:00 committed by LexManos
parent 267cd19291
commit 8a285e0fed
4 changed files with 267 additions and 25 deletions

View File

@ -1,6 +1,23 @@
--- ../src-base/minecraft/net/minecraft/world/chunk/Chunk.java
+++ ../src-work/minecraft/net/minecraft/world/chunk/Chunk.java
@@ -179,7 +179,7 @@
@@ -41,7 +41,7 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-public class Chunk
+public class Chunk implements net.minecraftforge.common.capabilities.ICapabilityProvider
{
private static final Logger field_150817_t = LogManager.getLogger();
public static final ExtendedBlockStorage field_186036_a = null;
@@ -91,6 +91,7 @@
Arrays.fill(this.field_76638_b, -999);
Arrays.fill(this.field_76651_r, (byte) - 1);
+ capabilities = net.minecraftforge.event.ForgeEventFactory.gatherCapabilities(this);
}
public Chunk(World p_i45645_1_, ChunkPrimer p_i45645_2_, int p_i45645_3_, int p_i45645_4_)
@@ -179,7 +180,7 @@
{
IBlockState iblockstate = this.func_186032_a(j, l - 1, k);
@ -9,7 +26,7 @@
{
this.field_76634_f[k << 4 | j] = l;
@@ -452,12 +452,13 @@
@@ -452,12 +453,13 @@
public int func_177437_b(BlockPos p_177437_1_)
{
@ -25,7 +42,7 @@
}
public IBlockState func_177435_g(BlockPos p_177435_1_)
@@ -539,6 +540,7 @@
@@ -539,6 +541,7 @@
{
Block block = p_177436_2_.func_177230_c();
Block block1 = iblockstate.func_177230_c();
@ -33,7 +50,7 @@
ExtendedBlockStorage extendedblockstorage = this.field_76652_q[j >> 4];
boolean flag = false;
@@ -556,14 +558,19 @@
@@ -556,14 +559,19 @@
extendedblockstorage.func_177484_a(i, j & 15, k, p_177436_2_);
@ -55,7 +72,7 @@
this.field_76637_e.func_175713_t(p_177436_1_);
}
}
@@ -580,8 +587,7 @@
@@ -580,8 +588,7 @@
}
else
{
@ -65,7 +82,7 @@
if (j1 > 0)
{
@@ -601,28 +607,19 @@
@@ -601,28 +608,19 @@
}
}
@ -98,7 +115,7 @@
this.field_76637_e.func_175690_a(p_177436_1_, tileentity1);
}
@@ -738,6 +735,7 @@
@@ -738,6 +736,7 @@
k = this.field_76645_j.length - 1;
}
@ -106,7 +123,7 @@
p_76612_1_.field_70175_ag = true;
p_76612_1_.field_70176_ah = this.field_76635_g;
p_76612_1_.field_70162_ai = k;
@@ -778,7 +776,7 @@
@@ -778,7 +777,7 @@
{
IBlockState iblockstate = this.func_177435_g(p_177422_1_);
Block block = iblockstate.func_177230_c();
@ -115,7 +132,7 @@
}
@Nullable
@@ -786,6 +784,12 @@
@@ -786,6 +785,12 @@
{
TileEntity tileentity = this.field_150816_i.get(p_177424_1_);
@ -128,7 +145,7 @@
if (tileentity == null)
{
if (p_177424_2_ == Chunk.EnumCreateEntityType.IMMEDIATE)
@@ -795,14 +799,9 @@
@@ -795,14 +800,9 @@
}
else if (p_177424_2_ == Chunk.EnumCreateEntityType.QUEUED)
{
@ -144,7 +161,7 @@
return tileentity;
}
@@ -819,10 +818,11 @@
@@ -819,10 +819,11 @@
public void func_177426_a(BlockPos p_177426_1_, TileEntity p_177426_2_)
{
@ -157,7 +174,7 @@
{
if (this.field_150816_i.containsKey(p_177426_1_))
{
@@ -854,8 +854,9 @@
@@ -854,8 +855,9 @@
for (ClassInheritanceMultiMap<Entity> classinheritancemultimap : this.field_76645_j)
{
@ -168,7 +185,7 @@
}
public void func_76623_d()
@@ -871,6 +872,7 @@
@@ -871,6 +873,7 @@
{
this.field_76637_e.func_175681_c(classinheritancemultimap);
}
@ -176,7 +193,7 @@
}
public void func_76630_e()
@@ -880,8 +882,8 @@
@@ -880,8 +883,8 @@
public void func_177414_a(@Nullable Entity p_177414_1_, AxisAlignedBB p_177414_2_, List<Entity> p_177414_3_, Predicate <? super Entity > p_177414_4_)
{
@ -187,7 +204,7 @@
i = MathHelper.func_76125_a(i, 0, this.field_76645_j.length - 1);
j = MathHelper.func_76125_a(j, 0, this.field_76645_j.length - 1);
@@ -918,8 +920,8 @@
@@ -918,8 +921,8 @@
public <T extends Entity> void func_177430_a(Class <? extends T > p_177430_1_, AxisAlignedBB p_177430_2_, List<T> p_177430_3_, Predicate <? super T > p_177430_4_)
{
@ -198,7 +215,7 @@
i = MathHelper.func_76125_a(i, 0, this.field_76645_j.length - 1);
j = MathHelper.func_76125_a(j, 0, this.field_76645_j.length - 1);
@@ -997,6 +999,8 @@
@@ -997,6 +100,8 @@
protected void func_186034_a(IChunkGenerator p_186034_1_)
{
@ -207,7 +224,7 @@
if (this.func_177419_t())
{
if (p_186034_1_.func_185933_a(this, this.field_76635_g, this.field_76647_h))
@@ -1008,8 +1012,10 @@
@@ -1008,8 +1013,10 @@
{
this.func_150809_p();
p_186034_1_.func_185931_b(this.field_76635_g, this.field_76647_h);
@ -218,7 +235,7 @@
}
public BlockPos func_177440_h(BlockPos p_177440_1_)
@@ -1064,7 +1070,7 @@
@@ -1064,7 +1071,7 @@
{
BlockPos blockpos = this.field_177447_w.poll();
@ -227,7 +244,7 @@
{
TileEntity tileentity = this.func_177422_i(blockpos);
this.field_76637_e.func_175690_a(blockpos, tileentity);
@@ -1128,6 +1134,13 @@
@@ -1128,6 +1135,13 @@
@SideOnly(Side.CLIENT)
public void func_186033_a(PacketBuffer p_186033_1_, int p_186033_2_, boolean p_186033_3_)
{
@ -241,7 +258,7 @@
boolean flag = this.field_76637_e.field_73011_w.func_191066_m();
for (int i = 0; i < this.field_76652_q.length; ++i)
@@ -1176,10 +1189,16 @@
@@ -1176,10 +1190,16 @@
this.field_76646_k = true;
this.func_76590_a();
@ -258,7 +275,7 @@
}
public Biome func_177411_a(BlockPos p_177411_1_, BiomeProvider p_177411_2_)
@@ -1244,13 +1263,13 @@
@@ -1244,13 +1264,13 @@
BlockPos blockpos1 = blockpos.func_177982_a(k, (j << 4) + i1, l);
boolean flag = i1 == 0 || i1 == 15 || k == 0 || k == 15 || l == 0 || l == 15;
@ -274,7 +291,7 @@
{
this.field_76637_e.func_175664_x(blockpos2);
}
@@ -1381,7 +1400,7 @@
@@ -1381,7 +1401,7 @@
{
blockpos$mutableblockpos.func_181079_c(blockpos$mutableblockpos.func_177958_n(), l, blockpos$mutableblockpos.func_177952_p());
@ -283,7 +300,7 @@
{
this.field_76637_e.func_175664_x(blockpos$mutableblockpos);
}
@@ -1489,4 +1508,34 @@
@@ -1489,4 +1509,34 @@
QUEUED,
CHECK;
}
@ -316,5 +333,23 @@
+ net.minecraftforge.fml.common.FMLLog.log.debug(format, "Minecraft", this.field_76635_g, this.field_76647_h, this.field_76637_e.field_73011_w.getDimension());
+ else
+ net.minecraftforge.fml.common.FMLLog.log.warn(format, activeModContainer.getName(), this.field_76635_g, this.field_76647_h, this.field_76637_e.field_73011_w.getDimension());
+ }
+
+ private final net.minecraftforge.common.capabilities.CapabilityDispatcher capabilities;
+ @Nullable
+ public net.minecraftforge.common.capabilities.CapabilityDispatcher getCapabilities()
+ {
+ return capabilities;
+ }
+ @Override
+ public boolean hasCapability(net.minecraftforge.common.capabilities.Capability<?> capability, @Nullable EnumFacing facing)
+ {
+ return capabilities == null ? false : capabilities.hasCapability(capability, facing);
+ }
+ @Override
+ @Nullable
+ public <T> T getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable EnumFacing facing)
+ {
+ return capabilities == null ? null : capabilities.getCapability(capability, facing);
+ }
}

View File

@ -132,10 +132,33 @@
}
p_75820_3_.func_74782_a("TileEntities", nbttaglist2);
@@ -388,6 +453,12 @@
@@ -345,6 +410,18 @@
p_75820_3_.func_74782_a("TileTicks", nbttaglist3);
}
+
+ if (p_75820_1_.getCapabilities() != null)
+ {
+ try
+ {
+ p_75820_3_.func_74782_a("ForgeCaps", p_75820_1_.getCapabilities().serializeNBT());
+ }
+ catch (Exception exception)
+ {
+ net.minecraftforge.fml.common.FMLLog.log.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 func_75823_a(World p_75823_1_, NBTTagCompound p_75823_2_)
@@ -388,6 +465,16 @@
chunk.func_76616_a(p_75823_2_.func_74770_j("Biomes"));
}
+ if (chunk.getCapabilities() != null && p_75823_2_.func_74764_b("ForgeCaps")) {
+ chunk.getCapabilities().deserializeNBT(p_75823_2_.func_74775_l("ForgeCaps"));
+ }
+
+ // End this method here and split off entity loading to another method
+ return chunk;
+ }
@ -145,7 +168,7 @@
NBTTagList nbttaglist1 = p_75823_2_.func_150295_c("Entities", 10);
for (int j1 = 0; j1 < nbttaglist1.func_74745_c(); ++j1)
@@ -431,8 +502,6 @@
@@ -431,8 +518,6 @@
p_75823_1_.func_180497_b(new BlockPos(nbttagcompound3.func_74762_e("x"), nbttagcompound3.func_74762_e("y"), nbttagcompound3.func_74762_e("z")), block, nbttagcompound3.func_74762_e("t"), nbttagcompound3.func_74762_e("p"));
}
}

View File

@ -59,6 +59,7 @@ import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.WorldSettings;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkPrimer;
import net.minecraft.world.gen.IChunkGenerator;
import net.minecraft.world.storage.IPlayerFileData;
@ -597,6 +598,12 @@ public class ForgeEventFactory
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
private static CapabilityDispatcher gatherCapabilities(AttachCapabilitiesEvent<?> event, @Nullable ICapabilityProvider parent)
{

View File

@ -0,0 +1,177 @@
package net.minecraftforge.debug;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagInt;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.chunk.Chunk;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Simple mod to test chunk capabilities.
* Use flint and steel to increase pollution in a chunk and saplings to decrease pollution in a chunk.
*/
@Mod(modid = ChunkCapabilityPollutionTest.MODID, name = "Chunk Capability Test", version = "0.0.0")
public class ChunkCapabilityPollutionTest {
public static final String MODID = "chunkcapabilitypollutiontest";
public static final boolean ENABLE = false;
public interface IPollution
{
int get();
void set(int value, boolean markDirty);
}
public static class PollutionStorage implements Capability.IStorage<IPollution>
{
@Nullable
@Override
public NBTBase writeNBT(Capability<IPollution> capability, IPollution instance, EnumFacing side) {
return new NBTTagInt(instance.get());
}
@Override
public void readNBT(Capability<IPollution> capability, IPollution instance, EnumFacing side, NBTBase nbt) {
if (nbt instanceof NBTTagInt)
{
// The state is being loaded and not updated. We set the value silently to avoid unnecessary dirty chunks
instance.set(((NBTTagInt) nbt).getInt(), false);
}
}
}
public static class DefaultPollution implements IPollution
{
private int value;
@Override
public int get() {
return value;
}
@Override
public void set(int value, boolean markDirty) {
this.value = value;
}
}
/**
* Marks the chunk as dirty when the value changes.
* Cannot be the default implementation because it requires a chunk in the constructor
*/
public static class SafePollution extends DefaultPollution
{
private final Chunk chunk;
public SafePollution(Chunk chunk)
{
this.chunk = chunk;
}
@Override
public void set(int value, boolean markDirty) {
super.set(value, markDirty);
if (markDirty) {
chunk.markDirty();
}
}
}
public static class PollutionProvider implements ICapabilitySerializable<NBTBase>
{
private final IPollution pollution;
public PollutionProvider(Chunk chunk)
{
pollution = new SafePollution(chunk);
}
@Override
public NBTBase serializeNBT() {
return POLLUTION_CAPABILITY.getStorage().writeNBT(POLLUTION_CAPABILITY, pollution, null);
}
@Override
public void deserializeNBT(NBTBase nbt) {
POLLUTION_CAPABILITY.getStorage().readNBT(POLLUTION_CAPABILITY, pollution, null, nbt);
}
@Override
public boolean hasCapability(@Nonnull Capability<?> capability, @Nullable EnumFacing facing) {
return capability == POLLUTION_CAPABILITY;
}
@Nullable
@Override
public <T> T getCapability(@Nonnull Capability<T> capability, @Nullable EnumFacing facing) {
return capability == POLLUTION_CAPABILITY ? POLLUTION_CAPABILITY.cast(pollution) : null;
}
}
public static class EventBusHandler
{
@SubscribeEvent
public void onAttachChunkCapabilities(AttachCapabilitiesEvent<Chunk> event)
{
event.addCapability(new ResourceLocation(MODID, "pollution"), new PollutionProvider(event.getObject()));
}
@SubscribeEvent
public void onUseItem(PlayerInteractEvent.RightClickBlock event)
{
if (!event.getWorld().isRemote) {
ItemStack stack = event.getEntityPlayer().getHeldItem(event.getHand());
int delta = 0;
if (stack.getItem() == Items.FLINT_AND_STEEL)
{
delta = 1;
}
else if (stack.getItem() == Item.getItemFromBlock(Blocks.SAPLING))
{
delta = -1;
}
if (delta != 0)
{
Chunk chunk = event.getWorld().getChunkFromBlockCoords(event.getPos());
IPollution pollution = chunk.getCapability(POLLUTION_CAPABILITY, null);
pollution.set(pollution.get() + delta, true);
event.getEntityPlayer().sendStatusMessage(new TextComponentString("Chunk pollution: " + pollution.get()), true);
}
}
}
}
@CapabilityInject(IPollution.class)
public static final Capability<IPollution> POLLUTION_CAPABILITY = null;
@Mod.EventHandler
public void init(FMLInitializationEvent event)
{
if (ENABLE)
{
CapabilityManager.INSTANCE.register(IPollution.class, new PollutionStorage(), DefaultPollution.class);
MinecraftForge.EVENT_BUS.register(new EventBusHandler());
}
}
}