Massive Java 17 overhual

This commit is contained in:
Brendan Robert 2023-07-03 15:44:23 -05:00
parent e43ddccb56
commit 9b51c7d733
77 changed files with 3786 additions and 1764 deletions

9
.gitignore vendored
View File

@ -60,4 +60,11 @@ error_stack.txt
# Ignore special links Martin uses
/Platform/Apple/virtual/genBuild
/Platform/Apple/virtual/mapBuild
/Platform/Apple/virtual/plasBuild
/Platform/Apple/virtual/plasBuild
# Hey, don't include the commercial game data you ninny!
/Platform/Apple/tools/jace/src/main/resources/jace/data/game.2mg
# Ignore NetBeans project files
Platform/Apple/tools/jace/nb-configuration.xml
Platform/Apple/tools/jace/nbactions.xml

1
.java-version Normal file
View File

@ -0,0 +1 @@
graalvm64-17.0.6

View File

@ -0,0 +1 @@
1.8

View File

@ -1 +1 @@
1.8
graalvm64-17.0.6

View File

@ -14,6 +14,6 @@ That way multiple projects can share the same settings (useful for formatting ru
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-html-editor-lib.default-html-public-id>HTML5</org-netbeans-modules-html-editor-lib.default-html-public-id>
<netbeans.hint.jdkPlatform>JDK_1.8</netbeans.hint.jdkPlatform>
<netbeans.hint.jdkPlatform>GraalVM_JDK_17</netbeans.hint.jdkPlatform>
</properties>
</project-shared-configuration>

View File

@ -6,15 +6,11 @@
<packaging>jar</packaging>
</packagings>
<goals>
<goal>-X</goal>
<goal>-e</goal>
<goal>process-classes</goal>
<goal>org.codehaus.mojo:exec-maven-plugin:1.2.1:exec</goal>
<goal>clean</goal>
<goal>javafx:run</goal>
</goals>
<properties>
<exec.args>-classpath %classpath jace.LawlessLegends</exec.args>
<exec.executable>java</exec.executable>
</properties>
</action>
<action>
<actionName>profile</actionName>
@ -22,12 +18,13 @@
<packaging>jar</packaging>
</packagings>
<goals>
<goal>clean</goal>
<goal>process-classes</goal>
<goal>org.codehaus.mojo:exec-maven-plugin:1.2.1:exec</goal>
<goal>javafx:run@ide-debug</goal>
</goals>
<properties>
<exec.args>-classpath %classpath jace.LawlessLegends</exec.args>
<exec.executable>java</exec.executable>
<jpda.listen>true</jpda.listen>
</properties>
</action>
@ -37,12 +34,12 @@
<packaging>jar</packaging>
</packagings>
<goals>
<goal>process-classes</goal>
<goal>org.codehaus.mojo:exec-maven-plugin:1.2.1:exec</goal>
<goal>clean</goal>
<goal>javafx:run@ide-debug</goal>
</goals>
<properties>
<exec.args>-agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address} -classpath %classpath jace.LawlessLegends</exec.args>
<exec.executable>java</exec.executable>
<jpda.listen>true</jpda.listen>
</properties>
</action>

View File

