Skip to content
Open
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
8 changes: 4 additions & 4 deletions .github/workflows/release-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v7
with:
ref: main

- name: Set up JDK 21
uses: actions/setup-java@v3
- name: Set up JDK 25
uses: actions/setup-java@v6
with:
distribution: 'adopt'
java-version: '21'
java-version: '25'

- name: Make gradlew executable
run: chmod +x ./gradlew
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]
Copyright [2024-2026] [SimpleCloud]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
138 changes: 84 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,60 +37,90 @@ Keep your staff informed about server state changes with real-time notifications

Here you can see the configuration file for the plugin. All possible options are explained in the comments.
```yaml
# The date format pattern the notify plugin uses.
# For more information, see the official Java documentation: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/text/SimpleDateFormat.html
date-format: dd.MM.yyyy HH:mm:ss

# Filter server states to notify about.
server-state-filter:
# server-state obviously sets the server state to filter for
- server-state: STARTING
# The message that is being sent to the permitted players goes here.
# Don't get irritated by the |- format, it's just a multiline string. You can also pass oneliners.
# Possible placeholders you can use here are:
# - <server_group>: The group name the server belongs to
# - <server_id>: The numerical id of the server
# - <server_uuid>: The UUID of the server
# - <server_state>: The state of the server after the update
# - <server_ip>: The IP that the server is running on
# - <server_port>: The port that the server is bound to
# - <online_players>: The amount of players currently online on the server
# - <max_players>: The maximum amount of players that can join the server
# - <server_update_date>: The date of the last update of the server
# - <server_create_date>: The date of the initial update (creation) of the server
message: |-
<color:#38bdf8><bold>⚡</bold></color> <hover:show_text:'<color:#38bdf8><bold>⚡</bold></color> Information of <server_group> <server_id>
<color:#a3a3a3>Timestamp:</color> <color:#38bdf8><server_update_date></color>
<color:#a3a3a3>State:</color> <color:#38bdf8><server_state></color>
<color:#a3a3a3>Server-IP:</color> <color:#38bdf8><server_ip></color>
<color:#a3a3a3>Port:</color> <color:#38bdf8><server_port></color>
<color:#a3a3a3>Players:</color> <color:#38bdf8><online_players>/<max_players></color>'><color:white>Server <server_group> <server_id></hover> updated its state to <color:#fbbf24><server_state></color>.
# Users will need this permission to receive the message. Leave it empty (just '') to allow everyone to receive it.
permission: notify.receive.state-changed.starting

# You can add more server states to filter like this:
- server-state: AVAILABLE
# To design your own messages, we recommend using the minimessage web-ui: https://webui.advntr.dev/
message: |-
<color:#38bdf8><bold>⚡</bold></color> <hover:show_text:'<color:#38bdf8><bold>⚡</bold></color> Information of <server_group> <server_id>
<color:#a3a3a3>Timestamp:</color> <color:#38bdf8><server_update_date></color>
<color:#a3a3a3>State:</color> <color:#38bdf8><server_state></color>
<color:#a3a3a3>Server-IP:</color> <color:#38bdf8><server_ip></color>
<color:#a3a3a3>Port:</color> <color:#38bdf8><server_port></color>
<color:#a3a3a3>Players:</color> <color:#38bdf8><online_players>/<max_players></color>'><color:white>Server <server_group> <server_id></hover> updated its state to <color:#fbbf24><server_state></color>.
# The default permission is notify.receive.state-changed.[server-state]
permission: notify.receive.state-changed.available

- server-state: STOPPING
message: |-
<color:#38bdf8><bold>⚡</bold></color> <hover:show_text:'<color:#38bdf8><bold>⚡</bold></color> Information of <server_group> <server_id>
<color:#a3a3a3>Timestamp:</color> <color:#38bdf8><server_update_date></color>
<color:#a3a3a3>State:</color> <color:#38bdf8><server_state></color>
<color:#a3a3a3>Server-IP:</color> <color:#38bdf8><server_ip></color>
<color:#a3a3a3>Port:</color> <color:#38bdf8><server_port></color>
<color:#a3a3a3>Players:</color> <color:#38bdf8><online_players>/<max_players></color>'><color:white>Server <server_group> <server_id></hover> updated its state to <color:#fbbf24><server_state></color>.
# Here you can see that everyone will receive the message, as the permission is empty.
permission: ''
version: 1

# ───────────────────────────────────────────────────────────────────────────────
# Format Settings
# ───────────────────────────────────────────────────────────────────────────────
format:
date: "dd.MM.yyyy HH:mm:ss"

# ───────────────────────────────────────────────────────────────────────────────
# Variables
# Reusable variables that can be used throughout the messages.
# Usage: <variable_name> will be replaced with the defined value.
# ───────────────────────────────────────────────────────────────────────────────
variables:
prefix: "<color:#0EA5E9><bold>⚡</bold></color>"

# ───────────────────────────────────────────────────────────────────────────────
# Command Messages
# ───────────────────────────────────────────────────────────────────────────────
command:
help:
title: "<prefix> <#0EA5E9>SimpleCloud Notify commands"
entry: "<#E2E8F0><command>"
empty: "<prefix> <#F59E0B>No notify commands are available for you."

usage:
invalid: "<prefix> <#DC2626>Use <#F8FAFC><command> <#DC2626>instead."
entry: "<#E2E8F0><command>"
invalid-state: "<prefix> <#DC2626>Use <#F8FAFC>enable <#DC2626>or <#F8FAFC>disable<#DC2626>."
invalid-toggle-value: "<prefix> <#DC2626>Use <#F8FAFC>true <#DC2626>or <#F8FAFC>false<#DC2626>."
missing-player: "<prefix> <#DC2626>Missing player <#F8FAFC><playername><#DC2626>."

permission:
denied: "<prefix> <#DC2626>You do not have permission to use this command."

notify:
enabled: "<prefix> <#A3E635>Server notifications are now <#F8FAFC>enabled<#A3E635>."
disabled: "<prefix> <#A3E635>Server notifications are now <#F8FAFC>disabled<#A3E635>."
already-enabled: "<prefix> <#F59E0B>Server notifications are already <#F8FAFC>enabled<#F59E0B>."
already-disabled: "<prefix> <#F59E0B>Server notifications are already <#F8FAFC>disabled<#F59E0B>."

set:
enabled: "<prefix> <#A3E635>Server notifications are now <#F8FAFC>enabled <#A3E635>for <white><head:<playername>:true> <#F8FAFC><displayname><#A3E635>."
disabled: "<prefix> <#A3E635>Server notifications are now <#F8FAFC>disabled <#A3E635>for <white><head:<playername>:true> <#F8FAFC><displayname><#A3E635>."
already-enabled: "<prefix> <#F59E0B>Server notifications are already <#F8FAFC>enabled <#F59E0B>for <white><head:<playername>:true> <#F8FAFC><displayname><#F59E0B>."
already-disabled: "<prefix> <#F59E0B>Server notifications are already <#F8FAFC>disabled <#F59E0B>for <white><head:<playername>:true> <#F8FAFC><displayname><#F59E0B>."

reload:
config:
success: "<prefix> <#A3E635>Notify configuration was reloaded."
failed: "<prefix> <#DC2626>Notify configuration could not be reloaded."

error:
player-not-found: "<prefix> <#DC2626>Player <#F8FAFC><playername> <#DC2626>was not found."
player-not-online: "<prefix> <#DC2626>Player <#F8FAFC><playername> <#DC2626>is not online."
only-players: "<prefix> <#DC2626>This command can only be used by players."
storage-unavailable: "<prefix> <#DC2626>Notify settings are currently unavailable."
internal: "<prefix> <#DC2626>An internal error occurred. Try again later."

# ───────────────────────────────────────────────────────────────────────────────
# Notifications
# Notification messages for different server and group states.
#
# NOTE: If you delete a state entry, the corresponding notification will not be sent.
# ───────────────────────────────────────────────────────────────────────────────
notifications:
hover:
server: |-
<#E2E8F0>Server information
<br><#94A3B8>Time<#475569>: <#E2E8F0><time>
<br><#94A3B8>State<#475569>: <#E2E8F0><state>
<br><#94A3B8>Address<#475569>: <#E2E8F0><ip>:<port>
<br><#94A3B8>Players<#475569>: <#E2E8F0><players>/<max>
group: |-
<#E2E8F0>Group information
<br><#94A3B8>Time<#475569>: <#E2E8F0><time>
server:
starting: "<prefix> <#0EA5E9>Server <hover:show_text:'<notifications.hover.server>'><#F8FAFC><server></hover> <#0EA5E9>is now <#F8FAFC>starting<#0EA5E9>."
available: "<prefix> <#A3E635>Server <hover:show_text:'<notifications.hover.server>'><#F8FAFC><server></hover> <#A3E635>is now <#F8FAFC>available<#A3E635>."
stopping: "<prefix> <#F59E0B>Server <hover:show_text:'<notifications.hover.server>'><#F8FAFC><server></hover> <#F59E0B>is now <#F8FAFC>stopping<#F59E0B>."
stopped: "<prefix> <#DC2626>Server <hover:show_text:'<notifications.hover.server>'><#F8FAFC><server></hover> <#DC2626>is now <#F8FAFC>stopped<#DC2626>."
group:
created: "<prefix> <#0EA5E9>Group <hover:show_text:'<notifications.hover.group>'><#F8FAFC><group></hover> <#0EA5E9>was created."
deleted: "<prefix> <#DC2626>Group <hover:show_text:'<notifications.hover.group>'><#F8FAFC><group></hover> <#DC2626>was deleted."
```

