mirror of
https://github.com/badvision/jace.git
synced 2024-11-28 10:52:33 +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.core.RAMListener;
|
||||||
import jace.state.State;
|
import jace.state.State;
|
||||||
import jace.ui.MetacheatUI;
|
import jace.ui.MetacheatUI;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import javafx.beans.property.BooleanProperty;
|
import javafx.beans.property.BooleanProperty;
|
||||||
import javafx.beans.property.IntegerProperty;
|
|
||||||
import javafx.beans.property.Property;
|
import javafx.beans.property.Property;
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.beans.property.SimpleIntegerProperty;
|
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.beans.property.StringProperty;
|
import javafx.beans.property.StringProperty;
|
||||||
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 javax.script.Invocable;
|
||||||
|
import javax.script.ScriptEngine;
|
||||||
|
import javax.script.ScriptEngineManager;
|
||||||
|
|
||||||
public class MetaCheat extends Cheats {
|
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 {
|
public static enum SearchType {
|
||||||
VALUE, TEXT, CHANGE
|
VALUE, TEXT, CHANGE
|
||||||
}
|
}
|
||||||
@ -33,62 +35,6 @@ public class MetaCheat extends Cheats {
|
|||||||
NO_CHANGE, ANY_CHANGE, LESS, GREATER, AMOUNT
|
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 {
|
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;
|
MetacheatUI ui;
|
||||||
|
|
||||||
@ -159,7 +69,7 @@ public class MetaCheat extends Cheats {
|
|||||||
private final BooleanProperty signedProperty = new SimpleBooleanProperty(false);
|
private final BooleanProperty signedProperty = new SimpleBooleanProperty(false);
|
||||||
private final StringProperty searchValueProperty = new SimpleStringProperty("0");
|
private final StringProperty searchValueProperty = new SimpleStringProperty("0");
|
||||||
private final StringProperty changeByProperty = 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<SearchResult> resultList = FXCollections.observableArrayList();
|
||||||
private final ObservableList<State> snapshotList = FXCollections.observableArrayList();
|
private final ObservableList<State> snapshotList = FXCollections.observableArrayList();
|
||||||
|
|
||||||
@ -194,14 +104,14 @@ public class MetaCheat extends Cheats {
|
|||||||
}
|
}
|
||||||
if (s.matches("(\\+|-)?[0-9]+")) {
|
if (s.matches("(\\+|-)?[0-9]+")) {
|
||||||
return Integer.parseInt(s);
|
return Integer.parseInt(s);
|
||||||
} else if (s.matches("(\\+|-)?[0-9a-fA-F]+")) {
|
} else {
|
||||||
return Integer.parseInt(s.toUpperCase(), 16);
|
|
||||||
} else if (s.matches("(\\+|-)?(x|$)[0-9a-fA-F]+")) {
|
|
||||||
String upper = s.toUpperCase();
|
String upper = s.toUpperCase();
|
||||||
boolean positive = true;
|
boolean positive = true;
|
||||||
if (upper.startsWith("-")) {
|
if (upper.startsWith("-")) {
|
||||||
positive = false;
|
positive = false;
|
||||||
|
upper = upper.substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < upper.length(); i++) {
|
for (int i = 0; i < upper.length(); i++) {
|
||||||
char c = upper.charAt(i);
|
char c = upper.charAt(i);
|
||||||
if ((c >= '0' && c <= '9') || (c >= 'A' & c <= 'F')) {
|
if ((c >= '0' && c <= '9') || (c >= 'A' & c <= 'F')) {
|
||||||
@ -220,10 +130,15 @@ public class MetaCheat extends Cheats {
|
|||||||
void registerListeners() {
|
void registerListeners() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addCheat(Cheat cheat) {
|
public void addCheat(DynamicCheat cheat) {
|
||||||
cheat.activeProperty().set(true);
|
cheat.activeProperty().set(true);
|
||||||
cheatList.add(cheat);
|
cheatList.add(cheat);
|
||||||
computer.getMemory().addListener(cheat);
|
computer.getMemory().addListener(cheat);
|
||||||
|
cheat.addressProperty().addListener((prop, oldVal, newVal)->{
|
||||||
|
computer.getMemory().removeListener(cheat);
|
||||||
|
cheat.doConfig();
|
||||||
|
computer.getMemory().addListener(cheat);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -282,7 +197,7 @@ public class MetaCheat extends Cheats {
|
|||||||
return changeByProperty;
|
return changeByProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObservableList<Cheat> getCheats() {
|
public ObservableList<DynamicCheat> getCheats() {
|
||||||
return cheatList;
|
return cheatList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,7 +299,7 @@ public class MetaCheat extends Cheats {
|
|||||||
public void tick() {
|
public void tick() {
|
||||||
if (fadeCounter-- <= 0) {
|
if (fadeCounter-- <= 0) {
|
||||||
fadeCounter = FADE_TIMER_VALUE;
|
fadeCounter = FADE_TIMER_VALUE;
|
||||||
memoryCells.values().stream().forEach((cell) -> {
|
memoryCells.values().stream().forEach((jace.cheat.MemoryCell cell) -> {
|
||||||
boolean change = false;
|
boolean change = false;
|
||||||
if (cell.execCount.get() > 0) {
|
if (cell.execCount.get() > 0) {
|
||||||
cell.execCount.set(Math.max(0, cell.execCount.get() - fadeRate));
|
cell.execCount.set(Math.max(0, cell.execCount.get() - fadeRate));
|
||||||
|
@ -2,16 +2,14 @@ package jace.ui;
|
|||||||
|
|
||||||
import com.sun.glass.ui.Application;
|
import com.sun.glass.ui.Application;
|
||||||
import jace.Emulator;
|
import jace.Emulator;
|
||||||
|
import jace.cheat.DynamicCheat;
|
||||||
|
import jace.cheat.MemoryCell;
|
||||||
import jace.cheat.MetaCheat;
|
import jace.cheat.MetaCheat;
|
||||||
import jace.cheat.MetaCheat.Cheat;
|
|
||||||
import jace.cheat.MetaCheat.SearchChangeType;
|
import jace.cheat.MetaCheat.SearchChangeType;
|
||||||
import jace.cheat.MetaCheat.SearchType;
|
import jace.cheat.MetaCheat.SearchType;
|
||||||
import jace.core.RAMListener;
|
import jace.core.RAMListener;
|
||||||
import jace.state.State;
|
import jace.state.State;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
|
||||||
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;
|
||||||
@ -19,7 +17,6 @@ import java.util.concurrent.ScheduledFuture;
|
|||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.property.BooleanProperty;
|
|
||||||
import javafx.beans.value.ChangeListener;
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
@ -35,22 +32,21 @@ import javafx.scene.control.ListView;
|
|||||||
import javafx.scene.control.RadioButton;
|
import javafx.scene.control.RadioButton;
|
||||||
import javafx.scene.control.ScrollPane;
|
import javafx.scene.control.ScrollPane;
|
||||||
import javafx.scene.control.TabPane;
|
import javafx.scene.control.TabPane;
|
||||||
|
import javafx.scene.control.TableColumn;
|
||||||
import javafx.scene.control.TableView;
|
import javafx.scene.control.TableView;
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
import javafx.scene.control.Toggle;
|
import javafx.scene.control.Toggle;
|
||||||
import javafx.scene.control.ToggleGroup;
|
import javafx.scene.control.ToggleGroup;
|
||||||
import javafx.scene.control.Tooltip;
|
import javafx.scene.control.Tooltip;
|
||||||
|
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.input.MouseEvent;
|
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.StackPane;
|
||||||
import javafx.scene.layout.TilePane;
|
import javafx.scene.layout.TilePane;
|
||||||
import javafx.scene.layout.VBox;
|
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.text.Font;
|
import javafx.util.converter.DefaultStringConverter;
|
||||||
import javafx.scene.text.TextAlignment;
|
import javafx.util.converter.IntegerStringConverter;
|
||||||
|
|
||||||
public class MetacheatUI {
|
public class MetacheatUI {
|
||||||
|
|
||||||
@ -127,7 +123,7 @@ public class MetacheatUI {
|
|||||||
private ListView<State> snapshotsListView;
|
private ListView<State> snapshotsListView;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private TableView<Cheat> cheatsTableView;
|
private TableView<DynamicCheat> cheatsTableView;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
void addCheat(ActionEvent event) {
|
void addCheat(ActionEvent event) {
|
||||||
@ -274,9 +270,33 @@ public class MetacheatUI {
|
|||||||
|
|
||||||
RAMListener l;
|
RAMListener l;
|
||||||
|
|
||||||
cheatsTableView.getColumns().get(0).setCellValueFactory(new PropertyValueFactory<>("active"));
|
TableColumn<DynamicCheat, Boolean> activeColumn = (TableColumn<DynamicCheat, Boolean>) cheatsTableView.getColumns().get(0);
|
||||||
cheatsTableView.getColumns().get(1).setCellValueFactory(new PropertyValueFactory<>("address"));
|
activeColumn.setCellValueFactory(new PropertyValueFactory<>("active"));
|
||||||
cheatsTableView.getColumns().get(2).setCellValueFactory(new PropertyValueFactory<>("value"));
|
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;
|
MetaCheat cheatEngine = null;
|
||||||
|
|
||||||
@ -303,7 +323,7 @@ public class MetacheatUI {
|
|||||||
public int memoryViewColumns;
|
public int memoryViewColumns;
|
||||||
public int memoryViewRows;
|
public int memoryViewRows;
|
||||||
|
|
||||||
public static Set<MetaCheat.MemoryCell> redrawNodes = new ConcurrentSkipListSet<>();
|
public static Set<MemoryCell> redrawNodes = new ConcurrentSkipListSet<>();
|
||||||
ScheduledExecutorService animationTimer = null;
|
ScheduledExecutorService animationTimer = null;
|
||||||
ScheduledFuture animationFuture = null;
|
ScheduledFuture animationFuture = null;
|
||||||
StackPane pane = new StackPane();
|
StackPane pane = new StackPane();
|
||||||
@ -322,7 +342,7 @@ public class MetacheatUI {
|
|||||||
int col = (int) (x / MEMORY_BOX_TOTAL_SIZE);
|
int col = (int) (x / MEMORY_BOX_TOTAL_SIZE);
|
||||||
int row = (int) (y / MEMORY_BOX_TOTAL_SIZE);
|
int row = (int) (y / MEMORY_BOX_TOTAL_SIZE);
|
||||||
int addr = cheatEngine.getStartAddress() + row * memoryViewColumns + col;
|
int addr = cheatEngine.getStartAddress() + row * memoryViewColumns + col;
|
||||||
Watch watch = new Watch(addr);
|
Watch watch = new Watch(addr, this);
|
||||||
|
|
||||||
Label addWatch = new Label("Watch >>");
|
Label addWatch = new Label("Watch >>");
|
||||||
addWatch.setOnMouseClicked((mouseEvent) -> {
|
addWatch.setOnMouseClicked((mouseEvent) -> {
|
||||||
@ -353,9 +373,9 @@ public class MetacheatUI {
|
|||||||
private void processMemoryViewUpdates() {
|
private void processMemoryViewUpdates() {
|
||||||
Application.invokeLater(() -> {
|
Application.invokeLater(() -> {
|
||||||
GraphicsContext context = memoryViewCanvas.getGraphicsContext2D();
|
GraphicsContext context = memoryViewCanvas.getGraphicsContext2D();
|
||||||
Set<MetaCheat.MemoryCell> draw = new HashSet<>(redrawNodes);
|
Set<MemoryCell> draw = new HashSet<>(redrawNodes);
|
||||||
redrawNodes.clear();
|
redrawNodes.clear();
|
||||||
draw.stream().forEach((cell) -> {
|
draw.stream().forEach((jace.cheat.MemoryCell cell) -> {
|
||||||
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));
|
context.setFill(Color.rgb(val, val, val));
|
||||||
@ -401,11 +421,11 @@ public class MetacheatUI {
|
|||||||
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;
|
||||||
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);
|
cell.setRect(col * MEMORY_BOX_TOTAL_SIZE, row * MEMORY_BOX_TOTAL_SIZE, MEMORY_BOX_SIZE, MEMORY_BOX_SIZE);
|
||||||
redrawNodes.add(cell);
|
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);
|
redrawNodes.add(newCell);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -446,7 +466,7 @@ public class MetacheatUI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Watch addWatch(int addr) {
|
private Watch addWatch(int addr) {
|
||||||
Watch watch = new Watch(addr);
|
Watch watch = new Watch(addr, this);
|
||||||
watch.setPadding(new Insets(5));
|
watch.setPadding(new Insets(5));
|
||||||
watch.setOpaqueInsets(new Insets(10));
|
watch.setOpaqueInsets(new Insets(10));
|
||||||
|
|
||||||
@ -470,100 +490,7 @@ public class MetacheatUI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void addCheat(int addr, int val) {
|
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>
|
</children>
|
||||||
</StackPane>
|
</StackPane>
|
||||||
</content></ScrollPane>
|
</content></ScrollPane>
|
||||||
<Accordion>
|
<Accordion centerShape="false" scaleShape="false">
|
||||||
<panes>
|
<panes>
|
||||||
<TitledPane prefHeight="200.0" prefWidth="200.0" text="Search">
|
<TitledPane prefHeight="200.0" prefWidth="200.0" text="Search">
|
||||||
<content>
|
<content>
|
||||||
@ -198,12 +198,16 @@
|
|||||||
</ToolBar>
|
</ToolBar>
|
||||||
</bottom>
|
</bottom>
|
||||||
<center>
|
<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>
|
<columns>
|
||||||
<TableColumn prefWidth="35.0" text="On" />
|
<TableColumn prefWidth="26.0" sortable="false" text="On" />
|
||||||
<TableColumn prefWidth="63.0" text="Address" />
|
<TableColumn prefWidth="74.0" text="Name" />
|
||||||
<TableColumn prefWidth="127.0" text="Effect" />
|
<TableColumn prefWidth="50.0" text="Addr" />
|
||||||
|
<TableColumn prefWidth="84.0" text="Effect" />
|
||||||
</columns>
|
</columns>
|
||||||
|
<columnResizePolicy>
|
||||||
|
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
|
||||||
|
</columnResizePolicy>
|
||||||
</TableView>
|
</TableView>
|
||||||
</center>
|
</center>
|
||||||
</BorderPane>
|
</BorderPane>
|
||||||
|
Loading…
Reference in New Issue
Block a user