updated particle debug tools (emitter debug coming soon)
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user