Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/syd711/vpin-studio
Browse files Browse the repository at this point in the history
  • Loading branch information
leprinco committed Jan 26, 2025
2 parents b1ee624 + 24b6144 commit 9d25efd
Show file tree
Hide file tree
Showing 15 changed files with 184 additions and 81 deletions.
39 changes: 24 additions & 15 deletions .github/workflows/workflow-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,20 @@ jobs:
path: ./vpin-mania-rest-client
token: ${{ secrets.ACCESS_TOKEN }}

# Step 2: Set up Zulu OpenJDK 11
- name: Set up Zulu JDK 11
# Step 2: Set up Zulu OpenJDK 17
- name: Set up Zulu JDK 17
uses: actions/setup-java@v2
with:
distribution: 'zulu'
java-version: '11'
java-version: '17'

# Step 3: Install Maven and dependencies
#Zulu 11 does not include jpackage, need to install it
- name: Install Dependencies
run: |
brew update
brew install maven
brew install openjdk@17 # Ensure Zulu JDK 11 is installed on macOS
# - name: Install Dependencies
# run: |
# brew update
# brew install maven
# brew install openjdk@17 # Ensure Zulu JDK 17 is installed on macOS

# Step 4: Build the Java application
- name: Run maven build for vpin mania rest client
Expand All @@ -72,23 +72,32 @@ jobs:
run: mvn --batch-mode --update-snapshots clean package -DskipMacOSBuild=false -DmacOSBuild=true -DskipTests

# Step 5: Package the Java application as a macOS .app bundle
#The jpackage config needs to be updated to properly reference the locations of the files.
#The jpackage config needs to be updated to properly reference the locations of the files.
#jpackage @jpackage_config.txt
- name: Package as macOS App
working-directory: ./mac-package
run: |
jpackage @jpackage_config.txt
echo "ls . results"
ls -al .
echo "ls .. results"
ls -al ..
echo "ls package results"
ls -al package
echo "ls package/macos results"
ls -al package/macos
jpackage --name VPin-Studio --input . --app-version 3.11.2 --main-jar ../vpin-studio-ui/target/vpin-studio-ui.jar --main-class de.mephisto.vpin.ui.Launcher --resource-dir package/macos --type app-image --icon VpinStudio.icns --dest ../ --runtime-image $(/usr/libexec/java_home -v 11)
# Step 7: Zip the .app bundle for easy distribution
#Update for correct location
- name: Zip macOS .app Bundle
working-directory: ./
run: |
mkdir -p target/macApp
cd target/macApp
zip -r VpinStudioMac.zip VpinStudio.app
zip VPin-Studio-MacOS.zip VPin-Studio.app
# Step 8: Upload the .app zip file as an artifact
#Update for correct location
- name: Upload macOS Build Artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: macOS-build
path: target/macApp/VpinStudioMac.zip
path: ./VPin-Studio-MacOS.zip
4 changes: 3 additions & 1 deletion RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

## Changes

- **Installation**: The highscore scan is now executed after a the initial table scan. This should avoid "database locked" errors which caused broken installations.
- **Installation**: The highscore scan is now executed after the initial table scan. This should avoid "database locked" errors which caused broken installations.
- **Highscore Resets**: Switched the default from 99 to 0. These values are only used when the highscore has been reset through the "Delete Table" dialog.
- **Highscore Displays**: use client default thousands separator eveywhere when displaying scores, dashboard and player badges were not rendered properly
- **VPin Studio Server**: Improved launch and exit curl calls. The curl call is replaced now with the additional parameter **emu** which contains additional information about the game emulator used, depending on the frontend you are using. This way, you can share your tables folder between different VPX emulators and the correct emulator is still detected corrected. The parameter is optional, so if the automatic update of the **curl** call fails for some reason, the old format is still valid.
- **Highscore Settings**: Removed configuration option for highscore titles, e.g. "GRAND CHAMPION". These values are now part of the internal scoring database so that the user never has to deal with this kind of stuff.
- **Highscore Parsing**: Fixed highscores for tables **Defender, Black Pyramid and Catacomb**.
- **Tables / Playlists**: Renamed **Local Favorites** to **Playlist Favorites**.
- **Tables / PinVOL Settings**: The user interface for the PinVOL settings used the SSF DB limit value now. You can't configure this via Studio yet and have to configure it once via the PinVOL UI.
- **PinballX Frontend**: fixed zero byte download by using FTP passive mode, then try active mode if failure
- **System Manager**: Fixed **Backglass Server** update detection.

---

