diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 85746ba..e16dfdf 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -14,9 +14,23 @@ version = versionVar dependencies { compileOnly("org.spigotmc:spigot-api:1.20.6-R0.1-SNAPSHOT") implementation(project(":common")) + implementation(project(":v1_13")) + implementation(project(":v1_13_1")) + implementation(project(":v1_13_2")) + implementation(project(":v1_14_1")) + implementation(project(":v1_14_2")) + implementation(project(":v1_14_3")) + implementation(project(":v1_14_4")) + implementation(project(":v1_15")) + implementation(project(":v1_15_1")) + implementation(project(":v1_15_2")) + implementation(project(":v1_16_1")) + implementation(project(":v1_16_2")) + implementation(project(":v1_16_3")) + implementation(project(":v1_16_4")) implementation(project(":v1_16_5")) implementation(project(":v1_17")) - implementation(project(":v1_17_1")) + implementation(project(":v1_17_1", "reobf")) implementation(project(":v1_18_1")) implementation(project(":v1_18_2")) implementation(project(":v1_19_2")) diff --git a/api/src/main/kotlin/com/undefined/stellar/manager/CommandManager.kt b/api/src/main/kotlin/com/undefined/stellar/manager/CommandManager.kt index 1d1f875..a3e417c 100644 --- a/api/src/main/kotlin/com/undefined/stellar/manager/CommandManager.kt +++ b/api/src/main/kotlin/com/undefined/stellar/manager/CommandManager.kt @@ -10,6 +10,22 @@ import kotlin.reflect.KClass @ApiStatus.Internal object CommandManager { val registrars: Map> = mapOf( + "1.13" to com.undefined.stellar.v1_13.CommandRegistrar::class, + "1.13.1" to com.undefined.stellar.v1_13_1.CommandRegistrar::class, + "1.13.2" to com.undefined.stellar.v1_13_2.CommandRegistrar::class, + "1.14" to com.undefined.stellar.v1_14_1.CommandRegistrar::class, + "1.14.1" to com.undefined.stellar.v1_14_1.CommandRegistrar::class, + "1.14.2" to com.undefined.stellar.v1_14_2.CommandRegistrar::class, + "1.14.3" to com.undefined.stellar.v1_14_3.CommandRegistrar::class, + "1.14.4" to com.undefined.stellar.v1_14_4.CommandRegistrar::class, + "1.15" to com.undefined.stellar.v1_15.CommandRegistrar::class, + "1.15.1" to com.undefined.stellar.v1_15_1.CommandRegistrar::class, + "1.15.2" to com.undefined.stellar.v1_15_2.CommandRegistrar::class, + "1.16" to com.undefined.stellar.v1_16_1.CommandRegistrar::class, + "1.16.1" to com.undefined.stellar.v1_16_1.CommandRegistrar::class, + "1.16.2" to com.undefined.stellar.v1_16_2.CommandRegistrar::class, + "1.16.3" to com.undefined.stellar.v1_16_3.CommandRegistrar::class, + "1.16.4" to com.undefined.stellar.v1_16_4.CommandRegistrar::class, "1.16.5" to com.undefined.stellar.v1_16_5.CommandRegistrar::class, "1.17" to com.undefined.stellar.v1_17.CommandRegistrar::class, "1.17.1" to com.undefined.stellar.v1_17_1.CommandRegistrar::class, diff --git a/build.gradle.kts b/build.gradle.kts index 4be8606..87effa7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -79,8 +79,23 @@ allprojects { dependencies { implementation(project(":api")) implementation(project(":common")) + implementation(project(":v1_13")) + implementation(project(":v1_13_1")) + implementation(project(":v1_13_2")) + implementation(project(":v1_14_1")) + implementation(project(":v1_14_2")) + implementation(project(":v1_14_3")) + implementation(project(":v1_14_4")) + implementation(project(":v1_15")) + implementation(project(":v1_15_1")) + implementation(project(":v1_15_2")) + implementation(project(":v1_16_1")) + implementation(project(":v1_16_2")) + implementation(project(":v1_16_3")) + implementation(project(":v1_16_4")) implementation(project(":v1_16_5")) implementation(project(":v1_17")) + implementation(project(":v1_17")) implementation(project(":v1_17_1:", "reobf")) implementation(project(":v1_18_1:", "reobf")) implementation(project(":v1_18_2:", "reobf")) diff --git a/common/src/main/kotlin/com/undefined/stellar/util/ReflectionUtil.kt b/common/src/main/kotlin/com/undefined/stellar/util/ReflectionUtil.kt index fd3a431..7cdb695 100644 --- a/common/src/main/kotlin/com/undefined/stellar/util/ReflectionUtil.kt +++ b/common/src/main/kotlin/com/undefined/stellar/util/ReflectionUtil.kt @@ -9,7 +9,7 @@ object ReflectionUtil { fun getPrivateField(any: Class<*>, name: String): T = any::class.java.getDeclaredField(name).apply { isAccessible = true }[this] as T - inline fun getPrivateMethod(name: String, vararg args: Any?): R = + inline fun executePrivateMethod(name: String, vararg args: Any?): R = T::class.java.getDeclaredMethod(name).apply { isAccessible = true }(null, args) as R } diff --git a/server/build.gradle.kts b/server/build.gradle.kts index e6bf101..d81ac7b 100644 --- a/server/build.gradle.kts +++ b/server/build.gradle.kts @@ -9,10 +9,24 @@ val groupIdVar = "com.undefined" val artifactIdVar = "stellar" dependencies { - compileOnly("org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT") + compileOnly("org.spigotmc:spigot-api:1.13-R0.1-SNAPSHOT") implementation(project(":api")) implementation(project(":common")) + implementation(project(":v1_13")) + implementation(project(":v1_13_1")) + implementation(project(":v1_13_2")) + implementation(project(":v1_14_1")) + implementation(project(":v1_14_2")) + implementation(project(":v1_14_3")) + implementation(project(":v1_14_4")) + implementation(project(":v1_15")) + implementation(project(":v1_15_1")) + implementation(project(":v1_15_2")) + implementation(project(":v1_16_1")) + implementation(project(":v1_16_2")) + implementation(project(":v1_16_3")) + implementation(project(":v1_16_4")) implementation(project(":v1_16_5")) implementation(project(":v1_17")) implementation(project(":v1_17_1:", "reobf")) @@ -30,7 +44,7 @@ dependencies { implementation(project(":v1_21_1:", "reobf")) implementation(project(":v1_21_3:", "reobf")) implementation(project(":v1_21_4:", "reobf")) - compileOnly(project(":v1_16_5")) + compileOnly(project(":v1_13")) } tasks { @@ -43,11 +57,15 @@ tasks { } compileKotlin { - kotlinOptions.jvmTarget = "16" + kotlinOptions.jvmTarget = "1.8" + } + + compileJava { + options.release = 8 } runServer { - minecraftVersion("1.16.5") + minecraftVersion("1.13") jvmArgs("-Xmx2G") } } @@ -57,5 +75,5 @@ java { } kotlin { - jvmToolchain(16) + jvmToolchain(8) } \ No newline at end of file diff --git a/server/src/main/kotlin/com/undefined/stellar/Main.kt b/server/src/main/kotlin/com/undefined/stellar/Main.kt index c3cb6a4..2174336 100644 --- a/server/src/main/kotlin/com/undefined/stellar/Main.kt +++ b/server/src/main/kotlin/com/undefined/stellar/Main.kt @@ -1,16 +1,17 @@ package com.undefined.stellar +import com.undefined.stellar.data.argument.ParticleData import org.bukkit.entity.Player import org.bukkit.plugin.java.JavaPlugin class Main : JavaPlugin() { override fun onEnable() { - StellarCommand("set-time") - .addTimeArgument("time") + StellarCommand("spawn-particle") + .addParticleArgument("particle") .addExecution { - val time = getArgument("time") - sender.world.time = time + val data = getArgument>("particle") + sender.spawnParticle(data.particle, sender.eyeLocation, 10, 1.0, 1.0, 1.0, data.options) } .register(this) } diff --git a/server/src/main/resources/plugin.yml b/server/src/main/resources/plugin.yml index 44f031a..8fbcb75 100644 --- a/server/src/main/resources/plugin.yml +++ b/server/src/main/resources/plugin.yml @@ -1,4 +1,4 @@ name: Stellar version: '${version}' main: com.undefined.stellar.Main -api-version: '1.16' \ No newline at end of file +api-version: '1.13' \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 4e79812..9485035 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,2 +1,37 @@ rootProject.name = "stellar" -include("server", "api", "common", "v1_16_5", "v1_17", "v1_17_1", "v1_18_1", "v1_18_2", "v1_19_2", "v1_19_3", "v1_19_4", "v1_20", "v1_20_1", "v1_20_2", "v1_20_4", "v1_20_6", "v1_21", "v1_21_1", "v1_21_3", "v1_21_4") \ No newline at end of file +include( + "server", + "api", + "common", + "v1_13", + "v1_13_1", + "v1_13_2", + "v1_14_1", + "v1_14_2", + "v1_14_3", + "v1_14_4", + "v1_15", + "v1_15_1", + "v1_15_2", + "v1_16_1", + "v1_16_2", + "v1_16_3", + "v1_16_4", + "v1_16_5", + "v1_17", + "v1_17_1", + "v1_18_1", + "v1_18_2", + "v1_19_2", + "v1_19_3", + "v1_19_4", + "v1_20", + "v1_20_1", + "v1_20_2", + "v1_20_4", + "v1_20_6", + "v1_21", + "v1_21_1", + "v1_21_3", + "v1_21_4" +) \ No newline at end of file diff --git a/v1_13/build.gradle.kts b/v1_13/build.gradle.kts new file mode 100644 index 0000000..63f2378 --- /dev/null +++ b/v1_13/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + kotlin("jvm") version "1.9.22" +} + +repositories { + mavenLocal() +} + +dependencies { + compileOnly("org.spigotmc:spigot:1.13-R0.1-SNAPSHOT") + compileOnly(project(":common")) +} + +tasks { + compileKotlin { + kotlinOptions.jvmTarget = "1.8" + } + compileJava { + options.release.set(8) + } +} + +java { + disableAutoTargetJvm() +} + +kotlin { + jvmToolchain(21) +} \ No newline at end of file diff --git a/v1_13/src/main/kotlin/com/undefined/stellar/v1_13/ArgumentHelper.kt b/v1_13/src/main/kotlin/com/undefined/stellar/v1_13/ArgumentHelper.kt new file mode 100644 index 0000000..0e3a537 --- /dev/null +++ b/v1_13/src/main/kotlin/com/undefined/stellar/v1_13/ArgumentHelper.kt @@ -0,0 +1,373 @@ +package com.undefined.stellar.v1_13 + +import com.mojang.brigadier.arguments.* +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 com.mojang.brigadier.context.ParsedArgument +import com.mojang.brigadier.context.StringRange +import com.mojang.brigadier.exceptions.CommandSyntaxException +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.block.BlockDataArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.argument.types.custom.ListArgument +import com.undefined.stellar.argument.types.entity.EntityDisplayType +import com.undefined.stellar.argument.types.item.ItemSlotArgument +import com.undefined.stellar.argument.types.item.ItemSlotsArgument +import com.undefined.stellar.argument.types.math.AxisArgument +import com.undefined.stellar.argument.types.misc.NamespacedKeyArgument +import com.undefined.stellar.argument.types.misc.UUIDArgument +import com.undefined.stellar.argument.types.player.GameModeArgument +import com.undefined.stellar.argument.types.primitive.* +import com.undefined.stellar.argument.types.registry.* +import com.undefined.stellar.argument.types.scoreboard.DisplaySlotArgument +import com.undefined.stellar.argument.types.scoreboard.ScoreHolderType +import com.undefined.stellar.argument.types.structure.LootTableArgument +import com.undefined.stellar.argument.types.structure.MirrorArgument +import com.undefined.stellar.argument.types.structure.StructureRotationArgument +import com.undefined.stellar.argument.types.world.HeightMapArgument +import com.undefined.stellar.argument.types.world.LocationArgument +import com.undefined.stellar.argument.types.world.LocationType +import com.undefined.stellar.data.argument.Anchor +import com.undefined.stellar.data.argument.Operation +import com.undefined.stellar.data.argument.ParticleData +import com.undefined.stellar.exception.ArgumentVersionMismatchException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import com.undefined.stellar.exception.UnsupportedArgumentException +import com.undefined.stellar.util.NMSVersion +import com.undefined.stellar.util.ReflectionUtil +import com.undefined.stellar.util.executePrivateMethod +import net.kyori.adventure.text.format.Style +import net.kyori.adventure.text.format.TextColor +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.minecraft.server.v1_13_R1.* +import org.bukkit.* +import org.bukkit.Particle +import org.bukkit.World +import org.bukkit.block.Block +import org.bukkit.block.data.BlockData +import org.bukkit.craftbukkit.v1_13_R1.block.data.CraftBlockData +import org.bukkit.craftbukkit.v1_13_R1.CraftParticle +import org.bukkit.craftbukkit.v1_13_R1.inventory.CraftItemStack +import org.bukkit.inventory.ItemStack +import org.bukkit.scoreboard.DisplaySlot +import java.time.Duration +import java.util.* +import java.util.function.Predicate + +@Suppress("UNCHECKED_CAST", "DEPRECATION") +object ArgumentHelper { + + fun getLiteralArguments(argument: AbstractStellarArgument<*>): List> { + val arguments: MutableList> = mutableListOf() + for (name in argument.aliases + argument.name) + arguments.add(LiteralArgumentBuilder.literal(name)) + return arguments + } + + fun getRequiredArgumentBuilder(argument: AbstractStellarArgument<*>): RequiredArgumentBuilder = + RequiredArgumentBuilder.argument(argument.name, getArgumentType(argument)) + + private fun > getArgumentType(argument: T): ArgumentType<*> = + when (argument) { + is ListArgument<*> -> getArgumentType(argument.type) + is CustomArgument<*> -> getArgumentType(argument.type) + is StringArgument -> brigadier(argument.type) + is PhraseArgument -> brigadier(StringType.PHRASE) + is IntegerArgument -> IntegerArgumentType.integer(argument.min, argument.max) + is LongArgument -> throwArgumentVersionException(argument) + is FloatArgument -> FloatArgumentType.floatArg(argument.min, argument.max) + is DoubleArgument -> DoubleArgumentType.doubleArg(argument.min, argument.max) + is BooleanArgument -> BoolArgumentType.bool() + is com.undefined.stellar.argument.types.entity.EntityArgument -> brigadier(argument.type) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a() + is LocationArgument -> when (argument.type) { + LocationType.LOCATION_3D -> ArgumentPosition.a() + LocationType.LOCATION_2D -> throwArgumentVersionException(argument) + LocationType.PRECISE_LOCATION_2D -> ArgumentVec3.a() + LocationType.PRECISE_LOCATION_3D -> ArgumentVec2.a() + } + is BlockDataArgument -> ArgumentTile.a() + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> ArgumentBlockPredicate.a() + is com.undefined.stellar.argument.types.item.ItemArgument -> ArgumentItemStack.a() + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> ArgumentItemPredicate.a() + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a() + is com.undefined.stellar.argument.types.text.ComponentArgument -> ArgumentChatComponent.a() + is com.undefined.stellar.argument.types.text.StyleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.text.MessageArgument -> ArgumentChat.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> ArgumentScoreboardObjective.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a() + is com.undefined.stellar.argument.types.math.OperationArgument -> ArgumentMathOperation.a() + is com.undefined.stellar.argument.types.world.ParticleArgument -> ArgumentParticle.a() + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> ArgumentRotation.a() + is DisplaySlotArgument -> ArgumentScoreboardSlot.a() + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a() + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b() + } + is AxisArgument -> ArgumentRotationAxis.a() + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> ArgumentScoreboardTeam.a() + is ItemSlotArgument -> ArgumentInventorySlot.a() + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> ArgumentMinecraftKeyRegistered.a() + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> ArgumentAnchor.a() + is com.undefined.stellar.argument.types.math.RangeArgument -> ReflectionUtil.executePrivateMethod, ArgumentCriterionValue<*>>("a") + is com.undefined.stellar.argument.types.world.DimensionArgument -> throwArgumentVersionException(argument) + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> throwArgumentVersionException(argument) + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> throwArgumentVersionException(argument) + is GameEventArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> ArgumentMinecraftKeyRegistered.a() + is VillagerTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> throwArgumentVersionException(argument) + is AttributeArgument -> ArgumentMinecraftKeyRegistered.a() + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> ArgumentMinecraftKeyRegistered.a() + else -> throw UnsupportedArgumentException(argument) + } + + fun > getParsedArgument(context: CommandContext, argument: T): Any? { + return when (argument) { + is LiteralStellarArgument -> throw LiteralArgumentMismatchException() + is CustomArgument<*> -> argument.parse(CommandContextAdapter.getStellarCommandContext(context)) + is StringArgument -> StringArgumentType.getString(context, argument.name) + is IntegerArgument -> IntegerArgumentType.getInteger(context, argument.name) + is FloatArgument -> FloatArgumentType.getFloat(context, argument.name) + is DoubleArgument -> DoubleArgumentType.getDouble(context, argument.name) + is BooleanArgument -> BoolArgumentType.getBool(context, argument.name) + is ListArgument<*> -> argument.parse(getParsedArgument(context, argument)) + is com.undefined.stellar.argument.types.entity.EntityArgument -> ArgumentEntity.b(context, argument.name) + .map { it.bukkitEntity }.toMutableList() + .addAll(listOf(ArgumentEntity.a(context, argument.name).bukkitEntity)) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a(context, argument.name) + is LocationArgument -> getLocation(context, argument) + is BlockDataArgument -> CraftBlockData.fromData(ArgumentTile.a(context, argument.name).a()) + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> Predicate { block: Block -> + ArgumentBlockPredicate.a(context, argument.name).test(ShapeDetectorBlock( + context.source.world, + BlockPosition(block.x, block.y, block.z), true + )) + } + is com.undefined.stellar.argument.types.item.ItemArgument -> CraftItemStack.asBukkitCopy( + ArgumentItemStack.a(context, argument.name).a(1, false) + ) + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> Predicate { item: ItemStack -> + ArgumentItemPredicate.a(context, argument.name).test(CraftItemStack.asNMSCopy(item)) + } + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a( + context, + argument.name + ).executePrivateMethod("e").let { Style.style(TextColor.color(it)) } + is com.undefined.stellar.argument.types.text.ComponentArgument -> GsonComponentSerializer.gson() + .deserialize(IChatBaseComponent.ChatSerializer.a( + ArgumentChatComponent.a(context, argument.name) + )) + is com.undefined.stellar.argument.types.text.StyleArgument -> GsonComponentSerializer.gson().deserialize( + getArgumentInput(context, argument.name) ?: return null + ).style() + is com.undefined.stellar.argument.types.text.MessageArgument -> GsonComponentSerializer.gson().deserialize( + IChatBaseComponent.ChatSerializer.a(ArgumentChat.a(context, argument.name)) + ) + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getObjective( + ArgumentScoreboardObjective.a(context, argument.name).name + ) + + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a( + context, + argument.name + ).name + is com.undefined.stellar.argument.types.math.OperationArgument -> Operation.getOperation( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.world.ParticleArgument -> { + val particleOptions = ArgumentParticle.a(context, argument.name) + getParticleData(CraftParticle.toBukkit(particleOptions.b()), particleOptions) + } + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> { + val rotation = ArgumentRotation.a(context, argument.name).a(context.source) + Location(context.source.world.world, rotation.x, rotation.y, rotation.z) + } + is DisplaySlotArgument -> getBukkitDisplaySlot(ArgumentScoreboardSlot.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a(context, argument.name) + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b(context, argument.name) + } + is AxisArgument -> getBukkitAxis(ArgumentRotationAxis.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getTeam( + ArgumentScoreboardTeam.a(context, argument.name).name + ) + is ItemSlotArgument -> ArgumentInventorySlot.a(context, argument.name) + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> NamespacedKey( + ArgumentMinecraftKeyRegistered.c(context, argument.name).b(), + ArgumentMinecraftKeyRegistered.c(context, argument.name).key + ) + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> Anchor.getFromName( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.math.RangeArgument -> { + val range = ArgumentCriterionValue.b.a(context, argument.name) + IntRange(range.a() ?: 1, range.b() ?: 2) + } + is com.undefined.stellar.argument.types.world.DimensionArgument -> throwArgumentVersionException(argument) + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> Duration.ofSeconds(IntegerArgumentType.getInteger(context, argument.name).toLong() / 20) + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> throwArgumentVersionException(argument) + is GameEventArgument -> throwArgumentVersionException(argument) + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> throwArgumentVersionException(argument) + is VillagerTypeArgument -> throwArgumentVersionException(argument) + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> throwArgumentVersionException(argument) + is AttributeArgument -> throwArgumentVersionException(argument) + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> throwArgumentVersionException(argument) + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> throwArgumentVersionException(argument) + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> throwArgumentVersionException(argument) + else -> throw UnsupportedArgumentException(argument) + } + } + + fun getArgumentInput(context: CommandContext, name: String): String? { + val field = CommandContext::class.java.getDeclaredField("arguments") + field.isAccessible = true + val arguments: Map> = field.get(context) as Map> + val argument = arguments[name] ?: return null + val range = StringRange.between(argument.range.start, context.input.length) + return range.get(context.input) + } + + @Throws(CommandSyntaxException::class) + private fun getId( + context: CommandContext, + name: String + ): NamespacedKey { + val key = ArgumentMinecraftKeyRegistered.c(context, name) + return NamespacedKey(key.b(), key.key) + } + + private fun brigadier(type: StringType): StringArgumentType = when (type) { + StringType.WORD -> StringArgumentType.word() + StringType.QUOTABLE_PHRASE -> StringArgumentType.string() + StringType.PHRASE -> StringArgumentType.greedyString() + } + + private fun brigadier(type: EntityDisplayType): ArgumentEntity = when (type) { + EntityDisplayType.ENTITY -> ReflectionUtil.executePrivateMethod("a") + EntityDisplayType.ENTITIES -> ArgumentEntity.b() + EntityDisplayType.PLAYER -> ArgumentEntity.c() + EntityDisplayType.PLAYERS -> ArgumentEntity.d() + } + + private fun getBukkitAxis(argument: EnumSet): EnumSet = + argument.mapTo(EnumSet.noneOf(Axis::class.java)) { + when (it) { + EnumDirection.EnumAxis.X -> Axis.X + EnumDirection.EnumAxis.Y -> Axis.Y + EnumDirection.EnumAxis.Z -> Axis.Z + null -> Axis.X + } + } + + private fun getBukkitDisplaySlot(slot: Int): DisplaySlot = when (slot) { + 0 -> DisplaySlot.PLAYER_LIST + 2 -> DisplaySlot.BELOW_NAME + else -> DisplaySlot.SIDEBAR + } + + private fun getParticleData( + particle: Particle, + particleOptions: ParticleParam + ): ParticleData<*> = when (particleOptions) { + is ParticleType -> ParticleData(particle, null) + is ParticleParamBlock -> ParticleData(particle, CraftBlockData.fromData(particleOptions.executePrivateMethod("c"))) + is ParticleParamRedstone -> { + val colors = particleOptions.a().split(" ") + val red = colors[1].toFloat() + val green = colors[2].toFloat() + val blue = colors[3].toFloat() + val scale = colors[4].toFloat() + ParticleData( + particle, + Particle.DustOptions( + Color.fromRGB( + (red * 255.0f).toInt(), + (green * 255.0f).toInt(), (blue * 255.0f).toInt() + ), scale + ) + ) + } + is ParticleParamItem -> ParticleData( + particle, + CraftItemStack.asBukkitCopy(particleOptions.executePrivateMethod("c")) + ) + else -> ParticleData(particle, null) + } + + private fun getLocation(context: CommandContext, argument: LocationArgument): Location { + val world = context.source.world.world + return when (argument.type) { + LocationType.LOCATION_3D -> toLocation(world, context.getArgument(argument.name, IVectorPosition::class.java).c(context.source)) + LocationType.LOCATION_2D -> throwArgumentVersionException(argument) + LocationType.PRECISE_LOCATION_3D -> toLocation(world, ArgumentVec3.a(context, argument.name)) + LocationType.PRECISE_LOCATION_2D -> toLocation(world, ArgumentVec2.a(context, argument.name)) + } + } + + private fun toLocation(world: World, position: BlockPosition) = + Location(world, position.x.toDouble(), position.y.toDouble(), position.z.toDouble()) + private fun toLocation(world: World, vec: Vec3D) = + Location(world, vec.x, vec.y, vec.z) + private fun toLocation(world: World, vec: Vec2F) = + Location(world, vec.i.toDouble(), 0.0, vec.j.toDouble()) + + private fun throwArgumentVersionException(argument: AbstractStellarArgument<*>): Nothing = + throw ArgumentVersionMismatchException(argument, NMSVersion.version) + +} \ No newline at end of file diff --git a/v1_13/src/main/kotlin/com/undefined/stellar/v1_13/BrigadierCommandHelper.kt b/v1_13/src/main/kotlin/com/undefined/stellar/v1_13/BrigadierCommandHelper.kt new file mode 100644 index 0000000..09e3e25 --- /dev/null +++ b/v1_13/src/main/kotlin/com/undefined/stellar/v1_13/BrigadierCommandHelper.kt @@ -0,0 +1,76 @@ +package com.undefined.stellar.v1_13 + +import com.mojang.brigadier.CommandDispatcher +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.tree.LiteralCommandNode +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.data.help.CustomCommandHelpTopic +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_13_R1.CommandListenerWrapper +import net.minecraft.server.v1_13_R1.MinecraftServer +import org.bukkit.Bukkit + +@Suppress("DEPRECATION") +object BrigadierCommandHelper { + + val COMMAND_SOURCE: CommandListenerWrapper by lazy { + MinecraftServer.getServer().serverCommandListener + } + val dispatcher: CommandDispatcher by lazy { + MinecraftServer.getServer().functionData.d() + } + + fun register(command: LiteralArgumentBuilder): LiteralCommandNode? = + dispatcher.register(command) + + fun handleHelpTopic(command: AbstractStellarCommand<*>) { + Bukkit.getServer().helpMap.addTopic( + CustomCommandHelpTopic(command.name, command.description, command.helpTopic) { + val context = MinecraftServer.getServer().serverCommandListener + val requirements = command.requirements.all { it(this) } + val permissionRequirements = command.permissionRequirements.all { + if (it.permission.isEmpty()) context.hasPermission(it.level) + else context.hasPermission(it.level) && context.bukkitSender.hasPermission(it.permission) + } + requirements.and(permissionRequirements) + } + ) + } + + fun handleExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + val stellarContext = CommandContextAdapter.getStellarCommandContext(context) + + for (runnable in command.base.runnables) runnable(stellarContext) + val arguments = getArguments(command.base, context) + for (argument in arguments) for (runnable in argument.runnables) runnable(stellarContext) + for (execution in command.executions) execution(stellarContext) + } + + fun fulfillsRequirements(command: AbstractStellarCommand<*>, source: CommandListenerWrapper): Boolean { + val fulfillsExecutionRequirements = command.requirements.all { it(source.bukkitSender) } + val fulfillsPermissionRequirements = command.permissionRequirements.all { source.hasPermission(it.level) && source.bukkitSender.hasPermission(it.permission) } + return fulfillsExecutionRequirements.and(fulfillsPermissionRequirements) + } + + fun handleFailureMessageAndExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + for (execution in command.failureExecutions) execution(CommandContextAdapter.getStellarCommandContext(context)) + for (message in command.failureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + for (message in command.globalFailureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + } + + fun getArguments( + baseCommand: AbstractStellarCommand<*>, + context: CommandContext, + currentIndex: Int = 1, + listOfArguments: List> = emptyList() + ): List> { + if (listOfArguments.size == context.nodes.size - 1) return listOfArguments + for (argument in baseCommand.arguments) + if (argument.name == context.nodes.entries.first().key.name) + return getArguments(argument, context, currentIndex + 1, listOfArguments + argument) + return emptyList() + } + +} \ No newline at end of file diff --git a/v1_13/src/main/kotlin/com/undefined/stellar/v1_13/CommandAdapter.kt b/v1_13/src/main/kotlin/com/undefined/stellar/v1_13/CommandAdapter.kt new file mode 100644 index 0000000..8e08f7d --- /dev/null +++ b/v1_13/src/main/kotlin/com/undefined/stellar/v1_13/CommandAdapter.kt @@ -0,0 +1,96 @@ +package com.undefined.stellar.v1_13 + +import com.mojang.brigadier.Command +import com.mojang.brigadier.builder.ArgumentBuilder +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.primitive.PhraseArgument +import net.minecraft.server.v1_13_R1.CommandListenerWrapper + +object CommandAdapter { + + fun getBaseCommand(command: AbstractStellarCommand<*>, name: String = command.name): LiteralArgumentBuilder { + val brigadierCommand = LiteralArgumentBuilder.literal(name) + handleCommandFunctions(command, brigadierCommand) + handleArguments(command, brigadierCommand) + return brigadierCommand + } + + private fun handleCommandFunctions(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + if (command.executions.isNotEmpty() || command.executions.isNotEmpty()) + brigadierCommand.executes { context -> + BrigadierCommandHelper.handleExecutions(command, context) + 1 + } + brigadierCommand.requires { source -> + BrigadierCommandHelper.fulfillsRequirements(command, source) + } + } + + private fun handleArguments(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + for (argument in command.arguments) { + when (argument) { + is LiteralStellarArgument -> handleLiteralArgument(argument, brigadierCommand) + is PhraseArgument-> handlePhraseArgument(argument, brigadierCommand) + else -> handleRequiredArgument(argument, brigadierCommand) + } + } + } + + private fun handleLiteralArgument(argument: LiteralStellarArgument, brigadierCommand: ArgumentBuilder) { + for (argumentBuilder in ArgumentHelper.getLiteralArguments(argument)) { + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + } + + private fun handlePhraseArgument(argument: PhraseArgument, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleGreedyStringWordFunctions(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + + private fun handleGreedyStringWordFunctions(argument: PhraseArgument, argumentBuilder: RequiredArgumentBuilder) { + argumentBuilder.executes { context -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + + for (i in greedyContext.arguments.indices) { + val word = argument.words[i] ?: continue + for (runnable in word.runnables) runnable(greedyContext) + if (i == greedyContext.arguments.lastIndex) + for (execution in word.executions) execution(greedyContext) + } + Command.SINGLE_SUCCESS + } + + argumentBuilder.suggests { context, builder -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + var prevChar = ' ' + val input = ArgumentHelper.getArgumentInput(context, argument.name) ?: "" + val amountOfSpaces: Int = if (input.isEmpty()) 0 else input.count { + if (prevChar == ' ' && it == ' ') return@count false + prevChar = it + it == ' ' + } + val newBuilder = builder.createOffset(builder.input.lastIndexOf(' ') + 1) + val word = argument.words[amountOfSpaces] ?: return@suggests newBuilder.buildFuture() + for (stellarSuggestion in word.suggestions) + for (suggestion in stellarSuggestion.get(greedyContext)) + newBuilder.suggest(suggestion.text) { suggestion.tooltip } + newBuilder.buildFuture() + } + } + + private fun handleRequiredArgument(argument: AbstractStellarArgument<*>, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + +} diff --git a/v1_13/src/main/kotlin/com/undefined/stellar/v1_13/CommandContextAdapter.kt b/v1_13/src/main/kotlin/com/undefined/stellar/v1_13/CommandContextAdapter.kt new file mode 100644 index 0000000..b0fc8ae --- /dev/null +++ b/v1_13/src/main/kotlin/com/undefined/stellar/v1_13/CommandContextAdapter.kt @@ -0,0 +1,83 @@ +package com.undefined.stellar.v1_13 + +import com.mojang.brigadier.context.CommandContext +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.data.argument.CommandNode +import com.undefined.stellar.data.argument.PhraseCommandContext +import com.undefined.stellar.exception.DuplicateArgumentNameException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_13_R1.* +import org.bukkit.command.CommandSender + +object CommandContextAdapter { + + fun getStellarCommandContext(context: CommandContext): com.undefined.stellar.data.argument.CommandContext { + val input = context.input.removePrefix("/") + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes.entries.first().key.name)!! + val arguments = BrigadierCommandHelper.getArguments(baseCommand, context) + if (arguments.filter { it !is LiteralStellarArgument }.groupingBy { it.name }.eachCount().any { it.value > 1 }) throw DuplicateArgumentNameException() + val parsedArguments: CommandNode = + BrigadierCommandHelper.getArguments(baseCommand, context) + .associate, String, (com.undefined.stellar.data.argument.CommandContext) -> Any?> { argument -> + if (argument is CustomArgument) return@associate Pair(argument.name) { argument.parse(it) } + if (argument is LiteralStellarArgument) return@associate Pair(argument.name) { throw LiteralArgumentMismatchException() } + Pair(argument.name) { + ArgumentHelper.getParsedArgument(context, argument) + } + } as CommandNode + return com.undefined.stellar.data.argument.CommandContext( + parsedArguments, + context.source.bukkitSender, + input + ) + } + + fun getGreedyCommandContext(context: CommandContext): PhraseCommandContext { + val input = context.input.removePrefix("/") + val words = input.split(' ').toMutableList() + + val totalOtherArguments = context.nodes.size - 1 + for (i in (1..totalOtherArguments)) words.removeFirst() + return PhraseCommandContext( + words, + context.source.bukkitSender, + input + ) + } + + @Suppress("DEPRECATION") + fun getCommandListenerWrapper(sender: CommandSender): CommandListenerWrapper { + val overworld = MinecraftServer.getServer().getWorldServer(DimensionManager.OVERWORLD.dimensionID) + return CommandListenerWrapper( + Source(sender), + Vec3D(overworld.spawn), + Vec2F.a, + overworld, + 4, + sender.name, + ChatComponentText(sender.name), + MinecraftServer.getServer(), + null + ) + } + + private data class Source(val sender: CommandSender) : ICommandListener { + override fun sendMessage(message: IChatBaseComponent) { + this.sender.sendMessage(LegacyComponentSerializer.legacySection().serialize(asAdventure(message))) + } + override fun a(): Boolean = true + override fun b(): Boolean = true + override fun B_(): Boolean = false + override fun getBukkitSender(stack: CommandListenerWrapper): CommandSender = this.sender + } + + fun asAdventure(component: IChatBaseComponent): net.kyori.adventure.text.Component = + GsonComponentSerializer.gson().deserializeFromTree(IChatBaseComponent.ChatSerializer.b(component)) + +} \ No newline at end of file diff --git a/v1_13/src/main/kotlin/com/undefined/stellar/v1_13/CommandRegistrar.kt b/v1_13/src/main/kotlin/com/undefined/stellar/v1_13/CommandRegistrar.kt new file mode 100644 index 0000000..d6efc21 --- /dev/null +++ b/v1_13/src/main/kotlin/com/undefined/stellar/v1_13/CommandRegistrar.kt @@ -0,0 +1,38 @@ +package com.undefined.stellar.v1_13 + +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.registrar.AbstractCommandRegistrar +import com.undefined.stellar.v1_13.BrigadierCommandHelper.dispatcher +import org.bukkit.command.CommandSender +import org.bukkit.plugin.java.JavaPlugin + +object CommandRegistrar : AbstractCommandRegistrar { + + override fun register(command: AbstractStellarCommand<*>, plugin: JavaPlugin) { + BrigadierCommandHelper.handleHelpTopic(command) + for (name in command.aliases + command.name) + BrigadierCommandHelper.register(CommandAdapter.getBaseCommand(command, name)) + } + + override fun handleCommandFailure(sender: CommandSender, input: String): Boolean { + val results = dispatcher.parse(input, BrigadierCommandHelper.COMMAND_SOURCE) + val context = results.context.withSource(CommandContextAdapter.getCommandListenerWrapper(sender)).build(input) + + if (results.reader.remainingLength == 0) return false + if (context.nodes.isEmpty()) return false + + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes.entries.first().key.name)!! + val argument = BrigadierCommandHelper.getArguments(baseCommand, context).lastOrNull() + argument?.let { + BrigadierCommandHelper.handleFailureMessageAndExecutions(argument, context) + if (argument.hideDefaultFailureMessages.hide) return true + } ?: run { + BrigadierCommandHelper.handleFailureMessageAndExecutions(baseCommand, context) + if (baseCommand.hideDefaultFailureMessages.hide) return true + } + + return baseCommand.hasGlobalHiddenDefaultFailureMessages() + } + +} \ No newline at end of file diff --git a/v1_13_1/build.gradle.kts b/v1_13_1/build.gradle.kts new file mode 100644 index 0000000..4349315 --- /dev/null +++ b/v1_13_1/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + kotlin("jvm") version "1.9.22" +} + +repositories { + mavenLocal() +} + +dependencies { + compileOnly("org.spigotmc:spigot:1.13.1-R0.1-SNAPSHOT") + compileOnly(project(":common")) +} + +tasks { + compileKotlin { + kotlinOptions.jvmTarget = "1.8" + } + compileJava { + options.release.set(8) + } +} + +java { + disableAutoTargetJvm() +} + +kotlin { + jvmToolchain(21) +} \ No newline at end of file diff --git a/v1_13_1/src/main/kotlin/com/undefined/stellar/v1_13_1/ArgumentHelper.kt b/v1_13_1/src/main/kotlin/com/undefined/stellar/v1_13_1/ArgumentHelper.kt new file mode 100644 index 0000000..e326203 --- /dev/null +++ b/v1_13_1/src/main/kotlin/com/undefined/stellar/v1_13_1/ArgumentHelper.kt @@ -0,0 +1,397 @@ +package com.undefined.stellar.v1_13_1 + +import com.mojang.brigadier.arguments.* +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 com.mojang.brigadier.context.ParsedArgument +import com.mojang.brigadier.context.StringRange +import com.mojang.brigadier.exceptions.CommandSyntaxException +import com.mojang.brigadier.suggestion.SuggestionProvider +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.block.BlockDataArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.argument.types.custom.ListArgument +import com.undefined.stellar.argument.types.entity.EntityDisplayType +import com.undefined.stellar.argument.types.item.ItemSlotArgument +import com.undefined.stellar.argument.types.item.ItemSlotsArgument +import com.undefined.stellar.argument.types.math.AxisArgument +import com.undefined.stellar.argument.types.misc.NamespacedKeyArgument +import com.undefined.stellar.argument.types.misc.UUIDArgument +import com.undefined.stellar.argument.types.player.GameModeArgument +import com.undefined.stellar.argument.types.primitive.* +import com.undefined.stellar.argument.types.registry.* +import com.undefined.stellar.argument.types.scoreboard.DisplaySlotArgument +import com.undefined.stellar.argument.types.scoreboard.ScoreHolderType +import com.undefined.stellar.argument.types.structure.LootTableArgument +import com.undefined.stellar.argument.types.structure.MirrorArgument +import com.undefined.stellar.argument.types.structure.StructureRotationArgument +import com.undefined.stellar.argument.types.world.HeightMapArgument +import com.undefined.stellar.argument.types.world.LocationArgument +import com.undefined.stellar.argument.types.world.LocationType +import com.undefined.stellar.data.argument.Anchor +import com.undefined.stellar.data.argument.Operation +import com.undefined.stellar.data.argument.ParticleData +import com.undefined.stellar.exception.ArgumentVersionMismatchException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import com.undefined.stellar.exception.UnsupportedArgumentException +import com.undefined.stellar.util.NMSVersion +import com.undefined.stellar.util.ReflectionUtil +import com.undefined.stellar.util.executePrivateMethod +import net.kyori.adventure.text.format.Style +import net.kyori.adventure.text.format.TextColor +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.minecraft.server.v1_13_R2.* +import org.bukkit.* +import org.bukkit.Particle +import org.bukkit.World +import org.bukkit.block.Block +import org.bukkit.block.data.BlockData +import org.bukkit.craftbukkit.v1_13_R2.block.data.CraftBlockData +import org.bukkit.craftbukkit.v1_13_R2.CraftParticle +import org.bukkit.craftbukkit.v1_13_R2.inventory.CraftItemStack +import org.bukkit.inventory.ItemStack +import org.bukkit.scoreboard.DisplaySlot +import java.time.Duration +import java.util.* +import java.util.function.Predicate + +@Suppress("UNCHECKED_CAST", "DEPRECATION") +object ArgumentHelper { + + fun getLiteralArguments(argument: AbstractStellarArgument<*>): List> { + val arguments: MutableList> = mutableListOf() + for (name in argument.aliases + argument.name) + arguments.add(LiteralArgumentBuilder.literal(name)) + return arguments + } + + fun getRequiredArgumentBuilder(argument: AbstractStellarArgument<*>): RequiredArgumentBuilder { + val argumentBuilder: RequiredArgumentBuilder = RequiredArgumentBuilder.argument(argument.name, getArgumentType(argument)) + getSuggestions(argument)?.let { argumentBuilder.suggests(it) } + return argumentBuilder + } + + private fun > getSuggestions(argument: T): SuggestionProvider? = + when (argument) { + is GameEventArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MOB_EFFECT.keySet(), builder) + } + is VillagerProfessionArgument -> throwArgumentVersionException(argument) + is VillagerTypeArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> SuggestionProvider { context, builder -> + CompletionProviders.d.getSuggestions(context, builder) + } + is EntityTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.ENTITY_TYPE.keySet(), builder) + } + is MemoryKeyArgument -> throwArgumentVersionException(argument) + else -> null + } + + private fun > getArgumentType(argument: T): ArgumentType<*> = + when (argument) { + is ListArgument<*> -> getArgumentType(argument.type) + is CustomArgument<*> -> getArgumentType(argument.type) + is StringArgument -> brigadier(argument.type) + is PhraseArgument -> brigadier(StringType.PHRASE) + is IntegerArgument -> IntegerArgumentType.integer(argument.min, argument.max) + is LongArgument -> throwArgumentVersionException(argument) + is FloatArgument -> FloatArgumentType.floatArg(argument.min, argument.max) + is DoubleArgument -> DoubleArgumentType.doubleArg(argument.min, argument.max) + is BooleanArgument -> BoolArgumentType.bool() + is com.undefined.stellar.argument.types.entity.EntityArgument -> brigadier(argument.type) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a() + is LocationArgument -> when (argument.type) { + LocationType.LOCATION_3D -> ArgumentPosition.a() + LocationType.LOCATION_2D -> ArgumentVec2I.a() + LocationType.PRECISE_LOCATION_2D -> ArgumentVec3.a() + LocationType.PRECISE_LOCATION_3D -> ArgumentVec2.a() + } + is BlockDataArgument -> ArgumentTile.a() + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> ArgumentBlockPredicate.a() + is com.undefined.stellar.argument.types.item.ItemArgument -> ArgumentItemStack.a() + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> ArgumentItemPredicate.a() + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a() + is com.undefined.stellar.argument.types.text.ComponentArgument -> ArgumentChatComponent.a() + is com.undefined.stellar.argument.types.text.StyleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.text.MessageArgument -> ArgumentChat.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> ArgumentScoreboardObjective.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a() + is com.undefined.stellar.argument.types.math.OperationArgument -> ArgumentMathOperation.a() + is com.undefined.stellar.argument.types.world.ParticleArgument -> ArgumentParticle.a() + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> ArgumentRotation.a() + is DisplaySlotArgument -> ArgumentScoreboardSlot.a() + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a() + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b() + } + is AxisArgument -> ArgumentRotationAxis.a() + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> ArgumentScoreboardTeam.a() + is ItemSlotArgument -> ArgumentInventorySlot.a() + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> ArgumentMinecraftKeyRegistered.a() + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> ArgumentAnchor.a() + is com.undefined.stellar.argument.types.math.RangeArgument -> ReflectionUtil.executePrivateMethod, ArgumentCriterionValue<*>>("a") + is com.undefined.stellar.argument.types.world.DimensionArgument -> ArgumentDimension.a() + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> throwArgumentVersionException(argument) + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> throwArgumentVersionException(argument) + is GameEventArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> ArgumentMinecraftKeyRegistered.a() + is VillagerTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> throwArgumentVersionException(argument) + is AttributeArgument -> ArgumentMinecraftKeyRegistered.a() + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> ArgumentMinecraftKeyRegistered.a() + else -> throw UnsupportedArgumentException(argument) + } + + fun > getParsedArgument(context: CommandContext, argument: T): Any? { + return when (argument) { + is LiteralStellarArgument -> throw LiteralArgumentMismatchException() + is CustomArgument<*> -> argument.parse(CommandContextAdapter.getStellarCommandContext(context)) + is StringArgument -> StringArgumentType.getString(context, argument.name) + is IntegerArgument -> IntegerArgumentType.getInteger(context, argument.name) + is FloatArgument -> FloatArgumentType.getFloat(context, argument.name) + is DoubleArgument -> DoubleArgumentType.getDouble(context, argument.name) + is BooleanArgument -> BoolArgumentType.getBool(context, argument.name) + is ListArgument<*> -> argument.parse(getParsedArgument(context, argument)) + is com.undefined.stellar.argument.types.entity.EntityArgument -> ArgumentEntity.b(context, argument.name) + .map { it.bukkitEntity }.toMutableList() + .addAll(listOf(ArgumentEntity.a(context, argument.name).bukkitEntity)) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a(context, argument.name) + is LocationArgument -> getLocation(context, argument) + is BlockDataArgument -> CraftBlockData.fromData(ArgumentTile.a(context, argument.name).a()) + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> Predicate { block: Block -> + ArgumentBlockPredicate.a(context, argument.name).test(ShapeDetectorBlock( + context.source.world, + BlockPosition(block.x, block.y, block.z), true + )) + } + is com.undefined.stellar.argument.types.item.ItemArgument -> CraftItemStack.asBukkitCopy( + ArgumentItemStack.a(context, argument.name).a(1, false) + ) + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> Predicate { item: ItemStack -> + ArgumentItemPredicate.a(context, argument.name).test(CraftItemStack.asNMSCopy(item)) + } + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a( + context, + argument.name + ).executePrivateMethod("e").let { Style.style(TextColor.color(it)) } + is com.undefined.stellar.argument.types.text.ComponentArgument -> GsonComponentSerializer.gson() + .deserialize(IChatBaseComponent.ChatSerializer.a( + ArgumentChatComponent.a(context, argument.name) + )) + is com.undefined.stellar.argument.types.text.StyleArgument -> GsonComponentSerializer.gson().deserialize( + getArgumentInput(context, argument.name) ?: return null + ).style() + is com.undefined.stellar.argument.types.text.MessageArgument -> GsonComponentSerializer.gson().deserialize( + IChatBaseComponent.ChatSerializer.a(ArgumentChat.a(context, argument.name)) + ) + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getObjective( + ArgumentScoreboardObjective.a(context, argument.name).name + ) + + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a( + context, + argument.name + ).name + is com.undefined.stellar.argument.types.math.OperationArgument -> Operation.getOperation( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.world.ParticleArgument -> { + val particleOptions = ArgumentParticle.a(context, argument.name) + getParticleData(CraftParticle.toBukkit(particleOptions.b()), particleOptions) + } + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> { + val rotation = ArgumentRotation.a(context, argument.name).a(context.source) + Location(context.source.world.world, rotation.x, rotation.y, rotation.z) + } + is DisplaySlotArgument -> getBukkitDisplaySlot(ArgumentScoreboardSlot.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a(context, argument.name) + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b(context, argument.name) + } + is AxisArgument -> getBukkitAxis(ArgumentRotationAxis.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getTeam( + ArgumentScoreboardTeam.a(context, argument.name).name + ) + is ItemSlotArgument -> ArgumentInventorySlot.a(context, argument.name) + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> NamespacedKey( + ArgumentMinecraftKeyRegistered.c(context, argument.name).b(), + ArgumentMinecraftKeyRegistered.c(context, argument.name).key + ) + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> Anchor.getFromName( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.math.RangeArgument -> { + val range = ArgumentCriterionValue.b.a(context, argument.name) + IntRange(range.a() ?: 1, range.b() ?: 2) + } + is com.undefined.stellar.argument.types.world.DimensionArgument -> World.Environment.getEnvironment(ArgumentDimension.a(context, argument.name).dimensionID) + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> Duration.ofSeconds(IntegerArgumentType.getInteger(context, argument.name).toLong() / 20) + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> throwArgumentVersionException(argument) + is GameEventArgument -> throwArgumentVersionException(argument) + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> throwArgumentVersionException(argument) + is VillagerTypeArgument -> throwArgumentVersionException(argument) + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> throwArgumentVersionException(argument) + is AttributeArgument -> throwArgumentVersionException(argument) + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> throwArgumentVersionException(argument) + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> throwArgumentVersionException(argument) + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> throwArgumentVersionException(argument) + else -> throw UnsupportedArgumentException(argument) + } + } + + fun getArgumentInput(context: CommandContext, name: String): String? { + val field = CommandContext::class.java.getDeclaredField("arguments") + field.isAccessible = true + val arguments: Map> = field.get(context) as Map> + val argument = arguments[name] ?: return null + val range = StringRange.between(argument.range.start, context.input.length) + return range.get(context.input) + } + + @Throws(CommandSyntaxException::class) + private fun getId( + context: CommandContext, + name: String + ): NamespacedKey { + val key = ArgumentMinecraftKeyRegistered.c(context, name) + return NamespacedKey(key.b(), key.key) + } + + private fun brigadier(type: StringType): StringArgumentType = when (type) { + StringType.WORD -> StringArgumentType.word() + StringType.QUOTABLE_PHRASE -> StringArgumentType.string() + StringType.PHRASE -> StringArgumentType.greedyString() + } + + private fun brigadier(type: EntityDisplayType): ArgumentEntity = when (type) { + EntityDisplayType.ENTITY -> ReflectionUtil.executePrivateMethod("a") + EntityDisplayType.ENTITIES -> ArgumentEntity.b() + EntityDisplayType.PLAYER -> ArgumentEntity.c() + EntityDisplayType.PLAYERS -> ArgumentEntity.d() + } + + private fun getBukkitAxis(argument: EnumSet): EnumSet = + argument.mapTo(EnumSet.noneOf(Axis::class.java)) { + when (it) { + EnumDirection.EnumAxis.X -> Axis.X + EnumDirection.EnumAxis.Y -> Axis.Y + EnumDirection.EnumAxis.Z -> Axis.Z + null -> Axis.X + } + } + + private fun getBukkitDisplaySlot(slot: Int): DisplaySlot = when (slot) { + 0 -> DisplaySlot.PLAYER_LIST + 2 -> DisplaySlot.BELOW_NAME + else -> DisplaySlot.SIDEBAR + } + + private fun getParticleData( + particle: Particle, + particleOptions: ParticleParam + ): ParticleData<*> = when (particleOptions) { + is ParticleType -> ParticleData(particle, null) + is ParticleParamBlock -> ParticleData(particle, CraftBlockData.fromData(particleOptions.executePrivateMethod("c"))) + is ParticleParamRedstone -> { + val colors = particleOptions.a().split(" ") + val red = colors[1].toFloat() + val green = colors[2].toFloat() + val blue = colors[3].toFloat() + val scale = colors[4].toFloat() + ParticleData( + particle, + Particle.DustOptions( + Color.fromRGB( + (red * 255.0f).toInt(), + (green * 255.0f).toInt(), (blue * 255.0f).toInt() + ), scale + ) + ) + } + is ParticleParamItem -> ParticleData( + particle, + CraftItemStack.asBukkitCopy(particleOptions.executePrivateMethod("c")) + ) + else -> ParticleData(particle, null) + } + + private fun getLocation(context: CommandContext, command: LocationArgument): Location { + val world = context.source.world.world + return when (command.type) { + LocationType.LOCATION_3D -> toLocation(world, context.getArgument(command.name, IVectorPosition::class.java).c(context.source)) + LocationType.LOCATION_2D -> toLocation(world, ArgumentVec2I.a(context, command.name)) + LocationType.PRECISE_LOCATION_3D -> toLocation(world, ArgumentVec3.a(context, command.name)) + LocationType.PRECISE_LOCATION_2D -> toLocation(world, ArgumentVec2.a(context, command.name)) + } + } + + private fun toLocation(world: World, position: BlockPosition) = + Location(world, position.x.toDouble(), position.y.toDouble(), position.z.toDouble()) + private fun toLocation(world: World, position: ArgumentVec2I.a) = + Location(world, position.a.toDouble(), 0.0, position.b.toDouble()) + private fun toLocation(world: World, vec: Vec3D) = + Location(world, vec.x, vec.y, vec.z) + private fun toLocation(world: World, vec: Vec2F) = + Location(world, vec.i.toDouble(), 0.0, vec.j.toDouble()) + + private fun throwArgumentVersionException(argument: AbstractStellarArgument<*>): Nothing = + throw ArgumentVersionMismatchException(argument, NMSVersion.version) + +} \ No newline at end of file diff --git a/v1_13_1/src/main/kotlin/com/undefined/stellar/v1_13_1/BrigadierCommandHelper.kt b/v1_13_1/src/main/kotlin/com/undefined/stellar/v1_13_1/BrigadierCommandHelper.kt new file mode 100644 index 0000000..95f271b --- /dev/null +++ b/v1_13_1/src/main/kotlin/com/undefined/stellar/v1_13_1/BrigadierCommandHelper.kt @@ -0,0 +1,76 @@ +package com.undefined.stellar.v1_13_1 + +import com.mojang.brigadier.CommandDispatcher +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.tree.LiteralCommandNode +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.data.help.CustomCommandHelpTopic +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_13_R2.CommandListenerWrapper +import net.minecraft.server.v1_13_R2.MinecraftServer +import org.bukkit.Bukkit + +@Suppress("DEPRECATION") +object BrigadierCommandHelper { + + val COMMAND_SOURCE: CommandListenerWrapper by lazy { + MinecraftServer.getServer().serverCommandListener + } + val dispatcher: CommandDispatcher by lazy { + MinecraftServer.getServer().functionData.d() + } + + fun register(command: LiteralArgumentBuilder): LiteralCommandNode? = + dispatcher.register(command) + + fun handleHelpTopic(command: AbstractStellarCommand<*>) { + Bukkit.getServer().helpMap.addTopic( + CustomCommandHelpTopic(command.name, command.description, command.helpTopic) { + val context = MinecraftServer.getServer().serverCommandListener + val requirements = command.requirements.all { it(this) } + val permissionRequirements = command.permissionRequirements.all { + if (it.permission.isEmpty()) context.hasPermission(it.level) + else context.hasPermission(it.level) && context.bukkitSender.hasPermission(it.permission) + } + requirements.and(permissionRequirements) + } + ) + } + + fun handleExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + val stellarContext = CommandContextAdapter.getStellarCommandContext(context) + + for (runnable in command.base.runnables) runnable(stellarContext) + val arguments = getArguments(command.base, context) + for (argument in arguments) for (runnable in argument.runnables) runnable(stellarContext) + for (execution in command.executions) execution(stellarContext) + } + + fun fulfillsRequirements(command: AbstractStellarCommand<*>, source: CommandListenerWrapper): Boolean { + val fulfillsExecutionRequirements = command.requirements.all { it(source.bukkitSender) } + val fulfillsPermissionRequirements = command.permissionRequirements.all { source.hasPermission(it.level) && source.bukkitSender.hasPermission(it.permission) } + return fulfillsExecutionRequirements.and(fulfillsPermissionRequirements) + } + + fun handleFailureMessageAndExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + for (execution in command.failureExecutions) execution(CommandContextAdapter.getStellarCommandContext(context)) + for (message in command.failureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + for (message in command.globalFailureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + } + + fun getArguments( + baseCommand: AbstractStellarCommand<*>, + context: CommandContext, + currentIndex: Int = 1, + listOfArguments: List> = emptyList() + ): List> { + if (listOfArguments.size == context.nodes.size - 1) return listOfArguments + for (argument in baseCommand.arguments) + if (argument.name == context.nodes.entries.first().key.name) + return getArguments(argument, context, currentIndex + 1, listOfArguments + argument) + return emptyList() + } + +} \ No newline at end of file diff --git a/v1_13_1/src/main/kotlin/com/undefined/stellar/v1_13_1/CommandAdapter.kt b/v1_13_1/src/main/kotlin/com/undefined/stellar/v1_13_1/CommandAdapter.kt new file mode 100644 index 0000000..6d136e8 --- /dev/null +++ b/v1_13_1/src/main/kotlin/com/undefined/stellar/v1_13_1/CommandAdapter.kt @@ -0,0 +1,96 @@ +package com.undefined.stellar.v1_13_1 + +import com.mojang.brigadier.Command +import com.mojang.brigadier.builder.ArgumentBuilder +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.primitive.PhraseArgument +import net.minecraft.server.v1_13_R2.CommandListenerWrapper + +object CommandAdapter { + + fun getBaseCommand(command: AbstractStellarCommand<*>, name: String = command.name): LiteralArgumentBuilder { + val brigadierCommand = LiteralArgumentBuilder.literal(name) + handleCommandFunctions(command, brigadierCommand) + handleArguments(command, brigadierCommand) + return brigadierCommand + } + + private fun handleCommandFunctions(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + if (command.executions.isNotEmpty() || command.executions.isNotEmpty()) + brigadierCommand.executes { context -> + BrigadierCommandHelper.handleExecutions(command, context) + 1 + } + brigadierCommand.requires { source -> + BrigadierCommandHelper.fulfillsRequirements(command, source) + } + } + + private fun handleArguments(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + for (argument in command.arguments) { + when (argument) { + is LiteralStellarArgument -> handleLiteralArgument(argument, brigadierCommand) + is PhraseArgument-> handlePhraseArgument(argument, brigadierCommand) + else -> handleRequiredArgument(argument, brigadierCommand) + } + } + } + + private fun handleLiteralArgument(argument: LiteralStellarArgument, brigadierCommand: ArgumentBuilder) { + for (argumentBuilder in ArgumentHelper.getLiteralArguments(argument)) { + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + } + + private fun handlePhraseArgument(argument: PhraseArgument, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleGreedyStringWordFunctions(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + + private fun handleGreedyStringWordFunctions(argument: PhraseArgument, argumentBuilder: RequiredArgumentBuilder) { + argumentBuilder.executes { context -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + + for (i in greedyContext.arguments.indices) { + val word = argument.words[i] ?: continue + for (runnable in word.runnables) runnable(greedyContext) + if (i == greedyContext.arguments.lastIndex) + for (execution in word.executions) execution(greedyContext) + } + Command.SINGLE_SUCCESS + } + + argumentBuilder.suggests { context, builder -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + var prevChar = ' ' + val input = ArgumentHelper.getArgumentInput(context, argument.name) ?: "" + val amountOfSpaces: Int = if (input.isEmpty()) 0 else input.count { + if (prevChar == ' ' && it == ' ') return@count false + prevChar = it + it == ' ' + } + val newBuilder = builder.createOffset(builder.input.lastIndexOf(' ') + 1) + val word = argument.words[amountOfSpaces] ?: return@suggests newBuilder.buildFuture() + for (stellarSuggestion in word.suggestions) + for (suggestion in stellarSuggestion.get(greedyContext)) + newBuilder.suggest(suggestion.text) { suggestion.tooltip } + newBuilder.buildFuture() + } + } + + private fun handleRequiredArgument(argument: AbstractStellarArgument<*>, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + +} diff --git a/v1_13_1/src/main/kotlin/com/undefined/stellar/v1_13_1/CommandContextAdapter.kt b/v1_13_1/src/main/kotlin/com/undefined/stellar/v1_13_1/CommandContextAdapter.kt new file mode 100644 index 0000000..6c3244d --- /dev/null +++ b/v1_13_1/src/main/kotlin/com/undefined/stellar/v1_13_1/CommandContextAdapter.kt @@ -0,0 +1,83 @@ +package com.undefined.stellar.v1_13_1 + +import com.mojang.brigadier.context.CommandContext +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.data.argument.CommandNode +import com.undefined.stellar.data.argument.PhraseCommandContext +import com.undefined.stellar.exception.DuplicateArgumentNameException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_13_R2.* +import org.bukkit.command.CommandSender + +object CommandContextAdapter { + + fun getStellarCommandContext(context: CommandContext): com.undefined.stellar.data.argument.CommandContext { + val input = context.input.removePrefix("/") + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes.entries.first().key.name)!! + val arguments = BrigadierCommandHelper.getArguments(baseCommand, context) + if (arguments.filter { it !is LiteralStellarArgument }.groupingBy { it.name }.eachCount().any { it.value > 1 }) throw DuplicateArgumentNameException() + val parsedArguments: CommandNode = + BrigadierCommandHelper.getArguments(baseCommand, context) + .associate, String, (com.undefined.stellar.data.argument.CommandContext) -> Any?> { argument -> + if (argument is CustomArgument) return@associate Pair(argument.name) { argument.parse(it) } + if (argument is LiteralStellarArgument) return@associate Pair(argument.name) { throw LiteralArgumentMismatchException() } + Pair(argument.name) { + ArgumentHelper.getParsedArgument(context, argument) + } + } as CommandNode + return com.undefined.stellar.data.argument.CommandContext( + parsedArguments, + context.source.bukkitSender, + input + ) + } + + fun getGreedyCommandContext(context: CommandContext): PhraseCommandContext { + val input = context.input.removePrefix("/") + val words = input.split(' ').toMutableList() + + val totalOtherArguments = context.nodes.size - 1 + for (i in (1..totalOtherArguments)) words.removeFirst() + return PhraseCommandContext( + words, + context.source.bukkitSender, + input + ) + } + + @Suppress("DEPRECATION") + fun getCommandListenerWrapper(sender: CommandSender): CommandListenerWrapper { + val overworld = MinecraftServer.getServer().getWorldServer(DimensionManager.OVERWORLD) + return CommandListenerWrapper( + Source(sender), + Vec3D(overworld.spawn), + Vec2F.a, + overworld, + 4, + sender.name, + ChatComponentText(sender.name), + MinecraftServer.getServer(), + null + ) + } + + private data class Source(val sender: CommandSender) : ICommandListener { + override fun sendMessage(message: IChatBaseComponent) { + this.sender.sendMessage(LegacyComponentSerializer.legacySection().serialize(asAdventure(message))) + } + override fun a(): Boolean = true + override fun b(): Boolean = true + override fun B_(): Boolean = false + override fun getBukkitSender(stack: CommandListenerWrapper): CommandSender = this.sender + } + + fun asAdventure(component: IChatBaseComponent): net.kyori.adventure.text.Component = + GsonComponentSerializer.gson().deserializeFromTree(IChatBaseComponent.ChatSerializer.b(component)) + +} \ No newline at end of file diff --git a/v1_13_1/src/main/kotlin/com/undefined/stellar/v1_13_1/CommandRegistrar.kt b/v1_13_1/src/main/kotlin/com/undefined/stellar/v1_13_1/CommandRegistrar.kt new file mode 100644 index 0000000..6dff373 --- /dev/null +++ b/v1_13_1/src/main/kotlin/com/undefined/stellar/v1_13_1/CommandRegistrar.kt @@ -0,0 +1,38 @@ +package com.undefined.stellar.v1_13_1 + +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.registrar.AbstractCommandRegistrar +import com.undefined.stellar.v1_13_1.BrigadierCommandHelper.dispatcher +import org.bukkit.command.CommandSender +import org.bukkit.plugin.java.JavaPlugin + +object CommandRegistrar : AbstractCommandRegistrar { + + override fun register(command: AbstractStellarCommand<*>, plugin: JavaPlugin) { + BrigadierCommandHelper.handleHelpTopic(command) + for (name in command.aliases + command.name) + BrigadierCommandHelper.register(CommandAdapter.getBaseCommand(command, name)) + } + + override fun handleCommandFailure(sender: CommandSender, input: String): Boolean { + val results = dispatcher.parse(input, BrigadierCommandHelper.COMMAND_SOURCE) + val context = results.context.withSource(CommandContextAdapter.getCommandListenerWrapper(sender)).build(input) + + if (results.reader.remainingLength == 0) return false + if (context.nodes.isEmpty()) return false + + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes.entries.first().key.name)!! + val argument = BrigadierCommandHelper.getArguments(baseCommand, context).lastOrNull() + argument?.let { + BrigadierCommandHelper.handleFailureMessageAndExecutions(argument, context) + if (argument.hideDefaultFailureMessages.hide) return true + } ?: run { + BrigadierCommandHelper.handleFailureMessageAndExecutions(baseCommand, context) + if (baseCommand.hideDefaultFailureMessages.hide) return true + } + + return baseCommand.hasGlobalHiddenDefaultFailureMessages() + } + +} \ No newline at end of file diff --git a/v1_13_2/build.gradle.kts b/v1_13_2/build.gradle.kts new file mode 100644 index 0000000..ca75704 --- /dev/null +++ b/v1_13_2/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + kotlin("jvm") version "1.9.22" +} + +repositories { + mavenLocal() +} + +dependencies { + compileOnly("org.spigotmc:spigot:1.13.2-R0.1-SNAPSHOT") + compileOnly(project(":common")) +} + +tasks { + compileKotlin { + kotlinOptions.jvmTarget = "1.8" + } + compileJava { + options.release.set(8) + } +} + +java { + disableAutoTargetJvm() +} + +kotlin { + jvmToolchain(21) +} \ No newline at end of file diff --git a/v1_13_2/src/main/kotlin/com/undefined/stellar/v1_13_2/ArgumentHelper.kt b/v1_13_2/src/main/kotlin/com/undefined/stellar/v1_13_2/ArgumentHelper.kt new file mode 100644 index 0000000..f01c53b --- /dev/null +++ b/v1_13_2/src/main/kotlin/com/undefined/stellar/v1_13_2/ArgumentHelper.kt @@ -0,0 +1,397 @@ +package com.undefined.stellar.v1_13_2 + +import com.mojang.brigadier.arguments.* +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 com.mojang.brigadier.context.ParsedArgument +import com.mojang.brigadier.context.StringRange +import com.mojang.brigadier.exceptions.CommandSyntaxException +import com.mojang.brigadier.suggestion.SuggestionProvider +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.block.BlockDataArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.argument.types.custom.ListArgument +import com.undefined.stellar.argument.types.entity.EntityDisplayType +import com.undefined.stellar.argument.types.item.ItemSlotArgument +import com.undefined.stellar.argument.types.item.ItemSlotsArgument +import com.undefined.stellar.argument.types.math.AxisArgument +import com.undefined.stellar.argument.types.misc.NamespacedKeyArgument +import com.undefined.stellar.argument.types.misc.UUIDArgument +import com.undefined.stellar.argument.types.player.GameModeArgument +import com.undefined.stellar.argument.types.primitive.* +import com.undefined.stellar.argument.types.registry.* +import com.undefined.stellar.argument.types.scoreboard.DisplaySlotArgument +import com.undefined.stellar.argument.types.scoreboard.ScoreHolderType +import com.undefined.stellar.argument.types.structure.LootTableArgument +import com.undefined.stellar.argument.types.structure.MirrorArgument +import com.undefined.stellar.argument.types.structure.StructureRotationArgument +import com.undefined.stellar.argument.types.world.HeightMapArgument +import com.undefined.stellar.argument.types.world.LocationArgument +import com.undefined.stellar.argument.types.world.LocationType +import com.undefined.stellar.data.argument.Anchor +import com.undefined.stellar.data.argument.Operation +import com.undefined.stellar.data.argument.ParticleData +import com.undefined.stellar.exception.ArgumentVersionMismatchException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import com.undefined.stellar.exception.UnsupportedArgumentException +import com.undefined.stellar.util.NMSVersion +import com.undefined.stellar.util.ReflectionUtil +import com.undefined.stellar.util.executePrivateMethod +import net.kyori.adventure.text.format.Style +import net.kyori.adventure.text.format.TextColor +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.minecraft.server.v1_13_R2.* +import org.bukkit.* +import org.bukkit.Particle +import org.bukkit.World +import org.bukkit.block.Block +import org.bukkit.block.data.BlockData +import org.bukkit.craftbukkit.v1_13_R2.block.data.CraftBlockData +import org.bukkit.craftbukkit.v1_13_R2.CraftParticle +import org.bukkit.craftbukkit.v1_13_R2.inventory.CraftItemStack +import org.bukkit.inventory.ItemStack +import org.bukkit.scoreboard.DisplaySlot +import java.time.Duration +import java.util.* +import java.util.function.Predicate + +@Suppress("UNCHECKED_CAST", "DEPRECATION") +object ArgumentHelper { + + fun getLiteralArguments(argument: AbstractStellarArgument<*>): List> { + val arguments: MutableList> = mutableListOf() + for (name in argument.aliases + argument.name) + arguments.add(LiteralArgumentBuilder.literal(name)) + return arguments + } + + fun getRequiredArgumentBuilder(argument: AbstractStellarArgument<*>): RequiredArgumentBuilder { + val argumentBuilder: RequiredArgumentBuilder = RequiredArgumentBuilder.argument(argument.name, getArgumentType(argument)) + getSuggestions(argument)?.let { argumentBuilder.suggests(it) } + return argumentBuilder + } + + private fun > getSuggestions(argument: T): SuggestionProvider? = + when (argument) { + is GameEventArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MOB_EFFECT.keySet(), builder) + } + is VillagerProfessionArgument -> throwArgumentVersionException(argument) + is VillagerTypeArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> SuggestionProvider { context, builder -> + CompletionProviders.d.getSuggestions(context, builder) + } + is EntityTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.ENTITY_TYPE.keySet(), builder) + } + is MemoryKeyArgument -> throwArgumentVersionException(argument) + else -> null + } + + private fun > getArgumentType(argument: T): ArgumentType<*> = + when (argument) { + is ListArgument<*> -> getArgumentType(argument.type) + is CustomArgument<*> -> getArgumentType(argument.type) + is StringArgument -> brigadier(argument.type) + is PhraseArgument -> brigadier(StringType.PHRASE) + is IntegerArgument -> IntegerArgumentType.integer(argument.min, argument.max) + is LongArgument -> throwArgumentVersionException(argument) + is FloatArgument -> FloatArgumentType.floatArg(argument.min, argument.max) + is DoubleArgument -> DoubleArgumentType.doubleArg(argument.min, argument.max) + is BooleanArgument -> BoolArgumentType.bool() + is com.undefined.stellar.argument.types.entity.EntityArgument -> brigadier(argument.type) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a() + is LocationArgument -> when (argument.type) { + LocationType.LOCATION_3D -> ArgumentPosition.a() + LocationType.LOCATION_2D -> ArgumentVec2I.a() + LocationType.PRECISE_LOCATION_2D -> ArgumentVec3.a() + LocationType.PRECISE_LOCATION_3D -> ArgumentVec2.a() + } + is BlockDataArgument -> ArgumentTile.a() + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> ArgumentBlockPredicate.a() + is com.undefined.stellar.argument.types.item.ItemArgument -> ArgumentItemStack.a() + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> ArgumentItemPredicate.a() + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a() + is com.undefined.stellar.argument.types.text.ComponentArgument -> ArgumentChatComponent.a() + is com.undefined.stellar.argument.types.text.StyleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.text.MessageArgument -> ArgumentChat.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> ArgumentScoreboardObjective.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a() + is com.undefined.stellar.argument.types.math.OperationArgument -> ArgumentMathOperation.a() + is com.undefined.stellar.argument.types.world.ParticleArgument -> ArgumentParticle.a() + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> ArgumentRotation.a() + is DisplaySlotArgument -> ArgumentScoreboardSlot.a() + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a() + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b() + } + is AxisArgument -> ArgumentRotationAxis.a() + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> ArgumentScoreboardTeam.a() + is ItemSlotArgument -> ArgumentInventorySlot.a() + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> ArgumentMinecraftKeyRegistered.a() + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> ArgumentAnchor.a() + is com.undefined.stellar.argument.types.math.RangeArgument -> ReflectionUtil.executePrivateMethod, ArgumentCriterionValue<*>>("a") + is com.undefined.stellar.argument.types.world.DimensionArgument -> ArgumentDimension.a() + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> throwArgumentVersionException(argument) + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> throwArgumentVersionException(argument) + is GameEventArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> ArgumentMinecraftKeyRegistered.a() + is VillagerTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> throwArgumentVersionException(argument) + is AttributeArgument -> ArgumentMinecraftKeyRegistered.a() + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> ArgumentMinecraftKeyRegistered.a() + else -> throw UnsupportedArgumentException(argument) + } + + fun > getParsedArgument(context: CommandContext, argument: T): Any? { + return when (argument) { + is LiteralStellarArgument -> throw LiteralArgumentMismatchException() + is CustomArgument<*> -> argument.parse(CommandContextAdapter.getStellarCommandContext(context)) + is StringArgument -> StringArgumentType.getString(context, argument.name) + is IntegerArgument -> IntegerArgumentType.getInteger(context, argument.name) + is FloatArgument -> FloatArgumentType.getFloat(context, argument.name) + is DoubleArgument -> DoubleArgumentType.getDouble(context, argument.name) + is BooleanArgument -> BoolArgumentType.getBool(context, argument.name) + is ListArgument<*> -> argument.parse(getParsedArgument(context, argument)) + is com.undefined.stellar.argument.types.entity.EntityArgument -> ArgumentEntity.b(context, argument.name) + .map { it.bukkitEntity }.toMutableList() + .addAll(listOf(ArgumentEntity.a(context, argument.name).bukkitEntity)) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a(context, argument.name) + is LocationArgument -> getLocation(context, argument) + is BlockDataArgument -> CraftBlockData.fromData(ArgumentTile.a(context, argument.name).a()) + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> Predicate { block: Block -> + ArgumentBlockPredicate.a(context, argument.name).test(ShapeDetectorBlock( + context.source.world, + BlockPosition(block.x, block.y, block.z), true + )) + } + is com.undefined.stellar.argument.types.item.ItemArgument -> CraftItemStack.asBukkitCopy( + ArgumentItemStack.a(context, argument.name).a(1, false) + ) + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> Predicate { item: ItemStack -> + ArgumentItemPredicate.a(context, argument.name).test(CraftItemStack.asNMSCopy(item)) + } + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a( + context, + argument.name + ).executePrivateMethod("e").let { Style.style(TextColor.color(it)) } + is com.undefined.stellar.argument.types.text.ComponentArgument -> GsonComponentSerializer.gson() + .deserialize(IChatBaseComponent.ChatSerializer.a( + ArgumentChatComponent.a(context, argument.name) + )) + is com.undefined.stellar.argument.types.text.StyleArgument -> GsonComponentSerializer.gson().deserialize( + getArgumentInput(context, argument.name) ?: return null + ).style() + is com.undefined.stellar.argument.types.text.MessageArgument -> GsonComponentSerializer.gson().deserialize( + IChatBaseComponent.ChatSerializer.a(ArgumentChat.a(context, argument.name)) + ) + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getObjective( + ArgumentScoreboardObjective.a(context, argument.name).name + ) + + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a( + context, + argument.name + ).name + is com.undefined.stellar.argument.types.math.OperationArgument -> Operation.getOperation( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.world.ParticleArgument -> { + val particleOptions = ArgumentParticle.a(context, argument.name) + getParticleData(CraftParticle.toBukkit(particleOptions.b()), particleOptions) + } + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> { + val rotation = ArgumentRotation.a(context, argument.name).a(context.source) + Location(context.source.world.world, rotation.x, rotation.y, rotation.z) + } + is DisplaySlotArgument -> getBukkitDisplaySlot(ArgumentScoreboardSlot.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a(context, argument.name) + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b(context, argument.name) + } + is AxisArgument -> getBukkitAxis(ArgumentRotationAxis.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getTeam( + ArgumentScoreboardTeam.a(context, argument.name).name + ) + is ItemSlotArgument -> ArgumentInventorySlot.a(context, argument.name) + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> NamespacedKey( + ArgumentMinecraftKeyRegistered.c(context, argument.name).b(), + ArgumentMinecraftKeyRegistered.c(context, argument.name).key + ) + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> Anchor.getFromName( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.math.RangeArgument -> { + val range = ArgumentCriterionValue.b.a(context, argument.name) + IntRange(range.a() ?: 1, range.b() ?: 2) + } + is com.undefined.stellar.argument.types.world.DimensionArgument -> World.Environment.getEnvironment(ArgumentDimension.a(context, argument.name).dimensionID) + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> Duration.ofSeconds(IntegerArgumentType.getInteger(context, argument.name).toLong() / 20) + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> throwArgumentVersionException(argument) + is GameEventArgument -> throwArgumentVersionException(argument) + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> throwArgumentVersionException(argument) + is VillagerTypeArgument -> throwArgumentVersionException(argument) + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> throwArgumentVersionException(argument) + is AttributeArgument -> throwArgumentVersionException(argument) + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> throwArgumentVersionException(argument) + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> throwArgumentVersionException(argument) + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> throwArgumentVersionException(argument) + else -> throw UnsupportedArgumentException(argument) + } + } + + fun getArgumentInput(context: CommandContext, name: String): String? { + val field = CommandContext::class.java.getDeclaredField("arguments") + field.isAccessible = true + val arguments: Map> = field.get(context) as Map> + val argument = arguments[name] ?: return null + val range = StringRange.between(argument.range.start, context.input.length) + return range.get(context.input) + } + + @Throws(CommandSyntaxException::class) + private fun getId( + context: CommandContext, + name: String + ): NamespacedKey { + val key = ArgumentMinecraftKeyRegistered.c(context, name) + return NamespacedKey(key.b(), key.key) + } + + private fun brigadier(type: StringType): StringArgumentType = when (type) { + StringType.WORD -> StringArgumentType.word() + StringType.QUOTABLE_PHRASE -> StringArgumentType.string() + StringType.PHRASE -> StringArgumentType.greedyString() + } + + private fun brigadier(type: EntityDisplayType): ArgumentEntity = when (type) { + EntityDisplayType.ENTITY -> ReflectionUtil.executePrivateMethod("a") + EntityDisplayType.ENTITIES -> ArgumentEntity.b() + EntityDisplayType.PLAYER -> ArgumentEntity.c() + EntityDisplayType.PLAYERS -> ArgumentEntity.d() + } + + private fun getBukkitAxis(argument: EnumSet): EnumSet = + argument.mapTo(EnumSet.noneOf(Axis::class.java)) { + when (it) { + EnumDirection.EnumAxis.X -> Axis.X + EnumDirection.EnumAxis.Y -> Axis.Y + EnumDirection.EnumAxis.Z -> Axis.Z + null -> Axis.X + } + } + + private fun getBukkitDisplaySlot(slot: Int): DisplaySlot = when (slot) { + 0 -> DisplaySlot.PLAYER_LIST + 2 -> DisplaySlot.BELOW_NAME + else -> DisplaySlot.SIDEBAR + } + + private fun getParticleData( + particle: Particle, + particleOptions: ParticleParam + ): ParticleData<*> = when (particleOptions) { + is ParticleType -> ParticleData(particle, null) + is ParticleParamBlock -> ParticleData(particle, CraftBlockData.fromData(particleOptions.executePrivateMethod("c"))) + is ParticleParamRedstone -> { + val colors = particleOptions.a().split(" ") + val red = colors[1].toFloat() + val green = colors[2].toFloat() + val blue = colors[3].toFloat() + val scale = colors[4].toFloat() + ParticleData( + particle, + Particle.DustOptions( + Color.fromRGB( + (red * 255.0f).toInt(), + (green * 255.0f).toInt(), (blue * 255.0f).toInt() + ), scale + ) + ) + } + is ParticleParamItem -> ParticleData( + particle, + CraftItemStack.asBukkitCopy(particleOptions.executePrivateMethod("c")) + ) + else -> ParticleData(particle, null) + } + + private fun getLocation(context: CommandContext, command: LocationArgument): Location { + val world = context.source.world.world + return when (command.type) { + LocationType.LOCATION_3D -> toLocation(world, context.getArgument(command.name, IVectorPosition::class.java).c(context.source)) + LocationType.LOCATION_2D -> toLocation(world, ArgumentVec2I.a(context, command.name)) + LocationType.PRECISE_LOCATION_3D -> toLocation(world, ArgumentVec3.a(context, command.name)) + LocationType.PRECISE_LOCATION_2D -> toLocation(world, ArgumentVec2.a(context, command.name)) + } + } + + private fun toLocation(world: World, position: BlockPosition) = + Location(world, position.x.toDouble(), position.y.toDouble(), position.z.toDouble()) + private fun toLocation(world: World, position: ArgumentVec2I.a) = + Location(world, position.a.toDouble(), 0.0, position.b.toDouble()) + private fun toLocation(world: World, vec: Vec3D) = + Location(world, vec.x, vec.y, vec.z) + private fun toLocation(world: World, vec: Vec2F) = + Location(world, vec.i.toDouble(), 0.0, vec.j.toDouble()) + + private fun throwArgumentVersionException(argument: AbstractStellarArgument<*>): Nothing = + throw ArgumentVersionMismatchException(argument, NMSVersion.version) + +} \ No newline at end of file diff --git a/v1_13_2/src/main/kotlin/com/undefined/stellar/v1_13_2/BrigadierCommandHelper.kt b/v1_13_2/src/main/kotlin/com/undefined/stellar/v1_13_2/BrigadierCommandHelper.kt new file mode 100644 index 0000000..5850350 --- /dev/null +++ b/v1_13_2/src/main/kotlin/com/undefined/stellar/v1_13_2/BrigadierCommandHelper.kt @@ -0,0 +1,76 @@ +package com.undefined.stellar.v1_13_2 + +import com.mojang.brigadier.CommandDispatcher +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.tree.LiteralCommandNode +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.data.help.CustomCommandHelpTopic +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_13_R2.CommandListenerWrapper +import net.minecraft.server.v1_13_R2.MinecraftServer +import org.bukkit.Bukkit + +@Suppress("DEPRECATION") +object BrigadierCommandHelper { + + val COMMAND_SOURCE: CommandListenerWrapper by lazy { + MinecraftServer.getServer().serverCommandListener + } + val dispatcher: CommandDispatcher by lazy { + MinecraftServer.getServer().functionData.d() + } + + fun register(command: LiteralArgumentBuilder): LiteralCommandNode? = + dispatcher.register(command) + + fun handleHelpTopic(command: AbstractStellarCommand<*>) { + Bukkit.getServer().helpMap.addTopic( + CustomCommandHelpTopic(command.name, command.description, command.helpTopic) { + val context = MinecraftServer.getServer().serverCommandListener + val requirements = command.requirements.all { it(this) } + val permissionRequirements = command.permissionRequirements.all { + if (it.permission.isEmpty()) context.hasPermission(it.level) + else context.hasPermission(it.level, it.permission) + } + requirements.and(permissionRequirements) + } + ) + } + + fun handleExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + val stellarContext = CommandContextAdapter.getStellarCommandContext(context) + + for (runnable in command.base.runnables) runnable(stellarContext) + val arguments = getArguments(command.base, context) + for (argument in arguments) for (runnable in argument.runnables) runnable(stellarContext) + for (execution in command.executions) execution(stellarContext) + } + + fun fulfillsRequirements(command: AbstractStellarCommand<*>, source: CommandListenerWrapper): Boolean { + val fulfillsExecutionRequirements = command.requirements.all { it(source.bukkitSender) } + val fulfillsPermissionRequirements = command.permissionRequirements.all { source.hasPermission(it.level, it.permission) } + return fulfillsExecutionRequirements.and(fulfillsPermissionRequirements) + } + + fun handleFailureMessageAndExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + for (execution in command.failureExecutions) execution(CommandContextAdapter.getStellarCommandContext(context)) + for (message in command.failureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + for (message in command.globalFailureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + } + + fun getArguments( + baseCommand: AbstractStellarCommand<*>, + context: CommandContext, + currentIndex: Int = 1, + listOfArguments: List> = emptyList() + ): List> { + if (listOfArguments.size == context.nodes.size - 1) return listOfArguments + for (argument in baseCommand.arguments) + if (argument.name == context.nodes.entries.first().key.name) + return getArguments(argument, context, currentIndex + 1, listOfArguments + argument) + return emptyList() + } + +} \ No newline at end of file diff --git a/v1_13_2/src/main/kotlin/com/undefined/stellar/v1_13_2/CommandAdapter.kt b/v1_13_2/src/main/kotlin/com/undefined/stellar/v1_13_2/CommandAdapter.kt new file mode 100644 index 0000000..3f4987d --- /dev/null +++ b/v1_13_2/src/main/kotlin/com/undefined/stellar/v1_13_2/CommandAdapter.kt @@ -0,0 +1,96 @@ +package com.undefined.stellar.v1_13_2 + +import com.mojang.brigadier.Command +import com.mojang.brigadier.builder.ArgumentBuilder +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.primitive.PhraseArgument +import net.minecraft.server.v1_13_R2.CommandListenerWrapper + +object CommandAdapter { + + fun getBaseCommand(command: AbstractStellarCommand<*>, name: String = command.name): LiteralArgumentBuilder { + val brigadierCommand = LiteralArgumentBuilder.literal(name) + handleCommandFunctions(command, brigadierCommand) + handleArguments(command, brigadierCommand) + return brigadierCommand + } + + private fun handleCommandFunctions(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + if (command.executions.isNotEmpty() || command.executions.isNotEmpty()) + brigadierCommand.executes { context -> + BrigadierCommandHelper.handleExecutions(command, context) + 1 + } + brigadierCommand.requires { source -> + BrigadierCommandHelper.fulfillsRequirements(command, source) + } + } + + private fun handleArguments(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + for (argument in command.arguments) { + when (argument) { + is LiteralStellarArgument -> handleLiteralArgument(argument, brigadierCommand) + is PhraseArgument-> handlePhraseArgument(argument, brigadierCommand) + else -> handleRequiredArgument(argument, brigadierCommand) + } + } + } + + private fun handleLiteralArgument(argument: LiteralStellarArgument, brigadierCommand: ArgumentBuilder) { + for (argumentBuilder in ArgumentHelper.getLiteralArguments(argument)) { + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + } + + private fun handlePhraseArgument(argument: PhraseArgument, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleGreedyStringWordFunctions(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + + private fun handleGreedyStringWordFunctions(argument: PhraseArgument, argumentBuilder: RequiredArgumentBuilder) { + argumentBuilder.executes { context -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + + for (i in greedyContext.arguments.indices) { + val word = argument.words[i] ?: continue + for (runnable in word.runnables) runnable(greedyContext) + if (i == greedyContext.arguments.lastIndex) + for (execution in word.executions) execution(greedyContext) + } + Command.SINGLE_SUCCESS + } + + argumentBuilder.suggests { context, builder -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + var prevChar = ' ' + val input = ArgumentHelper.getArgumentInput(context, argument.name) ?: "" + val amountOfSpaces: Int = if (input.isEmpty()) 0 else input.count { + if (prevChar == ' ' && it == ' ') return@count false + prevChar = it + it == ' ' + } + val newBuilder = builder.createOffset(builder.input.lastIndexOf(' ') + 1) + val word = argument.words[amountOfSpaces] ?: return@suggests newBuilder.buildFuture() + for (stellarSuggestion in word.suggestions) + for (suggestion in stellarSuggestion.get(greedyContext)) + newBuilder.suggest(suggestion.text) { suggestion.tooltip } + newBuilder.buildFuture() + } + } + + private fun handleRequiredArgument(argument: AbstractStellarArgument<*>, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + +} diff --git a/v1_13_2/src/main/kotlin/com/undefined/stellar/v1_13_2/CommandContextAdapter.kt b/v1_13_2/src/main/kotlin/com/undefined/stellar/v1_13_2/CommandContextAdapter.kt new file mode 100644 index 0000000..78985fe --- /dev/null +++ b/v1_13_2/src/main/kotlin/com/undefined/stellar/v1_13_2/CommandContextAdapter.kt @@ -0,0 +1,83 @@ +package com.undefined.stellar.v1_13_2 + +import com.mojang.brigadier.context.CommandContext +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.data.argument.CommandNode +import com.undefined.stellar.data.argument.PhraseCommandContext +import com.undefined.stellar.exception.DuplicateArgumentNameException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_13_R2.* +import org.bukkit.command.CommandSender + +object CommandContextAdapter { + + fun getStellarCommandContext(context: CommandContext): com.undefined.stellar.data.argument.CommandContext { + val input = context.input.removePrefix("/") + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes.entries.first().key.name)!! + val arguments = BrigadierCommandHelper.getArguments(baseCommand, context) + if (arguments.filter { it !is LiteralStellarArgument }.groupingBy { it.name }.eachCount().any { it.value > 1 }) throw DuplicateArgumentNameException() + val parsedArguments: CommandNode = + BrigadierCommandHelper.getArguments(baseCommand, context) + .associate, String, (com.undefined.stellar.data.argument.CommandContext) -> Any?> { argument -> + if (argument is CustomArgument) return@associate Pair(argument.name) { argument.parse(it) } + if (argument is LiteralStellarArgument) return@associate Pair(argument.name) { throw LiteralArgumentMismatchException() } + Pair(argument.name) { + ArgumentHelper.getParsedArgument(context, argument) + } + } as CommandNode + return com.undefined.stellar.data.argument.CommandContext( + parsedArguments, + context.source.bukkitSender, + input + ) + } + + fun getGreedyCommandContext(context: CommandContext): PhraseCommandContext { + val input = context.input.removePrefix("/") + val words = input.split(' ').toMutableList() + + val totalOtherArguments = context.nodes.size - 1 + for (i in (1..totalOtherArguments)) words.removeFirst() + return PhraseCommandContext( + words, + context.source.bukkitSender, + input + ) + } + + @Suppress("DEPRECATION") + fun getCommandListenerWrapper(sender: CommandSender): CommandListenerWrapper { + val overworld = MinecraftServer.getServer().getWorldServer(DimensionManager.OVERWORLD) + return CommandListenerWrapper( + Source(sender), + Vec3D(overworld.spawn), + Vec2F.a, + overworld, + 4, + sender.name, + ChatComponentText(sender.name), + MinecraftServer.getServer(), + null + ) + } + + private data class Source(val sender: CommandSender) : ICommandListener { + override fun sendMessage(message: IChatBaseComponent) { + this.sender.sendMessage(LegacyComponentSerializer.legacySection().serialize(asAdventure(message))) + } + override fun a(): Boolean = true + override fun b(): Boolean = true + override fun B_(): Boolean = false + override fun getBukkitSender(stack: CommandListenerWrapper): CommandSender = this.sender + } + + fun asAdventure(component: IChatBaseComponent): net.kyori.adventure.text.Component = + GsonComponentSerializer.gson().deserializeFromTree(IChatBaseComponent.ChatSerializer.b(component)) + +} \ No newline at end of file diff --git a/v1_13_2/src/main/kotlin/com/undefined/stellar/v1_13_2/CommandRegistrar.kt b/v1_13_2/src/main/kotlin/com/undefined/stellar/v1_13_2/CommandRegistrar.kt new file mode 100644 index 0000000..19e368b --- /dev/null +++ b/v1_13_2/src/main/kotlin/com/undefined/stellar/v1_13_2/CommandRegistrar.kt @@ -0,0 +1,38 @@ +package com.undefined.stellar.v1_13_2 + +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.registrar.AbstractCommandRegistrar +import com.undefined.stellar.v1_13_2.BrigadierCommandHelper.dispatcher +import org.bukkit.command.CommandSender +import org.bukkit.plugin.java.JavaPlugin + +object CommandRegistrar : AbstractCommandRegistrar { + + override fun register(command: AbstractStellarCommand<*>, plugin: JavaPlugin) { + BrigadierCommandHelper.handleHelpTopic(command) + for (name in command.aliases + command.name) + BrigadierCommandHelper.register(CommandAdapter.getBaseCommand(command, name)) + } + + override fun handleCommandFailure(sender: CommandSender, input: String): Boolean { + val results = dispatcher.parse(input, BrigadierCommandHelper.COMMAND_SOURCE) + val context = results.context.withSource(CommandContextAdapter.getCommandListenerWrapper(sender)).build(input) + + if (results.reader.remainingLength == 0) return false + if (context.nodes.isEmpty()) return false + + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes.entries.first().key.name)!! + val argument = BrigadierCommandHelper.getArguments(baseCommand, context).lastOrNull() + argument?.let { + BrigadierCommandHelper.handleFailureMessageAndExecutions(argument, context) + if (argument.hideDefaultFailureMessages.hide) return true + } ?: run { + BrigadierCommandHelper.handleFailureMessageAndExecutions(baseCommand, context) + if (baseCommand.hideDefaultFailureMessages.hide) return true + } + + return baseCommand.hasGlobalHiddenDefaultFailureMessages() + } + +} \ No newline at end of file diff --git a/v1_14_1/build.gradle.kts b/v1_14_1/build.gradle.kts new file mode 100644 index 0000000..c0f7906 --- /dev/null +++ b/v1_14_1/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + kotlin("jvm") version "1.9.22" +} + +repositories { + mavenLocal() +} + +dependencies { + compileOnly("org.spigotmc:spigot:1.14.1-R0.1-SNAPSHOT") + compileOnly(project(":common")) +} + +tasks { + compileKotlin { + kotlinOptions.jvmTarget = "1.8" + } + compileJava { + options.release.set(8) + } +} + +java { + disableAutoTargetJvm() +} + +kotlin { + jvmToolchain(21) +} \ No newline at end of file diff --git a/v1_14_1/src/main/kotlin/com/undefined/stellar/v1_14_1/ArgumentHelper.kt b/v1_14_1/src/main/kotlin/com/undefined/stellar/v1_14_1/ArgumentHelper.kt new file mode 100644 index 0000000..0e6165a --- /dev/null +++ b/v1_14_1/src/main/kotlin/com/undefined/stellar/v1_14_1/ArgumentHelper.kt @@ -0,0 +1,434 @@ +package com.undefined.stellar.v1_14_1 + +import com.mojang.brigadier.arguments.* +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 com.mojang.brigadier.context.ParsedArgument +import com.mojang.brigadier.context.StringRange +import com.mojang.brigadier.exceptions.CommandSyntaxException +import com.mojang.brigadier.suggestion.SuggestionProvider +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.block.BlockDataArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.argument.types.custom.ListArgument +import com.undefined.stellar.argument.types.entity.EntityDisplayType +import com.undefined.stellar.argument.types.item.ItemSlotArgument +import com.undefined.stellar.argument.types.item.ItemSlotsArgument +import com.undefined.stellar.argument.types.math.AxisArgument +import com.undefined.stellar.argument.types.misc.NamespacedKeyArgument +import com.undefined.stellar.argument.types.misc.UUIDArgument +import com.undefined.stellar.argument.types.player.GameModeArgument +import com.undefined.stellar.argument.types.primitive.* +import com.undefined.stellar.argument.types.registry.* +import com.undefined.stellar.argument.types.scoreboard.DisplaySlotArgument +import com.undefined.stellar.argument.types.scoreboard.ScoreHolderType +import com.undefined.stellar.argument.types.structure.LootTableArgument +import com.undefined.stellar.argument.types.structure.MirrorArgument +import com.undefined.stellar.argument.types.structure.StructureRotationArgument +import com.undefined.stellar.argument.types.world.HeightMapArgument +import com.undefined.stellar.argument.types.world.LocationArgument +import com.undefined.stellar.argument.types.world.LocationType +import com.undefined.stellar.data.argument.Anchor +import com.undefined.stellar.data.argument.Operation +import com.undefined.stellar.data.argument.ParticleData +import com.undefined.stellar.exception.ArgumentVersionMismatchException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import com.undefined.stellar.exception.UnsupportedArgumentException +import com.undefined.stellar.util.NMSVersion +import com.undefined.stellar.util.ReflectionUtil +import com.undefined.stellar.util.executePrivateMethod +import net.kyori.adventure.text.format.Style +import net.kyori.adventure.text.format.TextColor +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.minecraft.server.v1_14_R1.* +import org.bukkit.* +import org.bukkit.Particle +import org.bukkit.Registry +import org.bukkit.World +import org.bukkit.block.Block +import org.bukkit.block.data.BlockData +import org.bukkit.craftbukkit.v1_14_R1.block.data.CraftBlockData +import org.bukkit.craftbukkit.v1_14_R1.CraftParticle +import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftItemStack +import org.bukkit.event.inventory.InventoryType +import org.bukkit.inventory.ItemStack +import org.bukkit.scoreboard.DisplaySlot +import java.time.Duration +import java.util.* +import java.util.function.Predicate + +@Suppress("UNCHECKED_CAST", "DEPRECATION") +object ArgumentHelper { + + fun getLiteralArguments(argument: AbstractStellarArgument<*>): List> { + val arguments: MutableList> = mutableListOf() + for (name in argument.aliases + argument.name) + arguments.add(LiteralArgumentBuilder.literal(name)) + return arguments + } + + fun getRequiredArgumentBuilder(argument: AbstractStellarArgument<*>): RequiredArgumentBuilder { + val argumentBuilder: RequiredArgumentBuilder = RequiredArgumentBuilder.argument(argument.name, getArgumentType(argument)) + getSuggestions(argument)?.let { argumentBuilder.suggests(it) } + return argumentBuilder + } + + private fun > getSuggestions(argument: T): SuggestionProvider? = + when (argument) { + is GameEventArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MOB_EFFECT.keySet(), builder) + } + is VillagerProfessionArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_PROFESSION.keySet(), builder) + } + is VillagerTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_TYPE.keySet(), builder) + } + is BiomeArgument -> SuggestionProvider { context, builder -> + CompletionProviders.d.getSuggestions(context, builder) + } + is EntityTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.ENTITY_TYPE.keySet(), builder) + } + is MemoryKeyArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MEMORY_MODULE_TYPE.keySet(), builder) + } + else -> null + } + + private fun > getArgumentType(argument: T): ArgumentType<*> = + when (argument) { + is ListArgument<*> -> getArgumentType(argument.type) + is CustomArgument<*> -> getArgumentType(argument.type) + is StringArgument -> brigadier(argument.type) + is PhraseArgument -> brigadier(StringType.PHRASE) + is IntegerArgument -> IntegerArgumentType.integer(argument.min, argument.max) + is LongArgument -> LongArgumentType.longArg(argument.min, argument.max) + is FloatArgument -> FloatArgumentType.floatArg(argument.min, argument.max) + is DoubleArgument -> DoubleArgumentType.doubleArg(argument.min, argument.max) + is BooleanArgument -> BoolArgumentType.bool() + is com.undefined.stellar.argument.types.entity.EntityArgument -> brigadier(argument.type) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a() + is LocationArgument -> when (argument.type) { + LocationType.LOCATION_3D -> ArgumentPosition.a() + LocationType.LOCATION_2D -> ArgumentVec2I.a() + LocationType.PRECISE_LOCATION_2D -> ArgumentVec3.a() + LocationType.PRECISE_LOCATION_3D -> ArgumentVec2.a() + } + is BlockDataArgument -> ArgumentTile.a() + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> ArgumentBlockPredicate.a() + is com.undefined.stellar.argument.types.item.ItemArgument -> ArgumentItemStack.a() + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> ArgumentItemPredicate.a() + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a() + is com.undefined.stellar.argument.types.text.ComponentArgument -> ArgumentChatComponent.a() + is com.undefined.stellar.argument.types.text.StyleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.text.MessageArgument -> ArgumentChat.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> ArgumentScoreboardObjective.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a() + is com.undefined.stellar.argument.types.math.OperationArgument -> ArgumentMathOperation.a() + is com.undefined.stellar.argument.types.world.ParticleArgument -> ArgumentParticle.a() + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> ArgumentRotation.a() + is DisplaySlotArgument -> ArgumentScoreboardSlot.a() + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a() + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b() + } + is AxisArgument -> ArgumentRotationAxis.a() + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> ArgumentScoreboardTeam.a() + is ItemSlotArgument -> ArgumentInventorySlot.a() + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> ArgumentMinecraftKeyRegistered.a() + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> ArgumentAnchor.a() + is com.undefined.stellar.argument.types.math.RangeArgument -> ReflectionUtil.executePrivateMethod, ArgumentCriterionValue<*>>("a") + is com.undefined.stellar.argument.types.world.DimensionArgument -> ArgumentDimension.a() + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> ArgumentTime.a() + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> throwArgumentVersionException(argument) + is GameEventArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> ArgumentMinecraftKeyRegistered.a() + is VillagerTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> throwArgumentVersionException(argument) + is AttributeArgument -> ArgumentMinecraftKeyRegistered.a() + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> ArgumentMinecraftKeyRegistered.a() + else -> throw UnsupportedArgumentException(argument) + } + + fun > getParsedArgument(context: CommandContext, argument: T): Any? { + return when (argument) { + is LiteralStellarArgument -> throw LiteralArgumentMismatchException() + is CustomArgument<*> -> argument.parse(CommandContextAdapter.getStellarCommandContext(context)) + is StringArgument -> StringArgumentType.getString(context, argument.name) + is IntegerArgument -> IntegerArgumentType.getInteger(context, argument.name) + is FloatArgument -> FloatArgumentType.getFloat(context, argument.name) + is DoubleArgument -> DoubleArgumentType.getDouble(context, argument.name) + is BooleanArgument -> BoolArgumentType.getBool(context, argument.name) + is ListArgument<*> -> argument.parse(getParsedArgument(context, argument)) + is com.undefined.stellar.argument.types.entity.EntityArgument -> ArgumentEntity.b(context, argument.name) + .map { it.bukkitEntity }.toMutableList() + .addAll(listOf(ArgumentEntity.a(context, argument.name).bukkitEntity)) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a(context, argument.name) + is LocationArgument -> getLocation(context, argument) + is BlockDataArgument -> CraftBlockData.fromData(ArgumentTile.a(context, argument.name).a()) + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> Predicate { block: Block -> + ArgumentBlockPredicate.a(context, argument.name).test(ShapeDetectorBlock( + context.source.world, + BlockPosition(block.x, block.y, block.z), true + )) + } + is com.undefined.stellar.argument.types.item.ItemArgument -> CraftItemStack.asBukkitCopy( + ArgumentItemStack.a(context, argument.name).a(1, false) + ) + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> Predicate { item: ItemStack -> + ArgumentItemPredicate.a(context, argument.name).test(CraftItemStack.asNMSCopy(item)) + } + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a( + context, + argument.name + ).executePrivateMethod("e").let { Style.style(TextColor.color(it)) } + is com.undefined.stellar.argument.types.text.ComponentArgument -> GsonComponentSerializer.gson() + .deserialize(IChatBaseComponent.ChatSerializer.a( + ArgumentChatComponent.a(context, argument.name) + )) + is com.undefined.stellar.argument.types.text.StyleArgument -> GsonComponentSerializer.gson().deserialize( + getArgumentInput(context, argument.name) ?: return null + ).style() + is com.undefined.stellar.argument.types.text.MessageArgument -> GsonComponentSerializer.gson().deserialize( + IChatBaseComponent.ChatSerializer.a(ArgumentChat.a(context, argument.name)) + ) + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getObjective( + ArgumentScoreboardObjective.a(context, argument.name).name + ) + + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a( + context, + argument.name + ).name + is com.undefined.stellar.argument.types.math.OperationArgument -> Operation.getOperation( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.world.ParticleArgument -> { + val particleOptions = ArgumentParticle.a(context, argument.name) + getParticleData(CraftParticle.toBukkit(particleOptions.b()), particleOptions) + } + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> { + val rotation = ArgumentRotation.a(context, argument.name).a(context.source) + Location(context.source.world.world, rotation.x, rotation.y, rotation.z) + } + is DisplaySlotArgument -> getBukkitDisplaySlot(ArgumentScoreboardSlot.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a(context, argument.name) + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b(context, argument.name) + } + is AxisArgument -> getBukkitAxis(ArgumentRotationAxis.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getTeam( + ArgumentScoreboardTeam.a(context, argument.name).name + ) + is ItemSlotArgument -> ArgumentInventorySlot.a(context, argument.name) + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> NamespacedKey( + ArgumentMinecraftKeyRegistered.c(context, argument.name).b(), + ArgumentMinecraftKeyRegistered.c(context, argument.name).key + ) + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> Anchor.getFromName( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.math.RangeArgument -> { + val range = ArgumentCriterionValue.b.a(context, argument.name) + IntRange(range.a() ?: 1, range.b() ?: 2) + } + is com.undefined.stellar.argument.types.world.DimensionArgument -> World.Environment.getEnvironment(ArgumentDimension.a(context, argument.name).dimensionID) + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> Duration.ofSeconds(IntegerArgumentType.getInteger(context, argument.name).toLong() / 20) + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> throwArgumentVersionException(argument) + is GameEventArgument -> throwArgumentVersionException(argument) + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> Registry.VILLAGER_PROFESSION.get(getId(context, argument.name)) + is VillagerTypeArgument -> Registry.VILLAGER_TYPE.get(getId(context, argument.name)) + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> getInventoryType( + IRegistry.MENU[ArgumentMinecraftKeyRegistered.c(context, argument.name)] + ) + is AttributeArgument -> throwArgumentVersionException(argument) + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> Registry.BIOME.get(getId(context, argument.name)) + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> Registry.ENTITY_TYPE.get(getId(context, argument.name)) + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> Registry.MEMORY_MODULE_TYPE.get(getId(context, argument.name)) + else -> throw UnsupportedArgumentException(argument) + } + } + + fun getArgumentInput(context: CommandContext, name: String): String? { + val field = CommandContext::class.java.getDeclaredField("arguments") + field.isAccessible = true + val arguments: Map> = field.get(context) as Map> + val argument = arguments[name] ?: return null + val range = StringRange.between(argument.range.start, context.input.length) + return range.get(context.input) + } + + private fun getInventoryType(menu: Containers<*>?): InventoryType = when (menu) { + Containers.GENERIC_9X1 -> InventoryType.CHEST + Containers.GENERIC_9X2 -> InventoryType.CHEST + Containers.GENERIC_9X3 -> InventoryType.CHEST + Containers.GENERIC_9X4 -> InventoryType.CHEST + Containers.GENERIC_9X5 -> InventoryType.CHEST + Containers.GENERIC_9X6 -> InventoryType.CHEST + Containers.GENERIC_3X3 -> InventoryType.WORKBENCH + Containers.ANVIL -> InventoryType.ANVIL + Containers.BEACON -> InventoryType.BEACON + Containers.BLAST_FURNACE -> InventoryType.BLAST_FURNACE + Containers.BREWING_STAND -> InventoryType.BREWING + Containers.CRAFTING -> InventoryType.CRAFTING + Containers.ENCHANTMENT -> InventoryType.ENCHANTING + Containers.FURNACE -> InventoryType.FURNACE + Containers.GRINDSTONE -> InventoryType.GRINDSTONE + Containers.HOPPER -> InventoryType.HOPPER + Containers.LECTERN -> InventoryType.LECTERN + Containers.LOOM -> InventoryType.LOOM + Containers.MERCHANT -> InventoryType.MERCHANT + Containers.SHULKER_BOX -> InventoryType.SHULKER_BOX + Containers.SMOKER -> InventoryType.SMOKER + Containers.CARTOGRAPHY -> InventoryType.CARTOGRAPHY + Containers.STONECUTTER -> InventoryType.STONECUTTER + else -> throw IllegalStateException("No inventory type found! This is not intentional behaviour, please contact the developers.") + } + + @Throws(CommandSyntaxException::class) + private fun getId( + context: CommandContext, + name: String + ): NamespacedKey { + val key = ArgumentMinecraftKeyRegistered.c(context, name) + return NamespacedKey(key.b(), key.key) + } + + private fun brigadier(type: StringType): StringArgumentType = when (type) { + StringType.WORD -> StringArgumentType.word() + StringType.QUOTABLE_PHRASE -> StringArgumentType.string() + StringType.PHRASE -> StringArgumentType.greedyString() + } + + private fun brigadier(type: EntityDisplayType): ArgumentEntity = when (type) { + EntityDisplayType.ENTITY -> ReflectionUtil.executePrivateMethod("a") + EntityDisplayType.ENTITIES -> ArgumentEntity.multipleEntities() + EntityDisplayType.PLAYER -> ArgumentEntity.c() + EntityDisplayType.PLAYERS -> ArgumentEntity.d() + } + + private fun getBukkitAxis(argument: EnumSet): EnumSet = + argument.mapTo(EnumSet.noneOf(Axis::class.java)) { + when (it) { + EnumDirection.EnumAxis.X -> Axis.X + EnumDirection.EnumAxis.Y -> Axis.Y + EnumDirection.EnumAxis.Z -> Axis.Z + null -> Axis.X + } + } + + private fun getBukkitDisplaySlot(slot: Int): DisplaySlot = when (slot) { + 0 -> DisplaySlot.PLAYER_LIST + 2 -> DisplaySlot.BELOW_NAME + else -> DisplaySlot.SIDEBAR + } + + private fun getParticleData( + particle: Particle, + particleOptions: ParticleParam + ): ParticleData<*> = when (particleOptions) { + is ParticleType -> ParticleData(particle, null) + is ParticleParamBlock -> ParticleData(particle, CraftBlockData.fromData(particleOptions.executePrivateMethod("c"))) + is ParticleParamRedstone -> { + val colors = particleOptions.a().split(" ") + val red = colors[1].toFloat() + val green = colors[2].toFloat() + val blue = colors[3].toFloat() + val scale = colors[4].toFloat() + ParticleData( + particle, + Particle.DustOptions( + Color.fromRGB( + (red * 255.0f).toInt(), + (green * 255.0f).toInt(), (blue * 255.0f).toInt() + ), scale + ) + ) + } + is ParticleParamItem -> ParticleData( + particle, + CraftItemStack.asBukkitCopy(particleOptions.executePrivateMethod("c")) + ) + else -> ParticleData(particle, null) + } + + private fun getLocation(context: CommandContext, command: LocationArgument): Location { + val world = context.source.world.world + return when (command.type) { + LocationType.LOCATION_3D -> toLocation(world, context.getArgument(command.name, IVectorPosition::class.java).c(context.source)) + LocationType.LOCATION_2D -> toLocation(world, ArgumentVec2I.a(context, command.name)) + LocationType.PRECISE_LOCATION_3D -> toLocation(world, ArgumentVec3.a(context, command.name)) + LocationType.PRECISE_LOCATION_2D -> toLocation(world, ArgumentVec2.a(context, command.name)) + } + } + + private fun toLocation(world: World, position: BlockPosition) = + Location(world, position.x.toDouble(), position.y.toDouble(), position.z.toDouble()) + private fun toLocation(world: World, position: BlockPosition2D) = + Location(world, position.a.toDouble(), 0.0, position.b.toDouble()) + private fun toLocation(world: World, vec: Vec3D) = + Location(world, vec.x, vec.y, vec.z) + private fun toLocation(world: World, vec: Vec2F) = + Location(world, vec.i.toDouble(), 0.0, vec.j.toDouble()) + + private fun throwArgumentVersionException(argument: AbstractStellarArgument<*>): Nothing = + throw ArgumentVersionMismatchException(argument, NMSVersion.version) + +} \ No newline at end of file diff --git a/v1_14_1/src/main/kotlin/com/undefined/stellar/v1_14_1/BrigadierCommandHelper.kt b/v1_14_1/src/main/kotlin/com/undefined/stellar/v1_14_1/BrigadierCommandHelper.kt new file mode 100644 index 0000000..b75bd5d --- /dev/null +++ b/v1_14_1/src/main/kotlin/com/undefined/stellar/v1_14_1/BrigadierCommandHelper.kt @@ -0,0 +1,76 @@ +package com.undefined.stellar.v1_14_1 + +import com.mojang.brigadier.CommandDispatcher +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.tree.LiteralCommandNode +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.data.help.CustomCommandHelpTopic +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_14_R1.CommandListenerWrapper +import net.minecraft.server.v1_14_R1.MinecraftServer +import org.bukkit.Bukkit + +@Suppress("DEPRECATION") +object BrigadierCommandHelper { + + val COMMAND_SOURCE: CommandListenerWrapper by lazy { + MinecraftServer.getServer().serverCommandListener + } + val dispatcher: CommandDispatcher by lazy { + MinecraftServer.getServer().functionData.d() + } + + fun register(command: LiteralArgumentBuilder): LiteralCommandNode? = + dispatcher.register(command) + + fun handleHelpTopic(command: AbstractStellarCommand<*>) { + Bukkit.getServer().helpMap.addTopic( + CustomCommandHelpTopic(command.name, command.description, command.helpTopic) { + val context = MinecraftServer.getServer().serverCommandListener + val requirements = command.requirements.all { it(this) } + val permissionRequirements = command.permissionRequirements.all { + if (it.permission.isEmpty()) context.hasPermission(it.level) + else context.hasPermission(it.level, it.permission) + } + requirements.and(permissionRequirements) + } + ) + } + + fun handleExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + val stellarContext = CommandContextAdapter.getStellarCommandContext(context) + + for (runnable in command.base.runnables) runnable(stellarContext) + val arguments = getArguments(command.base, context) + for (argument in arguments) for (runnable in argument.runnables) runnable(stellarContext) + for (execution in command.executions) execution(stellarContext) + } + + fun fulfillsRequirements(command: AbstractStellarCommand<*>, source: CommandListenerWrapper): Boolean { + val fulfillsExecutionRequirements = command.requirements.all { it(source.bukkitSender) } + val fulfillsPermissionRequirements = command.permissionRequirements.all { source.hasPermission(it.level, it.permission) } + return fulfillsExecutionRequirements.and(fulfillsPermissionRequirements) + } + + fun handleFailureMessageAndExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + for (execution in command.failureExecutions) execution(CommandContextAdapter.getStellarCommandContext(context)) + for (message in command.failureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + for (message in command.globalFailureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + } + + fun getArguments( + baseCommand: AbstractStellarCommand<*>, + context: CommandContext, + currentIndex: Int = 1, + listOfArguments: List> = emptyList() + ): List> { + if (listOfArguments.size == context.nodes.size - 1) return listOfArguments + for (argument in baseCommand.arguments) + if (argument.name == context.nodes[currentIndex].node.name) + return getArguments(argument, context, currentIndex + 1, listOfArguments + argument) + return emptyList() + } + +} \ No newline at end of file diff --git a/v1_14_1/src/main/kotlin/com/undefined/stellar/v1_14_1/CommandAdapter.kt b/v1_14_1/src/main/kotlin/com/undefined/stellar/v1_14_1/CommandAdapter.kt new file mode 100644 index 0000000..498c5bc --- /dev/null +++ b/v1_14_1/src/main/kotlin/com/undefined/stellar/v1_14_1/CommandAdapter.kt @@ -0,0 +1,96 @@ +package com.undefined.stellar.v1_14_1 + +import com.mojang.brigadier.Command +import com.mojang.brigadier.builder.ArgumentBuilder +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.primitive.PhraseArgument +import net.minecraft.server.v1_14_R1.CommandListenerWrapper + +object CommandAdapter { + + fun getBaseCommand(command: AbstractStellarCommand<*>, name: String = command.name): LiteralArgumentBuilder { + val brigadierCommand = LiteralArgumentBuilder.literal(name) + handleCommandFunctions(command, brigadierCommand) + handleArguments(command, brigadierCommand) + return brigadierCommand + } + + private fun handleCommandFunctions(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + if (command.executions.isNotEmpty() || command.executions.isNotEmpty()) + brigadierCommand.executes { context -> + BrigadierCommandHelper.handleExecutions(command, context) + 1 + } + brigadierCommand.requires { source -> + BrigadierCommandHelper.fulfillsRequirements(command, source) + } + } + + private fun handleArguments(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + for (argument in command.arguments) { + when (argument) { + is LiteralStellarArgument -> handleLiteralArgument(argument, brigadierCommand) + is PhraseArgument-> handlePhraseArgument(argument, brigadierCommand) + else -> handleRequiredArgument(argument, brigadierCommand) + } + } + } + + private fun handleLiteralArgument(argument: LiteralStellarArgument, brigadierCommand: ArgumentBuilder) { + for (argumentBuilder in ArgumentHelper.getLiteralArguments(argument)) { + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + } + + private fun handlePhraseArgument(argument: PhraseArgument, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleGreedyStringWordFunctions(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + + private fun handleGreedyStringWordFunctions(argument: PhraseArgument, argumentBuilder: RequiredArgumentBuilder) { + argumentBuilder.executes { context -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + + for (i in greedyContext.arguments.indices) { + val word = argument.words[i] ?: continue + for (runnable in word.runnables) runnable(greedyContext) + if (i == greedyContext.arguments.lastIndex) + for (execution in word.executions) execution(greedyContext) + } + Command.SINGLE_SUCCESS + } + + argumentBuilder.suggests { context, builder -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + var prevChar = ' ' + val input = ArgumentHelper.getArgumentInput(context, argument.name) ?: "" + val amountOfSpaces: Int = if (input.isEmpty()) 0 else input.count { + if (prevChar == ' ' && it == ' ') return@count false + prevChar = it + it == ' ' + } + val newBuilder = builder.createOffset(builder.input.lastIndexOf(' ') + 1) + val word = argument.words[amountOfSpaces] ?: return@suggests newBuilder.buildFuture() + for (stellarSuggestion in word.suggestions) + for (suggestion in stellarSuggestion.get(greedyContext)) + newBuilder.suggest(suggestion.text) { suggestion.tooltip } + newBuilder.buildFuture() + } + } + + private fun handleRequiredArgument(argument: AbstractStellarArgument<*>, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + +} diff --git a/v1_14_1/src/main/kotlin/com/undefined/stellar/v1_14_1/CommandContextAdapter.kt b/v1_14_1/src/main/kotlin/com/undefined/stellar/v1_14_1/CommandContextAdapter.kt new file mode 100644 index 0000000..9aa6755 --- /dev/null +++ b/v1_14_1/src/main/kotlin/com/undefined/stellar/v1_14_1/CommandContextAdapter.kt @@ -0,0 +1,83 @@ +package com.undefined.stellar.v1_14_1 + +import com.mojang.brigadier.context.CommandContext +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.data.argument.CommandNode +import com.undefined.stellar.data.argument.PhraseCommandContext +import com.undefined.stellar.exception.DuplicateArgumentNameException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_14_R1.* +import org.bukkit.command.CommandSender + +object CommandContextAdapter { + + fun getStellarCommandContext(context: CommandContext): com.undefined.stellar.data.argument.CommandContext { + val input = context.input.removePrefix("/") + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val arguments = BrigadierCommandHelper.getArguments(baseCommand, context) + if (arguments.filter { it !is LiteralStellarArgument }.groupingBy { it.name }.eachCount().any { it.value > 1 }) throw DuplicateArgumentNameException() + val parsedArguments: CommandNode = + BrigadierCommandHelper.getArguments(baseCommand, context) + .associate, String, (com.undefined.stellar.data.argument.CommandContext) -> Any?> { argument -> + if (argument is CustomArgument) return@associate Pair(argument.name) { argument.parse(it) } + if (argument is LiteralStellarArgument) return@associate Pair(argument.name) { throw LiteralArgumentMismatchException() } + Pair(argument.name) { + ArgumentHelper.getParsedArgument(context, argument) + } + } as CommandNode + return com.undefined.stellar.data.argument.CommandContext( + parsedArguments, + context.source.bukkitSender, + input + ) + } + + fun getGreedyCommandContext(context: CommandContext): PhraseCommandContext { + val input = context.input.removePrefix("/") + val words = input.split(' ').toMutableList() + + val totalOtherArguments = context.nodes.size - 1 + for (i in (1..totalOtherArguments)) words.removeFirst() + return PhraseCommandContext( + words, + context.source.bukkitSender, + input + ) + } + + @Suppress("DEPRECATION") + fun getCommandListenerWrapper(sender: CommandSender): CommandListenerWrapper { + val overworld = MinecraftServer.getServer().getWorldServer(DimensionManager.OVERWORLD) + return CommandListenerWrapper( + Source(sender), + Vec3D(overworld.spawn), + Vec2F.a, + overworld, + 4, + sender.name, + ChatComponentText(sender.name), + MinecraftServer.getServer(), + null + ) + } + + private data class Source(val sender: CommandSender) : ICommandListener { + override fun sendMessage(message: IChatBaseComponent) { + this.sender.sendMessage(LegacyComponentSerializer.legacySection().serialize(asAdventure(message))) + } + override fun shouldSendSuccess(): Boolean = true + override fun shouldSendFailure(): Boolean = true + override fun shouldBroadcastCommands(): Boolean = false + override fun getBukkitSender(stack: CommandListenerWrapper): CommandSender = this.sender + } + + fun asAdventure(component: IChatBaseComponent): net.kyori.adventure.text.Component = + GsonComponentSerializer.gson().deserializeFromTree(IChatBaseComponent.ChatSerializer.b(component)) + +} \ No newline at end of file diff --git a/v1_14_1/src/main/kotlin/com/undefined/stellar/v1_14_1/CommandRegistrar.kt b/v1_14_1/src/main/kotlin/com/undefined/stellar/v1_14_1/CommandRegistrar.kt new file mode 100644 index 0000000..d9c586e --- /dev/null +++ b/v1_14_1/src/main/kotlin/com/undefined/stellar/v1_14_1/CommandRegistrar.kt @@ -0,0 +1,38 @@ +package com.undefined.stellar.v1_14_1 + +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.registrar.AbstractCommandRegistrar +import com.undefined.stellar.v1_14_1.BrigadierCommandHelper.dispatcher +import org.bukkit.command.CommandSender +import org.bukkit.plugin.java.JavaPlugin + +object CommandRegistrar : AbstractCommandRegistrar { + + override fun register(command: AbstractStellarCommand<*>, plugin: JavaPlugin) { + BrigadierCommandHelper.handleHelpTopic(command) + for (name in command.aliases + command.name) + BrigadierCommandHelper.register(CommandAdapter.getBaseCommand(command, name)) + } + + override fun handleCommandFailure(sender: CommandSender, input: String): Boolean { + val results = dispatcher.parse(input, BrigadierCommandHelper.COMMAND_SOURCE) + val context = results.context.withSource(CommandContextAdapter.getCommandListenerWrapper(sender)).build(input) + + if (results.reader.remainingLength == 0) return false + if (context.nodes.isEmpty()) return false + + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val argument = BrigadierCommandHelper.getArguments(baseCommand, context).lastOrNull() + argument?.let { + BrigadierCommandHelper.handleFailureMessageAndExecutions(argument, context) + if (argument.hideDefaultFailureMessages.hide) return true + } ?: run { + BrigadierCommandHelper.handleFailureMessageAndExecutions(baseCommand, context) + if (baseCommand.hideDefaultFailureMessages.hide) return true + } + + return baseCommand.hasGlobalHiddenDefaultFailureMessages() + } + +} \ No newline at end of file diff --git a/v1_14_2/build.gradle.kts b/v1_14_2/build.gradle.kts new file mode 100644 index 0000000..c0f7906 --- /dev/null +++ b/v1_14_2/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + kotlin("jvm") version "1.9.22" +} + +repositories { + mavenLocal() +} + +dependencies { + compileOnly("org.spigotmc:spigot:1.14.1-R0.1-SNAPSHOT") + compileOnly(project(":common")) +} + +tasks { + compileKotlin { + kotlinOptions.jvmTarget = "1.8" + } + compileJava { + options.release.set(8) + } +} + +java { + disableAutoTargetJvm() +} + +kotlin { + jvmToolchain(21) +} \ No newline at end of file diff --git a/v1_14_2/src/main/kotlin/com/undefined/stellar/v1_14_2/ArgumentHelper.kt b/v1_14_2/src/main/kotlin/com/undefined/stellar/v1_14_2/ArgumentHelper.kt new file mode 100644 index 0000000..edfe995 --- /dev/null +++ b/v1_14_2/src/main/kotlin/com/undefined/stellar/v1_14_2/ArgumentHelper.kt @@ -0,0 +1,434 @@ +package com.undefined.stellar.v1_14_2 + +import com.mojang.brigadier.arguments.* +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 com.mojang.brigadier.context.ParsedArgument +import com.mojang.brigadier.context.StringRange +import com.mojang.brigadier.exceptions.CommandSyntaxException +import com.mojang.brigadier.suggestion.SuggestionProvider +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.block.BlockDataArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.argument.types.custom.ListArgument +import com.undefined.stellar.argument.types.entity.EntityDisplayType +import com.undefined.stellar.argument.types.item.ItemSlotArgument +import com.undefined.stellar.argument.types.item.ItemSlotsArgument +import com.undefined.stellar.argument.types.math.AxisArgument +import com.undefined.stellar.argument.types.misc.NamespacedKeyArgument +import com.undefined.stellar.argument.types.misc.UUIDArgument +import com.undefined.stellar.argument.types.player.GameModeArgument +import com.undefined.stellar.argument.types.primitive.* +import com.undefined.stellar.argument.types.registry.* +import com.undefined.stellar.argument.types.scoreboard.DisplaySlotArgument +import com.undefined.stellar.argument.types.scoreboard.ScoreHolderType +import com.undefined.stellar.argument.types.structure.LootTableArgument +import com.undefined.stellar.argument.types.structure.MirrorArgument +import com.undefined.stellar.argument.types.structure.StructureRotationArgument +import com.undefined.stellar.argument.types.world.HeightMapArgument +import com.undefined.stellar.argument.types.world.LocationArgument +import com.undefined.stellar.argument.types.world.LocationType +import com.undefined.stellar.data.argument.Anchor +import com.undefined.stellar.data.argument.Operation +import com.undefined.stellar.data.argument.ParticleData +import com.undefined.stellar.exception.ArgumentVersionMismatchException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import com.undefined.stellar.exception.UnsupportedArgumentException +import com.undefined.stellar.util.NMSVersion +import com.undefined.stellar.util.ReflectionUtil +import com.undefined.stellar.util.executePrivateMethod +import net.kyori.adventure.text.format.Style +import net.kyori.adventure.text.format.TextColor +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.minecraft.server.v1_14_R1.* +import org.bukkit.* +import org.bukkit.Particle +import org.bukkit.Registry +import org.bukkit.World +import org.bukkit.block.Block +import org.bukkit.block.data.BlockData +import org.bukkit.craftbukkit.v1_14_R1.block.data.CraftBlockData +import org.bukkit.craftbukkit.v1_14_R1.CraftParticle +import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftItemStack +import org.bukkit.event.inventory.InventoryType +import org.bukkit.inventory.ItemStack +import org.bukkit.scoreboard.DisplaySlot +import java.time.Duration +import java.util.* +import java.util.function.Predicate + +@Suppress("UNCHECKED_CAST", "DEPRECATION") +object ArgumentHelper { + + fun getLiteralArguments(argument: AbstractStellarArgument<*>): List> { + val arguments: MutableList> = mutableListOf() + for (name in argument.aliases + argument.name) + arguments.add(LiteralArgumentBuilder.literal(name)) + return arguments + } + + fun getRequiredArgumentBuilder(argument: AbstractStellarArgument<*>): RequiredArgumentBuilder { + val argumentBuilder: RequiredArgumentBuilder = RequiredArgumentBuilder.argument(argument.name, getArgumentType(argument)) + getSuggestions(argument)?.let { argumentBuilder.suggests(it) } + return argumentBuilder + } + + private fun > getSuggestions(argument: T): SuggestionProvider? = + when (argument) { + is GameEventArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MOB_EFFECT.keySet(), builder) + } + is VillagerProfessionArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_PROFESSION.keySet(), builder) + } + is VillagerTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_TYPE.keySet(), builder) + } + is BiomeArgument -> SuggestionProvider { context, builder -> + CompletionProviders.d.getSuggestions(context, builder) + } + is EntityTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.ENTITY_TYPE.keySet(), builder) + } + is MemoryKeyArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MEMORY_MODULE_TYPE.keySet(), builder) + } + else -> null + } + + private fun > getArgumentType(argument: T): ArgumentType<*> = + when (argument) { + is ListArgument<*> -> getArgumentType(argument.type) + is CustomArgument<*> -> getArgumentType(argument.type) + is StringArgument -> brigadier(argument.type) + is PhraseArgument -> brigadier(StringType.PHRASE) + is IntegerArgument -> IntegerArgumentType.integer(argument.min, argument.max) + is LongArgument -> LongArgumentType.longArg(argument.min, argument.max) + is FloatArgument -> FloatArgumentType.floatArg(argument.min, argument.max) + is DoubleArgument -> DoubleArgumentType.doubleArg(argument.min, argument.max) + is BooleanArgument -> BoolArgumentType.bool() + is com.undefined.stellar.argument.types.entity.EntityArgument -> brigadier(argument.type) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a() + is LocationArgument -> when (argument.type) { + LocationType.LOCATION_3D -> ArgumentPosition.a() + LocationType.LOCATION_2D -> ArgumentVec2I.a() + LocationType.PRECISE_LOCATION_2D -> ArgumentVec3.a() + LocationType.PRECISE_LOCATION_3D -> ArgumentVec2.a() + } + is BlockDataArgument -> ArgumentTile.a() + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> ArgumentBlockPredicate.a() + is com.undefined.stellar.argument.types.item.ItemArgument -> ArgumentItemStack.a() + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> ArgumentItemPredicate.a() + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a() + is com.undefined.stellar.argument.types.text.ComponentArgument -> ArgumentChatComponent.a() + is com.undefined.stellar.argument.types.text.StyleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.text.MessageArgument -> ArgumentChat.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> ArgumentScoreboardObjective.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a() + is com.undefined.stellar.argument.types.math.OperationArgument -> ArgumentMathOperation.a() + is com.undefined.stellar.argument.types.world.ParticleArgument -> ArgumentParticle.a() + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> ArgumentRotation.a() + is DisplaySlotArgument -> ArgumentScoreboardSlot.a() + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a() + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b() + } + is AxisArgument -> ArgumentRotationAxis.a() + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> ArgumentScoreboardTeam.a() + is ItemSlotArgument -> ArgumentInventorySlot.a() + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> ArgumentMinecraftKeyRegistered.a() + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> ArgumentAnchor.a() + is com.undefined.stellar.argument.types.math.RangeArgument -> ReflectionUtil.executePrivateMethod, ArgumentCriterionValue<*>>("a") + is com.undefined.stellar.argument.types.world.DimensionArgument -> ArgumentDimension.a() + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> ArgumentTime.a() + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> throwArgumentVersionException(argument) + is GameEventArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> ArgumentMinecraftKeyRegistered.a() + is VillagerTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> throwArgumentVersionException(argument) + is AttributeArgument -> ArgumentMinecraftKeyRegistered.a() + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> ArgumentMinecraftKeyRegistered.a() + else -> throw UnsupportedArgumentException(argument) + } + + fun > getParsedArgument(context: CommandContext, argument: T): Any? { + return when (argument) { + is LiteralStellarArgument -> throw LiteralArgumentMismatchException() + is CustomArgument<*> -> argument.parse(CommandContextAdapter.getStellarCommandContext(context)) + is StringArgument -> StringArgumentType.getString(context, argument.name) + is IntegerArgument -> IntegerArgumentType.getInteger(context, argument.name) + is FloatArgument -> FloatArgumentType.getFloat(context, argument.name) + is DoubleArgument -> DoubleArgumentType.getDouble(context, argument.name) + is BooleanArgument -> BoolArgumentType.getBool(context, argument.name) + is ListArgument<*> -> argument.parse(getParsedArgument(context, argument)) + is com.undefined.stellar.argument.types.entity.EntityArgument -> ArgumentEntity.b(context, argument.name) + .map { it.bukkitEntity }.toMutableList() + .addAll(listOf(ArgumentEntity.a(context, argument.name).bukkitEntity)) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a(context, argument.name) + is LocationArgument -> getLocation(context, argument) + is BlockDataArgument -> CraftBlockData.fromData(ArgumentTile.a(context, argument.name).a()) + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> Predicate { block: Block -> + ArgumentBlockPredicate.a(context, argument.name).test(ShapeDetectorBlock( + context.source.world, + BlockPosition(block.x, block.y, block.z), true + )) + } + is com.undefined.stellar.argument.types.item.ItemArgument -> CraftItemStack.asBukkitCopy( + ArgumentItemStack.a(context, argument.name).a(1, false) + ) + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> Predicate { item: ItemStack -> + ArgumentItemPredicate.a(context, argument.name).test(CraftItemStack.asNMSCopy(item)) + } + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a( + context, + argument.name + ).executePrivateMethod("e").let { Style.style(TextColor.color(it)) } + is com.undefined.stellar.argument.types.text.ComponentArgument -> GsonComponentSerializer.gson() + .deserialize(IChatBaseComponent.ChatSerializer.a( + ArgumentChatComponent.a(context, argument.name) + )) + is com.undefined.stellar.argument.types.text.StyleArgument -> GsonComponentSerializer.gson().deserialize( + getArgumentInput(context, argument.name) ?: return null + ).style() + is com.undefined.stellar.argument.types.text.MessageArgument -> GsonComponentSerializer.gson().deserialize( + IChatBaseComponent.ChatSerializer.a(ArgumentChat.a(context, argument.name)) + ) + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getObjective( + ArgumentScoreboardObjective.a(context, argument.name).name + ) + + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a( + context, + argument.name + ).name + is com.undefined.stellar.argument.types.math.OperationArgument -> Operation.getOperation( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.world.ParticleArgument -> { + val particleOptions = ArgumentParticle.a(context, argument.name) + getParticleData(CraftParticle.toBukkit(particleOptions.b()), particleOptions) + } + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> { + val rotation = ArgumentRotation.a(context, argument.name).a(context.source) + Location(context.source.world.world, rotation.x, rotation.y, rotation.z) + } + is DisplaySlotArgument -> getBukkitDisplaySlot(ArgumentScoreboardSlot.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a(context, argument.name) + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b(context, argument.name) + } + is AxisArgument -> getBukkitAxis(ArgumentRotationAxis.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getTeam( + ArgumentScoreboardTeam.a(context, argument.name).name + ) + is ItemSlotArgument -> ArgumentInventorySlot.a(context, argument.name) + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> NamespacedKey( + ArgumentMinecraftKeyRegistered.c(context, argument.name).b(), + ArgumentMinecraftKeyRegistered.c(context, argument.name).key + ) + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> Anchor.getFromName( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.math.RangeArgument -> { + val range = ArgumentCriterionValue.b.a(context, argument.name) + IntRange(range.a() ?: 1, range.b() ?: 2) + } + is com.undefined.stellar.argument.types.world.DimensionArgument -> World.Environment.getEnvironment(ArgumentDimension.a(context, argument.name).dimensionID) + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> Duration.ofSeconds(IntegerArgumentType.getInteger(context, argument.name).toLong() / 20) + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> throwArgumentVersionException(argument) + is GameEventArgument -> throwArgumentVersionException(argument) + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> Registry.VILLAGER_PROFESSION.get(getId(context, argument.name)) + is VillagerTypeArgument -> Registry.VILLAGER_TYPE.get(getId(context, argument.name)) + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> getInventoryType( + IRegistry.MENU[ArgumentMinecraftKeyRegistered.c(context, argument.name)] + ) + is AttributeArgument -> throwArgumentVersionException(argument) + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> Registry.BIOME.get(getId(context, argument.name)) + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> Registry.ENTITY_TYPE.get(getId(context, argument.name)) + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> Registry.MEMORY_MODULE_TYPE.get(getId(context, argument.name)) + else -> throw UnsupportedArgumentException(argument) + } + } + + fun getArgumentInput(context: CommandContext, name: String): String? { + val field = CommandContext::class.java.getDeclaredField("arguments") + field.isAccessible = true + val arguments: Map> = field.get(context) as Map> + val argument = arguments[name] ?: return null + val range = StringRange.between(argument.range.start, context.input.length) + return range.get(context.input) + } + + private fun getInventoryType(menu: Containers<*>?): InventoryType = when (menu) { + Containers.GENERIC_9X1 -> InventoryType.CHEST + Containers.GENERIC_9X2 -> InventoryType.CHEST + Containers.GENERIC_9X3 -> InventoryType.CHEST + Containers.GENERIC_9X4 -> InventoryType.CHEST + Containers.GENERIC_9X5 -> InventoryType.CHEST + Containers.GENERIC_9X6 -> InventoryType.CHEST + Containers.GENERIC_3X3 -> InventoryType.WORKBENCH + Containers.ANVIL -> InventoryType.ANVIL + Containers.BEACON -> InventoryType.BEACON + Containers.BLAST_FURNACE -> InventoryType.BLAST_FURNACE + Containers.BREWING_STAND -> InventoryType.BREWING + Containers.CRAFTING -> InventoryType.CRAFTING + Containers.ENCHANTMENT -> InventoryType.ENCHANTING + Containers.FURNACE -> InventoryType.FURNACE + Containers.GRINDSTONE -> InventoryType.GRINDSTONE + Containers.HOPPER -> InventoryType.HOPPER + Containers.LECTERN -> InventoryType.LECTERN + Containers.LOOM -> InventoryType.LOOM + Containers.MERCHANT -> InventoryType.MERCHANT + Containers.SHULKER_BOX -> InventoryType.SHULKER_BOX + Containers.SMOKER -> InventoryType.SMOKER + Containers.CARTOGRAPHY -> InventoryType.CARTOGRAPHY + Containers.STONECUTTER -> InventoryType.STONECUTTER + else -> throw IllegalStateException("No inventory type found! This is not intentional behaviour, please contact the developers.") + } + + @Throws(CommandSyntaxException::class) + private fun getId( + context: CommandContext, + name: String + ): NamespacedKey { + val key = ArgumentMinecraftKeyRegistered.c(context, name) + return NamespacedKey(key.b(), key.key) + } + + private fun brigadier(type: StringType): StringArgumentType = when (type) { + StringType.WORD -> StringArgumentType.word() + StringType.QUOTABLE_PHRASE -> StringArgumentType.string() + StringType.PHRASE -> StringArgumentType.greedyString() + } + + private fun brigadier(type: EntityDisplayType): ArgumentEntity = when (type) { + EntityDisplayType.ENTITY -> ReflectionUtil.executePrivateMethod("a") + EntityDisplayType.ENTITIES -> ArgumentEntity.multipleEntities() + EntityDisplayType.PLAYER -> ArgumentEntity.c() + EntityDisplayType.PLAYERS -> ArgumentEntity.d() + } + + private fun getBukkitAxis(argument: EnumSet): EnumSet = + argument.mapTo(EnumSet.noneOf(Axis::class.java)) { + when (it) { + EnumDirection.EnumAxis.X -> Axis.X + EnumDirection.EnumAxis.Y -> Axis.Y + EnumDirection.EnumAxis.Z -> Axis.Z + null -> Axis.X + } + } + + private fun getBukkitDisplaySlot(slot: Int): DisplaySlot = when (slot) { + 0 -> DisplaySlot.PLAYER_LIST + 2 -> DisplaySlot.BELOW_NAME + else -> DisplaySlot.SIDEBAR + } + + private fun getParticleData( + particle: Particle, + particleOptions: ParticleParam + ): ParticleData<*> = when (particleOptions) { + is ParticleType -> ParticleData(particle, null) + is ParticleParamBlock -> ParticleData(particle, CraftBlockData.fromData(particleOptions.executePrivateMethod("c"))) + is ParticleParamRedstone -> { + val colors = particleOptions.a().split(" ") + val red = colors[1].toFloat() + val green = colors[2].toFloat() + val blue = colors[3].toFloat() + val scale = colors[4].toFloat() + ParticleData( + particle, + Particle.DustOptions( + Color.fromRGB( + (red * 255.0f).toInt(), + (green * 255.0f).toInt(), (blue * 255.0f).toInt() + ), scale + ) + ) + } + is ParticleParamItem -> ParticleData( + particle, + CraftItemStack.asBukkitCopy(particleOptions.executePrivateMethod("c")) + ) + else -> ParticleData(particle, null) + } + + private fun getLocation(context: CommandContext, command: LocationArgument): Location { + val world = context.source.world.world + return when (command.type) { + LocationType.LOCATION_3D -> toLocation(world, context.getArgument(command.name, IVectorPosition::class.java).c(context.source)) + LocationType.LOCATION_2D -> toLocation(world, ArgumentVec2I.a(context, command.name)) + LocationType.PRECISE_LOCATION_3D -> toLocation(world, ArgumentVec3.a(context, command.name)) + LocationType.PRECISE_LOCATION_2D -> toLocation(world, ArgumentVec2.a(context, command.name)) + } + } + + private fun toLocation(world: World, position: BlockPosition) = + Location(world, position.x.toDouble(), position.y.toDouble(), position.z.toDouble()) + private fun toLocation(world: World, position: BlockPosition2D) = + Location(world, position.a.toDouble(), 0.0, position.b.toDouble()) + private fun toLocation(world: World, vec: Vec3D) = + Location(world, vec.x, vec.y, vec.z) + private fun toLocation(world: World, vec: Vec2F) = + Location(world, vec.i.toDouble(), 0.0, vec.j.toDouble()) + + private fun throwArgumentVersionException(argument: AbstractStellarArgument<*>): Nothing = + throw ArgumentVersionMismatchException(argument, NMSVersion.version) + +} \ No newline at end of file diff --git a/v1_14_2/src/main/kotlin/com/undefined/stellar/v1_14_2/BrigadierCommandHelper.kt b/v1_14_2/src/main/kotlin/com/undefined/stellar/v1_14_2/BrigadierCommandHelper.kt new file mode 100644 index 0000000..d610333 --- /dev/null +++ b/v1_14_2/src/main/kotlin/com/undefined/stellar/v1_14_2/BrigadierCommandHelper.kt @@ -0,0 +1,76 @@ +package com.undefined.stellar.v1_14_2 + +import com.mojang.brigadier.CommandDispatcher +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.tree.LiteralCommandNode +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.data.help.CustomCommandHelpTopic +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_14_R1.CommandListenerWrapper +import net.minecraft.server.v1_14_R1.MinecraftServer +import org.bukkit.Bukkit + +@Suppress("DEPRECATION") +object BrigadierCommandHelper { + + val COMMAND_SOURCE: CommandListenerWrapper by lazy { + MinecraftServer.getServer().serverCommandListener + } + val dispatcher: CommandDispatcher by lazy { + MinecraftServer.getServer().functionData.d() + } + + fun register(command: LiteralArgumentBuilder): LiteralCommandNode? = + dispatcher.register(command) + + fun handleHelpTopic(command: AbstractStellarCommand<*>) { + Bukkit.getServer().helpMap.addTopic( + CustomCommandHelpTopic(command.name, command.description, command.helpTopic) { + val context = MinecraftServer.getServer().serverCommandListener + val requirements = command.requirements.all { it(this) } + val permissionRequirements = command.permissionRequirements.all { + if (it.permission.isEmpty()) context.hasPermission(it.level) + else context.hasPermission(it.level, it.permission) + } + requirements.and(permissionRequirements) + } + ) + } + + fun handleExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + val stellarContext = CommandContextAdapter.getStellarCommandContext(context) + + for (runnable in command.base.runnables) runnable(stellarContext) + val arguments = getArguments(command.base, context) + for (argument in arguments) for (runnable in argument.runnables) runnable(stellarContext) + for (execution in command.executions) execution(stellarContext) + } + + fun fulfillsRequirements(command: AbstractStellarCommand<*>, source: CommandListenerWrapper): Boolean { + val fulfillsExecutionRequirements = command.requirements.all { it(source.bukkitSender) } + val fulfillsPermissionRequirements = command.permissionRequirements.all { source.hasPermission(it.level, it.permission) } + return fulfillsExecutionRequirements.and(fulfillsPermissionRequirements) + } + + fun handleFailureMessageAndExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + for (execution in command.failureExecutions) execution(CommandContextAdapter.getStellarCommandContext(context)) + for (message in command.failureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + for (message in command.globalFailureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + } + + fun getArguments( + baseCommand: AbstractStellarCommand<*>, + context: CommandContext, + currentIndex: Int = 1, + listOfArguments: List> = emptyList() + ): List> { + if (listOfArguments.size == context.nodes.size - 1) return listOfArguments + for (argument in baseCommand.arguments) + if (argument.name == context.nodes[currentIndex].node.name) + return getArguments(argument, context, currentIndex + 1, listOfArguments + argument) + return emptyList() + } + +} \ No newline at end of file diff --git a/v1_14_2/src/main/kotlin/com/undefined/stellar/v1_14_2/CommandAdapter.kt b/v1_14_2/src/main/kotlin/com/undefined/stellar/v1_14_2/CommandAdapter.kt new file mode 100644 index 0000000..588d9a5 --- /dev/null +++ b/v1_14_2/src/main/kotlin/com/undefined/stellar/v1_14_2/CommandAdapter.kt @@ -0,0 +1,96 @@ +package com.undefined.stellar.v1_14_2 + +import com.mojang.brigadier.Command +import com.mojang.brigadier.builder.ArgumentBuilder +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.primitive.PhraseArgument +import net.minecraft.server.v1_14_R1.CommandListenerWrapper + +object CommandAdapter { + + fun getBaseCommand(command: AbstractStellarCommand<*>, name: String = command.name): LiteralArgumentBuilder { + val brigadierCommand = LiteralArgumentBuilder.literal(name) + handleCommandFunctions(command, brigadierCommand) + handleArguments(command, brigadierCommand) + return brigadierCommand + } + + private fun handleCommandFunctions(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + if (command.executions.isNotEmpty() || command.executions.isNotEmpty()) + brigadierCommand.executes { context -> + BrigadierCommandHelper.handleExecutions(command, context) + 1 + } + brigadierCommand.requires { source -> + BrigadierCommandHelper.fulfillsRequirements(command, source) + } + } + + private fun handleArguments(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + for (argument in command.arguments) { + when (argument) { + is LiteralStellarArgument -> handleLiteralArgument(argument, brigadierCommand) + is PhraseArgument-> handlePhraseArgument(argument, brigadierCommand) + else -> handleRequiredArgument(argument, brigadierCommand) + } + } + } + + private fun handleLiteralArgument(argument: LiteralStellarArgument, brigadierCommand: ArgumentBuilder) { + for (argumentBuilder in ArgumentHelper.getLiteralArguments(argument)) { + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + } + + private fun handlePhraseArgument(argument: PhraseArgument, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleGreedyStringWordFunctions(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + + private fun handleGreedyStringWordFunctions(argument: PhraseArgument, argumentBuilder: RequiredArgumentBuilder) { + argumentBuilder.executes { context -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + + for (i in greedyContext.arguments.indices) { + val word = argument.words[i] ?: continue + for (runnable in word.runnables) runnable(greedyContext) + if (i == greedyContext.arguments.lastIndex) + for (execution in word.executions) execution(greedyContext) + } + Command.SINGLE_SUCCESS + } + + argumentBuilder.suggests { context, builder -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + var prevChar = ' ' + val input = ArgumentHelper.getArgumentInput(context, argument.name) ?: "" + val amountOfSpaces: Int = if (input.isEmpty()) 0 else input.count { + if (prevChar == ' ' && it == ' ') return@count false + prevChar = it + it == ' ' + } + val newBuilder = builder.createOffset(builder.input.lastIndexOf(' ') + 1) + val word = argument.words[amountOfSpaces] ?: return@suggests newBuilder.buildFuture() + for (stellarSuggestion in word.suggestions) + for (suggestion in stellarSuggestion.get(greedyContext)) + newBuilder.suggest(suggestion.text) { suggestion.tooltip } + newBuilder.buildFuture() + } + } + + private fun handleRequiredArgument(argument: AbstractStellarArgument<*>, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + +} diff --git a/v1_14_2/src/main/kotlin/com/undefined/stellar/v1_14_2/CommandContextAdapter.kt b/v1_14_2/src/main/kotlin/com/undefined/stellar/v1_14_2/CommandContextAdapter.kt new file mode 100644 index 0000000..a576a07 --- /dev/null +++ b/v1_14_2/src/main/kotlin/com/undefined/stellar/v1_14_2/CommandContextAdapter.kt @@ -0,0 +1,83 @@ +package com.undefined.stellar.v1_14_2 + +import com.mojang.brigadier.context.CommandContext +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.data.argument.CommandNode +import com.undefined.stellar.data.argument.PhraseCommandContext +import com.undefined.stellar.exception.DuplicateArgumentNameException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_14_R1.* +import org.bukkit.command.CommandSender + +object CommandContextAdapter { + + fun getStellarCommandContext(context: CommandContext): com.undefined.stellar.data.argument.CommandContext { + val input = context.input.removePrefix("/") + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val arguments = BrigadierCommandHelper.getArguments(baseCommand, context) + if (arguments.filter { it !is LiteralStellarArgument }.groupingBy { it.name }.eachCount().any { it.value > 1 }) throw DuplicateArgumentNameException() + val parsedArguments: CommandNode = + BrigadierCommandHelper.getArguments(baseCommand, context) + .associate, String, (com.undefined.stellar.data.argument.CommandContext) -> Any?> { argument -> + if (argument is CustomArgument) return@associate Pair(argument.name) { argument.parse(it) } + if (argument is LiteralStellarArgument) return@associate Pair(argument.name) { throw LiteralArgumentMismatchException() } + Pair(argument.name) { + ArgumentHelper.getParsedArgument(context, argument) + } + } as CommandNode + return com.undefined.stellar.data.argument.CommandContext( + parsedArguments, + context.source.bukkitSender, + input + ) + } + + fun getGreedyCommandContext(context: CommandContext): PhraseCommandContext { + val input = context.input.removePrefix("/") + val words = input.split(' ').toMutableList() + + val totalOtherArguments = context.nodes.size - 1 + for (i in (1..totalOtherArguments)) words.removeFirst() + return PhraseCommandContext( + words, + context.source.bukkitSender, + input + ) + } + + @Suppress("DEPRECATION") + fun getCommandListenerWrapper(sender: CommandSender): CommandListenerWrapper { + val overworld = MinecraftServer.getServer().getWorldServer(DimensionManager.OVERWORLD) + return CommandListenerWrapper( + Source(sender), + Vec3D(overworld.spawn), + Vec2F.a, + overworld, + 4, + sender.name, + ChatComponentText(sender.name), + MinecraftServer.getServer(), + null + ) + } + + private data class Source(val sender: CommandSender) : ICommandListener { + override fun sendMessage(message: IChatBaseComponent) { + this.sender.sendMessage(LegacyComponentSerializer.legacySection().serialize(asAdventure(message))) + } + override fun shouldSendSuccess(): Boolean = true + override fun shouldSendFailure(): Boolean = true + override fun shouldBroadcastCommands(): Boolean = false + override fun getBukkitSender(stack: CommandListenerWrapper): CommandSender = this.sender + } + + fun asAdventure(component: IChatBaseComponent): net.kyori.adventure.text.Component = + GsonComponentSerializer.gson().deserializeFromTree(IChatBaseComponent.ChatSerializer.b(component)) + +} \ No newline at end of file diff --git a/v1_14_2/src/main/kotlin/com/undefined/stellar/v1_14_2/CommandRegistrar.kt b/v1_14_2/src/main/kotlin/com/undefined/stellar/v1_14_2/CommandRegistrar.kt new file mode 100644 index 0000000..3a60805 --- /dev/null +++ b/v1_14_2/src/main/kotlin/com/undefined/stellar/v1_14_2/CommandRegistrar.kt @@ -0,0 +1,38 @@ +package com.undefined.stellar.v1_14_2 + +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.registrar.AbstractCommandRegistrar +import com.undefined.stellar.v1_14_2.BrigadierCommandHelper.dispatcher +import org.bukkit.command.CommandSender +import org.bukkit.plugin.java.JavaPlugin + +object CommandRegistrar : AbstractCommandRegistrar { + + override fun register(command: AbstractStellarCommand<*>, plugin: JavaPlugin) { + BrigadierCommandHelper.handleHelpTopic(command) + for (name in command.aliases + command.name) + BrigadierCommandHelper.register(CommandAdapter.getBaseCommand(command, name)) + } + + override fun handleCommandFailure(sender: CommandSender, input: String): Boolean { + val results = dispatcher.parse(input, BrigadierCommandHelper.COMMAND_SOURCE) + val context = results.context.withSource(CommandContextAdapter.getCommandListenerWrapper(sender)).build(input) + + if (results.reader.remainingLength == 0) return false + if (context.nodes.isEmpty()) return false + + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val argument = BrigadierCommandHelper.getArguments(baseCommand, context).lastOrNull() + argument?.let { + BrigadierCommandHelper.handleFailureMessageAndExecutions(argument, context) + if (argument.hideDefaultFailureMessages.hide) return true + } ?: run { + BrigadierCommandHelper.handleFailureMessageAndExecutions(baseCommand, context) + if (baseCommand.hideDefaultFailureMessages.hide) return true + } + + return baseCommand.hasGlobalHiddenDefaultFailureMessages() + } + +} \ No newline at end of file diff --git a/v1_14_3/build.gradle.kts b/v1_14_3/build.gradle.kts new file mode 100644 index 0000000..faa4df5 --- /dev/null +++ b/v1_14_3/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + kotlin("jvm") version "1.9.22" +} + +repositories { + mavenLocal() +} + +dependencies { + compileOnly("org.spigotmc:spigot:1.14.3-R0.1-SNAPSHOT") + compileOnly(project(":common")) +} + +tasks { + compileKotlin { + kotlinOptions.jvmTarget = "1.8" + } + compileJava { + options.release.set(8) + } +} + +java { + disableAutoTargetJvm() +} + +kotlin { + jvmToolchain(21) +} \ No newline at end of file diff --git a/v1_14_3/src/main/kotlin/com/undefined/stellar/v1_14_3/ArgumentHelper.kt b/v1_14_3/src/main/kotlin/com/undefined/stellar/v1_14_3/ArgumentHelper.kt new file mode 100644 index 0000000..f79ee0c --- /dev/null +++ b/v1_14_3/src/main/kotlin/com/undefined/stellar/v1_14_3/ArgumentHelper.kt @@ -0,0 +1,434 @@ +package com.undefined.stellar.v1_14_3 + +import com.mojang.brigadier.arguments.* +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 com.mojang.brigadier.context.ParsedArgument +import com.mojang.brigadier.context.StringRange +import com.mojang.brigadier.exceptions.CommandSyntaxException +import com.mojang.brigadier.suggestion.SuggestionProvider +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.block.BlockDataArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.argument.types.custom.ListArgument +import com.undefined.stellar.argument.types.entity.EntityDisplayType +import com.undefined.stellar.argument.types.item.ItemSlotArgument +import com.undefined.stellar.argument.types.item.ItemSlotsArgument +import com.undefined.stellar.argument.types.math.AxisArgument +import com.undefined.stellar.argument.types.misc.NamespacedKeyArgument +import com.undefined.stellar.argument.types.misc.UUIDArgument +import com.undefined.stellar.argument.types.player.GameModeArgument +import com.undefined.stellar.argument.types.primitive.* +import com.undefined.stellar.argument.types.registry.* +import com.undefined.stellar.argument.types.scoreboard.DisplaySlotArgument +import com.undefined.stellar.argument.types.scoreboard.ScoreHolderType +import com.undefined.stellar.argument.types.structure.LootTableArgument +import com.undefined.stellar.argument.types.structure.MirrorArgument +import com.undefined.stellar.argument.types.structure.StructureRotationArgument +import com.undefined.stellar.argument.types.world.HeightMapArgument +import com.undefined.stellar.argument.types.world.LocationArgument +import com.undefined.stellar.argument.types.world.LocationType +import com.undefined.stellar.data.argument.Anchor +import com.undefined.stellar.data.argument.Operation +import com.undefined.stellar.data.argument.ParticleData +import com.undefined.stellar.exception.ArgumentVersionMismatchException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import com.undefined.stellar.exception.UnsupportedArgumentException +import com.undefined.stellar.util.NMSVersion +import com.undefined.stellar.util.ReflectionUtil +import com.undefined.stellar.util.executePrivateMethod +import net.kyori.adventure.text.format.Style +import net.kyori.adventure.text.format.TextColor +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.minecraft.server.v1_14_R1.* +import org.bukkit.* +import org.bukkit.Particle +import org.bukkit.Registry +import org.bukkit.World +import org.bukkit.block.Block +import org.bukkit.block.data.BlockData +import org.bukkit.craftbukkit.v1_14_R1.block.data.CraftBlockData +import org.bukkit.craftbukkit.v1_14_R1.CraftParticle +import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftItemStack +import org.bukkit.event.inventory.InventoryType +import org.bukkit.inventory.ItemStack +import org.bukkit.scoreboard.DisplaySlot +import java.time.Duration +import java.util.* +import java.util.function.Predicate + +@Suppress("UNCHECKED_CAST", "DEPRECATION") +object ArgumentHelper { + + fun getLiteralArguments(argument: AbstractStellarArgument<*>): List> { + val arguments: MutableList> = mutableListOf() + for (name in argument.aliases + argument.name) + arguments.add(LiteralArgumentBuilder.literal(name)) + return arguments + } + + fun getRequiredArgumentBuilder(argument: AbstractStellarArgument<*>): RequiredArgumentBuilder { + val argumentBuilder: RequiredArgumentBuilder = RequiredArgumentBuilder.argument(argument.name, getArgumentType(argument)) + getSuggestions(argument)?.let { argumentBuilder.suggests(it) } + return argumentBuilder + } + + private fun > getSuggestions(argument: T): SuggestionProvider? = + when (argument) { + is GameEventArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MOB_EFFECT.keySet(), builder) + } + is VillagerProfessionArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_PROFESSION.keySet(), builder) + } + is VillagerTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_TYPE.keySet(), builder) + } + is BiomeArgument -> SuggestionProvider { context, builder -> + CompletionProviders.d.getSuggestions(context, builder) + } + is EntityTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.ENTITY_TYPE.keySet(), builder) + } + is MemoryKeyArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MEMORY_MODULE_TYPE.keySet(), builder) + } + else -> null + } + + private fun > getArgumentType(argument: T): ArgumentType<*> = + when (argument) { + is ListArgument<*> -> getArgumentType(argument.type) + is CustomArgument<*> -> getArgumentType(argument.type) + is StringArgument -> brigadier(argument.type) + is PhraseArgument -> brigadier(StringType.PHRASE) + is IntegerArgument -> IntegerArgumentType.integer(argument.min, argument.max) + is LongArgument -> LongArgumentType.longArg(argument.min, argument.max) + is FloatArgument -> FloatArgumentType.floatArg(argument.min, argument.max) + is DoubleArgument -> DoubleArgumentType.doubleArg(argument.min, argument.max) + is BooleanArgument -> BoolArgumentType.bool() + is com.undefined.stellar.argument.types.entity.EntityArgument -> brigadier(argument.type) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a() + is LocationArgument -> when (argument.type) { + LocationType.LOCATION_3D -> ArgumentPosition.a() + LocationType.LOCATION_2D -> ArgumentVec2I.a() + LocationType.PRECISE_LOCATION_2D -> ArgumentVec3.a() + LocationType.PRECISE_LOCATION_3D -> ArgumentVec2.a() + } + is BlockDataArgument -> ArgumentTile.a() + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> ArgumentBlockPredicate.a() + is com.undefined.stellar.argument.types.item.ItemArgument -> ArgumentItemStack.a() + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> ArgumentItemPredicate.a() + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a() + is com.undefined.stellar.argument.types.text.ComponentArgument -> ArgumentChatComponent.a() + is com.undefined.stellar.argument.types.text.StyleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.text.MessageArgument -> ArgumentChat.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> ArgumentScoreboardObjective.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a() + is com.undefined.stellar.argument.types.math.OperationArgument -> ArgumentMathOperation.a() + is com.undefined.stellar.argument.types.world.ParticleArgument -> ArgumentParticle.a() + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> ArgumentRotation.a() + is DisplaySlotArgument -> ArgumentScoreboardSlot.a() + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a() + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b() + } + is AxisArgument -> ArgumentRotationAxis.a() + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> ArgumentScoreboardTeam.a() + is ItemSlotArgument -> ArgumentInventorySlot.a() + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> ArgumentMinecraftKeyRegistered.a() + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> ArgumentAnchor.a() + is com.undefined.stellar.argument.types.math.RangeArgument -> ReflectionUtil.executePrivateMethod, ArgumentCriterionValue<*>>("a") + is com.undefined.stellar.argument.types.world.DimensionArgument -> ArgumentDimension.a() + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> ArgumentTime.a() + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> throwArgumentVersionException(argument) + is GameEventArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> ArgumentMinecraftKeyRegistered.a() + is VillagerTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> throwArgumentVersionException(argument) + is AttributeArgument -> ArgumentMinecraftKeyRegistered.a() + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> ArgumentMinecraftKeyRegistered.a() + else -> throw UnsupportedArgumentException(argument) + } + + fun > getParsedArgument(context: CommandContext, argument: T): Any? { + return when (argument) { + is LiteralStellarArgument -> throw LiteralArgumentMismatchException() + is CustomArgument<*> -> argument.parse(CommandContextAdapter.getStellarCommandContext(context)) + is StringArgument -> StringArgumentType.getString(context, argument.name) + is IntegerArgument -> IntegerArgumentType.getInteger(context, argument.name) + is FloatArgument -> FloatArgumentType.getFloat(context, argument.name) + is DoubleArgument -> DoubleArgumentType.getDouble(context, argument.name) + is BooleanArgument -> BoolArgumentType.getBool(context, argument.name) + is ListArgument<*> -> argument.parse(getParsedArgument(context, argument)) + is com.undefined.stellar.argument.types.entity.EntityArgument -> ArgumentEntity.b(context, argument.name) + .map { it.bukkitEntity }.toMutableList() + .addAll(listOf(ArgumentEntity.a(context, argument.name).bukkitEntity)) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a(context, argument.name) + is LocationArgument -> getLocation(context, argument) + is BlockDataArgument -> CraftBlockData.fromData(ArgumentTile.a(context, argument.name).a()) + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> Predicate { block: Block -> + ArgumentBlockPredicate.a(context, argument.name).test(ShapeDetectorBlock( + context.source.world, + BlockPosition(block.x, block.y, block.z), true + )) + } + is com.undefined.stellar.argument.types.item.ItemArgument -> CraftItemStack.asBukkitCopy( + ArgumentItemStack.a(context, argument.name).a(1, false) + ) + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> Predicate { item: ItemStack -> + ArgumentItemPredicate.a(context, argument.name).test(CraftItemStack.asNMSCopy(item)) + } + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a( + context, + argument.name + ).executePrivateMethod("e").let { Style.style(TextColor.color(it)) } + is com.undefined.stellar.argument.types.text.ComponentArgument -> GsonComponentSerializer.gson() + .deserialize(IChatBaseComponent.ChatSerializer.a( + ArgumentChatComponent.a(context, argument.name) + )) + is com.undefined.stellar.argument.types.text.StyleArgument -> GsonComponentSerializer.gson().deserialize( + getArgumentInput(context, argument.name) ?: return null + ).style() + is com.undefined.stellar.argument.types.text.MessageArgument -> GsonComponentSerializer.gson().deserialize( + IChatBaseComponent.ChatSerializer.a(ArgumentChat.a(context, argument.name)) + ) + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getObjective( + ArgumentScoreboardObjective.a(context, argument.name).name + ) + + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a( + context, + argument.name + ).name + is com.undefined.stellar.argument.types.math.OperationArgument -> Operation.getOperation( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.world.ParticleArgument -> { + val particleOptions = ArgumentParticle.a(context, argument.name) + getParticleData(CraftParticle.toBukkit(particleOptions.b()), particleOptions) + } + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> { + val rotation = ArgumentRotation.a(context, argument.name).a(context.source) + Location(context.source.world.world, rotation.x, rotation.y, rotation.z) + } + is DisplaySlotArgument -> getBukkitDisplaySlot(ArgumentScoreboardSlot.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a(context, argument.name) + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b(context, argument.name) + } + is AxisArgument -> getBukkitAxis(ArgumentRotationAxis.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getTeam( + ArgumentScoreboardTeam.a(context, argument.name).name + ) + is ItemSlotArgument -> ArgumentInventorySlot.a(context, argument.name) + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> NamespacedKey( + ArgumentMinecraftKeyRegistered.c(context, argument.name).b(), + ArgumentMinecraftKeyRegistered.c(context, argument.name).key + ) + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> Anchor.getFromName( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.math.RangeArgument -> { + val range = ArgumentCriterionValue.b.a(context, argument.name) + IntRange(range.a() ?: 1, range.b() ?: 2) + } + is com.undefined.stellar.argument.types.world.DimensionArgument -> World.Environment.getEnvironment(ArgumentDimension.a(context, argument.name).dimensionID) + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> Duration.ofSeconds(IntegerArgumentType.getInteger(context, argument.name).toLong() / 20) + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> throwArgumentVersionException(argument) + is GameEventArgument -> throwArgumentVersionException(argument) + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> Registry.VILLAGER_PROFESSION.get(getId(context, argument.name)) + is VillagerTypeArgument -> Registry.VILLAGER_TYPE.get(getId(context, argument.name)) + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> getInventoryType( + IRegistry.MENU[ArgumentMinecraftKeyRegistered.c(context, argument.name)] + ) + is AttributeArgument -> throwArgumentVersionException(argument) + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> Registry.BIOME.get(getId(context, argument.name)) + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> Registry.ENTITY_TYPE.get(getId(context, argument.name)) + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> Registry.MEMORY_MODULE_TYPE.get(getId(context, argument.name)) + else -> throw UnsupportedArgumentException(argument) + } + } + + fun getArgumentInput(context: CommandContext, name: String): String? { + val field = CommandContext::class.java.getDeclaredField("arguments") + field.isAccessible = true + val arguments: Map> = field.get(context) as Map> + val argument = arguments[name] ?: return null + val range = StringRange.between(argument.range.start, context.input.length) + return range.get(context.input) + } + + private fun getInventoryType(menu: Containers<*>?): InventoryType = when (menu) { + Containers.GENERIC_9X1 -> InventoryType.CHEST + Containers.GENERIC_9X2 -> InventoryType.CHEST + Containers.GENERIC_9X3 -> InventoryType.CHEST + Containers.GENERIC_9X4 -> InventoryType.CHEST + Containers.GENERIC_9X5 -> InventoryType.CHEST + Containers.GENERIC_9X6 -> InventoryType.CHEST + Containers.GENERIC_3X3 -> InventoryType.WORKBENCH + Containers.ANVIL -> InventoryType.ANVIL + Containers.BEACON -> InventoryType.BEACON + Containers.BLAST_FURNACE -> InventoryType.BLAST_FURNACE + Containers.BREWING_STAND -> InventoryType.BREWING + Containers.CRAFTING -> InventoryType.CRAFTING + Containers.ENCHANTMENT -> InventoryType.ENCHANTING + Containers.FURNACE -> InventoryType.FURNACE + Containers.GRINDSTONE -> InventoryType.GRINDSTONE + Containers.HOPPER -> InventoryType.HOPPER + Containers.LECTERN -> InventoryType.LECTERN + Containers.LOOM -> InventoryType.LOOM + Containers.MERCHANT -> InventoryType.MERCHANT + Containers.SHULKER_BOX -> InventoryType.SHULKER_BOX + Containers.SMOKER -> InventoryType.SMOKER + Containers.CARTOGRAPHY -> InventoryType.CARTOGRAPHY + Containers.STONECUTTER -> InventoryType.STONECUTTER + else -> throw IllegalStateException("No inventory type found! This is not intentional behaviour, please contact the developers.") + } + + @Throws(CommandSyntaxException::class) + private fun getId( + context: CommandContext, + name: String + ): NamespacedKey { + val key = ArgumentMinecraftKeyRegistered.c(context, name) + return NamespacedKey(key.b(), key.key) + } + + private fun brigadier(type: StringType): StringArgumentType = when (type) { + StringType.WORD -> StringArgumentType.word() + StringType.QUOTABLE_PHRASE -> StringArgumentType.string() + StringType.PHRASE -> StringArgumentType.greedyString() + } + + private fun brigadier(type: EntityDisplayType): ArgumentEntity = when (type) { + EntityDisplayType.ENTITY -> ReflectionUtil.executePrivateMethod("a") + EntityDisplayType.ENTITIES -> ArgumentEntity.multipleEntities() + EntityDisplayType.PLAYER -> ArgumentEntity.c() + EntityDisplayType.PLAYERS -> ArgumentEntity.d() + } + + private fun getBukkitAxis(argument: EnumSet): EnumSet = + argument.mapTo(EnumSet.noneOf(Axis::class.java)) { + when (it) { + EnumDirection.EnumAxis.X -> Axis.X + EnumDirection.EnumAxis.Y -> Axis.Y + EnumDirection.EnumAxis.Z -> Axis.Z + null -> Axis.X + } + } + + private fun getBukkitDisplaySlot(slot: Int): DisplaySlot = when (slot) { + 0 -> DisplaySlot.PLAYER_LIST + 2 -> DisplaySlot.BELOW_NAME + else -> DisplaySlot.SIDEBAR + } + + private fun getParticleData( + particle: Particle, + particleOptions: ParticleParam + ): ParticleData<*> = when (particleOptions) { + is ParticleType -> ParticleData(particle, null) + is ParticleParamBlock -> ParticleData(particle, CraftBlockData.fromData(particleOptions.executePrivateMethod("c"))) + is ParticleParamRedstone -> { + val colors = particleOptions.a().split(" ") + val red = colors[1].toFloat() + val green = colors[2].toFloat() + val blue = colors[3].toFloat() + val scale = colors[4].toFloat() + ParticleData( + particle, + Particle.DustOptions( + Color.fromRGB( + (red * 255.0f).toInt(), + (green * 255.0f).toInt(), (blue * 255.0f).toInt() + ), scale + ) + ) + } + is ParticleParamItem -> ParticleData( + particle, + CraftItemStack.asBukkitCopy(particleOptions.executePrivateMethod("c")) + ) + else -> ParticleData(particle, null) + } + + private fun getLocation(context: CommandContext, command: LocationArgument): Location { + val world = context.source.world.world + return when (command.type) { + LocationType.LOCATION_3D -> toLocation(world, context.getArgument(command.name, IVectorPosition::class.java).c(context.source)) + LocationType.LOCATION_2D -> toLocation(world, ArgumentVec2I.a(context, command.name)) + LocationType.PRECISE_LOCATION_3D -> toLocation(world, ArgumentVec3.a(context, command.name)) + LocationType.PRECISE_LOCATION_2D -> toLocation(world, ArgumentVec2.a(context, command.name)) + } + } + + private fun toLocation(world: World, position: BlockPosition) = + Location(world, position.x.toDouble(), position.y.toDouble(), position.z.toDouble()) + private fun toLocation(world: World, position: BlockPosition2D) = + Location(world, position.a.toDouble(), 0.0, position.b.toDouble()) + private fun toLocation(world: World, vec: Vec3D) = + Location(world, vec.x, vec.y, vec.z) + private fun toLocation(world: World, vec: Vec2F) = + Location(world, vec.i.toDouble(), 0.0, vec.j.toDouble()) + + private fun throwArgumentVersionException(argument: AbstractStellarArgument<*>): Nothing = + throw ArgumentVersionMismatchException(argument, NMSVersion.version) + +} \ No newline at end of file diff --git a/v1_14_3/src/main/kotlin/com/undefined/stellar/v1_14_3/BrigadierCommandHelper.kt b/v1_14_3/src/main/kotlin/com/undefined/stellar/v1_14_3/BrigadierCommandHelper.kt new file mode 100644 index 0000000..78c7686 --- /dev/null +++ b/v1_14_3/src/main/kotlin/com/undefined/stellar/v1_14_3/BrigadierCommandHelper.kt @@ -0,0 +1,76 @@ +package com.undefined.stellar.v1_14_3 + +import com.mojang.brigadier.CommandDispatcher +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.tree.LiteralCommandNode +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.data.help.CustomCommandHelpTopic +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_14_R1.CommandListenerWrapper +import net.minecraft.server.v1_14_R1.MinecraftServer +import org.bukkit.Bukkit + +@Suppress("DEPRECATION") +object BrigadierCommandHelper { + + val COMMAND_SOURCE: CommandListenerWrapper by lazy { + MinecraftServer.getServer().serverCommandListener + } + val dispatcher: CommandDispatcher by lazy { + MinecraftServer.getServer().functionData.d() + } + + fun register(command: LiteralArgumentBuilder): LiteralCommandNode? = + dispatcher.register(command) + + fun handleHelpTopic(command: AbstractStellarCommand<*>) { + Bukkit.getServer().helpMap.addTopic( + CustomCommandHelpTopic(command.name, command.description, command.helpTopic) { + val context = MinecraftServer.getServer().serverCommandListener + val requirements = command.requirements.all { it(this) } + val permissionRequirements = command.permissionRequirements.all { + if (it.permission.isEmpty()) context.hasPermission(it.level) + else context.hasPermission(it.level, it.permission) + } + requirements.and(permissionRequirements) + } + ) + } + + fun handleExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + val stellarContext = CommandContextAdapter.getStellarCommandContext(context) + + for (runnable in command.base.runnables) runnable(stellarContext) + val arguments = getArguments(command.base, context) + for (argument in arguments) for (runnable in argument.runnables) runnable(stellarContext) + for (execution in command.executions) execution(stellarContext) + } + + fun fulfillsRequirements(command: AbstractStellarCommand<*>, source: CommandListenerWrapper): Boolean { + val fulfillsExecutionRequirements = command.requirements.all { it(source.bukkitSender) } + val fulfillsPermissionRequirements = command.permissionRequirements.all { source.hasPermission(it.level, it.permission) } + return fulfillsExecutionRequirements.and(fulfillsPermissionRequirements) + } + + fun handleFailureMessageAndExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + for (execution in command.failureExecutions) execution(CommandContextAdapter.getStellarCommandContext(context)) + for (message in command.failureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + for (message in command.globalFailureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + } + + fun getArguments( + baseCommand: AbstractStellarCommand<*>, + context: CommandContext, + currentIndex: Int = 1, + listOfArguments: List> = emptyList() + ): List> { + if (listOfArguments.size == context.nodes.size - 1) return listOfArguments + for (argument in baseCommand.arguments) + if (argument.name == context.nodes[currentIndex].node.name) + return getArguments(argument, context, currentIndex + 1, listOfArguments + argument) + return emptyList() + } + +} \ No newline at end of file diff --git a/v1_14_3/src/main/kotlin/com/undefined/stellar/v1_14_3/CommandAdapter.kt b/v1_14_3/src/main/kotlin/com/undefined/stellar/v1_14_3/CommandAdapter.kt new file mode 100644 index 0000000..703461b --- /dev/null +++ b/v1_14_3/src/main/kotlin/com/undefined/stellar/v1_14_3/CommandAdapter.kt @@ -0,0 +1,96 @@ +package com.undefined.stellar.v1_14_3 + +import com.mojang.brigadier.Command +import com.mojang.brigadier.builder.ArgumentBuilder +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.primitive.PhraseArgument +import net.minecraft.server.v1_14_R1.CommandListenerWrapper + +object CommandAdapter { + + fun getBaseCommand(command: AbstractStellarCommand<*>, name: String = command.name): LiteralArgumentBuilder { + val brigadierCommand = LiteralArgumentBuilder.literal(name) + handleCommandFunctions(command, brigadierCommand) + handleArguments(command, brigadierCommand) + return brigadierCommand + } + + private fun handleCommandFunctions(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + if (command.executions.isNotEmpty() || command.executions.isNotEmpty()) + brigadierCommand.executes { context -> + BrigadierCommandHelper.handleExecutions(command, context) + 1 + } + brigadierCommand.requires { source -> + BrigadierCommandHelper.fulfillsRequirements(command, source) + } + } + + private fun handleArguments(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + for (argument in command.arguments) { + when (argument) { + is LiteralStellarArgument -> handleLiteralArgument(argument, brigadierCommand) + is PhraseArgument-> handlePhraseArgument(argument, brigadierCommand) + else -> handleRequiredArgument(argument, brigadierCommand) + } + } + } + + private fun handleLiteralArgument(argument: LiteralStellarArgument, brigadierCommand: ArgumentBuilder) { + for (argumentBuilder in ArgumentHelper.getLiteralArguments(argument)) { + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + } + + private fun handlePhraseArgument(argument: PhraseArgument, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleGreedyStringWordFunctions(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + + private fun handleGreedyStringWordFunctions(argument: PhraseArgument, argumentBuilder: RequiredArgumentBuilder) { + argumentBuilder.executes { context -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + + for (i in greedyContext.arguments.indices) { + val word = argument.words[i] ?: continue + for (runnable in word.runnables) runnable(greedyContext) + if (i == greedyContext.arguments.lastIndex) + for (execution in word.executions) execution(greedyContext) + } + Command.SINGLE_SUCCESS + } + + argumentBuilder.suggests { context, builder -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + var prevChar = ' ' + val input = ArgumentHelper.getArgumentInput(context, argument.name) ?: "" + val amountOfSpaces: Int = if (input.isEmpty()) 0 else input.count { + if (prevChar == ' ' && it == ' ') return@count false + prevChar = it + it == ' ' + } + val newBuilder = builder.createOffset(builder.input.lastIndexOf(' ') + 1) + val word = argument.words[amountOfSpaces] ?: return@suggests newBuilder.buildFuture() + for (stellarSuggestion in word.suggestions) + for (suggestion in stellarSuggestion.get(greedyContext)) + newBuilder.suggest(suggestion.text) { suggestion.tooltip } + newBuilder.buildFuture() + } + } + + private fun handleRequiredArgument(argument: AbstractStellarArgument<*>, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + +} diff --git a/v1_14_3/src/main/kotlin/com/undefined/stellar/v1_14_3/CommandContextAdapter.kt b/v1_14_3/src/main/kotlin/com/undefined/stellar/v1_14_3/CommandContextAdapter.kt new file mode 100644 index 0000000..357da0d --- /dev/null +++ b/v1_14_3/src/main/kotlin/com/undefined/stellar/v1_14_3/CommandContextAdapter.kt @@ -0,0 +1,83 @@ +package com.undefined.stellar.v1_14_3 + +import com.mojang.brigadier.context.CommandContext +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.data.argument.CommandNode +import com.undefined.stellar.data.argument.PhraseCommandContext +import com.undefined.stellar.exception.DuplicateArgumentNameException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_14_R1.* +import org.bukkit.command.CommandSender + +object CommandContextAdapter { + + fun getStellarCommandContext(context: CommandContext): com.undefined.stellar.data.argument.CommandContext { + val input = context.input.removePrefix("/") + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val arguments = BrigadierCommandHelper.getArguments(baseCommand, context) + if (arguments.filter { it !is LiteralStellarArgument }.groupingBy { it.name }.eachCount().any { it.value > 1 }) throw DuplicateArgumentNameException() + val parsedArguments: CommandNode = + BrigadierCommandHelper.getArguments(baseCommand, context) + .associate, String, (com.undefined.stellar.data.argument.CommandContext) -> Any?> { argument -> + if (argument is CustomArgument) return@associate Pair(argument.name) { argument.parse(it) } + if (argument is LiteralStellarArgument) return@associate Pair(argument.name) { throw LiteralArgumentMismatchException() } + Pair(argument.name) { + ArgumentHelper.getParsedArgument(context, argument) + } + } as CommandNode + return com.undefined.stellar.data.argument.CommandContext( + parsedArguments, + context.source.bukkitSender, + input + ) + } + + fun getGreedyCommandContext(context: CommandContext): PhraseCommandContext { + val input = context.input.removePrefix("/") + val words = input.split(' ').toMutableList() + + val totalOtherArguments = context.nodes.size - 1 + for (i in (1..totalOtherArguments)) words.removeFirst() + return PhraseCommandContext( + words, + context.source.bukkitSender, + input + ) + } + + @Suppress("DEPRECATION") + fun getCommandListenerWrapper(sender: CommandSender): CommandListenerWrapper { + val overworld = MinecraftServer.getServer().getWorldServer(DimensionManager.OVERWORLD) + return CommandListenerWrapper( + Source(sender), + Vec3D(overworld.spawn), + Vec2F.a, + overworld, + 4, + sender.name, + ChatComponentText(sender.name), + MinecraftServer.getServer(), + null + ) + } + + private data class Source(val sender: CommandSender) : ICommandListener { + override fun sendMessage(message: IChatBaseComponent) { + this.sender.sendMessage(LegacyComponentSerializer.legacySection().serialize(asAdventure(message))) + } + override fun shouldSendSuccess(): Boolean = true + override fun shouldSendFailure(): Boolean = true + override fun shouldBroadcastCommands(): Boolean = false + override fun getBukkitSender(stack: CommandListenerWrapper): CommandSender = this.sender + } + + fun asAdventure(component: IChatBaseComponent): net.kyori.adventure.text.Component = + GsonComponentSerializer.gson().deserializeFromTree(IChatBaseComponent.ChatSerializer.b(component)) + +} \ No newline at end of file diff --git a/v1_14_3/src/main/kotlin/com/undefined/stellar/v1_14_3/CommandRegistrar.kt b/v1_14_3/src/main/kotlin/com/undefined/stellar/v1_14_3/CommandRegistrar.kt new file mode 100644 index 0000000..35229e3 --- /dev/null +++ b/v1_14_3/src/main/kotlin/com/undefined/stellar/v1_14_3/CommandRegistrar.kt @@ -0,0 +1,38 @@ +package com.undefined.stellar.v1_14_3 + +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.registrar.AbstractCommandRegistrar +import com.undefined.stellar.v1_14_3.BrigadierCommandHelper.dispatcher +import org.bukkit.command.CommandSender +import org.bukkit.plugin.java.JavaPlugin + +object CommandRegistrar : AbstractCommandRegistrar { + + override fun register(command: AbstractStellarCommand<*>, plugin: JavaPlugin) { + BrigadierCommandHelper.handleHelpTopic(command) + for (name in command.aliases + command.name) + BrigadierCommandHelper.register(CommandAdapter.getBaseCommand(command, name)) + } + + override fun handleCommandFailure(sender: CommandSender, input: String): Boolean { + val results = dispatcher.parse(input, BrigadierCommandHelper.COMMAND_SOURCE) + val context = results.context.withSource(CommandContextAdapter.getCommandListenerWrapper(sender)).build(input) + + if (results.reader.remainingLength == 0) return false + if (context.nodes.isEmpty()) return false + + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val argument = BrigadierCommandHelper.getArguments(baseCommand, context).lastOrNull() + argument?.let { + BrigadierCommandHelper.handleFailureMessageAndExecutions(argument, context) + if (argument.hideDefaultFailureMessages.hide) return true + } ?: run { + BrigadierCommandHelper.handleFailureMessageAndExecutions(baseCommand, context) + if (baseCommand.hideDefaultFailureMessages.hide) return true + } + + return baseCommand.hasGlobalHiddenDefaultFailureMessages() + } + +} \ No newline at end of file diff --git a/v1_14_4/build.gradle.kts b/v1_14_4/build.gradle.kts new file mode 100644 index 0000000..4f8bfec --- /dev/null +++ b/v1_14_4/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + kotlin("jvm") version "1.9.22" +} + +repositories { + mavenLocal() +} + +dependencies { + compileOnly("org.spigotmc:spigot:1.14.4-R0.1-SNAPSHOT") + compileOnly(project(":common")) +} + +tasks { + compileKotlin { + kotlinOptions.jvmTarget = "1.8" + } + compileJava { + options.release.set(8) + } +} + +java { + disableAutoTargetJvm() +} + +kotlin { + jvmToolchain(21) +} \ No newline at end of file diff --git a/v1_14_4/src/main/kotlin/com/undefined/stellar/v1_14_4/ArgumentHelper.kt b/v1_14_4/src/main/kotlin/com/undefined/stellar/v1_14_4/ArgumentHelper.kt new file mode 100644 index 0000000..c71941d --- /dev/null +++ b/v1_14_4/src/main/kotlin/com/undefined/stellar/v1_14_4/ArgumentHelper.kt @@ -0,0 +1,434 @@ +package com.undefined.stellar.v1_14_4 + +import com.mojang.brigadier.arguments.* +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 com.mojang.brigadier.context.ParsedArgument +import com.mojang.brigadier.context.StringRange +import com.mojang.brigadier.exceptions.CommandSyntaxException +import com.mojang.brigadier.suggestion.SuggestionProvider +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.block.BlockDataArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.argument.types.custom.ListArgument +import com.undefined.stellar.argument.types.entity.EntityDisplayType +import com.undefined.stellar.argument.types.item.ItemSlotArgument +import com.undefined.stellar.argument.types.item.ItemSlotsArgument +import com.undefined.stellar.argument.types.math.AxisArgument +import com.undefined.stellar.argument.types.misc.NamespacedKeyArgument +import com.undefined.stellar.argument.types.misc.UUIDArgument +import com.undefined.stellar.argument.types.player.GameModeArgument +import com.undefined.stellar.argument.types.primitive.* +import com.undefined.stellar.argument.types.registry.* +import com.undefined.stellar.argument.types.scoreboard.DisplaySlotArgument +import com.undefined.stellar.argument.types.scoreboard.ScoreHolderType +import com.undefined.stellar.argument.types.structure.LootTableArgument +import com.undefined.stellar.argument.types.structure.MirrorArgument +import com.undefined.stellar.argument.types.structure.StructureRotationArgument +import com.undefined.stellar.argument.types.world.HeightMapArgument +import com.undefined.stellar.argument.types.world.LocationArgument +import com.undefined.stellar.argument.types.world.LocationType +import com.undefined.stellar.data.argument.Anchor +import com.undefined.stellar.data.argument.Operation +import com.undefined.stellar.data.argument.ParticleData +import com.undefined.stellar.exception.ArgumentVersionMismatchException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import com.undefined.stellar.exception.UnsupportedArgumentException +import com.undefined.stellar.util.NMSVersion +import com.undefined.stellar.util.ReflectionUtil +import com.undefined.stellar.util.executePrivateMethod +import net.kyori.adventure.text.format.Style +import net.kyori.adventure.text.format.TextColor +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.minecraft.server.v1_14_R1.* +import org.bukkit.* +import org.bukkit.Particle +import org.bukkit.Registry +import org.bukkit.World +import org.bukkit.block.Block +import org.bukkit.block.data.BlockData +import org.bukkit.craftbukkit.v1_14_R1.block.data.CraftBlockData +import org.bukkit.craftbukkit.v1_14_R1.CraftParticle +import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftItemStack +import org.bukkit.event.inventory.InventoryType +import org.bukkit.inventory.ItemStack +import org.bukkit.scoreboard.DisplaySlot +import java.time.Duration +import java.util.* +import java.util.function.Predicate + +@Suppress("UNCHECKED_CAST", "DEPRECATION") +object ArgumentHelper { + + fun getLiteralArguments(argument: AbstractStellarArgument<*>): List> { + val arguments: MutableList> = mutableListOf() + for (name in argument.aliases + argument.name) + arguments.add(LiteralArgumentBuilder.literal(name)) + return arguments + } + + fun getRequiredArgumentBuilder(argument: AbstractStellarArgument<*>): RequiredArgumentBuilder { + val argumentBuilder: RequiredArgumentBuilder = RequiredArgumentBuilder.argument(argument.name, getArgumentType(argument)) + getSuggestions(argument)?.let { argumentBuilder.suggests(it) } + return argumentBuilder + } + + private fun > getSuggestions(argument: T): SuggestionProvider? = + when (argument) { + is GameEventArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MOB_EFFECT.keySet(), builder) + } + is VillagerProfessionArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_PROFESSION.keySet(), builder) + } + is VillagerTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_TYPE.keySet(), builder) + } + is BiomeArgument -> SuggestionProvider { context, builder -> + CompletionProviders.d.getSuggestions(context, builder) + } + is EntityTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.ENTITY_TYPE.keySet(), builder) + } + is MemoryKeyArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MEMORY_MODULE_TYPE.keySet(), builder) + } + else -> null + } + + private fun > getArgumentType(argument: T): ArgumentType<*> = + when (argument) { + is ListArgument<*> -> getArgumentType(argument.type) + is CustomArgument<*> -> getArgumentType(argument.type) + is StringArgument -> brigadier(argument.type) + is PhraseArgument -> brigadier(StringType.PHRASE) + is IntegerArgument -> IntegerArgumentType.integer(argument.min, argument.max) + is LongArgument -> LongArgumentType.longArg(argument.min, argument.max) + is FloatArgument -> FloatArgumentType.floatArg(argument.min, argument.max) + is DoubleArgument -> DoubleArgumentType.doubleArg(argument.min, argument.max) + is BooleanArgument -> BoolArgumentType.bool() + is com.undefined.stellar.argument.types.entity.EntityArgument -> brigadier(argument.type) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a() + is LocationArgument -> when (argument.type) { + LocationType.LOCATION_3D -> ArgumentPosition.a() + LocationType.LOCATION_2D -> ArgumentVec2I.a() + LocationType.PRECISE_LOCATION_2D -> ArgumentVec3.a() + LocationType.PRECISE_LOCATION_3D -> ArgumentVec2.a() + } + is BlockDataArgument -> ArgumentTile.a() + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> ArgumentBlockPredicate.a() + is com.undefined.stellar.argument.types.item.ItemArgument -> ArgumentItemStack.a() + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> ArgumentItemPredicate.a() + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a() + is com.undefined.stellar.argument.types.text.ComponentArgument -> ArgumentChatComponent.a() + is com.undefined.stellar.argument.types.text.StyleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.text.MessageArgument -> ArgumentChat.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> ArgumentScoreboardObjective.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a() + is com.undefined.stellar.argument.types.math.OperationArgument -> ArgumentMathOperation.a() + is com.undefined.stellar.argument.types.world.ParticleArgument -> ArgumentParticle.a() + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> ArgumentRotation.a() + is DisplaySlotArgument -> ArgumentScoreboardSlot.a() + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a() + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b() + } + is AxisArgument -> ArgumentRotationAxis.a() + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> ArgumentScoreboardTeam.a() + is ItemSlotArgument -> ArgumentInventorySlot.a() + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> ArgumentMinecraftKeyRegistered.a() + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> ArgumentAnchor.a() + is com.undefined.stellar.argument.types.math.RangeArgument -> ReflectionUtil.executePrivateMethod, ArgumentCriterionValue<*>>("a") + is com.undefined.stellar.argument.types.world.DimensionArgument -> ArgumentDimension.a() + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> ArgumentTime.a() + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> throwArgumentVersionException(argument) + is GameEventArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> ArgumentMinecraftKeyRegistered.a() + is VillagerTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> throwArgumentVersionException(argument) + is AttributeArgument -> ArgumentMinecraftKeyRegistered.a() + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> ArgumentMinecraftKeyRegistered.a() + else -> throw UnsupportedArgumentException(argument) + } + + fun > getParsedArgument(context: CommandContext, argument: T): Any? { + return when (argument) { + is LiteralStellarArgument -> throw LiteralArgumentMismatchException() + is CustomArgument<*> -> argument.parse(CommandContextAdapter.getStellarCommandContext(context)) + is StringArgument -> StringArgumentType.getString(context, argument.name) + is IntegerArgument -> IntegerArgumentType.getInteger(context, argument.name) + is FloatArgument -> FloatArgumentType.getFloat(context, argument.name) + is DoubleArgument -> DoubleArgumentType.getDouble(context, argument.name) + is BooleanArgument -> BoolArgumentType.getBool(context, argument.name) + is ListArgument<*> -> argument.parse(getParsedArgument(context, argument)) + is com.undefined.stellar.argument.types.entity.EntityArgument -> ArgumentEntity.b(context, argument.name) + .map { it.bukkitEntity }.toMutableList() + .addAll(listOf(ArgumentEntity.a(context, argument.name).bukkitEntity)) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a(context, argument.name) + is LocationArgument -> getLocation(context, argument) + is BlockDataArgument -> CraftBlockData.fromData(ArgumentTile.a(context, argument.name).a()) + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> Predicate { block: Block -> + ArgumentBlockPredicate.a(context, argument.name).test(ShapeDetectorBlock( + context.source.world, + BlockPosition(block.x, block.y, block.z), true + )) + } + is com.undefined.stellar.argument.types.item.ItemArgument -> CraftItemStack.asBukkitCopy( + ArgumentItemStack.a(context, argument.name).a(1, false) + ) + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> Predicate { item: ItemStack -> + ArgumentItemPredicate.a(context, argument.name).test(CraftItemStack.asNMSCopy(item)) + } + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a( + context, + argument.name + ).executePrivateMethod("e").let { Style.style(TextColor.color(it)) } + is com.undefined.stellar.argument.types.text.ComponentArgument -> GsonComponentSerializer.gson() + .deserialize(IChatBaseComponent.ChatSerializer.a( + ArgumentChatComponent.a(context, argument.name) + )) + is com.undefined.stellar.argument.types.text.StyleArgument -> GsonComponentSerializer.gson().deserialize( + getArgumentInput(context, argument.name) ?: return null + ).style() + is com.undefined.stellar.argument.types.text.MessageArgument -> GsonComponentSerializer.gson().deserialize( + IChatBaseComponent.ChatSerializer.a(ArgumentChat.a(context, argument.name)) + ) + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getObjective( + ArgumentScoreboardObjective.a(context, argument.name).name + ) + + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a( + context, + argument.name + ).name + is com.undefined.stellar.argument.types.math.OperationArgument -> Operation.getOperation( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.world.ParticleArgument -> { + val particleOptions = ArgumentParticle.a(context, argument.name) + getParticleData(CraftParticle.toBukkit(particleOptions.particle), particleOptions) + } + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> { + val rotation = ArgumentRotation.a(context, argument.name).a(context.source) + Location(context.source.world.world, rotation.x, rotation.y, rotation.z) + } + is DisplaySlotArgument -> getBukkitDisplaySlot(ArgumentScoreboardSlot.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a(context, argument.name) + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b(context, argument.name) + } + is AxisArgument -> getBukkitAxis(ArgumentRotationAxis.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getTeam( + ArgumentScoreboardTeam.a(context, argument.name).name + ) + is ItemSlotArgument -> ArgumentInventorySlot.a(context, argument.name) + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> NamespacedKey( + ArgumentMinecraftKeyRegistered.c(context, argument.name).namespace, + ArgumentMinecraftKeyRegistered.c(context, argument.name).key + ) + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> Anchor.getFromName( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.math.RangeArgument -> { + val range = ArgumentCriterionValue.b.a(context, argument.name) + IntRange(range.a() ?: 1, range.b() ?: 2) + } + is com.undefined.stellar.argument.types.world.DimensionArgument -> World.Environment.getEnvironment(ArgumentDimension.a(context, argument.name).dimensionID) + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> Duration.ofSeconds(IntegerArgumentType.getInteger(context, argument.name).toLong() / 20) + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> throwArgumentVersionException(argument) + is GameEventArgument -> throwArgumentVersionException(argument) + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> Registry.VILLAGER_PROFESSION.get(getId(context, argument.name)) + is VillagerTypeArgument -> Registry.VILLAGER_TYPE.get(getId(context, argument.name)) + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> getInventoryType( + IRegistry.MENU[ArgumentMinecraftKeyRegistered.c(context, argument.name)] + ) + is AttributeArgument -> throwArgumentVersionException(argument) + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> Registry.BIOME.get(getId(context, argument.name)) + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> Registry.ENTITY_TYPE.get(getId(context, argument.name)) + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> Registry.MEMORY_MODULE_TYPE.get(getId(context, argument.name)) + else -> throw UnsupportedArgumentException(argument) + } + } + + fun getArgumentInput(context: CommandContext, name: String): String? { + val field = CommandContext::class.java.getDeclaredField("arguments") + field.isAccessible = true + val arguments: Map> = field.get(context) as Map> + val argument = arguments[name] ?: return null + val range = StringRange.between(argument.range.start, context.input.length) + return range.get(context.input) + } + + private fun getInventoryType(menu: Containers<*>?): InventoryType = when (menu) { + Containers.GENERIC_9X1 -> InventoryType.CHEST + Containers.GENERIC_9X2 -> InventoryType.CHEST + Containers.GENERIC_9X3 -> InventoryType.CHEST + Containers.GENERIC_9X4 -> InventoryType.CHEST + Containers.GENERIC_9X5 -> InventoryType.CHEST + Containers.GENERIC_9X6 -> InventoryType.CHEST + Containers.GENERIC_3X3 -> InventoryType.WORKBENCH + Containers.ANVIL -> InventoryType.ANVIL + Containers.BEACON -> InventoryType.BEACON + Containers.BLAST_FURNACE -> InventoryType.BLAST_FURNACE + Containers.BREWING_STAND -> InventoryType.BREWING + Containers.CRAFTING -> InventoryType.CRAFTING + Containers.ENCHANTMENT -> InventoryType.ENCHANTING + Containers.FURNACE -> InventoryType.FURNACE + Containers.GRINDSTONE -> InventoryType.GRINDSTONE + Containers.HOPPER -> InventoryType.HOPPER + Containers.LECTERN -> InventoryType.LECTERN + Containers.LOOM -> InventoryType.LOOM + Containers.MERCHANT -> InventoryType.MERCHANT + Containers.SHULKER_BOX -> InventoryType.SHULKER_BOX + Containers.SMOKER -> InventoryType.SMOKER + Containers.CARTOGRAPHY -> InventoryType.CARTOGRAPHY + Containers.STONECUTTER -> InventoryType.STONECUTTER + else -> throw IllegalStateException("No inventory type found! This is not intentional behaviour, please contact the developers.") + } + + @Throws(CommandSyntaxException::class) + private fun getId( + context: CommandContext, + name: String + ): NamespacedKey { + val key = ArgumentMinecraftKeyRegistered.c(context, name) + return NamespacedKey(key.namespace, key.key) + } + + private fun brigadier(type: StringType): StringArgumentType = when (type) { + StringType.WORD -> StringArgumentType.word() + StringType.QUOTABLE_PHRASE -> StringArgumentType.string() + StringType.PHRASE -> StringArgumentType.greedyString() + } + + private fun brigadier(type: EntityDisplayType): ArgumentEntity = when (type) { + EntityDisplayType.ENTITY -> ReflectionUtil.executePrivateMethod("a") + EntityDisplayType.ENTITIES -> ArgumentEntity.multipleEntities() + EntityDisplayType.PLAYER -> ArgumentEntity.c() + EntityDisplayType.PLAYERS -> ArgumentEntity.d() + } + + private fun getBukkitAxis(argument: EnumSet): EnumSet = + argument.mapTo(EnumSet.noneOf(Axis::class.java)) { + when (it) { + EnumDirection.EnumAxis.X -> Axis.X + EnumDirection.EnumAxis.Y -> Axis.Y + EnumDirection.EnumAxis.Z -> Axis.Z + null -> Axis.X + } + } + + private fun getBukkitDisplaySlot(slot: Int): DisplaySlot = when (slot) { + 0 -> DisplaySlot.PLAYER_LIST + 2 -> DisplaySlot.BELOW_NAME + else -> DisplaySlot.SIDEBAR + } + + private fun getParticleData( + particle: Particle, + particleOptions: ParticleParam + ): ParticleData<*> = when (particleOptions) { + is ParticleType -> ParticleData(particle, null) + is ParticleParamBlock -> ParticleData(particle, CraftBlockData.fromData(particleOptions.executePrivateMethod("c"))) + is ParticleParamRedstone -> { + val colors = particleOptions.a().split(" ") + val red = colors[1].toFloat() + val green = colors[2].toFloat() + val blue = colors[3].toFloat() + val scale = colors[4].toFloat() + ParticleData( + particle, + Particle.DustOptions( + Color.fromRGB( + (red * 255.0f).toInt(), + (green * 255.0f).toInt(), (blue * 255.0f).toInt() + ), scale + ) + ) + } + is ParticleParamItem -> ParticleData( + particle, + CraftItemStack.asBukkitCopy(particleOptions.executePrivateMethod("c")) + ) + else -> ParticleData(particle, null) + } + + private fun getLocation(context: CommandContext, command: LocationArgument): Location { + val world = context.source.world.world + return when (command.type) { + LocationType.LOCATION_3D -> toLocation(world, context.getArgument(command.name, IVectorPosition::class.java).c(context.source)) + LocationType.LOCATION_2D -> toLocation(world, ArgumentVec2I.a(context, command.name)) + LocationType.PRECISE_LOCATION_3D -> toLocation(world, ArgumentVec3.a(context, command.name)) + LocationType.PRECISE_LOCATION_2D -> toLocation(world, ArgumentVec2.a(context, command.name)) + } + } + + private fun toLocation(world: World, position: BlockPosition) = + Location(world, position.x.toDouble(), position.y.toDouble(), position.z.toDouble()) + private fun toLocation(world: World, position: BlockPosition2D) = + Location(world, position.a.toDouble(), 0.0, position.b.toDouble()) + private fun toLocation(world: World, vec: Vec3D) = + Location(world, vec.x, vec.y, vec.z) + private fun toLocation(world: World, vec: Vec2F) = + Location(world, vec.i.toDouble(), 0.0, vec.j.toDouble()) + + private fun throwArgumentVersionException(argument: AbstractStellarArgument<*>): Nothing = + throw ArgumentVersionMismatchException(argument, NMSVersion.version) + +} \ No newline at end of file diff --git a/v1_14_4/src/main/kotlin/com/undefined/stellar/v1_14_4/BrigadierCommandHelper.kt b/v1_14_4/src/main/kotlin/com/undefined/stellar/v1_14_4/BrigadierCommandHelper.kt new file mode 100644 index 0000000..d71f234 --- /dev/null +++ b/v1_14_4/src/main/kotlin/com/undefined/stellar/v1_14_4/BrigadierCommandHelper.kt @@ -0,0 +1,76 @@ +package com.undefined.stellar.v1_14_4 + +import com.mojang.brigadier.CommandDispatcher +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.tree.LiteralCommandNode +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.data.help.CustomCommandHelpTopic +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_14_R1.CommandListenerWrapper +import net.minecraft.server.v1_14_R1.MinecraftServer +import org.bukkit.Bukkit + +@Suppress("DEPRECATION") +object BrigadierCommandHelper { + + val COMMAND_SOURCE: CommandListenerWrapper by lazy { + MinecraftServer.getServer().serverCommandListener + } + val dispatcher: CommandDispatcher by lazy { + MinecraftServer.getServer().functionData.d() + } + + fun register(command: LiteralArgumentBuilder): LiteralCommandNode? = + dispatcher.register(command) + + fun handleHelpTopic(command: AbstractStellarCommand<*>) { + Bukkit.getServer().helpMap.addTopic( + CustomCommandHelpTopic(command.name, command.description, command.helpTopic) { + val context = MinecraftServer.getServer().serverCommandListener + val requirements = command.requirements.all { it(this) } + val permissionRequirements = command.permissionRequirements.all { + if (it.permission.isEmpty()) context.hasPermission(it.level) + else context.hasPermission(it.level, it.permission) + } + requirements.and(permissionRequirements) + } + ) + } + + fun handleExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + val stellarContext = CommandContextAdapter.getStellarCommandContext(context) + + for (runnable in command.base.runnables) runnable(stellarContext) + val arguments = getArguments(command.base, context) + for (argument in arguments) for (runnable in argument.runnables) runnable(stellarContext) + for (execution in command.executions) execution(stellarContext) + } + + fun fulfillsRequirements(command: AbstractStellarCommand<*>, source: CommandListenerWrapper): Boolean { + val fulfillsExecutionRequirements = command.requirements.all { it(source.bukkitSender) } + val fulfillsPermissionRequirements = command.permissionRequirements.all { source.hasPermission(it.level, it.permission) } + return fulfillsExecutionRequirements.and(fulfillsPermissionRequirements) + } + + fun handleFailureMessageAndExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + for (execution in command.failureExecutions) execution(CommandContextAdapter.getStellarCommandContext(context)) + for (message in command.failureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + for (message in command.globalFailureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + } + + fun getArguments( + baseCommand: AbstractStellarCommand<*>, + context: CommandContext, + currentIndex: Int = 1, + listOfArguments: List> = emptyList() + ): List> { + if (listOfArguments.size == context.nodes.size - 1) return listOfArguments + for (argument in baseCommand.arguments) + if (argument.name == context.nodes[currentIndex].node.name) + return getArguments(argument, context, currentIndex + 1, listOfArguments + argument) + return emptyList() + } + +} \ No newline at end of file diff --git a/v1_14_4/src/main/kotlin/com/undefined/stellar/v1_14_4/CommandAdapter.kt b/v1_14_4/src/main/kotlin/com/undefined/stellar/v1_14_4/CommandAdapter.kt new file mode 100644 index 0000000..d38b01b --- /dev/null +++ b/v1_14_4/src/main/kotlin/com/undefined/stellar/v1_14_4/CommandAdapter.kt @@ -0,0 +1,96 @@ +package com.undefined.stellar.v1_14_4 + +import com.mojang.brigadier.Command +import com.mojang.brigadier.builder.ArgumentBuilder +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.primitive.PhraseArgument +import net.minecraft.server.v1_14_R1.CommandListenerWrapper + +object CommandAdapter { + + fun getBaseCommand(command: AbstractStellarCommand<*>, name: String = command.name): LiteralArgumentBuilder { + val brigadierCommand = LiteralArgumentBuilder.literal(name) + handleCommandFunctions(command, brigadierCommand) + handleArguments(command, brigadierCommand) + return brigadierCommand + } + + private fun handleCommandFunctions(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + if (command.executions.isNotEmpty() || command.executions.isNotEmpty()) + brigadierCommand.executes { context -> + BrigadierCommandHelper.handleExecutions(command, context) + 1 + } + brigadierCommand.requires { source -> + BrigadierCommandHelper.fulfillsRequirements(command, source) + } + } + + private fun handleArguments(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + for (argument in command.arguments) { + when (argument) { + is LiteralStellarArgument -> handleLiteralArgument(argument, brigadierCommand) + is PhraseArgument-> handlePhraseArgument(argument, brigadierCommand) + else -> handleRequiredArgument(argument, brigadierCommand) + } + } + } + + private fun handleLiteralArgument(argument: LiteralStellarArgument, brigadierCommand: ArgumentBuilder) { + for (argumentBuilder in ArgumentHelper.getLiteralArguments(argument)) { + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + } + + private fun handlePhraseArgument(argument: PhraseArgument, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleGreedyStringWordFunctions(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + + private fun handleGreedyStringWordFunctions(argument: PhraseArgument, argumentBuilder: RequiredArgumentBuilder) { + argumentBuilder.executes { context -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + + for (i in greedyContext.arguments.indices) { + val word = argument.words[i] ?: continue + for (runnable in word.runnables) runnable(greedyContext) + if (i == greedyContext.arguments.lastIndex) + for (execution in word.executions) execution(greedyContext) + } + Command.SINGLE_SUCCESS + } + + argumentBuilder.suggests { context, builder -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + var prevChar = ' ' + val input = ArgumentHelper.getArgumentInput(context, argument.name) ?: "" + val amountOfSpaces: Int = if (input.isEmpty()) 0 else input.count { + if (prevChar == ' ' && it == ' ') return@count false + prevChar = it + it == ' ' + } + val newBuilder = builder.createOffset(builder.input.lastIndexOf(' ') + 1) + val word = argument.words[amountOfSpaces] ?: return@suggests newBuilder.buildFuture() + for (stellarSuggestion in word.suggestions) + for (suggestion in stellarSuggestion.get(greedyContext)) + newBuilder.suggest(suggestion.text) { suggestion.tooltip } + newBuilder.buildFuture() + } + } + + private fun handleRequiredArgument(argument: AbstractStellarArgument<*>, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + +} diff --git a/v1_14_4/src/main/kotlin/com/undefined/stellar/v1_14_4/CommandContextAdapter.kt b/v1_14_4/src/main/kotlin/com/undefined/stellar/v1_14_4/CommandContextAdapter.kt new file mode 100644 index 0000000..7811c56 --- /dev/null +++ b/v1_14_4/src/main/kotlin/com/undefined/stellar/v1_14_4/CommandContextAdapter.kt @@ -0,0 +1,83 @@ +package com.undefined.stellar.v1_14_4 + +import com.mojang.brigadier.context.CommandContext +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.data.argument.CommandNode +import com.undefined.stellar.data.argument.PhraseCommandContext +import com.undefined.stellar.exception.DuplicateArgumentNameException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_14_R1.* +import org.bukkit.command.CommandSender + +object CommandContextAdapter { + + fun getStellarCommandContext(context: CommandContext): com.undefined.stellar.data.argument.CommandContext { + val input = context.input.removePrefix("/") + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val arguments = BrigadierCommandHelper.getArguments(baseCommand, context) + if (arguments.filter { it !is LiteralStellarArgument }.groupingBy { it.name }.eachCount().any { it.value > 1 }) throw DuplicateArgumentNameException() + val parsedArguments: CommandNode = + BrigadierCommandHelper.getArguments(baseCommand, context) + .associate, String, (com.undefined.stellar.data.argument.CommandContext) -> Any?> { argument -> + if (argument is CustomArgument) return@associate Pair(argument.name) { argument.parse(it) } + if (argument is LiteralStellarArgument) return@associate Pair(argument.name) { throw LiteralArgumentMismatchException() } + Pair(argument.name) { + ArgumentHelper.getParsedArgument(context, argument) + } + } as CommandNode + return com.undefined.stellar.data.argument.CommandContext( + parsedArguments, + context.source.bukkitSender, + input + ) + } + + fun getGreedyCommandContext(context: CommandContext): PhraseCommandContext { + val input = context.input.removePrefix("/") + val words = input.split(' ').toMutableList() + + val totalOtherArguments = context.nodes.size - 1 + for (i in (1..totalOtherArguments)) words.removeFirst() + return PhraseCommandContext( + words, + context.source.bukkitSender, + input + ) + } + + @Suppress("DEPRECATION") + fun getCommandListenerWrapper(sender: CommandSender): CommandListenerWrapper { + val overworld = MinecraftServer.getServer().getWorldServer(DimensionManager.OVERWORLD) + return CommandListenerWrapper( + Source(sender), + Vec3D(overworld.spawn), + Vec2F.a, + overworld, + 4, + sender.name, + ChatComponentText(sender.name), + MinecraftServer.getServer(), + null + ) + } + + private data class Source(val sender: CommandSender) : ICommandListener { + override fun sendMessage(message: IChatBaseComponent) { + this.sender.sendMessage(LegacyComponentSerializer.legacySection().serialize(asAdventure(message))) + } + override fun shouldSendSuccess(): Boolean = true + override fun shouldSendFailure(): Boolean = true + override fun shouldBroadcastCommands(): Boolean = false + override fun getBukkitSender(stack: CommandListenerWrapper): CommandSender = this.sender + } + + fun asAdventure(component: IChatBaseComponent): net.kyori.adventure.text.Component = + GsonComponentSerializer.gson().deserializeFromTree(IChatBaseComponent.ChatSerializer.b(component)) + +} \ No newline at end of file diff --git a/v1_14_4/src/main/kotlin/com/undefined/stellar/v1_14_4/CommandRegistrar.kt b/v1_14_4/src/main/kotlin/com/undefined/stellar/v1_14_4/CommandRegistrar.kt new file mode 100644 index 0000000..bc8250f --- /dev/null +++ b/v1_14_4/src/main/kotlin/com/undefined/stellar/v1_14_4/CommandRegistrar.kt @@ -0,0 +1,38 @@ +package com.undefined.stellar.v1_14_4 + +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.registrar.AbstractCommandRegistrar +import com.undefined.stellar.v1_14_4.BrigadierCommandHelper.dispatcher +import org.bukkit.command.CommandSender +import org.bukkit.plugin.java.JavaPlugin + +object CommandRegistrar : AbstractCommandRegistrar { + + override fun register(command: AbstractStellarCommand<*>, plugin: JavaPlugin) { + BrigadierCommandHelper.handleHelpTopic(command) + for (name in command.aliases + command.name) + BrigadierCommandHelper.register(CommandAdapter.getBaseCommand(command, name)) + } + + override fun handleCommandFailure(sender: CommandSender, input: String): Boolean { + val results = dispatcher.parse(input, BrigadierCommandHelper.COMMAND_SOURCE) + val context = results.context.withSource(CommandContextAdapter.getCommandListenerWrapper(sender)).build(input) + + if (results.reader.remainingLength == 0) return false + if (context.nodes.isEmpty()) return false + + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val argument = BrigadierCommandHelper.getArguments(baseCommand, context).lastOrNull() + argument?.let { + BrigadierCommandHelper.handleFailureMessageAndExecutions(argument, context) + if (argument.hideDefaultFailureMessages.hide) return true + } ?: run { + BrigadierCommandHelper.handleFailureMessageAndExecutions(baseCommand, context) + if (baseCommand.hideDefaultFailureMessages.hide) return true + } + + return baseCommand.hasGlobalHiddenDefaultFailureMessages() + } + +} \ No newline at end of file diff --git a/v1_15/build.gradle.kts b/v1_15/build.gradle.kts new file mode 100644 index 0000000..8b339f4 --- /dev/null +++ b/v1_15/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + kotlin("jvm") version "1.9.22" +} + +repositories { + mavenLocal() +} + +dependencies { + compileOnly("org.spigotmc:spigot:1.15-R0.1-SNAPSHOT") + compileOnly(project(":common")) +} + +tasks { + compileKotlin { + kotlinOptions.jvmTarget = "1.8" + } + compileJava { + options.release.set(8) + } +} + +java { + disableAutoTargetJvm() +} + +kotlin { + jvmToolchain(21) +} \ No newline at end of file diff --git a/v1_15/src/main/kotlin/com/undefined/stellar/v1_15/ArgumentHelper.kt b/v1_15/src/main/kotlin/com/undefined/stellar/v1_15/ArgumentHelper.kt new file mode 100644 index 0000000..f218fd3 --- /dev/null +++ b/v1_15/src/main/kotlin/com/undefined/stellar/v1_15/ArgumentHelper.kt @@ -0,0 +1,434 @@ +package com.undefined.stellar.v1_15 + +import com.mojang.brigadier.arguments.* +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 com.mojang.brigadier.context.ParsedArgument +import com.mojang.brigadier.context.StringRange +import com.mojang.brigadier.exceptions.CommandSyntaxException +import com.mojang.brigadier.suggestion.SuggestionProvider +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.block.BlockDataArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.argument.types.custom.ListArgument +import com.undefined.stellar.argument.types.entity.EntityDisplayType +import com.undefined.stellar.argument.types.item.ItemSlotArgument +import com.undefined.stellar.argument.types.item.ItemSlotsArgument +import com.undefined.stellar.argument.types.math.AxisArgument +import com.undefined.stellar.argument.types.misc.NamespacedKeyArgument +import com.undefined.stellar.argument.types.misc.UUIDArgument +import com.undefined.stellar.argument.types.player.GameModeArgument +import com.undefined.stellar.argument.types.primitive.* +import com.undefined.stellar.argument.types.registry.* +import com.undefined.stellar.argument.types.scoreboard.DisplaySlotArgument +import com.undefined.stellar.argument.types.scoreboard.ScoreHolderType +import com.undefined.stellar.argument.types.structure.LootTableArgument +import com.undefined.stellar.argument.types.structure.MirrorArgument +import com.undefined.stellar.argument.types.structure.StructureRotationArgument +import com.undefined.stellar.argument.types.world.HeightMapArgument +import com.undefined.stellar.argument.types.world.LocationArgument +import com.undefined.stellar.argument.types.world.LocationType +import com.undefined.stellar.data.argument.Anchor +import com.undefined.stellar.data.argument.Operation +import com.undefined.stellar.data.argument.ParticleData +import com.undefined.stellar.exception.ArgumentVersionMismatchException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import com.undefined.stellar.exception.UnsupportedArgumentException +import com.undefined.stellar.util.NMSVersion +import com.undefined.stellar.util.ReflectionUtil +import com.undefined.stellar.util.executePrivateMethod +import net.kyori.adventure.text.format.Style +import net.kyori.adventure.text.format.TextColor +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.minecraft.server.v1_15_R1.* +import org.bukkit.* +import org.bukkit.Particle +import org.bukkit.Registry +import org.bukkit.World +import org.bukkit.block.Block +import org.bukkit.block.data.BlockData +import org.bukkit.craftbukkit.v1_15_R1.block.data.CraftBlockData +import org.bukkit.craftbukkit.v1_15_R1.CraftParticle +import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack +import org.bukkit.event.inventory.InventoryType +import org.bukkit.inventory.ItemStack +import org.bukkit.scoreboard.DisplaySlot +import java.time.Duration +import java.util.* +import java.util.function.Predicate + +@Suppress("UNCHECKED_CAST", "DEPRECATION") +object ArgumentHelper { + + fun getLiteralArguments(argument: AbstractStellarArgument<*>): List> { + val arguments: MutableList> = mutableListOf() + for (name in argument.aliases + argument.name) + arguments.add(LiteralArgumentBuilder.literal(name)) + return arguments + } + + fun getRequiredArgumentBuilder(argument: AbstractStellarArgument<*>): RequiredArgumentBuilder { + val argumentBuilder: RequiredArgumentBuilder = RequiredArgumentBuilder.argument(argument.name, getArgumentType(argument)) + getSuggestions(argument)?.let { argumentBuilder.suggests(it) } + return argumentBuilder + } + + private fun > getSuggestions(argument: T): SuggestionProvider? = + when (argument) { + is GameEventArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MOB_EFFECT.keySet(), builder) + } + is VillagerProfessionArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_PROFESSION.keySet(), builder) + } + is VillagerTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_TYPE.keySet(), builder) + } + is BiomeArgument -> SuggestionProvider { context, builder -> + CompletionProviders.d.getSuggestions(context, builder) + } + is EntityTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.ENTITY_TYPE.keySet(), builder) + } + is MemoryKeyArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MEMORY_MODULE_TYPE.keySet(), builder) + } + else -> null + } + + private fun > getArgumentType(argument: T): ArgumentType<*> = + when (argument) { + is ListArgument<*> -> getArgumentType(argument.type) + is CustomArgument<*> -> getArgumentType(argument.type) + is StringArgument -> brigadier(argument.type) + is PhraseArgument -> brigadier(StringType.PHRASE) + is IntegerArgument -> IntegerArgumentType.integer(argument.min, argument.max) + is LongArgument -> LongArgumentType.longArg(argument.min, argument.max) + is FloatArgument -> FloatArgumentType.floatArg(argument.min, argument.max) + is DoubleArgument -> DoubleArgumentType.doubleArg(argument.min, argument.max) + is BooleanArgument -> BoolArgumentType.bool() + is com.undefined.stellar.argument.types.entity.EntityArgument -> brigadier(argument.type) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a() + is LocationArgument -> when (argument.type) { + LocationType.LOCATION_3D -> ArgumentPosition.a() + LocationType.LOCATION_2D -> ArgumentVec2I.a() + LocationType.PRECISE_LOCATION_2D -> ArgumentVec3.a() + LocationType.PRECISE_LOCATION_3D -> ArgumentVec2.a() + } + is BlockDataArgument -> ArgumentTile.a() + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> ArgumentBlockPredicate.a() + is com.undefined.stellar.argument.types.item.ItemArgument -> ArgumentItemStack.a() + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> ArgumentItemPredicate.a() + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a() + is com.undefined.stellar.argument.types.text.ComponentArgument -> ArgumentChatComponent.a() + is com.undefined.stellar.argument.types.text.StyleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.text.MessageArgument -> ArgumentChat.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> ArgumentScoreboardObjective.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a() + is com.undefined.stellar.argument.types.math.OperationArgument -> ArgumentMathOperation.a() + is com.undefined.stellar.argument.types.world.ParticleArgument -> ArgumentParticle.a() + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> ArgumentRotation.a() + is DisplaySlotArgument -> ArgumentScoreboardSlot.a() + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a() + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b() + } + is AxisArgument -> ArgumentRotationAxis.a() + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> ArgumentScoreboardTeam.a() + is ItemSlotArgument -> ArgumentInventorySlot.a() + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> ArgumentMinecraftKeyRegistered.a() + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> ArgumentAnchor.a() + is com.undefined.stellar.argument.types.math.RangeArgument -> ReflectionUtil.executePrivateMethod, ArgumentCriterionValue<*>>("a") + is com.undefined.stellar.argument.types.world.DimensionArgument -> ArgumentDimension.a() + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> ArgumentTime.a() + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> throwArgumentVersionException(argument) + is GameEventArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> ArgumentMinecraftKeyRegistered.a() + is VillagerTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> throwArgumentVersionException(argument) + is AttributeArgument -> ArgumentMinecraftKeyRegistered.a() + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> ArgumentMinecraftKeyRegistered.a() + else -> throw UnsupportedArgumentException(argument) + } + + fun > getParsedArgument(context: CommandContext, argument: T): Any? { + return when (argument) { + is LiteralStellarArgument -> throw LiteralArgumentMismatchException() + is CustomArgument<*> -> argument.parse(CommandContextAdapter.getStellarCommandContext(context)) + is StringArgument -> StringArgumentType.getString(context, argument.name) + is IntegerArgument -> IntegerArgumentType.getInteger(context, argument.name) + is FloatArgument -> FloatArgumentType.getFloat(context, argument.name) + is DoubleArgument -> DoubleArgumentType.getDouble(context, argument.name) + is BooleanArgument -> BoolArgumentType.getBool(context, argument.name) + is ListArgument<*> -> argument.parse(getParsedArgument(context, argument)) + is com.undefined.stellar.argument.types.entity.EntityArgument -> ArgumentEntity.b(context, argument.name) + .map { it.bukkitEntity }.toMutableList() + .addAll(listOf(ArgumentEntity.a(context, argument.name).bukkitEntity)) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a(context, argument.name) + is LocationArgument -> getLocation(context, argument) + is BlockDataArgument -> CraftBlockData.fromData(ArgumentTile.a(context, argument.name).a()) + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> Predicate { block: Block -> + ArgumentBlockPredicate.a(context, argument.name).test(ShapeDetectorBlock( + context.source.world, + BlockPosition(block.x, block.y, block.z), true + )) + } + is com.undefined.stellar.argument.types.item.ItemArgument -> CraftItemStack.asBukkitCopy( + ArgumentItemStack.a(context, argument.name).a(1, false) + ) + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> Predicate { item: ItemStack -> + ArgumentItemPredicate.a(context, argument.name).test(CraftItemStack.asNMSCopy(item)) + } + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a( + context, + argument.name + ).executePrivateMethod("e").let { Style.style(TextColor.color(it)) } + is com.undefined.stellar.argument.types.text.ComponentArgument -> GsonComponentSerializer.gson() + .deserialize(IChatBaseComponent.ChatSerializer.a( + ArgumentChatComponent.a(context, argument.name) + )) + is com.undefined.stellar.argument.types.text.StyleArgument -> GsonComponentSerializer.gson().deserialize( + getArgumentInput(context, argument.name) ?: return null + ).style() + is com.undefined.stellar.argument.types.text.MessageArgument -> GsonComponentSerializer.gson().deserialize( + IChatBaseComponent.ChatSerializer.a(ArgumentChat.a(context, argument.name)) + ) + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getObjective( + ArgumentScoreboardObjective.a(context, argument.name).name + ) + + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a( + context, + argument.name + ).name + is com.undefined.stellar.argument.types.math.OperationArgument -> Operation.getOperation( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.world.ParticleArgument -> { + val particleOptions = ArgumentParticle.a(context, argument.name) + getParticleData(CraftParticle.toBukkit(particleOptions.particle), particleOptions) + } + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> { + val rotation = ArgumentRotation.a(context, argument.name).a(context.source) + Location(context.source.world.world, rotation.x, rotation.y, rotation.z) + } + is DisplaySlotArgument -> getBukkitDisplaySlot(ArgumentScoreboardSlot.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a(context, argument.name) + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b(context, argument.name) + } + is AxisArgument -> getBukkitAxis(ArgumentRotationAxis.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getTeam( + ArgumentScoreboardTeam.a(context, argument.name).name + ) + is ItemSlotArgument -> ArgumentInventorySlot.a(context, argument.name) + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> NamespacedKey( + ArgumentMinecraftKeyRegistered.d(context, argument.name).namespace, + ArgumentMinecraftKeyRegistered.d(context, argument.name).key + ) + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> Anchor.getFromName( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.math.RangeArgument -> { + val range = ArgumentCriterionValue.b.a(context, argument.name) + IntRange(range.a() ?: 1, range.b() ?: 2) + } + is com.undefined.stellar.argument.types.world.DimensionArgument -> World.Environment.getEnvironment(ArgumentDimension.a(context, argument.name).dimensionID) + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> Duration.ofSeconds(IntegerArgumentType.getInteger(context, argument.name).toLong() / 20) + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> throwArgumentVersionException(argument) + is GameEventArgument -> throwArgumentVersionException(argument) + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> Registry.VILLAGER_PROFESSION.get(getId(context, argument.name)) + is VillagerTypeArgument -> Registry.VILLAGER_TYPE.get(getId(context, argument.name)) + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> getInventoryType( + IRegistry.MENU[ArgumentMinecraftKeyRegistered.d(context, argument.name)] + ) + is AttributeArgument -> throwArgumentVersionException(argument) + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> Registry.BIOME.get(getId(context, argument.name)) + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> Registry.ENTITY_TYPE.get(getId(context, argument.name)) + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> Registry.MEMORY_MODULE_TYPE.get(getId(context, argument.name)) + else -> throw UnsupportedArgumentException(argument) + } + } + + fun getArgumentInput(context: CommandContext, name: String): String? { + val field = CommandContext::class.java.getDeclaredField("arguments") + field.isAccessible = true + val arguments: Map> = field.get(context) as Map> + val argument = arguments[name] ?: return null + val range = StringRange.between(argument.range.start, context.input.length) + return range.get(context.input) + } + + private fun getInventoryType(menu: Containers<*>?): InventoryType = when (menu) { + Containers.GENERIC_9X1 -> InventoryType.CHEST + Containers.GENERIC_9X2 -> InventoryType.CHEST + Containers.GENERIC_9X3 -> InventoryType.CHEST + Containers.GENERIC_9X4 -> InventoryType.CHEST + Containers.GENERIC_9X5 -> InventoryType.CHEST + Containers.GENERIC_9X6 -> InventoryType.CHEST + Containers.GENERIC_3X3 -> InventoryType.WORKBENCH + Containers.ANVIL -> InventoryType.ANVIL + Containers.BEACON -> InventoryType.BEACON + Containers.BLAST_FURNACE -> InventoryType.BLAST_FURNACE + Containers.BREWING_STAND -> InventoryType.BREWING + Containers.CRAFTING -> InventoryType.CRAFTING + Containers.ENCHANTMENT -> InventoryType.ENCHANTING + Containers.FURNACE -> InventoryType.FURNACE + Containers.GRINDSTONE -> InventoryType.GRINDSTONE + Containers.HOPPER -> InventoryType.HOPPER + Containers.LECTERN -> InventoryType.LECTERN + Containers.LOOM -> InventoryType.LOOM + Containers.MERCHANT -> InventoryType.MERCHANT + Containers.SHULKER_BOX -> InventoryType.SHULKER_BOX + Containers.SMOKER -> InventoryType.SMOKER + Containers.CARTOGRAPHY_TABLE -> InventoryType.CARTOGRAPHY + Containers.STONECUTTER -> InventoryType.STONECUTTER + else -> throw IllegalStateException("No inventory type found! This is not intentional behaviour, please contact the developers.") + } + + @Throws(CommandSyntaxException::class) + private fun getId( + context: CommandContext, + name: String + ): NamespacedKey { + val key = ArgumentMinecraftKeyRegistered.d(context, name) + return NamespacedKey(key.namespace, key.key) + } + + private fun brigadier(type: StringType): StringArgumentType = when (type) { + StringType.WORD -> StringArgumentType.word() + StringType.QUOTABLE_PHRASE -> StringArgumentType.string() + StringType.PHRASE -> StringArgumentType.greedyString() + } + + private fun brigadier(type: EntityDisplayType): ArgumentEntity = when (type) { + EntityDisplayType.ENTITY -> ReflectionUtil.executePrivateMethod("a") + EntityDisplayType.ENTITIES -> ArgumentEntity.multipleEntities() + EntityDisplayType.PLAYER -> ArgumentEntity.c() + EntityDisplayType.PLAYERS -> ArgumentEntity.d() + } + + private fun getBukkitAxis(argument: EnumSet): EnumSet = + argument.mapTo(EnumSet.noneOf(Axis::class.java)) { + when (it) { + EnumDirection.EnumAxis.X -> Axis.X + EnumDirection.EnumAxis.Y -> Axis.Y + EnumDirection.EnumAxis.Z -> Axis.Z + null -> Axis.X + } + } + + private fun getBukkitDisplaySlot(slot: Int): DisplaySlot = when (slot) { + 0 -> DisplaySlot.PLAYER_LIST + 2 -> DisplaySlot.BELOW_NAME + else -> DisplaySlot.SIDEBAR + } + + private fun getParticleData( + particle: Particle, + particleOptions: ParticleParam + ): ParticleData<*> = when (particleOptions) { + is ParticleType -> ParticleData(particle, null) + is ParticleParamBlock -> ParticleData(particle, CraftBlockData.fromData(particleOptions.executePrivateMethod("c"))) + is ParticleParamRedstone -> { + val colors = particleOptions.a().split(" ") + val red = colors[1].toFloat() + val green = colors[2].toFloat() + val blue = colors[3].toFloat() + val scale = colors[4].toFloat() + ParticleData( + particle, + Particle.DustOptions( + Color.fromRGB( + (red * 255.0f).toInt(), + (green * 255.0f).toInt(), (blue * 255.0f).toInt() + ), scale + ) + ) + } + is ParticleParamItem -> ParticleData( + particle, + CraftItemStack.asBukkitCopy(particleOptions.executePrivateMethod("c")) + ) + else -> ParticleData(particle, null) + } + + private fun getLocation(context: CommandContext, command: LocationArgument): Location { + val world = context.source.world.world + return when (command.type) { + LocationType.LOCATION_3D -> toLocation(world, context.getArgument(command.name, IVectorPosition::class.java).c(context.source)) + LocationType.LOCATION_2D -> toLocation(world, ArgumentVec2I.a(context, command.name)) + LocationType.PRECISE_LOCATION_3D -> toLocation(world, ArgumentVec3.a(context, command.name)) + LocationType.PRECISE_LOCATION_2D -> toLocation(world, ArgumentVec2.a(context, command.name)) + } + } + + private fun toLocation(world: World, position: BlockPosition) = + Location(world, position.x.toDouble(), position.y.toDouble(), position.z.toDouble()) + private fun toLocation(world: World, position: BlockPosition2D) = + Location(world, position.a.toDouble(), 0.0, position.b.toDouble()) + private fun toLocation(world: World, vec: Vec3D) = + Location(world, vec.x, vec.y, vec.z) + private fun toLocation(world: World, vec: Vec2F) = + Location(world, vec.i.toDouble(), 0.0, vec.j.toDouble()) + + private fun throwArgumentVersionException(argument: AbstractStellarArgument<*>): Nothing = + throw ArgumentVersionMismatchException(argument, NMSVersion.version) + +} \ No newline at end of file diff --git a/v1_15/src/main/kotlin/com/undefined/stellar/v1_15/BrigadierCommandHelper.kt b/v1_15/src/main/kotlin/com/undefined/stellar/v1_15/BrigadierCommandHelper.kt new file mode 100644 index 0000000..3edeccc --- /dev/null +++ b/v1_15/src/main/kotlin/com/undefined/stellar/v1_15/BrigadierCommandHelper.kt @@ -0,0 +1,76 @@ +package com.undefined.stellar.v1_15 + +import com.mojang.brigadier.CommandDispatcher +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.tree.LiteralCommandNode +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.data.help.CustomCommandHelpTopic +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_15_R1.CommandListenerWrapper +import net.minecraft.server.v1_15_R1.MinecraftServer +import org.bukkit.Bukkit + +@Suppress("DEPRECATION") +object BrigadierCommandHelper { + + val COMMAND_SOURCE: CommandListenerWrapper by lazy { + MinecraftServer.getServer().serverCommandListener + } + val dispatcher: CommandDispatcher by lazy { + MinecraftServer.getServer().functionData.d() + } + + fun register(command: LiteralArgumentBuilder): LiteralCommandNode? = + dispatcher.register(command) + + fun handleHelpTopic(command: AbstractStellarCommand<*>) { + Bukkit.getServer().helpMap.addTopic( + CustomCommandHelpTopic(command.name, command.description, command.helpTopic) { + val context = MinecraftServer.getServer().serverCommandListener + val requirements = command.requirements.all { it(this) } + val permissionRequirements = command.permissionRequirements.all { + if (it.permission.isEmpty()) context.hasPermission(it.level) + else context.hasPermission(it.level, it.permission) + } + requirements.and(permissionRequirements) + } + ) + } + + fun handleExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + val stellarContext = CommandContextAdapter.getStellarCommandContext(context) + + for (runnable in command.base.runnables) runnable(stellarContext) + val arguments = getArguments(command.base, context) + for (argument in arguments) for (runnable in argument.runnables) runnable(stellarContext) + for (execution in command.executions) execution(stellarContext) + } + + fun fulfillsRequirements(command: AbstractStellarCommand<*>, source: CommandListenerWrapper): Boolean { + val fulfillsExecutionRequirements = command.requirements.all { it(source.bukkitSender) } + val fulfillsPermissionRequirements = command.permissionRequirements.all { source.hasPermission(it.level, it.permission) } + return fulfillsExecutionRequirements.and(fulfillsPermissionRequirements) + } + + fun handleFailureMessageAndExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + for (execution in command.failureExecutions) execution(CommandContextAdapter.getStellarCommandContext(context)) + for (message in command.failureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + for (message in command.globalFailureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + } + + fun getArguments( + baseCommand: AbstractStellarCommand<*>, + context: CommandContext, + currentIndex: Int = 1, + listOfArguments: List> = emptyList() + ): List> { + if (listOfArguments.size == context.nodes.size - 1) return listOfArguments + for (argument in baseCommand.arguments) + if (argument.name == context.nodes[currentIndex].node.name) + return getArguments(argument, context, currentIndex + 1, listOfArguments + argument) + return emptyList() + } + +} \ No newline at end of file diff --git a/v1_15/src/main/kotlin/com/undefined/stellar/v1_15/CommandAdapter.kt b/v1_15/src/main/kotlin/com/undefined/stellar/v1_15/CommandAdapter.kt new file mode 100644 index 0000000..9e03e00 --- /dev/null +++ b/v1_15/src/main/kotlin/com/undefined/stellar/v1_15/CommandAdapter.kt @@ -0,0 +1,96 @@ +package com.undefined.stellar.v1_15 + +import com.mojang.brigadier.Command +import com.mojang.brigadier.builder.ArgumentBuilder +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.primitive.PhraseArgument +import net.minecraft.server.v1_15_R1.CommandListenerWrapper + +object CommandAdapter { + + fun getBaseCommand(command: AbstractStellarCommand<*>, name: String = command.name): LiteralArgumentBuilder { + val brigadierCommand = LiteralArgumentBuilder.literal(name) + handleCommandFunctions(command, brigadierCommand) + handleArguments(command, brigadierCommand) + return brigadierCommand + } + + private fun handleCommandFunctions(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + if (command.executions.isNotEmpty() || command.executions.isNotEmpty()) + brigadierCommand.executes { context -> + BrigadierCommandHelper.handleExecutions(command, context) + 1 + } + brigadierCommand.requires { source -> + BrigadierCommandHelper.fulfillsRequirements(command, source) + } + } + + private fun handleArguments(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + for (argument in command.arguments) { + when (argument) { + is LiteralStellarArgument -> handleLiteralArgument(argument, brigadierCommand) + is PhraseArgument-> handlePhraseArgument(argument, brigadierCommand) + else -> handleRequiredArgument(argument, brigadierCommand) + } + } + } + + private fun handleLiteralArgument(argument: LiteralStellarArgument, brigadierCommand: ArgumentBuilder) { + for (argumentBuilder in ArgumentHelper.getLiteralArguments(argument)) { + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + } + + private fun handlePhraseArgument(argument: PhraseArgument, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleGreedyStringWordFunctions(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + + private fun handleGreedyStringWordFunctions(argument: PhraseArgument, argumentBuilder: RequiredArgumentBuilder) { + argumentBuilder.executes { context -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + + for (i in greedyContext.arguments.indices) { + val word = argument.words[i] ?: continue + for (runnable in word.runnables) runnable(greedyContext) + if (i == greedyContext.arguments.lastIndex) + for (execution in word.executions) execution(greedyContext) + } + Command.SINGLE_SUCCESS + } + + argumentBuilder.suggests { context, builder -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + var prevChar = ' ' + val input = ArgumentHelper.getArgumentInput(context, argument.name) ?: "" + val amountOfSpaces: Int = if (input.isEmpty()) 0 else input.count { + if (prevChar == ' ' && it == ' ') return@count false + prevChar = it + it == ' ' + } + val newBuilder = builder.createOffset(builder.input.lastIndexOf(' ') + 1) + val word = argument.words[amountOfSpaces] ?: return@suggests newBuilder.buildFuture() + for (stellarSuggestion in word.suggestions) + for (suggestion in stellarSuggestion.get(greedyContext)) + newBuilder.suggest(suggestion.text) { suggestion.tooltip } + newBuilder.buildFuture() + } + } + + private fun handleRequiredArgument(argument: AbstractStellarArgument<*>, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + +} diff --git a/v1_15/src/main/kotlin/com/undefined/stellar/v1_15/CommandContextAdapter.kt b/v1_15/src/main/kotlin/com/undefined/stellar/v1_15/CommandContextAdapter.kt new file mode 100644 index 0000000..aed4e40 --- /dev/null +++ b/v1_15/src/main/kotlin/com/undefined/stellar/v1_15/CommandContextAdapter.kt @@ -0,0 +1,83 @@ +package com.undefined.stellar.v1_15 + +import com.mojang.brigadier.context.CommandContext +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.data.argument.CommandNode +import com.undefined.stellar.data.argument.PhraseCommandContext +import com.undefined.stellar.exception.DuplicateArgumentNameException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_15_R1.* +import org.bukkit.command.CommandSender + +object CommandContextAdapter { + + fun getStellarCommandContext(context: CommandContext): com.undefined.stellar.data.argument.CommandContext { + val input = context.input.removePrefix("/") + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val arguments = BrigadierCommandHelper.getArguments(baseCommand, context) + if (arguments.filter { it !is LiteralStellarArgument }.groupingBy { it.name }.eachCount().any { it.value > 1 }) throw DuplicateArgumentNameException() + val parsedArguments: CommandNode = + BrigadierCommandHelper.getArguments(baseCommand, context) + .associate, String, (com.undefined.stellar.data.argument.CommandContext) -> Any?> { argument -> + if (argument is CustomArgument) return@associate Pair(argument.name) { argument.parse(it) } + if (argument is LiteralStellarArgument) return@associate Pair(argument.name) { throw LiteralArgumentMismatchException() } + Pair(argument.name) { + ArgumentHelper.getParsedArgument(context, argument) + } + } as CommandNode + return com.undefined.stellar.data.argument.CommandContext( + parsedArguments, + context.source.bukkitSender, + input + ) + } + + fun getGreedyCommandContext(context: CommandContext): PhraseCommandContext { + val input = context.input.removePrefix("/") + val words = input.split(' ').toMutableList() + + val totalOtherArguments = context.nodes.size - 1 + for (i in (1..totalOtherArguments)) words.removeFirst() + return PhraseCommandContext( + words, + context.source.bukkitSender, + input + ) + } + + @Suppress("DEPRECATION") + fun getCommandListenerWrapper(sender: CommandSender): CommandListenerWrapper { + val overworld = MinecraftServer.getServer().getWorldServer(DimensionManager.OVERWORLD) + return CommandListenerWrapper( + Source(sender), + Vec3D(overworld.spawn), + Vec2F.a, + overworld, + 4, + sender.name, + ChatComponentText(sender.name), + MinecraftServer.getServer(), + null + ) + } + + private data class Source(val sender: CommandSender) : ICommandListener { + override fun sendMessage(message: IChatBaseComponent) { + this.sender.sendMessage(LegacyComponentSerializer.legacySection().serialize(asAdventure(message))) + } + override fun shouldSendSuccess(): Boolean = true + override fun shouldSendFailure(): Boolean = true + override fun shouldBroadcastCommands(): Boolean = false + override fun getBukkitSender(stack: CommandListenerWrapper): CommandSender = this.sender + } + + fun asAdventure(component: IChatBaseComponent): net.kyori.adventure.text.Component = + GsonComponentSerializer.gson().deserializeFromTree(IChatBaseComponent.ChatSerializer.b(component)) + +} \ No newline at end of file diff --git a/v1_15/src/main/kotlin/com/undefined/stellar/v1_15/CommandRegistrar.kt b/v1_15/src/main/kotlin/com/undefined/stellar/v1_15/CommandRegistrar.kt new file mode 100644 index 0000000..eac5928 --- /dev/null +++ b/v1_15/src/main/kotlin/com/undefined/stellar/v1_15/CommandRegistrar.kt @@ -0,0 +1,38 @@ +package com.undefined.stellar.v1_15 + +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.registrar.AbstractCommandRegistrar +import com.undefined.stellar.v1_15.BrigadierCommandHelper.dispatcher +import org.bukkit.command.CommandSender +import org.bukkit.plugin.java.JavaPlugin + +object CommandRegistrar : AbstractCommandRegistrar { + + override fun register(command: AbstractStellarCommand<*>, plugin: JavaPlugin) { + BrigadierCommandHelper.handleHelpTopic(command) + for (name in command.aliases + command.name) + BrigadierCommandHelper.register(CommandAdapter.getBaseCommand(command, name)) + } + + override fun handleCommandFailure(sender: CommandSender, input: String): Boolean { + val results = dispatcher.parse(input, BrigadierCommandHelper.COMMAND_SOURCE) + val context = results.context.withSource(CommandContextAdapter.getCommandListenerWrapper(sender)).build(input) + + if (results.reader.remainingLength == 0) return false + if (context.nodes.isEmpty()) return false + + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val argument = BrigadierCommandHelper.getArguments(baseCommand, context).lastOrNull() + argument?.let { + BrigadierCommandHelper.handleFailureMessageAndExecutions(argument, context) + if (argument.hideDefaultFailureMessages.hide) return true + } ?: run { + BrigadierCommandHelper.handleFailureMessageAndExecutions(baseCommand, context) + if (baseCommand.hideDefaultFailureMessages.hide) return true + } + + return baseCommand.hasGlobalHiddenDefaultFailureMessages() + } + +} \ No newline at end of file diff --git a/v1_15_1/build.gradle.kts b/v1_15_1/build.gradle.kts new file mode 100644 index 0000000..a1c6e86 --- /dev/null +++ b/v1_15_1/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + kotlin("jvm") version "1.9.22" +} + +repositories { + mavenLocal() +} + +dependencies { + compileOnly("org.spigotmc:spigot:1.15.1-R0.1-SNAPSHOT") + compileOnly(project(":common")) +} + +tasks { + compileKotlin { + kotlinOptions.jvmTarget = "1.8" + } + compileJava { + options.release.set(8) + } +} + +java { + disableAutoTargetJvm() +} + +kotlin { + jvmToolchain(21) +} \ No newline at end of file diff --git a/v1_15_1/src/main/kotlin/com/undefined/stellar/v1_15_1/ArgumentHelper.kt b/v1_15_1/src/main/kotlin/com/undefined/stellar/v1_15_1/ArgumentHelper.kt new file mode 100644 index 0000000..9980156 --- /dev/null +++ b/v1_15_1/src/main/kotlin/com/undefined/stellar/v1_15_1/ArgumentHelper.kt @@ -0,0 +1,434 @@ +package com.undefined.stellar.v1_15_1 + +import com.mojang.brigadier.arguments.* +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 com.mojang.brigadier.context.ParsedArgument +import com.mojang.brigadier.context.StringRange +import com.mojang.brigadier.exceptions.CommandSyntaxException +import com.mojang.brigadier.suggestion.SuggestionProvider +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.block.BlockDataArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.argument.types.custom.ListArgument +import com.undefined.stellar.argument.types.entity.EntityDisplayType +import com.undefined.stellar.argument.types.item.ItemSlotArgument +import com.undefined.stellar.argument.types.item.ItemSlotsArgument +import com.undefined.stellar.argument.types.math.AxisArgument +import com.undefined.stellar.argument.types.misc.NamespacedKeyArgument +import com.undefined.stellar.argument.types.misc.UUIDArgument +import com.undefined.stellar.argument.types.player.GameModeArgument +import com.undefined.stellar.argument.types.primitive.* +import com.undefined.stellar.argument.types.registry.* +import com.undefined.stellar.argument.types.scoreboard.DisplaySlotArgument +import com.undefined.stellar.argument.types.scoreboard.ScoreHolderType +import com.undefined.stellar.argument.types.structure.LootTableArgument +import com.undefined.stellar.argument.types.structure.MirrorArgument +import com.undefined.stellar.argument.types.structure.StructureRotationArgument +import com.undefined.stellar.argument.types.world.HeightMapArgument +import com.undefined.stellar.argument.types.world.LocationArgument +import com.undefined.stellar.argument.types.world.LocationType +import com.undefined.stellar.data.argument.Anchor +import com.undefined.stellar.data.argument.Operation +import com.undefined.stellar.data.argument.ParticleData +import com.undefined.stellar.exception.ArgumentVersionMismatchException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import com.undefined.stellar.exception.UnsupportedArgumentException +import com.undefined.stellar.util.NMSVersion +import com.undefined.stellar.util.ReflectionUtil +import com.undefined.stellar.util.executePrivateMethod +import net.kyori.adventure.text.format.Style +import net.kyori.adventure.text.format.TextColor +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.minecraft.server.v1_15_R1.* +import org.bukkit.* +import org.bukkit.Particle +import org.bukkit.Registry +import org.bukkit.World +import org.bukkit.block.Block +import org.bukkit.block.data.BlockData +import org.bukkit.craftbukkit.v1_15_R1.block.data.CraftBlockData +import org.bukkit.craftbukkit.v1_15_R1.CraftParticle +import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack +import org.bukkit.event.inventory.InventoryType +import org.bukkit.inventory.ItemStack +import org.bukkit.scoreboard.DisplaySlot +import java.time.Duration +import java.util.* +import java.util.function.Predicate + +@Suppress("UNCHECKED_CAST", "DEPRECATION") +object ArgumentHelper { + + fun getLiteralArguments(argument: AbstractStellarArgument<*>): List> { + val arguments: MutableList> = mutableListOf() + for (name in argument.aliases + argument.name) + arguments.add(LiteralArgumentBuilder.literal(name)) + return arguments + } + + fun getRequiredArgumentBuilder(argument: AbstractStellarArgument<*>): RequiredArgumentBuilder { + val argumentBuilder: RequiredArgumentBuilder = RequiredArgumentBuilder.argument(argument.name, getArgumentType(argument)) + getSuggestions(argument)?.let { argumentBuilder.suggests(it) } + return argumentBuilder + } + + private fun > getSuggestions(argument: T): SuggestionProvider? = + when (argument) { + is GameEventArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MOB_EFFECT.keySet(), builder) + } + is VillagerProfessionArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_PROFESSION.keySet(), builder) + } + is VillagerTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_TYPE.keySet(), builder) + } + is BiomeArgument -> SuggestionProvider { context, builder -> + CompletionProviders.d.getSuggestions(context, builder) + } + is EntityTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.ENTITY_TYPE.keySet(), builder) + } + is MemoryKeyArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MEMORY_MODULE_TYPE.keySet(), builder) + } + else -> null + } + + private fun > getArgumentType(argument: T): ArgumentType<*> = + when (argument) { + is ListArgument<*> -> getArgumentType(argument.type) + is CustomArgument<*> -> getArgumentType(argument.type) + is StringArgument -> brigadier(argument.type) + is PhraseArgument -> brigadier(StringType.PHRASE) + is IntegerArgument -> IntegerArgumentType.integer(argument.min, argument.max) + is LongArgument -> LongArgumentType.longArg(argument.min, argument.max) + is FloatArgument -> FloatArgumentType.floatArg(argument.min, argument.max) + is DoubleArgument -> DoubleArgumentType.doubleArg(argument.min, argument.max) + is BooleanArgument -> BoolArgumentType.bool() + is com.undefined.stellar.argument.types.entity.EntityArgument -> brigadier(argument.type) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a() + is LocationArgument -> when (argument.type) { + LocationType.LOCATION_3D -> ArgumentPosition.a() + LocationType.LOCATION_2D -> ArgumentVec2I.a() + LocationType.PRECISE_LOCATION_2D -> ArgumentVec3.a() + LocationType.PRECISE_LOCATION_3D -> ArgumentVec2.a() + } + is BlockDataArgument -> ArgumentTile.a() + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> ArgumentBlockPredicate.a() + is com.undefined.stellar.argument.types.item.ItemArgument -> ArgumentItemStack.a() + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> ArgumentItemPredicate.a() + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a() + is com.undefined.stellar.argument.types.text.ComponentArgument -> ArgumentChatComponent.a() + is com.undefined.stellar.argument.types.text.StyleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.text.MessageArgument -> ArgumentChat.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> ArgumentScoreboardObjective.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a() + is com.undefined.stellar.argument.types.math.OperationArgument -> ArgumentMathOperation.a() + is com.undefined.stellar.argument.types.world.ParticleArgument -> ArgumentParticle.a() + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> ArgumentRotation.a() + is DisplaySlotArgument -> ArgumentScoreboardSlot.a() + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a() + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b() + } + is AxisArgument -> ArgumentRotationAxis.a() + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> ArgumentScoreboardTeam.a() + is ItemSlotArgument -> ArgumentInventorySlot.a() + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> ArgumentMinecraftKeyRegistered.a() + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> ArgumentAnchor.a() + is com.undefined.stellar.argument.types.math.RangeArgument -> ReflectionUtil.executePrivateMethod, ArgumentCriterionValue<*>>("a") + is com.undefined.stellar.argument.types.world.DimensionArgument -> ArgumentDimension.a() + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> ArgumentTime.a() + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> throwArgumentVersionException(argument) + is GameEventArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> ArgumentMinecraftKeyRegistered.a() + is VillagerTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> throwArgumentVersionException(argument) + is AttributeArgument -> ArgumentMinecraftKeyRegistered.a() + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> ArgumentMinecraftKeyRegistered.a() + else -> throw UnsupportedArgumentException(argument) + } + + fun > getParsedArgument(context: CommandContext, argument: T): Any? { + return when (argument) { + is LiteralStellarArgument -> throw LiteralArgumentMismatchException() + is CustomArgument<*> -> argument.parse(CommandContextAdapter.getStellarCommandContext(context)) + is StringArgument -> StringArgumentType.getString(context, argument.name) + is IntegerArgument -> IntegerArgumentType.getInteger(context, argument.name) + is FloatArgument -> FloatArgumentType.getFloat(context, argument.name) + is DoubleArgument -> DoubleArgumentType.getDouble(context, argument.name) + is BooleanArgument -> BoolArgumentType.getBool(context, argument.name) + is ListArgument<*> -> argument.parse(getParsedArgument(context, argument)) + is com.undefined.stellar.argument.types.entity.EntityArgument -> ArgumentEntity.b(context, argument.name) + .map { it.bukkitEntity }.toMutableList() + .addAll(listOf(ArgumentEntity.a(context, argument.name).bukkitEntity)) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a(context, argument.name) + is LocationArgument -> getLocation(context, argument) + is BlockDataArgument -> CraftBlockData.fromData(ArgumentTile.a(context, argument.name).a()) + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> Predicate { block: Block -> + ArgumentBlockPredicate.a(context, argument.name).test(ShapeDetectorBlock( + context.source.world, + BlockPosition(block.x, block.y, block.z), true + )) + } + is com.undefined.stellar.argument.types.item.ItemArgument -> CraftItemStack.asBukkitCopy( + ArgumentItemStack.a(context, argument.name).a(1, false) + ) + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> Predicate { item: ItemStack -> + ArgumentItemPredicate.a(context, argument.name).test(CraftItemStack.asNMSCopy(item)) + } + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a( + context, + argument.name + ).executePrivateMethod("e").let { Style.style(TextColor.color(it)) } + is com.undefined.stellar.argument.types.text.ComponentArgument -> GsonComponentSerializer.gson() + .deserialize(IChatBaseComponent.ChatSerializer.a( + ArgumentChatComponent.a(context, argument.name) + )) + is com.undefined.stellar.argument.types.text.StyleArgument -> GsonComponentSerializer.gson().deserialize( + getArgumentInput(context, argument.name) ?: return null + ).style() + is com.undefined.stellar.argument.types.text.MessageArgument -> GsonComponentSerializer.gson().deserialize( + IChatBaseComponent.ChatSerializer.a(ArgumentChat.a(context, argument.name)) + ) + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getObjective( + ArgumentScoreboardObjective.a(context, argument.name).name + ) + + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a( + context, + argument.name + ).name + is com.undefined.stellar.argument.types.math.OperationArgument -> Operation.getOperation( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.world.ParticleArgument -> { + val particleOptions = ArgumentParticle.a(context, argument.name) + getParticleData(CraftParticle.toBukkit(particleOptions.particle), particleOptions) + } + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> { + val rotation = ArgumentRotation.a(context, argument.name).a(context.source) + Location(context.source.world.world, rotation.x, rotation.y, rotation.z) + } + is DisplaySlotArgument -> getBukkitDisplaySlot(ArgumentScoreboardSlot.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a(context, argument.name) + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b(context, argument.name) + } + is AxisArgument -> getBukkitAxis(ArgumentRotationAxis.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getTeam( + ArgumentScoreboardTeam.a(context, argument.name).name + ) + is ItemSlotArgument -> ArgumentInventorySlot.a(context, argument.name) + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> NamespacedKey( + ArgumentMinecraftKeyRegistered.d(context, argument.name).namespace, + ArgumentMinecraftKeyRegistered.d(context, argument.name).key + ) + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> Anchor.getFromName( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.math.RangeArgument -> { + val range = ArgumentCriterionValue.b.a(context, argument.name) + IntRange(range.a() ?: 1, range.b() ?: 2) + } + is com.undefined.stellar.argument.types.world.DimensionArgument -> World.Environment.getEnvironment(ArgumentDimension.a(context, argument.name).dimensionID) + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> Duration.ofSeconds(IntegerArgumentType.getInteger(context, argument.name).toLong() / 20) + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> throwArgumentVersionException(argument) + is GameEventArgument -> throwArgumentVersionException(argument) + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> Registry.VILLAGER_PROFESSION.get(getId(context, argument.name)) + is VillagerTypeArgument -> Registry.VILLAGER_TYPE.get(getId(context, argument.name)) + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> getInventoryType( + IRegistry.MENU[ArgumentMinecraftKeyRegistered.d(context, argument.name)] + ) + is AttributeArgument -> throwArgumentVersionException(argument) + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> Registry.BIOME.get(getId(context, argument.name)) + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> Registry.ENTITY_TYPE.get(getId(context, argument.name)) + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> Registry.MEMORY_MODULE_TYPE.get(getId(context, argument.name)) + else -> throw UnsupportedArgumentException(argument) + } + } + + fun getArgumentInput(context: CommandContext, name: String): String? { + val field = CommandContext::class.java.getDeclaredField("arguments") + field.isAccessible = true + val arguments: Map> = field.get(context) as Map> + val argument = arguments[name] ?: return null + val range = StringRange.between(argument.range.start, context.input.length) + return range.get(context.input) + } + + private fun getInventoryType(menu: Containers<*>?): InventoryType = when (menu) { + Containers.GENERIC_9X1 -> InventoryType.CHEST + Containers.GENERIC_9X2 -> InventoryType.CHEST + Containers.GENERIC_9X3 -> InventoryType.CHEST + Containers.GENERIC_9X4 -> InventoryType.CHEST + Containers.GENERIC_9X5 -> InventoryType.CHEST + Containers.GENERIC_9X6 -> InventoryType.CHEST + Containers.GENERIC_3X3 -> InventoryType.WORKBENCH + Containers.ANVIL -> InventoryType.ANVIL + Containers.BEACON -> InventoryType.BEACON + Containers.BLAST_FURNACE -> InventoryType.BLAST_FURNACE + Containers.BREWING_STAND -> InventoryType.BREWING + Containers.CRAFTING -> InventoryType.CRAFTING + Containers.ENCHANTMENT -> InventoryType.ENCHANTING + Containers.FURNACE -> InventoryType.FURNACE + Containers.GRINDSTONE -> InventoryType.GRINDSTONE + Containers.HOPPER -> InventoryType.HOPPER + Containers.LECTERN -> InventoryType.LECTERN + Containers.LOOM -> InventoryType.LOOM + Containers.MERCHANT -> InventoryType.MERCHANT + Containers.SHULKER_BOX -> InventoryType.SHULKER_BOX + Containers.SMOKER -> InventoryType.SMOKER + Containers.CARTOGRAPHY_TABLE -> InventoryType.CARTOGRAPHY + Containers.STONECUTTER -> InventoryType.STONECUTTER + else -> throw IllegalStateException("No inventory type found! This is not intentional behaviour, please contact the developers.") + } + + @Throws(CommandSyntaxException::class) + private fun getId( + context: CommandContext, + name: String + ): NamespacedKey { + val key = ArgumentMinecraftKeyRegistered.d(context, name) + return NamespacedKey(key.namespace, key.key) + } + + private fun brigadier(type: StringType): StringArgumentType = when (type) { + StringType.WORD -> StringArgumentType.word() + StringType.QUOTABLE_PHRASE -> StringArgumentType.string() + StringType.PHRASE -> StringArgumentType.greedyString() + } + + private fun brigadier(type: EntityDisplayType): ArgumentEntity = when (type) { + EntityDisplayType.ENTITY -> ReflectionUtil.executePrivateMethod("a") + EntityDisplayType.ENTITIES -> ArgumentEntity.multipleEntities() + EntityDisplayType.PLAYER -> ArgumentEntity.c() + EntityDisplayType.PLAYERS -> ArgumentEntity.d() + } + + private fun getBukkitAxis(argument: EnumSet): EnumSet = + argument.mapTo(EnumSet.noneOf(Axis::class.java)) { + when (it) { + EnumDirection.EnumAxis.X -> Axis.X + EnumDirection.EnumAxis.Y -> Axis.Y + EnumDirection.EnumAxis.Z -> Axis.Z + null -> Axis.X + } + } + + private fun getBukkitDisplaySlot(slot: Int): DisplaySlot = when (slot) { + 0 -> DisplaySlot.PLAYER_LIST + 2 -> DisplaySlot.BELOW_NAME + else -> DisplaySlot.SIDEBAR + } + + private fun getParticleData( + particle: Particle, + particleOptions: ParticleParam + ): ParticleData<*> = when (particleOptions) { + is ParticleType -> ParticleData(particle, null) + is ParticleParamBlock -> ParticleData(particle, CraftBlockData.fromData(particleOptions.executePrivateMethod("c"))) + is ParticleParamRedstone -> { + val colors = particleOptions.a().split(" ") + val red = colors[1].toFloat() + val green = colors[2].toFloat() + val blue = colors[3].toFloat() + val scale = colors[4].toFloat() + ParticleData( + particle, + Particle.DustOptions( + Color.fromRGB( + (red * 255.0f).toInt(), + (green * 255.0f).toInt(), (blue * 255.0f).toInt() + ), scale + ) + ) + } + is ParticleParamItem -> ParticleData( + particle, + CraftItemStack.asBukkitCopy(particleOptions.executePrivateMethod("c")) + ) + else -> ParticleData(particle, null) + } + + private fun getLocation(context: CommandContext, command: LocationArgument): Location { + val world = context.source.world.world + return when (command.type) { + LocationType.LOCATION_3D -> toLocation(world, context.getArgument(command.name, IVectorPosition::class.java).c(context.source)) + LocationType.LOCATION_2D -> toLocation(world, ArgumentVec2I.a(context, command.name)) + LocationType.PRECISE_LOCATION_3D -> toLocation(world, ArgumentVec3.a(context, command.name)) + LocationType.PRECISE_LOCATION_2D -> toLocation(world, ArgumentVec2.a(context, command.name)) + } + } + + private fun toLocation(world: World, position: BlockPosition) = + Location(world, position.x.toDouble(), position.y.toDouble(), position.z.toDouble()) + private fun toLocation(world: World, position: BlockPosition2D) = + Location(world, position.a.toDouble(), 0.0, position.b.toDouble()) + private fun toLocation(world: World, vec: Vec3D) = + Location(world, vec.x, vec.y, vec.z) + private fun toLocation(world: World, vec: Vec2F) = + Location(world, vec.i.toDouble(), 0.0, vec.j.toDouble()) + + private fun throwArgumentVersionException(argument: AbstractStellarArgument<*>): Nothing = + throw ArgumentVersionMismatchException(argument, NMSVersion.version) + +} \ No newline at end of file diff --git a/v1_15_1/src/main/kotlin/com/undefined/stellar/v1_15_1/BrigadierCommandHelper.kt b/v1_15_1/src/main/kotlin/com/undefined/stellar/v1_15_1/BrigadierCommandHelper.kt new file mode 100644 index 0000000..83c087a --- /dev/null +++ b/v1_15_1/src/main/kotlin/com/undefined/stellar/v1_15_1/BrigadierCommandHelper.kt @@ -0,0 +1,76 @@ +package com.undefined.stellar.v1_15_1 + +import com.mojang.brigadier.CommandDispatcher +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.tree.LiteralCommandNode +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.data.help.CustomCommandHelpTopic +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_15_R1.CommandListenerWrapper +import net.minecraft.server.v1_15_R1.MinecraftServer +import org.bukkit.Bukkit + +@Suppress("DEPRECATION") +object BrigadierCommandHelper { + + val COMMAND_SOURCE: CommandListenerWrapper by lazy { + MinecraftServer.getServer().serverCommandListener + } + val dispatcher: CommandDispatcher by lazy { + MinecraftServer.getServer().functionData.d() + } + + fun register(command: LiteralArgumentBuilder): LiteralCommandNode? = + dispatcher.register(command) + + fun handleHelpTopic(command: AbstractStellarCommand<*>) { + Bukkit.getServer().helpMap.addTopic( + CustomCommandHelpTopic(command.name, command.description, command.helpTopic) { + val context = MinecraftServer.getServer().serverCommandListener + val requirements = command.requirements.all { it(this) } + val permissionRequirements = command.permissionRequirements.all { + if (it.permission.isEmpty()) context.hasPermission(it.level) + else context.hasPermission(it.level, it.permission) + } + requirements.and(permissionRequirements) + } + ) + } + + fun handleExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + val stellarContext = CommandContextAdapter.getStellarCommandContext(context) + + for (runnable in command.base.runnables) runnable(stellarContext) + val arguments = getArguments(command.base, context) + for (argument in arguments) for (runnable in argument.runnables) runnable(stellarContext) + for (execution in command.executions) execution(stellarContext) + } + + fun fulfillsRequirements(command: AbstractStellarCommand<*>, source: CommandListenerWrapper): Boolean { + val fulfillsExecutionRequirements = command.requirements.all { it(source.bukkitSender) } + val fulfillsPermissionRequirements = command.permissionRequirements.all { source.hasPermission(it.level, it.permission) } + return fulfillsExecutionRequirements.and(fulfillsPermissionRequirements) + } + + fun handleFailureMessageAndExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + for (execution in command.failureExecutions) execution(CommandContextAdapter.getStellarCommandContext(context)) + for (message in command.failureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + for (message in command.globalFailureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + } + + fun getArguments( + baseCommand: AbstractStellarCommand<*>, + context: CommandContext, + currentIndex: Int = 1, + listOfArguments: List> = emptyList() + ): List> { + if (listOfArguments.size == context.nodes.size - 1) return listOfArguments + for (argument in baseCommand.arguments) + if (argument.name == context.nodes[currentIndex].node.name) + return getArguments(argument, context, currentIndex + 1, listOfArguments + argument) + return emptyList() + } + +} \ No newline at end of file diff --git a/v1_15_1/src/main/kotlin/com/undefined/stellar/v1_15_1/CommandAdapter.kt b/v1_15_1/src/main/kotlin/com/undefined/stellar/v1_15_1/CommandAdapter.kt new file mode 100644 index 0000000..c562436 --- /dev/null +++ b/v1_15_1/src/main/kotlin/com/undefined/stellar/v1_15_1/CommandAdapter.kt @@ -0,0 +1,96 @@ +package com.undefined.stellar.v1_15_1 + +import com.mojang.brigadier.Command +import com.mojang.brigadier.builder.ArgumentBuilder +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.primitive.PhraseArgument +import net.minecraft.server.v1_15_R1.CommandListenerWrapper + +object CommandAdapter { + + fun getBaseCommand(command: AbstractStellarCommand<*>, name: String = command.name): LiteralArgumentBuilder { + val brigadierCommand = LiteralArgumentBuilder.literal(name) + handleCommandFunctions(command, brigadierCommand) + handleArguments(command, brigadierCommand) + return brigadierCommand + } + + private fun handleCommandFunctions(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + if (command.executions.isNotEmpty() || command.executions.isNotEmpty()) + brigadierCommand.executes { context -> + BrigadierCommandHelper.handleExecutions(command, context) + 1 + } + brigadierCommand.requires { source -> + BrigadierCommandHelper.fulfillsRequirements(command, source) + } + } + + private fun handleArguments(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + for (argument in command.arguments) { + when (argument) { + is LiteralStellarArgument -> handleLiteralArgument(argument, brigadierCommand) + is PhraseArgument-> handlePhraseArgument(argument, brigadierCommand) + else -> handleRequiredArgument(argument, brigadierCommand) + } + } + } + + private fun handleLiteralArgument(argument: LiteralStellarArgument, brigadierCommand: ArgumentBuilder) { + for (argumentBuilder in ArgumentHelper.getLiteralArguments(argument)) { + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + } + + private fun handlePhraseArgument(argument: PhraseArgument, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleGreedyStringWordFunctions(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + + private fun handleGreedyStringWordFunctions(argument: PhraseArgument, argumentBuilder: RequiredArgumentBuilder) { + argumentBuilder.executes { context -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + + for (i in greedyContext.arguments.indices) { + val word = argument.words[i] ?: continue + for (runnable in word.runnables) runnable(greedyContext) + if (i == greedyContext.arguments.lastIndex) + for (execution in word.executions) execution(greedyContext) + } + Command.SINGLE_SUCCESS + } + + argumentBuilder.suggests { context, builder -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + var prevChar = ' ' + val input = ArgumentHelper.getArgumentInput(context, argument.name) ?: "" + val amountOfSpaces: Int = if (input.isEmpty()) 0 else input.count { + if (prevChar == ' ' && it == ' ') return@count false + prevChar = it + it == ' ' + } + val newBuilder = builder.createOffset(builder.input.lastIndexOf(' ') + 1) + val word = argument.words[amountOfSpaces] ?: return@suggests newBuilder.buildFuture() + for (stellarSuggestion in word.suggestions) + for (suggestion in stellarSuggestion.get(greedyContext)) + newBuilder.suggest(suggestion.text) { suggestion.tooltip } + newBuilder.buildFuture() + } + } + + private fun handleRequiredArgument(argument: AbstractStellarArgument<*>, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + +} diff --git a/v1_15_1/src/main/kotlin/com/undefined/stellar/v1_15_1/CommandContextAdapter.kt b/v1_15_1/src/main/kotlin/com/undefined/stellar/v1_15_1/CommandContextAdapter.kt new file mode 100644 index 0000000..8f2676b --- /dev/null +++ b/v1_15_1/src/main/kotlin/com/undefined/stellar/v1_15_1/CommandContextAdapter.kt @@ -0,0 +1,83 @@ +package com.undefined.stellar.v1_15_1 + +import com.mojang.brigadier.context.CommandContext +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.data.argument.CommandNode +import com.undefined.stellar.data.argument.PhraseCommandContext +import com.undefined.stellar.exception.DuplicateArgumentNameException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_15_R1.* +import org.bukkit.command.CommandSender + +object CommandContextAdapter { + + fun getStellarCommandContext(context: CommandContext): com.undefined.stellar.data.argument.CommandContext { + val input = context.input.removePrefix("/") + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val arguments = BrigadierCommandHelper.getArguments(baseCommand, context) + if (arguments.filter { it !is LiteralStellarArgument }.groupingBy { it.name }.eachCount().any { it.value > 1 }) throw DuplicateArgumentNameException() + val parsedArguments: CommandNode = + BrigadierCommandHelper.getArguments(baseCommand, context) + .associate, String, (com.undefined.stellar.data.argument.CommandContext) -> Any?> { argument -> + if (argument is CustomArgument) return@associate Pair(argument.name) { argument.parse(it) } + if (argument is LiteralStellarArgument) return@associate Pair(argument.name) { throw LiteralArgumentMismatchException() } + Pair(argument.name) { + ArgumentHelper.getParsedArgument(context, argument) + } + } as CommandNode + return com.undefined.stellar.data.argument.CommandContext( + parsedArguments, + context.source.bukkitSender, + input + ) + } + + fun getGreedyCommandContext(context: CommandContext): PhraseCommandContext { + val input = context.input.removePrefix("/") + val words = input.split(' ').toMutableList() + + val totalOtherArguments = context.nodes.size - 1 + for (i in (1..totalOtherArguments)) words.removeFirst() + return PhraseCommandContext( + words, + context.source.bukkitSender, + input + ) + } + + @Suppress("DEPRECATION") + fun getCommandListenerWrapper(sender: CommandSender): CommandListenerWrapper { + val overworld = MinecraftServer.getServer().getWorldServer(DimensionManager.OVERWORLD) + return CommandListenerWrapper( + Source(sender), + Vec3D(overworld.spawn), + Vec2F.a, + overworld, + 4, + sender.name, + ChatComponentText(sender.name), + MinecraftServer.getServer(), + null + ) + } + + private data class Source(val sender: CommandSender) : ICommandListener { + override fun sendMessage(message: IChatBaseComponent) { + this.sender.sendMessage(LegacyComponentSerializer.legacySection().serialize(asAdventure(message))) + } + override fun shouldSendSuccess(): Boolean = true + override fun shouldSendFailure(): Boolean = true + override fun shouldBroadcastCommands(): Boolean = false + override fun getBukkitSender(stack: CommandListenerWrapper): CommandSender = this.sender + } + + fun asAdventure(component: IChatBaseComponent): net.kyori.adventure.text.Component = + GsonComponentSerializer.gson().deserializeFromTree(IChatBaseComponent.ChatSerializer.b(component)) + +} \ No newline at end of file diff --git a/v1_15_1/src/main/kotlin/com/undefined/stellar/v1_15_1/CommandRegistrar.kt b/v1_15_1/src/main/kotlin/com/undefined/stellar/v1_15_1/CommandRegistrar.kt new file mode 100644 index 0000000..8c6a071 --- /dev/null +++ b/v1_15_1/src/main/kotlin/com/undefined/stellar/v1_15_1/CommandRegistrar.kt @@ -0,0 +1,38 @@ +package com.undefined.stellar.v1_15_1 + +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.registrar.AbstractCommandRegistrar +import com.undefined.stellar.v1_15_1.BrigadierCommandHelper.dispatcher +import org.bukkit.command.CommandSender +import org.bukkit.plugin.java.JavaPlugin + +object CommandRegistrar : AbstractCommandRegistrar { + + override fun register(command: AbstractStellarCommand<*>, plugin: JavaPlugin) { + BrigadierCommandHelper.handleHelpTopic(command) + for (name in command.aliases + command.name) + BrigadierCommandHelper.register(CommandAdapter.getBaseCommand(command, name)) + } + + override fun handleCommandFailure(sender: CommandSender, input: String): Boolean { + val results = dispatcher.parse(input, BrigadierCommandHelper.COMMAND_SOURCE) + val context = results.context.withSource(CommandContextAdapter.getCommandListenerWrapper(sender)).build(input) + + if (results.reader.remainingLength == 0) return false + if (context.nodes.isEmpty()) return false + + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val argument = BrigadierCommandHelper.getArguments(baseCommand, context).lastOrNull() + argument?.let { + BrigadierCommandHelper.handleFailureMessageAndExecutions(argument, context) + if (argument.hideDefaultFailureMessages.hide) return true + } ?: run { + BrigadierCommandHelper.handleFailureMessageAndExecutions(baseCommand, context) + if (baseCommand.hideDefaultFailureMessages.hide) return true + } + + return baseCommand.hasGlobalHiddenDefaultFailureMessages() + } + +} \ No newline at end of file diff --git a/v1_15_2/build.gradle.kts b/v1_15_2/build.gradle.kts new file mode 100644 index 0000000..b25ffea --- /dev/null +++ b/v1_15_2/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + kotlin("jvm") version "1.9.22" +} + +repositories { + mavenLocal() +} + +dependencies { + compileOnly("org.spigotmc:spigot:1.15.2-R0.1-SNAPSHOT") + compileOnly(project(":common")) +} + +tasks { + compileKotlin { + kotlinOptions.jvmTarget = "1.8" + } + compileJava { + options.release.set(8) + } +} + +java { + disableAutoTargetJvm() +} + +kotlin { + jvmToolchain(21) +} \ No newline at end of file diff --git a/v1_15_2/src/main/kotlin/com/undefined/stellar/v1_15_2/ArgumentHelper.kt b/v1_15_2/src/main/kotlin/com/undefined/stellar/v1_15_2/ArgumentHelper.kt new file mode 100644 index 0000000..3536210 --- /dev/null +++ b/v1_15_2/src/main/kotlin/com/undefined/stellar/v1_15_2/ArgumentHelper.kt @@ -0,0 +1,434 @@ +package com.undefined.stellar.v1_15_2 + +import com.mojang.brigadier.arguments.* +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 com.mojang.brigadier.context.ParsedArgument +import com.mojang.brigadier.context.StringRange +import com.mojang.brigadier.exceptions.CommandSyntaxException +import com.mojang.brigadier.suggestion.SuggestionProvider +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.block.BlockDataArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.argument.types.custom.ListArgument +import com.undefined.stellar.argument.types.entity.EntityDisplayType +import com.undefined.stellar.argument.types.item.ItemSlotArgument +import com.undefined.stellar.argument.types.item.ItemSlotsArgument +import com.undefined.stellar.argument.types.math.AxisArgument +import com.undefined.stellar.argument.types.misc.NamespacedKeyArgument +import com.undefined.stellar.argument.types.misc.UUIDArgument +import com.undefined.stellar.argument.types.player.GameModeArgument +import com.undefined.stellar.argument.types.primitive.* +import com.undefined.stellar.argument.types.registry.* +import com.undefined.stellar.argument.types.scoreboard.DisplaySlotArgument +import com.undefined.stellar.argument.types.scoreboard.ScoreHolderType +import com.undefined.stellar.argument.types.structure.LootTableArgument +import com.undefined.stellar.argument.types.structure.MirrorArgument +import com.undefined.stellar.argument.types.structure.StructureRotationArgument +import com.undefined.stellar.argument.types.world.HeightMapArgument +import com.undefined.stellar.argument.types.world.LocationArgument +import com.undefined.stellar.argument.types.world.LocationType +import com.undefined.stellar.data.argument.Anchor +import com.undefined.stellar.data.argument.Operation +import com.undefined.stellar.data.argument.ParticleData +import com.undefined.stellar.exception.ArgumentVersionMismatchException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import com.undefined.stellar.exception.UnsupportedArgumentException +import com.undefined.stellar.util.NMSVersion +import com.undefined.stellar.util.ReflectionUtil +import com.undefined.stellar.util.executePrivateMethod +import net.kyori.adventure.text.format.Style +import net.kyori.adventure.text.format.TextColor +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.minecraft.server.v1_15_R1.* +import org.bukkit.* +import org.bukkit.Particle +import org.bukkit.Registry +import org.bukkit.World +import org.bukkit.block.Block +import org.bukkit.block.data.BlockData +import org.bukkit.craftbukkit.v1_15_R1.block.data.CraftBlockData +import org.bukkit.craftbukkit.v1_15_R1.CraftParticle +import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack +import org.bukkit.event.inventory.InventoryType +import org.bukkit.inventory.ItemStack +import org.bukkit.scoreboard.DisplaySlot +import java.time.Duration +import java.util.* +import java.util.function.Predicate + +@Suppress("UNCHECKED_CAST", "DEPRECATION") +object ArgumentHelper { + + fun getLiteralArguments(argument: AbstractStellarArgument<*>): List> { + val arguments: MutableList> = mutableListOf() + for (name in argument.aliases + argument.name) + arguments.add(LiteralArgumentBuilder.literal(name)) + return arguments + } + + fun getRequiredArgumentBuilder(argument: AbstractStellarArgument<*>): RequiredArgumentBuilder { + val argumentBuilder: RequiredArgumentBuilder = RequiredArgumentBuilder.argument(argument.name, getArgumentType(argument)) + getSuggestions(argument)?.let { argumentBuilder.suggests(it) } + return argumentBuilder + } + + private fun > getSuggestions(argument: T): SuggestionProvider? = + when (argument) { + is GameEventArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MOB_EFFECT.keySet(), builder) + } + is VillagerProfessionArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_PROFESSION.keySet(), builder) + } + is VillagerTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_TYPE.keySet(), builder) + } + is BiomeArgument -> SuggestionProvider { context, builder -> + CompletionProviders.d.getSuggestions(context, builder) + } + is EntityTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.ENTITY_TYPE.keySet(), builder) + } + is MemoryKeyArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MEMORY_MODULE_TYPE.keySet(), builder) + } + else -> null + } + + private fun > getArgumentType(argument: T): ArgumentType<*> = + when (argument) { + is ListArgument<*> -> getArgumentType(argument.type) + is CustomArgument<*> -> getArgumentType(argument.type) + is StringArgument -> brigadier(argument.type) + is PhraseArgument -> brigadier(StringType.PHRASE) + is IntegerArgument -> IntegerArgumentType.integer(argument.min, argument.max) + is LongArgument -> LongArgumentType.longArg(argument.min, argument.max) + is FloatArgument -> FloatArgumentType.floatArg(argument.min, argument.max) + is DoubleArgument -> DoubleArgumentType.doubleArg(argument.min, argument.max) + is BooleanArgument -> BoolArgumentType.bool() + is com.undefined.stellar.argument.types.entity.EntityArgument -> brigadier(argument.type) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a() + is LocationArgument -> when (argument.type) { + LocationType.LOCATION_3D -> ArgumentPosition.a() + LocationType.LOCATION_2D -> ArgumentVec2I.a() + LocationType.PRECISE_LOCATION_2D -> ArgumentVec3.a() + LocationType.PRECISE_LOCATION_3D -> ArgumentVec2.a() + } + is BlockDataArgument -> ArgumentTile.a() + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> ArgumentBlockPredicate.a() + is com.undefined.stellar.argument.types.item.ItemArgument -> ArgumentItemStack.a() + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> ArgumentItemPredicate.a() + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a() + is com.undefined.stellar.argument.types.text.ComponentArgument -> ArgumentChatComponent.a() + is com.undefined.stellar.argument.types.text.StyleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.text.MessageArgument -> ArgumentChat.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> ArgumentScoreboardObjective.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a() + is com.undefined.stellar.argument.types.math.OperationArgument -> ArgumentMathOperation.a() + is com.undefined.stellar.argument.types.world.ParticleArgument -> ArgumentParticle.a() + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> ArgumentRotation.a() + is DisplaySlotArgument -> ArgumentScoreboardSlot.a() + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a() + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b() + } + is AxisArgument -> ArgumentRotationAxis.a() + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> ArgumentScoreboardTeam.a() + is ItemSlotArgument -> ArgumentInventorySlot.a() + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> ArgumentMinecraftKeyRegistered.a() + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> ArgumentAnchor.a() + is com.undefined.stellar.argument.types.math.RangeArgument -> ReflectionUtil.executePrivateMethod, ArgumentCriterionValue<*>>("a") + is com.undefined.stellar.argument.types.world.DimensionArgument -> ArgumentDimension.a() + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> ArgumentTime.a() + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> throwArgumentVersionException(argument) + is GameEventArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> ArgumentMinecraftKeyRegistered.a() + is VillagerTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> throwArgumentVersionException(argument) + is AttributeArgument -> ArgumentMinecraftKeyRegistered.a() + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> ArgumentMinecraftKeyRegistered.a() + else -> throw UnsupportedArgumentException(argument) + } + + fun > getParsedArgument(context: CommandContext, argument: T): Any? { + return when (argument) { + is LiteralStellarArgument -> throw LiteralArgumentMismatchException() + is CustomArgument<*> -> argument.parse(CommandContextAdapter.getStellarCommandContext(context)) + is StringArgument -> StringArgumentType.getString(context, argument.name) + is IntegerArgument -> IntegerArgumentType.getInteger(context, argument.name) + is FloatArgument -> FloatArgumentType.getFloat(context, argument.name) + is DoubleArgument -> DoubleArgumentType.getDouble(context, argument.name) + is BooleanArgument -> BoolArgumentType.getBool(context, argument.name) + is ListArgument<*> -> argument.parse(getParsedArgument(context, argument)) + is com.undefined.stellar.argument.types.entity.EntityArgument -> ArgumentEntity.b(context, argument.name) + .map { it.bukkitEntity }.toMutableList() + .addAll(listOf(ArgumentEntity.a(context, argument.name).bukkitEntity)) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a(context, argument.name) + is LocationArgument -> getLocation(context, argument) + is BlockDataArgument -> CraftBlockData.fromData(ArgumentTile.a(context, argument.name).a()) + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> Predicate { block: Block -> + ArgumentBlockPredicate.a(context, argument.name).test(ShapeDetectorBlock( + context.source.world, + BlockPosition(block.x, block.y, block.z), true + )) + } + is com.undefined.stellar.argument.types.item.ItemArgument -> CraftItemStack.asBukkitCopy( + ArgumentItemStack.a(context, argument.name).a(1, false) + ) + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> Predicate { item: ItemStack -> + ArgumentItemPredicate.a(context, argument.name).test(CraftItemStack.asNMSCopy(item)) + } + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a( + context, + argument.name + ).executePrivateMethod("e").let { Style.style(TextColor.color(it)) } + is com.undefined.stellar.argument.types.text.ComponentArgument -> GsonComponentSerializer.gson() + .deserialize(IChatBaseComponent.ChatSerializer.a( + ArgumentChatComponent.a(context, argument.name) + )) + is com.undefined.stellar.argument.types.text.StyleArgument -> GsonComponentSerializer.gson().deserialize( + getArgumentInput(context, argument.name) ?: return null + ).style() + is com.undefined.stellar.argument.types.text.MessageArgument -> GsonComponentSerializer.gson().deserialize( + IChatBaseComponent.ChatSerializer.a(ArgumentChat.a(context, argument.name)) + ) + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getObjective( + ArgumentScoreboardObjective.a(context, argument.name).name + ) + + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a( + context, + argument.name + ).name + is com.undefined.stellar.argument.types.math.OperationArgument -> Operation.getOperation( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.world.ParticleArgument -> { + val particleOptions = ArgumentParticle.a(context, argument.name) + getParticleData(CraftParticle.toBukkit(particleOptions.particle), particleOptions) + } + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> { + val rotation = ArgumentRotation.a(context, argument.name).a(context.source) + Location(context.source.world.world, rotation.x, rotation.y, rotation.z) + } + is DisplaySlotArgument -> getBukkitDisplaySlot(ArgumentScoreboardSlot.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a(context, argument.name) + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b(context, argument.name) + } + is AxisArgument -> getBukkitAxis(ArgumentRotationAxis.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getTeam( + ArgumentScoreboardTeam.a(context, argument.name).name + ) + is ItemSlotArgument -> ArgumentInventorySlot.a(context, argument.name) + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> NamespacedKey( + ArgumentMinecraftKeyRegistered.d(context, argument.name).namespace, + ArgumentMinecraftKeyRegistered.d(context, argument.name).key + ) + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> Anchor.getFromName( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.math.RangeArgument -> { + val range = ArgumentCriterionValue.b.a(context, argument.name) + IntRange(range.a() ?: 1, range.b() ?: 2) + } + is com.undefined.stellar.argument.types.world.DimensionArgument -> World.Environment.getEnvironment(ArgumentDimension.a(context, argument.name).dimensionID) + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> Duration.ofSeconds(IntegerArgumentType.getInteger(context, argument.name).toLong() / 20) + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> throwArgumentVersionException(argument) + is GameEventArgument -> throwArgumentVersionException(argument) + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> Registry.VILLAGER_PROFESSION.get(getId(context, argument.name)) + is VillagerTypeArgument -> Registry.VILLAGER_TYPE.get(getId(context, argument.name)) + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> getInventoryType( + IRegistry.MENU[ArgumentMinecraftKeyRegistered.d(context, argument.name)] + ) + is AttributeArgument -> throwArgumentVersionException(argument) + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> Registry.BIOME.get(getId(context, argument.name)) + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> Registry.ENTITY_TYPE.get(getId(context, argument.name)) + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> Registry.MEMORY_MODULE_TYPE.get(getId(context, argument.name)) + else -> throw UnsupportedArgumentException(argument) + } + } + + fun getArgumentInput(context: CommandContext, name: String): String? { + val field = CommandContext::class.java.getDeclaredField("arguments") + field.isAccessible = true + val arguments: Map> = field.get(context) as Map> + val argument = arguments[name] ?: return null + val range = StringRange.between(argument.range.start, context.input.length) + return range.get(context.input) + } + + private fun getInventoryType(menu: Containers<*>?): InventoryType = when (menu) { + Containers.GENERIC_9X1 -> InventoryType.CHEST + Containers.GENERIC_9X2 -> InventoryType.CHEST + Containers.GENERIC_9X3 -> InventoryType.CHEST + Containers.GENERIC_9X4 -> InventoryType.CHEST + Containers.GENERIC_9X5 -> InventoryType.CHEST + Containers.GENERIC_9X6 -> InventoryType.CHEST + Containers.GENERIC_3X3 -> InventoryType.WORKBENCH + Containers.ANVIL -> InventoryType.ANVIL + Containers.BEACON -> InventoryType.BEACON + Containers.BLAST_FURNACE -> InventoryType.BLAST_FURNACE + Containers.BREWING_STAND -> InventoryType.BREWING + Containers.CRAFTING -> InventoryType.CRAFTING + Containers.ENCHANTMENT -> InventoryType.ENCHANTING + Containers.FURNACE -> InventoryType.FURNACE + Containers.GRINDSTONE -> InventoryType.GRINDSTONE + Containers.HOPPER -> InventoryType.HOPPER + Containers.LECTERN -> InventoryType.LECTERN + Containers.LOOM -> InventoryType.LOOM + Containers.MERCHANT -> InventoryType.MERCHANT + Containers.SHULKER_BOX -> InventoryType.SHULKER_BOX + Containers.SMOKER -> InventoryType.SMOKER + Containers.CARTOGRAPHY_TABLE -> InventoryType.CARTOGRAPHY + Containers.STONECUTTER -> InventoryType.STONECUTTER + else -> throw IllegalStateException("No inventory type found! This is not intentional behaviour, please contact the developers.") + } + + @Throws(CommandSyntaxException::class) + private fun getId( + context: CommandContext, + name: String + ): NamespacedKey { + val key = ArgumentMinecraftKeyRegistered.d(context, name) + return NamespacedKey(key.namespace, key.key) + } + + private fun brigadier(type: StringType): StringArgumentType = when (type) { + StringType.WORD -> StringArgumentType.word() + StringType.QUOTABLE_PHRASE -> StringArgumentType.string() + StringType.PHRASE -> StringArgumentType.greedyString() + } + + private fun brigadier(type: EntityDisplayType): ArgumentEntity = when (type) { + EntityDisplayType.ENTITY -> ReflectionUtil.executePrivateMethod("a") + EntityDisplayType.ENTITIES -> ArgumentEntity.multipleEntities() + EntityDisplayType.PLAYER -> ArgumentEntity.c() + EntityDisplayType.PLAYERS -> ArgumentEntity.d() + } + + private fun getBukkitAxis(argument: EnumSet): EnumSet = + argument.mapTo(EnumSet.noneOf(Axis::class.java)) { + when (it) { + EnumDirection.EnumAxis.X -> Axis.X + EnumDirection.EnumAxis.Y -> Axis.Y + EnumDirection.EnumAxis.Z -> Axis.Z + null -> Axis.X + } + } + + private fun getBukkitDisplaySlot(slot: Int): DisplaySlot = when (slot) { + 0 -> DisplaySlot.PLAYER_LIST + 2 -> DisplaySlot.BELOW_NAME + else -> DisplaySlot.SIDEBAR + } + + private fun getParticleData( + particle: Particle, + particleOptions: ParticleParam + ): ParticleData<*> = when (particleOptions) { + is ParticleType -> ParticleData(particle, null) + is ParticleParamBlock -> ParticleData(particle, CraftBlockData.fromData(particleOptions.executePrivateMethod("c"))) + is ParticleParamRedstone -> { + val colors = particleOptions.a().split(" ") + val red = colors[1].toFloat() + val green = colors[2].toFloat() + val blue = colors[3].toFloat() + val scale = colors[4].toFloat() + ParticleData( + particle, + Particle.DustOptions( + Color.fromRGB( + (red * 255.0f).toInt(), + (green * 255.0f).toInt(), (blue * 255.0f).toInt() + ), scale + ) + ) + } + is ParticleParamItem -> ParticleData( + particle, + CraftItemStack.asBukkitCopy(particleOptions.executePrivateMethod("c")) + ) + else -> ParticleData(particle, null) + } + + private fun getLocation(context: CommandContext, command: LocationArgument): Location { + val world = context.source.world.world + return when (command.type) { + LocationType.LOCATION_3D -> toLocation(world, context.getArgument(command.name, IVectorPosition::class.java).c(context.source)) + LocationType.LOCATION_2D -> toLocation(world, ArgumentVec2I.a(context, command.name)) + LocationType.PRECISE_LOCATION_3D -> toLocation(world, ArgumentVec3.a(context, command.name)) + LocationType.PRECISE_LOCATION_2D -> toLocation(world, ArgumentVec2.a(context, command.name)) + } + } + + private fun toLocation(world: World, position: BlockPosition) = + Location(world, position.x.toDouble(), position.y.toDouble(), position.z.toDouble()) + private fun toLocation(world: World, position: BlockPosition2D) = + Location(world, position.a.toDouble(), 0.0, position.b.toDouble()) + private fun toLocation(world: World, vec: Vec3D) = + Location(world, vec.x, vec.y, vec.z) + private fun toLocation(world: World, vec: Vec2F) = + Location(world, vec.i.toDouble(), 0.0, vec.j.toDouble()) + + private fun throwArgumentVersionException(argument: AbstractStellarArgument<*>): Nothing = + throw ArgumentVersionMismatchException(argument, NMSVersion.version) + +} \ No newline at end of file diff --git a/v1_15_2/src/main/kotlin/com/undefined/stellar/v1_15_2/BrigadierCommandHelper.kt b/v1_15_2/src/main/kotlin/com/undefined/stellar/v1_15_2/BrigadierCommandHelper.kt new file mode 100644 index 0000000..08b91c3 --- /dev/null +++ b/v1_15_2/src/main/kotlin/com/undefined/stellar/v1_15_2/BrigadierCommandHelper.kt @@ -0,0 +1,76 @@ +package com.undefined.stellar.v1_15_2 + +import com.mojang.brigadier.CommandDispatcher +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.tree.LiteralCommandNode +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.data.help.CustomCommandHelpTopic +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_15_R1.CommandListenerWrapper +import net.minecraft.server.v1_15_R1.MinecraftServer +import org.bukkit.Bukkit + +@Suppress("DEPRECATION") +object BrigadierCommandHelper { + + val COMMAND_SOURCE: CommandListenerWrapper by lazy { + MinecraftServer.getServer().serverCommandListener + } + val dispatcher: CommandDispatcher by lazy { + MinecraftServer.getServer().functionData.commandDispatcher + } + + fun register(command: LiteralArgumentBuilder): LiteralCommandNode? = + dispatcher.register(command) + + fun handleHelpTopic(command: AbstractStellarCommand<*>) { + Bukkit.getServer().helpMap.addTopic( + CustomCommandHelpTopic(command.name, command.description, command.helpTopic) { + val context = MinecraftServer.getServer().serverCommandListener + val requirements = command.requirements.all { it(this) } + val permissionRequirements = command.permissionRequirements.all { + if (it.permission.isEmpty()) context.hasPermission(it.level) + else context.hasPermission(it.level, it.permission) + } + requirements.and(permissionRequirements) + } + ) + } + + fun handleExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + val stellarContext = CommandContextAdapter.getStellarCommandContext(context) + + for (runnable in command.base.runnables) runnable(stellarContext) + val arguments = getArguments(command.base, context) + for (argument in arguments) for (runnable in argument.runnables) runnable(stellarContext) + for (execution in command.executions) execution(stellarContext) + } + + fun fulfillsRequirements(command: AbstractStellarCommand<*>, source: CommandListenerWrapper): Boolean { + val fulfillsExecutionRequirements = command.requirements.all { it(source.bukkitSender) } + val fulfillsPermissionRequirements = command.permissionRequirements.all { source.hasPermission(it.level, it.permission) } + return fulfillsExecutionRequirements.and(fulfillsPermissionRequirements) + } + + fun handleFailureMessageAndExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + for (execution in command.failureExecutions) execution(CommandContextAdapter.getStellarCommandContext(context)) + for (message in command.failureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + for (message in command.globalFailureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + } + + fun getArguments( + baseCommand: AbstractStellarCommand<*>, + context: CommandContext, + currentIndex: Int = 1, + listOfArguments: List> = emptyList() + ): List> { + if (listOfArguments.size == context.nodes.size - 1) return listOfArguments + for (argument in baseCommand.arguments) + if (argument.name == context.nodes[currentIndex].node.name) + return getArguments(argument, context, currentIndex + 1, listOfArguments + argument) + return emptyList() + } + +} \ No newline at end of file diff --git a/v1_15_2/src/main/kotlin/com/undefined/stellar/v1_15_2/CommandAdapter.kt b/v1_15_2/src/main/kotlin/com/undefined/stellar/v1_15_2/CommandAdapter.kt new file mode 100644 index 0000000..208c25d --- /dev/null +++ b/v1_15_2/src/main/kotlin/com/undefined/stellar/v1_15_2/CommandAdapter.kt @@ -0,0 +1,96 @@ +package com.undefined.stellar.v1_15_2 + +import com.mojang.brigadier.Command +import com.mojang.brigadier.builder.ArgumentBuilder +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.primitive.PhraseArgument +import net.minecraft.server.v1_15_R1.CommandListenerWrapper + +object CommandAdapter { + + fun getBaseCommand(command: AbstractStellarCommand<*>, name: String = command.name): LiteralArgumentBuilder { + val brigadierCommand = LiteralArgumentBuilder.literal(name) + handleCommandFunctions(command, brigadierCommand) + handleArguments(command, brigadierCommand) + return brigadierCommand + } + + private fun handleCommandFunctions(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + if (command.executions.isNotEmpty() || command.executions.isNotEmpty()) + brigadierCommand.executes { context -> + BrigadierCommandHelper.handleExecutions(command, context) + 1 + } + brigadierCommand.requires { source -> + BrigadierCommandHelper.fulfillsRequirements(command, source) + } + } + + private fun handleArguments(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + for (argument in command.arguments) { + when (argument) { + is LiteralStellarArgument -> handleLiteralArgument(argument, brigadierCommand) + is PhraseArgument-> handlePhraseArgument(argument, brigadierCommand) + else -> handleRequiredArgument(argument, brigadierCommand) + } + } + } + + private fun handleLiteralArgument(argument: LiteralStellarArgument, brigadierCommand: ArgumentBuilder) { + for (argumentBuilder in ArgumentHelper.getLiteralArguments(argument)) { + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + } + + private fun handlePhraseArgument(argument: PhraseArgument, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleGreedyStringWordFunctions(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + + private fun handleGreedyStringWordFunctions(argument: PhraseArgument, argumentBuilder: RequiredArgumentBuilder) { + argumentBuilder.executes { context -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + + for (i in greedyContext.arguments.indices) { + val word = argument.words[i] ?: continue + for (runnable in word.runnables) runnable(greedyContext) + if (i == greedyContext.arguments.lastIndex) + for (execution in word.executions) execution(greedyContext) + } + Command.SINGLE_SUCCESS + } + + argumentBuilder.suggests { context, builder -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + var prevChar = ' ' + val input = ArgumentHelper.getArgumentInput(context, argument.name) ?: "" + val amountOfSpaces: Int = if (input.isEmpty()) 0 else input.count { + if (prevChar == ' ' && it == ' ') return@count false + prevChar = it + it == ' ' + } + val newBuilder = builder.createOffset(builder.input.lastIndexOf(' ') + 1) + val word = argument.words[amountOfSpaces] ?: return@suggests newBuilder.buildFuture() + for (stellarSuggestion in word.suggestions) + for (suggestion in stellarSuggestion.get(greedyContext)) + newBuilder.suggest(suggestion.text) { suggestion.tooltip } + newBuilder.buildFuture() + } + } + + private fun handleRequiredArgument(argument: AbstractStellarArgument<*>, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + +} diff --git a/v1_15_2/src/main/kotlin/com/undefined/stellar/v1_15_2/CommandContextAdapter.kt b/v1_15_2/src/main/kotlin/com/undefined/stellar/v1_15_2/CommandContextAdapter.kt new file mode 100644 index 0000000..b647246 --- /dev/null +++ b/v1_15_2/src/main/kotlin/com/undefined/stellar/v1_15_2/CommandContextAdapter.kt @@ -0,0 +1,83 @@ +package com.undefined.stellar.v1_15_2 + +import com.mojang.brigadier.context.CommandContext +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.data.argument.CommandNode +import com.undefined.stellar.data.argument.PhraseCommandContext +import com.undefined.stellar.exception.DuplicateArgumentNameException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_15_R1.* +import org.bukkit.command.CommandSender + +object CommandContextAdapter { + + fun getStellarCommandContext(context: CommandContext): com.undefined.stellar.data.argument.CommandContext { + val input = context.input.removePrefix("/") + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val arguments = BrigadierCommandHelper.getArguments(baseCommand, context) + if (arguments.filter { it !is LiteralStellarArgument }.groupingBy { it.name }.eachCount().any { it.value > 1 }) throw DuplicateArgumentNameException() + val parsedArguments: CommandNode = + BrigadierCommandHelper.getArguments(baseCommand, context) + .associate, String, (com.undefined.stellar.data.argument.CommandContext) -> Any?> { argument -> + if (argument is CustomArgument) return@associate Pair(argument.name) { argument.parse(it) } + if (argument is LiteralStellarArgument) return@associate Pair(argument.name) { throw LiteralArgumentMismatchException() } + Pair(argument.name) { + ArgumentHelper.getParsedArgument(context, argument) + } + } as CommandNode + return com.undefined.stellar.data.argument.CommandContext( + parsedArguments, + context.source.bukkitSender, + input + ) + } + + fun getGreedyCommandContext(context: CommandContext): PhraseCommandContext { + val input = context.input.removePrefix("/") + val words = input.split(' ').toMutableList() + + val totalOtherArguments = context.nodes.size - 1 + for (i in (1..totalOtherArguments)) words.removeFirst() + return PhraseCommandContext( + words, + context.source.bukkitSender, + input + ) + } + + @Suppress("DEPRECATION") + fun getCommandListenerWrapper(sender: CommandSender): CommandListenerWrapper { + val overworld = MinecraftServer.getServer().getWorldServer(DimensionManager.OVERWORLD) + return CommandListenerWrapper( + Source(sender), + Vec3D(overworld.spawn), + Vec2F.a, + overworld, + 4, + sender.name, + ChatComponentText(sender.name), + MinecraftServer.getServer(), + null + ) + } + + private data class Source(val sender: CommandSender) : ICommandListener { + override fun sendMessage(message: IChatBaseComponent) { + this.sender.sendMessage(LegacyComponentSerializer.legacySection().serialize(asAdventure(message))) + } + override fun shouldSendSuccess(): Boolean = true + override fun shouldSendFailure(): Boolean = true + override fun shouldBroadcastCommands(): Boolean = false + override fun getBukkitSender(stack: CommandListenerWrapper): CommandSender = this.sender + } + + fun asAdventure(component: IChatBaseComponent): net.kyori.adventure.text.Component = + GsonComponentSerializer.gson().deserializeFromTree(IChatBaseComponent.ChatSerializer.b(component)) + +} \ No newline at end of file diff --git a/v1_15_2/src/main/kotlin/com/undefined/stellar/v1_15_2/CommandRegistrar.kt b/v1_15_2/src/main/kotlin/com/undefined/stellar/v1_15_2/CommandRegistrar.kt new file mode 100644 index 0000000..8b5ad8f --- /dev/null +++ b/v1_15_2/src/main/kotlin/com/undefined/stellar/v1_15_2/CommandRegistrar.kt @@ -0,0 +1,38 @@ +package com.undefined.stellar.v1_15_2 + +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.registrar.AbstractCommandRegistrar +import com.undefined.stellar.v1_15_2.BrigadierCommandHelper.dispatcher +import org.bukkit.command.CommandSender +import org.bukkit.plugin.java.JavaPlugin + +object CommandRegistrar : AbstractCommandRegistrar { + + override fun register(command: AbstractStellarCommand<*>, plugin: JavaPlugin) { + BrigadierCommandHelper.handleHelpTopic(command) + for (name in command.aliases + command.name) + BrigadierCommandHelper.register(CommandAdapter.getBaseCommand(command, name)) + } + + override fun handleCommandFailure(sender: CommandSender, input: String): Boolean { + val results = dispatcher.parse(input, BrigadierCommandHelper.COMMAND_SOURCE) + val context = results.context.withSource(CommandContextAdapter.getCommandListenerWrapper(sender)).build(input) + + if (results.reader.remainingLength == 0) return false + if (context.nodes.isEmpty()) return false + + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val argument = BrigadierCommandHelper.getArguments(baseCommand, context).lastOrNull() + argument?.let { + BrigadierCommandHelper.handleFailureMessageAndExecutions(argument, context) + if (argument.hideDefaultFailureMessages.hide) return true + } ?: run { + BrigadierCommandHelper.handleFailureMessageAndExecutions(baseCommand, context) + if (baseCommand.hideDefaultFailureMessages.hide) return true + } + + return baseCommand.hasGlobalHiddenDefaultFailureMessages() + } + +} \ No newline at end of file diff --git a/v1_16_1/build.gradle.kts b/v1_16_1/build.gradle.kts new file mode 100644 index 0000000..57f17bd --- /dev/null +++ b/v1_16_1/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + kotlin("jvm") version "1.9.22" +} + +repositories { + mavenLocal() +} + +dependencies { + compileOnly("org.spigotmc:spigot:1.16.1-R0.1-SNAPSHOT") + compileOnly(project(":common")) +} + +tasks { + compileKotlin { + kotlinOptions.jvmTarget = "1.8" + } + compileJava { + options.release.set(8) + } +} + +java { + disableAutoTargetJvm() +} + +kotlin { + jvmToolchain(21) +} \ No newline at end of file diff --git a/v1_16_1/src/main/kotlin/com/undefined/stellar/v1_16_1/ArgumentHelper.kt b/v1_16_1/src/main/kotlin/com/undefined/stellar/v1_16_1/ArgumentHelper.kt new file mode 100644 index 0000000..12890b3 --- /dev/null +++ b/v1_16_1/src/main/kotlin/com/undefined/stellar/v1_16_1/ArgumentHelper.kt @@ -0,0 +1,438 @@ +package com.undefined.stellar.v1_16_1 + +import com.mojang.brigadier.arguments.* +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 com.mojang.brigadier.context.ParsedArgument +import com.mojang.brigadier.context.StringRange +import com.mojang.brigadier.exceptions.CommandSyntaxException +import com.mojang.brigadier.suggestion.SuggestionProvider +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.block.BlockDataArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.argument.types.custom.ListArgument +import com.undefined.stellar.argument.types.entity.EntityDisplayType +import com.undefined.stellar.argument.types.item.ItemSlotArgument +import com.undefined.stellar.argument.types.item.ItemSlotsArgument +import com.undefined.stellar.argument.types.math.AxisArgument +import com.undefined.stellar.argument.types.misc.NamespacedKeyArgument +import com.undefined.stellar.argument.types.misc.UUIDArgument +import com.undefined.stellar.argument.types.player.GameModeArgument +import com.undefined.stellar.argument.types.primitive.* +import com.undefined.stellar.argument.types.registry.* +import com.undefined.stellar.argument.types.scoreboard.DisplaySlotArgument +import com.undefined.stellar.argument.types.scoreboard.ScoreHolderType +import com.undefined.stellar.argument.types.structure.LootTableArgument +import com.undefined.stellar.argument.types.structure.MirrorArgument +import com.undefined.stellar.argument.types.structure.StructureRotationArgument +import com.undefined.stellar.argument.types.world.HeightMapArgument +import com.undefined.stellar.argument.types.world.LocationArgument +import com.undefined.stellar.argument.types.world.LocationType +import com.undefined.stellar.data.argument.Anchor +import com.undefined.stellar.data.argument.Operation +import com.undefined.stellar.data.argument.ParticleData +import com.undefined.stellar.exception.ArgumentVersionMismatchException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import com.undefined.stellar.exception.UnsupportedArgumentException +import com.undefined.stellar.util.NMSVersion +import com.undefined.stellar.util.ReflectionUtil +import com.undefined.stellar.util.executePrivateMethod +import net.kyori.adventure.text.format.Style +import net.kyori.adventure.text.format.TextColor +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.minecraft.server.v1_16_R1.* +import org.bukkit.* +import org.bukkit.Particle +import org.bukkit.Registry +import org.bukkit.World +import org.bukkit.block.Block +import org.bukkit.block.data.BlockData +import org.bukkit.craftbukkit.v1_16_R1.block.data.CraftBlockData +import org.bukkit.craftbukkit.v1_16_R1.CraftParticle +import org.bukkit.craftbukkit.v1_16_R1.inventory.CraftItemStack +import org.bukkit.event.inventory.InventoryType +import org.bukkit.inventory.ItemStack +import org.bukkit.scoreboard.DisplaySlot +import java.time.Duration +import java.util.* +import java.util.function.Predicate + +@Suppress("UNCHECKED_CAST", "DEPRECATION") +object ArgumentHelper { + + fun getLiteralArguments(argument: AbstractStellarArgument<*>): List> { + val arguments: MutableList> = mutableListOf() + for (name in argument.aliases + argument.name) + arguments.add(LiteralArgumentBuilder.literal(name)) + return arguments + } + + fun getRequiredArgumentBuilder(argument: AbstractStellarArgument<*>): RequiredArgumentBuilder { + val argumentBuilder: RequiredArgumentBuilder = RequiredArgumentBuilder.argument(argument.name, getArgumentType(argument)) + getSuggestions(argument)?.let { argumentBuilder.suggests(it) } + return argumentBuilder + } + + private fun > getSuggestions(argument: T): SuggestionProvider? = + when (argument) { + is GameEventArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MOB_EFFECT.keySet(), builder) + } + is VillagerProfessionArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_PROFESSION.keySet(), builder) + } + is VillagerTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_TYPE.keySet(), builder) + } + is AttributeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.ATTRIBUTE.keySet(), builder) + } + is BiomeArgument -> SuggestionProvider { context, builder -> + CompletionProviders.d.getSuggestions(context, builder) + } + is EntityTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.ENTITY_TYPE.keySet(), builder) + } + is MemoryKeyArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MEMORY_MODULE_TYPE.keySet(), builder) + } + else -> null + } + + private fun > getArgumentType(argument: T): ArgumentType<*> = + when (argument) { + is ListArgument<*> -> getArgumentType(argument.type) + is CustomArgument<*> -> getArgumentType(argument.type) + is StringArgument -> brigadier(argument.type) + is PhraseArgument -> brigadier(StringType.PHRASE) + is IntegerArgument -> IntegerArgumentType.integer(argument.min, argument.max) + is LongArgument -> LongArgumentType.longArg(argument.min, argument.max) + is FloatArgument -> FloatArgumentType.floatArg(argument.min, argument.max) + is DoubleArgument -> DoubleArgumentType.doubleArg(argument.min, argument.max) + is BooleanArgument -> BoolArgumentType.bool() + is com.undefined.stellar.argument.types.entity.EntityArgument -> brigadier(argument.type) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a() + is LocationArgument -> when (argument.type) { + LocationType.LOCATION_3D -> ArgumentPosition.a() + LocationType.LOCATION_2D -> ArgumentVec2I.a() + LocationType.PRECISE_LOCATION_2D -> ArgumentVec3.a() + LocationType.PRECISE_LOCATION_3D -> ArgumentVec2.a() + } + is BlockDataArgument -> ArgumentTile.a() + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> ArgumentBlockPredicate.a() + is com.undefined.stellar.argument.types.item.ItemArgument -> ArgumentItemStack.a() + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> ArgumentItemPredicate.a() + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a() + is com.undefined.stellar.argument.types.text.ComponentArgument -> ArgumentChatComponent.a() + is com.undefined.stellar.argument.types.text.StyleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.text.MessageArgument -> ArgumentChat.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> ArgumentScoreboardObjective.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a() + is com.undefined.stellar.argument.types.math.OperationArgument -> ArgumentMathOperation.a() + is com.undefined.stellar.argument.types.world.ParticleArgument -> ArgumentParticle.a() + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> ArgumentRotation.a() + is DisplaySlotArgument -> ArgumentScoreboardSlot.a() + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a() + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b() + } + is AxisArgument -> ArgumentRotationAxis.a() + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> ArgumentScoreboardTeam.a() + is ItemSlotArgument -> ArgumentInventorySlot.a() + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> ArgumentMinecraftKeyRegistered.a() + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> ArgumentAnchor.a() + is com.undefined.stellar.argument.types.math.RangeArgument -> ReflectionUtil.executePrivateMethod, ArgumentCriterionValue<*>>("a") + is com.undefined.stellar.argument.types.world.DimensionArgument -> ArgumentDimension.a() + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> ArgumentTime.a() + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> ArgumentUUID.a() + is GameEventArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> ArgumentMinecraftKeyRegistered.a() + is VillagerTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> throwArgumentVersionException(argument) + is AttributeArgument -> ArgumentMinecraftKeyRegistered.a() + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> ArgumentMinecraftKeyRegistered.a() + else -> throw UnsupportedArgumentException(argument) + } + + fun > getParsedArgument(context: CommandContext, argument: T): Any? { + return when (argument) { + is LiteralStellarArgument -> throw LiteralArgumentMismatchException() + is CustomArgument<*> -> argument.parse(CommandContextAdapter.getStellarCommandContext(context)) + is StringArgument -> StringArgumentType.getString(context, argument.name) + is IntegerArgument -> IntegerArgumentType.getInteger(context, argument.name) + is FloatArgument -> FloatArgumentType.getFloat(context, argument.name) + is DoubleArgument -> DoubleArgumentType.getDouble(context, argument.name) + is BooleanArgument -> BoolArgumentType.getBool(context, argument.name) + is ListArgument<*> -> argument.parse(getParsedArgument(context, argument)) + is com.undefined.stellar.argument.types.entity.EntityArgument -> ArgumentEntity.b(context, argument.name) + .map { it.bukkitEntity }.toMutableList() + .addAll(listOf(ArgumentEntity.a(context, argument.name).bukkitEntity)) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a(context, argument.name) + is LocationArgument -> getLocation(context, argument) + is BlockDataArgument -> CraftBlockData.fromData(ArgumentTile.a(context, argument.name).a()) + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> Predicate { block: Block -> + ArgumentBlockPredicate.a(context, argument.name).test(ShapeDetectorBlock( + context.source.world, + BlockPosition(block.x, block.y, block.z), true + )) + } + is com.undefined.stellar.argument.types.item.ItemArgument -> CraftItemStack.asBukkitCopy( + ArgumentItemStack.a(context, argument.name).a(1, false) + ) + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> Predicate { item: ItemStack -> + ArgumentItemPredicate.a(context, argument.name).test(CraftItemStack.asNMSCopy(item)) + } + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a( + context, + argument.name + ).e()?.let { Style.style(TextColor.color(it)) } ?: Style.empty() + is com.undefined.stellar.argument.types.text.ComponentArgument -> GsonComponentSerializer.gson() + .deserialize(IChatBaseComponent.ChatSerializer.a( + ArgumentChatComponent.a(context, argument.name) + )) + is com.undefined.stellar.argument.types.text.StyleArgument -> GsonComponentSerializer.gson().deserialize( + getArgumentInput(context, argument.name) ?: return null + ).style() + is com.undefined.stellar.argument.types.text.MessageArgument -> GsonComponentSerializer.gson().deserialize( + IChatBaseComponent.ChatSerializer.a(ArgumentChat.a(context, argument.name)) + ) + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getObjective( + ArgumentScoreboardObjective.a(context, argument.name).name + ) + + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a( + context, + argument.name + ).name + is com.undefined.stellar.argument.types.math.OperationArgument -> Operation.getOperation( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.world.ParticleArgument -> { + val particleOptions = ArgumentParticle.a(context, argument.name) + getParticleData(CraftParticle.toBukkit(particleOptions.particle), particleOptions) + } + is com.undefined.stellar.argument.types.math.AngleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.RotationArgument -> { + val rotation = ArgumentRotation.a(context, argument.name).a(context.source) + Location(context.source.world.world, rotation.x, rotation.y, rotation.z) + } + is DisplaySlotArgument -> getBukkitDisplaySlot(ArgumentScoreboardSlot.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a(context, argument.name) + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b(context, argument.name) + } + is AxisArgument -> getBukkitAxis(ArgumentRotationAxis.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getTeam( + ArgumentScoreboardTeam.a(context, argument.name).name + ) + is ItemSlotArgument -> ArgumentInventorySlot.a(context, argument.name) + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> NamespacedKey( + ArgumentMinecraftKeyRegistered.e(context, argument.name).namespace, + ArgumentMinecraftKeyRegistered.e(context, argument.name).key + ) + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> Anchor.getFromName( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.math.RangeArgument -> { + val range = ArgumentCriterionValue.b.a(context, argument.name) + IntRange(range.a() ?: 1, range.b() ?: 2) + } + is com.undefined.stellar.argument.types.world.DimensionArgument -> ArgumentDimension.a(context, argument.name).world.environment + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> Duration.ofSeconds(IntegerArgumentType.getInteger(context, argument.name).toLong() / 20) + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> ArgumentUUID.a(context, argument.name) + is GameEventArgument -> throwArgumentVersionException(argument) + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> Registry.VILLAGER_PROFESSION.get(getId(context, argument.name)) + is VillagerTypeArgument -> Registry.VILLAGER_TYPE.get(getId(context, argument.name)) + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> getInventoryType( + IRegistry.MENU[ArgumentMinecraftKeyRegistered.e(context, argument.name)] + ) + is AttributeArgument -> Registry.ATTRIBUTE.get(getId(context, argument.name)) + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> Registry.BIOME.get(getId(context, argument.name)) + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> Registry.ENTITY_TYPE.get(getId(context, argument.name)) + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> Registry.MEMORY_MODULE_TYPE.get(getId(context, argument.name)) + else -> throw UnsupportedArgumentException(argument) + } + } + + fun getArgumentInput(context: CommandContext, name: String): String? { + val field = CommandContext::class.java.getDeclaredField("arguments") + field.isAccessible = true + val arguments: Map> = field.get(context) as Map> + val argument = arguments[name] ?: return null + val range = StringRange.between(argument.range.start, context.input.length) + return range.get(context.input) + } + + private fun getInventoryType(menu: Containers<*>?): InventoryType = when (menu) { + Containers.GENERIC_9X1 -> InventoryType.CHEST + Containers.GENERIC_9X2 -> InventoryType.CHEST + Containers.GENERIC_9X3 -> InventoryType.CHEST + Containers.GENERIC_9X4 -> InventoryType.CHEST + Containers.GENERIC_9X5 -> InventoryType.CHEST + Containers.GENERIC_9X6 -> InventoryType.CHEST + Containers.GENERIC_3X3 -> InventoryType.WORKBENCH + Containers.ANVIL -> InventoryType.ANVIL + Containers.BEACON -> InventoryType.BEACON + Containers.BLAST_FURNACE -> InventoryType.BLAST_FURNACE + Containers.BREWING_STAND -> InventoryType.BREWING + Containers.CRAFTING -> InventoryType.CRAFTING + Containers.ENCHANTMENT -> InventoryType.ENCHANTING + Containers.FURNACE -> InventoryType.FURNACE + Containers.GRINDSTONE -> InventoryType.GRINDSTONE + Containers.HOPPER -> InventoryType.HOPPER + Containers.LECTERN -> InventoryType.LECTERN + Containers.LOOM -> InventoryType.LOOM + Containers.MERCHANT -> InventoryType.MERCHANT + Containers.SHULKER_BOX -> InventoryType.SHULKER_BOX + Containers.SMITHING -> InventoryType.SMITHING + Containers.SMOKER -> InventoryType.SMOKER + Containers.CARTOGRAPHY_TABLE -> InventoryType.CARTOGRAPHY + Containers.STONECUTTER -> InventoryType.STONECUTTER + else -> throw IllegalStateException("No inventory type found! This is not intentional behaviour, please contact the developers.") + } + + @Throws(CommandSyntaxException::class) + private fun getId( + context: CommandContext, + name: String + ): NamespacedKey { + val key = ArgumentMinecraftKeyRegistered.e(context, name) + return NamespacedKey(key.namespace, key.key) + } + + private fun brigadier(type: StringType): StringArgumentType = when (type) { + StringType.WORD -> StringArgumentType.word() + StringType.QUOTABLE_PHRASE -> StringArgumentType.string() + StringType.PHRASE -> StringArgumentType.greedyString() + } + + private fun brigadier(type: EntityDisplayType): ArgumentEntity = when (type) { + EntityDisplayType.ENTITY -> ReflectionUtil.executePrivateMethod("a") + EntityDisplayType.ENTITIES -> ArgumentEntity.multipleEntities() + EntityDisplayType.PLAYER -> ArgumentEntity.c() + EntityDisplayType.PLAYERS -> ArgumentEntity.d() + } + + private fun getBukkitAxis(argument: EnumSet): EnumSet = + argument.mapTo(EnumSet.noneOf(Axis::class.java)) { + when (it) { + EnumDirection.EnumAxis.X -> Axis.X + EnumDirection.EnumAxis.Y -> Axis.Y + EnumDirection.EnumAxis.Z -> Axis.Z + null -> Axis.X + } + } + + private fun getBukkitDisplaySlot(slot: Int): DisplaySlot = when (slot) { + 0 -> DisplaySlot.PLAYER_LIST + 2 -> DisplaySlot.BELOW_NAME + else -> DisplaySlot.SIDEBAR + } + + private fun getParticleData( + particle: Particle, + particleOptions: ParticleParam + ): ParticleData<*> = when (particleOptions) { + is ParticleType -> ParticleData(particle, null) + is ParticleParamBlock -> ParticleData(particle, CraftBlockData.fromData(particleOptions.executePrivateMethod("c"))) + is ParticleParamRedstone -> { + val colors = particleOptions.a().split(" ") + val red = colors[1].toFloat() + val green = colors[2].toFloat() + val blue = colors[3].toFloat() + val scale = colors[4].toFloat() + ParticleData( + particle, + Particle.DustOptions( + Color.fromRGB( + (red * 255.0f).toInt(), + (green * 255.0f).toInt(), (blue * 255.0f).toInt() + ), scale + ) + ) + } + is ParticleParamItem -> ParticleData( + particle, + CraftItemStack.asBukkitCopy(particleOptions.executePrivateMethod("c")) + ) + else -> ParticleData(particle, null) + } + + private fun getLocation(context: CommandContext, command: LocationArgument): Location { + val world = context.source.world.world + return when (command.type) { + LocationType.LOCATION_3D -> toLocation(world, context.getArgument(command.name, IVectorPosition::class.java).c(context.source)) + LocationType.LOCATION_2D -> toLocation(world, ArgumentVec2I.a(context, command.name)) + LocationType.PRECISE_LOCATION_3D -> toLocation(world, ArgumentVec3.a(context, command.name)) + LocationType.PRECISE_LOCATION_2D -> toLocation(world, ArgumentVec2.a(context, command.name)) + } + } + + private fun toLocation(world: World, position: BlockPosition) = + Location(world, position.x.toDouble(), position.y.toDouble(), position.z.toDouble()) + private fun toLocation(world: World, position: BlockPosition2D) = + Location(world, position.a.toDouble(), 0.0, position.b.toDouble()) + private fun toLocation(world: World, vec: Vec3D) = + Location(world, vec.x, vec.y, vec.z) + private fun toLocation(world: World, vec: Vec2F) = + Location(world, vec.i.toDouble(), 0.0, vec.j.toDouble()) + + private fun throwArgumentVersionException(argument: AbstractStellarArgument<*>): Nothing = + throw ArgumentVersionMismatchException(argument, NMSVersion.version) + +} \ No newline at end of file diff --git a/v1_16_1/src/main/kotlin/com/undefined/stellar/v1_16_1/BrigadierCommandHelper.kt b/v1_16_1/src/main/kotlin/com/undefined/stellar/v1_16_1/BrigadierCommandHelper.kt new file mode 100644 index 0000000..1b04c34 --- /dev/null +++ b/v1_16_1/src/main/kotlin/com/undefined/stellar/v1_16_1/BrigadierCommandHelper.kt @@ -0,0 +1,76 @@ +package com.undefined.stellar.v1_16_1 + +import com.mojang.brigadier.CommandDispatcher +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.tree.LiteralCommandNode +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.data.help.CustomCommandHelpTopic +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_16_R1.CommandListenerWrapper +import net.minecraft.server.v1_16_R1.MinecraftServer +import org.bukkit.Bukkit + +@Suppress("DEPRECATION") +object BrigadierCommandHelper { + + val COMMAND_SOURCE: CommandListenerWrapper by lazy { + MinecraftServer.getServer().serverCommandListener + } + val dispatcher: CommandDispatcher by lazy { + MinecraftServer.getServer().functionData.commandDispatcher + } + + fun register(command: LiteralArgumentBuilder): LiteralCommandNode? = + dispatcher.register(command) + + fun handleHelpTopic(command: AbstractStellarCommand<*>) { + Bukkit.getServer().helpMap.addTopic( + CustomCommandHelpTopic(command.name, command.description, command.helpTopic) { + val context = MinecraftServer.getServer().serverCommandListener + val requirements = command.requirements.all { it(this) } + val permissionRequirements = command.permissionRequirements.all { + if (it.permission.isEmpty()) context.hasPermission(it.level) + else context.hasPermission(it.level, it.permission) + } + requirements.and(permissionRequirements) + } + ) + } + + fun handleExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + val stellarContext = CommandContextAdapter.getStellarCommandContext(context) + + for (runnable in command.base.runnables) runnable(stellarContext) + val arguments = getArguments(command.base, context) + for (argument in arguments) for (runnable in argument.runnables) runnable(stellarContext) + for (execution in command.executions) execution(stellarContext) + } + + fun fulfillsRequirements(command: AbstractStellarCommand<*>, source: CommandListenerWrapper): Boolean { + val fulfillsExecutionRequirements = command.requirements.all { it(source.bukkitSender) } + val fulfillsPermissionRequirements = command.permissionRequirements.all { source.hasPermission(it.level, it.permission) } + return fulfillsExecutionRequirements.and(fulfillsPermissionRequirements) + } + + fun handleFailureMessageAndExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + for (execution in command.failureExecutions) execution(CommandContextAdapter.getStellarCommandContext(context)) + for (message in command.failureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + for (message in command.globalFailureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + } + + fun getArguments( + baseCommand: AbstractStellarCommand<*>, + context: CommandContext, + currentIndex: Int = 1, + listOfArguments: List> = emptyList() + ): List> { + if (listOfArguments.size == context.nodes.size - 1) return listOfArguments + for (argument in baseCommand.arguments) + if (argument.name == context.nodes[currentIndex].node.name) + return getArguments(argument, context, currentIndex + 1, listOfArguments + argument) + return emptyList() + } + +} \ No newline at end of file diff --git a/v1_16_1/src/main/kotlin/com/undefined/stellar/v1_16_1/CommandAdapter.kt b/v1_16_1/src/main/kotlin/com/undefined/stellar/v1_16_1/CommandAdapter.kt new file mode 100644 index 0000000..f2788fa --- /dev/null +++ b/v1_16_1/src/main/kotlin/com/undefined/stellar/v1_16_1/CommandAdapter.kt @@ -0,0 +1,96 @@ +package com.undefined.stellar.v1_16_1 + +import com.mojang.brigadier.Command +import com.mojang.brigadier.builder.ArgumentBuilder +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.primitive.PhraseArgument +import net.minecraft.server.v1_16_R1.CommandListenerWrapper + +object CommandAdapter { + + fun getBaseCommand(command: AbstractStellarCommand<*>, name: String = command.name): LiteralArgumentBuilder { + val brigadierCommand = LiteralArgumentBuilder.literal(name) + handleCommandFunctions(command, brigadierCommand) + handleArguments(command, brigadierCommand) + return brigadierCommand + } + + private fun handleCommandFunctions(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + if (command.executions.isNotEmpty() || command.executions.isNotEmpty()) + brigadierCommand.executes { context -> + BrigadierCommandHelper.handleExecutions(command, context) + 1 + } + brigadierCommand.requires { source -> + BrigadierCommandHelper.fulfillsRequirements(command, source) + } + } + + private fun handleArguments(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + for (argument in command.arguments) { + when (argument) { + is LiteralStellarArgument -> handleLiteralArgument(argument, brigadierCommand) + is PhraseArgument-> handlePhraseArgument(argument, brigadierCommand) + else -> handleRequiredArgument(argument, brigadierCommand) + } + } + } + + private fun handleLiteralArgument(argument: LiteralStellarArgument, brigadierCommand: ArgumentBuilder) { + for (argumentBuilder in ArgumentHelper.getLiteralArguments(argument)) { + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + } + + private fun handlePhraseArgument(argument: PhraseArgument, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleGreedyStringWordFunctions(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + + private fun handleGreedyStringWordFunctions(argument: PhraseArgument, argumentBuilder: RequiredArgumentBuilder) { + argumentBuilder.executes { context -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + + for (i in greedyContext.arguments.indices) { + val word = argument.words[i] ?: continue + for (runnable in word.runnables) runnable(greedyContext) + if (i == greedyContext.arguments.lastIndex) + for (execution in word.executions) execution(greedyContext) + } + Command.SINGLE_SUCCESS + } + + argumentBuilder.suggests { context, builder -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + var prevChar = ' ' + val input = ArgumentHelper.getArgumentInput(context, argument.name) ?: "" + val amountOfSpaces: Int = if (input.isEmpty()) 0 else input.count { + if (prevChar == ' ' && it == ' ') return@count false + prevChar = it + it == ' ' + } + val newBuilder = builder.createOffset(builder.input.lastIndexOf(' ') + 1) + val word = argument.words[amountOfSpaces] ?: return@suggests newBuilder.buildFuture() + for (stellarSuggestion in word.suggestions) + for (suggestion in stellarSuggestion.get(greedyContext)) + newBuilder.suggest(suggestion.text) { suggestion.tooltip } + newBuilder.buildFuture() + } + } + + private fun handleRequiredArgument(argument: AbstractStellarArgument<*>, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + +} diff --git a/v1_16_1/src/main/kotlin/com/undefined/stellar/v1_16_1/CommandContextAdapter.kt b/v1_16_1/src/main/kotlin/com/undefined/stellar/v1_16_1/CommandContextAdapter.kt new file mode 100644 index 0000000..6a09f62 --- /dev/null +++ b/v1_16_1/src/main/kotlin/com/undefined/stellar/v1_16_1/CommandContextAdapter.kt @@ -0,0 +1,84 @@ +package com.undefined.stellar.v1_16_1 + +import com.mojang.brigadier.context.CommandContext +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.data.argument.CommandNode +import com.undefined.stellar.data.argument.PhraseCommandContext +import com.undefined.stellar.exception.DuplicateArgumentNameException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_16_R1.* +import org.bukkit.command.CommandSender +import java.util.* + +object CommandContextAdapter { + + fun getStellarCommandContext(context: CommandContext): com.undefined.stellar.data.argument.CommandContext { + val input = context.input.removePrefix("/") + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val arguments = BrigadierCommandHelper.getArguments(baseCommand, context) + if (arguments.filter { it !is LiteralStellarArgument }.groupingBy { it.name }.eachCount().any { it.value > 1 }) throw DuplicateArgumentNameException() + val parsedArguments: CommandNode = + BrigadierCommandHelper.getArguments(baseCommand, context) + .associate, String, (com.undefined.stellar.data.argument.CommandContext) -> Any?> { argument -> + if (argument is CustomArgument) return@associate Pair(argument.name) { argument.parse(it) } + if (argument is LiteralStellarArgument) return@associate Pair(argument.name) { throw LiteralArgumentMismatchException() } + Pair(argument.name) { + ArgumentHelper.getParsedArgument(context, argument) + } + } as CommandNode + return com.undefined.stellar.data.argument.CommandContext( + parsedArguments, + context.source.bukkitSender, + input + ) + } + + fun getGreedyCommandContext(context: CommandContext): PhraseCommandContext { + val input = context.input.removePrefix("/") + val words = input.split(' ').toMutableList() + + val totalOtherArguments = context.nodes.size - 1 + for (i in (1..totalOtherArguments)) words.removeFirst() + return PhraseCommandContext( + words, + context.source.bukkitSender, + input + ) + } + + @Suppress("DEPRECATION") + fun getCommandListenerWrapper(sender: CommandSender): CommandListenerWrapper { + val overworld = MinecraftServer.getServer().D() + return CommandListenerWrapper( + Source(sender), + Vec3D.b(overworld.spawn), + Vec2F.a, + overworld, + 4, + sender.name, + ChatComponentText(sender.name), + MinecraftServer.getServer(), + null + ) + } + + private data class Source(val sender: CommandSender) : ICommandListener { + override fun sendMessage(message: IChatBaseComponent, sender: UUID) { + this.sender.sendMessage(LegacyComponentSerializer.legacySection().serialize(asAdventure(message))) + } + override fun shouldSendSuccess(): Boolean = true + override fun shouldSendFailure(): Boolean = true + override fun shouldBroadcastCommands(): Boolean = false + override fun getBukkitSender(stack: CommandListenerWrapper): CommandSender = this.sender + } + + fun asAdventure(component: IChatBaseComponent): net.kyori.adventure.text.Component = + GsonComponentSerializer.gson().deserializeFromTree(IChatBaseComponent.ChatSerializer.b(component)) + +} \ No newline at end of file diff --git a/v1_16_1/src/main/kotlin/com/undefined/stellar/v1_16_1/CommandRegistrar.kt b/v1_16_1/src/main/kotlin/com/undefined/stellar/v1_16_1/CommandRegistrar.kt new file mode 100644 index 0000000..7b102af --- /dev/null +++ b/v1_16_1/src/main/kotlin/com/undefined/stellar/v1_16_1/CommandRegistrar.kt @@ -0,0 +1,38 @@ +package com.undefined.stellar.v1_16_1 + +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.registrar.AbstractCommandRegistrar +import com.undefined.stellar.v1_16_1.BrigadierCommandHelper.dispatcher +import org.bukkit.command.CommandSender +import org.bukkit.plugin.java.JavaPlugin + +object CommandRegistrar : AbstractCommandRegistrar { + + override fun register(command: AbstractStellarCommand<*>, plugin: JavaPlugin) { + BrigadierCommandHelper.handleHelpTopic(command) + for (name in command.aliases + command.name) + BrigadierCommandHelper.register(CommandAdapter.getBaseCommand(command, name)) + } + + override fun handleCommandFailure(sender: CommandSender, input: String): Boolean { + val results = dispatcher.parse(input, BrigadierCommandHelper.COMMAND_SOURCE) + val context = results.context.withSource(CommandContextAdapter.getCommandListenerWrapper(sender)).build(input) + + if (results.reader.remainingLength == 0) return false + if (context.nodes.isEmpty()) return false + + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val argument = BrigadierCommandHelper.getArguments(baseCommand, context).lastOrNull() + argument?.let { + BrigadierCommandHelper.handleFailureMessageAndExecutions(argument, context) + if (argument.hideDefaultFailureMessages.hide) return true + } ?: run { + BrigadierCommandHelper.handleFailureMessageAndExecutions(baseCommand, context) + if (baseCommand.hideDefaultFailureMessages.hide) return true + } + + return baseCommand.hasGlobalHiddenDefaultFailureMessages() + } + +} \ No newline at end of file diff --git a/v1_16_2/build.gradle.kts b/v1_16_2/build.gradle.kts new file mode 100644 index 0000000..c1f9edd --- /dev/null +++ b/v1_16_2/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + kotlin("jvm") version "1.9.22" +} + +repositories { + mavenLocal() +} + +dependencies { + compileOnly("org.spigotmc:spigot:1.16.2-R0.1-SNAPSHOT") + compileOnly(project(":common")) +} + +tasks { + compileKotlin { + kotlinOptions.jvmTarget = "1.8" + } + compileJava { + options.release.set(8) + } +} + +java { + disableAutoTargetJvm() +} + +kotlin { + jvmToolchain(21) +} \ No newline at end of file diff --git a/v1_16_2/src/main/kotlin/com/undefined/stellar/v1_16_2/ArgumentHelper.kt b/v1_16_2/src/main/kotlin/com/undefined/stellar/v1_16_2/ArgumentHelper.kt new file mode 100644 index 0000000..c501275 --- /dev/null +++ b/v1_16_2/src/main/kotlin/com/undefined/stellar/v1_16_2/ArgumentHelper.kt @@ -0,0 +1,438 @@ +package com.undefined.stellar.v1_16_2 + +import com.mojang.brigadier.arguments.* +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 com.mojang.brigadier.context.ParsedArgument +import com.mojang.brigadier.context.StringRange +import com.mojang.brigadier.exceptions.CommandSyntaxException +import com.mojang.brigadier.suggestion.SuggestionProvider +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.block.BlockDataArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.argument.types.custom.ListArgument +import com.undefined.stellar.argument.types.entity.EntityDisplayType +import com.undefined.stellar.argument.types.item.ItemSlotArgument +import com.undefined.stellar.argument.types.item.ItemSlotsArgument +import com.undefined.stellar.argument.types.math.AxisArgument +import com.undefined.stellar.argument.types.misc.NamespacedKeyArgument +import com.undefined.stellar.argument.types.misc.UUIDArgument +import com.undefined.stellar.argument.types.player.GameModeArgument +import com.undefined.stellar.argument.types.primitive.* +import com.undefined.stellar.argument.types.registry.* +import com.undefined.stellar.argument.types.scoreboard.DisplaySlotArgument +import com.undefined.stellar.argument.types.scoreboard.ScoreHolderType +import com.undefined.stellar.argument.types.structure.LootTableArgument +import com.undefined.stellar.argument.types.structure.MirrorArgument +import com.undefined.stellar.argument.types.structure.StructureRotationArgument +import com.undefined.stellar.argument.types.world.HeightMapArgument +import com.undefined.stellar.argument.types.world.LocationArgument +import com.undefined.stellar.argument.types.world.LocationType +import com.undefined.stellar.data.argument.Anchor +import com.undefined.stellar.data.argument.Operation +import com.undefined.stellar.data.argument.ParticleData +import com.undefined.stellar.exception.ArgumentVersionMismatchException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import com.undefined.stellar.exception.UnsupportedArgumentException +import com.undefined.stellar.util.NMSVersion +import com.undefined.stellar.util.ReflectionUtil +import com.undefined.stellar.util.executePrivateMethod +import net.kyori.adventure.text.format.Style +import net.kyori.adventure.text.format.TextColor +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.minecraft.server.v1_16_R2.* +import org.bukkit.* +import org.bukkit.Particle +import org.bukkit.Registry +import org.bukkit.World +import org.bukkit.block.Block +import org.bukkit.block.data.BlockData +import org.bukkit.craftbukkit.v1_16_R2.block.data.CraftBlockData +import org.bukkit.craftbukkit.v1_16_R2.CraftParticle +import org.bukkit.craftbukkit.v1_16_R2.inventory.CraftItemStack +import org.bukkit.event.inventory.InventoryType +import org.bukkit.inventory.ItemStack +import org.bukkit.scoreboard.DisplaySlot +import java.time.Duration +import java.util.* +import java.util.function.Predicate + +@Suppress("UNCHECKED_CAST", "DEPRECATION") +object ArgumentHelper { + + fun getLiteralArguments(argument: AbstractStellarArgument<*>): List> { + val arguments: MutableList> = mutableListOf() + for (name in argument.aliases + argument.name) + arguments.add(LiteralArgumentBuilder.literal(name)) + return arguments + } + + fun getRequiredArgumentBuilder(argument: AbstractStellarArgument<*>): RequiredArgumentBuilder { + val argumentBuilder: RequiredArgumentBuilder = RequiredArgumentBuilder.argument(argument.name, getArgumentType(argument)) + getSuggestions(argument)?.let { argumentBuilder.suggests(it) } + return argumentBuilder + } + + private fun > getSuggestions(argument: T): SuggestionProvider? = + when (argument) { + is GameEventArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MOB_EFFECT.keySet(), builder) + } + is VillagerProfessionArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_PROFESSION.keySet(), builder) + } + is VillagerTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_TYPE.keySet(), builder) + } + is AttributeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.ATTRIBUTE.keySet(), builder) + } + is BiomeArgument -> SuggestionProvider { context, builder -> + CompletionProviders.d.getSuggestions(context, builder) + } + is EntityTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.ENTITY_TYPE.keySet(), builder) + } + is MemoryKeyArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MEMORY_MODULE_TYPE.keySet(), builder) + } + else -> null + } + + private fun > getArgumentType(argument: T): ArgumentType<*> = + when (argument) { + is ListArgument<*> -> getArgumentType(argument.type) + is CustomArgument<*> -> getArgumentType(argument.type) + is StringArgument -> brigadier(argument.type) + is PhraseArgument -> brigadier(StringType.PHRASE) + is IntegerArgument -> IntegerArgumentType.integer(argument.min, argument.max) + is LongArgument -> LongArgumentType.longArg(argument.min, argument.max) + is FloatArgument -> FloatArgumentType.floatArg(argument.min, argument.max) + is DoubleArgument -> DoubleArgumentType.doubleArg(argument.min, argument.max) + is BooleanArgument -> BoolArgumentType.bool() + is com.undefined.stellar.argument.types.entity.EntityArgument -> brigadier(argument.type) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a() + is LocationArgument -> when (argument.type) { + LocationType.LOCATION_3D -> ArgumentPosition.a() + LocationType.LOCATION_2D -> ArgumentVec2I.a() + LocationType.PRECISE_LOCATION_2D -> ArgumentVec3.a() + LocationType.PRECISE_LOCATION_3D -> ArgumentVec2.a() + } + is BlockDataArgument -> ArgumentTile.a() + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> ArgumentBlockPredicate.a() + is com.undefined.stellar.argument.types.item.ItemArgument -> ArgumentItemStack.a() + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> ArgumentItemPredicate.a() + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a() + is com.undefined.stellar.argument.types.text.ComponentArgument -> ArgumentChatComponent.a() + is com.undefined.stellar.argument.types.text.StyleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.text.MessageArgument -> ArgumentChat.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> ArgumentScoreboardObjective.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a() + is com.undefined.stellar.argument.types.math.OperationArgument -> ArgumentMathOperation.a() + is com.undefined.stellar.argument.types.world.ParticleArgument -> ArgumentParticle.a() + is com.undefined.stellar.argument.types.math.AngleArgument -> ArgumentAngle.a() + is com.undefined.stellar.argument.types.math.RotationArgument -> ArgumentRotation.a() + is DisplaySlotArgument -> ArgumentScoreboardSlot.a() + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a() + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b() + } + is AxisArgument -> ArgumentRotationAxis.a() + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> ArgumentScoreboardTeam.a() + is ItemSlotArgument -> ArgumentInventorySlot.a() + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> ArgumentMinecraftKeyRegistered.a() + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> ArgumentAnchor.a() + is com.undefined.stellar.argument.types.math.RangeArgument -> ReflectionUtil.executePrivateMethod, ArgumentCriterionValue<*>>("a") + is com.undefined.stellar.argument.types.world.DimensionArgument -> ArgumentDimension.a() + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> ArgumentTime.a() + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> ArgumentUUID.a() + is GameEventArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> ArgumentMinecraftKeyRegistered.a() + is VillagerTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> throwArgumentVersionException(argument) + is AttributeArgument -> ArgumentMinecraftKeyRegistered.a() + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> ArgumentMinecraftKeyRegistered.a() + else -> throw UnsupportedArgumentException(argument) + } + + fun > getParsedArgument(context: CommandContext, argument: T): Any? { + return when (argument) { + is LiteralStellarArgument -> throw LiteralArgumentMismatchException() + is CustomArgument<*> -> argument.parse(CommandContextAdapter.getStellarCommandContext(context)) + is StringArgument -> StringArgumentType.getString(context, argument.name) + is IntegerArgument -> IntegerArgumentType.getInteger(context, argument.name) + is FloatArgument -> FloatArgumentType.getFloat(context, argument.name) + is DoubleArgument -> DoubleArgumentType.getDouble(context, argument.name) + is BooleanArgument -> BoolArgumentType.getBool(context, argument.name) + is ListArgument<*> -> argument.parse(getParsedArgument(context, argument)) + is com.undefined.stellar.argument.types.entity.EntityArgument -> ArgumentEntity.b(context, argument.name) + .map { it.bukkitEntity }.toMutableList() + .addAll(listOf(ArgumentEntity.a(context, argument.name).bukkitEntity)) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a(context, argument.name) + is LocationArgument -> getLocation(context, argument) + is BlockDataArgument -> CraftBlockData.fromData(ArgumentTile.a(context, argument.name).a()) + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> Predicate { block: Block -> + ArgumentBlockPredicate.a(context, argument.name).test(ShapeDetectorBlock( + context.source.world, + BlockPosition(block.x, block.y, block.z), true + )) + } + is com.undefined.stellar.argument.types.item.ItemArgument -> CraftItemStack.asBukkitCopy( + ArgumentItemStack.a(context, argument.name).a(1, false) + ) + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> Predicate { item: ItemStack -> + ArgumentItemPredicate.a(context, argument.name).test(CraftItemStack.asNMSCopy(item)) + } + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a( + context, + argument.name + ).e()?.let { Style.style(TextColor.color(it)) } ?: Style.empty() + is com.undefined.stellar.argument.types.text.ComponentArgument -> GsonComponentSerializer.gson() + .deserialize(IChatBaseComponent.ChatSerializer.a( + ArgumentChatComponent.a(context, argument.name) + )) + is com.undefined.stellar.argument.types.text.StyleArgument -> GsonComponentSerializer.gson().deserialize( + getArgumentInput(context, argument.name) ?: return null + ).style() + is com.undefined.stellar.argument.types.text.MessageArgument -> GsonComponentSerializer.gson().deserialize( + IChatBaseComponent.ChatSerializer.a(ArgumentChat.a(context, argument.name)) + ) + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getObjective( + ArgumentScoreboardObjective.a(context, argument.name).name + ) + + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a( + context, + argument.name + ).name + is com.undefined.stellar.argument.types.math.OperationArgument -> Operation.getOperation( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.world.ParticleArgument -> { + val particleOptions = ArgumentParticle.a(context, argument.name) + getParticleData(CraftParticle.toBukkit(particleOptions.particle), particleOptions) + } + is com.undefined.stellar.argument.types.math.AngleArgument -> ArgumentAngle.a(context, argument.name) + is com.undefined.stellar.argument.types.math.RotationArgument -> { + val rotation = ArgumentRotation.a(context, argument.name).a(context.source) + Location(context.source.world.world, rotation.x, rotation.y, rotation.z) + } + is DisplaySlotArgument -> getBukkitDisplaySlot(ArgumentScoreboardSlot.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a(context, argument.name) + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b(context, argument.name) + } + is AxisArgument -> getBukkitAxis(ArgumentRotationAxis.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getTeam( + ArgumentScoreboardTeam.a(context, argument.name).name + ) + is ItemSlotArgument -> ArgumentInventorySlot.a(context, argument.name) + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> NamespacedKey( + ArgumentMinecraftKeyRegistered.e(context, argument.name).namespace, + ArgumentMinecraftKeyRegistered.e(context, argument.name).key + ) + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> Anchor.getFromName( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.math.RangeArgument -> { + val range = ArgumentCriterionValue.b.a(context, argument.name) + IntRange(range.a() ?: 1, range.b() ?: 2) + } + is com.undefined.stellar.argument.types.world.DimensionArgument -> ArgumentDimension.a(context, argument.name).world.environment + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> Duration.ofSeconds(IntegerArgumentType.getInteger(context, argument.name).toLong() / 20) + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> ArgumentUUID.a(context, argument.name) + is GameEventArgument -> throwArgumentVersionException(argument) + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> Registry.VILLAGER_PROFESSION.get(getId(context, argument.name)) + is VillagerTypeArgument -> Registry.VILLAGER_TYPE.get(getId(context, argument.name)) + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> getInventoryType( + IRegistry.MENU.d(ResourceKey.a(IRegistry.v, ArgumentMinecraftKeyRegistered.e(context, argument.name))) + ) + is AttributeArgument -> Registry.ATTRIBUTE.get(getId(context, argument.name)) + is FluidArgument -> throwArgumentVersionException(argument) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> Registry.BIOME.get(getId(context, argument.name)) + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> Registry.ENTITY_TYPE.get(getId(context, argument.name)) + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> Registry.MEMORY_MODULE_TYPE.get(getId(context, argument.name)) + else -> throw UnsupportedArgumentException(argument) + } + } + + fun getArgumentInput(context: CommandContext, name: String): String? { + val field = CommandContext::class.java.getDeclaredField("arguments") + field.isAccessible = true + val arguments: Map> = field.get(context) as Map> + val argument = arguments[name] ?: return null + val range = StringRange.between(argument.range.start, context.input.length) + return range.get(context.input) + } + + private fun getInventoryType(menu: Containers<*>): InventoryType = when (menu) { + Containers.GENERIC_9X1 -> InventoryType.CHEST + Containers.GENERIC_9X2 -> InventoryType.CHEST + Containers.GENERIC_9X3 -> InventoryType.CHEST + Containers.GENERIC_9X4 -> InventoryType.CHEST + Containers.GENERIC_9X5 -> InventoryType.CHEST + Containers.GENERIC_9X6 -> InventoryType.CHEST + Containers.GENERIC_3X3 -> InventoryType.WORKBENCH + Containers.ANVIL -> InventoryType.ANVIL + Containers.BEACON -> InventoryType.BEACON + Containers.BLAST_FURNACE -> InventoryType.BLAST_FURNACE + Containers.BREWING_STAND -> InventoryType.BREWING + Containers.CRAFTING -> InventoryType.CRAFTING + Containers.ENCHANTMENT -> InventoryType.ENCHANTING + Containers.FURNACE -> InventoryType.FURNACE + Containers.GRINDSTONE -> InventoryType.GRINDSTONE + Containers.HOPPER -> InventoryType.HOPPER + Containers.LECTERN -> InventoryType.LECTERN + Containers.LOOM -> InventoryType.LOOM + Containers.MERCHANT -> InventoryType.MERCHANT + Containers.SHULKER_BOX -> InventoryType.SHULKER_BOX + Containers.SMITHING -> InventoryType.SMITHING + Containers.SMOKER -> InventoryType.SMOKER + Containers.CARTOGRAPHY_TABLE -> InventoryType.CARTOGRAPHY + Containers.STONECUTTER -> InventoryType.STONECUTTER + else -> throw IllegalStateException("No inventory type found! This is not intentional behaviour, please contact the developers.") + } + + @Throws(CommandSyntaxException::class) + private fun getId( + context: CommandContext, + name: String + ): NamespacedKey { + val key = ArgumentMinecraftKeyRegistered.e(context, name) + return NamespacedKey(key.namespace, key.key) + } + + private fun brigadier(type: StringType): StringArgumentType = when (type) { + StringType.WORD -> StringArgumentType.word() + StringType.QUOTABLE_PHRASE -> StringArgumentType.string() + StringType.PHRASE -> StringArgumentType.greedyString() + } + + private fun brigadier(type: EntityDisplayType): ArgumentEntity = when (type) { + EntityDisplayType.ENTITY -> ReflectionUtil.executePrivateMethod("a") + EntityDisplayType.ENTITIES -> ArgumentEntity.multipleEntities() + EntityDisplayType.PLAYER -> ArgumentEntity.c() + EntityDisplayType.PLAYERS -> ArgumentEntity.d() + } + + private fun getBukkitAxis(argument: EnumSet): EnumSet = + argument.mapTo(EnumSet.noneOf(Axis::class.java)) { + when (it) { + EnumDirection.EnumAxis.X -> Axis.X + EnumDirection.EnumAxis.Y -> Axis.Y + EnumDirection.EnumAxis.Z -> Axis.Z + null -> Axis.X + } + } + + private fun getBukkitDisplaySlot(slot: Int): DisplaySlot = when (slot) { + 0 -> DisplaySlot.PLAYER_LIST + 2 -> DisplaySlot.BELOW_NAME + else -> DisplaySlot.SIDEBAR + } + + private fun getParticleData( + particle: Particle, + particleOptions: ParticleParam + ): ParticleData<*> = when (particleOptions) { + is ParticleType -> ParticleData(particle, null) + is ParticleParamBlock -> ParticleData(particle, CraftBlockData.fromData(particleOptions.executePrivateMethod("c"))) + is ParticleParamRedstone -> { + val colors = particleOptions.a().split(" ") + val red = colors[1].toFloat() + val green = colors[2].toFloat() + val blue = colors[3].toFloat() + val scale = colors[4].toFloat() + ParticleData( + particle, + Particle.DustOptions( + Color.fromRGB( + (red * 255.0f).toInt(), + (green * 255.0f).toInt(), (blue * 255.0f).toInt() + ), scale + ) + ) + } + is ParticleParamItem -> ParticleData( + particle, + CraftItemStack.asBukkitCopy(particleOptions.executePrivateMethod("c")) + ) + else -> ParticleData(particle, null) + } + + private fun getLocation(context: CommandContext, command: LocationArgument): Location { + val world = context.source.world.world + return when (command.type) { + LocationType.LOCATION_3D -> toLocation(world, context.getArgument(command.name, IVectorPosition::class.java).c(context.source)) + LocationType.LOCATION_2D -> toLocation(world, ArgumentVec2I.a(context, command.name)) + LocationType.PRECISE_LOCATION_3D -> toLocation(world, ArgumentVec3.a(context, command.name)) + LocationType.PRECISE_LOCATION_2D -> toLocation(world, ArgumentVec2.a(context, command.name)) + } + } + + private fun toLocation(world: World, position: BlockPosition) = + Location(world, position.x.toDouble(), position.y.toDouble(), position.z.toDouble()) + private fun toLocation(world: World, position: BlockPosition2D) = + Location(world, position.a.toDouble(), 0.0, position.b.toDouble()) + private fun toLocation(world: World, vec: Vec3D) = + Location(world, vec.x, vec.y, vec.z) + private fun toLocation(world: World, vec: Vec2F) = + Location(world, vec.i.toDouble(), 0.0, vec.j.toDouble()) + + private fun throwArgumentVersionException(argument: AbstractStellarArgument<*>): Nothing = + throw ArgumentVersionMismatchException(argument, NMSVersion.version) + +} \ No newline at end of file diff --git a/v1_16_2/src/main/kotlin/com/undefined/stellar/v1_16_2/BrigadierCommandHelper.kt b/v1_16_2/src/main/kotlin/com/undefined/stellar/v1_16_2/BrigadierCommandHelper.kt new file mode 100644 index 0000000..a48b0c7 --- /dev/null +++ b/v1_16_2/src/main/kotlin/com/undefined/stellar/v1_16_2/BrigadierCommandHelper.kt @@ -0,0 +1,76 @@ +package com.undefined.stellar.v1_16_2 + +import com.mojang.brigadier.CommandDispatcher +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.tree.LiteralCommandNode +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.data.help.CustomCommandHelpTopic +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_16_R2.CommandListenerWrapper +import net.minecraft.server.v1_16_R2.MinecraftServer +import org.bukkit.Bukkit + +@Suppress("DEPRECATION") +object BrigadierCommandHelper { + + val COMMAND_SOURCE: CommandListenerWrapper by lazy { + MinecraftServer.getServer().serverCommandListener + } + val dispatcher: CommandDispatcher by lazy { + MinecraftServer.getServer().functionData.commandDispatcher + } + + fun register(command: LiteralArgumentBuilder): LiteralCommandNode? = + dispatcher.register(command) + + fun handleHelpTopic(command: AbstractStellarCommand<*>) { + Bukkit.getServer().helpMap.addTopic( + CustomCommandHelpTopic(command.name, command.description, command.helpTopic) { + val context = MinecraftServer.getServer().serverCommandListener + val requirements = command.requirements.all { it(this) } + val permissionRequirements = command.permissionRequirements.all { + if (it.permission.isEmpty()) context.hasPermission(it.level) + else context.hasPermission(it.level, it.permission) + } + requirements.and(permissionRequirements) + } + ) + } + + fun handleExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + val stellarContext = CommandContextAdapter.getStellarCommandContext(context) + + for (runnable in command.base.runnables) runnable(stellarContext) + val arguments = getArguments(command.base, context) + for (argument in arguments) for (runnable in argument.runnables) runnable(stellarContext) + for (execution in command.executions) execution(stellarContext) + } + + fun fulfillsRequirements(command: AbstractStellarCommand<*>, source: CommandListenerWrapper): Boolean { + val fulfillsExecutionRequirements = command.requirements.all { it(source.bukkitSender) } + val fulfillsPermissionRequirements = command.permissionRequirements.all { source.hasPermission(it.level, it.permission) } + return fulfillsExecutionRequirements.and(fulfillsPermissionRequirements) + } + + fun handleFailureMessageAndExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + for (execution in command.failureExecutions) execution(CommandContextAdapter.getStellarCommandContext(context)) + for (message in command.failureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + for (message in command.globalFailureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + } + + fun getArguments( + baseCommand: AbstractStellarCommand<*>, + context: CommandContext, + currentIndex: Int = 1, + listOfArguments: List> = emptyList() + ): List> { + if (listOfArguments.size == context.nodes.size - 1) return listOfArguments + for (argument in baseCommand.arguments) + if (argument.name == context.nodes[currentIndex].node.name) + return getArguments(argument, context, currentIndex + 1, listOfArguments + argument) + return emptyList() + } + +} \ No newline at end of file diff --git a/v1_16_2/src/main/kotlin/com/undefined/stellar/v1_16_2/CommandAdapter.kt b/v1_16_2/src/main/kotlin/com/undefined/stellar/v1_16_2/CommandAdapter.kt new file mode 100644 index 0000000..0c78fc1 --- /dev/null +++ b/v1_16_2/src/main/kotlin/com/undefined/stellar/v1_16_2/CommandAdapter.kt @@ -0,0 +1,96 @@ +package com.undefined.stellar.v1_16_2 + +import com.mojang.brigadier.Command +import com.mojang.brigadier.builder.ArgumentBuilder +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.primitive.PhraseArgument +import net.minecraft.server.v1_16_R2.CommandListenerWrapper + +object CommandAdapter { + + fun getBaseCommand(command: AbstractStellarCommand<*>, name: String = command.name): LiteralArgumentBuilder { + val brigadierCommand = LiteralArgumentBuilder.literal(name) + handleCommandFunctions(command, brigadierCommand) + handleArguments(command, brigadierCommand) + return brigadierCommand + } + + private fun handleCommandFunctions(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + if (command.executions.isNotEmpty() || command.executions.isNotEmpty()) + brigadierCommand.executes { context -> + BrigadierCommandHelper.handleExecutions(command, context) + 1 + } + brigadierCommand.requires { source -> + BrigadierCommandHelper.fulfillsRequirements(command, source) + } + } + + private fun handleArguments(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + for (argument in command.arguments) { + when (argument) { + is LiteralStellarArgument -> handleLiteralArgument(argument, brigadierCommand) + is PhraseArgument-> handlePhraseArgument(argument, brigadierCommand) + else -> handleRequiredArgument(argument, brigadierCommand) + } + } + } + + private fun handleLiteralArgument(argument: LiteralStellarArgument, brigadierCommand: ArgumentBuilder) { + for (argumentBuilder in ArgumentHelper.getLiteralArguments(argument)) { + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + } + + private fun handlePhraseArgument(argument: PhraseArgument, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleGreedyStringWordFunctions(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + + private fun handleGreedyStringWordFunctions(argument: PhraseArgument, argumentBuilder: RequiredArgumentBuilder) { + argumentBuilder.executes { context -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + + for (i in greedyContext.arguments.indices) { + val word = argument.words[i] ?: continue + for (runnable in word.runnables) runnable(greedyContext) + if (i == greedyContext.arguments.lastIndex) + for (execution in word.executions) execution(greedyContext) + } + Command.SINGLE_SUCCESS + } + + argumentBuilder.suggests { context, builder -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + var prevChar = ' ' + val input = ArgumentHelper.getArgumentInput(context, argument.name) ?: "" + val amountOfSpaces: Int = if (input.isEmpty()) 0 else input.count { + if (prevChar == ' ' && it == ' ') return@count false + prevChar = it + it == ' ' + } + val newBuilder = builder.createOffset(builder.input.lastIndexOf(' ') + 1) + val word = argument.words[amountOfSpaces] ?: return@suggests newBuilder.buildFuture() + for (stellarSuggestion in word.suggestions) + for (suggestion in stellarSuggestion.get(greedyContext)) + newBuilder.suggest(suggestion.text) { suggestion.tooltip } + newBuilder.buildFuture() + } + } + + private fun handleRequiredArgument(argument: AbstractStellarArgument<*>, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + +} diff --git a/v1_16_2/src/main/kotlin/com/undefined/stellar/v1_16_2/CommandContextAdapter.kt b/v1_16_2/src/main/kotlin/com/undefined/stellar/v1_16_2/CommandContextAdapter.kt new file mode 100644 index 0000000..354f78b --- /dev/null +++ b/v1_16_2/src/main/kotlin/com/undefined/stellar/v1_16_2/CommandContextAdapter.kt @@ -0,0 +1,84 @@ +package com.undefined.stellar.v1_16_2 + +import com.mojang.brigadier.context.CommandContext +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.data.argument.CommandNode +import com.undefined.stellar.data.argument.PhraseCommandContext +import com.undefined.stellar.exception.DuplicateArgumentNameException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_16_R2.* +import org.bukkit.command.CommandSender +import java.util.* + +object CommandContextAdapter { + + fun getStellarCommandContext(context: CommandContext): com.undefined.stellar.data.argument.CommandContext { + val input = context.input.removePrefix("/") + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val arguments = BrigadierCommandHelper.getArguments(baseCommand, context) + if (arguments.filter { it !is LiteralStellarArgument }.groupingBy { it.name }.eachCount().any { it.value > 1 }) throw DuplicateArgumentNameException() + val parsedArguments: CommandNode = + BrigadierCommandHelper.getArguments(baseCommand, context) + .associate, String, (com.undefined.stellar.data.argument.CommandContext) -> Any?> { argument -> + if (argument is CustomArgument) return@associate Pair(argument.name) { argument.parse(it) } + if (argument is LiteralStellarArgument) return@associate Pair(argument.name) { throw LiteralArgumentMismatchException() } + Pair(argument.name) { + ArgumentHelper.getParsedArgument(context, argument) + } + } as CommandNode + return com.undefined.stellar.data.argument.CommandContext( + parsedArguments, + context.source.bukkitSender, + input + ) + } + + fun getGreedyCommandContext(context: CommandContext): PhraseCommandContext { + val input = context.input.removePrefix("/") + val words = input.split(' ').toMutableList() + + val totalOtherArguments = context.nodes.size - 1 + for (i in (1..totalOtherArguments)) words.removeFirst() + return PhraseCommandContext( + words, + context.source.bukkitSender, + input + ) + } + + @Suppress("DEPRECATION") + fun getCommandListenerWrapper(sender: CommandSender): CommandListenerWrapper { + val overworld = MinecraftServer.getServer().E() + return CommandListenerWrapper( + Source(sender), + Vec3D.b(overworld.spawn), + Vec2F.a, + overworld, + 4, + sender.name, + ChatComponentText(sender.name), + MinecraftServer.getServer(), + null + ) + } + + private data class Source(val sender: CommandSender) : ICommandListener { + override fun sendMessage(message: IChatBaseComponent, sender: UUID) { + this.sender.sendMessage(LegacyComponentSerializer.legacySection().serialize(asAdventure(message))) + } + override fun shouldSendSuccess(): Boolean = true + override fun shouldSendFailure(): Boolean = true + override fun shouldBroadcastCommands(): Boolean = false + override fun getBukkitSender(stack: CommandListenerWrapper): CommandSender = this.sender + } + + fun asAdventure(component: IChatBaseComponent): net.kyori.adventure.text.Component = + GsonComponentSerializer.gson().deserializeFromTree(IChatBaseComponent.ChatSerializer.b(component)) + +} \ No newline at end of file diff --git a/v1_16_2/src/main/kotlin/com/undefined/stellar/v1_16_2/CommandRegistrar.kt b/v1_16_2/src/main/kotlin/com/undefined/stellar/v1_16_2/CommandRegistrar.kt new file mode 100644 index 0000000..cb1d40d --- /dev/null +++ b/v1_16_2/src/main/kotlin/com/undefined/stellar/v1_16_2/CommandRegistrar.kt @@ -0,0 +1,38 @@ +package com.undefined.stellar.v1_16_2 + +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.registrar.AbstractCommandRegistrar +import com.undefined.stellar.v1_16_2.BrigadierCommandHelper.dispatcher +import org.bukkit.command.CommandSender +import org.bukkit.plugin.java.JavaPlugin + +object CommandRegistrar : AbstractCommandRegistrar { + + override fun register(command: AbstractStellarCommand<*>, plugin: JavaPlugin) { + BrigadierCommandHelper.handleHelpTopic(command) + for (name in command.aliases + command.name) + BrigadierCommandHelper.register(CommandAdapter.getBaseCommand(command, name)) + } + + override fun handleCommandFailure(sender: CommandSender, input: String): Boolean { + val results = dispatcher.parse(input, BrigadierCommandHelper.COMMAND_SOURCE) + val context = results.context.withSource(CommandContextAdapter.getCommandListenerWrapper(sender)).build(input) + + if (results.reader.remainingLength == 0) return false + if (context.nodes.isEmpty()) return false + + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val argument = BrigadierCommandHelper.getArguments(baseCommand, context).lastOrNull() + argument?.let { + BrigadierCommandHelper.handleFailureMessageAndExecutions(argument, context) + if (argument.hideDefaultFailureMessages.hide) return true + } ?: run { + BrigadierCommandHelper.handleFailureMessageAndExecutions(baseCommand, context) + if (baseCommand.hideDefaultFailureMessages.hide) return true + } + + return baseCommand.hasGlobalHiddenDefaultFailureMessages() + } + +} \ No newline at end of file diff --git a/v1_16_3/build.gradle.kts b/v1_16_3/build.gradle.kts new file mode 100644 index 0000000..a95c372 --- /dev/null +++ b/v1_16_3/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + kotlin("jvm") version "1.9.22" +} + +repositories { + mavenLocal() +} + +dependencies { + compileOnly("org.spigotmc:spigot:1.16.3-R0.1-SNAPSHOT") + compileOnly(project(":common")) +} + +tasks { + compileKotlin { + kotlinOptions.jvmTarget = "1.8" + } + compileJava { + options.release.set(8) + } +} + +java { + disableAutoTargetJvm() +} + +kotlin { + jvmToolchain(21) +} \ No newline at end of file diff --git a/v1_16_3/src/main/kotlin/com/undefined/stellar/v1_16_3/ArgumentHelper.kt b/v1_16_3/src/main/kotlin/com/undefined/stellar/v1_16_3/ArgumentHelper.kt new file mode 100644 index 0000000..7113b60 --- /dev/null +++ b/v1_16_3/src/main/kotlin/com/undefined/stellar/v1_16_3/ArgumentHelper.kt @@ -0,0 +1,444 @@ +package com.undefined.stellar.v1_16_3 + +import com.mojang.brigadier.arguments.* +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 com.mojang.brigadier.context.ParsedArgument +import com.mojang.brigadier.context.StringRange +import com.mojang.brigadier.exceptions.CommandSyntaxException +import com.mojang.brigadier.suggestion.SuggestionProvider +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.block.BlockDataArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.argument.types.custom.ListArgument +import com.undefined.stellar.argument.types.entity.EntityDisplayType +import com.undefined.stellar.argument.types.item.ItemSlotArgument +import com.undefined.stellar.argument.types.item.ItemSlotsArgument +import com.undefined.stellar.argument.types.math.AxisArgument +import com.undefined.stellar.argument.types.misc.NamespacedKeyArgument +import com.undefined.stellar.argument.types.misc.UUIDArgument +import com.undefined.stellar.argument.types.player.GameModeArgument +import com.undefined.stellar.argument.types.primitive.* +import com.undefined.stellar.argument.types.registry.* +import com.undefined.stellar.argument.types.scoreboard.DisplaySlotArgument +import com.undefined.stellar.argument.types.scoreboard.ScoreHolderType +import com.undefined.stellar.argument.types.structure.LootTableArgument +import com.undefined.stellar.argument.types.structure.MirrorArgument +import com.undefined.stellar.argument.types.structure.StructureRotationArgument +import com.undefined.stellar.argument.types.world.HeightMapArgument +import com.undefined.stellar.argument.types.world.LocationArgument +import com.undefined.stellar.argument.types.world.LocationType +import com.undefined.stellar.data.argument.Anchor +import com.undefined.stellar.data.argument.Operation +import com.undefined.stellar.data.argument.ParticleData +import com.undefined.stellar.exception.ArgumentVersionMismatchException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import com.undefined.stellar.exception.UnsupportedArgumentException +import com.undefined.stellar.util.NMSVersion +import com.undefined.stellar.util.ReflectionUtil +import com.undefined.stellar.util.executePrivateMethod +import net.kyori.adventure.text.format.Style +import net.kyori.adventure.text.format.TextColor +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.minecraft.server.v1_16_R2.* +import org.bukkit.* +import org.bukkit.Particle +import org.bukkit.Registry +import org.bukkit.World +import org.bukkit.block.Block +import org.bukkit.block.data.BlockData +import org.bukkit.craftbukkit.v1_16_R2.block.data.CraftBlockData +import org.bukkit.craftbukkit.v1_16_R2.CraftParticle +import org.bukkit.craftbukkit.v1_16_R2.inventory.CraftItemStack +import org.bukkit.event.inventory.InventoryType +import org.bukkit.inventory.ItemStack +import org.bukkit.scoreboard.DisplaySlot +import java.time.Duration +import java.util.* +import java.util.function.Predicate + +@Suppress("UNCHECKED_CAST", "DEPRECATION") +object ArgumentHelper { + + fun getLiteralArguments(argument: AbstractStellarArgument<*>): List> { + val arguments: MutableList> = mutableListOf() + for (name in argument.aliases + argument.name) + arguments.add(LiteralArgumentBuilder.literal(name)) + return arguments + } + + fun getRequiredArgumentBuilder(argument: AbstractStellarArgument<*>): RequiredArgumentBuilder { + val argumentBuilder: RequiredArgumentBuilder = RequiredArgumentBuilder.argument(argument.name, getArgumentType(argument)) + getSuggestions(argument)?.let { argumentBuilder.suggests(it) } + return argumentBuilder + } + + private fun > getSuggestions(argument: T): SuggestionProvider? = + when (argument) { + is GameEventArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MOB_EFFECT.keySet(), builder) + } + is VillagerProfessionArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_PROFESSION.keySet(), builder) + } + is VillagerTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_TYPE.keySet(), builder) + } + is AttributeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.ATTRIBUTE.keySet(), builder) + } + is FluidArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.FLUID.keySet(), builder) + } + is SoundArgument -> SuggestionProvider { context, builder -> + CompletionProviders.c.getSuggestions(context, builder) + } + is BiomeArgument -> SuggestionProvider { context, builder -> + CompletionProviders.d.getSuggestions(context, builder) + } + is EntityTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.ENTITY_TYPE.keySet(), builder) + } + is MemoryKeyArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MEMORY_MODULE_TYPE.keySet(), builder) + } + else -> null + } + + private fun > getArgumentType(argument: T): ArgumentType<*> = + when (argument) { + is ListArgument<*> -> getArgumentType(argument.type) + is CustomArgument<*> -> getArgumentType(argument.type) + is StringArgument -> brigadier(argument.type) + is PhraseArgument -> brigadier(StringType.PHRASE) + is IntegerArgument -> IntegerArgumentType.integer(argument.min, argument.max) + is LongArgument -> LongArgumentType.longArg(argument.min, argument.max) + is FloatArgument -> FloatArgumentType.floatArg(argument.min, argument.max) + is DoubleArgument -> DoubleArgumentType.doubleArg(argument.min, argument.max) + is BooleanArgument -> BoolArgumentType.bool() + is com.undefined.stellar.argument.types.entity.EntityArgument -> brigadier(argument.type) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a() + is LocationArgument -> when (argument.type) { + LocationType.LOCATION_3D -> ArgumentPosition.a() + LocationType.LOCATION_2D -> ArgumentVec2I.a() + LocationType.PRECISE_LOCATION_2D -> ArgumentVec3.a() + LocationType.PRECISE_LOCATION_3D -> ArgumentVec2.a() + } + is BlockDataArgument -> ArgumentTile.a() + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> ArgumentBlockPredicate.a() + is com.undefined.stellar.argument.types.item.ItemArgument -> ArgumentItemStack.a() + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> ArgumentItemPredicate.a() + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a() + is com.undefined.stellar.argument.types.text.ComponentArgument -> ArgumentChatComponent.a() + is com.undefined.stellar.argument.types.text.StyleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.text.MessageArgument -> ArgumentChat.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> ArgumentScoreboardObjective.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a() + is com.undefined.stellar.argument.types.math.OperationArgument -> ArgumentMathOperation.a() + is com.undefined.stellar.argument.types.world.ParticleArgument -> ArgumentParticle.a() + is com.undefined.stellar.argument.types.math.AngleArgument -> ArgumentAngle.a() + is com.undefined.stellar.argument.types.math.RotationArgument -> ArgumentRotation.a() + is DisplaySlotArgument -> ArgumentScoreboardSlot.a() + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a() + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b() + } + is AxisArgument -> ArgumentRotationAxis.a() + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> ArgumentScoreboardTeam.a() + is ItemSlotArgument -> ArgumentInventorySlot.a() + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> ArgumentMinecraftKeyRegistered.a() + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> ArgumentAnchor.a() + is com.undefined.stellar.argument.types.math.RangeArgument -> ReflectionUtil.executePrivateMethod, ArgumentCriterionValue<*>>("a") + is com.undefined.stellar.argument.types.world.DimensionArgument -> ArgumentDimension.a() + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> ArgumentTime.a() + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> ArgumentUUID.a() + is GameEventArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> ArgumentMinecraftKeyRegistered.a() + is VillagerTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> throwArgumentVersionException(argument) + is AttributeArgument -> ArgumentMinecraftKeyRegistered.a() + is FluidArgument -> ArgumentMinecraftKeyRegistered.a() + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> ArgumentMinecraftKeyRegistered.a() + else -> throw UnsupportedArgumentException(argument) + } + + fun > getParsedArgument(context: CommandContext, argument: T): Any? { + return when (argument) { + is LiteralStellarArgument -> throw LiteralArgumentMismatchException() + is CustomArgument<*> -> argument.parse(CommandContextAdapter.getStellarCommandContext(context)) + is StringArgument -> StringArgumentType.getString(context, argument.name) + is IntegerArgument -> IntegerArgumentType.getInteger(context, argument.name) + is FloatArgument -> FloatArgumentType.getFloat(context, argument.name) + is DoubleArgument -> DoubleArgumentType.getDouble(context, argument.name) + is BooleanArgument -> BoolArgumentType.getBool(context, argument.name) + is ListArgument<*> -> argument.parse(getParsedArgument(context, argument)) + is com.undefined.stellar.argument.types.entity.EntityArgument -> ArgumentEntity.b(context, argument.name) + .map { it.bukkitEntity }.toMutableList() + .addAll(listOf(ArgumentEntity.a(context, argument.name).bukkitEntity)) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a(context, argument.name) + is LocationArgument -> getLocation(context, argument) + is BlockDataArgument -> CraftBlockData.fromData(ArgumentTile.a(context, argument.name).a()) + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> Predicate { block: Block -> + ArgumentBlockPredicate.a(context, argument.name).test(ShapeDetectorBlock( + context.source.world, + BlockPosition(block.x, block.y, block.z), true + )) + } + is com.undefined.stellar.argument.types.item.ItemArgument -> CraftItemStack.asBukkitCopy( + ArgumentItemStack.a(context, argument.name).a(1, false) + ) + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> Predicate { item: ItemStack -> + ArgumentItemPredicate.a(context, argument.name).test(CraftItemStack.asNMSCopy(item)) + } + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a( + context, + argument.name + ).e()?.let { Style.style(TextColor.color(it)) } ?: Style.empty() + is com.undefined.stellar.argument.types.text.ComponentArgument -> GsonComponentSerializer.gson() + .deserialize(IChatBaseComponent.ChatSerializer.a( + ArgumentChatComponent.a(context, argument.name) + )) + is com.undefined.stellar.argument.types.text.StyleArgument -> GsonComponentSerializer.gson().deserialize( + getArgumentInput(context, argument.name) ?: return null + ).style() + is com.undefined.stellar.argument.types.text.MessageArgument -> GsonComponentSerializer.gson().deserialize( + IChatBaseComponent.ChatSerializer.a(ArgumentChat.a(context, argument.name)) + ) + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getObjective( + ArgumentScoreboardObjective.a(context, argument.name).name + ) + + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a( + context, + argument.name + ).name + is com.undefined.stellar.argument.types.math.OperationArgument -> Operation.getOperation( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.world.ParticleArgument -> { + val particleOptions = ArgumentParticle.a(context, argument.name) + getParticleData(CraftParticle.toBukkit(particleOptions.particle), particleOptions) + } + is com.undefined.stellar.argument.types.math.AngleArgument -> ArgumentAngle.a(context, argument.name) + is com.undefined.stellar.argument.types.math.RotationArgument -> { + val rotation = ArgumentRotation.a(context, argument.name).a(context.source) + Location(context.source.world.world, rotation.x, rotation.y, rotation.z) + } + is DisplaySlotArgument -> getBukkitDisplaySlot(ArgumentScoreboardSlot.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a(context, argument.name) + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b(context, argument.name) + } + is AxisArgument -> getBukkitAxis(ArgumentRotationAxis.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getTeam( + ArgumentScoreboardTeam.a(context, argument.name).name + ) + is ItemSlotArgument -> ArgumentInventorySlot.a(context, argument.name) + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> NamespacedKey( + ArgumentMinecraftKeyRegistered.e(context, argument.name).namespace, + ArgumentMinecraftKeyRegistered.e(context, argument.name).key + ) + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> Anchor.getFromName( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.math.RangeArgument -> { + val range = ArgumentCriterionValue.b.a(context, argument.name) + IntRange(range.a() ?: 1, range.b() ?: 2) + } + is com.undefined.stellar.argument.types.world.DimensionArgument -> ArgumentDimension.a(context, argument.name).world.environment + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> Duration.ofSeconds(IntegerArgumentType.getInteger(context, argument.name).toLong() / 20) + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> ArgumentUUID.a(context, argument.name) + is GameEventArgument -> throwArgumentVersionException(argument) + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> Registry.VILLAGER_PROFESSION.get(getId(context, argument.name)) + is VillagerTypeArgument -> Registry.VILLAGER_TYPE.get(getId(context, argument.name)) + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> getInventoryType( + IRegistry.MENU.d(ResourceKey.a(IRegistry.v, ArgumentMinecraftKeyRegistered.e(context, argument.name))) + ) + is AttributeArgument -> Registry.ATTRIBUTE.get(getId(context, argument.name)) + is FluidArgument -> Registry.FLUID.get(getId(context, argument.name)) + is SoundArgument -> throwArgumentVersionException(argument) + is BiomeArgument -> Registry.BIOME.get(getId(context, argument.name)) + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> Registry.ENTITY_TYPE.get(getId(context, argument.name)) + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> Registry.MEMORY_MODULE_TYPE.get(getId(context, argument.name)) + else -> throw UnsupportedArgumentException(argument) + } + } + + fun getArgumentInput(context: CommandContext, name: String): String? { + val field = CommandContext::class.java.getDeclaredField("arguments") + field.isAccessible = true + val arguments: Map> = field.get(context) as Map> + val argument = arguments[name] ?: return null + val range = StringRange.between(argument.range.start, context.input.length) + return range.get(context.input) + } + + private fun getInventoryType(menu: Containers<*>): InventoryType = when (menu) { + Containers.GENERIC_9X1 -> InventoryType.CHEST + Containers.GENERIC_9X2 -> InventoryType.CHEST + Containers.GENERIC_9X3 -> InventoryType.CHEST + Containers.GENERIC_9X4 -> InventoryType.CHEST + Containers.GENERIC_9X5 -> InventoryType.CHEST + Containers.GENERIC_9X6 -> InventoryType.CHEST + Containers.GENERIC_3X3 -> InventoryType.WORKBENCH + Containers.ANVIL -> InventoryType.ANVIL + Containers.BEACON -> InventoryType.BEACON + Containers.BLAST_FURNACE -> InventoryType.BLAST_FURNACE + Containers.BREWING_STAND -> InventoryType.BREWING + Containers.CRAFTING -> InventoryType.CRAFTING + Containers.ENCHANTMENT -> InventoryType.ENCHANTING + Containers.FURNACE -> InventoryType.FURNACE + Containers.GRINDSTONE -> InventoryType.GRINDSTONE + Containers.HOPPER -> InventoryType.HOPPER + Containers.LECTERN -> InventoryType.LECTERN + Containers.LOOM -> InventoryType.LOOM + Containers.MERCHANT -> InventoryType.MERCHANT + Containers.SHULKER_BOX -> InventoryType.SHULKER_BOX + Containers.SMITHING -> InventoryType.SMITHING + Containers.SMOKER -> InventoryType.SMOKER + Containers.CARTOGRAPHY_TABLE -> InventoryType.CARTOGRAPHY + Containers.STONECUTTER -> InventoryType.STONECUTTER + else -> throw IllegalStateException("No inventory type found! This is not intentional behaviour, please contact the developers.") + } + + @Throws(CommandSyntaxException::class) + private fun getId( + context: CommandContext, + name: String + ): NamespacedKey { + val key = ArgumentMinecraftKeyRegistered.e(context, name) + return NamespacedKey(key.namespace, key.key) + } + + private fun brigadier(type: StringType): StringArgumentType = when (type) { + StringType.WORD -> StringArgumentType.word() + StringType.QUOTABLE_PHRASE -> StringArgumentType.string() + StringType.PHRASE -> StringArgumentType.greedyString() + } + + private fun brigadier(type: EntityDisplayType): ArgumentEntity = when (type) { + EntityDisplayType.ENTITY -> ReflectionUtil.executePrivateMethod("a") + EntityDisplayType.ENTITIES -> ArgumentEntity.multipleEntities() + EntityDisplayType.PLAYER -> ArgumentEntity.c() + EntityDisplayType.PLAYERS -> ArgumentEntity.d() + } + + private fun getBukkitAxis(argument: EnumSet): EnumSet = + argument.mapTo(EnumSet.noneOf(Axis::class.java)) { + when (it) { + EnumDirection.EnumAxis.X -> Axis.X + EnumDirection.EnumAxis.Y -> Axis.Y + EnumDirection.EnumAxis.Z -> Axis.Z + null -> Axis.X + } + } + + private fun getBukkitDisplaySlot(slot: Int): DisplaySlot = when (slot) { + 0 -> DisplaySlot.PLAYER_LIST + 2 -> DisplaySlot.BELOW_NAME + else -> DisplaySlot.SIDEBAR + } + + private fun getParticleData( + particle: Particle, + particleOptions: ParticleParam + ): ParticleData<*> = when (particleOptions) { + is ParticleType -> ParticleData(particle, null) + is ParticleParamBlock -> ParticleData(particle, CraftBlockData.fromData(particleOptions.executePrivateMethod("c"))) + is ParticleParamRedstone -> { + val colors = particleOptions.a().split(" ") + val red = colors[1].toFloat() + val green = colors[2].toFloat() + val blue = colors[3].toFloat() + val scale = colors[4].toFloat() + ParticleData( + particle, + Particle.DustOptions( + Color.fromRGB( + (red * 255.0f).toInt(), + (green * 255.0f).toInt(), (blue * 255.0f).toInt() + ), scale + ) + ) + } + is ParticleParamItem -> ParticleData( + particle, + CraftItemStack.asBukkitCopy(particleOptions.executePrivateMethod("c")) + ) + else -> ParticleData(particle, null) + } + + private fun getLocation(context: CommandContext, command: LocationArgument): Location { + val world = context.source.world.world + return when (command.type) { + LocationType.LOCATION_3D -> toLocation(world, context.getArgument(command.name, IVectorPosition::class.java).c(context.source)) + LocationType.LOCATION_2D -> toLocation(world, ArgumentVec2I.a(context, command.name)) + LocationType.PRECISE_LOCATION_3D -> toLocation(world, ArgumentVec3.a(context, command.name)) + LocationType.PRECISE_LOCATION_2D -> toLocation(world, ArgumentVec2.a(context, command.name)) + } + } + + private fun toLocation(world: World, position: BlockPosition) = + Location(world, position.x.toDouble(), position.y.toDouble(), position.z.toDouble()) + private fun toLocation(world: World, position: BlockPosition2D) = + Location(world, position.a.toDouble(), 0.0, position.b.toDouble()) + private fun toLocation(world: World, vec: Vec3D) = + Location(world, vec.x, vec.y, vec.z) + private fun toLocation(world: World, vec: Vec2F) = + Location(world, vec.i.toDouble(), 0.0, vec.j.toDouble()) + + private fun throwArgumentVersionException(argument: AbstractStellarArgument<*>): Nothing = + throw ArgumentVersionMismatchException(argument, NMSVersion.version) + +} \ No newline at end of file diff --git a/v1_16_3/src/main/kotlin/com/undefined/stellar/v1_16_3/BrigadierCommandHelper.kt b/v1_16_3/src/main/kotlin/com/undefined/stellar/v1_16_3/BrigadierCommandHelper.kt new file mode 100644 index 0000000..6205c25 --- /dev/null +++ b/v1_16_3/src/main/kotlin/com/undefined/stellar/v1_16_3/BrigadierCommandHelper.kt @@ -0,0 +1,76 @@ +package com.undefined.stellar.v1_16_3 + +import com.mojang.brigadier.CommandDispatcher +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.tree.LiteralCommandNode +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.data.help.CustomCommandHelpTopic +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_16_R2.CommandListenerWrapper +import net.minecraft.server.v1_16_R2.MinecraftServer +import org.bukkit.Bukkit + +@Suppress("DEPRECATION") +object BrigadierCommandHelper { + + val COMMAND_SOURCE: CommandListenerWrapper by lazy { + MinecraftServer.getServer().serverCommandListener + } + val dispatcher: CommandDispatcher by lazy { + MinecraftServer.getServer().functionData.commandDispatcher + } + + fun register(command: LiteralArgumentBuilder): LiteralCommandNode? = + dispatcher.register(command) + + fun handleHelpTopic(command: AbstractStellarCommand<*>) { + Bukkit.getServer().helpMap.addTopic( + CustomCommandHelpTopic(command.name, command.description, command.helpTopic) { + val context = MinecraftServer.getServer().serverCommandListener + val requirements = command.requirements.all { it(this) } + val permissionRequirements = command.permissionRequirements.all { + if (it.permission.isEmpty()) context.hasPermission(it.level) + else context.hasPermission(it.level, it.permission) + } + requirements.and(permissionRequirements) + } + ) + } + + fun handleExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + val stellarContext = CommandContextAdapter.getStellarCommandContext(context) + + for (runnable in command.base.runnables) runnable(stellarContext) + val arguments = getArguments(command.base, context) + for (argument in arguments) for (runnable in argument.runnables) runnable(stellarContext) + for (execution in command.executions) execution(stellarContext) + } + + fun fulfillsRequirements(command: AbstractStellarCommand<*>, source: CommandListenerWrapper): Boolean { + val fulfillsExecutionRequirements = command.requirements.all { it(source.bukkitSender) } + val fulfillsPermissionRequirements = command.permissionRequirements.all { source.hasPermission(it.level, it.permission) } + return fulfillsExecutionRequirements.and(fulfillsPermissionRequirements) + } + + fun handleFailureMessageAndExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + for (execution in command.failureExecutions) execution(CommandContextAdapter.getStellarCommandContext(context)) + for (message in command.failureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + for (message in command.globalFailureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + } + + fun getArguments( + baseCommand: AbstractStellarCommand<*>, + context: CommandContext, + currentIndex: Int = 1, + listOfArguments: List> = emptyList() + ): List> { + if (listOfArguments.size == context.nodes.size - 1) return listOfArguments + for (argument in baseCommand.arguments) + if (argument.name == context.nodes[currentIndex].node.name) + return getArguments(argument, context, currentIndex + 1, listOfArguments + argument) + return emptyList() + } + +} \ No newline at end of file diff --git a/v1_16_3/src/main/kotlin/com/undefined/stellar/v1_16_3/CommandAdapter.kt b/v1_16_3/src/main/kotlin/com/undefined/stellar/v1_16_3/CommandAdapter.kt new file mode 100644 index 0000000..9683b54 --- /dev/null +++ b/v1_16_3/src/main/kotlin/com/undefined/stellar/v1_16_3/CommandAdapter.kt @@ -0,0 +1,96 @@ +package com.undefined.stellar.v1_16_3 + +import com.mojang.brigadier.Command +import com.mojang.brigadier.builder.ArgumentBuilder +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.primitive.PhraseArgument +import net.minecraft.server.v1_16_R2.CommandListenerWrapper + +object CommandAdapter { + + fun getBaseCommand(command: AbstractStellarCommand<*>, name: String = command.name): LiteralArgumentBuilder { + val brigadierCommand = LiteralArgumentBuilder.literal(name) + handleCommandFunctions(command, brigadierCommand) + handleArguments(command, brigadierCommand) + return brigadierCommand + } + + private fun handleCommandFunctions(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + if (command.executions.isNotEmpty() || command.executions.isNotEmpty()) + brigadierCommand.executes { context -> + BrigadierCommandHelper.handleExecutions(command, context) + 1 + } + brigadierCommand.requires { source -> + BrigadierCommandHelper.fulfillsRequirements(command, source) + } + } + + private fun handleArguments(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + for (argument in command.arguments) { + when (argument) { + is LiteralStellarArgument -> handleLiteralArgument(argument, brigadierCommand) + is PhraseArgument-> handlePhraseArgument(argument, brigadierCommand) + else -> handleRequiredArgument(argument, brigadierCommand) + } + } + } + + private fun handleLiteralArgument(argument: LiteralStellarArgument, brigadierCommand: ArgumentBuilder) { + for (argumentBuilder in ArgumentHelper.getLiteralArguments(argument)) { + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + } + + private fun handlePhraseArgument(argument: PhraseArgument, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleGreedyStringWordFunctions(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + + private fun handleGreedyStringWordFunctions(argument: PhraseArgument, argumentBuilder: RequiredArgumentBuilder) { + argumentBuilder.executes { context -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + + for (i in greedyContext.arguments.indices) { + val word = argument.words[i] ?: continue + for (runnable in word.runnables) runnable(greedyContext) + if (i == greedyContext.arguments.lastIndex) + for (execution in word.executions) execution(greedyContext) + } + Command.SINGLE_SUCCESS + } + + argumentBuilder.suggests { context, builder -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + var prevChar = ' ' + val input = ArgumentHelper.getArgumentInput(context, argument.name) ?: "" + val amountOfSpaces: Int = if (input.isEmpty()) 0 else input.count { + if (prevChar == ' ' && it == ' ') return@count false + prevChar = it + it == ' ' + } + val newBuilder = builder.createOffset(builder.input.lastIndexOf(' ') + 1) + val word = argument.words[amountOfSpaces] ?: return@suggests newBuilder.buildFuture() + for (stellarSuggestion in word.suggestions) + for (suggestion in stellarSuggestion.get(greedyContext)) + newBuilder.suggest(suggestion.text) { suggestion.tooltip } + newBuilder.buildFuture() + } + } + + private fun handleRequiredArgument(argument: AbstractStellarArgument<*>, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + +} diff --git a/v1_16_3/src/main/kotlin/com/undefined/stellar/v1_16_3/CommandContextAdapter.kt b/v1_16_3/src/main/kotlin/com/undefined/stellar/v1_16_3/CommandContextAdapter.kt new file mode 100644 index 0000000..b6648d1 --- /dev/null +++ b/v1_16_3/src/main/kotlin/com/undefined/stellar/v1_16_3/CommandContextAdapter.kt @@ -0,0 +1,84 @@ +package com.undefined.stellar.v1_16_3 + +import com.mojang.brigadier.context.CommandContext +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.data.argument.CommandNode +import com.undefined.stellar.data.argument.PhraseCommandContext +import com.undefined.stellar.exception.DuplicateArgumentNameException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_16_R2.* +import org.bukkit.command.CommandSender +import java.util.* + +object CommandContextAdapter { + + fun getStellarCommandContext(context: CommandContext): com.undefined.stellar.data.argument.CommandContext { + val input = context.input.removePrefix("/") + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val arguments = BrigadierCommandHelper.getArguments(baseCommand, context) + if (arguments.filter { it !is LiteralStellarArgument }.groupingBy { it.name }.eachCount().any { it.value > 1 }) throw DuplicateArgumentNameException() + val parsedArguments: CommandNode = + BrigadierCommandHelper.getArguments(baseCommand, context) + .associate, String, (com.undefined.stellar.data.argument.CommandContext) -> Any?> { argument -> + if (argument is CustomArgument) return@associate Pair(argument.name) { argument.parse(it) } + if (argument is LiteralStellarArgument) return@associate Pair(argument.name) { throw LiteralArgumentMismatchException() } + Pair(argument.name) { + ArgumentHelper.getParsedArgument(context, argument) + } + } as CommandNode + return com.undefined.stellar.data.argument.CommandContext( + parsedArguments, + context.source.bukkitSender, + input + ) + } + + fun getGreedyCommandContext(context: CommandContext): PhraseCommandContext { + val input = context.input.removePrefix("/") + val words = input.split(' ').toMutableList() + + val totalOtherArguments = context.nodes.size - 1 + for (i in (1..totalOtherArguments)) words.removeFirst() + return PhraseCommandContext( + words, + context.source.bukkitSender, + input + ) + } + + @Suppress("DEPRECATION") + fun getCommandListenerWrapper(sender: CommandSender): CommandListenerWrapper { + val overworld = MinecraftServer.getServer().E() + return CommandListenerWrapper( + Source(sender), + Vec3D.b(overworld.spawn), + Vec2F.a, + overworld, + 4, + sender.name, + ChatComponentText(sender.name), + MinecraftServer.getServer(), + null + ) + } + + private data class Source(val sender: CommandSender) : ICommandListener { + override fun sendMessage(message: IChatBaseComponent, sender: UUID) { + this.sender.sendMessage(LegacyComponentSerializer.legacySection().serialize(asAdventure(message))) + } + override fun shouldSendSuccess(): Boolean = true + override fun shouldSendFailure(): Boolean = true + override fun shouldBroadcastCommands(): Boolean = false + override fun getBukkitSender(stack: CommandListenerWrapper): CommandSender = this.sender + } + + fun asAdventure(component: IChatBaseComponent): net.kyori.adventure.text.Component = + GsonComponentSerializer.gson().deserializeFromTree(IChatBaseComponent.ChatSerializer.b(component)) + +} \ No newline at end of file diff --git a/v1_16_3/src/main/kotlin/com/undefined/stellar/v1_16_3/CommandRegistrar.kt b/v1_16_3/src/main/kotlin/com/undefined/stellar/v1_16_3/CommandRegistrar.kt new file mode 100644 index 0000000..06dccdb --- /dev/null +++ b/v1_16_3/src/main/kotlin/com/undefined/stellar/v1_16_3/CommandRegistrar.kt @@ -0,0 +1,38 @@ +package com.undefined.stellar.v1_16_3 + +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.registrar.AbstractCommandRegistrar +import com.undefined.stellar.v1_16_3.BrigadierCommandHelper.dispatcher +import org.bukkit.command.CommandSender +import org.bukkit.plugin.java.JavaPlugin + +object CommandRegistrar : AbstractCommandRegistrar { + + override fun register(command: AbstractStellarCommand<*>, plugin: JavaPlugin) { + BrigadierCommandHelper.handleHelpTopic(command) + for (name in command.aliases + command.name) + BrigadierCommandHelper.register(CommandAdapter.getBaseCommand(command, name)) + } + + override fun handleCommandFailure(sender: CommandSender, input: String): Boolean { + val results = dispatcher.parse(input, BrigadierCommandHelper.COMMAND_SOURCE) + val context = results.context.withSource(CommandContextAdapter.getCommandListenerWrapper(sender)).build(input) + + if (results.reader.remainingLength == 0) return false + if (context.nodes.isEmpty()) return false + + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val argument = BrigadierCommandHelper.getArguments(baseCommand, context).lastOrNull() + argument?.let { + BrigadierCommandHelper.handleFailureMessageAndExecutions(argument, context) + if (argument.hideDefaultFailureMessages.hide) return true + } ?: run { + BrigadierCommandHelper.handleFailureMessageAndExecutions(baseCommand, context) + if (baseCommand.hideDefaultFailureMessages.hide) return true + } + + return baseCommand.hasGlobalHiddenDefaultFailureMessages() + } + +} \ No newline at end of file diff --git a/v1_16_4/build.gradle.kts b/v1_16_4/build.gradle.kts new file mode 100644 index 0000000..2297679 --- /dev/null +++ b/v1_16_4/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + kotlin("jvm") version "1.9.22" +} + +repositories { + mavenLocal() +} + +dependencies { + compileOnly("org.spigotmc:spigot:1.16.4-R0.1-SNAPSHOT") + compileOnly(project(":common")) +} + +tasks { + compileKotlin { + kotlinOptions.jvmTarget = "1.8" + } + compileJava { + options.release.set(8) + } +} + +java { + disableAutoTargetJvm() +} + +kotlin { + jvmToolchain(21) +} \ No newline at end of file diff --git a/v1_16_4/src/main/kotlin/com/undefined/stellar/v1_16_4/ArgumentHelper.kt b/v1_16_4/src/main/kotlin/com/undefined/stellar/v1_16_4/ArgumentHelper.kt new file mode 100644 index 0000000..366509d --- /dev/null +++ b/v1_16_4/src/main/kotlin/com/undefined/stellar/v1_16_4/ArgumentHelper.kt @@ -0,0 +1,444 @@ +package com.undefined.stellar.v1_16_4 + +import com.mojang.brigadier.arguments.* +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 com.mojang.brigadier.context.ParsedArgument +import com.mojang.brigadier.context.StringRange +import com.mojang.brigadier.exceptions.CommandSyntaxException +import com.mojang.brigadier.suggestion.SuggestionProvider +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.block.BlockDataArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.argument.types.custom.ListArgument +import com.undefined.stellar.argument.types.entity.EntityDisplayType +import com.undefined.stellar.argument.types.item.ItemSlotArgument +import com.undefined.stellar.argument.types.item.ItemSlotsArgument +import com.undefined.stellar.argument.types.math.AxisArgument +import com.undefined.stellar.argument.types.misc.NamespacedKeyArgument +import com.undefined.stellar.argument.types.misc.UUIDArgument +import com.undefined.stellar.argument.types.player.GameModeArgument +import com.undefined.stellar.argument.types.primitive.* +import com.undefined.stellar.argument.types.registry.* +import com.undefined.stellar.argument.types.scoreboard.DisplaySlotArgument +import com.undefined.stellar.argument.types.scoreboard.ScoreHolderType +import com.undefined.stellar.argument.types.structure.LootTableArgument +import com.undefined.stellar.argument.types.structure.MirrorArgument +import com.undefined.stellar.argument.types.structure.StructureRotationArgument +import com.undefined.stellar.argument.types.world.HeightMapArgument +import com.undefined.stellar.argument.types.world.LocationArgument +import com.undefined.stellar.argument.types.world.LocationType +import com.undefined.stellar.data.argument.Anchor +import com.undefined.stellar.data.argument.Operation +import com.undefined.stellar.data.argument.ParticleData +import com.undefined.stellar.exception.ArgumentVersionMismatchException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import com.undefined.stellar.exception.UnsupportedArgumentException +import com.undefined.stellar.util.NMSVersion +import com.undefined.stellar.util.ReflectionUtil +import com.undefined.stellar.util.executePrivateMethod +import net.kyori.adventure.text.format.Style +import net.kyori.adventure.text.format.TextColor +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.minecraft.server.v1_16_R3.* +import org.bukkit.* +import org.bukkit.Particle +import org.bukkit.Registry +import org.bukkit.World +import org.bukkit.block.Block +import org.bukkit.block.data.BlockData +import org.bukkit.craftbukkit.v1_16_R3.block.data.CraftBlockData +import org.bukkit.craftbukkit.v1_16_R3.CraftParticle +import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack +import org.bukkit.event.inventory.InventoryType +import org.bukkit.inventory.ItemStack +import org.bukkit.scoreboard.DisplaySlot +import java.time.Duration +import java.util.* +import java.util.function.Predicate + +@Suppress("UNCHECKED_CAST", "DEPRECATION") +object ArgumentHelper { + + fun getLiteralArguments(argument: AbstractStellarArgument<*>): List> { + val arguments: MutableList> = mutableListOf() + for (name in argument.aliases + argument.name) + arguments.add(LiteralArgumentBuilder.literal(name)) + return arguments + } + + fun getRequiredArgumentBuilder(argument: AbstractStellarArgument<*>): RequiredArgumentBuilder { + val argumentBuilder: RequiredArgumentBuilder = RequiredArgumentBuilder.argument(argument.name, getArgumentType(argument)) + getSuggestions(argument)?.let { argumentBuilder.suggests(it) } + return argumentBuilder + } + + private fun > getSuggestions(argument: T): SuggestionProvider? = + when (argument) { + is GameEventArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MOB_EFFECT.keySet(), builder) + } + is VillagerProfessionArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_PROFESSION.keySet(), builder) + } + is VillagerTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.VILLAGER_TYPE.keySet(), builder) + } + is AttributeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.ATTRIBUTE.keySet(), builder) + } + is FluidArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.FLUID.keySet(), builder) + } + is SoundArgument -> SuggestionProvider { context, builder -> + CompletionProviders.c.getSuggestions(context, builder) + } + is BiomeArgument -> SuggestionProvider { context, builder -> + CompletionProviders.d.getSuggestions(context, builder) + } + is EntityTypeArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.ENTITY_TYPE.keySet(), builder) + } + is MemoryKeyArgument -> SuggestionProvider { _, builder -> + ICompletionProvider.a(IRegistry.MEMORY_MODULE_TYPE.keySet(), builder) + } + else -> null + } + + private fun > getArgumentType(argument: T): ArgumentType<*> = + when (argument) { + is ListArgument<*> -> getArgumentType(argument.type) + is CustomArgument<*> -> getArgumentType(argument.type) + is StringArgument -> brigadier(argument.type) + is PhraseArgument -> brigadier(StringType.PHRASE) + is IntegerArgument -> IntegerArgumentType.integer(argument.min, argument.max) + is LongArgument -> LongArgumentType.longArg(argument.min, argument.max) + is FloatArgument -> FloatArgumentType.floatArg(argument.min, argument.max) + is DoubleArgument -> DoubleArgumentType.doubleArg(argument.min, argument.max) + is BooleanArgument -> BoolArgumentType.bool() + is com.undefined.stellar.argument.types.entity.EntityArgument -> brigadier(argument.type) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a() + is LocationArgument -> when (argument.type) { + LocationType.LOCATION_3D -> ArgumentPosition.a() + LocationType.LOCATION_2D -> ArgumentVec2I.a() + LocationType.PRECISE_LOCATION_2D -> ArgumentVec3.a() + LocationType.PRECISE_LOCATION_3D -> ArgumentVec2.a() + } + is BlockDataArgument -> ArgumentTile.a() + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> ArgumentBlockPredicate.a() + is com.undefined.stellar.argument.types.item.ItemArgument -> ArgumentItemStack.a() + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> ArgumentItemPredicate.a() + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a() + is com.undefined.stellar.argument.types.text.ComponentArgument -> ArgumentChatComponent.a() + is com.undefined.stellar.argument.types.text.StyleArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.text.MessageArgument -> ArgumentChat.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> ArgumentScoreboardObjective.a() + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a() + is com.undefined.stellar.argument.types.math.OperationArgument -> ArgumentMathOperation.a() + is com.undefined.stellar.argument.types.world.ParticleArgument -> ArgumentParticle.a() + is com.undefined.stellar.argument.types.math.AngleArgument -> ArgumentAngle.a() + is com.undefined.stellar.argument.types.math.RotationArgument -> ArgumentRotation.a() + is DisplaySlotArgument -> ArgumentScoreboardSlot.a() + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a() + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b() + } + is AxisArgument -> ArgumentRotationAxis.a() + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> ArgumentScoreboardTeam.a() + is ItemSlotArgument -> ArgumentInventorySlot.a() + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> ArgumentMinecraftKeyRegistered.a() + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> ArgumentAnchor.a() + is com.undefined.stellar.argument.types.math.RangeArgument -> ReflectionUtil.executePrivateMethod, ArgumentCriterionValue<*>>("a") + is com.undefined.stellar.argument.types.world.DimensionArgument -> ArgumentDimension.a() + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> ArgumentTime.a() + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> ArgumentUUID.a() + is GameEventArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> ArgumentMinecraftKeyRegistered.a() + is VillagerTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> throwArgumentVersionException(argument) + is AttributeArgument -> ArgumentMinecraftKeyRegistered.a() + is FluidArgument -> ArgumentMinecraftKeyRegistered.a() + is SoundArgument -> ArgumentMinecraftKeyRegistered.a() + is BiomeArgument -> ArgumentMinecraftKeyRegistered.a() + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> ArgumentMinecraftKeyRegistered.a() + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> ArgumentMinecraftKeyRegistered.a() + else -> throw UnsupportedArgumentException(argument) + } + + fun > getParsedArgument(context: CommandContext, argument: T): Any? { + return when (argument) { + is LiteralStellarArgument -> throw LiteralArgumentMismatchException() + is CustomArgument<*> -> argument.parse(CommandContextAdapter.getStellarCommandContext(context)) + is StringArgument -> StringArgumentType.getString(context, argument.name) + is IntegerArgument -> IntegerArgumentType.getInteger(context, argument.name) + is FloatArgument -> FloatArgumentType.getFloat(context, argument.name) + is DoubleArgument -> DoubleArgumentType.getDouble(context, argument.name) + is BooleanArgument -> BoolArgumentType.getBool(context, argument.name) + is ListArgument<*> -> argument.parse(getParsedArgument(context, argument)) + is com.undefined.stellar.argument.types.entity.EntityArgument -> ArgumentEntity.b(context, argument.name) + .map { it.bukkitEntity }.toMutableList() + .addAll(listOf(ArgumentEntity.a(context, argument.name).bukkitEntity)) + is com.undefined.stellar.argument.types.player.GameProfileArgument -> ArgumentProfile.a(context, argument.name) + is LocationArgument -> getLocation(context, argument) + is BlockDataArgument -> CraftBlockData.fromData(ArgumentTile.a(context, argument.name).a()) + is com.undefined.stellar.argument.types.block.BlockPredicateArgument -> Predicate { block: Block -> + ArgumentBlockPredicate.a(context, argument.name).test(ShapeDetectorBlock( + context.source.world, + BlockPosition(block.x, block.y, block.z), true + )) + } + is com.undefined.stellar.argument.types.item.ItemArgument -> CraftItemStack.asBukkitCopy( + ArgumentItemStack.a(context, argument.name).a(1, false) + ) + is com.undefined.stellar.argument.types.item.ItemPredicateArgument -> Predicate { item: ItemStack -> + ArgumentItemPredicate.a(context, argument.name).test(CraftItemStack.asNMSCopy(item)) + } + is com.undefined.stellar.argument.types.text.ColorArgument -> ArgumentChatFormat.a( + context, + argument.name + ).e()?.let { Style.style(TextColor.color(it)) } ?: Style.empty() + is com.undefined.stellar.argument.types.text.ComponentArgument -> GsonComponentSerializer.gson() + .deserialize(IChatBaseComponent.ChatSerializer.a( + ArgumentChatComponent.a(context, argument.name) + )) + is com.undefined.stellar.argument.types.text.StyleArgument -> GsonComponentSerializer.gson().deserialize( + getArgumentInput(context, argument.name) ?: return null + ).style() + is com.undefined.stellar.argument.types.text.MessageArgument -> GsonComponentSerializer.gson().deserialize( + IChatBaseComponent.ChatSerializer.a(ArgumentChat.a(context, argument.name)) + ) + is com.undefined.stellar.argument.types.scoreboard.ObjectiveArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getObjective( + ArgumentScoreboardObjective.a(context, argument.name).name + ) + + is com.undefined.stellar.argument.types.scoreboard.ObjectiveCriteriaArgument -> ArgumentScoreboardCriteria.a( + context, + argument.name + ).name + is com.undefined.stellar.argument.types.math.OperationArgument -> Operation.getOperation( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.world.ParticleArgument -> { + val particleOptions = ArgumentParticle.a(context, argument.name) + getParticleData(CraftParticle.toBukkit(particleOptions.particle), particleOptions) + } + is com.undefined.stellar.argument.types.math.AngleArgument -> ArgumentAngle.a(context, argument.name) + is com.undefined.stellar.argument.types.math.RotationArgument -> { + val rotation = ArgumentRotation.a(context, argument.name).a(context.source) + Location(context.source.world.world, rotation.x, rotation.y, rotation.z) + } + is DisplaySlotArgument -> getBukkitDisplaySlot(ArgumentScoreboardSlot.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.ScoreHolderArgument -> when (argument.type) { + ScoreHolderType.SINGLE -> ArgumentScoreholder.a(context, argument.name) + ScoreHolderType.MULTIPLE -> ArgumentScoreholder.b(context, argument.name) + } + is AxisArgument -> getBukkitAxis(ArgumentRotationAxis.a(context, argument.name)) + is com.undefined.stellar.argument.types.scoreboard.TeamArgument -> Bukkit.getScoreboardManager()!!.mainScoreboard.getTeam( + ArgumentScoreboardTeam.a(context, argument.name).name + ) + is ItemSlotArgument -> ArgumentInventorySlot.a(context, argument.name) + is ItemSlotsArgument -> throwArgumentVersionException(argument) + is NamespacedKeyArgument -> NamespacedKey( + ArgumentMinecraftKeyRegistered.e(context, argument.name).namespace, + ArgumentMinecraftKeyRegistered.e(context, argument.name).key + ) + is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> Anchor.getFromName( + getArgumentInput(context, argument.name) ?: return null + ) + is com.undefined.stellar.argument.types.math.RangeArgument -> { + val range = ArgumentCriterionValue.b.a(context, argument.name) + IntRange(range.a() ?: 1, range.b() ?: 2) + } + is com.undefined.stellar.argument.types.world.DimensionArgument -> ArgumentDimension.a(context, argument.name).world.environment + is GameModeArgument -> throwArgumentVersionException(argument) + is com.undefined.stellar.argument.types.math.TimeArgument -> Duration.ofSeconds(IntegerArgumentType.getInteger(context, argument.name).toLong() / 20) + is MirrorArgument -> throwArgumentVersionException(argument) + is StructureRotationArgument -> throwArgumentVersionException(argument) + is HeightMapArgument -> throwArgumentVersionException(argument) + is LootTableArgument -> throwArgumentVersionException(argument) + is UUIDArgument -> ArgumentUUID.a(context, argument.name) + is GameEventArgument -> throwArgumentVersionException(argument) + is StructureTypeArgument -> throwArgumentVersionException(argument) + is PotionEffectTypeArgument -> throwArgumentVersionException(argument) + is BlockTypeArgument -> throwArgumentVersionException(argument) + is ItemTypeArgument -> throwArgumentVersionException(argument) + is CatTypeArgument -> throwArgumentVersionException(argument) + is FrogVariantArgument -> throwArgumentVersionException(argument) + is VillagerProfessionArgument -> Registry.VILLAGER_PROFESSION.get(getId(context, argument.name)) + is VillagerTypeArgument -> Registry.VILLAGER_TYPE.get(getId(context, argument.name)) + is MapDecorationTypeArgument -> throwArgumentVersionException(argument) + is InventoryTypeArgument -> getInventoryType( + IRegistry.MENU.d(ResourceKey.a(IRegistry.v, ArgumentMinecraftKeyRegistered.e(context, argument.name))) + ) + is AttributeArgument -> Registry.ATTRIBUTE.get(getId(context, argument.name)) + is FluidArgument -> Registry.FLUID.get(getId(context, argument.name)) + is SoundArgument -> Registry.SOUNDS.get(getId(context, argument.name)) + is BiomeArgument -> Registry.BIOME.get(getId(context, argument.name)) + is StructureArgument -> throwArgumentVersionException(argument) + is TrimMaterialArgument -> throwArgumentVersionException(argument) + is TrimPatternArgument -> throwArgumentVersionException(argument) + is DamageTypeArgument -> throwArgumentVersionException(argument) + is WolfVariantArgument -> throwArgumentVersionException(argument) + is PatternTypeArgument -> throwArgumentVersionException(argument) + is ArtArgument -> throwArgumentVersionException(argument) + is InstrumentArgument -> throwArgumentVersionException(argument) + is EntityTypeArgument -> Registry.ENTITY_TYPE.get(getId(context, argument.name)) + is PotionArgument -> throwArgumentVersionException(argument) + is MemoryKeyArgument -> Registry.MEMORY_MODULE_TYPE.get(getId(context, argument.name)) + else -> throw UnsupportedArgumentException(argument) + } + } + + fun getArgumentInput(context: CommandContext, name: String): String? { + val field = CommandContext::class.java.getDeclaredField("arguments") + field.isAccessible = true + val arguments: Map> = field.get(context) as Map> + val argument = arguments[name] ?: return null + val range = StringRange.between(argument.range.start, context.input.length) + return range.get(context.input) + } + + private fun getInventoryType(menu: Containers<*>): InventoryType = when (menu) { + Containers.GENERIC_9X1 -> InventoryType.CHEST + Containers.GENERIC_9X2 -> InventoryType.CHEST + Containers.GENERIC_9X3 -> InventoryType.CHEST + Containers.GENERIC_9X4 -> InventoryType.CHEST + Containers.GENERIC_9X5 -> InventoryType.CHEST + Containers.GENERIC_9X6 -> InventoryType.CHEST + Containers.GENERIC_3X3 -> InventoryType.WORKBENCH + Containers.ANVIL -> InventoryType.ANVIL + Containers.BEACON -> InventoryType.BEACON + Containers.BLAST_FURNACE -> InventoryType.BLAST_FURNACE + Containers.BREWING_STAND -> InventoryType.BREWING + Containers.CRAFTING -> InventoryType.CRAFTING + Containers.ENCHANTMENT -> InventoryType.ENCHANTING + Containers.FURNACE -> InventoryType.FURNACE + Containers.GRINDSTONE -> InventoryType.GRINDSTONE + Containers.HOPPER -> InventoryType.HOPPER + Containers.LECTERN -> InventoryType.LECTERN + Containers.LOOM -> InventoryType.LOOM + Containers.MERCHANT -> InventoryType.MERCHANT + Containers.SHULKER_BOX -> InventoryType.SHULKER_BOX + Containers.SMITHING -> InventoryType.SMITHING + Containers.SMOKER -> InventoryType.SMOKER + Containers.CARTOGRAPHY_TABLE -> InventoryType.CARTOGRAPHY + Containers.STONECUTTER -> InventoryType.STONECUTTER + else -> throw IllegalStateException("No inventory type found! This is not intentional behaviour, please contact the developers.") + } + + @Throws(CommandSyntaxException::class) + private fun getId( + context: CommandContext, + name: String + ): NamespacedKey { + val key = ArgumentMinecraftKeyRegistered.e(context, name) + return NamespacedKey(key.namespace, key.key) + } + + private fun brigadier(type: StringType): StringArgumentType = when (type) { + StringType.WORD -> StringArgumentType.word() + StringType.QUOTABLE_PHRASE -> StringArgumentType.string() + StringType.PHRASE -> StringArgumentType.greedyString() + } + + private fun brigadier(type: EntityDisplayType): ArgumentEntity = when (type) { + EntityDisplayType.ENTITY -> ReflectionUtil.executePrivateMethod("a") + EntityDisplayType.ENTITIES -> ArgumentEntity.multipleEntities() + EntityDisplayType.PLAYER -> ArgumentEntity.c() + EntityDisplayType.PLAYERS -> ArgumentEntity.d() + } + + private fun getBukkitAxis(argument: EnumSet): EnumSet = + argument.mapTo(EnumSet.noneOf(Axis::class.java)) { + when (it) { + EnumDirection.EnumAxis.X -> Axis.X + EnumDirection.EnumAxis.Y -> Axis.Y + EnumDirection.EnumAxis.Z -> Axis.Z + null -> Axis.X + } + } + + private fun getBukkitDisplaySlot(slot: Int): DisplaySlot = when (slot) { + 0 -> DisplaySlot.PLAYER_LIST + 2 -> DisplaySlot.BELOW_NAME + else -> DisplaySlot.SIDEBAR + } + + private fun getParticleData( + particle: Particle, + particleOptions: ParticleParam + ): ParticleData<*> = when (particleOptions) { + is ParticleType -> ParticleData(particle, null) + is ParticleParamBlock -> ParticleData(particle, CraftBlockData.fromData(particleOptions.executePrivateMethod("c"))) + is ParticleParamRedstone -> { + val colors = particleOptions.a().split(" ") + val red = colors[1].toFloat() + val green = colors[2].toFloat() + val blue = colors[3].toFloat() + val scale = colors[4].toFloat() + ParticleData( + particle, + Particle.DustOptions( + Color.fromRGB( + (red * 255.0f).toInt(), + (green * 255.0f).toInt(), (blue * 255.0f).toInt() + ), scale + ) + ) + } + is ParticleParamItem -> ParticleData( + particle, + CraftItemStack.asBukkitCopy(particleOptions.executePrivateMethod("c")) + ) + else -> ParticleData(particle, null) + } + + private fun getLocation(context: CommandContext, command: LocationArgument): Location { + val world = context.source.world.world + return when (command.type) { + LocationType.LOCATION_3D -> toLocation(world, context.getArgument(command.name, IVectorPosition::class.java).c(context.source)) + LocationType.LOCATION_2D -> toLocation(world, ArgumentVec2I.a(context, command.name)) + LocationType.PRECISE_LOCATION_3D -> toLocation(world, ArgumentVec3.a(context, command.name)) + LocationType.PRECISE_LOCATION_2D -> toLocation(world, ArgumentVec2.a(context, command.name)) + } + } + + private fun toLocation(world: World, position: BlockPosition) = + Location(world, position.x.toDouble(), position.y.toDouble(), position.z.toDouble()) + private fun toLocation(world: World, position: BlockPosition2D) = + Location(world, position.a.toDouble(), 0.0, position.b.toDouble()) + private fun toLocation(world: World, vec: Vec3D) = + Location(world, vec.x, vec.y, vec.z) + private fun toLocation(world: World, vec: Vec2F) = + Location(world, vec.i.toDouble(), 0.0, vec.j.toDouble()) + + private fun throwArgumentVersionException(argument: AbstractStellarArgument<*>): Nothing = + throw ArgumentVersionMismatchException(argument, NMSVersion.version) + +} \ No newline at end of file diff --git a/v1_16_4/src/main/kotlin/com/undefined/stellar/v1_16_4/BrigadierCommandHelper.kt b/v1_16_4/src/main/kotlin/com/undefined/stellar/v1_16_4/BrigadierCommandHelper.kt new file mode 100644 index 0000000..fd4dd5e --- /dev/null +++ b/v1_16_4/src/main/kotlin/com/undefined/stellar/v1_16_4/BrigadierCommandHelper.kt @@ -0,0 +1,76 @@ +package com.undefined.stellar.v1_16_4 + +import com.mojang.brigadier.CommandDispatcher +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.tree.LiteralCommandNode +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.data.help.CustomCommandHelpTopic +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_16_R3.CommandListenerWrapper +import net.minecraft.server.v1_16_R3.MinecraftServer +import org.bukkit.Bukkit + +@Suppress("DEPRECATION") +object BrigadierCommandHelper { + + val COMMAND_SOURCE: CommandListenerWrapper by lazy { + MinecraftServer.getServer().serverCommandListener + } + val dispatcher: CommandDispatcher by lazy { + MinecraftServer.getServer().functionData.commandDispatcher + } + + fun register(command: LiteralArgumentBuilder): LiteralCommandNode? = + dispatcher.register(command) + + fun handleHelpTopic(command: AbstractStellarCommand<*>) { + Bukkit.getServer().helpMap.addTopic( + CustomCommandHelpTopic(command.name, command.description, command.helpTopic) { + val context = MinecraftServer.getServer().serverCommandListener + val requirements = command.requirements.all { it(this) } + val permissionRequirements = command.permissionRequirements.all { + if (it.permission.isEmpty()) context.hasPermission(it.level) + else context.hasPermission(it.level, it.permission) + } + requirements.and(permissionRequirements) + } + ) + } + + fun handleExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + val stellarContext = CommandContextAdapter.getStellarCommandContext(context) + + for (runnable in command.base.runnables) runnable(stellarContext) + val arguments = getArguments(command.base, context) + for (argument in arguments) for (runnable in argument.runnables) runnable(stellarContext) + for (execution in command.executions) execution(stellarContext) + } + + fun fulfillsRequirements(command: AbstractStellarCommand<*>, source: CommandListenerWrapper): Boolean { + val fulfillsExecutionRequirements = command.requirements.all { it(source.bukkitSender) } + val fulfillsPermissionRequirements = command.permissionRequirements.all { source.hasPermission(it.level, it.permission) } + return fulfillsExecutionRequirements.and(fulfillsPermissionRequirements) + } + + fun handleFailureMessageAndExecutions(command: AbstractStellarCommand<*>, context: CommandContext) { + for (execution in command.failureExecutions) execution(CommandContextAdapter.getStellarCommandContext(context)) + for (message in command.failureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + for (message in command.globalFailureMessages) context.source.bukkitSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message)) + } + + fun getArguments( + baseCommand: AbstractStellarCommand<*>, + context: CommandContext, + currentIndex: Int = 1, + listOfArguments: List> = emptyList() + ): List> { + if (listOfArguments.size == context.nodes.size - 1) return listOfArguments + for (argument in baseCommand.arguments) + if (argument.name == context.nodes[currentIndex].node.name) + return getArguments(argument, context, currentIndex + 1, listOfArguments + argument) + return emptyList() + } + +} \ No newline at end of file diff --git a/v1_16_4/src/main/kotlin/com/undefined/stellar/v1_16_4/CommandAdapter.kt b/v1_16_4/src/main/kotlin/com/undefined/stellar/v1_16_4/CommandAdapter.kt new file mode 100644 index 0000000..4f654a7 --- /dev/null +++ b/v1_16_4/src/main/kotlin/com/undefined/stellar/v1_16_4/CommandAdapter.kt @@ -0,0 +1,96 @@ +package com.undefined.stellar.v1_16_4 + +import com.mojang.brigadier.Command +import com.mojang.brigadier.builder.ArgumentBuilder +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.primitive.PhraseArgument +import net.minecraft.server.v1_16_R3.CommandListenerWrapper + +object CommandAdapter { + + fun getBaseCommand(command: AbstractStellarCommand<*>, name: String = command.name): LiteralArgumentBuilder { + val brigadierCommand = LiteralArgumentBuilder.literal(name) + handleCommandFunctions(command, brigadierCommand) + handleArguments(command, brigadierCommand) + return brigadierCommand + } + + private fun handleCommandFunctions(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + if (command.executions.isNotEmpty() || command.executions.isNotEmpty()) + brigadierCommand.executes { context -> + BrigadierCommandHelper.handleExecutions(command, context) + 1 + } + brigadierCommand.requires { source -> + BrigadierCommandHelper.fulfillsRequirements(command, source) + } + } + + private fun handleArguments(command: AbstractStellarCommand<*>, brigadierCommand: ArgumentBuilder) { + for (argument in command.arguments) { + when (argument) { + is LiteralStellarArgument -> handleLiteralArgument(argument, brigadierCommand) + is PhraseArgument-> handlePhraseArgument(argument, brigadierCommand) + else -> handleRequiredArgument(argument, brigadierCommand) + } + } + } + + private fun handleLiteralArgument(argument: LiteralStellarArgument, brigadierCommand: ArgumentBuilder) { + for (argumentBuilder in ArgumentHelper.getLiteralArguments(argument)) { + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + } + + private fun handlePhraseArgument(argument: PhraseArgument, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleGreedyStringWordFunctions(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + + private fun handleGreedyStringWordFunctions(argument: PhraseArgument, argumentBuilder: RequiredArgumentBuilder) { + argumentBuilder.executes { context -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + + for (i in greedyContext.arguments.indices) { + val word = argument.words[i] ?: continue + for (runnable in word.runnables) runnable(greedyContext) + if (i == greedyContext.arguments.lastIndex) + for (execution in word.executions) execution(greedyContext) + } + Command.SINGLE_SUCCESS + } + + argumentBuilder.suggests { context, builder -> + val greedyContext = CommandContextAdapter.getGreedyCommandContext(context) + var prevChar = ' ' + val input = ArgumentHelper.getArgumentInput(context, argument.name) ?: "" + val amountOfSpaces: Int = if (input.isEmpty()) 0 else input.count { + if (prevChar == ' ' && it == ' ') return@count false + prevChar = it + it == ' ' + } + val newBuilder = builder.createOffset(builder.input.lastIndexOf(' ') + 1) + val word = argument.words[amountOfSpaces] ?: return@suggests newBuilder.buildFuture() + for (stellarSuggestion in word.suggestions) + for (suggestion in stellarSuggestion.get(greedyContext)) + newBuilder.suggest(suggestion.text) { suggestion.tooltip } + newBuilder.buildFuture() + } + } + + private fun handleRequiredArgument(argument: AbstractStellarArgument<*>, brigadierCommand: ArgumentBuilder) { + val argumentBuilder = ArgumentHelper.getRequiredArgumentBuilder(argument) + handleCommandFunctions(argument, argumentBuilder) + handleArguments(argument, argumentBuilder) + brigadierCommand.then(argumentBuilder) + } + +} diff --git a/v1_16_4/src/main/kotlin/com/undefined/stellar/v1_16_4/CommandContextAdapter.kt b/v1_16_4/src/main/kotlin/com/undefined/stellar/v1_16_4/CommandContextAdapter.kt new file mode 100644 index 0000000..649ae35 --- /dev/null +++ b/v1_16_4/src/main/kotlin/com/undefined/stellar/v1_16_4/CommandContextAdapter.kt @@ -0,0 +1,84 @@ +package com.undefined.stellar.v1_16_4 + +import com.mojang.brigadier.context.CommandContext +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.argument.AbstractStellarArgument +import com.undefined.stellar.argument.LiteralStellarArgument +import com.undefined.stellar.argument.types.custom.CustomArgument +import com.undefined.stellar.data.argument.CommandNode +import com.undefined.stellar.data.argument.PhraseCommandContext +import com.undefined.stellar.exception.DuplicateArgumentNameException +import com.undefined.stellar.exception.LiteralArgumentMismatchException +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.minecraft.server.v1_16_R3.* +import org.bukkit.command.CommandSender +import java.util.* + +object CommandContextAdapter { + + fun getStellarCommandContext(context: CommandContext): com.undefined.stellar.data.argument.CommandContext { + val input = context.input.removePrefix("/") + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val arguments = BrigadierCommandHelper.getArguments(baseCommand, context) + if (arguments.filter { it !is LiteralStellarArgument }.groupingBy { it.name }.eachCount().any { it.value > 1 }) throw DuplicateArgumentNameException() + val parsedArguments: CommandNode = + BrigadierCommandHelper.getArguments(baseCommand, context) + .associate, String, (com.undefined.stellar.data.argument.CommandContext) -> Any?> { argument -> + if (argument is CustomArgument) return@associate Pair(argument.name) { argument.parse(it) } + if (argument is LiteralStellarArgument) return@associate Pair(argument.name) { throw LiteralArgumentMismatchException() } + Pair(argument.name) { + ArgumentHelper.getParsedArgument(context, argument) + } + } as CommandNode + return com.undefined.stellar.data.argument.CommandContext( + parsedArguments, + context.source.bukkitSender, + input + ) + } + + fun getGreedyCommandContext(context: CommandContext): PhraseCommandContext { + val input = context.input.removePrefix("/") + val words = input.split(' ').toMutableList() + + val totalOtherArguments = context.nodes.size - 1 + for (i in (1..totalOtherArguments)) words.removeFirst() + return PhraseCommandContext( + words, + context.source.bukkitSender, + input + ) + } + + @Suppress("DEPRECATION") + fun getCommandListenerWrapper(sender: CommandSender): CommandListenerWrapper { + val overworld = MinecraftServer.getServer().E() + return CommandListenerWrapper( + Source(sender), + Vec3D.b(overworld.spawn), + Vec2F.a, + overworld, + 4, + sender.name, + ChatComponentText(sender.name), + MinecraftServer.getServer(), + null + ) + } + + private data class Source(val sender: CommandSender) : ICommandListener { + override fun sendMessage(message: IChatBaseComponent, sender: UUID) { + this.sender.sendMessage(LegacyComponentSerializer.legacySection().serialize(asAdventure(message))) + } + override fun shouldSendSuccess(): Boolean = true + override fun shouldSendFailure(): Boolean = true + override fun shouldBroadcastCommands(): Boolean = false + override fun getBukkitSender(stack: CommandListenerWrapper): CommandSender = this.sender + } + + fun asAdventure(component: IChatBaseComponent): net.kyori.adventure.text.Component = + GsonComponentSerializer.gson().deserializeFromTree(IChatBaseComponent.ChatSerializer.b(component)) + +} \ No newline at end of file diff --git a/v1_16_4/src/main/kotlin/com/undefined/stellar/v1_16_4/CommandRegistrar.kt b/v1_16_4/src/main/kotlin/com/undefined/stellar/v1_16_4/CommandRegistrar.kt new file mode 100644 index 0000000..cddd998 --- /dev/null +++ b/v1_16_4/src/main/kotlin/com/undefined/stellar/v1_16_4/CommandRegistrar.kt @@ -0,0 +1,38 @@ +package com.undefined.stellar.v1_16_4 + +import com.undefined.stellar.AbstractStellarCommand +import com.undefined.stellar.StellarCommands +import com.undefined.stellar.registrar.AbstractCommandRegistrar +import com.undefined.stellar.v1_16_4.BrigadierCommandHelper.dispatcher +import org.bukkit.command.CommandSender +import org.bukkit.plugin.java.JavaPlugin + +object CommandRegistrar : AbstractCommandRegistrar { + + override fun register(command: AbstractStellarCommand<*>, plugin: JavaPlugin) { + BrigadierCommandHelper.handleHelpTopic(command) + for (name in command.aliases + command.name) + BrigadierCommandHelper.register(CommandAdapter.getBaseCommand(command, name)) + } + + override fun handleCommandFailure(sender: CommandSender, input: String): Boolean { + val results = dispatcher.parse(input, BrigadierCommandHelper.COMMAND_SOURCE) + val context = results.context.withSource(CommandContextAdapter.getCommandListenerWrapper(sender)).build(input) + + if (results.reader.remainingLength == 0) return false + if (context.nodes.isEmpty()) return false + + val baseCommand: AbstractStellarCommand<*> = StellarCommands.getStellarCommand(context.nodes[0].node.name)!! + val argument = BrigadierCommandHelper.getArguments(baseCommand, context).lastOrNull() + argument?.let { + BrigadierCommandHelper.handleFailureMessageAndExecutions(argument, context) + if (argument.hideDefaultFailureMessages.hide) return true + } ?: run { + BrigadierCommandHelper.handleFailureMessageAndExecutions(baseCommand, context) + if (baseCommand.hideDefaultFailureMessages.hide) return true + } + + return baseCommand.hasGlobalHiddenDefaultFailureMessages() + } + +} \ No newline at end of file diff --git a/v1_16_5/src/main/kotlin/com/undefined/stellar/v1_16_5/ArgumentHelper.kt b/v1_16_5/src/main/kotlin/com/undefined/stellar/v1_16_5/ArgumentHelper.kt index cc51c47..f804889 100644 --- a/v1_16_5/src/main/kotlin/com/undefined/stellar/v1_16_5/ArgumentHelper.kt +++ b/v1_16_5/src/main/kotlin/com/undefined/stellar/v1_16_5/ArgumentHelper.kt @@ -155,7 +155,7 @@ object ArgumentHelper { is ItemSlotsArgument -> throwArgumentVersionException(argument) is NamespacedKeyArgument -> ArgumentMinecraftKeyRegistered.a() is com.undefined.stellar.argument.types.entity.EntityAnchorArgument -> ArgumentAnchor.a() - is com.undefined.stellar.argument.types.math.RangeArgument -> ReflectionUtil.getPrivateMethod, ArgumentCriterionValue<*>>("a") + is com.undefined.stellar.argument.types.math.RangeArgument -> ReflectionUtil.executePrivateMethod, ArgumentCriterionValue<*>>("a") is com.undefined.stellar.argument.types.world.DimensionArgument -> ArgumentDimension.a() is GameModeArgument -> throwArgumentVersionException(argument) is com.undefined.stellar.argument.types.math.TimeArgument -> ArgumentTime.a() @@ -370,7 +370,7 @@ object ArgumentHelper { } private fun brigadier(type: EntityDisplayType): ArgumentEntity = when (type) { - EntityDisplayType.ENTITY -> ReflectionUtil.getPrivateMethod("a") + EntityDisplayType.ENTITY -> ReflectionUtil.executePrivateMethod("a") EntityDisplayType.ENTITIES -> ArgumentEntity.multipleEntities() EntityDisplayType.PLAYER -> ArgumentEntity.c() EntityDisplayType.PLAYERS -> ArgumentEntity.d() diff --git a/v1_17_1/build.gradle.kts b/v1_17_1/build.gradle.kts index 6a0c7ac..accf8d7 100644 --- a/v1_17_1/build.gradle.kts +++ b/v1_17_1/build.gradle.kts @@ -12,10 +12,10 @@ dependencies { tasks { compileKotlin { - kotlinOptions.jvmTarget = "16" + kotlinOptions.jvmTarget = "1.8" } compileJava { - options.release.set(16) + options.release.set(8) } paperweight { javaLauncher.set(