Skip to content

Commit

Permalink
Remove Development Branch.
Browse files Browse the repository at this point in the history
This PR merges the previous development branch onto the master branch.
  • Loading branch information
ShindouMihou authored Oct 19, 2021
2 parents 6bcdb4c + 013c599 commit 7efdaae
Show file tree
Hide file tree
Showing 43 changed files with 4,496 additions and 518 deletions.
87 changes: 9 additions & 78 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,17 @@
> 🛑 **WARNING**: Velen is currently relying on the development version of Javacord, as I do not know when the patch will be released, I decided to release the framework's version 3.0.0 officially while requiring the Development Version of Javacord (3.4.0-SNAPSHOT). Please use the SNAPSHOT version of Javacord instead which can be found on [their wiki](https://javacord.org/wiki/getting-started/download-installation.html#gradle-2)
<img src="https://i.ibb.co/Ny1V3sg/Velen-Banner.png" width="800px" width="250px">
# ✨ Velen ![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/ShindouMihou/Velen?label=version&style=flat-square) [![Discord](https://img.shields.io/discord/807084089013174272?color=blue&label=Discord&style=flat-square)](https://discord.gg/9FefYq4p83) ![GitHub commit activity](https://img.shields.io/github/commit-activity/m/ShindouMihou/Velen?color=red&style=flat-square) ![GitHub last commit](https://img.shields.io/github/last-commit/ShindouMihou/Velen?color=orange&style=flat-square)
Velen is a command framework (or library) that is created mainly for Javacord with the aim to make everything more easier
and faster to create, for example, slash commands, hybrid commands, cooldowns (rate-limiters), per-server prefixes, pagination and more!
Aiming to become the Laravel of Javacord; Velen is a framework for Discord bots using Javacord with complete features from hybrid (message and slash commands), slash commands, prefix managers, blacklists, fuzzy command search, cooldowns and many more. The aim of Velen is to reduce the time it takes for developers to setup a Discord bot without compromising on performance.

For a more organized look-through at Velen, please check our [GitHub Wiki](https:/ShindouMihou/Velen/wiki) instead
where everything is more organized and easier to read.

## 🎂 Features
| Feature | Supported |
|:--------------------------: |:---------: |
| Permission-locked commands | ✔️ |
| Role-locked commands | ✔️ |
| Fuzzy Command Suggestion | ✔️ |
| Blacklist (Ignore Users) | ✔️ |
| Prefix Manager | ✔️ |
| Customizable Messages | ✔️ |
| Pagination | ✔️ |
| Pagination (Buttons) | ✔️ |
| Rate-limiter (Cooldown) | ✔️ |
| Slash Comamnds | ✔️ |
| Hybrid Commands | ✔️ |
| Normal Commands | ✔️ |
| Mention as Prefix | ✔️ |
| Fast Updates | ✔️ |

## 🔌 Requirements
Velen only has one requirements and that is the latest Javacord, this will be
updated everytime Javacord releases a new patch. Please ensure your Javacord version
will be always up-to-date when using Velen!
- Javacord v3.3.2
- Javacord v3.4.0

## 📚 Wiki & Guide
We highly recommend reading our wiki where everything is explained more in detailed
Expand All @@ -47,58 +29,14 @@ We highly recommend reading our wiki where everything is explained more in detai
- [Velen Utilities](https:/ShindouMihou/Velen/wiki/Velen-Utils)

## ✔️ Ping-Pong Example
A very simple of a ping-pong command in Velen is:
```java
Velen velen = Velen.builder().setDefaultPrefix("v.").build();
VelenCommand.of("ping", velen, (event, message, user, args) -> message.reply("Pong!")).attach();

DiscordApi api = new DiscordApiBuilder().setToken(token)
.addListener(velen).login().join();
```

