-
-
Notifications
You must be signed in to change notification settings - Fork 9
GH-148 Implement mentions system with @player detection and sound notifications #208
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
d17b275
2dbe929
a510853
839a39f
40b63ba
917834f
f030cd6
1212723
58ce9e9
04cff90
b07f8f4
37a4da0
64cb446
fe13db6
59b2265
5ac4ff7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar | ||
| import java.io.FileOutputStream | ||
| import java.io.IOException | ||
| import java.io.Serializable | ||
| import java.util.jar.JarEntry | ||
| import java.util.jar.JarFile | ||
| import java.util.jar.JarOutputStream | ||
|
|
@@ -23,110 +24,114 @@ tasks.register<ShadowJar>("shadowChatFormatter") { | |
| this.dependsOn("${targetProject.name}:shadowJar") | ||
| } | ||
|
|
||
| this.doLast { | ||
| [email protected]( | ||
| "ChatFormatter v${project.version}.jar", | ||
| targetProjects | ||
| ) | ||
| } | ||
| } | ||
| val projectVersion = project.version.toString() | ||
| val outputFile = project.layout.buildDirectory.file("libs/ChatFormatter v${projectVersion}.jar") | ||
| .map { it.asFile } | ||
|
|
||
| fun ShadowJar.mergeJars(archiveFileName: String, projects: List<Project>) { | ||
| val outputFile = File( | ||
| this.project.layout.buildDirectory.asFile.get(), | ||
| "libs/$archiveFileName" | ||
| ) | ||
| val outputDir = outputFile.parentFile | ||
| ?: throw IllegalStateException("Cannot find output directory") | ||
| val shadowJarFiles = targetProjects | ||
| .map { targetProject -> targetProject.tasks.named("shadowJar", ShadowJar::class.java).get().archiveFile.get().asFile } | ||
|
|
||
| if (!outputDir.exists() && !outputDir.mkdirs()) { | ||
| throw IllegalStateException("Failed to create directory: ${outputDir.absolutePath}") | ||
| } | ||
| val merger = JarMerger(outputFile.get(), shadowJarFiles) | ||
|
|
||
| if (outputFile.exists() && !outputFile.delete()) { | ||
| throw IllegalStateException("Cannot delete existing file: ${outputFile.absolutePath}") | ||
| } | ||
| inputs.files(shadowJarFiles) | ||
| outputs.files(outputFile) | ||
|
|
||
| if (!outputFile.createNewFile()) { | ||
| throw IllegalStateException("Cannot create output file: ${outputFile.absolutePath}") | ||
| doLast { | ||
| merger.mergeJars() | ||
| } | ||
|
|
||
| mergeShadowJarsIntoOutput(outputFile, projects) | ||
| } | ||
|
|
||
| private fun mergeShadowJarsIntoOutput( | ||
| outputFile: File, | ||
| projects: List<Project> | ||
| ) { | ||
| JarOutputStream(FileOutputStream(outputFile)).use { outputJar -> | ||
| val processedEntries = mutableSetOf<String>() | ||
| class JarMerger( | ||
| private val outputFile: File, | ||
| private val inputFiles: List<File> | ||
| ) : Serializable { | ||
|
|
||
| fun mergeJars() { | ||
| val outputDir = outputFile.parentFile | ||
| ?: throw IllegalStateException("Cannot find output directory") | ||
|
|
||
| if (!outputDir.exists() && !outputDir.mkdirs()) { | ||
| throw IllegalStateException("Failed to create directory: ${outputDir.absolutePath}") | ||
| } | ||
|
|
||
| if (outputFile.exists() && !outputFile.delete()) { | ||
| throw IllegalStateException("Cannot delete existing file: ${outputFile.absolutePath}") | ||
| } | ||
|
|
||
| if (!outputFile.createNewFile()) { | ||
| throw IllegalStateException("Cannot create output file: ${outputFile.absolutePath}") | ||
| } | ||
|
|
||
| for (targetProject in projects) { | ||
| val shadowJarTask = targetProject.tasks.named("shadowJar", ShadowJar::class.java).get() | ||
| JarOutputStream(FileOutputStream(outputFile)).use { outputJar -> | ||
| val processedEntries = mutableSetOf<String>() | ||
|
|
||
| for (jarFile in shadowJarTask.outputs.files.files) { | ||
| for (jarFile in inputFiles) { | ||
| processJarFile(jarFile, outputJar, processedEntries) | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private fun processJarFile( | ||
| jarFile: File, | ||
| outputJar: JarOutputStream, | ||
| processedEntries: MutableSet<String> | ||
| ) { | ||
| JarFile(jarFile).use { sourceJar -> | ||
| for (entry in sourceJar.entries()) { | ||
| if (entry.isDirectory || processedEntries.contains(entry.name)) { | ||
| continue | ||
| } | ||
|
|
||
| try { | ||
| copyJarEntry(sourceJar, entry, outputJar) | ||
| processedEntries.add(entry.name) | ||
| } catch (exception: IOException) { | ||
| if (exception.message?.contains("duplicate entry:") != true) { | ||
| throw exception | ||
| private fun processJarFile( | ||
| jarFile: File, | ||
| outputJar: JarOutputStream, | ||
| processedEntries: MutableSet<String> | ||
| ) { | ||
| JarFile(jarFile).use { sourceJar -> | ||
| for (entry in sourceJar.entries()) { | ||
| if (entry.isDirectory || processedEntries.contains(entry.name)) { | ||
| continue | ||
| } | ||
|
|
||
| try { | ||
| copyJarEntry(sourceJar, entry, outputJar) | ||
| processedEntries.add(entry.name) | ||
| } catch (exception: IOException) { | ||
| if (exception.message?.contains("duplicate entry:") != true) { | ||
| throw exception | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private fun copyJarEntry( | ||
| sourceJar: JarFile, | ||
| entry: JarEntry, | ||
| outputJar: JarOutputStream | ||
| ) { | ||
| val entryBytes = sourceJar.getInputStream(entry).use { it.readBytes() } | ||
| val newEntry = JarEntry(entry.name).apply { | ||
| this.time = System.currentTimeMillis() | ||
| this.size = entryBytes.size.toLong() | ||
| private fun copyJarEntry( | ||
| sourceJar: JarFile, | ||
| entry: JarEntry, | ||
| outputJar: JarOutputStream | ||
| ) { | ||
| val entryBytes = sourceJar.getInputStream(entry).use { it.readBytes() } | ||
| val newEntry = JarEntry(entry.name).apply { | ||
| this.time = System.currentTimeMillis() | ||
| this.size = entryBytes.size.toLong() | ||
| } | ||
|
|
||
| outputJar.putNextEntry(newEntry) | ||
| outputJar.write(entryBytes) | ||
| outputJar.closeEntry() | ||
| } | ||
|
|
||
| outputJar.putNextEntry(newEntry) | ||
| outputJar.write(entryBytes) | ||
| outputJar.closeEntry() | ||
| } | ||
|
|
||
| runPaper { | ||
| this.disablePluginJarDetection() | ||
| } | ||
|
|
||
| tasks.runServer { | ||
| minecraftVersion("1.21.10") | ||
| minecraftVersion("1.21.11") | ||
| dependsOn("shadowChatFormatter") | ||
| pluginJars.from(layout.buildDirectory.file("libs/ChatFormatter v${project.version}.jar")) | ||
| jvmArgs("-Dcom.mojang.eula.agree=true", "-XX:+AllowEnhancedClassRedefinition") | ||
|
|
||
| javaLauncher.set( | ||
| javaToolchains.launcherFor { | ||
| this.vendor = JvmVendorSpec.JETBRAINS | ||
| this.languageVersion.set(JavaLanguageVersion.of(21)) | ||
| } | ||
| ) | ||
|
|
||
| downloadPlugins { | ||
| this.modrinth("luckperms", "v5.5.0-bukkit") | ||
| this.modrinth("VaultUnlocked", "2.16.0") | ||
| this.modrinth("luckperms", "v5.5.17-bukkit") | ||
| this.modrinth("VaultUnlocked", "2.19.0") | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,11 @@ | ||
| package com.eternalcode.formatter; | ||
|
|
||
| import com.eternalcode.formatter.adventure.AdventureUrlPostProcessor; | ||
| import java.util.Optional; | ||
| import net.kyori.adventure.text.serializer.json.JSONOptions; | ||
| import static net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection; | ||
|
|
||
| import com.eternalcode.formatter.adventure.TextColorTagResolver; | ||
| import com.eternalcode.formatter.legacy.Legacy; | ||
| import com.eternalcode.formatter.placeholder.PlaceholderRegistry; | ||
| import com.eternalcode.formatter.rank.ChatRankProvider; | ||
| import com.eternalcode.formatter.template.TemplateService; | ||
| import com.eternalcode.formatter.placeholder.PlaceholderRegistry; | ||
| import com.google.common.collect.ImmutableMap; | ||
| import net.kyori.adventure.text.Component; | ||
| import net.kyori.adventure.text.format.NamedTextColor; | ||
|
|
@@ -19,11 +15,15 @@ | |
| import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; | ||
| import net.kyori.adventure.text.minimessage.tag.standard.StandardTags; | ||
| import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; | ||
| import net.kyori.adventure.text.serializer.json.JSONOptions; | ||
| import org.bukkit.entity.Player; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.Optional; | ||
|
|
||
| import static net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We dont use static imports |
||
|
|
||
| class ChatHandlerImpl implements ChatHandler { | ||
|
|
||
|
|
@@ -75,7 +75,7 @@ class ChatHandlerImpl implements ChatHandler { | |
| .build(); | ||
|
|
||
| private static final MiniMessage EMPTY_MESSAGE_DESERIALIZER = MiniMessage.builder() | ||
| .postProcessor(new AdventureUrlPostProcessor()) | ||
| .postProcessor(new AdventureUrlPostProcessor()) | ||
| .tags(TagResolver.empty()) | ||
| .build(); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,24 @@ | ||||||
| package com.eternalcode.formatter.mention; | ||||||
|
|
||||||
| import net.dzikoysk.cdn.entity.Contextual; | ||||||
| import net.dzikoysk.cdn.entity.Description; | ||||||
|
|
||||||
| import java.io.Serializable; | ||||||
|
|
||||||
| @Contextual | ||||||
| public class MentionConfig implements Serializable { | ||||||
|
|
||||||
| @Description({ " ", "# Mention system configuration" }) | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| @Description("# When a player mentions another player with @playername, the mentioned player will hear a sound") | ||||||
| public boolean enabled = true; | ||||||
|
|
||||||
| @Description({ " ", "# The sound to play when a player is mentioned" }) | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| @Description("# Available sounds: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Sound.html") | ||||||
| public String sound = "BLOCK_NOTE_BLOCK_PLING"; | ||||||
|
|
||||||
| @Description({ " ", "# The volume of the mention sound (0.0 to 1.0)" }) | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| public float volume = 1.0f; | ||||||
|
|
||||||
| @Description({ " ", "# The pitch of the mention sound (0.5 to 2.0)" }) | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| public float pitch = 1.0f; | ||||||
| } | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comments prbly not needed here