@ -25,86 +25,168 @@
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.2</version>
<executions>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
<version>3.11.0</version>
</plugin>
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
<version>1.0.18</version>
<configuration>
<mainClass>jace.LawlessLegends</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<configuration>
<mainClass>lawlesslegends/jace.LawlessLegends</mainClass>
<executions>
<execution>
<id>unpack-dependencies</id>
<phase>package</phase>
<goals>
<goal>unpack-dependencies</goal>
</goals>
<!-- Default configuration for running -->
<!-- Usage: mvn clean javafx:run -->
<id>default-cli</id>
</execution>
<execution>
<!-- Configuration for manual attach debugging -->
<!-- Usage: mvn clean javafx:run@debug -->
<id>debug</id>
<configuration>
<excludes>**/*.SF,**/*.DSA,**/*.RSA</excludes>
<excludeScope>system</excludeScope>
<excludeGroupIds>junit,org.mockito,org.hamcrest</excludeGroupIds>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
<options>
<option>-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=localhost:8000</option>
</options>
</configuration>
</execution>
<execution>
<!-- Configuration for automatic IDE debugging -->
<id>ide-debug</id>
<configuration>
<options>
<option>-agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address}</option>
</options>
</configuration>
</execution>
<execution>
<!-- Configuration for automatic IDE profiling -->
<id>ide-profile</id>
<configuration>
<options>
<option>${profiler.jvmargs.arg1}</option>
<option>${profiler.jvmargs.arg2}</option>
<option>${profiler.jvmargs.arg3}</option>
<option>${profiler.jvmargs.arg4}</option>
<option>${profiler.jvmargs.arg5}</option>
</options>
</configuration>
</execution>
</executions>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.0.0</version>
<groupId>org.moditect</groupId>
<artifactId>moditect-maven-plugin</artifactId>
<version>1.0.0.Final</version>
<executions>
<execution>
<id>unpack-dependencies</id>
<phase>package</phase>
<id>add-module-infos</id>
<phase>generate-resources</phase>
<goals>
<goal>exec</goal>
<goal>add-module-info</goal>
</goals>
<configuration>
<executable>${java.home}/../bin/javapackager</executable>
<arguments>
<argument>-createjar</argument>
<argument>-nocss2bin</argument>
<argument>-appclass</argument>
<argument>${mainClass}</argument>
<argument>-srcdir</argument>
<argument>${project.build.directory}/classes</argument>
<argument>-outdir</argument>
<argument>${project.build.directory}</argument>
<argument>-outfile</argument>
<argument>${project.build.finalName}.jar</argument>
</arguments>
<modules>
<module>
<artifact>
<groupId>org.xerial.thirdparty</groupId>
<artifactId>nestedvm</artifactId>
<version>1.0</version>
</artifact>
<moduleInfoSource>
module nestedvm {
exports org.ibex.nestedvm;
exports org.ibex.nestedvm.util;
}
</moduleInfoSource>
</module>
<module>
<artifact>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.10.2</version>
</artifact>
<moduleInfoSource>
module reflections {
exports org.reflections;
}
</moduleInfoSource>
</module>
</modules>
<overwriteExistingFiles>true</overwriteExistingFiles>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
<version>3.8.1</version>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.collections</groupId>
<artifactId>eclipse-collections</artifactId>
<version>10.4.0</version>
</dependency>
<dependency>
<groupId>org.xerial.thirdparty</groupId>
<artifactId>nestedvm</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-base</artifactId>
<version>20</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>20</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-web</artifactId>
<version>20</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>20</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>20</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-swing</artifactId>
<version>18</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.10.2</version>
<type>jar</type>
</dependency>
</dependencies>
</project>

View File

@ -18,11 +18,15 @@
*/
package jace;
import jace.config.Configuration;
import jace.lawless.LawlessComputer;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import jace.config.Configuration;
import jace.core.RAM;
import jace.lawless.LawlessComputer;
/**
* Created on January 15, 2007, 10:10 PM
@ -47,6 +51,16 @@ public class Emulator {
return i;
}
public static void abort() {
if (instance != null) {
if (instance.computer != null) {
instance.computer.getMotherboard().suspend();
instance.computer.getMotherboard().detach();
}
}
instance = null;
}
public static Emulator getInstance() {
if (instance == null) {
instance = new Emulator();
@ -54,10 +68,55 @@ public class Emulator {
return instance;
}
public static LawlessComputer getComputer() {
private static LawlessComputer getComputer() {
return getInstance().computer;
}
public static void withComputer(Consumer<LawlessComputer> c) {
LawlessComputer computer = getComputer();
if (computer != null) {
c.accept(computer);
} else {
System.err.println("No computer available!");
Thread.dumpStack();
}
}
public static <T> T withComputer(Function<LawlessComputer, T> f, T defaultValue) {
LawlessComputer computer = getComputer();
if (computer != null) {
return f.apply(computer);
} else {
System.err.println("No computer available!");
Thread.dumpStack();
return defaultValue;
}
}
public static void withMemory(Consumer<RAM> m) {
withComputer(c->{
RAM memory = c.getMemory();
if (memory != null) {
m.accept(memory);
} else {
System.err.println("No memory available!");
Thread.dumpStack();
}
});
}
public static void withVideo(Consumer<jace.core.Video> v) {
withComputer(c->{
jace.core.Video video = c.getVideo();
if (video != null) {
v.accept(video);
} else {
System.err.println("No video available!");
Thread.dumpStack();
}
});
}
/**
* Creates a new instance of Emulator
*/
@ -65,6 +124,7 @@ public class Emulator {
instance = this;
computer = new LawlessComputer();
Configuration.buildTree();
computer.getMotherboard().suspend();
Configuration.loadSettings();
mainThread = Thread.currentThread();
// EmulatorUILogic.registerDebugger();

View File

@ -18,20 +18,6 @@
*/
package jace;
import jace.apple2e.MOS65C02;
import jace.apple2e.RAM128k;
import jace.apple2e.SoftSwitches;
import jace.config.ConfigurableField;
import jace.config.ConfigurationUIController;
import jace.config.InvokableAction;
import jace.config.Reconfigurable;
import jace.core.CPU;
import jace.core.Computer;
import jace.core.Debugger;
import jace.core.RAM;
import jace.core.RAMListener;
import static jace.core.Utility.*;
import jace.ide.IdeController;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@ -43,15 +29,28 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import jace.apple2e.MOS65C02;
import jace.apple2e.RAM128k;
import jace.apple2e.SoftSwitches;
import jace.config.ConfigurableField;
import jace.config.ConfigurationUIController;
import jace.config.InvokableAction;
import jace.config.Reconfigurable;
import jace.core.Debugger;
import jace.core.RAM;
import jace.core.RAMListener;
import static jace.core.Utility.gripe;
import jace.ide.IdeController;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
@ -75,7 +74,7 @@ public class EmulatorUILogic implements Reconfigurable {
@Override
public void updateStatus() {
enableDebug(true);
MOS65C02 cpu = (MOS65C02) Emulator.getComputer().getCpu();
MOS65C02 cpu = (MOS65C02) Emulator.withComputer(c->c.getCpu(), null);
updateCPURegisters(cpu);
}
};
@ -113,7 +112,7 @@ public class EmulatorUILogic implements Reconfigurable {
}
public static void enableTrace(boolean b) {
Emulator.getComputer().getCpu().setTraceEnabled(b);
Emulator.withComputer(c->c.getCpu().setTraceEnabled(b));
}
public static void stepForward() {
@ -121,7 +120,7 @@ public class EmulatorUILogic implements Reconfigurable {
}
static void registerDebugger() {
Emulator.getComputer().getCpu().setDebug(debugger);
Emulator.withComputer(c->c.getCpu().setDebug(debugger));
}
public static Integer getValidAddress(String s) {
@ -210,14 +209,14 @@ public class EmulatorUILogic implements Reconfigurable {
alternatives = "Execute program;Load binary;Load program;Load rom;Play single-load game",
defaultKeyMapping = "ctrl+shift+b")
public static void runFile() {
Emulator.getComputer().pause();
FileChooser select = new FileChooser();
File binary = select.showOpenDialog(LawlessLegends.getApplication().primaryStage);
if (binary == null) {
Emulator.getComputer().resume();
return;
}
runFileNamed(binary);
Emulator.withComputer(c->
c.getMotherboard().whileSuspended(()->{
FileChooser select = new FileChooser();
File binary = select.showOpenDialog(LawlessLegends.getApplication().primaryStage);
if (binary != null) {
runFileNamed(binary);
}
}));
}
public static void runFileNamed(File binary) {
@ -232,7 +231,6 @@ public class EmulatorUILogic implements Reconfigurable {
}
} catch (NumberFormatException | IOException ex) {
}
Emulator.getComputer().getCpu().resume();
}
public static void brun(File binary, int address) throws IOException {
@ -240,16 +238,19 @@ public class EmulatorUILogic implements Reconfigurable {
// If it was not yet halted, then it is the case that the CPU is processing another opcode
// So if that is the case, the program counter will need to be decremented here to compensate
// TODO: Find a better mousetrap for this one -- it's an ugly hack
Emulator.getComputer().pause();
FileInputStream in = new FileInputStream(binary);
byte[] data = new byte[in.available()];
in.read(data);
RAM ram = Emulator.getComputer().getMemory();
for (int i = 0; i < data.length; i++) {
ram.write(address + i, data[i], false, true);
byte[] data;
try (FileInputStream in = new FileInputStream(binary)) {
data = new byte[in.available()];
in.read(data);
}
Emulator.getComputer().getCpu().setProgramCounter(address);
Emulator.getComputer().resume();
Emulator.withComputer(c->c.getMotherboard().whileSuspended(()->{
RAM ram = c.getMemory();
for (int i = 0; i < data.length; i++) {
ram.write(address + i, data[i], false, true);
}
c.getCpu().setProgramCounter(address);
}));
}
@InvokableAction(
@ -293,7 +294,7 @@ public class EmulatorUILogic implements Reconfigurable {
SimpleDateFormat df = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss");
String timestamp = df.format(new Date());
String type;
int start = Emulator.getComputer().getVideo().getCurrentWriter().actualWriter().getYOffset(0);
int start = Emulator.withComputer(c->c.getVideo().getCurrentWriter().actualWriter().getYOffset(0), 0);
int len;
if (start < 0x02000) {
// Lo-res or double-lores
@ -310,16 +311,23 @@ public class EmulatorUILogic implements Reconfigurable {
}
File outFile = new File("screen_" + type + "_a" + Integer.toHexString(start) + "_" + timestamp);
try (FileOutputStream out = new FileOutputStream(outFile)) {
RAM128k ram = (RAM128k) Emulator.getComputer().memory;
Emulator.getComputer().pause();
if (dres) {
for (int i = 0; i < len; i++) {
out.write(ram.getAuxVideoMemory().readByte(start + i));
}
}
for (int i = 0; i < len; i++) {
out.write(ram.getMainMemory().readByte(start + i));
}
Emulator.withComputer(c -> {
RAM128k ram = (RAM128k) c.getMemory();
c.getMotherboard().whileSuspended(() -> {
try {
if (dres) {
for (int i = 0; i < len; i++) {
out.write(ram.getAuxVideoMemory().readByte(start + i));
}
}
for (int i = 0; i < len; i++) {
out.write(ram.getMainMemory().readByte(start + i));
}
} catch (IOException e) {
Logger.getLogger(EmulatorUILogic.class.getName()).log(Level.SEVERE, "Error writing screenshot", e);
}
});
});
}
System.out.println("Wrote screenshot to " + outFile.getAbsolutePath());
}
@ -332,8 +340,7 @@ public class EmulatorUILogic implements Reconfigurable {
defaultKeyMapping = "ctrl+shift+s")
public static void saveScreenshot() throws IOException {
FileChooser select = new FileChooser();
Emulator.getComputer().pause();
Image i = Emulator.getComputer().getVideo().getFrameBuffer();
// Image i = Emulator.getComputer().getVideo().getFrameBuffer();
// BufferedImage bufImageARGB = SwingFXUtils.fromFXImage(i, null);
File targetFile = select.showSaveDialog(LawlessLegends.getApplication().primaryStage);
if (targetFile == null) {
@ -421,25 +428,31 @@ public class EmulatorUILogic implements Reconfigurable {
} else {
int width, height;
switch (size) {
case 0: // 1x
case 0 -> {
// 1x
width = 560;
height = 384;
break;
case 1: // 1.5x
}
case 1 -> {
// 1.5x
width = 840;
height = 576;
break;
case 2: // 2x
}
case 2 -> {
// 2x
width = 560 * 2;
height = 384 * 2;
break;
case 3: // 3x (retina) 2880x1800
}
case 3 -> {
// 3x (retina) 2880x1800
width = 560 * 3;
height = 384 * 3;
break;
default: // 2x
}
default -> {
// 2x
width = 560 * 2;
height = 384 * 2;
}
}
double vgap = stage.getScene().getY();
double hgap = stage.getScene().getX();
@ -527,16 +540,17 @@ public class EmulatorUILogic implements Reconfigurable {
}
public static void simulateCtrlAppleReset() {
Computer computer = LawlessLegends.singleton.controller.computer;
computer.keyboard.openApple(true);
computer.warmStart();
Platform.runLater(() -> {
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
Logger.getLogger(EmulatorUILogic.class.getName()).log(Level.SEVERE, null, ex);
}
computer.keyboard.openApple(false);
Emulator.withComputer(c -> {
c.getKeyboard().openApple(true);
c.warmStart();
Platform.runLater(() -> {
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
Logger.getLogger(EmulatorUILogic.class.getName()).log(Level.SEVERE, null, ex);
}
c.getKeyboard().openApple(false);
});
});
}
@ -558,6 +572,8 @@ public class EmulatorUILogic implements Reconfigurable {
@Override
public void reconfigure() {
LawlessLegends.getApplication().controller.setSpeed(speedSetting);
// Null-safe so there are no errors in unit tests
Optional.ofNullable(LawlessLegends.getApplication())
.ifPresent(app->app.controller.setSpeed(speedSetting));
}
}

View File

@ -1,15 +1,26 @@
/*
* 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;
import com.sun.glass.ui.Application;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import jace.core.Card;
import jace.core.Computer;
import jace.core.Motherboard;
import jace.core.Utility;
import jace.core.Video;
import jace.lawless.LawlessComputer;
import jace.lawless.LawlessHacks;
import jace.library.MediaCache;
@ -39,21 +50,18 @@ import javafx.scene.input.DragEvent;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.*;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;
import javafx.util.StringConverter;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.util.*;
import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author blurry
@ -90,8 +98,6 @@ public class JaceUIController {
@FXML
private ComboBox musicSelection;
Computer computer;
private final BooleanProperty aspectRatioCorrectionEnabled = new SimpleBooleanProperty(false);
@FXML
@ -117,12 +123,14 @@ public class JaceUIController {
rootPane.setBackground(new Background(new BackgroundFill(Color.BLACK, null, null)));
rootPane.setOnMouseMoved(this::showMenuButton);
rootPane.setOnMouseExited(this::hideControlOverlay);
rootPane.setOnMouseClicked((evt)->rootPane.requestFocus());
menuButton.setOnMouseClicked(this::showControlOverlay);
controlOverlay.setOnMouseClicked(this::hideControlOverlay);
delayTimer.getKeyFrames().add(new KeyFrame(Duration.millis(3000), evt -> {
hideControlOverlay(null);
rootPane.requestFocus();
}));
rootPane.requestFocus();
}
private void showMenuButton(MouseEvent evt) {
@ -198,15 +206,24 @@ public class JaceUIController {
}
}
private void connectControls(Stage primaryStage) {
Stage primaryStage;
public void reconnectKeyboard() {
Emulator.withComputer(computer -> {
if (computer.getKeyboard() != null) {
EventHandler<KeyEvent> keyboardHandler = computer.getKeyboard().getListener();
primaryStage.setOnShowing(evt -> computer.getKeyboard().resetState());
rootPane.setOnKeyPressed(keyboardHandler);
rootPane.setOnKeyReleased(keyboardHandler);
rootPane.setFocusTraversable(true);
}
});
}
private void connectControls(Stage ps) {
primaryStage = ps;
connectButtons(controlOverlay);
if (computer.getKeyboard() != null) {
EventHandler<KeyEvent> keyboardHandler = computer.getKeyboard().getListener();
primaryStage.setOnShowing(evt -> computer.getKeyboard().resetState());
rootPane.setOnKeyPressed(keyboardHandler);
rootPane.setOnKeyReleased(keyboardHandler);
rootPane.setFocusTraversable(true);
}
speedSlider.setMinorTickCount(0);
speedSlider.setMajorTickUnit(1);
speedSlider.setLabelFormatter(new StringConverter<Double>() {
@ -237,29 +254,33 @@ public class JaceUIController {
setSpeed(Emulator.logic.speedSetting);
});
musicSelection.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) ->
Emulator.withComputer(computer ->
((LawlessHacks) ((LawlessComputer) computer).activeCheatEngine).changeMusicScore(String.valueOf(newValue))
)
);
reconnectKeyboard();
}
private void connectButtons(Node n) {
if (n instanceof Button) {
Button button = (Button) n;
if (n instanceof Button button) {
Runnable action = Utility.getNamedInvokableAction(button.getText());
button.setOnMouseClicked(evt -> action.run());
} else if (n instanceof Parent) {
((Parent) n).getChildrenUnmodifiable().forEach(child -> connectButtons(child));
} else if (n instanceof Parent parent) {
parent.getChildrenUnmodifiable().forEach(child -> connectButtons(child));
}
}
protected void setSpeed(double speed) {
public void setSpeed(double speed) {
Emulator.logic.speedSetting = (int) speed;
double speedRatio = convertSpeedToRatio(speed);
if (speedSlider.getValue() != speed) {
Platform.runLater(()->speedSlider.setValue(speed));
}
if (speedRatio >= 100.0) {
Emulator.getComputer().getMotherboard().setMaxSpeed(true);
Emulator.getComputer().getMotherboard().setSpeedInPercentage(20000);
Emulator.withComputer(c -> {
c.getMotherboard().setSpeedInPercentage(20000);
c.getMotherboard().setMaxSpeed(true);
});
// Motherboard.cpuPerClock = 10;
} else {
if (speedRatio > 1000) {
@ -267,10 +288,12 @@ public class JaceUIController {
} else {
Motherboard.cpuPerClock = 1;
}
Emulator.getComputer().getMotherboard().setMaxSpeed(false);
Emulator.getComputer().getMotherboard().setSpeedInPercentage((int) (speedRatio * 100));
Emulator.withComputer(c -> {
c.getMotherboard().setMaxSpeed(false);
c.getMotherboard().setSpeedInPercentage((int) (speedRatio * 100));
});
}
Emulator.getComputer().getMotherboard().reconfigure();
Emulator.withComputer(c -> c.getMotherboard().reconfigure());
}
public void toggleAspectRatio() {
@ -281,19 +304,23 @@ public class JaceUIController {
aspectRatioCorrectionEnabled.set(enabled);
}
public void connectComputer(Computer computer, Stage primaryStage) {
if (computer == null) {
return;
}
this.computer = computer;
public void connectComputer(Stage primaryStage) {
Platform.runLater(() -> {
connectControls(primaryStage);
appleScreen.setImage(computer.getVideo().getFrameBuffer());
Emulator.withVideo(this::connectVideo);
appleScreen.setVisible(true);
rootPane.requestFocus();
});
}
public void connectVideo(Video video) {
if (video != null) {
appleScreen.setImage(video.getFrameBuffer());
} else {
appleScreen.setImage(null);
}
}
private void processDragEnteredEvent(DragEvent evt) {
MediaEntry media = null;
if (evt.getDragboard().hasFiles()) {
@ -355,15 +382,17 @@ public class JaceUIController {
});
icon.setOnDragDropped(event -> {
System.out.println("Dropping media on " + icon.getText());
try {
computer.pause();
consumer.insertMedia(media, media.files.get(0));
computer.resume();
Emulator.withComputer(c -> {
c.getMotherboard().whileSuspended(() -> {
try {
consumer.insertMedia(media, media.files.get(0));
} catch (IOException ex) {
Logger.getLogger(JaceUIController.class.getName()).log(Level.SEVERE, null, ex);
}
});
});
event.setDropCompleted(true);
event.consume();
} catch (IOException ex) {
Logger.getLogger(JaceUIController.class.getName()).log(Level.SEVERE, null, ex);
}
endDragEvent();
});
});
@ -379,13 +408,15 @@ public class JaceUIController {
private List<MediaConsumer> getMediaConsumers() {
List<MediaConsumer> consumers = new ArrayList<>();
consumers.add(Emulator.getComputer().getUpgradeHandler());
Emulator.withComputer(c -> consumers.add(((LawlessComputer) c).getUpgradeHandler()));
if (Emulator.logic.showDrives) {
for (Optional<Card> card : computer.memory.getAllCards()) {
card.filter(c -> c instanceof MediaConsumerParent).ifPresent(parent ->
Emulator.withMemory(m -> {
for (Optional<Card> card : m.getAllCards()) {
card.filter(c -> c instanceof MediaConsumerParent).ifPresent(parent ->
consumers.addAll(Arrays.asList(((MediaConsumerParent) parent).getConsumers()))
);
}
);
}
});
}
return consumers;
}
@ -398,7 +429,7 @@ public class JaceUIController {
public void addIndicator(Label icon, long TTL) {
if (!iconTTL.containsKey(icon)) {
Application.invokeLater(() -> {
Platform.runLater(() -> {
if (!notificationBox.getChildren().contains(icon)) {
notificationBox.getChildren().add(icon);
}
@ -408,7 +439,7 @@ public class JaceUIController {
}
public void removeIndicator(Label icon) {
Application.invokeLater(() -> {
Platform.runLater(() -> {
notificationBox.getChildren().remove(icon);
iconTTL.remove(icon);
});
@ -453,13 +484,13 @@ public class JaceUIController {
notification.setEffect(new DropShadow(2.0, Color.BLACK));
notification.setTextFill(Color.WHITE);
notification.setBackground(new Background(new BackgroundFill(Color.rgb(0, 0, 80, 0.7), new CornerRadii(5.0), new Insets(-5.0))));
Application.invokeLater(() -> {
Platform.runLater(() -> {
stackPane.getChildren().remove(oldNotification);
stackPane.getChildren().add(notification);
});
notificationExecutor.schedule(
() -> Application.invokeLater(() -> stackPane.getChildren().remove(notification)),
() -> Platform.runLater(() -> stackPane.getChildren().remove(notification)),
4, TimeUnit.SECONDS);
}
}

View File

@ -1,8 +1,16 @@
package jace;
import java.awt.Taskbar;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import jace.apple2e.Apple2e;
import jace.apple2e.SoftSwitches;
import jace.apple2e.VideoNTSC;
import jace.config.Configuration;
import jace.core.Computer;
import jace.core.RAMEvent;
import jace.core.RAMListener;
import jace.core.Utility;
@ -10,12 +18,14 @@ import jace.hardware.CardDiskII;
import jace.hardware.CardRamFactor;
import jace.hardware.CardRamworks;
import jace.hardware.massStorage.CardMassStorage;
import jace.lawless.LawlessComputer;
import jace.lawless.LawlessHacks;
import jace.lawless.LawlessImageTool;
import jace.lawless.LawlessVideo;
import jace.ui.MetacheatUI;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.SwingFXUtils;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
@ -24,10 +34,6 @@ import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author blurry
@ -54,8 +60,18 @@ public class LawlessLegends extends Application {
Scene s = new Scene(node);
s.setFill(Color.BLACK);
primaryStage.setScene(s);
primaryStage.setTitle("Lawless Legends");
Utility.loadIcon("game_icon.png").ifPresent(primaryStage.getIcons()::add);
primaryStage.titleProperty().set("Lawless Legends");
Utility.loadIcon("game_icon.png").ifPresent(icon -> {
primaryStage.getIcons().add(icon);
try {
//set icon for mac os (and other systems which do support this method)
Taskbar.getTaskbar().setIconImage(SwingFXUtils.fromFXImage(icon, null));
} catch (final UnsupportedOperationException e) {
System.out.println("The os does not support: 'taskbar.setIconImage'");
} catch (final SecurityException e) {
System.out.println("There was a security exception for: 'taskbar.setIconImage'");
}
});
} catch (IOException exception) {
throw new RuntimeException(exception);
}
@ -63,23 +79,30 @@ public class LawlessLegends extends Application {
primaryStage.show();
Platform.runLater(() -> new Thread(() -> {
Emulator.getInstance(getParameters().getRaw());
Emulator.withComputer(c->((LawlessComputer)c).initLawlessLegendsConfiguration());
configureEmulatorForGame();
reconnectUIHooks();
EmulatorUILogic.scaleIntegerRatio();
while (Emulator.getComputer().getVideo() == null || Emulator.getComputer().getVideo().getFrameBuffer() == null) {
Thread.yield();
AtomicBoolean waitingForVideo = new AtomicBoolean(true);
while (waitingForVideo.get()) {
Emulator.withVideo(v -> {
if (v.getFrameBuffer() != null) {
waitingForVideo.set(false);
}
});
Thread.onSpinWait();
}
bootWatchdog();
}).start());
primaryStage.setOnCloseRequest(event -> {
Emulator.getComputer().deactivate();
Emulator.withComputer(Computer::deactivate);
Platform.exit();
System.exit(0);
});
}
public void reconnectUIHooks() {
controller.connectComputer(Emulator.getComputer(), primaryStage);
controller.connectComputer(primaryStage);
}
public static LawlessLegends getApplication() {
@ -123,51 +146,76 @@ public class LawlessLegends extends Application {
*/
private void bootWatchdog() {
romStarted = false;
if (Emulator.getComputer().PRODUCTION_MODE) {
RAMListener startListener = Emulator.getComputer().getMemory().
observe(RAMEvent.TYPE.EXECUTE, 0x0c700, (e) -> romStarted = true);
Emulator.getComputer().invokeColdStart();
try {
Thread.sleep(7500);
if (!romStarted) {
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Boot not detected, performing a cold start");
Emulator.getComputer().invokeColdStart();
}
} catch (InterruptedException ex) {
Logger.getLogger(LawlessLegends.class.getName()).log(Level.SEVERE, null, ex);
Emulator.withComputer(c -> {
if (c.PRODUCTION_MODE) {
new Thread(()->{
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Booting with watchdog");
RAMListener startListener = c.getMemory().
observe(RAMEvent.TYPE.EXECUTE, 0x2000, (e) -> {
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Boot was detected, watchdog terminated.");
romStarted = true;
});
c.invokeColdStart();
try {
Thread.sleep(6500);
if (!romStarted) {
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Boot not detected, performing a cold start");
resetEmulator();
configureEmulatorForGame();
bootWatchdog();
// Emulator.getComputer().getCpu().trace=true;
} else {
c.getMemory().removeListener(startListener);
}
} catch (InterruptedException ex) {
Logger.getLogger(LawlessLegends.class.getName()).log(Level.SEVERE, null, ex);
}
}).start();
} else {
romStarted = true;
c.invokeColdStart();
}
Emulator.getComputer().getMemory().removeListener(startListener);
} else {
romStarted = true;
Emulator.getComputer().invokeColdStart();
}
});
}
public void resetEmulator() {
// Reset the emulator memory and reconfigure
Emulator.withComputer(c -> {
c.pause();
c.getMemory().resetState();
c.reconfigure();
c.resume();
});
}
private void configureEmulatorForGame() {
Emulator.getComputer().enableHints = false;
Emulator.getComputer().clockEnabled = true;
Emulator.getComputer().joy1enabled = false;
Emulator.getComputer().joy2enabled = false;
Emulator.getComputer().enableStateManager = false;
Emulator.getComputer().ramCard.setValue(CardRamworks.class);
Emulator.getComputer().videoRenderer.setValue(LawlessVideo.class);
if (Emulator.getComputer().PRODUCTION_MODE) {
Emulator.getComputer().card7.setValue(CardMassStorage.class);
Emulator.getComputer().card6.setValue(CardDiskII.class);
Emulator.getComputer().card5.setValue(CardRamFactor.class);
Emulator.getComputer().card4.setValue(null);
Emulator.getComputer().card2.setValue(null);
}
Emulator.getComputer().cheatEngine.setValue(LawlessHacks.class);
Configuration.buildTree();
Emulator.getComputer().reconfigure();
VideoNTSC.setVideoMode(VideoNTSC.VideoMode.TextFriendly, false);
if (Emulator.getComputer().PRODUCTION_MODE) {
((LawlessImageTool) Emulator.getComputer().getUpgradeHandler()).loadGame();
} else {
for (SoftSwitches s : SoftSwitches.values()) {
s.getSwitch().reset();
Emulator.withComputer(c -> {
c.enableHints = false;
c.clockEnabled = true;
c.joy1enabled = false;
c.joy2enabled = false;
c.enableStateManager = false;
c.ramCard.setValue(CardRamworks.class);
c.videoRenderer.setValue(LawlessVideo.class);
if (c.PRODUCTION_MODE) {
c.card7.setValue(CardMassStorage.class);
c.card6.setValue(CardDiskII.class);
c.card5.setValue(CardRamFactor.class);
c.card4.setValue(null);
c.card2.setValue(null);
c.getMemory().writeWord(0x03f0, 0x0c700, false, false);
}
}
c.cheatEngine.setValue(LawlessHacks.class);
Configuration.buildTree();
c.reconfigure();
VideoNTSC.setVideoMode(VideoNTSC.VideoMode.TextFriendly, false);
if (c.PRODUCTION_MODE) {
((LawlessImageTool) c.getUpgradeHandler()).loadGame();
} else {
for (SoftSwitches s : SoftSwitches.values()) {
s.getSwitch().reset();
}
}
});
}
}

View File

@ -18,21 +18,13 @@
*/
package jace.apple2e;
import jace.LawlessLegends;
import jace.apple2e.softswitch.VideoSoftSwitch;
import jace.cheat.Cheats;
import jace.config.ClassSelection;
import jace.config.ConfigurableField;
import jace.core.*;
import jace.hardware.*;
import jace.hardware.massStorage.CardMassStorage;
import jace.lawless.FPSMonitorDevice;
import jace.lawless.LawlessVideo;
import jace.state.Stateful;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
@ -40,6 +32,32 @@ import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import jace.LawlessLegends;
import jace.apple2e.softswitch.VideoSoftSwitch;
import jace.cheat.Cheats;
import jace.config.ClassSelection;
import jace.config.ConfigurableField;
import jace.core.Card;
import jace.core.Computer;
import jace.core.Device;
import jace.core.Motherboard;
import jace.core.RAM;
import jace.core.RAMEvent;
import jace.core.RAMListener;
import jace.core.Utility;
import jace.core.Video;
import jace.hardware.CardDiskII;
import jace.hardware.CardExt80Col;
import jace.hardware.CardRamworks;
import jace.hardware.ConsoleProbe;
import jace.hardware.Joystick;
import jace.hardware.NoSlotClock;
import jace.hardware.ZipWarpAccelerator;
import jace.hardware.massStorage.CardMassStorage;
import jace.lawless.FPSMonitorDevice;
import jace.lawless.LawlessVideo;
import jace.state.Stateful;
/**
* Apple2e is a computer with a 65c02 CPU, 128k of bankswitched ram,
* double-hires graphics, and up to seven peripheral I/O cards installed. Pause
@ -173,7 +191,7 @@ public class Apple2e extends Computer {
if (getMemory().getCard(slot).isPresent()) {
if (getMemory().getCard(slot).get().getClass().equals(type)) {
return;
}
}
getMemory().removeCard(slot);
}
if (type != null) {
@ -214,13 +232,12 @@ public class Apple2e extends Computer {
return;
}
motherboard.whileSuspended(()-> {
if (getMemory() != null) {
for (SoftSwitches s : SoftSwitches.values()) {