An example of slash command in Velen is:
```java
Velen velen = Velen.builder().setDefaultPrefix("v.").build();
VelenCommand.ofSlash("velenSlash", "A normal velen slash command.", velen, (event, user, args, options, firstResponder) ->
firstResponder.setContent("Hello!").respond()).attach();

DiscordApi api = new DiscordApiBuilder().setToken(token)
.addListener(velen).login().join();
```

An example of a hybrid command in Velen is:
```java
VelenCommand.ofHybrid("velenHybrid", "A velen hybrid command!", velen,
(event, message, user, args) -> message.reply("Hello!"),
(event, user, args1, options, firstResponder) -> firstResponder.setContent("Hello").respond())
.attach();
```

You can place the event handlers on their own classes, as well. If you want to learn more about those,
feel free to look at our Wiki where we explain everything more in detail:
- [Slash Commands and Hybrid Commands](https:/ShindouMihou/Velen/wiki/Building-Slash-&-Hybrid-Commands!)
- [Message Commands](https:/ShindouMihou/Velen/wiki/Building-Commands!)

You can also check out our example bot that utilizes Velen `v2.0` and Javacord `v3.3.2` paired with Redis to create
a persistent per-server prefix and blacklist:
- [Javacord & Velen Example Discord Bot](https:/ShindouMihou/Javacord-Velen-Example)
As we are still re-organizing the wiki to match the incredibly new style of Velen (the wikis are outdated), please refer to the examples (for now) located on.
- [MUST READ FIRST](https:/ShindouMihou/Velen/tree/development/examples)
- [Hybrid Commands](https:/ShindouMihou/Velen/tree/development/examples/hybrid)
- [Message Commands](https:/ShindouMihou/Velen/tree/development/examples/message)
- [Slash Commands](https:/ShindouMihou/Velen/tree/development/examples/slash)

## ❤️ Installation
You can easily install Velen through Maven Central by adding these entries onto your `build.gradle` or `pom.xml`:

### Maven
```xml
<dependency>
<groupId>pw.mihou</groupId>
<artifactId>Velen</artifactId>
<version>2.1.1</version>
</dependency>
```

### Gradle
```gradle
implementation 'pw.mihou:Velen:2.1.1'
```
We are currently disabling Maven Central until Javacord's 3.4.0 is released officially, for now, [please use Jitpack in the meantime](https://jitpack.io/#pw.mihou/Velen)

## ⛰️ Velen is used by
- [Amelia](https:/ManaNet/Amelia): A Discord bot that is dedicated to a webnovel site called ScribbleHub.
Expand All @@ -115,10 +53,3 @@ The library also follows a similar version number policy with Javacord:
- A change in the first digit of the version will mean: **major update or two-three major breaking change**.
- A change in the second digit of the version will mean: **a large quantity of __accumulated__ updates or a breaking change**.
- A change in the last digit of the version will mean: **a minor update, usually new features or fixes**.

## 🏎️ How does Velen work?
Velen functions through a single class that acts as the processor of the events, it handles and dispatches
the events accordingly to the command that was invoked, for example, if a command with the name `help` was invoked
and received by Velen. It will start to look for the command `help` to see if it is registered or not and if it
is then it will trigger that event in an **asynchronous** manner, which means all the events are handled in
different threads.
184 changes: 184 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
# ☪ Velen Mirror Examples
To understand all the examples that are shown here, please read each of the README.md of the individual folders
as they show details such as how the handlers (that handles the commands) and what the purpose of the folder is, these
examples are made to showcase the neatness of Velen Mirror.

# 🎁 What is Velen Mirror
Velen Mirror is the new command constructor system of Velen that aims to separate the nature of your code and
the command constructors which tends to be a mess especially for bots with tons of commands. Mirror is far cleaner
and verbose to read than ordinary Java builders, written under the `.velen` syntax.

To fully understand the outline of Mirror, let us take a glance at a simple ping-pong command that can be found written
similarly on both Message and Slash folders but adapted to their own use-case. Our example here will showcase how they can
be written in Hybrid Command.

