This commit is contained in:
2024-11-30 19:52:25 +01:00
parent 828297aef2
commit 2edb23e9ec
8 changed files with 72 additions and 41 deletions
@@ -163,7 +163,8 @@ fun onRightClick(player: PlayerEntity, world: ServerWorld, hand: Hand) : TypedAc
return TypedActionResult(ActionResult.PASS, handItem) return TypedActionResult(ActionResult.PASS, handItem)
} }
val emitter = ParticleEmitter(hitResult.pos, Vector2f(0.0f, 0.0f), world, emitterParams) val debug = world.gameRules.getBoolean(Bde_particles.SHOW_PARTICLE_DEBUG)
val emitter = ParticleEmitter(hitResult.pos, Vector2f(0.0f, 0.0f), world, emitterParams, debug)
ALL_PARTICLE_EMITTERS += emitter ALL_PARTICLE_EMITTERS += emitter
return TypedActionResult(ActionResult.PASS, handItem) return TypedActionResult(ActionResult.PASS, handItem)
@@ -1,16 +1,11 @@
package com.bytedice.bde_particles package com.bytedice.bde_particles
import net.minecraft.component.Component
import net.minecraft.component.ComponentType
import net.minecraft.entity.EntityType import net.minecraft.entity.EntityType
import net.minecraft.entity.decoration.DisplayEntity.ItemDisplayEntity import net.minecraft.entity.decoration.DisplayEntity.ItemDisplayEntity
import net.minecraft.item.Item
import net.minecraft.nbt.NbtCompound import net.minecraft.nbt.NbtCompound
import net.minecraft.nbt.NbtFloat import net.minecraft.nbt.NbtFloat
import net.minecraft.nbt.NbtList import net.minecraft.nbt.NbtList
import net.minecraft.nbt.NbtString import net.minecraft.nbt.NbtString
import net.minecraft.registry.Registries
import net.minecraft.registry.Registry
import net.minecraft.server.world.ServerWorld import net.minecraft.server.world.ServerWorld
class DisplayEntity(private var properties: DisplayEntityProperties?) { class DisplayEntity(private var properties: DisplayEntityProperties?) {
@@ -38,7 +33,7 @@ class DisplayEntity(private var properties: DisplayEntityProperties?) {
if (matchResult != null) { if (matchResult != null) {
modelName = matchResult.groupValues[1] modelName = matchResult.groupValues[1]
customModelNum = matchResult.groupValues[2].toInt() customModelNum = matchResult.groupValues[2].toIntOrNull() ?: 0
} }
else { else {
modelName = properties.model modelName = properties.model
@@ -92,6 +87,10 @@ class DisplayEntity(private var properties: DisplayEntityProperties?) {
put("view_range", NbtCompound().apply { properties.viewRange }) put("view_range", NbtCompound().apply { properties.viewRange })
if (properties.name != null) {
putString("CustomName", properties.name)
putByte("CustomNameVisible", 1)
}
} }
entity?.readNbt(nbt) entity?.readNbt(nbt)
@@ -17,5 +17,6 @@ data class DisplayEntityProperties (
val scale: Vector3f = Vector3f(1.0f, 1.0f, 1.0f), val scale: Vector3f = Vector3f(1.0f, 1.0f, 1.0f),
val rightRotation: Vector4f = Vector4f(0.0f, 0.0f, 0.0f, 1.0f), val rightRotation: Vector4f = Vector4f(0.0f, 0.0f, 0.0f, 1.0f),
val viewRange: Float = 2.0f val viewRange: Float = 2.0f,
var name: String? = null
) )
@@ -14,6 +14,7 @@ import kotlin.random.Random
class LerpCurves(val function: (Float) -> Float) { class LerpCurves(val function: (Float) -> Float) {
companion object { companion object {
val Constant = LerpCurves { _ -> 1.0f }
val Linear = LerpCurves { y -> y } val Linear = LerpCurves { y -> y }
val Sqrt = LerpCurves { y -> sqrt(y) } val Sqrt = LerpCurves { y -> sqrt(y) }
val Exponent = LerpCurves { y -> y.pow(2.0f) } val Exponent = LerpCurves { y -> y.pow(2.0f) }
@@ -166,7 +167,8 @@ fun transformOffsetByScale(offset: Vector3f, scale: Vector3f): Vector3f {
fun lerp(x: Float, y: Float, t: Float) : Float { fun lerp(x: Float, y: Float, t: Float) : Float {
return x + (y - x) * t val clampedT = t.coerceIn(0f, 1f)
return x + (y - x) * clampedT
} }
@@ -35,8 +35,8 @@ data class EmitterParams (
{ {
companion object Presets { companion object Presets {
val DEFAULT = EmitterParams( val DEFAULT = EmitterParams(
maxCount = 400, maxCount = 200,
spawnRate = 100, spawnRate = 50,
spawnChance = 1.0f, spawnChance = 1.0f,
spawnDuration = ParamClasses.Duration.SingleBurst(4), spawnDuration = ParamClasses.Duration.SingleBurst(4),
spawnPosOffset = Vector3f(0.0f, 0.0f, 0.0f), spawnPosOffset = Vector3f(0.0f, 0.0f, 0.0f),
@@ -47,15 +47,15 @@ data class EmitterParams (
rotVel = ParamClasses.PairVec3f.NonUniform(-0.2f, -0.2f, -0.2f, 0.2f, 0.2f, 0.2f), rotVel = ParamClasses.PairVec3f.NonUniform(-0.2f, -0.2f, -0.2f, 0.2f, 0.2f, 0.2f),
initVel = ParamClasses.PairVec3f.Null, initVel = ParamClasses.PairVec3f.Null,
initCenterVel = ParamClasses.PairFloat(0.4f, 0.5f), initCenterVel = ParamClasses.PairFloat(0.4f, 0.5f),
initScale = ParamClasses.PairVec3f.Uniform(1.5f, 1.0f), initScale = ParamClasses.PairVec3f.Uniform(0.5f, 1.5f),
transformWithVel = ParamClasses.TransformWithVel.none, transformWithVel = ParamClasses.TransformWithVel.None,
forceFields = emptyArray(), forceFields = emptyArray(),
constVel = Vector3f(0.0f, 0.0f, 0.0f), constVel = Vector3f(0.0f, 0.0f, 0.0f),
drag = 0.075f, drag = 0.075f,
minVel = 0.0f, minVel = 0.0f,
offsetCurve = ParamClasses.LerpVal.NoLerpVec3f, offsetCurve = ParamClasses.LerpVal.NoLerpVec3f,
rotVelCurve = ParamClasses.LerpVal.LerpUniform(1.0f, 0.0f, LerpCurves.Sqrt), rotVelCurve = ParamClasses.LerpVal.LerpUniform(1.0f, 0.0f, LerpCurves.Sqrt),
scaleCurve = ParamClasses.LerpVal.LerpUniform(0.0f, 2.0f, LerpCurves.Linear), scaleCurve = ParamClasses.LerpVal.LerpUniform(1.0f, 2.5f, LerpCurves.Constant),
modelCurve = Pair( modelCurve = Pair(
arrayOf("shroomlight", "orange_concrete", "orange_stained_glass", "gray_wool", "gray_stained_glass", "light_gray_stained_glass", "light_gray_stained_glass_pane"), arrayOf("shroomlight", "orange_concrete", "orange_stained_glass", "gray_wool", "gray_stained_glass", "light_gray_stained_glass", "light_gray_stained_glass_pane"),
LerpCurves.Sqrt LerpCurves.Sqrt
@@ -119,8 +119,8 @@ class ParamClasses {
) : Duration() ) : Duration()
} }
enum class TransformWithVel { enum class TransformWithVel {
rotOnly, RotOnly,
scaleAndRot, ScaleAndRot,
none None
} }
} }
@@ -1,6 +1,7 @@
package com.bytedice.bde_particles.particles package com.bytedice.bde_particles.particles
import com.bytedice.bde_particles.* import com.bytedice.bde_particles.*
import net.minecraft.particle.DustParticleEffect
import net.minecraft.server.world.ServerWorld import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.Vec3d import net.minecraft.util.math.Vec3d
import org.joml.Vector2f import org.joml.Vector2f
@@ -61,8 +62,6 @@ class Particle(
private var lifeTime = emitterParams.lifeTime.randomize() private var lifeTime = emitterParams.lifeTime.randomize()
private lateinit var particleEntity: DisplayEntity private lateinit var particleEntity: DisplayEntity
private lateinit var debugOriginEntity: DisplayEntity
private lateinit var debugVelEntity: DisplayEntity
fun init() { fun init() {
val so = emitterParams.spawnPosOffset val so = emitterParams.spawnPosOffset
@@ -86,7 +85,7 @@ class Particle(
model = lerpArray(emitterParams.modelCurve.first as Array<Any>, 0.0f, emitterParams.modelCurve.second) as String, model = lerpArray(emitterParams.modelCurve.first as Array<Any>, 0.0f, emitterParams.modelCurve.second) as String,
translation = newPos.add(pos), translation = newPos.add(pos),
leftRotation = quatRot, leftRotation = quatRot,
scale = scale, scale = Vector3f(scale).mul(emitterParams.scaleCurve.lerpToVector3f(0.0f)),
tags = arrayOf("BPS_Particle", "BPS_UUID", SESSION_UUID.toString()) tags = arrayOf("BPS_Particle", "BPS_UUID", SESSION_UUID.toString())
) )
@@ -105,7 +104,7 @@ class Particle(
} }
fun tick() { fun tick(world: ServerWorld) {
if (!isInit) { error("Particle is not initialized before being ticked. Please use Particle.init() to initialize it.") } if (!isInit) { error("Particle is not initialized before being ticked. Please use Particle.init() to initialize it.") }
val newProperties = calcNewProperties() val newProperties = calcNewProperties()
@@ -114,6 +113,10 @@ class Particle(
if (timeAlive > lifeTime) { kill() } if (timeAlive > lifeTime) { kill() }
if (debug) {
tickDebug(world)
}
timeAlive += 1 timeAlive += 1
} }
@@ -195,7 +198,7 @@ class Particle(
private fun calcRot(t: Float) : Vector3f { private fun calcRot(t: Float) : Vector3f {
val newRot = Vector3f(rot) val newRot = Vector3f(rot)
if (emitterParams.transformWithVel == ParamClasses.TransformWithVel.none) { if (emitterParams.transformWithVel == ParamClasses.TransformWithVel.None) {
val newVel = Vector3f(rotVel) val newVel = Vector3f(rotVel)
newVel.mul(emitterParams.rotVelCurve.lerpToVector3f(t)) newVel.mul(emitterParams.rotVelCurve.lerpToVector3f(t))
@@ -225,27 +228,46 @@ class Particle(
private fun calcScale(t: Float) : Vector3f { private fun calcScale(t: Float) : Vector3f {
val newScale = Vector3f(scale) val newScale = Vector3f(scale)
newScale.mul(emitterParams.scaleCurve.lerpToVector3f(t)) return newScale.mul(emitterParams.scaleCurve.lerpToVector3f(t))
return scale
} }
private fun spawnDebug() { private fun tickDebug(world: ServerWorld) {
// spawn cube at particle origin // spawn particle at particle origin
// show arrow pointing toward particle direction // show trail pointing toward particle direction
// name-tag its data
// origin debug
val greenDustEffect = DustParticleEffect(Vector3f(0.0f, 1.0f, 0.0f), 2.0f)
world.spawnParticles(
greenDustEffect,
entityPos.x + pos.x,
entityPos.y + pos.y,
entityPos.z + pos.z,
1,
0.0,
0.0,
0.0,
0.0
)
} // vel debug
var timesLooped = 0
repeat(3) {
private fun updateDebug() { val redDustEffect = DustParticleEffect(Vector3f(1.0f, 0.0f, 0.0f), 1.0f)
world.spawnParticles(
} redDustEffect,
entityPos.x + pos.x + originOffset.x + vel.x * timesLooped,
entityPos.y + pos.y + originOffset.y + vel.y * timesLooped,
private fun calcDebug() { entityPos.z + pos.z + originOffset.z + vel.z * timesLooped,
1,
0.0,
0.0,
0.0,
0.0
)
timesLooped += 1
}
} }
@@ -7,8 +7,13 @@ import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.Vec3d import net.minecraft.util.math.Vec3d
import org.joml.Vector2f import org.joml.Vector2f
class ParticleEmitter(private val pos: Vec3d, private val rot: Vector2f, private val world: ServerWorld, private val params: EmitterParams) { class ParticleEmitter(
private val pos: Vec3d,
private val rot: Vector2f,
private val world: ServerWorld,
private val params: EmitterParams,
private val debug: Boolean
) {
private var allParticles: Array<Particle> = emptyArray() private var allParticles: Array<Particle> = emptyArray()
private var timeAlive = 0 private var timeAlive = 0
@@ -28,7 +33,7 @@ class ParticleEmitter(private val pos: Vec3d, private val rot: Vector2f, private
for (particle in allParticles) { for (particle in allParticles) {
if (particle.isDead) { allParticles = allParticles.toMutableList().apply { remove(particle) }.toTypedArray() } if (particle.isDead) { allParticles = allParticles.toMutableList().apply { remove(particle) }.toTypedArray() }
else { particle.tick() } else { particle.tick(world) }
} }
} }
@@ -45,7 +50,6 @@ class ParticleEmitter(private val pos: Vec3d, private val rot: Vector2f, private
val randomSpawnChance = randomFloatBetween(0.0f, params.spawnChance.coerceIn(0.0f, 1.0f)) val randomSpawnChance = randomFloatBetween(0.0f, params.spawnChance.coerceIn(0.0f, 1.0f))
if (randomSpawnChance > params.spawnChance) { return } if (randomSpawnChance > params.spawnChance) { return }
val debug = world.gameRules.getBoolean(Bde_particles.SHOW_PARTICLE_DEBUG)
val particle = Particle(params, pos, rot, debug) val particle = Particle(params, pos, rot, debug)
particle.init() particle.init()
particle.spawn(world) particle.spawn(world)
@@ -91,6 +95,8 @@ class ParticleEmitter(private val pos: Vec3d, private val rot: Vector2f, private
isTicking = false isTicking = false
isDead = true isDead = true
} }
fun stopTicking() { fun stopTicking() {
isTicking = false isTicking = false
} }