BEHOLD! The Resurrection of MetaCheat!

This commit is contained in:
Brendan Robert 2018-05-23 00:38:22 -05:00
parent 9118b83a43
commit 142ee2df2a
3 changed files with 89 additions and 91 deletions

View File

@ -13,6 +13,7 @@ import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.scene.shape.Shape;
/** /**
* *
@ -31,10 +32,6 @@ public class MemoryCell implements Comparable<MemoryCell> {
public ObservableList<Integer> writeInstructions = FXCollections.observableList(new ArrayList<>()); public ObservableList<Integer> writeInstructions = FXCollections.observableList(new ArrayList<>());
public ObservableList<String> writeInstructionsDisassembly = FXCollections.observableArrayList(new ArrayList<>()); public ObservableList<String> writeInstructionsDisassembly = FXCollections.observableArrayList(new ArrayList<>());
public ObservableList<String> execInstructionsDisassembly = FXCollections.observableArrayList(new ArrayList<>()); public ObservableList<String> execInstructionsDisassembly = FXCollections.observableArrayList(new ArrayList<>());
private int x;
private int y;
private int width;
private int height;
public static void setListener(ChangeListener<MemoryCell> l) { public static void setListener(ChangeListener<MemoryCell> l) {
listener = l; listener = l;
@ -49,29 +46,6 @@ public class MemoryCell implements Comparable<MemoryCell> {
value.addListener(changeListener); value.addListener(changeListener);
} }
public void setRect(int x, int y, int w, int h) {
this.x = x;
this.y = y;
this.width = w;
this.height = h;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
@Override @Override
public int compareTo(MemoryCell o) { public int compareTo(MemoryCell o) {
return address - o.address; return address - o.address;
@ -80,4 +54,14 @@ public class MemoryCell implements Comparable<MemoryCell> {
public boolean hasCounts() { public boolean hasCounts() {
return hasCount.get(); return hasCount.get();
} }
private Shape shape;
public void setShape(Shape s) {
shape = s;
}
public Shape getShape() {
return shape;
}
} }

View File

@ -12,6 +12,7 @@ import jace.cheat.MetaCheat.SearchType;
import jace.state.State; import jace.state.State;
import java.io.File; import java.io.File;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
@ -25,8 +26,8 @@ import javafx.collections.FXCollections;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.scene.canvas.Canvas; import javafx.scene.Group;
import javafx.scene.canvas.GraphicsContext; import javafx.scene.SubScene;
import javafx.scene.control.Button; import javafx.scene.control.Button;
import javafx.scene.control.CheckBox; import javafx.scene.control.CheckBox;
import javafx.scene.control.Label; import javafx.scene.control.Label;
@ -44,18 +45,22 @@ import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell; import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.input.MouseEvent; import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import javafx.scene.layout.TilePane; import javafx.scene.layout.TilePane;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.FileChooser; import javafx.stage.FileChooser;
import javafx.stage.Screen; import javafx.stage.Screen;
import javafx.util.converter.DefaultStringConverter; import javafx.util.converter.DefaultStringConverter;
import javafx.util.converter.IntegerStringConverter; import javafx.util.converter.IntegerStringConverter;
public class MetacheatUI { public class MetacheatUI {
boolean isRetina; boolean isRetina;
double drawScale; double drawScale;
@FXML @FXML
private Button pauseButton; private Button pauseButton;
@ -70,10 +75,7 @@ public class MetacheatUI {
@FXML @FXML
private StackPane memoryViewContents; private StackPane memoryViewContents;
@FXML
private Canvas memoryViewCanvas;
@FXML @FXML
private TabPane searchTypesTabPane; private TabPane searchTypesTabPane;
@ -238,6 +240,7 @@ public class MetacheatUI {
assert searchStartAddressField != null : "fx:id=\"searchStartAddressField\" was not injected: check your FXML file 'Metacheat.fxml'."; assert searchStartAddressField != null : "fx:id=\"searchStartAddressField\" was not injected: check your FXML file 'Metacheat.fxml'.";
assert searchEndAddressField != null : "fx:id=\"searchEndAddressField\" was not injected: check your FXML file 'Metacheat.fxml'."; assert searchEndAddressField != null : "fx:id=\"searchEndAddressField\" was not injected: check your FXML file 'Metacheat.fxml'.";
assert memoryViewPane != null : "fx:id=\"memoryViewPane\" was not injected: check your FXML file 'Metacheat.fxml'."; assert memoryViewPane != null : "fx:id=\"memoryViewPane\" was not injected: check your FXML file 'Metacheat.fxml'.";
assert memoryViewContents != null : "fx:id=\"memoryViewContents\" was not injected: check your FXML file 'Metacheat.fxml'.";
assert searchTypesTabPane != null : "fx:id=\"searchTypesTabPane\" was not injected: check your FXML file 'Metacheat.fxml'."; assert searchTypesTabPane != null : "fx:id=\"searchTypesTabPane\" was not injected: check your FXML file 'Metacheat.fxml'.";
assert searchValueField != null : "fx:id=\"searchValueField\" was not injected: check your FXML file 'Metacheat.fxml'."; assert searchValueField != null : "fx:id=\"searchValueField\" was not injected: check your FXML file 'Metacheat.fxml'.";
assert searchTypeByte != null : "fx:id=\"searchTypeByte\" was not injected: check your FXML file 'Metacheat.fxml'."; assert searchTypeByte != null : "fx:id=\"searchTypeByte\" was not injected: check your FXML file 'Metacheat.fxml'.";
@ -261,7 +264,7 @@ public class MetacheatUI {
assert cheatsTableView != null : "fx:id=\"cheatsTableView\" was not injected: check your FXML file 'Metacheat.fxml'."; assert cheatsTableView != null : "fx:id=\"cheatsTableView\" was not injected: check your FXML file 'Metacheat.fxml'.";
isRetina = Screen.getPrimary().getDpi() >= 110; isRetina = Screen.getPrimary().getDpi() >= 110;
Emulator.computer.getRunningProperty().addListener((val, oldVal, newVal) -> { Emulator.computer.getRunningProperty().addListener((val, oldVal, newVal) -> {
Platform.runLater(() -> pauseButton.setText(newVal ? "Pause" : "Resume")); Platform.runLater(() -> pauseButton.setText(newVal ? "Pause" : "Resume"));
}); });
@ -301,8 +304,6 @@ public class MetacheatUI {
addWatch(result.getAddress()); addWatch(result.getAddress());
}); });
memoryViewCanvas.setMouseTransparent(false);
memoryViewCanvas.addEventFilter(MouseEvent.MOUSE_CLICKED, this::memoryViewClicked);
showValuesCheckbox.selectedProperty().addListener((prop, oldVal, newVal) -> { showValuesCheckbox.selectedProperty().addListener((prop, oldVal, newVal) -> {
if (newVal) { if (newVal) {
redrawMemoryView(); redrawMemoryView();
@ -310,7 +311,6 @@ public class MetacheatUI {
}); });
memoryViewPane.boundsInParentProperty().addListener((prop, oldVal, newVal) -> redrawMemoryView()); memoryViewPane.boundsInParentProperty().addListener((prop, oldVal, newVal) -> redrawMemoryView());
drawScale = isRetina ? 0.5 : 1.0; drawScale = isRetina ? 0.5 : 1.0;
memoryViewCanvas.widthProperty().bind(memoryViewPane.widthProperty().multiply(drawScale).subtract(8));
watchesPane.setHgap(5); watchesPane.setHgap(5);
watchesPane.setVgap(5); watchesPane.setVgap(5);
@ -377,9 +377,10 @@ public class MetacheatUI {
ChangeListener<String> addressRangeListener = (prop, oldVal, newVal) -> Application.invokeLater(this::redrawMemoryView); ChangeListener<String> addressRangeListener = (prop, oldVal, newVal) -> Application.invokeLater(this::redrawMemoryView);
public static final int MEMORY_BOX_SIZE = 4; public static final int MEMORY_BOX_SIZE = 5;
public static final int MEMORY_BOX_GAP = 2; public static final int MEMORY_BOX_GAP = 1;
public static final int MEMORY_BOX_TOTAL_SIZE = (MEMORY_BOX_SIZE + MEMORY_BOX_GAP); public static final int MEMORY_BOX_TOTAL_SIZE = (MEMORY_BOX_SIZE + MEMORY_BOX_GAP);
public static final int UPDATE_NODE_LIMIT = 10000;
public int memoryViewColumns; public int memoryViewColumns;
public int memoryViewRows; public int memoryViewRows;
@ -388,18 +389,14 @@ public class MetacheatUI {
ScheduledFuture animationFuture = null; ScheduledFuture animationFuture = null;
Tooltip memoryWatchTooltip = new Tooltip(); Tooltip memoryWatchTooltip = new Tooltip();
private void memoryViewClicked(MouseEvent e) { private void memoryViewClicked(MouseEvent e, MemoryCell cell) {
if (cheatEngine != null) { if (cheatEngine != null) {
Watch currentWatch = (Watch) memoryWatchTooltip.getGraphic(); Watch currentWatch = (Watch) memoryWatchTooltip.getGraphic();
if (currentWatch != null) { if (currentWatch != null) {
currentWatch.disconnect(); currentWatch.disconnect();
} }
double x = e.getX() / drawScale; int addr = cell.address;
double y = e.getY() / drawScale;
int col = (int) (x / MEMORY_BOX_TOTAL_SIZE);
int row = (int) (y / MEMORY_BOX_TOTAL_SIZE);
int addr = cheatEngine.getStartAddress() + row * memoryViewColumns + col;
Watch watch = new Watch(addr, this); Watch watch = new Watch(addr, this);
Label addWatch = new Label("Watch >>"); Label addWatch = new Label("Watch >>");
@ -424,7 +421,7 @@ public class MetacheatUI {
memoryWatchTooltip.setGraphic(null); memoryWatchTooltip.setGraphic(null);
}); });
memoryWatchTooltip.setGraphic(watch); memoryWatchTooltip.setGraphic(watch);
memoryWatchTooltip.show(memoryViewContents, e.getScreenX() + 5, e.getScreenY() - 15); memoryWatchTooltip.show(memoryViewPane.getContent(), e.getScreenX() + 5, e.getScreenY() - 15);
} }
} }
@ -432,22 +429,21 @@ public class MetacheatUI {
if (!Emulator.computer.getRunningProperty().get()) { if (!Emulator.computer.getRunningProperty().get()) {
return; return;
} }
GraphicsContext context = memoryViewCanvas.getGraphicsContext2D();
Set<MemoryCell> draw = new HashSet<>(redrawNodes);
redrawNodes.clear();
Application.invokeLater(() -> { Application.invokeLater(() -> {
draw.stream().forEach((jace.cheat.MemoryCell cell) -> { Iterator<MemoryCell> i = redrawNodes.iterator();
for (int limit = 0; i.hasNext() && limit < UPDATE_NODE_LIMIT; limit++) {
MemoryCell cell = i.next();
i.remove();
if (showValuesCheckbox.isSelected()) { if (showValuesCheckbox.isSelected()) {
int val = cell.value.get() & 0x0ff; int val = cell.value.get() & 0x0ff;
context.setFill(Color.rgb(val, val, val)); cell.getShape().setFill(Color.rgb(val, val, val));
} else { } else {
context.setFill(Color.rgb( cell.getShape().setFill(Color.rgb(
cell.writeCount.get(), cell.writeCount.get(),
cell.readCount.get(), cell.readCount.get(),
cell.execCount.get())); cell.execCount.get()));
} }
context.fillRect(cell.getX(), cell.getY(), cell.getWidth(), cell.getHeight()); }
});
}); });
} }
@ -473,29 +469,29 @@ public class MetacheatUI {
int pixelsPerBlock = 16 * MEMORY_BOX_TOTAL_SIZE; int pixelsPerBlock = 16 * MEMORY_BOX_TOTAL_SIZE;
memoryViewColumns = (int) (memoryViewPane.getWidth() / pixelsPerBlock) * 16; memoryViewColumns = (int) (memoryViewPane.getWidth() / pixelsPerBlock) * 16;
memoryViewRows = ((cheatEngine.getEndAddress() - cheatEngine.getStartAddress()) / memoryViewColumns) + 1; memoryViewRows = ((cheatEngine.getEndAddress() - cheatEngine.getStartAddress()) / memoryViewColumns) + 1;
double canvasHeight = memoryViewRows * MEMORY_BOX_TOTAL_SIZE * drawScale;
memoryViewContents.prefWidthProperty().bind(memoryViewPane.widthProperty().multiply(drawScale).subtract(8));
memoryViewContents.setPrefHeight(canvasHeight);
memoryViewCanvas.setHeight(canvasHeight); Group memoryView = new Group();
GraphicsContext context = memoryViewCanvas.getGraphicsContext2D(); memoryViewContents.setBackground(new Background(new BackgroundFill(Color.rgb(40, 40, 40), null, null)));
context.setFill(Color.rgb(40, 40, 40));
context.fillRect(0, 0, memoryViewCanvas.getWidth(), memoryViewCanvas.getHeight());
for (int addr = cheatEngine.getStartAddress(); addr <= cheatEngine.getEndAddress(); addr++) { for (int addr = cheatEngine.getStartAddress(); addr <= cheatEngine.getEndAddress(); addr++) {
int col = (addr - cheatEngine.getStartAddress()) % memoryViewColumns; int col = (addr - cheatEngine.getStartAddress()) % memoryViewColumns;
int row = (addr - cheatEngine.getStartAddress()) / memoryViewColumns; int row = (addr - cheatEngine.getStartAddress()) / memoryViewColumns;
MemoryCell cell = cheatEngine.getMemoryCell(addr); MemoryCell cell = cheatEngine.getMemoryCell(addr);
cell.setRect( Rectangle rect = new Rectangle(col * MEMORY_BOX_TOTAL_SIZE * drawScale, row * MEMORY_BOX_TOTAL_SIZE * drawScale, MEMORY_BOX_SIZE * drawScale, MEMORY_BOX_SIZE * drawScale);
(int) (col * MEMORY_BOX_TOTAL_SIZE * drawScale), rect.setOnMouseClicked(e -> memoryViewClicked(e, cell));
(int) (row * MEMORY_BOX_TOTAL_SIZE * drawScale), rect.setFill(Color.GRAY);
(int) (MEMORY_BOX_SIZE * drawScale), cell.setShape(rect);
(int) (MEMORY_BOX_SIZE * drawScale)); memoryView.getChildren().add(rect);
redrawNodes.add(cell); redrawNodes.add(cell);
} }
memoryViewContents.getChildren().clear();
memoryViewContents.getChildren().add(memoryView);
MemoryCell.setListener((javafx.beans.value.ObservableValue<? extends jace.cheat.MemoryCell> prop, jace.cheat.MemoryCell oldCell, jace.cheat.MemoryCell newCell) -> { MemoryCell.setListener((javafx.beans.value.ObservableValue<? extends jace.cheat.MemoryCell> prop, jace.cheat.MemoryCell oldCell, jace.cheat.MemoryCell newCell) -> {
redrawNodes.add(newCell); redrawNodes.add(newCell);
}); });
setZoom(1/drawScale); setZoom(1 / drawScale);
if (resume) { if (resume) {
Emulator.computer.resume(); Emulator.computer.resume();
@ -503,19 +499,19 @@ public class MetacheatUI {
} }
private void changeZoom(double amount) { private void changeZoom(double amount) {
if (memoryViewCanvas != null) { if (memoryViewContents != null) {
double zoom = memoryViewCanvas.getScaleX(); double zoom = memoryViewContents.getScaleX();
zoom += amount; zoom += amount;
setZoom(zoom); setZoom(zoom);
} }
} }
private void setZoom(double zoom) { private void setZoom(double zoom) {
if (memoryViewCanvas != null) { if (memoryViewContents != null) {
memoryViewCanvas.setScaleX(zoom); memoryViewContents.setScaleX(zoom);
memoryViewCanvas.setScaleY(zoom); memoryViewContents.setScaleY(zoom);
StackPane scrollArea = (StackPane) memoryViewCanvas.getParent(); // StackPane scrollArea = (StackPane) memoryViewCanvas.getParent();
scrollArea.setPrefSize(memoryViewCanvas.getWidth() * zoom, memoryViewCanvas.getHeight() * zoom); // scrollArea.setPrefSize(memoryViewCanvas.getWidth() * zoom, memoryViewCanvas.getHeight() * zoom);
} }
} }

View File

@ -1,14 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?> <?import java.net.URL?>
<?import javafx.geometry.*?> <?import javafx.geometry.Insets?>
<?import java.net.*?> <?import javafx.scene.SubScene?>
<?import javafx.scene.canvas.*?> <?import javafx.scene.control.Button?>
<?import javafx.scene.text.*?> <?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.*?> <?import javafx.scene.control.Label?>
<?import javafx.scene.layout.*?> <?import javafx.scene.control.ListView?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.control.ToolBar?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.TilePane?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="520.0" prefWidth="710.0" stylesheets="@../styles/style.css" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="jace.ui.MetacheatUI"> <!--<?import javafx.scene.canvas.*?>-->
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="520.0" prefWidth="710.0" stylesheets="@../styles/style.css" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="jace.ui.MetacheatUI">
<stylesheets> <stylesheets>
<URL value="@/styles/style.css" /> <URL value="@/styles/style.css" />
</stylesheets> </stylesheets>
@ -29,11 +51,7 @@
<items> <items>
<ScrollPane fx:id="memoryViewPane" prefHeight="450.0" prefWidth="391.0"> <ScrollPane fx:id="memoryViewPane" prefHeight="450.0" prefWidth="391.0">
<content> <content>
<StackPane fx:id="memoryViewContents" prefHeight="150.0" prefWidth="200.0"> <StackPane fx:id="memoryViewContents" prefHeight="150.0" prefWidth="200.0"/>
<children>
<Canvas fx:id="memoryViewCanvas" height="200.0" width="200.0" />
</children>
</StackPane>
</content></ScrollPane> </content></ScrollPane>
<ScrollPane fitToHeight="true" fitToWidth="true" prefHeight="200.0" prefWidth="200.0"> <ScrollPane fitToHeight="true" fitToWidth="true" prefHeight="200.0" prefWidth="200.0">
<content> <content>