package game.gui; import java.util.List; import game.collect.Lists; import game.Game; import game.color.TextColor; import game.gui.element.ActButton; import game.gui.element.Fill; import game.gui.element.Textbox; import game.gui.element.Textbox.Action; import game.gui.element.TransparentBox; import game.network.NetHandlerPlayServer; import game.packet.CPacketComplete; import game.util.ExtMath; import game.vars.BoolVar; import game.vars.CVar; import game.window.Keysym; import game.world.BlockPos; import game.world.HitPosition; public class GuiConsole extends Gui implements Textbox.Callback { public static final GuiConsole INSTANCE = new GuiConsole(); private final List sentMessages = Lists.newArrayList(); private boolean full; private String historyBuffer = ""; private int sentHistoryCursor = -1; private boolean playerNamesFound; private boolean waitingOnAutocomplete; private boolean reverse; private String prefixFirst; private int autocompleteIndex; private List foundPlayerNames = Lists.newArrayList(); private Textbox inputField; private TransparentBox logBox; public GuiConsole setFull(boolean full) { this.full = full; return this; } public void init(int width, int height) { if(this.full) { this.addSelector("con_autoclose", 0, 0, 160, 24); this.addSelector("con_timestamps", 160, 0, 160, 24); this.addSelector("con_loglevel", 320, 0, 160, 24); this.add(new ActButton(480, 0, 160, 24, new ActButton.Callback() { public void use(ActButton elem, ActButton.Mode action) { GuiConsole.this.reset(); GuiConsole.this.setLog(GuiConsole.this.gm.getBuffer()); } }, "Löschen")); } this.logBox = this.add(new TransparentBox(0, this.full ? 24 : 0, width, height - (this.full ? 48 : 24), this.gm.getBuffer())); if(this.full) this.add(new Fill(640, 0, width - 640, 24)); this.inputField = this.add(new Textbox(0, height - 24, width, 24, NetHandlerPlayServer.MAX_CMD_LENGTH, true, this, "")); this.inputField.setSelected(); this.sentHistoryCursor = this.sentMessages.size(); } public String getTitle() { return "Konsole / Chat"; } public void reset() { this.gm.reset(); this.sentMessages.clear(); this.sentHistoryCursor = -1; } public void setLog(String buffer) { if(this.logBox != null) this.logBox.setText(buffer); } public void drawMainBackground() { if(this.gm.theWorld == null) super.drawMainBackground(); } public void key(Keysym key, boolean ctrl, boolean shift) { super.key(key, ctrl, shift); // this.waitingOnAutocomplete = false; if(key != Keysym.TAB && key != Keysym.LEFT_SHIFT && key != Keysym.RIGHT_SHIFT) this.playerNamesFound = false; } public void use(Textbox elem, Action value) { this.waitingOnAutocomplete = false; if (value == Action.FORWARD || value == Action.BACKWARD) { this.reverse = value == Action.BACKWARD; this.autocompletePlayerNames(); } else { this.playerNamesFound = false; } if(value == Action.PREVIOUS) this.getSentHistory(-1); else if (value == Action.NEXT) this.getSentHistory(1); if(value == Action.SEND) { String s = this.inputField.getText().trim(); if (s.length() > 0) { if(this.sentMessages.isEmpty() || !((String)this.sentMessages.get(this.sentMessages.size() - 1)).equals(s)) this.sentMessages.add(s); this.sentHistoryCursor = this.sentMessages.size(); this.gm.exec(s); // if(this.gm.thePlayer != null) // this.gm.thePlayer.sendQueue.addToSendQueue(new CPacketMessage(CPacketMessage.Type.CHAT, s)); } this.inputField.setText(""); if((this.gm.conAutoclose || !this.full) && this.gm.theWorld != null) this.gm.displayGuiScreen(null); } } protected void setText(String newChatText, boolean shouldOverwrite) { if (shouldOverwrite) { this.inputField.setText(newChatText); } else { this.inputField.insertText(newChatText); } } private void addMessage(String msg) { String buffer = this.gm.getBuffer(); if((buffer.length() + msg.length() + 2) > Game.LOG_BUFFER) { int offset = (msg.length() + 2) > 1024 ? (msg.length() + 2) : 1024; int nl = buffer.indexOf('\n', offset); buffer = nl >= 0 ? buffer.substring(nl + 1) : ""; } this.setLog(buffer + "\n" + TextColor.RESET + msg); } public void autocompletePlayerNames() { if (this.playerNamesFound) { this.inputField.deleteFromCursor(); if (this.autocompleteIndex >= this.foundPlayerNames.size()) { this.autocompleteIndex = 0; } else if (this.autocompleteIndex < 0) { this.autocompleteIndex = this.foundPlayerNames.size() - 1; } } else { int i = this.inputField.getNthCharFromPos(); this.foundPlayerNames.clear(); this.autocompleteIndex = 0; String s = this.inputField.getText().substring(i).toLowerCase(); String s1 = this.inputField.getText().substring(0, this.inputField.getCursorPosition()); String[] localMatches = this.sendAutocompleteRequest(s1, s); if(localMatches != null) { this.onAutocompleteResponse(localMatches); return; } if (this.foundPlayerNames.isEmpty()) { return; } this.playerNamesFound = true; this.inputField.deleteFromCursor(); } if (this.foundPlayerNames.size() > 1) { StringBuilder stringbuilder = new StringBuilder(); for (String s2 : this.foundPlayerNames) { if (stringbuilder.length() > 0) { stringbuilder.append(", "); } stringbuilder.append(s2); } this.addMessage(stringbuilder.toString()); } this.inputField.insertText((String)this.foundPlayerNames.get(this.autocompleteIndex)); this.autocompleteIndex += this.reverse ? -1 : 1; } private String[] complete(String s) { List list = Lists.newArrayList(); String[] argv = s.split(" ", -1); String pre = argv[0]; s = argv[argv.length - 1]; Iterable res = pre.startsWith("#") ? (argv.length == 1 ? this.gm.getVars() : (argv.length == 2 ? getVarCompletion(argv[0].substring(1)) : Lists.newArrayList())) : (this.gm.thePlayer == null ? Lists.newArrayList() : this.gm.thePlayer.sendQueue.getPlayerNames()); if(argv.length == 1 && pre.startsWith("#")) s = s.substring(1); for(String s1 : res) { if(s1.regionMatches(true, 0, s, 0, s.length())) list.add((argv.length == 1 && pre.startsWith("#") ? "#" : "") + s1); } return list.isEmpty() ? null : list.toArray(new String[list.size()]); } private List getVarCompletion(String var) { CVar cv = this.gm.getVar(var); if(cv == null) return Lists.newArrayList(); if(cv instanceof BoolVar) return Boolean.parseBoolean(cv.format()) ? Lists.newArrayList("false", "true") : Lists.newArrayList("true", "false"); else return Lists.newArrayList(cv.getDefault()); // return Lists.newArrayList(); } private String[] sendAutocompleteRequest(String currentText, String newText) { if (currentText.length() >= 1) { BlockPos blockpos = null; int eid = -1; if (this.gm.pointed != null && this.gm.pointed.type == HitPosition.ObjectType.BLOCK) { blockpos = this.gm.pointed.block; } else if (this.gm.pointed != null && this.gm.pointed.type == HitPosition.ObjectType.ENTITY) { eid = this.gm.pointed.entity.getId(); blockpos = new BlockPos(this.gm.pointed.entity); } if(currentText.startsWith("/")) { if(this.gm.thePlayer != null) { currentText = currentText.substring(1); this.prefixFirst = currentText.split(" ", -1).length == 1 ? "/" : null; this.gm.thePlayer.sendQueue.addToSendQueue(new CPacketComplete(currentText, eid, blockpos)); this.waitingOnAutocomplete = true; } } else { String[] comp = this.complete(currentText); this.prefixFirst = null; if(comp != null) this.waitingOnAutocomplete = true; return comp; } } return null; } private void getSentHistory(int msgPos) { int i = this.sentHistoryCursor + msgPos; int j = this.sentMessages.size(); i = ExtMath.clampi(i, 0, j); if (i != this.sentHistoryCursor) { if (i == j) { this.sentHistoryCursor = j; this.inputField.setText(this.historyBuffer); } else { if (this.sentHistoryCursor == j) { this.historyBuffer = this.inputField.getText(); } this.inputField.setText(this.sentMessages.get(i)); this.sentHistoryCursor = i; } } } public void onAutocompleteResponse(String[] choices) { if (this.waitingOnAutocomplete) { this.playerNamesFound = false; this.foundPlayerNames.clear(); for (int z = 0; z < choices.length; z++) { String s = choices[z]; if(this.prefixFirst != null) choices[z] = s = this.prefixFirst + s; if (s.length() > 0) { this.foundPlayerNames.add(s); } } String s1 = this.inputField.getText().substring(this.inputField.getNthCharFromPos()); String s2 = getCommonPrefix(choices); if (s2.length() > 0 && !s1.equalsIgnoreCase(s2)) { this.inputField.deleteFromCursor(); this.inputField.insertText(s2); } else if (this.foundPlayerNames.size() > 0) { this.playerNamesFound = true; this.autocompletePlayerNames(); } } } private static String getCommonPrefix(String[] strs) { if (strs != null && strs.length != 0) { int smallestIndexOfDiff = indexOfDifference(strs); if (smallestIndexOfDiff == -1) { return strs[0] == null ? "" : strs[0]; } else { return smallestIndexOfDiff == 0 ? "" : strs[0].substring(0, smallestIndexOfDiff); } } else { return ""; } } private static int indexOfDifference(CharSequence[] css) { if (css != null && css.length > 1) { boolean anyStringNull = false; boolean allStringsNull = true; int arrayLen = css.length; int shortestStrLen = Integer.MAX_VALUE; int longestStrLen = 0; int firstDiff; for (firstDiff = 0; firstDiff < arrayLen; ++firstDiff) { if (css[firstDiff] == null) { anyStringNull = true; shortestStrLen = 0; } else { allStringsNull = false; shortestStrLen = Math.min(css[firstDiff].length(), shortestStrLen); longestStrLen = Math.max(css[firstDiff].length(), longestStrLen); } } if (allStringsNull || longestStrLen == 0 && !anyStringNull) { return -1; } else if (shortestStrLen == 0) { return 0; } else { firstDiff = -1; for (int stringPos = 0; stringPos < shortestStrLen; ++stringPos) { char comparisonChar = css[0].charAt(stringPos); for (int arrayPos = 1; arrayPos < arrayLen; ++arrayPos) { if (css[arrayPos].charAt(stringPos) != comparisonChar) { firstDiff = stringPos; break; } } if (firstDiff != -1) { break; } } return firstDiff == -1 && shortestStrLen != longestStrLen ? shortestStrLen : firstDiff; } } else { return -1; } } }