mirror of
https://github.com/2OOP/pism.git
synced 2026-02-04 10:54:51 +00:00
Merge remote-tracking branch 'refs/remotes/origin/Development' into UI
# Conflicts: # app/src/main/java/org/toop/app/App.java # framework/src/main/java/org/toop/framework/asset/AssetLoader.java # framework/src/main/java/org/toop/framework/asset/AssetManager.java
This commit is contained in:
@@ -10,10 +10,11 @@ import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import org.toop.framework.asset.AssetManager;
|
||||
import org.toop.framework.asset.resources.LocalizationAsset;
|
||||
import org.toop.framework.audio.events.AudioEvents;
|
||||
import org.toop.framework.eventbus.EventFlow;
|
||||
import org.toop.local.AppContext;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class App extends Application {
|
||||
private static Stage stage;
|
||||
@@ -49,6 +50,9 @@ public class App extends Application {
|
||||
App.stage = stage;
|
||||
App.scene = scene;
|
||||
App.root = root;
|
||||
|
||||
new EventFlow().addPostEvent(new AudioEvents.StartBackgroundMusic()).postEvent();
|
||||
new EventFlow().addPostEvent(new AudioEvents.ChangeVolume(0.3)).postEvent();
|
||||
}
|
||||
|
||||
public static void activate(Menu menu) {
|
||||
|
||||
BIN
app/src/main/resources/assets/audio/music/damned.mp3
Normal file
BIN
app/src/main/resources/assets/audio/music/damned.mp3
Normal file
Binary file not shown.
BIN
app/src/main/resources/assets/audio/music/extraction-point.mp3
Normal file
BIN
app/src/main/resources/assets/audio/music/extraction-point.mp3
Normal file
Binary file not shown.
BIN
app/src/main/resources/assets/audio/music/godfrey.mp3
Normal file
BIN
app/src/main/resources/assets/audio/music/godfrey.mp3
Normal file
Binary file not shown.
BIN
app/src/main/resources/assets/audio/music/mw2-main-menu.mp3
Normal file
BIN
app/src/main/resources/assets/audio/music/mw2-main-menu.mp3
Normal file
Binary file not shown.
@@ -102,6 +102,14 @@
|
||||
<version>25</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JavaFX Media -->
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-media</artifactId>
|
||||
<version>25</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.reflections/reflections -->
|
||||
<dependency>
|
||||
<groupId>org.reflections</groupId>
|
||||
@@ -122,24 +130,6 @@
|
||||
<target>25</target>
|
||||
<release>25</release>
|
||||
<encoding>UTF-8</encoding>
|
||||
<!-- <compilerArgs>-->
|
||||
<!-- <arg>-XDcompilePolicy=simple</arg>-->
|
||||
<!-- <arg>--should-stop=ifError=FLOW</arg>-->
|
||||
<!-- <arg>-Xplugin:ErrorProne</arg>-->
|
||||
<!-- </compilerArgs>-->
|
||||
<!-- <annotationProcessorPaths>-->
|
||||
<!-- <path>-->
|
||||
<!-- <groupId>com.google.errorprone</groupId>-->
|
||||
<!-- <artifactId>error_prone_core</artifactId>-->
|
||||
<!-- <version>2.42.0</version>-->
|
||||
<!-- </path>-->
|
||||
<!-- <!– Other annotation processors go here.-->
|
||||
|
||||
<!-- If 'annotationProcessorPaths' is set, processors will no longer be-->
|
||||
<!-- discovered on the regular -classpath; see also 'Using Error Prone-->
|
||||
<!-- together with other annotation processors' below. –>-->
|
||||
<!-- </annotationProcessorPaths>-->
|
||||
<!-- <fork>true</fork>-->
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
|
||||
@@ -60,7 +60,23 @@ public class AssetLoader {
|
||||
List<File> foundFiles = new ArrayList<>();
|
||||
fileSearcher(rootFolder, foundFiles);
|
||||
this.totalCount = foundFiles.size();
|
||||
|
||||
// measure memory before loading
|
||||
long before = getUsedMemory();
|
||||
|
||||
loader(foundFiles);
|
||||
|
||||
// ~measure memory after loading
|
||||
long after = getUsedMemory();
|
||||
long used = after - before;
|
||||
|
||||
logger.info("Total files loaded: {}", this.totalCount);
|
||||
logger.info("Memory used by assets: ~{} MB", used / (1024 * 1024));
|
||||
}
|
||||
|
||||
private static long getUsedMemory() {
|
||||
Runtime runtime = Runtime.getRuntime();
|
||||
return runtime.totalMemory() - runtime.freeMemory();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,6 +144,7 @@ public class AssetLoader {
|
||||
"File " + file.getName() + " is not of type " + type.getSimpleName()
|
||||
);
|
||||
}
|
||||
|
||||
return type.cast(resource);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.toop.framework.asset.resources;
|
||||
|
||||
import javafx.scene.media.Media;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
@FileExtension({"mp3"})
|
||||
public class MusicAsset extends BaseResource implements LoadableResource {
|
||||
private Media media;
|
||||
|
||||
public MusicAsset(final File audioFile) {
|
||||
super(audioFile);
|
||||
}
|
||||
|
||||
public Media getMedia() {
|
||||
if (media == null) {
|
||||
media = new Media(file.toURI().toString());
|
||||
}
|
||||
return media;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
if (media == null) media = new Media(file.toURI().toString());
|
||||
this.isLoaded = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
media = null;
|
||||
isLoaded = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoaded() {
|
||||
return isLoaded;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
package org.toop.framework.asset.resources;
|
||||
|
||||
import javafx.scene.media.Media;
|
||||
|
||||
import javax.sound.sampled.*;
|
||||
import java.io.*;
|
||||
import java.net.URI;
|
||||
|
||||
@FileExtension({"wav"})
|
||||
public class AudioAsset extends BaseResource implements LoadableResource {
|
||||
public class SoundEffectAsset extends BaseResource implements LoadableResource {
|
||||
|
||||
public AudioAsset(final File audioFile) {
|
||||
public SoundEffectAsset(final File audioFile) {
|
||||
super(audioFile);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package org.toop.framework.audio;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.media.MediaPlayer;
|
||||
import org.toop.framework.SnowflakeGenerator;
|
||||
import org.toop.framework.asset.Asset;
|
||||
import org.toop.framework.asset.AssetManager;
|
||||
import org.toop.framework.asset.resources.AudioAsset;
|
||||
import org.toop.framework.asset.resources.MusicAsset;
|
||||
import org.toop.framework.asset.resources.SoundEffectAsset;
|
||||
import org.toop.framework.audio.events.AudioEvents;
|
||||
import org.toop.framework.eventbus.EventFlow;
|
||||
|
||||
@@ -12,13 +15,17 @@ import java.util.*;
|
||||
import javax.sound.sampled.*;
|
||||
|
||||
public class SoundManager {
|
||||
private final Map<Long, Clip> activeClips = new HashMap<>();
|
||||
private final HashMap<String, AudioAsset> audioResources = new HashMap<>();
|
||||
private final List<MediaPlayer> activeMusic = new ArrayList<>();
|
||||
private final Queue<MusicAsset> backgroundMusicQueue = new LinkedList<>();
|
||||
private final Map<Long, Clip> activeSoundEffects = new HashMap<>();
|
||||
private final HashMap<String, SoundEffectAsset> audioResources = new HashMap<>();
|
||||
private final SnowflakeGenerator idGenerator = new SnowflakeGenerator(); // TODO: Don't create a new generator
|
||||
|
||||
private double volume = 1.0;
|
||||
|
||||
public SoundManager() {
|
||||
// Get all Audio Resources and add them to a list.
|
||||
for (Asset<AudioAsset> asset : AssetManager.getAllOfType(AudioAsset.class)) {
|
||||
for (Asset<SoundEffectAsset> asset : AssetManager.getAllOfType(SoundEffectAsset.class)) {
|
||||
try {
|
||||
this.addAudioResource(asset);
|
||||
} catch (IOException | LineUnavailableException | UnsupportedAudioFileException e) {
|
||||
@@ -27,12 +34,21 @@ public class SoundManager {
|
||||
}
|
||||
new EventFlow()
|
||||
.listen(this::handlePlaySound)
|
||||
.listen(this::handleStopSound);
|
||||
.listen(this::handleStopSound)
|
||||
.listen(this::handleMusicStart)
|
||||
.listen(this::handleVolumeChange)
|
||||
.listen(AudioEvents.playOnClickButton.class, _ -> {
|
||||
try {
|
||||
playSound("hitsound0.wav", false);
|
||||
} catch (UnsupportedAudioFileException | LineUnavailableException | IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void handlePlaySound(AudioEvents.PlayAudio event) {
|
||||
try {
|
||||
this.playSound(event.fileNameNoExtensionAndNoDirectory(), event.loop());
|
||||
this.playSound(event.fileName(), event.loop());
|
||||
} catch (UnsupportedAudioFileException | LineUnavailableException | IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -42,14 +58,70 @@ public class SoundManager {
|
||||
this.stopSound(event.clipId());
|
||||
}
|
||||
|
||||
private void addAudioResource(Asset<AudioAsset> audioAsset)
|
||||
private void addAudioResource(Asset<SoundEffectAsset> audioAsset)
|
||||
throws IOException, UnsupportedAudioFileException, LineUnavailableException {
|
||||
|
||||
this.audioResources.put(audioAsset.getName(), audioAsset.getResource());
|
||||
}
|
||||
|
||||
private void handleVolumeChange(AudioEvents.ChangeVolume event) {
|
||||
if (event.newVolume() > 1.0) this.volume = 1.0;
|
||||
else this.volume = Math.max(event.newVolume(), 0.0);
|
||||
for (MediaPlayer mediaPlayer : this.activeMusic) {
|
||||
mediaPlayer.setVolume(this.volume);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleMusicStart(AudioEvents.StartBackgroundMusic e) {
|
||||
backgroundMusicQueue.clear();
|
||||
Platform.runLater(() -> {
|
||||
backgroundMusicQueue.addAll(
|
||||
AssetManager.getAllOfType(MusicAsset.class).stream()
|
||||
.map(Asset::getResource)
|
||||
.toList()
|
||||
);
|
||||
backgroundMusicPlayer();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void addBackgroundMusic(MusicAsset musicAsset) {
|
||||
backgroundMusicQueue.add(musicAsset);
|
||||
}
|
||||
|
||||
private void backgroundMusicPlayer() {
|
||||
MusicAsset ma = backgroundMusicQueue.poll();
|
||||
if (ma == null) return;
|
||||
|
||||
MediaPlayer mediaPlayer = new MediaPlayer(ma.getMedia());
|
||||
|
||||
mediaPlayer.setOnEndOfMedia(() -> {
|
||||
addBackgroundMusic(ma);
|
||||
activeMusic.remove(mediaPlayer);
|
||||
mediaPlayer.dispose();
|
||||
ma.unload();
|
||||
backgroundMusicPlayer(); // play next
|
||||
});
|
||||
|
||||
mediaPlayer.setOnStopped(() -> {
|
||||
addBackgroundMusic(ma);
|
||||
activeMusic.remove(mediaPlayer);
|
||||
ma.unload();
|
||||
});
|
||||
|
||||
mediaPlayer.setOnError(() -> {
|
||||
addBackgroundMusic(ma);
|
||||
activeMusic.remove(mediaPlayer);
|
||||
ma.unload();
|
||||
});
|
||||
|
||||
mediaPlayer.setVolume(this.volume);
|
||||
mediaPlayer.play();
|
||||
activeMusic.add(mediaPlayer);
|
||||
}
|
||||
|
||||
private long playSound(String audioFileName, boolean loop) throws UnsupportedAudioFileException, LineUnavailableException, IOException {
|
||||
AudioAsset asset = audioResources.get(audioFileName);
|
||||
SoundEffectAsset asset = audioResources.get(audioFileName);
|
||||
|
||||
// Return -1 which indicates resource wasn't available
|
||||
if (asset == null){
|
||||
@@ -71,12 +143,12 @@ public class SoundManager {
|
||||
long clipId = idGenerator.nextId();
|
||||
|
||||
// store it so we can stop it later
|
||||
activeClips.put(clipId, clip); // TODO: Do on snowflake for specific sound to stop
|
||||
activeSoundEffects.put(clipId, clip); // TODO: Do on snowflake for specific sound to stop
|
||||
|
||||
// remove when finished (only for non-looping sounds)
|
||||
clip.addLineListener(event -> {
|
||||
if (event.getType() == LineEvent.Type.STOP && !clip.isRunning()) {
|
||||
activeClips.remove(clipId);
|
||||
activeSoundEffects.remove(clipId);
|
||||
clip.close();
|
||||
}
|
||||
});
|
||||
@@ -86,7 +158,7 @@ public class SoundManager {
|
||||
}
|
||||
|
||||
public void stopSound(long clipId) {
|
||||
Clip clip = activeClips.get(clipId);
|
||||
Clip clip = activeSoundEffects.get(clipId);
|
||||
|
||||
if (clip == null) {
|
||||
return;
|
||||
@@ -94,14 +166,14 @@ public class SoundManager {
|
||||
|
||||
clip.stop();
|
||||
clip.close();
|
||||
activeClips.remove(clipId);
|
||||
activeSoundEffects.remove(clipId);
|
||||
}
|
||||
|
||||
public void stopAllSounds() {
|
||||
for (Clip clip : activeClips.values()) {
|
||||
for (Clip clip : activeSoundEffects.values()) {
|
||||
clip.stop();
|
||||
clip.close();
|
||||
}
|
||||
activeClips.clear();
|
||||
activeSoundEffects.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
package org.toop.framework.audio.events;
|
||||
|
||||
import org.toop.framework.asset.resources.MusicAsset;
|
||||
import org.toop.framework.eventbus.events.EventWithoutSnowflake;
|
||||
import org.toop.framework.eventbus.events.EventsBase;
|
||||
|
||||
public class AudioEvents extends EventsBase {
|
||||
/** Starts playing a sound. */
|
||||
public record PlayAudio(String fileNameNoExtensionAndNoDirectory, boolean loop)
|
||||
public record PlayAudio(String fileName, boolean loop)
|
||||
implements EventWithoutSnowflake {}
|
||||
|
||||
public record StopAudio(long clipId) implements EventWithoutSnowflake {}
|
||||
|
||||
public record StartBackgroundMusic() implements EventWithoutSnowflake {}
|
||||
public record ChangeVolume(double newVolume) implements EventWithoutSnowflake {}
|
||||
public record playOnClickButton() implements EventWithoutSnowflake {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user