package openblocks.common.tileentity;
import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import com.mojang.authlib.GameProfile;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.util.Constants;
import openblocks.Config;
import openblocks.common.MagnetWhitelists;
import openblocks.common.entity.EntityMiniMe;
import openmods.Log;
import openmods.api.IBreakAwareTile;
import openmods.api.IPlacerAwareTile;
import openmods.entity.EntityBlock;
import openmods.fakeplayer.FakePlayerPool;
import openmods.fakeplayer.FakePlayerPool.PlayerUser;
import openmods.fakeplayer.OpenModsFakePlayer;
import openmods.sync.SyncableEnum;
import openmods.tileentity.SyncedTileEntity;
public class TileEntityGoldenEgg extends SyncedTileEntity implements IPlacerAwareTile, IBreakAwareTile {
private static final float SPEED_CHANGE_RATE = 0.1f;
private static final Random RANDOM = new Random();
private static final int STAGE_CHANGE_TICK = 100;
private static final int RISING_TIME = 400;
private static final int FALLING_TIME = 10;
public static final int MAX_HEIGHT = 5;
private static final double STAGE_CHANGE_CHANCE = 0.8;
private static final GameProfile MR_GLITCH = new GameProfile(UUID.fromString("d4d119aa-d410-488a-8734-0053577d4a1a"), null);
public static enum State {
INERT(0, 0, false) {
@Override
public State getNextState(TileEntityGoldenEgg target) {
return target.tryRandomlyChangeState(STAGE_CHANGE_TICK, ROTATING_SLOW);
}
@Override
public void onServerTick(TileEntityGoldenEgg target, WorldServer world) {
target.tickCounter++;
}
},
ROTATING_SLOW(1, 0, false) {
@Override
public State getNextState(TileEntityGoldenEgg target) {
return target.tryRandomlyChangeState(STAGE_CHANGE_TICK, ROTATING_MEDIUM);
}
@Override
public void onServerTick(TileEntityGoldenEgg target, WorldServer world) {
target.tickCounter++;
}
},
ROTATING_MEDIUM(10, 0, false) {
@Override
public State getNextState(TileEntityGoldenEgg target) {
return target.tryRandomlyChangeState(STAGE_CHANGE_TICK, ROTATING_FAST);
}
@Override
public void onServerTick(TileEntityGoldenEgg target, WorldServer world) {
target.tickCounter++;
}
},
ROTATING_FAST(50, 0, false) {
@Override
public State getNextState(TileEntityGoldenEgg target) {
return target.tryRandomlyChangeState(STAGE_CHANGE_TICK, FLOATING);
}
@Override
public void onServerTick(TileEntityGoldenEgg target, WorldServer world) {
target.tickCounter++;
}
},
FLOATING(100, 1.0f / RISING_TIME, true) {
@Override
public void onEntry(TileEntityGoldenEgg target) {
target.tickCounter = RISING_TIME;
}
@Override
public void onServerTick(TileEntityGoldenEgg target, WorldServer world) {
target.tickCounter--;
if (Config.eggCanPickBlocks && RANDOM.nextInt(6) == 0) {
int posX = target.xCoord + RANDOM.nextInt(20) - 10;
int posY = target.yCoord + RANDOM.nextInt(2) - 1;
int posZ = target.zCoord + RANDOM.nextInt(20) - 10;
boolean canMove = MagnetWhitelists.instance.testBlock(target.worldObj, posX, posY, posZ);
if (canMove) target.pickUpBlock(world, posX, posY, posZ);
}
}
@Override
public State getNextState(TileEntityGoldenEgg target) {
return (target.tickCounter <= 0)? FALLING : null;
}
},
FALLING(150, -1.0f / FALLING_TIME, true) {
@Override
public void onEntry(TileEntityGoldenEgg target) {
target.tickCounter = FALLING_TIME;
target.dropBlocks();
}
@Override
public void onServerTick(TileEntityGoldenEgg target, WorldServer world) {
target.tickCounter--;
}
@Override
public State getNextState(TileEntityGoldenEgg target) {
return (target.tickCounter <= 0)? EXPLODING : null;
}
},
EXPLODING(666, 0, true) {
@Override
public void onEntry(TileEntityGoldenEgg target) {
target.explode();
}
@Override
public State getNextState(TileEntityGoldenEgg target) {
return null;
}
};
public final float rotationSpeed;
public final float progressSpeed;
public final boolean specialEffects;
public void onEntry(TileEntityGoldenEgg target) {}
public void onServerTick(TileEntityGoldenEgg target, WorldServer world) {}
public abstract State getNextState(TileEntityGoldenEgg target);
private State(float rotationSpeed, float riseSpeed, boolean specialEffects) {
this.rotationSpeed = rotationSpeed;
this.progressSpeed = riseSpeed;
this.specialEffects = specialEffects;
}
}
public int tickCounter;
private float rotation;
private float progress;
private float rotationSpeed;
private float progressSpeed;
private List<EntityBlock> blocks = Lists.newArrayList();
private SyncableEnum<State> stage;
private GameProfile owner;
public float getRotation(float partialTickTime) {
return rotation + rotationSpeed * partialTickTime;
}
public float getProgress(float partialTickTime) {
return progress + progressSpeed * partialTickTime;
}
public float getOffset(float partialTickTime) {
return getProgress(partialTickTime) * MAX_HEIGHT;
}
public State tryRandomlyChangeState(int delay, State nextState) {
return (tickCounter % delay == 0) && (RANDOM.nextDouble() < STAGE_CHANGE_CHANCE)? nextState : null;
}
@Override
protected void createSyncedFields() {
stage = SyncableEnum.create(State.INERT);
}
private void pickUpBlock(final WorldServer world, final int x, final int y, final int z) {
FakePlayerPool.instance.executeOnPlayer(world, new PlayerUser() {
@Override
public void usePlayer(OpenModsFakePlayer fakePlayer) {
EntityBlock block = EntityBlock.create(fakePlayer, worldObj, x, y, z);
if (block != null) {
block.setHasAirResistance(false);
block.setHasGravity(false);
block.motionY = 0.1;
blocks.add(block);
world.spawnEntityInWorld(block);
}
}
});
}
private void dropBlocks() {
for (EntityBlock block : blocks) {
block.motionY = -0.9;
block.setHasGravity(true);
}
blocks.clear();
}
private void explode() {
worldObj.setBlockToAir(xCoord, yCoord, zCoord);
worldObj.createExplosion(null, 0.5 + xCoord, 0.5 + yCoord, 0.5 + zCoord, 2, true);
EntityMiniMe miniMe = new EntityMiniMe(worldObj, Objects.firstNonNull(owner, MR_GLITCH));
miniMe.setPositionAndRotation(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5, 0, 0);
worldObj.spawnEntityInWorld(miniMe);
}
public State getState() {
return stage.get();
}
@Override
public void updateEntity() {
super.updateEntity();
State state = getState();
if (worldObj.isRemote) {
rotationSpeed = (1 - SPEED_CHANGE_RATE) * rotationSpeed + SPEED_CHANGE_RATE * state.rotationSpeed;
rotation += rotationSpeed;
progressSpeed = (1 - SPEED_CHANGE_RATE) * progressSpeed + SPEED_CHANGE_RATE * state.progressSpeed;
progress += progressSpeed;
} else {
if (worldObj instanceof WorldServer) state.onServerTick(this, (WorldServer)worldObj);
State nextState = state.getNextState(this);
if (nextState != null) {
stage.set(nextState);
nextState.onEntry(this);
sync();
}
}
}
@Override
public void writeToNBT(NBTTagCompound nbt) {
super.writeToNBT(nbt);
if (owner != null) {
NBTTagCompound ownerTag = new NBTTagCompound();
NBTUtil.func_152460_a(ownerTag, owner);
nbt.setTag("Owner", ownerTag);
}
}
@Override
public void readFromNBT(NBTTagCompound nbt) {
super.readFromNBT(nbt);
if (nbt.hasKey("owner", Constants.NBT.TAG_STRING)) {
String ownerName = nbt.getString("owner");
this.owner = MinecraftServer.getServer().func_152358_ax().func_152655_a(ownerName);
} else if (nbt.hasKey("OwnerUUID", Constants.NBT.TAG_STRING)) {
final String uuidStr = nbt.getString("OwnerUUID");
try {
UUID uuid = UUID.fromString(uuidStr);
this.owner = new GameProfile(uuid, null);
} catch (IllegalArgumentException e) {
Log.warn(e, "Failed to parse UUID: %s", uuidStr);
}
} else if (nbt.hasKey("Owner", Constants.NBT.TAG_COMPOUND)) {
this.owner = NBTUtil.func_152459_a(nbt.getCompoundTag("Owner"));
}
}
@Override
public void onBlockBroken() {
dropBlocks();
}
@Override
public void onBlockPlacedBy(EntityLivingBase placer, ItemStack stack) {
if (!worldObj.isRemote && placer instanceof EntityPlayer) {
this.owner = ((EntityPlayer)placer).getGameProfile();
}
}
@Override
@SideOnly(Side.CLIENT)
public AxisAlignedBB getRenderBoundingBox() {
return AxisAlignedBB.getBoundingBox(xCoord, -1024, zCoord, xCoord + 1, 1024, zCoord + 1);
}
}