From b3aede2fee4e39d8ff0ca5747fc6fd1b577af4df Mon Sep 17 00:00:00 2001 From: Nicolas BARBOTIN Date: Thu, 8 Feb 2018 22:29:49 +0100 Subject: [PATCH] + Server Block [WIP] --- README.md | 1 + .../net/montoyo/wd/client/gui/GuiServer.java | 196 +++++++++++++++--- .../montoyo/wd/miniserv/client/Client.java | 2 + .../miniserv/client/ClientTaskCheckFile.java | 54 +++++ .../wd/miniserv/client/ClientTaskGetFile.java | 1 + .../wd/miniserv/server/ServerClient.java | 18 +- .../java/net/montoyo/wd/utilities/Util.java | 8 + .../assets/webdisplays/lang/en_us.lang | 7 + 8 files changed, 246 insertions(+), 41 deletions(-) create mode 100644 src/main/java/net/montoyo/wd/miniserv/client/ClientTaskCheckFile.java diff --git a/README.md b/README.md index 4963482..ed7b060 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ This is the unfinished port of the WebDisplays mod for Minecraft 1.12.2. The tex * Read config (see "Config elements" below) * Miniserv timeout * Recipe for server block +* del command ### TODO * French translations diff --git a/src/main/java/net/montoyo/wd/client/gui/GuiServer.java b/src/main/java/net/montoyo/wd/client/gui/GuiServer.java index 79dcbc8..9b6ff75 100644 --- a/src/main/java/net/montoyo/wd/client/gui/GuiServer.java +++ b/src/main/java/net/montoyo/wd/client/gui/GuiServer.java @@ -14,15 +14,15 @@ import net.minecraft.client.resources.I18n; import net.minecraft.util.ResourceLocation; import net.minecraft.util.SoundCategory; import net.montoyo.wd.WebDisplays; -import net.montoyo.wd.miniserv.client.Client; -import net.montoyo.wd.miniserv.client.ClientTask; -import net.montoyo.wd.miniserv.client.ClientTaskGetFileList; -import net.montoyo.wd.miniserv.client.ClientTaskGetQuota; +import net.montoyo.wd.miniserv.Constants; +import net.montoyo.wd.miniserv.client.*; import net.montoyo.wd.utilities.Log; import net.montoyo.wd.utilities.NameUUIDPair; import net.montoyo.wd.utilities.Util; import org.lwjgl.input.Keyboard; +import javax.swing.filechooser.FileSystemView; +import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -38,6 +38,8 @@ public class GuiServer extends WDScreen { private static final ResourceLocation BG_IMAGE = new ResourceLocation("webdisplays", "textures/gui/server_bg.png"); private static final ResourceLocation FG_IMAGE = new ResourceLocation("webdisplays", "textures/gui/server_fg.png"); private static final HashMap COMMAND_MAP = new HashMap<>(); + private static final int MAX_LINE_LEN = 30; + private static final int MAX_LINES = 12; private final NameUUIDPair owner; private final ArrayList lines = new ArrayList<>(); @@ -55,6 +57,13 @@ public class GuiServer extends WDScreen { private int accessState = -1; private PositionedSoundRecord accessSound; + //Upload wizard + private boolean uploadWizard; + private int selectedLine = -1; + private File uploadDir; + private File[] uploadFiles; + private int uploadOffset; + public GuiServer(NameUUIDPair owner) { this.owner = owner; //userPrompt = owner.name + "@miniserv$ "; @@ -65,6 +74,7 @@ public class GuiServer extends WDScreen { lines.add("MiniServ 1.0"); lines.add(tr("info")); + uploadCD(FileSystemView.getFileSystemView().getDefaultDirectory()); } private static String tr(String key, Object ... args) { @@ -86,8 +96,13 @@ public class GuiServer extends WDScreen { x += 18; y += 18; - for(String line: lines) { - fontRenderer.drawString(line, x, y, 0xFFFFFFFF, false); + for(int i = 0; i < lines.size(); i++) { + if(selectedLine == i) { + drawWhiteQuad(x - 1, y - 2, fontRenderer.getStringWidth(lines.get(i)) + 1, 12); + fontRenderer.drawString(lines.get(i), x, y, 0xFF129700, false); + } else + fontRenderer.drawString(lines.get(i), x, y, 0xFFFFFFFF, false); + y += 12; } @@ -96,22 +111,8 @@ public class GuiServer extends WDScreen { x = fontRenderer.drawString(prompt, x, y, 0xFFFFFFFF, false); } - if(blinkTime < 5) { - double xd = (double) (x + 1); - double yd = (double) y; - double zd = (double) zLevel; - - GlStateManager.disableTexture2D(); - GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f); - Tessellator t = Tessellator.getInstance(); - BufferBuilder bb = t.getBuffer(); - bb.begin(GL_QUADS, DefaultVertexFormats.POSITION); - bb.pos(xd, yd + 8.0f, zd).endVertex(); - bb.pos(xd + 6.0f, yd + 8.0f, zd).endVertex(); - bb.pos(xd + 6.0f, yd, zd).endVertex(); - bb.pos(xd, yd, zd).endVertex(); - t.draw(); - } + if(!uploadWizard && blinkTime < 5) + drawWhiteQuad(x + 1, y, 6, 8); GlStateManager.disableAlpha(); GlStateManager.enableTexture2D(); @@ -120,6 +121,27 @@ public class GuiServer extends WDScreen { mc.renderEngine.bindTexture(FG_IMAGE); GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f); drawTexturedModalRect((width - 256) / 2, (height - 176) / 2, 0, 0, 256, 176); + GlStateManager.enableAlpha(); + } + + private void drawWhiteQuad(int x, int y, int w, int h) { + double xd = (double) x; + double xd2 = (double) (x + w); + double yd = (double) y; + double yd2 = (double) (y + h); + double zd = (double) zLevel; + + GlStateManager.disableTexture2D(); + GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f); + Tessellator t = Tessellator.getInstance(); + BufferBuilder bb = t.getBuffer(); + bb.begin(GL_QUADS, DefaultVertexFormats.POSITION); + bb.pos(xd, yd2, zd).endVertex(); + bb.pos(xd2, yd2, zd).endVertex(); + bb.pos(xd2, yd, zd).endVertex(); + bb.pos(xd, yd, zd).endVertex(); + t.draw(); + GlStateManager.enableTexture2D(); } @Override @@ -159,24 +181,51 @@ public class GuiServer extends WDScreen { @Override public void handleKeyboardInput() throws IOException { - if(!promptLocked && Keyboard.getEventKeyState() && Keyboard.getEventKey() == Keyboard.KEY_UP) { - if(lastCmd != null) - prompt = lastCmd; + boolean keyState = Keyboard.getEventKeyState(); + int keyCode = Keyboard.getEventKey(); - return; + if(uploadWizard) { + if(keyState) { + if(keyCode == Keyboard.KEY_UP) { + if(--selectedLine < 3) + selectedLine = MAX_LINES - 1; + } else if(keyCode == Keyboard.KEY_DOWN) { + if(++selectedLine >= MAX_LINES) + selectedLine = 3; + } + } + + if(keyCode == Keyboard.KEY_ESCAPE) { + lines.clear(); + promptLocked = false; + uploadWizard = false; + selectedLine = -1; + return; //Don't let the screen handle this + } + + super.handleKeyboardInput(); + } else { + super.handleKeyboardInput(); + + if(keyState) { + if(keyCode == Keyboard.KEY_L && (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL))) + lines.clear(); + else if(keyCode == Keyboard.KEY_UP) { + if(lastCmd != null) { + String tmp = prompt; + prompt = lastCmd; + lastCmd = tmp; + } + } + } } - - super.handleKeyboardInput(); - - if(Keyboard.getEventKeyState() && Keyboard.getEventKey() == Keyboard.KEY_L && (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL))) - lines.clear(); } @Override protected void keyTyped(char typedChar, int keyCode) throws IOException { super.keyTyped(typedChar, keyCode); - if(promptLocked) + if(promptLocked || uploadWizard) return; if(keyCode == Keyboard.KEY_BACK) { @@ -190,7 +239,7 @@ public class GuiServer extends WDScreen { prompt = ""; } else writeLine(userPrompt); - } else if(prompt.length() + 1 < 30 && typedChar >= 32 && typedChar <= 126) + } else if(prompt.length() + 1 < MAX_LINE_LEN && typedChar >= 32 && typedChar <= 126) prompt = prompt + typedChar; blinkTime = 0; @@ -223,7 +272,8 @@ public class GuiServer extends WDScreen { } private void writeLine(String line) { - while(lines.size() >= 11) + final int maxl = uploadWizard ? MAX_LINES : (MAX_LINES - 1); //Cuz prompt is hidden + while(lines.size() >= maxl) lines.remove(0); lines.add(line); @@ -268,6 +318,18 @@ public class GuiServer extends WDScreen { currentTask = null; } + private static String trimStringL(String str) { + int delta = str.length() - MAX_LINE_LEN; + if(delta <= 0) + return str; + + return "..." + str.substring(delta + 3); + } + + private static String trimStringR(String str) { + return (str.length() <= MAX_LINE_LEN) ? str : (str.substring(0, MAX_LINE_LEN - 3) + "..."); + } + @CommandHandler("clear") public void commandClear() { lines.clear(); @@ -343,4 +405,70 @@ public class GuiServer extends WDScreen { queueTask(task); } + @CommandHandler("url") + public void commandURL(String[] args) { + if(args.length < 1) { + writeLine(tr("urlarg")); + return; + } + + String fname = Util.join(args, " "); + if(Util.isFileNameInvalid(fname)) { + writeLine(tr("nameerr")); + return; + } + + ClientTaskCheckFile task = new ClientTaskCheckFile(owner.uuid, fname); + task.setFinishCallback((t) -> { + int status = t.getStatus(); + if(status == 0) { + writeLine(tr("urlcopied")); + setClipboardString(t.getURL()); + } else if(status == Constants.GETF_STATUS_NOT_FOUND) + writeLine(tr("notfound")); + else + writeLine(tr("error2", status)); + + clearTask(); + }); + + queueTask(task); + } + + private void uploadCD(File newDir) { + try { + uploadDir = newDir.getCanonicalFile(); + } catch(IOException ex) { + uploadDir = newDir; + } + + uploadFiles = uploadDir.listFiles(); + if(uploadFiles == null) + uploadFiles = new File[0]; + else + uploadFiles = Arrays.stream(uploadFiles).filter(f -> !f.isHidden() && (f.isDirectory() || (f.isFile() && !Util.isFileNameInvalid(f.getName())))).toArray(File[]::new); + } + + private void updateUploadScreen() { + lines.clear(); + + lines.add("Choose a file to upload"); + lines.add(trimStringL(uploadDir.getPath())); + lines.add(""); + lines.add("[Parent]"); + + final int maxl = Math.min(MAX_LINES - 4, uploadFiles.length); + for(int i = uploadOffset; i < maxl; i++) + lines.add(trimStringR(uploadFiles[i].getName())); + } + + @CommandHandler("upload") + public void commandUpload() { + uploadWizard = true; + promptLocked = true; + selectedLine = 3; + uploadOffset = 0; + updateUploadScreen(); + } + } diff --git a/src/main/java/net/montoyo/wd/miniserv/client/Client.java b/src/main/java/net/montoyo/wd/miniserv/client/Client.java index 7f02c47..cd74178 100644 --- a/src/main/java/net/montoyo/wd/miniserv/client/Client.java +++ b/src/main/java/net/montoyo/wd/miniserv/client/Client.java @@ -287,6 +287,8 @@ public class Client extends AbstractClient implements Runnable { public void handleGetFile(DataInputStream dis) throws IOException { if(currentTask instanceof ClientTaskGetFile) ((ClientTaskGetFile) currentTask).onGetFileResponse(dis.readByte()); + else if(currentTask instanceof ClientTaskCheckFile) + ((ClientTaskCheckFile) currentTask).onStatus(dis.readByte()); } @PacketHandler(PacketID.FILE_PART) diff --git a/src/main/java/net/montoyo/wd/miniserv/client/ClientTaskCheckFile.java b/src/main/java/net/montoyo/wd/miniserv/client/ClientTaskCheckFile.java new file mode 100644 index 0000000..b84a490 --- /dev/null +++ b/src/main/java/net/montoyo/wd/miniserv/client/ClientTaskCheckFile.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2018 BARBOTIN Nicolas + */ + +package net.montoyo.wd.miniserv.client; + +import net.montoyo.wd.miniserv.Constants; +import net.montoyo.wd.miniserv.OutgoingPacket; +import net.montoyo.wd.miniserv.PacketID; + +import java.util.UUID; + +public class ClientTaskCheckFile extends ClientTask { + + private final UUID uuid; + private final String fname; + private int status = Constants.GETF_STATUS_INTERNAL_ERROR; + + public ClientTaskCheckFile(UUID id, String name) { + uuid = id; + fname = name; + runCallbackOnMcThread = true; + } + + @Override + public void start() { + OutgoingPacket pkt = new OutgoingPacket(); + pkt.writeByte(PacketID.GET_FILE.ordinal()); + pkt.writeLong(uuid.getMostSignificantBits()); + pkt.writeLong(uuid.getLeastSignificantBits()); + pkt.writeString(fname); + pkt.writeBoolean(false); + + client.sendPacket(pkt); + } + + @Override + public void abort() { + } + + public void onStatus(int s) { + status = s; + client.nextTask(); + } + + public int getStatus() { + return status; + } + + public String getURL() { + return ((new StringBuilder("wd://"))).append(uuid.toString()).append('/').append(fname).toString(); + } + +} diff --git a/src/main/java/net/montoyo/wd/miniserv/client/ClientTaskGetFile.java b/src/main/java/net/montoyo/wd/miniserv/client/ClientTaskGetFile.java index b94e7f4..e5cff1d 100644 --- a/src/main/java/net/montoyo/wd/miniserv/client/ClientTaskGetFile.java +++ b/src/main/java/net/montoyo/wd/miniserv/client/ClientTaskGetFile.java @@ -40,6 +40,7 @@ public class ClientTaskGetFile extends ClientTask { pkt.writeLong(uuid.getMostSignificantBits()); pkt.writeLong(uuid.getLeastSignificantBits()); pkt.writeString(fname); + pkt.writeBoolean(true); client.sendPacket(pkt); } diff --git a/src/main/java/net/montoyo/wd/miniserv/server/ServerClient.java b/src/main/java/net/montoyo/wd/miniserv/server/ServerClient.java index babae53..3530ed0 100644 --- a/src/main/java/net/montoyo/wd/miniserv/server/ServerClient.java +++ b/src/main/java/net/montoyo/wd/miniserv/server/ServerClient.java @@ -214,6 +214,7 @@ public class ServerClient extends AbstractClient { long msb = dis.readLong(); long lsb = dis.readLong(); String fname = readString(dis); + boolean doQuery = dis.readBoolean(); OutgoingPacket rep = new OutgoingPacket(); rep.writeByte(PacketID.GET_FILE.ordinal()); @@ -224,13 +225,16 @@ public class ServerClient extends AbstractClient { UUID user = new UUID(msb, lsb); File fle = new File(Server.getInstance().getDirectory(), user.toString() + File.separatorChar + fname); - try { - rep.setOnFinishAction(new SendFileCallback(fle)); - rep.writeByte(0); - sendingFile = true; - } catch(FileNotFoundException ex) { - rep.writeByte(Constants.GETF_STATUS_NOT_FOUND); - } + if(doQuery) { + try { + rep.setOnFinishAction(new SendFileCallback(fle)); + rep.writeByte(0); + sendingFile = true; + } catch(FileNotFoundException ex) { + rep.writeByte(Constants.GETF_STATUS_NOT_FOUND); + } + } else + rep.writeByte((fle.exists() && fle.isFile()) ? 0 : Constants.GETF_STATUS_NOT_FOUND); } sendPacket(rep); diff --git a/src/main/java/net/montoyo/wd/utilities/Util.java b/src/main/java/net/montoyo/wd/utilities/Util.java index 32d71e9..876c677 100644 --- a/src/main/java/net/montoyo/wd/utilities/Util.java +++ b/src/main/java/net/montoyo/wd/utilities/Util.java @@ -14,6 +14,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; +import java.util.StringJoiner; public abstract class Util { @@ -242,4 +243,11 @@ public abstract class Util { return String.format("%.2f %s", d, SIZES[size]); } + + public static String join(String[] array, String sep) { + StringJoiner j = new StringJoiner(sep); + Arrays.stream(array).forEach(j::add); + return j.toString(); + } + } diff --git a/src/main/resources/assets/webdisplays/lang/en_us.lang b/src/main/resources/assets/webdisplays/lang/en_us.lang index 113e2a0..4fc39bc 100644 --- a/src/main/resources/assets/webdisplays/lang/en_us.lang +++ b/src/main/resources/assets/webdisplays/lang/en_us.lang @@ -114,6 +114,7 @@ webdisplays.side.east=East webdisplays.server.info=Type "help" if you need some. webdisplays.server.unknowncmd=Unknown command. webdisplays.server.error=Internal error. Check logs. +webdisplays.server.error2=Internal error %d. Check logs. webdisplays.server.argerror=Unrecognized argument. webdisplays.server.queryerr=Query error, check logs. webdisplays.server.errowner=Only the owner can access this. @@ -121,6 +122,10 @@ webdisplays.server.timeout=Query timed out. Check logs. webdisplays.server.ownername=Owner name: %s webdisplays.server.owneruuid=Owner UUID: webdisplays.server.quota=%s/%s used +webdisplays.server.urlarg=Missing file name argument +webdisplays.server.nameerr=Invalid file name +webdisplays.server.urlcopied=Copied URL to clipboard. +webdisplays.server.notfound=File not found webdisplays.server.help.help=Displays this text webdisplays.server.help.clear=Clears the screen webdisplays.server.help.exit=Leaves this console @@ -128,3 +133,5 @@ webdisplays.server.help.access=§kNo help data webdisplays.server.help.owner=Displays the server owner webdisplays.server.help.quota=Displays the storage quota webdisplays.server.help.ls=Lists the files on this server +webdisplays.server.help.url=Copies a file URL into your clipboard +webdisplays.server.help.upload=Opens the upload wizard