forked from Apple-2-Tools/jace
Memory view is now performance-optimized and a lot of minor UX issues have been resolved.
This commit is contained in:
parent
eec3fdbcf7
commit
7dada32cbf
@ -314,6 +314,7 @@ public class Apple2e extends Computer {
|
|||||||
if (cheatEngine.getValue() == null) {
|
if (cheatEngine.getValue() == null) {
|
||||||
if (activeCheatEngine != null) {
|
if (activeCheatEngine != null) {
|
||||||
activeCheatEngine.detach();
|
activeCheatEngine.detach();
|
||||||
|
motherboard.miscDevices.remove(activeCheatEngine);
|
||||||
}
|
}
|
||||||
activeCheatEngine = null;
|
activeCheatEngine = null;
|
||||||
} else {
|
} else {
|
||||||
@ -324,6 +325,7 @@ public class Apple2e extends Computer {
|
|||||||
} else {
|
} else {
|
||||||
activeCheatEngine.detach();
|
activeCheatEngine.detach();
|
||||||
activeCheatEngine = null;
|
activeCheatEngine = null;
|
||||||
|
motherboard.miscDevices.remove(activeCheatEngine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (startCheats) {
|
if (startCheats) {
|
||||||
@ -333,6 +335,7 @@ public class Apple2e extends Computer {
|
|||||||
Logger.getLogger(Apple2e.class.getName()).log(Level.SEVERE, null, ex);
|
Logger.getLogger(Apple2e.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
}
|
}
|
||||||
activeCheatEngine.attach();
|
activeCheatEngine.attach();
|
||||||
|
motherboard.miscDevices.add(activeCheatEngine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
|
@ -89,6 +89,11 @@ public abstract class Cheats extends Device {
|
|||||||
listeners.clear();
|
listeners.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeListener(RAMListener l) {
|
||||||
|
computer.getMemory().removeListener(l);
|
||||||
|
listeners.remove(l);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reconfigure() {
|
public void reconfigure() {
|
||||||
unregisterListeners();
|
unregisterListeners();
|
||||||
|
@ -4,14 +4,21 @@ import jace.Emulator;
|
|||||||
import jace.JaceApplication;
|
import jace.JaceApplication;
|
||||||
import jace.core.Computer;
|
import jace.core.Computer;
|
||||||
import jace.core.RAM;
|
import jace.core.RAM;
|
||||||
|
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.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;
|
||||||
@ -26,6 +33,60 @@ 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 {
|
||||||
|
|
||||||
int address;
|
int address;
|
||||||
@ -43,11 +104,16 @@ public class MetaCheat extends Cheats {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MetacheatUI ui;
|
MetacheatUI ui;
|
||||||
|
|
||||||
|
public int fadeRate = 2;
|
||||||
|
public int lightRate = 20;
|
||||||
|
public int historyLength = 10;
|
||||||
|
|
||||||
private int startAddress = 0;
|
private int startAddress = 0;
|
||||||
private int endAddress = 0x0ffff;
|
private int endAddress = 0x0ffff;
|
||||||
private final StringProperty startAddressProperty = new SimpleStringProperty("0");
|
private final StringProperty startAddressProperty = new SimpleStringProperty(Integer.toHexString(startAddress));
|
||||||
private final StringProperty endAddressProperty = new SimpleStringProperty("FFFF");
|
private final StringProperty endAddressProperty = new SimpleStringProperty(Integer.toHexString(endAddress));
|
||||||
private boolean byteSized = false;
|
private boolean byteSized = true;
|
||||||
private SearchType searchType = SearchType.VALUE;
|
private SearchType searchType = SearchType.VALUE;
|
||||||
private SearchChangeType searchChangeType = SearchChangeType.NO_CHANGE;
|
private SearchChangeType searchChangeType = SearchChangeType.NO_CHANGE;
|
||||||
private final BooleanProperty signedProperty = new SimpleBooleanProperty(false);
|
private final BooleanProperty signedProperty = new SimpleBooleanProperty(false);
|
||||||
@ -64,10 +130,10 @@ public class MetaCheat extends Cheats {
|
|||||||
addNumericValidator(searchValueProperty);
|
addNumericValidator(searchValueProperty);
|
||||||
addNumericValidator(changeByProperty);
|
addNumericValidator(changeByProperty);
|
||||||
startAddressProperty.addListener((prop, oldVal, newVal) -> {
|
startAddressProperty.addListener((prop, oldVal, newVal) -> {
|
||||||
startAddress = parseInt(newVal);
|
startAddress = Math.max(0, Math.min(65535, parseInt(newVal)));
|
||||||
});
|
});
|
||||||
endAddressProperty.addListener((prop, oldVal, newVal) -> {
|
endAddressProperty.addListener((prop, oldVal, newVal) -> {
|
||||||
endAddress = parseInt(newVal);
|
endAddress = Math.max(0, Math.min(65535, parseInt(newVal)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,6 +149,9 @@ public class MetaCheat extends Cheats {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int parseInt(String s) throws NumberFormatException {
|
public int parseInt(String s) throws NumberFormatException {
|
||||||
|
if (s == null || s.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
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 if (s.matches("(\\+|-)?[0-9a-fA-F]+")) {
|
||||||
@ -116,10 +185,6 @@ public class MetaCheat extends Cheats {
|
|||||||
return "MetaCheat";
|
return "MetaCheat";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void tick() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void detach() {
|
public void detach() {
|
||||||
super.detach();
|
super.detach();
|
||||||
@ -210,7 +275,7 @@ public class MetaCheat extends Cheats {
|
|||||||
? signed ? memory.readRaw(result.address) : memory.readRaw(result.address) & 0x0ff
|
? signed ? memory.readRaw(result.address) : memory.readRaw(result.address) & 0x0ff
|
||||||
: signed ? memory.readWordRaw(result.address) : memory.readWordRaw(result.address) & 0x0ffff;
|
: signed ? memory.readWordRaw(result.address) : memory.readWordRaw(result.address) & 0x0ffff;
|
||||||
int last = result.lastObservedValue;
|
int last = result.lastObservedValue;
|
||||||
result.lastObservedValue = val;
|
result.lastObservedValue = val;
|
||||||
switch (searchType) {
|
switch (searchType) {
|
||||||
case VALUE:
|
case VALUE:
|
||||||
int compare = parseInt(searchValueProperty.get());
|
int compare = parseInt(searchValueProperty.get());
|
||||||
@ -237,4 +302,81 @@ public class MetaCheat extends Cheats {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RAMListener memoryViewListener = null;
|
||||||
|
private final Map<Integer, MemoryCell> memoryCells = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public MemoryCell getMemoryCell(int address) {
|
||||||
|
return memoryCells.get(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initMemoryView() {
|
||||||
|
RAM memory = Emulator.computer.getMemory();
|
||||||
|
for (int addr = getStartAddress(); addr <= getEndAddress(); addr++) {
|
||||||
|
if (getMemoryCell(addr) == null) {
|
||||||
|
MemoryCell cell = new MemoryCell();
|
||||||
|
cell.address = addr;
|
||||||
|
cell.value.set(memory.readRaw(addr));
|
||||||
|
memoryCells.put(addr, cell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (memoryViewListener == null) {
|
||||||
|
memoryViewListener = memory.observe(RAMEvent.TYPE.ANY, startAddress, endAddress, this::processMemoryEvent);
|
||||||
|
listeners.add(memoryViewListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int fadeCounter = 0;
|
||||||
|
int FADE_TIMER_VALUE = (int) (Emulator.computer.getMotherboard().cyclesPerSecond / 60);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
if (fadeCounter-- <= 0) {
|
||||||
|
fadeCounter = FADE_TIMER_VALUE;
|
||||||
|
memoryCells.values().stream().forEach((cell) -> {
|
||||||
|
boolean change = false;
|
||||||
|
if (cell.execCount.get() > 0) {
|
||||||
|
cell.execCount.set(Math.max(0, cell.execCount.get() - fadeRate));
|
||||||
|
change = true;
|
||||||
|
}
|
||||||
|
if (cell.readCount.get() > 0) {
|
||||||
|
cell.readCount.set(Math.max(0, cell.readCount.get() - fadeRate));
|
||||||
|
change = true;
|
||||||
|
}
|
||||||
|
if (cell.writeCount.get() > 0) {
|
||||||
|
cell.writeCount.set(Math.max(0, cell.writeCount.get() - fadeRate));
|
||||||
|
change = true;
|
||||||
|
}
|
||||||
|
if (change) {
|
||||||
|
cell.listener.changed(null, cell, cell);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processMemoryEvent(RAMEvent e) {
|
||||||
|
MemoryCell cell = getMemoryCell(e.getAddress());
|
||||||
|
if (cell != null) {
|
||||||
|
int programCounter = Emulator.computer.getCpu().getProgramCounter();
|
||||||
|
switch (e.getType()) {
|
||||||
|
case EXECUTE:
|
||||||
|
case READ_OPERAND:
|
||||||
|
cell.execCount.set(Math.min(255, cell.execCount.get() + lightRate));
|
||||||
|
break;
|
||||||
|
case WRITE:
|
||||||
|
cell.writeCount.set(Math.min(255, cell.writeCount.get() + lightRate));
|
||||||
|
cell.writeInstructions.add(programCounter);
|
||||||
|
if (cell.writeInstructions.size() > historyLength) {
|
||||||
|
cell.writeInstructions.remove(0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cell.readCount.set(Math.min(255, cell.readCount.get() + lightRate));
|
||||||
|
cell.readInstructions.add(programCounter);
|
||||||
|
if (cell.readInstructions.size() > historyLength) {
|
||||||
|
cell.readInstructions.remove(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cell.value.set(e.getNewValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,28 +5,38 @@ import jace.Emulator;
|
|||||||
import jace.cheat.MetaCheat;
|
import jace.cheat.MetaCheat;
|
||||||
import jace.cheat.MetaCheat.SearchChangeType;
|
import jace.cheat.MetaCheat.SearchChangeType;
|
||||||
import jace.cheat.MetaCheat.SearchType;
|
import jace.cheat.MetaCheat.SearchType;
|
||||||
import jace.core.RAMEvent;
|
|
||||||
import jace.core.RAMListener;
|
import jace.core.RAMListener;
|
||||||
import jace.state.State;
|
import jace.state.State;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentSkipListSet;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
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.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.canvas.Canvas;
|
||||||
|
import javafx.scene.canvas.GraphicsContext;
|
||||||
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;
|
||||||
import javafx.scene.control.ListView;
|
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.SingleSelectionModel;
|
|
||||||
import javafx.scene.control.Tab;
|
|
||||||
import javafx.scene.control.TabPane;
|
import javafx.scene.control.TabPane;
|
||||||
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.layout.AnchorPane;
|
||||||
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.layout.TilePane;
|
import javafx.scene.layout.TilePane;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
|
||||||
public class MetacheatUI {
|
public class MetacheatUI {
|
||||||
|
|
||||||
@ -87,6 +97,9 @@ public class MetacheatUI {
|
|||||||
@FXML
|
@FXML
|
||||||
private ListView<MetaCheat.SearchResult> searchResultsListView;
|
private ListView<MetaCheat.SearchResult> searchResultsListView;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private CheckBox showValuesCheckbox;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private TilePane watchesPane;
|
private TilePane watchesPane;
|
||||||
|
|
||||||
@ -199,7 +212,6 @@ public class MetacheatUI {
|
|||||||
searchTypesTabPane.getTabs().get(1).setUserData(SearchType.CHANGE);
|
searchTypesTabPane.getTabs().get(1).setUserData(SearchType.CHANGE);
|
||||||
searchTypesTabPane.getTabs().get(2).setUserData(SearchType.TEXT);
|
searchTypesTabPane.getTabs().get(2).setUserData(SearchType.TEXT);
|
||||||
searchTypesTabPane.getSelectionModel().selectedItemProperty().addListener((prop, oldVal, newVal) -> {
|
searchTypesTabPane.getSelectionModel().selectedItemProperty().addListener((prop, oldVal, newVal) -> {
|
||||||
System.out.println("Tab selected: " + newVal.getText());
|
|
||||||
if (cheatEngine != null) {
|
if (cheatEngine != null) {
|
||||||
cheatEngine.setSearchType((SearchType) newVal.getUserData());
|
cheatEngine.setSearchType((SearchType) newVal.getUserData());
|
||||||
}
|
}
|
||||||
@ -222,7 +234,7 @@ public class MetacheatUI {
|
|||||||
if (cheatEngine != null) {
|
if (cheatEngine != null) {
|
||||||
cheatEngine.setByteSized((boolean) newVal.getUserData());
|
cheatEngine.setByteSized((boolean) newVal.getUserData());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaCheat cheatEngine = null;
|
MetaCheat cheatEngine = null;
|
||||||
@ -239,21 +251,91 @@ public class MetacheatUI {
|
|||||||
searchValueField.textProperty().bindBidirectional(cheatEngine.searchValueProperty());
|
searchValueField.textProperty().bindBidirectional(cheatEngine.searchValueProperty());
|
||||||
searchChangeByField.textProperty().bindBidirectional(cheatEngine.searchChangeByProperty());
|
searchChangeByField.textProperty().bindBidirectional(cheatEngine.searchChangeByProperty());
|
||||||
|
|
||||||
engine.addCheat(RAMEvent.TYPE.ANY, this::processMemoryEvent, 0, 0x0ffff);
|
searchStartAddressField.textProperty().addListener(addressRangeListener);
|
||||||
|
searchEndAddressField.textProperty().addListener(addressRangeListener);
|
||||||
|
|
||||||
|
memoryViewPane.boundsInParentProperty().addListener((prop, oldVal, newVal) -> redrawMemoryView());
|
||||||
|
Application.invokeLater(this::redrawMemoryView);
|
||||||
|
}
|
||||||
|
|
||||||
|
ChangeListener<String> addressRangeListener = (prop, oldVal, newVal) -> Application.invokeLater(this::redrawMemoryView);
|
||||||
|
|
||||||
|
Canvas memoryView = null;
|
||||||
|
public static final int MEMORY_BOX_SIZE = 4;
|
||||||
|
public static final int MEMORY_BOX_GAP = 2;
|
||||||
|
public static final int MEMORY_BOX_TOTAL_SIZE = (MEMORY_BOX_SIZE + MEMORY_BOX_GAP);
|
||||||
|
|
||||||
|
public static Set<MetaCheat.MemoryCell> redrawNodes = new ConcurrentSkipListSet<>();
|
||||||
|
ScheduledExecutorService animationTimer = new ScheduledThreadPoolExecutor(1);
|
||||||
|
ScheduledFuture animationFuture = null;
|
||||||
|
|
||||||
|
private void processMemoryViewUpdates() {
|
||||||
|
Application.invokeLater(() -> {
|
||||||
|
GraphicsContext context = memoryView.getGraphicsContext2D();
|
||||||
|
Set<MetaCheat.MemoryCell> draw = new HashSet<>(redrawNodes);
|
||||||
|
redrawNodes.clear();
|
||||||
|
draw.stream().forEach((cell) -> {
|
||||||
|
if (showValuesCheckbox.isSelected()) {
|
||||||
|
int val = cell.value.get() & 0x0ff;
|
||||||
|
context.setFill(Color.rgb(val, val, val));
|
||||||
|
} else {
|
||||||
|
context.setFill(Color.rgb(
|
||||||
|
cell.writeCount.get(),
|
||||||
|
cell.readCount.get(),
|
||||||
|
cell.execCount.get()));
|
||||||
|
}
|
||||||
|
context.fillRect(cell.getX(), cell.getY(), cell.getWidth(), cell.getHeight());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void redrawMemoryView() {
|
||||||
|
boolean resume = Emulator.computer.pause();
|
||||||
|
if (memoryViewPane.getContent() != null && memoryView != null) {
|
||||||
|
memoryViewPane.setContent(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (animationFuture != null) {
|
||||||
|
animationFuture.cancel(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
animationFuture = animationTimer.scheduleAtFixedRate(this::processMemoryViewUpdates, 1000 / 60, 1000 / 60, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
cheatEngine.initMemoryView();
|
||||||
|
int pixelsPerBlock = 16 * MEMORY_BOX_TOTAL_SIZE;
|
||||||
|
int cols = ((int) memoryViewPane.getWidth()) / pixelsPerBlock * 16;
|
||||||
|
int rows = ((cheatEngine.getEndAddress() - cheatEngine.getStartAddress()) / cols) + 1;
|
||||||
|
memoryView = new Canvas(memoryViewPane.getWidth(), rows * MEMORY_BOX_TOTAL_SIZE);
|
||||||
|
StackPane pane = new StackPane(memoryView);
|
||||||
|
memoryViewPane.setContent(pane);
|
||||||
|
GraphicsContext context = memoryView.getGraphicsContext2D();
|
||||||
|
context.setFill(Color.rgb(40, 40, 40));
|
||||||
|
context.fillRect(0, 0, memoryView.getWidth(), memoryView.getHeight());
|
||||||
|
for (int addr = cheatEngine.getStartAddress(); addr <= cheatEngine.getEndAddress(); addr++) {
|
||||||
|
int col = (addr - cheatEngine.getStartAddress()) % cols;
|
||||||
|
int row = (addr - cheatEngine.getStartAddress()) / cols;
|
||||||
|
MetaCheat.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) -> {
|
||||||
|
redrawNodes.add(newCell);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (resume) {
|
||||||
|
Emulator.computer.resume();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void changeZoom(double amount) {
|
private void changeZoom(double amount) {
|
||||||
double zoom = memoryViewPane.getScaleX();
|
if (memoryView != null) {
|
||||||
zoom += amount;
|
double zoom = memoryView.getScaleX();
|
||||||
memoryViewPane.setScaleX(zoom);
|
zoom += amount;
|
||||||
memoryViewPane.setScaleY(zoom);
|
memoryView.setScaleX(zoom);
|
||||||
}
|
memoryView.setScaleY(zoom);
|
||||||
|
StackPane scrollArea = (StackPane) memoryView.getParent();
|
||||||
private void processMemoryEvent(RAMEvent e) {
|
scrollArea.setPrefSize(memoryView.getWidth() * zoom, memoryView.getHeight() * zoom);
|
||||||
if (e.getAddress() < cheatEngine.getStartAddress() || e.getAddress() > cheatEngine.getEndAddress()) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void detach() {
|
public void detach() {
|
||||||
|
@ -14,9 +14,10 @@
|
|||||||
<Button mnemonicParsing="false" onAction="#zoomIn" text="Zoom in" />
|
<Button mnemonicParsing="false" onAction="#zoomIn" text="Zoom in" />
|
||||||
<Button mnemonicParsing="false" onAction="#zoomOut" text="Zoom out" />
|
<Button mnemonicParsing="false" onAction="#zoomOut" text="Zoom out" />
|
||||||
<Label text="Start:" />
|
<Label text="Start:" />
|
||||||
<TextField fx:id="searchStartAddressField" prefHeight="26.0" prefWidth="50.0" text="0000" />
|
<TextField fx:id="searchStartAddressField" prefHeight="26.0" prefWidth="60.0" text="0000" />
|
||||||
<Label text="End:" />
|
<Label text="End:" />
|
||||||
<TextField fx:id="searchEndAddressField" prefHeight="26.0" prefWidth="48.0" text="FFFF" />
|
<TextField fx:id="searchEndAddressField" prefHeight="26.0" prefWidth="60.0" text="FFFF" />
|
||||||
|
<CheckBox fx:id="showValuesCheckbox" mnemonicParsing="false" text="Show Values" />
|
||||||
</items>
|
</items>
|
||||||
</ToolBar>
|
</ToolBar>
|
||||||
<SplitPane dividerPositions="0.6304347826086957" prefHeight="363.0" prefWidth="600.0" VBox.vgrow="ALWAYS">
|
<SplitPane dividerPositions="0.6304347826086957" prefHeight="363.0" prefWidth="600.0" VBox.vgrow="ALWAYS">
|
||||||
|
Loading…
Reference in New Issue
Block a user