mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-13 17:37:58 -04:00
sounds: improve sound api, play packet sounds, 3d surround sound
This commit is contained in:
parent
504302025f
commit
4534304d15
@ -28,6 +28,5 @@ data class SoundEvent(
|
|||||||
resourceLocation = resourceLocation,
|
resourceLocation = resourceLocation,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import de.bixilon.minosoft.data.mappings.items.tools.MiningToolItem
|
|||||||
import de.bixilon.minosoft.data.player.Hands
|
import de.bixilon.minosoft.data.player.Hands
|
||||||
import de.bixilon.minosoft.gui.rendering.RenderConstants
|
import de.bixilon.minosoft.gui.rendering.RenderConstants
|
||||||
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3
|
||||||
import de.bixilon.minosoft.modding.event.CallbackEventInvoker
|
import de.bixilon.minosoft.modding.event.CallbackEventInvoker
|
||||||
import de.bixilon.minosoft.modding.event.events.BlockBreakAckEvent
|
import de.bixilon.minosoft.modding.event.events.BlockBreakAckEvent
|
||||||
import de.bixilon.minosoft.protocol.packets.c2s.play.ArmSwingC2SP
|
import de.bixilon.minosoft.protocol.packets.c2s.play.ArmSwingC2SP
|
||||||
@ -133,7 +134,7 @@ class LeftClickHandler(
|
|||||||
clearDigging()
|
clearDigging()
|
||||||
connection.world.setBlockState(raycastHit.blockPosition, null)
|
connection.world.setBlockState(raycastHit.blockPosition, null)
|
||||||
|
|
||||||
renderWindow.rendering.audioPlayer.playSoundEvent(connection.registries.soundEventRegistry[BLOCK_BREAK_SOUND]!!) // ToDO
|
renderWindow.rendering.audioPlayer.playSoundEvent(connection.registries.soundEventRegistry[BLOCK_BREAK_SOUND]!!, raycastHit.blockPosition.toVec3) // ToDo
|
||||||
}
|
}
|
||||||
|
|
||||||
val canStartBreaking = currentTime - breakSent >= ProtocolDefinition.TICK_TIME
|
val canStartBreaking = currentTime - breakSent >= ProtocolDefinition.TICK_TIME
|
||||||
|
@ -21,6 +21,7 @@ import de.bixilon.minosoft.data.mappings.biomes.Biome
|
|||||||
import de.bixilon.minosoft.gui.rendering.RenderConstants
|
import de.bixilon.minosoft.gui.rendering.RenderConstants
|
||||||
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||||
import de.bixilon.minosoft.gui.rendering.modding.events.CameraMatrixChangeEvent
|
import de.bixilon.minosoft.gui.rendering.modding.events.CameraMatrixChangeEvent
|
||||||
|
import de.bixilon.minosoft.gui.rendering.modding.events.CameraPositionChangeEvent
|
||||||
import de.bixilon.minosoft.gui.rendering.modding.events.FrustumChangeEvent
|
import de.bixilon.minosoft.gui.rendering.modding.events.FrustumChangeEvent
|
||||||
import de.bixilon.minosoft.gui.rendering.modding.events.ScreenResizeEvent
|
import de.bixilon.minosoft.gui.rendering.modding.events.ScreenResizeEvent
|
||||||
import de.bixilon.minosoft.gui.rendering.sky.SkyRenderer
|
import de.bixilon.minosoft.gui.rendering.sky.SkyRenderer
|
||||||
@ -173,6 +174,7 @@ class Camera(
|
|||||||
skyRenderer.setSkyColor(RenderConstants.BLACK_COLOR)
|
skyRenderer.setSkyColor(RenderConstants.BLACK_COLOR)
|
||||||
}
|
}
|
||||||
} ?: skyRenderer.setSkyColor(RenderConstants.DEFAULT_SKY_COLOR)
|
} ?: skyRenderer.setSkyColor(RenderConstants.DEFAULT_SKY_COLOR)
|
||||||
|
connection.fireEvent(CameraPositionChangeEvent(renderWindow, cameraPosition))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun calculateProjectionMatrix(screenDimensions: Vec2): Mat4 {
|
private fun calculateProjectionMatrix(screenDimensions: Vec2): Mat4 {
|
||||||
@ -302,6 +304,7 @@ class Camera(
|
|||||||
fun setPosition(position: Vec3) {
|
fun setPosition(position: Vec3) {
|
||||||
playerEntity.position = position
|
playerEntity.position = position
|
||||||
cameraPosition = getAbsoluteCameraPosition()
|
cameraPosition = getAbsoluteCameraPosition()
|
||||||
|
positionChangeCallback()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTargetBlock(): RaycastHit? {
|
fun getTargetBlock(): RaycastHit? {
|
||||||
@ -339,7 +342,7 @@ class Camera(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val CAMERA_UP_VEC3 = Vec3(0.0f, 1.0f, 0.0f)
|
val CAMERA_UP_VEC3 = Vec3(0.0f, 1.0f, 0.0f)
|
||||||
private const val PLAYER_EYE_HEIGHT = 1.3 // player is 1.8 blocks high, the camera is normally at 0.5. 1.8 - 0.5 = 1.3
|
private const val PLAYER_EYE_HEIGHT = 1.3 // player is 1.8 blocks high, the camera is normally at 0.5. 1.8 - 0.5 = 1.3
|
||||||
private const val PLAYER_SPRINT_SPEED_MODIFIER = 1.30000001192092896
|
private const val PLAYER_SPRINT_SPEED_MODIFIER = 1.30000001192092896
|
||||||
|
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.gui.rendering.modding.events
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||||
|
import de.bixilon.minosoft.gui.rendering.Rendering
|
||||||
|
import glm_.vec3.Vec3
|
||||||
|
|
||||||
|
class CameraPositionChangeEvent(
|
||||||
|
renderWindow: RenderWindow = Rendering.currentContext!!,
|
||||||
|
newPosition: Vec3,
|
||||||
|
) : RenderEvent(renderWindow) {
|
||||||
|
val newPosition: Vec3 = newPosition
|
||||||
|
get() = Vec3(field)
|
||||||
|
}
|
@ -19,8 +19,13 @@ import com.google.gson.JsonPrimitive
|
|||||||
import de.bixilon.minosoft.data.mappings.ResourceLocation
|
import de.bixilon.minosoft.data.mappings.ResourceLocation
|
||||||
import de.bixilon.minosoft.data.mappings.sounds.SoundEvent
|
import de.bixilon.minosoft.data.mappings.sounds.SoundEvent
|
||||||
import de.bixilon.minosoft.gui.rendering.Rendering
|
import de.bixilon.minosoft.gui.rendering.Rendering
|
||||||
|
import de.bixilon.minosoft.gui.rendering.input.camera.Camera
|
||||||
|
import de.bixilon.minosoft.gui.rendering.modding.events.CameraPositionChangeEvent
|
||||||
import de.bixilon.minosoft.gui.rendering.sound.sounds.Sound
|
import de.bixilon.minosoft.gui.rendering.sound.sounds.Sound
|
||||||
import de.bixilon.minosoft.gui.rendering.sound.sounds.SoundList
|
import de.bixilon.minosoft.gui.rendering.sound.sounds.SoundList
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3
|
||||||
|
import de.bixilon.minosoft.modding.event.CallbackEventInvoker
|
||||||
|
import de.bixilon.minosoft.modding.event.events.PlaySoundEvent
|
||||||
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
|
||||||
import de.bixilon.minosoft.protocol.protocol.ConnectionStates
|
import de.bixilon.minosoft.protocol.protocol.ConnectionStates
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||||
@ -32,6 +37,7 @@ import de.bixilon.minosoft.util.Queue
|
|||||||
import de.bixilon.minosoft.util.logging.Log
|
import de.bixilon.minosoft.util.logging.Log
|
||||||
import de.bixilon.minosoft.util.logging.LogLevels
|
import de.bixilon.minosoft.util.logging.LogLevels
|
||||||
import de.bixilon.minosoft.util.logging.LogMessageType
|
import de.bixilon.minosoft.util.logging.LogMessageType
|
||||||
|
import glm_.vec3.Vec3
|
||||||
import org.lwjgl.openal.AL
|
import org.lwjgl.openal.AL
|
||||||
import org.lwjgl.openal.ALC
|
import org.lwjgl.openal.ALC
|
||||||
import org.lwjgl.openal.ALC10.*
|
import org.lwjgl.openal.ALC10.*
|
||||||
@ -99,6 +105,17 @@ class AudioPlayer(
|
|||||||
|
|
||||||
listener = SoundListener()
|
listener = SoundListener()
|
||||||
|
|
||||||
|
connection.registerEvent(CallbackEventInvoker.of<CameraPositionChangeEvent> {
|
||||||
|
queue += {
|
||||||
|
listener.position = it.newPosition
|
||||||
|
listener.setOrientation(it.renderWindow.inputHandler.camera.cameraFront, Camera.CAMERA_UP_VEC3)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
connection.registerEvent(CallbackEventInvoker.of<PlaySoundEvent> {
|
||||||
|
playSoundEvent(it.soundEvent, it.position.toVec3, it.volume, it.pitch)
|
||||||
|
})
|
||||||
|
|
||||||
Log.log(LogMessageType.RENDERING_LOADING, LogLevels.INFO) { "OpenAL loaded!" }
|
Log.log(LogMessageType.RENDERING_LOADING, LogLevels.INFO) { "OpenAL loaded!" }
|
||||||
|
|
||||||
|
|
||||||
@ -106,11 +123,10 @@ class AudioPlayer(
|
|||||||
latch.countDown()
|
latch.countDown()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun playSoundEvent(soundEvent: SoundEvent) {
|
fun playSoundEvent(soundEvent: SoundEvent, position: Vec3? = null, volume: Float = 1.0f, pitch: Float = 1.0f) {
|
||||||
playSound(sounds[soundEvent]!!.getRandom())
|
playSound(sounds[soundEvent]!!.getRandom(), position, volume, pitch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun getAvailableSource(): SoundSource? {
|
private fun getAvailableSource(): SoundSource? {
|
||||||
for (source in sources.toSynchronizedList()) {
|
for (source in sources.toSynchronizedList()) {
|
||||||
if (source.available) {
|
if (source.available) {
|
||||||
@ -121,24 +137,34 @@ class AudioPlayer(
|
|||||||
if (sources.size > SoundConstants.MAX_SOURCES_AMOUNT) {
|
if (sources.size > SoundConstants.MAX_SOURCES_AMOUNT) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
val source = SoundSource(false)
|
val source = SoundSource()
|
||||||
sources += source
|
sources += source
|
||||||
|
|
||||||
return source
|
return source
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun playSound(sound: Sound) {
|
fun playSound(sound: Sound, position: Vec3? = null, volume: Float = 1.0f, pitch: Float = 1.0f) {
|
||||||
queue += add@{
|
queue += add@{
|
||||||
sound.load(connection.assetsManager)
|
sound.load(connection.assetsManager)
|
||||||
if (sound.loadFailed) {
|
if (sound.loadFailed) {
|
||||||
return@add
|
return@add
|
||||||
}
|
}
|
||||||
val source = getAvailableSource() ?: let {
|
val source = getAvailableSource() ?: let {
|
||||||
|
// ToDo: Queue sound for later (and check a certain delay to not make the game feel laggy)
|
||||||
Log.log(LogMessageType.RENDERING_GENERAL, LogLevels.WARN) { "Can not play sound: No source available!" }
|
Log.log(LogMessageType.RENDERING_GENERAL, LogLevels.WARN) { "Can not play sound: No source available!" }
|
||||||
return@add
|
return@add
|
||||||
}
|
}
|
||||||
|
position?.let {
|
||||||
|
source.relative = false
|
||||||
|
source.position = it
|
||||||
|
} ?: let {
|
||||||
|
source.position = Vec3(0, 0, 0)
|
||||||
|
source.relative = true
|
||||||
|
}
|
||||||
source.sound = sound
|
source.sound = sound
|
||||||
|
source.pitch = pitch * sound.pitch
|
||||||
|
source.gain = volume * sound.volume
|
||||||
source.play()
|
source.play()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,16 +18,20 @@ import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY
|
|||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
import org.lwjgl.openal.AL10.*
|
import org.lwjgl.openal.AL10.*
|
||||||
|
|
||||||
class SoundSource(loop: Boolean = false) {
|
class SoundSource {
|
||||||
private val source: Int = alGenSources()
|
private val source: Int = alGenSources()
|
||||||
|
|
||||||
init {
|
var loop: Boolean = false
|
||||||
if (loop) {
|
set(value) {
|
||||||
alSourcei(source, AL_LOOPING, AL_TRUE)
|
alSourcei(source, AL_LOOPING, value.AL_VALUE)
|
||||||
} else {
|
field = value
|
||||||
alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE)
|
}
|
||||||
|
|
||||||
|
var relative: Boolean = false
|
||||||
|
set(value) {
|
||||||
|
alSourcei(source, AL_SOURCE_RELATIVE, value.AL_VALUE)
|
||||||
|
field = value
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var position: Vec3 = Vec3.EMPTY
|
var position: Vec3 = Vec3.EMPTY
|
||||||
set(value) {
|
set(value) {
|
||||||
@ -68,7 +72,7 @@ class SoundSource(loop: Boolean = false) {
|
|||||||
get() = alGetSourcei(source, AL_SOURCE_STATE) == AL_PLAYING
|
get() = alGetSourcei(source, AL_SOURCE_STATE) == AL_PLAYING
|
||||||
|
|
||||||
val available: Boolean
|
val available: Boolean
|
||||||
get() = isPlaying
|
get() = !isPlaying
|
||||||
|
|
||||||
fun play() {
|
fun play() {
|
||||||
alSourcePlay(source)
|
alSourcePlay(source)
|
||||||
@ -87,4 +91,13 @@ class SoundSource(loop: Boolean = false) {
|
|||||||
alDeleteSources(source)
|
alDeleteSources(source)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val Boolean.AL_VALUE: Int
|
||||||
|
get() = if (this) {
|
||||||
|
AL_TRUE
|
||||||
|
} else {
|
||||||
|
AL_FALSE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.modding.event.events
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.data.SoundCategories
|
||||||
|
import de.bixilon.minosoft.data.mappings.sounds.SoundEvent
|
||||||
|
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
|
||||||
|
import de.bixilon.minosoft.protocol.packets.s2c.play.SoundEventS2CP
|
||||||
|
import glm_.vec3.Vec3i
|
||||||
|
|
||||||
|
class PlaySoundEvent(
|
||||||
|
connection: PlayConnection,
|
||||||
|
val category: SoundCategories?,
|
||||||
|
position: Vec3i,
|
||||||
|
val soundEvent: SoundEvent,
|
||||||
|
val volume: Float,
|
||||||
|
val pitch: Float,
|
||||||
|
) : CancelableEvent(connection) {
|
||||||
|
val position: Vec3i = position
|
||||||
|
get() = Vec3i(field)
|
||||||
|
|
||||||
|
constructor(connection: PlayConnection, packet: SoundEventS2CP) : this(connection, packet.category, packet.position, packet.soundEvent, packet.volume, packet.pitch)
|
||||||
|
}
|
@ -14,6 +14,8 @@ package de.bixilon.minosoft.protocol.packets.s2c.play
|
|||||||
|
|
||||||
import de.bixilon.minosoft.data.SoundCategories
|
import de.bixilon.minosoft.data.SoundCategories
|
||||||
import de.bixilon.minosoft.data.mappings.sounds.SoundEvent
|
import de.bixilon.minosoft.data.mappings.sounds.SoundEvent
|
||||||
|
import de.bixilon.minosoft.modding.event.events.PlaySoundEvent
|
||||||
|
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
|
||||||
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
|
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
|
||||||
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||||
@ -46,12 +48,16 @@ class SoundEventS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
|||||||
position = Vec3i(buffer.readFixedPointNumberInt() * 4, buffer.readFixedPointNumberInt() * 4, buffer.readFixedPointNumberInt() * 4)
|
position = Vec3i(buffer.readFixedPointNumberInt() * 4, buffer.readFixedPointNumberInt() * 4, buffer.readFixedPointNumberInt() * 4)
|
||||||
volume = buffer.readFloat()
|
volume = buffer.readFloat()
|
||||||
pitch = if (buffer.versionId < ProtocolVersions.V_16W20A) {
|
pitch = if (buffer.versionId < ProtocolVersions.V_16W20A) {
|
||||||
buffer.readByte() * ProtocolDefinition.PITCH_CALCULATION_CONSTANT / 100f
|
buffer.readByte() * ProtocolDefinition.PITCH_CALCULATION_CONSTANT / 100.0f
|
||||||
} else {
|
} else {
|
||||||
buffer.readFloat()
|
buffer.readFloat()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun handle(connection: PlayConnection) {
|
||||||
|
connection.fireEvent(PlaySoundEvent(connection, this))
|
||||||
|
}
|
||||||
|
|
||||||
override fun log() {
|
override fun log() {
|
||||||
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "SoundEvent effect (category=$category, position=$position, soundEvent=$soundEvent, volume=$volume, pitch=$pitch)" }
|
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "SoundEvent effect (category=$category, position=$position, soundEvent=$soundEvent, volume=$volume, pitch=$pitch)" }
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user