mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-18 03:44:54 -04:00
refactor audio system
This commit is contained in:
parent
8f010c6b84
commit
38993d28da
@ -18,7 +18,6 @@ import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties
|
|||||||
import de.bixilon.minosoft.data.registries.blocks.types.Block
|
import de.bixilon.minosoft.data.registries.blocks.types.Block
|
||||||
import de.bixilon.minosoft.data.registries.materials.Material
|
import de.bixilon.minosoft.data.registries.materials.Material
|
||||||
import de.bixilon.minosoft.data.registries.registries.Registries
|
import de.bixilon.minosoft.data.registries.registries.Registries
|
||||||
import de.bixilon.minosoft.data.registries.sounds.SoundEvent
|
|
||||||
import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel
|
import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel
|
||||||
import de.bixilon.minosoft.util.KUtil.toBoolean
|
import de.bixilon.minosoft.util.KUtil.toBoolean
|
||||||
import de.bixilon.minosoft.util.KUtil.toInt
|
import de.bixilon.minosoft.util.KUtil.toInt
|
||||||
@ -35,11 +34,11 @@ data class BlockState(
|
|||||||
val outlineShape: VoxelShape,
|
val outlineShape: VoxelShape,
|
||||||
val hardness: Float,
|
val hardness: Float,
|
||||||
val requiresTool: Boolean,
|
val requiresTool: Boolean,
|
||||||
val breakSoundEvent: SoundEvent?,
|
val breakSoundEvent: ResourceLocation?,
|
||||||
val stepSoundEvent: SoundEvent?,
|
val stepSoundEvent: ResourceLocation?,
|
||||||
val placeSoundEvent: SoundEvent?,
|
val placeSoundEvent: ResourceLocation?,
|
||||||
val hitSoundEvent: SoundEvent?,
|
val hitSoundEvent: ResourceLocation?,
|
||||||
val fallSoundEvent: SoundEvent?,
|
val fallSoundEvent: ResourceLocation?,
|
||||||
val soundEventVolume: Float = 1.0f,
|
val soundEventVolume: Float = 1.0f,
|
||||||
val soundEventPitch: Float = 1.0f,
|
val soundEventPitch: Float = 1.0f,
|
||||||
) {
|
) {
|
||||||
|
@ -40,7 +40,6 @@ import kotlin.random.Random
|
|||||||
open class CampfireBlock(resourceLocation: ResourceLocation, registries: Registries, data: Map<String, Any>) : Block(resourceLocation, registries, data) {
|
open class CampfireBlock(resourceLocation: ResourceLocation, registries: Registries, data: Map<String, Any>) : Block(resourceLocation, registries, data) {
|
||||||
val lavaParticles = data["lava_particles"]?.toBoolean() ?: true
|
val lavaParticles = data["lava_particles"]?.toBoolean() ?: true
|
||||||
|
|
||||||
private val campfireCrackleSoundEvent = registries.soundEventRegistry[CAMPFIRE_CRACKLE_SOUND_RESOURCE_LOCATION]!!
|
|
||||||
private val cosySmokeParticle = registries.particleTypeRegistry[CampfireSmokeParticle.CosyFactory]!!
|
private val cosySmokeParticle = registries.particleTypeRegistry[CampfireSmokeParticle.CosyFactory]!!
|
||||||
private val signalSmokeParticle = registries.particleTypeRegistry[CampfireSmokeParticle.SignalFactory]!!
|
private val signalSmokeParticle = registries.particleTypeRegistry[CampfireSmokeParticle.SignalFactory]!!
|
||||||
private val lavaParticle = registries.particleTypeRegistry[LavaParticle]!!
|
private val lavaParticle = registries.particleTypeRegistry[LavaParticle]!!
|
||||||
@ -82,7 +81,7 @@ open class CampfireBlock(resourceLocation: ResourceLocation, registries: Registr
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (random.chance(10)) {
|
if (random.chance(10)) {
|
||||||
connection.world.playSoundEvent(campfireCrackleSoundEvent, blockPosition + Vec3(0.5f), 0.5f + random.nextFloat(), 0.6f + random.nextFloat() * 0.7f)
|
connection.world.playSoundEvent(CAMPFIRE_CRACKLE_SOUND, blockPosition + Vec3(0.5f), 0.5f + random.nextFloat(), 0.6f + random.nextFloat() * 0.7f)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lavaParticles && random.chance(20)) {
|
if (lavaParticles && random.chance(20)) {
|
||||||
@ -104,7 +103,7 @@ open class CampfireBlock(resourceLocation: ResourceLocation, registries: Registr
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object : BlockFactory<CampfireBlock> {
|
companion object : BlockFactory<CampfireBlock> {
|
||||||
private val CAMPFIRE_CRACKLE_SOUND_RESOURCE_LOCATION = "minecraft:block.campfire.crackle".toResourceLocation()
|
private val CAMPFIRE_CRACKLE_SOUND = "minecraft:block.campfire.crackle".toResourceLocation()
|
||||||
|
|
||||||
override fun build(resourceLocation: ResourceLocation, registries: Registries, data: Map<String, Any>): CampfireBlock {
|
override fun build(resourceLocation: ResourceLocation, registries: Registries, data: Map<String, Any>): CampfireBlock {
|
||||||
return CampfireBlock(resourceLocation, registries, data)
|
return CampfireBlock(resourceLocation, registries, data)
|
||||||
|
@ -15,7 +15,6 @@ package de.bixilon.minosoft.data.registries.items
|
|||||||
|
|
||||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
import de.bixilon.minosoft.data.registries.registries.Registries
|
import de.bixilon.minosoft.data.registries.registries.Registries
|
||||||
import de.bixilon.minosoft.data.registries.sounds.SoundEvent
|
|
||||||
import de.bixilon.minosoft.util.KUtil.nullCast
|
import de.bixilon.minosoft.util.KUtil.nullCast
|
||||||
|
|
||||||
open class MusicDiscItem(
|
open class MusicDiscItem(
|
||||||
@ -24,9 +23,5 @@ open class MusicDiscItem(
|
|||||||
data: Map<String, Any>,
|
data: Map<String, Any>,
|
||||||
) : Item(resourceLocation, registries, data) {
|
) : Item(resourceLocation, registries, data) {
|
||||||
val analogOutput = data["analog_output"].nullCast<Item>() ?: 0
|
val analogOutput = data["analog_output"].nullCast<Item>() ?: 0
|
||||||
val sound: SoundEvent? = null
|
val sound: ResourceLocation? = registries.soundEventRegistry[data["sound"]]
|
||||||
|
|
||||||
init {
|
|
||||||
this::sound.inject(data["sound"])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,6 @@ import de.bixilon.minosoft.data.registries.other.containers.ContainerType
|
|||||||
import de.bixilon.minosoft.data.registries.other.game.event.GameEvent
|
import de.bixilon.minosoft.data.registries.other.game.event.GameEvent
|
||||||
import de.bixilon.minosoft.data.registries.particle.ParticleType
|
import de.bixilon.minosoft.data.registries.particle.ParticleType
|
||||||
import de.bixilon.minosoft.data.registries.registries.registry.*
|
import de.bixilon.minosoft.data.registries.registries.registry.*
|
||||||
import de.bixilon.minosoft.data.registries.sounds.SoundEvent
|
|
||||||
import de.bixilon.minosoft.data.registries.statistics.Statistic
|
import de.bixilon.minosoft.data.registries.statistics.Statistic
|
||||||
import de.bixilon.minosoft.data.registries.versions.Version
|
import de.bixilon.minosoft.data.registries.versions.Version
|
||||||
import de.bixilon.minosoft.protocol.packets.c2s.play.EntityActionC2SP
|
import de.bixilon.minosoft.protocol.packets.c2s.play.EntityActionC2SP
|
||||||
@ -69,7 +68,7 @@ class Registries {
|
|||||||
val dimensionRegistry: Registry<Dimension> = Registry()
|
val dimensionRegistry: Registry<Dimension> = Registry()
|
||||||
val materialRegistry: Registry<Material> = Registry()
|
val materialRegistry: Registry<Material> = Registry()
|
||||||
val fluidRegistry: Registry<Fluid> = Registry()
|
val fluidRegistry: Registry<Fluid> = Registry()
|
||||||
val soundEventRegistry: Registry<SoundEvent> = Registry()
|
val soundEventRegistry: ResourceLocationRegistry = ResourceLocationRegistry()
|
||||||
|
|
||||||
val villagerProfessionRegistry: Registry<VillagerProfession> = Registry()
|
val villagerProfessionRegistry: Registry<VillagerProfession> = Registry()
|
||||||
|
|
||||||
@ -159,7 +158,7 @@ class Registries {
|
|||||||
entityTypeRegistry.rawInitialize(pixlyzerData["entities"]?.compoundCast(), this, EntityType)
|
entityTypeRegistry.rawInitialize(pixlyzerData["entities"]?.compoundCast(), this, EntityType)
|
||||||
|
|
||||||
motiveRegistry.rawInitialize(pixlyzerData["motives"]?.compoundCast(), this, Motive, version.isFlattened())
|
motiveRegistry.rawInitialize(pixlyzerData["motives"]?.compoundCast(), this, Motive, version.isFlattened())
|
||||||
soundEventRegistry.rawInitialize(pixlyzerData["sound_events"]?.compoundCast(), this, SoundEvent)
|
soundEventRegistry.rawInitialize(pixlyzerData["sound_events"]?.compoundCast())
|
||||||
particleTypeRegistry.rawInitialize(pixlyzerData["particles"]?.compoundCast(), this, ParticleType)
|
particleTypeRegistry.rawInitialize(pixlyzerData["particles"]?.compoundCast(), this, ParticleType)
|
||||||
materialRegistry.rawInitialize(pixlyzerData["materials"]?.compoundCast(), this, Material)
|
materialRegistry.rawInitialize(pixlyzerData["materials"]?.compoundCast(), this, Material)
|
||||||
enchantmentRegistry.rawInitialize(pixlyzerData["enchantments"]?.compoundCast(), this, Enchantment)
|
enchantmentRegistry.rawInitialize(pixlyzerData["enchantments"]?.compoundCast(), this, Enchantment)
|
||||||
|
@ -195,6 +195,7 @@ open class Registry<T : RegistryItem>(
|
|||||||
BITS_16,
|
BITS_16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated("TODO")
|
||||||
override fun iterator(): Iterator<T> {
|
override fun iterator(): Iterator<T> {
|
||||||
return resourceLocationMap.values.iterator()
|
return resourceLocationMap.values.iterator()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,81 @@
|
|||||||
|
package de.bixilon.minosoft.data.registries.registries.registry
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
|
import de.bixilon.minosoft.util.KUtil.toInt
|
||||||
|
import de.bixilon.minosoft.util.json.ResourceLocationJsonMap.toResourceLocationMap
|
||||||
|
|
||||||
|
class ResourceLocationRegistry(
|
||||||
|
override var parent: AbstractRegistry<ResourceLocation>? = null,
|
||||||
|
) : AbstractRegistry<ResourceLocation> {
|
||||||
|
private var initialized = false
|
||||||
|
private val idValueMap: MutableMap<Int, ResourceLocation> = mutableMapOf()
|
||||||
|
private val valueIdMap: MutableMap<ResourceLocation, Int> = mutableMapOf()
|
||||||
|
|
||||||
|
|
||||||
|
override val size: Int
|
||||||
|
get() {
|
||||||
|
val value = idValueMap.size
|
||||||
|
parent?.let {
|
||||||
|
return value + it.size
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clear() {
|
||||||
|
idValueMap.clear()
|
||||||
|
valueIdMap.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun get(any: Any?): ResourceLocation? {
|
||||||
|
check(any is Int) { "Don't know how to get $any" }
|
||||||
|
return idValueMap[any]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun get(id: Int): ResourceLocation? {
|
||||||
|
return idValueMap[id]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getId(value: ResourceLocation): Int {
|
||||||
|
return valueIdMap[value] ?: -1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun initialize(data: Map<ResourceLocation, Any>?, alternative: ResourceLocationRegistry? = null): ResourceLocationRegistry {
|
||||||
|
check(!initialized) { "Already initialized" }
|
||||||
|
|
||||||
|
if (data == null) {
|
||||||
|
if (alternative != null) {
|
||||||
|
parent = alternative
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((resourceLocation, value) in data) {
|
||||||
|
val id: Int = when (value) {
|
||||||
|
is Number -> value.toInt()
|
||||||
|
is Map<*, *> -> value["id"].toInt()
|
||||||
|
else -> throw IllegalArgumentException("Don't know what $value is!")
|
||||||
|
}
|
||||||
|
idValueMap[id] = resourceLocation
|
||||||
|
valueIdMap[resourceLocation] = id
|
||||||
|
}
|
||||||
|
if (idValueMap.isEmpty()) {
|
||||||
|
parent = alternative
|
||||||
|
}
|
||||||
|
initialized = true
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun rawInitialize(data: Map<String, Any>?, alternative: ResourceLocationRegistry? = null): ResourceLocationRegistry {
|
||||||
|
return initialize(data?.toResourceLocationMap(), alternative)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return super.toString() + ": ${idValueMap.size}x"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("TODO")
|
||||||
|
override fun iterator(): Iterator<ResourceLocation> {
|
||||||
|
return idValueMap.values.iterator()
|
||||||
|
}
|
||||||
|
}
|
@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.data.registries.sounds
|
|
||||||
|
|
||||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
|
||||||
import de.bixilon.minosoft.data.registries.registries.Registries
|
|
||||||
import de.bixilon.minosoft.data.registries.registries.registry.RegistryItem
|
|
||||||
import de.bixilon.minosoft.data.registries.registries.registry.ResourceLocationDeserializer
|
|
||||||
|
|
||||||
data class SoundEvent(
|
|
||||||
override val resourceLocation: ResourceLocation,
|
|
||||||
) : RegistryItem() {
|
|
||||||
|
|
||||||
override fun toString(): String {
|
|
||||||
return resourceLocation.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object : ResourceLocationDeserializer<SoundEvent> {
|
|
||||||
override fun deserialize(registries: Registries?, resourceLocation: ResourceLocation, data: Map<String, Any>): SoundEvent {
|
|
||||||
return SoundEvent(
|
|
||||||
resourceLocation = resourceLocation,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,19 @@
|
|||||||
|
package de.bixilon.minosoft.data.world
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.centerf
|
||||||
|
import glm_.vec3.Vec3
|
||||||
|
import glm_.vec3.Vec3i
|
||||||
|
|
||||||
|
interface AbstractAudioPlayer {
|
||||||
|
|
||||||
|
fun playSoundEvent(sound: ResourceLocation, position: Vec3i? = null, volume: Float = 1.0f, pitch: Float = 1.0f) {
|
||||||
|
playSoundEvent(sound, position?.centerf, volume, pitch)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun playSoundEvent(sound: ResourceLocation, position: Vec3? = null, volume: Float = 1.0f, pitch: Float = 1.0f)
|
||||||
|
|
||||||
|
fun stopSound(sound: ResourceLocation)
|
||||||
|
|
||||||
|
// ToDo: Stop category
|
||||||
|
}
|
@ -20,12 +20,10 @@ import de.bixilon.minosoft.data.registries.biomes.Biome
|
|||||||
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
||||||
import de.bixilon.minosoft.data.registries.blocks.types.FluidBlock
|
import de.bixilon.minosoft.data.registries.blocks.types.FluidBlock
|
||||||
import de.bixilon.minosoft.data.registries.dimension.DimensionProperties
|
import de.bixilon.minosoft.data.registries.dimension.DimensionProperties
|
||||||
import de.bixilon.minosoft.data.registries.sounds.SoundEvent
|
|
||||||
import de.bixilon.minosoft.data.world.biome.accessor.BiomeAccessor
|
import de.bixilon.minosoft.data.world.biome.accessor.BiomeAccessor
|
||||||
import de.bixilon.minosoft.data.world.biome.accessor.NoiseBiomeAccessor
|
import de.bixilon.minosoft.data.world.biome.accessor.NoiseBiomeAccessor
|
||||||
import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer
|
import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer
|
||||||
import de.bixilon.minosoft.gui.rendering.particle.types.Particle
|
import de.bixilon.minosoft.gui.rendering.particle.types.Particle
|
||||||
import de.bixilon.minosoft.gui.rendering.sound.AudioPlayer
|
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.blockPosition
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.blockPosition
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.chunkPosition
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.chunkPosition
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkPosition
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkPosition
|
||||||
@ -59,7 +57,7 @@ import kotlin.random.Random
|
|||||||
*/
|
*/
|
||||||
class World(
|
class World(
|
||||||
val connection: PlayConnection,
|
val connection: PlayConnection,
|
||||||
) : BiomeAccessor {
|
) : BiomeAccessor, AbstractAudioPlayer {
|
||||||
val lock = ReadWriteLock()
|
val lock = ReadWriteLock()
|
||||||
var cacheBiomeAccessor: NoiseBiomeAccessor? = null
|
var cacheBiomeAccessor: NoiseBiomeAccessor? = null
|
||||||
val chunks: LockMap<Vec2i, Chunk> = lockMapOf()
|
val chunks: LockMap<Vec2i, Chunk> = lockMapOf()
|
||||||
@ -76,7 +74,7 @@ class World(
|
|||||||
var thunderGradient = 0.0f
|
var thunderGradient = 0.0f
|
||||||
private val random = Random
|
private val random = Random
|
||||||
|
|
||||||
var audioPlayer: AudioPlayer? = null
|
var audioPlayer: AbstractAudioPlayer? = null
|
||||||
var particleRenderer: ParticleRenderer? = null
|
var particleRenderer: ParticleRenderer? = null
|
||||||
|
|
||||||
operator fun get(blockPosition: Vec3i): BlockState? {
|
operator fun get(blockPosition: Vec3i): BlockState? {
|
||||||
@ -188,20 +186,13 @@ class World(
|
|||||||
return ret.toMap()
|
return ret.toMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun playSoundEvent(resourceLocation: ResourceLocation, position: Vec3i? = null, volume: Float = 1.0f, pitch: Float = 1.0f) {
|
|
||||||
audioPlayer?.playSoundEvent(resourceLocation, position, volume, pitch)
|
override fun playSoundEvent(sound: ResourceLocation, position: Vec3?, volume: Float, pitch: Float) {
|
||||||
|
audioPlayer?.playSoundEvent(sound, position, volume, pitch)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun playSoundEvent(resourceLocation: ResourceLocation, position: Vec3? = null, volume: Float = 1.0f, pitch: Float = 1.0f) {
|
override fun stopSound(sound: ResourceLocation) {
|
||||||
audioPlayer?.playSoundEvent(resourceLocation, position, volume, pitch)
|
audioPlayer?.stopSound(sound)
|
||||||
}
|
|
||||||
|
|
||||||
fun playSoundEvent(soundEvent: SoundEvent, position: Vec3i? = null, volume: Float = 1.0f, pitch: Float = 1.0f) {
|
|
||||||
audioPlayer?.playSoundEvent(soundEvent, position, volume, pitch)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun playSoundEvent(soundEvent: SoundEvent, position: Vec3? = null, volume: Float = 1.0f, pitch: Float = 1.0f) {
|
|
||||||
audioPlayer?.playSoundEvent(soundEvent, position, volume, pitch)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addParticle(particle: Particle) {
|
fun addParticle(particle: Particle) {
|
||||||
|
@ -43,9 +43,7 @@ class WeightedBakedModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getModel(random: Random): BakedBlockModel {
|
private fun getModel(random: Random): BakedBlockModel {
|
||||||
val totalWeight = abs(random.nextLong() % totalWeight)
|
var weightLeft = abs(random.nextLong() % totalWeight)
|
||||||
|
|
||||||
var weightLeft = totalWeight
|
|
||||||
|
|
||||||
for ((model, weight) in models) {
|
for ((model, weight) in models) {
|
||||||
weightLeft -= weight
|
weightLeft -= weight
|
||||||
|
@ -13,35 +13,24 @@
|
|||||||
|
|
||||||
package de.bixilon.minosoft.gui.rendering.sound
|
package de.bixilon.minosoft.gui.rendering.sound
|
||||||
|
|
||||||
import com.google.gson.JsonArray
|
|
||||||
import de.bixilon.minosoft.Minosoft
|
import de.bixilon.minosoft.Minosoft
|
||||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
import de.bixilon.minosoft.data.registries.sounds.SoundEvent
|
import de.bixilon.minosoft.data.world.AbstractAudioPlayer
|
||||||
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.input.camera.Camera
|
||||||
import de.bixilon.minosoft.gui.rendering.modding.events.CameraPositionChangeEvent
|
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.util.VecUtil.centerf
|
|
||||||
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY
|
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY
|
||||||
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
|
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
|
||||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
|
||||||
import de.bixilon.minosoft.util.CountUpAndDownLatch
|
import de.bixilon.minosoft.util.CountUpAndDownLatch
|
||||||
import de.bixilon.minosoft.util.KUtil.nullCast
|
|
||||||
import de.bixilon.minosoft.util.KUtil.synchronizedListOf
|
import de.bixilon.minosoft.util.KUtil.synchronizedListOf
|
||||||
import de.bixilon.minosoft.util.KUtil.toBoolean
|
|
||||||
import de.bixilon.minosoft.util.KUtil.toInt
|
|
||||||
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
|
||||||
import de.bixilon.minosoft.util.KUtil.toSynchronizedList
|
import de.bixilon.minosoft.util.KUtil.toSynchronizedList
|
||||||
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
|
||||||
import de.bixilon.minosoft.util.Queue
|
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 de.bixilon.minosoft.util.nbt.tag.NBTUtil.listCast
|
|
||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
import glm_.vec3.Vec3i
|
|
||||||
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.*
|
||||||
@ -54,14 +43,13 @@ import java.nio.IntBuffer
|
|||||||
class AudioPlayer(
|
class AudioPlayer(
|
||||||
val connection: PlayConnection,
|
val connection: PlayConnection,
|
||||||
val rendering: Rendering,
|
val rendering: Rendering,
|
||||||
) {
|
) : AbstractAudioPlayer {
|
||||||
private val sounds: MutableMap<SoundEvent, SoundList> = mutableMapOf()
|
private val soundManager = SoundManager(connection)
|
||||||
|
|
||||||
var initialized = false
|
var initialized = false
|
||||||
private set
|
private set
|
||||||
|
|
||||||
private var device = 0L
|
private var device = -1L
|
||||||
private var context = 0L
|
private var context = -1L
|
||||||
|
|
||||||
private val queue = Queue()
|
private val queue = Queue()
|
||||||
private lateinit var listener: SoundListener
|
private lateinit var listener: SoundListener
|
||||||
@ -74,27 +62,12 @@ class AudioPlayer(
|
|||||||
get() = sources.size
|
get() = sources.size
|
||||||
|
|
||||||
|
|
||||||
private fun preloadSounds() {
|
|
||||||
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.VERBOSE) { "Preloading sounds..." }
|
|
||||||
if (SoundConstants.DISABLE_PRELOADING) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for (soundList in sounds.values) {
|
|
||||||
for (sound in soundList.sounds) {
|
|
||||||
if (SoundConstants.PRELOAD_ALL_SOUNDS || sound.preload) {
|
|
||||||
sound.load(connection.assetsManager)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun init(latch: CountUpAndDownLatch) {
|
fun init(latch: CountUpAndDownLatch) {
|
||||||
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.INFO) { "Loading OpenAL..." }
|
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.INFO) { "Loading OpenAL..." }
|
||||||
|
|
||||||
loadSounds()
|
soundManager.load()
|
||||||
preloadSounds()
|
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.VERBOSE) { "Preloading sounds..." }
|
||||||
|
soundManager.preload()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -125,31 +98,33 @@ class AudioPlayer(
|
|||||||
|
|
||||||
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.INFO) { "OpenAL loaded!" }
|
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.INFO) { "OpenAL loaded!" }
|
||||||
|
|
||||||
|
|
||||||
initialized = true
|
initialized = true
|
||||||
connection.world.audioPlayer = this
|
connection.world.audioPlayer = this
|
||||||
latch.dec()
|
latch.dec()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun playSoundEvent(resourceLocation: ResourceLocation, position: Vec3i? = null, volume: Float = 1.0f, pitch: Float = 1.0f) {
|
override fun playSoundEvent(sound: ResourceLocation, position: Vec3?, volume: Float, pitch: Float) {
|
||||||
connection.registries.soundEventRegistry[resourceLocation]?.let { playSoundEvent(it, position?.centerf, volume, pitch) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun playSoundEvent(resourceLocation: ResourceLocation, position: Vec3? = null, volume: Float = 1.0f, pitch: Float = 1.0f) {
|
|
||||||
connection.registries.soundEventRegistry[resourceLocation]?.let { playSoundEvent(it, position, volume, pitch) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun playSoundEvent(soundEvent: SoundEvent, position: Vec3i? = null, volume: Float = 1.0f, pitch: Float = 1.0f) {
|
|
||||||
playSoundEvent(soundEvent, position?.centerf, volume, pitch)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun playSoundEvent(soundEvent: SoundEvent, position: Vec3? = null, volume: Float = 1.0f, pitch: Float = 1.0f) {
|
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
playSound(sounds[soundEvent]!!.getRandom(), position, volume, pitch)
|
playSound(soundManager[sound] ?: return, position, volume, pitch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun stopSound(sound: ResourceLocation) {
|
||||||
|
queue += {
|
||||||
|
for (source in sources) {
|
||||||
|
if (!source.isPlaying) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (source.sound?.soundEvent != sound) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
source.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
private fun getAvailableSource(): SoundSource? {
|
private fun getAvailableSource(): SoundSource? {
|
||||||
for (source in sources.toSynchronizedList()) {
|
for (source in sources.toSynchronizedList()) {
|
||||||
if (source.available) {
|
if (source.available) {
|
||||||
@ -169,11 +144,8 @@ class AudioPlayer(
|
|||||||
private fun playSound(sound: Sound, position: Vec3? = null, volume: Float = 1.0f, pitch: Float = 1.0f) {
|
private 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) {
|
val source = getAvailableSource()
|
||||||
return@add
|
if (source == null) {
|
||||||
}
|
|
||||||
val source = getAvailableSource() ?: let {
|
|
||||||
// ToDo: Queue sound for later (and check a certain delay to not make the game feel laggy)
|
|
||||||
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.WARN) { "Can not play sound: No source available: $sound" }
|
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.WARN) { "Can not play sound: No source available: $sound" }
|
||||||
return@add
|
return@add
|
||||||
}
|
}
|
||||||
@ -191,20 +163,23 @@ class AudioPlayer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun calculateAvailableSources() {
|
||||||
|
var availableSources = 0
|
||||||
|
for (source in sources) {
|
||||||
|
if (source.available) {
|
||||||
|
availableSources++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.availableSources = availableSources
|
||||||
|
}
|
||||||
|
|
||||||
fun startLoop() {
|
fun startLoop() {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (connection.wasConnected || connection.error != null) {
|
if (connection.wasConnected || connection.error != null) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
queue.work()
|
queue.work()
|
||||||
|
calculateAvailableSources()
|
||||||
var availableSources = 0
|
|
||||||
for (source in sources) {
|
|
||||||
if (source.available) {
|
|
||||||
availableSources++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.availableSources = availableSources
|
|
||||||
|
|
||||||
Thread.sleep(1L)
|
Thread.sleep(1L)
|
||||||
}
|
}
|
||||||
@ -214,11 +189,8 @@ class AudioPlayer(
|
|||||||
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.INFO) { "Unloading OpenAL..." }
|
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.INFO) { "Unloading OpenAL..." }
|
||||||
|
|
||||||
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.VERBOSE) { "Unloading sounds..." }
|
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.VERBOSE) { "Unloading sounds..." }
|
||||||
for (soundList in sounds.values) {
|
soundManager.unload()
|
||||||
for (sound in soundList.sounds) {
|
|
||||||
sound.unload()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.VERBOSE) { "Unloading sources..." }
|
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.VERBOSE) { "Unloading sources..." }
|
||||||
for (source in sources.toSynchronizedList()) {
|
for (source in sources.toSynchronizedList()) {
|
||||||
source.unload()
|
source.unload()
|
||||||
@ -229,53 +201,7 @@ class AudioPlayer(
|
|||||||
alcSetThreadContext(MemoryUtil.NULL)
|
alcSetThreadContext(MemoryUtil.NULL)
|
||||||
alcDestroyContext(context)
|
alcDestroyContext(context)
|
||||||
alcCloseDevice(device)
|
alcCloseDevice(device)
|
||||||
|
|
||||||
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.INFO) { "Unloaded OpenAL!" }
|
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.INFO) { "Unloaded OpenAL!" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("Refactoring needed")
|
|
||||||
private fun loadSounds() {
|
|
||||||
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.VERBOSE) { "Loading sounds.json" }
|
|
||||||
val data = connection.assetsManager.readJsonAsset(SOUNDS_INDEX_FILE)
|
|
||||||
|
|
||||||
for ((soundEventResourceLocation, json) in data) {
|
|
||||||
check(json is Map<*, *>)
|
|
||||||
val soundEvent = connection.registries.soundEventRegistry[ResourceLocation(soundEventResourceLocation)]!!
|
|
||||||
|
|
||||||
val sounds: MutableSet<Sound> = mutableSetOf()
|
|
||||||
|
|
||||||
fun String.getSoundLocation(): ResourceLocation {
|
|
||||||
return ResourceLocation(ProtocolDefinition.DEFAULT_NAMESPACE, "sounds/${this}".replace('.', '/') + ".ogg") // ToDo: Resource Location
|
|
||||||
}
|
|
||||||
|
|
||||||
for (soundJson in json["sounds"]!!.listCast<Any>()!!) {
|
|
||||||
when (soundJson) {
|
|
||||||
is String -> {
|
|
||||||
sounds += Sound(soundJson.getSoundLocation())
|
|
||||||
}
|
|
||||||
is Map<*, *> -> {
|
|
||||||
sounds += Sound(
|
|
||||||
path = soundJson["name"].unsafeCast<String>().getSoundLocation(),
|
|
||||||
volume = soundJson["volume"]?.unsafeCast<Double>()?.toFloat() ?: 1.0f,
|
|
||||||
pitch = soundJson["pitch"]?.unsafeCast<Double>()?.toFloat() ?: 1.0f,
|
|
||||||
weight = soundJson["weight"]?.toInt() ?: 1,
|
|
||||||
stream = soundJson["stream"]?.toBoolean() ?: false,
|
|
||||||
attenuationDistance = soundJson["attenuation_distance"]?.toInt() ?: 16,
|
|
||||||
preload = soundJson["preload"]?.toBoolean() ?: false,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is JsonArray -> TODO()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.sounds[soundEvent] = SoundList(
|
|
||||||
soundEvent = soundEvent,
|
|
||||||
sounds = sounds.toSet(),
|
|
||||||
subTitle = json["subtitle"].nullCast<String>()?.let { ResourceLocation(ProtocolDefinition.DEFAULT_NAMESPACE, it) },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val SOUNDS_INDEX_FILE = "minecraft:sounds.json".toResourceLocation()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
package de.bixilon.minosoft.gui.rendering.sound
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
|
import de.bixilon.minosoft.gui.rendering.sound.sounds.Sound
|
||||||
|
import de.bixilon.minosoft.gui.rendering.sound.sounds.SoundType
|
||||||
|
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||||
|
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||||
|
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.asCompound
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class SoundManager(
|
||||||
|
private val connection: PlayConnection,
|
||||||
|
) {
|
||||||
|
private val random = Random()
|
||||||
|
private val sounds: MutableMap<ResourceLocation, SoundType> = mutableMapOf()
|
||||||
|
|
||||||
|
|
||||||
|
fun load() {
|
||||||
|
val soundsIndex = connection.assetsManager.readJsonAsset(SOUNDS_INDEX_FILE)
|
||||||
|
|
||||||
|
for ((name, data) in soundsIndex) {
|
||||||
|
val resourceLocation = name.toResourceLocation()
|
||||||
|
sounds[resourceLocation] = SoundType(resourceLocation, data.asCompound())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun unload() {
|
||||||
|
for (soundType in sounds.values) {
|
||||||
|
for (sound in soundType.sounds) {
|
||||||
|
sound.unload()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun preload() {
|
||||||
|
for (soundType in sounds.values) {
|
||||||
|
for (sound in soundType.sounds) {
|
||||||
|
if (!sound.preload) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sound.load(connection.assetsManager)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun get(sound: ResourceLocation): Sound? {
|
||||||
|
return sounds[sound]?.getSound(random)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val SOUNDS_INDEX_FILE = "minecraft:sounds.json".toResourceLocation()
|
||||||
|
}
|
||||||
|
}
|
@ -61,11 +61,15 @@ class SoundSource {
|
|||||||
var sound: Sound? = null
|
var sound: Sound? = null
|
||||||
set(value) {
|
set(value) {
|
||||||
stop()
|
stop()
|
||||||
if (value?.loaded != true || value.loadFailed) {
|
val buffer = value?.buffer
|
||||||
|
if (buffer == null) {
|
||||||
field = null
|
field = null
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
alSourcei(source, AL_BUFFER, value.buffer)
|
if (buffer.unloaded) {
|
||||||
|
throw IllegalArgumentException("OpenAL buffer is not loaded: ${value.soundEvent}")
|
||||||
|
}
|
||||||
|
alSourcei(source, AL_BUFFER, buffer.buffer)
|
||||||
field = value
|
field = value
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +77,7 @@ class SoundSource {
|
|||||||
get() = alGetSourcei(source, AL_SOURCE_STATE) == AL_PLAYING
|
get() = alGetSourcei(source, AL_SOURCE_STATE) == AL_PLAYING
|
||||||
|
|
||||||
val available: Boolean
|
val available: Boolean
|
||||||
get() = !isPlaying || System.currentTimeMillis() - playTime > (sound?.length ?: 0L) // ToDo: Allow pause
|
get() = !isPlaying || System.currentTimeMillis() - playTime > (sound?.data?.length ?: 0L) // ToDo: Allow pause
|
||||||
|
|
||||||
fun play() {
|
fun play() {
|
||||||
playTime = System.currentTimeMillis()
|
playTime = System.currentTimeMillis()
|
||||||
|
@ -11,18 +11,25 @@
|
|||||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package de.bixilon.minosoft.gui.rendering.sound.sounds
|
package de.bixilon.minosoft.gui.rendering.sound
|
||||||
|
|
||||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
import de.bixilon.minosoft.data.registries.sounds.SoundEvent
|
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||||
|
|
||||||
data class SoundList(
|
object SoundUtil {
|
||||||
val soundEvent: SoundEvent,
|
fun ResourceLocation.sound(): ResourceLocation {
|
||||||
val sounds: Set<Sound>,
|
var path = ""
|
||||||
val subTitle: ResourceLocation?,
|
|
||||||
) {
|
if (!this.path.startsWith("sounds/")) {
|
||||||
fun getRandom(): Sound {
|
path += "sounds/"
|
||||||
// ToDo: Support weight
|
}
|
||||||
return sounds.random()
|
path += this.path
|
||||||
|
|
||||||
|
if (!path.contains(".")) {
|
||||||
|
// ending
|
||||||
|
path += ".ogg"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "$namespace:$path".toResourceLocation()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package de.bixilon.minosoft.gui.rendering.sound.sounds
|
||||||
|
|
||||||
|
import org.lwjgl.openal.AL10.*
|
||||||
|
import org.lwjgl.system.MemoryUtil.memFree
|
||||||
|
import java.nio.ShortBuffer
|
||||||
|
|
||||||
|
class OpenALBuffer(
|
||||||
|
val data: SoundData,
|
||||||
|
) {
|
||||||
|
val buffer: Int
|
||||||
|
private val pcm: ShortBuffer
|
||||||
|
var unloaded: Boolean = false
|
||||||
|
private set
|
||||||
|
|
||||||
|
init {
|
||||||
|
val pcm = data.createPCM()
|
||||||
|
this.pcm = pcm
|
||||||
|
|
||||||
|
this.buffer = alGenBuffers()
|
||||||
|
|
||||||
|
alBufferData(buffer, data.format, pcm, data.sampleRate)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun unload() {
|
||||||
|
if (unloaded) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
alDeleteBuffers(buffer)
|
||||||
|
memFree(pcm)
|
||||||
|
unloaded = true
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun finalize() {
|
||||||
|
unload()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -15,102 +15,80 @@ package de.bixilon.minosoft.gui.rendering.sound.sounds
|
|||||||
|
|
||||||
import de.bixilon.minosoft.data.assets.AssetsManager
|
import de.bixilon.minosoft.data.assets.AssetsManager
|
||||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
|
import de.bixilon.minosoft.gui.rendering.sound.SoundUtil.sound
|
||||||
|
import de.bixilon.minosoft.util.KUtil.toBoolean
|
||||||
|
import de.bixilon.minosoft.util.KUtil.toFloat
|
||||||
|
import de.bixilon.minosoft.util.KUtil.toInt
|
||||||
|
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||||
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 org.lwjgl.BufferUtils
|
|
||||||
import org.lwjgl.openal.AL10.*
|
|
||||||
import org.lwjgl.stb.STBVorbis.*
|
|
||||||
import org.lwjgl.stb.STBVorbisInfo
|
|
||||||
import org.lwjgl.system.MemoryUtil
|
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
import java.nio.ByteBuffer
|
|
||||||
|
|
||||||
data class Sound(
|
data class Sound(
|
||||||
|
val soundEvent: ResourceLocation,
|
||||||
val path: ResourceLocation,
|
val path: ResourceLocation,
|
||||||
val volume: Float = 1.0f,
|
val volume: Float = 1.0f,
|
||||||
val pitch: Float = 1.0f,
|
val pitch: Float = 1.0f,
|
||||||
val weight: Int = 1,
|
val weight: Int = 1,
|
||||||
val stream: Boolean = false, // ToDo
|
val stream: Boolean = false, // ToDo: Implement
|
||||||
val attenuationDistance: Int = 16,
|
val attenuationDistance: Int = 16, // ToDo: Implement
|
||||||
val preload: Boolean = false,
|
val preload: Boolean = false,
|
||||||
// ToDo: type
|
|
||||||
) {
|
) {
|
||||||
var length: Long = -1L
|
var data: SoundData? = null
|
||||||
private set
|
private set
|
||||||
var loaded: Boolean = false
|
var buffer: OpenALBuffer? = null
|
||||||
private set
|
private set
|
||||||
var loadFailed: Boolean = false
|
|
||||||
private set
|
|
||||||
var channels: Int = -1
|
|
||||||
private set
|
|
||||||
var sampleRate: Int = -1
|
|
||||||
private set
|
|
||||||
var samplesLength: Int = -1
|
|
||||||
private set
|
|
||||||
var sampleSeconds: Float = -1.0f
|
|
||||||
private set
|
|
||||||
var buffer = -1
|
|
||||||
private set
|
|
||||||
|
|
||||||
private var vorbisBuffer: ByteBuffer? = null
|
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun load(assetsManager: AssetsManager) {
|
fun load(assetsManager: AssetsManager) {
|
||||||
if (loaded || loadFailed) {
|
if (data != null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.VERBOSE) { "Loading audio file: $path" }
|
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.VERBOSE) { "Loading audio file: $path" }
|
||||||
try {
|
try {
|
||||||
val vorbisBuffer = assetsManager.readByteAsset(path)
|
val data = SoundData(assetsManager, this)
|
||||||
this.vorbisBuffer = vorbisBuffer
|
this.data = data
|
||||||
|
this.buffer = OpenALBuffer(data)
|
||||||
val error = BufferUtils.createIntBuffer(1)
|
|
||||||
val vorbis = stb_vorbis_open_memory(vorbisBuffer, error, null)
|
|
||||||
if (vorbis == MemoryUtil.NULL) {
|
|
||||||
throw IllegalStateException("Can not load vorbis: ${path}: ${error[0]}")
|
|
||||||
}
|
|
||||||
val info = stb_vorbis_get_info(vorbis, STBVorbisInfo.malloc())
|
|
||||||
channels = info.channels()
|
|
||||||
val format = when (channels) {
|
|
||||||
1 -> AL_FORMAT_MONO16
|
|
||||||
2 -> AL_FORMAT_STEREO16
|
|
||||||
else -> error("Don't know vorbis channels: $channels")
|
|
||||||
}
|
|
||||||
sampleRate = info.sample_rate()
|
|
||||||
|
|
||||||
samplesLength = stb_vorbis_stream_length_in_samples(vorbis)
|
|
||||||
sampleSeconds = stb_vorbis_stream_length_in_seconds(vorbis)
|
|
||||||
length = (sampleSeconds * 1000).toLong()
|
|
||||||
|
|
||||||
|
|
||||||
val pcm = BufferUtils.createShortBuffer(samplesLength)
|
|
||||||
|
|
||||||
pcm.limit(stb_vorbis_get_samples_short_interleaved(vorbis, channels, pcm) * channels)
|
|
||||||
//ToDo: Somehow crashed?: MemoryUtil.memFree(vorbisBuffer)
|
|
||||||
|
|
||||||
this.buffer = alGenBuffers()
|
|
||||||
|
|
||||||
alBufferData(buffer, format, pcm, sampleRate)
|
|
||||||
loaded = true
|
|
||||||
} catch (exception: FileNotFoundException) {
|
} catch (exception: FileNotFoundException) {
|
||||||
loadFailed = true
|
|
||||||
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.WARN) { "Can not load sound: $path: $exception" }
|
Log.log(LogMessageType.AUDIO_LOADING, LogLevels.WARN) { "Can not load sound: $path: $exception" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun unload() {
|
fun unload() {
|
||||||
if (!loaded) {
|
data?.unload()
|
||||||
return
|
buffer?.unload()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun finalize() {
|
||||||
|
unload()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
operator fun invoke(soundEvent: ResourceLocation, data: Any): Sound {
|
||||||
|
if (data is String) {
|
||||||
|
return Sound(
|
||||||
|
soundEvent = soundEvent,
|
||||||
|
path = data.toResourceLocation().sound(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
check(data is Map<*, *>)
|
||||||
|
|
||||||
|
// ToDo: "type" attribute: event
|
||||||
|
|
||||||
|
return Sound(
|
||||||
|
soundEvent = soundEvent,
|
||||||
|
path = data["name"].toResourceLocation(),
|
||||||
|
volume = data["volume"]?.toFloat() ?: 1.0f,
|
||||||
|
pitch = data["pitch"]?.toFloat() ?: 1.0f,
|
||||||
|
weight = data["weight"]?.toInt() ?: 1,
|
||||||
|
stream = data["stream"]?.toBoolean() ?: false,
|
||||||
|
attenuationDistance = data["attenuation_distance"]?.toInt() ?: 16,
|
||||||
|
preload = data["preload"]?.toBoolean() ?: false,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
alDeleteBuffers(buffer)
|
|
||||||
vorbisBuffer?.let { MemoryUtil.memFree(it) }
|
|
||||||
buffer = -1
|
|
||||||
channels = -1
|
|
||||||
sampleRate = -1
|
|
||||||
samplesLength = -1
|
|
||||||
sampleSeconds = -1.0f
|
|
||||||
loaded = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
package de.bixilon.minosoft.gui.rendering.sound.sounds
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.data.assets.AssetsManager
|
||||||
|
import org.lwjgl.BufferUtils
|
||||||
|
import org.lwjgl.openal.AL10.AL_FORMAT_MONO16
|
||||||
|
import org.lwjgl.openal.AL10.AL_FORMAT_STEREO16
|
||||||
|
import org.lwjgl.stb.STBVorbis.*
|
||||||
|
import org.lwjgl.stb.STBVorbisInfo
|
||||||
|
import org.lwjgl.system.MemoryUtil
|
||||||
|
import org.lwjgl.system.MemoryUtil.memFree
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.nio.ShortBuffer
|
||||||
|
|
||||||
|
class SoundData(
|
||||||
|
val vorbis: Long,
|
||||||
|
val format: Int,
|
||||||
|
val buffer: ByteBuffer,
|
||||||
|
val length: Long,
|
||||||
|
val channels: Int,
|
||||||
|
val sampleRate: Int,
|
||||||
|
val samplesLength: Int,
|
||||||
|
val sampleSeconds: Float,
|
||||||
|
) {
|
||||||
|
private var unloaded = false
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun unload() {
|
||||||
|
if (unloaded) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
memFree(buffer)
|
||||||
|
unloaded = true
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun finalize() {
|
||||||
|
unload()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createPCM(): ShortBuffer {
|
||||||
|
val pcm = BufferUtils.createShortBuffer(samplesLength)
|
||||||
|
pcm.limit(stb_vorbis_get_samples_short_interleaved(vorbis, channels, pcm) * channels)
|
||||||
|
return pcm
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
operator fun invoke(assetsManager: AssetsManager, sound: Sound): SoundData {
|
||||||
|
val buffer = assetsManager.readByteAsset(sound.path)
|
||||||
|
|
||||||
|
val error = BufferUtils.createIntBuffer(1)
|
||||||
|
val vorbis = stb_vorbis_open_memory(buffer, error, null)
|
||||||
|
if (vorbis == MemoryUtil.NULL) {
|
||||||
|
throw IllegalStateException("Can not load vorbis: ${sound.path}: ${error[0]}")
|
||||||
|
}
|
||||||
|
val info = stb_vorbis_get_info(vorbis, STBVorbisInfo.malloc())
|
||||||
|
val channels = info.channels()
|
||||||
|
val format = when (channels) {
|
||||||
|
1 -> AL_FORMAT_MONO16
|
||||||
|
2 -> AL_FORMAT_STEREO16
|
||||||
|
else -> error("Don't know vorbis channels: $channels")
|
||||||
|
}
|
||||||
|
val sampleRate = info.sample_rate()
|
||||||
|
|
||||||
|
val samplesLength = stb_vorbis_stream_length_in_samples(vorbis)
|
||||||
|
val sampleSeconds = stb_vorbis_stream_length_in_seconds(vorbis)
|
||||||
|
val length = (sampleSeconds * 1000).toLong()
|
||||||
|
|
||||||
|
return SoundData(
|
||||||
|
vorbis = vorbis,
|
||||||
|
format = format,
|
||||||
|
buffer = buffer,
|
||||||
|
length = length,
|
||||||
|
channels = channels,
|
||||||
|
sampleRate = sampleRate,
|
||||||
|
samplesLength = samplesLength,
|
||||||
|
sampleSeconds = sampleSeconds
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* 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.sound.sounds
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
|
import de.bixilon.minosoft.util.KUtil.asList
|
||||||
|
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
data class SoundType(
|
||||||
|
val soundEvent: ResourceLocation,
|
||||||
|
val sounds: Set<Sound>,
|
||||||
|
val subtitle: ResourceLocation?,
|
||||||
|
) {
|
||||||
|
val totalWeight: Int
|
||||||
|
|
||||||
|
init {
|
||||||
|
var totalWeight = 0
|
||||||
|
for (sound in sounds) {
|
||||||
|
totalWeight += sound.weight
|
||||||
|
}
|
||||||
|
|
||||||
|
this.totalWeight = totalWeight
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSound(random: Random): Sound {
|
||||||
|
var weightLeft = abs(random.nextLong() % totalWeight)
|
||||||
|
|
||||||
|
for (sound in sounds) {
|
||||||
|
weightLeft -= sound.weight
|
||||||
|
if (weightLeft < 0) {
|
||||||
|
return sound
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw IllegalStateException("Could not find sound: This should never happen!")
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
operator fun invoke(soundEvent: ResourceLocation, data: Map<String, Any>): SoundType {
|
||||||
|
// ToDo: "replace" attribute
|
||||||
|
val subtitle = data["subtitle"]?.toResourceLocation()
|
||||||
|
val sounds: MutableSet<Sound> = mutableSetOf()
|
||||||
|
|
||||||
|
for (soundData in data["sounds"].asList()) {
|
||||||
|
sounds += Sound(soundEvent, soundData)
|
||||||
|
}
|
||||||
|
return SoundType(
|
||||||
|
soundEvent = soundEvent,
|
||||||
|
sounds = sounds,
|
||||||
|
subtitle = subtitle,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,7 @@
|
|||||||
package de.bixilon.minosoft.modding.event.events
|
package de.bixilon.minosoft.modding.event.events
|
||||||
|
|
||||||
import de.bixilon.minosoft.data.SoundCategories
|
import de.bixilon.minosoft.data.SoundCategories
|
||||||
import de.bixilon.minosoft.data.registries.sounds.SoundEvent
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
import de.bixilon.minosoft.modding.event.EventInitiators
|
import de.bixilon.minosoft.modding.event.EventInitiators
|
||||||
import de.bixilon.minosoft.modding.event.events.connection.play.PlayConnectionEvent
|
import de.bixilon.minosoft.modding.event.events.connection.play.PlayConnectionEvent
|
||||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||||
@ -27,7 +27,7 @@ class PlaySoundEvent(
|
|||||||
initiator: EventInitiators,
|
initiator: EventInitiators,
|
||||||
val category: SoundCategories?,
|
val category: SoundCategories?,
|
||||||
position: Vec3,
|
position: Vec3,
|
||||||
val soundEvent: SoundEvent,
|
val soundEvent: ResourceLocation,
|
||||||
val volume: Float,
|
val volume: Float,
|
||||||
val pitch: Float,
|
val pitch: Float,
|
||||||
) : PlayConnectionEvent(connection, initiator), CancelableEvent {
|
) : PlayConnectionEvent(connection, initiator), CancelableEvent {
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
package de.bixilon.minosoft.protocol.packets.s2c.play
|
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.registries.sounds.SoundEvent
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
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.util.logging.Log
|
import de.bixilon.minosoft.util.logging.Log
|
||||||
@ -21,7 +21,7 @@ import de.bixilon.minosoft.util.logging.LogLevels
|
|||||||
import de.bixilon.minosoft.util.logging.LogMessageType
|
import de.bixilon.minosoft.util.logging.LogMessageType
|
||||||
|
|
||||||
class EntitySoundEventS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
class EntitySoundEventS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||||
val soundEvent: SoundEvent = buffer.connection.registries.soundEventRegistry[buffer.readVarInt()]
|
val soundEvent: ResourceLocation = buffer.connection.registries.soundEventRegistry[buffer.readVarInt()]!!
|
||||||
val category: SoundCategories = SoundCategories[buffer.readVarInt()]
|
val category: SoundCategories = SoundCategories[buffer.readVarInt()]
|
||||||
val entityId: Int = buffer.readVarInt()
|
val entityId: Int = buffer.readVarInt()
|
||||||
val volume: Float = buffer.readFloat()
|
val volume: Float = buffer.readFloat()
|
||||||
@ -30,5 +30,4 @@ class EntitySoundEventS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
|||||||
override fun log() {
|
override fun log() {
|
||||||
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Entity sound effect (soundEvent=$soundEvent, category=$category, entityId$entityId, volume=$volume, pitch=$pitch)" }
|
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Entity sound effect (soundEvent=$soundEvent, category=$category, entityId$entityId, volume=$volume, pitch=$pitch)" }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ package de.bixilon.minosoft.protocol.packets.s2c.play
|
|||||||
|
|
||||||
import de.bixilon.minosoft.Minosoft
|
import de.bixilon.minosoft.Minosoft
|
||||||
import de.bixilon.minosoft.data.SoundCategories
|
import de.bixilon.minosoft.data.SoundCategories
|
||||||
import de.bixilon.minosoft.data.registries.sounds.SoundEvent
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
import de.bixilon.minosoft.modding.event.events.PlaySoundEvent
|
import de.bixilon.minosoft.modding.event.events.PlaySoundEvent
|
||||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||||
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
|
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
|
||||||
@ -27,7 +27,7 @@ import de.bixilon.minosoft.util.logging.LogMessageType
|
|||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
|
|
||||||
class NamedSoundEventS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
class NamedSoundEventS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||||
val soundEvent: SoundEvent?
|
val soundEvent: ResourceLocation?
|
||||||
val volume: Float
|
val volume: Float
|
||||||
val pitch: Float
|
val pitch: Float
|
||||||
lateinit var position: Vec3
|
lateinit var position: Vec3
|
||||||
|
@ -14,7 +14,7 @@ package de.bixilon.minosoft.protocol.packets.s2c.play
|
|||||||
|
|
||||||
import de.bixilon.minosoft.Minosoft
|
import de.bixilon.minosoft.Minosoft
|
||||||
import de.bixilon.minosoft.data.SoundCategories
|
import de.bixilon.minosoft.data.SoundCategories
|
||||||
import de.bixilon.minosoft.data.registries.sounds.SoundEvent
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
import de.bixilon.minosoft.modding.event.events.PlaySoundEvent
|
import de.bixilon.minosoft.modding.event.events.PlaySoundEvent
|
||||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||||
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
|
import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket
|
||||||
@ -30,7 +30,7 @@ class SoundEventS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
|||||||
var category: SoundCategories? = null
|
var category: SoundCategories? = null
|
||||||
private set
|
private set
|
||||||
val position: Vec3i
|
val position: Vec3i
|
||||||
val soundEvent: SoundEvent
|
val soundEvent: ResourceLocation
|
||||||
val volume: Float
|
val volume: Float
|
||||||
val pitch: Float
|
val pitch: Float
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ class SoundEventS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
|||||||
// category was moved to the top
|
// category was moved to the top
|
||||||
this.category = SoundCategories[buffer.readVarInt()]
|
this.category = SoundCategories[buffer.readVarInt()]
|
||||||
}
|
}
|
||||||
soundEvent = buffer.connection.registries.soundEventRegistry[buffer.readVarInt()]
|
soundEvent = buffer.connection.registries.soundEventRegistry[buffer.readVarInt()]!!
|
||||||
if (buffer.versionId >= ProtocolVersions.V_17W15A && buffer.versionId < ProtocolVersions.V_17W18A) {
|
if (buffer.versionId >= ProtocolVersions.V_17W15A && buffer.versionId < ProtocolVersions.V_17W18A) {
|
||||||
buffer.readString() // parrot entity type
|
buffer.readString() // parrot entity type
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ 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.registries.ResourceLocation
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
|
import de.bixilon.minosoft.protocol.network.connection.play.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.ProtocolVersions
|
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions
|
||||||
@ -21,7 +22,6 @@ import de.bixilon.minosoft.util.BitByte.isBitMask
|
|||||||
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 java.util.*
|
|
||||||
|
|
||||||
class StopSoundS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
class StopSoundS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
||||||
val category: SoundCategories?
|
val category: SoundCategories?
|
||||||
@ -31,7 +31,7 @@ class StopSoundS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
|||||||
var category: SoundCategories? = null
|
var category: SoundCategories? = null
|
||||||
var sound: ResourceLocation? = null
|
var sound: ResourceLocation? = null
|
||||||
if (buffer.versionId < ProtocolVersions.V_17W45A) { // ToDo: these 2 values need to be switched in before 1.12.2
|
if (buffer.versionId < ProtocolVersions.V_17W45A) { // ToDo: these 2 values need to be switched in before 1.12.2
|
||||||
category = SoundCategories.valueOf(buffer.readString().uppercase(Locale.getDefault()))
|
category = SoundCategories.valueOf(buffer.readString().uppercase())
|
||||||
sound = buffer.readResourceLocation()
|
sound = buffer.readResourceLocation()
|
||||||
} else {
|
} else {
|
||||||
val flags = buffer.readByte()
|
val flags = buffer.readByte()
|
||||||
@ -46,6 +46,11 @@ class StopSoundS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
|||||||
this.sound = sound
|
this.sound = sound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun handle(connection: PlayConnection) {
|
||||||
|
sound?.let { connection.world.stopSound(it) }
|
||||||
|
// ToDo: Category
|
||||||
|
}
|
||||||
|
|
||||||
override fun log() {
|
override fun log() {
|
||||||
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Stop sound (category=$category, sound=$sound)" }
|
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Stop sound (category=$category, sound=$sound)" }
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user