diff --git a/.github/workflows/CODEOWNERS b/.github/CODEOWNERS
similarity index 100%
rename from .github/workflows/CODEOWNERS
rename to .github/CODEOWNERS
diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index 086d8f7..ddf6578 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -1,4 +1,4 @@
-name: Java CI with Gradle
+name: CI
on:
push:
@@ -8,29 +8,23 @@ on:
jobs:
build:
+ name: Build
runs-on: ubuntu-latest
- strategy:
- matrix:
- java:
- - 17
- fail-fast: false
steps:
- name: Checkout
- uses: actions/checkout@v4.3.1
- - name: 'Set up JDK ${{ matrix.java }}'
- uses: actions/setup-java@v4.8.0
- with:
- distribution: adopt
- java-version: '${{ matrix.java }}'
- - name: Cache Gradle
- uses: actions/cache@v4.3.0
+ uses: actions/checkout@v5
+
+ - name: Set up JDK 21
+ uses: actions/setup-java@v5
with:
- path: ~/.gradle/caches
- key: >-
- ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*',
- '**/gradle-wrapper.properties') }}
- restore-keys: '${{ runner.os }}-gradle-'
- - name: Grant execute permission for gradlew
+ distribution: 'temurin'
+ java-version: 21
+
+ - name: Setup Gradle
+ uses: gradle/actions/setup-gradle@v5
+
+ - name: Make gradlew executable
run: chmod +x gradlew
- - name: Build the Jar
- run: './gradlew clean test build'
\ No newline at end of file
+
+ - name: Build with Gradle
+ run: ./gradlew build
\ No newline at end of file
diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml
index ba81f0d..158db5b 100644
--- a/.github/workflows/publish-release.yml
+++ b/.github/workflows/publish-release.yml
@@ -1,25 +1,30 @@
name: Publish Multification
+
on:
release:
- branches: [ master ]
+ types: [published]
+
jobs:
publish:
+ name: Publish
runs-on: ubuntu-latest
environment: deployment
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- - name: Set up JDK
- uses: actions/setup-java@v4
+ - name: Set up JDK 21
+ uses: actions/setup-java@v5
with:
distribution: 'temurin'
- java-version: 17
- cache: 'gradle'
+ java-version: 21
- - name: Grant execute permission for gradlew
- run: chmod +x gradlew
+ - name: Setup Gradle
+ uses: gradle/actions/setup-gradle@v5
+ - name: Make gradlew executable
+ run: chmod +x gradlew
+
- name: Publish with Gradle
run: ./gradlew publish
env:
diff --git a/README.md b/README.md
index 8808aed..4360d91 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,9 @@
-
+

