significantly changed emitter params. STILL A LOT OF ERRORS.
This commit is contained in:
@@ -24,6 +24,7 @@ import net.minecraft.util.ActionResult
|
|||||||
import net.minecraft.util.Hand
|
import net.minecraft.util.Hand
|
||||||
import net.minecraft.util.TypedActionResult
|
import net.minecraft.util.TypedActionResult
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
|
import org.joml.Vector2f
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
@@ -34,22 +35,19 @@ import java.util.*
|
|||||||
// blockCurve array not needing "minecraft:"
|
// blockCurve array not needing "minecraft:"
|
||||||
|
|
||||||
// Adding a parameter for an initial velocity from an origin point (you currently have to use force fields)
|
// Adding a parameter for an initial velocity from an origin point (you currently have to use force fields)
|
||||||
// Pair<Pair<Vec3f, Vec3f>, Pair<Vec3f, Vec3f>>
|
|
||||||
// "min center vel", "max center vel", "min edge vel", "max edge vel"
|
|
||||||
|
|
||||||
// Parameters
|
// Parameters
|
||||||
// localOffset (Vec3f)
|
|
||||||
// velocity based, relative coordinate based, or rotation based
|
|
||||||
// localOffsetCurve (curve)
|
|
||||||
// spawnOffset (Vec3f)
|
|
||||||
// originOffset (Vec3f)
|
// originOffset (Vec3f)
|
||||||
|
// velocity based, relative coordinate based, or rotation based
|
||||||
|
|
||||||
|
// originOffsetCurve (curve)
|
||||||
|
// spawnOffset (Vec3f)
|
||||||
// velRot (bool)
|
// velRot (bool)
|
||||||
// rotates the particle to face the velocity
|
// rotates the particle to face the velocity
|
||||||
|
|
||||||
// spawnChance (Float)
|
// spawnChance (Float)
|
||||||
// shape: spawnOnlyOnEdge (Boolean)
|
// shape: spawnOnlyOnEdge (Boolean)
|
||||||
|
|
||||||
// Move most (if not all) particle params to emitters.
|
|
||||||
// 3D curves (curves for all X Y Z)
|
|
||||||
// Custom curve equation command args (parse from strings)
|
// Custom curve equation command args (parse from strings)
|
||||||
// Cylinder and cone force field shape.
|
// Cylinder and cone force field shape.
|
||||||
// Better particle performance.
|
// Better particle performance.
|
||||||
@@ -109,7 +107,7 @@ class Bde_particles : ModInitializer {
|
|||||||
|
|
||||||
|
|
||||||
fun init() {
|
fun init() {
|
||||||
addToEmitterRegister("DEFAULT", EmitterParams.DEFAULT)
|
addToRegister("DEFAULT", EmitterParams.DEFAULT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -139,7 +137,7 @@ fun onRightClick(player: PlayerEntity, world: ServerWorld, hand: Hand) : TypedAc
|
|||||||
val handItem = player.getStackInHand(hand)
|
val handItem = player.getStackInHand(hand)
|
||||||
val (isEmitterTool, emitterId) = ParticleEmitterTool.getToolDetails(handItem)
|
val (isEmitterTool, emitterId) = ParticleEmitterTool.getToolDetails(handItem)
|
||||||
val hitResult = raycastFromPlayer(player as ServerPlayerEntity, 200.0)
|
val hitResult = raycastFromPlayer(player as ServerPlayerEntity, 200.0)
|
||||||
val emitterParams = getEmitterParams(emitterId)
|
val emitterParams = getParamsById(emitterId)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!isEmitterTool
|
!isEmitterTool
|
||||||
@@ -149,7 +147,7 @@ fun onRightClick(player: PlayerEntity, world: ServerWorld, hand: Hand) : TypedAc
|
|||||||
return TypedActionResult(ActionResult.PASS, handItem)
|
return TypedActionResult(ActionResult.PASS, handItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
val emitter = ParticleEmitter(hitResult.pos, world, emitterParams)
|
val emitter = ParticleEmitter(hitResult.pos, Vector2f(0.0f, 0.0f), world, emitterParams)
|
||||||
ALL_PARTICLE_EMITTERS += emitter
|
ALL_PARTICLE_EMITTERS += emitter
|
||||||
|
|
||||||
return TypedActionResult(ActionResult.PASS, handItem)
|
return TypedActionResult(ActionResult.PASS, handItem)
|
||||||
@@ -157,35 +155,16 @@ fun onRightClick(player: PlayerEntity, world: ServerWorld, hand: Hand) : TypedAc
|
|||||||
|
|
||||||
|
|
||||||
fun emitterParamsToJson(params: EmitterParams) : Map<String, Any> { // TODO: map to new params
|
fun emitterParamsToJson(params: EmitterParams) : Map<String, Any> { // TODO: map to new params
|
||||||
val allParticleParamsJSON: MutableList<Map<String, Any?>> = mutableListOf()
|
val allParamsJson: MutableList<Map<String, Any?>> = mutableListOf()
|
||||||
val particle = params.particle
|
|
||||||
|
|
||||||
val particleParamsJSON = mapOf(
|
val paramsJson = mapOf(
|
||||||
"shape" to particle.shape,
|
"shape" to params.shape
|
||||||
"blockCurve" to particle.blockCurve,
|
|
||||||
"rotRandom" to particle.rotRandom,
|
|
||||||
"rotVelRandom" to particle.rotVelRandom,
|
|
||||||
"rotVelCurve" to particle.rotVelCurve,
|
|
||||||
"sizeRandom" to particle.sizeRandom,
|
|
||||||
"uniformSize" to particle.uniformSize,
|
|
||||||
"sizeCurve" to particle.sizeCurve,
|
|
||||||
"velRandom" to particle.velRandom,
|
|
||||||
"forceFields" to particle.forceFields,
|
|
||||||
"gravity" to particle.gravity,
|
|
||||||
"drag" to particle.drag,
|
|
||||||
"minVel" to particle.minVel,
|
|
||||||
"lifeTime" to particle.lifeTime
|
|
||||||
)
|
)
|
||||||
|
|
||||||
allParticleParamsJSON.add(particleParamsJSON)
|
allParamsJson.add(paramsJson)
|
||||||
|
|
||||||
val emitterParamsJSON = mapOf(
|
val emitterParamsJSON = mapOf(
|
||||||
"maxCount" to params.maxCount,
|
"maxCount" to params.maxCount,
|
||||||
"spawnsPerTick" to params.spawnsPerTick,
|
|
||||||
"loopDur" to params.loopDur,
|
|
||||||
"loopDelay" to params.loopDelay,
|
|
||||||
"loopCount" to params.loopCount,
|
|
||||||
"particleTypes" to allParticleParamsJSON
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return emitterParamsJSON
|
return emitterParamsJSON
|
||||||
|
|||||||
@@ -137,45 +137,6 @@ fun quatToEuler(quat: Vector4f): Vector3f {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun randomInCircle(r: Float) : Vector2f {
|
|
||||||
val randRadius = r * sqrt(randomFloatBetween(0.0f, 1.0f))
|
|
||||||
val randAngle = randomFloatBetween(0.0f, Math.PI.toFloat() * 2)
|
|
||||||
|
|
||||||
val randomPos = Vector2f(randRadius * cos(randAngle), randRadius * sin(randAngle))
|
|
||||||
return randomPos
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun randomInSphere(r: Float) : Vector3f {
|
|
||||||
val randRadius = r * Random.nextDouble().pow(1.0 / 3.0)
|
|
||||||
|
|
||||||
val phi = Random.nextDouble(0.0, 2 * Math.PI)
|
|
||||||
|
|
||||||
val cosTheta = Random.nextDouble(-1.0, 1.0)
|
|
||||||
val theta = acos(cosTheta)
|
|
||||||
|
|
||||||
val x = randRadius * sin(theta) * cos(phi)
|
|
||||||
val y = randRadius * sin(theta) * sin(phi)
|
|
||||||
val z = randRadius * cos(theta)
|
|
||||||
|
|
||||||
return Vector3f(x.toFloat(), y.toFloat(), z.toFloat())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun randomInRect(size: Vector2f) : Vector2f {
|
|
||||||
return Vector2f(randomFloatBetween(0.0f, size.x), randomFloatBetween(0.0f, size.y))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun randomInCube(size: Vector3f) : Vector3f {
|
|
||||||
return Vector3f(
|
|
||||||
randomFloatBetween(0.0f, size.x),
|
|
||||||
randomFloatBetween(0.0f, size.y),
|
|
||||||
randomFloatBetween(0.0f, size.z)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun transformOffsetByQuat(offset: Vector3f, rotation: Vector4f): Vector3f {
|
fun transformOffsetByQuat(offset: Vector3f, rotation: Vector4f): Vector3f {
|
||||||
val x = offset.x
|
val x = offset.x
|
||||||
val y = offset.y
|
val y = offset.y
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.bytedice.bde_particles.commands
|
package com.bytedice.bde_particles.commands
|
||||||
|
|
||||||
import com.bytedice.bde_particles.items.ParticleEmitterTool
|
import com.bytedice.bde_particles.items.ParticleEmitterTool
|
||||||
import com.bytedice.bde_particles.particles.emitterIdRegister
|
import com.bytedice.bde_particles.particles.idRegister
|
||||||
import com.mojang.brigadier.Command
|
import com.mojang.brigadier.Command
|
||||||
import com.mojang.brigadier.CommandDispatcher
|
import com.mojang.brigadier.CommandDispatcher
|
||||||
import com.mojang.brigadier.arguments.StringArgumentType
|
import com.mojang.brigadier.arguments.StringArgumentType
|
||||||
@@ -20,7 +20,7 @@ object GiveEmitterTool {
|
|||||||
val command = CommandManager.literal("GiveEmitterTool")
|
val command = CommandManager.literal("GiveEmitterTool")
|
||||||
.requires { source -> source.hasPermissionLevel(4) }
|
.requires { source -> source.hasPermissionLevel(4) }
|
||||||
|
|
||||||
val allEmitterIds = emitterIdRegister.keys
|
val allEmitterIds = idRegister.keys
|
||||||
|
|
||||||
val itemNameArg = CommandManager.argument("Item Name", StringArgumentType.string())
|
val itemNameArg = CommandManager.argument("Item Name", StringArgumentType.string())
|
||||||
val itemTypeArg = CommandManager.argument("Item Type", ItemStackArgumentType.itemStack(registryAccess))
|
val itemTypeArg = CommandManager.argument("Item Type", ItemStackArgumentType.itemStack(registryAccess))
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import com.bytedice.bde_particles.emitterParamsToJson
|
|||||||
import com.bytedice.bde_particles.particles.*
|
import com.bytedice.bde_particles.particles.*
|
||||||
import com.mojang.brigadier.Command
|
import com.mojang.brigadier.Command
|
||||||
import com.mojang.brigadier.CommandDispatcher
|
import com.mojang.brigadier.CommandDispatcher
|
||||||
import com.mojang.brigadier.arguments.IntegerArgumentType
|
|
||||||
import com.mojang.brigadier.arguments.StringArgumentType
|
import com.mojang.brigadier.arguments.StringArgumentType
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder
|
||||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder
|
import com.mojang.brigadier.builder.RequiredArgumentBuilder
|
||||||
|
|||||||
@@ -31,30 +31,63 @@ import org.joml.Vector3f
|
|||||||
* @param blockCurve Specifies an array of block names that the particle transitions through during its lifetime, combined with a curve to control transitions. Defaults to "minecraft:air" if empty.
|
* @param blockCurve Specifies an array of block names that the particle transitions through during its lifetime, combined with a curve to control transitions. Defaults to "minecraft:air" if empty.
|
||||||
*/
|
*/
|
||||||
data class EmitterParams (
|
data class EmitterParams (
|
||||||
var maxCount: Int = 200,
|
// spawning
|
||||||
var spawnRate: Int = 1,
|
var maxCount: Int,
|
||||||
var spawnChance: Float = 1.0f,
|
var spawnRate: Int,
|
||||||
var loopDur: Int = 25,
|
var spawnChance: Float,
|
||||||
var loopDelay: Int = 0,
|
var spawnDuration: ParamClasses.Duration,
|
||||||
var loopCount: Int = 0,
|
var spawnPosOffset: Vector3f,
|
||||||
var shape: SpawningShape = SpawningShape.Circle(3.0f),
|
var lifeTime: ParamClasses.PairInt,
|
||||||
var initRot: ParamClasses.PairVec3f = ParamClasses.PairVec3f(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f),
|
var shape: SpawningShape,
|
||||||
var rotVel: ParamClasses.PairVec3f = ParamClasses.PairVec3f(-0.2f, -0.2f, -0.2f, 0.2f, 0.2f, 0.2f),
|
// init transforms
|
||||||
var rotTowardVel: Boolean = true,
|
var offset: ParamClasses.PairVec3f,
|
||||||
var initVel: ParamClasses.PairVec3f = ParamClasses.PairVec3f(-0.1f, 0.3f, -0.1f, 0.1f, 0.6f, 0.1f),
|
var initRot: ParamClasses.PairVec3f,
|
||||||
var initScale: ParamClasses.RandScale = ParamClasses.RandScale.Uniform(),
|
var rotVel: ParamClasses.PairVec3f,
|
||||||
var scaleTowardVel: Boolean = true,
|
var rotWithVel: Boolean,
|
||||||
var forceFields: Array<ForceField> = emptyArray(),
|
var initVel: ParamClasses.PairVec3f,
|
||||||
var constVel: Vector3f = Vector3f(0.0f, -0.01f, 0.0f),
|
var initCenterVel: ParamClasses.PairFloat,
|
||||||
var drag: Float = 0.075f,
|
var initScale: ParamClasses.PairVec3f,
|
||||||
var minVel: Float = 0.0f,
|
var scaleWithVel: Boolean,
|
||||||
var lifeTime: ParamClasses.PairInt = ParamClasses.PairInt(25, 40),
|
// velocity
|
||||||
var rotVelCurve: ParamClasses.LerpVal = ParamClasses.LerpVal.LerpUniform(1.0f, 0.0f, LerpCurves.Sqrt),
|
var forceFields: Array<ForceField>,
|
||||||
var scaleCurve: ParamClasses.LerpVal = ParamClasses.LerpVal.LerpUniform(1.0f, 0.5f, LerpCurves.Linear),
|
var constVel: Vector3f,
|
||||||
var blockCurve: Pair<Array<String>, LerpCurves> = Pair(arrayOf("minecraft:purple_concrete", "minecraft:purple_stained_glass"), LerpCurves.Sqrt),
|
var drag: Float,
|
||||||
|
var minVel: Float,
|
||||||
|
// curves
|
||||||
|
var offsetCurve: ParamClasses.LerpVal,
|
||||||
|
var rotVelCurve: ParamClasses.LerpVal,
|
||||||
|
var scaleCurve: ParamClasses.LerpVal,
|
||||||
|
var blockCurve: Pair<Array<String>, LerpCurves>,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
companion object Presets {
|
companion object Presets {
|
||||||
val DEFAULT = EmitterParams()
|
val DEFAULT = EmitterParams(
|
||||||
|
maxCount = 200,
|
||||||
|
spawnRate = 1,
|
||||||
|
spawnChance = 1.0f,
|
||||||
|
spawnDuration = ParamClasses.Duration.SingleBurst(25),
|
||||||
|
spawnPosOffset = Vector3f(0.0f, 0.0f, 0.0f),
|
||||||
|
lifeTime = ParamClasses.PairInt(25, 40),
|
||||||
|
shape = SpawningShape.Circle(3.0f),
|
||||||
|
offset = ParamClasses.PairVec3f.Uniform(-0.5f, -0.5f),
|
||||||
|
initRot = ParamClasses.PairVec3f.Null,
|
||||||
|
rotVel = ParamClasses.PairVec3f.NonUniform(-0.2f, -0.2f, -0.2f, 0.2f, 0.2f, 0.2f),
|
||||||
|
rotWithVel = true,
|
||||||
|
initVel = ParamClasses.PairVec3f.Null,
|
||||||
|
initCenterVel = ParamClasses.PairFloat(0.1f, 0.3f),
|
||||||
|
initScale = ParamClasses.PairVec3f.Uniform(1.0f, 0.2f),
|
||||||
|
scaleWithVel = true,
|
||||||
|
forceFields = emptyArray(),
|
||||||
|
constVel = Vector3f(0.0f, -0.01f, 0.0f),
|
||||||
|
drag = 0.075f,
|
||||||
|
minVel = 0.0f,
|
||||||
|
offsetCurve = ParamClasses.LerpVal.NoLerpVec3f(Vector3f(-0.5f, -0.5f, -0.5f)),
|
||||||
|
rotVelCurve = ParamClasses.LerpVal.LerpUniform(1.0f, 0.0f, LerpCurves.Sqrt),
|
||||||
|
scaleCurve = ParamClasses.LerpVal.LerpUniform(1.0f, 0.5f, LerpCurves.Linear),
|
||||||
|
blockCurve = Pair(
|
||||||
|
arrayOf("minecraft:purple_concrete", "minecraft:purple_stained_glass"),
|
||||||
|
LerpCurves.Sqrt
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,40 +6,24 @@ import com.bytedice.bde_particles.randomIntBetween
|
|||||||
import org.joml.Vector3f
|
import org.joml.Vector3f
|
||||||
|
|
||||||
class ParamClasses {
|
class ParamClasses {
|
||||||
class PairVec3f (
|
sealed class PairVec3f {
|
||||||
private val minX: Float = 0.0f,
|
|
||||||
private val minY: Float = 0.0f,
|
|
||||||
private val minZ: Float = 0.0f,
|
|
||||||
private val maxX: Float = 1.0f,
|
|
||||||
private val maxY: Float = 1.0f,
|
|
||||||
private val maxZ: Float = 1.0f,
|
|
||||||
) {
|
|
||||||
fun randomize() : Vector3f {
|
|
||||||
return Vector3f(
|
|
||||||
randomFloatBetween(minX, maxX),
|
|
||||||
randomFloatBetween(minY, maxY),
|
|
||||||
randomFloatBetween(minZ, maxZ),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sealed class RandScale {
|
|
||||||
class Uniform (
|
class Uniform (
|
||||||
private val min: Float = 0.0f,
|
private val min: Float,
|
||||||
private val max: Float = 1.0f,
|
private val max: Float,
|
||||||
) : RandScale() {
|
) : PairVec3f() {
|
||||||
fun randomize() : Vector3f {
|
fun randomize() : Vector3f {
|
||||||
val x = randomFloatBetween(min, max)
|
val x = randomFloatBetween(min, max)
|
||||||
return Vector3f(x, x, x)
|
return Vector3f(x, x, x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class NonUniform (
|
class NonUniform (
|
||||||
private val minX: Float = 0.0f,
|
private val minX: Float,
|
||||||
private val minY: Float = 0.0f,
|
private val minY: Float,
|
||||||
private val minZ: Float = 0.0f,
|
private val minZ: Float,
|
||||||
private val maxX: Float = 1.0f,
|
private val maxX: Float,
|
||||||
private val maxY: Float = 1.0f,
|
private val maxY: Float,
|
||||||
private val maxZ: Float = 1.0f
|
private val maxZ: Float
|
||||||
) : RandScale() {
|
) : PairVec3f() {
|
||||||
fun randomize(): Vector3f {
|
fun randomize(): Vector3f {
|
||||||
return Vector3f(
|
return Vector3f(
|
||||||
randomFloatBetween(minX, maxX),
|
randomFloatBetween(minX, maxX),
|
||||||
@@ -48,35 +32,29 @@ class ParamClasses {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
data object Null : PairVec3f()
|
||||||
class PairVec2i (
|
|
||||||
private val minX: Int = 0,
|
|
||||||
private val minY: Int = 0,
|
|
||||||
private val maxX: Int = 1,
|
|
||||||
private val maxY: Int = 1,
|
|
||||||
) {
|
|
||||||
fun randomize() : Pair<Int, Int> {
|
|
||||||
return Pair(
|
|
||||||
randomIntBetween(minX, maxX),
|
|
||||||
randomIntBetween(minY, maxY),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
class PairInt (
|
class PairInt (
|
||||||
private val min: Int = 0,
|
private val min: Int,
|
||||||
private val max: Int = 1,
|
private val max: Int,
|
||||||
) {
|
) {
|
||||||
fun randomize() : Int { return randomIntBetween(min, max) }
|
fun randomize() : Int { return randomIntBetween(min, max) }
|
||||||
}
|
}
|
||||||
|
class PairFloat(
|
||||||
|
private val min: Float,
|
||||||
|
private val max: Float,
|
||||||
|
) {
|
||||||
|
fun randomize() : Float { return randomFloatBetween(min, max) }
|
||||||
|
}
|
||||||
sealed class LerpVal {
|
sealed class LerpVal {
|
||||||
class LerpVec3f(
|
class LerpVec3f(
|
||||||
private val fromX: Float = 0.0f,
|
private val fromX: Float,
|
||||||
private val fromY: Float = 0.0f,
|
private val fromY: Float,
|
||||||
private val fromZ: Float = 0.0f,
|
private val fromZ: Float,
|
||||||
private val toX: Float = 1.0f,
|
private val toX: Float,
|
||||||
private val toY: Float = 1.0f,
|
private val toY: Float,
|
||||||
private val toZ: Float = 1.0f,
|
private val toZ: Float,
|
||||||
private val curve: LerpCurves = LerpCurves.Linear,
|
private val curve: LerpCurves,
|
||||||
) : LerpVal() {
|
) : LerpVal() {
|
||||||
fun lerp(t: Float): Vector3f {
|
fun lerp(t: Float): Vector3f {
|
||||||
val x = com.bytedice.bde_particles.lerp(fromX, toX, t) * curve.function(t)
|
val x = com.bytedice.bde_particles.lerp(fromX, toX, t) * curve.function(t)
|
||||||
@@ -86,15 +64,15 @@ class ParamClasses {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
class MultiLerpVec3f(
|
class MultiLerpVec3f(
|
||||||
private val fromX: Float = 0.0f,
|
private val fromX: Float,
|
||||||
private val fromY: Float = 0.0f,
|
private val fromY: Float,
|
||||||
private val fromZ: Float = 0.0f,
|
private val fromZ: Float,
|
||||||
private val toX: Float = 1.0f,
|
private val toX: Float,
|
||||||
private val toY: Float = 1.0f,
|
private val toY: Float,
|
||||||
private val toZ: Float = 1.0f,
|
private val toZ: Float,
|
||||||
private val curveX: LerpCurves = LerpCurves.Linear,
|
private val curveX: LerpCurves,
|
||||||
private val curveY: LerpCurves = LerpCurves.Linear,
|
private val curveY: LerpCurves,
|
||||||
private val curveZ: LerpCurves = LerpCurves.Linear
|
private val curveZ: LerpCurves
|
||||||
) : LerpVal() {
|
) : LerpVal() {
|
||||||
fun lerp(t: Float): Vector3f {
|
fun lerp(t: Float): Vector3f {
|
||||||
val x = com.bytedice.bde_particles.lerp(fromX, toX, t) * curveX.function(t)
|
val x = com.bytedice.bde_particles.lerp(fromX, toX, t) * curveX.function(t)
|
||||||
@@ -104,14 +82,15 @@ class ParamClasses {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
class LerpUniform(
|
class LerpUniform(
|
||||||
private val from: Float = 0.0f,
|
private val from: Float,
|
||||||
private val to: Float = 1.0f,
|
private val to: Float,
|
||||||
private val curve: LerpCurves = LerpCurves.Linear,
|
private val curve: LerpCurves,
|
||||||
) : LerpVal() {
|
) : LerpVal() {
|
||||||
fun lerp(t: Float): Float {
|
fun lerp(t: Float): Float {
|
||||||
return com.bytedice.bde_particles.lerp(from, to, t) * curve.function(t)
|
return com.bytedice.bde_particles.lerp(from, to, t) * curve.function(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
data class NoLerpVec3f(val value: Vector3f) : LerpVal()
|
||||||
|
|
||||||
fun lerpToVector3f(t: Float) : Vector3f {
|
fun lerpToVector3f(t: Float) : Vector3f {
|
||||||
when (this) {
|
when (this) {
|
||||||
@@ -121,7 +100,22 @@ class ParamClasses {
|
|||||||
val x = this.lerp(t)
|
val x = this.lerp(t)
|
||||||
return Vector3f(x, x, x)
|
return Vector3f(x, x, x)
|
||||||
}
|
}
|
||||||
|
is NoLerpVec3f -> return this.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sealed class Duration {
|
||||||
|
data class SingleBurst(
|
||||||
|
val loopDur: Int
|
||||||
|
) : Duration()
|
||||||
|
data class MultiBurst(
|
||||||
|
val loopDur: Int,
|
||||||
|
val loopDelay: Int,
|
||||||
|
val loopCount: Int,
|
||||||
|
) : Duration()
|
||||||
|
data class InfiniteLoop(
|
||||||
|
val loopDur: Int,
|
||||||
|
val loopDelay: Int
|
||||||
|
) : Duration()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,10 @@ package com.bytedice.bde_particles.particles
|
|||||||
|
|
||||||
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.Vector3f
|
||||||
|
|
||||||
class ParticleEmitter(private val emitterPos: Vec3d, private val emitterWorld: ServerWorld, private val emitterParams: EmitterParams) {
|
class ParticleEmitter(private val pos: Vec3d, private val rot: Vector2f, private val world: ServerWorld, private val params: EmitterParams) {
|
||||||
|
|
||||||
private var allParticles: Array<Particle> = emptyArray()
|
private var allParticles: Array<Particle> = emptyArray()
|
||||||
|
|
||||||
@@ -33,12 +35,12 @@ class ParticleEmitter(private val emitterPos: Vec3d, private val emitterWorld: S
|
|||||||
private fun addParticle() {
|
private fun addParticle() {
|
||||||
if (loopDelayActive) { return }
|
if (loopDelayActive) { return }
|
||||||
|
|
||||||
repeat(this.emitterParams.spawnsPerTick) {
|
repeat(params.spawnRate) {
|
||||||
if (allParticles.size >= emitterParams.maxCount) { return }
|
if (allParticles.size >= params.maxCount) { return }
|
||||||
|
|
||||||
val particle = Particle(emitterParams.particle)
|
val particle = Particle(params)
|
||||||
particle.init(this.emitterPos)
|
particle.init(pos, rot)
|
||||||
particle.spawn(emitterWorld)
|
particle.spawn(world)
|
||||||
|
|
||||||
allParticles += particle
|
allParticles += particle
|
||||||
}
|
}
|
||||||
@@ -50,30 +52,30 @@ class ParticleEmitter(private val emitterPos: Vec3d, private val emitterWorld: S
|
|||||||
// because im so damn good at cooking spaghetti
|
// because im so damn good at cooking spaghetti
|
||||||
|
|
||||||
// if max duration is 0 or less, skip counting, its infinite
|
// if max duration is 0 or less, skip counting, its infinite
|
||||||
if (emitterParams.loopDur <= 0) { return }
|
if (params.loopDur <= 0) { return }
|
||||||
|
|
||||||
// if the duration is greater than max duration, add 1 loopCount
|
// if the duration is greater than max duration, add 1 loopCount
|
||||||
// return if max loopCount is 0
|
// return if max loopCount is 0
|
||||||
// if the delay is greater than 0 then enable it
|
// if the delay is greater than 0 then enable it
|
||||||
if (loopDur >= emitterParams.loopDur) {
|
if (loopDur >= params.loopDur) {
|
||||||
if (loopCount == 0) {
|
if (loopCount == 0) {
|
||||||
isTicking = false
|
isTicking = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
loopCount += 1
|
loopCount += 1
|
||||||
loopDur = 0
|
loopDur = 0
|
||||||
if (emitterParams.loopDelay > 0) { loopDelayActive = true }
|
if (params.loopDelay > 0) { loopDelayActive = true }
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the delay is greater than max delay, disable the delay
|
// if the delay is greater than max delay, disable the delay
|
||||||
else if (loopDelay >= emitterParams.loopDelay) {
|
else if (loopDelay >= params.loopDelay) {
|
||||||
loopDelay = 0
|
loopDelay = 0
|
||||||
loopDelayActive = false
|
loopDelayActive = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// if loopCount is greater than max loopCount then stop immediately
|
// if loopCount is greater than max loopCount then stop immediately
|
||||||
// if max loopCount is below 0 then don't do anything, loop infinitely
|
// if max loopCount is below 0 then don't do anything, loop infinitely
|
||||||
if (loopCount > 0 && loopCount >= emitterParams.loopCount) {
|
if (loopCount > 0 && loopCount >= params.loopCount) {
|
||||||
isTicking = false
|
isTicking = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,133 +2,60 @@
|
|||||||
|
|
||||||
package com.bytedice.bde_particles.particles
|
package com.bytedice.bde_particles.particles
|
||||||
|
|
||||||
import com.bytedice.bde_particles.LerpCurves
|
|
||||||
import org.joml.Vector3f
|
val idRegister: MutableMap<String, EmitterParams> = mutableMapOf()
|
||||||
|
val forbiddenIds = arrayOf("", "NULL")
|
||||||
|
|
||||||
|
|
||||||
val emitterIdRegister: MutableMap<String, EmitterParams> = mutableMapOf()
|
fun addToRegister(id: String, params: EmitterParams) : Pair<String, Boolean> {
|
||||||
val forbiddenIds = arrayOf("", "DEFAULT", "NULL")
|
val newId = replaceForbiddenChars(id.replace(" ", "_"))
|
||||||
|
|
||||||
|
if (idRegister.containsKey(newId)) { return Pair(newId, false) }
|
||||||
|
|
||||||
fun addToEmitterRegister(id: String, params: EmitterParams) : Pair<String, Boolean> {
|
idRegister[id] = params
|
||||||
val newId = id.replace(" ", "_")
|
|
||||||
|
|
||||||
if (newId in forbiddenIds && newId != "DEFAULT") { return Pair(newId, false) }
|
|
||||||
if (emitterIdRegister.containsKey(newId)) { return Pair(newId, false) }
|
|
||||||
|
|
||||||
emitterIdRegister[id] = params
|
|
||||||
return Pair(newId, true)
|
return Pair(newId, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun removeFromEmitterRegister(id: String) : Boolean {
|
fun removeFromRegister(id: String) : Boolean {
|
||||||
if (id in forbiddenIds) { return false }
|
if (id in forbiddenIds) { return false }
|
||||||
if (!emitterIdRegister.containsKey(id)) { return false }
|
if (!idRegister.containsKey(id)) { return false }
|
||||||
|
|
||||||
emitterIdRegister.remove(id)
|
idRegister.remove(id)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun getEmitterParams(id: String) : EmitterParams? {
|
fun getParamsById(id: String) : EmitterParams? {
|
||||||
return emitterIdRegister[id]
|
return idRegister[id]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun updateEmitterParams(id: String, newParams: EmitterParams) {
|
fun updateRegistered(id: String, newParams: EmitterParams) {
|
||||||
emitterIdRegister[id] = newParams
|
idRegister[id] = newParams
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun updateSingleEmitterParam(id: String, paramName: String, paramValue: Any) : Boolean {
|
fun updateParam(id: String, paramName: String, paramValue: Any) : Boolean {
|
||||||
val emitter = getEmitterParams(id) ?: return false
|
val emitter = getParamsById(id) ?: return false
|
||||||
val updatedValues = updateSingleEmitterParam(emitter, paramName, paramValue)
|
val updatedValues = updateParams(emitter, paramName, paramValue)
|
||||||
updateEmitterParams(id, updatedValues.first)
|
|
||||||
|
|
||||||
return updatedValues.second
|
return updatedValues.second
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun updateSingleParticleParam(emitterId: String, paramName: String, paramValue: Any) : Boolean { // TODO: map to new params
|
fun updateParams(params: EmitterParams, paramName: String, paramValue: Any) : Pair<EmitterParams, Boolean> { // TODO: map to new params
|
||||||
val emitter = getEmitterParams(emitterId) ?: return false
|
|
||||||
val particle = emitter.particle
|
|
||||||
|
|
||||||
val updatedValues = updateSingleParticleParam(particle, paramName, paramValue)
|
|
||||||
|
|
||||||
emitter.particle = updatedValues.first
|
|
||||||
updateEmitterParams(emitterId, emitter)
|
|
||||||
|
|
||||||
return updatedValues.second
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun updateSingleEmitterParam(params: EmitterParams, paramName: String, paramValue: Any) : Pair<EmitterParams, Boolean> { // TODO: map to new params
|
|
||||||
val value: Any? = when (paramName) {
|
|
||||||
"maxCount" -> paramValue as Int
|
|
||||||
"spawnsPerTick" -> paramValue as Int
|
|
||||||
"loopDur" -> paramValue as Int
|
|
||||||
"loopDelay" -> paramValue as Int
|
|
||||||
"loopCount" -> paramValue as Int
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value == null) { return Pair(params, false) }
|
|
||||||
|
|
||||||
val newParams = params.copy()
|
val newParams = params.copy()
|
||||||
|
|
||||||
when (paramName) {
|
when (paramName) {
|
||||||
"maxCount" -> newParams.maxCount = value as Int
|
"maxCount" -> newParams.maxCount = paramValue as Int
|
||||||
"spawnsPerTick" -> newParams.spawnsPerTick = value as Int
|
|
||||||
"loopDur" -> newParams.loopDur = value as Int
|
|
||||||
"loopDelay" -> newParams.loopDelay = value as Int
|
|
||||||
"loopCount" -> newParams.loopCount = value as Int
|
|
||||||
else -> return Pair(params, false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Pair(newParams, true)
|
return Pair(newParams, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun updateSingleParticleParam(params: ParticleParams, paramName: String, paramValue: Any) : Pair<ParticleParams, Boolean> { // TODO: map to new params
|
fun replaceForbiddenChars(input: String): String {
|
||||||
val value: Any? = when (paramName) {
|
val regex = "[^a-zA-Z0-9_-]".toRegex()
|
||||||
"shape" -> paramValue as SpawningShape?
|
return input.replace(regex, "-")
|
||||||
"blockCurve" -> paramValue as Array<String>
|
|
||||||
"rotRandom" -> paramValue as Pair<Vector3f, Vector3f>
|
|
||||||
"rotVelRandom" -> paramValue as Pair<Vector3f, Vector3f>
|
|
||||||
"sizeRandom" -> paramValue as Pair<Vector3f, Vector3f>
|
|
||||||
"uniformSize" -> paramValue as Boolean
|
|
||||||
"velRandom" -> paramValue as Pair<Vector3f, Vector3f>
|
|
||||||
"forceFields" -> paramValue as Array<ForceField>
|
|
||||||
"gravity" -> paramValue as Vector3f
|
|
||||||
"drag" -> paramValue as Float
|
|
||||||
"minVel" -> paramValue as Float
|
|
||||||
"lifeTime" -> paramValue as Pair<Int, Int>
|
|
||||||
"rotVelCurve" -> paramValue as Triple<Vector3f, Vector3f, LerpCurves>
|
|
||||||
"sizeCurve" -> paramValue as Triple<Vector3f, Vector3f, LerpCurves>
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value == null) { return Pair(params, false) }
|
|
||||||
|
|
||||||
val newParams = params.copy()
|
|
||||||
|
|
||||||
when (paramName) {
|
|
||||||
"shape" -> newParams.shape = value as SpawningShape
|
|
||||||
"blockCurve" -> newParams.blockCurve = value as Array<String>
|
|
||||||
"rotRandom" -> newParams.rotRandom = value as Pair<Vector3f, Vector3f>
|
|
||||||
"rotVelRandom" -> newParams.rotVelRandom = value as Pair<Vector3f, Vector3f>
|
|
||||||
"sizeRandom" -> newParams.sizeRandom = value as Pair<Vector3f, Vector3f>
|
|
||||||
"uniformSize" -> newParams.uniformSize = value as Boolean
|
|
||||||
"velRandom" -> newParams.velRandom = value as Pair<Vector3f, Vector3f>
|
|
||||||
"forceFields" -> newParams.forceFields = value as Array<ForceField>
|
|
||||||
"gravity" -> newParams.gravity = value as Vector3f
|
|
||||||
"drag" -> newParams.drag = value as Float
|
|
||||||
"minVel" -> newParams.minVel = value as Float
|
|
||||||
"lifeTime" -> newParams.lifeTime = value as Pair<Int, Int>
|
|
||||||
"rotVelCurve" -> newParams.rotVelCurve = value as Triple<Vector3f, Vector3f, LerpCurves>
|
|
||||||
"sizeCurve" -> newParams.sizeCurve = value as Triple<Vector3f, Vector3f, LerpCurves>
|
|
||||||
else -> return Pair(params, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
return Pair(newParams, true)
|
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,111 @@
|
|||||||
package com.bytedice.bde_particles.particles
|
package com.bytedice.bde_particles.particles
|
||||||
|
|
||||||
|
import com.bytedice.bde_particles.randomFloatBetween
|
||||||
|
import com.bytedice.bde_particles.randomIntBetween
|
||||||
import org.joml.Vector2f
|
import org.joml.Vector2f
|
||||||
import org.joml.Vector3f
|
import org.joml.Vector3f
|
||||||
|
import kotlin.math.*
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
sealed class SpawningShape {
|
sealed class SpawningShape {
|
||||||
data class Circle(val radius: Float = 1.0f) : SpawningShape()
|
class Circle(val radius: Float = 1.0f) : SpawningShape() {
|
||||||
data class Rect (val size: Vector2f = Vector2f(1.0f, 1.0f)) : SpawningShape()
|
fun randomWithin(): Vector3f {
|
||||||
data class Cube (val size: Vector3f = Vector3f(1.0f, 1.0f, 1.0f)) : SpawningShape()
|
val randRadius = radius * sqrt(randomFloatBetween(0.0f, 1.0f))
|
||||||
data class Sphere(val radius: Float = 1.0f) : SpawningShape()
|
val randAngle = randomFloatBetween(0.0f, Math.PI.toFloat() * 2)
|
||||||
|
|
||||||
|
val randomPos = Vector3f(randRadius * cos(randAngle), 0.0f, randRadius * sin(randAngle))
|
||||||
|
return randomPos
|
||||||
|
}
|
||||||
|
|
||||||
|
fun randomOnEdge(): Vector3f {
|
||||||
|
val randAngle = randomFloatBetween(0.0f, Math.PI.toFloat() * 2)
|
||||||
|
return Vector3f(radius * cos(randAngle), 0.0f, radius * sin(randAngle))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Rect(val size: Vector2f = Vector2f(1.0f, 1.0f)) : SpawningShape() {
|
||||||
|
fun randomWithin(): Vector3f {
|
||||||
|
return Vector3f(randomFloatBetween(0.0f, size.x), 0.0f, randomFloatBetween(0.0f, size.y))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun randomOnEdge(): Vector3f {
|
||||||
|
val perimeter = 2 * (size.x + size.y)
|
||||||
|
val randPos = randomFloatBetween(0.0f, perimeter)
|
||||||
|
|
||||||
|
return when {
|
||||||
|
randPos <= size.x -> Vector3f(randPos, 0.0f, 0.0f)
|
||||||
|
randPos <= size.x + size.y -> Vector3f(size.x, 0.0f, randPos - size.x)
|
||||||
|
randPos <= 2 * size.x + size.y -> Vector3f(size.x - (randPos - size.x - size.y), 0.0f, size.y)
|
||||||
|
else -> Vector3f(0.0f, 0.0f, size.y - (randPos - 2 * size.x - size.y))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Cube(val size: Vector3f = Vector3f(1.0f, 1.0f, 1.0f)) : SpawningShape() {
|
||||||
|
fun randomWithin(): Vector3f {
|
||||||
|
return Vector3f(
|
||||||
|
randomFloatBetween(0.0f, size.x),
|
||||||
|
randomFloatBetween(0.0f, size.y),
|
||||||
|
randomFloatBetween(0.0f, size.z)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun randomOnEdge(): Vector3f {
|
||||||
|
val edgeIndex = randomIntBetween(0, 11) // 12 edges
|
||||||
|
val randPos = randomFloatBetween(0.0f, 1.0f)
|
||||||
|
|
||||||
|
return when (edgeIndex) {
|
||||||
|
0 -> Vector3f(randPos * size.x, 0.0f, 0.0f)
|
||||||
|
1 -> Vector3f(size.x, 0.0f, randPos * size.z)
|
||||||
|
2 -> Vector3f(size.x - randPos * size.x, 0.0f, size.z)
|
||||||
|
3 -> Vector3f(0.0f, 0.0f, size.z - randPos * size.z)
|
||||||
|
4 -> Vector3f(randPos * size.x, size.y, 0.0f)
|
||||||
|
5 -> Vector3f(size.x, size.y, randPos * size.z)
|
||||||
|
6 -> Vector3f(size.x - randPos * size.x, size.y, size.z)
|
||||||
|
7 -> Vector3f(0.0f, size.y, size.z - randPos * size.z)
|
||||||
|
8 -> Vector3f(0.0f, randPos * size.y, 0.0f)
|
||||||
|
9 -> Vector3f(size.x, randPos * size.y, 0.0f)
|
||||||
|
10 -> Vector3f(size.x, randPos * size.y, size.z)
|
||||||
|
11 -> Vector3f(0.0f, randPos * size.y, size.z)
|
||||||
|
|
||||||
|
else -> Vector3f(0.0f, 0.0f, 0.0f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Sphere(val radius: Float = 1.0f) : SpawningShape() {
|
||||||
|
fun randomWithin(): Vector3f {
|
||||||
|
val randRadius = radius * Random.nextDouble().pow(1.0 / 3.0)
|
||||||
|
|
||||||
|
val phi = Random.nextDouble(0.0, 2 * Math.PI)
|
||||||
|
|
||||||
|
val cosTheta = Random.nextDouble(-1.0, 1.0)
|
||||||
|
val theta = acos(cosTheta)
|
||||||
|
|
||||||
|
val x = randRadius * sin(theta) * cos(phi)
|
||||||
|
val y = randRadius * sin(theta) * sin(phi)
|
||||||
|
val z = randRadius * cos(theta)
|
||||||
|
|
||||||
|
return Vector3f(x.toFloat(), y.toFloat(), z.toFloat())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun randomOnEdge(): Vector3f {
|
||||||
|
val phi = randomFloatBetween(0.0f, Math.PI.toFloat() * 2)
|
||||||
|
val cosTheta = randomFloatBetween(-1.0f, 1.0f)
|
||||||
|
val sinTheta = sqrt(1 - cosTheta * cosTheta)
|
||||||
|
|
||||||
|
val x = radius * sinTheta * cos(phi)
|
||||||
|
val y = radius * sinTheta * sin(phi)
|
||||||
|
val z = radius * cosTheta
|
||||||
|
|
||||||
|
return Vector3f(x, y, z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data object Point : SpawningShape()
|
data object Point : SpawningShape()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sealed class ForceFieldShape {
|
sealed class ForceFieldShape {
|
||||||
data class Sphere(
|
data class Sphere(
|
||||||
val radius: Float = 3.0f,
|
val radius: Float = 3.0f,
|
||||||
|
|||||||
Reference in New Issue
Block a user