Expand Down
2 changes: 1 addition & 1 deletion resources/vpsdb.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ public class PinVolPreferences {
private int global = 0;
private int night = 0;
private int defaultVol = 0;
private int ssfDbLimit = 10;

public int getSsfDbLimit() {
return ssfDbLimit;
}

public void setSsfDbLimit(int ssfDbLimit) {
this.ssfDbLimit = ssfDbLimit;
}

public int getGlobal() {
return global;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,29 +66,29 @@ public void applyValues(PinVolTableEntry tableVolume) {
setSecondaryVolume(tableVolume.getSecondaryVolume());
}

public String toSettingsString() {
public String toSettingsString(int ssfDbLimit) {
StringBuilder builder = new StringBuilder(getName());
builder.append("\t");
builder.append(getPrimaryVolume());
builder.append("\t");
builder.append(getSecondaryVolume());
builder.append("\t");
builder.append(formatGainValue(getSsfBassVolume()));
builder.append(formatGainValue(getSsfBassVolume(), ssfDbLimit));
builder.append("\t");
builder.append(formatGainValue(getSsfRearVolume()));
builder.append(formatGainValue(getSsfRearVolume(), ssfDbLimit));
builder.append("\t");
builder.append(formatGainValue(getSsfFrontVolume()));
builder.append(formatGainValue(getSsfFrontVolume(), ssfDbLimit));
builder.append("\n");
return builder.toString();
}

public static int formatGainValue(int i) {
public static int formatGainValue(int i, int ssfDbLimit) {
try {
if (i < -10) {
i = -10;
if (i < -ssfDbLimit) {
i = -ssfDbLimit;
}
else if (i > 10) {
i = 10;
else if (i > ssfDbLimit) {
i = ssfDbLimit;
}
return i;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ private ReleaseArtifact getReleaseArtifact(@NonNull String artifact, GithubRelea
if (releaseArtifact == null) {
releaseArtifact = githubRelease.getArtifacts().stream().filter(a -> a.getName().equals(artifact)).findFirst().orElse(null);
}

if (releaseArtifact == null) {
releaseArtifact = githubRelease.getArtifacts().stream().filter(a -> a.getName().toLowerCase().contains("release")).findFirst().orElse(null);
}
return releaseArtifact;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ public PinVolPreferences getPinVolTablePreferences() {
private void loadIni() {
preferences = new PinVolPreferences();
try {
INIConfiguration pinVolSettingsConfig = getPinVolSettingsConfig();
if (pinVolSettingsConfig != null) {
preferences.setSsfDbLimit(pinVolSettingsConfig.getInt("SSFdBLimit", 10));
}

File tablesIni = getPinVolTablesIniFile();
if (!tablesIni.exists()) {
LOG.info("PinVol service table settings have not been loaded, because {} was not found.", tablesIni.getAbsolutePath());
Expand All @@ -120,7 +125,7 @@ private void loadIni() {
try (FileInputStream fileInputStream = new FileInputStream(tablesIni)) {
List<String> entries = IOUtils.readLines(fileInputStream, StandardCharsets.UTF_8);
for (String entry : entries) {
PinVolTableEntry e = createEntry(entry);
PinVolTableEntry e = createEntry(entry, preferences.getSsfDbLimit());
if (e != null) {
preferences.getTableEntries().add(e);
}
Expand Down Expand Up @@ -152,28 +157,29 @@ private void loadIni() {
}
}

private PinVolTableEntry createEntry(String line) {
private PinVolTableEntry createEntry(String line, int ssfDbLimit) {
String[] split = line.split("\\t");
if (split.length == 6) {
PinVolTableEntry entry = new PinVolTableEntry();
entry.setName(split[0]);
entry.setPrimaryVolume(Integer.parseInt(split[1]));
entry.setSecondaryVolume(Integer.parseInt(split[2]));
entry.setSsfBassVolume(parseGainValue(split[3]));
entry.setSsfRearVolume(parseGainValue(split[4]));
entry.setSsfFrontVolume(parseGainValue(split[5]));

entry.setSsfBassVolume(parseGainValue(split[3], ssfDbLimit));
entry.setSsfRearVolume(parseGainValue(split[4], ssfDbLimit));
entry.setSsfFrontVolume(parseGainValue(split[5], ssfDbLimit));
return entry;
}
return null;
}

private int parseGainValue(String value) {
private int parseGainValue(String value, int ssfDbLimit) {
try {
if (StringUtils.isEmpty(value)) {
return 0;
}
int i = Integer.parseInt(value);
return PinVolTableEntry.formatGainValue(i);
return PinVolTableEntry.formatGainValue(i, ssfDbLimit);
}
catch (NumberFormatException e) {
return 0;
Expand All @@ -184,13 +190,22 @@ private static File getPinVolTablesIniFile() {
return new File(SystemService.RESOURCES, "PinVolTables.ini");
}

private static File getPinVolSettingsIniFile() {
return new File(SystemService.RESOURCES, "PinVolSettings.ini");
}

private static File getPinVolVolIniFile() {
return new File(SystemService.RESOURCES, "PinVolVol.ini");
}

private void initListener() {
FileMonitoringThread monitoringThread = new FileMonitoringThread(this, getPinVolTablesIniFile(), true);
monitoringThread.startMonitoring();

if (getPinVolSettingsIniFile().exists()) {
FileMonitoringThread settingsThread = new FileMonitoringThread(this, getPinVolSettingsIniFile(), true);
settingsThread.startMonitoring();
}
}

public PinVolPreferences update(@NonNull PinVolUpdate update) {
Expand Down Expand Up @@ -228,7 +243,7 @@ private PinVolPreferences saveIniFile(PinVolPreferences preferences) {

List<PinVolTableEntry> tableEntries = preferences.getTableEntries();
for (PinVolTableEntry tableEntry : tableEntries) {
String value = tableEntry.toSettingsString();
String value = tableEntry.toSettingsString(preferences.getSsfDbLimit());
builder.append(value);
}

Expand Down Expand Up @@ -261,9 +276,35 @@ public void delete(@NonNull Game game) {
}
}

@Nullable
private INIConfiguration getPinVolSettingsConfig() {
try {
File volIni = getPinVolSettingsIniFile();
if (volIni.exists()) {
INIConfiguration iniConfiguration = new INIConfiguration();
iniConfiguration.setCommentLeadingCharsUsedInInput(";");
iniConfiguration.setSeparatorUsedInOutput("=");
iniConfiguration.setSeparatorUsedInInput("=");

try (FileReader fileReader = new FileReader(volIni)) {
iniConfiguration.read(fileReader);
}

return iniConfiguration;
}
else {
LOG.info("Skipped loading of {}, file not found.", volIni.getAbsolutePath());
}
}
catch (Exception e) {
LOG.error("Failed to load {}", "PinVolSettings.ini", e);
}
return null;
}

@Override
public void notifyFileChange(@Nullable File file) {
LOG.info("PinVolTable.ini changed");
LOG.info("PinVolSettings changed");
loadIni();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import de.mephisto.vpin.restclient.recorder.RecordingData;
import de.mephisto.vpin.restclient.recorder.RecordingDataSummary;
import de.mephisto.vpin.restclient.recorder.RecordingScreen;
import de.mephisto.vpin.server.dmd.DMDPositionService;
import de.mephisto.vpin.server.fp.FPService;
import de.mephisto.vpin.server.frontend.FrontendConnector;
import de.mephisto.vpin.server.frontend.FrontendStatusService;
Expand All @@ -26,8 +27,8 @@ public class EmulatorRecorderJob extends FrontendRecorderJob {

GameRecorder gameRecorder;

public EmulatorRecorderJob(GameService gameService, VPXService vpxService, FPService fpService, FrontendConnector frontend, FrontendStatusService frontendStatusService, RecorderSettings settings, RecordingDataSummary recordingDataSummary, List<RecordingScreen> recordingScreens) {
super(gameService, frontend, frontendStatusService, settings, recordingDataSummary, recordingScreens);
public EmulatorRecorderJob(DMDPositionService dmdPositionService, GameService gameService, VPXService vpxService, FPService fpService, FrontendConnector frontend, FrontendStatusService frontendStatusService, RecorderSettings settings, RecordingDataSummary recordingDataSummary, List<RecordingScreen> recordingScreens) {
super(dmdPositionService, gameService, frontend, frontendStatusService, settings, recordingDataSummary, recordingScreens);
this.vpxService = vpxService;
this.fpService = fpService;
}
Expand Down Expand Up @@ -99,7 +100,7 @@ else if (game.getEmulator().isFpEmulator()) {
jobDescriptor.setStatus("Recording \"" + game.getGameDisplayName() + "\"");

//create the game recorder which includes all screens
gameRecorder = new GameRecorder(frontend, game, recorderSettings, data, jobDescriptor, recordingDataSummary.size(), recordingScreens);
gameRecorder = new GameRecorder(frontend, game, recorderSettings, data, jobDescriptor, getRecordingScreensForGame(game));
gameRecorder.startRecording();

updateSingleProgress(jobDescriptor, recordingDataSummary, 90);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package de.mephisto.vpin.server.recorder;

import de.mephisto.vpin.restclient.dmd.DMDInfo;
import de.mephisto.vpin.restclient.frontend.FrontendPlayerDisplay;
import de.mephisto.vpin.restclient.frontend.VPinScreen;
import de.mephisto.vpin.restclient.games.descriptors.JobDescriptor;
import de.mephisto.vpin.restclient.jobs.Job;
import de.mephisto.vpin.restclient.recorder.*;
import de.mephisto.vpin.server.dmd.DMDPositionService;
import de.mephisto.vpin.server.frontend.FrontendConnector;
import de.mephisto.vpin.server.frontend.FrontendStatusService;
import de.mephisto.vpin.server.games.Game;
Expand All @@ -12,11 +15,13 @@
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class FrontendRecorderJob implements Job {
private final static Logger LOG = LoggerFactory.getLogger(FrontendRecorderJob.class);

final DMDPositionService dmdPositionService;
final GameService gameService;
final FrontendConnector frontend;
final FrontendStatusService frontendStatusService;
Expand All @@ -26,7 +31,8 @@ public class FrontendRecorderJob implements Job {

GameRecorder gameRecorder;

public FrontendRecorderJob(GameService gameService, FrontendConnector frontend, FrontendStatusService frontendStatusService, RecorderSettings settings, RecordingDataSummary recordingDataSummary, List<RecordingScreen> recordingScreens) {
public FrontendRecorderJob(DMDPositionService dmdPositionService, GameService gameService, FrontendConnector frontend, FrontendStatusService frontendStatusService, RecorderSettings settings, RecordingDataSummary recordingDataSummary, List<RecordingScreen> recordingScreens) {
this.dmdPositionService = dmdPositionService;
this.gameService = gameService;
this.frontend = frontend;
this.frontendStatusService = frontendStatusService;
Expand Down Expand Up @@ -88,7 +94,7 @@ public void execute(JobDescriptor jobDescriptor) {
jobDescriptor.setStatus("Recording \"" + game.getGameDisplayName() + "\"");

//create the game recorder which includes all screens
gameRecorder = new GameRecorder(frontend, game, recorderSettings, data, jobDescriptor, recordingDataSummary.size(), recordingScreens);
gameRecorder = new GameRecorder(frontend, game, recorderSettings, data, jobDescriptor, getRecordingScreensForGame(game));
gameRecorder.startRecording();
}
finally {
Expand Down Expand Up @@ -172,4 +178,44 @@ protected boolean isRecordingRequired(Game game) {
}
return false;
}

/**
* Updates the recording screens with custom positions relevant for the given game.
* E.g. DMDs may have a custom position.
*
* @param game the game to customize the recording screens for
* @return the adapted screens
*/
protected List<RecordingScreen> getRecordingScreensForGame(Game game) {
List<RecordingScreen> updated = new ArrayList<>();
for (RecordingScreen recordingScreen : recordingScreens) {
//TODO
// if (recordingScreen.getScreen().equals(VPinScreen.DMD)) {
// DMDInfo dmdInfo = dmdPositionService.getDMDInfo(game.getId());
//
// int x = (int) (recordingScreen.getDisplay().getX() + dmdInfo.getX());
// int y = (int) (recordingScreen.getDisplay().getY() + dmdInfo.getY());
//
// FrontendPlayerDisplay updatedDisplay = new FrontendPlayerDisplay();
// updatedDisplay.setHeight((int) dmdInfo.getHeight());
// updatedDisplay.setWidth((int) dmdInfo.getWidth());
// updatedDisplay.setX(x);
// updatedDisplay.setY(y);
// updatedDisplay.setName(recordingScreen.getDisplay().getName());
// updatedDisplay.setScreen(recordingScreen.getDisplay().getScreen());
// updatedDisplay.setRotation(recordingScreen.getDisplay().getRotation());
// updatedDisplay.setMonitor(recordingScreen.getDisplay().getMonitor());
// updatedDisplay.setInverted(recordingScreen.getDisplay().isInverted());
//
// RecordingScreen updatedScreen = new RecordingScreen();
// updatedScreen.setScreen(VPinScreen.DMD);
// updatedScreen.setDisplay(updatedDisplay);
// updated.add(updatedScreen);
// continue;
// }

updated.add(recordingScreen);
}
return updated;
}
}
Loading

0 comments on commit 9d25efd

Please sign in to comment.