From 483fdd80f2fcb4bcaad734448e53e088a8faec6e Mon Sep 17 00:00:00 2001 From: Bixilon Date: Wed, 26 May 2021 22:55:01 +0200 Subject: [PATCH] explosion particles --- .../data/mappings/particle/ParticleType.kt | 8 +- .../data/mappings/registry/Registry.kt | 6 ++ .../de/bixilon/minosoft/data/text/RGBColor.kt | 8 ++ .../minosoft/gui/rendering/RenderConstants.kt | 2 + .../particle/DefaultParticleBehavior.kt | 39 +++++++ .../particle/DefaultParticleFactory.kt | 14 ++- .../gui/rendering/particle/ParticleFactory.kt | 3 +- .../rendering/particle/ParticleRenderer.kt | 18 ++-- .../gui/rendering/particle/types/Particle.kt | 102 +++++++----------- .../norender/ExplosionEmitterParticle.kt | 52 +++++++++ .../types/norender/NoRenderParticle.kt | 26 +++++ .../particle/types/render/RenderParticle.kt | 74 +++++++++++++ .../types/render/texture/TextureParticle.kt | 31 ++++++ .../texture/simple}/ExplosionParticle.kt | 18 +++- .../texture/simple}/HappyVillagerParticle.kt | 10 +- .../texture/simple/SimpleTextureParticle.kt | 46 ++++++++ .../gui/rendering/sound/AudioPlayer.kt | 15 ++- .../rendering/sound/DefaultAudioBehavior.kt | 35 ++++++ .../minosoft/gui/rendering/util/VecUtil.kt | 14 ++- .../modding/event/events/ExplosionEvent.kt | 29 +++++ .../protocol/network/connection/Connection.kt | 4 + .../packets/s2c/play/ExplosionS2CP.kt | 15 +-- 22 files changed, 475 insertions(+), 94 deletions(-) create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/particle/DefaultParticleBehavior.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/norender/ExplosionEmitterParticle.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/norender/NoRenderParticle.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/render/RenderParticle.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/render/texture/TextureParticle.kt rename src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/{ => render/texture/simple}/ExplosionParticle.kt (60%) rename src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/{ => render/texture/simple}/HappyVillagerParticle.kt (69%) create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/render/texture/simple/SimpleTextureParticle.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/sound/DefaultAudioBehavior.kt create mode 100644 src/main/java/de/bixilon/minosoft/modding/event/events/ExplosionEvent.kt diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/particle/ParticleType.kt b/src/main/java/de/bixilon/minosoft/data/mappings/particle/ParticleType.kt index 835643f91..8c03ea1c6 100644 --- a/src/main/java/de/bixilon/minosoft/data/mappings/particle/ParticleType.kt +++ b/src/main/java/de/bixilon/minosoft/data/mappings/particle/ParticleType.kt @@ -14,6 +14,7 @@ package de.bixilon.minosoft.data.mappings.particle import com.google.gson.JsonObject import de.bixilon.minosoft.data.mappings.ResourceLocation +import de.bixilon.minosoft.data.mappings.particle.data.ParticleData import de.bixilon.minosoft.data.mappings.registry.RegistryItem import de.bixilon.minosoft.data.mappings.registry.ResourceLocationDeserializer import de.bixilon.minosoft.data.mappings.versions.Registries @@ -22,12 +23,17 @@ import de.bixilon.minosoft.gui.rendering.textures.Texture data class ParticleType( override val resourceLocation: ResourceLocation, val textures: List, + val overrideLimiter: Boolean = false, ) : RegistryItem { override fun toString(): String { return resourceLocation.full } + fun simple(): ParticleData { + return ParticleData(this) + } + companion object : ResourceLocationDeserializer { override fun deserialize(mappings: Registries?, resourceLocation: ResourceLocation, data: JsonObject): ParticleType { val textures: MutableList = mutableListOf() @@ -37,7 +43,7 @@ data class ParticleType( textures += Texture.getResourceTextureIdentifier(textureResourceLocation.namespace, textureName = "particle/${textureResourceLocation.path}") } } - return ParticleType(resourceLocation, textures.toList()) + return ParticleType(resourceLocation, textures.toList(), data["override_limiter"]?.asBoolean ?: false) } } } diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/registry/Registry.kt b/src/main/java/de/bixilon/minosoft/data/mappings/registry/Registry.kt index 0ffd4af8d..8092b5cf4 100644 --- a/src/main/java/de/bixilon/minosoft/data/mappings/registry/Registry.kt +++ b/src/main/java/de/bixilon/minosoft/data/mappings/registry/Registry.kt @@ -17,6 +17,7 @@ import com.google.gson.JsonElement import com.google.gson.JsonObject import com.google.gson.JsonPrimitive import de.bixilon.minosoft.data.mappings.ResourceLocation +import de.bixilon.minosoft.data.mappings.ResourceLocationAble import de.bixilon.minosoft.data.mappings.versions.Registries import de.bixilon.minosoft.util.KUtil.asResourceLocation import de.bixilon.minosoft.util.collections.Clearable @@ -51,6 +52,11 @@ open class Registry( return get(ResourceLocation.getPathResourceLocation(resourceLocation)) } + open operator fun get(resourceLocation: ResourceLocationAble): T? { + return get(resourceLocation.resourceLocation) + } + + open operator fun get(id: Int): T { return idValueMap[id] ?: parentRegistry?.get(id) ?: throw NullPointerException("Can not find item with id $id") } diff --git a/src/main/java/de/bixilon/minosoft/data/text/RGBColor.kt b/src/main/java/de/bixilon/minosoft/data/text/RGBColor.kt index 0d03890d3..dc48f9841 100644 --- a/src/main/java/de/bixilon/minosoft/data/text/RGBColor.kt +++ b/src/main/java/de/bixilon/minosoft/data/text/RGBColor.kt @@ -92,6 +92,14 @@ class RGBColor(val rgba: Int) : ChatCode { return RGBColor(this) } + fun Int.asGray(): RGBColor { + return RGBColor(this, this, this) + } + + fun Float.asGray(): RGBColor { + return RGBColor(this, this, this) + } + fun mix(vararg colors: RGBColor): RGBColor { var red = 0 var green = 0 diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderConstants.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderConstants.kt index c46fab952..2269f7ba4 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderConstants.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderConstants.kt @@ -78,4 +78,6 @@ object RenderConstants { const val DOUBLE_PRESS_DELAY_BETWEEN_PRESSED = 500 const val MAX_BLOCK_OUTLINE_RAYCAST_DISTANCE = 5.0f + + const val MAXIMUM_PARTICLE_AMOUNT = 200000 } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/DefaultParticleBehavior.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/DefaultParticleBehavior.kt new file mode 100644 index 000000000..6aac3a9ae --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/DefaultParticleBehavior.kt @@ -0,0 +1,39 @@ +/* + * 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.particle + +import de.bixilon.minosoft.gui.rendering.particle.types.norender.ExplosionEmitterParticle +import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.ExplosionParticle +import de.bixilon.minosoft.modding.event.CallbackEventInvoker +import de.bixilon.minosoft.modding.event.events.ExplosionEvent +import de.bixilon.minosoft.protocol.network.connection.PlayConnection + +object DefaultParticleBehavior { + + fun register(connection: PlayConnection, particleRenderer: ParticleRenderer) { + val explosionParticleType = connection.registries.particleTypeRegistry[ExplosionParticle]!! + val explosionEmitterParticleType = connection.registries.particleTypeRegistry[ExplosionEmitterParticle]!! + val invokers = listOf( + CallbackEventInvoker.of { + if (it.power >= 2.0f) { + particleRenderer.add(ExplosionEmitterParticle(connection, particleRenderer, it.position, explosionEmitterParticleType.simple())) + } else { + particleRenderer.add(ExplosionParticle(connection, particleRenderer, it.position, explosionParticleType.simple())) + } + } + ) + + connection.registerEvents(*invokers.toTypedArray()) + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/DefaultParticleFactory.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/DefaultParticleFactory.kt index 79204beef..884e81dbc 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/DefaultParticleFactory.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/DefaultParticleFactory.kt @@ -14,9 +14,19 @@ package de.bixilon.minosoft.gui.rendering.particle import de.bixilon.minosoft.data.mappings.DefaultFactory -import de.bixilon.minosoft.gui.rendering.particle.types.HappyVillagerParticle +import de.bixilon.minosoft.data.mappings.ResourceLocation +import de.bixilon.minosoft.data.mappings.particle.data.ParticleData import de.bixilon.minosoft.gui.rendering.particle.types.Particle +import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.ExplosionParticle +import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.HappyVillagerParticle +import de.bixilon.minosoft.protocol.network.connection.PlayConnection +import glm_.vec3.Vec3 object DefaultParticleFactory : DefaultFactory>( HappyVillagerParticle, -) + ExplosionParticle, +) { + fun build(particleType: ResourceLocation, particleRenderer: ParticleRenderer, connection: PlayConnection, position: Vec3, data: ParticleData = ParticleData(connection.registries.particleTypeRegistry[particleType]!!)) { + this[particleType]!!.build(connection, particleRenderer, position, data) + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleFactory.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleFactory.kt index 384eb2aba..03f5a9632 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleFactory.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleFactory.kt @@ -18,10 +18,9 @@ import de.bixilon.minosoft.data.mappings.particle.data.ParticleData import de.bixilon.minosoft.gui.rendering.particle.types.Particle import de.bixilon.minosoft.protocol.network.connection.PlayConnection import glm_.vec3.Vec3 -import kotlin.random.Random interface ParticleFactory : CompanionResourceLocation { - fun build(connection: PlayConnection, position: Vec3, data: ParticleData, random: Random): T + fun build(connection: PlayConnection, particleRenderer: ParticleRenderer = connection.rendering!!.renderWindow[ParticleRenderer]!!, position: Vec3, data: ParticleData = ParticleData(connection.registries.particleTypeRegistry[RESOURCE_LOCATION]!!)): T } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt index c7e1e5e61..665714f0a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt @@ -15,12 +15,13 @@ package de.bixilon.minosoft.gui.rendering.particle import de.bixilon.minosoft.data.mappings.ResourceLocation import de.bixilon.minosoft.data.mappings.particle.data.ParticleData +import de.bixilon.minosoft.gui.rendering.RenderConstants import de.bixilon.minosoft.gui.rendering.RenderWindow import de.bixilon.minosoft.gui.rendering.Renderer import de.bixilon.minosoft.gui.rendering.RendererBuilder import de.bixilon.minosoft.gui.rendering.modding.events.CameraMatrixChangeEvent -import de.bixilon.minosoft.gui.rendering.particle.types.ExplosionParticle import de.bixilon.minosoft.gui.rendering.particle.types.Particle +import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.ExplosionParticle import de.bixilon.minosoft.gui.rendering.shader.Shader import de.bixilon.minosoft.gui.rendering.textures.Texture import de.bixilon.minosoft.gui.rendering.textures.TextureArray @@ -61,14 +62,16 @@ class ParticleRenderer( val random = Random.Default val type = connection.registries.particleTypeRegistry[ExplosionParticle.RESOURCE_LOCATION]!! - for (i in 0 until 10000) { - val particle = ExplosionParticle(connection, Vec3(random.nextFloat(0.0f, 50.0f), random.nextFloat(6.0f, 50.0f), random.nextFloat(0.0f, 50.0f)), ParticleData(type), Random(random.nextLong())) + for (i in 0 until 20) { + val particle = ExplosionParticle(connection, this, Vec3(random.nextFloat(0.0f, 10.0f), random.nextFloat(6.0f, 10.0f), random.nextFloat(0.0f, 10.0f)), ParticleData(type)) // particle.grow(0.5f, 20000L) // particle.velocity = Vec3(1f, 0.2f, 1f) // particle.friction = Vec3(0.1f, 0.1f, 0.1f) particle.relativeHover(-1.0f, 1.0f) particles += particle } + + DefaultParticleBehavior.register(connection, this) } override fun postInit() { @@ -81,12 +84,16 @@ class ParticleRenderer( renderWindow.textures.animator.use(particleShader) } - var last = 0L + + fun add(particle: Particle) { + check(particles.size < RenderConstants.MAXIMUM_PARTICLE_AMOUNT) { "Can not add particle: Limit reached (${particles.size} > ${RenderConstants.MAXIMUM_PARTICLE_AMOUNT}" } + particles += particle + } + override fun draw() { particleShader.use() - val time = System.currentTimeMillis() particleMesh.unload() particleMesh = ParticleMesh() @@ -100,7 +107,6 @@ class ParticleRenderer( } particleMesh.load() - last = time particleMesh.draw() } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/Particle.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/Particle.kt index e6b90037c..7b3cff96b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/Particle.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/Particle.kt @@ -14,36 +14,40 @@ package de.bixilon.minosoft.gui.rendering.particle.types import de.bixilon.minosoft.data.mappings.particle.data.ParticleData -import de.bixilon.minosoft.data.text.ChatColors -import de.bixilon.minosoft.data.text.RGBColor import de.bixilon.minosoft.gui.rendering.particle.ParticleMesh +import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY import de.bixilon.minosoft.gui.rendering.util.VecUtil.ONE +import de.bixilon.minosoft.gui.rendering.util.VecUtil.clear import de.bixilon.minosoft.protocol.network.connection.PlayConnection +import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import glm_.vec3.Vec3 -import kotlin.math.abs import kotlin.random.Random -abstract class Particle(protected val connection: PlayConnection, protected val position: Vec3, protected val data: ParticleData, protected val random: Random) { - protected var texture = connection.rendering!!.renderWindow.textures.allTextures[data.type.textures.first()]!! - protected var scale: Float = 0.1f - protected var color: RGBColor = ChatColors.WHITE - +abstract class Particle(protected val connection: PlayConnection, protected val particleRenderer: ParticleRenderer, protected val position: Vec3, protected val data: ParticleData) { + protected val random = Random private var lastTickTime = -1L - // growing - protected var nextScale: Float = scale - protected var scalePerMillisecond = -1.0f // ageing var dead = false var age: Int = 0 protected set - var maxAge: Int = 10000 + random.nextInt(0, 10000) + var tickAge: Int + get() = age / ProtocolDefinition.TICK_TIME + set(value) { + age = value * ProtocolDefinition.TICK_TIME + } + var maxAge: Int = Integer.MAX_VALUE + var maxTickAge: Int + get() = maxAge / ProtocolDefinition.TICK_TIME + set(value) { + maxAge = value * ProtocolDefinition.TICK_TIME + } // moving - var friction = Vec3.EMPTY - var velocity = Vec3.EMPTY + val friction = Vec3.EMPTY + val velocity = Vec3.EMPTY // hover protected var hovering = false @@ -51,36 +55,16 @@ abstract class Particle(protected val connection: PlayConnection, protected val protected var hoverMaxY = 0.0f - fun grow(scale: Float, time: Long) { - nextScale = scale - scalePerMillisecond = (scale - this.scale) / time - } + protected var lastRealTickTime = 0L - private fun grow(deltaTime: Int) { - val deltaScale = nextScale - scale - if (abs(deltaScale) > GROW_LOWER_LIMIT) { - // we need to grow - val scaleAdd = scalePerMillisecond * deltaTime - - // checke if the delta gets bigger (aka. we'd grew to much) - val nextScale = scale + scaleAdd - if (abs(this.nextScale - nextScale) > deltaScale) { - // abort scaling and avoid getting called another time - scale = nextScale - return - } - // we can grow - scale = nextScale - } - } private fun move(deltaTime: Int) { val perSecond = deltaTime / 1000.0f position += velocity * perSecond - velocity = velocity * (Vec3.ONE - friction * perSecond) + velocity *= Vec3.ONE - friction * perSecond if (velocity.length() < MINIMUM_VELOCITY) { - velocity = Vec3.EMPTY + velocity.clear() } } @@ -125,21 +109,8 @@ abstract class Particle(protected val connection: PlayConnection, protected val } } - private fun checkSpriteTexture() { - val totalTextures = data.type.textures.size - if (totalTextures <= 1) { - return - } - // calculate next texture - val nextTextureResourceLocation = data.type.textures[age / ((maxAge / totalTextures) + 1)] - if (texture.resourceLocation == nextTextureResourceLocation) { - return - } - texture = connection.rendering!!.renderWindow.textures.allTextures[nextTextureResourceLocation]!! - } - open fun tick() { - check(!dead) { "Cannot tick dead particle!" } + fun tick() { val currentTime = System.currentTimeMillis() if (lastTickTime == -1L) { // never ticked before, skip @@ -147,8 +118,22 @@ abstract class Particle(protected val connection: PlayConnection, protected val return } val deltaTime = (currentTime - lastTickTime).toInt() - check(deltaTime >= 0) + tick(deltaTime) + + if (lastRealTickTime == -1L) { + lastRealTickTime = System.currentTimeMillis() + } else if (currentTime - lastRealTickTime >= ProtocolDefinition.TICK_TIME) { + realTick() + lastRealTickTime = currentTime + } + + lastTickTime = currentTime + } + + open fun tick(deltaTime: Int) { + check(!dead) { "Cannot tick dead particle!" } + check(deltaTime >= 0) age += deltaTime if (age >= maxAge) { @@ -156,22 +141,17 @@ abstract class Particle(protected val connection: PlayConnection, protected val return } - grow(deltaTime) move(deltaTime) hover(deltaTime) - - checkSpriteTexture() - - lastTickTime = currentTime } - open fun addVertex(particleMesh: ParticleMesh) { - particleMesh.addVertex(position, scale, texture, color) + open fun realTick() { + } + abstract fun addVertex(particleMesh: ParticleMesh) + companion object { - const val GROW_LOWER_LIMIT = 0.001f const val MINIMUM_VELOCITY = 0.01f } - } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/norender/ExplosionEmitterParticle.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/norender/ExplosionEmitterParticle.kt new file mode 100644 index 000000000..7422fa564 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/norender/ExplosionEmitterParticle.kt @@ -0,0 +1,52 @@ +/* + * 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.particle.types.norender + +import de.bixilon.minosoft.data.mappings.ResourceLocation +import de.bixilon.minosoft.data.mappings.particle.data.ParticleData +import de.bixilon.minosoft.gui.rendering.particle.ParticleFactory +import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer +import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.ExplosionParticle +import de.bixilon.minosoft.protocol.network.connection.PlayConnection +import de.bixilon.minosoft.util.KUtil.asResourceLocation +import glm_.vec3.Vec3 + +class ExplosionEmitterParticle(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, data: ParticleData) : NoRenderParticle(connection, particleRenderer, position, data) { + val explosionParticleType = connection.registries.particleTypeRegistry[ExplosionParticle]!! + + init { + maxTickAge = 8 + } + + + override fun realTick() { + super.realTick() + for (i in 0 until 6) { + val position = Vec3( + x = position.x + (random.nextFloat() - random.nextFloat()) * 4.0f, + y = position.y + (random.nextFloat() - random.nextFloat()) * 4.0f, + z = position.z + (random.nextFloat() - random.nextFloat()) * 4.0f + ) + particleRenderer.add(ExplosionParticle(connection, particleRenderer, position, explosionParticleType.simple(), (tickAge.toFloat() / maxTickAge))) + } + } + + companion object : ParticleFactory { + override val RESOURCE_LOCATION: ResourceLocation = "minecraft:explosion_emitter".asResourceLocation() + + override fun build(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, data: ParticleData): ExplosionEmitterParticle { + return ExplosionEmitterParticle(connection, particleRenderer, position, data) + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/norender/NoRenderParticle.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/norender/NoRenderParticle.kt new file mode 100644 index 000000000..9c9d02c79 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/norender/NoRenderParticle.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.particle.types.norender + +import de.bixilon.minosoft.data.mappings.particle.data.ParticleData +import de.bixilon.minosoft.gui.rendering.particle.ParticleMesh +import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer +import de.bixilon.minosoft.gui.rendering.particle.types.Particle +import de.bixilon.minosoft.protocol.network.connection.PlayConnection +import glm_.vec3.Vec3 + +abstract class NoRenderParticle(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, data: ParticleData) : Particle(connection, particleRenderer, position, data) { + + override fun addVertex(particleMesh: ParticleMesh) {} +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/render/RenderParticle.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/render/RenderParticle.kt new file mode 100644 index 000000000..7590469e3 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/render/RenderParticle.kt @@ -0,0 +1,74 @@ +/* + * 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.particle.types.render + +import de.bixilon.minosoft.data.mappings.particle.data.ParticleData +import de.bixilon.minosoft.data.text.ChatColors +import de.bixilon.minosoft.data.text.RGBColor +import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer +import de.bixilon.minosoft.gui.rendering.particle.types.Particle +import de.bixilon.minosoft.protocol.network.connection.PlayConnection +import glm_.vec3.Vec3 +import kotlin.math.abs + +abstract class RenderParticle(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, data: ParticleData) : Particle(connection, particleRenderer, position, data) { + protected var scale: Float = 0.1f + protected var color: RGBColor = ChatColors.WHITE + + // growing + protected var nextScale: Float = scale + protected var scalePerMillisecond = Float.NEGATIVE_INFINITY + + + override fun tick(deltaTime: Int) { + super.tick(deltaTime) + if (dead) { + return + } + grow(deltaTime) + } + + fun grow(scale: Float, time: Long) { + nextScale = scale + scalePerMillisecond = (scale - this.scale) / time + } + + private fun grow(deltaTime: Int) { + if (scalePerMillisecond == Float.NEGATIVE_INFINITY) { + return + } + val deltaScale = nextScale - scale + if (abs(deltaScale) > GROW_LOWER_LIMIT) { + // we need to grow + val scaleAdd = scalePerMillisecond * deltaTime + + // checke if the delta gets bigger (aka. we'd grew to much) + val nextScale = scale + scaleAdd + if (abs(this.nextScale - nextScale) > deltaScale) { + // abort scaling and avoid getting called another time + scale = nextScale + scalePerMillisecond = Float.NEGATIVE_INFINITY + return + } + // we can grow + scale = nextScale + } + } + + companion object { + const val GROW_LOWER_LIMIT = 0.001f + } + + +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/render/texture/TextureParticle.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/render/texture/TextureParticle.kt new file mode 100644 index 000000000..5b4b49f19 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/render/texture/TextureParticle.kt @@ -0,0 +1,31 @@ +/* + * 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.particle.types.render.texture + +import de.bixilon.minosoft.data.mappings.particle.data.ParticleData +import de.bixilon.minosoft.gui.rendering.particle.ParticleMesh +import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer +import de.bixilon.minosoft.gui.rendering.particle.types.render.RenderParticle +import de.bixilon.minosoft.gui.rendering.textures.Texture +import de.bixilon.minosoft.protocol.network.connection.PlayConnection +import glm_.vec3.Vec3 + +abstract class TextureParticle(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, data: ParticleData) : RenderParticle(connection, particleRenderer, position, data) { + abstract val texture: Texture + + + override fun addVertex(particleMesh: ParticleMesh) { + particleMesh.addVertex(position, scale, texture, color) + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/ExplosionParticle.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/render/texture/simple/ExplosionParticle.kt similarity index 60% rename from src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/ExplosionParticle.kt rename to src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/render/texture/simple/ExplosionParticle.kt index b24be1b35..7eab8021c 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/ExplosionParticle.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/render/texture/simple/ExplosionParticle.kt @@ -11,23 +11,31 @@ * This software is not affiliated with Mojang AB, the original developer of Minecraft. */ -package de.bixilon.minosoft.gui.rendering.particle.types +package de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple import de.bixilon.minosoft.data.mappings.ResourceLocation import de.bixilon.minosoft.data.mappings.particle.data.ParticleData +import de.bixilon.minosoft.data.text.RGBColor.Companion.asGray import de.bixilon.minosoft.gui.rendering.particle.ParticleFactory +import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.util.KUtil.asResourceLocation import glm_.vec3.Vec3 -import kotlin.random.Random -class ExplosionParticle(connection: PlayConnection, position: Vec3, data: ParticleData, random: Random) : Particle(connection, position, data, random) { +class ExplosionParticle(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, data: ParticleData, val power: Float = 1.0f) : SimpleTextureParticle(connection, particleRenderer, position, data) { + + init { + maxTickAge = 6 + random.nextInt(4) + val gray = random.nextFloat() * 0.6f + 0.4f + color = gray.asGray() + scale = 2.0f * (1.0f - gray * 0.5f) + } companion object : ParticleFactory { override val RESOURCE_LOCATION: ResourceLocation = "minecraft:explosion".asResourceLocation() - override fun build(connection: PlayConnection, position: Vec3, data: ParticleData, random: Random): ExplosionParticle { - return ExplosionParticle(connection, position, data, random) + override fun build(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, data: ParticleData): ExplosionParticle { + return ExplosionParticle(connection, particleRenderer, position, data) } } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/HappyVillagerParticle.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/render/texture/simple/HappyVillagerParticle.kt similarity index 69% rename from src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/HappyVillagerParticle.kt rename to src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/render/texture/simple/HappyVillagerParticle.kt index 41dfdcc2a..57f897e1c 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/HappyVillagerParticle.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/render/texture/simple/HappyVillagerParticle.kt @@ -11,23 +11,23 @@ * This software is not affiliated with Mojang AB, the original developer of Minecraft. */ -package de.bixilon.minosoft.gui.rendering.particle.types +package de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple import de.bixilon.minosoft.data.mappings.ResourceLocation import de.bixilon.minosoft.data.mappings.particle.data.ParticleData import de.bixilon.minosoft.gui.rendering.particle.ParticleFactory +import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.util.KUtil.asResourceLocation import glm_.vec3.Vec3 -import kotlin.random.Random -class HappyVillagerParticle(connection: PlayConnection, position: Vec3, data: ParticleData, random: Random) : Particle(connection, position, data, random) { +class HappyVillagerParticle(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, data: ParticleData) : SimpleTextureParticle(connection, particleRenderer, position, data) { companion object : ParticleFactory { override val RESOURCE_LOCATION: ResourceLocation = "minecraft:happy_villager".asResourceLocation() - override fun build(connection: PlayConnection, position: Vec3, data: ParticleData, random: Random): HappyVillagerParticle { - return HappyVillagerParticle(connection, position, data, random) + override fun build(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, data: ParticleData): HappyVillagerParticle { + return HappyVillagerParticle(connection, particleRenderer, position, data) } } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/render/texture/simple/SimpleTextureParticle.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/render/texture/simple/SimpleTextureParticle.kt new file mode 100644 index 000000000..7689d1609 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/types/render/texture/simple/SimpleTextureParticle.kt @@ -0,0 +1,46 @@ +/* + * 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.particle.types.render.texture.simple + +import de.bixilon.minosoft.data.mappings.particle.data.ParticleData +import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer +import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.TextureParticle +import de.bixilon.minosoft.protocol.network.connection.PlayConnection +import glm_.vec3.Vec3 + +abstract class SimpleTextureParticle(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, data: ParticleData) : TextureParticle(connection, particleRenderer, position, data) { + override var texture = particleRenderer.renderWindow.textures.allTextures[data.type.textures.first()]!! + + + private fun checkSpriteTexture() { + val totalTextures = data.type.textures.size + if (totalTextures <= 1) { + return + } + // calculate next texture + val nextTextureResourceLocation = data.type.textures[age / (maxAge / totalTextures + 1)] + if (texture.resourceLocation == nextTextureResourceLocation) { + return + } + texture = particleRenderer.renderWindow.textures.allTextures[nextTextureResourceLocation]!! + } + + override fun tick(deltaTime: Int) { + super.tick(deltaTime) + if (dead) { + return + } + checkSpriteTexture() + } +} 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 4a55dba62..8e9ba4af1 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 @@ -26,9 +26,7 @@ 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.EMPTY import de.bixilon.minosoft.gui.rendering.util.VecUtil.center -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 @@ -113,9 +111,7 @@ class AudioPlayer( } }) - connection.registerEvent(CallbackEventInvoker.of { - playSoundEvent(it.soundEvent, it.position.toVec3, it.volume, it.pitch) - }) + DefaultAudioBehavior.register(connection, this) Log.log(LogMessageType.AUDIO_LOADING, LogLevels.INFO) { "OpenAL loaded!" } @@ -124,10 +120,19 @@ class AudioPlayer( latch.dec() } + fun playSoundEvent(resourceLocation: ResourceLocation, position: Vec3i? = null, volume: Float = 1.0f, pitch: Float = 1.0f) { + connection.registries.soundEventRegistry[resourceLocation]?.let { playSoundEvent(it, position?.center, 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?.center, volume, pitch) } + fun playSoundEvent(soundEvent: SoundEvent, position: Vec3? = null, volume: Float = 1.0f, pitch: Float = 1.0f) { if (!initialized) { return diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/sound/DefaultAudioBehavior.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/sound/DefaultAudioBehavior.kt new file mode 100644 index 000000000..4ac118424 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/sound/DefaultAudioBehavior.kt @@ -0,0 +1,35 @@ +/* + * 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.sound + +import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3 +import de.bixilon.minosoft.modding.event.CallbackEventInvoker +import de.bixilon.minosoft.modding.event.events.ExplosionEvent +import de.bixilon.minosoft.modding.event.events.PlaySoundEvent +import de.bixilon.minosoft.protocol.network.connection.PlayConnection +import de.bixilon.minosoft.util.KUtil.asResourceLocation +import kotlin.random.Random + +object DefaultAudioBehavior { + val ENTITY_GENERIC_EXPLODE = "minecraft:entity.generic.explode".asResourceLocation() + + fun register(connection: PlayConnection, audioPlayer: AudioPlayer) { + val invokers = listOf( + CallbackEventInvoker.of { audioPlayer.playSoundEvent(it.soundEvent, it.position.toVec3, it.volume, it.pitch) }, + CallbackEventInvoker.of { audioPlayer.playSoundEvent(ENTITY_GENERIC_EXPLODE, it.position, 4.0f, (1.0f + (Random.nextFloat() - Random.nextFloat()) * 0.2f) * 0.7f) }, + ) + + connection.registerEvents(*invokers.toTypedArray()) + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt index 4fc5b9b6b..c068cb8aa 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt @@ -55,6 +55,18 @@ object VecUtil { } } + fun Vec3.clear() { + x = 0.0f + y = 0.0f + z = 0.0f + } + + fun Vec3.assign(vec3: Vec3) { + x = vec3.x + y = vec3.y + z = vec3.z + } + fun getRotatedValues(x: Float, y: Float, sin: Float, cos: Float, rescale: Boolean): Vec2 { val result = Vec2(x * cos - y * sin, x * sin + y * cos) if (rescale) { @@ -294,7 +306,7 @@ object VecUtil { } operator fun Vec3i.get(axis: Axes): Int { - return when(axis) { + return when (axis) { Axes.X -> this.x Axes.Y -> this.y Axes.Z -> this.z diff --git a/src/main/java/de/bixilon/minosoft/modding/event/events/ExplosionEvent.kt b/src/main/java/de/bixilon/minosoft/modding/event/events/ExplosionEvent.kt new file mode 100644 index 000000000..893e1c480 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/modding/event/events/ExplosionEvent.kt @@ -0,0 +1,29 @@ +/* + * Minosoft + * Copyright (C) 2020 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.protocol.network.connection.PlayConnection +import de.bixilon.minosoft.protocol.packets.s2c.play.ExplosionS2CP +import glm_.vec3.Vec3 + +class ExplosionEvent( + connection: PlayConnection, + val position: Vec3, + val power: Float, + val explodedBlocks: List, + val velocity: Vec3, +) : PlayConnectionEvent(connection) { + + constructor(connection: PlayConnection, packet: ExplosionS2CP) : this(connection, packet.position, packet.power, packet.explodedBlocks, packet.velocity) + +} diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/connection/Connection.kt b/src/main/java/de/bixilon/minosoft/protocol/network/connection/Connection.kt index bf7820f2d..f188fcffa 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/connection/Connection.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/network/connection/Connection.kt @@ -86,6 +86,10 @@ abstract class Connection { eventListeners.add(method) } + open fun registerEvents(vararg method: EventInvoker) { + eventListeners.addAll(method) + } + val isDisconnected: Boolean get() = connectionState == ConnectionStates.DISCONNECTING || connectionState == ConnectionStates.DISCONNECTED || connectionState == ConnectionStates.FAILED || connectionState == ConnectionStates.FAILED_NO_RETRY diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ExplosionS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ExplosionS2CP.kt index f59287a15..a7f3fceb8 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ExplosionS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ExplosionS2CP.kt @@ -12,6 +12,7 @@ */ package de.bixilon.minosoft.protocol.packets.s2c.play +import de.bixilon.minosoft.modding.event.events.ExplosionEvent import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer @@ -23,15 +24,15 @@ import glm_.vec3.Vec3i class ExplosionS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() { val position = buffer.readFloatPosition() - val radius = buffer.readFloat() - val explodedBlocks: Array = buffer.readArray(buffer.readInt()) { Vec3(buffer.readByte(), buffer.readByte(), buffer.readByte()) } + val power = buffer.readFloat() + val explodedBlocks: List = buffer.readArray(buffer.readInt()) { Vec3(buffer.readByte(), buffer.readByte(), buffer.readByte()) }.toList() val velocity = buffer.readFloatPosition() override fun check(connection: PlayConnection) { - require(radius <= 100.0f) { + require(power <= 100.0f) { // maybe somebody tries to make bullshit? // Sorry, Maximilian Rosenmüller - "Explosion to big $radius > 100.0F" + "Explosion to big $power > 100.0F" } } @@ -40,10 +41,12 @@ class ExplosionS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() { val blockPosition = Vec3i(position + record) connection.world.setBlockState(blockPosition, null) } - connection.player.entity.velocity = velocity + connection.player.entity.velocity = connection.player.entity.velocity + velocity + + connection.fireEvent(ExplosionEvent(connection, this)) } override fun log() { - Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Explosion (position=$position, radius=$radius, explodedBlocks=$explodedBlocks, velocity=$velocity)" } + Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Explosion (position=$position, radius=$power, explodedBlocks=$explodedBlocks, velocity=$velocity)" } } }