+ Server Block [WIP]

This commit is contained in:
Nicolas BARBOTIN 2018-02-08 19:28:00 +01:00
parent ec09b2a7f5
commit 9649f8ab7d
25 changed files with 667 additions and 12 deletions

View File

@ -91,7 +91,11 @@ public class SharedProxy {
public void setMiniservClientPort(int port) {
}
public void startMiniServClient() {
public void startMiniservClient() {
}
public boolean isMiniservDisabled() {
return false;
}
}

View File

@ -82,6 +82,7 @@ public class WebDisplays {
public SoundEvent soundUpgradeAdd;
public SoundEvent soundUpgradeDel;
public SoundEvent soundScreenCfg;
public SoundEvent soundServer;
//Criterions
public Criterion criterionPadBreak;
@ -176,6 +177,7 @@ public class WebDisplays {
soundUpgradeAdd = registerSound(ev, "upgradeAdd");
soundUpgradeDel = registerSound(ev, "upgradeDel");
soundScreenCfg = registerSound(ev, "screencfgOpen");
soundServer = registerSound(ev, "server");
}
@SubscribeEvent

View File

@ -309,7 +309,7 @@ public class ClientProxy extends SharedProxy implements IResourceManagerReloadLi
}
@Override
public void startMiniServClient() {
public void startMiniservClient() {
if(miniservPort <= 0) {
Log.warning("Can't start miniserv client: miniserv is disabled");
return;
@ -331,6 +331,11 @@ public class ClientProxy extends SharedProxy implements IResourceManagerReloadLi
msClientStarted = true;
}
@Override
public boolean isMiniservDisabled() {
return miniservPort <= 0;
}
/**************************************** RESOURCE MANAGER METHODS ****************************************/
@Override

View File

@ -0,0 +1,18 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CommandHandler {
String value();
}

View File

@ -0,0 +1,346 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.client.gui;
import net.minecraft.client.audio.ISound;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
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.utilities.Log;
import net.montoyo.wd.utilities.NameUUIDPair;
import net.montoyo.wd.utilities.Util;
import org.lwjgl.input.Keyboard;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import static org.lwjgl.opengl.GL11.*;
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<String, Method> COMMAND_MAP = new HashMap<>();
private final NameUUIDPair owner;
private final ArrayList<String> lines = new ArrayList<>();
private String prompt = "";
private String userPrompt;
private int blinkTime;
private String lastCmd;
private boolean promptLocked;
private long queryTime;
private ClientTask<?> currentTask;
//Access command
private int accessTrials;
private int accessTime;
private int accessState = -1;
private PositionedSoundRecord accessSound;
public GuiServer(NameUUIDPair owner) {
this.owner = owner;
//userPrompt = owner.name + "@miniserv$ ";
userPrompt = "> ";
if(COMMAND_MAP.isEmpty())
buildCommandMap();
lines.add("MiniServ 1.0");
lines.add(tr("info"));
}
private static String tr(String key, Object ... args) {
return I18n.format("webdisplays.server." + key, args);
}
@Override
public void drawScreen(int mouseX, int mouseY, float ptt) {
super.drawScreen(mouseX, mouseY, ptt);
int x = (width - 256) / 2;
int y = (height - 176) / 2;
GlStateManager.enableTexture2D();
mc.renderEngine.bindTexture(BG_IMAGE);
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
drawTexturedModalRect(x, y, 0, 0, 256, 176);
x += 18;
y += 18;
for(String line: lines) {
fontRenderer.drawString(line, x, y, 0xFFFFFFFF, false);
y += 12;
}
if(!promptLocked) {
x = fontRenderer.drawString(userPrompt, x, y, 0xFFFFFFFF, false);
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();
}
GlStateManager.disableAlpha();
GlStateManager.enableTexture2D();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
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);
}
@Override
public void updateScreen() {
super.updateScreen();
if(accessState >= 0) {
if(--accessTime <= 0) {
accessState++;
if(accessState == 1) {
if(lines.size() > 0)
lines.remove(lines.size() - 1);
lines.add("access: PERMISSION DENIED....and...");
accessTime = 20;
} else {
if(accessSound == null) {
accessSound = new PositionedSoundRecord(WebDisplays.INSTANCE.soundServer.getSoundName(), SoundCategory.MASTER, 1.0f, 1.0f, true, 0, ISound.AttenuationType.NONE, 0.0f, 0.0f, 0.0f);
mc.getSoundHandler().playSound(accessSound);
}
writeLine("YOU DIDN'T SAY THE MAGIC WORD!");
accessTime = 2;
}
}
} else {
blinkTime = (blinkTime + 1) % 10;
if(currentTask != null && System.currentTimeMillis() - queryTime >= 10000) {
writeLine(tr("timeout"));
currentTask.cancel();
clearTask();
}
}
}
@Override
public void handleKeyboardInput() throws IOException {
if(!promptLocked && Keyboard.getEventKeyState() && Keyboard.getEventKey() == Keyboard.KEY_UP) {
if(lastCmd != null)
prompt = lastCmd;
return;
}
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)
return;
if(keyCode == Keyboard.KEY_BACK) {
if(prompt.length() > 0)
prompt = prompt.substring(0, prompt.length() - 1);
} else if(keyCode == Keyboard.KEY_RETURN || keyCode == Keyboard.KEY_NUMPADENTER) {
if(prompt.length() > 0) {
writeLine(userPrompt + prompt);
evaluateCommand(prompt);
lastCmd = prompt;
prompt = "";
} else
writeLine(userPrompt);
} else if(prompt.length() + 1 < 30 && typedChar >= 32 && typedChar <= 126)
prompt = prompt + typedChar;
blinkTime = 0;
}
private void evaluateCommand(String str) {
String[] args = str.trim().split("\\s+");
Method handler = COMMAND_MAP.get(args[0].toLowerCase());
if(handler == null) {
writeLine(tr("unknowncmd"));
return;
}
Object[] params;
if(handler.getParameterCount() == 0)
params = new Object[0];
else {
String[] args2 = new String[args.length - 1];
System.arraycopy(args, 1, args2, 0, args2.length);
params = new Object[] { args2 };
}
try {
handler.invoke(this, params);
} catch(IllegalAccessException | InvocationTargetException e) {
Log.errorEx("Caught exception while running command \"%s\"", e, str);
writeLine(tr("error"));
}
}
private void writeLine(String line) {
while(lines.size() >= 11)
lines.remove(0);
lines.add(line);
}
private static void buildCommandMap() {
COMMAND_MAP.clear();
Method[] methods = GuiServer.class.getMethods();
for(Method m: methods) {
CommandHandler cmd = m.getAnnotation(CommandHandler.class);
if(cmd != null && Modifier.isPublic(m.getModifiers())) {
if(m.getParameterCount() == 0 || (m.getParameterCount() == 1 && m.getParameterTypes()[0] == String[].class))
COMMAND_MAP.put(cmd.value().toLowerCase(), m);
}
}
}
@Override
public void onGuiClosed() {
super.onGuiClosed();
if(accessSound != null)
mc.getSoundHandler().stopSound(accessSound);
}
private boolean queueTask(ClientTask<?> task) {
if(Client.getInstance().addTask(task)) {
promptLocked = true;
queryTime = System.currentTimeMillis();
currentTask = task;
return true;
} else {
writeLine(tr("queryerr"));
return false;
}
}
private void clearTask() {
promptLocked = false;
currentTask = null;
}
@CommandHandler("clear")
public void commandClear() {
lines.clear();
}
@CommandHandler("help")
public void commandHelp() {
for(String c : COMMAND_MAP.keySet())
writeLine(c + " - " + tr("help." + c));
}
@CommandHandler("exit")
public void commandExit() {
mc.displayGuiScreen(null);
}
@CommandHandler("access")
public void commandAccess(String[] args) {
boolean handled = false;
if(args.length >= 1 && args[0].equalsIgnoreCase("security")) {
if(args.length == 1 || (args.length == 2 && args[1].equalsIgnoreCase("grid")))
handled = true;
} else if(args.length == 3 && args[0].equalsIgnoreCase("main") && args[1].equalsIgnoreCase("security") && args[2].equalsIgnoreCase("grid"))
handled = true;
if(handled) {
writeLine("access: PERMISSION DENIED.");
if(++accessTrials >= 3) {
promptLocked = true;
accessState = 0;
accessTime = 20;
}
} else
writeLine(tr("argerror"));
}
@CommandHandler("owner")
public void commandOwner() {
writeLine(tr("ownername", owner.name));
writeLine(tr("owneruuid"));
writeLine(owner.uuid.toString());
}
@CommandHandler("quota")
public void commandQuota() {
if(!mc.player.getGameProfile().getId().equals(owner.uuid)) {
writeLine(tr("errowner"));
return;
}
ClientTaskGetQuota task = new ClientTaskGetQuota();
task.setFinishCallback((t) -> {
writeLine(tr("quota", Util.sizeString(t.getQuota()), Util.sizeString(t.getMaxQuota())));
clearTask();
});
queueTask(task);
}
@CommandHandler("ls")
public void commandList() {
ClientTaskGetFileList task = new ClientTaskGetFileList(owner.uuid);
task.setFinishCallback((t) -> {
String[] files = t.getFileList();
if(files != null)
Arrays.stream(files).forEach(this::writeLine);
clearTask();
});
queueTask(task);
}
}

