/** * Copyright (c) Lambda Innovation, 2013-2015 * 本作品版权由Lambda Innovation所有。 * http://www.li-dev.cn/ * * This project is open-source, and it is distributed under * the terms of GNU General Public License. You can modify * and distribute freely as long as you follow the license. * 本项目是一个开源项目,且遵循GNU通用公共授权协议。 * 在遵照该协议的情况下,您可以自由传播和修改。 * http://www.gnu.org/licenses/gpl.html */ package cn.liutils.util.helper; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; import cn.annoreg.core.Registrant; import cn.annoreg.mc.network.RegNetworkCall; import cn.annoreg.mc.s11n.InstanceSerializer; import cn.annoreg.mc.s11n.RegSerializable; import cn.annoreg.mc.s11n.SerializationManager; import cn.annoreg.mc.s11n.StorageOption.Data; import cn.annoreg.mc.s11n.StorageOption.Target; import cpw.mods.fml.relauncher.Side; /** * DataPart represents a single tickable instance attached on an EntityPlayer. * It is driven by the PlayerData of this player. <br/> * * The DataPart is attached statically via {@link PlayerData#register(String, Class)} * method or @RegDataPart (This should be done at init stages), and is automatically constructed when an * EntityPlayer enters the world. At server, the {@link DataPart#fromNBT(NBTTagCompound)} * method will be called right away, and the NBT will also be sync to client ASAP. * Also when the world is being saved, the {@link DataPart#toNBT()} will be called to save stuffs * in server. * <br/> * * A simple sync helper is provided. You can use sync() in both CLIENT and SERVER side to make a new NBT * synchronization. However, for complex syncs you might want to consider using NetworkCall. * * When player is available the {@link DataPart#tick()} will get called every tick. You can * process update stuffs within that method. <br/> * * TODO If tick is too slow make selective ticking optimization <br/> * @author WeAthFolD */ @Registrant @RegSerializable(instance = DataPart.Serializer.class) public abstract class DataPart { /** * Internal sync flag, used to determine whether this part is init in client. */ boolean dirty = true; int tickUntilQuery = 0; /** * The player instance when this data is available. Do NOT modify this field! */ PlayerData data; public DataPart() {} /** * Invoked every tick */ public void tick() {} public EntityPlayer getPlayer() { return data.player; } public boolean isRemote() { return getPlayer().worldObj.isRemote; } public <T extends DataPart> T getPart(String name) { return data.getPart(name); } public String getName() { return data.getName(this); } /** * Return true if this data has received the initial sync. * ALWAYS true in server. */ protected boolean isSynced() { return !dirty; } protected void sync() { if(isRemote()) { syncFromClient(toNBTSync()); } else { syncFromServer(getPlayer(), toNBTSync()); } } @RegNetworkCall(side = Side.SERVER) private void syncFromClient(@Data NBTTagCompound tag) { fromNBTSync(tag); } @RegNetworkCall(side = Side.CLIENT) private void syncFromServer(@Target EntityPlayer player, @Data NBTTagCompound tag) { fromNBTSync(tag); } public abstract void fromNBT(NBTTagCompound tag); public abstract NBTTagCompound toNBT(); public void fromNBTSync(NBTTagCompound tag) { fromNBT(tag); } public NBTTagCompound toNBTSync() { return toNBT(); } protected void checkSide(boolean isRemote) { if(isRemote ^ isRemote()) { throw new IllegalStateException("Wrong side: " + isRemote()); } } public static class Serializer implements InstanceSerializer<DataPart> { InstanceSerializer entitySer = SerializationManager.INSTANCE.getInstanceSerializer(Entity.class); @Override public DataPart readInstance(NBTBase nbt) throws Exception { NBTTagCompound tag = (NBTTagCompound) nbt; NBTBase entityTag = tag.getTag("e"); if(entityTag != null) { Entity e = (Entity) entitySer.readInstance(entityTag); if(e instanceof EntityPlayer) { return PlayerData.get((EntityPlayer) e).getPart(tag.getString("n")); } } return null; } @Override public NBTBase writeInstance(DataPart obj) throws Exception { NBTTagCompound ret = new NBTTagCompound(); NBTBase entityTag = entitySer.writeInstance(obj.getPlayer()); ret.setTag("e", entityTag); ret.setString("n", obj.getName()); return ret; } } }