diff --git a/java/src/game/Game.java b/java/src/game/Game.java index 1ddcee2..a8b0d6f 100755 --- a/java/src/game/Game.java +++ b/java/src/game/Game.java @@ -440,6 +440,7 @@ public class Game implements IThreadListener { } public void connect(String address, int port, String user, String pass, String access) { + this.displayGuiScreen(GuiLoading.makeWaitTask("Verbinde zu " + (address == null ? "localhost" : address) + ":" + port + " ...")); Log.JNI.info("Verbinde zu " + (address == null ? "localhost" : address) + ":" + port); NetConnection connection = null; try @@ -2353,9 +2354,9 @@ public class Game implements IThreadListener { public void startServer(File dir) { if(this.server != null) return; - server = new ServerProcess(dir, 1024, 4096, this.port); + server = new ServerProcess(this, dir, 1024, 4096, this.port); server.start(); - this.displayGuiScreen(GuiLoading.makeLoadTask(server)); + this.displayGuiScreen(GuiLoading.makeStartTask(server)); // while(server != null && !server.isStarted()) { // try { // Thread.sleep(10L); @@ -2371,7 +2372,7 @@ public class Game implements IThreadListener { if(server != null) { server.shutdown(); if(display) { - this.displayGuiScreen(GuiLoading.makeSaveTask(server)); + this.displayGuiScreen(GuiLoading.makeStopTask(server)); } else { while(!server.isStopped()) { @@ -2893,6 +2894,11 @@ public class Game implements IThreadListener { return; } } + else if(line.startsWith("!")) { + if(this.server != null) + this.server.runCommand(line.substring(1)); + return; + } if(this.thePlayer != null && this.getNetHandler() != null) this.getNetHandler().addToSendQueue(new CPacketMessage(line.startsWith("/") ? CPacketMessage.Type.COMMAND : CPacketMessage.Type.CHAT, line.startsWith("/") ? line.substring(1) : line)); // Log.CONSOLE.user("%s", line); diff --git a/java/src/game/Server.java b/java/src/game/Server.java index 4be8721..4c0c661 100755 --- a/java/src/game/Server.java +++ b/java/src/game/Server.java @@ -27,6 +27,7 @@ import game.future.ThreadFactoryBuilder; import game.color.TextColor; import game.command.CommandEnvironment; +import game.command.FixedExecutor; import game.dimension.Dimension; import game.dimension.Space; import game.entity.Entity; @@ -307,9 +308,9 @@ public final class Server implements IThreadListener { } WorldServer.loadWarps(dim, this.warps); } - if(port >= 0) - this.bind(port); } + if(port >= 0) + this.bind(port); Thread con = new Thread(new Runnable() { private final BufferedReader reader = new BufferedReader(new InputStreamReader(new BufferedInputStream(System.in))); @@ -331,6 +332,12 @@ public final class Server implements IThreadListener { Server.this.shutdown(); continue; } + final String cmd = line; + Server.this.schedule(new Runnable() { + public void run() { + Server.this.scriptEnv.execute(cmd, new FixedExecutor(Server.this, "#con", "KONSOLE", null)); + } + }); } } }, "Server console handler"); @@ -1193,4 +1200,11 @@ public final class Server implements IThreadListener { System.out.flush(); } } + + public void logConsole(String message) { + if(this.ipcpipe) + this.sendPipeIPC("console", message); + else + Log.CONSOLE.info(message); + } } diff --git a/java/src/game/ServerProcess.java b/java/src/game/ServerProcess.java index a6759b1..445f74e 100644 --- a/java/src/game/ServerProcess.java +++ b/java/src/game/ServerProcess.java @@ -16,6 +16,7 @@ import game.util.Tuple; import game.util.Util; public class ServerProcess { + private final Game monitor; private final ProcessBuilder builder; private Process process; @@ -26,7 +27,8 @@ public class ServerProcess { private int progress = -1; private int lastTick; - public ServerProcess(File dir, int minMem, int maxMem, int port) { + public ServerProcess(Game monitor, File dir, int minMem, int maxMem, int port) { + this.monitor = monitor; File jar = new File("game.jar"); String path; if(jar.exists()) { @@ -87,6 +89,12 @@ public class ServerProcess { ServerProcess.this.progress = Integer.parseInt(data.second); else if(data.first.equals("tick")) ServerProcess.this.lastTick = Integer.parseInt(data.second); + else if(data.first.equals("console")) + ServerProcess.this.monitor.schedule(new Runnable() { + public void run() { + ServerProcess.this.monitor.logConsole(data.second); + } + }); Log.SYSTEM.trace("server cmd %s -- %s", data.first, data.second); continue; } @@ -130,4 +138,12 @@ public class ServerProcess { catch(Exception e) { } } + + public void runCommand(String cmd) { + try { + this.writer.println(cmd); + } + catch(Exception e) { + } + } } diff --git a/java/src/game/command/FixedExecutor.java b/java/src/game/command/FixedExecutor.java new file mode 100644 index 0000000..04b5d43 --- /dev/null +++ b/java/src/game/command/FixedExecutor.java @@ -0,0 +1,53 @@ +package game.command; + +import game.Server; +import game.entity.Entity; +import game.world.BlockPos; +import game.world.Position; + +public class FixedExecutor implements Executor { + private final Server server; + private final String id; + + private String name; + private Position position; + + public FixedExecutor(Server server, String id, String name, Position pos) { + this.server = server; + this.id = id; + this.name = name; + this.position = pos; + } + + public void setName(String name) { + this.name = name; + } + + public void setPosition(Position pos) { + this.position = pos; + } + + public void logConsole(String msg) { + this.server.logConsole(msg); + } + + public String getExecId() { + return this.id; + } + + public String getExecName() { + return this.name; + } + + public Position getExecPos() { + return this.position; + } + + public Entity getPointedEntity() { + return null; + } + + public BlockPos getPointedPosition() { + return null; + } +} diff --git a/java/src/game/command/commands/CommandAdmin.java b/java/src/game/command/commands/CommandAdmin.java index 267ffbd..eb58a51 100644 --- a/java/src/game/command/commands/CommandAdmin.java +++ b/java/src/game/command/commands/CommandAdmin.java @@ -14,9 +14,7 @@ public class CommandAdmin extends Command { } public void exec(CommandEnvironment env, Executor exec, Player player) { - if(!(exec instanceof Player)) - throw new RunException("Dieser Befehl kann nur von Spielern ausgeführt werden"); - else if(player == exec) + if(player == exec) throw new RunException("Du kannst nicht deinen eigenen Admin-Status erneut setzen"); else if(player.getAdmin()) throw new RunException("%s ist bereits ein Admin", player.getUser()); diff --git a/java/src/game/command/commands/CommandRevoke.java b/java/src/game/command/commands/CommandRevoke.java index ca3daf3..25ceb93 100644 --- a/java/src/game/command/commands/CommandRevoke.java +++ b/java/src/game/command/commands/CommandRevoke.java @@ -16,8 +16,8 @@ public class CommandRevoke extends Command { public void exec(CommandEnvironment env, Executor exec, Player player) { if(exec instanceof Player) throw new RunException("Dieser Befehl kann nur der Konsole ausgeführt werden"); - else if(player == exec) - throw new RunException("Du kannst nicht deinen eigenen Admin-Status entfernen"); +// else if(player == exec) +// throw new RunException("Du kannst nicht deinen eigenen Admin-Status entfernen"); else if(!player.getAdmin()) throw new RunException("%s ist kein Admin", player.getUser()); player.setAdmin(false); diff --git a/java/src/game/gui/GuiLoading.java b/java/src/game/gui/GuiLoading.java index 97f7bde..352b91f 100644 --- a/java/src/game/gui/GuiLoading.java +++ b/java/src/game/gui/GuiLoading.java @@ -18,7 +18,7 @@ public class GuiLoading extends Gui { private Bar progressBar1; private Bar progressBar2; - public static GuiLoading makeLoadTask(final ServerProcess server) { + public static GuiLoading makeStartTask(final ServerProcess server) { return new GuiLoading("Starte Server ...", new Callback() { boolean started = false; @@ -40,8 +40,8 @@ public class GuiLoading extends Gui { }); } - public static GuiLoading makeSaveTask(final ServerProcess server) { - return new GuiLoading("Speichere Welt ...", new Callback() { + public static GuiLoading makeStopTask(final ServerProcess server) { + return new GuiLoading("Beende Server ...", new Callback() { public void poll(Game gm, GuiLoading gui) { if(server.isStopped()) { gm.displayGuiScreen(GuiMenu.INSTANCE); diff --git a/java/src/game/gui/GuiMenu.java b/java/src/game/gui/GuiMenu.java index 09a6ed5..d8d3f6b 100644 --- a/java/src/game/gui/GuiMenu.java +++ b/java/src/game/gui/GuiMenu.java @@ -9,7 +9,7 @@ import game.gui.element.Label; import game.gui.element.NavButton; import game.gui.element.Textbox; import game.gui.options.GuiOptions; -import game.gui.server.GuiConnect; +import game.gui.world.GuiServers; import game.gui.world.GuiWorlds; import game.init.Config; import game.renderer.Drawing; @@ -74,7 +74,7 @@ public class GuiMenu extends Gui { if(GuiMenu.this.hacked == 8) GuiMenu.this.hacked++; else - GuiMenu.this.gm.displayGuiScreen(GuiConnect.INSTANCE); + GuiMenu.this.gm.displayGuiScreen(GuiServers.INSTANCE); } }, "Server beitreten")); this.infoButton = this.add(new ActButton(0, 56, 400, 24, new ActButton.Callback() { diff --git a/java/src/game/gui/server/GuiConnect.java b/java/src/game/gui/server/GuiConnect.java index b8731d3..72be950 100644 --- a/java/src/game/gui/server/GuiConnect.java +++ b/java/src/game/gui/server/GuiConnect.java @@ -2,32 +2,39 @@ package game.gui.server; import game.color.TextColor; import game.gui.Gui; -import game.gui.GuiMenu; import game.gui.element.ActButton; import game.gui.element.Label; +import game.gui.element.NavButton; import game.gui.element.Textbox; import game.gui.element.Textbox.Action; +import game.gui.world.GuiServers; +import game.gui.world.GuiServers.ServerInfo; import game.init.Config; import game.network.Player; import game.vars.CVarCategory; import game.vars.Variable; public class GuiConnect extends Gui implements Textbox.Callback { - public static final GuiConnect INSTANCE = new GuiConnect(); + public static final GuiConnect INSTANCE = new GuiConnect(null); - private GuiConnect() { - } + private final ServerInfo server; + private Textbox nameBox; private Textbox addrBox; private Textbox portBox; private Textbox userBox; private Textbox passBox; private Textbox accBox; + private Label nameLabel; private Label addrLabel; private Label portLabel; private Label userLabel; private Label passLabel; private Label accLabel; + + public GuiConnect(ServerInfo server) { + this.server = server; + } @Variable(name = "srv_last_address", category = CVarCategory.SYSTEM, min = 1, max = 128, display = "Letzte Server-Adresse") private String lastAddr = ""; @@ -41,21 +48,21 @@ public class GuiConnect extends Gui implements Textbox.Callback { private String lastAcc = ""; public void init(int width, int height) { - this.addrBox = this.add(new Textbox(0, 20, 400, 24, 128, true, this, this.lastAddr)); - this.portBox = this.add(new Textbox(404, 20, 76, 24, 5, true, this, "" + this.lastPort)); - this.userBox = this.add(new Textbox(0, 70, 220, 24, Player.MAX_USER_LENGTH, true, this, Player.VALID_USER, this.lastUser)); - this.passBox = this.add(new Textbox(0, 120, 480, 24, Player.MAX_PASS_LENGTH, true, this, this.lastPass)); - this.accBox = this.add(new Textbox(0, 170, 480, 24, Player.MAX_PASS_LENGTH, true, this, this.lastAcc)); + if(this.server != null) + this.nameBox = this.add(new Textbox(0, -50, 400, 24, 128, true, this, this.server.getName())); + this.addrBox = this.add(new Textbox(0, 20, 400, 24, 128, true, this, this.server == null ? this.lastAddr : this.server.getAddress())); + this.portBox = this.add(new Textbox(404, 20, 76, 24, 5, true, this, "" + (this.server == null ? this.lastPort : this.server.getPort()))); + this.userBox = this.add(new Textbox(0, 70, 220, 24, Player.MAX_USER_LENGTH, true, this, Player.VALID_USER, this.server == null ? this.lastUser : this.server.getUser())); + this.passBox = this.add(new Textbox(0, 120, 480, 24, Player.MAX_PASS_LENGTH, true, this, this.server == null ? this.lastPass : this.server.getPassword())); + this.accBox = this.add(new Textbox(0, 170, 480, 24, Player.MAX_PASS_LENGTH, true, this, this.server == null ? this.lastAcc : this.server.getAccess())); this.add(new ActButton(0, 220, 480, 24, new ActButton.Callback() { public void use(ActButton elem, ActButton.Mode action) { GuiConnect.this.connect(); } - }, "Verbinden")); - this.add(new ActButton(0, 250, 480, 24, new ActButton.Callback() { - public void use(ActButton elem, ActButton.Mode action) { - GuiConnect.this.gm.displayGuiScreen(GuiMenu.INSTANCE); - } - }, "Zurück")); + }, this.server == null ? "Verbinden" : (this.server.getName().isEmpty() ? "Hinzufügen" : "Übernehmen"))); + this.add(new NavButton(0, 250, 480, 24, GuiServers.INSTANCE, "Zurück")); + if(this.server != null) + this.nameLabel = this.add(new Label(0, -70, 410, 20, "Name", true)); this.addrLabel = this.add(new Label(0, 0, 410, 20, "Adresse", true)); this.portLabel = this.add(new Label(414, 0, 66, 20, "Port", true)); this.userLabel = this.add(new Label(0, 50, 220, 20, "Nutzer", true)); @@ -65,12 +72,20 @@ public class GuiConnect extends Gui implements Textbox.Callback { } public String getTitle() { - return "Mit Server verbinden"; + return this.server == null ? "Mit Server verbinden" : (this.server.getName().isEmpty() ? "Server hinzufügen" : "Server bearbeiten"); } private void connect() { if(this.gm.theWorld != null) return; + String name = null; + if(this.server != null) { + name = this.nameBox.getText(); + if(name.isEmpty()) { + this.nameLabel.setText(TextColor.RED + "Name"); + return; + } + } String addr = this.addrBox.getText(); if(addr.isEmpty()) { this.addrLabel.setText(TextColor.RED + "Adresse"); @@ -99,13 +114,19 @@ public class GuiConnect extends Gui implements Textbox.Callback { } String pass = this.passBox.getText(); String acc = this.accBox.getText(); - this.lastAddr = addr; - this.lastPort = port; - this.lastUser = user; - this.lastPass = pass; - this.lastAcc = acc; - this.gm.setDirty(); - this.gm.connect(addr, port, user, pass, acc); + if(this.server == null) { + this.lastAddr = addr; + this.lastPort = port; + this.lastUser = user; + this.lastPass = pass; + this.lastAcc = acc; + this.gm.setDirty(); + this.gm.connect(addr, port, user, pass, acc); + } + else { + this.server.setData(name, addr, port, user, pass, acc); + GuiServers.INSTANCE.applyServer(this.server); + } } public void use(Textbox elem, Action value) { @@ -120,10 +141,8 @@ public class GuiConnect extends Gui implements Textbox.Callback { this.portLabel.setText("Port"); else if(elem == this.userBox) this.userLabel.setText("Nutzer"); + else if(this.server != null && elem == this.nameBox) + this.nameLabel.setText("Name"); } } - -// public void updateScreen() { -// -// } } diff --git a/java/src/game/gui/world/GuiServers.java b/java/src/game/gui/world/GuiServers.java new file mode 100644 index 0000000..c00ffa7 --- /dev/null +++ b/java/src/game/gui/world/GuiServers.java @@ -0,0 +1,269 @@ +package game.gui.world; + +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Collections; +import java.util.Date; +import game.color.TextColor; +import game.gui.GuiMenu; +import game.gui.element.ActButton; +import game.gui.element.ActButton.Mode; +import game.gui.element.GuiList; +import game.gui.element.ListEntry; +import game.gui.element.NavButton; +import game.gui.server.GuiConnect; +import game.init.Config; +import game.log.Log; +import game.network.Player; +import game.renderer.Drawing; +import game.util.FileUtils; +import game.util.Tuple; +import game.util.Util; + +public class GuiServers extends GuiList implements ActButton.Callback { + public class ServerInfo implements Comparable, ListEntry { + private String name; + private String address; + private int port; + private String user; + private String password; + private String access; + private long lastConnected; + + public ServerInfo(String name, String address, int port, String user, String password, String access, long lastConnected) { + this.name = name; + this.address = address; + this.port = port; + this.user = user; + this.password = password; + this.access = access; + this.lastConnected = lastConnected; + } + + public String getName() { + return this.name; + } + + public String getAddress() { + return this.address; + } + + public int getPort() { + return this.port; + } + + public String getUser() { + return this.user; + } + + public String getPassword() { + return this.password; + } + + public String getAccess() { + return this.access; + } + + public long getLastConnected() { + return this.lastConnected; + } + + public void setData(String name, String address, int port, String user, String password, String access) { + this.name = name; + this.address = address; + this.port = port; + this.user = user; + this.password = password; + this.access = access; + } + + public void setLastConnected() { + this.lastConnected = System.currentTimeMillis(); + } + + public int compareTo(ServerInfo comp) { + return this.lastConnected < comp.lastConnected ? 1 : (this.lastConnected > comp.lastConnected ? -1 : this.name.compareTo(comp.name)); + } + + public void select(boolean isDoubleClick, int mouseX, int mouseY) { + GuiServers.this.selectButton.enabled = true; + GuiServers.this.deleteButton.enabled = true; + GuiServers.this.editButton.enabled = true; + GuiServers.this.copyButton.enabled = true; + + if(isDoubleClick) { + GuiServers.this.use(GuiServers.this.selectButton, Mode.PRIMARY); + } + } + + public void draw(int x, int y, int mouseXIn, int mouseYIn, boolean hover) { + Drawing.drawText(this.name + TextColor.GRAY + " - " + TextColor.RESET + this.user, x + 2, y, 0xffffffff); + Drawing.drawText(this.address + TextColor.GRAY + " Port " + TextColor.RESET + this.port, x + 2, y + 18, 0xff808080); + Drawing.drawText("Zuletzt verbunden: " + (this.lastConnected == -1L ? "nie" : DATE_FORMAT.format(new Date(this.lastConnected))), x + 2, y + 18 + 16, 0xff808080); + } + } + + public static final GuiServers INSTANCE = new GuiServers(); + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss"); + private static final File SERVERS_FILE = new File("servers.cfg"); + + private ActButton deleteButton; + private ActButton selectButton; + private ActButton copyButton; + private ActButton editButton; + private ActButton createButton; + + private GuiServers() { + } + + public void init(int width, int height) { + super.init(width, height); + this.setDimensions(width, height, 32, height - 60); + this.elements.clear(); + if(SERVERS_FILE.exists()) { + try { + String[] lines = FileUtils.read(SERVERS_FILE).split("\n"); + String name = ""; + String address = ""; + int port = -1; + String user = ""; + String password = ""; + String access = ""; + long time = -1L; + for(int z = 0; z <= lines.length; z++) { + String line = z == lines.length ? null : lines[z]; + if(line == null || (line.startsWith("[") && line.endsWith("]"))) { + if(!name.isEmpty() && !address.isEmpty() && !user.isEmpty() && user.length() < Player.MAX_USER_LENGTH && Player.isValidUser(user) && password.length() < Player.MAX_PASS_LENGTH && access.length() < Player.MAX_PASS_LENGTH && address.length() < 128 && name.length() < 128 && port >= 0 && port < 65536) + this.elements.add(new ServerInfo(name, address, port, user, password, access, time)); + if(line != null) { + address = ""; + port = -1; + user = ""; + password = ""; + access = ""; + time = -1L; + name = line.substring(1, line.length() - 1); + } + } + else { + Tuple value = Util.getKeyValue(line); + if(value.first.equals("address")) + address = value.second; + else if(value.first.equals("port")) + try { + port = Integer.parseInt(value.second); + } + catch(NumberFormatException e) { + } + else if(value.first.equals("user")) + user = value.second; + else if(value.first.equals("password")) + password = value.second; + else if(value.first.equals("access")) + access = value.second; + else if(value.first.equals("connected")) + try { + time = Long.parseLong(value.second); + } + catch(NumberFormatException e) { + } + } + } + Collections.sort(this.elements); + } + catch(Exception e) { + Log.IO.error("Konnte Serverliste nicht laden", e); + this.elements.clear(); + } + } + + this.add(this.selectButton = new ActButton(width / 2 - 383, height - 56, 150, 24, this, "Verbinden")); + this.add(this.createButton = new ActButton(width / 2 + 233, height - 56, 150, 24, this, "Hinzufügen ...")); + this.add(this.deleteButton = new ActButton(width / 2 - 229, height - 28, 150, 24, this, "Löschen")); + this.add(this.editButton = new ActButton(width / 2 - 75, height - 28, 150, 24, this, "Bearbeiten")); + this.add(this.copyButton = new ActButton(width / 2 - 383, height - 28, 150, 24, this, "Kopieren")); + this.add(new NavButton(width / 2 - 75, height - 56, 150, 24, GuiConnect.INSTANCE, "Schnellverbdg.")); + this.add(new NavButton(width / 2 + 233, height - 28, 150, 24, GuiMenu.INSTANCE, "Abbrechen")); + + this.selectButton.enabled = false; + this.deleteButton.enabled = false; + this.editButton.enabled = false; + this.copyButton.enabled = false; + } + + public void onGuiClosed() { + this.save(); + } + + public void applyServer(ServerInfo server) { + if(this.selectedElement < 0) + this.elements.add(server); + this.save(); + this.gm.displayGuiScreen(this); + } + + private void save() { + try { + StringBuilder sb = new StringBuilder(); + for(ServerInfo server : this.elements) { + if(sb.length() > 0) + sb.append("\n"); + sb.append("[" + server.getName() + "]\n"); + sb.append("address " + server.getAddress() + "\n"); + sb.append("port " + server.getPort() + "\n"); + sb.append("user " + server.getUser() + "\n"); + sb.append("password " + server.getPassword() + "\n"); + sb.append("access " + server.getAccess() + "\n"); + sb.append("connected " + server.getLastConnected()); + } + FileUtils.write(SERVERS_FILE, sb.toString()); + } + catch(Exception e) { + Log.IO.error("Konnte Serverliste nicht speichern", e); + } + } + + public String getTitle() { + return "Server auswählen"; + } + + public int getListWidth() { + return 660; + } + + public int getSlotHeight() { + return 56; + } + + public void use(ActButton button, Mode mode) { + if(button == this.deleteButton) { + if(this.selectedElement >= 0) { + this.elements.remove(this.selectedElement); + this.gm.displayGuiScreen(this); + } + } + else if(button == this.selectButton) { + ServerInfo server = this.getSelected(); + if(server != null) { + server.setLastConnected(); + this.gm.connect(server.address, server.port, server.user, server.password, server.access); + } + } + else if(button == this.createButton) { + this.setSelected(-1); + this.gm.displayGuiScreen(new GuiConnect(new ServerInfo("", "", Config.PORT, "", "", "", -1L))); + } + else if(button == this.editButton) { + ServerInfo server = this.getSelected(); + if(server != null) + this.gm.displayGuiScreen(new GuiConnect(server)); + } + else if(button == this.copyButton) { + ServerInfo server = this.getSelected(); + if(server != null) { + this.setSelected(-1); + this.gm.displayGuiScreen(new GuiConnect(new ServerInfo(server.name, server.address, server.port, server.user, server.address, server.access, -1L))); + } + } + } +} diff --git a/java/src/game/network/PacketDecoder.java b/java/src/game/network/PacketDecoder.java index 13a47a0..3fb1715 100755 --- a/java/src/game/network/PacketDecoder.java +++ b/java/src/game/network/PacketDecoder.java @@ -42,7 +42,7 @@ public class PacketDecoder extends ByteToMessageDecoder // if (Log.isTraceEnabled()) // { - // Log.SYSTEM.info("EIN: [" + p_decode_1_.channel().attr(NetConnection.ATTR_STATE).get() + ":" + i + "] " + packet.getClass().getName()); +// Log.SYSTEM.info("EIN: [" + p_decode_1_.channel().attr(NetConnection.ATTR_STATE).get() + ":" + i + "] " + packet.getClass().getName()); // } } }