Desenho feito por đHirođŠ#3360
Apenas mais outra framework bacana e incrĂvel para facilitar a criação e despacho de comandos! Genericamente utilizĂĄvel em mĂșltiplas plataformas diferentes, mas ao mesmo tempo incrivelmente customizĂĄvel para implementar funcionalidades especĂficas para cada plataforma.
Ela foi criada para a Loritta e para o SparklyPower, e foi planejada com as seguintes ideias:
- Comandos devem ser criados de uma forma simples e intuitiva.
- Mesmo sendo simples, precisa permitir customizar como os comandos para implementar funcionalidades especĂficas para cada plataforma.
- Precisa suportar as funcionalidades que o Kotlin oferece. (Não precisar ficar colocando @Optionalem parùmetros, suportar argumentos padrÔes, suportar criação de comandos usando DSL, etc)
- Precisa ser genĂ©rica, para que seja possĂvel implementar a framework em plataformas diversas para ter um Ășnico sistema unificado para comandos.
- Precisa suportar sub sub sub ... argumentos.
- Suportar contextos personalizados para comandos, como, por exemplo, retornar a instĂąncia de um Playerao digitarLoritta!
- Suportar Kotlin Coroutines.
- NĂŁo ser "mĂĄgico", como registrar comandos magicamente ao declarar eles.
Ela foi inspirada em vĂĄrias frameworks diferentes: Annotation Command Framework, Plugin Annotations e KotlinBukkitAPI, essas frameworks sĂŁo excelentes, mas cada uma tem algum problema diferente que nĂŁo se "encaixa" no que a gente precisa, por exemplo:
- NĂŁo sĂŁo feitas em Kotlin, ou seja, existem coisas redudantes que nĂŁo seriam necessĂĄrias (como @Optional) (Annotation Command Framework, Plugin Annotations)
- Dependem de plataformas para funcionar, em vez de serem "genéricas" para usar em qualquer tipo de sistema (Plugin Annotations, KotlinBukkitAPI)
- Apenas suporta DSL (KotlinBukkitAPI)
        <repository>
            <id>perfectdreams-repo</id>
            <url>https://repo.perfectdreams.net/</url>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>always</updatePolicy>
            </snapshots>
        </repository>
... coisas coisas coisas ...
        <dependency>
            <groupId>net.perfectdreams.commands</groupId>
            <artifactId>command-framework-core</artifactId>
            <version>0.0.2-SNAPSHOT</version> <!-- Veja a Ășltima versĂŁo no pom.xml! -->
        </dependency>Nestes exemplos, estamos usando a nossa implementação que fizemos para unit tests, como vocĂȘ terĂĄ que implementar algumas coisas vocĂȘ mesmo, talvez existam algumas diferenças. (Mas nada tĂŁĂŁĂŁĂŁĂŁo diferente, nĂŁo se preocupe!)
class HelloWorldCommand : DreamCommand("hello", "olĂĄ") {
	@Subcommand
	fun helloWorld(sender: Sender) {
		// Isto serĂĄ executado se o usuĂĄrio escrever
		// "hello"
		// "olĂĄ"
		// "hello algo_aqui_blah"
		// "olĂĄ qdhd qdqgdyqwd dhqudquhd"
		sender.sendMessage("OlĂĄ, mundo!")
	}
}fun main() {
	val commandManager = ConsoleCommandManager() // Criar o nosso CommandManager
	commandManager.registerCommand(HelloWorldCommand()) // Registrar o nosso lindo comando
	while (true) {
		val line = readLine()!!
		commandManager.dispatchBlocking( // Caso vocĂȘ esteja usando coroutines, use apenas "dispatch"
			ConsoleSender(),
			line
		)
	}
}E Ă© isto!
"Que nada, cadĂȘ as implementaçÔes que vocĂȘ falou??"
Verdade, elas estĂŁo aqui:
ImplementaçÔes Marotas
NĂŁo se preocupe, tem coisas aqui que vocĂȘ nĂŁo precisarĂĄ implementar (como o Sender), ele sĂł estĂĄ aqui para demonstrar o exemplo acima!
Senders:
interface Sender {    
   fun sendMessage(message: String)  
}class ConsoleSender(val senderName: String) : Sender {  
   override fun sendMessage(message: String) {  
      println(message)  
   }  
}DeclaraçÔes de Comandos:
open class DreamCommand(override vararg val labels: String) : BaseCommand {  
   override val subcommands: MutableList<BaseCommand> = mutableListOf()  
  
