Files
Wizardry/src/main/java/electroblob/wizardry/data/SpellEmitterData.java
T

129 lines
4.4 KiB
Java

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)}.<br>
* <br>
* 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<SpellEmitter> 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);
}
}
}