hopefully the last commit before 1.0

This commit is contained in:
2024-11-24 15:37:24 +01:00
parent 4f5a6c1ae9
commit c87b2f7483
11 changed files with 181 additions and 204 deletions
@@ -27,10 +27,6 @@ import net.minecraft.world.World
import java.util.* import java.util.*
// TODO: finish the particle ticking
// TODO: make custom commands to create particles easier (only temporarily saved)
var ALL_PARTICLE_EMITTERS: Array<ParticleEmitter> = emptyArray() var ALL_PARTICLE_EMITTERS: Array<ParticleEmitter> = emptyArray()
val sessionUuid: UUID = UUID.randomUUID() val sessionUuid: UUID = UUID.randomUUID()
@@ -122,27 +118,26 @@ fun onRightClick(player: PlayerEntity, world: ServerWorld, hand: Hand) : TypedAc
fun emitterParamsToJson(params: EmitterParams) : Map<String, Any> { fun emitterParamsToJson(params: EmitterParams) : Map<String, Any> {
val allParticleParamsJSON: MutableList<Map<String, Any?>> = mutableListOf() val allParticleParamsJSON: MutableList<Map<String, Any?>> = mutableListOf()
val particle = params.particle
for (particle in params.particleTypes) { val particleParamsJSON = mapOf(
val particleParamsJSON = mapOf( "shape" to particle.shape,
"shape" to particle.shape, "blockCurve" to particle.blockCurve,
"blockCurve" to particle.blockCurve, "rotRandom" to particle.rotRandom,
"rotRandom" to particle.rotRandom, "rotVelRandom" to particle.rotVelRandom,
"rotVelRandom" to particle.rotVelRandom, "rotVelCurve" to particle.rotVelCurve,
"rotVelCurve" to particle.rotVelCurve, "sizeRandom" to particle.sizeRandom,
"sizeRandom" to particle.sizeRandom, "uniformSize" to particle.uniformSize,
"uniformSize" to particle.uniformSize, "sizeCurve" to particle.sizeCurve,
"sizeCurve" to particle.sizeCurve, "velRandom" to particle.velRandom,
"velRandom" to particle.velRandom, "forceFields" to particle.forceFields,
"forceFields" to particle.forceFields, "gravity" to particle.gravity,
"gravity" to particle.gravity, "drag" to particle.drag,
"drag" to particle.drag, "minVel" to particle.minVel,
"minVel" to particle.minVel, "lifeTime" to particle.lifeTime
"lifeTime" to particle.lifeTime )
)
allParticleParamsJSON.add(particleParamsJSON) allParticleParamsJSON.add(particleParamsJSON)
}
val emitterParamsJSON = mapOf( val emitterParamsJSON = mapOf(
"maxCount" to params.maxCount, "maxCount" to params.maxCount,
@@ -224,24 +224,25 @@ fun interpolateCurve(start: Vector3f, end: Vector3f, t: Float, curve: Interpolat
} }
fun sdfSphere(point: Vec3d, radius: Double): Double { fun sdfSphere(pos: Vector3f, radius: Float, objectPos: Vector3f): Float {
val x = point.x val dx = objectPos.x - pos.x
val y = point.y val dy = objectPos.y - pos.y
val z = point.z val dz = objectPos.z - pos.z
val distanceFromCenter = sqrt(x * x + y * y + z * z) val distanceFromCenter = sqrt(dx * dx + dy * dy + dz * dz)
return distanceFromCenter - radius return (distanceFromCenter - radius)
} }
fun sdfCube(point: Vec3d, size: Vec3d): Double {
val px = point.x
val py = point.y
val pz = point.z
val sx = size.x fun sdfCube(pos: Vector3f, size: Vector3f, objectPos: Vector3f): Float {
val sy = size.y val px = objectPos.x - pos.x
val sz = size.z val py = objectPos.y - pos.y
val pz = objectPos.z - pos.z
val sx = size.x.toDouble()
val sy = size.y.toDouble()
val sz = size.z.toDouble()
val halfSize = Triple(sx / 2, sy / 2, sz / 2) val halfSize = Triple(sx / 2, sy / 2, sz / 2)
@@ -256,5 +257,10 @@ fun sdfCube(point: Vec3d, size: Vec3d): Double {
val insideDistance = min(max(dx, max(dy, dz)), 0.0) val insideDistance = min(max(dx, max(dy, dz)), 0.0)
return outsideDistance + insideDistance return (outsideDistance + insideDistance).toFloat()
}
fun normalizeSdf(sdf: Float, radius: Float): Float {
return if (sdf < 0) (sdf + radius) / radius else 0f
} }
@@ -24,9 +24,10 @@ import java.util.concurrent.CompletableFuture
val curves = arrayOf("LINEAR", "SQRT", "EXPONENT", "CUBIC", "SINE", "COSINE", "INVERSE", "LOG", "EXP", "BOUNCE") val curves = arrayOf("LINEAR", "SQRT", "EXPONENT", "CUBIC", "SINE", "COSINE", "INVERSE", "LOG", "EXP", "BOUNCE")
fun argUpdateEmitterParam(context: CommandContext<ServerCommandSource>, paramName: String, typeValue: Any) : MutableText {
fun updateEmitterParam(context: CommandContext<ServerCommandSource>, paramName: String, typeValue: Any) : MutableText {
val emitterIdVal = StringArgumentType.getString(context, "Registered Emitter ID") val emitterIdVal = StringArgumentType.getString(context, "Registered Emitter ID")
val success = updateSingleParam(emitterIdVal, -1, paramName, typeValue) val success = updateSingleEmitterParam(emitterIdVal, paramName, typeValue)
val feedback = if (success) { val feedback = if (success) {
Text.literal("BPS - Successfully updated Emitter ID \"$emitterIdVal\": Parameter \"$paramName\", value \"$typeValue\"") Text.literal("BPS - Successfully updated Emitter ID \"$emitterIdVal\": Parameter \"$paramName\", value \"$typeValue\"")
@@ -42,17 +43,18 @@ fun argUpdateEmitterParam(context: CommandContext<ServerCommandSource>, paramNam
} }
fun argUpdateParticleParam(context: CommandContext<ServerCommandSource>, particleIndex: Int, paramName: String, typeValue: Any) : MutableText { fun updateParticleParam(context: CommandContext<ServerCommandSource>, paramName: String, typeValue: Any) : MutableText {
val emitterIdVal = StringArgumentType.getString(context, "Registered Emitter ID") val emitterIdVal = StringArgumentType.getString(context, "Registered Emitter ID")
val success = updateSingleParam(emitterIdVal, particleIndex, paramName, typeValue) val particle = getEmitterParams(emitterIdVal)?.particle
val success = updateSingleParticleParam(emitterIdVal, paramName, typeValue)
val feedback = if (success) { val feedback = if (success) {
Text.literal("BPS - Successfully updated Emitter ID \"$emitterIdVal\": Index \"$particleIndex\", parameter \"$paramName\", value \"$typeValue\"") Text.literal("BPS - Successfully updated Particle of Emitter ID \"$emitterIdVal\": parameter \"$paramName\", value \"$typeValue\"")
.setStyle(Style.EMPTY.withColor(Color(0, 200, 0).rgb)) .setStyle(Style.EMPTY.withColor(Color(0, 200, 0).rgb))
} }
else { else {
Text.literal("BPS - Failed to update Emitter ID \"$emitterIdVal\": Index \"$particleIndex\", parameter \"$paramName\", value \"$typeValue\": Unknown Error\n" + Text.literal("BPS - Failed to update Emitter ID \"$emitterIdVal\": parameter \"$paramName\", value \"$typeValue\": Unknown Error\n" +
"Try checking if the emitter, particle index, and parameter exist, and the value is the correct type.") "Try checking if the Emitter ID and parameter exist, and the value is the correct type.")
.setStyle(Style.EMPTY.withColor(Color(200, 0, 0).rgb)) .setStyle(Style.EMPTY.withColor(Color(200, 0, 0).rgb))
} }
@@ -63,62 +65,57 @@ fun argUpdateParticleParam(context: CommandContext<ServerCommandSource>, particl
class ArgConfigEmitterKeys { class ArgConfigEmitterKeys {
fun maxCount() : LiteralArgumentBuilder<ServerCommandSource> { fun maxCount() : LiteralArgumentBuilder<ServerCommandSource> {
return CommandManager.literal("maxCount") return CommandManager.literal("maxCount")
.then( .then(CommandManager.argument("Int", IntegerArgumentType.integer())
CommandManager.argument("Int", IntegerArgumentType.integer()) .executes { context ->
.executes { context -> val typeValue = IntegerArgumentType.getInteger(context, "Int")
val typeValue = IntegerArgumentType.getInteger(context, "Int") val feedback = updateEmitterParam(context, "maxCount", typeValue)
val feedback = argUpdateEmitterParam(context, "maxCount", typeValue) context.source.sendFeedback({ feedback }, false)
context.source.sendFeedback({ feedback }, false) Command.SINGLE_SUCCESS
Command.SINGLE_SUCCESS }
}
) )
} }
fun spawnsPerTick() : LiteralArgumentBuilder<ServerCommandSource> { fun spawnsPerTick() : LiteralArgumentBuilder<ServerCommandSource> {
return CommandManager.literal("spawnsPerTick") return CommandManager.literal("spawnsPerTick")
.then( .then(CommandManager.argument("Int", IntegerArgumentType.integer())
CommandManager.argument("Int", IntegerArgumentType.integer()) .executes { context ->
.executes { context -> val typeValue = IntegerArgumentType.getInteger(context, "Int")
val typeValue = IntegerArgumentType.getInteger(context, "Int") val feedback = updateEmitterParam(context, "spawnsPerTick", typeValue)
val feedback = argUpdateEmitterParam(context, "spawnsPerTick", typeValue) context.source.sendFeedback({ feedback }, false)
context.source.sendFeedback({ feedback }, false) Command.SINGLE_SUCCESS
Command.SINGLE_SUCCESS }
}
) )
} }
fun loopDur() : LiteralArgumentBuilder<ServerCommandSource> { fun loopDur() : LiteralArgumentBuilder<ServerCommandSource> {
return CommandManager.literal("loopDur") return CommandManager.literal("loopDur")
.then( .then(CommandManager.argument("Int", IntegerArgumentType.integer())
CommandManager.argument("Int", IntegerArgumentType.integer()) .executes { context ->
.executes { context -> val typeValue = IntegerArgumentType.getInteger(context, "Int")
val typeValue = IntegerArgumentType.getInteger(context, "Int") val feedback = updateEmitterParam(context, "loopDur", typeValue)
val feedback = argUpdateEmitterParam(context, "loopDur", typeValue) context.source.sendFeedback({ feedback }, false)
context.source.sendFeedback({ feedback }, false) Command.SINGLE_SUCCESS
Command.SINGLE_SUCCESS }
}
) )
} }
fun loopDelay() : LiteralArgumentBuilder<ServerCommandSource> { fun loopDelay() : LiteralArgumentBuilder<ServerCommandSource> {
return CommandManager.literal("loopDelay") return CommandManager.literal("loopDelay")
.then( .then(CommandManager.argument("Int", IntegerArgumentType.integer())
CommandManager.argument("Int", IntegerArgumentType.integer()) .executes { context ->
.executes { context -> val typeValue = IntegerArgumentType.getInteger(context, "Int")
val typeValue = IntegerArgumentType.getInteger(context, "Int") val feedback = updateEmitterParam(context, "loopDelay", typeValue)
val feedback = argUpdateEmitterParam(context, "loopDelay", typeValue) context.source.sendFeedback({ feedback }, false)
context.source.sendFeedback({ feedback }, false) Command.SINGLE_SUCCESS
Command.SINGLE_SUCCESS }
}
) )
} }
fun loopCount() : LiteralArgumentBuilder<ServerCommandSource> { fun loopCount() : LiteralArgumentBuilder<ServerCommandSource> {
return CommandManager.literal("loopCount") return CommandManager.literal("loopCount")
.then( .then(CommandManager.argument("Int", IntegerArgumentType.integer())
CommandManager.argument("Int", IntegerArgumentType.integer()) .executes { context ->
.executes { context -> val typeValue = IntegerArgumentType.getInteger(context, "Int")
val typeValue = IntegerArgumentType.getInteger(context, "Int") val feedback = updateEmitterParam(context, "loopCount", typeValue)
val feedback = argUpdateEmitterParam(context, "loopCount", typeValue) context.source.sendFeedback({ feedback }, false)
context.source.sendFeedback({ feedback }, false) Command.SINGLE_SUCCESS
Command.SINGLE_SUCCESS }
}
) )
} }
} }
@@ -130,9 +127,8 @@ class ArgConfigParticleKeys {
.then(CommandManager.literal("circle") .then(CommandManager.literal("circle")
.then(CommandManager.argument("Radius", FloatArgumentType.floatArg()) .then(CommandManager.argument("Radius", FloatArgumentType.floatArg())
.executes { context -> .executes { context ->
val particleIndex = IntegerArgumentType.getInteger(context, "Particle Index")
val radius = FloatArgumentType.getFloat(context, "Radius") val radius = FloatArgumentType.getFloat(context, "Radius")
val feedback = argUpdateParticleParam(context, particleIndex, "shape", SpawningShape.CIRCLE(radius)) val feedback = updateParticleParam(context, "shape", SpawningShape.CIRCLE(radius))
context.source.sendFeedback( { feedback }, false) context.source.sendFeedback( { feedback }, false)
Command.SINGLE_SUCCESS Command.SINGLE_SUCCESS
} }
@@ -142,10 +138,9 @@ class ArgConfigParticleKeys {
.then(CommandManager.argument("Width", FloatArgumentType.floatArg()) .then(CommandManager.argument("Width", FloatArgumentType.floatArg())
.then(CommandManager.argument("Height", FloatArgumentType.floatArg()) .then(CommandManager.argument("Height", FloatArgumentType.floatArg())
.executes { context -> .executes { context ->
val particleIndex = IntegerArgumentType.getInteger(context, "Particle Index")
val w = FloatArgumentType.getFloat(context, "Width") val w = FloatArgumentType.getFloat(context, "Width")
val h = FloatArgumentType.getFloat(context, "Height") val h = FloatArgumentType.getFloat(context, "Height")
val feedback = argUpdateParticleParam(context, particleIndex, "shape", SpawningShape.RECT(Vector2f(w, h))) val feedback = updateParticleParam(context, "shape", SpawningShape.RECT(Vector2f(w, h)))
context.source.sendFeedback( { feedback }, false) context.source.sendFeedback( { feedback }, false)
Command.SINGLE_SUCCESS Command.SINGLE_SUCCESS
} }
@@ -157,11 +152,10 @@ class ArgConfigParticleKeys {
.then(CommandManager.argument("Y", FloatArgumentType.floatArg()) .then(CommandManager.argument("Y", FloatArgumentType.floatArg())
.then(CommandManager.argument("Z", FloatArgumentType.floatArg()) .then(CommandManager.argument("Z", FloatArgumentType.floatArg())
.executes { context -> .executes { context ->
val particleIndex = IntegerArgumentType.getInteger(context, "Particle Index")
val x = FloatArgumentType.getFloat(context, "X") val x = FloatArgumentType.getFloat(context, "X")
val y = FloatArgumentType.getFloat(context, "Y") val y = FloatArgumentType.getFloat(context, "Y")
val z = FloatArgumentType.getFloat(context, "Z") val z = FloatArgumentType.getFloat(context, "Z")
val feedback = argUpdateParticleParam(context, particleIndex, "shape", SpawningShape.CUBE(Vector3f(x, y, z))) val feedback = updateParticleParam(context, "shape", SpawningShape.CUBE(Vector3f(x, y, z)))
context.source.sendFeedback( { feedback }, false) context.source.sendFeedback( { feedback }, false)
Command.SINGLE_SUCCESS Command.SINGLE_SUCCESS
} }
@@ -172,9 +166,8 @@ class ArgConfigParticleKeys {
.then(CommandManager.literal("sphere") .then(CommandManager.literal("sphere")
.then(CommandManager.argument("Radius", FloatArgumentType.floatArg()) .then(CommandManager.argument("Radius", FloatArgumentType.floatArg())
.executes { context -> .executes { context ->
val particleIndex = IntegerArgumentType.getInteger(context, "Particle Index")
val radius = FloatArgumentType.getFloat(context, "Radius") val radius = FloatArgumentType.getFloat(context, "Radius")
val feedback = argUpdateParticleParam(context, particleIndex, "shape", SpawningShape.SPHERE(radius)) val feedback = updateParticleParam(context, "shape", SpawningShape.SPHERE(radius))
context.source.sendFeedback( { feedback }, false) context.source.sendFeedback( { feedback }, false)
Command.SINGLE_SUCCESS Command.SINGLE_SUCCESS
} }
@@ -185,10 +178,9 @@ class ArgConfigParticleKeys {
return CommandManager.literal("blockCurve") return CommandManager.literal("blockCurve")
.then(CommandManager.argument("Array (separate by comma)", StringArgumentType.string()) .then(CommandManager.argument("Array (separate by comma)", StringArgumentType.string())
.executes { context -> .executes { context ->
val particleIndex = IntegerArgumentType.getInteger(context, "Particle Index")
val typeValue = StringArgumentType.getString(context, "Array (separate by comma)") val typeValue = StringArgumentType.getString(context, "Array (separate by comma)")
val typeArray = typeValue.split(",").toTypedArray() val typeArray = typeValue.split(",").toTypedArray()
val feedback = argUpdateParticleParam(context, particleIndex, "blockCurve", typeArray) val feedback = updateParticleParam(context, "blockCurve", typeArray)
context.source.sendFeedback({ feedback }, false) context.source.sendFeedback({ feedback }, false)
Command.SINGLE_SUCCESS Command.SINGLE_SUCCESS
} }
@@ -203,10 +195,8 @@ class ArgConfigParticleKeys {
.then(CommandManager.argument("Max Y", FloatArgumentType.floatArg()) .then(CommandManager.argument("Max Y", FloatArgumentType.floatArg())
.then(CommandManager.argument("Max Z", FloatArgumentType.floatArg()) .then(CommandManager.argument("Max Z", FloatArgumentType.floatArg())
.executes { context -> .executes { context ->
val particleIndex = IntegerArgumentType.getInteger(context, "Particle Index")
val vectors = x1x2ToPairVector3f(context) val vectors = x1x2ToPairVector3f(context)
val feedback = updateParticleParam(context, "rotRandom", vectors)
val feedback = argUpdateParticleParam(context, particleIndex, "rotRandom", vectors)
context.source.sendFeedback({ feedback }, false) context.source.sendFeedback({ feedback }, false)
Command.SINGLE_SUCCESS Command.SINGLE_SUCCESS
} }
@@ -226,10 +216,8 @@ class ArgConfigParticleKeys {
.then(CommandManager.argument("Max Y", FloatArgumentType.floatArg()) .then(CommandManager.argument("Max Y", FloatArgumentType.floatArg())
.then(CommandManager.argument("Max Z", FloatArgumentType.floatArg()) .then(CommandManager.argument("Max Z", FloatArgumentType.floatArg())
.executes { context -> .executes { context ->
val particleIndex = IntegerArgumentType.getInteger(context, "Particle Index")
val vectors = x1x2ToPairVector3f(context) val vectors = x1x2ToPairVector3f(context)
val feedback = updateParticleParam(context, "rotVelRandom", vectors)
val feedback = argUpdateParticleParam(context, particleIndex, "rotVelRandom", vectors)
context.source.sendFeedback({ feedback }, false) context.source.sendFeedback({ feedback }, false)
Command.SINGLE_SUCCESS Command.SINGLE_SUCCESS
} }
@@ -249,10 +237,8 @@ class ArgConfigParticleKeys {
.then(CommandManager.argument("Max Y", FloatArgumentType.floatArg()) .then(CommandManager.argument("Max Y", FloatArgumentType.floatArg())
.then(CommandManager.argument("Max Z", FloatArgumentType.floatArg()) .then(CommandManager.argument("Max Z", FloatArgumentType.floatArg())
.executes { context -> .executes { context ->
val particleIndex = IntegerArgumentType.getInteger(context, "Particle Index")
val vectors = x1x2ToPairVector3f(context) val vectors = x1x2ToPairVector3f(context)
val feedback = updateParticleParam(context, "sizeRandom", vectors)
val feedback = argUpdateParticleParam(context, particleIndex, "sizeRandom", vectors)
context.source.sendFeedback({ feedback }, false) context.source.sendFeedback({ feedback }, false)
Command.SINGLE_SUCCESS Command.SINGLE_SUCCESS
} }
@@ -267,9 +253,8 @@ class ArgConfigParticleKeys {
return CommandManager.literal("uniformSize") return CommandManager.literal("uniformSize")
.then(CommandManager.argument("Bool", BoolArgumentType.bool()) .then(CommandManager.argument("Bool", BoolArgumentType.bool())
.executes { context -> .executes { context ->
val particleIndex = IntegerArgumentType.getInteger(context, "Particle Index")
val uniform = BoolArgumentType.getBool(context, "Bool") val uniform = BoolArgumentType.getBool(context, "Bool")
val feedback = argUpdateParticleParam(context, particleIndex, "uniformSize", uniform) val feedback = updateParticleParam(context, "uniformSize", uniform)
context.source.sendFeedback( { feedback }, false) context.source.sendFeedback( { feedback }, false)
Command.SINGLE_SUCCESS Command.SINGLE_SUCCESS
} }
@@ -284,10 +269,8 @@ class ArgConfigParticleKeys {
.then(CommandManager.argument("Max Y", FloatArgumentType.floatArg()) .then(CommandManager.argument("Max Y", FloatArgumentType.floatArg())
.then(CommandManager.argument("Max Z", FloatArgumentType.floatArg()) .then(CommandManager.argument("Max Z", FloatArgumentType.floatArg())
.executes { context -> .executes { context ->
val particleIndex = IntegerArgumentType.getInteger(context, "Particle Index")
val vectors = x1x2ToPairVector3f(context) val vectors = x1x2ToPairVector3f(context)
val feedback = updateParticleParam(context, "velRandom", vectors)
val feedback = argUpdateParticleParam(context, particleIndex, "velRandom", vectors)
context.source.sendFeedback({ feedback }, false) context.source.sendFeedback({ feedback }, false)
Command.SINGLE_SUCCESS Command.SINGLE_SUCCESS
} }
@@ -299,7 +282,7 @@ class ArgConfigParticleKeys {
) )
} }
fun forceFields() : LiteralArgumentBuilder<ServerCommandSource> { fun forceFields() : LiteralArgumentBuilder<ServerCommandSource> {
return CommandManager.literal("ForceFields") return CommandManager.literal("forceFields")
.then(argAddForceField()) .then(argAddForceField())
.then(argRemoveForceField()) .then(argRemoveForceField())
} }
@@ -309,12 +292,11 @@ class ArgConfigParticleKeys {
.then(CommandManager.argument("Y", FloatArgumentType.floatArg()) .then(CommandManager.argument("Y", FloatArgumentType.floatArg())
.then(CommandManager.argument("Z", FloatArgumentType.floatArg()) .then(CommandManager.argument("Z", FloatArgumentType.floatArg())
.executes { context -> .executes { context ->
val particleIndex = IntegerArgumentType.getInteger(context, "Particle Index")
val x1 = FloatArgumentType.getFloat(context, "X") val x1 = FloatArgumentType.getFloat(context, "X")
val y1 = FloatArgumentType.getFloat(context, "Y") val y1 = FloatArgumentType.getFloat(context, "Y")
val z1 = FloatArgumentType.getFloat(context, "Z") val z1 = FloatArgumentType.getFloat(context, "Z")
val feedback = argUpdateParticleParam(context, particleIndex, "gravity", Vector3f(x1, y1, z1)) val feedback = updateParticleParam(context, "gravity", Vector3f(x1, y1, z1))
context.source.sendFeedback({ feedback }, false) context.source.sendFeedback({ feedback }, false)
Command.SINGLE_SUCCESS Command.SINGLE_SUCCESS
} }
@@ -326,9 +308,8 @@ class ArgConfigParticleKeys {
return CommandManager.literal("drag") return CommandManager.literal("drag")
.then(CommandManager.argument("Float", FloatArgumentType.floatArg()) .then(CommandManager.argument("Float", FloatArgumentType.floatArg())
.executes { context -> .executes { context ->
val particleIndex = IntegerArgumentType.getInteger(context, "Particle Index")
val value = FloatArgumentType.getFloat(context, "Float") val value = FloatArgumentType.getFloat(context, "Float")
val feedback = argUpdateParticleParam(context, particleIndex, "drag", value) val feedback = updateParticleParam(context, "drag", value)
context.source.sendFeedback( { feedback }, false) context.source.sendFeedback( { feedback }, false)
Command.SINGLE_SUCCESS Command.SINGLE_SUCCESS
} }
@@ -338,9 +319,8 @@ class ArgConfigParticleKeys {
return CommandManager.literal("minVel") return CommandManager.literal("minVel")
.then(CommandManager.argument("Float", FloatArgumentType.floatArg()) .then(CommandManager.argument("Float", FloatArgumentType.floatArg())
.executes { context -> .executes { context ->
val particleIndex = IntegerArgumentType.getInteger(context, "Particle Index")
val value = FloatArgumentType.getFloat(context, "Float") val value = FloatArgumentType.getFloat(context, "Float")
val feedback = argUpdateParticleParam(context, particleIndex, "minVel", value) val feedback = updateParticleParam(context, "minVel", value)
context.source.sendFeedback( { feedback }, false) context.source.sendFeedback( { feedback }, false)
Command.SINGLE_SUCCESS Command.SINGLE_SUCCESS
} }
@@ -351,10 +331,9 @@ class ArgConfigParticleKeys {
.then(CommandManager.argument("min", IntegerArgumentType.integer()) .then(CommandManager.argument("min", IntegerArgumentType.integer())
.then(CommandManager.argument("max", IntegerArgumentType.integer()) .then(CommandManager.argument("max", IntegerArgumentType.integer())
.executes { context -> .executes { context ->
val particleIndex = IntegerArgumentType.getInteger(context, "Particle Index")
val min = IntegerArgumentType.getInteger(context, "min") val min = IntegerArgumentType.getInteger(context, "min")
val max = IntegerArgumentType.getInteger(context, "max") val max = IntegerArgumentType.getInteger(context, "max")
val feedback = argUpdateParticleParam(context, particleIndex, "lifeTime", Pair(min, max)) val feedback = updateParticleParam(context, "lifeTime", Pair(min, max))
context.source.sendFeedback( { feedback }, false) context.source.sendFeedback( { feedback }, false)
Command.SINGLE_SUCCESS Command.SINGLE_SUCCESS
} }
@@ -375,13 +354,11 @@ class ArgConfigParticleKeys {
CompletableFuture.completedFuture(builder.build()) CompletableFuture.completedFuture(builder.build())
} }
.executes { context -> .executes { context ->
val particleIndex = IntegerArgumentType.getInteger(context, "Particle Index")
val vectors = x1x2ToPairVector3f(context) val vectors = x1x2ToPairVector3f(context)
val curveString = StringArgumentType.getString(context, "Curve") val curveString = StringArgumentType.getString(context, "Curve")
val feedback = argUpdateParticleParam( val feedback = updateParticleParam(
context, context,
particleIndex,
"rotVelCurve", "rotVelCurve",
Triple(vectors.first, vectors.second, getCurveByString(curveString))) Triple(vectors.first, vectors.second, getCurveByString(curveString)))
@@ -410,13 +387,11 @@ class ArgConfigParticleKeys {
CompletableFuture.completedFuture(builder.build()) CompletableFuture.completedFuture(builder.build())
} }
.executes { context -> .executes { context ->
val particleIndex = IntegerArgumentType.getInteger(context, "Particle Index")
val vectors = x1x2ToPairVector3f(context) val vectors = x1x2ToPairVector3f(context)
val curveString = StringArgumentType.getString(context, "Curve") val curveString = StringArgumentType.getString(context, "Curve")
val feedback = argUpdateParticleParam( val feedback = updateParticleParam(
context, context,
particleIndex,
"sizeCurve", "sizeCurve",
Triple(vectors.first, vectors.second, getCurveByString(curveString))) Triple(vectors.first, vectors.second, getCurveByString(curveString)))
@@ -503,10 +478,10 @@ fun argRemoveForceField() : LiteralArgumentBuilder<ServerCommandSource> {
return CommandManager.literal("remove") return CommandManager.literal("remove")
.then(CommandManager.argument("Force Field Name", StringArgumentType.string()) .then(CommandManager.argument("Force Field Name", StringArgumentType.string())
.suggests { context, builder -> .suggests { context, builder ->
val particleId = StringArgumentType.getString(context, "Registered Emitter ID") val emitterIdVal = StringArgumentType.getString(context, "Registered Emitter ID")
val particleIndex = IntegerArgumentType.getInteger(context, "Particle Index")
val params = getEmitterParams(particleId) val params = getEmitterParams(emitterIdVal)
val forceFields = params!!.particleTypes[particleIndex].forceFields val forceFields = params!!.particle.forceFields
forceFields.iterator().forEach { forceFields.iterator().forEach {
builder.suggest(it.name) builder.suggest(it.name)
@@ -516,11 +491,10 @@ fun argRemoveForceField() : LiteralArgumentBuilder<ServerCommandSource> {
} }
.executes { context -> .executes { context ->
val ffName = StringArgumentType.getString(context, "Force Field Name") val ffName = StringArgumentType.getString(context, "Force Field Name")
val particleId = StringArgumentType.getString(context, "Registered Emitter ID") val emitterIdVal = StringArgumentType.getString(context, "Registered Emitter ID")
val particleIndex = IntegerArgumentType.getInteger(context, "Particle Index")
val params = getEmitterParams(particleId) val params = getEmitterParams(emitterIdVal)
val forceFields = params!!.particleTypes[particleIndex].forceFields val forceFields = params!!.particle.forceFields
val newForceFields: MutableList<ForceField> = forceFields.toMutableList() val newForceFields: MutableList<ForceField> = forceFields.toMutableList()
for (forceField in forceFields) { for (forceField in forceFields) {
@@ -529,9 +503,8 @@ fun argRemoveForceField() : LiteralArgumentBuilder<ServerCommandSource> {
} }
} }
val feedback = argUpdateParticleParam( val feedback = updateParticleParam(
context, context,
particleIndex,
"forceFields", "forceFields",
newForceFields newForceFields
) )
@@ -543,19 +516,20 @@ fun argRemoveForceField() : LiteralArgumentBuilder<ServerCommandSource> {
fun forceFieldAddSphereExec(context: CommandContext<ServerCommandSource>) : Int { fun forceFieldAddSphereExec(context: CommandContext<ServerCommandSource>) : Int {
val particleIndex = IntegerArgumentType.getInteger(context, "Particle Index")
val radius = FloatArgumentType.getFloat(context, "Radius")
val emitterIdVal = StringArgumentType.getString(context, "Registered Emitter ID") val emitterIdVal = StringArgumentType.getString(context, "Registered Emitter ID")
val radius = FloatArgumentType.getFloat(context, "Radius")
val minForce = FloatArgumentType.getFloat(context, "Min Force")
val maxForce = FloatArgumentType.getFloat(context, "Max Force")
val shape = ForceFieldShape.SPHERE(radius) val shape = ForceFieldShape.SPHERE(radius, Pair(minForce, maxForce))
val forceField = forceFieldGenericParams(context, shape) val forceField = forceFieldGenericParams(context, shape)
val currentParams = getEmitterParams(emitterIdVal) val currentParams = getEmitterParams(emitterIdVal)
val forceFields = currentParams!!.particleTypes[particleIndex].forceFields val forceFields = currentParams!!.particle.forceFields
val feedback = argUpdateParticleParam( val feedback = updateParticleParam(
context, context,
particleIndex,
"forceFields", "forceFields",
forceFields.toMutableList().add(forceField) forceFields.toMutableList().add(forceField)
) )
@@ -568,7 +542,6 @@ fun forceFieldAddSphereExec(context: CommandContext<ServerCommandSource>) : Int
fun forceFieldAddCubeExec(context: CommandContext<ServerCommandSource>) : Int { fun forceFieldAddCubeExec(context: CommandContext<ServerCommandSource>) : Int {
val particleIndex = IntegerArgumentType.getInteger(context, "Particle Index")
val xSize = FloatArgumentType.getFloat(context, "X Size") val xSize = FloatArgumentType.getFloat(context, "X Size")
val ySize = FloatArgumentType.getFloat(context, "Y Size") val ySize = FloatArgumentType.getFloat(context, "Y Size")
val zSize = FloatArgumentType.getFloat(context, "Z Size") val zSize = FloatArgumentType.getFloat(context, "Z Size")
@@ -581,11 +554,10 @@ fun forceFieldAddCubeExec(context: CommandContext<ServerCommandSource>) : Int {
val forceField = forceFieldGenericParams(context, shape) val forceField = forceFieldGenericParams(context, shape)
val currentParams = getEmitterParams(emitterIdVal) val currentParams = getEmitterParams(emitterIdVal)
val forceFields = currentParams!!.particleTypes[particleIndex].forceFields val forceFields = currentParams!!.particle.forceFields
val feedback = argUpdateParticleParam( val feedback = updateParticleParam(
context, context,
particleIndex,
"forceFields", "forceFields",
forceFields.toMutableList().add(forceField) forceFields.toMutableList().add(forceField)
) )
@@ -602,13 +574,10 @@ fun forceFieldGenericParams(context: CommandContext<ServerCommandSource>, shape:
val posX = FloatArgumentType.getFloat(context, "X Pos") val posX = FloatArgumentType.getFloat(context, "X Pos")
val posY = FloatArgumentType.getFloat(context, "Y Pos") val posY = FloatArgumentType.getFloat(context, "Y Pos")
val posZ = FloatArgumentType.getFloat(context, "Z Pos") val posZ = FloatArgumentType.getFloat(context, "Z Pos")
val minForce = FloatArgumentType.getFloat(context, "Min Force")
val maxForce = FloatArgumentType.getFloat(context, "Max Force")
return ForceField( return ForceField(
name.replace(" ", "_"), name.replace(" ", "_"),
Vector3f(posX, posY, posZ), Vector3f(posX, posY, posZ),
Pair(minForce, maxForce),
shape shape
) )
} }
@@ -36,7 +36,7 @@ import java.util.concurrent.CompletableFuture
// config // config
// <emitter id> // <emitter id>
// <[particle index] / EMITTER> // <PARTICLE / EMITTER>
// <param key> // HARDCODED KEYS, if EMITTER use emitter params. // <param key> // HARDCODED KEYS, if EMITTER use emitter params.
// <new param value> // HARDCODED TYPES // <new param value> // HARDCODED TYPES
// output -> update the selected parameter of the selected emitter id to the new value // output -> update the selected parameter of the selected emitter id to the new value
@@ -69,7 +69,7 @@ object ManageEmitters {
val allEmitterIds = emitterIdRegister.keys val allEmitterIds = emitterIdRegister.keys
// TODO: maybe make this a Command.literal() if possible // TODO: perhaps make this a Command.literal() if possible
val emitterIdSuggestion: RequiredArgumentBuilder<ServerCommandSource, String> = CommandManager.argument("Registered Emitter ID", StringArgumentType.string()) val emitterIdSuggestion: RequiredArgumentBuilder<ServerCommandSource, String> = CommandManager.argument("Registered Emitter ID", StringArgumentType.string())
.suggests { _, builder -> .suggests { _, builder ->
allEmitterIds.forEach { key -> allEmitterIds.forEach { key ->
@@ -212,30 +212,21 @@ fun argCopy() : LiteralArgumentBuilder<ServerCommandSource> {
// config // config
// <emitter id> // <emitter id>
// <[particle index] / EMITTER> // <PARTICLE / EMITTER>
// <param key> // HARDCODED KEYS, if EMITTER use emitter params. // <param key> // HARDCODED KEYS, if EMITTER use emitter params.
// <new param value> // HARDCODED TYPES // <new param value> // HARDCODED TYPES
// output -> update the selected parameter of the selected emitter id to the new value // output -> update the selected parameter of the selected emitter id to the new value
fun argConfig() : LiteralArgumentBuilder<ServerCommandSource> { fun argConfig() : LiteralArgumentBuilder<ServerCommandSource> {
return CommandManager.literal("config") return CommandManager.literal("config")
.then(emitterIdSuggestion .then(emitterIdSuggestion
.then(CommandManager.literal("EMITTER") .then(CommandManager.literal("emitter")
.then(emitterConfigKeys.maxCount()) .then(emitterConfigKeys.maxCount())
.then(emitterConfigKeys.spawnsPerTick()) .then(emitterConfigKeys.spawnsPerTick())
.then(emitterConfigKeys.loopDur()) .then(emitterConfigKeys.loopDur())
.then(emitterConfigKeys.loopDelay()) .then(emitterConfigKeys.loopDelay())
.then(emitterConfigKeys.loopCount()) .then(emitterConfigKeys.loopCount())
) )
.then(CommandManager.argument("Particle Index", IntegerArgumentType.integer()) .then(CommandManager.literal("particle")
.suggests { context, builder ->
val emitterId = StringArgumentType.getString(context, "Registered Emitter ID")
getEmitterParams(emitterId)?.particleTypes?.indices?.forEach {
builder.suggest(it)
}
CompletableFuture.completedFuture(builder.build())
}
.then(particleConfigKeys.shape()) .then(particleConfigKeys.shape())
.then(particleConfigKeys.blockCurve()) .then(particleConfigKeys.blockCurve())
.then(particleConfigKeys.rotRandom()) .then(particleConfigKeys.rotRandom())
@@ -9,15 +9,15 @@ package com.bytedice.bde_particles.particles
* @param loopDur The duration for which the loop runs, in ticks. A value 0 or below means the loop is infinite, and `loopDelay` and `loopCount` will be ignored. * @param loopDur The duration for which the loop runs, in ticks. A value 0 or below means the loop is infinite, and `loopDelay` and `loopCount` will be ignored.
* @param loopDelay The delay between each loop cycle, in ticks. Negative values are treated as 0, meaning no delay. * @param loopDelay The delay between each loop cycle, in ticks. Negative values are treated as 0, meaning no delay.
* @param loopCount The number of times the loop will repeat. 0 means it will shoot a single burst of particles. A value below 0 means it will repeat indefinitely. * @param loopCount The number of times the loop will repeat. 0 means it will shoot a single burst of particles. A value below 0 means it will repeat indefinitely.
* @param particleTypes An array of `ParticleParams` defining the types of particles to spawn. If empty, no particles will spawn. * @param particle The particle params of the particle that will spawn.
*/ */
data class EmitterParams ( data class EmitterParams (
var maxCount: Int = 200, var maxCount: Int = 200,
var spawnsPerTick: Int = 1, var spawnsPerTick: Int = 1,
var loopDur: Int = 25, var loopDur: Int = 25,
var loopDelay: Int = 0, var loopDelay: Int = 0,
var loopCount: Int = 0, var loopCount: Int = 0,
var particleTypes: Array<ParticleParams> = arrayOf(ParticleParams()), var particle: ParticleParams = ParticleParams(),
) )
{ {
companion object Presets { companion object Presets {
@@ -28,7 +28,7 @@ data class EmitterParams (
25, 25,
0, 0,
0, 0,
arrayOf(ParticleParams.DEFAULT) ParticleParams.FIRE_GEYSER
) )
} }
} }
@@ -4,7 +4,6 @@ import org.joml.Vector3f
data class ForceField ( data class ForceField (
val name: String = "DEFAULT", val name: String = "DEFAULT",
val pos: Vector3f = Vector3f(0.0f, 0.0f, 0.0f), val pos: Vector3f = Vector3f(0.0f, 5.0f, 0.0f),
val force: Pair<Float, Float> = Pair(0.0f, 1.0f),
val shape: ForceFieldShape = ForceFieldShape.SPHERE() val shape: ForceFieldShape = ForceFieldShape.SPHERE()
) )
@@ -5,8 +5,7 @@ import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.Vec3d import net.minecraft.util.math.Vec3d
import org.joml.Vector3f import org.joml.Vector3f
import org.joml.Vector4f import org.joml.Vector4f
import kotlin.math.abs import kotlin.math.*
import kotlin.math.round
class Particle(private val particleParams: ParticleParams) { class Particle(private val particleParams: ParticleParams) {
@@ -124,13 +123,28 @@ class Particle(private val particleParams: ParticleParams) {
return particleParams.blockCurve[newBlockIdx] return particleParams.blockCurve[newBlockIdx]
} }
/*fun calcVel() { fun sphereSdfVel(forceField: ForceField) : Vector3f {
for (forceField in particleParams.forceFields) { if (forceField.shape !is ForceFieldShape.SPHERE) { return Vector3f(0.0f, 0.0f, 0.0f) }
if (forceField.shape::class == ForceFieldShape.Sphere::class) { val shape = forceField.shape
} val sdfVal = sdfSphere(forceField.pos, shape.radius, offset)
} val normalizedSdf = normalizeSdf(sdfVal, shape.radius)
}*/ val velDir = Vector3f(offset).sub(forceField.pos).normalize()
val velMul = lerp(shape.force.second, shape.force.second, 1 - normalizedSdf)
return velDir.mul(velMul)
}
fun cubeSdfVel(forceField: ForceField) : Vector3f {
if (forceField.shape !is ForceFieldShape.CUBE) { return Vector3f(0.0f, 0.0f, 0.0f) }
val shape = forceField.shape
val sdfVal = sdfCube(forceField.pos, shape.size, offset)
val velDir = if (sdfVal < 0) { shape.forceDir }
else { Vector3f(0.0f, 0.0f, 0.0f) }
return velDir
}
fun calcRot(timeAliveClamped: Float) : Vector3f { fun calcRot(timeAliveClamped: Float) : Vector3f {
val newRot = Vector3f(rot) val newRot = Vector3f(rot)
@@ -174,6 +188,11 @@ class Particle(private val particleParams: ParticleParams) {
offset = newOffset offset = newOffset
rot = newRot rot = newRot
for (forceField in particleParams.forceFields) {
if (forceField.shape is ForceFieldShape.SPHERE) { vel.add(sphereSdfVel(forceField)) }
else if (forceField.shape is ForceFieldShape.CUBE) { vel.add(cubeSdfVel(forceField)) }
}
val (quatRot, transformOffset) = calcTransformOffset(newRot, initOffset, newScale) val (quatRot, transformOffset) = calcTransformOffset(newRot, initOffset, newScale)
val combinedOffset = transformOffset.add(newOffset) val combinedOffset = transformOffset.add(newOffset)
@@ -33,16 +33,14 @@ class ParticleEmitter(private val emitterPos: Vec3d, private val emitterWorld: S
private fun addParticle() { private fun addParticle() {
if (loopDelayActive) { return } if (loopDelayActive) { return }
for (i in emitterParams.particleTypes.indices) { repeat(this.emitterParams.spawnsPerTick) {
repeat(this.emitterParams.spawnsPerTick) { if (allParticles.size >= emitterParams.maxCount) { return }
if (allParticles.size >= emitterParams.maxCount) { return }
val particle = Particle(emitterParams.particleTypes[i]) val particle = Particle(emitterParams.particle)
particle.init(this.emitterPos) particle.init(this.emitterPos)
particle.spawn(emitterWorld) particle.spawn(emitterWorld)
allParticles += particle allParticles += particle
}
} }
} }
@@ -40,28 +40,25 @@ fun updateEmitterParams(id: String, newParams: EmitterParams) {
} }
fun updateSingleParam(id: String, particleIndex: Int, paramName: String, paramValue: Any) : Boolean { fun updateSingleEmitterParam(id: String, paramName: String, paramValue: Any) : Boolean {
val emitter = getEmitterParams(id) ?: return false val emitter = getEmitterParams(id) ?: return false
val updatedValues = updateSingleEmitterParam(emitter, paramName, paramValue)
updateEmitterParams(id, updatedValues.first)
if (particleIndex == -1) { return updatedValues.second
val updatedValues = updateSingleEmitterParam(emitter, paramName, paramValue) }
updateEmitterParams(id, updatedValues.first)
return updatedValues.second
}
else if (emitter.particleTypes.isNotEmpty()) {
val particle = emitter.particleTypes[particleIndex]
val updatedValues = updateSingleParticleParam(particle, paramName, paramValue) fun updateSingleParticleParam(emitterId: String, paramName: String, paramValue: Any) : Boolean {
val emitter = getEmitterParams(emitterId) ?: return false
val particle = emitter.particle
emitter.particleTypes[particleIndex] = updatedValues.first val updatedValues = updateSingleParticleParam(particle, paramName, paramValue)
updateEmitterParams(id, emitter)
return updatedValues.second emitter.particle = updatedValues.first
} updateEmitterParams(emitterId, emitter)
else {
return false return updatedValues.second
}
} }
@@ -29,7 +29,7 @@ data class ParticleParams (
var sizeRandom: Pair<Vector3f, Vector3f> = Pair(Vector3f(0.5f, 0.5f, 0.5f), Vector3f(1.0f, 1.0f, 1.0f)), var sizeRandom: Pair<Vector3f, Vector3f> = Pair(Vector3f(0.5f, 0.5f, 0.5f), Vector3f(1.0f, 1.0f, 1.0f)),
var uniformSize: Boolean = true, var uniformSize: Boolean = true,
var velRandom: Pair<Vector3f, Vector3f> = Pair(Vector3f(-0.1f, 0.4f, -0.1f), Vector3f(0.1f, 0.8f, 0.1f)), var velRandom: Pair<Vector3f, Vector3f> = Pair(Vector3f(-0.1f, 0.4f, -0.1f), Vector3f(0.1f, 0.8f, 0.1f)),
var forceFields: Array<ForceField> = emptyArray(), var forceFields: Array<ForceField> = arrayOf(ForceField()),
var gravity: Vector3f = Vector3f(0.0f, -0.01f, 0.0f), var gravity: Vector3f = Vector3f(0.0f, -0.01f, 0.0f),
var drag: Float = 0.075f, var drag: Float = 0.075f,
var minVel: Float = 0.0f, var minVel: Float = 0.0f,
@@ -11,9 +11,12 @@ sealed class SpawningShape {
} }
sealed class ForceFieldShape { sealed class ForceFieldShape {
data class SPHERE(val radius: Float = 1.0f) : ForceFieldShape() data class SPHERE(
val radius: Float = 3.0f,
val force: Pair<Float, Float> = Pair(0.0f, 0.02f),
) : ForceFieldShape()
data class CUBE( data class CUBE(
val size: Vector3f = Vector3f(1.0f, 1.0f, 1.0f), val size: Vector3f = Vector3f(1.0f, 1.0f, 1.0f),
val forceDir: Vector3f = Vector3f(0.0f, 0.0f, 0.0f) // 0.0 on all means from center val forceDir: Vector3f = Vector3f(0.0f, 0.0f, 0.0f)
) : ForceFieldShape() ) : ForceFieldShape()
} }