Added about window, version number info to build

This commit is contained in:
Brendan Robert
2025-04-18 12:28:58 -05:00
parent 75d86b6ddb
commit 9ccae6c1e1
11 changed files with 373 additions and 5 deletions

View File

@@ -0,0 +1,95 @@
# Lawless Legends Developer Guide
## Version Management
Lawless Legends uses a centralized version management system to ensure consistent versioning across the application and packaging process.
### How to Update the Version Number
The version number is stored in a single file at the project root:
```
/version.properties
```
To update the version:
1. Edit the `version.properties` file in the project root
2. Update the `version` property with the new version number
3. Optionally, update the `build.date` property with the current date
Example:
```
version=1.1
build.date=2024-07-15
```
### How Version Information is Used
The version information is automatically used in:
1. **About Window**: The About dialog displays the version number from `version.properties`
2. **macOS Packaging**: The packaging script reads the version number from `version.properties` for DMG and app bundle versioning
3. **Application**: The `VersionInfo` utility class provides version information throughout the application
### Version Format Recommendations
For version numbering, we recommend following semantic versioning (MAJOR.MINOR.PATCH):
- **MAJOR**: Increment for incompatible API changes
- **MINOR**: Increment for backward-compatible new features
- **PATCH**: Increment for backward-compatible bug fixes
For example: `1.0.0`, `1.1.0`, `1.1.1`, etc.
#### macOS Packaging Compatibility
For macOS packaging compatibility, note the following:
- The macOS packaging system requires version numbers to be in the format of 1-3 integers separated by dots (e.g., `1.0`, `1.2.3`)
- If you use non-standard version formats (e.g., `1.0-beta.1`, `1.0-4n23k.99-DEMO`), the packaging script will automatically:
- Extract only the part before the first hyphen for the application bundle version
- Use the full version for the DMG file name and in the application's About window
- This allows you to use descriptive version strings while maintaining compatibility with macOS
For example, if `version.properties` contains `version=1.0-4n23k.99-DEMO`:
- The app bundle will use `1.0` as its internal version number
- The DMG file will be named `Lawless Legends 1.0-4n23k.99-DEMO.dmg`
- The About window will display `Version 1.0-4n23k.99-DEMO`
## Building the Application
To build the application:
```bash
mvn clean package
```
The version information is automatically included in the built JAR file.
## Packaging for Distribution
When packaging the application for distribution using the `package-macos.zsh` script, the version from `version.properties` is automatically used to:
1. Set the application bundle version
2. Name the DMG file with the appropriate version
3. Update internal version information in the app bundle's Info.plist
No additional configuration is needed to include version information when packaging.
## Development Guidelines
When adding new features that need version information:
1. Use the `VersionInfo` utility class to access version information:
```java
import jace.core.VersionInfo;
// Get the version string
String version = VersionInfo.getVersion();
// Get a formatted version display (includes build date if available)
String versionDisplay = VersionInfo.getVersionDisplay();
```
2. Never hardcode version numbers in the application code

View File

@@ -12,6 +12,15 @@ This document summarizes the successful approach for packaging the Lawless Legen
- The embedded runtime is created using `jlink` to include only the necessary Java modules, resulting in a smaller package size.
- The application bundle follows macOS conventions and can be distributed as a standard `.app` package.
### Version Management
- The application version is managed through a single `version.properties` file in the project root.
- The packaging script automatically reads the version from this file and applies it to:
- The application bundle version
- The DMG file name
- The Info.plist file's version information
- To update the version before packaging, simply edit the `version.properties` file.
### Architecture-Specific Support
- The solution correctly handles ARM64 architecture for Apple Silicon Macs.

View File

@@ -15,6 +15,11 @@ To Build:
* See [build.sh](build.sh)
Version Management:
* The application version is stored in [version.properties](version.properties) at the project root
* To update the version, edit this file (see [README-DEVELOPERS.md](README-DEVELOPERS.md) for details)
Jace is a java-based Apple //e emulator with many compelling features:
* NEW: Built-in IDE for writing basic and assembly programs, using ACME to compile and execute directly without leaving the emulator.
* Disk and Mass-storage (hard drive, 3.5 floppy) images

View File