# 🎂 Ping-Pong with Velen Mirror
Now that we know of all the currently possible options of Velen Mirror, let us start to minimize
the file to view the actual parts of the command, shall we?

**To see a full explanation of everything, please scroll even more below.**
### 😲 ping.min.velen
```dotenv
&[ping]: hybrid {
desc: Do you want to ping-pong with me?
usage: ping [pong|ping]
usage: ping [ping|pong]
shortcut: pong
&[response]: option {
desc: What kind of move will you make?
choice: [PING, PONG]
choice: [PONG, PING]
required: true
type: string
}
cooldown: 5000
handler: hybrid.ping
}
```

Doesn't that look quite clean and readable, compare that to the original Java builder method:
```java
VelenCommand.ofHybrid("ping", "Do you want to ping-pong with me?",
velen, new PingHandler(),
SlashCommandOption.createWithChoices(SlashCommandOptionType.STRING, "response", "What kind of move will you make?", true,
Arrays.asList(
SlashCommandOptionChoice.create("ping", "pong"),
SlashCommandOptionChoice.create("pong", "ping")
)))
.addFormats("ping :[response::(ping,pong)::required()]")
.addShortcut("pong")
.addUsages("ping [pong|ping]", "ping [ping|pong]")
.attach();
```

And now, imagine the same command but with two or four options, doesn't it look a bit too meh?
That is what was Velen Mirror was created for, to mirror a cleaner and readable look of command constructing.

# 🔬 Mirror Explanation
Now, you may be thinking... can I have an explanation and more details about the currently available ways
of creating commands and options? Don't worry, feel free to look at here.
**Note: I will be showing all the possible options and their explanation in the code block below**

### ⏱ Ping.velen
```dotenv
# This is how we specify what category the command
# will be located on.
# &[fun]: category
# We construct the name and type of the
# command using this.
&[ping]: hybrid {
# This is the description of the command that will show up in
# slash commands and also can be fetched via getDescription method.
desc: Do you want to ping-pong with me?
# This is how we initialize a usage that can be fetched via
# the getUsages method, it returns back a list because there can be
# multiple usages in a single command.
usage: ping [pong|ping]
usage: ping [ping|pong]
# This is otherwisely called an alias of a command, this only applies
# to message commands but can be placed in hybrid commands as it utilizes
# message commands as well.
shortcut: pong
# This is how you initialize an option, if you want to setup a subcommand
# all you have to do is change `option` to `subcommand` and wrap the options
# inside the brackets, the same thing for `subcommand_group`.
&[response]: option {
desc: What kind of move will you make?
# This is how you initialize choices in hybrid and slash commands.
# because slash commands uses [key, value], it is required here.
# but on message commands, you can use [choiceOne, choiceTwo, choiceThree].
# In our case, we are using [USER'S CHOICE, OUR RESPONSE].
choice: [PING, PONG]
choice: [PONG, PING]
# This is how we make a slash command option required.
# Message commands always has options required.
required: true
# This can be placed on the last option of a command
# to tell Velen to grab all the input of the user and squash
# it into this option, for example, Hello World would be returned
# if this option is enabled instead of just "Hello"
# but you can also replicate this behavior by wrapping the user input
# in quotes like: "Hello World".
# has_many: true
# You can specify the type of this option, there are a little bit
# of a list of options and to list them all:
#
# user, channel, role, numeric, boolean, mentionable, number, integer : These will all convert to their slash command equivalent.
# user, channel, role, message, emoji, webhook, boolean, numeric, integer, string: These will all convert to string on slash command
# but the second line of types will be aliased to their regex pattern (or algorithm) for message commands.
type: string
# You can also set regex patterns required for an option
# this only applies to message commands at the moment though.
# regex: ^[0-9]+
}
# This is how you specify the cooldown in milliseconds.
# It must be in milliseconds.
cooldown: 5000
# This is how you specify a command format using message commands.
# You should generally not use this and simply use the option constructor
# shown above since it will also be easier to move to slash commands.
# This is how the resposne option above looks though if you were to convert
# it to a command format.
# has_formats: ping :[response::(ping,pong)::required()]
# This is how you tell Velen to make this command only respond
# to servers.
# server_only: [true]
# This is how you tell Velen to make this command only in
# the specified server (also register the slash command there).
# server_only: [true, 123123123123L]
# This is how you tell Velen to limit this command to only
# the people with these permissions.
#
# For a list of permissions, please use the names of the enums on
# https:/Javacord/Javacord/blob/master/javacord-api/src/main/java/org/javacord/api/entity/permission/PermissionType.java
# permissions: [MANAGE_SERVER, ADMINISTRATOR]
# This is how you tell Velen to limit this command to
# the people with the specific roles.
# roles: [123123123L, 123123123L]
# This is how we specify the handler for the command.
# The best practice right now is to place [command type].[command name]
# to make them easier to find, you can also just go with [command name] or
# some other name.
handler: hybrid.ping
# If you want to separate the handling for both message and slash
# you can tell Velen by replacing the handler above with these two.
# handler: message.ping
# handler: slash.ping
}
```

