/* * This file is part of Spoutcraft (http://wiki.getspout.org/). * * Spoutcraft is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Spoutcraft is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.getspout.spout.player; import java.util.ArrayList; import net.minecraft.client.Minecraft; import net.minecraft.src.FontRenderer; import net.minecraft.src.GuiChat; import org.getspout.spout.client.SpoutClient; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import org.bukkit.ChatColor; import java.util.HashMap; import java.awt.Toolkit; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import net.minecraft.src.ChatAllowedCharacters; public class ChatManager { public int commandScroll = 0; public int chatScroll = 0; private HashMap<Character, String> boundCommands = new HashMap<Character, String>(); public ArrayList<String> pastCommands = new ArrayList<String>(1000); public boolean onChatKeyTyped(char character, int key, GuiChat chat) { try { boolean control = Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL); String message = chat.message; int cursor = chat.cursorPosition; if (Keyboard.isKeyDown(Keyboard.KEY_LEFT) && cursor > 0) { updateCursor(--cursor, chat); } else if (Keyboard.isKeyDown(Keyboard.KEY_RIGHT) && cursor < message.length()) { updateCursor(++cursor, chat); } else if (Keyboard.isKeyDown(Keyboard.KEY_DELETE) && cursor < message.length()) { message = message.substring(0, cursor) + message.substring(cursor + 1); updateMessage(message, chat); } else if (Keyboard.isKeyDown(Keyboard.KEY_PRIOR) && chatScroll < getChatHistorySize()) { chatScroll += 20; chatScroll = Math.min(getChatHistorySize() - 1, chatScroll); } else if (Keyboard.isKeyDown(Keyboard.KEY_NEXT) && chatScroll > 0) { chatScroll -= 20; chatScroll = Math.max(0, chatScroll); } else if (Keyboard.isKeyDown(Keyboard.KEY_HOME)) { chatScroll = 0; } else if (Keyboard.isKeyDown(Keyboard.KEY_END)) { chatScroll = getChatHistorySize() - 2; if (chatScroll < 0) { chatScroll = 0; } } else if (Keyboard.isKeyDown(Keyboard.KEY_UP) && commandScroll < pastCommands.size()) { commandScroll++; message = updateCommandScroll(chat); updateMessage(message, chat); } else if (Keyboard.isKeyDown(Keyboard.KEY_DOWN) && commandScroll > 0) { commandScroll--; message = updateCommandScroll(chat); updateMessage(message, chat); } else if (control && Keyboard.isKeyDown(Keyboard.KEY_V)) { String paste = paste(); message = (message.substring(0, cursor) + paste + message.substring(cursor)); cursor += paste.length(); updateMessage(message, chat); updateCursor(cursor, chat); } else if (control && Keyboard.isKeyDown(Keyboard.KEY_C)) { copy(message); } else if (Keyboard.isKeyDown(Keyboard.KEY_BACK) && message.length() > 0 && cursor > 0) { if (message.length() == 1) { message = ""; } else { String text = message; if (cursor > text.length()) { cursor = text.length(); } if (cursor > 1) { text = message.substring(0, cursor - 1); } else { text = ""; } if (cursor > 0) { text += message.substring(cursor); } message = text; } updateCursor(--cursor, chat); updateMessage(message, chat); } //Messages are infinite length, commands's are limited to 100 chars else if (ChatAllowedCharacters.allowedCharacters.indexOf(character) > -1 && (!message.startsWith("/") || message.length() < 100)) { if (cursor == 0) { message = character + message; } else if (cursor > 0) { message = (message.substring(0, cursor) + character + message.substring(cursor)); } else { message += character; } updateMessage(message, chat); updateCursor(++cursor, chat); } //Not handled else { return false; } //Handled return true; } catch (Exception e) { e.printStackTrace(); return false; } } public int getChatHistorySize() { return SpoutClient.getHandle().ingameGUI.chatMessageList.size(); } public int checkCursor(String message, int cursor) { if (cursor > message.length()) { cursor = message.length(); } else if (cursor < 0) { cursor = 0; } return cursor; } public String updateCommandScroll(GuiChat chat) { String command; if (commandScroll == 0) { command = ""; } else { command = (String)pastCommands.get(pastCommands.size() - commandScroll); } updateMessage(command, chat); updateCursor(command.length(), chat); return command; } public void updateCursor(int position, GuiChat chat) { chat.cursorPosition = checkCursor(chat.message, position); } public void updateMessage(String message, GuiChat chat) { chat.message = message; updateCursor(chat.cursorPosition, chat); } public void sendChat(String message) { ArrayList<String> lines = formatChat(message, false); for (String chat : lines) { SpoutClient.getHandle().thePlayer.sendChatMessage(chat); } } public String formatChatColors(String message) { String text = ""; ChatColor last = null; for (int i = 0; i < message.length(); i++) { char ch = message.charAt(i); if (ch == '&' && i < message.length() - 2) { char next = message.charAt(i + 1); int number = -1; String temp = "" + next; if (Character.isDigit(next)) { number = Integer.parseInt(temp); i++; } else if (next >= 'a' && next <= 'f') { number = 10 + next - 'a'; i++; } else { text += ch; } if (number > -1 && number < 16) { last = ChatColor.getByCode(number); } if (last != null) { text += last.toString(); } } else { text += ch; } } return text; } public ArrayList<String> formatChat(String message, boolean display) { ArrayList<String> lines = new ArrayList<String>(); FontRenderer font = Minecraft.theMinecraft.fontRenderer; int width = (int) SpoutClient.getInstance().getActivePlayer().getMainScreen().getChatBar().getActualWidth(); @SuppressWarnings("unused") int line = 0; int total = 0; ChatColor last = null; String text = ""; for (int i = 0; i < message.length(); i++) { char ch = message.charAt(i); boolean newline = ch == '\n'; if (!newline && i < message.length() - 1 && ch == '\\' && message.charAt(i + 1) == 'n') { i++; newline = true; } if (ch == '&' && i < message.length() - 2) { char next = message.charAt(i + 1); int number = -1; String temp = "" + next; if (Character.isDigit(next)) { number = Integer.parseInt(temp); i++; } else if (next >= 'a' && next <= 'f') { number = 10 + next - 'a'; i++; } if (number > -1 && number < 16) { last = ChatColor.getByCode(number); } } if (display && total > 1 && total % 99 == 0) { text += ChatColor.RED + " [LINE BREAK] " + (last != null ? last.toString() : ChatColor.WHITE); } if ((display && font.getStringWidth(text + ch) > (width - 8)) || newline || (!display && total > 1 && total % 99 == 0)) { lines.add(text); line = 0; text = ""; if (last != null) { text += last.toString(); } } else { text += ch; line++; } total++; } lines.add(text); return lines; } public void handleMouseWheel() { int wheel = Mouse.getDWheel(); if (wheel > 0) { if (chatScroll < getChatHistorySize()) { chatScroll++; } } else if (wheel < 0) { if (chatScroll > 0) { chatScroll--; } } } public void unbind(char ch) { boundCommands.remove(ch); } public void bindCommand(char ch, String command) { boundCommands.put(ch, command); } public String getBoundCommand(char ch) { return boundCommands.get(ch); } public boolean handleCommand(String command) { try { if (command.startsWith("~bind")) { command = command.substring(6); //eat the ~bind prefix String[] split = command.split(" "); char key = split[0].toUpperCase().charAt(0); if (key >= 'A' && key <= 'Z') { command = command.substring(2); //eat the key and the following space if (command.startsWith("/")) { bindCommand(key, command); SpoutClient.getHandle().ingameGUI.addChatMessage(ChatColor.GREEN.toString() + "Successfully bound key '" + key + "' to the command '" + command + "'"); return true; } } } else if (command.startsWith("~unbind")) { command = command.substring(8); //eat the ~unbind prefix if (command.length() == 1) { char key = command.toUpperCase().charAt(0); unbind(key); SpoutClient.getHandle().ingameGUI.addChatMessage(ChatColor.GREEN.toString() + "Successfully unbound key '" + key + "'"); return true; } } else if (command.startsWith("/client gc")) { SpoutClient.getHandle().ingameGUI.addChatMessage(ChatColor.YELLOW.toString() + "Starting Garbage Collection..."); long start = System.currentTimeMillis(); int i = 1; while ((System.currentTimeMillis() - start) < 50) { System.gc(); System.out.println("Garbage Collect Pass: " + i); i++; } SpoutClient.getHandle().ingameGUI.addChatMessage(ChatColor.GREEN.toString() + "Garbage Collection Complete!"); return true; } } catch (Exception e) {} return false; } public static void copy(String a) { Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(a), null); } public static String paste() { String str = ""; Transferable localTransferable = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null); if (localTransferable != null && localTransferable.isDataFlavorSupported(DataFlavor.stringFlavor)) { try { str = (String)localTransferable.getTransferData(DataFlavor.stringFlavor); } catch (Exception e) {} } return str; } public static String formatUrl(String message) { int start = -1; if (start == -1) { start = message.indexOf("http://"); } if (start == -1) { start = message.indexOf("www."); } if (start != -1) { char end; int endPos = message.length(); for (int i = start; i < message.length(); i++) { end = message.charAt(i); endPos = i; if (Character.isWhitespace(end)) { break; } } String begin = ""; if (start > 0) { begin = message.substring(0, start); } String ending = ""; if (endPos < message.length()) { ending = message.substring(endPos + 1); } StringBuffer format = new StringBuffer(begin).append(ChatColor.AQUA.toString()).append(message.substring(start, endPos + 1)).append(ChatColor.WHITE.toString()).append(ending); return format.toString(); } return message; } }