updated particle debug tools (emitter debug coming soon)

This commit is contained in:
2024-12-25 16:29:32 +01:00
parent a7212dbe42
commit c416432f7b
8 changed files with 257 additions and 59 deletions
@@ -173,6 +173,7 @@ fun onRightClick(player: PlayerEntity, world: ServerWorld, hand: Hand) : TypedAc
}
val debug = world.gameRules.getBoolean(Bde_particles.SHOW_PARTICLE_DEBUG)
val emitter = ParticleEmitter(
hitResult.pos,
Vector2f(0.0f, 0.0f),
@@ -8,7 +8,7 @@ import net.minecraft.nbt.NbtList
import net.minecraft.nbt.NbtString
import net.minecraft.server.world.ServerWorld
class DisplayEntity(private var properties: DisplayEntityProperties?) {
class DisplayEntity(var properties: DisplayEntityProperties?) {
private var hasSpawned = false
private var entity: ItemDisplayEntity? = null
@@ -84,6 +84,7 @@ class DisplayEntity(private var properties: DisplayEntityProperties?) {
if (properties.brightnessOverride != null) {
put("brightness", NbtCompound().apply {
putInt("block", properties.brightnessOverride!!)
putInt("sky", properties.brightnessOverride!!)
})
}
}
@@ -6,21 +6,21 @@ import org.joml.Vector3f
import org.joml.Vector4f
data class DisplayEntityProperties (
val pos: Vec3d = Vec3d(0.0, 0.0, 0.0),
val rot: Vector2f = Vector2f(0.0f, 0.0f),
var pos: Vec3d = Vec3d(0.0, 0.0, 0.0),
var rot: Vector2f = Vector2f(0.0f, 0.0f),
val model: String = "minecraft:purple_concrete",
val customModel: Int = 0,
val tags: Array<String> = emptyArray(),
val viewRange: Float = 2.0f,
var model: String = "minecraft:purple_concrete",
var customModel: Int = 0,
var tags: Array<String> = emptyArray(),
var viewRange: Float = 2.0f,
var customName: String? = null,
var brightnessOverride: Int? = null,
var billboard: String = Billboard.FIXED,
val translation: Vector3f = Vector3f(0.0f, 0.0f, 0.0f),
val leftRotation: Vector4f = Vector4f(0.0f, 0.0f, 0.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)
var translation: Vector3f = Vector3f(0.0f, 0.0f, 0.0f),
var leftRotation: Vector4f = Vector4f(0.0f, 0.0f, 0.0f, 1.0f),
var scale: Vector3f = Vector3f(1.0f, 1.0f, 1.0f),
var rightRotation: Vector4f = Vector4f(0.0f, 0.0f, 0.0f, 1.0f)
)
class Billboard () {
@@ -0,0 +1,107 @@
package com.bytedice.bde_particles.particles
import com.bytedice.bde_particles.Billboard
import com.bytedice.bde_particles.DisplayEntity
import com.bytedice.bde_particles.DisplayEntityProperties
import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.Vec3d
import org.joml.Vector2f
import org.joml.Vector3f
import org.joml.Vector4f
class EmitterDebug(
rot: Vector2f,
eOrigin: Vec3d,
spawnPosOffset: Vector3f,
shape: SpawningShape,
forceFields: ParamClasses.ForceFieldArray
) {
private val eOrigin = EOrigin(rot, eOrigin)
private val shapeDebug = ShapeDebug(rot, eOrigin, spawnPosOffset, shape)
fun spawn(world: ServerWorld) {
eOrigin.spawn(world)
shapeDebug.spawn(world)
}
fun update(
rot: Vector2f,
eOrigin: Vec3d,
pOrigin: Vector3f,
pVel: Vector3f,
pScale: Vector3f,
spawnPosOffset: Vector3f,
shape: SpawningShape,
) {
}
}
class EOrigin(rot: Vector2f, eOrigin: Vec3d) {
val eOriginDE = DisplayEntity(
DisplayEntityProperties(
pos = eOrigin,
rot = rot,
model = "minecraft:red_concrete",
tags = arrayOf("DEBUG", "E_DEBUG", "eOrigin_DEBUG"),
brightnessOverride = 15,
scale = Vector3f(0.25f, 0.25f, 0.25f)
)
)
fun spawn(world: ServerWorld) {
eOriginDE.spawn(world)
}
fun update(rot: Vector2f, eOrigin: Vec3d) {
val newProperties = eOriginDE.properties
newProperties?.rot = rot
newProperties?.pos = eOrigin
eOriginDE.updateProperties(newProperties!!)
}
}
class ShapeDebug(rot: Vector2f, eOrigin: Vec3d, spawnPosOffset: Vector3f, shape: SpawningShape) {
val shapeScale: Vector3f? = when (shape) {
is SpawningShape.Circle -> Vector3f(shape.radius * 1.75f, shape.radius * 1.75f, 0.0f)
is SpawningShape.Sphere -> Vector3f(shape.radius * 1.75f, shape.radius * 1.75f, 0.0f)
is SpawningShape.Rect -> Vector3f(shape.size.x, 0.0f, shape.size.y)
is SpawningShape.Cube -> Vector3f(shape.size.x, shape.size.y, shape.size.z)
else -> null
}
val shapeRot = if (shape is SpawningShape.Circle) { Vector4f(-0.707f, 0.0f, 0.0f, 0.707f) }
else { Vector4f(0.0f, 0.0f, 0.0f, 1.0f) }
val shapeDE: DisplayEntity? = if (shape !is SpawningShape.Point) {
DisplayEntity(DisplayEntityProperties(
pos = eOrigin.add(spawnPosOffset.x.toDouble(), spawnPosOffset.y.toDouble(), spawnPosOffset.z.toDouble()),
rot = rot,
model = if (shape is SpawningShape.Circle || shape is SpawningShape.Sphere) { "minecraft:sunflower" }
else { "minecraft:yellow_stained_glass" },
tags = arrayOf("DEBUG", "P_DEBUG", "shape_DEBUG"),
brightnessOverride = 15,
billboard = if (shape !is SpawningShape.Sphere) { Billboard.FIXED } else { Billboard.CENTER },
translation = spawnPosOffset,
leftRotation = shapeRot,
scale = shapeScale!!
))
}
else { null }
fun spawn(world: ServerWorld) {
shapeDE?.spawn(world)
}
fun update(rot: Vector2f, eOrigin: Vec3d, spawnPosOffset: Vector3f) {
val newProperties = shapeDE?.properties
newProperties?.rot = rot
newProperties?.pos = eOrigin
newProperties?.translation = spawnPosOffset
shapeDE?.updateProperties(newProperties!!)
}
}
@@ -13,8 +13,8 @@ import kotlin.math.*
class Particle(
private val emitterParams: EmitterParams,
private var entityPos: Vec3d,
private val entityRot: Vector2f,
private var debug: Boolean
private var entityRot: Vector2f,
private val debug: Boolean = false
) {
private var pos = Vector3f(0.0f, 0.0f, 0.0f)
private var timeAlive = 0
@@ -56,6 +56,9 @@ class Particle(
private lateinit var particleEntity: DisplayEntity
private val debugTool = ParticleDebug(entityRot, entityPos, pos, vel, scale)
fun init() {
val so = emitterParams.spawnPosOffset
entityPos = entityPos.add(so.x.toDouble(), so.y.toDouble(), so.z.toDouble())
@@ -92,13 +95,14 @@ class Particle(
fun spawn(world: ServerWorld) {
if (isInit) {
particleEntity.spawn(world)
if (debug) { debugTool.spawn(world) }
LIVING_PARTICLE_COUNT += 1
}
else { error("Particle is not initialized before being spawned. Please use Particle.init() to initialize it.") }
}
fun tick(world: ServerWorld) {
fun tick() {
if (!isInit) { error("Particle is not initialized before being ticked. Please use Particle.init() to initialize it.") }
val newProperties = calcNewProperties()
@@ -107,10 +111,6 @@ class Particle(
if (timeAlive > lifeTime) { kill() }
if (debug) {
tickDebug(world)
}
timeAlive += 1
}
@@ -166,17 +166,21 @@ class Particle(
val (quatRot, transformOffset) = calcTransformOffset(newRot, originOffset, newScale)
val combinedOffset = transformOffset.add(newPos)
val newTranslate = combinedOffset.add(newOriginOffset)
val newProperties = DisplayEntityProperties(
pos = entityPos,
rot = entityRot,
model = newModel,
translation = combinedOffset.add(newOriginOffset),
translation = newTranslate,
leftRotation = quatRot,
scale = newScale,
tags = arrayOf("BPS_Particle", "BPS_UUID", SESSION_UUID.toString()),
brightnessOverride = newBrightness
)
if (debug) { debugTool.update(entityRot, entityPos, newTranslate, vel, newScale) }
return newProperties
}
@@ -237,40 +241,10 @@ class Particle(
}
private fun tickDebug(world: ServerWorld) {
// 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
val redDustEffect = DustParticleEffect(Vector3f(1.0f, 0.0f, 0.0f), 1.0f)
world.spawnParticles(
redDustEffect,
entityPos.x + pos.x + originOffset.x + vel.x * 10,
entityPos.y + pos.y + originOffset.y + vel.y * 10,
entityPos.z + pos.z + originOffset.z + vel.z * 10,
1,
0.0,
0.0,
0.0,
0.0
)
}
fun kill() {
if (!isDead) {
particleEntity.kill()
if (debug) { debugTool.kill() }
LIVING_PARTICLE_COUNT -= 1
isDead = true
}
@@ -1,4 +1,120 @@
package com.bytedice.bde_particles.particles
class ParticleDebug {
import com.bytedice.bde_particles.*
import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.Vec3d
import org.joml.Vector2f
import org.joml.Vector3f
import kotlin.math.atan2
import kotlin.math.max
import kotlin.math.pow
import kotlin.math.sqrt
class ParticleDebug(
rot: Vector2f,
eOrigin: Vec3d,
pOrigin: Vector3f,
pVel: Vector3f,
pScale: Vector3f
) {
private val pOriginDebug = POrigin(rot, eOrigin, pOrigin)
private val pVelDebug = PVel(rot, eOrigin, pOrigin, pVel, pScale)
fun spawn(world: ServerWorld) {
pOriginDebug.spawn(world)
pVelDebug.spawn(world)
}
fun update(
rot: Vector2f,
eOrigin: Vec3d,
pOrigin: Vector3f,
pVel: Vector3f,
pScale: Vector3f
) {
pOriginDebug.update(rot, eOrigin, pOrigin)
pVelDebug.update(rot, eOrigin, pOrigin, pVel, pScale)
}
fun kill() {
pOriginDebug.kill()
pVelDebug.kill()
}
}
class POrigin(rot: Vector2f, eOrigin: Vec3d, pOrigin: Vector3f) {
val pOriginDE = DisplayEntity(DisplayEntityProperties(
pos = eOrigin,
rot = rot,
model = "minecraft:lime_concrete",
tags = arrayOf("DEBUG", "P_DEBUG", "pOrigin_DEBUG"),
brightnessOverride = 15,
translation = Vector3f(pOrigin),
scale = Vector3f(0.15f, 0.15f, 0.15f)
))
fun spawn(world: ServerWorld) {
pOriginDE.spawn(world)
}
fun update(rot: Vector2f, eOrigin: Vec3d, pOrigin: Vector3f) {
val newProperties = pOriginDE.properties
newProperties?.rot = rot
newProperties?.pos = eOrigin
newProperties?.translation = Vector3f(pOrigin)
pOriginDE.updateProperties(newProperties!!)
}
fun kill() {
pOriginDE.kill()
}
}
class PVel(rot: Vector2f, eOrigin: Vec3d, pOrigin: Vector3f, pVel: Vector3f, pScale: Vector3f) {
val pVelDE = DisplayEntity(DisplayEntityProperties(
pos = eOrigin,
rot = rot,
model = "minecraft:red_nether_brick_slab", //"minecraft:red_stained_glass",
tags = arrayOf("DEBUG", "P_DEBUG", "pVel_DEBUG"),
brightnessOverride = 15,
translation = Vector3f(pOrigin),
scale = Vector3f(0.05f, max(max(pScale.x, pScale.y), pScale.z) + (pVel.x + pVel.y + pVel.z), 0.05f)
))
fun spawn(world: ServerWorld) {
pVelDE.spawn(world)
}
fun update(rot: Vector2f, eOrigin: Vec3d, pOrigin: Vector3f, pVel: Vector3f, pScale: Vector3f) {
val newProperties = pVelDE.properties
val scale = (max(max(pScale.x, pScale.y), pScale.z) + (pVel.x + pVel.y + pVel.z)) * 2.0f
val scaleVec3f = Vector3f(0.05f, scale, 0.05f)
val leftRotEuler = velToRot(pVel)
newProperties?.rot = rot
newProperties?.pos = eOrigin
newProperties?.translation = Vector3f(pOrigin)
newProperties?.leftRotation = eulerToQuat(leftRotEuler)
newProperties?.scale = scaleVec3f
pVelDE.updateProperties(newProperties!!)
}
fun kill() {
pVelDE.kill()
}
fun velToRot(velocity: Vector3f): Vector3f {
val normalizedVelocity = Vector3f(velocity).normalize()
val yaw = Math.toDegrees(atan2(normalizedVelocity.x.toDouble(), normalizedVelocity.z.toDouble())).toFloat()
val horizontalMag = sqrt(normalizedVelocity.x.toDouble().pow(2) + normalizedVelocity.z.toDouble().pow(2))
val pitch = Math.toDegrees(atan2(-normalizedVelocity.y.toDouble(), horizontalMag)).toFloat() + -90.0f
return Vector3f(pitch, yaw, 0.0f)
}
}
@@ -11,11 +11,11 @@ import net.minecraft.util.math.Vec3d
import org.joml.Vector2f
class ParticleEmitter(
private val pos: Vec3d,
private val rot: Vector2f,
private var pos: Vec3d,
private var rot: Vector2f,
private val world: ServerWorld,
private val params: EmitterParams,
private val debug: Boolean
private val debug: Boolean = false
) {
private var allParticles: Array<Particle> = emptyArray()
@@ -34,12 +34,11 @@ class ParticleEmitter(
if (isTicking) { addParticle() }
if (!isTicking && allParticles.isEmpty()) { isDead = true }
processParticlesInBatches(world, 100)
processParticlesInBatches(100)
}
private suspend fun processParticlesInBatches(
world: ServerWorld,
batchSize: Int
) = coroutineScope {
val batches = allParticles.toMutableList().chunked(batchSize)
@@ -51,7 +50,7 @@ class ParticleEmitter(
if (particle.isDead) {
toRemove.add(particle)
} else {
particle.tick(world)
particle.tick()
}
}
synchronized(allParticles) {
@@ -8,7 +8,7 @@ import kotlin.math.*
import kotlin.random.Random
sealed class SpawningShape() {
class Circle(private val radius: Float, val spawnOnEdge: Boolean) : SpawningShape() {
class Circle(val radius: Float, val spawnOnEdge: Boolean) : SpawningShape() {
fun randomWithin(): Vector3f {
val randRadius = radius * sqrt(randomFloatBetween(0.0f, 1.0f))
val randAngle = randomFloatBetween(0.0f, Math.PI.toFloat() * 2)
@@ -73,7 +73,7 @@ sealed class SpawningShape() {
}
}
class Sphere(private val radius: Float, val spawnOnEdge: Boolean) : SpawningShape() {
class Sphere(val radius: Float, val spawnOnEdge: Boolean) : SpawningShape() {
fun randomWithin(): Vector3f {
val randRadius = radius * Random.nextDouble().pow(1.0 / 3.0)