+
### Multification
+
Powerful library for sending custom notifications based on adventure.
[](https://www.patreon.com/eternalcode)
@@ -15,7 +17,9 @@ Powerful library for sending custom notifications based on adventure.
## About
-Multification makes it simple to create customizable notifications and messages within large plugins that require handling a high volume of messages (while the setup may not be easy, **itβs worthwhile for extensive plugins**). It offers a range of features, including:
+Multification makes it simple to create customizable notifications and messages within large plugins that require
+handling a high volume of messages (while the setup may not be easy, **itβs worthwhile for extensive plugins**). It
+offers a range of features, including:
- π Chat messages
- π Title & Subtitle
@@ -28,23 +32,55 @@ Multification makes it simple to create customizable notifications and messages
- π οΈ Formatter support
- π Flexible messages providing (easy to implement i18n)
- π¦ Configuration support (CDN, Okaeri Configs)
-- Cross-platform support (currently we support Bukkit, but it's easy to add support for other adventure-based platforms)
+- π Cross-platform support (Bukkit, Paper)
Messages can be sent to any audience, such as players or the console.
+## Supported Platforms
+
+| Platform | Module | Java Version | Adventure API | Status |
+|-------------------|------------------------|--------------|-----------------------|------------------------|
+| **Paper** | `multification-paper` | Java 21 | Native (built-in) | β
Recommended |
+| **Bukkit/Spigot** | `multification-bukkit` | Java 8+ | External adapter | β
Supported |
+| **Velocity** | `multification-velocity` | Java 21+ | Native | β Soon |
+| **Core** | `multification-core` | Java 8+ | Custom implementation | β
For custom platforms |
+
+> **π‘ Recommendation:** Use `multification-paper` for Paper servers (1.19.4+) to leverage native Adventure API without
+> external dependencies.
+
## Getting Started
-To use the library, you need to add the following repository and dependency to your `build.gradle` file:
+### For Paper Servers (Recommended)
+
+Add the following repository and dependency to your `build.gradle.kts`:
```kts
-maven("https://repo.eternalcode.pl/releases")
+repositories {
+ maven("https://repo.eternalcode.pl/releases")
+ maven("https://repo.papermc.io/repository/maven-public/")
+}
+
+dependencies {
+ implementation("com.eternalcode:multification-paper:1.2.3")
+}
```
+### For Bukkit/Spigot Servers
+
```kts
-implementation("com.eternalcode:multification-bukkit:1.2.2")
+repositories {
+ maven("https://repo.eternalcode.pl/releases")
+}
+
+dependencies {
+ implementation("com.eternalcode:multification-bukkit:1.2.3")
+}
```
-> **Note:** If you want to use the library with other platforms, then you need to use the `multification-core` dependency.
+> **Note:** For custom platforms or other Adventure-based servers, use `multification-core` and implement your own
+> platform adapter.
+
+## Quick Example
Then create a new instance of the `Multification` class and use it to send notifications:
@@ -55,7 +91,10 @@ public class YourMultification extends BukkitMultification
{
private final AudienceProvider audienceProvider;
private final MiniMessage miniMessage;
- public YourMultification(MessagesConfig messagesConfig, AudienceProvider audienceProvider, MiniMessage miniMessage) {
+ public YourMultification(
+ MessagesConfig messagesConfig,
+ AudienceProvider audienceProvider,
+ MiniMessage miniMessage) {
this.messagesConfig = messagesConfig;
this.audienceProvider = audienceProvider;
this.miniMessage = miniMessage;
@@ -73,7 +112,7 @@ public class YourMultification extends BukkitMultification {
@Override
protected @NotNull AudienceConverter audienceConverter() {
- return commandSender -> {
+ return commandSender -> {
if (commandSender instanceof Player player) {
return this.audienceProvider.player(player.getUniqueId());
}
@@ -81,7 +120,6 @@ public class YourMultification extends BukkitMultification {
return this.audienceProvider.console();
};
}
-
}
```
@@ -100,28 +138,32 @@ After that, you can use the `multification` instance to send notifications:
```java
multification.create()
- .player(player.getUniqueId())
- .notice(messages -> messages.yourMessage)
- .send();
+ .player(player.getUniqueId())
+ .notice(messages ->messages.yourMessage)
+ .send();
```
## Configuration Support
Multification currently supports two configuration libraries:
+
- [CDN](https://github.com/dzikoysk/cdn) _Simple and fast property-based configuration library for JVM apps_
-- [Okaeri Configs](https://github.com/OkaeriPoland/okaeri-configs) _Simple Java/POJO config library written with love and Lombok_
+- [Okaeri Configs](https://github.com/OkaeriPoland/okaeri-configs) _Simple Java/POJO config library written with love
+ and Lombok_
To use the Multification library with one of the configuration libraries, you need to:
### [CDN](https://github.com/dzikoysk/cdn)
#### (CDN) 1. Add dependency to your `build.gradle` file:
+
```gradle
implementation("com.eternalcode:multification-cdn:1.1.4")
implementation("net.dzikoysk:cdn:1.14.5")
```
#### (CDN) 2. Create configuration class:
+
```java
public class MessagesConfig {
@Description("# My first message")
@@ -130,11 +172,12 @@ public class MessagesConfig {
```
#### (CDN) 3. Create a new instance of the `Cdn` with the `MultificationNoticeCdnComposer`:
+
```java
Cdn cdn = CdnFactory.createYamlLike()
- .getSettings()
- .withComposer(Notice.class, new MultificationNoticeCdnComposer(multification.getNoticeRegistry()))
- .build();
+ .getSettings()
+ .withComposer(Notice.class, new MultificationNoticeCdnComposer(multification.getNoticeRegistry()))
+ .build();
```
#### (CDN) 4. Load the configuration:
@@ -145,14 +188,12 @@ To load and create the config file, use the following code in the init method su
MessagesConfig messages = new MessagesConfig();
Resource resource = Source.of(this.dataFolder, "messages.yml");
-cdn.load(resource, messages)
- .orThrow(cause -> cause);
-
-cdn.render(config, resource)
- .orThrow(cause -> cause);
+cdn.load(resource, messages).orThrow(cause ->cause);
+cdn.render(config, resource).orThrow(cause ->cause);
```
-Checkout example with CDN! [example plugin](https://github.com/EternalCodeTeam/multification/tree/master/examples/bukkit).
+Checkout example with
+CDN! [example plugin](https://github.com/EternalCodeTeam/multification/tree/master/examples/bukkit).
### [Okaeri Configs](https://github.com/OkaeriPoland/okaeri-configs)
@@ -163,11 +204,13 @@ implementation("com.eternalcode:multification-okaeri:1.1.4")
```
Probably also you will need to add additional dependencies for your platform, e.g. :
+
```gradle
implementation("eu.okaeri:okaeri-configs-serdes-commons:5.0.5")
implementation("eu.okaeri:okaeri-configs-serdes-bukkit:5.0.5")
implementation("eu.okaeri:okaeri-configs-yaml-bukkit:5.0.5")
```
+
See [Okaeri Configs](https://github.com/OkaeriPoland/okaeri-configs) for more information.
#### (Okaeri) 2. Create configuration class:
@@ -183,11 +226,25 @@ public class MessagesConfig extends OkaeriConfig {
```java
MessagesConfig config = (MessagesConfig) ConfigManager.create(MessagesConfig.class)
- .withConfigurer(new MultificationSerdesPack(multification.getNoticeRegistry()))
- .withConfigurer(new SerdesCommons(), new YamlBukkitConfigurer(), new SerdesBukkit()) // specify configurers for your platform
- .withBindFile(new File(dataFolder, "messages.yml"))
- .withRemoveOrphans(true) // automatic removal of undeclared keys
- .saveDefaults() // save file if does not exists
- .load(true);
+ .withConfigurer(new MultificationSerdesPack(multification.getNoticeRegistry()))
+ .withConfigurer(new SerdesCommons(), new YamlBukkitConfigurer(), new SerdesBukkit()) // specify configurers for your platform
+ .withBindFile(new File(dataFolder, "messages.yml"))
+ .withRemoveOrphans(true) // automatic removal of undeclared keys
+ .saveDefaults() // save file if does not exists
+ .load(true);
```
+## π License
+
+This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.
+
+## π Links
+
+- [GitHub Repository](https://github.com/EternalCodeTeam/multification)
+- [Discord Community](https://discord.gg/FQ7jmGBd6c)
+- [EternalCode Website](https://eternalcode.pl/)
+- [Issue Tracker](https://github.com/EternalCodeTeam/multification/issues)
+
+---
+
+Made with β€οΈ by [EternalCodeTeam](https://github.com/EternalCodeTeam)
diff --git a/buildSrc/src/main/kotlin/multification-repositories.gradle.kts b/buildSrc/src/main/kotlin/multification-repositories.gradle.kts
index 2726e38..dc1e440 100644
--- a/buildSrc/src/main/kotlin/multification-repositories.gradle.kts
+++ b/buildSrc/src/main/kotlin/multification-repositories.gradle.kts
@@ -5,7 +5,7 @@ plugins {
repositories {
mavenCentral()
- maven("https://papermc.io/repo/repository/maven-public/") // paper, adventure, velocity
+ maven("https://repo.papermc.io/repository/maven-public/") // paper, adventure, velocity
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") // spigot
maven("https://repo.panda-lang.org/releases/") // expressible
maven("https://repo.stellardrift.ca/repository/snapshots/")
diff --git a/examples/paper/build.gradle.kts b/examples/paper/build.gradle.kts
new file mode 100644
index 0000000..56521dc
--- /dev/null
+++ b/examples/paper/build.gradle.kts
@@ -0,0 +1,60 @@
+plugins {
+ id("java")
+ id("com.gradleup.shadow") version "9.0.0-beta4"
+ id("net.minecrell.plugin-yml.paper") version "0.6.0"
+ id("xyz.jpenilla.run-paper") version "2.3.1"
+}
+
+version = "1.0.0-SNAPSHOT"
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_21
+ targetCompatibility = JavaVersion.VERSION_21
+}
+
+repositories {
+ mavenCentral()
+ maven("https://repo.papermc.io/repository/maven-public/")
+ maven("https://repo.panda-lang.org/releases/")
+}
+
+dependencies {
+ compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
+
+ implementation("dev.rollczi:litecommands-bukkit:3.4.1")
+ // implementation("com.eternalcode:multification-paper:1.2.3") // <-- uncomment in your project
+ // implementation("com.eternalcode:multification-cdn:1.2.3") // <-- uncomment in your project
+
+ implementation(project(":multification-paper")) // don't use this line in your build.gradle
+ implementation(project(":multification-cdn")) // don't use this line in your build.gradle
+}
+
+val pluginName = "ExamplePaperPlugin"
+val packageName = "com.eternalcode.example.paper"
+
+paper {
+ main = "$packageName.$pluginName"
+ apiVersion = "1.21"
+ author = "EternalCode"
+ name = pluginName
+ version = "${project.version}"
+}
+
+tasks.shadowJar {
+ archiveFileName.set("$pluginName v${project.version}.jar")
+
+ listOf(
+ "dev.rollczi.litecommands",
+ "panda.std",
+ "panda.utilities",
+ ).forEach { relocate(it, "$packageName.libs.$it") }
+}
+
+sourceSets.test {
+ java.setSrcDirs(emptyList())
+ resources.setSrcDirs(emptyList())
+}
+
+tasks.runServer {
+ minecraftVersion("1.21.11")
+}
diff --git a/examples/paper/src/main/java/com/eternalcode/example/paper/ExamplePaperPlugin.java b/examples/paper/src/main/java/com/eternalcode/example/paper/ExamplePaperPlugin.java
new file mode 100644
index 0000000..e061e59
--- /dev/null
+++ b/examples/paper/src/main/java/com/eternalcode/example/paper/ExamplePaperPlugin.java
@@ -0,0 +1,47 @@
+package com.eternalcode.example.paper;
+
+import com.eternalcode.example.paper.command.FlyCommand;
+import com.eternalcode.example.paper.command.GiveCommand;
+import com.eternalcode.example.paper.command.ReloadCommand;
+import com.eternalcode.example.paper.command.TeleportCommand;
+import com.eternalcode.example.paper.command.timer.TimerCommand;
+import com.eternalcode.example.paper.command.timer.TimerManager;
+import com.eternalcode.example.paper.config.ConfigurationManager;
+import com.eternalcode.example.paper.config.MessagesConfig;
+import com.eternalcode.example.paper.multification.ExampleMultification;
+import dev.rollczi.litecommands.LiteCommands;
+import dev.rollczi.litecommands.bukkit.LiteBukkitFactory;
+import org.bukkit.command.CommandSender;
+import org.bukkit.plugin.java.JavaPlugin;
+
+public class ExamplePaperPlugin extends JavaPlugin {
+
+ private LiteCommands liteCommands;
+
+ @Override
+ public void onEnable() {
+ // Config & Multification
+ MessagesConfig messagesConfig = new MessagesConfig();
+ ExampleMultification multification = new ExampleMultification(messagesConfig);
+
+ ConfigurationManager configurationManager = new ConfigurationManager(this.getDataFolder(),
+ multification.getNoticeRegistry());
+ configurationManager.load(messagesConfig, "messages.yml");
+
+ this.liteCommands = LiteBukkitFactory.builder()
+ .commands(
+ new TeleportCommand(multification),
+ new FlyCommand(multification),
+ new GiveCommand(multification),
+ new ReloadCommand(configurationManager, multification),
+ new TimerCommand(new TimerManager(this.getServer().getScheduler(), this, multification)))
+ .build();
+ }
+
+ @Override
+ public void onDisable() {
+ if (this.liteCommands != null) {
+ this.liteCommands.unregister();
+ }
+ }
+}
diff --git a/examples/paper/src/main/java/com/eternalcode/example/paper/command/FlyCommand.java b/examples/paper/src/main/java/com/eternalcode/example/paper/command/FlyCommand.java
new file mode 100644
index 0000000..a7d4065
--- /dev/null
+++ b/examples/paper/src/main/java/com/eternalcode/example/paper/command/FlyCommand.java
@@ -0,0 +1,56 @@
+package com.eternalcode.example.paper.command;
+
+import com.eternalcode.example.paper.multification.ExampleMultification;
+import dev.rollczi.litecommands.annotations.argument.Arg;
+import dev.rollczi.litecommands.annotations.command.Command;
+import dev.rollczi.litecommands.annotations.context.Context;
+import dev.rollczi.litecommands.annotations.execute.Execute;
+import dev.rollczi.litecommands.annotations.permission.Permission;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+@Command(name = "fly", aliases = { "f" })
+@Permission("example.fly")
+public class FlyCommand {
+
+ private final ExampleMultification multification;
+
+ public FlyCommand(ExampleMultification multification) {
+ this.multification = multification;
+ }
+
+ @Execute
+ void execute(@Context Player sender) {
+ sender.setAllowFlight(!sender.getAllowFlight());
+ multification.create()
+ .player(sender.getUniqueId())
+ .notice(messages -> messages.selfFlyCommandMessage)
+ .placeholder("{state}", sender.getAllowFlight() ? "enabled" : "disabled")
+ .send();
+ }
+
+ @Execute
+ void executeOther(@Context CommandSender sender, @Arg Player target) {
+ target.setAllowFlight(!target.getAllowFlight());
+
+ multification.create()
+ .player(target.getUniqueId())
+ .notice(messages -> messages.selfFlyCommandMessage)
+ .placeholder("{state}", target.getAllowFlight() ? "enabled" : "disabled")
+ .send();
+
+ multification.create()
+ .viewer(sender)
+ .notice(messages -> messages.otherFlyCommandMessage)
+ .placeholder("{state}", target.getAllowFlight() ? "enabled" : "disabled")
+ .placeholder("{player}", target.getName())
+ .send();
+
+ multification.create()
+ .player(target.getUniqueId())
+ .notice(messages -> messages.otherFlyCommandMessageTarget)
+ .placeholder("{state}", target.getAllowFlight() ? "enabled" : "disabled")
+ .placeholder("{player}", sender.getName())
+ .send();
+ }
+}
diff --git a/examples/paper/src/main/java/com/eternalcode/example/paper/command/GiveCommand.java b/examples/paper/src/main/java/com/eternalcode/example/paper/command/GiveCommand.java
new file mode 100644
index 0000000..791aff8
--- /dev/null
+++ b/examples/paper/src/main/java/com/eternalcode/example/paper/command/GiveCommand.java
@@ -0,0 +1,52 @@
+package com.eternalcode.example.paper.command;
+
+import com.eternalcode.example.paper.multification.ExampleMultification;
+import dev.rollczi.litecommands.annotations.argument.Arg;
+import dev.rollczi.litecommands.annotations.command.Command;
+import dev.rollczi.litecommands.annotations.context.Context;
+import dev.rollczi.litecommands.annotations.execute.Execute;
+import dev.rollczi.litecommands.annotations.optional.OptionalArg;
+import org.bukkit.Material;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+
+@Command(name = "give")
+public class GiveCommand {
+
+ private final ExampleMultification multification;
+
+ public GiveCommand(ExampleMultification multification) {
+ this.multification = multification;
+ }
+
+ @Execute
+ public void execute(
+ @Context CommandSender commandSender,
+ @Arg("nick") Player target,
+ @Arg("item") Material item,
+ @OptionalArg("amount") Integer amount) {
+ if (amount == null) {
+ amount = 1;
+ }
+
+ multification.create()
+ .player(target.getUniqueId())
+ .notice(messages -> messages.receiverGiveCommandMessage)
+ .placeholder("{player}", commandSender.getName())
+ .placeholder("{amount}", amount.toString())
+ .placeholder("{item}", item.name())
+ .send();
+
+ multification
+ .create()
+ .viewer(commandSender)
+ .notice(messages -> messages.senderGiveCommandMessage)
+ .placeholder("{player}", target.getName())
+ .placeholder("{amount}", amount.toString())
+ .placeholder("{item}", item.name())
+ .send();
+
+ target.getInventory().addItem(new ItemStack(item, amount));
+ }
+}
diff --git a/examples/paper/src/main/java/com/eternalcode/example/paper/command/ReloadCommand.java b/examples/paper/src/main/java/com/eternalcode/example/paper/command/ReloadCommand.java
new file mode 100644
index 0000000..718d61b
--- /dev/null
+++ b/examples/paper/src/main/java/com/eternalcode/example/paper/command/ReloadCommand.java
@@ -0,0 +1,39 @@
+package com.eternalcode.example.paper.command;
+
+import com.eternalcode.example.paper.config.ConfigurationManager;
+import com.eternalcode.example.paper.multification.ExampleMultification;
+import dev.rollczi.litecommands.annotations.command.Command;
+import dev.rollczi.litecommands.annotations.context.Context;
+import dev.rollczi.litecommands.annotations.execute.Execute;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+@Command(name = "reload-config")
+public class ReloadCommand {
+
+ private final ConfigurationManager configurationManager;
+ private final ExampleMultification multification;
+
+ public ReloadCommand(ConfigurationManager configurationManager, ExampleMultification multification) {
+ this.configurationManager = configurationManager;
+ this.multification = multification;
+ }
+
+ @Execute
+ public void execute(@Context CommandSender sender) {
+ this.configurationManager.reload();
+
+ if (sender instanceof Player player) {
+ this.multification.create()
+ .player(player.getUniqueId())
+ .notice(messagesConfig -> messagesConfig.reloadMessage)
+ .send();
+ return;
+ }
+
+ this.multification.create()
+ .console()
+ .notice(messagesConfig -> messagesConfig.reloadMessage)
+ .send();
+ }
+}
diff --git a/examples/paper/src/main/java/com/eternalcode/example/paper/command/TeleportCommand.java b/examples/paper/src/main/java/com/eternalcode/example/paper/command/TeleportCommand.java
new file mode 100644
index 0000000..654ddff
--- /dev/null
+++ b/examples/paper/src/main/java/com/eternalcode/example/paper/command/TeleportCommand.java
@@ -0,0 +1,31 @@
+package com.eternalcode.example.paper.command;
+
+import com.eternalcode.example.paper.multification.ExampleMultification;
+import dev.rollczi.litecommands.annotations.argument.Arg;
+import dev.rollczi.litecommands.annotations.context.Context;
+import dev.rollczi.litecommands.annotations.execute.Execute;
+import dev.rollczi.litecommands.annotations.permission.Permission;
+import dev.rollczi.litecommands.annotations.command.Command;
+import org.bukkit.entity.Player;
+
+@Command(name = "teleport", aliases = "tp")
+@Permission("example.teleport")
+public class TeleportCommand {
+
+ private final ExampleMultification multification;
+
+ public TeleportCommand(ExampleMultification multification) {
+ this.multification = multification;
+ }
+
+ @Execute
+ public void teleportSelf(@Context Player sender, @Arg Player to) {
+ multification.create()
+ .player(sender.getUniqueId())
+ .notice(messages -> messages.selfTeleportCommandMessage)
+ .placeholder("{player}", to.getName())
+ .send();
+
+ sender.teleport(to.getLocation());
+ }
+}
diff --git a/examples/paper/src/main/java/com/eternalcode/example/paper/command/timer/TimerCommand.java b/examples/paper/src/main/java/com/eternalcode/example/paper/command/timer/TimerCommand.java
new file mode 100644
index 0000000..61867bf
--- /dev/null
+++ b/examples/paper/src/main/java/com/eternalcode/example/paper/command/timer/TimerCommand.java
@@ -0,0 +1,22 @@
+package com.eternalcode.example.paper.command.timer;
+
+import dev.rollczi.litecommands.annotations.command.Command;
+import dev.rollczi.litecommands.annotations.execute.Execute;
+import dev.rollczi.litecommands.annotations.permission.Permission;
+import java.time.Duration;
+
+@Command(name = "timer")
+@Permission("example.timer")
+public class TimerCommand {
+
+ private final TimerManager timerManager;
+
+ public TimerCommand(TimerManager timerManager) {
+ this.timerManager = timerManager;
+ }
+
+ @Execute
+ public void execute() {
+ this.timerManager.startTimer(Duration.ofSeconds(5));
+ }
+}
diff --git a/examples/paper/src/main/java/com/eternalcode/example/paper/command/timer/TimerManager.java b/examples/paper/src/main/java/com/eternalcode/example/paper/command/timer/TimerManager.java
new file mode 100644
index 0000000..9968db3
--- /dev/null
+++ b/examples/paper/src/main/java/com/eternalcode/example/paper/command/timer/TimerManager.java
@@ -0,0 +1,37 @@
+package com.eternalcode.example.paper.command.timer;
+
+import com.eternalcode.example.paper.multification.ExampleMultification;
+import java.time.Duration;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.scheduler.BukkitScheduler;
+
+public class TimerManager {
+
+ private final BukkitScheduler bukkitScheduler;
+ private final Plugin plugin;
+ private final ExampleMultification multification;
+
+ public TimerManager(BukkitScheduler bukkitScheduler, Plugin plugin, ExampleMultification multification) {
+ this.bukkitScheduler = bukkitScheduler;
+ this.plugin = plugin;
+ this.multification = multification;
+ }
+
+ public void startTimer(Duration duration) {
+ tickTimer(duration.toSeconds());
+ }
+
+ private void tickTimer(long seconds) {
+ if (seconds == 0) {
+ return;
+ }
+
+ this.multification.create()
+ .all()
+ .notice(messages -> messages.bossbarTimer)
+ .placeholder("{time}", String.valueOf(seconds))
+ .send();
+
+ this.bukkitScheduler.runTaskLater(plugin, () -> tickTimer(seconds - 1), 20L);
+ }
+}
diff --git a/examples/paper/src/main/java/com/eternalcode/example/paper/config/ConfigurationManager.java b/examples/paper/src/main/java/com/eternalcode/example/paper/config/ConfigurationManager.java
new file mode 100644
index 0000000..0551707
--- /dev/null
+++ b/examples/paper/src/main/java/com/eternalcode/example/paper/config/ConfigurationManager.java
@@ -0,0 +1,42 @@
+package com.eternalcode.example.paper.config;
+
+import com.eternalcode.multification.cdn.MultificationNoticeCdnComposer;
+import com.eternalcode.multification.notice.Notice;
+import com.eternalcode.multification.notice.resolver.NoticeResolverRegistry;
+import net.dzikoysk.cdn.Cdn;
+import net.dzikoysk.cdn.CdnFactory;
+import net.dzikoysk.cdn.source.Source;
+
+import java.io.File;
+
+public class ConfigurationManager {
+
+ private final File dataFolder;
+ private final Cdn cdn;
+ private MessagesConfig messagesConfig;
+
+ public ConfigurationManager(File dataFolder, NoticeResolverRegistry noticeRegistry) {
+ this.dataFolder = dataFolder;
+ this.cdn = CdnFactory.createYamlLike()
+ .getSettings()
+ .withComposer(Notice.class, new MultificationNoticeCdnComposer(noticeRegistry))
+ .build();
+ }
+
+ public void load(MessagesConfig config, String fileName) {
+ this.messagesConfig = config;
+ File file = new File(this.dataFolder, fileName);
+
+ this.cdn.load(Source.of(file), config)
+ .orThrow(cause -> cause);
+
+ this.cdn.render(config, Source.of(file))
+ .orThrow(cause -> cause);
+ }
+
+ public void reload() {
+ if (this.messagesConfig != null) {
+ load(this.messagesConfig, "messages.yml");
+ }
+ }
+}
diff --git a/examples/paper/src/main/java/com/eternalcode/example/paper/config/MessagesConfig.java b/examples/paper/src/main/java/com/eternalcode/example/paper/config/MessagesConfig.java
new file mode 100644
index 0000000..7cc9a7d
--- /dev/null
+++ b/examples/paper/src/main/java/com/eternalcode/example/paper/config/MessagesConfig.java
@@ -0,0 +1,46 @@
+package com.eternalcode.example.paper.config;
+
+import com.eternalcode.multification.notice.Notice;
+import net.dzikoysk.cdn.entity.Description;
+import net.kyori.adventure.bossbar.BossBar;
+
+import java.time.Duration;
+
+public class MessagesConfig {
+
+ @Description("# Fly command message")
+ public Notice selfFlyCommandMessage = Notice
+ .chat("You have toggled fly mode. It is now {state}.");
+ public Notice otherFlyCommandMessage = Notice.chat(
+ "You have toggled fly mode for {player}. It is now {state}.");
+ public Notice otherFlyCommandMessageTarget = Notice.builder()
+ .chat("Your fly mode has been toggled by {player}. It is now {state}.")
+ .sound("minecraft:entity.item.pickup")
+ .build();
+
+ @Description("# Give command message")
+ public Notice senderGiveCommandMessage = Notice
+ .title("You have given {amount}x {item} to {player}.");
+ public Notice receiverGiveCommandMessage = Notice.builder()
+ .title("You have received {amount}x {item} from {player}.")
+ .subtitle("Remember to say thank you!")
+ .sound("minecraft:entity.item.pickup")
+ .build();
+
+ @Description("# Teleport command message")
+ public Notice selfTeleportCommandMessage = Notice.builder()
+ .actionBar("You have been teleported to {player}.")
+ .sound("minecraft:entity.enderman.teleport", 2.0F, 2.0F)
+ .build();
+
+ @Description("# Epic bossbar timer!!!")
+ public Notice bossbarTimer = Notice.builder()
+ .bossBar(BossBar.Color.RED, Duration.ofSeconds(1), "Timer: {time}")
+ .build();
+
+ @Description("# Reload command message")
+ public Notice reloadMessage = Notice.builder()
+ .chat("Configuration has been reloaded!")
+ .sound("minecraft:ambient.basalt_deltas.additions", 1.0F, 1.0F)
+ .build();
+}
diff --git a/examples/paper/src/main/java/com/eternalcode/example/paper/multification/ExampleMultification.java b/examples/paper/src/main/java/com/eternalcode/example/paper/multification/ExampleMultification.java
new file mode 100644
index 0000000..4aa774a
--- /dev/null
+++ b/examples/paper/src/main/java/com/eternalcode/example/paper/multification/ExampleMultification.java
@@ -0,0 +1,37 @@
+package com.eternalcode.example.paper.multification;
+
+import com.eternalcode.example.paper.config.MessagesConfig;
+import com.eternalcode.multification.adventure.AudienceConverter;
+import com.eternalcode.multification.paper.PaperMultification;
+import com.eternalcode.multification.translation.TranslationProvider;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+import net.kyori.adventure.text.serializer.ComponentSerializer;
+import org.bukkit.command.CommandSender;
+import org.jetbrains.annotations.NotNull;
+
+public class ExampleMultification extends PaperMultification {
+
+ private final MessagesConfig messagesConfig;
+ private final MiniMessage miniMessage;
+
+ public ExampleMultification(MessagesConfig messagesConfig) {
+ this.messagesConfig = messagesConfig;
+ this.miniMessage = MiniMessage.miniMessage();
+ }
+
+ @Override
+ protected @NotNull TranslationProvider translationProvider() {
+ return locale -> this.messagesConfig;
+ }
+
+ @Override
+ protected @NotNull ComponentSerializer serializer() {
+ return this.miniMessage;
+ }
+
+ @Override
+ protected @NotNull AudienceConverter audienceConverter() {
+ return commandSender -> commandSender;
+ }
+}
diff --git a/multification-paper/build.gradle.kts b/multification-paper/build.gradle.kts
new file mode 100644
index 0000000..39cfa39
--- /dev/null
+++ b/multification-paper/build.gradle.kts
@@ -0,0 +1,17 @@
+plugins {
+ `multification-java`
+ `multification-java-17`
+ `multification-repositories`
+ `multification-publish`
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_21
+ targetCompatibility = JavaVersion.VERSION_21
+}
+
+dependencies {
+ api(project(":multification-core"))
+ compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
+ testImplementation("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
+}
diff --git a/multification-paper/src/com/eternalcode/multification/paper/PaperLocaleProvider.java b/multification-paper/src/com/eternalcode/multification/paper/PaperLocaleProvider.java
new file mode 100644
index 0000000..a4998ed
--- /dev/null
+++ b/multification-paper/src/com/eternalcode/multification/paper/PaperLocaleProvider.java
@@ -0,0 +1,20 @@
+package com.eternalcode.multification.paper;
+
+import com.eternalcode.multification.locate.LocaleProvider;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.Locale;
+import org.jspecify.annotations.NonNull;
+
+class PaperLocaleProvider implements LocaleProvider {
+
+ @Override
+ public @NonNull Locale provide(CommandSender viewer) {
+ if (viewer instanceof Player player) {
+ return player.locale();
+ }
+
+ return Locale.ROOT;
+ }
+}
diff --git a/multification-paper/src/com/eternalcode/multification/paper/PaperMultification.java b/multification-paper/src/com/eternalcode/multification/paper/PaperMultification.java
new file mode 100644
index 0000000..8df8fc2
--- /dev/null
+++ b/multification-paper/src/com/eternalcode/multification/paper/PaperMultification.java
@@ -0,0 +1,36 @@
+package com.eternalcode.multification.paper;
+
+import com.eternalcode.multification.Multification;
+import com.eternalcode.multification.executor.AsyncExecutor;
+import com.eternalcode.multification.locate.LocaleProvider;
+import com.eternalcode.multification.viewer.ViewerProvider;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.jetbrains.annotations.NotNull;
+
+public abstract class PaperMultification extends Multification {
+
+ public static final ViewerProvider DEFAULT_VIEWER_PROVIDER = new PaperViewerProvider();
+ public static final LocaleProvider DEFAULT_LOCALE_PROVIDER = new PaperLocaleProvider();
+
+ protected PaperMultification() {
+ super();
+ }
+
+ @Override
+ protected @NotNull ViewerProvider viewerProvider() {
+ return DEFAULT_VIEWER_PROVIDER;
+ }
+
+ @Override
+ protected @NotNull LocaleProvider localeProvider() {
+ return DEFAULT_LOCALE_PROVIDER;
+ }
+
+ @Override
+ protected @NotNull AsyncExecutor asyncExecutor() {
+ return (runnable) -> Bukkit.getScheduler()
+ .runTaskAsynchronously(JavaPlugin.getProvidingPlugin(PaperMultification.class), runnable);
+ }
+}
diff --git a/multification-paper/src/com/eternalcode/multification/paper/PaperViewerProvider.java b/multification-paper/src/com/eternalcode/multification/paper/PaperViewerProvider.java
new file mode 100644
index 0000000..957a665
--- /dev/null
+++ b/multification-paper/src/com/eternalcode/multification/paper/PaperViewerProvider.java
@@ -0,0 +1,57 @@
+package com.eternalcode.multification.paper;
+
+import com.eternalcode.multification.viewer.ViewerProvider;
+import java.util.Collection;
+import java.util.UUID;
+import java.util.stream.Collectors;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+class PaperViewerProvider implements ViewerProvider {
+
+ @Override
+ public CommandSender console() {
+ return Bukkit.getConsoleSender();
+ }
+
+ @Override
+ public CommandSender player(UUID uuid) {
+ Player player = Bukkit.getPlayer(uuid);
+
+ if (player == null || !player.isOnline()) {
+ return null;
+ }
+
+ return player;
+ }
+
+ @Override
+ public Collection all() {
+ return Bukkit.getOnlinePlayers()
+ .stream()
+ .map(player -> (CommandSender) player)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public Collection onlinePlayers() {
+ return Bukkit.getOnlinePlayers()
+ .stream()
+ .map(player -> (CommandSender) player)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public Collection onlinePlayers(String permission) {
+ if (permission == null || permission.isEmpty()) {
+ return onlinePlayers();
+ }
+
+ return Bukkit.getOnlinePlayers()
+ .stream()
+ .filter(player -> player.hasPermission(permission))
+ .map(player -> (CommandSender) player)
+ .collect(Collectors.toList());
+ }
+}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index f85e277..487047b 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -4,5 +4,6 @@ include("multification-core")
include("multification-cdn")
include("multification-okaeri")
include("multification-bukkit")
-
+include("multification-paper")
include("examples:bukkit")
+include("examples:paper")