From 1b2aee283e51e4a1a070b220b33ee3c3b98542df Mon Sep 17 00:00:00 2001 From: aidancbrady Date: Sat, 19 Mar 2016 22:03:17 -0400 Subject: [PATCH] Work on security framework --- .../client/gui/GuiFormulaicAssemblicator.java | 1 + .../gui/element/GuiRedstoneControl.java | 3 + .../client/gui/element/GuiSecurityTab.java | 107 +++++++++ src/main/java/mekanism/common/HashList.java | 16 +- src/main/java/mekanism/common/Mekanism.java | 3 + .../java/mekanism/common/PacketHandler.java | 4 +- .../mekanism/common/base/ITileComponent.java | 2 + .../common/network/PacketSecurityMode.java | 67 ++++++ .../mekanism/common/security/ISecurity.java | 106 +++++++++ .../common/security/ISecurityItem.java | 15 ++ .../common/security/SecurityFrequency.java | 111 +++++++++ .../common/tile/TileEntityBasicBlock.java | 11 + .../tile/TileEntityQuantumEntangloporter.java | 5 - .../common/tile/TileEntityTeleporter.java | 5 - .../tile/component/TileComponentConfig.java | 3 + .../tile/component/TileComponentEjector.java | 3 + .../tile/component/TileComponentSecurity.java | 220 ++++++++++++++++++ .../tile/component/TileComponentUpgrade.java | 3 + .../assets/mekanism/gui/GuiSecurityDesk.png | Bin 0 -> 10487 bytes .../mekanism/gui/elements/GuiSecurityTab.png | Bin 0 -> 4794 bytes .../resources/assets/mekanism/lang/en_US.lang | 1 + 21 files changed, 667 insertions(+), 19 deletions(-) create mode 100644 src/main/java/mekanism/client/gui/element/GuiSecurityTab.java create mode 100644 src/main/java/mekanism/common/network/PacketSecurityMode.java create mode 100644 src/main/java/mekanism/common/security/ISecurity.java create mode 100644 src/main/java/mekanism/common/security/ISecurityItem.java create mode 100644 src/main/java/mekanism/common/security/SecurityFrequency.java create mode 100644 src/main/java/mekanism/common/tile/component/TileComponentSecurity.java create mode 100644 src/main/resources/assets/mekanism/gui/GuiSecurityDesk.png create mode 100644 src/main/resources/assets/mekanism/gui/elements/GuiSecurityTab.png diff --git a/src/main/java/mekanism/client/gui/GuiFormulaicAssemblicator.java b/src/main/java/mekanism/client/gui/GuiFormulaicAssemblicator.java index c6ffa935f..6d06c1fe5 100644 --- a/src/main/java/mekanism/client/gui/GuiFormulaicAssemblicator.java +++ b/src/main/java/mekanism/client/gui/GuiFormulaicAssemblicator.java @@ -199,6 +199,7 @@ public class GuiFormulaicAssemblicator extends GuiMekanism GL11.glPushMatrix(); GL11.glEnable(GL11.GL_LIGHTING); MekanismRenderer.blendOn(); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 0.4F); itemRender.renderItemAndEffectIntoGUI(fontRendererObj, mc.getTextureManager(), stack, guiWidth + slot.xDisplayPosition, guiHeight + slot.yDisplayPosition); MekanismRenderer.blendOff(); GL11.glDisable(GL11.GL_LIGHTING); diff --git a/src/main/java/mekanism/client/gui/element/GuiRedstoneControl.java b/src/main/java/mekanism/client/gui/element/GuiRedstoneControl.java index 8f1018b11..02ae61822 100644 --- a/src/main/java/mekanism/client/gui/element/GuiRedstoneControl.java +++ b/src/main/java/mekanism/client/gui/element/GuiRedstoneControl.java @@ -12,7 +12,10 @@ import mekanism.common.util.MekanismUtils.ResourceType; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ResourceLocation; import codechicken.lib.vec.Rectangle4i; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +@SideOnly(Side.CLIENT) public class GuiRedstoneControl extends GuiElement { TileEntity tileEntity; diff --git a/src/main/java/mekanism/client/gui/element/GuiSecurityTab.java b/src/main/java/mekanism/client/gui/element/GuiSecurityTab.java new file mode 100644 index 000000000..bb7893610 --- /dev/null +++ b/src/main/java/mekanism/client/gui/element/GuiSecurityTab.java @@ -0,0 +1,107 @@ +package mekanism.client.gui.element; + +import mekanism.api.Coord4D; +import mekanism.api.EnumColor; +import mekanism.api.util.ListUtils; +import mekanism.client.gui.IGuiWrapper; +import mekanism.client.sound.SoundHandler; +import mekanism.common.Mekanism; +import mekanism.common.network.PacketSecurityMode.SecurityModeMessage; +import mekanism.common.security.ISecurity; +import mekanism.common.security.ISecurity.SecurityMode; +import mekanism.common.util.LangUtils; +import mekanism.common.util.MekanismUtils; +import mekanism.common.util.MekanismUtils.ResourceType; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; +import codechicken.lib.vec.Rectangle4i; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class GuiSecurityTab extends GuiElement +{ + TileEntity tileEntity; + + public GuiSecurityTab(IGuiWrapper gui, TileEntity tile, ResourceLocation def) + { + super(MekanismUtils.getResource(ResourceType.GUI_ELEMENT, "GuiSecurityTab.png"), gui, def); + + tileEntity = tile; + } + + @Override + public Rectangle4i getBounds(int guiWidth, int guiHeight) + { + return new Rectangle4i(guiWidth + 176, guiHeight + 32, 26, 26); + } + + @Override + public void renderBackground(int xAxis, int yAxis, int guiWidth, int guiHeight) + { + mc.renderEngine.bindTexture(RESOURCE); + + guiObj.drawTexturedRect(guiWidth + 176, guiHeight + 32, 0, 0, 26, 26); + + ISecurity tile = (ISecurity)tileEntity; + int renderX = 26 + (18*tile.getSecurity().getMode().ordinal()); + + if(tile.getSecurity().getOwner() != null && tile.getSecurity().getOwner().equals(mc.thePlayer.getCommandSenderName())) + { + if(xAxis >= 179 && xAxis <= 197 && yAxis >= 36 && yAxis <= 54) + { + guiObj.drawTexturedRect(guiWidth + 179, guiHeight + 36, renderX, 0, 18, 18); + } + else { + guiObj.drawTexturedRect(guiWidth + 179, guiHeight + 36, renderX, 18, 18, 18); + } + } + else { + guiObj.drawTexturedRect(guiWidth + 179, guiHeight + 36, renderX, 36, 18, 18); + } + + mc.renderEngine.bindTexture(defaultLocation); + } + + @Override + public void renderForeground(int xAxis, int yAxis) + { + mc.renderEngine.bindTexture(RESOURCE); + + ISecurity control = (ISecurity)tileEntity; + + if(xAxis >= 179 && xAxis <= 197 && yAxis >= 36 && yAxis <= 54) + { + String securityText = EnumColor.GREY + LangUtils.localize("gui.security") + ": " + control.getSecurity().getMode().getDisplay(); + String ownerText = ISecurity.getOwnerDisplay(mc.thePlayer.getCommandSenderName(), control.getSecurity().getOwner()); + + displayTooltips(ListUtils.asList(securityText, ownerText), xAxis, yAxis); + } + + mc.renderEngine.bindTexture(defaultLocation); + } + + @Override + public void preMouseClicked(int xAxis, int yAxis, int button) {} + + @Override + public void mouseClicked(int xAxis, int yAxis, int button) + { + ISecurity control = (ISecurity)tileEntity; + + if(button == 0) + { + if(control.getSecurity().getOwner() != null && mc.thePlayer.getCommandSenderName().equals(control.getSecurity().getOwner())) + { + if(xAxis >= 179 && xAxis <= 197 && yAxis >= 36 && yAxis <= 54) + { + SecurityMode current = control.getSecurity().getMode(); + int ordinalToSet = current.ordinal() < (SecurityMode.values().length-1) ? current.ordinal()+1 : 0; + + SoundHandler.playSound("gui.button.press"); + Mekanism.packetHandler.sendToServer(new SecurityModeMessage(Coord4D.get(tileEntity), SecurityMode.values()[ordinalToSet])); + } + } + } + } +} diff --git a/src/main/java/mekanism/common/HashList.java b/src/main/java/mekanism/common/HashList.java index 2d932f4ce..5d1ed660b 100644 --- a/src/main/java/mekanism/common/HashList.java +++ b/src/main/java/mekanism/common/HashList.java @@ -91,17 +91,17 @@ public class HashList implements Iterable return list.size(); } - public void swap( int source, int target ) + public void swap(int source, int target) { - // Make sure both source and target ar legal values - if( source == target ) return; - if( source < 0 || target < 0 ) return; - if( source >= list.size() || target >= list.size() ) return; + // Make sure both source and target are legal values + if(source == target) return; + if(source < 0 || target < 0) return; + if(source >= list.size() || target >= list.size()) return; // Perform swap - T temp = list.get( source ); - list.set( source, list.get( target ) ); - list.set( target, temp ); + T temp = list.get(source); + list.set(source, list.get( target)); + list.set(target, temp); } @Override diff --git a/src/main/java/mekanism/common/Mekanism.java b/src/main/java/mekanism/common/Mekanism.java index da863a21e..bff0f0c32 100644 --- a/src/main/java/mekanism/common/Mekanism.java +++ b/src/main/java/mekanism/common/Mekanism.java @@ -73,6 +73,7 @@ import mekanism.common.recipe.ShapelessMekanismRecipe; import mekanism.common.recipe.inputs.ItemStackInput; import mekanism.common.recipe.machines.SmeltingRecipe; import mekanism.common.recipe.outputs.ItemStackOutput; +import mekanism.common.security.SecurityFrequency; import mekanism.common.tile.TileEntityAdvancedBoundingBlock; import mekanism.common.tile.TileEntityBoundingBlock; import mekanism.common.tile.TileEntityCardboardBox; @@ -183,6 +184,8 @@ public class Mekanism public static FrequencyManager publicEntangloporters = new FrequencyManager(InventoryFrequency.class, "Entangloporter"); public static Map privateEntangloporters = new HashMap(); + public static FrequencyManager securityFrequencies = new FrequencyManager(SecurityFrequency.class, "Security"); + /** Mekanism creative tab */ public static CreativeTabMekanism tabMekanism = new CreativeTabMekanism(); diff --git a/src/main/java/mekanism/common/PacketHandler.java b/src/main/java/mekanism/common/PacketHandler.java index 03e85ab3b..08c32f438 100644 --- a/src/main/java/mekanism/common/PacketHandler.java +++ b/src/main/java/mekanism/common/PacketHandler.java @@ -55,6 +55,8 @@ import mekanism.common.network.PacketRobit; import mekanism.common.network.PacketRobit.RobitMessage; import mekanism.common.network.PacketScubaTankData; import mekanism.common.network.PacketScubaTankData.ScubaTankDataMessage; +import mekanism.common.network.PacketSecurityMode; +import mekanism.common.network.PacketSecurityMode.SecurityModeMessage; import mekanism.common.network.PacketSimpleGui; import mekanism.common.network.PacketSimpleGui.SimpleGuiMessage; import mekanism.common.network.PacketTileEntity; @@ -102,7 +104,7 @@ public class PacketHandler netHandler.registerMessage(PacketDataRequest.class, DataRequestMessage.class, 7, Side.SERVER); netHandler.registerMessage(PacketOredictionificatorGui.class, OredictionificatorGuiMessage.class, 8, Side.CLIENT); netHandler.registerMessage(PacketOredictionificatorGui.class, OredictionificatorGuiMessage.class, 8, Side.SERVER); - //EMPTY SLOT 9 + netHandler.registerMessage(PacketSecurityMode.class, SecurityModeMessage.class, 9, Side.SERVER); netHandler.registerMessage(PacketPortableTeleporter.class, PortableTeleporterMessage.class, 10, Side.CLIENT); netHandler.registerMessage(PacketPortableTeleporter.class, PortableTeleporterMessage.class, 10, Side.SERVER); netHandler.registerMessage(PacketRemoveUpgrade.class, RemoveUpgradeMessage.class, 11, Side.SERVER); diff --git a/src/main/java/mekanism/common/base/ITileComponent.java b/src/main/java/mekanism/common/base/ITileComponent.java index d69119553..d14126ade 100644 --- a/src/main/java/mekanism/common/base/ITileComponent.java +++ b/src/main/java/mekanism/common/base/ITileComponent.java @@ -17,4 +17,6 @@ public interface ITileComponent public void write(NBTTagCompound nbtTags); public void write(ArrayList data); + + public void invalidate(); } diff --git a/src/main/java/mekanism/common/network/PacketSecurityMode.java b/src/main/java/mekanism/common/network/PacketSecurityMode.java new file mode 100644 index 000000000..3cbc4b3da --- /dev/null +++ b/src/main/java/mekanism/common/network/PacketSecurityMode.java @@ -0,0 +1,67 @@ +package mekanism.common.network; + +import io.netty.buffer.ByteBuf; +import mekanism.api.Coord4D; +import mekanism.common.PacketHandler; +import mekanism.common.network.PacketSecurityMode.SecurityModeMessage; +import mekanism.common.security.ISecurity; +import mekanism.common.security.ISecurity.SecurityMode; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.tileentity.TileEntity; +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; + +public class PacketSecurityMode implements IMessageHandler +{ + @Override + public IMessage onMessage(SecurityModeMessage message, MessageContext context) + { + EntityPlayer player = PacketHandler.getPlayer(context); + TileEntity tileEntity = message.coord4D.getTileEntity(player.worldObj); + + if(tileEntity instanceof ISecurity) + { + String owner = ((ISecurity)tileEntity).getSecurity().getOwner(); + + if(owner != null && player.getCommandSenderName().equals(owner)) + { + ((ISecurity)tileEntity).getSecurity().setMode(message.value); + } + } + + return null; + } + + public static class SecurityModeMessage implements IMessage + { + public Coord4D coord4D; + public SecurityMode value; + + public SecurityModeMessage() {} + + public SecurityModeMessage(Coord4D coord, SecurityMode control) + { + coord4D = coord; + value = control; + } + + @Override + public void toBytes(ByteBuf dataStream) + { + dataStream.writeInt(coord4D.xCoord); + dataStream.writeInt(coord4D.yCoord); + dataStream.writeInt(coord4D.zCoord); + dataStream.writeInt(coord4D.dimensionId); + + dataStream.writeInt(value.ordinal()); + } + + @Override + public void fromBytes(ByteBuf dataStream) + { + coord4D = Coord4D.read(dataStream); + value = SecurityMode.values()[dataStream.readInt()]; + } + } +} diff --git a/src/main/java/mekanism/common/security/ISecurity.java b/src/main/java/mekanism/common/security/ISecurity.java new file mode 100644 index 000000000..1704a6557 --- /dev/null +++ b/src/main/java/mekanism/common/security/ISecurity.java @@ -0,0 +1,106 @@ +package mekanism.common.security; + +import mekanism.api.EnumColor; +import mekanism.common.Mekanism; +import mekanism.common.frequency.Frequency; +import mekanism.common.tile.component.TileComponentSecurity; +import mekanism.common.util.LangUtils; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; + +public interface ISecurity +{ + public TileComponentSecurity getSecurity(); + + public enum SecurityMode + { + PUBLIC(EnumColor.BRIGHT_GREEN + "security.public"), + PRIVATE(EnumColor.RED + "security.private"), + TRUSTED(EnumColor.ORANGE + "security.trusted"); + + private String display; + private EnumColor color; + + public String getDisplay() + { + return color + LangUtils.localize(display); + } + + private SecurityMode(String s) + { + display = s; + } + } + + public static boolean canAccess(EntityPlayer player, ItemStack stack) + { + if(stack == null || !(stack.getItem() instanceof ISecurityItem)) + { + return true; + } + + ISecurityItem security = (ISecurityItem)stack.getItem(); + + return canAccess(security.getSecurity(stack), player.getCommandSenderName(), security.getOwner(stack)); + } + + public static boolean canAccess(EntityPlayer player, TileEntity tile) + { + if(tile == null || !(tile instanceof ISecurity)) + { + return true; + } + + ISecurity security = (ISecurity)tile; + + return canAccess(security.getSecurity().getMode(), player.getCommandSenderName(), security.getSecurity().getOwner()); + } + + public static boolean canAccess(SecurityMode mode, String username, String owner) + { + if(owner == null || username.equals(owner)) + { + return true; + } + + if(mode == SecurityMode.PUBLIC) + { + return true; + } + else if(mode == SecurityMode.TRUSTED) + { + SecurityFrequency freq = getFrequency(owner); + + if(freq == null || freq.trusted.contains(username)) + { + return true; + } + } + + return false; + } + + public static SecurityFrequency getFrequency(String owner) + { + for(Frequency f : Mekanism.securityFrequencies.getFrequencies()) + { + if(f instanceof SecurityFrequency && f.owner.equals(owner)) + { + return (SecurityFrequency)f; + } + } + + return null; + } + + public static String getOwnerDisplay(String user, String owner) + { + if(owner == null) + { + return EnumColor.RED + LangUtils.localize("gui.noOwner"); + } + + return EnumColor.GREY + LangUtils.localize("gui.owner") + ": " + (user.equals(owner) ? EnumColor.BRIGHT_GREEN : EnumColor.RED) + owner; + } +} diff --git a/src/main/java/mekanism/common/security/ISecurityItem.java b/src/main/java/mekanism/common/security/ISecurityItem.java new file mode 100644 index 000000000..413cf2e6a --- /dev/null +++ b/src/main/java/mekanism/common/security/ISecurityItem.java @@ -0,0 +1,15 @@ +package mekanism.common.security; + +import mekanism.common.security.ISecurity.SecurityMode; +import net.minecraft.item.ItemStack; + +public interface ISecurityItem +{ + public String getOwner(ItemStack stack); + + public void setOwner(ItemStack stack, String owner); + + public SecurityMode getSecurity(ItemStack stack); + + public void setSecurity(ItemStack stack, SecurityMode mode); +} diff --git a/src/main/java/mekanism/common/security/SecurityFrequency.java b/src/main/java/mekanism/common/security/SecurityFrequency.java new file mode 100644 index 000000000..d028ade24 --- /dev/null +++ b/src/main/java/mekanism/common/security/SecurityFrequency.java @@ -0,0 +1,111 @@ +package mekanism.common.security; + +import io.netty.buffer.ByteBuf; + +import java.util.ArrayList; + +import mekanism.common.HashList; +import mekanism.common.PacketHandler; +import mekanism.common.frequency.Frequency; +import mekanism.common.security.ISecurity.SecurityMode; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.nbt.NBTTagString; +import net.minecraftforge.common.util.Constants.NBT; + +public class SecurityFrequency extends Frequency +{ + public boolean override; + + public HashList trusted = new HashList(); + + public SecurityMode securityMode = SecurityMode.PUBLIC; + + public SecurityFrequency(String o) + { + super("Security", o); + } + + public SecurityFrequency(NBTTagCompound nbtTags) + { + super(nbtTags); + } + + public SecurityFrequency(ByteBuf dataStream) + { + super(dataStream); + } + + @Override + public void write(NBTTagCompound nbtTags) + { + super.write(nbtTags); + + nbtTags.setBoolean("override", override); + nbtTags.setInteger("securityMode", securityMode.ordinal()); + + if(!trusted.isEmpty()) + { + NBTTagList trustedList = new NBTTagList(); + + for(String s : trusted) + { + trustedList.appendTag(new NBTTagString(s)); + } + + nbtTags.setTag("trusted", trustedList); + } + } + + @Override + protected void read(NBTTagCompound nbtTags) + { + super.read(nbtTags); + + override = nbtTags.getBoolean("override"); + securityMode = SecurityMode.values()[nbtTags.getInteger("securityMode")]; + + if(nbtTags.hasKey("trusted")) + { + NBTTagList trustedList = nbtTags.getTagList("trusted", NBT.TAG_STRING); + + for(int i = 0; i < trustedList.tagCount(); i++) + { + trusted.add(trustedList.getStringTagAt(i)); + } + } + } + + @Override + public void write(ArrayList data) + { + super.write(data); + + data.add(override); + data.add(securityMode.ordinal()); + + data.add(trusted.size()); + + for(String s : trusted) + { + data.add(trusted); + } + } + + @Override + protected void read(ByteBuf dataStream) + { + super.read(dataStream); + + override = dataStream.readBoolean(); + securityMode = SecurityMode.values()[dataStream.readInt()]; + + trusted.clear(); + int size = dataStream.readInt(); + + for(int i = 0; i < size; i++) + { + trusted.add(PacketHandler.readString(dataStream)); + } + } +} diff --git a/src/main/java/mekanism/common/tile/TileEntityBasicBlock.java b/src/main/java/mekanism/common/tile/TileEntityBasicBlock.java index 454d23d24..19d45b1f0 100644 --- a/src/main/java/mekanism/common/tile/TileEntityBasicBlock.java +++ b/src/main/java/mekanism/common/tile/TileEntityBasicBlock.java @@ -137,6 +137,17 @@ public abstract class TileEntityBasicBlock extends TileEntity implements IWrench return data; } + + @Override + public void invalidate() + { + super.invalidate(); + + for(ITileComponent component : components) + { + component.invalidate(); + } + } @Override public void validate() diff --git a/src/main/java/mekanism/common/tile/TileEntityQuantumEntangloporter.java b/src/main/java/mekanism/common/tile/TileEntityQuantumEntangloporter.java index 8cec6ce40..07e6ce3ac 100644 --- a/src/main/java/mekanism/common/tile/TileEntityQuantumEntangloporter.java +++ b/src/main/java/mekanism/common/tile/TileEntityQuantumEntangloporter.java @@ -192,11 +192,6 @@ public class TileEntityQuantumEntangloporter extends TileEntityElectricBlock imp public void setFrequency(String name, boolean publicFreq) { - if(name.equals(frequency)) - { - return; - } - FrequencyManager manager = getManager(new InventoryFrequency(name, null).setPublic(publicFreq)); manager.deactivate(Coord4D.get(this)); diff --git a/src/main/java/mekanism/common/tile/TileEntityTeleporter.java b/src/main/java/mekanism/common/tile/TileEntityTeleporter.java index 9460e8ca2..25117e502 100644 --- a/src/main/java/mekanism/common/tile/TileEntityTeleporter.java +++ b/src/main/java/mekanism/common/tile/TileEntityTeleporter.java @@ -165,11 +165,6 @@ public class TileEntityTeleporter extends TileEntityElectricBlock implements ICo public void setFrequency(String name, boolean publicFreq) { - if(name.equals(frequency)) - { - return; - } - FrequencyManager manager = getManager(new Frequency(name, null).setPublic(publicFreq)); manager.deactivate(Coord4D.get(this)); diff --git a/src/main/java/mekanism/common/tile/component/TileComponentConfig.java b/src/main/java/mekanism/common/tile/component/TileComponentConfig.java index 9a359b920..b074c2675 100644 --- a/src/main/java/mekanism/common/tile/component/TileComponentConfig.java +++ b/src/main/java/mekanism/common/tile/component/TileComponentConfig.java @@ -216,6 +216,9 @@ public class TileComponentConfig implements ITileComponent } } + @Override + public void invalidate() {} + public boolean isEjecting(TransmissionType type) { return ejecting.get(type.ordinal()); diff --git a/src/main/java/mekanism/common/tile/component/TileComponentEjector.java b/src/main/java/mekanism/common/tile/component/TileComponentEjector.java index c239d29f0..305534e6f 100644 --- a/src/main/java/mekanism/common/tile/component/TileComponentEjector.java +++ b/src/main/java/mekanism/common/tile/component/TileComponentEjector.java @@ -374,6 +374,9 @@ public class TileComponentEjector implements ITileComponent } } + @Override + public void invalidate() {} + private boolean getEjecting(TransmissionType type) { return ((ISideConfiguration)tileEntity).getConfig().isEjecting(type); diff --git a/src/main/java/mekanism/common/tile/component/TileComponentSecurity.java b/src/main/java/mekanism/common/tile/component/TileComponentSecurity.java new file mode 100644 index 000000000..c7a39147f --- /dev/null +++ b/src/main/java/mekanism/common/tile/component/TileComponentSecurity.java @@ -0,0 +1,220 @@ +package mekanism.common.tile.component; + +import io.netty.buffer.ByteBuf; + +import java.util.ArrayList; + +import mekanism.api.Coord4D; +import mekanism.common.Mekanism; +import mekanism.common.PacketHandler; +import mekanism.common.base.ITileComponent; +import mekanism.common.frequency.Frequency; +import mekanism.common.frequency.FrequencyManager; +import mekanism.common.security.ISecurity.SecurityMode; +import mekanism.common.security.SecurityFrequency; +import mekanism.common.tile.TileEntityContainerBlock; +import mekanism.common.util.MekanismUtils; +import net.minecraft.nbt.NBTTagCompound; + +public class TileComponentSecurity implements ITileComponent +{ + /** TileEntity implementing this component. */ + public TileEntityContainerBlock tileEntity; + + private String owner; + + private SecurityMode securityMode = SecurityMode.PUBLIC; + + private SecurityFrequency frequency; + + public TileComponentSecurity(TileEntityContainerBlock tile) + { + tileEntity = tile; + + tile.components.add(this); + } + + public String getOwner() + { + return owner; + } + + public void setOwner(String o) + { + frequency = null; + owner = o; + } + + public SecurityMode getMode() + { + return securityMode; + } + + public void setMode(SecurityMode mode) + { + securityMode = mode; + } + + public FrequencyManager getManager(Frequency freq) + { + if(owner == null || freq == null) + { + return null; + } + + return Mekanism.securityFrequencies; + } + + public void setFrequency(String owner) + { + FrequencyManager manager = Mekanism.securityFrequencies; + manager.deactivate(Coord4D.get(tileEntity)); + + for(Frequency freq : manager.getFrequencies()) + { + if(freq.owner.equals(owner)) + { + frequency = (SecurityFrequency)freq; + frequency.activeCoords.add(Coord4D.get(tileEntity)); + + return; + } + } + + Frequency freq = new SecurityFrequency(owner).setPublic(true); + freq.activeCoords.add(Coord4D.get(tileEntity)); + manager.addFrequency(freq); + frequency = (SecurityFrequency)freq; + + MekanismUtils.saveChunk(tileEntity); + tileEntity.markDirty(); + } + + @Override + public void tick() + { + if(!tileEntity.getWorldObj().isRemote) + { + if(frequency == null && owner != null) + { + setFrequency(owner); + } + + FrequencyManager manager = getManager(frequency); + + if(manager != null) + { + if(frequency != null && !frequency.valid) + { + frequency = (SecurityFrequency)manager.validateFrequency(owner, Coord4D.get(tileEntity), frequency); + } + + if(frequency != null) + { + frequency = (SecurityFrequency)manager.update(owner, Coord4D.get(tileEntity), frequency); + } + } + else { + frequency = null; + } + } + } + + @Override + public void read(NBTTagCompound nbtTags) + { + securityMode = SecurityMode.values()[nbtTags.getInteger("securityMode")]; + + if(nbtTags.hasKey("owner")) + { + owner = nbtTags.getString("owner"); + } + + if(nbtTags.hasKey("frequency")) + { + frequency = new SecurityFrequency(nbtTags.getCompoundTag("frequency")); + frequency.valid = false; + } + } + + @Override + public void read(ByteBuf dataStream) + { + securityMode = SecurityMode.values()[dataStream.readInt()]; + + if(dataStream.readBoolean()) + { + owner = PacketHandler.readString(dataStream); + } + else { + owner = null; + } + + if(dataStream.readBoolean()) + { + frequency = new SecurityFrequency(dataStream); + } + else { + frequency = null; + } + } + + @Override + public void write(NBTTagCompound nbtTags) + { + nbtTags.setInteger("securityMode", securityMode.ordinal()); + + if(owner != null) + { + nbtTags.setString("owner", owner); + } + + if(frequency != null) + { + NBTTagCompound frequencyTag = new NBTTagCompound(); + frequency.write(frequencyTag); + nbtTags.setTag("frequency", frequencyTag); + } + } + + @Override + public void write(ArrayList data) + { + data.add(securityMode.ordinal()); + + if(owner != null) + { + data.add(true); + data.add(owner); + } + else { + data.add(false); + } + + if(frequency != null) + { + data.add(true); + frequency.write(data); + } + else { + data.add(false); + } + } + + @Override + public void invalidate() + { + if(!tileEntity.getWorldObj().isRemote) + { + if(frequency != null) + { + FrequencyManager manager = getManager(frequency); + + if(manager != null) + { + manager.deactivate(Coord4D.get(tileEntity)); + } + } + } + } +} diff --git a/src/main/java/mekanism/common/tile/component/TileComponentUpgrade.java b/src/main/java/mekanism/common/tile/component/TileComponentUpgrade.java index 94f1662de..71f10d3fb 100644 --- a/src/main/java/mekanism/common/tile/component/TileComponentUpgrade.java +++ b/src/main/java/mekanism/common/tile/component/TileComponentUpgrade.java @@ -226,4 +226,7 @@ public class TileComponentUpgrade implements ITileComponent { Upgrade.saveMap(upgrades, nbtTags); } + + @Override + public void invalidate() {} } diff --git a/src/main/resources/assets/mekanism/gui/GuiSecurityDesk.png b/src/main/resources/assets/mekanism/gui/GuiSecurityDesk.png new file mode 100644 index 0000000000000000000000000000000000000000..72dd35c6152f7a310cf7b8df4553769e4488212b GIT binary patch literal 10487 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 rtr)<6#eX9F=Y;