## Contributing
Expand Down
47 changes: 30 additions & 17 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion

plugins {
alias(libs.plugins.kotlin)
alias(libs.plugins.shadow)
}

val baseVersion = "0.0.6"
val baseVersion = "0.0.7"
val commitHash = System.getenv("COMMIT_HASH")
val snapshotversion = "${baseVersion}-dev.$commitHash"

allprojects {
group = "app.simplecloud.plugin.proxy"
group = "app.simplecloud.plugin"
version = if (commitHash != null) snapshotversion else baseVersion

repositories {
Expand All @@ -22,40 +23,52 @@ allprojects {
}

subprojects {
apply(plugin = "org.jetbrains.kotlin.jvm")
apply(plugin = "com.gradleup.shadow")
apply {
plugin("kotlin")
plugin("com.gradleup.shadow")
}

repositories {
mavenCentral()
maven("https://buf.build/gen/maven")
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://oss.sonatype.org/content/repositories/snapshots")
maven("https://repo.simplecloud.app/snapshots")
}
}

dependencies {
testImplementation(rootProject.libs.kotlin.test)
implementation(rootProject.libs.kotlinx.coroutines.core)
implementation(rootProject.libs.kotlin.jvm)
}

java {
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
}

kotlin {
jvmToolchain(21)
jvmToolchain(25)
compilerOptions {
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
jvmTarget = JvmTarget.JVM_25
languageVersion = KotlinVersion.KOTLIN_2_4
apiVersion = KotlinVersion.KOTLIN_2_4
}
}

tasks.named("shadowJar", ShadowJar::class) {
mergeServiceFiles()
archiveFileName.set("${project.name}.jar")
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(25))
}

tasks.test {
useJUnitPlatform()
}
}

