mirror of
https://github.com/badvision/jace.git
synced 2024-11-24 15:30:51 +00:00
Refactored code a little, cheats are now editable and support javascript expressions. Almost done now! :-D
This commit is contained in:
parent
bed635c7fc
commit
facd73d345
99
src/main/java/jace/cheat/DynamicCheat.java
Normal file
99
src/main/java/jace/cheat/DynamicCheat.java
Normal file
@ -0,0 +1,99 @@
|
||||
package jace.cheat;
|
||||
|
||||
import jace.core.RAMEvent;
|
||||
import jace.core.RAMListener;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.util.Callback;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author blurry
|
||||
*/
|
||||
public class DynamicCheat extends RAMListener {
|
||||
int id;
|
||||
IntegerProperty addr;
|
||||
StringProperty expression;
|
||||
BooleanProperty active;
|
||||
StringProperty name;
|
||||
Callback<RAMEvent, Integer> expressionCallback;
|
||||
|
||||
public DynamicCheat(int address, String expr) {
|
||||
super(RAMEvent.TYPE.ANY, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY);
|
||||
id = (int) (Math.random() * 10000000);
|
||||
addr = new SimpleIntegerProperty(address);
|
||||
expression = new SimpleStringProperty(expr);
|
||||
active = new SimpleBooleanProperty(true);
|
||||
name = new SimpleStringProperty("Untitled");
|
||||
expression.addListener((param, oldValue, newValue) -> {
|
||||
expressionCallback = parseExpression(newValue);
|
||||
});
|
||||
expressionCallback = parseExpression(expr);
|
||||
doConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
if (addr != null) {
|
||||
setScopeStart(addr.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
if (active.get() && expressionCallback != null) {
|
||||
Integer newVal = expressionCallback.call(e);
|
||||
if (newVal != null) {
|
||||
e.setNewValue(newVal);
|
||||
} else {
|
||||
active.set(false);
|
||||
expressionCallback = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BooleanProperty activeProperty() {
|
||||
return active;
|
||||
}
|
||||
|
||||
public StringProperty nameProperty() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public IntegerProperty addressProperty() {
|
||||
return addr;
|
||||
}
|
||||
|
||||
public StringProperty expressionProperty() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
private Callback<RAMEvent, Integer> parseExpression(String expr) {
|
||||
String functionName = "processCheat" + id;
|
||||
String functionBody = "function " + functionName + "(old,val){" + (expr.contains("return") ? expr : "return " + expr) + "}";
|
||||
try {
|
||||
MetaCheat.NASHORN_ENGINE.eval(functionBody);
|
||||
return (RAMEvent e) -> {
|
||||
try {
|
||||
Object result = MetaCheat.NASHORN_INVOCABLE.invokeFunction(functionName, e.getOldValue(), e.getNewValue());
|
||||
if (result instanceof Number) {
|
||||
return ((Number) result).intValue();
|
||||
} else {
|
||||
System.err.println("Not able to handle non-numeric return value: " + result.getClass());
|
||||
return null;
|
||||
}
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
} catch (ScriptException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
75
src/main/java/jace/cheat/MemoryCell.java
Normal file
75
src/main/java/jace/cheat/MemoryCell.java
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package jace.cheat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author blurry
|
||||
*/
|
||||
public class MemoryCell implements Comparable<MemoryCell> {
|
||||
public static ChangeListener<MemoryCell> listener;
|
||||
public int address;
|
||||
public IntegerProperty value = new SimpleIntegerProperty();
|
||||
public IntegerProperty readCount = new SimpleIntegerProperty();
|
||||
public IntegerProperty execCount = new SimpleIntegerProperty();
|
||||
public IntegerProperty writeCount = new SimpleIntegerProperty();
|
||||
public ObservableList<Integer> readInstructions = FXCollections.observableList(new ArrayList<>());
|
||||
public ObservableList<Integer> writeInstructions = FXCollections.observableList(new ArrayList<>());
|
||||
private int x;
|
||||
private int y;
|
||||
private int width;
|
||||
private int height;
|
||||
|
||||
public static void setListener(ChangeListener<MemoryCell> l) {
|
||||
listener = l;
|
||||
}
|
||||
|
||||
public MemoryCell() {
|
||||
ChangeListener<Number> changeListener = (ObservableValue<? extends Number> val, Number oldVal, Number newVal) -> {
|
||||
if (listener != null) {
|
||||
listener.changed(null, this, this);
|
||||
}
|
||||
};
|
||||
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
|
||||
public int compareTo(MemoryCell o) {
|
||||
return address - o.address;
|
||||
}
|
||||
|
||||
}
|
@ -8,23 +8,25 @@ import jace.core.RAMEvent;
|
||||
import jace.core.RAMListener;
|
||||
import jace.state.State;
|
||||
import jace.ui.MetacheatUI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javax.script.Invocable;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
|
||||
public class MetaCheat extends Cheats {
|
||||
|
||||
static final ScriptEngine NASHORN_ENGINE = new ScriptEngineManager().getEngineByName("nashorn");
|
||||
static Invocable NASHORN_INVOCABLE = (Invocable) NASHORN_ENGINE;
|
||||
|
||||
public static enum SearchType {
|
||||
VALUE, TEXT, CHANGE
|
||||
}
|
||||
@ -33,62 +35,6 @@ public class MetaCheat extends Cheats {
|
||||
NO_CHANGE, ANY_CHANGE, LESS, GREATER, AMOUNT
|
||||
}
|
||||
|
||||
public static class MemoryCell implements Comparable<MemoryCell> {
|
||||
|
||||
public static ChangeListener<MemoryCell> listener;
|
||||
public int address;
|
||||
public IntegerProperty value = new SimpleIntegerProperty();
|
||||
public IntegerProperty readCount = new SimpleIntegerProperty();
|
||||
public IntegerProperty execCount = new SimpleIntegerProperty();
|
||||
public IntegerProperty writeCount = new SimpleIntegerProperty();
|
||||
public ObservableList<Integer> readInstructions = FXCollections.observableList(new ArrayList<>());
|
||||
public ObservableList<Integer> writeInstructions = FXCollections.observableList(new ArrayList<>());
|
||||
private int x;
|
||||
private int y;
|
||||
private int width;
|
||||
private int height;
|
||||
|
||||
public static void setListener(ChangeListener<MemoryCell> l) {
|
||||
listener = l;
|
||||
}
|
||||
|
||||
public MemoryCell() {
|
||||
ChangeListener<Number> changeListener = (ObservableValue<? extends Number> val, Number oldVal, Number newVal) -> {
|
||||
if (listener != null) {
|
||||
listener.changed(null, this, this);
|
||||
}
|
||||
};
|
||||
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
|
||||
public int compareTo(MemoryCell o) {
|
||||
return address - o.address;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SearchResult {
|
||||
|
||||
@ -106,42 +52,6 @@ public class MetaCheat extends Cheats {
|
||||
}
|
||||
}
|
||||
|
||||
public static class Cheat extends RAMListener {
|
||||
IntegerProperty addr;
|
||||
IntegerProperty val;
|
||||
BooleanProperty active;
|
||||
|
||||
public Cheat(int address, int value) {
|
||||
super(RAMEvent.TYPE.ANY, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY);
|
||||
addr = new SimpleIntegerProperty(address);
|
||||
val = new SimpleIntegerProperty(value);
|
||||
active = new SimpleBooleanProperty(true);
|
||||
setScopeStart(address);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
if (active.get()) {
|
||||
e.setNewValue(val.get());
|
||||
}
|
||||
}
|
||||
|
||||
public BooleanProperty activeProperty() {
|
||||
return active;
|
||||
}
|
||||
|
||||
public IntegerProperty addressProperty() {
|
||||
return addr;
|
||||
}
|
||||
|
||||
public IntegerProperty valueProperty() {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
MetacheatUI ui;
|
||||
|
||||
@ -159,7 +69,7 @@ public class MetaCheat extends Cheats {
|
||||
private final BooleanProperty signedProperty = new SimpleBooleanProperty(false);
|
||||
private final StringProperty searchValueProperty = new SimpleStringProperty("0");
|
||||
private final StringProperty changeByProperty = new SimpleStringProperty("0");
|
||||
private final ObservableList<Cheat> cheatList = FXCollections.observableArrayList();
|
||||
private final ObservableList<DynamicCheat> cheatList = FXCollections.observableArrayList();
|
||||
private final ObservableList<SearchResult> resultList = FXCollections.observableArrayList();
|
||||
private final ObservableList<State> snapshotList = FXCollections.observableArrayList();
|
||||
|
||||
@ -194,14 +104,14 @@ public class MetaCheat extends Cheats {
|
||||
}
|
||||
if (s.matches("(\\+|-)?[0-9]+")) {
|
||||
return Integer.parseInt(s);
|
||||
} else if (s.matches("(\\+|-)?[0-9a-fA-F]+")) {
|
||||
return Integer.parseInt(s.toUpperCase(), 16);
|
||||
} else if (s.matches("(\\+|-)?(x|$)[0-9a-fA-F]+")) {
|
||||
} else {
|
||||
String upper = s.toUpperCase();
|
||||
boolean positive = true;
|
||||
if (upper.startsWith("-")) {
|
||||
positive = false;
|
||||
upper = upper.substring(1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < upper.length(); i++) {
|
||||
char c = upper.charAt(i);
|
||||
if ((c >= '0' && c <= '9') || (c >= 'A' & c <= 'F')) {
|
||||
@ -220,10 +130,15 @@ public class MetaCheat extends Cheats {
|
||||
void registerListeners() {
|
||||
}
|
||||
|
||||
public void addCheat(Cheat cheat) {
|
||||
public void addCheat(DynamicCheat cheat) {
|
||||
cheat.activeProperty().set(true);
|
||||
cheatList.add(cheat);
|
||||
computer.getMemory().addListener(cheat);
|
||||
cheat.addressProperty().addListener((prop, oldVal, newVal)->{
|
||||
computer.getMemory().removeListener(cheat);
|
||||
cheat.doConfig();
|
||||
computer.getMemory().addListener(cheat);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -282,7 +197,7 @@ public class MetaCheat extends Cheats {
|
||||
return changeByProperty;
|
||||
}
|
||||
|
||||
public ObservableList<Cheat> getCheats() {
|
||||
public ObservableList<DynamicCheat> getCheats() {
|
||||
return cheatList;
|
||||
}
|
||||
|
||||
@ -384,7 +299,7 @@ public class MetaCheat extends Cheats {
|
||||
public void tick() {
|
||||
if (fadeCounter-- <= 0) {
|
||||
fadeCounter = FADE_TIMER_VALUE;
|
||||
memoryCells.values().stream().forEach((cell) -> {
|
||||
memoryCells.values().stream().forEach((jace.cheat.MemoryCell cell) -> {
|
||||
boolean change = false;
|
||||
if (cell.execCount.get() > 0) {
|
||||
cell.execCount.set(Math.max(0, cell.execCount.get() - fadeRate));
|
||||
|
@ -2,16 +2,14 @@ package jace.ui;
|
||||
|
||||
import com.sun.glass.ui.Application;
|
||||
import jace.Emulator;
|
||||
import jace.cheat.DynamicCheat;
|
||||
import jace.cheat.MemoryCell;
|
||||
import jace.cheat.MetaCheat;
|
||||
import jace.cheat.MetaCheat.Cheat;
|
||||
import jace.cheat.MetaCheat.SearchChangeType;
|
||||
import jace.cheat.MetaCheat.SearchType;
|
||||
import jace.core.RAMListener;
|
||||
import jace.state.State;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentSkipListSet;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
@ -19,7 +17,6 @@ import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
@ -35,22 +32,21 @@ import javafx.scene.control.ListView;
|
||||
import javafx.scene.control.RadioButton;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.Toggle;
|
||||
import javafx.scene.control.ToggleGroup;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.control.cell.CheckBoxTableCell;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.scene.control.cell.TextFieldTableCell;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.Background;
|
||||
import javafx.scene.layout.BackgroundFill;
|
||||
import javafx.scene.layout.CornerRadii;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.layout.TilePane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.text.Font;
|
||||
import javafx.scene.text.TextAlignment;
|
||||
import javafx.util.converter.DefaultStringConverter;
|
||||
import javafx.util.converter.IntegerStringConverter;
|
||||
|
||||
public class MetacheatUI {
|
||||
|
||||
@ -127,7 +123,7 @@ public class MetacheatUI {
|
||||
private ListView<State> snapshotsListView;
|
||||
|
||||
@FXML
|
||||
private TableView<Cheat> cheatsTableView;
|
||||
private TableView<DynamicCheat> cheatsTableView;
|
||||
|
||||
@FXML
|
||||
void addCheat(ActionEvent event) {
|
||||
@ -274,9 +270,33 @@ public class MetacheatUI {
|
||||
|
||||
RAMListener l;
|
||||
|
||||
cheatsTableView.getColumns().get(0).setCellValueFactory(new PropertyValueFactory<>("active"));
|
||||
cheatsTableView.getColumns().get(1).setCellValueFactory(new PropertyValueFactory<>("address"));
|
||||
cheatsTableView.getColumns().get(2).setCellValueFactory(new PropertyValueFactory<>("value"));
|
||||
TableColumn<DynamicCheat, Boolean> activeColumn = (TableColumn<DynamicCheat, Boolean>) cheatsTableView.getColumns().get(0);
|
||||
activeColumn.setCellValueFactory(new PropertyValueFactory<>("active"));
|
||||
activeColumn.setCellFactory((TableColumn<DynamicCheat, Boolean> param) -> new CheckBoxTableCell<>());
|
||||
|
||||
TableColumn<DynamicCheat, String> nameColumn = (TableColumn<DynamicCheat, String>) cheatsTableView.getColumns().get(1);
|
||||
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
|
||||
nameColumn.setCellFactory((TableColumn<DynamicCheat, String> param) -> new TextFieldTableCell<>(new DefaultStringConverter()));
|
||||
|
||||
TableColumn<DynamicCheat, Integer> addrColumn = (TableColumn<DynamicCheat, Integer>) cheatsTableView.getColumns().get(2);
|
||||
addrColumn.setCellValueFactory(new PropertyValueFactory<>("address"));
|
||||
addrColumn.setCellFactory((TableColumn<DynamicCheat, Integer> param) -> {
|
||||
return new TextFieldTableCell<>(new IntegerStringConverter(){
|
||||
@Override
|
||||
public String toString(Integer value) {
|
||||
return "$"+Integer.toHexString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer fromString(String value) {
|
||||
return cheatEngine.parseInt(value);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
TableColumn<DynamicCheat, String> exprColumn = (TableColumn<DynamicCheat, String>) cheatsTableView.getColumns().get(3);
|
||||
exprColumn.setCellValueFactory(new PropertyValueFactory<>("expression"));
|
||||
exprColumn.setCellFactory((TableColumn<DynamicCheat, String> param) -> new TextFieldTableCell<>(new DefaultStringConverter()));
|
||||
}
|
||||
MetaCheat cheatEngine = null;
|
||||
|
||||
@ -303,7 +323,7 @@ public class MetacheatUI {
|
||||
public int memoryViewColumns;
|
||||
public int memoryViewRows;
|
||||
|
||||
public static Set<MetaCheat.MemoryCell> redrawNodes = new ConcurrentSkipListSet<>();
|
||||
public static Set<MemoryCell> redrawNodes = new ConcurrentSkipListSet<>();
|
||||
ScheduledExecutorService animationTimer = null;
|
||||
ScheduledFuture animationFuture = null;
|
||||
StackPane pane = new StackPane();
|
||||
@ -322,7 +342,7 @@ public class MetacheatUI {
|
||||
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);
|
||||
Watch watch = new Watch(addr, this);
|
||||
|
||||
Label addWatch = new Label("Watch >>");
|
||||
addWatch.setOnMouseClicked((mouseEvent) -> {
|
||||
@ -353,9 +373,9 @@ public class MetacheatUI {
|
||||
private void processMemoryViewUpdates() {
|
||||
Application.invokeLater(() -> {
|
||||
GraphicsContext context = memoryViewCanvas.getGraphicsContext2D();
|
||||
Set<MetaCheat.MemoryCell> draw = new HashSet<>(redrawNodes);
|
||||
Set<MemoryCell> draw = new HashSet<>(redrawNodes);
|
||||
redrawNodes.clear();
|
||||
draw.stream().forEach((cell) -> {
|
||||
draw.stream().forEach((jace.cheat.MemoryCell cell) -> {
|
||||
if (showValuesCheckbox.isSelected()) {
|
||||
int val = cell.value.get() & 0x0ff;
|
||||
context.setFill(Color.rgb(val, val, val));
|
||||
@ -401,11 +421,11 @@ public class MetacheatUI {
|
||||
for (int addr = cheatEngine.getStartAddress(); addr <= cheatEngine.getEndAddress(); addr++) {
|
||||
int col = (addr - cheatEngine.getStartAddress()) % memoryViewColumns;
|
||||
int row = (addr - cheatEngine.getStartAddress()) / memoryViewColumns;
|
||||
MetaCheat.MemoryCell cell = cheatEngine.getMemoryCell(addr);
|
||||
MemoryCell cell = cheatEngine.getMemoryCell(addr);
|
||||
cell.setRect(col * MEMORY_BOX_TOTAL_SIZE, row * MEMORY_BOX_TOTAL_SIZE, MEMORY_BOX_SIZE, MEMORY_BOX_SIZE);
|
||||
redrawNodes.add(cell);
|
||||
}
|
||||
MetaCheat.MemoryCell.setListener((prop, oldCell, newCell) -> {
|
||||
MemoryCell.setListener((javafx.beans.value.ObservableValue<? extends jace.cheat.MemoryCell> prop, jace.cheat.MemoryCell oldCell, jace.cheat.MemoryCell newCell) -> {
|
||||
redrawNodes.add(newCell);
|
||||
});
|
||||
|
||||
@ -446,7 +466,7 @@ public class MetacheatUI {
|
||||
}
|
||||
|
||||
private Watch addWatch(int addr) {
|
||||
Watch watch = new Watch(addr);
|
||||
Watch watch = new Watch(addr, this);
|
||||
watch.setPadding(new Insets(5));
|
||||
watch.setOpaqueInsets(new Insets(10));
|
||||
|
||||
@ -470,100 +490,7 @@ public class MetacheatUI {
|
||||
}
|
||||
|
||||
private void addCheat(int addr, int val) {
|
||||
cheatEngine.addCheat(new Cheat(addr, val));
|
||||
cheatEngine.addCheat(new DynamicCheat(addr, String.valueOf(val)));
|
||||
}
|
||||
|
||||
private static final int GRAPH_WIDTH = 50;
|
||||
private static final double GRAPH_HEIGHT = 50;
|
||||
|
||||
private class Watch extends VBox {
|
||||
|
||||
int address;
|
||||
ScheduledFuture redraw;
|
||||
Canvas graph;
|
||||
List<Integer> samples = Collections.synchronizedList(new ArrayList<>());
|
||||
int value = 0;
|
||||
BooleanProperty holding = null;
|
||||
|
||||
public Watch(int address) {
|
||||
super();
|
||||
this.address = address;
|
||||
redraw = animationTimer.scheduleAtFixedRate(this::redraw, FRAME_RATE, FRAME_RATE, TimeUnit.MILLISECONDS);
|
||||
|
||||
setBackground(new Background(new BackgroundFill(Color.NAVY, CornerRadii.EMPTY, Insets.EMPTY)));
|
||||
Label addrLabel = new Label("$" + Integer.toHexString(address));
|
||||
addrLabel.setTextAlignment(TextAlignment.CENTER);
|
||||
addrLabel.setMinWidth(GRAPH_WIDTH);
|
||||
addrLabel.setFont(new Font(Font.getDefault().getFamily(), 14));
|
||||
addrLabel.setTextFill(Color.WHITE);
|
||||
graph = new Canvas(GRAPH_WIDTH, GRAPH_HEIGHT);
|
||||
getChildren().add(addrLabel);
|
||||
getChildren().add(graph);
|
||||
|
||||
CheckBox hold = new CheckBox("Hold");
|
||||
holding = hold.selectedProperty();
|
||||
holding.addListener((prop, oldVal, newVal) -> this.updateHold());
|
||||
|
||||
getChildren().add(hold);
|
||||
hold.setTextFill(Color.WHITE);
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void redraw() {
|
||||
int val = cheatEngine.getMemoryCell(address).value.get() & 0x0ff;
|
||||
if (!holding.get()) {
|
||||
value = val;
|
||||
}
|
||||
if (samples.size() >= GRAPH_WIDTH) {
|
||||
samples.remove(0);
|
||||
}
|
||||
samples.add(val);
|
||||
|
||||
Platform.runLater(() -> {
|
||||
GraphicsContext g = graph.getGraphicsContext2D();
|
||||
g.setFill(Color.BLACK);
|
||||
g.fillRect(0, 0, GRAPH_WIDTH, GRAPH_HEIGHT);
|
||||
|
||||
if (samples.size() > 1) {
|
||||
g.setLineWidth(1);
|
||||
g.setStroke(Color.LAWNGREEN);
|
||||
int y = (int) (GRAPH_HEIGHT - ((samples.get(0) / 255.0) * GRAPH_HEIGHT));
|
||||
g.beginPath();
|
||||
g.moveTo(0, y);
|
||||
for (int i = 1; i < samples.size(); i++) {
|
||||
y = (int) (GRAPH_HEIGHT - ((samples.get(i) / 255.0) * GRAPH_HEIGHT));
|
||||
g.lineTo(i, y);
|
||||
}
|
||||
g.stroke();
|
||||
}
|
||||
g.beginPath();
|
||||
g.setStroke(Color.WHITE);
|
||||
g.strokeText(String.valueOf(val), GRAPH_WIDTH - 25, GRAPH_HEIGHT - 5);
|
||||
});
|
||||
}
|
||||
|
||||
RAMListener holdListener;
|
||||
|
||||
public BooleanProperty holdingProperty() {
|
||||
return holding;
|
||||
}
|
||||
|
||||
private void updateHold() {
|
||||
if (!holding.get()) {
|
||||
cheatEngine.removeListener(holdListener);
|
||||
holdListener = null;
|
||||
} else {
|
||||
value = Emulator.computer.memory.readRaw(address) & 0x0ff;
|
||||
holdListener = cheatEngine.forceValue(value, address);
|
||||
}
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
holding.set(false);
|
||||
redraw.cancel(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
121
src/main/java/jace/ui/Watch.java
Normal file
121
src/main/java/jace/ui/Watch.java
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package jace.ui;
|
||||
|
||||
import jace.Emulator;
|
||||
import jace.core.RAMListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.canvas.Canvas;
|
||||
import javafx.scene.canvas.GraphicsContext;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.Background;
|
||||
import javafx.scene.layout.BackgroundFill;
|
||||
import javafx.scene.layout.CornerRadii;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.text.Font;
|
||||
import javafx.scene.text.TextAlignment;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author blurry
|
||||
*/
|
||||
class Watch extends VBox {
|
||||
private static final int GRAPH_WIDTH = 50;
|
||||
private static final double GRAPH_HEIGHT = 50;
|
||||
int address;
|
||||
ScheduledFuture redraw;
|
||||
Canvas graph;
|
||||
List<Integer> samples = Collections.synchronizedList(new ArrayList<>());
|
||||
int value = 0;
|
||||
BooleanProperty holding = null;
|
||||
private final MetacheatUI outer;
|
||||
|
||||
public Watch(int address, final MetacheatUI outer) {
|
||||
super();
|
||||
this.outer = outer;
|
||||
this.address = address;
|
||||
redraw = outer.animationTimer.scheduleAtFixedRate(this::redraw, MetacheatUI.FRAME_RATE, MetacheatUI.FRAME_RATE, TimeUnit.MILLISECONDS);
|
||||
setBackground(new Background(new BackgroundFill(Color.NAVY, CornerRadii.EMPTY, Insets.EMPTY)));
|
||||
Label addrLabel = new Label("$" + Integer.toHexString(address));
|
||||
addrLabel.setTextAlignment(TextAlignment.CENTER);
|
||||
addrLabel.setMinWidth(GRAPH_WIDTH);
|
||||
addrLabel.setFont(new Font(Font.getDefault().getFamily(), 14));
|
||||
addrLabel.setTextFill(Color.WHITE);
|
||||
graph = new Canvas(GRAPH_WIDTH, GRAPH_HEIGHT);
|
||||
getChildren().add(addrLabel);
|
||||
getChildren().add(graph);
|
||||
CheckBox hold = new CheckBox("Hold");
|
||||
holding = hold.selectedProperty();
|
||||
holding.addListener((prop, oldVal, newVal) -> this.updateHold());
|
||||
getChildren().add(hold);
|
||||
hold.setTextFill(Color.WHITE);
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void redraw() {
|
||||
int val = outer.cheatEngine.getMemoryCell(address).value.get() & 0x0ff;
|
||||
if (!holding.get()) {
|
||||
value = val;
|
||||
}
|
||||
if (samples.size() >= GRAPH_WIDTH) {
|
||||
samples.remove(0);
|
||||
}
|
||||
samples.add(val);
|
||||
Platform.runLater(() -> {
|
||||
GraphicsContext g = graph.getGraphicsContext2D();
|
||||
g.setFill(Color.BLACK);
|
||||
g.fillRect(0, 0, GRAPH_WIDTH, GRAPH_HEIGHT);
|
||||
if (samples.size() > 1) {
|
||||
g.setLineWidth(1);
|
||||
g.setStroke(Color.LAWNGREEN);
|
||||
int y = (int) (GRAPH_HEIGHT - ((samples.get(0) / 255.0) * GRAPH_HEIGHT));
|
||||
g.beginPath();
|
||||
g.moveTo(0, y);
|
||||
for (int i = 1; i < samples.size(); i++) {
|
||||
y = (int) (GRAPH_HEIGHT - ((samples.get(i) / 255.0) * GRAPH_HEIGHT));
|
||||
g.lineTo(i, y);
|
||||
}
|
||||
g.stroke();
|
||||
}
|
||||
g.beginPath();
|
||||
g.setStroke(Color.WHITE);
|
||||
g.strokeText(String.valueOf(val), GRAPH_WIDTH - 25, GRAPH_HEIGHT - 5);
|
||||
});
|
||||
}
|
||||
RAMListener holdListener;
|
||||
|
||||
public BooleanProperty holdingProperty() {
|
||||
return holding;
|
||||
}
|
||||
|
||||
private void updateHold() {
|
||||
if (!holding.get()) {
|
||||
outer.cheatEngine.removeListener(holdListener);
|
||||
holdListener = null;
|
||||
} else {
|
||||
value = Emulator.computer.memory.readRaw(address) & 0x0ff;
|
||||
holdListener = outer.cheatEngine.forceValue(value, address);
|
||||
}
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
holding.set(false);
|
||||
redraw.cancel(false);
|
||||
}
|
||||
|
||||
}
|
@ -31,7 +31,7 @@
|
||||
</children>
|
||||
</StackPane>
|
||||
</content></ScrollPane>
|
||||
<Accordion>
|
||||
<Accordion centerShape="false" scaleShape="false">
|
||||
<panes>
|
||||
<TitledPane prefHeight="200.0" prefWidth="200.0" text="Search">
|
||||
<content>
|
||||
@ -198,12 +198,16 @@
|
||||
</ToolBar>
|
||||
</bottom>
|
||||
<center>
|
||||
<TableView fx:id="cheatsTableView" prefHeight="321.0" prefWidth="207.0" BorderPane.alignment="CENTER">
|
||||
<TableView fx:id="cheatsTableView" editable="true" prefHeight="321.0" prefWidth="207.0" BorderPane.alignment="CENTER">
|
||||
<columns>
|
||||
<TableColumn prefWidth="35.0" text="On" />
|
||||
<TableColumn prefWidth="63.0" text="Address" />
|
||||
<TableColumn prefWidth="127.0" text="Effect" />
|
||||
<TableColumn prefWidth="26.0" sortable="false" text="On" />
|
||||
<TableColumn prefWidth="74.0" text="Name" />
|
||||
<TableColumn prefWidth="50.0" text="Addr" />
|
||||
<TableColumn prefWidth="84.0" text="Effect" />
|
||||
</columns>
|
||||
<columnResizePolicy>
|
||||
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
|
||||
</columnResizePolicy>
|
||||
</TableView>
|
||||
</center>
|
||||
</BorderPane>
|
||||
|
Loading…
Reference in New Issue
Block a user