package choonster.testmod3.capability.chunkenergy; import choonster.testmod3.TestMod3; import choonster.testmod3.api.capability.chunkenergy.IChunkEnergy; import choonster.testmod3.api.capability.chunkenergy.IChunkEnergyHolder; import choonster.testmod3.api.capability.chunkenergy.IChunkEnergyHolderModifiable; import choonster.testmod3.capability.CapabilityProviderSimple; import choonster.testmod3.network.MessageUpdateChunkEnergyValue; import choonster.testmod3.util.CapabilityUtils; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagInt; import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.ChunkPos; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.CapabilityInject; import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.common.util.Constants; import net.minecraftforge.event.AttachCapabilitiesEvent; import net.minecraftforge.event.world.ChunkDataEvent; import net.minecraftforge.event.world.ChunkEvent; import net.minecraftforge.event.world.ChunkWatchEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import javax.annotation.Nullable; /** * Capability to store per-chunk energy values. * * @author Choonster */ public class CapabilityChunkEnergy { /** * The {@link Capability} instance */ @CapabilityInject(IChunkEnergyHolder.class) public static final Capability<IChunkEnergyHolder> CHUNK_ENERGY_CAPABILITY = null; /** * The default {@link EnumFacing} to use for this capability. */ public static final EnumFacing DEFAULT_FACING = null; /** * The default capacity of an {@link IChunkEnergy}. */ public static final int DEFAULT_CAPACITY = 1000; /** * The ID of this capability. */ private static final ResourceLocation ID = new ResourceLocation(TestMod3.MODID, "chunk_energy"); /** * The ID of this capability. */ private static final String ID_STRING = ID.toString(); public static void register() { CapabilityManager.INSTANCE.register(IChunkEnergyHolder.class, new Capability.IStorage<IChunkEnergyHolder>() { @Override public NBTBase writeNBT(final Capability<IChunkEnergyHolder> capability, final IChunkEnergyHolder instance, final EnumFacing side) { return new NBTTagCompound(); } @Override public void readNBT(final Capability<IChunkEnergyHolder> capability, final IChunkEnergyHolder instance, final EnumFacing side, final NBTBase nbt) { } }, ChunkEnergyHolder::new); } /** * Get the {@link IChunkEnergyHolder} for the {@link World}, if any. * * @param world The World * @return The IChunkEnergyHolder, if any */ @Nullable public static IChunkEnergyHolder getChunkEnergyHolder(final World world) { return CapabilityUtils.getCapability(world, CHUNK_ENERGY_CAPABILITY, DEFAULT_FACING); } /** * Get the {@link IChunkEnergy} for the {@link World} and chunk position. * * @param world The World * @param chunkPos The chunk position * @return The IChunkEnergy, if any */ @Nullable public static IChunkEnergy getChunkEnergy(final World world, final ChunkPos chunkPos) { final IChunkEnergyHolder chunkEnergyHolder = getChunkEnergyHolder(world); if (chunkEnergyHolder == null) return null; return chunkEnergyHolder.getChunkEnergy(chunkPos); } /** * Get the {@link IChunkEnergy} for the chunk. * * @param chunk The chunk * @return The IChunkEnergy, if any */ @Nullable public static IChunkEnergy getChunkEnergy(final Chunk chunk) { return getChunkEnergy(chunk.getWorld(), chunk.getPos()); } @Mod.EventBusSubscriber @SuppressWarnings("unused") private static class EventHandler { /** * Attach the {@link IChunkEnergyHolder} capability to all {@link World}s. * * @param event The event */ @SubscribeEvent public static void attachCapabilities(final AttachCapabilitiesEvent<World> event) { final IChunkEnergyHolder chunkEnergyHolder = new ChunkEnergyHolder(); event.addCapability(ID, new CapabilityProviderSimple<>(chunkEnergyHolder, CHUNK_ENERGY_CAPABILITY, DEFAULT_FACING)); } /** * Load the {@link IChunkEnergy} for a chunk when the chunk is loaded. * * @param event The event */ @SubscribeEvent public static void chunkDataLoad(final ChunkDataEvent.Load event) { final World world = event.getWorld(); final ChunkPos chunkPos = event.getChunk().getPos(); final IChunkEnergyHolder chunkEnergyHolder = getChunkEnergyHolder(world); if (!(chunkEnergyHolder instanceof IChunkEnergyHolderModifiable)) return; final ChunkEnergy chunkEnergy = new ChunkEnergy(DEFAULT_CAPACITY, world, chunkPos); final NBTTagCompound chunkData = event.getData(); if (chunkData.hasKey(ID_STRING, Constants.NBT.TAG_INT)) { final NBTTagInt energyTag = (NBTTagInt) chunkData.getTag(ID_STRING); chunkEnergy.deserializeNBT(energyTag); } ((IChunkEnergyHolderModifiable) chunkEnergyHolder).setChunkEnergy(chunkPos, chunkEnergy); } /** * Create a default {@link IChunkEnergy} for a chunk when it's loaded, if it doesn't already have one. * <p> * {@link ChunkDataEvent.Load} is never fired for client-side chunks, so this allows them to have a default * {@link IChunkEnergy} created when they load. * * @param event The event */ @SubscribeEvent public static void chunkLoad(final ChunkEvent.Load event) { final World world = event.getWorld(); final ChunkPos chunkPos = event.getChunk().getPos(); final IChunkEnergyHolder chunkEnergyHolder = getChunkEnergyHolder(world); if (!(chunkEnergyHolder instanceof IChunkEnergyHolderModifiable)) return; if (chunkEnergyHolder.getChunkEnergy(chunkPos) != null) return; final IChunkEnergy chunkEnergy = new ChunkEnergy(DEFAULT_CAPACITY, world, chunkPos); ((IChunkEnergyHolderModifiable) chunkEnergyHolder).setChunkEnergy(chunkPos, chunkEnergy); } /** * Save the {@link IChunkEnergy} for a chunk when a chunk is saved. * * @param event The event */ @SubscribeEvent public static void chunkDataSave(final ChunkDataEvent.Save event) { final IChunkEnergy chunkEnergy = getChunkEnergy(event.getChunk()); if (!(chunkEnergy instanceof ChunkEnergy)) return; event.getData().setTag(ID_STRING, ((ChunkEnergy) chunkEnergy).serializeNBT()); } /** * Remove the {@link IChunkEnergy} for a chunk when a chunk is unloaded. * * @param event The event */ @SubscribeEvent public static void chunkUnload(final ChunkEvent.Unload event) { final IChunkEnergyHolder chunkEnergyHolder = getChunkEnergyHolder(event.getWorld()); if (!(chunkEnergyHolder instanceof IChunkEnergyHolderModifiable)) return; ((IChunkEnergyHolderModifiable) chunkEnergyHolder).removeChunkEnergy(event.getChunk().getPos()); } /** * Send the {@link IChunkEnergy} to the client when a player starts watching the chunk. * * @param event The event */ @SubscribeEvent public static void chunkWatch(final ChunkWatchEvent.Watch event) { final EntityPlayerMP player = event.getPlayer(); final IChunkEnergy chunkEnergy = getChunkEnergy(player.getEntityWorld(), event.getChunk()); if (chunkEnergy == null) return; TestMod3.network.sendTo(new MessageUpdateChunkEnergyValue(chunkEnergy), player); } } }