Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

PerfectDreams/CommandFramework

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🔖 Framework de Comandos para o PerfectDreams 🔖

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 @Optional em 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 Player ao digitar Loritta!
  • 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:

  1. 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)
  2. Dependem de plataformas para funcionar, em vez de serem "genéricas" para usar em qualquer tipo de sistema (Plugin Annotations, KotlinBukkitAPI)
  3. 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>

đŸ€” TĂĄ fera, mas cadĂȘ os exemplos?

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!

đŸ’« Agradecimentos especiais para...

YourKit-Logo

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!

📄 Licença

O cĂłdigo-fonte da Loritta estĂĄ licenciado sob a GNU Affero General Public License v3.0


About

🔖 Framework de Comandos para o PerfectDreams

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages