diff --git a/src/com/projectswg/ItemSelectedCallback.java b/src/com/projectswg/ItemSelectedCallback.java new file mode 100644 index 0000000..9da6b69 --- /dev/null +++ b/src/com/projectswg/ItemSelectedCallback.java @@ -0,0 +1,6 @@ +package com.projectswg; + +public interface ItemSelectedCallback { + void onPacketSelected(int index); + void onObjectSelected(long objectId); +} diff --git a/src/com/projectswg/LeftPanelContent.java b/src/com/projectswg/LeftPanelContent.java new file mode 100644 index 0000000..ed76102 --- /dev/null +++ b/src/com/projectswg/LeftPanelContent.java @@ -0,0 +1,6 @@ +package com.projectswg; + +public enum LeftPanelContent { + PACKETS, + OBJECTS +} diff --git a/src/com/projectswg/PacketMaster.java b/src/com/projectswg/PacketMaster.java index f7fdcbd..e72c23c 100644 --- a/src/com/projectswg/PacketMaster.java +++ b/src/com/projectswg/PacketMaster.java @@ -2,17 +2,16 @@ package com.projectswg; import java.io.File; import java.lang.reflect.Field; -import java.net.InetAddress; -import java.util.Date; import com.projectswg.layout.AnalysisPanel; import com.projectswg.layout.LayoutLoader; import com.projectswg.layout.PacketPanel; import com.projectswg.layout.ToolbarPanel; -import com.projectswg.packets.PacketData; import com.projectswg.packets.PacketInterface; +import com.projectswg.packets.PacketInterface.InterfacePacket; import com.projectswg.packets.PacketInterface.PacketInterfaceCallback; import com.projectswg.packets.PacketProcessor; +import com.projectswg.packets.PacketProcessor.CrcChangedException; import javafx.application.Application; import javafx.geometry.VPos; @@ -33,7 +32,7 @@ public class PacketMaster extends Application implements PacketInterfaceCallback private Stage stage; - private PacketData packetData; + private PacketMasterData packetMasterData; private PacketInterface packetInterface; private PacketProcessor packetProcessor; @@ -56,14 +55,14 @@ public class PacketMaster extends Application implements PacketInterfaceCallback @Override public void init() throws Exception { super.init(); - packetData = new PacketData(); + packetMasterData = new PacketMasterData(); packetInterface = new PacketInterface(); - packetProcessor = new PacketProcessor(packetData); + packetProcessor = new PacketProcessor(packetMasterData); packetInterface.setCallback(this); - toolbarPanel = new ToolbarPanel(packetData); - packetPanel = new PacketPanel(packetData); - analysisPanel = new AnalysisPanel(packetData); + toolbarPanel = new ToolbarPanel(packetMasterData); + packetPanel = new PacketPanel(packetMasterData); + analysisPanel = new AnalysisPanel(packetMasterData); packetPanel.setPacketSelectedCallback(analysisPanel); toolbarPanel.addPacketSelectedCallback(analysisPanel); toolbarPanel.addPacketSelectedCallback(packetPanel); @@ -173,18 +172,27 @@ public class PacketMaster extends Application implements PacketInterfaceCallback @Override public void onCaptureStarted() { - packetData.clear(); + packetMasterData.getData().clear(); + packetProcessor.reset(); } @Override - public void onPacket(InetAddress addr, int source, int destination, Date time, byte [] data) { - packetProcessor.onPacket(addr, time, data, packetData.isClient(addr) ? source : destination); + public void onPacket(InterfacePacket packet) { + try { + packetProcessor.onPacket(packet); + } catch (CrcChangedException e) { + if (!packetInterface.isLive()) { + packetInterface.restart(); + } + } } @Override public void onCaptureFinished() { // gui.repaint(); + packetProcessor.onCaptureFinished(); packetPanel.updatePackets(); + packetPanel.updateObjects(); } public void openFile(String file) { diff --git a/src/com/projectswg/PacketMasterData.java b/src/com/projectswg/PacketMasterData.java new file mode 100644 index 0000000..32da98e --- /dev/null +++ b/src/com/projectswg/PacketMasterData.java @@ -0,0 +1,50 @@ +package com.projectswg; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +import com.projectswg.packets.PacketData; + +public class PacketMasterData { + + private final AtomicReference leftPanel; + private final AtomicBoolean searchSoe; + private final AtomicBoolean searchSwg; + private final PacketData data; + + public PacketMasterData() { + leftPanel = new AtomicReference<>(LeftPanelContent.PACKETS); + searchSoe = new AtomicBoolean(false); + searchSwg = new AtomicBoolean(true); + data = new PacketData(); + } + + public PacketData getData() { + return data; + } + + public void setLeftPanelContent(LeftPanelContent content) { + leftPanel.set(content); + } + + public LeftPanelContent getLeftPanelContent() { + return leftPanel.get(); + } + + public void setSearchSoe(boolean searchSoe) { + this.searchSoe.set(searchSoe); + } + + public boolean isSearchSoe() { + return searchSoe.get(); + } + + public void setSearchSwg(boolean searchSwg) { + this.searchSwg.set(searchSwg); + } + + public boolean isSearchSwg() { + return searchSwg.get(); + } + +} diff --git a/src/com/projectswg/PacketSelectedCallback.java b/src/com/projectswg/PacketSelectedCallback.java deleted file mode 100644 index 2d40e5b..0000000 --- a/src/com/projectswg/PacketSelectedCallback.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.projectswg; - -public interface PacketSelectedCallback { - void onPacketSelected(int index); -} diff --git a/src/com/projectswg/gui/BaselineProcessor.java b/src/com/projectswg/gui/BaselineProcessor.java index 854cd40..f058a92 100644 --- a/src/com/projectswg/gui/BaselineProcessor.java +++ b/src/com/projectswg/gui/BaselineProcessor.java @@ -22,7 +22,7 @@ import resources.encodables.Encodable; import com.sun.org.apache.xerces.internal.parsers.DOMParser; -import network.packets.Packet; +import com.projectswg.network.packets.Packet; import network.packets.swg.zone.baselines.Baseline.BaselineType; public class BaselineProcessor { @@ -91,15 +91,15 @@ public class BaselineProcessor { int pos = data.position(); data.get(extra); data.position(pos); - int len = Packet.getInt(data); + int size = Packet.getInt(data); Packet.getInt(data); // updates StringBuilder bldr = new StringBuilder(); - for (int i = 0; i < len; i++) { + for (int i = 0; i < size; i++) { if (i > 0) bldr.append(", "); bldr.append(processVariable(data, subType)); } - return type + " " + bldr.toString(); + return type + " ["+size+"] " + bldr.toString(); } else if (type.startsWith("SWGMap")) { String [] subTypes = type.substring(type.indexOf(':')+1).split(",", 2); byte[] extra = new byte[data.remaining()]; @@ -119,7 +119,7 @@ public class BaselineProcessor { } catch (Exception e) { e.printStackTrace(); } - return type + " " + bldr.toString(); + return type + " ["+size+"] " + bldr.toString(); } try { Object o = Class.forName(type).newInstance(); diff --git a/src/com/projectswg/gui/GUIPacket.java b/src/com/projectswg/gui/GUIPacket.java index 68dd34f..586c076 100644 --- a/src/com/projectswg/gui/GUIPacket.java +++ b/src/com/projectswg/gui/GUIPacket.java @@ -4,11 +4,12 @@ import java.nio.ByteBuffer; import java.util.Date; import network.PacketType; +import network.packets.Packet; import network.packets.swg.SWGPacket; public class GUIPacket { - private SWGPacket packet; + private Packet packet; private PacketType type; private ByteBuffer data; private Date time; @@ -32,19 +33,18 @@ public class GUIPacket { this.port = port; } - public GUIPacket(ByteBuffer data, Date time, int soeOpcode, int port, boolean client) { - this.data = data; + public GUIPacket(Packet packet, Date time, int soeOpcode, int port, boolean client) { + this.packet = packet; + this.data = packet.getData(); this.soeOpcode = soeOpcode; this.client = client; this.time = time; this.port = port; - - this.packet = null; this.type = null; this.swgOpcode = 0; } - public SWGPacket getPacket() { return packet; } + public Packet getPacket() { return packet; } public PacketType getType() { return type; } public ByteBuffer getData() { return data; } public Date getTime() { return time; } @@ -52,7 +52,7 @@ public class GUIPacket { public int getSWGOpcode() { return swgOpcode; } public int getSOEOpcode() { return soeOpcode; } public boolean isClient() { return client; } - public boolean isSWGPacket() { return packet != null; } + public boolean isSWGPacket() { return swgOpcode != 0; } public String toString() { String packetName = getStringForSOEOpcode(soeOpcode); diff --git a/src/com/projectswg/layout/AnalysisPanel.java b/src/com/projectswg/layout/AnalysisPanel.java index 9083ae6..b20761f 100644 --- a/src/com/projectswg/layout/AnalysisPanel.java +++ b/src/com/projectswg/layout/AnalysisPanel.java @@ -1,13 +1,17 @@ package com.projectswg.layout; import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.net.URL; import java.nio.ByteBuffer; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; +import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; import java.util.Map.Entry; @@ -18,7 +22,12 @@ import network.packets.swg.zone.deltas.DeltasMessage; import org.jnetpcap.nio.JBuffer; -import com.projectswg.PacketSelectedCallback; +import resources.network.BaselineObject; +import resources.objects.SWGObject; +import resources.server_info.CrcDatabase; + +import com.projectswg.ItemSelectedCallback; +import com.projectswg.PacketMasterData; import com.projectswg.gui.BaselineProcessor; import com.projectswg.gui.GUIPacket; import com.projectswg.packets.PacketData; @@ -28,17 +37,19 @@ import javafx.geometry.Insets; import javafx.scene.control.TextArea; import javafx.scene.layout.Pane; -public class AnalysisPanel extends Pane implements Initializable, PacketSelectedCallback { +public class AnalysisPanel extends Pane implements Initializable, ItemSelectedCallback { private final PacketData packetData; + private final CrcDatabase crcDatabase; private DateFormat dateFormat; private GUIPacket packet; private TextArea packetDisplay; - public AnalysisPanel(PacketData data) { - this.packetData = data; - dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss.SSS z");; + public AnalysisPanel(PacketMasterData data) { + this.packetData = data.getData(); + this.crcDatabase = new CrcDatabase(); + dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss.SSS z"); LayoutLoader.load("AnalysisPanel.fxml", this, this); } @@ -54,19 +65,24 @@ public class AnalysisPanel extends Pane implements Initializable, PacketSelected @Override public void onPacketSelected(int index) { - setPacket(packetData.get(index)); - } - - public void setPacket(GUIPacket packet) { - this.packet = packet; + this.packet = packetData.get(index); StringBuilder str = new StringBuilder(); - if (packet.getSWGOpcode() != 0) + if (packet.getSWGOpcode() != 0 && packet.getPacket() instanceof SWGPacket) drawSWGPacket(str); else drawSOEPacket(str); packetDisplay.setText(str.toString()); } + @Override + public void onObjectSelected(long objectId) { + StringBuilder str = new StringBuilder(); + SWGObject obj = packetData.getObject(objectId); + if (obj != null) + drawObject(str, obj, 0); + packetDisplay.setText(str.toString()); + } + @Override protected void layoutChildren() { super.layoutChildren(); @@ -74,89 +90,142 @@ public class AnalysisPanel extends Pane implements Initializable, PacketSelected } private void drawSWGPacket(StringBuilder str) { - SWGPacket packet = this.packet.getPacket(); + if (!(packet.getPacket() instanceof SWGPacket)) + return; + SWGPacket packet = (SWGPacket) this.packet.getPacket(); ByteBuffer data = packet.getData(); data.position(0); - int line = 0; - drawString(str, "Date: " + dateFormat.format(this.packet.getTime()), line++); - drawString(str, "Port: " + this.packet.getPort(), line++); - drawString(str, "Priority: " + String.format("0x%04X", packet.getOpcode()), line++); - drawString(str, "SWG Opcode: " + String.format("0x%08X", packet.getSWGOpcode()).toUpperCase(), line++); - drawString(str, "Packet: " + packet.getClass().getSimpleName(), line++); + drawString(str, "Date: " + dateFormat.format(this.packet.getTime())); + drawString(str, "Source: " + this.packet.getPacket().getAddress() + ":" + this.packet.getPort()); + drawString(str, "Priority: " + String.format("0x%04X", packet.getOpcode())); + drawString(str, "SWG Opcode: " + String.format("0x%08X", packet.getSWGOpcode()).toUpperCase()); + drawString(str, "Packet: " + packet.getClass().getSimpleName()); if (packet instanceof Baseline) { Baseline b = (Baseline) packet; - drawString(str, "Type: " + b.getType() + " " + b.getNum(), line++); - drawString(str, "Object ID: " + b.getObjectId() + " [" + String.format("%016X", b.getObjectId()) + "]", line++); + drawString(str, "Type: " + b.getType() + " " + b.getNum()); + drawString(str, "Object ID: " + b.getObjectId() + " [" + String.format("%016X", b.getObjectId()) + "]"); + drawStrings(str, createRaw(data)); + drawString(str, ""); + SWGObject obj = packetData.getObject(b.getObjectId()); + if (obj != null) + drawObject(str, obj, 0); + else + drawString(str, "NULL"); + return; } else if (packet instanceof DeltasMessage) { DeltasMessage b = (DeltasMessage) packet; - drawString(str, "Type: " + b.getType() + " " + b.getNum(), line++); - drawString(str, "Object ID: " + b.getObjectId() + " [" + String.format("%016X", b.getObjectId()) + "]", line++); + drawString(str, "Type: " + b.getType() + " " + b.getNum()); + drawString(str, "Object ID: " + b.getObjectId() + " [" + String.format("%016X", b.getObjectId()) + "]"); } - line = drawStrings(str, createRaw(data), line); - drawString(str, "", line++); - line = drawObject(str, packet, line, 0); + drawStrings(str, createRaw(data)); + drawString(str, ""); + if (packet != null) + drawObject(str, packet, 0); } - private int drawObject(StringBuilder str, Object o, int line, int indentation) { - Field [] fields = o.getClass().getDeclaredFields(); - String formatString = (indentation>0)?("%-"+indentation*4+"s%-25s %s"):"%s%-25s %s"; - try { - for (Field f : fields) { - try { - if (o instanceof Baseline && f.getType().equals(byte[].class)) { - drawString(str, String.format(formatString, "", f.getName(), f.getType().getSimpleName()), line++); - line = drawBaseline(str, (Baseline) o, line, indentation+1); - } else - line = drawObject(str, o, f, line, indentation); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - } - } catch (Exception e) { - e.printStackTrace(); + private List getAllFields(List fields, Class type) { + Class s = type.getSuperclass(); + if (s != null && (SWGPacket.class.isAssignableFrom(s) || BaselineObject.class.isAssignableFrom(s))) { + fields = getAllFields(fields, type.getSuperclass()); } - return line; + fields.addAll(Arrays.asList(type.getDeclaredFields())); + + return fields; } - private int drawObject(StringBuilder str, Object o, Field f, int line, int indentation) throws IllegalArgumentException, IllegalAccessException { + private void drawObject(StringBuilder str, Object o, int indentation) { + for (Field f : getAllFields(new ArrayList<>(), o.getClass())) { + if ((f.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) != 0) + continue; + drawObject(str, o, f, indentation); + } + } + + private void drawObject(StringBuilder str, Object o, Field f, int indentation) { f.setAccessible(true); - String formatString = (indentation>0)?("%-"+indentation*4+"s%-25s %s"):"%s%-25s %s"; - Object field = f.get(o); - if (field == null) - drawString(str, String.format((indentation>0)?("%-"+indentation*4+"s%-25s null"):"%s%-25s null", "", f.getName()), line++); - else if (field.getClass().isArray()) - line = drawArray(str, f, field, line, indentation); - else if (field instanceof Collection) - drawArray(str, f, ((Collection)field).toArray(), line++, indentation); - else if (field instanceof Enum || field instanceof Enumeration) - drawString(str, String.format(formatString, "", f.getName(), field), line++); - else if (field instanceof String || field instanceof Number || field instanceof Boolean) - drawString(str, String.format(formatString, "", f.getName(), field), line++); - else if (o instanceof Baseline && field instanceof byte[]) { - drawString(str, String.format(formatString, "", f.getName(), field.getClass().getSimpleName()), line++); - line = drawBaseline(str, (Baseline) o, line, indentation+1); - } else { - drawString(str, String.format(formatString, "", f.getName(), field.getClass().getSimpleName()), line++); - line = drawObject(str, field, line, indentation+1); + String format = (indentation>0)?("%-"+indentation*4+"s%-25s %s"):"%s%-25s %s"; + Object field; + try { + field = f.get(o); + } catch (IllegalArgumentException | IllegalAccessException e) { + e.printStackTrace(); + return; } - return line; + boolean success = false; + success = success || drawNull(str, f, field, format); + success = success || drawNumber(str, f, field, format); + success = success || drawEnum(str, f, field, format); + success = success || drawCollection(str, f, field, format); + if (!success) + drawLeftover(str, f, field, o, format, indentation); } - private int drawArray(StringBuilder str, Field f, Object field, int line, int indentation) { - String formatString = (indentation>0)?("%-"+indentation*4+"s%-25s %s"):"%s%-25s %s"; + private boolean drawNull(StringBuilder str, Field f, Object field, String format) { + if (field == null) { + drawString(str, String.format(format, "", f.getName(), "null")); + return true; + } + return false; + } + + private boolean drawNumber(StringBuilder str, Field f, Object field, String format) { + if (field instanceof Integer) { + if (f.getName().toLowerCase(Locale.US).contains("crc")) { + drawString(str, String.format(format+" [%s]", "", f.getName(), field, crcDatabase.getString((Integer) field))); + } else + drawString(str, String.format(format, "", f.getName(), field)); + } else if (field instanceof String || field instanceof Number || field instanceof Boolean) + drawString(str, String.format(format, "", f.getName(), field)); + else + return false; + return true; + } + + private boolean drawEnum(StringBuilder str, Field f, Object field, String format) { + if (field instanceof Enum || field instanceof Enumeration) + drawString(str, String.format(format, "", f.getName(), field)); + else + return false; + return true; + } + + private boolean drawCollection(StringBuilder str, Field f, Object field, String format) { + if (field instanceof Collection) + return drawArray(str, f, ((Collection) field).toArray(), format); + else if (field instanceof Map) + drawString(str, String.format(format, "", f.getName(), field.getClass().getSimpleName() + " " + field)); + else if (field.getClass().isArray()) + drawArray(str, f, field, format); + else + return false; + return true; + } + + private void drawLeftover(StringBuilder str, Field f, Object field, Object o, String format, int indent) { + drawString(str, String.format(format, "", f.getName(), field.getClass().getSimpleName())); + if (o instanceof Baseline && field instanceof byte[]) + drawBaseline(str, (Baseline) o, indent+1); + else if (!field.getClass().isAssignableFrom(Object.class)) + drawObject(str, field, indent+1); + } + + private boolean drawArray(StringBuilder str, Field f, Object field, String format) { String array = drawArray(field); if (array != null) - drawString(str, String.format(formatString, "", f.getName(), array), line++); + drawString(str, String.format(format, "", f.getName(), f.getType().getSimpleName() + " " + array)); else if (field != null) { - drawString(str, String.format(formatString, "", f.getName(), "["), line++); + drawString(str, String.format(format, "", f.getName(), f.getType().getName() + " [")); for (Object sub : (Object []) field) { - drawString(str, String.format("%-"+(indentation+1)*4+"s%-25s %s", "", "", sub), line++); + String subStr = drawArray(sub); + if (subStr != null) + drawString(str, String.format(" "+format, "", "", subStr)); + else + drawString(str, String.format(" "+format, "", "", sub)); } - drawString(str, String.format(formatString, "", "", "]"), line++); - } - return line; + drawString(str, String.format(format, "", "", "]")); + } else + return false; + return true; } private String drawArray(Object o) { @@ -175,25 +244,25 @@ public class AnalysisPanel extends Pane implements Initializable, PacketSelected return null; } - private int drawBaseline(StringBuilder str, Baseline b, int line, int indentation) { + private void drawBaseline(StringBuilder str, Baseline b, int indentation) { String formatString = (indentation>0)?("%-"+indentation*4+"s%-25s %s"):"%s%-20s %s"; ByteBuffer data = ByteBuffer.wrap(b.getBaselineData()); data.getShort(); Map variables = new BaselineProcessor().process(data, b.getType(), b.getNum()); for (Entry e : variables.entrySet()) { - drawString(str, String.format(formatString, "", e.getKey(), e.getValue()), line++); + drawString(str, String.format(formatString, "", e.getKey(), e.getValue())); } - return line; } private void drawSOEPacket(StringBuilder str) { ByteBuffer data = packet.getData(); data.position(0); - int line = 0; - drawString(str, "Date: " + dateFormat.format(this.packet.getTime()), line++); - drawString(str, "Port: " + packet.getPort(), line++); - drawString(str, "SOE Opcode: " + packet.getSOEOpcode(), line++); - line = drawStrings(str, new JBuffer(data).toHexdump(), line); + drawString(str, "Date: " + dateFormat.format(this.packet.getTime())); + drawString(str, "Port: " + this.packet.getPacket().getAddress() + ":" + this.packet.getPort()); + drawString(str, "SOE Opcode: " + packet.getSOEOpcode()); + drawStrings(str, new JBuffer(data).toHexdump()); + drawString(str, ""); + drawObject(str, packet.getPacket(), 0); } private String createRaw(ByteBuffer data) { @@ -202,7 +271,7 @@ public class AnalysisPanel extends Pane implements Initializable, PacketSelected StringBuilder ascii = new StringBuilder(""); int ind = 0; int pos = 0; - while (data.remaining() > 0) { + while (data.hasRemaining()) { if (pos > 0 && pos % 4 == 0) s.append(' '); if (pos == 16) { @@ -241,7 +310,7 @@ public class AnalysisPanel extends Pane implements Initializable, PacketSelected return s.toString(); } - private int drawStrings(StringBuilder str, String completeStr, int line) { + private void drawStrings(StringBuilder str, String completeStr) { String [] strLines = completeStr.split("\n"); for (String s : strLines) { int finalIndex = 0; @@ -255,12 +324,11 @@ public class AnalysisPanel extends Pane implements Initializable, PacketSelected finalIndex = i+5; } s = s.substring(0, finalIndex).toUpperCase() + s.substring(finalIndex); - drawString(str, s, line++); + drawString(str, s); } - return line; } - private void drawString(StringBuilder s, String str, int line) { + private void drawString(StringBuilder s, String str) { s.append(str + '\n'); } diff --git a/src/com/projectswg/layout/PacketPanel.java b/src/com/projectswg/layout/PacketPanel.java index d7e11fb..a957870 100644 --- a/src/com/projectswg/layout/PacketPanel.java +++ b/src/com/projectswg/layout/PacketPanel.java @@ -3,83 +3,157 @@ package com.projectswg.layout; import java.net.URL; import java.util.ResourceBundle; -import com.projectswg.PacketSelectedCallback; +import resources.objects.SWGObject; + +import com.projectswg.ItemSelectedCallback; +import com.projectswg.LeftPanelContent; +import com.projectswg.PacketMasterData; import com.projectswg.gui.GUIPacket; import com.projectswg.packets.PacketData; import javafx.application.Platform; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.fxml.Initializable; import javafx.scene.control.ListCell; import javafx.scene.control.ListView; import javafx.scene.control.SelectionMode; +import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; +import javafx.scene.control.Tooltip; import javafx.scene.layout.Background; import javafx.scene.layout.BackgroundFill; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; -public class PacketPanel extends Pane implements Initializable, PacketSelectedCallback { +public class PacketPanel extends Pane implements Initializable, ItemSelectedCallback { + private final PacketMasterData packetMasterData; private final PacketData packetData; - private ListView list; - private ObservableList items; - private PacketSelectedCallback selectedCallback; + private ListView packetList; + private ListView objectList; + private ObservableList packetItems; + private ObservableList objectItems; + private ItemSelectedCallback selectedCallback; + private TabPane tabPane; + private Tab packetTab; + private Tab objectTab; - public PacketPanel(PacketData packetData) { - this.packetData = packetData; + public PacketPanel(PacketMasterData packetData) { + this.packetMasterData = packetData; + this.packetData = packetData.getData(); LayoutLoader.load("PacketPanel.fxml", this, this); selectedCallback = null; } @Override public void initialize(URL location, ResourceBundle resources) { - list = new ListView<>(); - list.setEditable(false); - list.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); - list.setCellFactory((param) -> new PacketListCell()); - list.setOnMouseClicked((event) -> { + packetList = new ListView<>(); + packetList.setEditable(false); + packetList.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); + packetList.setCellFactory((param) -> new PacketListCell()); + packetList.setOnMouseClicked((event) -> { if (selectedCallback != null) { - int index = list.getSelectionModel().getSelectedIndex(); - packetData.setSelectedIndex(index); - selectedCallback.onPacketSelected(index); + int index = packetList.getSelectionModel().getSelectedIndex(); + if (index >= 0 && index < packetData.size()) { + packetData.setSelectedIndex(index); + selectedCallback.onPacketSelected(index); + } + } + }); + objectList = new ListView<>(); + objectList.setEditable(false); + objectList.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); + objectList.setCellFactory((param) -> new ObjectListCell()); + objectList.setOnMouseClicked((event) -> { + if (selectedCallback != null) { + SWGObject obj = objectList.getSelectionModel().getSelectedItem(); + if (obj == null) + return; + long id = obj.getObjectId(); + packetData.setSelectedId(id); + selectedCallback.onObjectSelected(id); } }); updatePackets(); - getChildren().add(list); + updateObjects(); + tabPane = new TabPane(); + packetTab = new Tab("Packets", packetList); + objectTab = new Tab("Objects", objectList); + tabPane.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue ov, Tab oldTab, Tab newTab) { + if (newTab == packetTab) + packetMasterData.setLeftPanelContent(LeftPanelContent.PACKETS); + else if (newTab == objectTab) + packetMasterData.setLeftPanelContent(LeftPanelContent.OBJECTS); + } + }); + packetTab.setClosable(false); + objectTab.setClosable(false); + packetTab.setTooltip(new Tooltip("Raw Packet List")); + objectTab.setTooltip(new Tooltip("Object List")); + tabPane.getTabs().add(packetTab); + tabPane.getTabs().add(objectTab); + getChildren().add(tabPane); } @Override public void onPacketSelected(int index) { + tabPane.getSelectionModel().select(packetTab); packetData.setSelectedIndex(index); - list.getSelectionModel().clearAndSelect(index); - list.getFocusModel().focus(index); - list.scrollTo(index); + packetList.getSelectionModel().clearAndSelect(index); + packetList.getFocusModel().focus(index); + packetList.scrollTo(index); } + @Override + public void onObjectSelected(long objectId) { + tabPane.getSelectionModel().select(objectTab); + packetData.setSelectedId(objectId); + SWGObject obj = packetData.getObject(objectId); + if (obj == null) { + System.err.println("Object not found for ID: " + objectId); + return; + } + int index = objectItems.indexOf(obj); + if (index == -1) { + System.err.println("Item index not found!"); + return; + } + packetData.setSelectedIndex(index); + objectList.getSelectionModel().clearAndSelect(index); + objectList.getFocusModel().focus(index); + objectList.scrollTo(index); + } + @Override protected void layoutChildren() { super.layoutChildren(); - list.resize(getWidth(), getHeight()); + tabPane.resize(getWidth(), getHeight()); } - public void setPacketSelectedCallback(PacketSelectedCallback callback) { + public void setPacketSelectedCallback(ItemSelectedCallback callback) { this.selectedCallback = callback; } public void updatePackets() { - items = FXCollections.observableArrayList(); - for (GUIPacket packet : packetData.getPackets()) { - items.add(packet); - } - Platform.runLater(() -> list.setItems(items)); + packetItems = FXCollections.observableArrayList(packetData.getPackets()); + Platform.runLater(() -> packetList.setItems(packetItems)); + } + + public void updateObjects() { + objectItems = FXCollections.observableArrayList(packetData.getObjects()); + Platform.runLater(() -> objectList.setItems(objectItems)); } private static class PacketListCell extends ListCell { - private static final Background SOE_PACKET = new Background(new BackgroundFill(new Color(0, .75, 0, 1), null, null)); - private static final Background SWG_PACKET = new Background(new BackgroundFill(new Color(.6, .6, .6, 1), null, null)); + private static final Background SOE_PACKET = new Background(new BackgroundFill(new Color(.6, .6, .6, 1), null, null)); + private static final Background SWG_PACKET = new Background(new BackgroundFill(new Color(0, .75, 0, 1), null, null)); @Override public void updateItem(GUIPacket packet, boolean empty) { @@ -98,4 +172,23 @@ public class PacketPanel extends Pane implements Initializable, PacketSelectedCa } } + private static class ObjectListCell extends ListCell { + + private static final Background BACKGROUND = new Background(new BackgroundFill(new Color(.8, .8, .8, 1), null, null)); + + @Override + public void updateItem(SWGObject object, boolean empty) { + super.updateItem(object, empty); + if (empty) { + setText(null); + setGraphic(null); + setBackground(BACKGROUND); + } else { + setText(object.getClass().getSimpleName()); + setGraphic(null); + setBackground(BACKGROUND); + } + } + } + } diff --git a/src/com/projectswg/layout/ToolbarPanel.fxml b/src/com/projectswg/layout/ToolbarPanel.fxml index 86ba6f6..86c7b90 100644 --- a/src/com/projectswg/layout/ToolbarPanel.fxml +++ b/src/com/projectswg/layout/ToolbarPanel.fxml @@ -5,10 +5,10 @@ - +