@@ -38,7 +38,24 @@ ICON_FILE="${MAIN_TEMP_DIR}/AppIcon.icns"
DMG_TEMP_DIR="${MAIN_TEMP_DIR}/dmg_temp"
# Application info
VERSION="1.0.0"
# Read version from version.properties file
VERSION_PROPS_FILE="${JACE_DIR}/version.properties"
if [[ -f "${VERSION_PROPS_FILE}" ]]; then
FULL_VERSION=$(grep "^version=" "${VERSION_PROPS_FILE}" | cut -d= -f2)
# Extract only the first part of the version before any hyphen for macOS compatibility
VERSION=$(echo ${FULL_VERSION} | cut -d- -f1)
log "✅ Read full version ${FULL_VERSION} from ${VERSION_PROPS_FILE}"
log "✅ Using macOS-compatible version ${VERSION} for packaging"
else
VERSION="1.0.0"
FULL_VERSION="${VERSION}"
log "⚠️ Version properties file not found at ${VERSION_PROPS_FILE}, defaulting to version ${VERSION}"
fi
# Update the final DMG name to include the full version
FINAL_DMG="${DESKTOP_DIR}/Lawless Legends ${FULL_VERSION}.dmg"
log "✅ DMG will be created at: ${FINAL_DMG}"
MAIN_CLASS="jace.LawlessLegends"
JAVA_FX_JMODS=""
@@ -398,10 +415,12 @@ section "CREATING APPLICATION PACKAGE"
LAUNCHER_ARGS=(
# Main application properties
"--name" "Lawless Legends"
# Use macOS-compatible version (before any hyphen) for app-version
"--app-version" "${VERSION}"
"--vendor" "The 8-Bit Bunch"
"--copyright" "Copyright © 2025 The 8-Bit Bunch. All rights reserved."
"--description" "Lawless Legends - A retro-style RPG game"
# Use full version in description for reference
"--description" "Lawless Legends ${FULL_VERSION} - A retro-style RPG game"
# Input and output paths
"--input" "${PACKAGE_DIR}"
@@ -857,7 +876,7 @@ log "Updating Info.plist at ${INFO_PLIST}..."
</plist>
EOF
log "✅ Info.plist updated with proper icon references"
log "✅ Info.plist updated with proper icon references and clean version: ${VERSION} (from full version: ${FULL_VERSION})"
# Show contents of Info.plist for verification
log "Contents of Info.plist:"
@@ -986,7 +1005,7 @@ fi
# Generate DMG file
log "Creating DMG file with hdiutil..."
/usr/bin/hdiutil create \
-volname "Lawless Legends ${VERSION}" \
-volname "Lawless Legends ${FULL_VERSION}" \
-srcfolder "${DMG_TEMP_DIR}" \
-ov -format UDZO \
"${TEMP_DMG}"

View File

@@ -16,6 +16,7 @@
<mainClass>jace.LawlessLegends</mainClass>
<netbeans.hint.license>apache20</netbeans.hint.license>
<lwjgl.version>3.3.3</lwjgl.version>
<app.version>1.0</app.version>
</properties>
<organization>
@@ -25,6 +26,17 @@
<build>
<finalName>LawlessLegends</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>${project.basedir}</directory>
<includes>
<include>version.properties</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>com.gluonhq</groupId>

View File

@@ -17,6 +17,7 @@ Most folks are too nervous to venture far from town...even for gold.
Technical Notes:
This application includes its own Java runtime - no need to install Java separately.
Version information is displayed in the About window (press Ctrl+Shift+.)
For more information and updates, visit:
https://lawlesslegends.wordpress.com/

View File

@@ -0,0 +1,63 @@
package jace;
import jace.core.VersionInfo;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;
import java.io.InputStream;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.Initializable;
/**
* Controller for the About window
*
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
*/
public class AboutController implements Initializable {
@FXML
private Button closeButton;
@FXML
private ImageView appIcon;
@FXML
private Label versionLabel;
/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
// Load application icon
try {
String iconPath = "/jace/data/game_icon.png";
InputStream iconStream = getClass().getResourceAsStream(iconPath);
if (iconStream != null) {
Image icon = new Image(iconStream);
appIcon.setImage(icon);
}
} catch (Exception e) {
System.err.println("Failed to load application icon: " + e.getMessage());
}
// Set version information
if (versionLabel != null) {
versionLabel.setText(VersionInfo.getVersionDisplay());
}
}
/**
* Close the About window when the close button is clicked
*/
@FXML
private void handleCloseButton() {
Stage stage = (Stage) closeButton.getScene().getWindow();
stage.close();
}
}

