diff --git a/assets/Audio/movement/surface/dirt/Bare Step Gravel Hard A.wav b/assets/Audio/movement/surface/dirt/Bare Step Gravel Hard A.wav new file mode 100644 index 00000000..877da448 Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Bare Step Gravel Hard A.wav differ diff --git a/assets/Audio/movement/surface/dirt/Bare Step Gravel Hard B.wav b/assets/Audio/movement/surface/dirt/Bare Step Gravel Hard B.wav new file mode 100644 index 00000000..dc1320a4 Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Bare Step Gravel Hard B.wav differ diff --git a/assets/Audio/movement/surface/dirt/Bare Step Gravel Hard C.wav b/assets/Audio/movement/surface/dirt/Bare Step Gravel Hard C.wav new file mode 100644 index 00000000..e5ad201f Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Bare Step Gravel Hard C.wav differ diff --git a/assets/Audio/movement/surface/dirt/Bare Step Gravel Hard D.wav b/assets/Audio/movement/surface/dirt/Bare Step Gravel Hard D.wav new file mode 100644 index 00000000..e89b876c Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Bare Step Gravel Hard D.wav differ diff --git a/assets/Audio/movement/surface/dirt/Bare Step Gravel Hard E.wav b/assets/Audio/movement/surface/dirt/Bare Step Gravel Hard E.wav new file mode 100644 index 00000000..bcbde1a5 Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Bare Step Gravel Hard E.wav differ diff --git a/assets/Audio/movement/surface/dirt/Bare Step Gravel Medium A.wav b/assets/Audio/movement/surface/dirt/Bare Step Gravel Medium A.wav new file mode 100644 index 00000000..d9e167e2 Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Bare Step Gravel Medium A.wav differ diff --git a/assets/Audio/movement/surface/dirt/Bare Step Gravel Medium B.wav b/assets/Audio/movement/surface/dirt/Bare Step Gravel Medium B.wav new file mode 100644 index 00000000..ff5db1c4 Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Bare Step Gravel Medium B.wav differ diff --git a/assets/Audio/movement/surface/dirt/Bare Step Gravel Medium C.wav b/assets/Audio/movement/surface/dirt/Bare Step Gravel Medium C.wav new file mode 100644 index 00000000..a689a04f Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Bare Step Gravel Medium C.wav differ diff --git a/assets/Audio/movement/surface/dirt/Bare Step Gravel Medium D.wav b/assets/Audio/movement/surface/dirt/Bare Step Gravel Medium D.wav new file mode 100644 index 00000000..a6605095 Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Bare Step Gravel Medium D.wav differ diff --git a/assets/Audio/movement/surface/dirt/Bare Step Gravel Medium E.wav b/assets/Audio/movement/surface/dirt/Bare Step Gravel Medium E.wav new file mode 100644 index 00000000..fddcb1dd Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Bare Step Gravel Medium E.wav differ diff --git a/assets/Audio/movement/surface/dirt/Jump Step Gravel A.wav b/assets/Audio/movement/surface/dirt/Jump Step Gravel A.wav new file mode 100644 index 00000000..7289c736 Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Jump Step Gravel A.wav differ diff --git a/assets/Audio/movement/surface/dirt/Jump Step Gravel B.wav b/assets/Audio/movement/surface/dirt/Jump Step Gravel B.wav new file mode 100644 index 00000000..04fcf173 Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Jump Step Gravel B.wav differ diff --git a/assets/Audio/movement/surface/dirt/Land Step Gravel A.wav b/assets/Audio/movement/surface/dirt/Land Step Gravel A.wav new file mode 100644 index 00000000..d17a4e04 Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Land Step Gravel A.wav differ diff --git a/assets/Audio/movement/surface/dirt/Land Step Gravel B.wav b/assets/Audio/movement/surface/dirt/Land Step Gravel B.wav new file mode 100644 index 00000000..466b1c74 Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Land Step Gravel B.wav differ diff --git a/assets/Audio/movement/surface/dirt/Shoe Step Gravel Hard A.wav b/assets/Audio/movement/surface/dirt/Shoe Step Gravel Hard A.wav new file mode 100644 index 00000000..9c9761df Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Shoe Step Gravel Hard A.wav differ diff --git a/assets/Audio/movement/surface/dirt/Shoe Step Gravel Hard B.wav b/assets/Audio/movement/surface/dirt/Shoe Step Gravel Hard B.wav new file mode 100644 index 00000000..abb61dfc Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Shoe Step Gravel Hard B.wav differ diff --git a/assets/Audio/movement/surface/dirt/Shoe Step Gravel Hard C.wav b/assets/Audio/movement/surface/dirt/Shoe Step Gravel Hard C.wav new file mode 100644 index 00000000..d27d4a08 Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Shoe Step Gravel Hard C.wav differ diff --git a/assets/Audio/movement/surface/dirt/Shoe Step Gravel Hard D.wav b/assets/Audio/movement/surface/dirt/Shoe Step Gravel Hard D.wav new file mode 100644 index 00000000..3e9f67f0 Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Shoe Step Gravel Hard D.wav differ diff --git a/assets/Audio/movement/surface/dirt/Shoe Step Gravel Hard E.wav b/assets/Audio/movement/surface/dirt/Shoe Step Gravel Hard E.wav new file mode 100644 index 00000000..20070b9b Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Shoe Step Gravel Hard E.wav differ diff --git a/assets/Audio/movement/surface/dirt/Shoe Step Gravel Medium A.wav b/assets/Audio/movement/surface/dirt/Shoe Step Gravel Medium A.wav new file mode 100644 index 00000000..8078195a Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Shoe Step Gravel Medium A.wav differ diff --git a/assets/Audio/movement/surface/dirt/Shoe Step Gravel Medium B.wav b/assets/Audio/movement/surface/dirt/Shoe Step Gravel Medium B.wav new file mode 100644 index 00000000..53615de2 Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Shoe Step Gravel Medium B.wav differ diff --git a/assets/Audio/movement/surface/dirt/Shoe Step Gravel Medium C.wav b/assets/Audio/movement/surface/dirt/Shoe Step Gravel Medium C.wav new file mode 100644 index 00000000..0b66706f Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Shoe Step Gravel Medium C.wav differ diff --git a/assets/Audio/movement/surface/dirt/Shoe Step Gravel Medium D.wav b/assets/Audio/movement/surface/dirt/Shoe Step Gravel Medium D.wav new file mode 100644 index 00000000..f7c7737e Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Shoe Step Gravel Medium D.wav differ diff --git a/assets/Audio/movement/surface/dirt/Shoe Step Gravel Medium E.wav b/assets/Audio/movement/surface/dirt/Shoe Step Gravel Medium E.wav new file mode 100644 index 00000000..a0004212 Binary files /dev/null and b/assets/Audio/movement/surface/dirt/Shoe Step Gravel Medium E.wav differ diff --git a/assets/Data/audio/surface.json b/assets/Data/audio/surface.json new file mode 100644 index 00000000..8996a41e --- /dev/null +++ b/assets/Data/audio/surface.json @@ -0,0 +1,87 @@ +{ + "ignoredVoxelTypes" : [ + 0 + ], + "defaultSurfaceAudio" : { + "voxelTypeIds" : [ + 1 + ], + "footstepRegularBareAudioPaths" : [ + "Audio/movement/surface/dirt/Bare Step Gravel Medium A.wav", + "Audio/movement/surface/dirt/Bare Step Gravel Medium B.wav", + "Audio/movement/surface/dirt/Bare Step Gravel Medium C.wav", + "Audio/movement/surface/dirt/Bare Step Gravel Medium D.wav", + "Audio/movement/surface/dirt/Bare Step Gravel Medium E.wav" + ], + "footstepHeavyBareAudioPaths" : [ + "Audio/movement/surface/dirt/Bare Step Gravel Hard A.wav", + "Audio/movement/surface/dirt/Bare Step Gravel Hard B.wav", + "Audio/movement/surface/dirt/Bare Step Gravel Hard C.wav", + "Audio/movement/surface/dirt/Bare Step Gravel Hard D.wav", + "Audio/movement/surface/dirt/Bare Step Gravel Hard E.wav" + ], + "footstepRegularShoeAudioPaths" : [ + "Audio/movement/surface/dirt/Shoe Step Gravel Medium A.wav", + "Audio/movement/surface/dirt/Shoe Step Gravel Medium B.wav", + "Audio/movement/surface/dirt/Shoe Step Gravel Medium C.wav", + "Audio/movement/surface/dirt/Shoe Step Gravel Medium D.wav", + "Audio/movement/surface/dirt/Shoe Step Gravel Medium E.wav" + ], + "footstepHeavyShoeAudioPaths" : [ + "Audio/movement/surface/dirt/Shoe Step Gravel Hard A.wav", + "Audio/movement/surface/dirt/Shoe Step Gravel Hard B.wav", + "Audio/movement/surface/dirt/Shoe Step Gravel Hard C.wav", + "Audio/movement/surface/dirt/Shoe Step Gravel Hard D.wav", + "Audio/movement/surface/dirt/Shoe Step Gravel Hard E.wav" + ], + "jumpAudioPaths" : [ + "Audio/movement/surface/dirt/Jump Step Gravel A.wav", + "Audio/movement/surface/dirt/Jump Step Gravel B.wav" + ], + "landAudioPaths" : [ + "Audio/movement/surface/dirt/Land Step Gravel A.wav", + "Audio/movement/surface/dirt/Land Step Gravel B.wav" + ] + }, + "surfaceAudio" : [ + { + "voxelTypeIds" : [1], + "footstepRegularBareAudioPaths" : [ + "Audio/movement/surface/dirt/Bare Step Gravel Medium A.wav", + "Audio/movement/surface/dirt/Bare Step Gravel Medium B.wav", + "Audio/movement/surface/dirt/Bare Step Gravel Medium C.wav", + "Audio/movement/surface/dirt/Bare Step Gravel Medium D.wav", + "Audio/movement/surface/dirt/Bare Step Gravel Medium E.wav" + ], + "footstepHeavyBareAudioPaths" : [ + "Audio/movement/surface/dirt/Bare Step Gravel Hard A.wav", + "Audio/movement/surface/dirt/Bare Step Gravel Hard B.wav", + "Audio/movement/surface/dirt/Bare Step Gravel Hard C.wav", + "Audio/movement/surface/dirt/Bare Step Gravel Hard D.wav", + "Audio/movement/surface/dirt/Bare Step Gravel Hard E.wav" + ], + "footstepRegularShoeAudioPaths" : [ + "Audio/movement/surface/dirt/Shoe Step Gravel Medium A.wav", + "Audio/movement/surface/dirt/Shoe Step Gravel Medium B.wav", + "Audio/movement/surface/dirt/Shoe Step Gravel Medium C.wav", + "Audio/movement/surface/dirt/Shoe Step Gravel Medium D.wav", + "Audio/movement/surface/dirt/Shoe Step Gravel Medium E.wav" + ], + "footstepHeavyShoeAudioPaths" : [ + "Audio/movement/surface/dirt/Shoe Step Gravel Hard A.wav", + "Audio/movement/surface/dirt/Shoe Step Gravel Hard B.wav", + "Audio/movement/surface/dirt/Shoe Step Gravel Hard C.wav", + "Audio/movement/surface/dirt/Shoe Step Gravel Hard D.wav", + "Audio/movement/surface/dirt/Shoe Step Gravel Hard E.wav" + ], + "jumpAudioPaths" : [ + "Audio/movement/surface/dirt/Jump Step Gravel A.wav", + "Audio/movement/surface/dirt/Jump Step Gravel B.wav" + ], + "landAudioPaths" : [ + "Audio/movement/surface/dirt/Land Step Gravel A.wav", + "Audio/movement/surface/dirt/Land Step Gravel B.wav" + ] + } + ] +} \ No newline at end of file diff --git a/assets/Data/creatures/human.json b/assets/Data/creatures/human.json index 0c6ddfef..33a6b7d0 100644 --- a/assets/Data/creatures/human.json +++ b/assets/Data/creatures/human.json @@ -131,6 +131,8 @@ "maxVelocity" : 500.5, "strafeMultiplier" : 0.7, "backpedalMultiplier" : 0.5, + "footstepFirstAudioOffset" : 0.2, + "footstepSecondAudioOffset" : 0.6, "animationStartup" : { "nameThirdPerson" : "Jog", "priorityCategory" : "CORE_MOVEMENT" @@ -180,9 +182,6 @@ "nameThirdPerson" : "Land", "nameFirstPerson" : "Land", "priorityCategory" : "MOVEMENT_MODIFIER" - }, - "audioData" : { - "audioPath" : "Audio/movement/landing-on-the-ground-4.wav" } } } diff --git a/buildNumber.properties b/buildNumber.properties index a3c10098..b316adf0 100644 --- a/buildNumber.properties +++ b/buildNumber.properties @@ -1,3 +1,3 @@ #maven.buildNumber.plugin properties file -#Thu Aug 01 18:31:38 EDT 2024 -buildNumber=199 +#Thu Aug 08 09:35:08 EDT 2024 +buildNumber=200 diff --git a/src/main/java/electrosphere/audio/AudioBuffer.java b/src/main/java/electrosphere/audio/AudioBuffer.java index 10515e14..d08d79ba 100644 --- a/src/main/java/electrosphere/audio/AudioBuffer.java +++ b/src/main/java/electrosphere/audio/AudioBuffer.java @@ -58,6 +58,9 @@ public class AudioBuffer { //whether this buffer has created an al buffer object or not boolean isBuffered = false; + + //The filepath associated with this buffer + String filePath = null; /** * Creates the audio buffer object @@ -65,6 +68,7 @@ public class AudioBuffer { */ public AudioBuffer(String fileNameRaw) { String fileNameSanitized = FileUtils.sanitizeFilePath(fileNameRaw); + this.filePath = fileNameSanitized; bufferId = alGenBuffers(); //read vorbis @@ -275,6 +279,22 @@ public class AudioBuffer { return bufferId; } + /** + * Gets the file path of the buffer + * @return The file path + */ + public String getFilePath(){ + return this.filePath; + } + + /** + * Gets the length of this audio buffer + * @return The length + */ + public double getLength(){ + return this.length; + } + /** * Cleans up this audio buffer */ diff --git a/src/main/java/electrosphere/audio/AudioEngine.java b/src/main/java/electrosphere/audio/AudioEngine.java index c4d89b71..08a914f3 100644 --- a/src/main/java/electrosphere/audio/AudioEngine.java +++ b/src/main/java/electrosphere/audio/AudioEngine.java @@ -5,6 +5,10 @@ import electrosphere.entity.types.camera.CameraEntityUtils; import electrosphere.logger.LoggerInterface; import java.nio.ByteBuffer; import java.nio.IntBuffer; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import javax.sound.sampled.AudioFileFormat; import javax.sound.sampled.AudioSystem; @@ -54,6 +58,9 @@ public class AudioEngine { //if true, efx present and active boolean hasEFX = false; + + //The list of sources being tracked + private List openALSources = new CopyOnWriteArrayList(); /** @@ -180,6 +187,7 @@ public class AudioEngine { */ public void update(){ updateListener(); + updateOpenALSources(); } /** @@ -189,6 +197,38 @@ public class AudioEngine { alcDestroyContext(context); alcCloseDevice(device); } + + /** + * Registers an openal audio source with the engine + * @param source The audio source + */ + protected void registerSource(AudioSource source){ + this.openALSources.add(source); + } + + /** + * Updates the status of all tracked sources + */ + private void updateOpenALSources(){ + List toRemove = new LinkedList(); + for(AudioSource source : this.openALSources){ + if(!source.isPlaying()){ + toRemove.add(source); + } + } + for(AudioSource source : toRemove){ + this.openALSources.remove(source); + source.cleanup(); + } + } + + /** + * Gets the list of openal sources + * @return The list of sources + */ + public List getOpenALSources(){ + return Collections.unmodifiableList(this.openALSources); + } /** * Sets the gain of the engine diff --git a/src/main/java/electrosphere/audio/AudioSource.java b/src/main/java/electrosphere/audio/AudioSource.java index 9b7c6430..19ddf067 100644 --- a/src/main/java/electrosphere/audio/AudioSource.java +++ b/src/main/java/electrosphere/audio/AudioSource.java @@ -20,14 +20,16 @@ public class AudioSource { * @param loop if true, will loop audio, otherwise will not * @param relative if true, will make the audio source position relative to the listener based on position */ - protected AudioSource(boolean loop, boolean relative){ - this.sourceId = AL10.alGenSources(); + protected static AudioSource create(boolean loop, boolean relative){ + AudioSource rVal = new AudioSource(); + rVal.sourceId = AL10.alGenSources(); if (loop) { - AL10.alSourcei(sourceId, AL10.AL_LOOPING, AL10.AL_TRUE); + AL10.alSourcei(rVal.sourceId, AL10.AL_LOOPING, AL10.AL_TRUE); } if (relative) { - AL10.alSourcei(sourceId, AL10.AL_SOURCE_RELATIVE, AL10.AL_TRUE); + AL10.alSourcei(rVal.sourceId, AL10.AL_SOURCE_RELATIVE, AL10.AL_TRUE); } + return rVal; } /** diff --git a/src/main/java/electrosphere/audio/AudioUtils.java b/src/main/java/electrosphere/audio/AudioUtils.java index e35448ba..7e73a10a 100644 --- a/src/main/java/electrosphere/audio/AudioUtils.java +++ b/src/main/java/electrosphere/audio/AudioUtils.java @@ -23,7 +23,7 @@ public class AudioUtils { AudioSource rVal = null; AudioBuffer buffer = Globals.assetManager.fetchAudio(audioFile); if(buffer != null && Globals.audioEngine.initialized()){ - rVal = new AudioSource(loops,false); + rVal = AudioSource.create(loops,true); rVal.setBuffer(buffer.getBufferId()); rVal.setGain(Globals.audioEngine.getGain()); rVal.setPosition(position); @@ -55,7 +55,7 @@ public class AudioUtils { AudioSource rVal = null; AudioBuffer buffer = Globals.assetManager.fetchAudio(FileUtils.sanitizeFilePath(audioFile)); if(buffer != null && Globals.audioEngine.initialized()){ - rVal = new AudioSource(loops,false); + rVal = AudioSource.create(loops,false); rVal.setBuffer(buffer.getBufferId()); rVal.setGain(Globals.audioEngine.getGain()); rVal.play(); diff --git a/src/main/java/electrosphere/audio/movement/MovementAudioService.java b/src/main/java/electrosphere/audio/movement/MovementAudioService.java new file mode 100644 index 00000000..1b14a3fb --- /dev/null +++ b/src/main/java/electrosphere/audio/movement/MovementAudioService.java @@ -0,0 +1,195 @@ +package electrosphere.audio.movement; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import org.joml.Vector3d; + +import electrosphere.audio.VirtualAudioSourceManager.VirtualAudioSourceType; +import electrosphere.engine.Globals; +import electrosphere.game.data.audio.SurfaceAudioCollection; +import electrosphere.game.data.audio.SurfaceAudioType; +import electrosphere.logger.LoggerInterface; + +/** + * Service that provides utilities and management for playing audio under different movement conditions + */ +public class MovementAudioService { + + /** + * Different types of interactions with the surface + */ + public static enum InteractionType { + + /** + * A bare footstep + */ + STEP_BARE_REG, + + /** + * A bare, heavy footstep + */ + STEP_BARE_HEAVY, + + /** + * A shoed foostep + */ + STEP_SHOE_REG, + + /** + * A shoed, heavy foostep + */ + STEP_SHOE_HEAVY, + + /** + * Jumping from the surface + */ + JUMP, + + /** + * Landing on the surface + */ + LAND, + } + + //The default surface audio data + SurfaceAudioType defaultSurfaceAudio; + + //Maps voxel types to the corresponding surface audio + Map surfaceAudioMap = new HashMap(); + + //The voxel types to ignore + List ignoredVoxelTypes; + + /** + * The random used to pick an audio file + */ + Random random = new Random(); + + + /** + * Initializes the movement audio service + */ + public void init(){ + SurfaceAudioCollection surfaceAudioCollection = Globals.gameConfigCurrent.getSurfaceAudioCollection(); + this.ignoredVoxelTypes = surfaceAudioCollection.getIgnoredVoxelTypes(); + this.defaultSurfaceAudio = surfaceAudioCollection.getDefaultSurfaceAudio(); + for(SurfaceAudioType audioType : surfaceAudioCollection.getSurfaceAudio()){ + for(int voxelType : audioType.getVoxelTypeIds()){ + if(surfaceAudioMap.containsKey(voxelType)){ + LoggerInterface.loggerAudio.ERROR(new IllegalStateException("Duplicate voxel definitions in the surface audio definitions! " + voxelType)); + } + surfaceAudioMap.put(voxelType,audioType); + } + } + //queue all audio to be loaded + this.loadSurfaceAudio(this.defaultSurfaceAudio); + for(SurfaceAudioType audioType : surfaceAudioCollection.getSurfaceAudio()){ + this.loadSurfaceAudio(audioType); + } + } + + /** + * Gets the audio path to play + * @param voxelType The type of voxel + * @param type The interaction type + * @return The path to the audio file to play + */ + public String getAudioPath(int voxelType, InteractionType type){ + SurfaceAudioType surfaceAudio = this.defaultSurfaceAudio; + + //Check if ignored + for(int ignoredVoxelType : this.ignoredVoxelTypes){ + if(ignoredVoxelType == voxelType){ + return null; + } + } + + //gets the surface audio definition + if(surfaceAudioMap.containsKey(voxelType)){ + surfaceAudio = surfaceAudioMap.get(voxelType); + } else { + LoggerInterface.loggerAudio.WARNING("Surface undefined in the surface audio collection! " + voxelType); + } + + //gets the list to pull from + List availableFiles = surfaceAudio.getFootstepRegularBareAudioPaths(); + switch(type){ + case STEP_BARE_REG: { + availableFiles = surfaceAudio.getFootstepRegularBareAudioPaths(); + } break; + case STEP_BARE_HEAVY: { + availableFiles = surfaceAudio.getFootstepHeavyBareAudioPaths(); + } break; + case STEP_SHOE_REG: { + availableFiles = surfaceAudio.getFootstepRegularShoeAudioPaths(); + } break; + case STEP_SHOE_HEAVY: { + availableFiles = surfaceAudio.getFootstepHeavyShoeAudioPaths(); + } break; + case JUMP: { + availableFiles = surfaceAudio.getJumpAudioPaths(); + } break; + case LAND: { + availableFiles = surfaceAudio.getLandAudioPaths(); + } break; + } + + //return the audio + int roll = random.nextInt(availableFiles.size()); + return availableFiles.get(roll); + } + + /** + * Plays an interaction + * @param voxelType The voxel type + * @param type The interaction type + */ + public void playAudio(int voxelType, InteractionType type){ + String audioPath = this.getAudioPath(voxelType, type); + if(audioPath != null){ + Globals.virtualAudioSourceManager.createVirtualAudioSource(audioPath, VirtualAudioSourceType.CREATURE, false); + } + } + + /** + * Plays an interaction at a given position + * @param voxelType The voxel type + * @param type The interaction type + * @param position The position of the audio + */ + public void playAudioPositional(int voxelType, InteractionType type, Vector3d position){ + String audioPath = this.getAudioPath(voxelType, type); + if(audioPath != null){ + Globals.virtualAudioSourceManager.createVirtualAudioSource(audioPath, VirtualAudioSourceType.CREATURE, false, position); + } + } + + /** + * Loads a given surface audio definition into memory + * @param surfaceAudioType The surface audio definition + */ + private void loadSurfaceAudio(SurfaceAudioType surfaceAudioType){ + for(String audioPath : surfaceAudioType.getFootstepRegularBareAudioPaths()){ + Globals.assetManager.addAudioPathToQueue(audioPath); + } + for(String audioPath : surfaceAudioType.getFootstepHeavyBareAudioPaths()){ + Globals.assetManager.addAudioPathToQueue(audioPath); + } + for(String audioPath : surfaceAudioType.getFootstepRegularShoeAudioPaths()){ + Globals.assetManager.addAudioPathToQueue(audioPath); + } + for(String audioPath : surfaceAudioType.getFootstepHeavyShoeAudioPaths()){ + Globals.assetManager.addAudioPathToQueue(audioPath); + } + for(String audioPath : surfaceAudioType.getJumpAudioPaths()){ + Globals.assetManager.addAudioPathToQueue(audioPath); + } + for(String audioPath : surfaceAudioType.getLandAudioPaths()){ + Globals.assetManager.addAudioPathToQueue(audioPath); + } + } + +} diff --git a/src/main/java/electrosphere/client/scene/ClientWorldData.java b/src/main/java/electrosphere/client/scene/ClientWorldData.java index d97954f5..1339cade 100644 --- a/src/main/java/electrosphere/client/scene/ClientWorldData.java +++ b/src/main/java/electrosphere/client/scene/ClientWorldData.java @@ -93,7 +93,12 @@ public class ClientWorldData { return convertChunkToRealSpace(world); } - public Vector3i convertRealToChunkSpace(Vector3d position){ + /** + * Converts a real space position to its world space equivalent + * @param position The real space position + * @return The world space position (ie the chunk containing the real space position) + */ + public Vector3i convertRealToWorldSpace(Vector3d position){ return new Vector3i( convertRealToChunkSpace(position.x), convertRealToChunkSpace(position.y), diff --git a/src/main/java/electrosphere/client/terrain/cells/DrawCellManager.java b/src/main/java/electrosphere/client/terrain/cells/DrawCellManager.java index 7c1debf4..5ee9b063 100644 --- a/src/main/java/electrosphere/client/terrain/cells/DrawCellManager.java +++ b/src/main/java/electrosphere/client/terrain/cells/DrawCellManager.java @@ -602,7 +602,7 @@ public class DrawCellManager { //pre-existing values Vector3d playerPosition = EntityUtils.getPosition(Globals.playerEntity); - Vector3i playerChunkPosition = Globals.clientWorldData.convertRealToChunkSpace(playerPosition); + Vector3i playerChunkPosition = Globals.clientWorldData.convertRealToWorldSpace(playerPosition); //variables used while iterating across chunk positions double currentRadius = 0; //the current radius is in units of chunks, even though it's a double (it's discrete, not real) diff --git a/src/main/java/electrosphere/client/terrain/sampling/ClientVoxelSampler.java b/src/main/java/electrosphere/client/terrain/sampling/ClientVoxelSampler.java new file mode 100644 index 00000000..aeafd040 --- /dev/null +++ b/src/main/java/electrosphere/client/terrain/sampling/ClientVoxelSampler.java @@ -0,0 +1,38 @@ +package electrosphere.client.terrain.sampling; + +import org.joml.Vector3d; +import org.joml.Vector3i; + +import electrosphere.client.terrain.cache.ChunkData; +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityUtils; + +/** + * Samples voxels + */ +public class ClientVoxelSampler { + + /** + * Gets the voxel type beneath an entity + * @param entity The entity + * @return The voxel type + */ + public static int getVoxelTypeBeneathEntity(Entity entity){ + return ClientVoxelSampler.getVoxelType(EntityUtils.getPosition(entity)); + } + + /** + * Gets the voxel type at a given real-space position + * @param realPos The real-space position + * @return The voxel type id + */ + public static int getVoxelType(Vector3d realPos){ + Vector3i chunkSpacePos = Globals.clientWorldData.convertRealToWorldSpace(realPos); + Vector3i voxelSpacePos = Globals.clientWorldData.convertRealToVoxelSpace(realPos); + ChunkData chunkData = Globals.clientTerrainManager.getChunkDataAtWorldPoint(chunkSpacePos); + int voxelId = chunkData.getType(voxelSpacePos); + return voxelId; + } + +} diff --git a/src/main/java/electrosphere/engine/Globals.java b/src/main/java/electrosphere/engine/Globals.java index 700fceae..498f8154 100644 --- a/src/main/java/electrosphere/engine/Globals.java +++ b/src/main/java/electrosphere/engine/Globals.java @@ -9,6 +9,7 @@ import org.joml.Vector3f; import electrosphere.audio.AudioEngine; import electrosphere.audio.VirtualAudioSourceManager; +import electrosphere.audio.movement.MovementAudioService; import electrosphere.auth.AuthenticationManager; import electrosphere.client.fluid.cells.FluidCellManager; import electrosphere.client.fluid.manager.ClientFluidManager; @@ -104,6 +105,7 @@ public class Globals { // public static AudioEngine audioEngine; public static VirtualAudioSourceManager virtualAudioSourceManager; + public static MovementAudioService movementAudioService = new MovementAudioService(); // @@ -478,6 +480,7 @@ public class Globals { Globals.assetManager.addAudioPathToQueue(path); } Globals.assetManager.loadAssetsInQueue(); + Globals.movementAudioService.init(); } /** diff --git a/src/main/java/electrosphere/engine/assetmanager/AssetManager.java b/src/main/java/electrosphere/engine/assetmanager/AssetManager.java index 14525f14..a30ee27e 100644 --- a/src/main/java/electrosphere/engine/assetmanager/AssetManager.java +++ b/src/main/java/electrosphere/engine/assetmanager/AssetManager.java @@ -20,6 +20,8 @@ import electrosphere.server.poseactor.PoseModel; import electrosphere.util.FileUtils; import java.io.File; +import java.util.Collection; +import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -362,6 +364,14 @@ public class AssetManager { } return rVal; } + + /** + * Gets all audio loaded into the engine + * @return The collection of all audio buffers + */ + public Collection getAllAudio(){ + return Collections.unmodifiableCollection(this.audioLoadedIntoMemory.values()); + } diff --git a/src/main/java/electrosphere/entity/state/movement/FallTree.java b/src/main/java/electrosphere/entity/state/movement/FallTree.java index b1ed3c7d..6a1d906b 100644 --- a/src/main/java/electrosphere/entity/state/movement/FallTree.java +++ b/src/main/java/electrosphere/entity/state/movement/FallTree.java @@ -1,6 +1,7 @@ package electrosphere.entity.state.movement; -import electrosphere.audio.VirtualAudioSourceManager.VirtualAudioSourceType; +import electrosphere.audio.movement.MovementAudioService.InteractionType; +import electrosphere.client.terrain.sampling.ClientVoxelSampler; import electrosphere.engine.Globals; import electrosphere.entity.Entity; import electrosphere.entity.EntityDataStrings; @@ -11,7 +12,6 @@ import electrosphere.entity.btree.StateTransitionUtil.StateTransitionUtilItem; import electrosphere.entity.state.AnimationPriorities; import electrosphere.entity.state.client.firstPerson.FirstPersonTree; import electrosphere.entity.state.movement.jump.ClientJumpTree; -import electrosphere.game.data.common.TreeDataAudio; import electrosphere.game.data.creature.type.movement.FallMovementSystem; import electrosphere.renderer.actor.Actor; @@ -101,19 +101,13 @@ public class FallTree implements BehaviorTree { } FirstPersonTree.conditionallyPlayAnimation(parent, fallMovementSystem.getLandState().getAnimation()); } - //play animation, audio, etc, for state - TreeDataAudio audioData = fallMovementSystem.getLandState().getAudioData(); if(parent == Globals.playerEntity && !Globals.controlHandler.cameraIsThirdPerson()){ //first person + Globals.movementAudioService.playAudio(ClientVoxelSampler.getVoxelTypeBeneathEntity(parent), InteractionType.LAND); //play first person audio - if(Globals.audioEngine.initialized() && audioData != null && audioData.getAudioPath() != null){ - Globals.virtualAudioSourceManager.createVirtualAudioSource(audioData.getAudioPath(), VirtualAudioSourceType.CREATURE, false); - } } else { //play third person audio - if(Globals.audioEngine.initialized() && audioData != null && audioData.getAudioPath() != null){ - Globals.virtualAudioSourceManager.createVirtualAudioSource(audioData.getAudioPath(), VirtualAudioSourceType.CREATURE, false, EntityUtils.getPosition(parent)); - } + Globals.movementAudioService.playAudioPositional(ClientVoxelSampler.getVoxelTypeBeneathEntity(parent), InteractionType.LAND, EntityUtils.getPosition(parent)); } } } diff --git a/src/main/java/electrosphere/entity/state/movement/groundmove/ClientGroundMovementTree.java b/src/main/java/electrosphere/entity/state/movement/groundmove/ClientGroundMovementTree.java index ee1947e1..0a9f2e79 100644 --- a/src/main/java/electrosphere/entity/state/movement/groundmove/ClientGroundMovementTree.java +++ b/src/main/java/electrosphere/entity/state/movement/groundmove/ClientGroundMovementTree.java @@ -4,12 +4,15 @@ package electrosphere.entity.state.movement.groundmove; import electrosphere.net.synchronization.BehaviorTreeIdEnums; import electrosphere.entity.state.gravity.GravityUtils; +import electrosphere.audio.movement.MovementAudioService.InteractionType; +import electrosphere.client.terrain.sampling.ClientVoxelSampler; import electrosphere.collision.PhysicsEntityUtils; import electrosphere.collision.collidable.Collidable; import electrosphere.engine.Globals; import electrosphere.entity.types.collision.CollisionObjUtils; import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.game.data.creature.type.movement.GroundMovementSystem; +import electrosphere.logger.LoggerInterface; import electrosphere.entity.Entity; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityUtils; @@ -104,6 +107,10 @@ public class ClientGroundMovementTree implements BehaviorTree { //the vector controling the direction the entity will move in Vector3d movementVector = new Vector3d(1,0,0); + + //Tracks whether footstep audio has been played or not + boolean playedFootstepFirst = false; + boolean playedFootstepSecond = false; /** * Constructor @@ -288,18 +295,20 @@ public class ClientGroundMovementTree implements BehaviorTree { //state machine switch(state){ case STARTUP: { + String animationToPlay = determineCorrectAnimation(); if(entityActor != null){ - String animationToPlay = determineCorrectAnimation(); - if( - !entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(animationToPlay) && - (jumpTree == null || !jumpTree.isJumping()) && - (fallTree == null || !fallTree.isFalling()) - ){ + if(!entityActor.isPlayingAnimation(animationToPlay)){ entityActor.playAnimation(animationToPlay,AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT)); entityActor.incrementAnimationTime(0.0001); + //reset footstep tracking + this.playedFootstepFirst = false; + this.playedFootstepSecond = false; } FirstPersonTree.conditionallyPlayAnimation(parent, groundMovementData.getAnimationStartup().getNameFirstPerson(), AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT)); } + //conditionally play footstep audio + this.playFootstepAudio(0,entityActor.getAnimationTime(animationToPlay),position); + //run startup code velocity = velocity + acceleration * (float)Globals.timekeeper.getSimFrameTime(); //check if can transition state @@ -320,20 +329,21 @@ public class ClientGroundMovementTree implements BehaviorTree { GravityUtils.clientAttemptActivateGravity(parent); } break; case MOVE: { - //check if can restart animation - //if yes, restart animation + String animationToPlay = determineCorrectAnimation(); if(entityActor != null){ - String animationToPlay = determineCorrectAnimation(); - if( - !entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(animationToPlay) && - (jumpTree == null || !jumpTree.isJumping()) && - (fallTree == null || !fallTree.isFalling()) - ){ + if(!entityActor.isPlayingAnimation(animationToPlay)){ entityActor.playAnimation(animationToPlay,AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT)); entityActor.incrementAnimationTime(0.0001); + //reset footstep tracking + this.playedFootstepFirst = false; + this.playedFootstepSecond = false; } FirstPersonTree.conditionallyPlayAnimation(parent, groundMovementData.getAnimationLoop().getNameFirstPerson(), AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT)); } + + //conditionally play footstep audio + this.playFootstepAudio(0,entityActor.getAnimationTime(animationToPlay),position); + if(velocity != maxNaturalVelocity){ velocity = maxNaturalVelocity; CreatureUtils.setVelocity(parent, velocity); @@ -350,18 +360,20 @@ public class ClientGroundMovementTree implements BehaviorTree { } break; case SLOWDOWN: { //run slowdown code + String animationToPlay = determineCorrectAnimation(); if(entityActor != null){ - String animationToPlay = determineCorrectAnimation(); - if( - !entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(animationToPlay) && - (jumpTree == null || !jumpTree.isJumping()) && - (fallTree == null || !fallTree.isFalling()) - ){ + if(!entityActor.isPlayingAnimation(animationToPlay)){ entityActor.playAnimation(animationToPlay,AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT)); entityActor.incrementAnimationTime(0.0001); + //reset footstep tracking + this.playedFootstepFirst = false; + this.playedFootstepSecond = false; } FirstPersonTree.conditionallyPlayAnimation(parent, groundMovementData.getAnimationWindDown().getNameFirstPerson(), AnimationPriorities.getValue(AnimationPriorities.CORE_MOVEMENT)); } + //conditionally play footstep audio + this.playFootstepAudio(0,entityActor.getAnimationTime(animationToPlay),position); + //velocity stuff velocity = velocity - acceleration * (float)Globals.timekeeper.getSimFrameTime(); //check if can transition state @@ -369,7 +381,7 @@ public class ClientGroundMovementTree implements BehaviorTree { velocity = 0; state = MovementTreeState.IDLE; if(entityActor != null){ - String animationToPlay = determineCorrectAnimation(); + animationToPlay = determineCorrectAnimation(); if(entityActor.isPlayingAnimation() && entityActor.isPlayingAnimation(animationToPlay)){ entityActor.stopAnimation(animationToPlay); } @@ -443,6 +455,36 @@ public class ClientGroundMovementTree implements BehaviorTree { this.fallTree = fallTree; } + /** + * Conditionally plays audio for footsteps + * @param voxelType The voxel type + * @param animationTime The time of the current animation + * @param position The position of the parent entity + */ + private void playFootstepAudio(int voxelType, double animationTime, Vector3d position){ + Float firstOffset = this.groundMovementData.getFootstepFirstAudioOffset(); + Float secondOffset = this.groundMovementData.getFootstepSecondAudioOffset(); + if(!this.playedFootstepFirst && firstOffset != null && animationTime > firstOffset){ + this.playedFootstepFirst = true; + if(parent == Globals.playerEntity && !Globals.controlHandler.cameraIsThirdPerson()){ + Globals.movementAudioService.playAudio(ClientVoxelSampler.getVoxelTypeBeneathEntity(parent), InteractionType.STEP_BARE_REG); + } else { + Globals.movementAudioService.playAudioPositional(ClientVoxelSampler.getVoxelTypeBeneathEntity(parent), InteractionType.STEP_BARE_REG, position); + } + } + if(!this.playedFootstepSecond && secondOffset != null && animationTime > secondOffset){ + this.playedFootstepSecond = true; + if(parent == Globals.playerEntity && !Globals.controlHandler.cameraIsThirdPerson()){ + Globals.movementAudioService.playAudio(ClientVoxelSampler.getVoxelTypeBeneathEntity(parent), InteractionType.STEP_BARE_REG); + } else { + Globals.movementAudioService.playAudioPositional(ClientVoxelSampler.getVoxelTypeBeneathEntity(parent), InteractionType.STEP_BARE_REG, position); + } + } + if(firstOffset == null || secondOffset == null){ + LoggerInterface.loggerAudio.WARNING("Footstep offset undefined for creature! " + CreatureUtils.getType(parent)); + } + } + /** *