tasks.shadowJar {
mergeServiceFiles()
archiveFileName.set("${project.name}.jar")
}

tasks.processResources {
filesMatching("plugin.yml") {
expand(
"version" to project.version
)
}
}

}
23 changes: 11 additions & 12 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
[versions]
kotlin = "2.2.20"
kotlinx-coroutines = "1.10.2"
kotlin = "2.4.10"
kotlinx-coroutines = "1.11.0"

shadow = "9.3.1"
kapt = "2.1.20"
minotaur = "2.8.10"
shadow = "9.5.1"
minotaur = "2.9.0"
blossom = "2.2.0"

simplecloud-api = "0.1.0-platform.29-dev.1776936118022-c717659"
simplecloud-plugin = "0.0.1-platform.1776615774559-382b07e"
simplecloud-api = "0.1.0-platform.40"
simplecloud-plugin = "0.0.1-platform.1778966459069-b1e45e2"

velocity = "3.5.0-SNAPSHOT"
velocity = "4.1.0-SNAPSHOT"
bungeecord-api = "1.21-R0.4"

adventure-api = "4.26.1"
adventure-api = "5.2.0"
adventure-platform-bungeecord = "4.4.1"

configurate = "4.2.0"
Expand All @@ -22,7 +22,6 @@ cloud-velocity = "2.0.0-beta.10"
cloud-bungeecord = "2.0.0-beta.10"

