mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-16 10:55:01 -04:00
more particles: collisions, velocity, fixes, campfire particle
This commit is contained in:
parent
70875d8785
commit
e4b18cf250
3
doc/physics/Particles.md
Normal file
3
doc/physics/Particles.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Particle physics
|
||||||
|
|
||||||
|
The velocity is in blocks/tick. The velocity gets recalculated every real tick (50ms). They still move if (`movement` is `true`) every tick call. But only the right velocity (according to the delta time) gets applied.
|
@ -12,8 +12,6 @@
|
|||||||
*/
|
*/
|
||||||
package de.bixilon.minosoft.data.entities.entities
|
package de.bixilon.minosoft.data.entities.entities
|
||||||
|
|
||||||
import de.bixilon.minosoft.data.Axes
|
|
||||||
import de.bixilon.minosoft.data.Directions
|
|
||||||
import de.bixilon.minosoft.data.entities.EntityMetaDataFields
|
import de.bixilon.minosoft.data.entities.EntityMetaDataFields
|
||||||
import de.bixilon.minosoft.data.entities.EntityRotation
|
import de.bixilon.minosoft.data.entities.EntityRotation
|
||||||
import de.bixilon.minosoft.data.entities.Poses
|
import de.bixilon.minosoft.data.entities.Poses
|
||||||
@ -24,11 +22,9 @@ import de.bixilon.minosoft.data.inventory.ItemStack
|
|||||||
import de.bixilon.minosoft.data.mappings.effects.StatusEffect
|
import de.bixilon.minosoft.data.mappings.effects.StatusEffect
|
||||||
import de.bixilon.minosoft.data.mappings.entities.EntityType
|
import de.bixilon.minosoft.data.mappings.entities.EntityType
|
||||||
import de.bixilon.minosoft.data.text.ChatComponent
|
import de.bixilon.minosoft.data.text.ChatComponent
|
||||||
import de.bixilon.minosoft.gui.rendering.chunk.VoxelShape
|
|
||||||
import de.bixilon.minosoft.gui.rendering.chunk.models.AABB
|
import de.bixilon.minosoft.gui.rendering.chunk.models.AABB
|
||||||
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.protocol.network.connection.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||||
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
|
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
|
||||||
@ -202,82 +198,11 @@ abstract class Entity(
|
|||||||
forceMove(deltaPosition)
|
forceMove(deltaPosition)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val currentAABB = aabb
|
val collisionsToCheck = connection.collisionDetector.getCollisionsToCheck(deltaPosition, aabb, ignoreUnloadedChunks)
|
||||||
val collisionsToCheck = getCollisionsToCheck(deltaPosition, currentAABB, ignoreUnloadedChunks)
|
val realMovement = connection.collisionDetector.collide(this, deltaPosition, collisionsToCheck, aabb)
|
||||||
val realMovement = collide(deltaPosition, collisionsToCheck, currentAABB)
|
|
||||||
forceMove(realMovement)
|
forceMove(realMovement)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getCollisionsToCheck(deltaPosition: Vec3, originalAABB: AABB, ignoreUnloadedChunks: Boolean = true): VoxelShape {
|
|
||||||
// also look at blocks further down to also cover blocks with a higher than normal hitbox (for example fences)
|
|
||||||
val blockPositions = (originalAABB extend deltaPosition extend Directions.DOWN.directionVector).getBlockPositions()
|
|
||||||
val result = VoxelShape()
|
|
||||||
for (blockPosition in blockPositions) {
|
|
||||||
val chunk = connection.world[blockPosition.chunkPosition]
|
|
||||||
if ((chunk == null || !chunk.isFullyLoaded) && !ignoreUnloadedChunks) {
|
|
||||||
// chunk is not loaded
|
|
||||||
result.add(VoxelShape.FULL + blockPosition)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
val blockState = chunk?.get(blockPosition.inChunkPosition) ?: continue
|
|
||||||
result.add(blockState.collisionShape + blockPosition)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun collide(deltaPosition: Vec3, collisionsToCheck: VoxelShape, aabb: AABB): Vec3 {
|
|
||||||
val delta = Vec3(deltaPosition)
|
|
||||||
if (delta.y != 0.0f) {
|
|
||||||
delta.y = collisionsToCheck.computeOffset(aabb, deltaPosition.y, Axes.Y)
|
|
||||||
if (delta.y != deltaPosition.y) {
|
|
||||||
onGround = false
|
|
||||||
velocity.y = 0.0f
|
|
||||||
if (deltaPosition.y < 0) {
|
|
||||||
onGround = true
|
|
||||||
}
|
|
||||||
aabb += Vec3(0f, delta.y, 0f)
|
|
||||||
} else if (delta.y < 0) {
|
|
||||||
onGround = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((deltaPosition.x != 0f || deltaPosition.z != 0f)) {
|
|
||||||
val testDelta = Vec3(delta)
|
|
||||||
testDelta.y = STEP_HEIGHT
|
|
||||||
val stepMovementY = collisionsToCheck.computeOffset(aabb + testDelta, -STEP_HEIGHT, Axes.Y)
|
|
||||||
if (stepMovementY < 0 && stepMovementY >= -STEP_HEIGHT) {
|
|
||||||
testDelta.y = STEP_HEIGHT + stepMovementY
|
|
||||||
aabb += Vec3(0f, testDelta.y, 0f)
|
|
||||||
delta.y += testDelta.y
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val xPriority = delta.x > delta.z
|
|
||||||
if (delta.x != 0.0f && xPriority) {
|
|
||||||
delta.x = collisionsToCheck.computeOffset(aabb, deltaPosition.x, Axes.X)
|
|
||||||
aabb += Vec3(delta.x, 0f, 0f)
|
|
||||||
if (delta.x != deltaPosition.x) {
|
|
||||||
velocity.x = 0.0f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (delta.z != 0.0f) {
|
|
||||||
delta.z = collisionsToCheck.computeOffset(aabb, deltaPosition.z, Axes.Z)
|
|
||||||
aabb += Vec3(0f, 0f, delta.z)
|
|
||||||
if (delta.z != deltaPosition.z) {
|
|
||||||
velocity.z = 0.0f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (delta.x != 0.0f && !xPriority) {
|
|
||||||
delta.x = collisionsToCheck.computeOffset(aabb, deltaPosition.x, Axes.X)
|
|
||||||
// no need to offset the aabb any more, as it won't be used any more
|
|
||||||
if (delta.x != deltaPosition.x) {
|
|
||||||
velocity.x = 0.0f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (delta.length() > deltaPosition.length() + STEP_HEIGHT) {
|
|
||||||
return Vec3() // abort all movement if the collision system would move the entity further than wanted
|
|
||||||
}
|
|
||||||
return delta
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun tickMovement(deltaMillis: Long) {
|
private fun tickMovement(deltaMillis: Long) {
|
||||||
if (connection.world[position.blockPosition.chunkPosition]?.isFullyLoaded != true) {
|
if (connection.world[position.blockPosition.chunkPosition]?.isFullyLoaded != true) {
|
||||||
return // ignore update if chunk is not loaded yet
|
return // ignore update if chunk is not loaded yet
|
||||||
@ -312,6 +237,6 @@ abstract class Entity(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val HITBOX_MARGIN = 1e-5f
|
private const val HITBOX_MARGIN = 1e-5f
|
||||||
private const val STEP_HEIGHT = 0.6f
|
const val STEP_HEIGHT = 0.6f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* 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.physics
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.data.Axes
|
||||||
|
import de.bixilon.minosoft.data.Directions
|
||||||
|
import de.bixilon.minosoft.data.entities.entities.Entity
|
||||||
|
import de.bixilon.minosoft.gui.rendering.chunk.VoxelShape
|
||||||
|
import de.bixilon.minosoft.gui.rendering.chunk.models.AABB
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.chunkPosition
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkPosition
|
||||||
|
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
|
||||||
|
import glm_.vec3.Vec3
|
||||||
|
|
||||||
|
class CollisionDetector(val connection: PlayConnection) {
|
||||||
|
|
||||||
|
fun getCollisionsToCheck(deltaPosition: Vec3, aabb: AABB, ignoreUnloadedChunks: Boolean = true): VoxelShape {
|
||||||
|
// also look at blocks further down to also cover blocks with a higher than normal hitbox (for example fences)
|
||||||
|
val blockPositions = (aabb extend deltaPosition extend Directions.DOWN.directionVector).getBlockPositions()
|
||||||
|
val result = VoxelShape()
|
||||||
|
for (blockPosition in blockPositions) {
|
||||||
|
val chunk = connection.world[blockPosition.chunkPosition]
|
||||||
|
if ((chunk == null || !chunk.isFullyLoaded) && !ignoreUnloadedChunks) {
|
||||||
|
// chunk is not loaded
|
||||||
|
result.add(VoxelShape.FULL + blockPosition)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
val blockState = chunk?.get(blockPosition.inChunkPosition) ?: continue
|
||||||
|
result.add(blockState.collisionShape + blockPosition)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun collide(entity: Entity?, deltaPosition: Vec3, collisionsToCheck: VoxelShape, aabb: AABB): Vec3 {
|
||||||
|
val delta = Vec3(deltaPosition)
|
||||||
|
if (delta.y != 0.0f) {
|
||||||
|
delta.y = collisionsToCheck.computeOffset(aabb, deltaPosition.y, Axes.Y)
|
||||||
|
if (delta.y != deltaPosition.y) {
|
||||||
|
entity?.let {
|
||||||
|
it.onGround = false
|
||||||
|
it.velocity.y = 0.0f
|
||||||
|
if (deltaPosition.y < 0) {
|
||||||
|
it.onGround = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aabb += Vec3(0f, delta.y, 0f)
|
||||||
|
} else if (delta.y < 0) {
|
||||||
|
entity?.let { it.onGround = false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((deltaPosition.x != 0f || deltaPosition.z != 0f)) {
|
||||||
|
val testDelta = Vec3(delta)
|
||||||
|
testDelta.y = Entity.STEP_HEIGHT
|
||||||
|
val stepMovementY = collisionsToCheck.computeOffset(aabb + testDelta, -Entity.STEP_HEIGHT, Axes.Y)
|
||||||
|
if (stepMovementY < 0 && stepMovementY >= -Entity.STEP_HEIGHT) {
|
||||||
|
testDelta.y = Entity.STEP_HEIGHT + stepMovementY
|
||||||
|
aabb += Vec3(0f, testDelta.y, 0f)
|
||||||
|
delta.y += testDelta.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val xPriority = delta.x > delta.z
|
||||||
|
if (delta.x != 0.0f && xPriority) {
|
||||||
|
delta.x = collisionsToCheck.computeOffset(aabb, deltaPosition.x, Axes.X)
|
||||||
|
aabb += Vec3(delta.x, 0f, 0f)
|
||||||
|
if (delta.x != deltaPosition.x) {
|
||||||
|
entity?.let { it.velocity.x = 0.0f }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (delta.z != 0.0f) {
|
||||||
|
delta.z = collisionsToCheck.computeOffset(aabb, deltaPosition.z, Axes.Z)
|
||||||
|
aabb += Vec3(0f, 0f, delta.z)
|
||||||
|
if (delta.z != deltaPosition.z) {
|
||||||
|
entity?.let { it.velocity.z = 0.0f }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (delta.x != 0.0f && !xPriority) {
|
||||||
|
delta.x = collisionsToCheck.computeOffset(aabb, deltaPosition.x, Axes.X)
|
||||||
|
// no need to offset the aabb any more, as it won't be used any more
|
||||||
|
if (delta.x != deltaPosition.x) {
|
||||||
|
entity?.let { it.velocity.x = 0.0f }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (delta.length() > deltaPosition.length() + Entity.STEP_HEIGHT) {
|
||||||
|
return Vec3() // abort all movement if the collision system would move the entity further than wanted
|
||||||
|
}
|
||||||
|
return delta
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
package de.bixilon.minosoft.data.text
|
package de.bixilon.minosoft.data.text
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.util.MMath
|
||||||
import org.checkerframework.common.value.qual.IntRange
|
import org.checkerframework.common.value.qual.IntRange
|
||||||
|
|
||||||
class RGBColor(val rgba: Int) : ChatCode {
|
class RGBColor(val rgba: Int) : ChatCode {
|
||||||
@ -21,7 +22,7 @@ class RGBColor(val rgba: Int) : ChatCode {
|
|||||||
|
|
||||||
constructor(red: Byte, green: Byte, blue: Byte, alpha: Byte = 0xFF.toByte()) : this(red.toInt() and 0xFF, green.toInt() and 0xFF, blue.toInt() and 0xFF, alpha.toInt() and 0xFF)
|
constructor(red: Byte, green: Byte, blue: Byte, alpha: Byte = 0xFF.toByte()) : this(red.toInt() and 0xFF, green.toInt() and 0xFF, blue.toInt() and 0xFF, alpha.toInt() and 0xFF)
|
||||||
|
|
||||||
constructor(red: Float, green: Float, blue: Float, alpha: Float = 1.0f) : this((red * 255.0f).toInt(), (green * 255.0f).toInt(), (blue * 255.0f).toInt(), (alpha * 255.0f).toInt())
|
constructor(red: Float, green: Float, blue: Float, alpha: Float = 1.0f) : this((red * 255.0f).toInt(), (green * COLOR_FLOAT_DIVIDER).toInt(), (blue * COLOR_FLOAT_DIVIDER).toInt(), (alpha * COLOR_FLOAT_DIVIDER).toInt())
|
||||||
|
|
||||||
val alpha: @IntRange(from = 0L, to = 255L) Int
|
val alpha: @IntRange(from = 0L, to = 255L) Int
|
||||||
get() = rgba and 0xFF
|
get() = rgba and 0xFF
|
||||||
@ -44,6 +45,9 @@ class RGBColor(val rgba: Int) : ChatCode {
|
|||||||
val floatBlue: @IntRange(from = 0L, to = 1L) Float
|
val floatBlue: @IntRange(from = 0L, to = 1L) Float
|
||||||
get() = blue / COLOR_FLOAT_DIVIDER
|
get() = blue / COLOR_FLOAT_DIVIDER
|
||||||
|
|
||||||
|
val floatAlpha: @IntRange(from = 0L, to = 1L) Float
|
||||||
|
get() = alpha / COLOR_FLOAT_DIVIDER
|
||||||
|
|
||||||
val rgb: Int
|
val rgb: Int
|
||||||
get() = rgba ushr 8
|
get() = rgba ushr 8
|
||||||
|
|
||||||
@ -67,6 +71,14 @@ class RGBColor(val rgba: Int) : ChatCode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun with(red: Int = this.red, green: Int = this.green, blue: Int = this.blue, alpha: Int = this.alpha): RGBColor {
|
||||||
|
return RGBColor(red, green, blue, alpha)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun with(red: Float = this.floatRed, green: Float = this.floatGreen, blue: Float = this.floatBlue, alpha: Float = this.floatAlpha): RGBColor {
|
||||||
|
return RGBColor(MMath.clamp(red, 0.0f, 1.0f), MMath.clamp(green, 0.0f, 1.0f), MMath.clamp(blue, 0.0f, 1.0f), MMath.clamp(alpha, 0.0f, 1.0f))
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val COLOR_FLOAT_DIVIDER = 255.0f
|
private const val COLOR_FLOAT_DIVIDER = 255.0f
|
||||||
|
|
||||||
|
@ -166,7 +166,13 @@ class AABB {
|
|||||||
return (position.x in min.x..max.x && position.y in min.y..max.y && position.z in min.z..max.z)
|
return (position.x in min.x..max.x && position.y in min.y..max.y && position.z in min.z..max.z)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val center: Vec3
|
||||||
|
get() = Vec3((min.x + max.x) / 2.0f, (min.y + max.y) / 2.0f, (min.z + max.z) / 2.0f)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
val EMPTY: AABB
|
||||||
|
get() = AABB(Vec3.EMPTY, Vec3.EMPTY)
|
||||||
|
|
||||||
private fun getRange(min: Float, max: Float): IntRange {
|
private fun getRange(min: Float, max: Float): IntRange {
|
||||||
return IntRange(glm.floor(min).toInt(), glm.ceil(max).toInt())
|
return IntRange(glm.floor(min).toInt(), glm.ceil(max).toInt())
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
package de.bixilon.minosoft.gui.rendering.particle
|
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.norender.ExplosionEmitterParticle
|
||||||
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.ExplosionParticle
|
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.ExplosionLargeParticle
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.times
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.times
|
||||||
import de.bixilon.minosoft.modding.event.CallbackEventInvoker
|
import de.bixilon.minosoft.modding.event.CallbackEventInvoker
|
||||||
import de.bixilon.minosoft.modding.event.events.ExplosionEvent
|
import de.bixilon.minosoft.modding.event.events.ExplosionEvent
|
||||||
@ -29,14 +29,14 @@ object DefaultParticleBehavior {
|
|||||||
|
|
||||||
fun register(connection: PlayConnection, particleRenderer: ParticleRenderer) {
|
fun register(connection: PlayConnection, particleRenderer: ParticleRenderer) {
|
||||||
val random = java.util.Random()
|
val random = java.util.Random()
|
||||||
val explosionParticleType = connection.registries.particleTypeRegistry[ExplosionParticle]!!
|
val explosionParticleType = connection.registries.particleTypeRegistry[ExplosionLargeParticle]!!
|
||||||
val explosionEmitterParticleType = connection.registries.particleTypeRegistry[ExplosionEmitterParticle]!!
|
val explosionEmitterParticleType = connection.registries.particleTypeRegistry[ExplosionEmitterParticle]!!
|
||||||
val invokers = listOf(
|
val invokers = listOf(
|
||||||
CallbackEventInvoker.of<ExplosionEvent> {
|
CallbackEventInvoker.of<ExplosionEvent> {
|
||||||
if (it.power >= 2.0f) {
|
if (it.power >= 2.0f) {
|
||||||
particleRenderer.add(ExplosionEmitterParticle(connection, particleRenderer, it.position, explosionEmitterParticleType.simple()))
|
particleRenderer.add(ExplosionEmitterParticle(connection, particleRenderer, it.position, explosionEmitterParticleType.simple()))
|
||||||
} else {
|
} else {
|
||||||
particleRenderer.add(ExplosionParticle(connection, particleRenderer, it.position, explosionParticleType.simple()))
|
particleRenderer.add(ExplosionLargeParticle(connection, particleRenderer, it.position, explosionParticleType.simple()))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
CallbackEventInvoker.of<ParticleSpawnEvent> {
|
CallbackEventInvoker.of<ParticleSpawnEvent> {
|
||||||
@ -54,8 +54,8 @@ object DefaultParticleBehavior {
|
|||||||
spawn(it.position, velocity)
|
spawn(it.position, velocity)
|
||||||
} else {
|
} else {
|
||||||
for (i in 0 until it.count) {
|
for (i in 0 until it.count) {
|
||||||
val offset = it.offset * { random.nextGaussian() }
|
val offset = it.offset * { random.nextGaussian().toFloat() }
|
||||||
val velocity = Vec3(it.speed) * { random.nextGaussian() }
|
val velocity = Vec3(it.speed) * { random.nextGaussian().toFloat() }
|
||||||
|
|
||||||
spawn(it.position + offset, velocity)
|
spawn(it.position + offset, velocity)
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,12 @@ package de.bixilon.minosoft.gui.rendering.particle
|
|||||||
import de.bixilon.minosoft.data.mappings.DefaultFactory
|
import de.bixilon.minosoft.data.mappings.DefaultFactory
|
||||||
import de.bixilon.minosoft.gui.rendering.particle.types.Particle
|
import de.bixilon.minosoft.gui.rendering.particle.types.Particle
|
||||||
import de.bixilon.minosoft.gui.rendering.particle.types.norender.ExplosionEmitterParticle
|
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.gui.rendering.particle.types.render.texture.simple.CampfireSmokeParticle
|
||||||
|
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.ExplosionLargeParticle
|
||||||
|
|
||||||
object DefaultParticleFactory : DefaultFactory<ParticleFactory<out Particle>>(
|
object DefaultParticleFactory : DefaultFactory<ParticleFactory<out Particle>>(
|
||||||
ExplosionEmitterParticle,
|
ExplosionEmitterParticle,
|
||||||
ExplosionParticle,
|
ExplosionLargeParticle,
|
||||||
|
CampfireSmokeParticle.CosySmokeParticleFactory,
|
||||||
|
CampfireSmokeParticle.SignalSmokeParticleFactory,
|
||||||
)
|
)
|
||||||
|
@ -20,6 +20,7 @@ import de.bixilon.minosoft.gui.rendering.Renderer
|
|||||||
import de.bixilon.minosoft.gui.rendering.RendererBuilder
|
import de.bixilon.minosoft.gui.rendering.RendererBuilder
|
||||||
import de.bixilon.minosoft.gui.rendering.modding.events.CameraMatrixChangeEvent
|
import de.bixilon.minosoft.gui.rendering.modding.events.CameraMatrixChangeEvent
|
||||||
import de.bixilon.minosoft.gui.rendering.particle.types.Particle
|
import de.bixilon.minosoft.gui.rendering.particle.types.Particle
|
||||||
|
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.CampfireSmokeParticle
|
||||||
import de.bixilon.minosoft.gui.rendering.shader.Shader
|
import de.bixilon.minosoft.gui.rendering.shader.Shader
|
||||||
import de.bixilon.minosoft.gui.rendering.textures.Texture
|
import de.bixilon.minosoft.gui.rendering.textures.Texture
|
||||||
import de.bixilon.minosoft.gui.rendering.textures.TextureArray
|
import de.bixilon.minosoft.gui.rendering.textures.TextureArray
|
||||||
@ -30,6 +31,8 @@ import de.bixilon.minosoft.util.KUtil.synchronizedSetOf
|
|||||||
import de.bixilon.minosoft.util.KUtil.toSynchronizedSet
|
import de.bixilon.minosoft.util.KUtil.toSynchronizedSet
|
||||||
import de.bixilon.minosoft.util.MMath
|
import de.bixilon.minosoft.util.MMath
|
||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
|
import org.lwjgl.opengl.GL11.glDepthMask
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
|
||||||
class ParticleRenderer(
|
class ParticleRenderer(
|
||||||
@ -75,6 +78,7 @@ class ParticleRenderer(
|
|||||||
particles += particle
|
particles += particle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var lastTickTime = System.currentTimeMillis()
|
||||||
|
|
||||||
override fun draw() {
|
override fun draw() {
|
||||||
particleShader.use()
|
particleShader.use()
|
||||||
@ -82,6 +86,26 @@ class ParticleRenderer(
|
|||||||
particleMesh.unload()
|
particleMesh.unload()
|
||||||
particleMesh = ParticleMesh()
|
particleMesh = ParticleMesh()
|
||||||
|
|
||||||
|
// ToDo: Remove, this ist just for testing purposes
|
||||||
|
if (System.currentTimeMillis() - lastTickTime > ProtocolDefinition.TICK_TIME) {
|
||||||
|
val blockPosition = Vec3(0, 5, 0)
|
||||||
|
if (Random.nextFloat() < 0.11f) {
|
||||||
|
for (i in 0 until Random.nextInt(2) + 2) {
|
||||||
|
val horizontal = { 0.5f + Random.nextFloat() / 3.0f * if (Random.nextBoolean()) 1.0f else -1.0f }
|
||||||
|
val position = Vec3(
|
||||||
|
blockPosition.x + horizontal(),
|
||||||
|
blockPosition.y + Random.nextFloat() + Random.nextFloat(),
|
||||||
|
blockPosition.z + horizontal()
|
||||||
|
)
|
||||||
|
|
||||||
|
val data = connection.registries.particleTypeRegistry[CampfireSmokeParticle.CosySmokeParticleFactory]!!
|
||||||
|
val particle = CampfireSmokeParticle(connection, this, position, Vec3(0.0f, 0.07f, 0.0f), data.simple(), true)
|
||||||
|
add(particle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastTickTime = System.currentTimeMillis()
|
||||||
|
}
|
||||||
|
|
||||||
for (particle in particles.toSynchronizedSet()) {
|
for (particle in particles.toSynchronizedSet()) {
|
||||||
particle.tick()
|
particle.tick()
|
||||||
if (particle.dead) {
|
if (particle.dead) {
|
||||||
@ -93,7 +117,9 @@ class ParticleRenderer(
|
|||||||
|
|
||||||
particleMesh.load()
|
particleMesh.load()
|
||||||
|
|
||||||
|
glDepthMask(false)
|
||||||
particleMesh.draw()
|
particleMesh.draw()
|
||||||
|
glDepthMask(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : RendererBuilder<ParticleRenderer> {
|
companion object : RendererBuilder<ParticleRenderer> {
|
||||||
|
@ -14,26 +14,30 @@
|
|||||||
package de.bixilon.minosoft.gui.rendering.particle.types
|
package de.bixilon.minosoft.gui.rendering.particle.types
|
||||||
|
|
||||||
import de.bixilon.minosoft.data.mappings.particle.data.ParticleData
|
import de.bixilon.minosoft.data.mappings.particle.data.ParticleData
|
||||||
|
import de.bixilon.minosoft.gui.rendering.chunk.models.AABB
|
||||||
import de.bixilon.minosoft.gui.rendering.particle.ParticleMesh
|
import de.bixilon.minosoft.gui.rendering.particle.ParticleMesh
|
||||||
import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer
|
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.EMPTY
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.ONE
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.assign
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.clear
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.millis
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plusAssign
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.sqr
|
||||||
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||||
import de.bixilon.minosoft.util.KUtil.millis
|
import de.bixilon.minosoft.util.KUtil.millis
|
||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
|
import kotlin.math.sqrt
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
abstract class Particle(
|
abstract class Particle(
|
||||||
protected val connection: PlayConnection,
|
protected val connection: PlayConnection,
|
||||||
protected val particleRenderer: ParticleRenderer,
|
protected val particleRenderer: ParticleRenderer,
|
||||||
protected val position: Vec3,
|
protected val position: Vec3,
|
||||||
|
protected val velocity: Vec3 = Vec3.EMPTY,
|
||||||
protected val data: ParticleData,
|
protected val data: ParticleData,
|
||||||
) {
|
) {
|
||||||
protected val random = Random
|
protected val random = Random
|
||||||
private var lastTickTime = -1L
|
var lastTickTime = -1L
|
||||||
|
|
||||||
|
|
||||||
// ageing
|
// ageing
|
||||||
var dead = false
|
var dead = false
|
||||||
@ -42,25 +46,78 @@ abstract class Particle(
|
|||||||
var maxAge: Int = (4.0f / (random.nextFloat() * 0.9f + 0.1f)).millis
|
var maxAge: Int = (4.0f / (random.nextFloat() * 0.9f + 0.1f)).millis
|
||||||
|
|
||||||
// moving
|
// moving
|
||||||
val friction = Vec3.EMPTY
|
var previousPosition = position
|
||||||
val velocity = Vec3.EMPTY
|
var movement: Boolean = true
|
||||||
|
var physics: Boolean = true
|
||||||
|
var friction = 0.98f
|
||||||
|
var gravityStrength = 0.0f
|
||||||
|
|
||||||
|
// collisions
|
||||||
|
var onGround: Boolean = true
|
||||||
|
var accelerateIfYBlocked = false
|
||||||
|
var aabb: AABB = AABB.EMPTY
|
||||||
|
var spacing: Vec3 = Vec3.EMPTY
|
||||||
|
set(value) {
|
||||||
|
if (field == value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
field = value
|
||||||
|
|
||||||
|
|
||||||
protected var lastRealTickTime = 0L
|
val x = ((aabb.min.x + aabb.max.x) - spacing.x) / 2.0f
|
||||||
|
val z = ((aabb.min.z + aabb.max.z) - spacing.z) / 2.0f
|
||||||
|
|
||||||
|
aabb = AABB(Vec3(x, aabb.min.y, z), Vec3(x + spacing.x, aabb.min.y + spacing.y, z + spacing.z))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private var lastRealTickTime = -1L
|
||||||
|
|
||||||
|
|
||||||
|
init {
|
||||||
|
velocity += { (random.nextFloat() * 2.0f - 1.0f) * MAGIC_VELOCITY_CONSTANTf }
|
||||||
|
val modifier = (random.nextFloat() + random.nextFloat() + 1.0f) * 0.15000000596046448f
|
||||||
|
val divider = sqrt((velocity.x.sqr + velocity.y.sqr + velocity.z.sqr).toDouble()).toFloat()
|
||||||
|
|
||||||
|
velocity assign velocity / divider * modifier * MAGIC_VELOCITY_CONSTANTf
|
||||||
|
velocity.y += 0.10000000149011612f
|
||||||
|
|
||||||
|
spacing = Vec3(0.2f)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun move(velocity: Vec3) {
|
||||||
|
var newVelocity = Vec3(velocity)
|
||||||
|
if (this.physics && newVelocity != Vec3.EMPTY) {
|
||||||
|
val aabb = aabb + position
|
||||||
|
val collisions = connection.collisionDetector.getCollisionsToCheck(newVelocity, aabb)
|
||||||
|
newVelocity = connection.collisionDetector.collide(null, newVelocity, collisions, aabb)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newVelocity != Vec3.EMPTY) {
|
||||||
|
position += newVelocity
|
||||||
|
}
|
||||||
|
|
||||||
|
onGround = (newVelocity.y != velocity.y) && velocity.y < 0.0f
|
||||||
|
|
||||||
|
if (newVelocity.x != velocity.x) {
|
||||||
|
this.velocity.x = 0.0f
|
||||||
|
}
|
||||||
|
if (newVelocity.z != velocity.z) {
|
||||||
|
this.velocity.z = 0.0f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun move(deltaTime: Int) {
|
private fun move(deltaTime: Int) {
|
||||||
val perSecond = deltaTime / 1000.0f
|
if (!movement) {
|
||||||
position += velocity * perSecond
|
return
|
||||||
velocity *= Vec3.ONE - friction * perSecond
|
|
||||||
|
|
||||||
if (velocity.length() < MINIMUM_VELOCITY) {
|
|
||||||
velocity.clear()
|
|
||||||
}
|
}
|
||||||
|
previousPosition = Vec3(position)
|
||||||
|
|
||||||
|
velocity.y -= (0.04f * gravityStrength).millis
|
||||||
|
|
||||||
|
move(velocity.millis * (deltaTime / 1000.0f))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun tick() {
|
fun tick() {
|
||||||
val currentTime = System.currentTimeMillis()
|
val currentTime = System.currentTimeMillis()
|
||||||
if (lastTickTime == -1L) {
|
if (lastTickTime == -1L) {
|
||||||
@ -72,6 +129,10 @@ abstract class Particle(
|
|||||||
|
|
||||||
tick(deltaTime)
|
tick(deltaTime)
|
||||||
|
|
||||||
|
if (dead) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (lastRealTickTime == -1L) {
|
if (lastRealTickTime == -1L) {
|
||||||
lastRealTickTime = System.currentTimeMillis()
|
lastRealTickTime = System.currentTimeMillis()
|
||||||
} else if (currentTime - lastRealTickTime >= ProtocolDefinition.TICK_TIME) {
|
} else if (currentTime - lastRealTickTime >= ProtocolDefinition.TICK_TIME) {
|
||||||
@ -79,27 +140,55 @@ abstract class Particle(
|
|||||||
lastRealTickTime = currentTime
|
lastRealTickTime = currentTime
|
||||||
}
|
}
|
||||||
|
|
||||||
|
postTick(deltaTime)
|
||||||
lastTickTime = currentTime
|
lastTickTime = currentTime
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun age(deltaTime: Int) {
|
||||||
|
age += deltaTime
|
||||||
|
|
||||||
|
if (age >= maxAge) {
|
||||||
|
dead = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
open fun tick(deltaTime: Int) {
|
open fun tick(deltaTime: Int) {
|
||||||
check(!dead) { "Cannot tick dead particle!" }
|
check(!dead) { "Cannot tick dead particle!" }
|
||||||
check(deltaTime >= 0)
|
check(deltaTime >= 0)
|
||||||
age += deltaTime
|
|
||||||
|
|
||||||
if (age >= maxAge) {
|
age(deltaTime)
|
||||||
dead = true
|
if (dead) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun postTick(deltaTime: Int) {
|
||||||
move(deltaTime)
|
move(deltaTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun realTick() {}
|
open fun realTick() {
|
||||||
|
if (!movement) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accelerateIfYBlocked && position.y == previousPosition.y) {
|
||||||
|
velocity.x *= 1.1f
|
||||||
|
velocity.z *= 1.1f
|
||||||
|
}
|
||||||
|
|
||||||
|
velocity *= friction
|
||||||
|
|
||||||
|
if (onGround) {
|
||||||
|
velocity.x *= 0.699999988079071f
|
||||||
|
velocity.y *= 0.699999988079071f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
abstract fun addVertex(particleMesh: ParticleMesh)
|
abstract fun addVertex(particleMesh: ParticleMesh)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val MINIMUM_VELOCITY = 0.01f
|
private const val MINIMUM_VELOCITY = 0.01f
|
||||||
|
private const val MAGIC_VELOCITY_CONSTANT = 0.4000000059604645
|
||||||
|
private const val MAGIC_VELOCITY_CONSTANTf = MAGIC_VELOCITY_CONSTANT.toFloat()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,33 +17,38 @@ import de.bixilon.minosoft.data.mappings.ResourceLocation
|
|||||||
import de.bixilon.minosoft.data.mappings.particle.data.ParticleData
|
import de.bixilon.minosoft.data.mappings.particle.data.ParticleData
|
||||||
import de.bixilon.minosoft.gui.rendering.particle.ParticleFactory
|
import de.bixilon.minosoft.gui.rendering.particle.ParticleFactory
|
||||||
import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer
|
import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer
|
||||||
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.ExplosionParticle
|
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.ExplosionLargeParticle
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY
|
||||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
|
||||||
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
|
||||||
import de.bixilon.minosoft.util.KUtil.asResourceLocation
|
import de.bixilon.minosoft.util.KUtil.asResourceLocation
|
||||||
import de.bixilon.minosoft.util.KUtil.millis
|
|
||||||
import de.bixilon.minosoft.util.KUtil.ticks
|
|
||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
|
|
||||||
class ExplosionEmitterParticle(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, data: ParticleData) : NoRenderParticle(connection, particleRenderer, position, data) {
|
class ExplosionEmitterParticle(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, data: ParticleData) : NoRenderParticle(connection, particleRenderer, position, Vec3.EMPTY, data) {
|
||||||
private val explosionParticleType = connection.registries.particleTypeRegistry[ExplosionParticle]!!
|
private val explosionParticleType = connection.registries.particleTypeRegistry[ExplosionLargeParticle]!!
|
||||||
|
|
||||||
init {
|
init {
|
||||||
maxAge = 8.millis
|
maxAge = Int.MAX_VALUE
|
||||||
|
movement = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var ticks = 0
|
||||||
override fun realTick() {
|
override fun realTick() {
|
||||||
super.realTick()
|
super.realTick()
|
||||||
for (i in 0 until 6) {
|
for (i in 0 until 6) {
|
||||||
val position = position + { (random.nextFloat() - random.nextFloat()) * 4.0f }
|
val position = position + { (random.nextFloat() - random.nextFloat()) * 4.0f }
|
||||||
|
|
||||||
particleRenderer.add(ExplosionParticle(connection, particleRenderer, position, explosionParticleType.simple(), (age.ticks.toFloat() / maxAge.ticks)))
|
particleRenderer.add(ExplosionLargeParticle(connection, particleRenderer, position, explosionParticleType.simple(), (ticks.toFloat() / MAX_AGE)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ticks == MAX_AGE) {
|
||||||
|
dead = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : ParticleFactory<ExplosionEmitterParticle> {
|
companion object : ParticleFactory<ExplosionEmitterParticle> {
|
||||||
override val RESOURCE_LOCATION: ResourceLocation = "minecraft:explosion_emitter".asResourceLocation()
|
override val RESOURCE_LOCATION: ResourceLocation = "minecraft:explosion_emitter".asResourceLocation()
|
||||||
|
private const val MAX_AGE = 8
|
||||||
|
|
||||||
override fun build(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, velocity: Vec3, data: ParticleData): ExplosionEmitterParticle {
|
override fun build(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, velocity: Vec3, data: ParticleData): ExplosionEmitterParticle {
|
||||||
return ExplosionEmitterParticle(connection, particleRenderer, position, data)
|
return ExplosionEmitterParticle(connection, particleRenderer, position, data)
|
||||||
|
@ -20,7 +20,7 @@ import de.bixilon.minosoft.gui.rendering.particle.types.Particle
|
|||||||
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
|
||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
|
|
||||||
abstract class NoRenderParticle(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, data: ParticleData) : Particle(connection, particleRenderer, position, data) {
|
abstract class NoRenderParticle(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, velocity: Vec3, data: ParticleData) : Particle(connection, particleRenderer, position, velocity, data) {
|
||||||
|
|
||||||
override fun addVertex(particleMesh: ParticleMesh) {}
|
override fun addVertex(particleMesh: ParticleMesh) {}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ import de.bixilon.minosoft.protocol.network.connection.PlayConnection
|
|||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
abstract class RenderParticle(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, data: ParticleData) : Particle(connection, particleRenderer, position, data) {
|
abstract class RenderParticle(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, velocity: Vec3, data: ParticleData) : Particle(connection, particleRenderer, position, velocity, data) {
|
||||||
protected var scale: Float = 0.1f * (random.nextFloat() * 0.5f + 0.5f) * 2.0f
|
protected var scale: Float = 0.1f * (random.nextFloat() * 0.5f + 0.5f) * 2.0f
|
||||||
protected var color: RGBColor = ChatColors.WHITE
|
protected var color: RGBColor = ChatColors.WHITE
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ import de.bixilon.minosoft.gui.rendering.textures.Texture
|
|||||||
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
|
||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
|
|
||||||
abstract class TextureParticle(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, data: ParticleData) : RenderParticle(connection, particleRenderer, position, data) {
|
abstract class TextureParticle(connection: PlayConnection, particleRenderer: ParticleRenderer, velocity: Vec3, position: Vec3, data: ParticleData) : RenderParticle(connection, particleRenderer, velocity, position, data) {
|
||||||
abstract val texture: Texture
|
abstract val texture: Texture
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* 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.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.util.VecUtil.EMPTY
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.assign
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.millis
|
||||||
|
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
|
||||||
|
import de.bixilon.minosoft.util.KUtil.asResourceLocation
|
||||||
|
import de.bixilon.minosoft.util.KUtil.millis
|
||||||
|
import glm_.vec3.Vec3
|
||||||
|
|
||||||
|
class CampfireSmokeParticle(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, velocity: Vec3, data: ParticleData, signal: Boolean) : SimpleTextureParticle(connection, particleRenderer, position, Vec3.EMPTY, data) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
scale *= 3.0f
|
||||||
|
spacing = Vec3(0.25f)
|
||||||
|
maxAge = random.nextInt(50).millis
|
||||||
|
if (signal) {
|
||||||
|
maxAge += 280.millis
|
||||||
|
color = color.with(alpha = 0.95f)
|
||||||
|
} else {
|
||||||
|
maxAge += 80.millis
|
||||||
|
color = color.with(alpha = 0.90f)
|
||||||
|
}
|
||||||
|
|
||||||
|
gravityStrength = 3.0E-6f
|
||||||
|
|
||||||
|
this.velocity assign Vec3(velocity.x, velocity.y + (random.nextFloat() / 500.0f), velocity.z)
|
||||||
|
movement = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun tick(deltaTime: Int) {
|
||||||
|
super.tick(deltaTime)
|
||||||
|
if (dead) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun realTick() {
|
||||||
|
super.realTick()
|
||||||
|
val horizontal = { (random.nextFloat() / 5000.0f * (if (random.nextBoolean()) 1.0f else -1.0f)) }
|
||||||
|
velocity.x += horizontal()
|
||||||
|
velocity.y -= gravityStrength
|
||||||
|
velocity.z += horizontal()
|
||||||
|
|
||||||
|
if (age >= maxAge - 60.millis) {
|
||||||
|
color = color.with(alpha = color.floatAlpha - 0.015f)
|
||||||
|
}
|
||||||
|
if (color.alpha == 0) {
|
||||||
|
dead = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun postTick(deltaTime: Int) {
|
||||||
|
super.postTick(deltaTime)
|
||||||
|
move(velocity.millis * (deltaTime / 1000.0f))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
object CosySmokeParticleFactory : ParticleFactory<CampfireSmokeParticle> {
|
||||||
|
override val RESOURCE_LOCATION: ResourceLocation = "minecraft:campfire_cosy_smoke".asResourceLocation()
|
||||||
|
|
||||||
|
override fun build(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, velocity: Vec3, data: ParticleData): CampfireSmokeParticle {
|
||||||
|
return CampfireSmokeParticle(connection, particleRenderer, position, velocity, data, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
object SignalSmokeParticleFactory : ParticleFactory<CampfireSmokeParticle> {
|
||||||
|
override val RESOURCE_LOCATION: ResourceLocation = "minecraft:campfire_signal_smoke".asResourceLocation()
|
||||||
|
|
||||||
|
override fun build(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, velocity: Vec3, data: ParticleData): CampfireSmokeParticle {
|
||||||
|
return CampfireSmokeParticle(connection, particleRenderer, position, velocity, data, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,25 +18,27 @@ import de.bixilon.minosoft.data.mappings.particle.data.ParticleData
|
|||||||
import de.bixilon.minosoft.data.text.RGBColor.Companion.asGray
|
import de.bixilon.minosoft.data.text.RGBColor.Companion.asGray
|
||||||
import de.bixilon.minosoft.gui.rendering.particle.ParticleFactory
|
import de.bixilon.minosoft.gui.rendering.particle.ParticleFactory
|
||||||
import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer
|
import de.bixilon.minosoft.gui.rendering.particle.ParticleRenderer
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY
|
||||||
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
|
||||||
import de.bixilon.minosoft.util.KUtil.asResourceLocation
|
import de.bixilon.minosoft.util.KUtil.asResourceLocation
|
||||||
import de.bixilon.minosoft.util.KUtil.ticks
|
import de.bixilon.minosoft.util.KUtil.millis
|
||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
|
|
||||||
class ExplosionParticle(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, data: ParticleData, val power: Float = 1.0f) : SimpleTextureParticle(connection, particleRenderer, position, data) {
|
class ExplosionLargeParticle(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, data: ParticleData, power: Float = 1.0f) : SimpleTextureParticle(connection, particleRenderer, position, Vec3.EMPTY, data) {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
maxAge = (6 + random.nextInt(4)).ticks
|
movement = false
|
||||||
|
maxAge = (6 + random.nextInt(4)).millis
|
||||||
val gray = random.nextFloat() * 0.6f + 0.4f
|
val gray = random.nextFloat() * 0.6f + 0.4f
|
||||||
color = gray.asGray()
|
color = gray.asGray()
|
||||||
scale = 2.0f * (power - gray * 0.5f)
|
scale = 2.0f * (power - gray * 0.5f)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : ParticleFactory<ExplosionParticle> {
|
companion object : ParticleFactory<ExplosionLargeParticle> {
|
||||||
override val RESOURCE_LOCATION: ResourceLocation = "minecraft:explosion".asResourceLocation()
|
override val RESOURCE_LOCATION: ResourceLocation = "minecraft:explosion".asResourceLocation()
|
||||||
|
|
||||||
override fun build(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, velocity: Vec3, data: ParticleData): ExplosionParticle {
|
override fun build(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, velocity: Vec3, data: ParticleData): ExplosionLargeParticle {
|
||||||
return ExplosionParticle(connection, particleRenderer, position, data, velocity.x)
|
return ExplosionLargeParticle(connection, particleRenderer, position, data, velocity.x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,7 +19,7 @@ import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.TexturePa
|
|||||||
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
|
||||||
import glm_.vec3.Vec3
|
import glm_.vec3.Vec3
|
||||||
|
|
||||||
abstract class SimpleTextureParticle(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, data: ParticleData) : TextureParticle(connection, particleRenderer, position, data) {
|
abstract class SimpleTextureParticle(connection: PlayConnection, particleRenderer: ParticleRenderer, position: Vec3, velocity: Vec3, data: ParticleData) : TextureParticle(connection, particleRenderer, position, velocity, data) {
|
||||||
override var texture = particleRenderer.renderWindow.textures.allTextures[data.type.textures.first()]!!
|
override var texture = particleRenderer.renderWindow.textures.allTextures[data.type.textures.first()]!!
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,14 +70,14 @@ object VecUtil {
|
|||||||
z = 0.0f
|
z = 0.0f
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Vec3.assign(vec3: Vec3) {
|
infix fun Vec3.assign(vec3: Vec3) {
|
||||||
x = vec3.x
|
x = vec3.x
|
||||||
y = vec3.y
|
y = vec3.y
|
||||||
z = vec3.z
|
z = vec3.z
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName(name = "times2")
|
@JvmName(name = "times2")
|
||||||
infix operator fun Vec3.times(lambda: () -> Double): Vec3 {
|
infix operator fun Vec3.times(lambda: () -> Float): Vec3 {
|
||||||
return Vec3(
|
return Vec3(
|
||||||
x = x * lambda(),
|
x = x * lambda(),
|
||||||
y = y * lambda(),
|
y = y * lambda(),
|
||||||
@ -93,6 +93,23 @@ object VecUtil {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
infix operator fun Vec3.plusAssign(lambda: () -> Float) {
|
||||||
|
this assign this + lambda
|
||||||
|
}
|
||||||
|
|
||||||
|
infix operator fun Vec3.timesAssign(lambda: () -> Float) {
|
||||||
|
this assign this * lambda
|
||||||
|
}
|
||||||
|
|
||||||
|
val Float.sqr: Float
|
||||||
|
get() = this * this
|
||||||
|
|
||||||
|
val Vec3.ticks: Vec3
|
||||||
|
get() = this / ProtocolDefinition.TICKS_PER_SECOND
|
||||||
|
|
||||||
|
val Vec3.millis: Vec3
|
||||||
|
get() = this * ProtocolDefinition.TICKS_PER_SECOND
|
||||||
|
|
||||||
fun getRotatedValues(x: Float, y: Float, sin: Float, cos: Float, rescale: Boolean): Vec2 {
|
fun getRotatedValues(x: Float, y: Float, sin: Float, cos: Float, rescale: Boolean): Vec2 {
|
||||||
val result = Vec2(x * cos - y * sin, x * sin + y * cos)
|
val result = Vec2(x * cos - y * sin, x * sin + y * cos)
|
||||||
if (rescale) {
|
if (rescale) {
|
||||||
@ -290,14 +307,10 @@ object VecUtil {
|
|||||||
get() = glm.max(this.x, this.y, this.z)
|
get() = glm.max(this.x, this.y, this.z)
|
||||||
|
|
||||||
val Vec3.signs: Vec3
|
val Vec3.signs: Vec3
|
||||||
get() {
|
get() = Vec3(glm.sign(this.x), glm.sign(this.y), glm.sign(this.z))
|
||||||
return Vec3(glm.sign(this.x), glm.sign(this.y), glm.sign(this.z))
|
|
||||||
}
|
|
||||||
|
|
||||||
val Vec3.floor: Vec3i
|
val Vec3.floor: Vec3i
|
||||||
get() {
|
get() = Vec3i(this.x.floor, this.y.floor, this.z.floor)
|
||||||
return Vec3i(this.x.floor, this.y.floor, this.z.floor)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Vec3.getMinDistanceDirection(aabb: AABB): Directions {
|
fun Vec3.getMinDistanceDirection(aabb: AABB): Directions {
|
||||||
var minDistance = Float.MAX_VALUE
|
var minDistance = Float.MAX_VALUE
|
||||||
|
@ -24,6 +24,7 @@ import de.bixilon.minosoft.data.mappings.ResourceLocation
|
|||||||
import de.bixilon.minosoft.data.mappings.recipes.Recipes
|
import de.bixilon.minosoft.data.mappings.recipes.Recipes
|
||||||
import de.bixilon.minosoft.data.mappings.versions.Registries
|
import de.bixilon.minosoft.data.mappings.versions.Registries
|
||||||
import de.bixilon.minosoft.data.mappings.versions.Version
|
import de.bixilon.minosoft.data.mappings.versions.Version
|
||||||
|
import de.bixilon.minosoft.data.physics.CollisionDetector
|
||||||
import de.bixilon.minosoft.data.player.Player
|
import de.bixilon.minosoft.data.player.Player
|
||||||
import de.bixilon.minosoft.data.player.tab.TabList
|
import de.bixilon.minosoft.data.player.tab.TabList
|
||||||
import de.bixilon.minosoft.data.scoreboard.ScoreboardManager
|
import de.bixilon.minosoft.data.scoreboard.ScoreboardManager
|
||||||
@ -79,6 +80,7 @@ class PlayConnection(
|
|||||||
|
|
||||||
lateinit var velocityHandlerTask: TimeWorkerTask
|
lateinit var velocityHandlerTask: TimeWorkerTask
|
||||||
private var velocityHandlerLastExecutionTime: Long = 0L
|
private var velocityHandlerLastExecutionTime: Long = 0L
|
||||||
|
val collisionDetector = CollisionDetector(this)
|
||||||
|
|
||||||
override var connectionState: ConnectionStates = ConnectionStates.DISCONNECTED
|
override var connectionState: ConnectionStates = ConnectionStates.DISCONNECTED
|
||||||
set(value) {
|
set(value) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user