View File

@ -5,6 +5,7 @@
package net.montoyo.wd.client.gui.controls;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.init.SoundEvents;
import net.minecraft.util.ResourceLocation;
import net.montoyo.wd.client.gui.loading.JsonOWrapper;
@ -71,6 +72,8 @@ public class CheckBox extends BasicControl {
@Override
public void draw(int mouseX, int mouseY, float ptt) {
if(visible) {
GlStateManager.disableAlpha();
bindTexture(checked ? texChecked : texUnchecked);
blend(true);
fillTexturedRect(x, y, WIDTH, HEIGHT, 0.0, 0.0, 1.0, 1.0);

View File

@ -22,6 +22,7 @@ public abstract class GuiData {
dataTable.put("ScreenConfig", ScreenConfigData.class);
dataTable.put("Keyboard", KeyboardData.class);
dataTable.put("RedstoneCtrl", RedstoneCtrlData.class);
dataTable.put("Server", ServerData.class);
}
public static Class<? extends GuiData> classOf(String name) {

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.data;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.montoyo.wd.client.gui.GuiServer;
import net.montoyo.wd.utilities.NameUUIDPair;
public class ServerData extends GuiData {
public NameUUIDPair owner;
public ServerData() {
}
public ServerData(NameUUIDPair owner) {
this.owner = owner;
}
@SideOnly(Side.CLIENT)
@Override
public GuiScreen createGui(GuiScreen old, World world) {
return new GuiServer(owner);
}
@Override
public String getName() {
return "Server";
}
}

View File

@ -5,9 +5,12 @@
package net.montoyo.wd.entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.montoyo.wd.data.ServerData;
import net.montoyo.wd.utilities.NameUUIDPair;
import net.montoyo.wd.utilities.Util;
import javax.annotation.Nonnull;
import java.util.UUID;
@ -49,6 +52,11 @@ public class TileEntityServer extends TileEntity {
if(world.isRemote)
return true;
//TODO: Check if miniserv is disabled
//Util.toast(ply, "noMiniserv");
if(owner != null && ply instanceof EntityPlayerMP)
(new ServerData(owner)).sendTo((EntityPlayerMP) ply);
return true;
}

View File

@ -16,6 +16,7 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.World;
import net.montoyo.wd.WebDisplays;
import net.montoyo.wd.block.BlockKeyboardRight;
import net.montoyo.wd.core.DefaultPeripheral;
@ -53,6 +54,8 @@ public class ItemPeripheral extends ItemMultiTexture {
public void addInformation(ItemStack is, @Nullable World world, List<String> tt, ITooltipFlag ttFlags) {
if(is.getMetadata() == 1) //CC Interface
tt.add("" + ChatFormatting.RED + I18n.format("webdisplays.message.missingCC")); //CC is not available for 1.12.2
else if(is.getMetadata() == 11 && WebDisplays.PROXY.isMiniservDisabled()) //Server
tt.add("" + ChatFormatting.RED + I18n.format("webdisplays.message.noMiniserv"));
}
}

View File

@ -12,7 +12,9 @@ public enum PacketID {
BEGIN_FILE_UPLOAD, //C->S
FILE_PART, //C->S and S->C
FILE_STATUS, //S->C
GET_FILE; //C->S
GET_FILE, //C->S
QUOTA, //C->S and S->C
LIST; //C->S and S->C
public static PacketID fromInt(int i) {
PacketID[] values = values();

View File

@ -216,7 +216,7 @@ public class Client extends AbstractClient implements Runnable {
private void unsafeLoop() throws Throwable {
selector.select();
if(currentTask == null)
if(currentTask == null || currentTask.isCanceled())
nextTask();
for(SelectionKey key: selector.selectedKeys()) {
@ -297,6 +297,27 @@ public class Client extends AbstractClient implements Runnable {
}
}
@PacketHandler(PacketID.QUOTA)
public void handleQuota(DataInputStream dis) throws IOException {
long q = dis.readLong();
long m = dis.readLong();
if(currentTask instanceof ClientTaskGetQuota)
((ClientTaskGetQuota) currentTask).onQuotaData(q, m);
}
@PacketHandler(PacketID.LIST)
public void handleList(DataInputStream dis) throws IOException {
int cnt = dis.readByte() & 0xFF;
String[] files = new String[cnt];
for(int i = 0; i < cnt; i++)
files[i] = readString(dis);
if(currentTask instanceof ClientTaskGetFileList)
((ClientTaskGetFileList) currentTask).onFileList(files);
}
public void nextTask() {
if(currentTask != null)
currentTask.onFinished();
@ -326,4 +347,14 @@ public class Client extends AbstractClient implements Runnable {
return true;
}
public void wakeup() {
boolean conn;
synchronized(this) {
conn = connected;
}
if(conn)
selector.wakeup();
}
}

View File

@ -4,11 +4,15 @@
package net.montoyo.wd.miniserv.client;
import net.montoyo.wd.WebDisplays;
import java.util.function.Consumer;
public abstract class ClientTask {
public abstract class ClientTask<T extends ClientTask> {
private Consumer<ClientTask> finishCallback;
private Consumer<T> finishCallback;
private volatile boolean canceled;
protected boolean runCallbackOnMcThread;
protected final Client client = Client.getInstance();
public abstract void start();
@ -16,12 +20,37 @@ public abstract class ClientTask {
public void onFinished() {
//Called by Client, don't call it from a ClientTask!
if(finishCallback != null)
finishCallback.accept(this);
if(finishCallback != null && !isCanceled()) {
if(runCallbackOnMcThread)
WebDisplays.PROXY.enqueue(() -> finishCallback.accept((T) this));
else
finishCallback.accept((T) this);
}
}
public void setFinishCallback(Consumer<ClientTask> finishCallback) {
public void setFinishCallback(Consumer<T> finishCallback) {
this.finishCallback = finishCallback;
}
public void setRunCallbackOnMinecraftThread(boolean runCallbackOnMcThread) {
this.runCallbackOnMcThread = runCallbackOnMcThread;
}
public final void cancel() {
synchronized(this) {
canceled = true;
}
Client.getInstance().wakeup();
}
public final boolean isCanceled() {
boolean ret;
synchronized(this) {
ret = canceled;
}
return ret;
}
}

View File

@ -13,7 +13,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ClientTaskGetFile extends ClientTask {
public class ClientTaskGetFile extends ClientTask<ClientTaskGetFile> {
private final UUID uuid;
private final String fname;
@ -86,6 +86,7 @@ public class ClientTaskGetFile extends ClientTask {
while(!hasResponse) {
if(System.currentTimeMillis() - t > 10000) {
responseLock.unlock();
cancel();
return Constants.GETF_STATUS_TIMED_OUT;
}
@ -124,6 +125,7 @@ public class ClientTaskGetFile extends ClientTask {
data = new byte[0];
dataLen = -1;
dataLock.unlock();
cancel();
return data;
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.miniserv.client;
import net.montoyo.wd.miniserv.OutgoingPacket;
import net.montoyo.wd.miniserv.PacketID;
import java.util.UUID;
public class ClientTaskGetFileList extends ClientTask<ClientTaskGetFileList> {
private final UUID user;
private String[] files;
public ClientTaskGetFileList(UUID user) {
this.user = user;
runCallbackOnMcThread = true;
}
@Override
public void start() {
OutgoingPacket pkt = new OutgoingPacket();
pkt.writeByte(PacketID.LIST.ordinal());
pkt.writeLong(user.getMostSignificantBits());
pkt.writeLong(user.getLeastSignificantBits());
client.sendPacket(pkt);
}
@Override
public void abort() {
}
public void onFileList(String[] files) {
this.files = files;
client.nextTask();
}
public String[] getFileList() {
return files;
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2018 BARBOTIN Nicolas
*/
package net.montoyo.wd.miniserv.client;
import net.montoyo.wd.miniserv.OutgoingPacket;
import net.montoyo.wd.miniserv.PacketID;
public class ClientTaskGetQuota extends ClientTask<ClientTaskGetQuota> {
private long quota;
private long maxQuota;
public ClientTaskGetQuota() {
runCallbackOnMcThread = true;
}
@Override
public void start() {
OutgoingPacket pkt = new OutgoingPacket();
pkt.writeByte(PacketID.QUOTA.ordinal());
client.sendPacket(pkt);
}
@Override
public void abort() {
}
public void onQuotaData(long q, long m) {
quota = q;
maxQuota = m;
client.nextTask();
}
public long getMaxQuota() {
return maxQuota;
}
public long getQuota() {
return quota;
}
}

View File

@ -16,7 +16,7 @@ import java.io.IOException;
import java.nio.file.Files;
import java.util.function.Consumer;
public class ClientTaskUploadFile extends ClientTask implements Consumer<OutgoingPacket> {
public class ClientTaskUploadFile extends ClientTask<ClientTaskUploadFile> implements Consumer<OutgoingPacket> {
private static final byte[] UPLOAD_BUFFER = new byte[65535];

View File

@ -13,6 +13,7 @@ import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Arrays;
import java.util.UUID;
import java.util.function.Consumer;
@ -236,6 +237,43 @@ public class ServerClient extends AbstractClient {
}
}
@PacketHandler(PacketID.QUOTA)
public void handleQuota(DataInputStream dis) {
OutgoingPacket pkt = new OutgoingPacket();
pkt.writeByte(PacketID.QUOTA.ordinal());
pkt.writeLong(quota);
pkt.writeLong(Server.getInstance().getMaxQuota());
sendPacket(pkt);
}
@PacketHandler(PacketID.LIST)
public void handleList(DataInputStream dis) throws IOException {
long msb = dis.readLong();
long lsb = dis.readLong();
File dir = new File(Server.getInstance().getDirectory(), (new UUID(msb, lsb)).toString());
String[] list = null;
if(dir.exists() && dir.isDirectory()) {
File[] files = dir.listFiles();
if(files != null)
list = Arrays.stream(files).filter(f -> f.isFile() && !Util.isFileNameInvalid(f.getName())).map(File::getName).toArray(String[]::new);
}
OutgoingPacket pkt = new OutgoingPacket();
pkt.writeByte(PacketID.LIST.ordinal());
if(list == null)
pkt.writeByte(0);
else {
pkt.writeByte(list.length);
Arrays.stream(list).forEach(pkt::writeString);
}
sendPacket(pkt);
}
private void finishUpload(int status) {
if(currentFile != null) {
OutgoingPacket pkt = new OutgoingPacket();

View File

@ -40,7 +40,7 @@ public class CMessageMiniservKey implements IMessage, Runnable {
public void run() {
if(Client.getInstance().decryptKey(encryptedKey)) {
Log.info("Successfully received and decrypted key, starting miniserv client...");
WebDisplays.PROXY.startMiniServClient();
WebDisplays.PROXY.startMiniservClient();
}
}

View File

@ -227,4 +227,19 @@ public abstract class Util {
public static boolean isFileNameInvalid(String fname) {
return fname.isEmpty() || fname.length() > 64 || fname.charAt(0) == '.' || fname.indexOf('/') >= 0 || fname.indexOf('\\') >= 0;
}
public static final String[] SIZES = { "bytes", "KiB", "MiB", "GiB", "TiB" };
public static String sizeString(long l) {
double d = (double) l;
int size = 0;
while(l >= 1024L && size + 1 < SIZES.length) {
d /= 1024.0;
l /= 1024L;
size++;
}
return String.format("%.2f %s", d, SIZES[size]);
}
}

View File

@ -50,6 +50,7 @@ webdisplays.message.missingOC=OpenComputers is not available.
webdisplays.message.upgradeError=Upgrade error :( Check logs...
webdisplays.message.upgradeOk=Upgrade installed!
webdisplays.message.linkAbort=Linker reset
webdisplays.message.noMiniserv=Server block is disabled on this server
webdisplays.gui.screencfg.owner=Screen owner:
webdisplays.gui.screencfg.friends=Friends:
webdisplays.gui.screencfg.permissions=Permissions:
@ -110,3 +111,20 @@ webdisplays.side.north=North
webdisplays.side.south=South
webdisplays.side.west=West
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.argerror=Unrecognized argument.
webdisplays.server.queryerr=Query error, check logs.
webdisplays.server.errowner=Only the owner can access this.
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.help.help=Displays this text
webdisplays.server.help.clear=Clears the screen
webdisplays.server.help.exit=Leaves this console
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

View File

@ -29,5 +29,11 @@
"sounds": [
"webdisplays:screencfg_open"
]
},
"server": {
"category": "master",
"sounds": [
"webdisplays:server"
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 817 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB