package zmaster587.advancedRocketry.entity; import io.netty.buffer.ByteBuf; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityList; import net.minecraft.entity.MoverType; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.datasync.DataParameter; import net.minecraft.network.datasync.DataSerializers; import net.minecraft.network.datasync.EntityDataManager; import net.minecraft.server.MinecraftServer; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.world.Teleporter; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraftforge.common.DimensionManager; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import zmaster587.advancedRocketry.AdvancedRocketry; import zmaster587.advancedRocketry.api.Configuration; import zmaster587.advancedRocketry.api.RocketEvent; import zmaster587.advancedRocketry.event.PlanetEventHandler; import zmaster587.advancedRocketry.tile.multiblock.TileSpaceElevator; import zmaster587.advancedRocketry.util.DimensionBlockPosition; import zmaster587.advancedRocketry.util.TransitionEntity; import zmaster587.advancedRocketry.world.util.TeleporterNoPortal; import zmaster587.libVulpes.LibVulpes; import zmaster587.libVulpes.interfaces.INetworkEntity; import zmaster587.libVulpes.network.PacketEntity; import zmaster587.libVulpes.network.PacketHandler; import zmaster587.libVulpes.util.HashedBlockPosition; import javax.annotation.Nullable; import java.util.List; public class EntityElevatorCapsule extends Entity implements INetworkEntity { public static final double MAX_HEIGHT = Configuration.orbit; public static final double MAX_STANDTIME = 200; byte motion; int standTime, idleTime; DimensionBlockPosition dstTilePos, srcTilePos; private static final byte PACKET_WRITE_DST_INFO = 0; private static final byte PACKET_RECIEVE_NBT = 1; private static final byte PACKET_LAUNCH_EVENT = 2; private static final byte PACKET_DEORBIT = 3; private static final byte PACKET_WRITE_SRC_INFO = 4; protected static final DataParameter<Byte> motionDir = EntityDataManager.<Byte>createKey(EntityElevatorCapsule.class, DataSerializers.BYTE); protected static final DataParameter<Integer> standTimeCounter = EntityDataManager.<Integer>createKey(EntityElevatorCapsule.class, DataSerializers.VARINT); public EntityElevatorCapsule(World worldIn) { super(worldIn); setSize(3, 3); motion = 0; ignoreFrustumCheck = true; } public boolean isAscending() { return dataManager.get(motionDir) > 0; } public boolean isDescending() { return dataManager.get(motionDir) < 0; } public boolean isInMotion() { return dataManager.get(motionDir) != 0; } public void setCapsuleMotion(int motion) { this.dataManager.set(motionDir, (byte)motion); this.motion = (byte)motion; } public int getStandTime() { return (standTime = this.dataManager.get(standTimeCounter)); } public void setStandTime(int time) { this.dataManager.set(standTimeCounter, standTime); } public int decrStandTime() { this.dataManager.set(standTimeCounter, (standTime = getStandTime()-1)); return standTime; } @Override protected void entityInit() { this.dataManager.register(motionDir, motion); this.dataManager.register(standTimeCounter, standTime); } @Override protected void readEntityFromNBT(NBTTagCompound nbt) { setCapsuleMotion(nbt.getByte("motionDir")); if(nbt.hasKey("dstDimid")) { dstTilePos = new DimensionBlockPosition(-1, null); dstTilePos.dimid = nbt.getInteger("dstDimid"); int[] loc = nbt.getIntArray("dstLoc"); dstTilePos.pos = new HashedBlockPosition(loc[0], loc[1], loc[2]); } else dstTilePos = null; if(nbt.hasKey("srcDimid")) { srcTilePos = new DimensionBlockPosition(-1, null); srcTilePos.dimid = nbt.getInteger("srcDimid"); int[] loc = nbt.getIntArray("srcLoc"); srcTilePos.pos = new HashedBlockPosition(loc[0], loc[1], loc[2]); } else srcTilePos = null; } @Override public void setEntityId(int id){ super.setEntityId(id); //Ask server for nbt data if(world.isRemote) { PacketHandler.sendToServer(new PacketEntity(this, PACKET_RECIEVE_NBT)); } } @Override protected void writeEntityToNBT(NBTTagCompound nbt) { nbt.setByte("motionDir", motion); if(dstTilePos != null) { nbt.setInteger("dstDimid", dstTilePos.dimid); nbt.setIntArray("dstLoc", new int[] { dstTilePos.pos.x, dstTilePos.pos.y, dstTilePos.pos.z }); } if(srcTilePos != null) { nbt.setInteger("srcDimid", srcTilePos.dimid); nbt.setIntArray("srcLoc", new int[] { srcTilePos.pos.x, srcTilePos.pos.y, srcTilePos.pos.z }); } } public boolean shouldRiderSit() { return false; } public void setDst(DimensionBlockPosition location) { this.dstTilePos = location; if(!world.isRemote) PacketHandler.sendToPlayersTrackingEntity(new PacketEntity(this, PACKET_WRITE_DST_INFO), this); } public void setSourceTile(DimensionBlockPosition location) { this.srcTilePos = location; if(!world.isRemote) PacketHandler.sendToPlayersTrackingEntity(new PacketEntity(this, PACKET_WRITE_SRC_INFO), this); } @Override public Entity changeDimension(int newDimId) { return changeDimension(newDimId, this.posX, (double)Configuration.orbit, this.posZ); } public void copyDataFromOld(Entity entityIn) { NBTTagCompound nbttagcompound = entityIn.writeToNBT(new NBTTagCompound()); nbttagcompound.removeTag("Dimension"); nbttagcompound.removeTag("Passengers"); this.readFromNBT(nbttagcompound); this.timeUntilPortal = entityIn.timeUntilPortal; } @Nullable public Entity changeDimension(int dimensionIn, double posX, double y, double posZ) { if (!this.world.isRemote && !this.isDead) { List<Entity> passengers = getPassengers(); if (!net.minecraftforge.common.ForgeHooks.onTravelToDimension(this, dimensionIn)) return null; this.world.profiler.startSection("changeDimension"); MinecraftServer minecraftserver = this.getServer(); int i = this.dimension; WorldServer worldserver = minecraftserver.getWorld(i); WorldServer worldserver1 = minecraftserver.getWorld(dimensionIn); this.dimension = dimensionIn; if (i == 1 && dimensionIn == 1) { worldserver1 = minecraftserver.getWorld(0); this.dimension = 0; } this.world.removeEntity(this); this.isDead = false; this.world.profiler.startSection("reposition"); BlockPos blockpos; double d0 = this.posX; double d1 = this.posZ; double d2 = 8.0D; d0 = MathHelper.clamp(d0 * 8.0D, worldserver1.getWorldBorder().minX() + 16.0D, worldserver1.getWorldBorder().maxX() - 16.0D); d1 = MathHelper.clamp(d1 * 8.0D, worldserver1.getWorldBorder().minZ() + 16.0D, worldserver1.getWorldBorder().maxZ() - 16.0D); d0 = (double)MathHelper.clamp((int)d0, -29999872, 29999872); d1 = (double)MathHelper.clamp((int)d1, -29999872, 29999872); float f = this.rotationYaw; this.setLocationAndAngles(d0, this.posY, d1, 90.0F, 0.0F); Teleporter teleporter = new TeleporterNoPortal(worldserver1); teleporter.placeInExistingPortal(this, f); worldserver.updateEntityWithOptionalForce(this, false); this.world.profiler.endStartSection("reloading"); Entity entity = EntityList.newEntity(this.getClass(), worldserver1); if (entity != null) { this.moveToBlockPosAndAngles(new BlockPos(posX, y, posZ), entity.rotationYaw, entity.rotationPitch); ((EntityElevatorCapsule)entity).copyDataFromOld(this); entity.forceSpawn = true; worldserver1.spawnEntity(entity); worldserver1.updateEntityWithOptionalForce(entity, true); int timeOffset = 1; for(Entity e : passengers) { //Fix that darn random crash? worldserver.resetUpdateEntityTick(); worldserver1.resetUpdateEntityTick(); //Transfer the player if applicable //Need to handle our own removal to avoid race condition where player is mounted on client on the old entity but is already mounted to the new one on server //PacketHandler.sendToPlayer(new PacketEntity(this, (byte)PacketType.DISMOUNTCLIENT.ordinal()), (EntityPlayer) e); PlanetEventHandler.addDelayedTransition(worldserver.getTotalWorldTime(), new TransitionEntity(worldserver.getTotalWorldTime(), e, dimensionIn, new BlockPos(posX + 16, y, posZ), entity)); //minecraftserver.getPlayerList().transferPlayerToDimension((EntityPlayerMP)e, dimensionIn, teleporter); //e.setLocationAndAngles(posX, Configuration.orbit, posZ, this.rotationYaw, this.rotationPitch); //e.startRiding(entity); //e.playerNetServerHandler.sendPacket(new SPacketRespawn(e.dimension, e.world.getDifficulty(), worldserver1.getWorldInfo().getTerrainType(), ((EntityPlayerMP)e).interactionManager.getGameType())); //((WorldServer)startWorld).getPlayerManager().removePlayer(player); } } this.isDead = true; this.world.profiler.endSection(); worldserver.resetUpdateEntityTick(); worldserver1.resetUpdateEntityTick(); this.world.profiler.endSection(); return entity; } else { return null; } } @Override public AxisAlignedBB getRenderBoundingBox() { return getEntityBoundingBox().grow(posX, 2000, posZ); } @Override public void onEntityUpdate() { // TODO Auto-generated method stub super.onEntityUpdate(); //Make sure to update client if(!world.isRemote && this.ticksExisted == 5) { if(dstTilePos != null) setDst(dstTilePos); if(srcTilePos != null) setSourceTile(srcTilePos); } if(isAscending()) { if(this.posY > 255) this.motionY = 2.85; else this.motionY = 0.85; if(!world.isRemote) { List<EntityPlayer> list = world.getEntitiesWithinAABB(EntityPlayer.class, getEntityBoundingBox()); for(Entity ent : list) { if(this.getRidingEntity() == null) ent.startRiding(this); } if(this.posY > MAX_HEIGHT) { setCapsuleMotion(-1); double landingLocX, landingLocZ; World world; if((world = DimensionManager.getWorld(dstTilePos.dimid)) == null) { DimensionManager.initDimension(dstTilePos.dimid); world = DimensionManager.getWorld(dstTilePos.dimid); } if(world != null) { TileEntity tile = world.getTileEntity(dstTilePos.pos.getBlockPos()); if(tile instanceof TileSpaceElevator) { landingLocX = ((TileSpaceElevator)tile).getLandingLocationX(); landingLocZ = ((TileSpaceElevator)tile).getLandingLocationZ(); } else { setDead(); return; } } else { dstTilePos = srcTilePos; world = this.getEntityWorld(); TileEntity tile = world.getTileEntity(dstTilePos.pos.getBlockPos()); if(tile instanceof TileSpaceElevator) { landingLocX = ((TileSpaceElevator)tile).getLandingLocationX(); landingLocZ = ((TileSpaceElevator)tile).getLandingLocationZ(); } else { setDead(); return; } } changeDimension(dstTilePos.dimid, landingLocX, Configuration.orbit, landingLocZ); MinecraftForge.EVENT_BUS.post(new RocketEvent.RocketDeOrbitingEvent(this)); } } this.move(MoverType.SELF,0, this.motionY, 0); } else if(isDescending()) { this.onGround = false; if(this.posY > 255) this.motionY = -2.85; else this.motionY = -0.85; if(!world.isRemote) { //Send packet to player for deorbit a bit delayed if(this.ticksExisted == 20) PacketHandler.sendToPlayersTrackingEntity(new PacketEntity(this, PACKET_DEORBIT), this); List<EntityPlayer> list = world.getEntitiesWithinAABB(EntityPlayer.class, getEntityBoundingBox()); for(Entity ent : list) { if(this.getRidingEntity() == null) ent.startRiding(this); } if(this.posY <= dstTilePos.pos.y) { setCapsuleMotion(0); setPosition(dstTilePos.pos.x, dstTilePos.pos.y, dstTilePos.pos.z); TileEntity e; if((e = world.getTileEntity(dstTilePos.pos.getBlockPos())) instanceof TileSpaceElevator) { ((TileSpaceElevator)e).notifyLanded(this); standTime = 0; } else this.setDead(); //Dismount rider after being put in final place for(Entity ent : this.getPassengers()) { ent.dismountRidingEntity(); } } else this.move(MoverType.SELF,0, this.motionY, 0); } else this.move(MoverType.SELF,0, this.motionY, 0); } else { List<EntityPlayer> list = world.getEntitiesWithinAABB(EntityPlayer.class, getEntityBoundingBox()); if(!world.isRemote) { TileEntity srcTile = null; if(list.isEmpty()) standTime = 0; else if(dstTilePos != null && dstTilePos.dimid != world.provider.getDimension() && TileSpaceElevator.isDstValid(getEntityWorld(), dstTilePos, new HashedBlockPosition(getPosition()))) standTime++; if(srcTilePos != null && srcTilePos.pos != null) srcTile = world.getTileEntity(srcTilePos.pos.getBlockPos()); if( srcTile != null && srcTile instanceof TileSpaceElevator && !((TileSpaceElevator)srcTile).getMachineEnabled()) standTime = 0; setStandTime(standTime); //Begin ascending if(standTime > MAX_STANDTIME) { if(srcTilePos != null && srcTilePos.pos != null) { srcTile = world.getTileEntity(srcTilePos.pos.getBlockPos()); if(srcTile instanceof TileSpaceElevator && ((TileSpaceElevator)srcTile).attemptLaunch()) { setCapsuleMotion(1); //Make sure we mount player before takeoff List<EntityPlayer> list2 = world.getEntitiesWithinAABB(EntityPlayer.class, getEntityBoundingBox()); for(Entity ent : list2) { if(this.getRidingEntity() == null) ent.startRiding(this); } MinecraftForge.EVENT_BUS.post(new RocketEvent.RocketLaunchEvent(this)); PacketHandler.sendToPlayersTrackingEntity(new PacketEntity(this, PACKET_LAUNCH_EVENT), this); } } } } else if(!list.isEmpty()) { TileEntity srcTile = null; if(srcTilePos != null && srcTilePos.pos != null) srcTile = world.getTileEntity(srcTilePos.pos.getBlockPos()); if( srcTile != null && srcTile instanceof TileSpaceElevator && !((TileSpaceElevator)srcTile).getMachineEnabled()) AdvancedRocketry.proxy.displayMessage(LibVulpes.proxy.getLocalizedString("msg.spaceElevator.turnedOff"),5); else if(dstTilePos != null) AdvancedRocketry.proxy.displayMessage(LibVulpes.proxy.getLocalizedString("msg.spaceElevator.ascentReady") + ": " + (int)((MAX_STANDTIME - getStandTime())/20) + "\nDST " + dstTilePos,5); else AdvancedRocketry.proxy.displayMessage(LibVulpes.proxy.getLocalizedString("msg.label.noneSelected"), 5); } } //setDead(); } @Override public double getMountedYOffset() { return 0.3; } @Override public AxisAlignedBB getEntityBoundingBox() { return super.getEntityBoundingBox();//new AxisAlignedBB(-10,-20,-10, 10,10,10); } @Override public AxisAlignedBB getCollisionBoundingBox() { AxisAlignedBB aabb = new AxisAlignedBB(getEntityBoundingBox().minX, getEntityBoundingBox().minY, getEntityBoundingBox().minZ, getEntityBoundingBox().maxX, getEntityBoundingBox().maxY-3, getEntityBoundingBox().maxZ); return isAscending() || isDescending() ? null : aabb; } @SideOnly(Side.CLIENT) public boolean isInRangeToRenderDist(double par1) { //double d1 = this.boundingBox.getAverageEdgeLength(); //d1 *= 4096.0D * this.renderDistanceWeight; return par1 < 16777216D; } @Override public void writeDataToNetwork(ByteBuf out, byte id) { if(id == PACKET_WRITE_DST_INFO) { out.writeBoolean(dstTilePos != null); if(dstTilePos != null) { out.writeInt(dstTilePos.dimid); out.writeInt(dstTilePos.pos.x); out.writeInt(dstTilePos.pos.y); out.writeInt(dstTilePos.pos.z); } } else if(id == PACKET_WRITE_SRC_INFO) { out.writeBoolean(dstTilePos != null); if(srcTilePos != null) { out.writeInt(srcTilePos.dimid); out.writeInt(srcTilePos.pos.x); out.writeInt(srcTilePos.pos.y); out.writeInt(srcTilePos.pos.z); } } } @Override public void readDataFromNetwork(ByteBuf in, byte packetId, NBTTagCompound nbt) { if(packetId == PACKET_WRITE_DST_INFO || packetId == PACKET_WRITE_SRC_INFO) { if(in.readBoolean()) { nbt.setInteger("dimid", in.readInt()); nbt.setInteger("x", in.readInt()); nbt.setInteger("y", in.readInt()); nbt.setInteger("z", in.readInt()); } } } @Override public void useNetworkData(EntityPlayer player, Side side, byte id, NBTTagCompound nbt) { if(id == PACKET_WRITE_DST_INFO && world.isRemote) { if(nbt.hasKey("dimid")) { dstTilePos = new DimensionBlockPosition(nbt.getInteger("dimid"), new HashedBlockPosition(nbt.getInteger("x"), nbt.getInteger("y"), nbt.getInteger("z"))); } else dstTilePos = null; } else if(id == PACKET_WRITE_SRC_INFO && world.isRemote) { if(nbt.hasKey("dimid")) { srcTilePos = new DimensionBlockPosition(nbt.getInteger("dimid"), new HashedBlockPosition(nbt.getInteger("x"), nbt.getInteger("y"), nbt.getInteger("z"))); } else srcTilePos = null; } else if(id == PACKET_RECIEVE_NBT) { PacketHandler.sendToPlayersTrackingEntity(new PacketEntity(this, PACKET_WRITE_DST_INFO), this); } else if(id == PACKET_LAUNCH_EVENT && world.isRemote) { List<EntityPlayer> list = world.getEntitiesWithinAABB(EntityPlayer.class, getEntityBoundingBox()); for(Entity ent : list) { if(this.getRidingEntity() == null) ent.startRiding(this); } MinecraftForge.EVENT_BUS.post(new RocketEvent.RocketLaunchEvent(this)); } else if(id == PACKET_DEORBIT && world.isRemote) { MinecraftForge.EVENT_BUS.post(new RocketEvent.RocketDeOrbitingEvent(this)); } } }