View File

@@ -43,6 +43,7 @@ import jace.config.Reconfigurable;
import jace.core.Debugger;
import jace.core.RAM;
import jace.core.RAMListener;
import jace.core.Utility;
import jace.ide.IdeController;
import javafx.application.Platform;
import javafx.event.EventHandler;
@@ -454,7 +455,26 @@ public class EmulatorUILogic implements Reconfigurable {
alternatives = "info;credits",
defaultKeyMapping = {"ctrl+shift+."})
public static void showAboutWindow() {
//TODO: Implement
FXMLLoader fxmlLoader = new FXMLLoader(EmulatorUILogic.class.getResource("/fxml/About.fxml"));
fxmlLoader.setResources(null);
try {
Stage aboutWindow = new Stage();
AnchorPane node = fxmlLoader.load();
AboutController controller = fxmlLoader.getController();
Scene s = new Scene(node);
aboutWindow.setScene(s);
aboutWindow.setTitle("About Lawless Legends");
aboutWindow.setResizable(false);
// Set application icon on the about window
Utility.loadIcon("game_icon.png").ifPresent(icon -> {
aboutWindow.getIcons().add(icon);
});
aboutWindow.show();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
public static boolean confirm(String message) {

View File

@@ -0,0 +1,71 @@
package jace.core;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Utility class for providing version information
*
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
*/
public class VersionInfo {
private static final Logger LOG = Logger.getLogger(VersionInfo.class.getName());
private static String version = "1.0";
private static String buildDate = "";
static {
loadVersionInfo();
}
/**
* Load version information from properties file
*/
private static void loadVersionInfo() {
Properties properties = new Properties();
try (InputStream input = VersionInfo.class.getClassLoader().getResourceAsStream("version.properties")) {
if (input != null) {
properties.load(input);
version = properties.getProperty("version", "1.0");
buildDate = properties.getProperty("build.date", "");
} else {
LOG.log(Level.WARNING, "version.properties file not found in classpath");
}
} catch (IOException e) {
LOG.log(Level.SEVERE, "Failed to load version information", e);
}
}
/**
* Get the current application version
*
* @return The version string
*/
public static String getVersion() {
return version;
}
/**
* Get the build date
*
* @return The build date string
*/
public static String getBuildDate() {
return buildDate;
}
/**
* Get the version display string
*
* @return The formatted version display string
*/
public static String getVersionDisplay() {
if (buildDate.isEmpty()) {
return "Version " + version;
} else {
return "Version " + version.trim() + " (" + buildDate.trim() + ")";
}
}
}

View File

@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<AnchorPane id="AnchorPane" prefHeight="300.0" prefWidth="450.0" style="-fx-background-color: #1a1a1a;" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="jace.AboutController">
<children>
<VBox alignment="CENTER" spacing="10.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<HBox alignment="CENTER" spacing="15.0">
<children>
<ImageView fx:id="appIcon" fitHeight="96.0" fitWidth="96.0" pickOnBounds="true" preserveRatio="true" />
<VBox alignment="CENTER_LEFT">
<children>
<Label text="Lawless Legends" textFill="WHITE">
<font>
<Font name="System Bold" size="24.0" />
</font>
</Label>
<Label text="A fantasy role playing game set in the wild west!" textFill="#cccccc">
<font>
<Font size="14.0" />
</font>
</Label>
</children>
</VBox>
</children>
</HBox>
<Label text="Developed by The 8 Bit Bunch" textFill="#cccccc">
<font>
<Font size="14.0" />
</font>
</Label>
<Label text="Jace emulator by Brendan Robert" textFill="#cccccc">
<font>
<Font size="14.0" />
</font>
</Label>
<Label fx:id="versionLabel" text="Version 1.0" textFill="#cccccc">
<font>
<Font size="12.0" />
</font>
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</Label>
<HBox alignment="CENTER">
<children>
<Button fx:id="closeButton" mnemonicParsing="false" onAction="#handleCloseButton" text="Close">
<font>
<Font size="13.0" />
</font>
</Button>
</children>
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</HBox>
</children>
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</padding>
</VBox>
</children>
</AnchorPane>

View File

@@ -0,0 +1,2 @@
version=1.0-4n23k.99-DEMO
build.date=2025-04-18