[libraries]
kotlin-jvm = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }

Expand All @@ -49,5 +48,5 @@ configurate = ["configurate-kotlin", "configurate-yaml"]
[plugins]
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }
kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kapt" }
minotaur = { id = "com.modrinth.minotaur", version.ref = "minotaur" }
minotaur = { id = "com.modrinth.minotaur", version.ref = "minotaur" }
blossom = { id = "net.kyori.blossom", version.ref = "blossom" }
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
1 change: 0 additions & 1 deletion notify-bungeecord/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ dependencies {
implementation(libs.adventure.platform.bungeecord)
implementation(libs.adventure.api)
implementation(libs.adventure.text.minimessage)

implementation(libs.cloud.bungeecord)
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,26 +1,47 @@
package app.simplecloud.plugin.notify.bungeecord

import app.simplecloud.plugin.notify.shared.CloudSender
import app.simplecloud.plugin.notify.bungeecord.command.BungeeCloudSender
import app.simplecloud.plugin.notify.bungeecord.listener.NotifyConnectionListener
import app.simplecloud.plugin.notify.shared.NotifyPlugin
import app.simplecloud.plugin.notify.shared.command.CloudSender
import net.kyori.adventure.platform.bungeecord.BungeeAudiences
import net.md_5.bungee.api.plugin.Plugin
import org.incendo.cloud.SenderMapper
import org.incendo.cloud.bungee.BungeeCommandManager
import org.incendo.cloud.execution.ExecutionCoordinator

class BungeeCordNotifyPlugin : Plugin() {

private val adventure = BungeeAudiences.create(this)

private var notify: NotifyPlugin? = null
private var notifyPlugin: NotifyPlugin? = null

override fun onEnable() {
notify = NotifyPlugin(dataFolder.toPath(), ::onlinePlayers)
val notify = NotifyPlugin(dataFolder.toPath(), ::onlinePlayers)
notify.start()
notify.registerCommands(createCommandManager())

notifyPlugin = notify
proxy.pluginManager.registerListener(this, NotifyConnectionListener(notify))
}

override fun onDisable() {
notify?.close()
notify = null
notifyPlugin?.close()
notifyPlugin = null
adventure.close()
}

private fun createCommandManager(): BungeeCommandManager<BungeeCloudSender> {
return BungeeCommandManager(
this,
ExecutionCoordinator.simpleCoordinator(),
SenderMapper.create(
{ source -> BungeeCloudSender(source, adventure) },
BungeeCloudSender::source
)
)
}

private fun onlinePlayers(): Iterable<CloudSender> {
return proxy.players.map { BungeeCloudSender(it, adventure) }
}
Expand Down
Loading