# 🚉 Handlers

You may be thinking now, where is the logic behind how this ping command will work?
```java
Velen velen = Velen.ofDefaults();
velen.addHandler("hybrid.ping", (event, responder, user, args) -> {
args.withName("response").flatMap(VelenOption::asString).ifPresent(s -> responder.setContent(s).respond());
});
```

And that's quite literally how the command works, in fact, you can make it into two lines but for the sake for
readability, I've decided to expand the lambda function. Velen allows you to have a single handler for both message
and slash commands which is a key feature of the framework, but you can also opt to using multiple handlers.

That is the beauty of Velen Mirror and how you can make an entire Discord bot with very little code, did you like it?
58 changes: 58 additions & 0 deletions examples/hybrid/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# 🎁 Hybrid Command Examples
These are new examples of Hybrid Commands in Velen using the new file constructor system, all of these
attempts to utilize all possible methods for hybrid commands.

Please note that we are using the following handlers for this:

```java
import pw.mihou.velen.interfaces.hybrid.objects.VelenOption;

public class Test {

public static void main(String[] a) {
Velen velen = Velen.ofDefaults();

velen.addHandler("hybrid.hi", (event, responder, user, args) -> {
if (args.withName("user").isPresent()) {
responder.setContent("Hello " + args.withName("user").get().requestUser().get().join().getName());
} else {
responder.setContent("Hello " + user.getName());
}

responder.respond();
});

velen.addHandler("hybrid.number", (event, responder, user, args) -> args.withName("number").flatMap(VelenOption::asInteger)
.ifPresent(integer -> responder.setContent("I say number " + integer).respond()));

velen.addHandler("hybrid.ping", (event, responder, user, args) -> args.withName("response").flatMap(VelenOption::asString)
.ifPresent(s -> responder.setContent(s).respond()));

velen.addHandler("hybrid.say", (event, responder, user, args) -> args.getManyWithName("text")
.ifPresent(s -> responder.setContent(s).respond()));

velen.addHandler("hybrid.regex", (event, responder, user, args) -> {
if (args.withName("url").isPresent()) {
responder.setContent(args.withName("url").get().asString().get()).respond();
} else {
// This actually only works on message commands.
responder.setContent("The URL was rejected!").respond();
}
});

velen.addHandler("hybrid.scream", (event, responder, user, args) -> args.withName("scream")
.ifPresent(s -> responder.setContent(s).respond()));


velen.loadFrom("examples/hybrid");
DiscordApi api = new DiscordApiBuilder().setToken(System.getenv("token"))
.addListener(velen)
.setAllIntents()
.login()
.join();

new SlashCommandChecker(api, SlashCommandCheckerMode.NORMAL).run(velen);
System.out.println("You can now run the bot!");
}
}
```
Loading

0 comments on commit 7efdaae

Please sign in to comment.