package gory_moon.moarsigns.tileentites; import com.google.gson.JsonParseException; import gory_moon.moarsigns.api.SignInfo; import gory_moon.moarsigns.api.SignRegistry; import gory_moon.moarsigns.util.Utils; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.command.CommandException; import net.minecraft.command.CommandResultStats; import net.minecraft.command.ICommandSender; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagIntArray; import net.minecraft.nbt.NBTTagList; import net.minecraft.network.NetworkManager; import net.minecraft.network.play.server.SPacketUpdateTileEntity; import net.minecraft.server.MinecraftServer; import net.minecraft.tileentity.TileEntitySign; import net.minecraft.util.ITickable; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.Style; import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextComponentUtils; import net.minecraft.util.text.event.ClickEvent; import net.minecraft.world.World; import javax.annotation.Nullable; public class TileEntityMoarSign extends TileEntitySign implements ITickable { public static final String NBT_VERSION_TAG = "nbtVersion"; public static final String NBT_SETTINGS_TAG = "settings"; public static final String NBT_LOCKED_CHANGES_TAG = "lockedChanges"; public static final String NBT_METAL_TAG = "isMetal"; public static final String NBT_TEXTURE_TAG = "texture"; private final int NBT_VERSION = 2; public int[] rowLocations = new int[4]; public int[] rowSizes = {0, 0, 0, 0}; public boolean[] visibleRows = {true, true, true, true}; public boolean[] shadowRows = new boolean[4]; public boolean lockedChanges; public boolean isMetal = false; public String texture_name; public boolean showInGui = false; public boolean removeNoDrop; private boolean isEditable = true; private EntityPlayer playerEditing; private ResourceLocation resourceLocation; private boolean textureReq = false; private final CommandResultStats stats = new CommandResultStats(); public TileEntityMoarSign() { super(); for (int i = 0; i < 4; i++) { rowLocations[i] = 2 + 10 * i; } } public void setBlockType(Block block) { blockType = block; } @Override public void update() { if (worldObj.isRemote) { if (!textureReq) { textureReq = true; Block block = worldObj.getBlockState(pos).getBlock(); worldObj.addBlockEvent(pos, block, 0, 0); } SignInfo sign = SignRegistry.get(texture_name); if (sign != null && sign.property != null) sign.property.onUpdate(); } } public NBTTagCompound writeToNBT(NBTTagCompound compound) { super.writeToNBT(compound); compound.setInteger(NBT_VERSION_TAG, NBT_VERSION); NBTTagList settings = new NBTTagList(); int[] loc = new int[5]; loc[0] = 0; System.arraycopy(rowLocations, 0, loc, 1, 4); int[] size = new int[5]; size[0] = 1; System.arraycopy(rowSizes, 0, size, 1, 4); int[] visible = new int[5]; visible[0] = 2; for (int i = 0; i < 4; i++) visible[i + 1] = visibleRows[i] ? 1 : 0; int[] shadow = new int[5]; shadow[0] = 3; for (int i = 0; i < 4; i++) shadow[i + 1] = shadowRows[i] ? 1 : 0; NBTTagIntArray locations = new NBTTagIntArray(loc); NBTTagIntArray sizes = new NBTTagIntArray(size); NBTTagIntArray hidden = new NBTTagIntArray(visible); NBTTagIntArray shadows = new NBTTagIntArray(shadow); settings.appendTag(locations); settings.appendTag(sizes); settings.appendTag(hidden); settings.appendTag(shadows); compound.setTag(NBT_SETTINGS_TAG, settings); compound.setBoolean(NBT_LOCKED_CHANGES_TAG, lockedChanges); compound.setBoolean(NBT_METAL_TAG, isMetal); if (texture_name != null) compound.setString(NBT_TEXTURE_TAG, texture_name); stats.writeStatsToNBT(compound); return compound; } public void readFromNBT(NBTTagCompound compound) { super.readFromNBT(compound); ICommandSender icommandsender = new ICommandSender() { /** * Get the name of this object. For players this returns their username */ public String getName() { return "Sign"; } /** * Get the formatted ChatComponent that will be used for the sender's username in chat */ public ITextComponent getDisplayName() { return new TextComponentString(this.getName()); } /** * Send a chat message to the CommandSender */ public void addChatMessage(ITextComponent component) { } /** * Returns {@code true} if the CommandSender is allowed to execute the command, {@code false} if not */ public boolean canCommandSenderUseCommand(int permLevel, String commandName) { return permLevel <= 2; //Forge: Fixes MC-75630 - Exploit with signs and command blocks } /** * Get the position in the world. <b>{@code null} is not allowed!</b> If you are not an entity in the world, * return the coordinates 0, 0, 0 */ public BlockPos getPosition() { return pos; } /** * Get the position vector. <b>{@code null} is not allowed!</b> If you are not an entity in the world, * return 0.0D, 0.0D, 0.0D */ public Vec3d getPositionVector() { return new Vec3d((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D); } /** * Get the world, if available. <b>{@code null} is not allowed!</b> If you are not an entity in the world, * return the overworld */ public World getEntityWorld() { return worldObj; } /** * Returns the entity associated with the command sender. MAY BE NULL! */ public Entity getCommandSenderEntity() { return null; } /** * Returns true if the command sender should be sent feedback about executed commands */ public boolean sendCommandFeedback() { return false; } public void setCommandStat(CommandResultStats.Type type, int amount) { } @Override public MinecraftServer getServer() { return worldObj.getMinecraftServer(); } }; int nbtVersion = compound.getInteger(NBT_VERSION_TAG); if (nbtVersion == 1) { int fontSize = compound.getInteger("fontSize"); int rows = Utils.getRows(fontSize); rowSizes = new int[]{fontSize, fontSize, fontSize, fontSize}; visibleRows = new boolean[]{false, false, false, false}; for (int i = 0; i < rows; i++) { visibleRows[i] = true; } int textOffset = compound.getInteger("textOffset"); for (int i = 0; i < 4; i++) { int temp = Math.abs(textOffset) + rowLocations[i] - (textOffset != 0 ? 2 : 0); if (temp < 0) temp = 0; rowLocations[i] = temp; } } else if (nbtVersion == 2) { lockedChanges = compound.getBoolean(NBT_LOCKED_CHANGES_TAG); NBTTagList settings = compound.getTagList(NBT_SETTINGS_TAG, 11); for (int i = 0; i < settings.tagCount(); i++) { int[] array = settings.getIntArrayAt(i); if (array[0] == 0) { System.arraycopy(array, 1, rowLocations, 0, 4); } else if (array[0] == 1) { System.arraycopy(array, 1, rowSizes, 0, 4); } else if (array[0] == 2) { int[] hidden = new int[4]; System.arraycopy(array, 1, hidden, 0, 4); for (int j = 0; j < 4; j++) visibleRows[j] = hidden[j] == 1; } else if (array[0] == 3) { int[] shadows = new int[4]; System.arraycopy(array, 1, shadows, 0, 4); for (int j = 0; j < 4; j++) shadowRows[j] = shadows[j] == 1; } } } for (int i = 0; i < 4; ++i) { String s = compound.getString("Text" + (i + 1)); try { ITextComponent ichatcomponent = ITextComponent.Serializer.jsonToComponent(s); try { this.signText[i] = TextComponentUtils.processComponent(icommandsender, ichatcomponent, (Entity) null); } catch (CommandException var7) { this.signText[i] = ichatcomponent; } } catch (JsonParseException var8) { this.signText[i] = new TextComponentString(s); } } if (compound.hasKey(NBT_METAL_TAG)) isMetal = compound.getBoolean(NBT_METAL_TAG); if (compound.hasKey(NBT_TEXTURE_TAG)) texture_name = compound.getString(NBT_TEXTURE_TAG); if (texture_name == null || texture_name.isEmpty()) texture_name = "oak_sign"; setResourceLocation(texture_name); stats.readStatsFromNBT(compound); } @Override public boolean shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newSate) { return (oldState.getBlock() != newSate.getBlock()); } @Nullable @Override public SPacketUpdateTileEntity getUpdatePacket() { return new SPacketUpdateTileEntity(getPos(), 0, writeToNBT(new NBTTagCompound())); } @Override public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) { readFromNBT(pkt.getNbtCompound()); markDirty(); } @Override public boolean getIsEditable() { return this.isEditable; } @Override public boolean onlyOpsCanSetNbt() { return true; } @Override public void setEditable(boolean state) { this.isEditable = state; if (!state) { playerEditing = null; } } public ResourceLocation getResourceLocation() { return resourceLocation; } public void setResourceLocation(String texture) { if (worldObj != null && !worldObj.isRemote) { texture_name = texture; } else if (resourceLocation == null) { texture_name = texture; resourceLocation = Utils.getResourceLocation(texture, isMetal); } } @Override public void setPlayer(EntityPlayer par1EntityPlayer) { this.playerEditing = par1EntityPlayer; } @Override public EntityPlayer getPlayer() { return this.playerEditing; } @Override public boolean canRenderBreaking() { return true; } @Override public boolean executeCommand(final EntityPlayer playerIn) { ICommandSender icommandsender = new ICommandSender() { /** * Get the name of this object. For players this returns their username */ public String getName() { return playerIn.getName(); } /** * Get the formatted ChatComponent that will be used for the sender's username in chat */ public ITextComponent getDisplayName() { return playerIn.getDisplayName(); } /** * Send a chat message to the CommandSender */ public void addChatMessage(ITextComponent component) { } /** * Returns {@code true} if the CommandSender is allowed to execute the command, {@code false} if not */ public boolean canCommandSenderUseCommand(int permLevel, String commandName) { return permLevel <= 2; } /** * Get the position in the world. <b>{@code null} is not allowed!</b> If you are not an entity in the world, * return the coordinates 0, 0, 0 */ public BlockPos getPosition() { return pos; } /** * Get the position vector. <b>{@code null} is not allowed!</b> If you are not an entity in the world, * return 0.0D, 0.0D, 0.0D */ public Vec3d getPositionVector() { return new Vec3d((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D); } /** * Get the world, if available. <b>{@code null} is not allowed!</b> If you are not an entity in the world, * return the overworld */ public World getEntityWorld() { return playerIn.getEntityWorld(); } /** * Returns the entity associated with the command sender. MAY BE NULL! */ public Entity getCommandSenderEntity() { return playerIn; } /** * Returns true if the command sender should be sent feedback about executed commands */ public boolean sendCommandFeedback() { return false; } public void setCommandStat(CommandResultStats.Type type, int amount) { if (worldObj != null && !worldObj.isRemote) { stats.setCommandStatForSender(worldObj.getMinecraftServer(), this, type, amount); } } /** * Get the Minecraft server instance */ public MinecraftServer getServer() { return playerIn.getServer(); } }; for (ITextComponent itextcomponent : this.signText) { Style style = itextcomponent == null ? null : itextcomponent.getStyle(); if (style != null && style.getClickEvent() != null) { ClickEvent clickevent = style.getClickEvent(); if (clickevent.getAction() == ClickEvent.Action.RUN_COMMAND) { playerIn.getServer().getCommandManager().executeCommand(icommandsender, clickevent.getValue()); } } } return true; } @Override public CommandResultStats getStats() { return stats; } }