diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/sounds/SoundEvent.kt b/src/main/java/de/bixilon/minosoft/data/mappings/sounds/SoundEvent.kt
index e44650af8..f6473503b 100644
--- a/src/main/java/de/bixilon/minosoft/data/mappings/sounds/SoundEvent.kt
+++ b/src/main/java/de/bixilon/minosoft/data/mappings/sounds/SoundEvent.kt
@@ -28,6 +28,5 @@ data class SoundEvent(
resourceLocation = resourceLocation,
)
}
-
}
}
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/LeftClickHandler.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/LeftClickHandler.kt
index 308ce407e..149b7596a 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/LeftClickHandler.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/LeftClickHandler.kt
@@ -24,6 +24,7 @@ import de.bixilon.minosoft.data.mappings.items.tools.MiningToolItem
import de.bixilon.minosoft.data.player.Hands
import de.bixilon.minosoft.gui.rendering.RenderConstants
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.events.BlockBreakAckEvent
import de.bixilon.minosoft.protocol.packets.c2s.play.ArmSwingC2SP
@@ -133,7 +134,7 @@ class LeftClickHandler(
clearDigging()
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
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt
index 5142136c3..7d12ebd01 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt
@@ -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.RenderWindow
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.ScreenResizeEvent
import de.bixilon.minosoft.gui.rendering.sky.SkyRenderer
@@ -173,6 +174,7 @@ class Camera(
skyRenderer.setSkyColor(RenderConstants.BLACK_COLOR)
}
} ?: skyRenderer.setSkyColor(RenderConstants.DEFAULT_SKY_COLOR)
+ connection.fireEvent(CameraPositionChangeEvent(renderWindow, cameraPosition))
}
private fun calculateProjectionMatrix(screenDimensions: Vec2): Mat4 {
@@ -302,6 +304,7 @@ class Camera(
fun setPosition(position: Vec3) {
playerEntity.position = position
cameraPosition = getAbsoluteCameraPosition()
+ positionChangeCallback()
}
fun getTargetBlock(): RaycastHit? {
@@ -339,7 +342,7 @@ class Camera(
}
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_SPRINT_SPEED_MODIFIER = 1.30000001192092896
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/modding/events/CameraPositionChangeEvent.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/modding/events/CameraPositionChangeEvent.kt
new file mode 100644
index 000000000..ea64529d5
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/modding/events/CameraPositionChangeEvent.kt
@@ -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 .
+ *
+ * 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)
+}
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/sound/AudioPlayer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/sound/AudioPlayer.kt
index 2209366fc..07a33b1c0 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/sound/AudioPlayer.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/sound/AudioPlayer.kt
@@ -19,8 +19,13 @@ import com.google.gson.JsonPrimitive
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.sounds.SoundEvent
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.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.protocol.ConnectionStates
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.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType
+import glm_.vec3.Vec3
import org.lwjgl.openal.AL
import org.lwjgl.openal.ALC
import org.lwjgl.openal.ALC10.*
@@ -99,6 +105,17 @@ class AudioPlayer(
listener = SoundListener()
+ connection.registerEvent(CallbackEventInvoker.of {
+ queue += {
+ listener.position = it.newPosition
+ listener.setOrientation(it.renderWindow.inputHandler.camera.cameraFront, Camera.CAMERA_UP_VEC3)
+ }
+ })
+
+ connection.registerEvent(CallbackEventInvoker.of {
+ playSoundEvent(it.soundEvent, it.position.toVec3, it.volume, it.pitch)
+ })
+
Log.log(LogMessageType.RENDERING_LOADING, LogLevels.INFO) { "OpenAL loaded!" }
@@ -106,11 +123,10 @@ class AudioPlayer(
latch.countDown()
}
- fun playSoundEvent(soundEvent: SoundEvent) {
- playSound(sounds[soundEvent]!!.getRandom())
+ fun playSoundEvent(soundEvent: SoundEvent, position: Vec3? = null, volume: Float = 1.0f, pitch: Float = 1.0f) {
+ playSound(sounds[soundEvent]!!.getRandom(), position, volume, pitch)
}
-
private fun getAvailableSource(): SoundSource? {
for (source in sources.toSynchronizedList()) {
if (source.available) {
@@ -121,24 +137,34 @@ class AudioPlayer(
if (sources.size > SoundConstants.MAX_SOURCES_AMOUNT) {
return null
}
- val source = SoundSource(false)
+ val source = SoundSource()
sources += source
return source
}
- fun playSound(sound: Sound) {
+ fun playSound(sound: Sound, position: Vec3? = null, volume: Float = 1.0f, pitch: Float = 1.0f) {
queue += add@{
sound.load(connection.assetsManager)
if (sound.loadFailed) {
return@add
}
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!" }
return@add
}
+ position?.let {
+ source.relative = false
+ source.position = it
+ } ?: let {
+ source.position = Vec3(0, 0, 0)
+ source.relative = true
+ }
source.sound = sound
+ source.pitch = pitch * sound.pitch
+ source.gain = volume * sound.volume
source.play()
}
}
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/sound/SoundSource.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/sound/SoundSource.kt
index f506de72b..2e80837d7 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/sound/SoundSource.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/sound/SoundSource.kt
@@ -18,16 +18,20 @@ import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY
import glm_.vec3.Vec3
import org.lwjgl.openal.AL10.*
-class SoundSource(loop: Boolean = false) {
+class SoundSource {
private val source: Int = alGenSources()
- init {
- if (loop) {
- alSourcei(source, AL_LOOPING, AL_TRUE)
- } else {
- alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE)
+ var loop: Boolean = false
+ set(value) {
+ alSourcei(source, AL_LOOPING, value.AL_VALUE)
+ field = value
+ }
+
+ var relative: Boolean = false
+ set(value) {
+ alSourcei(source, AL_SOURCE_RELATIVE, value.AL_VALUE)
+ field = value
}
- }
var position: Vec3 = Vec3.EMPTY
set(value) {
@@ -68,7 +72,7 @@ class SoundSource(loop: Boolean = false) {
get() = alGetSourcei(source, AL_SOURCE_STATE) == AL_PLAYING
val available: Boolean
- get() = isPlaying
+ get() = !isPlaying
fun play() {
alSourcePlay(source)
@@ -87,4 +91,13 @@ class SoundSource(loop: Boolean = false) {
alDeleteSources(source)
}
+ companion object {
+ val Boolean.AL_VALUE: Int
+ get() = if (this) {
+ AL_TRUE
+ } else {
+ AL_FALSE
+ }
+ }
+
}
diff --git a/src/main/java/de/bixilon/minosoft/modding/event/events/PlaySoundEvent.kt b/src/main/java/de/bixilon/minosoft/modding/event/events/PlaySoundEvent.kt
new file mode 100644
index 000000000..a2f9babdc
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/modding/event/events/PlaySoundEvent.kt
@@ -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 .
+ *
+ * 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)
+}
diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/SoundEventS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/SoundEventS2CP.kt
index f5d826b14..05c97b26b 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/SoundEventS2CP.kt
+++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/SoundEventS2CP.kt
@@ -14,6 +14,8 @@ package de.bixilon.minosoft.protocol.packets.s2c.play
import de.bixilon.minosoft.data.SoundCategories
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.protocol.PlayInByteBuffer
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)
volume = buffer.readFloat()
pitch = if (buffer.versionId < ProtocolVersions.V_16W20A) {
- buffer.readByte() * ProtocolDefinition.PITCH_CALCULATION_CONSTANT / 100f
+ buffer.readByte() * ProtocolDefinition.PITCH_CALCULATION_CONSTANT / 100.0f
} else {
buffer.readFloat()
}
}
+ override fun handle(connection: PlayConnection) {
+ connection.fireEvent(PlaySoundEvent(connection, this))
+ }
+
override fun log() {
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "SoundEvent effect (category=$category, position=$position, soundEvent=$soundEvent, volume=$volume, pitch=$pitch)" }
}