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)
}
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
return TypedActionResult(ActionResult.PASS, handItem)
@@ -1,16 +1,11 @@
package com.bytedice.bde_particles
import net.minecraft.component.Component
import net.minecraft.component.ComponentType
import net.minecraft.entity.EntityType
import net.minecraft.entity.decoration.DisplayEntity.ItemDisplayEntity
import net.minecraft.item.Item
import net.minecraft.nbt.NbtCompound
import net.minecraft.nbt.NbtFloat
import net.minecraft.nbt.NbtList
import net.minecraft.nbt.NbtString
import net.minecraft.registry.Registries
import net.minecraft.registry.Registry
import net.minecraft.server.world.ServerWorld
class DisplayEntity(private var properties: DisplayEntityProperties?) {
@@ -38,7 +33,7 @@ class DisplayEntity(private var properties: DisplayEntityProperties?) {
if (matchResult != null) {
modelName = matchResult.groupValues[1]
customModelNum = matchResult.groupValues[2].toInt()
customModelNum = matchResult.groupValues[2].toIntOrNull() ?: 0
}
else {
modelName = properties.model
@@ -92,6 +87,10 @@ class DisplayEntity(private var properties: DisplayEntityProperties?) {
put("view_range", NbtCompound().apply { properties.viewRange })
if (properties.name != null) {
putString("CustomName", properties.name)
putByte("CustomNameVisible", 1)
}
}
entity?.readNbt(nbt)
@@ -17,5 +17,6 @@ data class DisplayEntityProperties (
val scale: Vector3f = Vector3f(1.0f, 1.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) {
companion object {
val Constant = LerpCurves { _ -> 1.0f }
val Linear = LerpCurves { y -> y }
val Sqrt = LerpCurves { y -> sqrt(y) }
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 {
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 {
val DEFAULT = EmitterParams(
maxCount = 400,
spawnRate = 100,
maxCount = 200,
spawnRate = 50,
spawnChance = 1.0f,
spawnDuration = ParamClasses.Duration.SingleBurst(4),
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),
initVel = ParamClasses.PairVec3f.Null,
initCenterVel = ParamClasses.PairFloat(0.4f, 0.5f),
initScale = ParamClasses.PairVec3f.Uniform(1.5f, 1.0f),
transformWithVel = ParamClasses.TransformWithVel.none,
initScale = ParamClasses.PairVec3f.Uniform(0.5f, 1.5f),
transformWithVel = ParamClasses.TransformWithVel.None,
forceFields = emptyArray(),
constVel = Vector3f(0.0f, 0.0f, 0.0f),
drag = 0.075f,
minVel = 0.0f,
offsetCurve = ParamClasses.LerpVal.NoLerpVec3f,
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(
arrayOf("shroomlight", "orange_concrete", "orange_stained_glass", "gray_wool", "gray_stained_glass", "light_gray_stained_glass", "light_gray_stained_glass_pane"),
LerpCurves.Sqrt
@@ -119,8 +119,8 @@ class ParamClasses {
) : Duration()
}
enum class TransformWithVel {
rotOnly,
scaleAndRot,
none
RotOnly,
ScaleAndRot,
None
}
}
@@ -1,6 +1,7 @@
package com.bytedice.bde_particles.particles
import com.bytedice.bde_particles.*
import net.minecraft.particle.DustParticleEffect
import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.Vec3d
import org.joml.Vector2f
@@ -61,8 +62,6 @@ class Particle(
private var lifeTime = emitterParams.lifeTime.randomize()
private lateinit var particleEntity: DisplayEntity
private lateinit var debugOriginEntity: DisplayEntity
private lateinit var debugVelEntity: DisplayEntity
fun init() {
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,
translation = newPos.add(pos),
leftRotation = quatRot,
scale = scale,
scale = Vector3f(scale).mul(emitterParams.scaleCurve.lerpToVector3f(0.0f)),
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.") }
val newProperties = calcNewProperties()
@@ -114,6 +113,10 @@ class Particle(
if (timeAlive > lifeTime) { kill() }
if (debug) {
tickDebug(world)
}
timeAlive += 1
}
@@ -195,7 +198,7 @@ class Particle(
private fun calcRot(t: Float) : Vector3f {
val newRot = Vector3f(rot)
if (emitterParams.transformWithVel == ParamClasses.TransformWithVel.none) {
if (emitterParams.transformWithVel == ParamClasses.TransformWithVel.None) {
val newVel = Vector3f(rotVel)
newVel.mul(emitterParams.rotVelCurve.lerpToVector3f(t))
@@ -225,27 +228,46 @@ class Particle(
private fun calcScale(t: Float) : Vector3f {
val newScale = Vector3f(scale)
newScale.mul(emitterParams.scaleCurve.lerpToVector3f(t))
return scale
return newScale.mul(emitterParams.scaleCurve.lerpToVector3f(t))
}
private fun spawnDebug() {
// spawn cube at particle origin
// show arrow pointing toward particle direction
// name-tag its data
private fun tickDebug(world: ServerWorld) {
// spawn particle at particle origin
// show trail pointing toward particle direction
// 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) {
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,
entityPos.z + pos.z + originOffset.z + vel.z * timesLooped,
1,
0.0,
0.0,
0.0,
0.0
)
timesLooped += 1
}
private fun updateDebug() {
}
private fun calcDebug() {
}
@@ -7,8 +7,13 @@ import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.Vec3d
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 timeAlive = 0
@@ -28,7 +33,7 @@ class ParticleEmitter(private val pos: Vec3d, private val rot: Vector2f, private
for (particle in allParticles) {
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))
if (randomSpawnChance > params.spawnChance) { return }
val debug = world.gameRules.getBoolean(Bde_particles.SHOW_PARTICLE_DEBUG)
val particle = Particle(params, pos, rot, debug)
particle.init()
particle.spawn(world)
@@ -91,6 +95,8 @@ class ParticleEmitter(private val pos: Vec3d, private val rot: Vector2f, private
isTicking = false
isDead = true
}
fun stopTicking() {
isTicking = false
}