Compare commits

..
106 Commits
Author SHA1 Message Date
Jason Penilla 5f6e2789e2 release: Version 2.0.13 2023-06-27 21:40:49 -07:00
Jason Penilla add32b31e7 fabric: 1.20.1 2023-06-17 10:08:41 -07:00
Jason Penilla b2b2801907 2.0.13-SNAPSHOT 2023-05-07 14:52:36 -07:00
Jason Penilla c919c40a59 release: Version 2.0.12 2023-05-07 14:35:19 -07:00
Jason Penilla b3cc4bce5c Fix style and add remap=false to favicon codec mixin 2023-05-07 13:54:36 -07:00
Jason Penilla 6fdf75dd3d Update license headers 2023-05-07 13:50:04 -07:00
Jason Penilla a8c2b0f23e Improve Folia detection 2023-05-07 13:49:21 -07:00
Jason Penilla 0ee99d90f2 fabric: Bring back caching of encoded server icons 2023-05-07 13:47:58 -07:00
renovate[bot] 6623a5928e chore(deps): update dependency gradle to v8.1.1 2023-05-07 13:18:43 -07:00
Jason Penilla 6532c03706 Add error handler to future 2023-03-27 21:21:15 -07:00
Jason Penilla 0bf3bfba7f Add Folia support 2023-03-27 21:17:18 -07:00
Jason Penilla f7094e0a77 2.0.12-SNAPSHOT 2023-03-18 13:21:57 -07:00
Jason Penilla 563da7f255 release: Version 2.0.11 2023-03-18 13:03:56 -07:00
Jason Penilla 51e599838d build: Setup automatic Hangar and Modrinth publishing 2023-03-18 12:57:17 -07:00
Jason Penilla e4970016e4 fabric: Update fabric.mod.json 2023-03-18 10:26:25 -07:00
Jason Penilla 2a04d0b2c8 fabric: Adjust lifecycle listeners 2023-03-18 10:22:44 -07:00
Jason Penilla f8c6c2db6f fabric: Update for Minecraft 1.19.4 2023-03-18 10:11:33 -07:00
Jason Penilla 9e25b68d00 Build and dependency updates 2023-01-31 14:22:26 -07:00
Jason Penilla 96b7d12743 Update loom 2023-01-31 14:17:39 -07:00
Jason Penilla 328ad6cd39 Preload some stuff on bungee
Avoids misleading and annoying log spam
2023-01-31 14:07:27 -07:00
Jason Penilla c0ee968e5b 2.0.11-SNAPSHOT 2022-12-09 10:18:17 -07:00
Jason Penilla bc4d1e3cdd release: Version 2.0.10 2022-12-09 10:07:42 -07:00
Jason Penilla 2626ed4551 Update testing Paper 2022-12-09 10:06:57 -07:00
Jason Penilla a1f51db093 Update for Minecraft 1.19.3 2022-12-08 22:03:20 -07:00
Jason Penilla 59ab61825b Update actions 2022-12-08 22:02:47 -07:00
Jason Penilla 5d7f79ce8a Update gradle wrapper files 2022-11-25 10:31:32 -07:00
renovate[bot] a5145384f6 chore(deps): update dependency gradle to v7.6 2022-11-25 09:58:39 -07:00
Jason Penilla fba4066522 Rename uploaded artifact 2022-11-22 20:18:02 -07:00
Jason Penilla 3c9261a92d Update actions 2022-11-22 20:09:06 -07:00
Jason Penilla ab409537ac Update jupiter engine 2022-11-15 12:26:46 -07:00
Jason Penilla 98a5bba407 Update adventure-platform-fabric 2022-11-15 12:26:38 -07:00
Jason Penilla 87bec5315b build: Update run-paper, apply run-velocity and run-waterfall to respective platforms 2022-11-15 12:26:15 -07:00
Jason Penilla bf9d92150c build: Update loom 2022-09-01 18:50:49 -07:00
Jason Penilla 4cad4d461b Remove universal jar and add bukkit/bungee jar for spigot resources, also reorganize project directory structure 2022-08-28 13:41:48 -07:00
Jason Penilla fc7b78f7a8 2.0.10-SNAPSHOT 2022-08-26 15:17:38 -07:00
Jason Penilla 15cffc2d71 release: Version 2.0.9 2022-08-26 14:39:08 -07:00
Jason Penilla 28cb91a40c Bump fabric loader 2022-08-26 14:38:19 -07:00
Jason Penilla 4ab6567fd2 Make virtual hosts case-insensitive (fixes #115) 2022-08-26 14:35:34 -07:00
Jason Penilla bdac395c2d Bump dependencies 2022-08-26 14:16:37 -07:00
Jason Penilla ffb475f529 Update gradle wrapper 2022-08-26 14:14:58 -07:00
renovate[bot] d690104a9e chore(deps): update dependency gradle to v7.5.1 2022-08-05 18:52:06 -07:00
Jason Penilla efa0c69840 Handle Bukkit/Spigot throwing UnsupportedOperationException in setServerIcon for legacy pings
this change does not affect Paper users
2022-07-21 20:19:12 -07:00
renovate[bot] 369e387a39 chore(deps): update dependency gradle to v7.5 2022-07-14 16:15:21 -07:00
Jason Penilla 2f98e67a93 build: Don't apply indra publishing, we don't have anything to publish 2022-06-19 00:11:26 -07:00
Jason Penilla e2894e211c 2.0.9-SNAPSHOT 2022-06-19 00:09:44 -07:00
Jason Penilla 58ff03aa95 release: Version 2.0.8 2022-06-18 23:51:55 -07:00
Jason Penilla 4155249878 Dependency updates 2022-06-18 23:51:25 -07:00
Jason Penilla de0936c5d2 Update for Minecraft 1.19 2022-06-13 19:28:31 -07:00
Jason Penilla a8e5e910ee fabric: update loom to 0.12 2022-05-29 19:49:41 -07:00
Jason Penilla 0d48b46621 Update SpongeGradle 2022-05-07 13:08:42 -07:00
Jason Penilla 2a18bc156d 2.0.8-SNAPSHOT 2022-05-03 18:15:53 -07:00
Jason Penilla 0dd650dacb release: Version 2.0.7 2022-05-03 18:06:49 -07:00
Jason Penilla 624a97346d Dependency updates 2022-05-03 18:04:56 -07:00
Jason Penilla 3d4fdc1f53 Minor clean up 2022-05-03 18:04:37 -07:00
Jason Penilla 286f72f746 Dependency updates 2022-04-20 22:18:29 -07:00
Renovate Bot 0cc8d9a98d chore(deps): update dependency gradle to v7.4.2 2022-03-31 10:51:27 -07:00
Jason Penilla 80ae413c9d 2.0.7-SNAPSHOT 2022-03-12 12:03:08 -07:00
Jason Penilla 1a2ba16194 release: Version 2.0.6 2022-03-12 11:59:28 -07:00
Jason Penilla 8c0a9b6811 Move project metadata into gradle.properties 2022-03-12 11:59:06 -07:00
Jason Penilla 310e8e7e7a Update Adventure and remove no longer needed repo 2022-03-12 11:54:02 -07:00
Renovate Bot 45604e6bb3 chore(deps): update dependency gradle to v7.4.1 2022-03-09 10:38:19 -08:00
Jason Penilla ec8d81144b update license 2022-03-04 11:17:51 -07:00
Jason Penilla 48c1c09d79 bukkit: Use paperlib for version detection 2022-03-04 11:16:56 -07:00
Renovate Bot df89471fdd chore(deps): update actions/upload-artifact action to v3 2022-03-03 14:13:35 -07:00
Jason Penilla d2e0bba539 Update Adventure & Initial update for Minecraft 1.18.2 2022-03-02 22:35:46 -07:00
Renovate Bot e715f3bb57 chore(deps): update actions/checkout action to v3 2022-03-01 13:45:10 -07:00
Renovate Bot bd774480b3 chore(deps): update actions/setup-java action to v3 2022-02-27 23:10:53 -07:00
Jason Penilla d91ea43aa8 Build updates 2022-02-27 23:10:22 -07:00
Jason Penilla 3bf3796ce2 Build updates 2022-02-08 11:53:31 -07:00
Jason Penilla 34e819abf4 Update checker framework 2022-01-27 14:30:59 -07:00
Jason Penilla 799dd82b4f Update loom 2022-01-27 14:30:47 -07:00
Jason Penilla 67d4a12546 update actions 2022-01-11 00:25:40 -07:00
Jason Penilla 06543a2c45 dependency updates 2022-01-11 00:22:38 -07:00
Renovate Bot acf9056f5b chore(deps): update dependency gradle to v7.3.3 2021-12-22 15:17:13 -08:00
Jason Penilla ae3fefb54d 2.0.6-SNAPSHOT 2021-12-02 01:50:32 -08:00
Jason Penilla bcfe67fc6f release: Version 2.0.5 2021-12-02 01:39:21 -08:00
Jason Penilla 10775836cb Update gradle wrapper 2021-12-01 21:33:45 -08:00
Jason Penilla 3a07128bd0 Update adventure-platform 2021-12-01 21:10:22 -08:00
Jason Penilla 336d613274 velocity: Use new event api 2021-12-01 02:16:34 -08:00
Jason Penilla a742fd9b62 fabric: Use release adventure-platform 2021-12-01 01:38:51 -08:00
Jason Penilla 577a77951a fabric: Bump java target 2021-12-01 01:34:06 -08:00
Jason Penilla f8456bec5c fabric: Build against 1.18 release 2021-12-01 01:30:50 -08:00
Jason Penilla b086550eae bukkit: Test on 1.18 2021-12-01 01:30:19 -08:00
Jason Penilla f512ca6174 Update loom 2021-11-14 00:27:08 -08:00
Jason Penilla 82b3a35a9e Update gradle wrapper and dependencies 2021-11-09 15:46:08 -08:00
Jason Penilla 5f4e8efa45 Enable build cache 2021-10-13 23:51:52 -07:00
Jason Penilla 22a47511a2 Use minimotd instead of minimotd-sponge7 and minimotd-sponge8 for Sponge platform plugin ids. 2021-10-13 23:51:24 -07:00
Jason Penilla 972ac8fcc5 Update shadow, adventure, junit 2021-10-09 15:01:34 -07:00
Jason Penilla c7f2d5f33b Improve Sponge 8 legacy check 2021-09-26 12:45:23 -07:00
Jason Penilla 2bc4a4caac Update for MiniMessage changes 2021-09-26 12:10:48 -07:00
Jason Penilla 3577d67820 fabric: Require >=1.17 2021-09-26 11:26:45 -07:00
Jason Penilla 9392601232 Simplify Components#ofChildren 2021-09-26 11:04:56 -07:00
Jason Penilla e4071d390c Update dependencies 2021-09-17 21:55:27 -07:00
Jason Penilla c4ca735e8b build: Update Gradle wrapper to 7.2 2021-08-27 09:33:36 -07:00
Jason Penilla 42ccd182b0 build: Update plugin-yml and run-paper 2021-08-27 09:33:13 -07:00
Jason Penilla 99e7954612 Improve handling of malformed config files 2021-08-12 03:38:42 -07:00
Jason Penilla bcf2589eb0 2.0.5-SNAPSHOT 2021-08-10 15:46:53 -07:00
Jason Penilla fe41b21d9b release: Version 2.0.4 2021-08-10 15:40:03 -07:00
Jason Penilla cbbe201710 Minor clean up 2021-08-10 15:14:12 -07:00
Jason Penilla 30d58fc0f9 2.0.4-SNAPSHOT 2021-07-30 14:45:43 -07:00
Jason Penilla 067ec4ea65 Build and test against 1.17.1 2021-07-23 23:51:06 -07:00
Jason Penilla 22f805f4ab build: Update Gradle & Indra 2021-07-23 23:50:36 -07:00
Jason Penilla ed21f45573 fabric: Use quiet-fabric-loom 2021-07-23 23:50:36 -07:00
Jason Penilla 41b1fdffe3 sponge 8: Update for Sponge API changes 2021-07-23 23:50:36 -07:00
Jason Penilla 142f7a34f7 Remove final from virtualHostTestMode field
This was not meant to be final in the first place, however this also was causing the config to silently fail to deserialize.
2021-07-13 22:53:59 -07:00
Jason Penilla ed7fe3591b Update Velocity API dependency to 3.0.0 2021-07-06 02:34:09 -07:00
75 changed files with 1058 additions and 494 deletions

No files matched your search

+19
View File
@@ -0,0 +1,19 @@
name: "build"
on:
push:
branches: [ "**" ]
tags-ignore: [ "**" ]
pull_request:
release:
types: [ released ]
jobs:
call-build:
uses: "jpenilla/actions/.github/workflows/shared-ci.yml@master"
secrets: inherit
with:
artifacts-path: 'build/libs/*.jar'
modrinth-publish: true
hangar-publish: true
loom: true
-22
View File
@@ -1,22 +0,0 @@
name: Build MiniMOTD
on: [ push, pull_request ]
jobs:
build:
# Only run on PRs if the source branch is on someone else's repo
if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: gradle/wrapper-validation-action@v1
- name: Set up JDK
uses: actions/setup-java@v2
with:
distribution: 'adopt'
java-version: '16'
- name: Build with Gradle
run: ./gradlew build
- run: mkdir staging && cp build/libs/*.jar staging
- uses: actions/upload-artifact@v2
with:
name: Package
path: staging
+4 -1
View File
@@ -8,8 +8,11 @@ repositories {
dependencies {
implementation(libs.indraCommon)
implementation(libs.indraLicenser)
implementation(libs.shadow)
implementation(libs.testLoggerPlugin)
implementation(libs.testLogger)
implementation(libs.minotaur)
implementation(libs.hangarPublishPlugin)
// https://github.com/gradle/gradle/issues/15383#issuecomment-779893192
implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location))
+1 -3
View File
@@ -1,10 +1,8 @@
import ca.stellardrift.build.configurate.ConfigFormats
import ca.stellardrift.build.configurate.catalog.PolyglotVersionCatalogExtension
enableFeaturePreview("VERSION_CATALOGS")
plugins {
id("ca.stellardrift.polyglot-version-catalogs") version "5.0.0"
id("ca.stellardrift.polyglot-version-catalogs") version "6.0.1"
}
extensions.configure<PolyglotVersionCatalogExtension> {
-10
View File
@@ -1,10 +0,0 @@
import net.kyori.indra.git.IndraGitExtension
import org.gradle.accessors.dm.LibrariesForLibs
import org.gradle.api.Project
import org.gradle.kotlin.dsl.the
fun Project.lastCommitHash(): String =
the<IndraGitExtension>().commit()?.name?.substring(0, 7) ?: "unknown"
val Project.libs: LibrariesForLibs
get() = the()
+6 -5
View File
@@ -1,17 +1,18 @@
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
abstract class FileCopyTask : DefaultTask() {
@InputFile
val fileToCopy = project.objects.fileProperty()
@get:InputFile
abstract val fileToCopy: RegularFileProperty
@OutputFile
val destination = project.objects.fileProperty()
@get:OutputFile
abstract val destination: RegularFileProperty
@TaskAction
private fun copyFile() {
fun copyFile() {
destination.get().asFile.parentFile.mkdirs()
fileToCopy.get().asFile.copyTo(destination.get().asFile, overwrite = true)
}
@@ -1,8 +1,7 @@
import org.gradle.api.Project
import org.gradle.api.provider.Property
import org.gradle.api.tasks.bundling.AbstractArchiveTask
import org.gradle.kotlin.dsl.property
open class MiniMOTDPlatformExtension(private val project: Project) {
val jarTask: Property<AbstractArchiveTask> = project.objects.property()
interface MiniMOTDPlatformExtension {
val jarTask: Property<AbstractArchiveTask>
val hangar: Property<Boolean>
}
+33
View File
@@ -0,0 +1,33 @@
import net.kyori.indra.git.IndraGitExtension
import org.gradle.accessors.dm.LibrariesForLibs
import org.gradle.api.Project
import org.gradle.api.provider.Provider
import org.gradle.kotlin.dsl.the
fun Project.lastCommitHash(): String =
the<IndraGitExtension>().commit()?.name?.substring(0, 7) ?: "unknown"
val Project.libs: LibrariesForLibs
get() = the()
val Project.releaseNotes: Provider<String>
get() = providers.environmentVariable("RELEASE_NOTES")
val Project.minecraftVersion
get() = libs.versions.minecraft.get()
val bukkitVersions = listOf(
"1.8.8",
"1.8.9",
"1.9.4",
"1.10.2",
"1.11.2",
"1.12.2",
"1.13.2",
"1.14.4",
"1.15.2",
"1.16.5",
"1.17.1",
"1.18.2",
"1.19.4"
)
@@ -3,7 +3,7 @@ import com.adarshr.gradle.testlogger.theme.ThemeType
plugins {
id("java-library")
id("net.kyori.indra")
id("net.kyori.indra.publishing")
id("net.kyori.indra.git")
id("net.kyori.indra.checkstyle")
id("net.kyori.indra.license-header")
id("com.adarshr.test-logger")
@@ -14,6 +14,7 @@ version = (version as String)
indra {
javaVersions {
minimumToolchain(17)
target(8)
}
github(Constants.GITHUB_USER, Constants.GITHUB_REPO)
@@ -1,3 +1,35 @@
import io.papermc.hangarpublishplugin.model.Platforms
plugins {
id("base")
base
id("io.papermc.hangar-publish-plugin")
}
fun jar(platform: String) = project(":minimotd-$platform")
.the<MiniMOTDPlatformExtension>().jarTask.flatMap { it.archiveFile }
hangarPublish.publications.register("plugin") {
version.set(project.version as String)
namespace("jmp", "MiniMOTD")
channel.set("Release")
changelog.set(releaseNotes)
apiKey.set(providers.environmentVariable("HANGAR_UPLOAD_KEY"))
platforms {
register(Platforms.PAPER) {
jar.set(jar("bukkit"))
val vers = bukkitVersions.toMutableList()
vers -= "1.8.8"
vers -= "1.8.9"
vers += "1.8"
platformVersions.addAll(vers)
}
register(Platforms.VELOCITY) {
jar.set(jar("velocity"))
platformVersions.addAll("3.2")
}
register(Platforms.WATERFALL) {
jar.set(jar("bungeecord"))
platformVersions.addAll("1.19")
}
}
}
@@ -1,9 +1,11 @@
import com.modrinth.minotaur.ModrinthExtension
plugins {
id("minimotd.base-conventions")
id("net.kyori.indra.git")
}
val platformExtension = extensions.create<MiniMOTDPlatformExtension>("miniMOTDPlatform", project)
val platformExtension = extensions.create<MiniMOTDPlatformExtension>("miniMOTDPlatform")
tasks {
val copyJar = register<FileCopyTask>("copyJar") {
@@ -16,3 +18,15 @@ tasks {
dependsOn(copyJar)
}
}
if (name != "minimotd-bukkit-bungeecord") {
plugins.apply("com.modrinth.minotaur")
the<ModrinthExtension>().apply {
projectId.set("16vhQOQN")
versionType.set("release")
file.set(platformExtension.jarTask.flatMap { it.archiveFile })
changelog.set(releaseNotes)
token.set(providers.environmentVariable("MODRINTH_TOKEN"))
}
}
@@ -14,5 +14,5 @@ tasks {
}
extensions.configure<MiniMOTDPlatformExtension> {
jarTask.set(tasks.named<AbstractArchiveTask>("shadowJar"))
jarTask.set(tasks.shadowJar)
}
@@ -1,4 +1,3 @@
import com.github.jengelman.gradle.plugins.shadow.internal.DependencyFilter
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
fun ShadowJar.commonRelocation(pkg: String) {
@@ -9,13 +8,6 @@ fun ShadowJar.platformRelocation(platform: String, pkg: String) {
relocate(pkg, "${Constants.RELOCATION_BASE_PACKAGE}.platform_$platform.$pkg")
}
fun ShadowJar.configureForNativeAdventurePlatform() {
platformRelocation("kyori", "net.kyori.adventure.text.minimessage")
dependencies {
excludeAdventureExceptMiniMessage()
}
}
fun ShadowJar.commonConfiguration() {
commonRelocation("org.spongepowered.configurate")
commonRelocation("com.typesafe.config")
@@ -25,9 +17,8 @@ fun ShadowJar.commonConfiguration() {
}
}
private fun DependencyFilter.excludeAdventureExceptMiniMessage() {
exclude { dependency ->
dependency.moduleGroup == "net.kyori"
&& dependency.moduleName != "adventure-text-minimessage"
fun ShadowJar.configureForNativeAdventurePlatform() {
dependencies {
exclude { dependency -> dependency.moduleGroup == "net.kyori" }
}
}
-4
View File
@@ -1,7 +1,3 @@
plugins {
id("minimotd.build-logic")
}
group = "xyz.jpenilla"
version = "2.0.3"
description = "Use MiniMessage text formatting in the server list MOTD."
-44
View File
@@ -1,44 +0,0 @@
plugins {
id("minimotd.shadow-platform")
id("net.minecrell.plugin-yml.bukkit")
id("xyz.jpenilla.run-paper")
}
dependencies {
implementation(projects.minimotdCommon)
implementation(libs.slf4jJdk14)
implementation(libs.adventurePlatformBukkit)
implementation(libs.bstatsBukkit)
compileOnly(libs.paperApi)
}
tasks {
runServer {
minecraftVersion("1.17")
}
generateBukkitPluginDescription {
mustRunAfter(clean)
}
shadowJar {
commonRelocation("org.slf4j")
commonRelocation("io.leangen.geantyref")
commonRelocation("net.kyori")
commonRelocation("org.bstats")
}
}
bukkit {
name = rootProject.name
main = "xyz.jpenilla.minimotd.bukkit.MiniMOTDPlugin"
apiVersion = "1.13"
website = Constants.GITHUB_URL
authors = listOf("jmp")
softDepend = listOf("ViaVersion")
commands {
create("minimotd") {
description = "MiniMOTD Command"
usage = "/minimotd help"
permission = "minimotd.admin"
}
}
}
+1 -1
View File
@@ -10,7 +10,6 @@ tasks.jar {
}
dependencies {
api(libs.slf4jApi)
api(libs.configurateHocon)
api(platform(libs.adventureBom))
api(libs.adventureApi)
@@ -19,6 +18,7 @@ dependencies {
exclude("com.google.code.gson", "gson")
}
api(libs.minimessage)
compileOnlyApi(libs.slf4jApi)
compileOnlyApi(libs.checkerQual)
compileOnlyApi(libs.gson)
testImplementation(libs.gson)
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,10 +26,10 @@ package xyz.jpenilla.minimotd.common;
import java.util.stream.Stream;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.framework.qual.DefaultQualifier;
import xyz.jpenilla.minimotd.common.util.Components;
import static net.kyori.adventure.text.Component.space;
import static net.kyori.adventure.text.Component.text;
@@ -38,6 +38,7 @@ import static net.kyori.adventure.text.event.ClickEvent.openUrl;
import static net.kyori.adventure.text.event.ClickEvent.runCommand;
import static net.kyori.adventure.text.format.NamedTextColor.GRAY;
import static net.kyori.adventure.text.format.NamedTextColor.GREEN;
import static net.kyori.adventure.text.format.NamedTextColor.RED;
import static net.kyori.adventure.text.format.NamedTextColor.WHITE;
import static net.kyori.adventure.text.format.TextColor.color;
import static net.kyori.adventure.text.format.TextDecoration.STRIKETHROUGH;
@@ -72,8 +73,19 @@ public final class CommandHandler {
}
public void reload(final Audience audience) {
this.miniMOTD.reload();
audience.sendMessage(TextComponent.ofChildren(
try {
this.miniMOTD.reload();
} catch (final Exception ex) {
this.miniMOTD.logger().warn("Failed to reload MiniMOTD. Ensure there are no errors in your config files.", ex);
audience.sendMessage(Components.ofChildren(
Constants.COMMAND_PREFIX,
space(),
text("Failed to reload MiniMOTD. Ensure there are no errors in your config files. See console for more details.", RED)
));
return;
}
audience.sendMessage(Components.ofChildren(
Constants.COMMAND_PREFIX,
space(),
text("Done reloading configuration.", GREEN)
@@ -109,7 +121,7 @@ public final class CommandHandler {
}
private static Component miniMessage(final String message) {
return MiniMessage.get().parse(message);
return MiniMessage.miniMessage().deserialize(message);
}
@FunctionalInterface
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -44,5 +44,5 @@ public final class Constants {
public static final int MINECRAFT_1_16_PROTOCOL_VERSION = 735;
public static final Component COMMAND_PREFIX = MiniMessage.get().parse("<white>[</white><gradient:#0047AB:#ADD8E6>" + PluginMetadata.NAME + "<white>]</white>");
public static final Component COMMAND_PREFIX = MiniMessage.miniMessage().deserialize("<white>[</white><gradient:#0047AB:#ADD8E6>" + PluginMetadata.NAME + "</gradient><white>]</white>");
}
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -28,9 +28,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Stream;
import javax.imageio.ImageIO;
@@ -38,7 +38,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class IconManager<I> {
private final Map<String, I> icons = new HashMap<>();
private final Map<String, I> icons = new ConcurrentHashMap<>();
private final MiniMOTD<I> miniMOTD;
private final Path iconsDirectory;
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,14 +26,16 @@ package xyz.jpenilla.minimotd.common;
import java.nio.file.Path;
import java.util.concurrent.ThreadLocalRandom;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.framework.qual.DefaultQualifier;
import org.slf4j.Logger;
import xyz.jpenilla.minimotd.common.config.ConfigManager;
import xyz.jpenilla.minimotd.common.config.MiniMOTDConfig;
import xyz.jpenilla.minimotd.common.util.Components;
import static net.kyori.adventure.text.Component.newline;
@@ -45,32 +47,37 @@ public final class MiniMOTD<I> {
public MiniMOTD(final MiniMOTDPlatform<I> platform) {
this.platform = platform;
this.iconManager = new IconManager<>(this);
this.configManager = new ConfigManager(this);
this.configManager.loadConfigs();
try {
this.iconManager = new IconManager<>(this);
this.configManager = new ConfigManager(this);
this.configManager.loadConfigs();
} catch (final Exception ex) {
throw new IllegalStateException("Failed to load MiniMOTD. Ensure your config files are without errors.", ex);
}
}
public MiniMOTDPlatform<I> platform() {
return this.platform;
}
public final Path dataDirectory() {
public Path dataDirectory() {
return this.platform.dataDirectory();
}
public final IconManager<I> iconManager() {
public IconManager<I> iconManager() {
return this.iconManager;
}
public final Logger logger() {
public Logger logger() {
return this.platform.logger();
}
public final ConfigManager configManager() {
public ConfigManager configManager() {
return this.configManager;
}
public final PingResponse<I> createMOTD(final MiniMOTDConfig config, final int onlinePlayers, final int maxPlayers) {
public PingResponse<I> createMOTD(final MiniMOTDConfig config, final int onlinePlayers, final int maxPlayers) {
final PingResponse.PlayerCount count = config.modifyPlayerCount(onlinePlayers, maxPlayers);
final PingResponse.Builder<I> response = PingResponse.<I>builder()
.playerCount(count)
@@ -84,7 +91,7 @@ public final class MiniMOTD<I> {
}
final int index = config.motds().size() == 1 ? 0 : ThreadLocalRandom.current().nextInt(config.motds().size());
final MiniMOTDConfig.MOTD motdConfig = config.motds().get(index);
final Component motd = TextComponent.ofChildren(
final Component motd = Components.ofChildren(
parse(motdConfig.line1(), count),
newline(),
parse(motdConfig.line2(), count)
@@ -103,10 +110,9 @@ public final class MiniMOTD<I> {
private static Component parse(final String input, final PingResponse.PlayerCount count) {
final String online = Integer.toString(count.onlinePlayers());
final String max = Integer.toString(count.maxPlayers());
return MiniMessage.get().parse(
return MiniMessage.miniMessage().deserialize(
replacePlayerCount(input, online, max),
"online_players", online,
"max_players", max
TagResolver.resolver(Placeholder.unparsed("online_players", online), Placeholder.unparsed("max_players", max))
);
}
@@ -114,7 +120,7 @@ public final class MiniMOTD<I> {
return input.replace("{onlinePlayers}", online).replace("{maxPlayers}", max);
}
public void reload() {
public synchronized void reload() {
this.iconManager.loadIcons();
this.configManager.loadConfigs();
this.platform.onReload();
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -60,7 +60,7 @@ public final class PingResponse<I> {
/**
* If {@link #icon()} is non-null, the provided {@link Consumer} will be called using
* it's return value. If {@link #icon()} is {@code null}, do nothing.
* its return value. If {@link #icon()} is {@code null}, do nothing.
*
* @param iconConsumer icon consumer
*/
@@ -76,7 +76,7 @@ public final class PingResponse<I> {
/**
* If {@link #motd()} is non-null, the provided {@link Consumer} will be called using
* it's return value. If {@link #motd()} is {@code null}, do nothing.
* its return value. If {@link #motd()} is {@code null}, do nothing.
*
* @param motdConsumer motd consumer
*/
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,9 +23,14 @@
*/
package xyz.jpenilla.minimotd.common.config;
import java.lang.reflect.Method;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.UnaryOperator;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.framework.qual.DefaultQualifier;
import org.spongepowered.configurate.CommentedConfigurationNode;
import org.spongepowered.configurate.ConfigurateException;
import org.spongepowered.configurate.ConfigurationOptions;
@@ -34,27 +39,31 @@ import org.spongepowered.configurate.objectmapping.ObjectMapper;
import org.spongepowered.configurate.serialize.SerializationException;
import org.spongepowered.configurate.serialize.TypeSerializerCollection;
@DefaultQualifier(NonNull.class)
public final class ConfigLoader<C> {
private static final TypeSerializerCollection SERIALIZERS;
static {
SERIALIZERS = TypeSerializerCollection.defaults()
.childBuilder()
SERIALIZERS = TypeSerializerCollection.builder()
.register(PlayerCountModifier.serializer())
.build();
}
private final HoconConfigurationLoader loader;
private final ObjectMapper<C> mapper;
private final List<Consumer<C>> postProcess;
public ConfigLoader(
final @NonNull Class<C> configClass,
final @NonNull Path configPath,
final @NonNull ConfigurationOptions options
final Class<C> configClass,
final Path configPath,
final UnaryOperator<ConfigurationOptions> optionsModifier
) {
this.postProcess = this.findPostProcessors(configClass);
this.loader = HoconConfigurationLoader.builder()
.path(configPath)
.defaultOptions(options.serializers(SERIALIZERS))
.defaultOptions(options ->
optionsModifier.apply(options)
.serializers(builder -> builder.registerAll(SERIALIZERS)))
.build();
try {
this.mapper = ObjectMapper.factory().get(configClass);
@@ -66,24 +75,38 @@ public final class ConfigLoader<C> {
}
}
public ConfigLoader(
final @NonNull Class<C> configClass,
final @NonNull Path configPath,
final @NonNull UnaryOperator<ConfigurationOptions> options
) {
this(configClass, configPath, options.apply(ConfigurationOptions.defaults()));
private List<Consumer<C>> findPostProcessors(final Class<C> configClass) {
final List<Consumer<C>> ret = new ArrayList<>();
for (final Method method : configClass.getDeclaredMethods()) {
if (method.getAnnotation(PostProcessor.class) == null) {
continue;
}
ret.add(config -> {
try {
method.setAccessible(true);
method.invoke(config);
} catch (final ReflectiveOperationException ex) {
throw new RuntimeException("Failed to invoke post processor method", ex);
}
});
}
return ret;
}
public ConfigLoader(
final @NonNull Class<C> configClass,
final @NonNull Path configPath
) {
this(configClass, configPath, ConfigurationOptions.defaults());
this(configClass, configPath, options -> options);
}
public @NonNull C load() throws ConfigurateException {
final CommentedConfigurationNode node = this.loader.load();
return this.mapper.load(node);
final C config = this.mapper.load(node);
for (final Consumer<C> processor : this.postProcess) {
processor.accept(config);
}
return config;
}
public void save(final @NonNull C config) throws ConfigurateException {
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -49,7 +49,7 @@ public final class MiniMOTDConfig {
@Comment("The list of MOTDs to display\n"
+ "\n"
+ " - Supported placeholders: {onlinePlayers}, {maxPlayers}\n"
+ " - Supported placeholders: <online_players>, <max_players>\n"
+ " - Putting more than one will cause one to be randomly chosen each refresh")
private final List<MOTD> motds = new ArrayList<>();
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -46,7 +46,7 @@ public final class PlayerCountModifier implements Int2IntFunction {
return this.function.apply(actualPlayers);
}
public final @NonNull String input() {
public @NonNull String input() {
return this.input;
}
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,6 +24,7 @@
package xyz.jpenilla.minimotd.common.config;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -57,14 +58,14 @@ public final class PluginSettings {
@Comment("Set whether to enable virtual host testing mode.\n"
+ "When enabled, MiniMOTD will print virtual host debug info to the console on each server ping.")
private final boolean virtualHostTestMode = false;
private boolean virtualHostTestMode = false;
public boolean virtualHostTestMode() {
return this.virtualHostTestMode;
}
public @Nullable String findConfigStringForHost(final @NonNull String host) {
return this.virtualHostConfigs.get(host);
return this.virtualHostConfigs.get(host.toLowerCase(Locale.ENGLISH));
}
}
@@ -76,4 +77,10 @@ public final class PluginSettings {
return this.updateChecker;
}
@PostProcessor
private void lowercaseVirtualHosts() {
final Map<String, String> virtualHosts = new HashMap<>(this.proxySettings.virtualHostConfigs);
this.proxySettings.virtualHostConfigs.clear();
virtualHosts.forEach((host, config) -> this.proxySettings.virtualHostConfigs.put(host.toLowerCase(Locale.ENGLISH), config));
}
}
@@ -0,0 +1,34 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package xyz.jpenilla.minimotd.common.config;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PostProcessor {
}
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,47 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package xyz.jpenilla.minimotd.common.util;
import net.kyori.adventure.text.ComponentLike;
import net.kyori.adventure.text.TextComponent;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.framework.qual.DefaultQualifier;
import static net.kyori.adventure.text.Component.empty;
import static net.kyori.adventure.text.Component.text;
@DefaultQualifier(NonNull.class)
public final class Components {
private Components() {
throw new IllegalStateException();
}
public static TextComponent ofChildren(final ComponentLike... children) {
if (children.length == 0) {
return empty();
}
return text().append(children).build();
}
}
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,7 +24,6 @@
package xyz.jpenilla.minimotd.common.util;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.TextColor;
import org.junit.jupiter.api.Test;
@@ -42,14 +41,14 @@ class ComponentColorDownsamplerTest {
@Test
void testColorDownsampling() {
final Component fullColor = TextComponent.ofChildren(
final Component fullColor = Components.ofChildren(
text("Green ", GREEN),
text("Orange Yellow ", ORANGE_YELLOW),
text("Pink ", PINK),
text("Blue ", BLUE),
text("Lime Green", LIME_GREEN)
);
final Component expectedDownsample = TextComponent.ofChildren(
final Component expectedDownsample = Components.ofChildren(
text("Green ", nearestTo(GREEN)),
text("Orange Yellow ", nearestTo(ORANGE_YELLOW)),
text("Pink ", nearestTo(PINK)),
@@ -9,13 +9,9 @@ tasks.jar {
val platforms = setOf(
projects.minimotdBukkit,
projects.minimotdBungeecord,
projects.minimotdVelocity,
projects.minimotdFabric,
projects.minimotdSponge7,
//projects.minimotdSponge8
).map { it.dependencyProject }
val universal = tasks.register<Jar>("universal") {
val dist = tasks.register<Jar>("bukkitAndBungeeJar") {
artifacts.add("archives", this)
archiveClassifier.set(null as String?)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
@@ -23,10 +19,9 @@ val universal = tasks.register<Jar>("universal") {
for (platform in platforms) {
val jarTask = platform.miniMOTDPlatform.jarTask
from(zipTree(jarTask.flatMap { it.archiveFile }))
dependsOn(jarTask) // todo: remove when updating Gradle to 7.1 (https://github.com/gradle/gradle/issues/15569)
}
}
miniMOTDPlatform {
jarTask.set(universal)
jarTask.set(dist)
}
+5
View File
@@ -1,3 +1,8 @@
group=xyz.jpenilla
version=2.0.13
description=Use MiniMessage text formatting in the server list MOTD.
org.gradle.caching=true
org.gradle.configureondemand=true
org.gradle.jvmargs=-Xmx2G
org.gradle.parallel=true
+43 -30
View File
@@ -5,34 +5,36 @@ metadata:
plugins:
net.kyori.blossom: 1.3.0
org.spongepowered.gradle.plugin: 1.1.1
net.minecrell.plugin-yml.bungee: &plugin-yml 0.4.0
net.minecrell.plugin-yml.bukkit: *plugin-yml
xyz.jpenilla.run-paper: 1.0.3
org.spongepowered.gradle.plugin: 2.1.1
net.minecrell.plugin-yml.bungee: 0.5.3
xyz.jpenilla.run-paper: &run-task 2.1.0
xyz.jpenilla.run-velocity: *run-task
xyz.jpenilla.run-waterfall: *run-task
versions:
indra: 2.0.5
shadow: 7.0.0
testLoggerPlugin: 3.0.0
adventure: 4.8.1
adventurePlatform: 4.0.0-SNAPSHOT
adventurePlatformFabric: 4.1.0-SNAPSHOT
minimessage: 4.2.0-SNAPSHOT
configurate: 4.1.1
checkerQual: 3.14.0
slf4j: 1.7.30
log4jSlf4jImpl: 2.8.1
minotaur: 2.7.5
hangarPublishPlugin: 0.0.5
indra: 3.0.1
shadow: 8.1.1
testLoggerPlugin: 3.2.0
adventure: 4.14.0
adventurePlatform: 4.3.0
adventurePlatformFabric: 5.10.0-SNAPSHOT
configurate: 4.1.2
checkerQual: 3.35.0
slf4j: 1.7.32
gson: 2.8.0
guava: 21.0
bstats: 2.2.1
bstats: 3.0.0
paperApi: 1.16.5-R0.1-SNAPSHOT
paperlib: 1.0.8-SNAPSHOT
waterfallApi: 1.16-R0.4-SNAPSHOT
fabricApi: 0.34.9+1.17
fabricLoader: 0.11.3
fabricMinecraft: 1.17
fabricApi: 0.83.0+1.20.1
fabricLoader: 0.14.19
minecraft: 1.20.1
spongeApi7: 7.2.0
velocityApi: 1.1.7
jupiterEngine: 5.7.0
velocityApi: 3.1.2-SNAPSHOT
jupiterEngine: 5.9.2
dependencies:
adventureBom:
@@ -67,7 +69,6 @@ dependencies:
minimessage:
group: net.kyori
name: adventure-text-minimessage
version: { ref: minimessage }
configurateHocon:
group: org.spongepowered
@@ -87,10 +88,6 @@ dependencies:
group: org.slf4j
name: slf4j-jdk14
version: { ref: slf4j }
log4jSlf4jImpl:
group: org.apache.logging.log4j
name: log4j-slf4j-impl
version: { ref: log4jSlf4jImpl }
gson:
group: com.google.code.gson
@@ -122,6 +119,10 @@ dependencies:
group: com.destroystokyo.paper
name: paper-api
version: { ref: paperApi }
paperlib:
group: io.papermc
name: paperlib
version: { ref: paperlib }
waterfallApi:
group: io.github.waterfallmc
@@ -136,10 +137,10 @@ dependencies:
group: net.fabricmc
name: fabric-loader
version: { ref: fabricLoader }
fabricMinecraft:
minecraft:
group: com.mojang
name: minecraft
version: { ref: fabricMinecraft }
version: { ref: minecraft }
spongeApi7:
group: org.spongepowered
@@ -161,13 +162,25 @@ dependencies:
group: net.kyori
name: indra-common
version: { ref: indra }
indraLicenser:
group: net.kyori
name: indra-licenser-cadix
version: { ref: indra }
shadow:
group: gradle.plugin.com.github.jengelman.gradle.plugins
group: com.github.johnrengelman
name: shadow
version: { ref: shadow }
testLoggerPlugin:
testLogger:
group: com.adarshr
name: gradle-test-logger-plugin
version: { ref: testLoggerPlugin }
minotaur:
group: com.modrinth.minotaur
name: Minotaur
version: { ref: minotaur }
hangarPublishPlugin:
group: io.papermc
name: hangar-publish-plugin
version: { ref: hangarPublishPlugin }
bundles:
Binary file not shown.
+2 -1
View File
@@ -1,5 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+174 -114
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,67 +17,98 @@
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -87,9 +118,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,7 +129,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@@ -106,80 +137,109 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
Vendored
+9 -6
View File
@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021 Jason Penilla
Copyright (c) 2020-2023 Jason Penilla
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
This file is part of MiniMOTD, licensed under the MIT License.
Copyright (c) 2021 Jason Penilla
Copyright (c) 2020-2023 Jason Penilla
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+44
View File
@@ -0,0 +1,44 @@
plugins {
id("minimotd.shadow-platform")
id("xyz.jpenilla.run-paper")
}
dependencies {
implementation(projects.minimotdCommon)
implementation(libs.slf4jJdk14)
implementation(libs.adventurePlatformBukkit)
implementation(libs.bstatsBukkit)
implementation(libs.paperlib)
compileOnly(libs.paperApi)
}
tasks {
runServer {
minecraftVersion(minecraftVersion)
}
shadowJar {
platformRelocation("bukkit", "xyz.jpenilla.minimotd.common")
commonRelocation("org.slf4j")
commonRelocation("io.leangen.geantyref")
commonRelocation("net.kyori")
commonRelocation("org.bstats")
commonRelocation("io.papermc.lib")
}
processResources {
val props = mapOf(
"version" to project.version,
"website" to Constants.GITHUB_URL,
"description" to project.description
)
inputs.properties(props)
filesMatching("plugin.yml") {
expand(props)
}
}
}
runPaper.folia.registerTask()
modrinth {
gameVersions.addAll(bukkitVersions)
}
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,8 +23,10 @@
*/
package xyz.jpenilla.minimotd.bukkit;
import io.papermc.lib.PaperLib;
import java.awt.image.BufferedImage;
import java.nio.file.Path;
import java.util.concurrent.CompletableFuture;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bstats.bukkit.Metrics;
import org.bukkit.command.PluginCommand;
@@ -44,24 +46,18 @@ public final class MiniMOTDPlugin extends JavaPlugin implements MiniMOTDPlatform
private Logger logger;
private MiniMOTD<CachedServerIcon> miniMOTD;
private BukkitAudiences audiences;
private String serverPackageName;
private String serverApiVersion;
private int majorMinecraftVersion;
@Override
public void onEnable() {
this.logger = LoggerFactory.getLogger(this.getName());
this.miniMOTD = new MiniMOTD<>(this);
this.audiences = BukkitAudiences.create(this);
this.serverPackageName = this.getServer().getClass().getPackage().getName();
this.serverApiVersion = this.serverPackageName.substring(this.serverPackageName.lastIndexOf('.') + 1);
this.majorMinecraftVersion = Integer.parseInt(this.serverApiVersion.split("_")[1]);
if (PAPER_PING_EVENT_EXISTS) {
this.getServer().getPluginManager().registerEvents(new PaperPingListener(this, this.miniMOTD), this);
this.getServer().getPluginManager().registerEvents(new PaperPingListener(this.miniMOTD), this);
} else {
this.getServer().getPluginManager().registerEvents(new PingListener(this, this.miniMOTD), this);
if (this.majorMinecraftVersion >= 12) { // PaperServerListPingEvent was added in 1.12
this.getServer().getPluginManager().registerEvents(new PingListener(this.miniMOTD), this);
if (PaperLib.getMinecraftVersion() >= 12) { // PaperServerListPingEvent was added in 1.12
this.suggestPaper();
}
}
@@ -76,8 +72,17 @@ public final class MiniMOTDPlugin extends JavaPlugin implements MiniMOTDPlatform
final Metrics metrics = new Metrics(this, 8132);
if (this.miniMOTD.configManager().pluginSettings().updateChecker()) {
this.getServer().getScheduler().runTaskAsynchronously(this, () ->
new UpdateChecker().checkVersion().forEach(this.logger::info));
try {
Class.forName("io.papermc.paper.threadedregions.RegionizedServer");
CompletableFuture.runAsync(() -> new UpdateChecker().checkVersion().forEach(this.logger::info)).whenComplete(($, thr) -> {
if (thr != null) {
this.logger.warn("Exception checking for updates", thr);
}
});
} catch (final ReflectiveOperationException ex) {
this.getServer().getScheduler().runTaskAsynchronously(this, () ->
new UpdateChecker().checkVersion().forEach(this.logger::info));
}
}
}
@@ -100,10 +105,6 @@ public final class MiniMOTDPlugin extends JavaPlugin implements MiniMOTDPlatform
return this.getServer().loadServerIcon(image);
}
public int majorMinecraftVersion() {
return this.majorMinecraftVersion;
}
public @NonNull BukkitAudiences audiences() {
return this.audiences;
}
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,6 +24,7 @@
package xyz.jpenilla.minimotd.bukkit;
import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
import io.papermc.lib.PaperLib;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@@ -34,14 +35,12 @@ import xyz.jpenilla.minimotd.common.MiniMOTD;
import xyz.jpenilla.minimotd.common.PingResponse;
import xyz.jpenilla.minimotd.common.config.MiniMOTDConfig;
final class PaperPingListener implements Listener {
private final MiniMOTDPlugin plugin;
public final class PaperPingListener implements Listener {
private final LegacyComponentSerializer unusualHexSerializer = LegacyComponentSerializer.builder().hexColors().useUnusualXRepeatedCharacterHexFormat().build();
private final MiniMOTD<CachedServerIcon> miniMOTD;
PaperPingListener(final @NonNull MiniMOTDPlugin plugin, final @NonNull MiniMOTD<CachedServerIcon> miniMOTD) {
PaperPingListener(final @NonNull MiniMOTD<CachedServerIcon> miniMOTD) {
this.miniMOTD = miniMOTD;
this.plugin = plugin;
}
@EventHandler
@@ -52,7 +51,7 @@ final class PaperPingListener implements Listener {
response.playerCount().applyCount(event::setNumPlayers, event::setMaxPlayers);
response.motd(motd -> {
if (event.getClient().getProtocolVersion() < Constants.MINECRAFT_1_16_PROTOCOL_VERSION || this.plugin.majorMinecraftVersion() < 16) {
if (event.getClient().getProtocolVersion() < Constants.MINECRAFT_1_16_PROTOCOL_VERSION || PaperLib.getMinecraftVersion() < 16) {
event.setMotd(LegacyComponentSerializer.legacySection().serialize(motd));
} else {
event.setMotd(this.unusualHexSerializer.serialize(motd));
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,6 +23,7 @@
*/
package xyz.jpenilla.minimotd.bukkit;
import io.papermc.lib.PaperLib;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@@ -33,13 +34,11 @@ import xyz.jpenilla.minimotd.common.MiniMOTD;
import xyz.jpenilla.minimotd.common.PingResponse;
import xyz.jpenilla.minimotd.common.config.MiniMOTDConfig;
final class PingListener implements Listener {
public final class PingListener implements Listener {
private final MiniMOTD<CachedServerIcon> miniMOTD;
private final LegacyComponentSerializer unusualHexSerializer = LegacyComponentSerializer.builder().hexColors().useUnusualXRepeatedCharacterHexFormat().build();
private final MiniMOTDPlugin plugin;
PingListener(final @NonNull MiniMOTDPlugin plugin, final @NonNull MiniMOTD<CachedServerIcon> miniMOTD) {
this.plugin = plugin;
PingListener(final @NonNull MiniMOTD<CachedServerIcon> miniMOTD) {
this.miniMOTD = miniMOTD;
}
@@ -51,12 +50,17 @@ final class PingListener implements Listener {
event.setMaxPlayers(response.playerCount().maxPlayers());
response.motd(motd -> {
if (this.plugin.majorMinecraftVersion() > 15) {
if (PaperLib.getMinecraftVersion() > 15) {
event.setMotd(this.unusualHexSerializer.serialize(motd));
} else {
event.setMotd(LegacyComponentSerializer.legacySection().serialize(motd));
}
});
response.icon(event::setServerIcon);
response.icon(icon -> {
try {
event.setServerIcon(icon);
} catch (final UnsupportedOperationException ignore) {
}
});
}
}
@@ -0,0 +1,16 @@
name: MiniMOTD
version: $version
main: xyz.jpenilla.minimotd.bukkit.MiniMOTDPlugin
folia-supported: true
description: $description
authors:
- jmp
website: $website
commands:
minimotd:
description: MiniMOTD Command
permission: minimotd.admin
usage: /minimotd help
api-version: 1.13
softdepend:
- ViaVersion
@@ -1,26 +1,26 @@
plugins {
id("minimotd.shadow-platform")
id("net.minecrell.plugin-yml.bungee")
id("xyz.jpenilla.run-waterfall")
}
dependencies {
implementation(projects.minimotdCommon)
implementation(libs.slf4jJdk14)
implementation(libs.adventurePlatformBungeecord)
implementation(libs.bstatsBungeecord)
compileOnly(libs.waterfallApi)
}
tasks {
generateBungeePluginDescription {
mustRunAfter(clean)
}
shadowJar {
commonRelocation("org.slf4j")
platformRelocation("bungee", "xyz.jpenilla.minimotd.common")
commonRelocation("io.leangen.geantyref")
commonRelocation("net.kyori")
commonRelocation("org.bstats")
}
runWaterfall {
waterfallVersion("1.19")
}
}
bungee {
@@ -28,3 +28,8 @@ bungee {
main = "xyz.jpenilla.minimotd.bungee.MiniMOTDPlugin"
author = "jmp"
}
modrinth {
loaders.add("waterfall") // not sure why this isn't detected automatically from run-waterfall...
gameVersions.addAll(minecraftVersion)
}
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -39,6 +39,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import xyz.jpenilla.minimotd.common.MiniMOTD;
import xyz.jpenilla.minimotd.common.MiniMOTDPlatform;
import xyz.jpenilla.minimotd.common.PingResponse;
import xyz.jpenilla.minimotd.common.config.MiniMOTDConfig;
import xyz.jpenilla.minimotd.common.util.UpdateChecker;
public final class MiniMOTDPlugin extends Plugin implements MiniMOTDPlatform<Favicon> {
@@ -65,6 +67,9 @@ public final class MiniMOTDPlugin extends Plugin implements MiniMOTDPlatform<Fav
this.getProxy().getScheduler().runAsync(this, () ->
new UpdateChecker().checkVersion().forEach(this.logger::info));
}
// preload some stuff, so the first ping is as fast as the rest
this.preload();
}
@Override
@@ -109,4 +114,10 @@ public final class MiniMOTDPlugin extends Plugin implements MiniMOTDPlatform<Fav
return null;
}
}
private void preload() {
final MiniMOTDConfig cfg = this.miniMOTD.configManager().mainConfig();
final PingResponse<Favicon> mini = this.miniMOTD.createMOTD(cfg, 0, 0);
mini.motd(motd -> BungeeComponentSerializer.get().serialize(motd));
}
}
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -1,28 +1,23 @@
plugins {
id("quiet-fabric-loom")
id("minimotd.platform-conventions")
id("com.github.johnrengelman.shadow")
id("fabric-loom")
}
val shade: Configuration by configurations.creating
val minecraftVersion = libs.versions.fabricMinecraft.get()
dependencies {
minecraft(libs.fabricMinecraft)
mappings(minecraft.officialMojangMappings())
minecraft(libs.minecraft)
mappings(loom.officialMojangMappings())
modImplementation(libs.fabricLoader)
modImplementation(libs.fabricApi)
shade(implementation(projects.minimotdCommon) {
exclude("net.kyori")
exclude("org.slf4j")
})
modImplementation(libs.adventurePlatformFabric)
include(libs.adventurePlatformFabric)
implementation(libs.minimessage)
include(libs.minimessage)
}
miniMOTDPlatform {
@@ -31,22 +26,17 @@ miniMOTDPlatform {
indra {
javaVersions {
target(16)
target(17)
}
}
tasks {
runServer {
standardInput = System.`in`
}
shadowJar {
configurations = listOf(shade)
commonConfiguration()
commonRelocation("io.leangen.geantyref")
platformRelocation("fabric", "xyz.jpenilla.minimotd.common")
}
remapJar {
input.set(shadowJar.flatMap { it.archiveFile })
archiveFileName.set("${project.name}-mc$minecraftVersion-${project.version}.jar")
}
processResources {
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -25,22 +25,19 @@ package xyz.jpenilla.minimotd.fabric;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.context.CommandContext;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufOutputStream;
import io.netty.buffer.Unpooled;
import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.io.ByteArrayOutputStream;
import java.nio.file.Path;
import java.util.Base64;
import java.util.concurrent.CompletableFuture;
import javax.imageio.ImageIO;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.loader.api.FabricLoader;
import net.kyori.adventure.platform.fabric.FabricServerAudiences;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.network.protocol.status.ServerStatus;
import net.minecraft.server.MinecraftServer;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -48,16 +45,18 @@ import xyz.jpenilla.minimotd.common.CommandHandler;
import xyz.jpenilla.minimotd.common.MiniMOTD;
import xyz.jpenilla.minimotd.common.MiniMOTDPlatform;
import xyz.jpenilla.minimotd.common.util.UpdateChecker;
import xyz.jpenilla.minimotd.fabric.access.ServerStatusFaviconAccess;
import static net.minecraft.commands.Commands.literal;
public final class MiniMOTDFabric implements ModInitializer, MiniMOTDPlatform<String> {
public final class MiniMOTDFabric implements ModInitializer, MiniMOTDPlatform<ServerStatus.Favicon> {
private static MiniMOTDFabric instance = null;
private final Logger logger = LoggerFactory.getLogger(MiniMOTD.class);
private final Path dataDirectory = FabricLoader.getInstance().getConfigDir().resolve("MiniMOTD");
private final MiniMOTD<String> miniMOTD = new MiniMOTD<>(this);
private final MiniMOTD<ServerStatus.Favicon> miniMOTD = new MiniMOTD<>(this);
private MinecraftServer server;
private FabricServerAudiences audiences;
public MiniMOTDFabric() {
@@ -67,19 +66,26 @@ public final class MiniMOTDFabric implements ModInitializer, MiniMOTDPlatform<St
instance = this;
}
public @NonNull MiniMOTD<String> miniMOTD() {
public @NonNull MiniMOTD<ServerStatus.Favicon> miniMOTD() {
return this.miniMOTD;
}
@Override
public void onInitialize() {
this.registerCommand();
ServerLifecycleEvents.SERVER_STARTED.register(minecraftServer -> {
ServerLifecycleEvents.SERVER_STARTING.register(minecraftServer -> {
this.server = minecraftServer;
this.audiences = FabricServerAudiences.of(minecraftServer);
});
ServerLifecycleEvents.SERVER_STARTED.register(minecraftServer -> {
if (this.miniMOTD.configManager().pluginSettings().updateChecker()) {
CompletableFuture.runAsync(() -> new UpdateChecker().checkVersion().forEach(this.logger()::info));
}
});
ServerLifecycleEvents.SERVER_STOPPED.register($ -> {
this.server = null;
this.audiences = null;
});
this.miniMOTD.logger().info("Done initializing MiniMOTD");
}
@@ -93,13 +99,13 @@ public final class MiniMOTDFabric implements ModInitializer, MiniMOTDPlatform<St
@Override
public int run(final @NonNull CommandContext<CommandSourceStack> context) {
this.handler.execute(MiniMOTDFabric.this.audiences.audience(context.getSource()));
this.handler.execute(context.getSource());
return Command.SINGLE_SUCCESS;
}
}
final CommandHandler handler = new CommandHandler(this.miniMOTD);
CommandRegistrationCallback.EVENT.register((dispatcher, $) -> dispatcher.register(
CommandRegistrationCallback.EVENT.register((dispatcher, commandBuildContext, commandSelection) -> dispatcher.register(
literal("minimotd")
.requires(source -> source.hasPermission(4))
.then(literal("reload").executes(new WrappingExecutor(handler::reload)))
@@ -116,6 +122,13 @@ public final class MiniMOTDFabric implements ModInitializer, MiniMOTDPlatform<St
return instance;
}
public @NonNull MinecraftServer requireServer() {
if (this.server == null) {
throw new IllegalStateException("Server requested before started");
}
return this.server;
}
@Override
public @NonNull Path dataDirectory() {
return this.dataDirectory;
@@ -127,16 +140,11 @@ public final class MiniMOTDFabric implements ModInitializer, MiniMOTDPlatform<St
}
@Override
public @NonNull String loadIcon(final @NonNull BufferedImage bufferedImage) throws Exception {
final ByteBuf byteBuf = Unpooled.buffer();
final String icon;
try {
ImageIO.write(bufferedImage, "PNG", new ByteBufOutputStream(byteBuf));
final ByteBuffer base64 = Base64.getEncoder().encode(byteBuf.nioBuffer());
icon = "data:image/png;base64," + StandardCharsets.UTF_8.decode(base64);
} finally {
byteBuf.release();
}
return icon;
public ServerStatus.@NonNull Favicon loadIcon(final @NonNull BufferedImage bufferedImage) throws Exception {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "PNG", out);
final ServerStatus.Favicon favicon = new ServerStatus.Favicon(out.toByteArray());
((ServerStatusFaviconAccess) (Object) favicon).cacheEncodedIcon();
return favicon;
}
}
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,32 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package xyz.jpenilla.minimotd.fabric.access;
import org.checkerframework.checker.nullness.qual.Nullable;
public interface ServerStatusFaviconAccess {
@Nullable String cachedEncodedIcon();
void cacheEncodedIcon();
}
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,78 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package xyz.jpenilla.minimotd.fabric.mixin;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.codecs.PrimitiveCodec;
import java.util.function.Function;
import net.minecraft.network.protocol.status.ServerStatus;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import xyz.jpenilla.minimotd.fabric.access.ServerStatusFaviconAccess;
@Mixin(ServerStatus.Favicon.class)
abstract class ServerStatusFaviconMixin implements ServerStatusFaviconAccess {
@Unique
private static Function<ServerStatus.Favicon, String> VANILLA_ENCODE_TO_STRING;
@Redirect(
method = "<clinit>",
at = @At(
target = "Lcom/mojang/serialization/codecs/PrimitiveCodec;comapFlatMap(Ljava/util/function/Function;Ljava/util/function/Function;)Lcom/mojang/serialization/Codec;",
value = "INVOKE"
),
remap = false
)
private static Codec<ServerStatus.Favicon> makeCodec(
final PrimitiveCodec<String> stringCodec,
final Function<String, DataResult<ServerStatus.Favicon>> decode,
final Function<ServerStatus.Favicon, String> encode
) {
VANILLA_ENCODE_TO_STRING = encode;
return stringCodec.comapFlatMap(decode, favicon -> {
final @Nullable String encodedIcon = ((ServerStatusFaviconAccess) (Object) favicon).cachedEncodedIcon();
if (encodedIcon != null) {
return encodedIcon;
}
return encode.apply(favicon);
});
}
@Unique
private String encodedIcon;
@Override
public @Nullable String cachedEncodedIcon() {
return this.encodedIcon;
}
@Override
public void cacheEncodedIcon() {
this.encodedIcon = VANILLA_ENCODE_TO_STRING.apply((ServerStatus.Favicon) (Object) this);
}
}
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,9 @@
*/
package xyz.jpenilla.minimotd.fabric.mixin;
import com.mojang.authlib.GameProfile;
import java.util.Collections;
import java.util.Objects;
import java.util.Optional;
import net.minecraft.network.Connection;
import net.minecraft.network.protocol.status.ServerStatus;
import net.minecraft.server.MinecraftServer;
@@ -40,46 +42,53 @@ import xyz.jpenilla.minimotd.common.config.MiniMOTDConfig;
import xyz.jpenilla.minimotd.common.util.ComponentColorDownsampler;
import xyz.jpenilla.minimotd.fabric.MiniMOTDFabric;
import xyz.jpenilla.minimotd.fabric.access.ConnectionAccess;
import xyz.jpenilla.minimotd.fabric.util.MutableServerStatus;
@Mixin(ServerStatusPacketListenerImpl.class)
abstract class ServerStatusPacketListenerImplMixin {
@Shadow @Final private Connection connection;
@Redirect(method = "handleStatusRequest", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;getStatus()Lnet/minecraft/network/protocol/status/ServerStatus;"))
public ServerStatus injectHandleStatusRequest(final MinecraftServer minecraftServer) {
final ServerStatus vanillaStatus = minecraftServer.getStatus();
final ServerStatus modifiedStatus = new ServerStatus();
modifiedStatus.setDescription(vanillaStatus.getDescription());
modifiedStatus.setFavicon(vanillaStatus.getFavicon());
modifiedStatus.setVersion(vanillaStatus.getVersion());
@Redirect(
method = "handleStatusRequest",
at = @At(value = "FIELD", target = "Lnet/minecraft/server/network/ServerStatusPacketListenerImpl;status:Lnet/minecraft/network/protocol/status/ServerStatus;")
)
public ServerStatus injectHandleStatusRequest(final ServerStatusPacketListenerImpl instance) {
final MiniMOTDFabric miniMOTDFabric = MiniMOTDFabric.get();
final MiniMOTD<String> miniMOTD = miniMOTDFabric.miniMOTD();
final MinecraftServer minecraftServer = miniMOTDFabric.requireServer();
final ServerStatus vanillaStatus = Objects.requireNonNull(minecraftServer.getStatus(), "vanillaStatus");
final MiniMOTD<ServerStatus.Favicon> miniMOTD = miniMOTDFabric.miniMOTD();
final MiniMOTDConfig config = miniMOTD.configManager().mainConfig();
final PingResponse<String> response = miniMOTD.createMOTD(config, minecraftServer.getPlayerCount(), vanillaStatus.getPlayers().getMaxPlayers());
final PingResponse<ServerStatus.Favicon> response = miniMOTD.createMOTD(
config,
minecraftServer.getPlayerCount(),
vanillaStatus.players().map(ServerStatus.Players::max).orElseGet(minecraftServer::getMaxPlayers)
);
final MutableServerStatus modifiedStatus = new MutableServerStatus(vanillaStatus);
response.motd(motd -> {
if (((ConnectionAccess) this.connection).protocolVersion() >= Constants.MINECRAFT_1_16_PROTOCOL_VERSION) {
modifiedStatus.setDescription(miniMOTDFabric.audiences().toNative(motd));
modifiedStatus.description(miniMOTDFabric.audiences().toNative(motd));
} else {
modifiedStatus.setDescription(miniMOTDFabric.audiences().toNative(ComponentColorDownsampler.downsampler().downsample(motd)));
modifiedStatus.description(miniMOTDFabric.audiences().toNative(ComponentColorDownsampler.downsampler().downsample(motd)));
}
});
response.icon(modifiedStatus::setFavicon);
response.icon(favicon -> modifiedStatus.favicon(Optional.of(favicon)));
if (!response.hidePlayerCount()) {
final GameProfile[] oldSample = vanillaStatus.getPlayers().getSample();
final ServerStatus.Players newPlayers = new ServerStatus.Players(response.playerCount().maxPlayers(), response.playerCount().onlinePlayers());
if (response.disablePlayerListHover()) {
newPlayers.setSample(new GameProfile[]{});
} else {
newPlayers.setSample(oldSample);
}
modifiedStatus.setPlayers(newPlayers);
if (response.hidePlayerCount()) {
modifiedStatus.players(Optional.empty());
} else {
final ServerStatus.Players newPlayers = new ServerStatus.Players(
response.playerCount().maxPlayers(),
response.playerCount().onlinePlayers(),
response.disablePlayerListHover()
? Collections.emptyList()
: vanillaStatus.players().map(ServerStatus.Players::sample).orElse(Collections.emptyList())
);
modifiedStatus.players(Optional.of(newPlayers));
}
return modifiedStatus;
return modifiedStatus.toServerStatus();
}
}
@@ -0,0 +1,97 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package xyz.jpenilla.minimotd.fabric.util;
import java.util.Objects;
import java.util.Optional;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.status.ServerStatus;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.framework.qual.DefaultQualifier;
@SuppressWarnings({"OptionalUsedAsFieldOrParameterType", "unused"})
@DefaultQualifier(NonNull.class)
public final class MutableServerStatus {
private Component description;
private Optional<ServerStatus.Players> players;
private Optional<ServerStatus.Version> version;
private Optional<ServerStatus.Favicon> favicon;
private boolean enforcesSecureChat;
public MutableServerStatus(final ServerStatus status) {
this.description = status.description();
this.players = status.players();
this.version = status.version();
this.favicon = status.favicon();
this.enforcesSecureChat = status.enforcesSecureChat();
}
public ServerStatus toServerStatus() {
return new ServerStatus(this.description, this.players, this.version, this.favicon, this.enforcesSecureChat);
}
public Component description() {
return this.description;
}
public void description(final Component description) {
Objects.requireNonNull(description, "description");
this.description = description;
}
public Optional<ServerStatus.Players> players() {
return this.players;
}
public void players(final Optional<ServerStatus.Players> players) {
Objects.requireNonNull(players, "players");
this.players = players;
}
public Optional<ServerStatus.Version> version() {
return this.version;
}
public void version(final Optional<ServerStatus.Version> version) {
Objects.requireNonNull(version, "version");
this.version = version;
}
public Optional<ServerStatus.Favicon> favicon() {
return this.favicon;
}
public void favicon(final Optional<ServerStatus.Favicon> favicon) {
Objects.requireNonNull(favicon, "favicon");
this.favicon = favicon;
}
public boolean enforcesSecureChat() {
return this.enforcesSecureChat;
}
public void enforcesSecureChat(final boolean enforcesSecureChat) {
this.enforcesSecureChat = enforcesSecureChat;
}
}
@@ -23,8 +23,8 @@
"minimotd-fabric.mixins.json"
],
"depends": {
"fabricloader": ">=0.11.1",
"fabric": ">=0.31.0",
"minecraft": "1.17.x"
"fabricloader": ">=0.14.6",
"fabric": "*",
"minecraft": ">=1.20.1"
}
}
@@ -1,11 +1,12 @@
{
"required": true,
"minVersion": "0.8",
"minVersion": "0.8.4",
"package": "xyz.jpenilla.minimotd.fabric.mixin",
"compatibilityLevel": "JAVA_8",
"compatibilityLevel": "JAVA_16",
"mixins": [
"ConnectionMixin",
"ServerHandshakePacketListenerImplMixin",
"ServerStatusFaviconMixin",
"ServerStatusPacketListenerImplMixin"
],
"client": [
@@ -1,11 +1,11 @@
import java.util.Locale
plugins {
id("minimotd.shadow-platform")
}
dependencies {
implementation(projects.minimotdCommon) {
exclude("org.slf4j", "slf4j-api")
}
implementation(projects.minimotdCommon)
implementation(libs.adventurePlatformSpongeApi)
compileOnly(libs.spongeApi7)
implementation(libs.bstatsSponge)
@@ -14,7 +14,7 @@ dependencies {
tasks {
processResources {
val replacements = mapOf(
"modid" to project.name,
"modid" to rootProject.name.toLowerCase(Locale.ENGLISH),
"name" to rootProject.name,
"version" to project.version.toString(),
"description" to project.description.toString(),
@@ -31,3 +31,8 @@ tasks {
commonRelocation("org.bstats")
}
}
modrinth {
loaders.add("sponge")
gameVersions.add("1.12.2")
}
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -101,7 +101,11 @@ public final class MiniMOTDPlugin implements MiniMOTDPlatform<Favicon> {
@Listener
public void reloaded(final @NonNull GameReloadEvent event) {
this.miniMOTD.reload();
try {
this.miniMOTD.reload();
} catch (final Exception ex) {
this.miniMOTD.logger().warn("Failed to reload MiniMOTD.", ex);
}
}
private void registerCommands() {
@@ -1,5 +1,6 @@
import org.spongepowered.gradle.plugin.config.PluginLoaders
import org.spongepowered.plugin.metadata.PluginDependency
import org.spongepowered.plugin.metadata.model.PluginDependency
import java.util.Locale
plugins {
id("minimotd.shadow-platform")
@@ -8,18 +9,19 @@ plugins {
dependencies {
implementation(projects.minimotdCommon)
implementation(libs.log4jSlf4jImpl) {
isTransitive = false
}
}
sponge {
injectRepositories(false)
apiVersion("8.0.0")
plugin(project.name) {
loader(PluginLoaders.JAVA_PLAIN)
apiVersion("8.1.0-SNAPSHOT")
plugin(rootProject.name.toLowerCase(Locale.ENGLISH)) {
loader {
name(PluginLoaders.JAVA_PLAIN)
version("1.0")
}
license("MIT")
displayName(rootProject.name)
mainClass("xyz.jpenilla.minimotd.sponge8.MiniMOTDPlugin")
entrypoint("xyz.jpenilla.minimotd.sponge8.MiniMOTDPlugin")
description(project.description)
links {
homepage(Constants.GITHUB_URL)
@@ -39,11 +41,17 @@ sponge {
tasks {
shadowJar {
configureForNativeAdventurePlatform()
commonRelocation("org.apache.logging.slf4j")
platformRelocation("log4j", "org.slf4j")
platformRelocation("sponge8", "xyz.jpenilla.minimotd.common")
dependencies {
exclude(dependency("io.leangen.geantyref:geantyref"))
}
}
}
modrinth {
gameVersions.addAll(
"1.16.5",
"1.17.1",
"1.18.2",
"1.19.4"
)
}
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -25,7 +25,6 @@ package xyz.jpenilla.minimotd.sponge8;
import com.google.inject.Inject;
import java.lang.reflect.Method;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.spongepowered.api.MinecraftVersion;
import org.spongepowered.api.event.EventListener;
@@ -38,8 +37,18 @@ import xyz.jpenilla.minimotd.common.config.MiniMOTDConfig;
import xyz.jpenilla.minimotd.common.util.ComponentColorDownsampler;
final class ClientPingServerEventListener implements EventListener<ClientPingServerEvent> {
private static final Method GET_PROTOCOL;
static {
try {
final Class<?> protocolMinecraftVersion = Class.forName("org.spongepowered.common.ProtocolMinecraftVersion");
GET_PROTOCOL = protocolMinecraftVersion.getMethod("getProtocol");
} catch (final ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
}
private final MiniMOTD<Favicon> miniMOTD;
private @MonotonicNonNull Method SpongeMinecraftVersion_getProtocol;
@Inject
private ClientPingServerEventListener(final @NonNull MiniMOTD<Favicon> miniMOTD) {
@@ -86,11 +95,8 @@ final class ClientPingServerEventListener implements EventListener<ClientPingSer
private boolean legacy(final @NonNull MinecraftVersion version) {
try {
if (!version.isLegacy() && this.SpongeMinecraftVersion_getProtocol == null) {
this.SpongeMinecraftVersion_getProtocol = version.getClass().getMethod("getProtocol");
}
return version.isLegacy()
|| (int) this.SpongeMinecraftVersion_getProtocol.invoke(version) < Constants.MINECRAFT_1_16_PROTOCOL_VERSION;
|| (int) GET_PROTOCOL.invoke(version) < Constants.MINECRAFT_1_16_PROTOCOL_VERSION;
} catch (final ReflectiveOperationException e) {
throw new IllegalStateException("Failed to get protocol version", e);
}
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -38,7 +38,9 @@ import org.spongepowered.api.command.CommandExecutor;
import org.spongepowered.api.command.CommandResult;
import org.spongepowered.api.command.parameter.CommandContext;
import org.spongepowered.api.config.ConfigDir;
import org.spongepowered.api.event.EventListenerRegistration;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.Order;
import org.spongepowered.api.event.lifecycle.LoadedGameEvent;
import org.spongepowered.api.event.lifecycle.RefreshGameEvent;
import org.spongepowered.api.event.lifecycle.RegisterCommandEvent;
@@ -46,7 +48,7 @@ import org.spongepowered.api.event.server.ClientPingServerEvent;
import org.spongepowered.api.network.status.Favicon;
import org.spongepowered.api.scheduler.Task;
import org.spongepowered.plugin.PluginContainer;
import org.spongepowered.plugin.jvm.Plugin;
import org.spongepowered.plugin.builtin.jvm.Plugin;
import org.spongepowered.plugin.metadata.PluginMetadata;
import xyz.jpenilla.minimotd.common.CommandHandler;
import xyz.jpenilla.minimotd.common.MiniMOTD;
@@ -81,9 +83,11 @@ public final class MiniMOTDPlugin implements MiniMOTDPlatform<Favicon> {
}
});
Sponge.eventManager().registerListener(
pluginContainer,
ClientPingServerEvent.class,
this.injector.getInstance(ClientPingServerEventListener.class)
EventListenerRegistration.builder(ClientPingServerEvent.class)
.plugin(pluginContainer)
.listener(this.injector.getInstance(ClientPingServerEventListener.class))
.order(Order.DEFAULT)
.build()
);
}
@@ -137,7 +141,11 @@ public final class MiniMOTDPlugin implements MiniMOTDPlatform<Favicon> {
@Listener
public void onRefresh(final @NonNull RefreshGameEvent event) {
this.miniMOTD.reload();
try {
this.miniMOTD.reload();
} catch (final Exception ex) {
this.miniMOTD.logger().warn("Failed to reload MiniMOTD.", ex);
}
}
@Override
@@ -1,12 +1,11 @@
plugins {
id("minimotd.shadow-platform")
id("net.kyori.blossom")
id("xyz.jpenilla.run-velocity")
}
dependencies {
implementation(projects.minimotdCommon) {
exclude("org.slf4j", "slf4j-api")
}
implementation(projects.minimotdCommon)
implementation(libs.bstatsVelocity)
compileOnly(libs.velocityApi)
annotationProcessor(libs.velocityApi)
@@ -16,9 +15,11 @@ tasks {
shadowJar {
configureForNativeAdventurePlatform()
commonRelocation("io.leangen.geantyref")
platformRelocation("velocity", "xyz.jpenilla.minimotd.common")
commonRelocation("org.bstats")
}
runVelocity {
velocityVersion(libs.versions.velocityApi.get())
}
}
blossom {
@@ -31,3 +32,7 @@ blossom {
replaceToken("\${$k}", v, file)
}
}
modrinth {
gameVersions.addAll(minecraftVersion)
}
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -1,7 +1,7 @@
/*
* This file is part of MiniMOTD, licensed under the MIT License.
*
* Copyright (c) 2021 Jason Penilla
* Copyright (c) 2020-2023 Jason Penilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,25 +24,32 @@
package xyz.jpenilla.minimotd.velocity;
import com.google.inject.Inject;
import com.velocitypowered.api.event.EventTask;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
import com.velocitypowered.api.proxy.server.ServerPing;
import com.velocitypowered.api.util.Favicon;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.framework.qual.DefaultQualifier;
import xyz.jpenilla.minimotd.common.MiniMOTD;
import xyz.jpenilla.minimotd.common.PingResponse;
import xyz.jpenilla.minimotd.common.config.MiniMOTDConfig;
@DefaultQualifier(NonNull.class)
public final class PingListener {
private final MiniMOTD<Favicon> miniMOTD;
@Inject
private PingListener(final @NonNull MiniMOTD<Favicon> miniMOTD) {
private PingListener(final MiniMOTD<Favicon> miniMOTD) {
this.miniMOTD = miniMOTD;
}
@Subscribe
public void handlePing(final @NonNull ProxyPingEvent event) {
public EventTask onProxyPingEvent(final ProxyPingEvent event) {
return EventTask.async(() -> this.handle(event));
}
private void handle(final ProxyPingEvent event) {
final MiniMOTDConfig config = this.miniMOTD.configManager().resolveConfig(event.getConnection().getVirtualHost().orElse(null));
final ServerPing.Builder pong = event.getPing().asBuilder();
+24 -14
View File
@@ -1,15 +1,16 @@
enableFeaturePreview("VERSION_CATALOGS")
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
dependencyResolutionManagement {
repositories {
//mavenLocal()
mavenCentral()
maven("https://oss.sonatype.org/content/repositories/snapshots/")
maven("https://papermc.io/repo/repository/maven-public/")
maven("https://nexus.velocitypowered.com/repository/maven-public/")
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") {
mavenContent { snapshotsOnly() }
}
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://repo.spongepowered.org/repository/maven-public/")
maven("https://repo.jpenilla.xyz/snapshots/")
maven("https://repo.jpenilla.xyz/snapshots/") {
mavenContent { snapshotsOnly() }
}
}
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
}
@@ -18,27 +19,36 @@ pluginManagement {
repositories {
gradlePluginPortal()
maven("https://maven.fabricmc.net/")
maven("https://maven.quiltmc.org/repository/release/")
maven("https://repo.jpenilla.xyz/snapshots/")
}
includeBuild("build-logic")
}
plugins {
id("ca.stellardrift.polyglot-version-catalogs") version "5.0.0"
id("fabric-loom") version "0.8-SNAPSHOT"
id("ca.stellardrift.polyglot-version-catalogs") version "6.0.1"
id("quiet-fabric-loom") version "1.2-SNAPSHOT"
}
rootProject.name = "MiniMOTD"
fun setup(name: String, dir: String) {
include(name)
project(":$name").projectDir = file(dir)
}
fun platform(name: String) = setup("minimotd-$name", "platform/$name")
fun dist(name: String) = setup("minimotd-$name", "dist/$name")
setup("minimotd-common", "common")
sequenceOf(
"common",
"bukkit",
"sponge8",
"sponge7",
"bungeecord",
"velocity",
"fabric",
"universal"
).forEach {
include("minimotd-$it")
project(":minimotd-$it").projectDir = file(it)
}
).forEach(::platform)
dist("bukkit-bungeecord")