added args

This commit is contained in:
2024-12-13 20:21:43 +01:00
parent 0b17f8688c
commit 46cc808889
5 changed files with 371 additions and 44 deletions
@@ -2,6 +2,7 @@ package com.bytedice.bde_particles.client
import com.bytedice.bde_particles.commands.GiveEmitterTool import com.bytedice.bde_particles.commands.GiveEmitterTool
import com.bytedice.bde_particles.commands.KillAllEmitters import com.bytedice.bde_particles.commands.KillAllEmitters
import com.bytedice.bde_particles.commands.ManageEmitters
import com.bytedice.bde_particles.commands.SpawnEmitter import com.bytedice.bde_particles.commands.SpawnEmitter
//import com.bytedice.bde_particles.commands.ManageEmitters //import com.bytedice.bde_particles.commands.ManageEmitters
import com.bytedice.bde_particles.init import com.bytedice.bde_particles.init
@@ -39,7 +40,7 @@ class Bde_particlesClient : ClientModInitializer {
CommandRegistrationCallback.EVENT.register { dispatcher, registryAccess, _ -> CommandRegistrationCallback.EVENT.register { dispatcher, registryAccess, _ ->
GiveEmitterTool.register(dispatcher, registryAccess) GiveEmitterTool.register(dispatcher, registryAccess)
//ManageEmitters .register(dispatcher) ManageEmitters .register(dispatcher)
KillAllEmitters.register(dispatcher) KillAllEmitters.register(dispatcher)
SpawnEmitter .register(dispatcher) SpawnEmitter .register(dispatcher)
} }
@@ -2,6 +2,7 @@ package com.bytedice.bde_particles
import com.bytedice.bde_particles.commands.GiveEmitterTool import com.bytedice.bde_particles.commands.GiveEmitterTool
import com.bytedice.bde_particles.commands.KillAllEmitters import com.bytedice.bde_particles.commands.KillAllEmitters
import com.bytedice.bde_particles.commands.ManageEmitters
import com.bytedice.bde_particles.commands.SpawnEmitter import com.bytedice.bde_particles.commands.SpawnEmitter
//import com.bytedice.bde_particles.commands.ManageEmitters //import com.bytedice.bde_particles.commands.ManageEmitters
import com.bytedice.bde_particles.items.ParticleEmitterTool import com.bytedice.bde_particles.items.ParticleEmitterTool
@@ -90,7 +91,7 @@ class Bde_particles : ModInitializer {
CommandRegistrationCallback.EVENT.register { dispatcher, registryAccess, _ -> CommandRegistrationCallback.EVENT.register { dispatcher, registryAccess, _ ->
GiveEmitterTool.register(dispatcher, registryAccess) GiveEmitterTool.register(dispatcher, registryAccess)
//ManageEmitters .register(dispatcher) ManageEmitters .register(dispatcher)
KillAllEmitters.register(dispatcher) KillAllEmitters.register(dispatcher)
SpawnEmitter .register(dispatcher) SpawnEmitter .register(dispatcher)
} }
@@ -0,0 +1,298 @@
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.positiveFeedback
import com.mojang.brigadier.Command
import com.mojang.brigadier.arguments.BoolArgumentType
import com.mojang.brigadier.arguments.FloatArgumentType
import com.mojang.brigadier.arguments.IntegerArgumentType
import com.mojang.brigadier.arguments.StringArgumentType
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.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
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, *> {
configArgs.forEach { arg ->
var configArg = CommandManager.literal(arg)
val argAccess = parseArgNameToAccess(arg)!!
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>? }
}
// Add the configArg to the root command builder
rootArg.then(configArg)
}
return rootArg
}
fun dataClassToArray(dataClass: KClass<*>): Array<String> {
return dataClass.memberProperties.map { it.name }.toTypedArray()
}
fun parseArgNameToAccess(name: String) : KProperty1<EmitterParams, *>? {
val access = EmitterParams::class.memberProperties
.firstOrNull { it.name == name }
return access
}
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 null
}
fun successText(access: KProperty1<EmitterParams, *>, value: String, id: String, context: CommandContext<ServerCommandSource>) {
positiveFeedback("Successfully updated parameter \"${access.name}\" to \"$value\" of Emitter ID \"$id\"", context)
}
fun intArg(access: KProperty1<EmitterParams, Int>) : RequiredArgumentBuilder<ServerCommandSource, Int> {
return CommandManager.argument("Int", IntegerArgumentType.integer())
.executes { context ->
val id = StringArgumentType.getString(context, "Emitter ID")
val value = IntegerArgumentType.getInteger(context, "Int")
updateParam(id, access, value)
successText(access, value.toString(), id, context)
Command.SINGLE_SUCCESS
}
}
fun floatArg(access: KProperty1<EmitterParams, Float>) : RequiredArgumentBuilder<ServerCommandSource, Float> {
return CommandManager.argument("Float", FloatArgumentType.floatArg())
.executes { context ->
val id = StringArgumentType.getString(context, "Emitter ID")
val value = FloatArgumentType.getFloat(context, "Float")
updateParam(id, access, value)
successText(access, value.toString(), id, context)
Command.SINGLE_SUCCESS
}
}
fun stringArg(access: KProperty1<EmitterParams, String>) : RequiredArgumentBuilder<ServerCommandSource, String> {
return CommandManager.argument("String", StringArgumentType.string())
.executes { context ->
val id = StringArgumentType.getString(context, "Emitter ID")
val value = StringArgumentType.getString(context, "String")
updateParam(id, access, value)
successText(access, value.toString(), id, context)
Command.SINGLE_SUCCESS
}
}
fun durArg(access: KProperty1<EmitterParams, ParamClasses.Duration>,
configArg: LiteralArgumentBuilder<ServerCommandSource>
) : LiteralArgumentBuilder<ServerCommandSource>
{
return configArg
.then(CommandManager.literal("SingleBurst")
.then(CommandManager.argument("loopDur", IntegerArgumentType.integer())
.executes { context -> durArgExec(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 }
)
)
)
)
.then(CommandManager.literal("InfiniteLoop")
.then(CommandManager.argument("loopDur", IntegerArgumentType.integer())
.then(CommandManager.argument("loopDelay", IntegerArgumentType.integer())
.executes { context -> durArgExec(access, context); Command.SINGLE_SUCCESS }
)
)
)
}
fun durArgExec(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 -> {
updateParam(id, access, ParamClasses.Duration.SingleBurst(loopDur))
}
is ParamClasses.Duration.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 -> {
val loopDelay = IntegerArgumentType.getInteger(context, "loopDelay")
updateParam(id, access, ParamClasses.Duration.InfiniteLoop(loopDur, loopDelay))
}
}
successText(access, access.get(eParams)::class.simpleName ?: "UNKNOWN", id, context)
}
fun vec3fArg(access: KProperty1<EmitterParams, Vector3f>) : RequiredArgumentBuilder<ServerCommandSource, Float> {
return CommandManager.argument("X", FloatArgumentType.floatArg())
.then(CommandManager.argument("Y", FloatArgumentType.floatArg())
.then(CommandManager.argument("Z", FloatArgumentType.floatArg())
.executes { context ->
val id = StringArgumentType.getString(context, "Emitter ID")
val valueX = FloatArgumentType.getFloat(context, "X")
val valueY = FloatArgumentType.getFloat(context, "Y")
val valueZ = FloatArgumentType.getFloat(context, "Z")
updateParam(id, access, Vector3f(valueX, valueY, valueX))
successText(access, "[$valueX, $valueY, $valueZ]", id, context)
Command.SINGLE_SUCCESS
}
)
)
}
fun pairIntArg(access: KProperty1<EmitterParams, ParamClasses.PairInt>) : RequiredArgumentBuilder<ServerCommandSource, Int> {
return CommandManager.argument("First Int", IntegerArgumentType.integer())
.then(CommandManager.argument("Second 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")
updateParam(id, access, ParamClasses.PairInt(valueX, valueY))
successText(access, "[$valueX, $valueY]", id, context)
Command.SINGLE_SUCCESS
}
)
}
fun shapeArg(access: KProperty1<EmitterParams, SpawningShape>,
configArg: LiteralArgumentBuilder<ServerCommandSource>
) : LiteralArgumentBuilder<ServerCommandSource>
{
return configArg
.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 }
)
)
)
.then(CommandManager.literal("Rect")
.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 }
)
)
)
)
.then(CommandManager.literal("Cube")
.then(CommandManager.argument("X", FloatArgumentType.floatArg())
.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 }
)
)
)
)
)
.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 }
)
)
)
.then(CommandManager.literal("Point")
.executes { context -> shapeArgExec(access, context); Command.SINGLE_SUCCESS }
)
}
fun shapeArgExec(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 -> {
val radius = FloatArgumentType.getFloat(context, "Radius")
val onEdge = BoolArgumentType.getBool(context, "Spawn On Edge")
updateParam(id, access, SpawningShape.Circle(radius, onEdge))
}
is SpawningShape.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 -> {
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 -> {
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 -> {
updateParam(id, access, SpawningShape.Point)
}
}
successText(access, access.get(eParams)::class.simpleName ?: "UNKNOWN", id, context)
}
@@ -8,6 +8,7 @@ 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
import com.mojang.brigadier.builder.RequiredArgumentBuilder import com.mojang.brigadier.builder.RequiredArgumentBuilder
import com.mojang.brigadier.context.CommandContext
import net.minecraft.server.command.CommandManager import net.minecraft.server.command.CommandManager
import net.minecraft.server.command.ServerCommandSource import net.minecraft.server.command.ServerCommandSource
import net.minecraft.text.Style import net.minecraft.text.Style
@@ -84,12 +85,12 @@ object ManageEmitters {
command command
.then(CommandManager.literal("create").then(create())) .then(CommandManager.literal("create").then(create()))
.then(CommandManager.literal("remove").then(remove())) .then(CommandManager.literal("remove").then(remove()))
.then(CommandManager.literal("config")) .then(CommandManager.literal("config").then(config()))
.then(CommandManager.literal("list") .then(CommandManager.literal("list")
.executes { context -> .executes { context ->
val emitterIdList = idRegister.keys.sorted().joinToString(" ") val emitterIdList = idRegister.keys.sorted().joinToString(" ")
val feedback = Text.literal("List of all registered Emitter IDs $emitterIdList") val feedback = Text.literal("List of all registered Emitter IDs:\n$emitterIdList")
.setStyle(Style.EMPTY.withColor(Color(0, 200, 0).rgb)) .setStyle(Style.EMPTY.withColor(Color(0, 200, 0).rgb))
context.source.sendFeedback({ feedback }, false) context.source.sendFeedback({ feedback }, false)
@@ -107,6 +108,19 @@ object ManageEmitters {
val newEmitterId = StringArgumentType.getString(context, "New Emitter ID") val newEmitterId = StringArgumentType.getString(context, "New Emitter ID")
val presetEmitterId = StringArgumentType.getString(context, "Preset Emitter ID") val presetEmitterId = StringArgumentType.getString(context, "Preset Emitter ID")
createExec(context, newEmitterId, presetEmitterId)
Command.SINGLE_SUCCESS
}
)
.executes { context ->
val newEmitterId = StringArgumentType.getString(context, "New Emitter ID")
createExec(context, newEmitterId, "")
Command.SINGLE_SUCCESS
}
}
private fun createExec(context: CommandContext<ServerCommandSource>, newEmitterId: String, presetEmitterId: String) {
val params = getEmitterDataById(presetEmitterId) val params = getEmitterDataById(presetEmitterId)
val usedDefault = params == null val usedDefault = params == null
@@ -133,10 +147,6 @@ object ManageEmitters {
context context
) )
} }
Command.SINGLE_SUCCESS
}
)
} }
private fun remove() : RequiredArgumentBuilder<ServerCommandSource, String> { private fun remove() : RequiredArgumentBuilder<ServerCommandSource, String> {
@@ -163,12 +173,13 @@ object ManageEmitters {
} }
} }
/*private fun config() : RequiredArgumentBuilder<ServerCommandSource, String> { private fun config() : RequiredArgumentBuilder<ServerCommandSource, String> {
return emitterList("Emitter ID") var emitterList = emitterListArg("Emitter ID")
.then(
) emitterList = listConfigArgs(dataClassToArray(EmitterParams::class), emitterList) as RequiredArgumentBuilder<ServerCommandSource, String>
}*/
return emitterList
}
// I am not going to torture myself by converting this to a json. // I am not going to torture myself by converting this to a json.
/* /*
@@ -1,5 +1,10 @@
package com.bytedice.bde_particles.particles package com.bytedice.bde_particles.particles
import kotlin.reflect.KMutableProperty1
import kotlin.reflect.KProperty1
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.isAccessible
val idRegister: MutableMap<String, EmitterParams> = mutableMapOf() val idRegister: MutableMap<String, EmitterParams> = mutableMapOf()
val forbiddenIds = arrayOf("", "NULL") val forbiddenIds = arrayOf("", "NULL")
@@ -37,10 +42,17 @@ fun addToRegister(id: String, params: EmitterParams) : Pair<String, Boolean> {
fun removeFromRegister(id: String) : Boolean { fun removeFromRegister(id: String) : Boolean {
if (id in forbiddenIds) { return false } if (!idRegister.containsKey(id)) {
if (!idRegister.containsKey(id)) { return false } println("BPS - Failed to remove Emitter ID \"$id\" as it doesn't exist!")
return false
}
if (id in forbiddenIds) {
println("BPS - Failed to remove Emitter ID \"$id\" as it's been reserved for system use!")
return false
}
idRegister.remove(id) idRegister.remove(id)
println("BPS - Removed Emitter ID \"$id\" from register.")
return true return true
} }
@@ -55,22 +67,26 @@ fun updateRegistered(id: String, newParams: EmitterParams) {
} }
fun updateParam(id: String, paramName: String, paramValue: Any) : Boolean { fun updateParam(id: String, paramAccess: KProperty1<EmitterParams, *>, paramValue: Any) : Boolean {
val emitter = getEmitterDataById(id) ?: return false val emitter = getEmitterDataById(id) ?: return false
val updatedValues = updateParams(emitter, paramName, paramValue) val updatedValues = updateParams(emitter, paramAccess as KProperty1<EmitterParams, Any>, paramValue)
updateRegistered(id, updatedValues.first)
return updatedValues.second return updatedValues.second
} }
fun updateParams(params: EmitterParams, paramName: String, paramValue: Any) : Pair<EmitterParams, Boolean> { // TODO: map to new params fun updateParams(params: EmitterParams, paramAccess: KProperty1<EmitterParams, Any>, paramValue: Any): Pair<EmitterParams, Boolean> {
val newParams = params.copy() val newParams = params.copy()
when (paramName) { if (paramAccess.returnType.classifier == paramValue::class) {
"maxCount" -> newParams.maxCount = paramValue as Int paramAccess as KMutableProperty1<EmitterParams, Any>
paramAccess.set(newParams, paramValue)
return Pair(newParams, true)
} }
return Pair(newParams, true) return Pair(params, false)
} }