diff --git a/src/main/java/train/client/core/ClientProxy.java b/src/main/java/train/client/core/ClientProxy.java index 789024044c..a240245f65 100644 --- a/src/main/java/train/client/core/ClientProxy.java +++ b/src/main/java/train/client/core/ClientProxy.java @@ -393,6 +393,8 @@ public Object getClientGuiElement(int ID, EntityPlayer player, World world, int return entity1 != null ? new GuiFixedOverlay(player, (EntityRollingStock) entity1) : null; case (GuiIDs.DYNAMIC_OVERLAY): return entity1 != null ? new GuiDynamicOverlay(player, (EntityRollingStock) entity1) : null; + case (GuiIDs.LOCK_MENU): + return entity1 != null ? new GuiLockMenu(player, ((EntityRollingStock) entity1)) : null; case (GuiIDs.SEAT_GUI): return entity1 != null ? new GUISeatManager(player, (EntityRollingStock) entity1) : null; default: diff --git a/src/main/java/train/client/gui/GuiButtonLockMenu.java b/src/main/java/train/client/gui/GuiButtonLockMenu.java new file mode 100644 index 0000000000..c954900fac --- /dev/null +++ b/src/main/java/train/client/gui/GuiButtonLockMenu.java @@ -0,0 +1,148 @@ +package train.client.gui; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; +import train.common.library.Info; + +/** + * @author 02skaplan + *

Class for buttons used for the lock menu.

+ */ +@SideOnly(Side.CLIENT) +class GuiButtonLockMenu extends GuiButton { + enum Type { + LOCKED, + UNLOCKED, + CLOSE, + REMOVE, + BREAKACCESSON, + BREAKACCESSOFF, + SAVETOALL, + ARROWUP, + ARROWDOWN, + COPY, + PASTE + } + enum Texture { + ACTIVE, + INACTIVE + } + /** + * if the button has to be drawn drawButton is more than just draw, it makes the button exists or not too + */ + public boolean showButton; + /** + * Starting x-value on texture. + */ + private int u; + /** + * Starting y-value on texture. + */ + private int v = 0; + private int TEXTURE_WIDTH; + private int TEXTURE_HEIGHT; + private Texture texture; + private Type type; + + public GuiButtonLockMenu(int buttonID, int x, int y, int xSize, int ySize, Type type) { + super(buttonID, x, y, xSize, ySize, ""); + this.setType(type, Texture.INACTIVE); + } + + /** + * Draws this button to the screen. + */ + @Override + public void drawButton(Minecraft mc, int par2, int par3) { + if (this.visible && showButton) { + if (par2 >= this.xPosition && par3 >= this.yPosition && par2 < this.xPosition + this.width && par3 < this.yPosition + this.height) { // If mouse is hovering over... + this.setType(this.type, Texture.ACTIVE); + } else { + this.setType(this.type, Texture.INACTIVE); + } + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + RenderHelper.enableGUIStandardItemLighting(); + GL11.glPushMatrix(); + mc.renderEngine.bindTexture(new ResourceLocation(Info.resourceLocation, Info.guiPrefix + "gui_lockmenu.png")); + this.drawTexturedModalRect(this.xPosition, this.yPosition, u, v, TEXTURE_WIDTH, TEXTURE_HEIGHT); + RenderHelper.disableStandardItemLighting(); + GL11.glPopMatrix(); + } + } + public void setType(Type type, Texture texture) { + this.type = type; + this.texture = texture; + switch (type) { + case LOCKED: + case UNLOCKED: + case CLOSE: + case REMOVE: + if (texture == Texture.INACTIVE) + v = 0; + else + v = 25; + if (type == Type.LOCKED || type == Type.UNLOCKED) { + TEXTURE_WIDTH = 17; + TEXTURE_HEIGHT = 25; + if (type == Type.LOCKED) + u = 176; + else + u = 193; + } else { + TEXTURE_WIDTH = 17; + TEXTURE_HEIGHT = 17; + if (type == Type.CLOSE) + u = 210; + else + u = 227; + } + break; + case BREAKACCESSON: + case BREAKACCESSOFF: + case SAVETOALL: + TEXTURE_WIDTH = 17; + TEXTURE_HEIGHT = 17; + if (texture == Texture.INACTIVE) + v = 50; + else + v = 75; + if (type == Type.BREAKACCESSON) + u = 193; + else if (type == Type.BREAKACCESSOFF) + u = 210; + else + u = 227; + break; + case ARROWUP: + case ARROWDOWN: + case COPY: + case PASTE: + if (texture == Texture.INACTIVE) + v = 92; + else + v = 117; + if (type == Type.ARROWUP || type == Type.ARROWDOWN) { + TEXTURE_WIDTH = 7; + TEXTURE_HEIGHT = 22; + if (type == Type.ARROWUP) + u = 176; + else + u = 192; + } else { + TEXTURE_WIDTH = 17; + TEXTURE_HEIGHT = 17; + if (type == Type.COPY) + u = 210; + else + u = 227; + } + } + } + public Texture getTexture() { return this.texture; } + public Type getType() { return this.type; } +} diff --git a/src/main/java/train/client/gui/GuiFreight.java b/src/main/java/train/client/gui/GuiFreight.java index e961c83caf..7eb0fe5713 100644 --- a/src/main/java/train/client/gui/GuiFreight.java +++ b/src/main/java/train/client/gui/GuiFreight.java @@ -15,6 +15,7 @@ import train.common.api.Freight; import train.common.core.network.PacketSetTrainLockedToClient; import train.common.inventory.InventoryFreight; +import train.common.library.GuiIDs; import train.common.library.Info; import java.util.List; @@ -54,8 +55,15 @@ public void initGui() { if (!freight.getTrainLockedFromPacket()) { this.buttonList.add(this.buttonLock = new GuiButton(3, buttonPosX + 124, buttonPosY - 10, 51, 10, "Unlocked")); - } else { - this.buttonList.add(this.buttonLock = new GuiButton(3, buttonPosX + 130, buttonPosY - 10, 43, 10, "Locked")); + } + else { + if (freight.getTrainOwner().equalsIgnoreCase(player.getDisplayName())) + this.buttonList.add(this.buttonLock = new GuiButton(3, buttonPosX + 130, buttonPosY - 10, 43, 10, "Locked")); + else if (freight.isPlayerTrusted(player.getDisplayName())) + if (freight.isPlayerTrustedToBreak(player.getDisplayName())) + this.buttonList.add(this.buttonLock = new GuiButton(3, buttonPosX + 125, buttonPosY - 10, 48, 10, "Trusted+")); + else + this.buttonList.add(this.buttonLock = new GuiButton(3, buttonPosX + 128, buttonPosY - 10, 45, 10, "Trusted")); } if (freight.seats.size() > 1) { this.buttonList.add(this.buttonSeatManager = new GUIButton(buttonPosX + 124,buttonPosY - 20, 51,10, "Seats") { @@ -84,35 +92,32 @@ public void onClick() { protected void actionPerformed(GuiButton guibutton) { if (guibutton.id == 3) { if (player != null && player.getCommandSenderName().equalsIgnoreCase(freight.getTrainOwner())) { - AxisAlignedBB box = freight.boundingBox.expand(5, 5, 5); - List lis3 = freight.worldObj.getEntitiesWithinAABBExcludingEntity(freight, box); - - if (!freight.getTrainLockedFromPacket()) { - if (lis3 != null && !lis3.isEmpty()) { - for (Object entity : lis3) { - if (entity instanceof EntityPlayer) { - Traincraft.lockChannel.sendToServer(new PacketSetTrainLockedToClient(true, freight.getEntityId())); - } - } - } - + if (!freight.getTrainLockedFromPacket() && !isShiftKeyDown()) { freight.locked = true; guibutton.displayString = "Locked"; - } else { - if (lis3 != null && !lis3.isEmpty()) { - for (Object entity : lis3) { - if (entity instanceof EntityPlayer) { - Traincraft.lockChannel.sendToServer(new PacketSetTrainLockedToClient(false, freight.getEntityId())); + this.initGui(); + } else if (!isShiftKeyDown()) { + freight.locked = false; + guibutton.displayString = "Unlocked"; + this.initGui(); + } + AxisAlignedBB box = freight.boundingBox.expand(5, 5, 5); + List lis3 = freight.worldObj.getEntitiesWithinAABBExcludingEntity(freight, box); + if (lis3 != null && !lis3.isEmpty()) { + for (Object entity : lis3) { + if (entity instanceof EntityPlayer) { + if (!isShiftKeyDown()) { + Traincraft.lockChannel.sendToServer(new PacketSetTrainLockedToClient(freight.locked, freight.getTrustedList(), freight.getEntityId(), false)); + } else { + this.mc.thePlayer.closeScreen(); + player.openGui(Traincraft.instance, GuiIDs.LOCK_MENU, player.getEntityWorld(), freight.getEntityId(), -1, (int) freight.posZ); + return; } } } - - freight.locked = false; - guibutton.displayString = "Unlocked"; } - - this.initGui(); - } else if (player != null) { + } + else if (player != null && player instanceof EntityPlayer) { player.addChatMessage(new ChatComponentText("You are not the owner")); } } else if (guibutton instanceof GUIButton) { @@ -124,12 +129,15 @@ protected void actionPerformed(GuiButton guibutton) { protected void drawCreativeTabHoveringText(String str, int t, int g) { String state = ""; if (freight.getTrainLockedFromPacket()) { - state = "Locked"; - } - - if (!freight.getTrainLockedFromPacket()) { - state = "Unlocked"; - } + if (freight.getTrainOwner().equalsIgnoreCase(player.getDisplayName())) + state = "Locked"; + else if (freight.isPlayerTrusted(player.getDisplayName())) + if (freight.isPlayerTrustedToBreak(player.getDisplayName())) + state = "Trusted Access+"; + else + state = "Trusted Access"; + } else + state = "Unlocked"; int textWidth = fontRendererObj.getStringWidth("the GUI, change speed, destroy it."); int startX = 90; diff --git a/src/main/java/train/client/gui/GuiLockMenu.java b/src/main/java/train/client/gui/GuiLockMenu.java new file mode 100644 index 0000000000..072b72558e --- /dev/null +++ b/src/main/java/train/client/gui/GuiLockMenu.java @@ -0,0 +1,42 @@ +package train.client.gui; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.entity.player.EntityPlayer; +import train.common.Traincraft; +import train.common.api.EntityRollingStock; +import train.common.core.network.PacketSetTrainLockedToClient; + +/** + * @author 02skaplan + *

Lock and Trusted Players Menu

+ *

Allows players to lock and unlock a piece of rolling stock and add & remove trusted individuals from using the rolling stock.

+ */ +@SideOnly(Side.CLIENT) +public class GuiLockMenu extends GuiLockMenuAbstract { + private final EntityRollingStock rollingStock; + + /** + * @author 02skaplan + */ + public GuiLockMenu(EntityPlayer editingPlayer, EntityRollingStock rollingStock) { + super(editingPlayer); + this.rollingStock = rollingStock; + currentTrustees.addAll(rollingStock.getTrustedList()); + } + + @Override + public boolean getLocked() { + return rollingStock.getTrainLockedFromPacket(); + } + + @Override + public void setLocked(boolean locked) { + rollingStock.setTrainLockedFromPacket(locked); + } + + @Override + public void sendUpdatePacket(boolean propagate) { + Traincraft.lockChannel.sendToServer(new PacketSetTrainLockedToClient(rollingStock.locked, exportTrustedPlayers(), rollingStock.getEntityId(), propagate)); + } +} diff --git a/src/main/java/train/client/gui/GuiLockMenuAbstract.java b/src/main/java/train/client/gui/GuiLockMenuAbstract.java new file mode 100644 index 0000000000..99150dada6 --- /dev/null +++ b/src/main/java/train/client/gui/GuiLockMenuAbstract.java @@ -0,0 +1,341 @@ +package train.client.gui; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.GuiTextField; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.StatCollector; +import org.lwjgl.input.Mouse; +import train.common.core.handlers.ConfigHandler; +import train.common.entity.TrustedPlayer; +import train.common.library.Info; + +import java.awt.*; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * @author 02skaplan + *

Lock and Trusted Players Menu

+ *

Allows players to lock and unlock a piece of rolling stock and add & remove trusted individuals from using the rolling stock.

+ */ +@SuppressWarnings("unchecked") +@SideOnly(Side.CLIENT) +public abstract class GuiLockMenuAbstract extends GuiScreen { + private final EntityPlayer editingPlayer; + final private int MENU_TEXTURE_WIDTH = 176; + final private int MENU_TEXTURE_HEIGHT = 222; + /** + * X-coordinate of top left of GUI. + */ + private int GUI_ANCHOR_X; + /** + * X-coordinate of top center of GUI. + */ + private int GUI_ANCHOR_MID_X; + private int TEXTBOX_LEFT_ANCHOR; + /** + * Y-coordinate of top left of GUI. + */ + private int GUI_ANCHOR_Y; + private GuiButtonLockMenu lockUnlockButton; + private GuiButtonLockMenu closeButton; + protected GuiButtonLockMenu closeAndSavetoAll; + private GuiButtonLockMenu arrowUp; + private GuiButtonLockMenu arrowDown; + private GuiButtonLockMenu copyButton; + private GuiButtonLockMenu pasteButton; + public final int MAX_TRUSTEES_ON_PAGE; + protected final int textBoxWidth; + protected final int textBoxHeight; + protected final int textBoxAndButtonWidth; + private int numberOfActiveTextboxes = 1; + protected final List currentTrustees; + private final List textFieldList = new ArrayList<>(); + private final int NUMBER_OF_STATIC_BUTTONS = 7; + private int currentPage; + + + /** + * @author 02skaplan + */ + public GuiLockMenuAbstract(EntityPlayer editingPlayer) { + this.editingPlayer = editingPlayer; + currentTrustees = new ArrayList<>(); + MAX_TRUSTEES_ON_PAGE = 6; + textBoxWidth = 100; + textBoxHeight = 20; + textBoxAndButtonWidth = textBoxWidth + 17 + 5; + currentPage = 0; + } + + /** + * Initial setup for buttons and GUI anchors. + */ + @Override + public void initGui() { + GUI_ANCHOR_MID_X = (this.width) / 2; + GUI_ANCHOR_Y = (this.height) / 2 - (MENU_TEXTURE_HEIGHT / 2); + GUI_ANCHOR_X = GUI_ANCHOR_MID_X - (MENU_TEXTURE_WIDTH) / 2; + TEXTBOX_LEFT_ANCHOR = GUI_ANCHOR_MID_X - (textBoxAndButtonWidth / 2) - 7; + this.buttonList.clear(); + this.buttonList.add(this.lockUnlockButton = new GuiButtonLockMenu(0, GUI_ANCHOR_MID_X - (17 / 2), GUI_ANCHOR_Y + 10, 17, 25, getLocked() ? GuiButtonLockMenu.Type.LOCKED : GuiButtonLockMenu.Type.UNLOCKED)); + this.buttonList.add(this.closeButton = new GuiButtonLockMenu(1, GUI_ANCHOR_X + MENU_TEXTURE_WIDTH - 22, GUI_ANCHOR_Y + 4, 17, 17, GuiButtonLockMenu.Type.CLOSE)); + this.buttonList.add(this.closeAndSavetoAll = new GuiButtonLockMenu(2, GUI_ANCHOR_X + MENU_TEXTURE_WIDTH - 41, GUI_ANCHOR_Y + 4, 17, 17, GuiButtonLockMenu.Type.SAVETOALL)); + this.buttonList.add(this.arrowUp = new GuiButtonLockMenu(3, GUI_ANCHOR_X + MENU_TEXTURE_WIDTH - 15, GUI_ANCHOR_Y + 95, 7, 22, GuiButtonLockMenu.Type.ARROWUP)); + this.buttonList.add(this.arrowDown = new GuiButtonLockMenu(4, GUI_ANCHOR_X + MENU_TEXTURE_WIDTH - 15, GUI_ANCHOR_Y + 120, 7, 22, GuiButtonLockMenu.Type.ARROWDOWN)); + + this.buttonList.add(this.copyButton = new GuiButtonLockMenu(5, GUI_ANCHOR_X + 5, GUI_ANCHOR_Y + 4, 17, 17, GuiButtonLockMenu.Type.COPY)); + this.buttonList.add(this.pasteButton = new GuiButtonLockMenu(6, GUI_ANCHOR_X + 24, GUI_ANCHOR_Y + 4, 17, 17, GuiButtonLockMenu.Type.PASTE)); + + textFieldList.clear(); + for (int i = 0; i < MAX_TRUSTEES_ON_PAGE; i ++) { // Add text boxes, line select delete buttons, import current trustees to text boxes. + this.buttonList.add(new GuiButtonLockMenu(i + NUMBER_OF_STATIC_BUTTONS, TEXTBOX_LEFT_ANCHOR + textBoxWidth + 3, (GUI_ANCHOR_Y + 55 + (i * (textBoxHeight + 5))) + 2, 17, 17, GuiButtonLockMenu.Type.REMOVE)); + textFieldList.add(new GuiLockMenuTextField(i, fontRendererObj, TEXTBOX_LEFT_ANCHOR, (GUI_ANCHOR_Y + 55 + (i * (textBoxHeight + 5))), textBoxWidth, textBoxHeight, this)); + textFieldList.get(i).setCanLoseFocus(true); + textFieldList.get(i).setMaxStringLength(16); + } + + for (int i = 0; i < MAX_TRUSTEES_ON_PAGE; i++) { // Add break access buttons (done in separate loop to preserve order of buttonList). + this.buttonList.add(new GuiButtonLockMenu(i + NUMBER_OF_STATIC_BUTTONS + MAX_TRUSTEES_ON_PAGE, TEXTBOX_LEFT_ANCHOR + textBoxWidth + 22, (GUI_ANCHOR_Y + 55 + (i * (textBoxHeight + 5))) + 2, 17, 17, GuiButtonLockMenu.Type.BREAKACCESSOFF)); + } + + this.updateButtons(); + } + + protected void updateButtons() { + numberOfActiveTextboxes = Math.min(currentTrustees.size() - MAX_TRUSTEES_ON_PAGE * currentPage + 1, MAX_TRUSTEES_ON_PAGE); + // Update text fields and break access buttons... + for (int i = 0; i < MAX_TRUSTEES_ON_PAGE; i ++) { + if (i + currentPage * MAX_TRUSTEES_ON_PAGE < currentTrustees.size()) + textFieldList.get(i).setText(currentTrustees.get(i + currentPage * MAX_TRUSTEES_ON_PAGE).getDisplayName()); + else + textFieldList.get(i).setText(""); + textFieldList.get(i).setVisible(i < numberOfActiveTextboxes); + if (i + currentPage * MAX_TRUSTEES_ON_PAGE < currentTrustees.size()) { + boolean hasBreakAccess = currentTrustees.get(i + currentPage * MAX_TRUSTEES_ON_PAGE).hasBreakAccess(); + ((GuiButtonLockMenu) this.buttonList.get(i + NUMBER_OF_STATIC_BUTTONS + MAX_TRUSTEES_ON_PAGE)).setType(hasBreakAccess ? GuiButtonLockMenu.Type.BREAKACCESSON : GuiButtonLockMenu.Type.BREAKACCESSOFF, GuiButtonLockMenu.Texture.INACTIVE); + } + ((GuiButtonLockMenu) this.buttonList.get(i + NUMBER_OF_STATIC_BUTTONS)).visible = i < numberOfActiveTextboxes; + ((GuiButtonLockMenu) this.buttonList.get(i + NUMBER_OF_STATIC_BUTTONS)).showButton = i < numberOfActiveTextboxes; + ((GuiButtonLockMenu) this.buttonList.get(i + NUMBER_OF_STATIC_BUTTONS + MAX_TRUSTEES_ON_PAGE)).visible = i < numberOfActiveTextboxes; + ((GuiButtonLockMenu) this.buttonList.get(i + NUMBER_OF_STATIC_BUTTONS + MAX_TRUSTEES_ON_PAGE)).showButton = i < numberOfActiveTextboxes; + } + + // Add an extra text box at the bottom if the current one at the bottom has text in it and the page is not yet full. + if (!textFieldList.get(numberOfActiveTextboxes - 1).isFocused()) { // Get the last text box on the page... + if (!textFieldList.get(numberOfActiveTextboxes - 1).getText().equalsIgnoreCase("")) { // If the text box is not empty... + if (numberOfActiveTextboxes < MAX_TRUSTEES_ON_PAGE) { // Add another text box if there is room on the page. + numberOfActiveTextboxes++; + } + } + } + + this.lockUnlockButton.showButton = true; + this.lockUnlockButton.visible = true; + this.lockUnlockButton.setType(getLocked() ? GuiButtonLockMenu.Type.LOCKED : GuiButtonLockMenu.Type.UNLOCKED, this.lockUnlockButton.getTexture()); + this.closeButton.showButton = true; + this.closeButton.visible = true; + this.closeAndSavetoAll.showButton = true; + this.closeAndSavetoAll.visible = true; + this.arrowUp.showButton = currentPage != 0; + this.arrowUp.visible = this.arrowUp.showButton; + this.arrowDown.showButton = numberOfActiveTextboxes == MAX_TRUSTEES_ON_PAGE && !textFieldList.get(MAX_TRUSTEES_ON_PAGE - 1).getText().isEmpty(); + this.arrowDown.visible = this.arrowDown.showButton; + this.copyButton.visible = true; + this.copyButton.showButton = true; + this.pasteButton.visible = true; + this.pasteButton.showButton = true; + } + + @Override + public void drawScreen(int mouseX, int mouseY, float par3) { + // Draw background. + mc.renderEngine.bindTexture(new ResourceLocation(Info.resourceLocation, Info.guiPrefix + "gui_lockmenu.png")); + this.drawTexturedModalRect(GUI_ANCHOR_X, GUI_ANCHOR_Y, 0, 0, MENU_TEXTURE_WIDTH, MENU_TEXTURE_HEIGHT); + super.drawScreen(mouseX, mouseY, par3); + for (int i = 0; i < numberOfActiveTextboxes; i++) { + textFieldList.get(i).drawTextBox(); + } + fontRendererObj.drawString(StatCollector.translateToLocal("lockmenu.Title_Trusted_Players.name"), GUI_ANCHOR_MID_X - (fontRendererObj.getStringWidth(StatCollector.translateToLocal("lockmenu.Title_Trusted_Players.name")) / 2), GUI_ANCHOR_Y + 40, -16777216); + if (lockUnlockButton.getTexture() == GuiButtonLockMenu.Texture.ACTIVE) + if (getLocked()) + drawHoveringText(Collections.singletonList(StatCollector.translateToLocal("lockmenu.Unlock.name")), mouseX, mouseY, fontRendererObj); + else + drawHoveringText(Collections.singletonList(StatCollector.translateToLocal("lockmenu.Lock.name")), mouseX, mouseY, fontRendererObj); + if (closeButton.getTexture() == GuiButtonLockMenu.Texture.ACTIVE) + drawHoveringText(Collections.singletonList(StatCollector.translateToLocal("lockmenu.Save and Close.name")), mouseX, mouseY, fontRendererObj); + if (closeAndSavetoAll.getTexture() == GuiButtonLockMenu.Texture.ACTIVE) + drawHoveringText(Collections.singletonList(StatCollector.translateToLocal("lockmenu.Save To All Cars in Consist.name")), mouseX, mouseY, fontRendererObj); + } + + @Override + protected void actionPerformed(GuiButton clickedButton) { + if (clickedButton.enabled) { + editingPlayer.playSound("random.click", 1f, 1f); + switch (clickedButton.id) { + case 0: // Main Lock Button + setLocked(!getLocked()); + exportTrustedPlayers(); + updateButtons(); + break; + case 1: // Save and Close Button + sendUpdatePacket(false); + this.mc.thePlayer.closeScreen(); + break; + case 2: + sendUpdatePacket(true); + this.mc.thePlayer.closeScreen(); + break; + case 3: + case 4: + if (clickedButton.id == 3) { + currentPage--; + } else { + currentPage++; + } + numberOfActiveTextboxes = currentTrustees.isEmpty() ? 1 : Math.min(currentTrustees.size(), MAX_TRUSTEES_ON_PAGE); + updateButtons(); + case 5: // Copy + StringBuilder concatenatedTrustees = new StringBuilder(); + for (TrustedPlayer trustee : currentTrustees) { + concatenatedTrustees.append(trustee.getDisplayName()).append(",").append(trustee.hasBreakAccess()).append(";"); + } + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(concatenatedTrustees.toString()), null); + break; + case 6: // Paste + try { + String fromClipboard = (String) Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.stringFlavor); + String[] splitTrustees = fromClipboard.split(";"); + if (splitTrustees.length <= ConfigHandler.MAX_TRUSTEES_ON_PADLOCK) { + currentTrustees.clear(); + String[] splitTrustee; + for (String trustee : splitTrustees) { + splitTrustee = trustee.split(","); + if (splitTrustee.length > 1) + currentTrustees.add(new TrustedPlayer(splitTrustee[0], Boolean.parseBoolean(splitTrustee[1]))); + else + break; + } + numberOfActiveTextboxes = currentTrustees.isEmpty() ? 1 : Math.min(currentTrustees.size(), MAX_TRUSTEES_ON_PAGE); + updateButtons(); + } + } catch (UnsupportedFlavorException | IOException e) { + throw new RuntimeException(e); + } + default: + if (clickedButton.id >= NUMBER_OF_STATIC_BUTTONS && clickedButton.id < MAX_TRUSTEES_ON_PAGE + NUMBER_OF_STATIC_BUTTONS) { // Line Select Delete Buttons + int trusteeToBeRemoved = (clickedButton.id - NUMBER_OF_STATIC_BUTTONS) + currentPage * MAX_TRUSTEES_ON_PAGE; + if (trusteeToBeRemoved < currentTrustees.size()) + currentTrustees.remove(trusteeToBeRemoved); + updateButtons(); + } else if (clickedButton.id > MAX_TRUSTEES_ON_PAGE + NUMBER_OF_STATIC_BUTTONS - 1) { // Break Access Buttons + GuiButtonLockMenu button = ((GuiButtonLockMenu) clickedButton); + if (button.getType() == GuiButtonLockMenu.Type.BREAKACCESSOFF) + button.setType(GuiButtonLockMenu.Type.BREAKACCESSON, button.getTexture()); + else + button.setType(GuiButtonLockMenu.Type.BREAKACCESSOFF, button.getTexture()); + updateTrustee((clickedButton.id - MAX_TRUSTEES_ON_PAGE - NUMBER_OF_STATIC_BUTTONS) + currentPage * MAX_TRUSTEES_ON_PAGE); + } + } + } + } + @Override + public void onGuiClosed() { + super.onGuiClosed(); + } + + @Override + public void mouseClicked(int x, int y, int par3) { + super.mouseClicked(x, y, par3); + for (GuiTextField textField : textFieldList) { + textField.mouseClicked(x, y, par3); + } + } + + @Override + public void handleMouseInput() { + int mouseEvent = Mouse.getEventDWheel(); + if (mouseEvent != 0) { + if (mouseEvent > 0) { // Scroll up. + if (currentPage != 0) { + currentPage--; + } + } else { // Scroll down. + if (arrowDown.visible) { + currentPage++; + } + } + updateButtons(); + } + super.handleMouseInput(); + } + + @Override + protected void keyTyped(char eventChar, int eventKey) { + if (eventKey == 1) { // If ESC... + this.mc.thePlayer.closeScreen(); + } + for (int i = 0; i < MAX_TRUSTEES_ON_PAGE; i++) { + GuiTextField textField = textFieldList.get(i); + if (textField.isFocused()) { + textField.textboxKeyTyped(eventChar, eventKey); + if (eventChar == '\r') { + textField.setFocused(false); + if (textFieldList.size() > i + 1) + textFieldList.get(i + 1).setFocused(true); + else { + currentPage++; + textFieldList.get(0).setFocused(true); + } + updateButtons(); + } + break; + } + } + } + + protected List exportTrustedPlayers() { + List newTrustees = new ArrayList<>(currentTrustees); + for (int i = 0; i < numberOfActiveTextboxes; i++) { + if (!textFieldList.get(i).getText().isEmpty()) { + if (i + currentPage * MAX_TRUSTEES_ON_PAGE >= newTrustees.size()) { + newTrustees.add(i + currentPage * MAX_TRUSTEES_ON_PAGE, new TrustedPlayer(textFieldList.get(i).getText().trim(), ((GuiButtonLockMenu) this.buttonList.get(i + NUMBER_OF_STATIC_BUTTONS + MAX_TRUSTEES_ON_PAGE)).getType() == GuiButtonLockMenu.Type.BREAKACCESSON)); + } else { + newTrustees.set(i + currentPage * MAX_TRUSTEES_ON_PAGE, new TrustedPlayer(textFieldList.get(i).getText().trim(), ((GuiButtonLockMenu) this.buttonList.get(i + NUMBER_OF_STATIC_BUTTONS + MAX_TRUSTEES_ON_PAGE)).getType() == GuiButtonLockMenu.Type.BREAKACCESSON)); + } + } + } + currentTrustees.clear(); + currentTrustees.addAll(newTrustees); + return newTrustees; + } + + public void updateTrustee(int trusteeIndex) { + int indexOnPage = trusteeIndex - currentPage * MAX_TRUSTEES_ON_PAGE; + if (!textFieldList.get(indexOnPage).getText().isEmpty()) { + if (trusteeIndex >= currentTrustees.size()) { + currentTrustees.add(trusteeIndex, new TrustedPlayer(textFieldList.get(indexOnPage).getText().trim(), ((GuiButtonLockMenu) this.buttonList.get(indexOnPage + NUMBER_OF_STATIC_BUTTONS + MAX_TRUSTEES_ON_PAGE)).getType() == GuiButtonLockMenu.Type.BREAKACCESSON)); + } else { + currentTrustees.set(trusteeIndex, new TrustedPlayer(textFieldList.get(indexOnPage).getText().trim(), ((GuiButtonLockMenu) this.buttonList.get(indexOnPage + NUMBER_OF_STATIC_BUTTONS + MAX_TRUSTEES_ON_PAGE)).getType() == GuiButtonLockMenu.Type.BREAKACCESSON)); + } + } + } + + public abstract boolean getLocked(); + public abstract void setLocked(boolean locked); + public abstract void sendUpdatePacket(boolean propagate); + public List getTextFieldList() { + return textFieldList; + } + public int getCurrentPage() { return currentPage; } + +} diff --git a/src/main/java/train/client/gui/GuiLockMenuTextField.java b/src/main/java/train/client/gui/GuiLockMenuTextField.java new file mode 100644 index 0000000000..c90911f002 --- /dev/null +++ b/src/main/java/train/client/gui/GuiLockMenuTextField.java @@ -0,0 +1,25 @@ +package train.client.gui; + +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiTextField; + +public class GuiLockMenuTextField extends GuiTextField { + private final GuiLockMenuAbstract guiClass; + private final int textFieldID; + public GuiLockMenuTextField(int textFieldID, FontRenderer p_i1032_1_, int p_i1032_2_, int p_i1032_3_, int p_i1032_4_, int p_i1032_5_, GuiLockMenuAbstract guiClass) { + super(p_i1032_1_, p_i1032_2_, p_i1032_3_, p_i1032_4_, p_i1032_5_); + this.textFieldID = textFieldID; + this.guiClass = guiClass; + } + + @Override + public void setFocused(boolean focused) { + if (super.isFocused() && !focused) { // If losing focus... + super.setFocused(false); + // Update the trustee list whenever the text box is deselected. + guiClass.updateTrustee(textFieldID + guiClass.getCurrentPage() * guiClass.MAX_TRUSTEES_ON_PAGE); + guiClass.updateButtons(); + } + super.setFocused(focused); + } +} diff --git a/src/main/java/train/client/gui/GuiLoco2.java b/src/main/java/train/client/gui/GuiLoco2.java index a698def1ad..df74a2f17c 100644 --- a/src/main/java/train/client/gui/GuiLoco2.java +++ b/src/main/java/train/client/gui/GuiLoco2.java @@ -17,6 +17,7 @@ import train.common.api.*; import train.common.core.network.*; import train.common.inventory.InventoryLoco; +import train.common.library.GuiIDs; import train.common.library.Info; import java.util.Collections; @@ -85,7 +86,14 @@ public void initGui() { if (!loco.getTrainLockedFromPacket()) { this.buttonList.add(this.buttonLock = new GuiButton(3, buttonPosX + 108, buttonPosY - 10, 67, 10, "Unlocked")); } else { - this.buttonList.add(this.buttonLock = new GuiButton(3, buttonPosX + 108, buttonPosY - 10, 67, 10, "Locked")); + EntityPlayer engineer = ((EntityPlayer) loco.seats.get(0).getPassenger()); + if (loco.getTrainOwner().equalsIgnoreCase(engineer.getDisplayName())) + this.buttonList.add(this.buttonLock = new GuiButton(3, buttonPosX + 108, buttonPosY - 10, 67, 10, "Locked")); + else if (loco.isPlayerTrusted(engineer.getDisplayName())) + if (loco.isPlayerTrustedToBreak(engineer.getDisplayName())) + this.buttonList.add(this.buttonLock = new GuiButton(3, buttonPosX + 104, buttonPosY - 10, 71, 10, "Trusted+")); + else + this.buttonList.add(this.buttonLock = new GuiButton(3, buttonPosX + 106, buttonPosY - 10, 69, 10, "Trusted")); } if (!(loco instanceof SteamTrain)) { @@ -172,15 +180,22 @@ protected void actionPerformed(GuiButton guibutton) { if (guibutton.id == 3) { if (!loco.isNotOwner()) { if ((!loco.getTrainLockedFromPacket())) { - Traincraft.lockChannel.sendToServer(new PacketSetTrainLockedToClient(true, loco.getEntityId())); - loco.locked = true; - guibutton.displayString = "Locked"; - this.initGui(); - } else { - Traincraft.lockChannel.sendToServer(new PacketSetTrainLockedToClient(false, loco.getEntityId())); - loco.locked = false; - guibutton.displayString = "UnLocked"; - this.initGui(); + if (!isShiftKeyDown()) { + Traincraft.lockChannel.sendToServer(new PacketSetTrainLockedToClient(true, loco.getTrustedList(), loco.getEntityId(), false)); + loco.locked = true; + guibutton.displayString = "Locked"; + this.initGui(); + } else + ((EntityPlayer) loco.seats.get(0).riddenByEntity).openGui(Traincraft.instance, GuiIDs.LOCK_MENU, ((EntityPlayer) loco.seats.get(0).riddenByEntity).getEntityWorld(), loco.getEntityId(), -1, (int) loco.seats.get(0).riddenByEntity.posZ); + } + else { + if (!isShiftKeyDown()) { + Traincraft.lockChannel.sendToServer(new PacketSetTrainLockedToClient(false, loco.getTrustedList(), loco.getEntityId(), false)); + loco.locked = false; + guibutton.displayString = "Unlocked"; + this.initGui(); + } else + ((EntityPlayer) loco.seats.get(0).riddenByEntity).openGui(Traincraft.instance, GuiIDs.LOCK_MENU, ((EntityPlayer) loco.seats.get(0).riddenByEntity).getEntityWorld(), loco.getEntityId(), -1, (int) loco.seats.get(0).riddenByEntity.posZ); } } else { getEntityPlayer().addChatMessage(new ChatComponentText("You are not the owner")); diff --git a/src/main/java/train/client/gui/GuiTender.java b/src/main/java/train/client/gui/GuiTender.java index 34e899eddd..1253e01d5a 100644 --- a/src/main/java/train/client/gui/GuiTender.java +++ b/src/main/java/train/client/gui/GuiTender.java @@ -16,6 +16,7 @@ import train.common.api.Tender; import train.common.core.network.PacketSetTrainLockedToClient; import train.common.inventory.InventoryTender; +import train.common.library.GuiIDs; import train.common.library.Info; import java.util.Collections; @@ -47,7 +48,13 @@ public void initGui() { if (!tender.getTrainLockedFromPacket()) { this.buttonList.add(this.buttonLock = new GuiButton(3, var1 + 124, var2 - 10, 51, 10, "Unlocked")); } else { - this.buttonList.add(this.buttonLock = new GuiButton(3, var1 + 130, var2 - 10, 43, 10, "Locked")); + if (tender.getTrainOwner().equalsIgnoreCase(player.getDisplayName())) + this.buttonList.add(this.buttonLock = new GuiButton(3, var1 + 130, var2 - 10, 43, 10, "Locked")); + else if (tender.isPlayerTrusted(player.getDisplayName())) + if (tender.isPlayerTrustedToBreak(player.getDisplayName())) + this.buttonList.add(this.buttonLock = new GuiButton(3, var1 + 125, var2 - 10, 48, 10, "Trusted+")); + else + this.buttonList.add(this.buttonLock = new GuiButton(3, var1 + 128, var2 - 10, 45, 10, "Trusted")); } if (tender.seats.size() > 1) { this.buttonList.add(this.buttonSeatManager = new GUIButton((int)guiLeft+166,(int)guiTop+166, 18,18) { @@ -83,8 +90,12 @@ protected void actionPerformed(GuiButton guibutton) { if (lis3 != null && !lis3.isEmpty()) { for (Object entity : lis3) { if (entity instanceof EntityPlayer) { - Traincraft.lockChannel - .sendToServer(new PacketSetTrainLockedToClient(true, tender.getEntityId())); + if (!isShiftKeyDown()) { + Traincraft.lockChannel.sendToServer(new PacketSetTrainLockedToClient(true, tender.getTrustedList(), tender.getEntityId(), false)); + } else { + this.mc.thePlayer.closeScreen(); + player.openGui(Traincraft.instance, GuiIDs.LOCK_MENU, player.getEntityWorld(), tender.getEntityId(), -1, (int) tender.posZ); + } } } } @@ -98,8 +109,12 @@ protected void actionPerformed(GuiButton guibutton) { if (lis3 != null && !lis3.isEmpty()) { for (Object entity : lis3) { if (entity instanceof EntityPlayer) { - Traincraft.lockChannel - .sendToServer(new PacketSetTrainLockedToClient(false, tender.getEntityId())); + if (!isShiftKeyDown()) { + Traincraft.lockChannel.sendToServer(new PacketSetTrainLockedToClient(false, tender.getTrustedList(), tender.getEntityId(), false)); + } else { + this.mc.thePlayer.closeScreen(); + player.openGui(Traincraft.instance, GuiIDs.LOCK_MENU, player.getEntityWorld(), tender.getEntityId(), -1, (int) tender.posZ); + } } } } @@ -158,7 +173,18 @@ protected void drawCreativeTabHoveringText(String str, int t, int g) { fontRendererObj.drawStringWithShadow(str, startX, startY, -1); fontRendererObj.drawStringWithShadow("only its owner can open", startX, startY + 10, -1); fontRendererObj.drawStringWithShadow("the GUI and destroy it.", startX, startY + 20, -1); - fontRendererObj.drawStringWithShadow("Current state: " + (tender.getTrainLockedFromPacket() ? "Locked" : "Unlocked"), startX, startY + 30, -1); + String state = ""; + if (tender.getTrainLockedFromPacket()) { + if (tender.getTrainOwner().equalsIgnoreCase(player.getDisplayName())) + state = "Locked"; + else if (tender.isPlayerTrusted(player.getDisplayName())) + if (tender.isPlayerTrustedToBreak(player.getDisplayName())) + state = "Trusted Access+"; + else + state = "Trusted Access"; + } else + state = "Unlocked"; + fontRendererObj.drawStringWithShadow("Current state: " + state, startX, startY + 30, -1); fontRendererObj.drawStringWithShadow("Owner: " + tender.getTrainOwner().trim(), startX, startY + 40, -1); } diff --git a/src/main/java/train/common/api/AbstractTrains.java b/src/main/java/train/common/api/AbstractTrains.java index 587bf05689..13c54743c2 100644 --- a/src/main/java/train/common/api/AbstractTrains.java +++ b/src/main/java/train/common/api/AbstractTrains.java @@ -28,6 +28,7 @@ import net.minecraft.world.World; import net.minecraftforge.common.ForgeChunkManager; import net.minecraftforge.common.ForgeChunkManager.Ticket; +import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidStack; @@ -41,6 +42,7 @@ import train.common.core.handlers.ConfigHandler; import train.common.core.handlers.TrainHandler; import train.common.core.util.DepreciatedUtil; +import train.common.entity.TrustedPlayer; import train.common.items.ItemChunkLoaderActivator; import train.common.items.ItemRollingStock; import train.common.items.ItemWrench; @@ -129,6 +131,10 @@ public TrainRenderRecord getRender() { * Whether this train is locked and can only be used by the Owner */ public boolean locked = false; + /** + *

List of players trusted to use the train

+ */ + private List trustedList = new ArrayList<>(); /** * The owner of the train: The user who spawned it */ @@ -223,13 +229,22 @@ public String getTrainType(){ } /** - * this is basically NBT for entity spawn, to keep data between client and server in sync because some data is not automatically shared. + *

This method is called on the client side when an entity is being loaded in. The additionalData buffer is sent from the server + * and is populated by the server using the writeSpawnData method.

+ *

"this is basically NBT for entity spawn, to keep data between client and server in sync because some data is not automatically shared."

+ * @param additionalData The packet data stream */ @Override public void readSpawnData(ByteBuf additionalData) { locked = additionalData.readBoolean(); } + /** + *

This method is called on the server side when a connected client is loading the entity. Data written + * to the ByteBuffer will be synced with the client and available to the client through the readSpawnData method.

+ *

"this is basically NBT for entity spawn, to keep data between client and server in sync because some data is not automatically shared."

+ * @param buffer The packet data stream + */ @Override public void writeSpawnData(ByteBuf buffer) { buffer.writeBoolean(locked); @@ -384,6 +399,7 @@ protected void writeEntityToNBT(NBTTagCompound nbttagcompound) { nbttagcompound.setString("theOwner", trainOwner); nbttagcompound.setBoolean("locked", locked); nbttagcompound.setString("theCreator", trainCreator); + exportTrustedListToNBT(nbttagcompound); nbttagcompound.setString("theName", trainName); nbttagcompound.setInteger("uniqueID", uniqueID); //nbttagcompound.setInteger("uniqueIDs",uniqueIDs); @@ -404,6 +420,7 @@ protected void writeEntityToNBT(NBTTagCompound nbttagcompound) { if (acceptsOverlayTextures) { nbttagcompound.setTag("overlayTextureConfigTag", overlayTextureContainer.getOverlayConfigTag()); } + exportTrustedListToNBT(nbttagcompound); } @Override @@ -420,6 +437,7 @@ protected void readEntityFromNBT(NBTTagCompound nbttagcompound) { this.locked = nbttagcompound.getBoolean("locked"); setFlag(8, locked); trainCreator = nbttagcompound.getString("theCreator"); + importTrustedListFromNBT(nbttagcompound); trainName = nbttagcompound.getString("theName"); uniqueID = nbttagcompound.getInteger("uniqueID"); //uniqueIDs = nbttagcompound.getInteger("uniqueIDs"); @@ -495,6 +513,7 @@ protected void setUniqueIDToItem(ItemStack stack) { } if (this.uniqueID != -1) stack.getTagCompound().setInteger("uniqueID", this.uniqueID); if (this.trainCreator != null && !this.trainCreator.isEmpty()) stack.getTagCompound().setString("trainCreator", this.trainCreator); + exportTrustedListToNBT(stack.getTagCompound()); stack.getTagCompound().setString("trainColor", this.getColor()); // Only save the overlay configuration to NBT if it exists. No need to store an empty configuration in NBT as it will be initialized as the default when the entity spawns in. if (this.acceptsOverlayTextures && this.getOverlayTextureContainer().getType() != OverlayTextureManager.Type.NONE) { @@ -574,9 +593,10 @@ protected boolean canBeDestroyedByPlayer(DamageSource damagesource) { ((EntityPlayer) damagesource.getEntity()).inventory.getCurrentItem() != null && ((EntityPlayer) damagesource.getEntity()).inventory.getCurrentItem().getItem() instanceof ItemWrench) { - ((EntityPlayer) damagesource.getEntity()).addChatMessage(new ChatComponentText("Removing the train using OP permission")); + ((EntityPlayer) damagesource.getEntity()).addChatMessage(new ChatComponentText("Removing the train using OP permission.")); return false; - } else if (!((EntityPlayer) damagesource.getEntity()).getDisplayName().equalsIgnoreCase(this.trainOwner)) { + } + else if (!((EntityPlayer) damagesource.getEntity()).getDisplayName().equalsIgnoreCase(this.trainOwner) && !(this.isPlayerTrustedToBreak(((EntityPlayerMP) damagesource.getEntity()).getDisplayName()))) { ((EntityPlayer) damagesource.getEntity()).addChatMessage(new ChatComponentText("You are not the owner!")); return true; } @@ -735,6 +755,80 @@ public void updateLinks(){ } } + /** + * @return Returns String ArrayList of trusted players' usernames. + */ + public List getTrustedList() { + return trustedList; + } + public void setTrustedList(List trustedList) { this.trustedList = trustedList; } + + /** + *

Returns whether a player is trusted to a piece of rolling stock.

+ * @param displayName Case-insensitive display name of player. + * @return True if the player is trusted, false if the player is not trusted. + */ + public boolean isPlayerTrusted(String displayName) { + for (TrustedPlayer trustedPlayer : this.getTrustedList()) { + if (trustedPlayer.getDisplayName().equalsIgnoreCase(displayName)) { + return true; + } + } + return false; + } + + /** + *

Returns whether a player is trusted to break a piece of rolling stock.

+ * @param displayName Case-insensitive display name of player. + * @return True if player has break access, false if player does not have break access. + */ + public boolean isPlayerTrustedToBreak(String displayName) { + for (TrustedPlayer trustedPlayer : this.getTrustedList()) { + if (trustedPlayer.getDisplayName().equalsIgnoreCase(displayName)) { + return trustedPlayer.hasBreakAccess(); + } + } + return false; + } + + /** + *

Export trusted players to NBT tag for data saving.

+ * @param nbttagcompound NBT tag into which to write trusted list. + */ + public void exportTrustedListToNBT(NBTTagCompound nbttagcompound) { + if (!trustedList.isEmpty()) { + NBTTagList trustedList = new NBTTagList(); + for (TrustedPlayer trustedPlayer : this.trustedList) { + NBTTagCompound trustedPlayerTag = new NBTTagCompound(); + trustedPlayerTag.setString("playerName", trustedPlayer.getDisplayName()); + trustedPlayerTag.setBoolean("breakAccess", trustedPlayer.hasBreakAccess()); + trustedList.appendTag(trustedPlayerTag); + } + nbttagcompound.setTag("trustedList", trustedList); + nbttagcompound.setString("trustedListPreviousOwner", getTrainOwner()); + } + } + + /** + *

Import a trusted player list from a given NBT tag.

+ * @param nbttagcompound NBT tag from which to import trusted list. + */ + public void importTrustedListFromNBT(NBTTagCompound nbttagcompound) { + if (nbttagcompound.hasKey("trustedList")) { + NBTTagList trustedList = nbttagcompound.getTagList("trustedList", Constants.NBT.TAG_COMPOUND); + this.trustedList.clear(); + for (int i = 0; i < trustedList.tagCount(); i++) { + if (!trustedList.getCompoundTagAt(i).getString("playerName").equalsIgnoreCase(trainOwner)) // Check to ensure we're not adding the current owner to the trusted list... + this.trustedList.add(new TrustedPlayer(trustedList.getCompoundTagAt(i).getString("playerName"), trustedList.getCompoundTagAt(i).getBoolean("breakAccess"))); + } + if (nbttagcompound.hasKey("trustedListPreviousOwner")) { // If the previous owner is not the one who placed down the piece of rolling stock... + if (!nbttagcompound.getString("trustedListPreviousOwner").equalsIgnoreCase(trainOwner)) { + getTrustedList().add(new TrustedPlayer(nbttagcompound.getString("trustedListPreviousOwner"), true)); + } + } + } + } + /** * @author 02skaplan *

Called to setup the overlay texture manager for the given AbstractTrain. It is recommended diff --git a/src/main/java/train/common/api/EntityRollingStock.java b/src/main/java/train/common/api/EntityRollingStock.java index f1185fc68c..4f37039207 100644 --- a/src/main/java/train/common/api/EntityRollingStock.java +++ b/src/main/java/train/common/api/EntityRollingStock.java @@ -52,7 +52,9 @@ import train.common.core.util.DepreciatedUtil; import train.common.entity.CollisionBox; import train.common.entity.EntityHitbox; +import train.common.entity.TrustedPlayer; import train.common.entity.rollingStockOld.special.EntityTracksBuilder; +import train.common.items.ItemPadlock; import train.common.items.ItemPaintbrushThing; import train.common.items.ItemRollingStock; import train.common.items.ItemWrench; @@ -223,20 +225,39 @@ public Entity[] getParts(){ } /** - * this is basically NBT for entity spawn, to keep data between client and server in sync because some data is not automatically shared. + *

This method is called on the client side when an entity is being loaded in. The additionalData buffer is sent from the server + * and is populated by the server using the writeSpawnData method.

+ *

"this is basically NBT for entity spawn, to keep data between client and server in sync because some data is not automatically shared."

+ * @param additionalData The packet data stream */ @Override public void readSpawnData(ByteBuf additionalData) { isBraking = additionalData.readBoolean(); setTrainLockedFromPacket(additionalData.readBoolean()); + int numOfTrustedPlayers = additionalData.readInt(); + for (int i = 0; i < numOfTrustedPlayers; i++) { + getTrustedList().add(new TrustedPlayer(ByteBufUtils.readUTF8String(additionalData), additionalData.readBoolean())); + } if (additionalData.readBoolean()) { // If accepts overlay textures... getOverlayTextureContainer().importFromConfigTag(ByteBufUtils.readTag(additionalData)); } } + + /** + *

This method is called on the server side when a connected client is loading the entity. Data written + * to the ByteBuffer will be synced with the client and available to the client through the readSpawnData method.

+ *

"this is basically NBT for entity spawn, to keep data between client and server in sync because some data is not automatically shared."

+ * @param buffer The packet data stream + */ @Override public void writeSpawnData(ByteBuf buffer) { buffer.writeBoolean(isBraking); buffer.writeBoolean(getTrainLockedFromPacket()); + buffer.writeInt(getTrustedList().size()); + for (TrustedPlayer player : getTrustedList()) { + ByteBufUtils.writeUTF8String(buffer, player.getDisplayName()); + buffer.writeBoolean(player.hasBreakAccess()); + } buffer.writeBoolean(acceptsOverlayTextures()); if (acceptsOverlayTextures()) { ByteBufUtils.writeTag(buffer, getOverlayTextureContainer().getOverlayConfigTag()); @@ -511,7 +532,7 @@ public boolean isLockedAndNotOwner(int player) { return false; } if (this.getTrainLockedFromPacket()) { - return !((EntityPlayer) p).getDisplayName().equalsIgnoreCase(this.getTrainOwner()); + return !((EntityPlayer) p).getDisplayName().equalsIgnoreCase(this.getTrainOwner()) && !isPlayerTrusted(((EntityPlayer) p).getDisplayName()); } return false; } @@ -1187,16 +1208,16 @@ public boolean interactFirst(EntityPlayer entityplayer) { playerEntity = entityplayer; ItemStack itemstack = entityplayer.inventory.getCurrentItem(); - if (this.getTrainLockedFromPacket() && !worldObj.isRemote && - !playerEntity.getDisplayName().toLowerCase().equals(this.trainOwner.toLowerCase())) { - if (!canBeRiddenWhileLocked(this)) { - entityplayer.addChatMessage(new ChatComponentText("Train is locked")); + if (this.getTrainLockedFromPacket() && !worldObj.isRemote) { + boolean isTrustedPlayer = isPlayerTrusted(playerEntity.getDisplayName()); + if (!playerEntity.getDisplayName().equalsIgnoreCase(this.getTrainOwner()) && !canBeRiddenWhileLocked(this) && !isTrustedPlayer) { + if (!worldObj.isRemote) entityplayer.addChatMessage(new ChatComponentText("Train is locked by " + this.getTrainOwner() + ".")); return true; - } else if (entityplayer.inventory.getCurrentItem() != null && entityplayer.inventory.getCurrentItem().getItem() instanceof ItemDye && (this instanceof Locomotive)) { - entityplayer.addChatMessage(new ChatComponentText("Train is locked")); + } + else if (!playerEntity.getDisplayName().equalsIgnoreCase(this.getTrainOwner()) && entityplayer.inventory.getCurrentItem() != null && entityplayer.inventory.getCurrentItem().getItem() instanceof ItemDye && (this instanceof Locomotive) && !isTrustedPlayer) { + if (!worldObj.isRemote) entityplayer.addChatMessage(new ChatComponentText("Train is locked by " + this.getTrainOwner() + ".")); return true; } - } @@ -1277,6 +1298,14 @@ public boolean interactFirst(EntityPlayer entityplayer) { return true; } } + } else if (entityplayer.isSneaking() && itemstack.getItem() instanceof ItemPadlock) { + if (getTrainOwner().equalsIgnoreCase(entityplayer.getDisplayName())) { + entityplayer.openGui(Traincraft.instance, GuiIDs.LOCK_MENU, entityplayer.getEntityWorld(), this.getEntityId(), -1, (int) this.posZ); + return true; + } else { + if (!worldObj.isRemote) entityplayer.addChatMessage(new ChatComponentText("Train is locked by " + this.getTrainOwner() + ".")); + return false; + } } } @@ -1685,7 +1714,7 @@ public boolean shouldRiderSit(){ */ public boolean getPermissions(EntityPlayer player, boolean driverOnly) { //make sure the player is not null, and be sure that driver only rules are applied. - if (player ==null){ + if (player ==null) { return false; } else if (driverOnly && (!(player.ridingEntity instanceof EntitySeat) || ! ((EntitySeat) player.ridingEntity).isControlSeat())){ return false; @@ -1693,7 +1722,9 @@ public boolean getPermissions(EntityPlayer player, boolean driverOnly) { //be sure operators and owners can do whatever if ((player.capabilities.isCreativeMode && player.canCommandSenderUseCommand(2, "")) - || (this.getOwner()!=null && this.getOwner() == player.getGameProfile())) { + || (this.getOwner()!=null && this.getOwner() == player.getGameProfile()) + || isPlayerTrusted(player.getDisplayName()) + || canBeRiddenWhileLocked(this)) { return true; } diff --git a/src/main/java/train/common/core/handlers/ConfigHandler.java b/src/main/java/train/common/core/handlers/ConfigHandler.java index dc85488193..b574275b64 100644 --- a/src/main/java/train/common/core/handlers/ConfigHandler.java +++ b/src/main/java/train/common/core/handlers/ConfigHandler.java @@ -51,6 +51,7 @@ public class ConfigHandler { public static boolean TRACK_OVERLAP; public static boolean ENABLE_SLOPE_ACCELERATION; + public static int MAX_TRUSTEES_ON_PADLOCK; public static void init(File configFile) { @@ -104,6 +105,7 @@ public static void init(File configFile) { ALLOW_ATO_ON_STEAMERS = cf.get(CATEGORY_GENERAL, "ALLOW_ATO_ON_STEAMERS", false, "Allows Minecraft Train Control's ATO system to be used on steam trains").getBoolean(true); PAINTBRUSH_DEFAULT_LOW_PERFORMANCE_MODE = cf.get(CATEGORY_GENERAL, "PAINTBRUSH_DEFAULT_LOW_PERFORMANCE_MODE", false, "Defaults to low performance mode in paintbrush menu.").getBoolean(false); ENABLE_SLOPE_ACCELERATION = cf.get(CATEGORY_GENERAL,"ENABLE_SLOPE_ACCELERATION",true,"Defaults to true").getBoolean(true); + MAX_TRUSTEES_ON_PADLOCK = cf.get(CATEGORY_GENERAL, "MAX_TRUSTEES_ON_PADLOCK", false, "Maximum number of trustees allowed in the padlock menu.").getInt(30); PUSHABLE_ROLLINGSTOCK = cf.get(CATEGORY_GENERAL, "ENABLE_PUSHING_ROLLINGSTOCK", true, "Defaults to true").getBoolean(true); } catch (Exception e) { diff --git a/src/main/java/train/common/core/handlers/PacketHandler.java b/src/main/java/train/common/core/handlers/PacketHandler.java index 3115ac7ed4..49f60ff581 100644 --- a/src/main/java/train/common/core/handlers/PacketHandler.java +++ b/src/main/java/train/common/core/handlers/PacketHandler.java @@ -88,6 +88,8 @@ public static void init(){ PacketTextureOverlayConfig.class, 11, Side.SERVER); Traincraft.overlayTextureChannel.registerMessage(PacketTextureOverlayConfig.Handler.class, PacketTextureOverlayConfig.class, 12, Side.CLIENT); + Traincraft.lockChannel.registerMessage(PacketSetTrainLockedToClient.Handler.class, + PacketSetTrainLockedToClient.class, 13, Side.CLIENT); Traincraft.rollingStockLightsChannel.registerMessage(PacketRollingStockLights.Handler.class, PacketRollingStockLights.class, 19, Side.SERVER); diff --git a/src/main/java/train/common/core/network/PacketHandler.java b/src/main/java/train/common/core/network/PacketHandler.java index f96134f7cd..3d296ee2ff 100644 --- a/src/main/java/train/common/core/network/PacketHandler.java +++ b/src/main/java/train/common/core/network/PacketHandler.java @@ -44,6 +44,8 @@ public static void init() { 4, Side.SERVER); Traincraft.lockChannel.registerMessage(PacketSetTrainLockedToClient.Handler.class, PacketSetTrainLockedToClient.class, 5, Side.SERVER); + Traincraft.lockChannel.registerMessage(PacketSetTrainLockedToClient.Handler.class, + PacketSetTrainLockedToClient.class, 10, Side.CLIENT); Traincraft.ignitionChannel.registerMessage(PacketSetLocoTurnedOn.Handler.class, PacketSetLocoTurnedOn.class, 6, Side.SERVER); Traincraft.modChannel.registerMessage(PacketLantern.Handler.class, PacketLantern.class, 7, diff --git a/src/main/java/train/common/core/network/PacketSetTrainLockedToClient.java b/src/main/java/train/common/core/network/PacketSetTrainLockedToClient.java index a4ebed9182..9e57e69408 100644 --- a/src/main/java/train/common/core/network/PacketSetTrainLockedToClient.java +++ b/src/main/java/train/common/core/network/PacketSetTrainLockedToClient.java @@ -1,47 +1,148 @@ package train.common.core.network; +import cpw.mods.fml.common.network.ByteBufUtils; +import cpw.mods.fml.common.network.NetworkRegistry; import cpw.mods.fml.common.network.simpleimpl.IMessage; import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; import cpw.mods.fml.common.network.simpleimpl.MessageContext; import io.netty.buffer.ByteBuf; +import net.minecraft.client.Minecraft; import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayerMP; +import train.common.Traincraft; import train.common.api.AbstractTrains; +import train.common.api.EntityRollingStock; +import train.common.entity.TrustedPlayer; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; public class PacketSetTrainLockedToClient implements IMessage { - boolean bool; - int entityID; + boolean bool; + boolean requestPacket; + int entityID; + int playerEntityID; + boolean propagate; + List trustedList = new ArrayList<>(); + public PacketSetTrainLockedToClient(){} - public PacketSetTrainLockedToClient() { + @Deprecated + public PacketSetTrainLockedToClient(boolean bool, int trainEntity) { + this.bool = bool; + this.entityID = trainEntity; } - public PacketSetTrainLockedToClient(boolean bool, int trainEntity) { + + /** + *

Client <-> Server communication packet to update lock and trusted list.

+ * @param bool Locked status. True for locked, false for unlocked. + * @param trustedList Trusted players list. + * @param propagate Whether to propagate the changes throughout the consist. + */ + public PacketSetTrainLockedToClient(boolean bool, List trustedList, int trainEntity, boolean propagate) { this.bool = bool; this.entityID = trainEntity; + this.trustedList = trustedList; + this.propagate = propagate; + requestPacket = false; + } + + /** + *

Client -> Server communication packet to request lock and trusted list from server.

+ */ + public PacketSetTrainLockedToClient(int trainEntity, int playerEntityID) { + this.entityID = trainEntity; + this.playerEntityID = playerEntityID; + requestPacket = true; } @Override public void fromBytes(ByteBuf bbuf) { - this.bool = bbuf.readBoolean(); this.entityID = bbuf.readInt(); + if (!bbuf.readBoolean()) { + requestPacket = false; + this.bool = bbuf.readBoolean(); + int numberOfTrustedPlayers = bbuf.readInt(); + for (int i = 0; i < numberOfTrustedPlayers; i++) { + trustedList.add(new TrustedPlayer(ByteBufUtils.readUTF8String(bbuf), bbuf.readBoolean())); + } + propagate = bbuf.readBoolean(); + } else { + requestPacket = true; + this.playerEntityID = bbuf.readInt(); + } } @Override public void toBytes(ByteBuf bbuf) { - bbuf.writeBoolean(this.bool); bbuf.writeInt(this.entityID); + bbuf.writeBoolean(requestPacket); + if (!requestPacket) { + bbuf.writeBoolean(this.bool); + bbuf.writeInt(trustedList.size()); + for (TrustedPlayer trustedPlayer : trustedList) { + ByteBufUtils.writeUTF8String(bbuf, trustedPlayer.getDisplayName()); + bbuf.writeBoolean(trustedPlayer.hasBreakAccess()); + } + bbuf.writeBoolean(propagate); + } else { + bbuf.writeInt(playerEntityID); + } } public static class Handler implements IMessageHandler { + @Override public IMessage onMessage(PacketSetTrainLockedToClient message, MessageContext context) { - Entity TrainEntity = context.getServerHandler().playerEntity.worldObj.getEntityByID(message.entityID); + if (context.side.isServer()) { + Entity TrainEntity = context.getServerHandler().playerEntity.worldObj.getEntityByID(message.entityID); + if (!message.requestPacket) { + if (TrainEntity instanceof AbstractTrains) { + ((AbstractTrains) TrainEntity).setTrainLockedFromPacket(message.bool); + ((AbstractTrains) TrainEntity).setTrustedList(message.trustedList); + Traincraft.lockChannel.sendToAllAround(new PacketSetTrainLockedToClient(message.bool, message.trustedList, message.entityID, false), new NetworkRegistry.TargetPoint(TrainEntity.dimension, TrainEntity.posX, TrainEntity.posY, TrainEntity.posZ, 256D)); + if (message.propagate) + propagateChanges((EntityRollingStock) TrainEntity, message.trustedList); - if (TrainEntity instanceof AbstractTrains) { - ((AbstractTrains) TrainEntity).setTrainLockedFromPacket(message.bool); + } + } else { + if (TrainEntity instanceof AbstractTrains) { + if (context.getServerHandler().playerEntity.worldObj.getEntityByID(message.playerEntityID) != null) { + Traincraft.lockChannel.sendTo(new PacketSetTrainLockedToClient(((AbstractTrains) TrainEntity).getTrainLockedFromPacket(), ((AbstractTrains) TrainEntity).getTrustedList(), message.entityID, false), ((EntityPlayerMP) context.getServerHandler().playerEntity.worldObj.getEntityByID(message.playerEntityID))); + } + } + } + } else { + if (!message.requestPacket) { + Entity TrainEntity = Minecraft.getMinecraft().theWorld.getEntityByID(message.entityID); + if (TrainEntity instanceof AbstractTrains) { + ((AbstractTrains) TrainEntity).setTrustedList(message.trustedList); + ((AbstractTrains) TrainEntity).setTrainLockedFromPacket(message.bool); + } + } } - return null; } + + /** + *

Server side method used to update the lock status and trusted players list for all cars in a given consist + * belonging to the train owner.

+ * @author 02skaplan + * @param rollingStock The main rolling stock entity being updated and from which we should propogate changes. + * @param trustedPlayerList List of trusted players. + */ + private static void propagateChanges(EntityRollingStock rollingStock, List trustedPlayerList) { + boolean locked = rollingStock.getTrainLockedFromPacket(); + for (AbstractTrains car : rollingStock.consist) { + if (car != rollingStock && car.getTrainOwner().equalsIgnoreCase(rollingStock.getTrainOwner())) { + car.setTrainLockedFromPacket(locked); + car.setTrustedList(trustedPlayerList); + Traincraft.lockChannel.sendToAllAround(new PacketSetTrainLockedToClient(locked, trustedPlayerList, car.getEntityId(), false), + new NetworkRegistry.TargetPoint(car.dimension, car.posX, car.posY, car.posZ, 256D)); + } + } + } } } \ No newline at end of file diff --git a/src/main/java/train/common/entity/TrustedPlayer.java b/src/main/java/train/common/entity/TrustedPlayer.java new file mode 100644 index 0000000000..84f03addae --- /dev/null +++ b/src/main/java/train/common/entity/TrustedPlayer.java @@ -0,0 +1,90 @@ +package train.common.entity; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraftforge.common.util.Constants; + +import java.util.ArrayList; +import java.util.List; + +public class TrustedPlayer { + private String displayName; + private boolean breakAccess; + public TrustedPlayer(String displayName, boolean breakAccess) { + this.displayName = displayName; + this.breakAccess = breakAccess; + } + public String getDisplayName() { + return displayName; + } + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + public boolean hasBreakAccess() { + return breakAccess; + } + public void setBreakAccess(boolean breakAccess) { + this.breakAccess = breakAccess; + } + public static void exportToNBT(List trustedPlayerList, NBTTagCompound nbtTagCompound) { + if (!trustedPlayerList.isEmpty()) { + NBTTagList trustedList = new NBTTagList(); + for (TrustedPlayer trustedPlayer : trustedPlayerList) { + NBTTagCompound trustedPlayerTag = new NBTTagCompound(); + trustedPlayerTag.setString("playerName", trustedPlayer.getDisplayName()); + trustedPlayerTag.setBoolean("breakAccess", trustedPlayer.hasBreakAccess()); + trustedList.appendTag(trustedPlayerTag); + } + nbtTagCompound.setTag("trustedList", trustedList); + } + } + + /** + *

Import a trusted player list from a given NBT tag.

+ * @param nbttagcompound NBT tag from which to import trusted list. + */ + public static List importTrustedListFromNBT(NBTTagCompound nbttagcompound, String owner) { + List trustedPlayerList = new ArrayList<>(); + if (nbttagcompound.hasKey("trustedList")) { + NBTTagList trustedList = nbttagcompound.getTagList("trustedList", Constants.NBT.TAG_COMPOUND); + for (int i = 0; i < trustedList.tagCount(); i++) { + if (!trustedList.getCompoundTagAt(i).getString("playerName").equalsIgnoreCase(owner)) // Check to ensure we're not adding the current owner to the trusted list... + trustedPlayerList.add(new TrustedPlayer(trustedList.getCompoundTagAt(i).getString("playerName"), trustedList.getCompoundTagAt(i).getBoolean("breakAccess"))); + } + if (nbttagcompound.hasKey("trustedListPreviousOwner")) { // If the previous owner is not the one who placed down the piece of rolling stock... + if (!nbttagcompound.getString("trustedListPreviousOwner").equalsIgnoreCase(owner)) { + trustedPlayerList.add(new TrustedPlayer(nbttagcompound.getString("trustedListPreviousOwner"), true)); + } + } + } + return trustedPlayerList; + } + + /** + *

Returns whether or not a player is trusted to a piece of rolling stock.

+ * @param displayName Case-insensitive display name of player. + * @return True if the player is trusted, false if the player is not trusted. + */ + public static boolean isPlayerTrusted(String displayName, List trustedPlayerList) { + for (TrustedPlayer trustedPlayer : trustedPlayerList) { + if (trustedPlayer.getDisplayName().equalsIgnoreCase(displayName)) { + return true; + } + } + return false; + } + + /** + *

Returns whether or not a player is trusted to break a piece of rolling stock.

+ * @param displayName Case-insensitive display name of player. + * @return True if player has break access, false if player does not have break access. + */ + public static boolean isPlayerTrustedToBreak(String displayName, List trustedPlayerList) { + for (TrustedPlayer trustedPlayer : trustedPlayerList) { + if (trustedPlayer.getDisplayName().equalsIgnoreCase(displayName)) { + return trustedPlayer.hasBreakAccess(); + } + } + return false; + } +} diff --git a/src/main/java/train/common/inventory/InventoryFreight.java b/src/main/java/train/common/inventory/InventoryFreight.java index fbfafaa328..28b8b089b5 100644 --- a/src/main/java/train/common/inventory/InventoryFreight.java +++ b/src/main/java/train/common/inventory/InventoryFreight.java @@ -44,11 +44,10 @@ public boolean canInteractWith(EntityPlayer entityplayer) { public ItemStack transferStackInSlot(EntityPlayer player, int i) { ItemStack itemstack = null; Slot slot = (Slot) inventorySlots.get(i); - SlotFreight slot2 = (SlotFreight) this.getSlot(0); if (slot != null && slot.getHasStack()) { ItemStack itemstack1 = slot.getStack(); itemstack = itemstack1.copy(); - if(slot2 != null && slot2.isItemValid(itemstack)) { + if (this.getSlot(0) instanceof SlotFreight && this.getSlot(0) != null && this.getSlot(0).isItemValid(itemstack)) { if (i < height * 9) { if (!mergeItemStack(itemstack1, height * 9, inventorySlots.size(), true)) { return null; diff --git a/src/main/java/train/common/items/ItemContainer.java b/src/main/java/train/common/items/ItemContainer.java index af7f5ea755..5cfd4ea52b 100644 --- a/src/main/java/train/common/items/ItemContainer.java +++ b/src/main/java/train/common/items/ItemContainer.java @@ -10,13 +10,12 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import train.common.Traincraft; -import train.common.library.Info; import train.common.library.ItemIDs; public class ItemContainer extends ItemPart { public ItemContainer(String itemName){ - super(itemName, Info.modID); + super(itemName); this.setMaxStackSize(64); this.setCreativeTab(Traincraft.tcTab); } diff --git a/src/main/java/train/common/items/ItemPadlock.java b/src/main/java/train/common/items/ItemPadlock.java new file mode 100644 index 0000000000..39462693d1 --- /dev/null +++ b/src/main/java/train/common/items/ItemPadlock.java @@ -0,0 +1,45 @@ +package train.common.items; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import train.common.Traincraft; +import train.common.library.Info; +import train.common.library.ItemIDs; + +import java.util.List; + +public class ItemPadlock extends ItemPart { + + public ItemPadlock() { + super(ItemIDs.padlock.iconName); + maxStackSize = 1; + setCreativeTab(Traincraft.tcTab); + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IIconRegister iconRegister) { + this.itemIcon = iconRegister.registerIcon(Info.modID.toLowerCase() + ":padlock"); + } + + @Override + public boolean onItemUseFirst(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ) { + return false; + } + @SideOnly(Side.CLIENT) + @Override + public void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4) { + par3List.add("\u00a77" + "Use it to lock/unlock train cars."); + par3List.add("\u00a77" + "Use it to trust players to locked train cars."); + par3List.add("\u00a77" + "Use it to lock & unlock switches."); + } + + @Override + public boolean doesSneakBypassUse(World world, int x, int y, int z, EntityPlayer player) { + return true; + } +} \ No newline at end of file diff --git a/src/main/java/train/common/items/ItemPart.java b/src/main/java/train/common/items/ItemPart.java index cf391936a6..d3970e0930 100644 --- a/src/main/java/train/common/items/ItemPart.java +++ b/src/main/java/train/common/items/ItemPart.java @@ -16,7 +16,7 @@ public class ItemPart extends Item{ protected String modID = ""; - public ItemPart(String iconName, String modID){ + public ItemPart(String iconName){ this.iconName = iconName; this.setMaxStackSize(64); this.setCreativeTab(Traincraft.tcTab); diff --git a/src/main/java/train/common/items/ItemRollingStock.java b/src/main/java/train/common/items/ItemRollingStock.java index d31b4108eb..a54e98ef7f 100644 --- a/src/main/java/train/common/items/ItemRollingStock.java +++ b/src/main/java/train/common/items/ItemRollingStock.java @@ -597,6 +597,7 @@ else if (meta == 0 || meta == 2) { rollingStock.trainCreator = trainCreator; if (var5.hasKey("overlayTextureConfigTag")) // Import overlay configuration from NBT and apply it to the entity. rollingStock.getOverlayTextureContainer().importFromConfigTag(var5.getCompoundTag("overlayTextureConfigTag")); + rollingStock.importTrustedListFromNBT(var5); } if (player != null) rollingStock.setInformation(player.getDisplayName(), trainCreator, (itemstack.getItem()).getItemStackDisplayName(itemstack), uniID); @@ -645,12 +646,12 @@ public static ItemStack setPersistentData(@Nullable ItemStack oldStack, @Nullabl tag.setString("theOwner", player); } tag.setString("train_Color",color); + train.exportTrustedListToNBT(tag); } else { tag.setString("trainCreator", creator!=null && creator.length()>1?creator:"Creative"); } tag.setInteger("uniqueID", trainID==null?AbstractTrains.uniqueIDs++:trainID); - stack.setTagCompound(tag); } else { return null;//THIS SHOULD NEVER HAPPEN, but compensate anyway because java is stupid and forge is unreliable. diff --git a/src/main/java/train/common/items/ItemTCRail.java b/src/main/java/train/common/items/ItemTCRail.java index ee0f337925..19dc0f56d5 100644 --- a/src/main/java/train/common/items/ItemTCRail.java +++ b/src/main/java/train/common/items/ItemTCRail.java @@ -20,7 +20,6 @@ import train.common.core.handlers.ConfigHandler; import train.common.library.BlockIDs; import train.common.library.EnumTracks; -import train.common.library.Info; import train.common.library.ItemIDs; import train.common.tile.TileTCRail; import train.common.tile.TileTCRailGag; @@ -49,7 +48,7 @@ public class ItemTCRail extends ItemPart { public ItemTCRail(EnumTracks t) { - super(t.getItem().iconName, Info.modID); + super(t.getItem().iconName); this.overridePath("tracks"); this.type = t; } diff --git a/src/main/java/train/common/items/ItemWrench.java b/src/main/java/train/common/items/ItemWrench.java index 1b3441f4ea..2b66b1381f 100644 --- a/src/main/java/train/common/items/ItemWrench.java +++ b/src/main/java/train/common/items/ItemWrench.java @@ -9,7 +9,6 @@ import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; import train.common.Traincraft; -import train.common.library.Info; import train.common.library.ItemIDs; import java.util.List; @@ -17,7 +16,7 @@ public class ItemWrench extends ItemPart implements buildcraft.api.tools.IToolWrench{ public ItemWrench() { - super(ItemIDs.composite_wrench.iconName, Info.modID); + super(ItemIDs.composite_wrench.iconName); maxStackSize = 1; setCreativeTab(Traincraft.tcTab); } diff --git a/src/main/java/train/common/items/TCItems.java b/src/main/java/train/common/items/TCItems.java index 379eb68d6c..e795ed2fc4 100644 --- a/src/main/java/train/common/items/TCItems.java +++ b/src/main/java/train/common/items/TCItems.java @@ -27,7 +27,7 @@ private static void loadItems() { for (ItemIDs items : ItemIDs.values()) { if (items.className != null) { if (items.className.equals("ItemTrain")) { - items.item = new ItemPart(items.iconName, Info.modID); + items.item = new ItemPart(items.iconName); } else if (items.className.equals("ItemRollingStock")) { items.item = new ItemRollingStock(Info.modID.toLowerCase() + ":trains/" + items.iconName); @@ -216,6 +216,7 @@ else if (items.className.equals("ItemContainer")) { ItemIDs.paintbrushThing.item = new ItemPaintbrushThing(); ItemIDs.whistle.item = new ItemWhistle(); + ItemIDs.padlock.item = new ItemPadlock(); ItemIDs.bolt.item = new ItemBolt(); //this is the spike for crafting } diff --git a/src/main/java/train/common/library/GuiIDs.java b/src/main/java/train/common/library/GuiIDs.java index 7be8e391a8..8851e947b9 100644 --- a/src/main/java/train/common/library/GuiIDs.java +++ b/src/main/java/train/common/library/GuiIDs.java @@ -30,4 +30,5 @@ public class GuiIDs { public static final int DYNAMIC_OVERLAY = 108; public static final int SEAT_GUI = 109; public static final int CONTROL_CAR = 110; + public static final int LOCK_MENU = 111; } \ No newline at end of file diff --git a/src/main/java/train/common/library/ItemIDs.java b/src/main/java/train/common/library/ItemIDs.java index bfe6919150..97751c0598 100644 --- a/src/main/java/train/common/library/ItemIDs.java +++ b/src/main/java/train/common/library/ItemIDs.java @@ -70,6 +70,7 @@ public enum ItemIDs implements IItemIDs { wirelessTransmitter("ItemWirelessTransmitter", "wireless_transmitter", 3), paintbrushThing("ItemPaintbrushThing", "paintbrushThing", 1), whistle("ItemWhistle", "whistle", 1), + padlock("ItemPadlock", "padlock", 1), bolt("ItemBolt", "bolt", 1), hat_ticketMan_paintable("ItemTCArmor", "armor_ticket_man_hat", 1), pants_ticketMan_paintable("ItemTCArmor", "armor_ticket_man_pants", 1), diff --git a/src/main/resources/assets/tc/lang/en_US.lang b/src/main/resources/assets/tc/lang/en_US.lang index f8f45621fe..4ff0b1139d 100644 --- a/src/main/resources/assets/tc/lang/en_US.lang +++ b/src/main/resources/assets/tc/lang/en_US.lang @@ -457,6 +457,7 @@ item.tc:minecartASTFAutorack.name=ASTF ft-41 Auto Rack item.tc:paintbrushThing.name=Paintbrush item.tc:whistle.name=Whistle +item.tc:padlock.name=Padlock item.tc:minecart4000GallonTender.name=4000 Gallon Tender item.tc:minecartLocoHallClass.name=Hall Class @@ -958,6 +959,11 @@ dynamicoverlaymenu.Background Color.name=Background Color dynamicoverlaymenu.Foreground Color.name=Foreground Color dynamicoverlaymenu.Submit.name=Submit dynamicoverlaymenu.Back.name=Back +lockmenu.Unlock.name=Unlock +lockmenu.Lock.name=Lock +lockmenu.Title_Trusted_Players.name=Trusted Players +lockmenu.Save and Close.name=Save and Close +lockmenu.Save To All Cars in Consist.name=Save To All Cars in Consist entity.tc.Entity Front Bogie.name=Bogie diff --git a/src/main/resources/assets/tc/lang/es_ES.lang b/src/main/resources/assets/tc/lang/es_ES.lang index be81fa0c3e..0b833d79d4 100644 --- a/src/main/resources/assets/tc/lang/es_ES.lang +++ b/src/main/resources/assets/tc/lang/es_ES.lang @@ -361,6 +361,9 @@ item.tc:minecartTenderC41.name=C41 Tender (EE.UU.) item.tc:minecartTankWagonThreeDome.name=Vagón cisterna de tres tomas item.tc:minecartGWRBrakeVan.name=Furgón de frenado GWR Toad (R.U.) item.tc:minecartLocoSteamPannier.name=GWR 0-6-0 Pannier (R.U.) +item.tc:paintbrushThing.name=Pincel de Tren +item.tc:whistle.name=Pito +item.tc:padlock.name=Candado achievement.tc:engineer=Prendas de ingeniero achievement.tc:engineer.desc=¡Un verdadero ferroviario! @@ -463,6 +466,11 @@ dynamicoverlaymenu.Background Color.name=Color de Fondo dynamicoverlaymenu.Foreground Color.name=Color de Primer Plano dynamicoverlaymenu.Submit.name=Entregar dynamicoverlaymenu.Back.name=Página Anterior +lockmenu.Unlock.name=Abrir +lockmenu.Lock.name=Cerrar +lockmenu.Title_Trusted_Players.name=Jugadores de Confianza +lockmenu.Save and Close.name=Entregar y Salir +lockmenu.Save To All Cars in Consist.name=Entregar a Todos Los Coches en el Tren entity.tc.Entity Front Bogie.name=Bogie diff --git a/src/main/resources/assets/tc/textures/gui/gui_lockmenu.png b/src/main/resources/assets/tc/textures/gui/gui_lockmenu.png new file mode 100644 index 0000000000..fd662a79aa Binary files /dev/null and b/src/main/resources/assets/tc/textures/gui/gui_lockmenu.png differ diff --git a/src/main/resources/assets/tc/textures/items/padlock.png b/src/main/resources/assets/tc/textures/items/padlock.png new file mode 100644 index 0000000000..7435057bcd Binary files /dev/null and b/src/main/resources/assets/tc/textures/items/padlock.png differ