   init {  
      registerSubcommands()  
   }  
}open class DreamDSLCommand(vararg labels: String, override val executors: List<DreamDSLExecutorWrapper>, dslSubcommands: List<BaseDSLCommand>) : DreamCommand(*labels), BaseDSLCommand {  
   init {  
      // lol nope, vamos ignorar todos os subcomandos registrados pela classe principal, elas sĂŁo chatas!  
  subcommands.clear()  
  
      // E colocar todos os subcomandos de DSL apĂłs iniciar  
  subcommands.addAll(dslSubcommands)  
  
      // Deste jeito ainda Ă© possĂvel usar o "subcommands" para adicionar subcomandos de outras classes! Yay!  
  }  
}Command Manager:
class ConsoleCommandManager : DispatchableCommandManager<Sender, DreamCommand, DreamDSLCommand>() {  
   private val commands = mutableListOf<DreamCommand>()  
 
   override fun registerCommand(command: DreamCommand) {  
   	commands.add(command)  
   }  
 
   override fun unregisterCommand(command: DreamCommand) {  
   	commands.remove(command)  
   }  
 
   override fun getRegisteredCommands(): List<DreamCommand> {  
   	return commands  
   }  
 
   override suspend fun dispatch(sender: Sender, command: DreamCommand, label: String, arguments: Array<String>): Boolean {
   	if (!command.labels.contains(label))
   		return false
   	for (subCommand in command.subcommands) {
   		if (dispatch(sender, subCommand as DreamCommand, arguments.drop(0).firstOrNull() ?: "", arguments.drop(1).toTypedArray()))
   			return true
   	}
   	return execute(sender, command, arguments)
   }  
}E Ă© claro, Ă© possĂvel criar exemplos mais complexos, por exemplo:
class RoleplayCommand : DreamCommand("undertale") {
	@Subcommand
	fun root(sender: Sender) {
		sender.sendMessage("Para começar o roleplay, use \"undertale roleplay personagem\"")
	}
	inner class RoleplaySubCommand : DreamCommand("roleplay") {
		@Subcommand
		fun showCharacters(sender: Sender) {
			Character.values().forEach { sender.sendMessage(it.name) }
		}
		@Subcommand
		fun chooseCharacter(sender: Sender, @InjectArgument(ArgumentType.PEEK_STRING) characterName: String, character: Character?) {
			if (character == null) {
				sender.sendMessage("O personagem $characterName nĂŁo existe, bobinho!")
				return
			}
			sender.sendMessage("VocĂȘ escolheu $character!")
		}
	}
	enum class Character {
		ASRIEL,
		TORIEL,
		FRISK,
		CHARA
	}
}VocĂȘ pode atĂ© usar DSLs para criar comandos!
class DomainSpecificLanguageCommand {
	fun generateCommand() = command("dslexample") {
		command("easter") {
			whenever<Sender, String?> { sender, input ->
				if (input == null) {
					sender.sendMessage("Apenas os fortes que possuem a senha poderĂŁo ver o easter egg.")
					return@whenever
				}
				if (input != "lorotajubinha") {
					sender.sendMessage("Errou! $input não é a senha, tente novamente, mas agora com mais confiança!")
					return@whenever
				}
				sender.sendMessage("ParabĂ©ns, vocĂȘ encotrou o easter egg! Guarde ele com muito carinho ^-^ https://bit.ly/segredolori")
			}
		}
		whenever<Sender> {
			it.sendMessage("i love u :3")
		}
	}
}E Ă© isto, have fun!
YourKit, criadores do YourKit Java Profiler, suportam projetos open source de todos os tipos com o excelente profiler de aplicaçÔes Java e .NET. NĂłs agradecemos por darem uma licença open source para conseguir deixar nossos projetos mais incrĂveis e maravilhosos para todos os nossos usuĂĄrios!
O cĂłdigo-fonte da Loritta estĂĄ licenciado sob a GNU Affero General Public License v3.0


