From 2077e4ba33b1624d649e9b91373b40d5f0005d89 Mon Sep 17 00:00:00 2001 From: StevenLawson Date: Sat, 16 Aug 2014 23:11:55 -0400 Subject: [PATCH] Added rough, initial version of player list. --- pom.xml | 5 + .../BTC_ConnectionManager.java | 16 +- .../BukkitTelnetClient/BTC_FormatHandler.java | 18 +- .../BukkitTelnetClient/BTC_MainPanel.form | 456 ++++++++++++------ .../BukkitTelnetClient/BTC_MainPanel.java | 283 ++++++++--- .../BTC_PlayerListDecoder.java | 111 +++++ 6 files changed, 660 insertions(+), 229 deletions(-) create mode 100644 src/main/java/me/StevenLawson/BukkitTelnetClient/BTC_PlayerListDecoder.java diff --git a/pom.xml b/pom.xml index 93ffb9d..8a73205 100644 --- a/pom.xml +++ b/pom.xml @@ -48,6 +48,11 @@ commons-io 2.4 + + org.json + json + 20140107 + UTF-8 diff --git a/src/main/java/me/StevenLawson/BukkitTelnetClient/BTC_ConnectionManager.java b/src/main/java/me/StevenLawson/BukkitTelnetClient/BTC_ConnectionManager.java index 16245ab..94112dc 100644 --- a/src/main/java/me/StevenLawson/BukkitTelnetClient/BTC_ConnectionManager.java +++ b/src/main/java/me/StevenLawson/BukkitTelnetClient/BTC_ConnectionManager.java @@ -5,6 +5,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; +import java.util.Map; import java.util.logging.Level; import org.apache.commons.lang3.StringUtils; import org.apache.commons.net.telnet.TelnetClient; @@ -158,10 +159,21 @@ public class BTC_ConnectionManager if (read == '\n') { final String line = consoleBuffer.toString(); - if (!BTC_FormatHandler.skipLine(line)) + + final Map playerList = BTC_PlayerListDecoder.decodePlayerListMessage(line); + + if (playerList != null) { - System.out.print(line); + btc.updatePlayerList(playerList); } + else + { + if (!BTC_FormatHandler.skipLine(line)) + { + System.out.print(line); + } + } + consoleBuffer.reset(); } } diff --git a/src/main/java/me/StevenLawson/BukkitTelnetClient/BTC_FormatHandler.java b/src/main/java/me/StevenLawson/BukkitTelnetClient/BTC_FormatHandler.java index 8a40f22..eff4d93 100644 --- a/src/main/java/me/StevenLawson/BukkitTelnetClient/BTC_FormatHandler.java +++ b/src/main/java/me/StevenLawson/BukkitTelnetClient/BTC_FormatHandler.java @@ -5,19 +5,27 @@ import java.util.regex.Pattern; public class BTC_FormatHandler { + private static final Color PURPLE = new Color(128, 0, 128); + private static final Color DARK_GREEN = new Color(86, 130, 3); + private static final Pattern CHAT_MESSAGE = Pattern.compile("^:\\[.+? INFO\\]: \\<"); private static final Pattern SAY_MESSAGE = Pattern.compile("^:\\[.+? INFO\\]: \\[Server:"); - private static final Pattern ADMINSAY_MESSAGE = Pattern.compile("^:\\[.+? INFO\\]: \\[TotalFreedomMod\\] \\[ADMIN\\] "); private static final Pattern CSAY_MESSAGE = Pattern.compile("^:\\[.+? INFO\\]: \\[CONSOLE\\]<"); + private static final Pattern ADMINSAY_MESSAGE = Pattern.compile("^:\\[.+? INFO\\]: \\[TotalFreedomMod\\] \\[ADMIN\\] "); + private static final Pattern WORLD_EDIT = Pattern.compile("^:\\[.+? INFO\\]: WorldEdit: "); private static final Pattern PREPROCESS_COMMAND = Pattern.compile("^:\\[.+? INFO\\]: \\[PREPROCESS_COMMAND\\] "); - private static final Color DARK_GREEN = new Color(86, 130, 3); private static final Pattern ISSUED_SERVER_COMMAND = Pattern.compile("^:\\[.+? INFO\\]: .+? issued server command: "); private static final Pattern PLAYER_COMMAND = Pattern.compile("^:\\[.+? INFO\\]: \\[PLAYER_COMMAND\\] "); + private BTC_FormatHandler() + { + throw new AssertionError(); + } + public static final boolean skipLine(String line) { final BTC_MainPanel mainPanel = BukkitTelnetClient.mainPanel; @@ -50,10 +58,14 @@ public class BTC_FormatHandler { Color color = Color.BLACK; - if (CHAT_MESSAGE.matcher(text).find() || SAY_MESSAGE.matcher(text).find() || ADMINSAY_MESSAGE.matcher(text).find() || CSAY_MESSAGE.matcher(text).find()) + if (CHAT_MESSAGE.matcher(text).find() || SAY_MESSAGE.matcher(text).find() || CSAY_MESSAGE.matcher(text).find()) { color = Color.BLUE; } + else if (ADMINSAY_MESSAGE.matcher(text).find()) + { + color = PURPLE; + } else if (WORLD_EDIT.matcher(text).find()) { color = Color.RED; diff --git a/src/main/java/me/StevenLawson/BukkitTelnetClient/BTC_MainPanel.form b/src/main/java/me/StevenLawson/BukkitTelnetClient/BTC_MainPanel.form index 54a7aea..7d044cb 100644 --- a/src/main/java/me/StevenLawson/BukkitTelnetClient/BTC_MainPanel.form +++ b/src/main/java/me/StevenLawson/BukkitTelnetClient/BTC_MainPanel.form @@ -1,6 +1,6 @@ -
+ @@ -25,171 +25,323 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - + + + + - + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + <Editor/> + <Renderer/> + </Column> + <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> + <Title/> + <Editor/> + <Renderer/> + </Column> + <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> + <Title/> + <Editor/> + <Renderer/> + </Column> + </TableColumnModel> + </Property> + <Property name="columnSelectionAllowed" type="boolean" value="true"/> + <Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor"> + <TableHeader reorderingAllowed="true" resizingAllowed="true"/> + </Property> + </Properties> + </Component> + </SubComponents> + </Container> + </SubComponents> + </Container> + <Container class="javax.swing.JPanel" name="jPanel1"> + <Constraints> + <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription"> + <JTabbedPaneConstraints tabName="Filters"> + <Property name="tabTitle" type="java.lang.String" value="Filters"/> + </JTabbedPaneConstraints> + </Constraint> + </Constraints> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Component id="chkIgnorePlayerCommands" alignment="0" min="-2" max="-2" attributes="0"/> + <Component id="chkIgnoreServerCommands" alignment="0" min="-2" max="-2" attributes="0"/> + <Component id="chkShowChatOnly" alignment="0" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Component id="chkIgnorePlayerCommands" min="-2" pref="23" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="chkIgnoreServerCommands" min="-2" pref="23" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="chkShowChatOnly" min="-2" pref="23" max="-2" attributes="0"/> + <EmptySpace pref="341" max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JCheckBox" name="chkIgnorePlayerCommands"> + <Properties> + <Property name="selected" type="boolean" value="true"/> + <Property name="text" type="java.lang.String" value="Ignore "[PLAYER_COMMAND]" messages"/> + </Properties> + </Component> + <Component class="javax.swing.JCheckBox" name="chkIgnoreServerCommands"> + <Properties> + <Property name="selected" type="boolean" value="true"/> + <Property name="text" type="java.lang.String" value="Ignore "issued server command" messages"/> + </Properties> + </Component> + <Component class="javax.swing.JCheckBox" name="chkShowChatOnly"> + <Properties> + <Property name="text" type="java.lang.String" value="Show chat only"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="chkShowChatOnlyActionPerformed"/> + </Events> + </Component> + </SubComponents> + </Container> + </SubComponents> + </Container> </SubComponents> </Container> - <Component class="javax.swing.JTextField" name="txtCommand"> - <Properties> - <Property name="enabled" type="boolean" value="false"/> - </Properties> - <Events> - <EventHandler event="keyPressed" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="txtCommandKeyPressed"/> - </Events> - </Component> - <Component class="javax.swing.JButton" name="btnConnect"> - <Properties> - <Property name="text" type="java.lang.String" value="Connect"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnConnectActionPerformed"/> - </Events> - </Component> - <Component class="javax.swing.JLabel" name="jLabel1"> - <Properties> - <Property name="text" type="java.lang.String" value="Command:"/> - </Properties> - </Component> - <Component class="javax.swing.JLabel" name="jLabel2"> - <Properties> - <Property name="text" type="java.lang.String" value="Server:"/> - </Properties> - </Component> - <Component class="javax.swing.JButton" name="btnDisconnect"> - <Properties> - <Property name="text" type="java.lang.String" value="Disconnect"/> - <Property name="enabled" type="boolean" value="false"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnDisconnectActionPerformed"/> - </Events> - </Component> - <Component class="javax.swing.JButton" name="btnSend"> - <Properties> - <Property name="text" type="java.lang.String" value="Send"/> - <Property name="enabled" type="boolean" value="false"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnSendActionPerformed"/> - </Events> - </Component> - <Component class="javax.swing.JComboBox" name="txtServer"> - <Properties> - <Property name="editable" type="boolean" value="true"/> - <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor"> - <StringArray count="0"/> - </Property> - </Properties> - </Component> - <Component class="javax.swing.JCheckBox" name="chkAutoScroll"> - <Properties> - <Property name="selected" type="boolean" value="true"/> - <Property name="text" type="java.lang.String" value="AutoScroll"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="chkAutoScrollActionPerformed"/> - </Events> - </Component> - <Component class="javax.swing.JCheckBox" name="chkIgnorePlayerCommands"> - <Properties> - <Property name="selected" type="boolean" value="true"/> - <Property name="text" type="java.lang.String" value="Ignore "[PLAYER_COMMAND]" messages"/> - </Properties> - </Component> - <Component class="javax.swing.JCheckBox" name="chkIgnoreServerCommands"> - <Properties> - <Property name="selected" type="boolean" value="true"/> - <Property name="text" type="java.lang.String" value="Ignore "issued server command" messages"/> - </Properties> - </Component> - <Component class="javax.swing.JCheckBox" name="chkShowChatOnly"> - <Properties> - <Property name="text" type="java.lang.String" value="Show chat only"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="chkShowChatOnlyActionPerformed"/> - </Events> - </Component> </SubComponents> </Form> diff --git a/src/main/java/me/StevenLawson/BukkitTelnetClient/BTC_MainPanel.java b/src/main/java/me/StevenLawson/BukkitTelnetClient/BTC_MainPanel.java index b317644..1c33cf5 100644 --- a/src/main/java/me/StevenLawson/BukkitTelnetClient/BTC_MainPanel.java +++ b/src/main/java/me/StevenLawson/BukkitTelnetClient/BTC_MainPanel.java @@ -1,5 +1,6 @@ package me.StevenLawson.BukkitTelnetClient; +import java.awt.EventQueue; import java.awt.Toolkit; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; @@ -10,10 +11,13 @@ import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.net.URL; +import java.util.Iterator; import java.util.LinkedList; +import java.util.Map; import java.util.logging.Level; import javax.swing.JCheckBox; import javax.swing.SwingUtilities; +import javax.swing.table.DefaultTableModel; import javax.swing.text.BadLocationException; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; @@ -51,6 +55,8 @@ public class BTC_MainPanel extends javax.swing.JFrame setIconImage(Toolkit.getDefaultToolkit().createImage(icon)); } + this.splitPane.setResizeWeight(1.0); + this.setLocationRelativeTo(null); this.setVisible(true); } @@ -85,6 +91,34 @@ public class BTC_MainPanel extends javax.swing.JFrame }); } + public final void updatePlayerList(final Map<String, BTC_PlayerListDecoder.PlayerInfo> playerList) + { + EventQueue.invokeLater(new Runnable() + { + @Override + public void run() + { + final DefaultTableModel model = (DefaultTableModel) BTC_MainPanel.this.tblPlayers.getModel(); + + model.setRowCount(0); + + final Iterator<Map.Entry<String, BTC_PlayerListDecoder.PlayerInfo>> it = playerList.entrySet().iterator(); + while (it.hasNext()) + { + final Map.Entry<String, BTC_PlayerListDecoder.PlayerInfo> entry = it.next(); + BTC_PlayerListDecoder.PlayerInfo playerInfo = entry.getValue(); + + model.addRow(new Object[] + { + playerInfo.getName(), + playerInfo.getDisplayName(), + playerInfo.getIp() + }); + } + } + }); + } + public void updateConsole() { final String data = BukkitTelnetClient.CONSOLE.toString(); @@ -181,16 +215,23 @@ public class BTC_MainPanel extends javax.swing.JFrame private void initComponents() { + splitPane = new javax.swing.JSplitPane(); + jPanel3 = new javax.swing.JPanel(); jScrollPane1 = new javax.swing.JScrollPane(); mainOutput = new javax.swing.JTextPane(); - txtCommand = new javax.swing.JTextField(); - btnConnect = new javax.swing.JButton(); - jLabel1 = new javax.swing.JLabel(); - jLabel2 = new javax.swing.JLabel(); btnDisconnect = new javax.swing.JButton(); btnSend = new javax.swing.JButton(); txtServer = new javax.swing.JComboBox(); chkAutoScroll = new javax.swing.JCheckBox(); + txtCommand = new javax.swing.JTextField(); + btnConnect = new javax.swing.JButton(); + jLabel1 = new javax.swing.JLabel(); + jLabel2 = new javax.swing.JLabel(); + jTabbedPane1 = new javax.swing.JTabbedPane(); + jPanel2 = new javax.swing.JPanel(); + jScrollPane2 = new javax.swing.JScrollPane(); + tblPlayers = new javax.swing.JTable(); + jPanel1 = new javax.swing.JPanel(); chkIgnorePlayerCommands = new javax.swing.JCheckBox(); chkIgnoreServerCommands = new javax.swing.JCheckBox(); chkShowChatOnly = new javax.swing.JCheckBox(); @@ -198,32 +239,12 @@ public class BTC_MainPanel extends javax.swing.JFrame setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setTitle("BukkitTelnetClient"); + splitPane.setDividerLocation(650); + mainOutput.setEditable(false); mainOutput.setFont(new java.awt.Font("Courier New", 0, 12)); // NOI18N jScrollPane1.setViewportView(mainOutput); - txtCommand.setEnabled(false); - txtCommand.addKeyListener(new java.awt.event.KeyAdapter() - { - public void keyPressed(java.awt.event.KeyEvent evt) - { - txtCommandKeyPressed(evt); - } - }); - - btnConnect.setText("Connect"); - btnConnect.addActionListener(new java.awt.event.ActionListener() - { - public void actionPerformed(java.awt.event.ActionEvent evt) - { - btnConnectActionPerformed(evt); - } - }); - - jLabel1.setText("Command:"); - - jLabel2.setText("Server:"); - btnDisconnect.setText("Disconnect"); btnDisconnect.setEnabled(false); btnDisconnect.addActionListener(new java.awt.event.ActionListener() @@ -256,6 +277,133 @@ public class BTC_MainPanel extends javax.swing.JFrame } }); + txtCommand.setEnabled(false); + txtCommand.addKeyListener(new java.awt.event.KeyAdapter() + { + public void keyPressed(java.awt.event.KeyEvent evt) + { + txtCommandKeyPressed(evt); + } + }); + + btnConnect.setText("Connect"); + btnConnect.addActionListener(new java.awt.event.ActionListener() + { + public void actionPerformed(java.awt.event.ActionEvent evt) + { + btnConnectActionPerformed(evt); + } + }); + + jLabel1.setText("Command:"); + + jLabel2.setText("Server:"); + + javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1) + .addGroup(jPanel3Layout.createSequentialGroup() + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jLabel1)) + .addGap(18, 18, 18) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(txtCommand) + .addComponent(txtServer, 0, 378, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(btnConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnSend, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(btnDisconnect) + .addComponent(chkAutoScroll)))) + .addContainerGap()) + ); + + jPanel3Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {btnConnect, btnDisconnect, btnSend, chkAutoScroll}); + + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 360, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtCommand, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel1) + .addComponent(btnSend) + .addComponent(chkAutoScroll)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel2) + .addComponent(btnConnect) + .addComponent(btnDisconnect) + .addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) + ); + + splitPane.setLeftComponent(jPanel3); + + tblPlayers.setAutoCreateRowSorter(true); + tblPlayers.setModel(new javax.swing.table.DefaultTableModel( + new Object [][] + { + + }, + new String [] + { + "Name", "Display Name", "IP" + } + ) + { + Class[] types = new Class [] + { + java.lang.String.class, java.lang.String.class, java.lang.String.class + }; + boolean[] canEdit = new boolean [] + { + false, false, false + }; + + public Class getColumnClass(int columnIndex) + { + return types [columnIndex]; + } + + public boolean isCellEditable(int rowIndex, int columnIndex) + { + return canEdit [columnIndex]; + } + }); + tblPlayers.setColumnSelectionAllowed(true); + jScrollPane2.setViewportView(tblPlayers); + tblPlayers.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); + + javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); + jPanel2.setLayout(jPanel2Layout); + jPanel2Layout.setHorizontalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 346, Short.MAX_VALUE) + .addContainerGap()) + ); + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 395, Short.MAX_VALUE) + .addContainerGap()) + ); + + jTabbedPane1.addTab("Player List", jPanel2); + chkIgnorePlayerCommands.setSelected(true); chkIgnorePlayerCommands.setText("Ignore \"[PLAYER_COMMAND]\" messages"); @@ -271,64 +419,48 @@ public class BTC_MainPanel extends javax.swing.JFrame } }); + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(chkIgnorePlayerCommands) + .addComponent(chkIgnoreServerCommands) + .addComponent(chkShowChatOnly)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(chkIgnorePlayerCommands, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(chkIgnoreServerCommands, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(chkShowChatOnly, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(341, Short.MAX_VALUE)) + ); + + jTabbedPane1.addTab("Filters", jPanel1); + + splitPane.setRightComponent(jTabbedPane1); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(chkIgnorePlayerCommands) - .addGap(18, 18, 18) - .addComponent(chkIgnoreServerCommands) - .addGap(18, 18, 18) - .addComponent(chkShowChatOnly) - .addGap(0, 0, Short.MAX_VALUE)) - .addComponent(jScrollPane1) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGap(18, 18, 18) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(txtCommand, javax.swing.GroupLayout.DEFAULT_SIZE, 680, Short.MAX_VALUE) - .addComponent(txtServer, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(btnConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btnSend, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(btnDisconnect) - .addComponent(chkAutoScroll)))) + .addComponent(splitPane) .addContainerGap()) ); - - layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {btnConnect, btnDisconnect, btnSend, chkAutoScroll}); - layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 338, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(chkIgnorePlayerCommands, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(chkIgnoreServerCommands, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(chkShowChatOnly, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(txtCommand, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jLabel1) - .addComponent(btnSend) - .addComponent(chkAutoScroll)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel2) - .addComponent(btnConnect) - .addComponent(btnDisconnect) - .addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(splitPane) .addContainerGap()) ); @@ -398,8 +530,15 @@ public class BTC_MainPanel extends javax.swing.JFrame private javax.swing.JCheckBox chkShowChatOnly; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel2; + private javax.swing.JPanel jPanel3; private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JScrollPane jScrollPane2; + private javax.swing.JTabbedPane jTabbedPane1; private javax.swing.JTextPane mainOutput; + private javax.swing.JSplitPane splitPane; + private javax.swing.JTable tblPlayers; private javax.swing.JTextField txtCommand; private javax.swing.JComboBox txtServer; // End of variables declaration//GEN-END:variables diff --git a/src/main/java/me/StevenLawson/BukkitTelnetClient/BTC_PlayerListDecoder.java b/src/main/java/me/StevenLawson/BukkitTelnetClient/BTC_PlayerListDecoder.java new file mode 100644 index 0000000..009f025 --- /dev/null +++ b/src/main/java/me/StevenLawson/BukkitTelnetClient/BTC_PlayerListDecoder.java @@ -0,0 +1,111 @@ +package me.StevenLawson.BukkitTelnetClient; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +public class BTC_PlayerListDecoder +{ + private static final Pattern PLAYER_LIST_MESSAGE = Pattern.compile(":\\[.+@BukkitTelnet\\]\\$ playerList~(.+)"); + + private BTC_PlayerListDecoder() + { + throw new AssertionError(); + } + + public static final Map<String, PlayerInfo> decodePlayerListMessage(String message) + { + final Matcher matcher = PLAYER_LIST_MESSAGE.matcher(message); + if (matcher.find()) + { + final String data = matcher.group(1); + try + { + final Map<String, PlayerInfo> playerInfo = new HashMap<>(); + + final JSONObject json = new JSONObject(data); + final JSONArrayIterable players = new JSONArrayIterable(json.getJSONArray("players")); + for (JSONObject player : players) + { + final String name = player.getString("name"); + final String ip = player.getString("ip"); + final String displayName = player.getString("displayName"); + playerInfo.put(name, new PlayerInfo(name, ip, displayName)); + } + + return playerInfo; + } + catch (JSONException ex) + { + } + } + + return null; + } + + public static final class PlayerInfo + { + private final String name; + private final String ip; + private final String displayName; + + public PlayerInfo(String name, String ip, String displayName) + { + this.name = name; + this.ip = ip; + this.displayName = displayName; + } + + public String getIp() + { + return ip; + } + + public String getName() + { + return name; + } + + public String getDisplayName() + { + return displayName; + } + } + + public static final class JSONArrayIterable implements Iterable<JSONObject> + { + private final JSONArray array; + + public JSONArrayIterable(JSONArray array) + { + this.array = array; + } + + @Override + public Iterator<JSONObject> iterator() + { + return new Iterator<JSONObject>() + { + private int index = 0; + private final int length = array.length(); + + @Override + public boolean hasNext() + { + return index < length; + } + + @Override + public JSONObject next() + { + return array.getJSONObject(index++); + } + }; + } + } +}