Added a crude music player and fixed a lot of OpenAL stuff
- Game will now play all Vorbis files in music/ directory (at runtime) - Random order with random pauses (15 to 60 sec) - Force start by pressing M - Added AudioRegistry for performance - Speakers now can change data correctly - Added ResourceReaders - Classpath and Filesystem for now - Added local controls. Use with ControlTriggers.localOf(...) NB: No actual music files included (yet). Place them in music/ directory of the game directory (e.g. in <project>/run/music).
This commit is contained in:
parent
9d7f69892b
commit
c49fdfa5ff
@ -32,6 +32,7 @@ import ru.windcorp.progressia.common.resource.ResourceManager;
|
|||||||
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||||
import ru.windcorp.progressia.server.ServerState;
|
import ru.windcorp.progressia.server.ServerState;
|
||||||
import ru.windcorp.progressia.test.TestContent;
|
import ru.windcorp.progressia.test.TestContent;
|
||||||
|
import ru.windcorp.progressia.test.TestMusicPlayer;
|
||||||
|
|
||||||
public class ClientProxy implements Proxy {
|
public class ClientProxy implements Proxy {
|
||||||
|
|
||||||
@ -59,6 +60,8 @@ public class ClientProxy implements Proxy {
|
|||||||
|
|
||||||
ServerState.startServer();
|
ServerState.startServer();
|
||||||
ClientState.connectToLocalServer();
|
ClientState.connectToLocalServer();
|
||||||
|
|
||||||
|
TestMusicPlayer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import ru.windcorp.progressia.client.audio.backend.AudioReader;
|
|||||||
import ru.windcorp.progressia.client.audio.backend.Listener;
|
import ru.windcorp.progressia.client.audio.backend.Listener;
|
||||||
import ru.windcorp.progressia.client.audio.backend.SoundType;
|
import ru.windcorp.progressia.client.audio.backend.SoundType;
|
||||||
import ru.windcorp.progressia.client.audio.backend.Speaker;
|
import ru.windcorp.progressia.client.audio.backend.Speaker;
|
||||||
|
import ru.windcorp.progressia.common.resource.Resource;
|
||||||
|
|
||||||
import static org.lwjgl.openal.AL11.*;
|
import static org.lwjgl.openal.AL11.*;
|
||||||
import static org.lwjgl.openal.ALC10.*;
|
import static org.lwjgl.openal.ALC10.*;
|
||||||
@ -40,7 +41,6 @@ public class AudioManager {
|
|||||||
|
|
||||||
private static List<Speaker> soundSpeakers = new ArrayList<>(SOUNDS_NUM);
|
private static List<Speaker> soundSpeakers = new ArrayList<>(SOUNDS_NUM);
|
||||||
private static Speaker musicSpeaker;
|
private static Speaker musicSpeaker;
|
||||||
private static ArrayList<SoundType> soundsBuffer = new ArrayList<>();
|
|
||||||
|
|
||||||
public static void initAL() {
|
public static void initAL() {
|
||||||
String defaultDeviceName = alcGetString(
|
String defaultDeviceName = alcGetString(
|
||||||
@ -82,18 +82,6 @@ public class AudioManager {
|
|||||||
return speaker;
|
return speaker;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SoundType findSoundType(String soundID) throws Exception {
|
|
||||||
for (SoundType s : soundsBuffer) {
|
|
||||||
if (s.getId().equals(soundID)) {
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new Exception(
|
|
||||||
"ERROR: The selected sound is not loaded or" +
|
|
||||||
" not exists"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Speaker initSpeaker(SoundType st) {
|
public static Speaker initSpeaker(SoundType st) {
|
||||||
Speaker speaker = getLastSpeaker();
|
Speaker speaker = getLastSpeaker();
|
||||||
try {
|
try {
|
||||||
@ -104,20 +92,9 @@ public class AudioManager {
|
|||||||
return speaker;
|
return speaker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SoundType getSoundType(String id) {
|
public static Speaker initMusicSpeaker(SoundType st) {
|
||||||
SoundType st;
|
|
||||||
try {
|
try {
|
||||||
st = findSoundType(id);
|
st.initSpeaker(musicSpeaker);
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
return st;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static Speaker initMusicSpeaker(String soundID) {
|
|
||||||
try {
|
|
||||||
findSoundType(soundID).initSpeaker(musicSpeaker);
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
@ -131,11 +108,11 @@ public class AudioManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void loadSound(String path, String id, AudioFormat format) {
|
public static void loadSound(Resource resource, String id, AudioFormat format) {
|
||||||
if (format == AudioFormat.MONO) {
|
if (format == AudioFormat.MONO) {
|
||||||
soundsBuffer.add(AudioReader.readAsMono(path, id));
|
AudioRegistry.getInstance().register(AudioReader.readAsMono(resource, id));
|
||||||
} else {
|
} else {
|
||||||
soundsBuffer.add(AudioReader.readAsStereo(path, id));
|
AudioRegistry.getInstance().register(AudioReader.readAsStereo(resource, id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.audio;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.audio.backend.SoundType;
|
||||||
|
import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry;
|
||||||
|
|
||||||
|
public class AudioRegistry extends NamespacedInstanceRegistry<SoundType> {
|
||||||
|
|
||||||
|
private static final AudioRegistry INSTANCE = new AudioRegistry();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the instance
|
||||||
|
*/
|
||||||
|
public static AudioRegistry getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
package ru.windcorp.progressia.client.audio;
|
package ru.windcorp.progressia.client.audio;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.resource.ResourceManager;
|
||||||
|
|
||||||
public class AudioSystem {
|
public class AudioSystem {
|
||||||
static public void initialize() {
|
static public void initialize() {
|
||||||
AudioManager.initAL();
|
AudioManager.initAL();
|
||||||
@ -28,7 +30,7 @@ public class AudioSystem {
|
|||||||
|
|
||||||
static void loadAudioData() {
|
static void loadAudioData() {
|
||||||
AudioManager.loadSound(
|
AudioManager.loadSound(
|
||||||
"assets/sounds/block_destroy_clap.ogg",
|
ResourceManager.getResource("assets/sounds/block_destroy_clap.ogg"),
|
||||||
"Progressia:BlockDestroy",
|
"Progressia:BlockDestroy",
|
||||||
AudioFormat.MONO
|
AudioFormat.MONO
|
||||||
);
|
);
|
||||||
|
@ -19,24 +19,33 @@
|
|||||||
package ru.windcorp.progressia.client.audio;
|
package ru.windcorp.progressia.client.audio;
|
||||||
|
|
||||||
import glm.vec._3.Vec3;
|
import glm.vec._3.Vec3;
|
||||||
|
import ru.windcorp.progressia.client.audio.backend.SoundType;
|
||||||
|
import ru.windcorp.progressia.client.audio.backend.Speaker;
|
||||||
|
|
||||||
public class Music
|
public class Music
|
||||||
extends Sound {
|
extends Sound {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public Music(SoundType soundType, int timeLength, float pitch, float gain) {
|
||||||
|
super(soundType, timeLength, new Vec3(), new Vec3(), pitch, gain);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Music(SoundType soundType) {
|
||||||
|
super(soundType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Music(String id, int timeLength, float pitch, float gain) {
|
||||||
|
super(id, timeLength, new Vec3(), new Vec3(), pitch, gain);
|
||||||
|
}
|
||||||
|
|
||||||
public Music(String id) {
|
public Music(String id) {
|
||||||
super(id);
|
super(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Music(
|
@Override
|
||||||
String id,
|
protected Speaker initSpeaker() {
|
||||||
Vec3 velocity,
|
return AudioManager.initMusicSpeaker(soundType);
|
||||||
float pitch,
|
|
||||||
float gain
|
|
||||||
) {
|
|
||||||
this(id);
|
|
||||||
super.velocity = velocity;
|
|
||||||
super.pitch = pitch;
|
|
||||||
super.gain = gain;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -32,8 +32,12 @@ public class Sound {
|
|||||||
|
|
||||||
protected SoundType soundType;
|
protected SoundType soundType;
|
||||||
|
|
||||||
|
public Sound(SoundType soundType) {
|
||||||
|
this.soundType = soundType;
|
||||||
|
}
|
||||||
|
|
||||||
public Sound(String id) {
|
public Sound(String id) {
|
||||||
soundType = AudioManager.getSoundType(id);
|
this(AudioRegistry.getInstance().get(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Sound(
|
public Sound(
|
||||||
@ -51,8 +55,27 @@ public class Sound {
|
|||||||
this.gain = gain;
|
this.gain = gain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Sound(
|
||||||
|
SoundType soundType,
|
||||||
|
int timeLength,
|
||||||
|
Vec3 position,
|
||||||
|
Vec3 velocity,
|
||||||
|
float pitch,
|
||||||
|
float gain
|
||||||
|
) {
|
||||||
|
this(soundType);
|
||||||
|
this.position = position;
|
||||||
|
this.velocity = velocity;
|
||||||
|
this.pitch = pitch;
|
||||||
|
this.gain = gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Speaker initSpeaker() {
|
||||||
|
return AudioManager.initSpeaker(soundType);
|
||||||
|
}
|
||||||
|
|
||||||
public void play(boolean loop) {
|
public void play(boolean loop) {
|
||||||
Speaker speaker = AudioManager.initSpeaker(soundType);
|
Speaker speaker = initSpeaker();
|
||||||
speaker.setGain(gain);
|
speaker.setGain(gain);
|
||||||
speaker.setPitch(pitch);
|
speaker.setPitch(pitch);
|
||||||
speaker.setPosition(position);
|
speaker.setPosition(position);
|
||||||
@ -97,8 +120,8 @@ public class Sound {
|
|||||||
return pitch;
|
return pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTimeLength() {
|
public double getDuration() {
|
||||||
return soundType.getTimeLength();
|
return soundType.getDuration();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -33,13 +33,11 @@ public class AudioReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO fix converting from mono-stereo
|
// TODO fix converting from mono-stereo
|
||||||
private static SoundType readAsSpecified(String path, String id, int format) {
|
private static SoundType readAsSpecified(Resource resource, String id, int format) {
|
||||||
IntBuffer channelBuffer = BufferUtils.createIntBuffer(1);
|
IntBuffer channelBuffer = BufferUtils.createIntBuffer(1);
|
||||||
IntBuffer rateBuffer = BufferUtils.createIntBuffer(1);
|
IntBuffer rateBuffer = BufferUtils.createIntBuffer(1);
|
||||||
|
|
||||||
Resource res = ResourceManager.getResource(path);
|
ShortBuffer rawAudio = decodeVorbis(resource, channelBuffer, rateBuffer);
|
||||||
|
|
||||||
ShortBuffer rawAudio = decodeVorbis(res, channelBuffer, rateBuffer);
|
|
||||||
|
|
||||||
return new SoundType(
|
return new SoundType(
|
||||||
id,
|
id,
|
||||||
@ -49,12 +47,12 @@ public class AudioReader {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SoundType readAsMono(String path, String id) {
|
public static SoundType readAsMono(Resource resource, String id) {
|
||||||
return readAsSpecified(path, id, AL_FORMAT_MONO16);
|
return readAsSpecified(resource, id, AL_FORMAT_MONO16);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SoundType readAsStereo(String path, String id) {
|
public static SoundType readAsStereo(Resource resource, String id) {
|
||||||
return readAsSpecified(path, id, AL_FORMAT_STEREO16);
|
return readAsSpecified(resource, id, AL_FORMAT_STEREO16);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShortBuffer decodeVorbis(
|
private static ShortBuffer decodeVorbis(
|
||||||
|
@ -21,6 +21,9 @@ package ru.windcorp.progressia.client.audio.backend;
|
|||||||
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
|
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
|
||||||
|
|
||||||
import java.nio.ShortBuffer;
|
import java.nio.ShortBuffer;
|
||||||
|
|
||||||
|
import org.lwjgl.openal.AL10;
|
||||||
|
|
||||||
import static org.lwjgl.openal.AL11.*;
|
import static org.lwjgl.openal.AL11.*;
|
||||||
|
|
||||||
public class SoundType extends Namespaced {
|
public class SoundType extends Namespaced {
|
||||||
@ -29,7 +32,7 @@ public class SoundType extends Namespaced {
|
|||||||
private int sampleRate;
|
private int sampleRate;
|
||||||
private int format;
|
private int format;
|
||||||
private int audioBuffer;
|
private int audioBuffer;
|
||||||
private int timeLength;
|
private double duration;
|
||||||
|
|
||||||
public SoundType(
|
public SoundType(
|
||||||
String id,
|
String id,
|
||||||
@ -47,14 +50,14 @@ public class SoundType extends Namespaced {
|
|||||||
private void createAudioBuffer() {
|
private void createAudioBuffer() {
|
||||||
this.audioBuffer = alGenBuffers();
|
this.audioBuffer = alGenBuffers();
|
||||||
alBufferData(audioBuffer, format, rawAudio, sampleRate);
|
alBufferData(audioBuffer, format, rawAudio, sampleRate);
|
||||||
timeLength = rawAudio.limit() / sampleRate;
|
duration = rawAudio.limit() / (double) sampleRate / (format == AL10.AL_FORMAT_STEREO16 ? 2 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initSpeaker(Speaker speaker) {
|
public void initSpeaker(Speaker speaker) {
|
||||||
speaker.setAudioData(audioBuffer);
|
speaker.setAudioData(audioBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTimeLength() {
|
public double getDuration() {
|
||||||
return timeLength;
|
return duration;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -120,6 +120,7 @@ public class Speaker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setAudioData(int audioData) {
|
public void setAudioData(int audioData) {
|
||||||
|
stop();
|
||||||
this.audioData = audioData;
|
this.audioData = audioData;
|
||||||
alSourcei(this.sourceData, AL_BUFFER, audioData);
|
alSourcei(this.sourceData, AL_BUFFER, audioData);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ru.windcorp.progressia.client.comms.controls;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||||
|
import ru.windcorp.progressia.common.comms.controls.PacketControl;
|
||||||
|
|
||||||
|
public class ControlTriggerLocalLambda extends ControlTriggerInputBased {
|
||||||
|
|
||||||
|
private final Predicate<InputEvent> predicate;
|
||||||
|
private final Consumer<InputEvent> action;
|
||||||
|
|
||||||
|
public ControlTriggerLocalLambda(
|
||||||
|
String id,
|
||||||
|
Predicate<InputEvent> predicate,
|
||||||
|
Consumer<InputEvent> action
|
||||||
|
) {
|
||||||
|
super(id);
|
||||||
|
|
||||||
|
this.predicate = predicate;
|
||||||
|
this.action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PacketControl onInputEvent(InputEvent event) {
|
||||||
|
if (!predicate.test(event))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
action.accept(event);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -143,6 +143,96 @@ public class ControlTriggers {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
///
|
||||||
|
///
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
public static ControlTriggerInputBased localOf(
|
||||||
|
String id,
|
||||||
|
Consumer<InputEvent> action,
|
||||||
|
Predicate<InputEvent> predicate
|
||||||
|
) {
|
||||||
|
return new ControlTriggerLocalLambda(id, predicate, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ControlTriggerInputBased localOf(
|
||||||
|
String id,
|
||||||
|
Runnable action,
|
||||||
|
Predicate<InputEvent> predicate
|
||||||
|
) {
|
||||||
|
return localOf(
|
||||||
|
id,
|
||||||
|
input -> action.run(),
|
||||||
|
predicate
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
|
public static <I extends InputEvent> ControlTriggerInputBased localOf(
|
||||||
|
String id,
|
||||||
|
Class<I> inputType,
|
||||||
|
Consumer<I> action,
|
||||||
|
Predicate<I>... predicates
|
||||||
|
) {
|
||||||
|
return localOf(
|
||||||
|
id,
|
||||||
|
createCheckedAction(inputType, action),
|
||||||
|
createCheckedCompoundPredicate(inputType, predicates)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
|
public static <I extends InputEvent> ControlTriggerInputBased localOf(
|
||||||
|
String id,
|
||||||
|
Class<I> inputType,
|
||||||
|
Runnable action,
|
||||||
|
Predicate<I>... predicates
|
||||||
|
) {
|
||||||
|
return localOf(
|
||||||
|
id,
|
||||||
|
inputType,
|
||||||
|
input -> action.run(),
|
||||||
|
predicates
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
|
public static ControlTriggerInputBased localOf(
|
||||||
|
String id,
|
||||||
|
Consumer<InputEvent> action,
|
||||||
|
Predicate<InputEvent>... predicates
|
||||||
|
) {
|
||||||
|
return localOf(
|
||||||
|
id,
|
||||||
|
InputEvent.class,
|
||||||
|
action,
|
||||||
|
predicates
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
|
public static <I extends InputEvent> ControlTriggerInputBased localOf(
|
||||||
|
String id,
|
||||||
|
Runnable action,
|
||||||
|
Predicate<InputEvent>... predicates
|
||||||
|
) {
|
||||||
|
return of(
|
||||||
|
id,
|
||||||
|
input -> action.run(),
|
||||||
|
predicates
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private static <I extends InputEvent> BiConsumer<InputEvent, ControlData> createCheckedDataWriter(
|
private static <I extends InputEvent> BiConsumer<InputEvent, ControlData> createCheckedDataWriter(
|
||||||
Class<I> inputType,
|
Class<I> inputType,
|
||||||
BiConsumer<I, ControlData> dataWriter
|
BiConsumer<I, ControlData> dataWriter
|
||||||
@ -150,6 +240,13 @@ public class ControlTriggers {
|
|||||||
return (inputEvent, control) -> dataWriter.accept(inputType.cast(inputEvent), control);
|
return (inputEvent, control) -> dataWriter.accept(inputType.cast(inputEvent), control);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static <I extends InputEvent> Consumer<InputEvent> createCheckedAction(
|
||||||
|
Class<I> inputType,
|
||||||
|
Consumer<I> action
|
||||||
|
) {
|
||||||
|
return inputEvent -> action.accept(inputType.cast(inputEvent));
|
||||||
|
}
|
||||||
|
|
||||||
private static <I extends InputEvent> Predicate<InputEvent> createCheckedCompoundPredicate(
|
private static <I extends InputEvent> Predicate<InputEvent> createCheckedCompoundPredicate(
|
||||||
Class<I> inputType,
|
Class<I> inputType,
|
||||||
Predicate<I>[] predicates
|
Predicate<I>[] predicates
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.resource;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.Progressia;
|
||||||
|
|
||||||
|
public class ClasspathResourceReader implements ResourceReader {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream read(String name) {
|
||||||
|
return Progressia.class.getClassLoader().getResourceAsStream(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.resource;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
public class FilesystemResourceReader implements ResourceReader {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream read(String name) {
|
||||||
|
try {
|
||||||
|
return Files.newInputStream(Paths.get(name));
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -30,19 +30,24 @@ import org.lwjgl.BufferUtils;
|
|||||||
import com.google.common.io.ByteStreams;
|
import com.google.common.io.ByteStreams;
|
||||||
import com.google.common.io.CharStreams;
|
import com.google.common.io.CharStreams;
|
||||||
|
|
||||||
import ru.windcorp.progressia.Progressia;
|
|
||||||
import ru.windcorp.progressia.common.util.Named;
|
import ru.windcorp.progressia.common.util.Named;
|
||||||
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||||
|
|
||||||
public class Resource extends Named {
|
public class Resource extends Named {
|
||||||
|
|
||||||
public Resource(String name) {
|
private final ResourceReader resourceReader;
|
||||||
|
|
||||||
|
public Resource(String name, ResourceReader resourceReader) {
|
||||||
super(name);
|
super(name);
|
||||||
|
this.resourceReader = resourceReader;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputStream getInputStream() {
|
public InputStream getInputStream() {
|
||||||
// TODO Do proper resource lookup
|
return getResourceReader().read(getName());
|
||||||
return Progressia.class.getClassLoader().getResourceAsStream(getName());
|
}
|
||||||
|
|
||||||
|
public ResourceReader getResourceReader() {
|
||||||
|
return resourceReader;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Reader getReader() {
|
public Reader getReader() {
|
||||||
|
@ -20,8 +20,15 @@ package ru.windcorp.progressia.common.resource;
|
|||||||
|
|
||||||
public class ResourceManager {
|
public class ResourceManager {
|
||||||
|
|
||||||
|
private static final ResourceReader CLASSPATH_READER = new ClasspathResourceReader();
|
||||||
|
private static final ResourceReader FILESYSTEM_READER = new FilesystemResourceReader();
|
||||||
|
|
||||||
public static Resource getResource(String name) {
|
public static Resource getResource(String name) {
|
||||||
return new Resource(name);
|
return new Resource(name, CLASSPATH_READER);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Resource getFileResource(String name) {
|
||||||
|
return new Resource(name, FILESYSTEM_READER);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Resource getTextureResource(String name) {
|
public static Resource getTextureResource(String name) {
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.resource;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public interface ResourceReader {
|
||||||
|
|
||||||
|
InputStream read(String name);
|
||||||
|
|
||||||
|
}
|
@ -287,6 +287,15 @@ public class TestContent {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
logic.register(ControlLogic.of("Test:PlaceTile", TestContent::onTilePlaceReceived));
|
logic.register(ControlLogic.of("Test:PlaceTile", TestContent::onTilePlaceReceived));
|
||||||
|
|
||||||
|
triggers.register(
|
||||||
|
ControlTriggers.localOf(
|
||||||
|
"Test:StartNextMusic",
|
||||||
|
KeyEvent.class,
|
||||||
|
TestMusicPlayer::startNextNow,
|
||||||
|
KeyMatcher.of(GLFW.GLFW_KEY_M).matcher()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void register(BlockData x) {
|
private static void register(BlockData x) {
|
||||||
|
152
src/main/java/ru/windcorp/progressia/test/TestMusicPlayer.java
Normal file
152
src/main/java/ru/windcorp/progressia/test/TestMusicPlayer.java
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.audio.AudioFormat;
|
||||||
|
import ru.windcorp.progressia.client.audio.AudioManager;
|
||||||
|
import ru.windcorp.progressia.client.audio.AudioRegistry;
|
||||||
|
import ru.windcorp.progressia.client.audio.Music;
|
||||||
|
import ru.windcorp.progressia.client.audio.Sound;
|
||||||
|
import ru.windcorp.progressia.client.audio.backend.SoundType;
|
||||||
|
import ru.windcorp.progressia.common.resource.ResourceManager;
|
||||||
|
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||||
|
|
||||||
|
public class TestMusicPlayer implements Runnable {
|
||||||
|
|
||||||
|
private static final int MIN_SILENCE = 15 * 1000; // 15 seconds
|
||||||
|
private static final int MAX_SILENCE = 60 * 1000; // one minute
|
||||||
|
|
||||||
|
private static TestMusicPlayer instance = null;
|
||||||
|
|
||||||
|
private final List<SoundType> compositions = new ArrayList<>();
|
||||||
|
|
||||||
|
private final Random random = new Random();
|
||||||
|
private long nextStart;
|
||||||
|
private Sound lastStarted = null;
|
||||||
|
|
||||||
|
public TestMusicPlayer() {
|
||||||
|
this.nextStart = System.currentTimeMillis();
|
||||||
|
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void start() {
|
||||||
|
Thread thread = new Thread(new TestMusicPlayer(), "Music Thread");
|
||||||
|
thread.setDaemon(true);
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
loadCompositions();
|
||||||
|
|
||||||
|
if (compositions.isEmpty()) {
|
||||||
|
LogManager.getLogger().warn("No music found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
synchronized (this) {
|
||||||
|
while (true) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
if (nextStart > now) {
|
||||||
|
wait(nextStart - now);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
LogManager.getLogger().warn("Received interrupt in music thread, terminating thread...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
startNextComposition();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadCompositions() {
|
||||||
|
try {
|
||||||
|
|
||||||
|
Path directory = Paths.get("music");
|
||||||
|
|
||||||
|
if (!Files.isDirectory(directory)) {
|
||||||
|
Files.createDirectories(directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator<Path> it = Files.walk(directory).filter(Files::isRegularFile).iterator();
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (it.hasNext()) {
|
||||||
|
String file = it.next().toString();
|
||||||
|
if (!file.endsWith(".ogg") && !file.endsWith(".oga")) {
|
||||||
|
LogManager.getLogger().warn("Skipping " + file + ": not .ogg nor .oga");
|
||||||
|
}
|
||||||
|
|
||||||
|
String id = "Progressia:Music" + (i++);
|
||||||
|
|
||||||
|
AudioManager.loadSound(ResourceManager.getFileResource(file.toString()), id, AudioFormat.STEREO);
|
||||||
|
SoundType composition = AudioRegistry.getInstance().get(id);
|
||||||
|
compositions.add(composition);
|
||||||
|
|
||||||
|
LogManager.getLogger().info("Loaded " + file);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw CrashReports.report(e, "Could not load music");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void startNextComposition() {
|
||||||
|
int index = random.nextInt(compositions.size());
|
||||||
|
SoundType composition = compositions.get(index);
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
long durationInMs = (long) (composition.getDuration() * 1000);
|
||||||
|
long silence = random.nextInt(MAX_SILENCE - MIN_SILENCE) + MIN_SILENCE;
|
||||||
|
|
||||||
|
nextStart = now + durationInMs + silence;
|
||||||
|
|
||||||
|
lastStarted = new Music(composition);
|
||||||
|
lastStarted.play(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void startNextNow() {
|
||||||
|
if (instance == null) return;
|
||||||
|
|
||||||
|
synchronized (instance) {
|
||||||
|
instance.nextStart = System.currentTimeMillis();
|
||||||
|
instance.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user