package choonster.testmod3.network;
import choonster.testmod3.Logger;
import choonster.testmod3.TestMod3;
import choonster.testmod3.client.gui.GuiSurvivalCommandBlock;
import choonster.testmod3.init.ModBlocks;
import choonster.testmod3.tileentity.SurvivalCommandBlockLogic;
import choonster.testmod3.tileentity.TileEntitySurvivalCommandBlock;
import io.netty.buffer.ByteBuf;
import net.minecraft.block.Block;
import net.minecraft.block.BlockCommandBlock;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.server.MinecraftServer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityCommandBlock;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.StringUtils;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.network.ByteBufUtils;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import javax.annotation.Nullable;
/**
* Sent by {@link GuiSurvivalCommandBlock} to save changes made to a Survival Command Block.
* <p>
* Imitates the vanilla Command Block's packet, but doesn't check if the player is in Creative Mode.
* <p>
* Test for this thread:
* http://www.minecraftforum.net/forums/mapping-and-modding/minecraft-mods/modification-development/2540671-command-block-replica-issue
*
* @author Choonster
*/
public class MessageSurvivalCommandBlockSaveChanges implements IMessage {
private SurvivalCommandBlockLogic.Type type;
private String command;
private boolean shouldTrackOutput;
private TileEntityCommandBlock.Mode commandBlockMode;
private boolean conditional;
private boolean automatic;
/**
* The {@link SurvivalCommandBlockLogic} instance. Client-only.
*/
private SurvivalCommandBlockLogic survivalCommandBlockLogic;
/**
* The Survival Command Block's {@link BlockPos}. {@code null} if {@link #type} is not {@link SurvivalCommandBlockLogic.Type#BLOCK}. Server-only.
*/
private BlockPos blockPos;
/**
* The Survival Command Block Minecart's entityID. -1 if {@link #type} is not {@link SurvivalCommandBlockLogic.Type#MINECART}. Server-only.
*/
private int minecartEntityID = -1;
@SuppressWarnings("unused")
public MessageSurvivalCommandBlockSaveChanges() {
}
public MessageSurvivalCommandBlockSaveChanges(SurvivalCommandBlockLogic survivalCommandBlockLogic, String command, TileEntityCommandBlock.Mode commandBlockMode, boolean conditional, boolean automatic) {
this.survivalCommandBlockLogic = survivalCommandBlockLogic;
this.type = survivalCommandBlockLogic.getType();
this.command = command;
this.shouldTrackOutput = survivalCommandBlockLogic.shouldTrackOutput();
this.commandBlockMode = commandBlockMode;
this.conditional = conditional;
this.automatic = automatic;
}
@Override
public void fromBytes(ByteBuf buf) {
type = SurvivalCommandBlockLogic.Type.values()[buf.readByte()];
command = ByteBufUtils.readUTF8String(buf);
shouldTrackOutput = buf.readBoolean();
commandBlockMode = TileEntityCommandBlock.Mode.valueOf(ByteBufUtils.readUTF8String(buf));
conditional = buf.readBoolean();
automatic = buf.readBoolean();
switch (type) {
case BLOCK:
blockPos = new BlockPos(buf.readInt(), buf.readInt(), buf.readInt());
break;
case MINECART:
minecartEntityID = buf.readInt();
break;
}
}
@Override
public void toBytes(ByteBuf buf) {
buf.writeByte(type.ordinal());
ByteBufUtils.writeUTF8String(buf, command);
buf.writeBoolean(shouldTrackOutput);
ByteBufUtils.writeUTF8String(buf, commandBlockMode.name());
buf.writeBoolean(conditional);
buf.writeBoolean(automatic);
survivalCommandBlockLogic.fillInInfo(buf);
}
public static class Handler implements IMessageHandler<MessageSurvivalCommandBlockSaveChanges, IMessage> {
@Nullable
@Override
public IMessage onMessage(MessageSurvivalCommandBlockSaveChanges message, MessageContext ctx) {
TestMod3.proxy.getThreadListener(ctx).addScheduledTask(() -> {
final EntityPlayer player = TestMod3.proxy.getPlayer(ctx);
final World world = player.world;
final MinecraftServer minecraftServer = world.getMinecraftServer();
if (minecraftServer != null && !minecraftServer.isCommandBlockEnabled()) {
player.sendMessage(new TextComponentTranslation("advMode.notEnabled"));
} else if (!player.canUseCommand(2, "")) {
player.sendMessage(new TextComponentTranslation("advMode.notAllowed"));
} else {
try {
SurvivalCommandBlockLogic survivalCommandBlockLogic = null;
if (message.type == SurvivalCommandBlockLogic.Type.BLOCK) {
final Block newBlock;
switch (message.commandBlockMode) {
case SEQUENCE:
newBlock = ModBlocks.CHAIN_SURVIVAL_COMMAND_BLOCK;
break;
case AUTO:
newBlock = ModBlocks.REPEATING_SURVIVAL_COMMAND_BLOCK;
break;
case REDSTONE:
default:
newBlock = ModBlocks.SURVIVAL_COMMAND_BLOCK;
break;
}
final TileEntity existingTileEntity = world.getTileEntity(message.blockPos);
final EnumFacing facing = world.getBlockState(message.blockPos).getValue(BlockCommandBlock.FACING);
final IBlockState newState = newBlock.getDefaultState().withProperty(BlockCommandBlock.FACING, facing).withProperty(BlockCommandBlock.CONDITIONAL, message.conditional);
world.setBlockState(message.blockPos, newState);
final TileEntity newTileEntity = world.getTileEntity(message.blockPos);
if (existingTileEntity instanceof TileEntitySurvivalCommandBlock && newTileEntity instanceof TileEntitySurvivalCommandBlock) {
final TileEntitySurvivalCommandBlock newTileEntitySurvivalCommandBlock = (TileEntitySurvivalCommandBlock) newTileEntity;
newTileEntitySurvivalCommandBlock.deserializeNBT(existingTileEntity.serializeNBT());
survivalCommandBlockLogic = newTileEntitySurvivalCommandBlock.getCommandBlockLogic();
newTileEntitySurvivalCommandBlock.setAuto(message.automatic);
}
} else if (message.type == SurvivalCommandBlockLogic.Type.MINECART) {
// no-op
}
if (survivalCommandBlockLogic != null) {
survivalCommandBlockLogic.setCommand(message.command);
survivalCommandBlockLogic.setTrackOutput(message.shouldTrackOutput);
if (!message.shouldTrackOutput) {
survivalCommandBlockLogic.setLastOutput(null);
}
survivalCommandBlockLogic.updateCommand();
if (!StringUtils.isNullOrEmpty(message.command)) {
player.sendMessage(new TextComponentTranslation("advMode.setCommand.success", message.command));
}
}
} catch (Exception e) {
Logger.error(e, "Couldn't set survival command block");
}
}
});
return null;
}
}
}