Metacheat speedup; program identity experimental feature

This commit is contained in:
Brendan Robert 2024-03-15 00:34:15 -05:00
parent d73ebd5765
commit f9114248d1
9 changed files with 235 additions and 44 deletions

View File

@ -63,7 +63,7 @@ public class Apple2e extends Computer {
static int IRQ_VECTOR = 0x003F2;
@ConfigurableField(name = "Production mode", shortName = "production")
public boolean PRODUCTION_MODE = true;
public boolean PRODUCTION_MODE = false;
@ConfigurableField(name = "Slot 1", shortName = "s1card")
public DeviceSelection<Cards> card1 = new DeviceSelection<>(Cards.class, null);
@ConfigurableField(name = "Slot 2", shortName = "s2card")

View File

@ -1246,13 +1246,11 @@ public class MOS65C02 extends CPU {
}
public String getState() {
return String.format("%s %s %s 01%s %s",
byte2(A),
byte2(X),
byte2(Y),
byte2(STACK),
getFlags()
);
return byte2(A) +
" " + byte2(X) +
" " + byte2(Y) +
" 01" + byte2(STACK) +
getFlags();
}
public String getFlags() {

View File

@ -223,7 +223,7 @@ abstract public class RAM128k extends RAM {
if (SoftSwitches.INTC8ROM.isOn()) {
rstate += "C8";
} else {
rstate += String.format("C8%d", getActiveSlot());
rstate += "C8"+getActiveSlot();
}
}

View File

@ -39,7 +39,8 @@ public abstract class Cheats extends Device {
Metacheat("Metacheat", MetaCheat.class, MetaCheat::new),
MontezumasRevenge("Montezuma's Revenge", MontezumasRevengeCheats.class, MontezumasRevengeCheats::new),
PrinceOfPersia("Prince of Persia", PrinceOfPersiaCheats.class, PrinceOfPersiaCheats::new),
LawlessHacks("Lawless Legends Enhancements", LawlessHacks.class, LawlessHacks::new);
LawlessHacks("Lawless Legends Enhancements", LawlessHacks.class, LawlessHacks::new),
ProgramIdentity("Identify program", ProgramIdentity.class, ProgramIdentity::new);
Supplier<Cheats> factory;
String name;

View File

@ -6,6 +6,7 @@
package jace.cheat;
import java.util.ArrayList;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
@ -77,6 +78,15 @@ public class MemoryCell implements Comparable<MemoryCell> {
return address - o.address;
}
@Override
public boolean equals(Object o) {
if (o instanceof MemoryCell) {
MemoryCell om = (MemoryCell) o;
return address == om.address || (x == om.x && y == om.y);
}
return false;
}
public boolean hasCounts() {
return hasCount.get();
}

View File

@ -64,7 +64,7 @@ public class MetaCheat extends Cheats {
public int historyLength = 10;
private int startAddress = 0;
private int endAddress = 0x0ffff;
private int endAddress = 0x0BFFF;
private final StringProperty startAddressProperty = new SimpleStringProperty(Integer.toHexString(startAddress));
private final StringProperty endAddressProperty = new SimpleStringProperty(Integer.toHexString(endAddress));
private boolean byteSized = true;
@ -248,26 +248,33 @@ public class MetaCheat extends Cheats {
int last = result.lastObservedValue;
result.lastObservedValue = val;
switch (searchType) {
case VALUE:
case VALUE -> {
int compare = parseInt(searchValueProperty.get());
return compare != val;
case CHANGE:
}
case CHANGE -> {
switch (searchChangeType) {
case AMOUNT:
case AMOUNT -> {
int amount = parseInt(searchChangeByProperty().getValue());
return (val - last) != amount;
case GREATER:
}
case GREATER -> {
return val <= last;
case ANY_CHANGE:
}
case ANY_CHANGE -> {
return val == last;
case LESS:
}
case LESS -> {
return val >= last;
case NO_CHANGE:
}
case NO_CHANGE -> {
return val != last;
}
}
break;
case TEXT:
break;
}
case TEXT -> {
}
}
return false;
});
@ -309,15 +316,9 @@ public class MetaCheat extends Cheats {
memoryCells.values().stream()
.filter(MemoryCell::hasCounts)
.forEach((cell) -> {
if (cell.execCount.get() > 0) {
cell.execCount.set(Math.max(0, cell.execCount.get() - fadeRate));
}
if (cell.readCount.get() > 0) {
cell.readCount.set(Math.max(0, cell.readCount.get() - fadeRate));
}
if (cell.writeCount.get() > 0) {
cell.writeCount.set(Math.max(0, cell.writeCount.get() - fadeRate));
}
cell.execCount.set(Math.max(0, cell.execCount.get() - fadeRate));
cell.readCount.set(Math.max(0, cell.readCount.get() - fadeRate));
cell.writeCount.set(Math.max(0, cell.writeCount.get() - fadeRate));
if (MemoryCell.listener != null) {
MemoryCell.listener.changed(null, cell, cell);
}

View File

@ -0,0 +1,119 @@
package jace.cheat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.CRC32;
import jace.apple2e.RAM128k;
import jace.apple2e.SoftSwitches;
import jace.core.PagedMemory;
import jace.core.RAMEvent;
import jace.core.RAMEvent.TYPE;
public class ProgramIdentity extends Cheats {
private Map<String, String> programIdentities;
@Override
public void registerListeners() {
addCheat("Track execution", TYPE.ANY, this::trackActivity, 0, 0x0ffff);
}
@Override
protected String getDeviceName() {
return "Program Identity";
}
int INTERVAL = 1000000;
int THRESHOLD_VALUE = 10000;
int CLIP_VALUE = THRESHOLD_VALUE * 2;
int DECAY = THRESHOLD_VALUE / 2;
int[] programRegions = new int[512];
private void trackActivity(RAMEvent e) {
int bank = e.getAddress() >> 8;
if (bank >= 0xc0 && bank < 0xd0) {
// Skip I/O region
return;
}
// Detect language card ram execution
if (bank >= 0xd0 && SoftSwitches.LCRAM.isOff()) {
// Skip rom execution
return;
}
if (!e.isMainMemory()) {
bank += 256;
}
if (e.getType() == RAMEvent.TYPE.EXECUTE) {
programRegions[bank] = Math.min(CLIP_VALUE, programRegions[bank] + 1);
} else if (e.getType() == RAMEvent.TYPE.WRITE) {
programRegions[bank] = 0;
}
}
private String generateChecksum() {
CRC32 crc = new CRC32();
RAM128k ram = (RAM128k) getMemory();
int bankCount = 0;
for (int i=0; i < 512; i++) {
if (programRegions[i] > THRESHOLD_VALUE) {
PagedMemory mem = ram.getMainMemory();
if (i >= 0x0d0 && i < 0x0100) {
mem = ram.getLanguageCard();
} else if (i >= 0x0100 && i < 0x01d0) {
mem = ram.getAuxMemory();
} else if (i >= 0x01d0) {
mem = ram.getAuxLanguageCard();
}
bankCount++;
crc.update(mem.getMemoryPage((i & 0x0ff) << 8));
}
}
return Long.toHexString(crc.getValue())+"-"+bankCount;
}
@Override
public void resume() {
super.resume();
Arrays.fill(programRegions, 0);
readProgramIdentities();
}
int counter = 0;
String lastChecksum = "";
@Override
public void tick() {
if (counter++ >= INTERVAL) {
String checksum = generateChecksum();
if (!checksum.equals(lastChecksum)) {
String identity = programIdentities.getOrDefault(checksum, "UNKNOWN");
System.out.println(checksum + "," + identity);
lastChecksum = checksum;
}
counter = 0;
for (int i=0; i < 512; i++) {
programRegions[i] = Math.max(0, programRegions[i] - DECAY);
}
}
}
private void readProgramIdentities() {
// Read from resources file
InputStream in = Cheats.class.getResourceAsStream("/jace/cheats/program-identities.txt");
try {
programIdentities = new HashMap<>();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split(",");
programIdentities.put(parts[0], parts[1]);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -1,9 +1,8 @@
package jace.ui;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
@ -384,8 +383,7 @@ public class MetacheatUI {
public static final int MEMORY_BOX_TOTAL_SIZE = (MEMORY_BOX_SIZE + MEMORY_BOX_GAP);
public int memoryViewColumns;
public int memoryViewRows;
public static Set<MemoryCell> redrawNodes = new ConcurrentSkipListSet<>();
public static Map<Integer, MemoryCell> redrawNodes = new ConcurrentSkipListMap<>();
ScheduledExecutorService animationTimer = null;
@SuppressWarnings("all")
ScheduledFuture animationFuture = null;
@ -432,13 +430,11 @@ public class MetacheatUI {
}
private void processMemoryViewUpdates() {
boolean isRunning = Emulator.withComputer(c->c.getRunningProperty().get(), false);
boolean isRunning = Emulator.withComputer(c->c.getMotherboard().isRunning(), false);
if (!isRunning) return;
GraphicsContext context = memoryViewCanvas.getGraphicsContext2D();
Set<MemoryCell> draw = new HashSet<>(redrawNodes);
redrawNodes.clear();
Platform.runLater(() -> {
draw.stream().forEach((jace.cheat.MemoryCell cell) -> {
redrawNodes.values().stream().forEach((jace.cheat.MemoryCell cell) -> {
if (showValuesCheckbox.isSelected()) {
int val = cell.value.get() & 0x0ff;
context.setFill(Color.rgb(val, val, val));
@ -450,10 +446,11 @@ public class MetacheatUI {
}
context.fillRect(cell.getX(), cell.getY(), cell.getWidth(), cell.getHeight());
});
redrawNodes.clear();
});
}
public static int FRAME_RATE = 1000 / 60;
public static int FRAME_RATE = 1000 / 30;
public void redrawMemoryView() {
if (cheatEngine == null) {
@ -468,8 +465,6 @@ public class MetacheatUI {
animationFuture.cancel(false);
}
animationFuture = animationTimer.scheduleAtFixedRate(this::processMemoryViewUpdates, FRAME_RATE, FRAME_RATE, TimeUnit.MILLISECONDS);
cheatEngine.initMemoryView();
int pixelsPerBlock = 16 * MEMORY_BOX_TOTAL_SIZE;
memoryViewColumns = (int) (memoryViewPane.getWidth() / pixelsPerBlock) * 16;
@ -490,13 +485,14 @@ public class MetacheatUI {
(int) (row * MEMORY_BOX_TOTAL_SIZE * drawScale),
(int) (MEMORY_BOX_SIZE * drawScale),
(int) (MEMORY_BOX_SIZE * drawScale));
redrawNodes.add(cell);
redrawNodes.put(cell.address, cell);
}
MemoryCell.setListener((javafx.beans.value.ObservableValue<? extends jace.cheat.MemoryCell> prop, jace.cheat.MemoryCell oldCell, jace.cheat.MemoryCell newCell) -> {
redrawNodes.add(newCell);
redrawNodes.put(newCell.address, newCell);
});
setZoom(1/drawScale);
animationFuture = animationTimer.scheduleAtFixedRate(this::processMemoryViewUpdates, FRAME_RATE, FRAME_RATE, TimeUnit.MILLISECONDS);
});
}

View File

@ -0,0 +1,66 @@
0-0,Firmware/Basic/Monitor
a3156625-1,Total Replay
158df73d-4,Miner 2049er
111cb7b9-5,Miner 2049er
d006d71b-6,A City Dies
d0d083aa-2,Alcazar (Title)
c05809d8-2,Alcazar (Menu)
6accc221-4,Alcazar (Game)
7381db02-4,Alien Downpour
580b57a0-5,Alien Downpour
f019024b-6,Alien Downpour (die)
2f1031b5-2,Alien Downpour (fail)
54d3700-3,Arctic Fox (Title)
b7fd2db6-13,Arctic Fox (Game)
d31a0d0a-14,Arctic Fox (Game)
82acd9ae-15,Arctic Fox (Game)
952fea92-16,Arctic Fox (Game)
bd7cf4f7-17,Arctic Fox (Game)
207242ca-2,Agent USA (Title)
9f9e6890-4,Agent USA (Menu)
536dad3-4,Agent USA (Menu)
90a1fd4f-2,Airheart (Title)
9a3b93f7-3,Airheart (Game)
6930a244-2,Apple Invader
aace1907-3,Apple Invader
c5c52757-2,Apple Invader (Title)
288ec83d-1,Apple Invader (Title)
bc3b2166-1,Arkanoid (Intro)
53a99672-7,Arkanoid (Demo)
87d4eab2-3,Arkanoid (Start)
cd93f077-3,Arkanoid (Game)
a6c1d770-3,Arkanoid (Game)
7b85b563-5,Arkanoid (Game)
53a99672-7,Arkanoid (Game)
6af90e52-1,Arkanoid (Game Over)
cde319e5-2,Montezuma's Revenge (Load)
eb28db32-3,Montezuma's Revenge (Title)
f447d42a-3,Montezuma's Revenge (Level Start 1 - Joystick)
312b8850-4,Montezuma's Revenge (Level Start 2 - Joystick)
73031104-5,Montezuma's Revenge (Level Start 3 - Joystick)
4b2cb3da-5,Montezuma's Revenge (Game 1 - Joystick)
72e913f2-3,Montezuma's Revenge (Game 2 - Joystick)
25e9bde4-4,Montezuma's Revenge (Game 3 - Joystick)
2e2db603-5,Montezuma's Revenge (Game 4 - Joystick)
160214dd-5,Montezuma's Revenge (Game 5 - Joystick)
43135e8-5,Montezuma's Revenge (Die)
b84a512-6,Montezuma's Revenge (Jump - Joystick)
d56c6cda-3,Montezuma's Revenge (Level Start 1 - Keyboard)
3cd3b2c5-4,Montezuma's Revenge (Level Start 2 - Keyboard)
23745a95-5,Montezuma's Revenge (Level Start 3 - Keyboard)
1b5bf84b-5,Montezuma's Revenge (Game - Keyboard)
b14ac573-6,Montezuma's Revenge (Jump - Keyboard)
f476b2d-2,Moon Patrol (Title)
4f94aa9-3,Moon Patrol (Menu)
396f7baf-3,Moon Patrol (Start 1)
6dfabc61-3,Moon Patrol (Start 2)
fb88733a-2,Moon Patrol (Start 3)
4e99aefb-5,Moon Patrol (Game 1)
dfd5fd5b-5,Moon Patrol (Game 2)
17e0326e-6,Moon Patrol (Game 3)
80243d6f-2,Moon Patrol (Game 5)
57a21d5d-6,Moon Patrol (Game - Shoot)
96130f7-6,Moon Patrol (Passed Pit or Checkpoint)
457104a-3,Moon Patrol (Die)
6a8bd750-2,Moon Patrol (Game Over)
1afccd0a-3,Moon Patrol (Bonus Screen)