Automatically generated

*

diff --git a/src/main/java/electrosphere/game/data/Config.java b/src/main/java/electrosphere/game/data/Config.java index ee6473f7..bd6b207c 100644 --- a/src/main/java/electrosphere/game/data/Config.java +++ b/src/main/java/electrosphere/game/data/Config.java @@ -3,6 +3,7 @@ package electrosphere.game.data; import java.util.LinkedList; import java.util.List; +import electrosphere.game.data.audio.SurfaceAudioCollection; import electrosphere.game.data.creature.type.CreatureData; import electrosphere.game.data.creature.type.CreatureTypeLoader; import electrosphere.game.data.creature.type.attack.AttackMoveResolver; @@ -39,6 +40,11 @@ public class Config { //the hints that are defined HintDefinition hintData; + + /** + * The surface audio definitions + */ + SurfaceAudioCollection surfaceAudioCollection; /** * Loads the default data @@ -56,6 +62,7 @@ public class Config { config.voxelData = FileUtils.loadObjectFromAssetPath("Data/voxelTypes.json", VoxelData.class); config.projectileTypeHolder = FileUtils.loadObjectFromAssetPath("Data/projectile.json", ProjectileTypeHolder.class); config.hintData = FileUtils.loadObjectFromAssetPath("Data/tutorial/hints.json", HintDefinition.class); + config.surfaceAudioCollection = FileUtils.loadObjectFromAssetPath("Data/audio/surface.json", SurfaceAudioCollection.class); config.projectileTypeHolder.init(); //validate @@ -225,5 +232,13 @@ public class Config { public HintDefinition getHintData(){ return hintData; } + + /** + * Gets the surface audio collection + * @return The surface audio collection + */ + public SurfaceAudioCollection getSurfaceAudioCollection(){ + return this.surfaceAudioCollection; + } } diff --git a/src/main/java/electrosphere/game/data/audio/SurfaceAudioCollection.java b/src/main/java/electrosphere/game/data/audio/SurfaceAudioCollection.java new file mode 100644 index 00000000..9420d95f --- /dev/null +++ b/src/main/java/electrosphere/game/data/audio/SurfaceAudioCollection.java @@ -0,0 +1,49 @@ +package electrosphere.game.data.audio; + +import java.util.List; + +/** + * Audio for different types of interactions with the ground + */ +public class SurfaceAudioCollection { + + /** + * The audio to play by default (ie for undefined surfaces) + */ + SurfaceAudioType defaultSurfaceAudio; + + /** + * The audio to play for different collections of surfaces + */ + List surfaceAudio; + + /** + * The voxel types to not play audio for + */ + List ignoredVoxelTypes; + + /** + * Gets the default audio for all surfaces + * @return The default audio + */ + public SurfaceAudioType getDefaultSurfaceAudio(){ + return this.defaultSurfaceAudio; + } + + /** + * Gets the audio to play for different surfaces + * @return The list of surface audio data + */ + public List getSurfaceAudio(){ + return this.surfaceAudio; + } + + /** + * Gets the list of voxel types to not play audio for + * @return The list of voxel types + */ + public List getIgnoredVoxelTypes(){ + return this.ignoredVoxelTypes; + } + +} diff --git a/src/main/java/electrosphere/game/data/audio/SurfaceAudioType.java b/src/main/java/electrosphere/game/data/audio/SurfaceAudioType.java new file mode 100644 index 00000000..aac71376 --- /dev/null +++ b/src/main/java/electrosphere/game/data/audio/SurfaceAudioType.java @@ -0,0 +1,101 @@ +package electrosphere.game.data.audio; + +import java.util.List; + +/** + * Audio data for a specific surface type + */ +public class SurfaceAudioType { + + /** + * The voxel types that this audio applies to + */ + List voxelTypeIds; + + /** + * The audio paths for sound effects to play for regular footsteps on these voxel types + */ + List footstepRegularBareAudioPaths; + + /** + * The audio paths for sound effects to play for heavy footsteps on these voxel types + */ + List footstepHeavyBareAudioPaths; + + /** + * The audio paths for sound effects to play for regular footsteps on these voxel types + */ + List footstepRegularShoeAudioPaths; + + /** + * The audio paths for sound effects to play for heavy footsteps on these voxel types + */ + List footstepHeavyShoeAudioPaths; + + /** + * The audio paths for sound effects to play for jumps beginning on these voxel types + */ + List jumpAudioPaths; + + /** + * The audio paths for sound effects to play for landing animations on these voxel types + */ + List landAudioPaths; + + /** + * Gets the voxels ids that use this audio + * @return The list of voxel ids + */ + public List getVoxelTypeIds(){ + return voxelTypeIds; + } + + /** + * Gets the audio to play for regular, bare footsteps on these surfaces + * @return The audio file paths + */ + public List getFootstepRegularBareAudioPaths(){ + return footstepRegularBareAudioPaths; + } + + /** + * Gets the audio to play for heavy, bare footsteps on these surfaces + * @return The audio file paths + */ + public List getFootstepHeavyBareAudioPaths(){ + return footstepHeavyBareAudioPaths; + } + + /** + * Gets the audio to play for regular, shoed footsteps on these surfaces + * @return The audio file paths + */ + public List getFootstepRegularShoeAudioPaths(){ + return footstepRegularShoeAudioPaths; + } + + /** + * Gets the audio to play for heavy, shoed footsteps on these surfaces + * @return The audio file paths + */ + public List getFootstepHeavyShoeAudioPaths(){ + return footstepHeavyShoeAudioPaths; + } + + /** + * Gets the audio to play for jumping from these surfaces + * @return The audio file paths + */ + public List getJumpAudioPaths(){ + return jumpAudioPaths; + } + + /** + * Gets the audio to play for landing on these surfaces + * @return The audio file paths + */ + public List getLandAudioPaths(){ + return landAudioPaths; + } + +} diff --git a/src/main/java/electrosphere/game/data/creature/type/movement/GroundMovementSystem.java b/src/main/java/electrosphere/game/data/creature/type/movement/GroundMovementSystem.java index e51806a3..03126059 100644 --- a/src/main/java/electrosphere/game/data/creature/type/movement/GroundMovementSystem.java +++ b/src/main/java/electrosphere/game/data/creature/type/movement/GroundMovementSystem.java @@ -35,6 +35,16 @@ public class GroundMovementSystem implements MovementSystem { //sprint data SprintSystem sprintSystem; + + /** + * The offset into the main animation to play the first footstep sound + */ + Float footstepFirstAudioOffset; + + /** + * The offset into the main animation to play the second footstep sound + */ + Float footstepSecondAudioOffset; /** @@ -101,6 +111,22 @@ public class GroundMovementSystem implements MovementSystem { return this.backpedalMultiplier; } + /** + * Gets the offset into the main animation to play the audio for the first footstep + * @return The offset into the audio + */ + public Float getFootstepFirstAudioOffset(){ + return footstepFirstAudioOffset; + } + + /** + * Gets the offset into the main animation to play the audio for the second footstep + * @return The offset into the audio + */ + public Float getFootstepSecondAudioOffset(){ + return footstepSecondAudioOffset; + } + @Override public String getType() { return type; diff --git a/src/main/java/electrosphere/menu/debug/ImGuiAudio.java b/src/main/java/electrosphere/menu/debug/ImGuiAudio.java new file mode 100644 index 00000000..56d2f4f5 --- /dev/null +++ b/src/main/java/electrosphere/menu/debug/ImGuiAudio.java @@ -0,0 +1,76 @@ +package electrosphere.menu.debug; + +import electrosphere.audio.AudioBuffer; +import electrosphere.audio.VirtualAudioSource; +import electrosphere.engine.Globals; +import electrosphere.renderer.ui.imgui.ImGuiWindow; +import electrosphere.renderer.ui.imgui.ImGuiWindow.ImGuiWindowCallback; +import imgui.ImGui; +import imgui.type.ImString; + +/** + * Audio debug menus + */ +public class ImGuiAudio { + + //audio debug menu + public static ImGuiWindow audioDebugMenu; + + //the audio buffer list filter + private static ImString bufferListFilter = new ImString(); + + /** + * Create audio debug menu + */ + public static void createAudioDebugMenu(){ + audioDebugMenu = new ImGuiWindow("Audio"); + audioDebugMenu.setCallback(new ImGuiWindowCallback() { + @Override + public void exec() { + //audio engine details + ImGui.text("Audio Engine Details"); + ImGui.text("Virtual Audio Source Manager Details"); + ImGui.text("Total number active virtual sources: " + Globals.virtualAudioSourceManager.getSourceQueue().size()); + if(ImGui.collapsingHeader("Engine Configuration")){ + ImGui.text("Current audio device: " + Globals.audioEngine.getDevice()); + ImGui.text("Default audio device: " + Globals.audioEngine.getDefaultDevice()); + ImGui.text("Has HRTF: " + Globals.audioEngine.getHRTFStatus()); + ImGui.text("Listener location: " + Globals.audioEngine.getListener().getPosition()); + ImGui.text("Listener eye vector: " + Globals.audioEngine.getListener().getEyeVector()); + ImGui.text("Listener up vector: " + Globals.audioEngine.getListener().getUpVector()); + } + //only active children + if(ImGui.collapsingHeader("Mapped Virtual Sources")){ + for(VirtualAudioSource source : Globals.virtualAudioSourceManager.getMappedSources()){ + ImGui.text("Source " + source.getPriority()); + ImGui.text(" - Position " + source.getPosition()); + ImGui.text(" - Gain " + source.getGain()); + ImGui.text(" - Type " + source.getType()); + ImGui.text(" - Total time played " + source.getTotalTimePlayed()); + ImGui.text(" - Buffer Lenth " + source.getBufferLength()); + } + } + //all virtual children + if(ImGui.collapsingHeader("All Virtual Sources")){ + for(VirtualAudioSource source : Globals.virtualAudioSourceManager.getSourceQueue()){ + ImGui.text("Position " + source.getPosition()); + } + } + //all buffers loaded into memory and stats about them + if(ImGui.collapsingHeader("All Loaded Audio Buffers")){ + if(ImGui.inputText("Filter", bufferListFilter)){ + + } + for(AudioBuffer buffer : Globals.assetManager.getAllAudio()){ + if(buffer.getFilePath().contains(bufferListFilter.get()) && ImGui.collapsingHeader(buffer.getFilePath())){ + ImGui.text("Length: " + buffer.getLength()); + } + } + } + } + }); + audioDebugMenu.setOpen(false); + Globals.renderingEngine.getImGuiPipeline().addImGuiWindow(audioDebugMenu); + } + +} diff --git a/src/main/java/electrosphere/menu/debug/ImGuiWindowMacros.java b/src/main/java/electrosphere/menu/debug/ImGuiWindowMacros.java index 42687fbd..dbb32c4c 100644 --- a/src/main/java/electrosphere/menu/debug/ImGuiWindowMacros.java +++ b/src/main/java/electrosphere/menu/debug/ImGuiWindowMacros.java @@ -5,7 +5,6 @@ import java.util.Map; import org.ode4j.ode.DBody; -import electrosphere.audio.VirtualAudioSource; import electrosphere.collision.PhysicsEntityUtils; import electrosphere.controls.ControlHandler.ControlsState; import electrosphere.engine.Globals; @@ -37,11 +36,6 @@ public class ImGuiWindowMacros { private static ImGuiLinePlot globalFrametimePlot; private static Map globalFrametimeDatasets; - //audio debug menu - private static ImGuiWindow audioDebugMenu; - private static boolean showAllVirtualAudioChildren = false; - private static boolean showMappedVirtualAudioChildren = true; - //player entity details private static ImGuiWindow playerEntityWindow; @@ -54,13 +48,13 @@ public class ImGuiWindowMacros { public static void initImGuiWindows(){ createMainDebugMenu(); createFramerateGraph(); - createAudioDebugMenu(); createPlayerEntityDebugWindow(); createFluidDebugWindow(); ImGuiEntityMacros.createClientEntityWindows(); ImGuiUIFramework.createUIFrameworkWindows(); ImGuiControls.createControlsWindows(); ImGuiAI.createAIDebugWindow(); + ImGuiAudio.createAudioDebugMenu(); } /** @@ -114,65 +108,6 @@ public class ImGuiWindowMacros { } } - /** - * Create audio debug menu - */ - private static void createAudioDebugMenu(){ - audioDebugMenu = new ImGuiWindow("Audio"); - audioDebugMenu.setCallback(new ImGuiWindowCallback() { - @Override - public void exec() { - //audio engine details - ImGui.text("Audio Engine Details"); - ImGui.text("Current audio device: " + Globals.audioEngine.getDevice()); - ImGui.text("Default audio device: " + Globals.audioEngine.getDefaultDevice()); - ImGui.text("Has HRTF: " + Globals.audioEngine.getHRTFStatus()); - ImGui.text("Listener location: " + Globals.audioEngine.getListener().getPosition()); - ImGui.text("Listener eye vector: " + Globals.audioEngine.getListener().getEyeVector()); - ImGui.text("Listener up vector: " + Globals.audioEngine.getListener().getUpVector()); - ImGui.text("Virtual Audio Source Manager Details"); - ImGui.text("Total number active virtual sources: " + Globals.virtualAudioSourceManager.getSourceQueue().size()); - //only active children - if(showMappedVirtualAudioChildren){ - ImGui.beginChild("mapped virtual sources"); - for(VirtualAudioSource source : Globals.virtualAudioSourceManager.getMappedSources()){ - ImGui.text("Source " + source.getPriority()); - ImGui.text(" - Position " + source.getPosition()); - ImGui.text(" - Gain " + source.getGain()); - ImGui.text(" - Type " + source.getType()); - ImGui.text(" - Total time played " + source.getTotalTimePlayed()); - ImGui.text(" - Buffer Lenth " + source.getBufferLength()); - } - ImGui.endChild(); - if(ImGui.button("Hide Mapped Virtual Children")){ - showMappedVirtualAudioChildren = false; - } - } else { - if(ImGui.button("Show Mapped Virtual Children")){ - showMappedVirtualAudioChildren = true; - } - } - //all virtual children - if(showAllVirtualAudioChildren){ - ImGui.beginChild("all virtual sources"); - for(VirtualAudioSource source : Globals.virtualAudioSourceManager.getSourceQueue()){ - ImGui.text("Position " + source.getPosition()); - } - ImGui.endChild(); - if(ImGui.button("Hide All Virtual Children")){ - showAllVirtualAudioChildren = false; - } - } else { - if(ImGui.button("Show All Virtual Children")){ - showAllVirtualAudioChildren = true; - } - } - } - }); - audioDebugMenu.setOpen(false); - Globals.renderingEngine.getImGuiPipeline().addImGuiWindow(audioDebugMenu); - } - /** * Create player entity debug menu @@ -266,7 +201,7 @@ public class ImGuiWindowMacros { } //show audio debug if(ImGui.button("Show Audio Debug Menu")){ - audioDebugMenu.setOpen(true); + ImGuiAudio.audioDebugMenu.setOpen(true); } //show audio debug if(ImGui.button("Show Player Entity Debug Menu")){ diff --git a/src/main/java/electrosphere/renderer/actor/Actor.java b/src/main/java/electrosphere/renderer/actor/Actor.java index e4229182..3a538a72 100644 --- a/src/main/java/electrosphere/renderer/actor/Actor.java +++ b/src/main/java/electrosphere/renderer/actor/Actor.java @@ -39,6 +39,11 @@ import org.joml.Vector4d; */ public class Actor { + /** + * Returned when the current time is requested of an animation that the actor is not playing + */ + public static final int INVALID_ANIMATION = -1; + //the model path of the model backing the actor String modelPath; @@ -91,13 +96,17 @@ public class Actor { } } - public double getAnimationTime(String animationName){ - for(ActorAnimationMask mask : animationQueue){ - if(mask.getAnimationName().contains(animationName)){ - return mask.getTime(); - } + /** + * Gets the current time of the given animation that is being played on this actor + * @param animation The animation's name + * @return The time into the animation, -1 if the animation is not being played + */ + public double getAnimationTime(String animation){ + ActorAnimationMask mask = this.getAnimationMask(animation); + if(mask != null){ + return mask.time; } - return -1.0f; + return INVALID_ANIMATION; } /** @@ -110,7 +119,7 @@ public class Actor { return false; } for(ActorAnimationMask mask : animationQueue){ - if(mask.getAnimationName().contains(animationName)){ + if(mask.getAnimationName().equals(animationName)){ return true; } } @@ -159,9 +168,6 @@ public class Actor { * @param priority The priority of the animation */ public void playAnimation(String animationName, int priority){ - // animationTime = 0; - // playingAnimation = true; - // animation = animationName; Model model = Globals.assetManager.fetchModel(modelPath); if(model != null && model.getAnimation(animationName) != null){ double length = model.getAnimation(animationName).duration; @@ -365,6 +371,22 @@ public class Actor { public void setAnimationScalar(float animationScalar) { this.animationScalar = animationScalar; } + + /** + * Gets the animation mask for a given animation + * @param animationName The animation's name + * @return The animation mask if the actor is playing the animation, null otherwise + */ + public ActorAnimationMask getAnimationMask(String animationName){ + for(ActorAnimationMask mask : this.getAnimationQueue()){ + if(mask.animationName.equals(animationName)){ + return mask; + } else if(mask.animationName.equalsIgnoreCase(animationName)){ + LoggerInterface.loggerEngine.WARNING("Animation mask failed to find, but there is an animation with a very similar name! " + animationName + " vs " + mask.animationName); + } + } + return null; + } /** * Applies spatial data on the actor, this includes the model matrix as well as the real world position