diff --git a/src/main/kotlin/com/bytedice/bde_particles/Bde_particles.kt b/src/main/kotlin/com/bytedice/bde_particles/Bde_particles.kt index 1312bf5..82bbef8 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/Bde_particles.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/Bde_particles.kt @@ -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), diff --git a/src/main/kotlin/com/bytedice/bde_particles/DisplayEntity.kt b/src/main/kotlin/com/bytedice/bde_particles/DisplayEntity.kt index ce6604a..0afd2b5 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/DisplayEntity.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/DisplayEntity.kt @@ -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!!) }) } } diff --git a/src/main/kotlin/com/bytedice/bde_particles/DisplayEntityProperties.kt b/src/main/kotlin/com/bytedice/bde_particles/DisplayEntityProperties.kt index be92dfe..c8cc59f 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/DisplayEntityProperties.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/DisplayEntityProperties.kt @@ -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 = emptyArray(), - val viewRange: Float = 2.0f, + var model: String = "minecraft:purple_concrete", + var customModel: Int = 0, + var tags: Array = 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 () { diff --git a/src/main/kotlin/com/bytedice/bde_particles/particles/EmitterDebug.kt b/src/main/kotlin/com/bytedice/bde_particles/particles/EmitterDebug.kt new file mode 100644 index 0000000..20db94b --- /dev/null +++ b/src/main/kotlin/com/bytedice/bde_particles/particles/EmitterDebug.kt @@ -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!!) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/bytedice/bde_particles/particles/Particle.kt b/src/main/kotlin/com/bytedice/bde_particles/particles/Particle.kt index 9238062..a175479 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/particles/Particle.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/particles/Particle.kt @@ -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 } diff --git a/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleDebug.kt b/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleDebug.kt index 4d21cc3..f334928 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleDebug.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleDebug.kt @@ -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) + } } \ No newline at end of file diff --git a/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleEmitter.kt b/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleEmitter.kt index 0f60dc3..b85a4b4 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleEmitter.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleEmitter.kt @@ -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 = 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) { diff --git a/src/main/kotlin/com/bytedice/bde_particles/particles/Shapes.kt b/src/main/kotlin/com/bytedice/bde_particles/particles/Shapes.kt index dcea6c0..6ee669b 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/particles/Shapes.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/particles/Shapes.kt @@ -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)