diff --git a/client/src/client/Client.java b/client/src/client/Client.java index 3547751..0d67257 100755 --- a/client/src/client/Client.java +++ b/client/src/client/Client.java @@ -765,6 +765,7 @@ public class Client implements IThreadListener { else if (this.connection != null) { this.connection.processReceivedPackets(); + this.connection.checkDisconnected(); } } @@ -2388,11 +2389,9 @@ public class Client implements IThreadListener { } public void unload(boolean loading) { - if(this.world != null) { - if(this.getNetHandler() != null) - this.getNetHandler().getNetworkManager().closeChannel("Quitting"); - this.unloadWorld(); - } + if(this.world != null && this.getNetHandler() != null) + this.getNetHandler().getNetworkManager().closeChannel("Quitting"); + this.unloadWorld(); this.displayGuiScreen(GuiMenu.INSTANCE); } diff --git a/client/src/client/gui/ingame/GuiForm.java b/client/src/client/gui/ingame/GuiForm.java new file mode 100644 index 0000000..33dd965 --- /dev/null +++ b/client/src/client/gui/ingame/GuiForm.java @@ -0,0 +1,118 @@ +package client.gui.ingame; + +import client.gui.Gui; +import client.gui.element.ActButton; +import client.gui.element.ActButton.Mode; +import client.gui.element.Element; +import client.gui.element.Label; +import client.gui.element.NavButton; +import client.gui.element.Switch; +import client.gui.element.Textbox; +import client.gui.element.Textbox.Action; +import client.gui.element.Toggle; +import client.network.ClientPlayer; +import common.color.TextColor; +import common.packet.CPacketForm; +import common.util.ExtMath; +import common.util.Triplet; + +public class GuiForm extends Gui implements ActButton.Callback { + private final int id; + private final String title; + private final Element[] inputs; + private final Label[] labels; + private final Triplet[] inputData; + private final Object[] outputData; + + private boolean sent; + + public void init(int width, int height) { + this.add(new Label(0, -100, 300, 20, this.title)); + for(int z = 0; z < this.inputs.length; z++) { + final int index = z; + final String name = this.inputData[z].first; + Object obj = this.inputData[z].second; + int param = this.inputData[z].third; + if(obj instanceof Boolean) { + this.inputs[z] = this.add(new Toggle(0, 50 * z, 300, 24, (Boolean)obj, (Boolean)obj, new Toggle.Callback() { + public void use(Toggle elem, boolean value) { + GuiForm.this.outputData[index] = value; + } + }, name)); + } + else if(obj instanceof String[]) { + final String[] strs = (String[])obj; + param = ExtMath.clampi(param, 0, strs.length - 1); + this.inputs[z] = this.add(new Switch(0, 50 * z, 300, 24, strs, strs[param], strs[param], new Switch.Callback() { + public void use(Switch elem, String value) { + for(int n = 0; n < strs.length; n++) { + if(value == strs[n]) { + GuiForm.this.outputData[index] = n; + break; + } + } + } + }, name)); + } + else { + this.labels[z] = this.add(new Label(0, 50 * z - 20, 300, 20, name, true)); + this.inputs[z] = this.add(new Textbox(0, 50 * z, 300, 24, Math.min(param & 0xffff, 256), true, new Textbox.Callback() { + public void use(Textbox elem, Action value) { + if(value == Action.FOCUS) + GuiForm.this.labels[index].setText(name); + } + }, (String)obj)); + } + } + this.add(new NavButton(0, 50 * (this.inputs.length + 1), 148, 24, null, "Abbrechen")); + this.add(new ActButton(152, 50 * (this.inputs.length + 1), 148, 24, this, "Senden")); + this.shift(); + } + + public String getTitle() { + return this.title; + } + + public void onGuiClosed() { + if(!this.sent) { + ClientPlayer nethandler = this.gm.getNetHandler(); + if(nethandler != null) { + nethandler.addToSendQueue(new CPacketForm(this.id, null)); + } + } + } + + public GuiForm(int id, String title, Triplet[] data) { + this.id = id; + this.title = title; + this.inputs = new Element[data.length]; + this.labels = new Label[data.length]; + this.inputData = data; + this.outputData = new Object[data.length]; + for(int z = 0; z < data.length; z++) { + Object obj = data[z].second; + this.outputData[z] = obj instanceof String[] ? data[z].third : obj; + } + } + + public void use(ActButton elem, Mode action) { + for(int z = 0; z < this.inputs.length; z++) { + if(this.inputs[z] instanceof Textbox) { + int min = this.inputData[z].third >> 16; + String text = this.inputs[z].getText(); + if(text.length() < min) { + if(!GuiForm.this.labels[z].getText().startsWith("" + TextColor.RED)) + GuiForm.this.labels[z].setText(TextColor.RED + GuiForm.this.labels[z].getText()); + return; + } + this.outputData[z] = text; + } + } + this.sent = true; + ClientPlayer nethandler = this.gm.getNetHandler(); + if(nethandler != null) { + nethandler.addToSendQueue(new CPacketForm(this.id, this.outputData)); + } + this.gm.displayGuiScreen(null); + } +} diff --git a/client/src/client/gui/ingame/GuiSign.java b/client/src/client/gui/ingame/GuiSign.java index 457c151..65eb72c 100644 --- a/client/src/client/gui/ingame/GuiSign.java +++ b/client/src/client/gui/ingame/GuiSign.java @@ -1,6 +1,7 @@ package client.gui.ingame; import client.gui.Gui; +import client.gui.element.Label; import client.gui.element.NavButton; import client.gui.element.Textbox; import client.gui.element.Textbox.Action; @@ -10,11 +11,14 @@ import common.util.BlockPos; public class GuiSign extends Gui implements Textbox.Callback { private final BlockPos position; - private final Textbox[] lines = new Textbox[4]; - private final String[] tempLines = new String[this.lines.length]; + private final Textbox[] lines; + private final String[] tempLines; public void init(int width, int height) { + this.add(new Label(0, -140, 300, 20, "Bearbeite Schild")); + this.add(new Label(0, -80, 300, 20, String.format("%d, %d, %d", this.position.getX(), this.position.getY(), this.position.getZ()))); + this.add(new Label(0, -50, 300, 20, this.gm.world == null ? "" : this.gm.world.dimension.getFormattedName(false))); for(int z = 0; z < this.lines.length; z++) { this.lines[z] = this.add(new Textbox(0, 40 * z, 300, 24, 50, true, this, this.tempLines[z] == null ? "" : this.tempLines[z])); } @@ -25,7 +29,6 @@ public class GuiSign extends Gui implements Textbox.Callback { public String getTitle() { return "Schild bearbeiten"; } - public void onGuiClosed() { ClientPlayer nethandler = this.gm.getNetHandler(); @@ -39,7 +42,9 @@ public class GuiSign extends Gui implements Textbox.Callback { public GuiSign(BlockPos sign, String[] lines) { this.position = sign; - System.arraycopy(lines, 0, this.tempLines, 0, this.lines.length); + this.lines = new Textbox[lines.length]; + this.tempLines = new String[lines.length]; + System.arraycopy(lines, 0, this.tempLines, 0, lines.length); } public void use(Textbox elem, Action value) { diff --git a/client/src/client/network/ClientPlayer.java b/client/src/client/network/ClientPlayer.java index eb1cbc1..eb3c533 100755 --- a/client/src/client/network/ClientPlayer.java +++ b/client/src/client/network/ClientPlayer.java @@ -25,6 +25,7 @@ import client.gui.container.GuiMachine; import client.gui.container.GuiMerchant; import client.gui.container.GuiRepair; import client.gui.ingame.GuiSign; +import client.gui.ingame.GuiForm; import client.renderer.particle.EntityPickupFX; import client.renderer.texture.EntityTexManager; import client.world.WorldClient; @@ -104,6 +105,7 @@ import common.packet.SPacketCollectItem; import common.packet.SPacketDestroyEntities; import common.packet.SPacketDimensionName; import common.packet.SPacketDisconnect; +import common.packet.SPacketDisplayForm; import common.packet.SPacketEntityEquipment; import common.packet.SPacketEntityVelocity; import common.packet.SPacketHeldItemChange; @@ -795,7 +797,7 @@ public class ClientPlayer extends NetHandler implements IClientPlayer */ public void handleDisconnect(SPacketDisconnect packetIn) { - this.netManager.closeChannel("Getrennt"); + this.netManager.closeChannel(packetIn.getMessage()); } public void onDisconnect(String reason) @@ -1284,6 +1286,11 @@ public class ClientPlayer extends NetHandler implements IClientPlayer this.gameController.player.openEditSign((TileEntitySign)tileentity); } + + public void handleForm(SPacketDisplayForm packet) { + NetHandler.checkThread(packet, this, this.gameController, this.clientWorldController); + this.gameController.displayGuiScreen(new GuiForm(packet.getId(), packet.getTitle(), packet.getData())); + } /** * Updates a specified sign with the specified text lines @@ -2061,8 +2068,8 @@ public class ClientPlayer extends NetHandler implements IClientPlayer this.gameController.displayGuiScreen(new GuiMerchant(inventory, title, worldObj)); } - public void displayGuiSign(BlockPos pos, String[] signText) { - this.gameController.displayGuiScreen(new GuiSign(pos, signText)); + public void displayGuiSign(BlockPos pos, String[] text) { + this.gameController.displayGuiScreen(new GuiSign(pos, text)); } public void closeGui() { diff --git a/common/src/common/biome/BaseBiome.java b/common/src/common/biome/BaseBiome.java index c2de8dd..81c9b42 100644 --- a/common/src/common/biome/BaseBiome.java +++ b/common/src/common/biome/BaseBiome.java @@ -28,7 +28,7 @@ public enum BaseBiome { ICEPLAINS(12, "icePlains", "Eisebene", 0xffffff, -20.0f), ICEMOUNTAINS(13, "iceMountains", "Vereistes Bergland", 0xa0a0a0, -20.0f), MUSHROOMPLAINS(14, "mushroomPlains", "Pilzland", 0xff00ff, 16.0f, 100.0f), - BLACKENED(15, "blackened", "Schwarz", 0x000000, 0.0f, 0.0f), + BLACKENED(15, "blackened", "Schwarz", 0x000000, 0.0f, 0.0f, 0x000000, 0x303030, 0x303030), BEACH(16, "beach", "Strand", 0xfade55, 12.0f, 40.0f), DESERTHILLS(17, "desertHills", "Wüsten-Bergland", 0xd25f12, 60.0f, 0.0f), FORESTHILLS(18, "forestHills", "Wald-Bergland", 0x22551c, 8.0f, 80.0f), diff --git a/common/src/common/block/BlockSign.java b/common/src/common/block/BlockSign.java index 70691aa..aa1aedf 100755 --- a/common/src/common/block/BlockSign.java +++ b/common/src/common/block/BlockSign.java @@ -1,5 +1,7 @@ package common.block; +import common.entity.npc.EntityNPC; +import common.init.Config; import common.init.Items; import common.item.Item; import common.material.Material; @@ -8,6 +10,7 @@ import common.tileentity.TileEntity; import common.tileentity.TileEntitySign; import common.util.BlockPos; import common.util.BoundingBox; +import common.util.Facing; import common.world.IBlockAccess; import common.world.State; import common.world.World; @@ -22,6 +25,20 @@ public class BlockSign extends BlockContainer this.setBlockBounds(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, f1, 0.5F + f); } + public boolean onBlockActivated(World worldIn, BlockPos pos, State state, EntityNPC playerIn, Facing side, float hitX, float hitY, float hitZ) + { + if (!worldIn.client && Config.editSigns) + { + TileEntity tileentity = worldIn.getTileEntity(pos); + + if (tileentity instanceof TileEntitySign) + { + playerIn.openEditSign((TileEntitySign)tileentity); + } + } + return true; + } + public BoundingBox getCollisionBoundingBox(World worldIn, BlockPos pos, State state) { return null; diff --git a/common/src/common/init/Config.java b/common/src/common/init/Config.java index 3393db2..483ee54 100755 --- a/common/src/common/init/Config.java +++ b/common/src/common/init/Config.java @@ -333,8 +333,12 @@ public abstract class Config { public static boolean itemFallDamage = true; @Var(name = "registration") public static boolean register = true; + @Var(name = "authentication") + public static boolean auth = true; @Var(name = "preload_chunks") public static boolean preload = true; + @Var(name = "signEditing") + public static boolean editSigns = true; @Var(name = "keepInventory") public static boolean keepInventory = false; @@ -348,8 +352,6 @@ public abstract class Config { public static boolean rabidRabbits = false; @Var(name = "snowStacking") public static boolean snowStack = false; - @Var(name = "authentication") - public static boolean auth = false; // @Var(name = "teleportForAll") // public static boolean teleportAllowed = false; // @Var(name = "preload_chunks_all") // Vorsicht Lag!! @@ -454,6 +456,8 @@ public abstract class Config { public static int eggTimer = 6000; @Var(name = "connectionTimeout", min = 10, max = 300) public static int timeout = 30; + @Var(name = "passwordMinLength", min = 1, max = 32) + public static int minPassLength = 8; // @Var(name = "spawnX", min = -World.MAX_SIZE + 1, max = World.MAX_SIZE - 1) // public static int spawnX = 0; diff --git a/common/src/common/network/IClientPlayer.java b/common/src/common/network/IClientPlayer.java index fc6ac1d..b412c36 100644 --- a/common/src/common/network/IClientPlayer.java +++ b/common/src/common/network/IClientPlayer.java @@ -45,6 +45,7 @@ import common.packet.SPacketCollectItem; import common.packet.SPacketDestroyEntities; import common.packet.SPacketDimensionName; import common.packet.SPacketDisconnect; +import common.packet.SPacketDisplayForm; import common.packet.SPacketEntityEquipment; import common.packet.SPacketEntityVelocity; import common.packet.SPacketHeldItemChange; @@ -146,11 +147,12 @@ public interface IClientPlayer { void handleTrades(SPacketTrades packetIn); void handleWorld(SPacketWorld packetIn); void handleDimName(SPacketDimensionName packetIn); + void handleForm(SPacketDisplayForm packet); void displayGUIChest(IInventory chestInventory, InventoryPlayer inventory); void displayGui(IInteractionObject guiOwner, InventoryPlayer inventory, World worldObj); void displayGuiHorse(EntityHorse horse, InventoryPlayer inventory, IInventory horseInventory); void displayGuiMerchant(String title, InventoryPlayer inventory, World worldObj); - void displayGuiSign(BlockPos pos, String[] signText); + void displayGuiSign(BlockPos pos, String[] text); void closeGui(); } \ No newline at end of file diff --git a/common/src/common/network/IPlayer.java b/common/src/common/network/IPlayer.java index a78d4fb..42d3fb6 100644 --- a/common/src/common/network/IPlayer.java +++ b/common/src/common/network/IPlayer.java @@ -16,6 +16,7 @@ import common.packet.CPacketBreak; import common.packet.CPacketCheat; import common.packet.CPacketClick; import common.packet.CPacketComplete; +import common.packet.CPacketForm; import common.packet.CPacketInput; import common.packet.CPacketKeepAlive; import common.packet.CPacketMessage; @@ -166,6 +167,8 @@ public interface IPlayer { void processSkin(CPacketSkin packetIn); void processBook(CPacketBook packetIn); + + void processForm(CPacketForm packet); List getLoadedChunkList(); double getManagedX(); diff --git a/common/src/common/network/PacketRegistry.java b/common/src/common/network/PacketRegistry.java index 60f2e0d..0a13153 100755 --- a/common/src/common/network/PacketRegistry.java +++ b/common/src/common/network/PacketRegistry.java @@ -11,6 +11,7 @@ import common.packet.CPacketBreak; import common.packet.CPacketCheat; import common.packet.CPacketClick; import common.packet.CPacketComplete; +import common.packet.CPacketForm; import common.packet.CPacketInput; import common.packet.CPacketKeepAlive; import common.packet.CPacketMessage; @@ -63,6 +64,7 @@ import common.packet.SPacketCollectItem; import common.packet.SPacketDestroyEntities; import common.packet.SPacketDimensionName; import common.packet.SPacketDisconnect; +import common.packet.SPacketDisplayForm; import common.packet.SPacketEntityEquipment; import common.packet.SPacketEntityVelocity; import common.packet.SPacketHeldItemChange; @@ -181,6 +183,7 @@ public enum PacketRegistry this.server(SPacketCharacterList.class); this.server(SPacketServerTick.class); this.server(SPacketLoading.class); + this.server(SPacketDisplayForm.class); this.client(CPacketKeepAlive.class); this.client(CPacketMessage.class); @@ -198,7 +201,7 @@ public enum PacketRegistry this.client(CPacketSkin.class); this.client(CPacketSign.class); this.client(CPacketBook.class); -// this.client(CPacketCmdBlock.class); + this.client(CPacketForm.class); } }; diff --git a/common/src/common/packet/CPacketForm.java b/common/src/common/packet/CPacketForm.java new file mode 100644 index 0000000..136fccc --- /dev/null +++ b/common/src/common/packet/CPacketForm.java @@ -0,0 +1,86 @@ +package common.packet; + +import java.io.IOException; + +import common.network.IPlayer; +import common.network.Packet; +import common.network.PacketBuffer; + +public class CPacketForm implements Packet +{ + private int id; + private Object[] data; + + public CPacketForm() + { + } + + public CPacketForm(int id, Object[] data) + { + this.id = id; + this.data = data; + } + + public void readPacketData(PacketBuffer buf) throws IOException + { + this.id = buf.readVarIntFromBuffer(); + if(!buf.readBoolean()) { + this.data = null; + return; + } + this.data = new Object[buf.readVarIntFromBuffer()]; + for(int z = 0; z < this.data.length; z++) { + Object obj; + switch(buf.readByte()) { + case 0: + obj = buf.readBoolean(); + break; + case 1: + obj = buf.readVarIntFromBuffer(); + break; + default: + obj = buf.readStringFromBuffer(256); + break; + } + this.data[z] = obj; + } + } + + public void writePacketData(PacketBuffer buf) throws IOException + { + buf.writeVarIntToBuffer(this.id); + buf.writeBoolean(this.data != null); + if(this.data == null) + return; + buf.writeVarIntToBuffer(this.data.length); + for(int z = 0; z < this.data.length; z++) { + Object obj = this.data[z]; + if(obj instanceof Boolean) { + buf.writeByte(0); + buf.writeBoolean((Boolean)obj); + } + else if(obj instanceof Integer) { + buf.writeByte(1); + buf.writeVarIntToBuffer((Integer)obj); + } + else { + buf.writeByte(2); + buf.writeString((String)obj); + } + } + } + + public void processPacket(IPlayer handler) + { + handler.processForm(this); + } + + public Object[] getData() + { + return this.data; + } + + public int getId() { + return this.id; + } +} diff --git a/common/src/common/packet/SPacketDisconnect.java b/common/src/common/packet/SPacketDisconnect.java index 5b690b7..133acdc 100755 --- a/common/src/common/packet/SPacketDisconnect.java +++ b/common/src/common/packet/SPacketDisconnect.java @@ -6,22 +6,29 @@ import common.network.IClientPlayer; import common.network.Packet; import common.network.PacketBuffer; -public class SPacketDisconnect implements Packet -{ - public SPacketDisconnect() - { - } - - public void readPacketData(PacketBuffer buf) throws IOException - { - } - - public void writePacketData(PacketBuffer buf) throws IOException - { - } - - public void processPacket(IClientPlayer handler) - { - handler.handleDisconnect(this); - } +public class SPacketDisconnect implements Packet { + private String message; + + public SPacketDisconnect() { + } + + public SPacketDisconnect(String message) { + this.message = message; + } + + public void readPacketData(PacketBuffer buf) throws IOException { + this.message = buf.readStringFromBuffer(2048); + } + + public void writePacketData(PacketBuffer buf) throws IOException { + buf.writeString(this.message); + } + + public void processPacket(IClientPlayer handler) { + handler.handleDisconnect(this); + } + + public String getMessage() { + return this.message; + } } diff --git a/common/src/common/packet/SPacketDisplayForm.java b/common/src/common/packet/SPacketDisplayForm.java new file mode 100644 index 0000000..372e8af --- /dev/null +++ b/common/src/common/packet/SPacketDisplayForm.java @@ -0,0 +1,99 @@ +package common.packet; + +import java.io.IOException; + +import common.network.IClientPlayer; +import common.network.Packet; +import common.network.PacketBuffer; +import common.util.Triplet; + +public class SPacketDisplayForm implements Packet +{ + private int id; + private String title; + private Triplet[] data; + + public SPacketDisplayForm() + { + } + + public SPacketDisplayForm(int id, String title, Triplet[] data) + { + this.id = id; + this.title = title; + this.data = data; + } + + public void processPacket(IClientPlayer handler) + { + handler.handleForm(this); + } + + public void readPacketData(PacketBuffer buf) throws IOException + { + this.id = buf.readVarIntFromBuffer(); + this.title = buf.readStringFromBuffer(256); + this.data = new Triplet[buf.readVarIntFromBuffer()]; + for(int z = 0; z < this.data.length; z++) { + String name = buf.readStringFromBuffer(64); + Object obj; + switch(buf.readByte()) { + case 0: + obj = buf.readBoolean(); + break; + case 1: + String[] strs = new String[buf.readVarIntFromBuffer()]; + obj = strs; + for(int n = 0; n < strs.length; n++) { + strs[n] = buf.readStringFromBuffer(128); + } + break; + default: + obj = buf.readStringFromBuffer(256); + break; + } + this.data[z] = new Triplet(name, obj, buf.readVarIntFromBuffer()); + } + } + + public void writePacketData(PacketBuffer buf) throws IOException + { + buf.writeVarIntToBuffer(this.id); + buf.writeString(this.title); + buf.writeVarIntToBuffer(this.data.length); + for(int z = 0; z < this.data.length; z++) { + buf.writeString(this.data[z].first); + Object obj = this.data[z].second; + if(obj instanceof Boolean) { + buf.writeByte(0); + buf.writeBoolean((Boolean)obj); + } + else if(obj instanceof String[]) { + buf.writeByte(1); + String[] strs = (String[])obj; + buf.writeVarIntToBuffer(strs.length); + for(int n = 0; n < strs.length; n++) { + buf.writeString(strs[n]); + } + } + else { + buf.writeByte(2); + buf.writeString((String)obj); + } + buf.writeVarIntToBuffer(this.data[z].third); + } + } + + public Triplet[] getData() + { + return this.data; + } + + public String getTitle() { + return this.title; + } + + public int getId() { + return this.id; + } +} diff --git a/common/src/common/util/Triplet.java b/common/src/common/util/Triplet.java new file mode 100644 index 0000000..6029985 --- /dev/null +++ b/common/src/common/util/Triplet.java @@ -0,0 +1,10 @@ +package common.util; + +public class Triplet extends Tuple { + public final U third; + + public Triplet(S first, T second, U third) { + super(first, second); + this.third = third; + } +} diff --git a/server/src/server/Server.java b/server/src/server/Server.java index 4e33741..a85b8b8 100755 --- a/server/src/server/Server.java +++ b/server/src/server/Server.java @@ -15,6 +15,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Queue; +import java.util.Map.Entry; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; @@ -36,6 +37,7 @@ import common.init.Config; import common.init.EntityRegistry; import common.init.Registry; import common.init.UniverseRegistry; +import common.init.Config.ValueType; import common.log.Log; import common.nbt.NBTLoader; import common.nbt.NBTTagCompound; @@ -69,7 +71,6 @@ import common.util.ExtMath; import common.util.LazyLoadBase; import common.util.PortalType; import common.util.Position; -import common.util.Tuple; import common.util.Util; import common.util.WorldPos; import common.world.World; @@ -90,6 +91,7 @@ import server.biome.Biome; import server.clipboard.ReorderRegistry; import server.clipboard.RotationRegistry; import server.command.CommandEnvironment; +import server.command.Executor; import server.command.FixedExecutor; import server.network.HandshakeHandler; import server.network.Player; @@ -121,10 +123,11 @@ public final class Server implements IThreadListener { private WorldServer space; private ChannelFuture endpoint; - + private boolean running = true; private boolean stopped; private boolean started; + private String endMessage = "Server beendet"; private long currentTime = System.nanoTime() / 1000L; private long tpsTarget; @@ -333,6 +336,90 @@ public final class Server implements IThreadListener { } } + public boolean setVar(Executor exec, String line) { + if(line.length() < 1) { + for(Entry entry : Config.VARS.entrySet()) { + Config.Value cvar = entry.getValue(); + String v = cvar.getValue(); + String comp = TextColor.YELLOW + entry.getKey() + TextColor.GRAY + " = "; + if(entry.getKey().equals("password") && !v.isEmpty()) + comp += TextColor.NEON + "'****'"; + else if(cvar.type == ValueType.STRING) + comp += TextColor.NEON + "'" + v + "'"; + else + comp += ((cvar.type == ValueType.BOOLEAN ? (v.equals("true") ? TextColor.GREEN : TextColor.RED) : TextColor.BLUE)) + v; + if(!cvar.def.equals(v)) { + comp += TextColor.GRAY + " (" + TextColor.BROWN + cvar.def + TextColor.GRAY + ")"; + } + exec.logConsole(comp); + } + exec.logConsole(TextColor.GREEN + "SVARs insgesamt registriert: %d", Config.VARS.size()); + return true; + } + line = line.trim(); + String[] args = /* line.isEmpty() ? new String[0] : */ line.split(" ", -1); + if(args.length == 1) { +// case 0: +// break; +// case 1: + Config.Value cfg = Config.VARS.get(args[0]); + if(cfg == null) + return false; + String v = cfg.getValue(); + String comp = TextColor.YELLOW + args[0] + TextColor.GRAY + " = "; + if(cfg.type == ValueType.STRING) + comp += TextColor.NEON + "'" + v + "'"; + else + comp += ((cfg.type == ValueType.BOOLEAN ? (v.equals("true") ? TextColor.GREEN : TextColor.RED) : TextColor.BLUE)) + v; + if(!cfg.def.equals(v)) + comp += TextColor.GRAY + " (" + TextColor.BROWN + cfg.def + TextColor.GRAY + ")"; + exec.logConsole(comp); +// break; +// default: + } + else { + Config.Value cv = Config.VARS.get(args[0]); + if(cv == null) + return false; + String value = args[1]; + if(cv.type == ValueType.STRING && "\"\"".equals(value)) { + value = ""; + } +// else if(cv.type == ValueType.BOOLEAN && "toggle".equalsIgnoreCase(value)) { +// value = "" + !Boolean.parseBoolean(cv.getValue()); +// } +// else + if(cv.type == ValueType.BOOLEAN && !"true".equals(value) && !"false".equals(value)) { + if(!value.equalsIgnoreCase("true") && !value.equalsIgnoreCase("false")) { + exec.logConsole(TextColor.DRED + "'%s' ist nicht 'true' oder 'false'", value); + return true; + } + value = value.toLowerCase(); + } + if(cv.type == ValueType.INTEGER) { + try { + Integer.parseInt(value); + } + catch(NumberFormatException e) { + exec.logConsole(TextColor.DRED + "'%s' ist keine gültige Zahl", value); + return true; + } + } + else if(cv.type == ValueType.FLOAT) { + try { + Float.parseFloat(value); + } + catch(NumberFormatException e) { + exec.logConsole(TextColor.DRED + "'%s' ist keine gültige Zahl", value); + return true; + } + } + Config.set(args[0], value, true); + exec.logConsole(TextColor.YELLOW + "%s" + TextColor.GRAY + " -> " + ((cv.type == ValueType.BOOLEAN ? (cv.getValue().equals("true") ? TextColor.GREEN : TextColor.RED) : (cv.type == ValueType.STRING ? TextColor.NEON : TextColor.BLUE))) + "%s", args[0], cv.type == ValueType.STRING ? ("'" + cv.getValue() + "'") : cv.getValue()); + } + return true; + } + public void run(int port) { long time = System.currentTimeMillis(); Log.JNI.info("Starte " + Config.NAME + " Server Version " + Config.VERSION); @@ -407,17 +494,12 @@ public final class Server implements IThreadListener { } if(line == null) break; - if(line.startsWith("#")) { - line = line.substring(1); - Tuple data = Util.getKeyValue(line); - if(data.first.equals("end")) - 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)); + FixedExecutor exec = new FixedExecutor(Server.this, "#con", "KONSOLE", null); + if(!Server.this.setVar(exec, cmd)) + Server.this.scriptEnv.execute(cmd, exec); } }); } @@ -770,9 +852,9 @@ public final class Server implements IThreadListener { if(!Config.register) return "Anmeldung neuer Accounts ist auf diesem Server deaktiviert (Whitelisted)"; if(loginPass.length() == 0) - return "Ein neues Passwort ist erforderlich um diesen Server zu betreten (mindestens 8 Zeichen)"; - if(loginPass.length() < 8) - return "Passwort ist zu kurz, mindestens 8 Zeichen"; + return "Ein neues Passwort ist erforderlich um diesen Server zu betreten (mindestens " + Config.minPassLength + " Zeichen)"; + if(loginPass.length() < Config.minPassLength) + return "Passwort ist zu kurz, mindestens " + Config.minPassLength + " Zeichen"; conn.setPassword(loginPass); Log.JNI.info(loginUser + " registrierte sich mit Passwort"); } @@ -1135,42 +1217,12 @@ public final class Server implements IThreadListener { player.connection.setPlayerHealthUpdated(); player.connection.sendPacket(new SPacketHeldItemChange(player.inventory.currentItem)); } - - private void setLanEndpoint(int port) throws IOException { - synchronized(this.serverThread) { - if(this.endpoint != null) - this.unsetLanEndpoint(); - // throw new IllegalStateException("Eingangspunkt bereits gesetzt"); - Log.JNI.info("Öffne Port %d auf 0.0.0.0 (Timeout %ds)", port, Config.timeout); - this.endpoint = ((ServerBootstrap)((ServerBootstrap)(new ServerBootstrap()).channel(NioServerSocketChannel.class)).childHandler(new ChannelInitializer() { - protected void initChannel(Channel channel) throws Exception { - try { - channel.config().setOption(ChannelOption.TCP_NODELAY, Boolean.valueOf(true)); - } - catch(ChannelException e) { - } - channel.pipeline().addLast((String)"timeout", (ChannelHandler)(new ReadTimeoutHandler(Config.timeout))) - .addLast((String)"splitter", (ChannelHandler)(new PacketSplitter())) - .addLast((String)"decoder", (ChannelHandler)(new PacketDecoder(true))) - .addLast((String)"prepender", (ChannelHandler)(new PacketPrepender())) - .addLast((String)"encoder", (ChannelHandler)(new PacketEncoder(false))); - NetConnection manager = new NetConnection(); - Server.this.clients.add(manager); - channel.pipeline().addLast((String)"packet_handler", (ChannelHandler)manager); - manager.setNetHandler(new HandshakeHandler(Server.this, manager)); - } - }).group(SERVER_NIO_EVENTLOOP.getValue()).localAddress((InetAddress)null, port)).bind().syncUninterruptibly(); - } - } - private void unsetLanEndpoint() { - for(Player conn : Lists.newArrayList(this.players)) { - conn.disconnect(); - } - this.terminateEndpoint(); - } - - private void terminateEndpoint() { + private void terminateEndpoint(String message) { + if(this.started) + for(Player conn : Lists.newArrayList(this.players)) { + conn.disconnect(message); + } synchronized(this.serverThread) { if(this.endpoint != null) { Log.JNI.info("Schließe Port"); @@ -1201,7 +1253,7 @@ public final class Server implements IThreadListener { } catch(Exception e) { Log.JNI.error(e, "Konnte Paket von " + manager.getCutAddress() + " nicht verarbeiten"); - manager.sendPacket(new SPacketDisconnect(), new GenericFutureListener>() { + manager.sendPacket(new SPacketDisconnect(e.getMessage()), new GenericFutureListener>() { public void operationComplete(Future future) throws Exception { manager.closeChannel("Fehlerhaftes Datenpaket"); } @@ -1227,11 +1279,7 @@ public final class Server implements IThreadListener { this.setProgress(-1); this.setMessage("Stoppe server"); Log.JNI.info("Beende Server"); - if(this.started) - for(Player conn : Lists.newArrayList(this.players)) { - conn.disconnect(); - } - this.terminateEndpoint(); + this.terminateEndpoint(this.endMessage); if(this.started) { Log.JNI.info("Speichere Spieler"); this.saveAllPlayerData(true); @@ -1243,34 +1291,46 @@ public final class Server implements IThreadListener { } public void bind(int port) { -// this.schedule(new Runnable() { -// public void run() { - if(port >= 0) { - try { - Server.this.setLanEndpoint(port); + synchronized(this.serverThread) { + if(port >= 0) { + try { + if(this.endpoint != null) + this.terminateEndpoint("Wechsele auf Port " + port); + // throw new IllegalStateException("Eingangspunkt bereits gesetzt"); + Log.JNI.info("Öffne Port %d auf 0.0.0.0 (Timeout %ds)", port, Config.timeout); + this.endpoint = ((ServerBootstrap)((ServerBootstrap)(new ServerBootstrap()).channel(NioServerSocketChannel.class)).childHandler(new ChannelInitializer() { + protected void initChannel(Channel channel) throws Exception { + try { + channel.config().setOption(ChannelOption.TCP_NODELAY, Boolean.valueOf(true)); + } + catch(ChannelException e) { + } + channel.pipeline().addLast((String)"timeout", (ChannelHandler)(new ReadTimeoutHandler(Config.timeout))) + .addLast((String)"splitter", (ChannelHandler)(new PacketSplitter())) + .addLast((String)"decoder", (ChannelHandler)(new PacketDecoder(true))) + .addLast((String)"prepender", (ChannelHandler)(new PacketPrepender())) + .addLast((String)"encoder", (ChannelHandler)(new PacketEncoder(false))); + NetConnection manager = new NetConnection(); + Server.this.clients.add(manager); + channel.pipeline().addLast((String)"packet_handler", (ChannelHandler)manager); + manager.setNetHandler(new HandshakeHandler(Server.this, manager)); + } + }).group(SERVER_NIO_EVENTLOOP.getValue()).localAddress((InetAddress)null, port)).bind().syncUninterruptibly(); + } + catch(Throwable e) { + Log.JNI.error(e, "**** KONNTE NICHT AN PORT " + port + " ANBINDEN!"); + } } - catch(IOException e) { - Log.JNI.error(e, "**** KONNTE NICHT AN PORT " + port + " ANBINDEN!"); + else { + if(this.endpoint != null) + this.terminateEndpoint("Trenne Verbindung"); } } - else { - Server.this.unsetLanEndpoint(); - } -// } -// }); } - public void shutdown() { -// Futures.getUnchecked(this.schedule(new Runnable() { -// public void run() { -// for(Player conn : Lists.newArrayList(Server.this.players)) { // = Server.this.getPlayer(Server.this.owner); -// // if(conn != null) -// if(conn.isLocal()) -// Server.this.removePlayer(conn); -// } -// } -// })); + public void shutdown(String message) { this.running = false; + this.endMessage = message; } public String getInfo() { diff --git a/server/src/server/command/ArgumentParser.java b/server/src/server/command/ArgumentParser.java index 4d55712..cf3b4b9 100644 --- a/server/src/server/command/ArgumentParser.java +++ b/server/src/server/command/ArgumentParser.java @@ -88,7 +88,7 @@ public abstract class ArgumentParser { public abstract Object parse(CommandEnvironment env, String input); public abstract Object getDefault(CommandEnvironment env); public abstract Collection getCompletions(CommandEnvironment env); - public abstract Class getTypeClass(); + public abstract Class getTypeClass(boolean required); public final String getName() { return this.name; diff --git a/server/src/server/command/BooleanParser.java b/server/src/server/command/BooleanParser.java index e821832..fc0935f 100644 --- a/server/src/server/command/BooleanParser.java +++ b/server/src/server/command/BooleanParser.java @@ -5,7 +5,7 @@ public class BooleanParser extends EnumParser { super(name, Boolean.class, def, true, false); } - public Class getTypeClass() { - return this.hasDefault() ? boolean.class : Boolean.class; + public Class getTypeClass(boolean required) { + return this.hasDefault() || required ? boolean.class : Boolean.class; } } diff --git a/server/src/server/command/CachedExecutable.java b/server/src/server/command/CachedExecutable.java index 55e64bb..97344af 100644 --- a/server/src/server/command/CachedExecutable.java +++ b/server/src/server/command/CachedExecutable.java @@ -54,7 +54,7 @@ public class CachedExecutable { continue; } for(ArgumentParser parser : param.getParsers()) { - classes.add(parser.getTypeClass()); + classes.add(parser.getTypeClass(param.isRequired())); } } Method method; diff --git a/server/src/server/command/Command.java b/server/src/server/command/Command.java index 56750cc..637c07d 100644 --- a/server/src/server/command/Command.java +++ b/server/src/server/command/Command.java @@ -192,6 +192,14 @@ public abstract class Command implements Executable { protected Command addString(String name, boolean allowEmpty, StringCompleter completer) { return this.addParameter(new StringParser(name, null, allowEmpty, null, null, null, completer)); } + + protected Command addString(String name, String def, boolean allowEmpty, Object ... completions) { + return this.addParameter(new StringParser(name, def, allowEmpty, null, null, null, completions)); + } + + protected Command addString(String name, String def, boolean allowEmpty, StringCompleter completer) { + return this.addParameter(new StringParser(name, def, allowEmpty, null, null, null, completer)); + } public Map getParameters() { return this.parameters; diff --git a/server/src/server/command/CommandEnvironment.java b/server/src/server/command/CommandEnvironment.java index 34d7fbf..a3a6e6a 100644 --- a/server/src/server/command/CommandEnvironment.java +++ b/server/src/server/command/CommandEnvironment.java @@ -19,9 +19,12 @@ import server.command.commands.CommandKick; import server.command.commands.CommandMessage; import server.command.commands.CommandMilk; import server.command.commands.CommandOfflinetp; +import server.command.commands.CommandPasswd; import server.command.commands.CommandPotion; +import server.command.commands.CommandRebind; import server.command.commands.CommandRemove; import server.command.commands.CommandRevoke; +import server.command.commands.CommandShutdown; import server.command.commands.CommandSpawn; import server.command.commands.CommandTele; import server.command.commands.CommandTime; @@ -269,6 +272,9 @@ public class CommandEnvironment { this.registerExecutable(new CommandWeather()); this.registerExecutable(new CommandKick()); this.registerExecutable(new CommandMessage()); + this.registerExecutable(new CommandShutdown()); + this.registerExecutable(new CommandRebind()); + this.registerExecutable(new CommandPasswd()); this.registerExecutable(new CommandHelp(this)); } diff --git a/server/src/server/command/DimensionParser.java b/server/src/server/command/DimensionParser.java index 30f9121..6263114 100644 --- a/server/src/server/command/DimensionParser.java +++ b/server/src/server/command/DimensionParser.java @@ -43,7 +43,7 @@ public class DimensionParser extends CompletingParser { return UniverseRegistry.getWorldNames(); } - public Class getTypeClass() { + public Class getTypeClass(boolean required) { return Dimension.class; } } diff --git a/server/src/server/command/DoubleParser.java b/server/src/server/command/DoubleParser.java index 353b4be..5b57bdb 100644 --- a/server/src/server/command/DoubleParser.java +++ b/server/src/server/command/DoubleParser.java @@ -75,8 +75,8 @@ public class DoubleParser extends DefaultingParser { return (Double)super.getDefault(env); } - public Class getTypeClass() { - return this.hasDefault() ? double.class : Double.class; + public Class getTypeClass(boolean required) { + return this.hasDefault() || required ? double.class : Double.class; } public Collection getCompletions(CommandEnvironment env) { diff --git a/server/src/server/command/EntityListParser.java b/server/src/server/command/EntityListParser.java index 130ebbb..fda515d 100644 --- a/server/src/server/command/EntityListParser.java +++ b/server/src/server/command/EntityListParser.java @@ -129,7 +129,7 @@ public class EntityListParser extends EntityParser { return comp; } - public Class getTypeClass() { + public Class getTypeClass(boolean required) { return List.class; } } diff --git a/server/src/server/command/EntityParser.java b/server/src/server/command/EntityParser.java index 09a88dd..e570d98 100644 --- a/server/src/server/command/EntityParser.java +++ b/server/src/server/command/EntityParser.java @@ -54,7 +54,7 @@ public class EntityParser extends PlayerEntityParser { return comp; } - public Class getTypeClass() { + public Class getTypeClass(boolean required) { return this.livingOnly ? EntityLiving.class : Entity.class; } } diff --git a/server/src/server/command/EnumParser.java b/server/src/server/command/EnumParser.java index a8b7a78..305dd00 100644 --- a/server/src/server/command/EnumParser.java +++ b/server/src/server/command/EnumParser.java @@ -44,7 +44,7 @@ public class EnumParser extends DefaultingParser { return this.selections[id]; } - public Class getTypeClass() { + public Class getTypeClass(boolean required) { return this.clazz; } } diff --git a/server/src/server/command/Executor.java b/server/src/server/command/Executor.java index d3888eb..193de3c 100644 --- a/server/src/server/command/Executor.java +++ b/server/src/server/command/Executor.java @@ -3,6 +3,7 @@ package server.command; import common.entity.Entity; import common.util.BlockPos; import common.util.Position; +import server.network.Player; public interface Executor { void logConsole(String msg); @@ -12,6 +13,14 @@ public interface Executor { Entity getPointedEntity(); BlockPos getPointedPosition(); + default boolean isConsole() { + return false; + } + + default boolean isPlayer() { + return this instanceof Player; + } + default void logConsole(String fmt, Object ... args) { this.logConsole(String.format(fmt, args)); } diff --git a/server/src/server/command/FixedExecutor.java b/server/src/server/command/FixedExecutor.java index 5f7d2cf..54d8eb8 100644 --- a/server/src/server/command/FixedExecutor.java +++ b/server/src/server/command/FixedExecutor.java @@ -50,4 +50,8 @@ public class FixedExecutor implements Executor { public BlockPos getPointedPosition() { return null; } + + public boolean isConsole() { + return true; + } } diff --git a/server/src/server/command/IntParser.java b/server/src/server/command/IntParser.java index a1673b0..4b9bdb4 100644 --- a/server/src/server/command/IntParser.java +++ b/server/src/server/command/IntParser.java @@ -33,7 +33,7 @@ public class IntParser extends DefaultingParser { return value; } - public Class getTypeClass() { - return this.hasDefault() ? int.class : Integer.class; + public Class getTypeClass(boolean required) { + return this.hasDefault() || required ? int.class : Integer.class; } } diff --git a/server/src/server/command/LongParser.java b/server/src/server/command/LongParser.java index c072ac2..ab7cf0e 100644 --- a/server/src/server/command/LongParser.java +++ b/server/src/server/command/LongParser.java @@ -31,7 +31,7 @@ public class LongParser extends DefaultingParser { return value; } - public Class getTypeClass() { - return this.hasDefault() ? long.class : Long.class; + public Class getTypeClass(boolean required) { + return this.hasDefault() || required ? long.class : Long.class; } } diff --git a/server/src/server/command/PlayerEntityListParser.java b/server/src/server/command/PlayerEntityListParser.java index d97c1e6..2ab4890 100644 --- a/server/src/server/command/PlayerEntityListParser.java +++ b/server/src/server/command/PlayerEntityListParser.java @@ -46,7 +46,7 @@ public class PlayerEntityListParser extends PlayerEntityParser { return comp; } - public Class getTypeClass() { + public Class getTypeClass(boolean required) { return List.class; } } diff --git a/server/src/server/command/PlayerEntityParser.java b/server/src/server/command/PlayerEntityParser.java index ff9eeb7..c7fee81 100644 --- a/server/src/server/command/PlayerEntityParser.java +++ b/server/src/server/command/PlayerEntityParser.java @@ -21,7 +21,7 @@ public class PlayerEntityParser extends PlayerParser { return net == null ? null : net.getPresentEntity(); } - public Class getTypeClass() { + public Class getTypeClass(boolean required) { return EntityNPC.class; } } diff --git a/server/src/server/command/PlayerListParser.java b/server/src/server/command/PlayerListParser.java index aed9691..d66c94f 100644 --- a/server/src/server/command/PlayerListParser.java +++ b/server/src/server/command/PlayerListParser.java @@ -39,7 +39,7 @@ public class PlayerListParser extends PlayerParser { return comp; } - public Class getTypeClass() { + public Class getTypeClass(boolean required) { return List.class; } } diff --git a/server/src/server/command/PlayerParser.java b/server/src/server/command/PlayerParser.java index 6e2cc07..2ca384a 100644 --- a/server/src/server/command/PlayerParser.java +++ b/server/src/server/command/PlayerParser.java @@ -20,14 +20,14 @@ public class PlayerParser extends CompletingParser { } public Object getDefault(CommandEnvironment env) { - return this.useSender && env.getExecutor() instanceof Player ? (Player)env.getExecutor() : null; + return this.useSender && env.getExecutor().isPlayer() ? (Player)env.getExecutor() : null; } public Collection getCompletions(CommandEnvironment env) { return env.getServer().getAllUsernames(); } - public Class getTypeClass() { + public Class getTypeClass(boolean required) { return Player.class; } } diff --git a/server/src/server/command/StringParser.java b/server/src/server/command/StringParser.java index b4ce0e8..5c2e35d 100644 --- a/server/src/server/command/StringParser.java +++ b/server/src/server/command/StringParser.java @@ -53,7 +53,7 @@ public class StringParser extends DefaultingParser { return input; } - public Class getTypeClass() { + public Class getTypeClass(boolean required) { return String.class; } diff --git a/server/src/server/command/TagParser.java b/server/src/server/command/TagParser.java index 848f6d8..ab1fad2 100644 --- a/server/src/server/command/TagParser.java +++ b/server/src/server/command/TagParser.java @@ -20,7 +20,7 @@ public class TagParser extends DefaultingParser { return value; } - public Class getTypeClass() { + public Class getTypeClass(boolean required) { return NBTTagCompound.class; } } diff --git a/server/src/server/command/WorldParser.java b/server/src/server/command/WorldParser.java index c76e27c..9649e30 100644 --- a/server/src/server/command/WorldParser.java +++ b/server/src/server/command/WorldParser.java @@ -42,7 +42,7 @@ public class WorldParser extends DimensionParser { return super.getCompletions(env); } - public Class getTypeClass() { + public Class getTypeClass(boolean required) { return WorldServer.class; } } diff --git a/server/src/server/command/commands/CommandKick.java b/server/src/server/command/commands/CommandKick.java index 6785b09..80b3b5e 100644 --- a/server/src/server/command/commands/CommandKick.java +++ b/server/src/server/command/commands/CommandKick.java @@ -11,16 +11,16 @@ public class CommandKick extends Command { super("kick"); this.addPlayer("player", false); + this.setParamsOptional(); + this.addString("message", "Du wurdest vom Server geworfen", false); } - 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) + public void exec(CommandEnvironment env, Executor exec, Player player, String message) { + if(player == exec) throw new RunException("Du kannst nicht dich nicht selbst vom Server werfen"); else if(player.getAdmin()) throw new RunException("%s ist ein Admin", player.getUser()); - player.disconnect(); + player.disconnect(message); exec.logConsole("%s wurde vom Server geworfen", player.getUser()); } } diff --git a/server/src/server/command/commands/CommandPasswd.java b/server/src/server/command/commands/CommandPasswd.java new file mode 100644 index 0000000..e67ee5b --- /dev/null +++ b/server/src/server/command/commands/CommandPasswd.java @@ -0,0 +1,64 @@ +package server.command.commands; + +import common.color.TextColor; +import common.init.Config; +import common.network.IPlayer; +import server.command.Command; +import server.command.CommandEnvironment; +import server.command.Executor; +import server.command.RunException; +import server.network.Player; +import server.util.Form; + +public class CommandPasswd extends Command { + public CommandPasswd() { + super("passwd"); + + this.addPlayer("player", true); + this.setParamsOptional(); + this.addString("password", false); + } + + public void exec(CommandEnvironment env, Executor exec, Player player, String password) { + if(exec.isPlayer()) { + if(password != null) + throw new RunException("Bei Verwendung als Spieler darf kein Passwort angegeben werden"); + if(player.getAdmin() && player != exec) + throw new RunException("%s ist ein Admin", player.getUser()); + ((Player)exec).displayForm(new Form() { + private Field checkField; + private Field passwordField; + private Field confirmField; + + protected void init() { + this.checkField = player != exec ? null : this.addField("Aktuelles Passwort", 0, IPlayer.MAX_PASS_LENGTH, ""); + this.passwordField = this.addField("Neues Passwort", Config.minPassLength, IPlayer.MAX_PASS_LENGTH, ""); + this.confirmField = this.addField("Passwort bestätigen", Config.minPassLength, IPlayer.MAX_PASS_LENGTH, ""); + } + + public String getTitle() { + return "Passwort für " + player.getUser() + " ändern"; + } + + protected void accept() { + if(this.checkField != null && !this.checkField.get().equals(player.getPassword())) { + exec.logConsole(TextColor.RED + "Falsches Passwort eingegeben"); + return; + } + if(!this.passwordField.get().equals(this.confirmField.get())) { + exec.logConsole(TextColor.RED + "Passwörter stimmen nicht überein"); + return; + } + player.setPassword(this.passwordField.get()); + exec.logConsole(TextColor.GREEN + "Passwort" + (player != exec ? " für %s" : "") + " gesetzt", player.getUser()); + } + }); + } + else if(exec.isConsole()) { + if(password == null) + throw new RunException("Bei Verwendung in der Konsole muss ein Passwort angegeben werden"); + player.setPassword(password); + exec.logConsole(TextColor.GREEN + "Passwort für %s gesetzt", player.getUser()); + } + } +} diff --git a/server/src/server/command/commands/CommandRebind.java b/server/src/server/command/commands/CommandRebind.java new file mode 100644 index 0000000..ad45c0e --- /dev/null +++ b/server/src/server/command/commands/CommandRebind.java @@ -0,0 +1,17 @@ +package server.command.commands; + +import server.command.Command; +import server.command.CommandEnvironment; +import server.command.Executor; + +public class CommandRebind extends Command { + public CommandRebind() { + super("rebind"); + + this.addInt("port", 1024, 65535); + } + + public void exec(CommandEnvironment env, Executor exec, int port) { + env.getServer().bind(port); + } +} diff --git a/server/src/server/command/commands/CommandRevoke.java b/server/src/server/command/commands/CommandRevoke.java index 10c88d2..075dd3d 100644 --- a/server/src/server/command/commands/CommandRevoke.java +++ b/server/src/server/command/commands/CommandRevoke.java @@ -14,7 +14,7 @@ public class CommandRevoke extends Command { } public void exec(CommandEnvironment env, Executor exec, Player player) { - if(exec instanceof Player) + if(!exec.isConsole()) 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"); diff --git a/server/src/server/command/commands/CommandShutdown.java b/server/src/server/command/commands/CommandShutdown.java new file mode 100644 index 0000000..5872df3 --- /dev/null +++ b/server/src/server/command/commands/CommandShutdown.java @@ -0,0 +1,18 @@ +package server.command.commands; + +import server.command.Command; +import server.command.CommandEnvironment; +import server.command.Executor; + +public class CommandShutdown extends Command { + public CommandShutdown() { + super("shutdown"); + + this.setParamsOptional(); + this.addString("message", "Server beendet", false); + } + + public void exec(CommandEnvironment env, Executor exec, String message) { + env.getServer().shutdown(message); + } +} diff --git a/server/src/server/command/commands/CommandSpawn.java b/server/src/server/command/commands/CommandSpawn.java index 053ff75..ab5f0a7 100644 --- a/server/src/server/command/commands/CommandSpawn.java +++ b/server/src/server/command/commands/CommandSpawn.java @@ -53,7 +53,7 @@ public class CommandSpawn extends Command { } world.strikeLightning(pos.xCoord, pos.yCoord, pos.zCoord, color, tag != null && tag.hasKey("damage", 3) ? tag.getInteger("damage") : 0, tag != null && tag.hasKey("fire", 1) && tag.getBoolean("fire"), - exec instanceof Player && tag != null && tag.hasKey("summoned", 1) && tag.getBoolean("summoned") ? ((Player)exec).getPresentEntity() : null); + exec.isPlayer() && tag != null && tag.hasKey("summoned", 1) && tag.getBoolean("summoned") ? ((Player)exec).getPresentEntity() : null); } exec.logConsole("%sBlitz bei %d, %d, %d in %s erschaffen", count == 1 ? "" : (count + "x "), (int)pos.xCoord, (int)pos.yCoord, (int)pos.zCoord, world.dimension.getFormattedName(false)); return null; diff --git a/server/src/server/network/Player.java b/server/src/server/network/Player.java index c667590..0ef2858 100755 --- a/server/src/server/network/Player.java +++ b/server/src/server/network/Player.java @@ -4,7 +4,6 @@ import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; -import java.util.Map.Entry; import java.util.Set; import java.util.function.Predicate; @@ -60,6 +59,7 @@ import common.packet.CPacketBreak; import common.packet.CPacketCheat; import common.packet.CPacketClick; import common.packet.CPacketComplete; +import common.packet.CPacketForm; import common.packet.CPacketInput; import common.packet.CPacketKeepAlive; import common.packet.CPacketMessage; @@ -88,6 +88,7 @@ import common.packet.SPacketCharacterList; import common.packet.SPacketChunkData; import common.packet.SPacketDestroyEntities; import common.packet.SPacketDisconnect; +import common.packet.SPacketDisplayForm; import common.packet.SPacketKeepAlive; import common.packet.SPacketLoading; import common.packet.SPacketMapChunkBulk; @@ -132,6 +133,7 @@ import server.clipboard.RotationRegistry; import server.clipboard.RotationValue; import server.clipboard.Vector; import server.command.Executor; +import server.util.Form; import server.world.Region; import server.world.WorldServer; @@ -165,6 +167,7 @@ public class Player extends NetHandler implements ICrafting, Executor, IPlayer private double lastPosZ; private boolean hasMoved = true; private boolean charEditor = true; + private Form form; private boolean admin; private int ping; @@ -200,6 +203,7 @@ public class Player extends NetHandler implements ICrafting, Executor, IPlayer private float lastHealth = -1.0E8F; private int lastExperience = -99999999; private int currentWindowId; + private int currentFormId; private int pointedEntity; private BlockPos pointedPosition; @@ -410,6 +414,11 @@ public class Player extends NetHandler implements ICrafting, Executor, IPlayer { this.currentWindowId = this.currentWindowId % 100 + 1; } + + private void getNextFormId() + { + this.currentFormId = this.currentFormId % 100 + 1; + } public void displayTradeGui(EntityNPC npc) { @@ -1520,9 +1529,10 @@ public class Player extends NetHandler implements ICrafting, Executor, IPlayer this.characters.set(this.selected, tag); } - public void disconnect() + public void disconnect(String message) { - this.connection.sendPacket(new SPacketDisconnect(), new GenericFutureListener < Future > () + Log.JNI.info("Trenne %s: %s", this.user, message); + this.connection.sendPacket(new SPacketDisconnect(message), new GenericFutureListener < Future > () { public void operationComplete(Future p_operationComplete_1_) throws Exception { @@ -1676,87 +1686,7 @@ public class Player extends NetHandler implements ICrafting, Executor, IPlayer private boolean setVar(String line) { if(!this.isAdmin()) return false; - if(line.length() < 1) { - for(Entry entry : Config.VARS.entrySet()) { - Config.Value cvar = entry.getValue(); - String v = cvar.getValue(); - String comp = TextColor.YELLOW + entry.getKey() + TextColor.GRAY + " = "; - if(entry.getKey().equals("password") && !v.isEmpty()) - comp += TextColor.NEON + "'****'"; - else if(cvar.type == ValueType.STRING) - comp += TextColor.NEON + "'" + v + "'"; - else - comp += ((cvar.type == ValueType.BOOLEAN ? (v.equals("true") ? TextColor.GREEN : TextColor.RED) : TextColor.BLUE)) + v; - if(!cvar.def.equals(v)) { - comp += TextColor.GRAY + " (" + TextColor.BROWN + cvar.def + TextColor.GRAY + ")"; - } - this.addConsole(comp); - } - this.addConsole(TextColor.GREEN + "SVARs insgesamt registriert: %d", Config.VARS.size()); - return true; - } - line = line.trim(); - String[] args = /* line.isEmpty() ? new String[0] : */ line.split(" ", -1); - if(args.length == 1) { -// case 0: -// break; -// case 1: - Config.Value cfg = Config.VARS.get(args[0]); - if(cfg == null) - return false; - String v = cfg.getValue(); - String comp = TextColor.YELLOW + args[0] + TextColor.GRAY + " = "; - if(cfg.type == ValueType.STRING) - comp += TextColor.NEON + "'" + v + "'"; - else - comp += ((cfg.type == ValueType.BOOLEAN ? (v.equals("true") ? TextColor.GREEN : TextColor.RED) : TextColor.BLUE)) + v; - if(!cfg.def.equals(v)) - comp += TextColor.GRAY + " (" + TextColor.BROWN + cfg.def + TextColor.GRAY + ")"; - this.addConsole(comp); -// break; -// default: - } - else { - Config.Value cv = Config.VARS.get(args[0]); - if(cv == null) - return false; - String value = args[1]; - if(cv.type == ValueType.STRING && "\"\"".equals(value)) { - value = ""; - } -// else if(cv.type == ValueType.BOOLEAN && "toggle".equalsIgnoreCase(value)) { -// value = "" + !Boolean.parseBoolean(cv.getValue()); -// } -// else - if(cv.type == ValueType.BOOLEAN && !"true".equals(value) && !"false".equals(value)) { - if(!value.equalsIgnoreCase("true") && !value.equalsIgnoreCase("false")) { - this.addConsole(TextColor.DRED + "'%s' ist nicht 'true' oder 'false'", value); - return true; - } - value = value.toLowerCase(); - } - if(cv.type == ValueType.INTEGER) { - try { - Integer.parseInt(value); - } - catch(NumberFormatException e) { - this.addConsole(TextColor.DRED + "'%s' ist keine gültige Zahl", value); - return true; - } - } - else if(cv.type == ValueType.FLOAT) { - try { - Float.parseFloat(value); - } - catch(NumberFormatException e) { - this.addConsole(TextColor.DRED + "'%s' ist keine gültige Zahl", value); - return true; - } - } - Config.set(args[0], value, true); - this.addConsole(TextColor.YELLOW + "%s" + TextColor.GRAY + " -> " + ((cv.type == ValueType.BOOLEAN ? (cv.getValue().equals("true") ? TextColor.GREEN : TextColor.RED) : (cv.type == ValueType.STRING ? TextColor.NEON : TextColor.BLUE))) + "%s", args[0], cv.type == ValueType.STRING ? ("'" + cv.getValue() + "'") : cv.getValue()); - } - return true; + return this.server.setVar(this, line); } public void setAdmin(boolean admin) { @@ -3082,6 +3012,7 @@ public class Player extends NetHandler implements ICrafting, Executor, IPlayer // this.signCommand = null; // } + tileentitysign.setPlayer(null); tileentitysign.markDirty(); worldserver.markBlockForUpdate(blockpos); } @@ -3147,6 +3078,20 @@ public class Player extends NetHandler implements ICrafting, Executor, IPlayer } } } + + public void processForm(CPacketForm packet) { + NetHandler.checkThread(packet, this, this.server); + if(this.charEditor || this.form == null || packet.getId() != this.currentFormId) + return; + this.form.accept(packet.getData()); + this.form = null; + } + + public void displayForm(Form form) { + this.form = form; + this.getNextFormId(); + this.sendPacket(new SPacketDisplayForm(this.currentFormId, form.getTitle(), form.getInputList())); + } public Entity getPointedEntity() { return this.pointedEntity != -1 && this.entity != null ? this.entity.worldObj.getEntityByID(this.pointedEntity) : null; diff --git a/server/src/server/util/Form.java b/server/src/server/util/Form.java new file mode 100644 index 0000000..cb6fbbf --- /dev/null +++ b/server/src/server/util/Form.java @@ -0,0 +1,179 @@ +package server.util; + +import java.util.List; + +import common.collect.Lists; +import common.util.Displayable; +import common.util.Triplet; + +public abstract class Form { + private abstract class FormElement { + protected final String name; + + protected FormElement(String name) { + this.name = name; + } + + protected abstract Object getInputData(); + protected abstract int getInputParameter(); + protected abstract boolean acceptValue(Object obj); + } + + protected class Toggle extends FormElement { + private boolean value; + + protected Toggle(String name, boolean value) { + super(name); + this.value = value; + } + + protected Object getInputData() { + return this.value; + } + + protected int getInputParameter() { + return 0; + } + + protected boolean acceptValue(Object obj) { + if(obj instanceof Boolean) + this.value = (Boolean)obj; + return obj instanceof Boolean; + } + + public boolean get() { + return this.value; + } + } + + protected class Switch extends FormElement { + private final T[] values; + private final int def; + + private T value; + + protected Switch(String name, T[] values, T value) { + super(name); + this.values = values; + this.value = value; + int def = 0; + for(int z = 0; z < values.length; z++) { + if(values[z] == value) { + def = z; + break; + } + } + this.def = def; + } + + protected Object getInputData() { + String[] strs = new String[this.values.length]; + for(int z = 0; z < strs.length; z++) { + strs[z] = this.values[z] instanceof Displayable ? ((Displayable)this.values[z]).getDisplay() : String.valueOf(this.values[z]); + } + return strs; + } + + protected int getInputParameter() { + return this.def; + } + + protected boolean acceptValue(Object obj) { + if(obj instanceof Integer && (Integer)obj >= 0 && (Integer)obj < this.values.length) { + this.value = this.values[(Integer)obj]; + return true; + } + return false; + } + + public T get() { + return this.value; + } + } + + protected class Field extends FormElement { + private final int minLength; + private final int maxLength; + + private String value; + + protected Field(String name, String value, int min, int max) { + super(name); + this.value = value; + this.minLength = min; + this.maxLength = max; + } + + protected Object getInputData() { + return this.value; + } + + protected int getInputParameter() { + return (this.minLength << 16) | this.maxLength; + } + + protected boolean acceptValue(Object obj) { + if(obj instanceof String && ((String)obj).length() >= this.minLength && ((String)obj).length() <= this.maxLength) { + this.value = (String)obj; + return true; + } + return false; + } + + public String get() { + return this.value; + } + } + + private final List inputs = Lists.newArrayList(); + + public Form() { + this.init(); + } + + private T add(T elem) { + this.inputs.add(elem); + return elem; + } + + protected Toggle addToggle(String name, boolean def) { + return this.add(new Toggle(name, def)); + } + + protected Switch addSwitch(String name, T def, T ... values) { + return this.add(new Switch(name, values, def)); + } + + protected Field addField(String name, int minLength, int maxLength, String def) { + return this.add(new Field(name, def, minLength, maxLength)); + } + + public abstract String getTitle(); + protected abstract void init(); + protected abstract void accept(); + + protected void cancel() { + } + + public final Triplet[] getInputList() { + Triplet[] data = new Triplet[this.inputs.size()]; + for(int z = 0; z < data.length; z++) { + data[z] = new Triplet(this.inputs.get(z).name, this.inputs.get(z).getInputData(), this.inputs.get(z).getInputParameter()); + } + return data; + } + + public final void accept(Object[] data) { + if(data == null || data.length != this.inputs.size()) { + this.cancel(); + return; + } + for(int z = 0; z < data.length; z++) { + if(!this.inputs.get(z).acceptValue(data[z])) { + this.cancel(); + return; + } + } + this.accept(); + } +}