package electroblob.wizardry.data; import electroblob.wizardry.Wizardry; import electroblob.wizardry.command.SpellEmitter; import electroblob.wizardry.packet.PacketEmitterData; import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.spell.Spell; import electroblob.wizardry.util.NBTExtras; import electroblob.wizardry.util.SpellModifiers; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.util.EnumFacing; import net.minecraft.world.World; import net.minecraft.world.storage.WorldSavedData; import net.minecraftforge.common.util.Constants; import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.PlayerEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; import java.util.ArrayList; import java.util.List; /** * Class responsible for storing and keeping track of {@link SpellEmitter}s. Each world has its own instance of * {@code SpellEmitterData} which can be retrieved using {@link SpellEmitterData#get(World)}.
*
* To add a new {@code SpellEmitter}, use {@link SpellEmitter#add(Spell, World, double, double, double, EnumFacing, int, SpellModifiers)}. * * @since Wizardry 4.2 * @author Electroblob */ @Mod.EventBusSubscriber public class SpellEmitterData extends WorldSavedData { public static final String NAME = Wizardry.MODID + "_spell_emitters"; private final List emitters = new ArrayList<>(); private NBTTagList emitterTags = null; // Required constructors public SpellEmitterData(){ this(NAME); } public SpellEmitterData(String name){ super(name); } /** Returns the spell emitter data for this world, or creates a new instance if it doesn't exist yet. */ public static SpellEmitterData get(World world){ SpellEmitterData instance = (SpellEmitterData)world.getPerWorldStorage().getOrLoadData(SpellEmitterData.class, NAME); if(instance == null){ instance = new SpellEmitterData(); world.getPerWorldStorage().setData(NAME, instance); }else if(instance.emitters.isEmpty() && instance.emitterTags != null){ instance.loadEmitters(world); } return instance; } /** Sends the active spell emitters for this world to the specified player's client. */ public void sync(EntityPlayerMP player){ PacketEmitterData.Message msg = new PacketEmitterData.Message(emitters); WizardryPacketHandler.net.sendTo(msg, player); Wizardry.logger.info("Synchronising spell emitters for " + player.getName()); } /** Adds the given {@link SpellEmitter} to the list of emitters for this {@code SpellEmitterData}. */ public void add(SpellEmitter emitter){ emitters.add(emitter); markDirty(); } @Override public void readFromNBT(NBTTagCompound nbt){ emitterTags = nbt.getTagList("emitters", Constants.NBT.TAG_COMPOUND); } private void loadEmitters(World world){ emitters.clear(); emitters.addAll(NBTExtras.NBTToList(emitterTags, (NBTTagCompound t) -> SpellEmitter.fromNBT(world, t))); emitterTags = null; // Now we know it's loaded } @Override public NBTTagCompound writeToNBT(NBTTagCompound compound){ NBTExtras.storeTagSafely(compound, "emitters", NBTExtras.listToNBT(emitters, SpellEmitter::toNBT)); return compound; } public static void update(World world){ SpellEmitterData data = SpellEmitterData.get(world); if(!data.emitters.isEmpty()){ data.emitters.forEach(SpellEmitter::update); data.emitters.removeIf(SpellEmitter::needsRemoving); data.markDirty(); // Mark dirty if there are changes to be saved } } @SubscribeEvent public static void tick(TickEvent.WorldTickEvent event){ if(!event.world.isRemote && event.phase == TickEvent.Phase.END){ update(event.world); } } @SubscribeEvent public static void onWorldLoadEvent(WorldEvent.Load event){ // Called to initialise the spell emitter data when a world loads, if it isn't already. SpellEmitterData.get(event.getWorld()); } @SubscribeEvent public static void onPlayerChangedDimensionEvent(PlayerEvent.PlayerChangedDimensionEvent event){ // Needs to be done here as well as PlayerLoggedInEvent because SpellEmitterData is dimension-specific if(event.player instanceof EntityPlayerMP){ SpellEmitterData.get(event.player.world).sync((EntityPlayerMP)event.player); } } }