package me.ichun.mods.sync.common.tileentity; import cofh.api.energy.IEnergyHandler; import com.mojang.authlib.GameProfile; import me.ichun.mods.sync.common.block.BlockDualVertical; import me.ichun.mods.sync.common.packet.PacketNBT; import me.ichun.mods.sync.common.packet.PacketZoomCamera; import me.ichun.mods.sync.common.shell.ShellHandler; import me.ichun.mods.sync.common.shell.TeleporterShell; import net.minecraft.network.play.server.SPacketUpdateTileEntity; import net.minecraft.util.ITickable; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.common.Optional; import net.minecraftforge.fml.common.network.ByteBufUtils; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import io.netty.buffer.ByteBuf; import net.minecraft.block.Block; import net.minecraft.client.entity.AbstractClientPlayer; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.network.NetworkManager; import net.minecraft.network.Packet; import net.minecraft.network.play.server.S35PacketUpdateTileEntity; import net.minecraft.server.management.ItemInWorldManager; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.ResourceLocation; import net.minecraft.world.WorldServer; import net.minecraft.world.WorldSettings; import me.ichun.mods.sync.common.Sync; import me.ichun.mods.sync.common.block.BlockDualVertical; import me.ichun.mods.sync.common.packet.PacketNBT; import me.ichun.mods.sync.common.packet.PacketZoomCamera; import me.ichun.mods.sync.common.shell.ShellHandler; import me.ichun.mods.sync.common.shell.TeleporterShell; @Optional.Interface(iface = "cofh.api.energy.IEnergyHandler", modid = "CoFHCore") public abstract class TileEntityDualVertical extends TileEntity implements IEnergyHandler, ITickable { public TileEntityDualVertical pair; public boolean top; public int face; //TODO use forgedirection or vanilla in 1.7? public boolean vacating; public boolean isHomeUnit; protected String playerName; protected String name; public TileEntityDualVertical resyncOrigin; protected NBTTagCompound playerNBT; public ResourceLocation locationSkin; public boolean resync; public int resyncPlayer; public int canSavePlayer; public final static int animationTime = 40; protected int powReceived; protected int rfIntake; public TileEntityDualVertical() { pair = null; top = false; vacating = false; isHomeUnit = false; face = 0; playerName = ""; name = ""; resyncPlayer = 0; canSavePlayer = 0; resyncOrigin = null; playerNBT = new NBTTagCompound(); resync = false; powReceived = 0; rfIntake = 0; } @Override public void update() { if (this.resync) { TileEntity tileEntity = worldObj.getTileEntity(this.pos.add(0, (this.top ? -1 : 1), 0)); if (tileEntity != null && tileEntity.getClass() == this.getClass()) { TileEntityDualVertical dualVertical = (TileEntityDualVertical)tileEntity; dualVertical.pair = this; this.pair = dualVertical; } //Reload Player Skin if (this.worldObj.isRemote) { this.locationSkin = AbstractClientPlayer.getLocationSkin(this.getPlayerName()); AbstractClientPlayer.getDownloadImageSkin(this.locationSkin, this.getPlayerName()); } } if (this.top && this.pair != null) { this.setPlayerName(this.pair.getPlayerName()); this.setName(this.pair.getName()); this.vacating = this.pair.vacating; } if (!this.top && !this.worldObj.isRemote) { //If this is true, we're syncing a player to this location if (this.resyncPlayer > -10) { this.resyncPlayer--; //Start of syncing player to this place if (this.resyncPlayer == 60) { if (this.getClass() == TileEntityShellStorage.class) { TileEntityShellStorage shellStorage = (TileEntityShellStorage)this; shellStorage.occupied = true; } EntityPlayerMP player = FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().getPlayerByUsername(this.getPlayerName()); if (player != null) { if (!player.isEntityAlive()) { player.setHealth(20); player.isDead = false; } player.extinguish(); //Remove fire int dim = player.dimension; //If player is in different dimension, bring them here if (player.dimension != worldObj.provider.getDimension()) { FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().transferPlayerToDimension(player, this.worldObj.provider.getDimension(), new TeleporterShell((WorldServer) this.worldObj, this.worldObj.provider.getDimension(), this.xCoord, this.yCoord, this.zCoord, (this.face - 2) * 90F, 0F)); //Refetch player TODO is this needed? player = FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().getPlayerByUsername(this.getPlayerName()); if (dim == 1) { if (player.isEntityAlive()) { this.worldObj.spawnEntityInWorld(player); player.setLocationAndAngles(pos.getX() + 0.5D, pos.getY(), pos.getZ() + 0.5D, (this.face - 2) * 90F, 0F); this.worldObj.updateEntityWithOptionalForce(player, false); player.fallDistance = 0F; } } } else { player.setLocationAndAngles(pos.getX() + 0.5D, pos.getY(), pos.getZ() + 0.5D, (this.face - 2) * 90F, 0F); player.fallDistance = 0F; } Sync.channel.sendTo(new PacketZoomCamera(this.xCoord, this.yCoord, this.zCoord, this.worldObj.provider.getDimension(), this.face, true, false), player); } } //Beginning of kicking the player out if (this.resyncPlayer == 40) { this.vacating = true; if (this.getClass() == TileEntityShellStorage.class) { TileEntityShellStorage shellStorage = (TileEntityShellStorage) this; shellStorage.occupied = true; shellStorage.occupationTime = animationTime; } else if (this.getClass() == TileEntityShellConstructor.class) { TileEntityShellConstructor shellConstructor = (TileEntityShellConstructor) this; shellConstructor.doorOpen = true; } this.worldObj.markBlockForUpdate(this.xCoord, this.yCoord, this.zCoord); this.worldObj.markBlockForUpdate(this.xCoord, this.yCoord + 1, this.zCoord); } //This is where we begin to sync the data aka point of no return if (this.resyncPlayer == 30) { EntityPlayerMP player = FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().getPlayerByUsername(playerName); if (player != null && player.isEntityAlive()) { //Clear active potion effects before syncing player.clearActivePotions(); if (!getPlayerNBT().hasKey("Inventory")) { //Copy data needed from player NBTTagCompound tag = new NBTTagCompound(); boolean keepInv = this.worldObj.getGameRules().getBoolean("keepInventory"); this.worldObj.getGameRules().setOrCreateGameRule("keepInventory", "false"); //Setup location for dummy EntityPlayerMP dummy = new EntityPlayerMP(FMLCommonHandler.instance().getMinecraftServerInstance(), FMLCommonHandler.instance().getMinecraftServerInstance().worldServerForDimension(player.dimension), EntityHelperBase.getSimpleGameProfileFromName(player.getName()), new ItemInWorldManager(FMLCommonHandler.instance().getMinecraftServerInstance().worldServerForDimension(player.dimension))); dummy.connection = player.connection; dummy.setLocationAndAngles(pos.getX() + 0.5D, pos.getY(), pos.getZ() + 0.5D, (this.face - 2) * 90F, 0F); dummy.fallDistance = 0F; //Clone data dummy.clonePlayer(player, false); dummy.dimension = player.dimension; dummy.setEntityId(player.getEntityId()); this.worldObj.getGameRules().setOrCreateGameRule("keepInventory", keepInv ? "true" : "false"); //Set data dummy.writeToNBT(tag); tag.setInteger("sync_playerGameMode", player.theItemInWorldManager.getGameType().getID()); this.setPlayerNBT(tag); } //Sync Forge persistent data as it's supposed to carry over on death NBTTagCompound persistentData = player.getEntityData(); if (persistentData != null) { NBTTagCompound forgeData = playerNBT.getCompoundTag("ForgeData"); forgeData.setTag(EntityPlayer.PERSISTED_NBT_TAG, player.getEntityData().getCompoundTag(EntityPlayer.PERSISTED_NBT_TAG)); persistentData.setBoolean("isDeathSyncing", false); forgeData.setBoolean("isDeathSyncing", false); playerNBT.setTag("ForgeData", forgeData); } NBTTagCompound persistent = player.getEntityData().getCompoundTag(EntityPlayer.PERSISTED_NBT_TAG); int healthReduction = persistent.getInteger("Sync_HealthReduction"); //Also sync ender chest. playerNBT.setTag("EnderItems", player.getInventoryEnderChest().saveInventoryToNBT()); //Update the players NBT stuff player.readFromNBT(this.getPlayerNBT()); if(healthReduction > 0) { double curMaxHealth = player.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).getBaseValue(); double morphMaxHealth = curMaxHealth - healthReduction; if(morphMaxHealth < 1D) { morphMaxHealth = 1D; } if(morphMaxHealth != curMaxHealth) { player.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(morphMaxHealth); } } player.theItemInWorldManager.initializeGameType(WorldSettings.GameType.getByID(this.getPlayerNBT().getInteger("sync_playerGameMode"))); Sync.channel.sendTo(new PacketNBT(this.getPlayerNBT()), player); } } if(this.resyncPlayer == 25) { ShellHandler.syncInProgress.remove(this.getPlayerName()); } if (this.resyncPlayer == 0) { ShellHandler.removeShell(this.getPlayerName(), this); if(this.getClass() == TileEntityShellStorage.class) { TileEntityShellStorage ss = (TileEntityShellStorage)this; ss.occupied = true; } } if(resyncPlayer == -10) { if(this.getClass() == TileEntityShellStorage.class) { TileEntityShellStorage ss = (TileEntityShellStorage)this; ss.occupied = true; } } } if (this.canSavePlayer > 0) { this.canSavePlayer--; } if (this.canSavePlayer < 0) { this.canSavePlayer = 60; } } this.resync = false; } public void setup(TileEntityDualVertical scPair, boolean isTop, int placeYaw) { pair = scPair; top = isTop; face = placeYaw; } public float powerAmount() { float power = 0.0F; for(int i = -1; i <= 1; i++) { for(int k = -1; k <= 1; k++) { if(!(i == 0 && k == 0)) { TileEntity te = worldObj.getTileEntity(pos.add(i, 0, k)); if(te instanceof TileEntityTreadmill && !((TileEntityTreadmill)te).back) { power += ((TileEntityTreadmill)te).powerOutput(); } } } } return power + (worldObj.isRemote ? rfIntake : powReceived); } public float getBuildProgress() { return this.playerName.equals("") ? 0 : Sync.config.shellConstructionPowerRequirement; //Using this for comparator output calculation } @Override public boolean shouldRenderInPass(int pass) { BlockDualVertical.renderPass = pass; return pass == 0 || pass == 1; } @Override public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) { readFromNBT(pkt.getNbtCompound()); } @Override public SPacketUpdateTileEntity getUpdatePacket() { return new SPacketUpdateTileEntity(getPos(), 0, getUpdateTag()); } @Override public NBTTagCompound getUpdateTag() { return this.writeToNBT(new NBTTagCompound()); } @Override public NBTTagCompound writeToNBT(NBTTagCompound tag) { super.writeToNBT(tag); tag.setBoolean("top", top); tag.setInteger("face", face); tag.setBoolean("vacating", vacating); tag.setBoolean("isHomeUnit", isHomeUnit); tag.setString("playerName", canSavePlayer > 0 ? "" : playerName); tag.setString("name", name); tag.setTag("playerNBT", canSavePlayer > 0 ? new NBTTagCompound() : playerNBT); tag.setInteger("rfIntake", rfIntake); return tag; } @Override public void readFromNBT(NBTTagCompound tag) { super.readFromNBT(tag); top = tag.getBoolean("top"); face = tag.getInteger("face"); vacating = tag.getBoolean("vacating"); isHomeUnit = tag.getBoolean("isHomeUnit"); playerName = tag.getString("playerName"); name = tag.getString("name"); playerNBT = tag.getCompoundTag("playerNBT"); rfIntake = tag.getInteger("rfIntake"); resync = true; } public void writeShellStateData(ByteBuf buffer) { if(top && pair != null) { pair.writeShellStateData(buffer); return; } buffer.writeInt(xCoord); buffer.writeInt(yCoord); buffer.writeInt(zCoord); buffer.writeInt(worldObj.provider.getDimension()); buffer.writeFloat(getBuildProgress()); buffer.writeFloat(powerAmount()); ByteBufUtils.writeUTF8String(buffer, name); ByteBufUtils.writeUTF8String(buffer, worldObj.provider.getDimensionName()); buffer.writeBoolean(this.getClass() == TileEntityShellConstructor.class); buffer.writeBoolean(isHomeUnit); NBTTagCompound invTag = new NBTTagCompound(); invTag.setTag("Inventory", generateShowableEquipTags(playerNBT)); ByteBufUtils.writeTag(buffer, invTag); } public static NBTTagList generateShowableEquipTags(NBTTagCompound tag) { NBTTagList list = new NBTTagList(); NBTTagList nbttaglist = tag.getTagList("Inventory", 10); int currentItem = tag.getInteger("SelectedItemSlot"); ItemStack[] items = new ItemStack[5]; for (int i = 0; i < nbttaglist.tagCount(); ++i) { NBTTagCompound nbttagcompound = nbttaglist.getCompoundTagAt(i); int j = nbttagcompound.getByte("Slot") & 255; ItemStack itemstack = ItemStack.loadItemStackFromNBT(nbttagcompound); if (itemstack != null) { if (j == currentItem) { items[0] = itemstack; } if (j >= 100 && j < 104) { items[j - 100 + 1] = itemstack; } } } int i; NBTTagCompound nbttagcompound; for (i = 0; i < items.length; ++i) { if (items[i] != null) { nbttagcompound = new NBTTagCompound(); nbttagcompound.setByte("Slot", (byte)i); items[i].writeToNBT(nbttagcompound); list.appendTag(nbttagcompound); } } return list; } public static void addShowableEquipToPlayer(EntityPlayer player, NBTTagCompound tag) { NBTTagList nbttaglist = tag.getTagList("Inventory", 10); for (int i = 0; i < nbttaglist.tagCount(); ++i) { NBTTagCompound nbttagcompound = nbttaglist.getCompoundTagAt(i); int j = nbttagcompound.getByte("Slot") & 255; ItemStack itemstack = ItemStack.loadItemStackFromNBT(nbttagcompound); if (itemstack != null) { player.setCurrentItemOrArmor(j, itemstack); } } } @Override @SideOnly(Side.CLIENT) public AxisAlignedBB getRenderBoundingBox() { return AxisAlignedBB.getBoundingBox(xCoord, yCoord, zCoord, xCoord + 1, yCoord + 2, zCoord + 1); } @Override public Block getBlockType() { return Sync.blockDualVertical; } public void reset() { this.setPlayerName(""); this.setPlayerNBT(new NBTTagCompound()); this.resyncOrigin = null; } //Setters and getters public void setPlayerName(String playerName) { if (playerName == null) playerName = ""; this.playerName = playerName; } public void setPlayerNBT(NBTTagCompound tagCompound) { if (tagCompound == null) tagCompound = new NBTTagCompound(); this.playerNBT = tagCompound; } public void setName(String name) { if (name == null) name = ""; this.name = name; } public String getPlayerName() { if (this.playerName == null) this.setPlayerName(""); return this.playerName; } public NBTTagCompound getPlayerNBT() { if (this.playerNBT == null) this.setPlayerNBT(new NBTTagCompound()); return this.playerNBT; } public String getName() { if (this.name == null) name = ""; return this.name; } }