mirror of
https://github.com/badvision/jace.git
synced 2024-12-29 17:30:03 +00:00
Code cleanup using Lambda expressions -- Cheats are now easier to write.
This commit is contained in:
parent
73987753ba
commit
9985f096e4
@ -18,27 +18,64 @@
|
||||
*/
|
||||
package jace.cheat;
|
||||
|
||||
import jace.apple2e.MOS65C02;
|
||||
import jace.apple2e.SoftSwitches;
|
||||
import jace.core.Computer;
|
||||
import jace.core.Device;
|
||||
import jace.core.RAMEvent;
|
||||
import jace.core.RAMListener;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents some combination of hacks that can be enabled or disabled
|
||||
* through the configuration interface.
|
||||
* Represents some combination of hacks that can be enabled or disabled through
|
||||
* the configuration interface.
|
||||
*
|
||||
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
|
||||
*/
|
||||
public abstract class Cheats extends Device {
|
||||
|
||||
Set<RAMListener> listeners = new HashSet<>();
|
||||
|
||||
public Cheats(Computer computer) {
|
||||
super(computer);
|
||||
}
|
||||
|
||||
public void addCheat(RAMListener l) {
|
||||
public void bypassCode(int address, int addressEnd) {
|
||||
addCheat(RAMEvent.TYPE.READ, address, addressEnd, (e) -> {
|
||||
e.setNewValue(MOS65C02.COMMAND.NOP.ordinal());
|
||||
});
|
||||
}
|
||||
|
||||
public void forceValue(int address, int value) {
|
||||
addCheat(RAMEvent.TYPE.READ, address, (e) -> {
|
||||
e.setNewValue(value);
|
||||
});
|
||||
}
|
||||
|
||||
public void forceValue(int address, boolean auxFlag, int value) {
|
||||
addCheat(RAMEvent.TYPE.READ, address, (e) -> {
|
||||
if (address < 0x0100) {
|
||||
if (SoftSwitches.AUXZP.getState() != auxFlag) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (SoftSwitches.RAMRD.getState() != auxFlag) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
e.setNewValue(value);
|
||||
});
|
||||
}
|
||||
|
||||
public void addCheat(RAMEvent.TYPE type, int address, RAMEvent.RAMEventHandler handler) {
|
||||
RAMListener l = computer.getMemory().observe(type, address, handler);
|
||||
listeners.add(l);
|
||||
}
|
||||
|
||||
public void addCheat(RAMEvent.TYPE type, int addressStart, int addressEnd, RAMEvent.RAMEventHandler handler) {
|
||||
RAMListener l = computer.getMemory().observe(type, addressStart, addressEnd, handler);
|
||||
listeners.add(l);
|
||||
computer.getMemory().addListener(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -5,9 +5,6 @@ import jace.apple2e.MOS65C02;
|
||||
import jace.config.ConfigurableField;
|
||||
import jace.core.Computer;
|
||||
import jace.core.RAMEvent;
|
||||
import jace.core.RAMListener;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.input.MouseButton;
|
||||
@ -48,6 +45,8 @@ public class MontezumasRevengeCheats extends Cheats {
|
||||
public static int Y_VELOCITY = 0x01550;
|
||||
public static int CHAR_STATE = 0x01570;
|
||||
|
||||
public static int lastX = 0;
|
||||
|
||||
public MontezumasRevengeCheats(Computer computer) {
|
||||
super(computer);
|
||||
}
|
||||
@ -66,148 +65,33 @@ public class MontezumasRevengeCheats extends Cheats {
|
||||
@Override
|
||||
void registerListeners() {
|
||||
if (repulsiveHack) {
|
||||
addCheat(new RAMListener(RAMEvent.TYPE.WRITE, RAMEvent.SCOPE.RANGE, RAMEvent.VALUE.ANY) {
|
||||
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
setScopeStart(0x1508);
|
||||
setScopeEnd(0x1518);
|
||||
}
|
||||
|
||||
int lastX = 0;
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
int playerX = computer.getMemory().readRaw(PLAYER_X);
|
||||
int playerY = computer.getMemory().readRaw(PLAYER_Y);
|
||||
for (int num = 7; num > 0; num--) {
|
||||
int monsterX = computer.getMemory().readRaw(PLAYER_X + num);
|
||||
int monsterY = computer.getMemory().readRaw(PLAYER_Y + num);
|
||||
if (monsterX != 0 && monsterY != 0) {
|
||||
if (Math.abs(monsterY - playerY) < 19) {
|
||||
if (Math.abs(monsterX - playerX) < 7) {
|
||||
int movement = Math.max(1, Math.abs(lastX - playerX));
|
||||
if (monsterX > playerX) {
|
||||
monsterX += movement;
|
||||
} else {
|
||||
monsterX -= movement;
|
||||
if (monsterX <= 0) {
|
||||
monsterX = 80;
|
||||
}
|
||||
}
|
||||
computer.getMemory().write(PLAYER_X + num, (byte) monsterX, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lastX = playerX;
|
||||
}
|
||||
});
|
||||
addCheat(RAMEvent.TYPE.WRITE, 0x1508, 0x1518, this::repulsiveBehavior);
|
||||
}
|
||||
|
||||
if (featherFall) {
|
||||
addCheat(new RAMListener(RAMEvent.TYPE.WRITE, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY) {
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
setScopeStart(PLAYER_Y);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
if (e.getNewValue() != e.getOldValue()) {
|
||||
int yVel = computer.getMemory().readRaw(Y_VELOCITY);
|
||||
if (yVel > MAX_VEL) {
|
||||
computer.getMemory().write(Y_VELOCITY, (byte) MAX_VEL, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
addCheat(new RAMListener(RAMEvent.TYPE.ANY, RAMEvent.SCOPE.RANGE, RAMEvent.VALUE.ANY) {
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
setScopeStart(0x6bb3);
|
||||
setScopeEnd(0x6bb4);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
e.setNewValue(MOS65C02.COMMAND.NOP.ordinal());
|
||||
}
|
||||
});
|
||||
addCheat(RAMEvent.TYPE.WRITE, PLAYER_Y, this::featherFallBehavior);
|
||||
// Bypass the part that realizes you should die when you hit the floor
|
||||
bypassCode(0x6bb3, 0x6bb4);
|
||||
}
|
||||
|
||||
if (moonJump) {
|
||||
addCheat(new RAMListener(RAMEvent.TYPE.WRITE, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY) {
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
setScopeStart(Y_VELOCITY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
if (inStartingSequence()) return;
|
||||
// System.out.println(e.getNewValue());
|
||||
if (e.getNewValue() < 0 && e.getNewValue() < e.getOldValue()) {
|
||||
e.setNewValue(MOON_JUMP_VELOCITY);
|
||||
}
|
||||
}
|
||||
});
|
||||
addCheat(RAMEvent.TYPE.WRITE, Y_VELOCITY, this::moonJumpBehavior);
|
||||
}
|
||||
|
||||
if (infiniteLives) {
|
||||
addCheat(new RAMListener(RAMEvent.TYPE.READ, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY) {
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
setScopeStart(LIVES);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
e.setNewValue(11);
|
||||
}
|
||||
});
|
||||
|
||||
forceValue(LIVES, 11);
|
||||
}
|
||||
|
||||
if (scoreHack) {
|
||||
addCheat(new RAMListener(RAMEvent.TYPE.READ, RAMEvent.SCOPE.RANGE, RAMEvent.VALUE.ANY) {
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
setScopeStart(SCORE);
|
||||
setScopeEnd(SCORE_END);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
switch(e.getAddress()) {
|
||||
case 0x0e8:
|
||||
e.setNewValue(0x90);
|
||||
break;
|
||||
case 0x0e9:
|
||||
e.setNewValue(0x09);
|
||||
break;
|
||||
case 0x0ea:
|
||||
e.setNewValue(0x13);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Score: 900913
|
||||
forceValue(SCORE, 0x90);
|
||||
forceValue(SCORE + 1, 0x09);
|
||||
forceValue(SCORE + 2, 0x13);
|
||||
}
|
||||
|
||||
if (snakeCharmer) {
|
||||
addCheat(new RAMListener(RAMEvent.TYPE.READ, RAMEvent.SCOPE.RANGE, RAMEvent.VALUE.ANY) {
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
setScopeStart(0x07963);
|
||||
setScopeEnd(0x07964);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
e.setNewValue(MOS65C02.COMMAND.NOP.ordinal());
|
||||
}
|
||||
});
|
||||
// Skip the code that determines you're touching an enemy
|
||||
bypassCode(0x07963, 0x07964);
|
||||
}
|
||||
if (mouseHack) {
|
||||
EmulatorUILogic.addMouseListener(listener);
|
||||
@ -216,26 +100,64 @@ public class MontezumasRevengeCheats extends Cheats {
|
||||
}
|
||||
}
|
||||
|
||||
private void repulsiveBehavior(RAMEvent e) {
|
||||
int playerX = computer.getMemory().readRaw(PLAYER_X);
|
||||
int playerY = computer.getMemory().readRaw(PLAYER_Y);
|
||||
for (int num = 7; num > 0; num--) {
|
||||
int monsterX = computer.getMemory().readRaw(PLAYER_X + num);
|
||||
int monsterY = computer.getMemory().readRaw(PLAYER_Y + num);
|
||||
if (monsterX != 0 && monsterY != 0) {
|
||||
if (Math.abs(monsterY - playerY) < 19) {
|
||||
if (Math.abs(monsterX - playerX) < 7) {
|
||||
int movement = Math.max(1, Math.abs(lastX - playerX));
|
||||
if (monsterX > playerX) {
|
||||
monsterX += movement;
|
||||
} else {
|
||||
monsterX -= movement;
|
||||
if (monsterX <= 0) {
|
||||
monsterX = 80;
|
||||
}
|
||||
}
|
||||
computer.getMemory().write(PLAYER_X + num, (byte) monsterX, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lastX = playerX;
|
||||
}
|
||||
|
||||
private void featherFallBehavior(RAMEvent yCoordChangeEvent) {
|
||||
if (yCoordChangeEvent.getNewValue() != yCoordChangeEvent.getOldValue()) {
|
||||
int yVel = computer.getMemory().readRaw(Y_VELOCITY);
|
||||
if (yVel > MAX_VEL) {
|
||||
computer.getMemory().write(Y_VELOCITY, (byte) MAX_VEL, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void moonJumpBehavior(RAMEvent velocityChangeEvent) {
|
||||
if (inStartingSequence()) {
|
||||
return;
|
||||
}
|
||||
if (velocityChangeEvent.getNewValue() < 0
|
||||
&& velocityChangeEvent.getNewValue() < velocityChangeEvent.getOldValue()) {
|
||||
velocityChangeEvent.setNewValue(MOON_JUMP_VELOCITY);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean inStartingSequence() {
|
||||
int roomLevel = computer.getMemory().readRaw(ROOM_LEVEL);
|
||||
return roomLevel == -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDeviceName() {
|
||||
public String getName() {
|
||||
return "Montezuma's Revenge";
|
||||
}
|
||||
|
||||
Map<Integer, Integer> oldValues = new HashMap<>();
|
||||
private void monitor(int start, int end) {
|
||||
for (int i=start; i < end; i++) {
|
||||
int old = oldValues.get(i) == null ? 0 : oldValues.get(i);
|
||||
int val = computer.getMemory().readRaw(i) & 0x0ff;
|
||||
if (old == val) continue;
|
||||
oldValues.put(i, val);
|
||||
System.out.println(Integer.toHexString(i) + ":" + val+";"+old+" ("+(val-old)+")");
|
||||
}
|
||||
System.out.println("-------");
|
||||
@Override
|
||||
protected String getDeviceName() {
|
||||
return "Montezuma's Revenge";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -25,13 +25,12 @@ import jace.config.ConfigurableField;
|
||||
import jace.core.Computer;
|
||||
import jace.core.PagedMemory;
|
||||
import jace.core.RAMEvent;
|
||||
import jace.core.RAMListener;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.input.MouseButton;
|
||||
|
||||
/**
|
||||
* Prince of Persia game cheats. This would not have been possible without the
|
||||
* Prince of Persia game cheats. This would not have been possible without the
|
||||
* source. I am eternally grateful to Jordan Mechner both for creating this
|
||||
* game, and for being so kind to release the source code to it so that we can
|
||||
* learn how it works. Where possible, I've indicated where I found the various
|
||||
@ -56,7 +55,6 @@ public class PrinceOfPersiaCheats extends Cheats {
|
||||
public static boolean swordHack;
|
||||
@ConfigurableField(category = "Hack", name = "Mouse", defaultValue = "false", description = "Left click kills/opens, Right click teleports")
|
||||
public static boolean mouseHack;
|
||||
boolean mouseRegistered = false;
|
||||
public static int PREV = 0x02b;
|
||||
public static int SPREV = 0x02e;
|
||||
public static int CharPosn = 0x040;
|
||||
@ -175,94 +173,19 @@ public class PrinceOfPersiaCheats extends Cheats {
|
||||
@Override
|
||||
public void registerListeners() {
|
||||
if (velocityHack) {
|
||||
addCheat(new RAMListener(RAMEvent.TYPE.READ_DATA, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY) {
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
setScopeStart(CharYVel);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
registerMouse();
|
||||
if (!SoftSwitches.AUXZP.getState()) {
|
||||
return;
|
||||
}
|
||||
int newVel = e.getNewValue();
|
||||
if (newVel > 5) {
|
||||
newVel = 1;
|
||||
}
|
||||
e.setNewValue(newVel & 0x0ff);
|
||||
}
|
||||
});
|
||||
addCheat(RAMEvent.TYPE.READ_DATA, CharYVel, this::velocityHackBehavior);
|
||||
}
|
||||
|
||||
if (invincibilityHack) {
|
||||
addCheat(new RAMListener(RAMEvent.TYPE.READ_DATA, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY) {
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
setScopeStart(KidStrength);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
registerMouse();
|
||||
if (!SoftSwitches.AUXZP.getState()) {
|
||||
return;
|
||||
}
|
||||
e.setNewValue(3);
|
||||
}
|
||||
});
|
||||
forceValue(KidStrength, true, 3);
|
||||
}
|
||||
if (sleepHack) {
|
||||
addCheat(new RAMListener(RAMEvent.TYPE.READ_DATA, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY) {
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
setScopeStart(EnemyAlert);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
registerMouse();
|
||||
if (!SoftSwitches.AUXZP.getState()) {
|
||||
return;
|
||||
}
|
||||
e.setNewValue(0);
|
||||
}
|
||||
});
|
||||
forceValue(EnemyAlert, true, 0);
|
||||
}
|
||||
if (swordHack) {
|
||||
addCheat(new RAMListener(RAMEvent.TYPE.READ_DATA, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY) {
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
setScopeStart(hasSword);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
registerMouse();
|
||||
if (!SoftSwitches.AUXZP.getState()) {
|
||||
return;
|
||||
}
|
||||
e.setNewValue(1);
|
||||
}
|
||||
});
|
||||
forceValue(hasSword, true, 1);
|
||||
}
|
||||
if (timeHack) {
|
||||
addCheat(new RAMListener(RAMEvent.TYPE.READ_DATA, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY) {
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
setScopeStart(MinLeft);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
registerMouse();
|
||||
if (!SoftSwitches.AUXZP.getState()) {
|
||||
return;
|
||||
}
|
||||
e.setNewValue(0x069);
|
||||
}
|
||||
});
|
||||
forceValue(MinLeft, true, 0x069);
|
||||
}
|
||||
if (mouseHack) {
|
||||
EmulatorUILogic.addMouseListener(listener);
|
||||
@ -275,15 +198,18 @@ public class PrinceOfPersiaCheats extends Cheats {
|
||||
public void unregisterListeners() {
|
||||
super.unregisterListeners();
|
||||
EmulatorUILogic.removeMouseListener(listener);
|
||||
mouseRegistered = false;
|
||||
}
|
||||
public static int BlueType = 0x0b700;
|
||||
|
||||
public void registerMouse() {
|
||||
if (mouseRegistered) {
|
||||
EmulatorUILogic.addMouseListener(listener);
|
||||
mouseRegistered = false;
|
||||
private void velocityHackBehavior(RAMEvent e) {
|
||||
if (!SoftSwitches.AUXZP.getState()) {
|
||||
return;
|
||||
}
|
||||
int newVel = e.getNewValue();
|
||||
if (newVel > 5) {
|
||||
newVel = 1;
|
||||
}
|
||||
e.setNewValue(newVel & 0x0ff);
|
||||
}
|
||||
|
||||
public void mouseClicked(MouseButton button) {
|
||||
@ -310,7 +236,6 @@ public class PrinceOfPersiaCheats extends Cheats {
|
||||
|
||||
// Note: POP uses a 255-pixel horizontal axis, Pixels 0-57 are offscreen to the left
|
||||
// and 198-255 offscreen to the right.
|
||||
|
||||
// System.out.println("Clicked on " + col + "," + row + " -- screen " + (x * 280) + "," + (y * 192));
|
||||
RAM128k mem = (RAM128k) computer.getMemory();
|
||||
PagedMemory auxMem = mem.getAuxMemory();
|
||||
|
@ -46,6 +46,7 @@ public abstract class RAM implements Reconfigurable {
|
||||
|
||||
/**
|
||||
* Creates a new instance of RAM
|
||||
* @param computer
|
||||
*/
|
||||
public RAM(Computer computer) {
|
||||
this.computer = computer;
|
||||
@ -151,9 +152,6 @@ public abstract class RAM implements Reconfigurable {
|
||||
int lsb = 0x00ff & read(address, eventType, triggerEvent, requireSynchronization);
|
||||
int msb = (0x00ff & read(address + 1, eventType, triggerEvent, requireSynchronization)) << 8;
|
||||
int value = msb + lsb;
|
||||
// if (generateEvent) {
|
||||
// callListener(RAMEvent.TYPE.READ, address, value, value);
|
||||
// }
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -205,16 +203,46 @@ public abstract class RAM implements Reconfigurable {
|
||||
});
|
||||
}
|
||||
|
||||
public void addListener(final RAMListener l) {
|
||||
public RAMListener observe(RAMEvent.TYPE type, int address, RAMEvent.RAMEventHandler handler) {
|
||||
return addListener(new RAMListener(type, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY) {
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
setScopeStart(address);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
handler.handleEvent(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public RAMListener observe(RAMEvent.TYPE type, int addressStart, int addressEnd, RAMEvent.RAMEventHandler handler) {
|
||||
return addListener(new RAMListener(type, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY) {
|
||||
@Override
|
||||
protected void doConfig() {
|
||||
setScopeStart(addressStart);
|
||||
setScopeEnd(addressEnd);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEvent(RAMEvent e) {
|
||||
handler.handleEvent(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public RAMListener addListener(final RAMListener l) {
|
||||
boolean restart = computer.pause();
|
||||
if (listeners.contains(l)) {
|
||||
return;
|
||||
return l;
|
||||
}
|
||||
listeners.add(l);
|
||||
addListenerRange(l);
|
||||
if (restart) {
|
||||
computer.resume();
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
public void removeListener(final RAMListener l) {
|
||||
|
@ -31,6 +31,10 @@ package jace.core;
|
||||
*/
|
||||
public class RAMEvent {
|
||||
|
||||
static public interface RAMEventHandler {
|
||||
public void handleEvent(RAMEvent e);
|
||||
}
|
||||
|
||||
public enum TYPE {
|
||||
|
||||
READ(true),
|
||||
|
@ -29,7 +29,7 @@ import jace.core.RAMEvent.TYPE;
|
||||
*
|
||||
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
|
||||
*/
|
||||
public abstract class RAMListener {
|
||||
public abstract class RAMListener implements RAMEvent.RAMEventHandler {
|
||||
|
||||
private RAMEvent.TYPE type;
|
||||
private RAMEvent.SCOPE scope;
|
||||
@ -157,6 +157,7 @@ public abstract class RAMListener {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEvent(RAMEvent e) {
|
||||
if (isRelevant(e)) {
|
||||
doEvent(e);
|
||||
|
Loading…
Reference in New Issue
Block a user