mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-12 17:07:55 -04:00
explosion particles
This commit is contained in:
parent
53d7789e15
commit
483fdd80f2
@ -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<ResourceLocation>,
|
||||
val overrideLimiter: Boolean = false,
|
||||
) : RegistryItem {
|
||||
|
||||
override fun toString(): String {
|
||||
return resourceLocation.full
|
||||
}
|
||||
|
||||
fun simple(): ParticleData {
|
||||
return ParticleData(this)
|
||||
}
|
||||
|
||||
companion object : ResourceLocationDeserializer<ParticleType> {
|
||||
override fun deserialize(mappings: Registries?, resourceLocation: ResourceLocation, data: JsonObject): ParticleType {
|
||||
val textures: MutableList<ResourceLocation> = 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<T : RegistryItem>(
|
||||
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")
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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<ExplosionEvent> {
|
||||
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())
|
||||
}
|
||||
}
|
@ -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<ParticleFactory<out Particle>>(
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -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<T : Particle> : 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
|
||||
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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<ExplosionEmitterParticle> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2021 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.gui.rendering.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) {}
|
||||
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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)
|
||||
}
|
||||
}
|
@ -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<ExplosionParticle> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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<HappyVillagerParticle> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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()
|
||||
}
|
||||
}
|
@ -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> {
|
||||
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
|
||||
|
@ -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 <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
|
||||
|
||||
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<PlaySoundEvent> { audioPlayer.playSoundEvent(it.soundEvent, it.position.toVec3, it.volume, it.pitch) },
|
||||
CallbackEventInvoker.of<ExplosionEvent> { audioPlayer.playSoundEvent(ENTITY_GENERIC_EXPLODE, it.position, 4.0f, (1.0f + (Random.nextFloat() - Random.nextFloat()) * 0.2f) * 0.7f) },
|
||||
)
|
||||
|
||||
connection.registerEvents(*invokers.toTypedArray())
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
package de.bixilon.minosoft.modding.event.events
|
||||
|
||||
import de.bixilon.minosoft.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<Vec3>,
|
||||
val velocity: Vec3,
|
||||
) : PlayConnectionEvent(connection) {
|
||||
|
||||
constructor(connection: PlayConnection, packet: ExplosionS2CP) : this(connection, packet.position, packet.power, packet.explodedBlocks, packet.velocity)
|
||||
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -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<Vec3> = buffer.readArray(buffer.readInt()) { Vec3(buffer.readByte(), buffer.readByte(), buffer.readByte()) }
|
||||
val power = buffer.readFloat()
|
||||
val explodedBlocks: List<Vec3> = 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)" }
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user