Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 54 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,62 @@
# SpentTime
# 💬 AutoMessage — Ultra-Efficient Broadcasting System

[![Build Status](https://github.com/imDMK/AutoMessage/actions/workflows/gradle.yml/badge.svg)](https://github.com/imDMK/AutoMessage/actions/workflows/gradle.yml)
![JDK](https://img.shields.io/badge/JDK-1.17-blue.svg)
![Supported versions](https://img.shields.io/badge/Minecraft-1.17--1.20.1-green.svg)
![Supported versions](https://img.shields.io/badge/Minecraft-1.17--1.21.5-green.svg)
[![SpigotMC](https://img.shields.io/badge/SpigotMC-yellow.svg)](https://www.spigotmc.org/resources/automessage.112363/)
[![Bukkit](https://img.shields.io/badge/Bukkit-blue.svg)](https://legacy.curseforge.com/minecraft/bukkit-plugins/auto-messages)
[![PaperMC](https://img.shields.io/badge/Paper-004ee9.svg)](https://hangar.papermc.io/imDMK/AutoMessage)
[![bStats](https://img.shields.io/badge/bStats-00695c)](https://bstats.org/plugin/bukkit/AutoMessages/19487)

Efficient plugin for automatic global messaging with many features and configuration possibilities.

# Features
* Sending a CHAT message.
* Sending an ACTIONBAR message.
* Sending a TITLE and SUBTITLE message.
* Sending a BOSSBAR message (Possibility to configure all parameters).
* Ability to configure all messages sent by the plugin.
* Ability to send messages in different modes.
* Ability to create a message using a command on the server.
* Possibility to enable and disable automatic messages using a command on the server.
* [Adventure](https://github.com/KyoriPowered/adventure) components support.

# Information
If you have suggestions, or questions, or find a bug, please report it using [this](https://github.com/imDMK/AutoMessage/issues) site.
---

### 🚀 Lightweight. Customizable. Blazing Fast.

**AutoMessage** is a high-performance plugin for fully customizable automatic server-wide broadcasts. No lag. No hassle. Just clean, dynamic message delivery across chat, actionbars, titles, and bossbars — all with nearly zero performance impact.

---

## 🧠 Features

✅ **Multiple broadcast types**
• Chat
• ActionBar
• Title & Subtitle
• BossBar (fully configurable: color, style, duration, progress, etc.)

✅ **Advanced configuration**
• Create/edit/delete messages directly
• Toggle automatic messages at any time
• Support for various broadcast modes
• Dynamic intervals between messages
• Full MiniMessage & Adventure API formatting

✅ **Command support**
• `/automessage delay`
• `/automessage reload`
• You can even configure a command like you want!

✅ **Zero-lag optimized**
Built with efficiency in mind — AutoMessage has no noticeable impact on server performance, even with hundreds of players online.

✅ **Adventure API support**
Integrates with [Kyori Adventure](https://github.com/KyoriPowered/adventure) for rich message styling and component-based formatting.

---

## ✨ Showcase
![AutoMessage Chat Preview](assets/automessage-preview.gif)

---

## 🛠️ Feedback & Support

Found a bug? Have a suggestion? Want to contribute?
Open an issue on [GitHub Issues](https://github.com/imDMK/AutoMessage/issues) — your feedback is welcome!

---

## ⭐ Like the plugin?

If you enjoy using **AutoMessage**, please consider leaving a ⭐ rating on [SpigotMC](https://www.spigotmc.org/resources/automessage.112363/)!
It helps support future development and lets others discover it too.
Binary file added assets/automessage-preview.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
47 changes: 24 additions & 23 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,44 +27,46 @@ repositories {
}

dependencies {
compileOnly("org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT")
compileOnly("org.spigotmc:spigot-api:1.21.5-R0.1-SNAPSHOT")

implementation("eu.okaeri:okaeri-configs-yaml-snakeyaml:5.0.0-beta.5")
implementation("eu.okaeri:okaeri-configs-serdes-commons:5.0.0-beta.5")

implementation("net.kyori:adventure-platform-bukkit:4.3.1")
implementation("net.kyori:adventure-text-minimessage:4.14.0")
implementation("net.kyori:adventure-platform-bukkit:4.3.4")
implementation("net.kyori:adventure-text-minimessage:4.19.0")

implementation("dev.rollczi.litecommands:core:2.8.9")
implementation("dev.rollczi.litecommands:bukkit-adventure:2.8.9")
implementation("dev.rollczi:litecommands-bukkit:3.9.7")
implementation("dev.rollczi:litecommands-annotations:3.9.7")

implementation("com.eternalcode:multification-bukkit:1.1.4")
implementation("com.eternalcode:multification-okaeri:1.1.4")
implementation("com.eternalcode:gitcheck:1.0.0")
implementation("org.bstats:bstats-bukkit:3.0.2")

implementation("org.bstats:bstats-bukkit:3.1.0")

testImplementation platform("org.junit:junit-bom:5.10.1")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.1")
}

test {
useJUnitPlatform()
}

checkstyle {
toolVersion = "10.12.1"

configFile = file("checkstyle.xml")
}

bukkit {
name = "AutoMessage"
version = "${project.version}"
apiVersion = "1.17"
main = "com.github.imdmk.automessage.AutoMessagePlugin"
author = "DMK"
description = "Simple auto message plugin"
author = "imDMK"
description = "Advanced plugin for sending automatic chat, bossbar, and title messages to players."
website = "https://github.com/imDMK/AutoMessage"
}

test {
useJUnitPlatform()
}

checkstyle {
toolVersion = "10.21.0"
configFile = file("checkstyle.xml")
}

shadowJar {
archiveFileName.set("${project.name} v${project.version}.jar")

Expand All @@ -80,14 +82,13 @@ shadowJar {

def prefix = "com.github.imdmk.automessage.lib"
[
"eu.okaeri",
"net.kyori",
"dev.rollczi",
"com.eternalcode",
"org.bstats",
"org.yaml",
"panda.std",
"org.json.simple",
"org.bstats",
"org.json",
"com.eternalcode",
"eu.okaeri",
].each { lib ->
relocate(lib, "${prefix}.${lib}")
}
Expand Down
161 changes: 75 additions & 86 deletions src/main/java/com/github/imdmk/automessage/AutoMessage.java
Original file line number Diff line number Diff line change
@@ -1,136 +1,125 @@
package com.github.imdmk.automessage;

import com.github.imdmk.automessage.command.handler.MissingPermissionHandler;
import com.github.imdmk.automessage.command.handler.NotificationHandler;
import com.github.imdmk.automessage.command.handler.UsageHandler;
import com.github.imdmk.automessage.command.implementation.AutoMessageCreateCommand;
import com.github.imdmk.automessage.command.implementation.AutoMessageListCommand;
import com.github.imdmk.automessage.command.implementation.AutoMessageRemoveCommand;
import com.github.imdmk.automessage.command.implementation.AutoMessageStateCommand;
import com.github.imdmk.automessage.configuration.ConfigurationFactory;
import com.eternalcode.multification.notice.Notice;
import com.github.imdmk.automessage.configuration.ConfigurationManager;
import com.github.imdmk.automessage.configuration.implementation.PluginConfiguration;
import com.github.imdmk.automessage.notification.Notification;
import com.github.imdmk.automessage.notification.NotificationSender;
import com.github.imdmk.automessage.notification.NotificationType;
import com.github.imdmk.automessage.notification.argument.NotificationArgument;
import com.github.imdmk.automessage.notification.argument.NotificationTypeArgument;
import com.github.imdmk.automessage.notification.implementation.bossbar.argument.BossBarProgressArgument;
import com.github.imdmk.automessage.notification.implementation.bossbar.audience.BossBarAudienceManager;
import com.github.imdmk.automessage.notification.implementation.bossbar.audience.BossBarAudienceService;
import com.github.imdmk.automessage.notification.implementation.bossbar.audience.BossBarAudienceTask;
import com.github.imdmk.automessage.notification.task.AutoNotificationTask;
import com.github.imdmk.automessage.feature.command.builder.configuration.CommandConfiguration;
import com.github.imdmk.automessage.feature.command.builder.configuration.CommandConfigurator;
import com.github.imdmk.automessage.feature.command.builder.handler.MissingPermissionHandler;
import com.github.imdmk.automessage.feature.command.builder.handler.UsageHandler;
import com.github.imdmk.automessage.feature.command.builder.player.PlayerArgument;
import com.github.imdmk.automessage.feature.command.builder.player.PlayerContextual;
import com.github.imdmk.automessage.feature.command.implementation.DelayCommand;
import com.github.imdmk.automessage.feature.command.implementation.ReloadCommand;
import com.github.imdmk.automessage.feature.message.MessageConfiguration;
import com.github.imdmk.automessage.feature.message.MessageResultHandler;
import com.github.imdmk.automessage.feature.message.MessageService;
import com.github.imdmk.automessage.feature.message.auto.AutoMessageConfiguration;
import com.github.imdmk.automessage.feature.message.auto.dispatcher.AutoMessageDispatcher;
import com.github.imdmk.automessage.feature.update.UpdateController;
import com.github.imdmk.automessage.feature.update.UpdateService;
import com.github.imdmk.automessage.scheduler.BukkitTaskScheduler;
import com.github.imdmk.automessage.scheduler.TaskScheduler;
import com.github.imdmk.automessage.scheduler.TaskSchedulerImpl;
import com.github.imdmk.automessage.update.UpdateListener;
import com.github.imdmk.automessage.update.UpdateService;
import com.github.imdmk.automessage.util.DurationUtil;
import com.google.common.base.Stopwatch;
import dev.rollczi.litecommands.LiteCommands;
import dev.rollczi.litecommands.bukkit.adventure.platform.LiteBukkitAdventurePlatformFactory;
import dev.rollczi.litecommands.bukkit.tools.BukkitOnlyPlayerContextual;
import dev.rollczi.litecommands.bukkit.tools.BukkitPlayerArgument;
import dev.rollczi.litecommands.bukkit.LiteBukkitFactory;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bstats.bukkit.Metrics;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;

import java.io.File;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import java.util.stream.Stream;

public class AutoMessage {
/**
* Core plugin initializer responsible for setting up configuration,
* services, commands, schedulers, and external integrations.
*/
class AutoMessage {

private final Server server;
private final Logger logger;

private final PluginConfiguration pluginConfiguration;
private final ConfigurationManager configurationManager;

private final BukkitAudiences bukkitAudiences;
private final NotificationSender notificationSender;
private final MessageService messageService;

private LiteCommands<CommandSender> liteCommands;
private final TaskScheduler taskScheduler;

private final LiteCommands<CommandSender> liteCommands;

private final Metrics metrics;

public AutoMessage(Plugin plugin) {
AutoMessage(Plugin plugin) {
Stopwatch stopwatch = Stopwatch.createStarted();

Logger logger = plugin.getLogger();
File dataFolder = plugin.getDataFolder();

this.server = plugin.getServer();
this.logger = plugin.getLogger();

/* Configuration */
this.pluginConfiguration = ConfigurationFactory.create(PluginConfiguration.class, new File(dataFolder, "configuration.yml"));
this.configurationManager = new ConfigurationManager(this.logger, plugin.getDataFolder());

/* Managers */
BossBarAudienceManager bossBarAudienceManager = new BossBarAudienceManager();
PluginConfiguration pluginConfiguration = this.configurationManager.create(PluginConfiguration.class);
MessageConfiguration messageConfiguration = this.configurationManager.create(MessageConfiguration.class);
AutoMessageConfiguration autoMessageConfiguration = this.configurationManager.create(AutoMessageConfiguration.class);
CommandConfiguration commandConfiguration = this.configurationManager.create(CommandConfiguration.class);

/* Services */
BossBarAudienceService bossBarAudienceService = new BossBarAudienceService(bossBarAudienceManager);
UpdateService updateService = new UpdateService(plugin.getDescription());
this.messageService = new MessageService(messageConfiguration, BukkitAudiences.create(plugin), MiniMessage.miniMessage());
UpdateService updateService = new UpdateService(pluginConfiguration, plugin.getDescription());

/* Adventure */
this.bukkitAudiences = BukkitAudiences.create(plugin);
this.notificationSender = new NotificationSender(this.bukkitAudiences);
/* Scheduler */
this.taskScheduler = new BukkitTaskScheduler(plugin, this.server);

/* Tasks */
TaskScheduler taskScheduler = new TaskSchedulerImpl(plugin, this.server);
/* Dispatcher */
AutoMessageDispatcher autoMessageDispatcher = new AutoMessageDispatcher(this.configurationManager, autoMessageConfiguration, this.messageService, this.taskScheduler);
autoMessageDispatcher.schedule();

taskScheduler.runTimerAsync(new AutoNotificationTask(this.pluginConfiguration, this.notificationSender, bossBarAudienceService), 0L, DurationUtil.toTicks(this.pluginConfiguration.autoMessagesDelay));
taskScheduler.runTimerAsync(new BossBarAudienceTask(bossBarAudienceManager, bossBarAudienceService), 0L, DurationUtil.toTicks(Duration.ofSeconds(1)));

/* Listeners */
/* Controllers */
Stream.of(
new UpdateListener(logger, this.pluginConfiguration, this.notificationSender, updateService, taskScheduler)
new UpdateController(this.logger, pluginConfiguration, this.messageService, updateService, this.taskScheduler)
).forEach(listener -> this.server.getPluginManager().registerEvents(listener, plugin));

/* Commands */
if (this.pluginConfiguration.commandSettings.autoMessageEnabled) {
this.liteCommands = this.registerLiteCommands();
}

/* Metrics */
this.metrics = new Metrics((JavaPlugin) plugin, 19487);

logger.info("Enabled plugin in " + stopwatch.stop().elapsed(TimeUnit.MILLISECONDS) + "ms.");
}
/* LiteCommands */
this.liteCommands = LiteBukkitFactory.builder("AutoMessage", plugin, this.server)
.argument(Player.class, new PlayerArgument(this.server, messageConfiguration))

public void onDisable() {
this.bukkitAudiences.close();
.context(Player.class, new PlayerContextual())
.result(Notice.class, new MessageResultHandler(this.messageService))

if (this.liteCommands != null) {
this.liteCommands.getPlatform().unregisterAll();
}
.missingPermission(new MissingPermissionHandler(this.messageService))
.invalidUsage(new UsageHandler(this.messageService))

this.metrics.shutdown();
}
.commands(
new DelayCommand(this.messageService, autoMessageDispatcher),
new ReloadCommand(this.logger, this.configurationManager, this.messageService)
)

private LiteCommands<CommandSender> registerLiteCommands() {
return LiteBukkitAdventurePlatformFactory.builder(this.server, "AutoMessage", false, this.bukkitAudiences, true)
.contextualBind(Player.class, new BukkitOnlyPlayerContextual<>("Command only for player"))
.editorGlobal(new CommandConfigurator(this.logger, commandConfiguration))

.argument(Player.class, new BukkitPlayerArgument<>(this.server, this.pluginConfiguration.notificationSettings.playerNotFound))
.argument(NotificationType.class, new NotificationTypeArgument(this.pluginConfiguration.notificationSettings))
.argument(Notification.class, new NotificationArgument(this.pluginConfiguration, this.pluginConfiguration.notificationSettings))
.build();

.argument(float.class, "bossBarProgress", new BossBarProgressArgument(this.pluginConfiguration.notificationSettings))
/* Metrics */
this.metrics = new Metrics(plugin, AutoMessagePlugin.METRICS_SERVICE_ID);

.invalidUsageHandler(new UsageHandler(this.pluginConfiguration.notificationSettings, this.notificationSender))
.permissionHandler(new MissingPermissionHandler(this.pluginConfiguration.notificationSettings, this.notificationSender))
.resultHandler(Notification.class, new NotificationHandler(this.notificationSender))
this.logger.info("Enabled plugin in " + stopwatch.elapsed(TimeUnit.MILLISECONDS) + "ms.");
}

.commandInstance(
new AutoMessageStateCommand(this.pluginConfiguration, this.pluginConfiguration.notificationSettings, this.notificationSender),
new AutoMessageCreateCommand(this.pluginConfiguration, this.pluginConfiguration.notificationSettings, this.notificationSender),
new AutoMessageListCommand(this.pluginConfiguration, this.pluginConfiguration.notificationSettings, this.notificationSender),
new AutoMessageRemoveCommand(this.pluginConfiguration, this.pluginConfiguration.notificationSettings, this.notificationSender)
)
/**
* Gracefully shuts down all plugin components and resources.
* Called during plugin disable.
*/
void disable() {
this.configurationManager.shutdown();
this.messageService.close();
this.liteCommands.unregister();
this.metrics.shutdown();
this.taskScheduler.shutdown();

.register();
this.logger.info("Successfully disabled plugin.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

public class AutoMessagePlugin extends JavaPlugin {

/** bStats Metrics service ID for reporting plugin statistics */
public static final int METRICS_SERVICE_ID = 19487;

private AutoMessage autoMessage;

@Override
Expand All @@ -13,6 +16,6 @@ public void onEnable() {

@Override
public void onDisable() {
this.autoMessage.onDisable();
this.autoMessage.disable();
}
}
Loading
Loading