added more args
This commit is contained in:
@@ -49,12 +49,11 @@ import java.util.concurrent.CompletableFuture
|
||||
// Allowing the use of regular Minecraft particles instead of just BDEs.
|
||||
// Cylinder and cone force field shape.
|
||||
// Copying particle params in-game
|
||||
// Custom curve equation command args (parse from strings)
|
||||
|
||||
|
||||
// TODO: (project)
|
||||
// fix ManageEmitter command
|
||||
// add SpawnEmitter command for spawning emitters via commands
|
||||
// Custom curve equation command args (parse from strings)
|
||||
// Better command auto-completion. (and change names of args)
|
||||
// force field "config" option
|
||||
|
||||
@@ -91,7 +90,7 @@ class Bde_particles : ModInitializer {
|
||||
|
||||
CommandRegistrationCallback.EVENT.register { dispatcher, registryAccess, _ ->
|
||||
GiveEmitterTool.register(dispatcher, registryAccess)
|
||||
ManageEmitters .register(dispatcher)
|
||||
ManageEmitters .register(dispatcher, registryAccess)
|
||||
KillAllEmitters.register(dispatcher)
|
||||
SpawnEmitter .register(dispatcher)
|
||||
}
|
||||
@@ -196,7 +195,7 @@ fun displayEntityContainsTag(entity: ItemDisplayEntity, tag: String) : Boolean {
|
||||
}
|
||||
|
||||
|
||||
fun emitterListArg (argName: String) : RequiredArgumentBuilder<ServerCommandSource, String> {
|
||||
fun emitterListArg(argName: String) : RequiredArgumentBuilder<ServerCommandSource, String> {
|
||||
return CommandManager.argument(argName, StringArgumentType.string())
|
||||
.suggests { _, builder ->
|
||||
idRegister.keys.forEach { key ->
|
||||
@@ -207,6 +206,23 @@ fun emitterListArg (argName: String) : RequiredArgumentBuilder<ServerCommandSour
|
||||
}
|
||||
|
||||
|
||||
fun curveListArg(argName: String) : RequiredArgumentBuilder<ServerCommandSource, String> {
|
||||
return CommandManager.argument(argName, StringArgumentType.string())
|
||||
.suggests { _, builder ->
|
||||
LerpCurves::class.nestedClasses.forEach { nestClass ->
|
||||
builder.suggest(nestClass.simpleName)
|
||||
}
|
||||
CompletableFuture.completedFuture(builder.build())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun stringToCurve(curveName: String): LerpCurves? {
|
||||
return LerpCurves::class.members
|
||||
.filter { it.name == curveName }.firstNotNullOfOrNull { it.call(LerpCurves) as? LerpCurves }
|
||||
}
|
||||
|
||||
|
||||
fun spawnEmitter(emitter: ParticleEmitter) {
|
||||
ALL_PARTICLE_EMITTERS += emitter
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import kotlin.random.Random
|
||||
|
||||
class LerpCurves(val function: (Float) -> Float) {
|
||||
companion object {
|
||||
val Constant = LerpCurves { _ -> 1.0f }
|
||||
val Linear = LerpCurves { y -> y }
|
||||
val Sqrt = LerpCurves { y -> sqrt(y) }
|
||||
val Exponent = LerpCurves { y -> y.pow(2.0f) }
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package com.bytedice.bde_particles.commands
|
||||
|
||||
import com.bytedice.bde_particles.particles.EmitterParams
|
||||
import com.bytedice.bde_particles.particles.ParamClasses
|
||||
import com.bytedice.bde_particles.particles.SpawningShape
|
||||
import com.bytedice.bde_particles.particles.updateParam
|
||||
import com.bytedice.bde_particles.curveListArg
|
||||
import com.bytedice.bde_particles.negativeFeedback
|
||||
import com.bytedice.bde_particles.particles.*
|
||||
import com.bytedice.bde_particles.positiveFeedback
|
||||
import com.bytedice.bde_particles.stringToCurve
|
||||
import com.mojang.brigadier.Command
|
||||
import com.mojang.brigadier.arguments.BoolArgumentType
|
||||
import com.mojang.brigadier.arguments.FloatArgumentType
|
||||
@@ -14,13 +14,15 @@ import com.mojang.brigadier.builder.ArgumentBuilder
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder
|
||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder
|
||||
import com.mojang.brigadier.context.CommandContext
|
||||
import net.minecraft.command.CommandRegistryAccess
|
||||
import net.minecraft.command.argument.ItemStackArgumentType
|
||||
import net.minecraft.server.command.CommandManager
|
||||
import net.minecraft.server.command.ServerCommandSource
|
||||
import org.joml.Vector2f
|
||||
import org.joml.Vector3f
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.reflect.*
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import net.minecraft.server.command.GiveCommand
|
||||
|
||||
|
||||
typealias CommandArgumentBuilder = KFunction<ArgumentBuilder<ServerCommandSource, *>>
|
||||
@@ -28,7 +30,11 @@ typealias CommandArgumentBuilder = KFunction<ArgumentBuilder<ServerCommandSource
|
||||
|
||||
// TODO: doesn't apply shape & duration. Error applying shape other than circle
|
||||
|
||||
fun listConfigArgs(configArgs: Array<String>, rootArg: RequiredArgumentBuilder<ServerCommandSource, *>) : RequiredArgumentBuilder<ServerCommandSource, *> {
|
||||
fun listConfigArgs(configArgs: Array<String>,
|
||||
rootArg: RequiredArgumentBuilder<ServerCommandSource, *>,
|
||||
registryAccess: CommandRegistryAccess
|
||||
) : RequiredArgumentBuilder<ServerCommandSource, *>
|
||||
{
|
||||
configArgs.forEach { arg ->
|
||||
var configArg = CommandManager.literal(arg)
|
||||
|
||||
@@ -36,11 +42,17 @@ fun listConfigArgs(configArgs: Array<String>, rootArg: RequiredArgumentBuilder<S
|
||||
val func = parseArgTypeToFunc(argAccess.returnType)
|
||||
|
||||
if (func != null) {
|
||||
if (func.parameters.lastIndex == 0) { configArg.then(func.call(argAccess)) }
|
||||
else { configArg = func.call(argAccess, configArg) as LiteralArgumentBuilder<ServerCommandSource>? }
|
||||
if (func.parameters.lastIndex == 0) {
|
||||
configArg.then(func.call(argAccess))
|
||||
}
|
||||
else if (func.parameters.lastIndex == 1) {
|
||||
configArg = func.call(argAccess, configArg) as LiteralArgumentBuilder<ServerCommandSource>?
|
||||
}
|
||||
else {
|
||||
configArg = func.call(argAccess, configArg, registryAccess) as LiteralArgumentBuilder<ServerCommandSource>?
|
||||
}
|
||||
}
|
||||
|
||||
// Add the configArg to the root command builder
|
||||
rootArg.then(configArg)
|
||||
}
|
||||
|
||||
@@ -60,26 +72,23 @@ fun parseArgNameToAccess(name: String) : KProperty1<EmitterParams, *>? {
|
||||
return access
|
||||
}
|
||||
|
||||
|
||||
// TODO: add forceField & implement rest of args
|
||||
fun parseArgTypeToFunc(type: KType) : CommandArgumentBuilder? {
|
||||
when (type.classifier) {
|
||||
Int::class -> return ::intArg
|
||||
Float::class -> return ::floatArg
|
||||
String::class -> return ::stringArg
|
||||
ParamClasses.Duration::class -> return ::durArg
|
||||
Vector3f::class -> return ::vec3fArg
|
||||
ParamClasses.PairInt::class -> return ::pairIntArg
|
||||
SpawningShape::class -> return ::shapeArg
|
||||
ParamClasses.PairVec3f::class -> println("Type is PairVec3f")
|
||||
ParamClasses.PairFloat::class -> println("Type is PairFloat")
|
||||
ParamClasses.TransformWithVel::class -> println("Type is TransformWithVel")
|
||||
Array::class -> println("Type is Array")
|
||||
ParamClasses.LerpVal::class -> println("Type is LerpVal")
|
||||
Pair::class -> println("Type is Pair")
|
||||
else -> return null
|
||||
return when (type.classifier) {
|
||||
Int::class -> ::intArg
|
||||
Float::class -> ::floatArg
|
||||
String::class -> ::stringArg
|
||||
ParamClasses.Duration::class -> ::durArg
|
||||
Vector3f::class -> ::vec3fArg
|
||||
ParamClasses.PairInt::class -> ::pairIntArg
|
||||
SpawningShape::class -> ::shapeArg
|
||||
ParamClasses.PairVec3f::class -> ::pairVec3fArg
|
||||
ParamClasses.PairFloat::class -> ::pairFloatArg
|
||||
ParamClasses.TransformWithVel::class -> ::transformWithVelArg
|
||||
ParamClasses.StringCurve::class -> ::stringCurveArg
|
||||
ParamClasses.LerpVal::class -> null
|
||||
else -> null
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@@ -134,14 +143,14 @@ fun durArg(access: KProperty1<EmitterParams, ParamClasses.Duration>,
|
||||
return configArg
|
||||
.then(CommandManager.literal("SingleBurst")
|
||||
.then(CommandManager.argument("loopDur", IntegerArgumentType.integer())
|
||||
.executes { context -> durArgExec(access, context); Command.SINGLE_SUCCESS }
|
||||
.executes { context -> durArgExec("SingleBurst", access, context); Command.SINGLE_SUCCESS }
|
||||
)
|
||||
)
|
||||
.then(CommandManager.literal("MultiBurst")
|
||||
.then(CommandManager.argument("loopDur", IntegerArgumentType.integer())
|
||||
.then(CommandManager.argument("loopDelay", IntegerArgumentType.integer())
|
||||
.then(CommandManager.argument("loopCount", IntegerArgumentType.integer())
|
||||
.executes { context -> durArgExec(access, context); Command.SINGLE_SUCCESS }
|
||||
.executes { context -> durArgExec("MultiBurst", access, context); Command.SINGLE_SUCCESS }
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -149,34 +158,33 @@ fun durArg(access: KProperty1<EmitterParams, ParamClasses.Duration>,
|
||||
.then(CommandManager.literal("InfiniteLoop")
|
||||
.then(CommandManager.argument("loopDur", IntegerArgumentType.integer())
|
||||
.then(CommandManager.argument("loopDelay", IntegerArgumentType.integer())
|
||||
.executes { context -> durArgExec(access, context); Command.SINGLE_SUCCESS }
|
||||
.executes { context -> durArgExec("InfiniteLoop", access, context); Command.SINGLE_SUCCESS }
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun durArgExec(access: KProperty1<EmitterParams, ParamClasses.Duration>, context: CommandContext<ServerCommandSource>) {
|
||||
fun durArgExec(paramName: String, access: KProperty1<EmitterParams, ParamClasses.Duration>, context: CommandContext<ServerCommandSource>) {
|
||||
val id = StringArgumentType.getString(context, "Emitter ID")
|
||||
val loopDur = IntegerArgumentType.getInteger(context, "loopDur")
|
||||
|
||||
val eParams = EmitterParams.DEFAULT
|
||||
|
||||
when (access.get(eParams)) {
|
||||
is ParamClasses.Duration.SingleBurst -> {
|
||||
when (paramName) {
|
||||
"SingleBurst" -> {
|
||||
updateParam(id, access, ParamClasses.Duration.SingleBurst(loopDur))
|
||||
}
|
||||
is ParamClasses.Duration.MultiBurst -> {
|
||||
"MultiBurst" -> {
|
||||
val loopDelay = IntegerArgumentType.getInteger(context, "loopDelay")
|
||||
val loopCount = IntegerArgumentType.getInteger(context, "loopCount")
|
||||
updateParam(id, access, ParamClasses.Duration.MultiBurst(loopDur, loopDelay, loopCount))
|
||||
}
|
||||
is ParamClasses.Duration.InfiniteLoop -> {
|
||||
"InfiniteLoop" -> {
|
||||
val loopDelay = IntegerArgumentType.getInteger(context, "loopDelay")
|
||||
updateParam(id, access, ParamClasses.Duration.InfiniteLoop(loopDur, loopDelay))
|
||||
}
|
||||
}
|
||||
|
||||
successText(access, access.get(eParams)::class.simpleName ?: "UNKNOWN", id, context)
|
||||
successText(access, access::class.simpleName ?: "UNKNOWN", id, context)
|
||||
}
|
||||
|
||||
fun vec3fArg(access: KProperty1<EmitterParams, Vector3f>) : RequiredArgumentBuilder<ServerCommandSource, Float> {
|
||||
@@ -199,12 +207,12 @@ fun vec3fArg(access: KProperty1<EmitterParams, Vector3f>) : RequiredArgumentBuil
|
||||
}
|
||||
|
||||
fun pairIntArg(access: KProperty1<EmitterParams, ParamClasses.PairInt>) : RequiredArgumentBuilder<ServerCommandSource, Int> {
|
||||
return CommandManager.argument("First Int", IntegerArgumentType.integer())
|
||||
.then(CommandManager.argument("Second Int", IntegerArgumentType.integer())
|
||||
return CommandManager.argument("Min Int", IntegerArgumentType.integer())
|
||||
.then(CommandManager.argument("Max Int", IntegerArgumentType.integer())
|
||||
.executes { context ->
|
||||
val id = StringArgumentType.getString(context, "Emitter ID")
|
||||
val valueX = IntegerArgumentType.getInteger(context, "First Int")
|
||||
val valueY = IntegerArgumentType.getInteger(context, "Second Int")
|
||||
val valueX = IntegerArgumentType.getInteger(context, "Min Int")
|
||||
val valueY = IntegerArgumentType.getInteger(context, "Max Int")
|
||||
|
||||
updateParam(id, access, ParamClasses.PairInt(valueX, valueY))
|
||||
successText(access, "[$valueX, $valueY]", id, context)
|
||||
@@ -221,7 +229,7 @@ fun shapeArg(access: KProperty1<EmitterParams, SpawningShape>,
|
||||
.then(CommandManager.literal("Circle")
|
||||
.then(CommandManager.argument("Radius", FloatArgumentType.floatArg())
|
||||
.then(CommandManager.argument("Spawn On Edge", BoolArgumentType.bool())
|
||||
.executes { context -> shapeArgExec(access, context); Command.SINGLE_SUCCESS }
|
||||
.executes { context -> shapeArgExec("Circle", access, context); Command.SINGLE_SUCCESS }
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -229,7 +237,7 @@ fun shapeArg(access: KProperty1<EmitterParams, SpawningShape>,
|
||||
.then(CommandManager.argument("X", FloatArgumentType.floatArg())
|
||||
.then(CommandManager.argument("Y", FloatArgumentType.floatArg())
|
||||
.then(CommandManager.argument("Spawn On Edge", BoolArgumentType.bool())
|
||||
.executes { context -> shapeArgExec(access, context); Command.SINGLE_SUCCESS }
|
||||
.executes { context -> shapeArgExec("Rect", access, context); Command.SINGLE_SUCCESS }
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -239,7 +247,7 @@ fun shapeArg(access: KProperty1<EmitterParams, SpawningShape>,
|
||||
.then(CommandManager.argument("Y", FloatArgumentType.floatArg())
|
||||
.then(CommandManager.argument("Z", FloatArgumentType.floatArg())
|
||||
.then(CommandManager.argument("Spawn On Edge", BoolArgumentType.bool())
|
||||
.executes { context -> shapeArgExec(access, context); Command.SINGLE_SUCCESS }
|
||||
.executes { context -> shapeArgExec("Cube", access, context); Command.SINGLE_SUCCESS }
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -248,51 +256,258 @@ fun shapeArg(access: KProperty1<EmitterParams, SpawningShape>,
|
||||
.then(CommandManager.literal("Sphere")
|
||||
.then(CommandManager.argument("Radius", FloatArgumentType.floatArg())
|
||||
.then(CommandManager.argument("Spawn On Edge", BoolArgumentType.bool())
|
||||
.executes { context -> shapeArgExec(access, context); Command.SINGLE_SUCCESS }
|
||||
.executes { context -> shapeArgExec("Sphere", access, context); Command.SINGLE_SUCCESS }
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(CommandManager.literal("Point")
|
||||
.executes { context -> shapeArgExec(access, context); Command.SINGLE_SUCCESS }
|
||||
.executes { context -> shapeArgExec("Point", access, context); Command.SINGLE_SUCCESS }
|
||||
)
|
||||
}
|
||||
|
||||
fun shapeArgExec(access: KProperty1<EmitterParams, SpawningShape>, context: CommandContext<ServerCommandSource>) {
|
||||
fun shapeArgExec(paramName: String, access: KProperty1<EmitterParams, SpawningShape>, context: CommandContext<ServerCommandSource>) {
|
||||
val id = StringArgumentType.getString(context, "Emitter ID")
|
||||
|
||||
val eParams = EmitterParams.DEFAULT
|
||||
|
||||
println(access.get(eParams)::class)
|
||||
|
||||
when (access.get(eParams)) {
|
||||
is SpawningShape.Circle -> {
|
||||
when (paramName) {
|
||||
"Circle" -> {
|
||||
val radius = FloatArgumentType.getFloat(context, "Radius")
|
||||
val onEdge = BoolArgumentType.getBool(context, "Spawn On Edge")
|
||||
updateParam(id, access, SpawningShape.Circle(radius, onEdge))
|
||||
}
|
||||
is SpawningShape.Rect -> {
|
||||
"Rect" -> {
|
||||
val onEdge = BoolArgumentType.getBool(context, "Spawn On Edge")
|
||||
val x = FloatArgumentType.getFloat(context, "X")
|
||||
val y = FloatArgumentType.getFloat(context, "Y")
|
||||
updateParam(id, access, SpawningShape.Rect(Vector2f(x, y), onEdge))
|
||||
}
|
||||
is SpawningShape.Cube -> {
|
||||
"Cube" -> {
|
||||
val onEdge = BoolArgumentType.getBool(context, "Spawn On Edge")
|
||||
val x = FloatArgumentType.getFloat(context, "X")
|
||||
val y = FloatArgumentType.getFloat(context, "Y")
|
||||
val z = FloatArgumentType.getFloat(context, "Z")
|
||||
updateParam(id, access, SpawningShape.Cube(Vector3f(x, y, z), onEdge))
|
||||
}
|
||||
is SpawningShape.Sphere -> {
|
||||
"Sphere" -> {
|
||||
val radius = FloatArgumentType.getFloat(context, "Radius")
|
||||
val onEdge = BoolArgumentType.getBool(context, "Spawn On Edge")
|
||||
updateParam(id, access, SpawningShape.Sphere(radius, onEdge))
|
||||
println("$id, ${access.name}, $radius, $onEdge")
|
||||
}
|
||||
is SpawningShape.Point -> {
|
||||
"Point" -> {
|
||||
updateParam(id, access, SpawningShape.Point)
|
||||
}
|
||||
}
|
||||
|
||||
successText(access, access.get(eParams)::class.simpleName ?: "UNKNOWN", id, context)
|
||||
successText(access, access::class.simpleName ?: "UNKNOWN", id, context)
|
||||
}
|
||||
|
||||
fun pairVec3fArg(access: KProperty1<EmitterParams,ParamClasses.PairVec3f>,
|
||||
configArg: LiteralArgumentBuilder<ServerCommandSource>
|
||||
) : LiteralArgumentBuilder<ServerCommandSource>
|
||||
{
|
||||
return configArg
|
||||
.then(CommandManager.literal("NonUniform")
|
||||
.then(CommandManager.argument("Min X", FloatArgumentType.floatArg())
|
||||
.then(CommandManager.argument("Min Y", FloatArgumentType.floatArg())
|
||||
.then(CommandManager.argument("Min Z", FloatArgumentType.floatArg())
|
||||
.then(CommandManager.argument("Max X", FloatArgumentType.floatArg())
|
||||
.then(CommandManager.argument("Max Y", FloatArgumentType.floatArg())
|
||||
.then(CommandManager.argument("Max Z", FloatArgumentType.floatArg())
|
||||
.executes { context ->
|
||||
val id = StringArgumentType.getString(context, "Emitter ID")
|
||||
val minX = FloatArgumentType.getFloat(context, "Min X")
|
||||
val minY = FloatArgumentType.getFloat(context, "Min Y")
|
||||
val minZ = FloatArgumentType.getFloat(context, "Min Z")
|
||||
val maxX = FloatArgumentType.getFloat(context, "Max X")
|
||||
val maxY = FloatArgumentType.getFloat(context, "Max Y")
|
||||
val maxZ = FloatArgumentType.getFloat(context, "Max Z")
|
||||
|
||||
updateParam(id, access, ParamClasses.PairVec3f.NonUniform(minX, minY, minZ, maxX, maxY, maxZ))
|
||||
|
||||
successText(access, "NonUniform", id, context)
|
||||
Command.SINGLE_SUCCESS
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(CommandManager.literal("Uniform")
|
||||
.then(CommandManager.argument("X", FloatArgumentType.floatArg())
|
||||
.then(CommandManager.argument("Y", FloatArgumentType.floatArg())
|
||||
.executes { context ->
|
||||
val id = StringArgumentType.getString(context, "Emitter ID")
|
||||
val min = FloatArgumentType.getFloat(context, "X")
|
||||
val max = FloatArgumentType.getFloat(context, "Y")
|
||||
|
||||
updateParam(id, access, ParamClasses.PairVec3f.Uniform(min, max))
|
||||
|
||||
successText(access, "Uniform", id, context)
|
||||
Command.SINGLE_SUCCESS
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(CommandManager.literal("Null")
|
||||
.executes { context ->
|
||||
val id = StringArgumentType.getString(context, "Emitter ID")
|
||||
|
||||
updateParam(id, access, ParamClasses.PairVec3f.Null)
|
||||
|
||||
successText(access, "Null", id, context)
|
||||
Command.SINGLE_SUCCESS
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun pairFloatArg(access: KProperty1<EmitterParams, ParamClasses.PairInt>) : RequiredArgumentBuilder<ServerCommandSource, Float> {
|
||||
return CommandManager.argument("Min Float", FloatArgumentType.floatArg())
|
||||
.then(CommandManager.argument("Max Float", FloatArgumentType.floatArg())
|
||||
.executes { context ->
|
||||
val id = StringArgumentType.getString(context, "Emitter ID")
|
||||
val valueX = FloatArgumentType.getFloat(context, "Min Int")
|
||||
val valueY = FloatArgumentType.getFloat(context, "Max Int")
|
||||
|
||||
updateParam(id, access, ParamClasses.PairFloat(valueX, valueY))
|
||||
successText(access, "[$valueX, $valueY]", id, context)
|
||||
Command.SINGLE_SUCCESS
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun transformWithVelArg(access: KProperty1<EmitterParams, ParamClasses.TransformWithVel>,
|
||||
configArg: LiteralArgumentBuilder<ServerCommandSource>
|
||||
) : LiteralArgumentBuilder<ServerCommandSource>
|
||||
{
|
||||
return configArg
|
||||
.then(CommandManager.literal("RotOnly")
|
||||
.executes { context ->
|
||||
val id = StringArgumentType.getString(context, "Emitter ID")
|
||||
|
||||
updateParam(id, access, ParamClasses.TransformWithVel.RotOnly)
|
||||
successText(access, "RotOnly", id, context)
|
||||
Command.SINGLE_SUCCESS
|
||||
}
|
||||
)
|
||||
.then(CommandManager.literal("ScaleAndRot")
|
||||
.then(CommandManager.argument("Scale Multiplier", FloatArgumentType.floatArg())
|
||||
.executes { context ->
|
||||
val id = StringArgumentType.getString(context, "Emitter ID")
|
||||
val scaleMul = FloatArgumentType.getFloat(context, "Scale Multiplier")
|
||||
|
||||
updateParam(id, access, ParamClasses.TransformWithVel.ScaleAndRot(scaleMul))
|
||||
successText(access, "ScaleAndRot", id, context)
|
||||
Command.SINGLE_SUCCESS
|
||||
}
|
||||
)
|
||||
)
|
||||
.then(CommandManager.literal("None")
|
||||
.executes { context ->
|
||||
val id = StringArgumentType.getString(context, "Emitter ID")
|
||||
|
||||
updateParam(id, access, ParamClasses.TransformWithVel.None)
|
||||
successText(access, "None", id, context)
|
||||
Command.SINGLE_SUCCESS
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun stringCurveArg(access: KProperty1<EmitterParams, ParamClasses.StringCurve>,
|
||||
configArg: LiteralArgumentBuilder<ServerCommandSource>,
|
||||
registryAccess: CommandRegistryAccess
|
||||
) : LiteralArgumentBuilder<ServerCommandSource>
|
||||
{
|
||||
return configArg
|
||||
.then(CommandManager.literal("Add")
|
||||
.then(CommandManager.argument("Item", ItemStackArgumentType.itemStack(registryAccess))
|
||||
.then(CommandManager.argument("Index", IntegerArgumentType.integer())
|
||||
.executes { context ->
|
||||
val index = IntegerArgumentType.getInteger(context, "Index")
|
||||
stringCurveAddArg(context, access, index)
|
||||
Command.SINGLE_SUCCESS
|
||||
}
|
||||
)
|
||||
.executes { context ->
|
||||
stringCurveAddArg(context, access, -1)
|
||||
Command.SINGLE_SUCCESS
|
||||
}
|
||||
)
|
||||
)
|
||||
.then(CommandManager.literal("Remove")
|
||||
.then(CommandManager.argument("Index", IntegerArgumentType.integer())
|
||||
.executes { context ->
|
||||
val index = IntegerArgumentType.getInteger(context, "Index")
|
||||
stringCurveRemoveArg(context, access, index)
|
||||
Command.SINGLE_SUCCESS
|
||||
}
|
||||
)
|
||||
.executes { context ->
|
||||
stringCurveRemoveArg(context, access, -1)
|
||||
Command.SINGLE_SUCCESS
|
||||
}
|
||||
)
|
||||
.then(CommandManager.literal("Curve")
|
||||
.then(curveListArg("Curve")
|
||||
.executes { context ->
|
||||
val id = StringArgumentType.getString(context, "Emitter ID")
|
||||
val curveName = StringArgumentType.getString(context, "Curve")
|
||||
|
||||
val curve = stringToCurve(curveName)
|
||||
val modelCurve = getEmitterDataById(id)?.modelCurve
|
||||
|
||||
if (curve != null && modelCurve != null) {
|
||||
modelCurve.curve = curve
|
||||
updateParam(id, access, modelCurve)
|
||||
successText(access, curveName, id, context)
|
||||
Command.SINGLE_SUCCESS
|
||||
}
|
||||
else {
|
||||
negativeFeedback("Failed to update param \"modelCurve.curve\"! The curve is most likely invalid!", context)
|
||||
Command.SINGLE_SUCCESS
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun stringCurveAddArg(context: CommandContext<ServerCommandSource>,
|
||||
access: KProperty1<EmitterParams, ParamClasses.StringCurve>,
|
||||
index: Int
|
||||
) {
|
||||
val id = StringArgumentType.getString(context, "Emitter ID")
|
||||
val item = ItemStackArgumentType.getItemStackArgument(context, "Item").item.name.string
|
||||
|
||||
val modelCurve = getEmitterDataById(id)?.modelCurve
|
||||
|
||||
if (index == -1 && modelCurve != null) {
|
||||
modelCurve.array.toMutableList().apply { add(item) }.toTypedArray()
|
||||
updateParam(id, access, modelCurve)
|
||||
}
|
||||
else if (modelCurve != null) {
|
||||
modelCurve.array.toMutableList().apply { add(index.coerceIn(0, modelCurve.array.lastIndex), item) }.toTypedArray()
|
||||
updateParam(id, access, modelCurve)
|
||||
}
|
||||
|
||||
successText(access, "++$item", id, context)
|
||||
}
|
||||
|
||||
fun stringCurveRemoveArg(context: CommandContext<ServerCommandSource>,
|
||||
access: KProperty1<EmitterParams, ParamClasses.StringCurve>,
|
||||
index: Int
|
||||
) {
|
||||
val id = StringArgumentType.getString(context, "Emitter ID")
|
||||
|
||||
val modelCurve = getEmitterDataById(id)?.modelCurve
|
||||
|
||||
if (index == -1 && modelCurve != null) {
|
||||
modelCurve.array.toMutableList().apply { removeLast() }.toTypedArray()
|
||||
updateParam(id, access, modelCurve)
|
||||
}
|
||||
else if (modelCurve != null) {
|
||||
modelCurve.array.toMutableList().apply { removeAt(index.coerceIn(0, modelCurve.array.lastIndex)) }.toTypedArray()
|
||||
updateParam(id, access, modelCurve)
|
||||
}
|
||||
|
||||
successText(access, "--item at $index", id, context)
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import com.mojang.brigadier.CommandDispatcher
|
||||
import com.mojang.brigadier.arguments.StringArgumentType
|
||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder
|
||||
import com.mojang.brigadier.context.CommandContext
|
||||
import net.minecraft.command.CommandRegistryAccess
|
||||
import net.minecraft.server.command.CommandManager
|
||||
import net.minecraft.server.command.ServerCommandSource
|
||||
import net.minecraft.text.Style
|
||||
@@ -77,7 +78,7 @@ blockCurve: Pair<Array<String>, LerpCurves>,
|
||||
|
||||
object ManageEmitters {
|
||||
|
||||
fun register(dispatcher: CommandDispatcher<ServerCommandSource>) {
|
||||
fun register(dispatcher: CommandDispatcher<ServerCommandSource>, registryAccess: CommandRegistryAccess) {
|
||||
val command = CommandManager.literal("ManageEmitters")
|
||||
.requires { source -> source.hasPermissionLevel(2) }
|
||||
|
||||
@@ -85,7 +86,7 @@ object ManageEmitters {
|
||||
command
|
||||
.then(CommandManager.literal("create").then(create()))
|
||||
.then(CommandManager.literal("remove").then(remove()))
|
||||
.then(CommandManager.literal("config").then(config()))
|
||||
.then(CommandManager.literal("config").then(config(registryAccess)))
|
||||
.then(CommandManager.literal("list")
|
||||
.executes { context ->
|
||||
val emitterIdList = idRegister.keys.sorted().joinToString(" ")
|
||||
@@ -173,10 +174,10 @@ object ManageEmitters {
|
||||
}
|
||||
}
|
||||
|
||||
private fun config() : RequiredArgumentBuilder<ServerCommandSource, String> {
|
||||
private fun config(registryAccess: CommandRegistryAccess) : RequiredArgumentBuilder<ServerCommandSource, String> {
|
||||
var emitterList = emitterListArg("Emitter ID")
|
||||
|
||||
emitterList = listConfigArgs(dataClassToArray(EmitterParams::class), emitterList) as RequiredArgumentBuilder<ServerCommandSource, String>
|
||||
emitterList = listConfigArgs(dataClassToArray(EmitterParams::class), emitterList, registryAccess) as RequiredArgumentBuilder<ServerCommandSource, String>
|
||||
|
||||
return emitterList
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ data class EmitterParams (
|
||||
var offsetCurve: ParamClasses.LerpVal,
|
||||
var rotVelCurve: ParamClasses.LerpVal,
|
||||
var scaleCurve: ParamClasses.LerpVal,
|
||||
var modelCurve: Pair<Array<String>, LerpCurves>,
|
||||
var modelCurve: ParamClasses.StringCurve,
|
||||
)
|
||||
{
|
||||
companion object Presets {
|
||||
@@ -55,8 +55,8 @@ data class EmitterParams (
|
||||
minVel = 0.0f,
|
||||
offsetCurve = ParamClasses.LerpVal.NoLerpVec3f,
|
||||
rotVelCurve = ParamClasses.LerpVal.LerpUniform(1.0f, 0.0f, LerpCurves.Sqrt),
|
||||
scaleCurve = ParamClasses.LerpVal.LerpUniform(1.0f, 2.5f, LerpCurves.Constant),
|
||||
modelCurve = Pair(
|
||||
scaleCurve = ParamClasses.LerpVal.LerpUniform(1.0f, 2.5f, LerpCurves.Linear),
|
||||
modelCurve = ParamClasses.StringCurve(
|
||||
arrayOf(
|
||||
"shroomlight",
|
||||
"orange_concrete",
|
||||
@@ -88,9 +88,9 @@ data class EmitterParams (
|
||||
drag = 0.075f,
|
||||
minVel = 0.0f,
|
||||
offsetCurve = ParamClasses.LerpVal.NoLerpVec3f,
|
||||
rotVelCurve = ParamClasses.LerpVal.LerpUniform(1.0f, 0.0f, LerpCurves.Constant),
|
||||
scaleCurve = ParamClasses.LerpVal.LerpUniform(1.0f, 1.0f, LerpCurves.Constant),
|
||||
modelCurve = Pair(
|
||||
rotVelCurve = ParamClasses.LerpVal.LerpUniform(1.0f, 0.0f, LerpCurves.Linear),
|
||||
scaleCurve = ParamClasses.LerpVal.LerpUniform(1.0f, 1.0f, LerpCurves.Linear),
|
||||
modelCurve = ParamClasses.StringCurve(
|
||||
arrayOf(
|
||||
"shroomlight",
|
||||
"orange_concrete",
|
||||
@@ -99,7 +99,7 @@ data class EmitterParams (
|
||||
"gray_stained_glass",
|
||||
"light_gray_stained_glass"
|
||||
),
|
||||
LerpCurves.Constant
|
||||
LerpCurves.Linear
|
||||
)
|
||||
)
|
||||
val STRESS_TEST = EmitterParams(
|
||||
@@ -126,9 +126,9 @@ data class EmitterParams (
|
||||
drag = 0.075f,
|
||||
minVel = 0.0f,
|
||||
offsetCurve = ParamClasses.LerpVal.NoLerpVec3f,
|
||||
rotVelCurve = ParamClasses.LerpVal.LerpUniform(1.0f, 0.0f, LerpCurves.Constant),
|
||||
scaleCurve = ParamClasses.LerpVal.LerpUniform(1.0f, 1.5f, LerpCurves.Constant),
|
||||
modelCurve = Pair(
|
||||
rotVelCurve = ParamClasses.LerpVal.LerpUniform(1.0f, 0.0f, LerpCurves.Linear),
|
||||
scaleCurve = ParamClasses.LerpVal.LerpUniform(1.0f, 1.5f, LerpCurves.Linear),
|
||||
modelCurve = ParamClasses.StringCurve(
|
||||
arrayOf(
|
||||
"shroomlight",
|
||||
"orange_concrete",
|
||||
@@ -137,7 +137,7 @@ data class EmitterParams (
|
||||
"gray_stained_glass",
|
||||
"light_gray_stained_glass"
|
||||
),
|
||||
LerpCurves.Constant
|
||||
LerpCurves.Linear
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.bytedice.bde_particles.particles
|
||||
|
||||
import com.bytedice.bde_particles.LerpCurves
|
||||
import com.bytedice.bde_particles.lerpArray
|
||||
import com.bytedice.bde_particles.randomFloatBetween
|
||||
import com.bytedice.bde_particles.randomIntBetween
|
||||
import org.joml.Vector3f
|
||||
@@ -60,9 +61,9 @@ class ParamClasses {
|
||||
private val curve: LerpCurves,
|
||||
) : LerpVal() {
|
||||
fun lerp(t: Float): Vector3f {
|
||||
val x = com.bytedice.bde_particles.lerp(fromX, toX, t) * curve.function(t)
|
||||
val y = com.bytedice.bde_particles.lerp(fromY, toY, t) * curve.function(t)
|
||||
val z = com.bytedice.bde_particles.lerp(fromZ, toZ, t) * curve.function(t)
|
||||
val x = com.bytedice.bde_particles.lerp(fromX, toX, curve.function(t))
|
||||
val y = com.bytedice.bde_particles.lerp(fromY, toY, curve.function(t))
|
||||
val z = com.bytedice.bde_particles.lerp(fromZ, toZ, curve.function(t))
|
||||
return Vector3f(x, y, z)
|
||||
}
|
||||
}
|
||||
@@ -78,9 +79,9 @@ class ParamClasses {
|
||||
private val curveZ: LerpCurves
|
||||
) : LerpVal() {
|
||||
fun lerp(t: Float): Vector3f {
|
||||
val x = com.bytedice.bde_particles.lerp(fromX, toX, t) * curveX.function(t)
|
||||
val y = com.bytedice.bde_particles.lerp(fromY, toY, t) * curveY.function(t)
|
||||
val z = com.bytedice.bde_particles.lerp(fromZ, toZ, t) * curveZ.function(t)
|
||||
val x = com.bytedice.bde_particles.lerp(fromX, toX, curveX.function(t))
|
||||
val y = com.bytedice.bde_particles.lerp(fromY, toY, curveY.function(t))
|
||||
val z = com.bytedice.bde_particles.lerp(fromZ, toZ, curveZ.function(t))
|
||||
return Vector3f(x, y, z)
|
||||
}
|
||||
}
|
||||
@@ -89,8 +90,8 @@ class ParamClasses {
|
||||
private val to: Float,
|
||||
private val curve: LerpCurves,
|
||||
) : LerpVal() {
|
||||
fun lerp(t: Float): Float {
|
||||
return com.bytedice.bde_particles.lerp(from, to, t) * curve.function(t)
|
||||
fun lerp(t: Float) : Float {
|
||||
return com.bytedice.bde_particles.lerp(from, to, curve.function(t))
|
||||
}
|
||||
}
|
||||
data object NoLerpVec3f : LerpVal()
|
||||
@@ -155,4 +156,10 @@ class ParamClasses {
|
||||
}
|
||||
data object None : TransformWithVel()
|
||||
}
|
||||
class StringCurve (
|
||||
var array: Array<String>,
|
||||
var curve: LerpCurves
|
||||
) {
|
||||
fun lerp(t: Float) : String { return lerpArray(array as Array<Any>, t, curve) as String }
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ class Particle(
|
||||
val properties = DisplayEntityProperties(
|
||||
pos = entityPos,
|
||||
rot = entityRot,
|
||||
model = lerpArray(emitterParams.modelCurve.first as Array<Any>, 0.0f, emitterParams.modelCurve.second) as String,
|
||||
model = emitterParams.modelCurve.lerp(0.0f),
|
||||
translation = newPos.add(pos),
|
||||
leftRotation = quatRot,
|
||||
scale = Vector3f(scale).mul(emitterParams.scaleCurve.lerpToVector3f(0.0f)),
|
||||
@@ -130,7 +130,7 @@ class Particle(
|
||||
private fun calcNewProperties() : DisplayEntityProperties {
|
||||
val timeAliveClamped = (timeAlive.toFloat() / lifeTime.toFloat()).coerceIn(0.0f, 1.0f)
|
||||
|
||||
val newModel = lerpArray(emitterParams.modelCurve.first as Array<Any>, timeAliveClamped, emitterParams.modelCurve.second) as String
|
||||
val newModel = emitterParams.modelCurve.lerp(timeAliveClamped)
|
||||
val (newVel, newPos) = calcPos()
|
||||
val newOriginOffset = Vector3f(originOffset.mul(emitterParams.offsetCurve.lerpToVector3f(timeAliveClamped)))
|
||||
|
||||
|
||||
@@ -98,10 +98,17 @@ class ParticleEmitter(
|
||||
val loopDelay = (params.spawnDuration as ParamClasses.Duration.MultiBurst).loopDelay
|
||||
val loopCount = (params.spawnDuration as ParamClasses.Duration.MultiBurst).loopCount
|
||||
|
||||
if (timeAlive >= loopDur && timesLooped >= loopCount) { isTicking = false; return }
|
||||
if (timeAlive >= loopDur && timesLooped + 1 >= loopCount) { isTicking = false; return }
|
||||
|
||||
if (timePaused >= loopDelay) { isPaused = false; timePaused = 0 }
|
||||
if (timeAlive >= loopDur && loopDelay > 0) { isPaused = true; timeAlive = 0 }
|
||||
if (timePaused >= loopDelay) {
|
||||
isPaused = false
|
||||
timePaused = 0
|
||||
timesLooped += 1
|
||||
}
|
||||
if (timeAlive >= loopDur && loopDelay > 0) {
|
||||
isPaused = true
|
||||
timeAlive = 0
|
||||
}
|
||||
|
||||
if (!isPaused) { timeAlive += 1 }
|
||||
else { timePaused += 1 }
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.bytedice.bde_particles.particles
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
|
||||
@@ -80,7 +82,10 @@ fun updateParam(id: String, paramAccess: KProperty1<EmitterParams, *>, paramValu
|
||||
fun updateParams(params: EmitterParams, paramAccess: KProperty1<EmitterParams, Any>, paramValue: Any): Pair<EmitterParams, Boolean> {
|
||||
val newParams = params.copy()
|
||||
|
||||
if (paramAccess.returnType.classifier == paramValue::class) {
|
||||
if (paramAccess.returnType.classifier == paramValue::class
|
||||
|| (paramAccess.returnType.classifier as? KClass<*>)?.let { paramValue::class.isSubclassOf(it) } == true
|
||||
)
|
||||
{
|
||||
paramAccess as KMutableProperty1<EmitterParams, Any>
|
||||
paramAccess.set(newParams, paramValue)
|
||||
return Pair(newParams, true)
|
||||
|
||||
Reference in New Issue
Block a user