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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
- Template System
- Custom Placeholders System
- Per-permission miniMessages Tags (see permissions below)
- Mentions System - mention players with @playername and they will hear a sound

## 🔗 Useful links:

Expand Down Expand Up @@ -151,6 +152,18 @@ placeholders:
# It is used to shorten the text even more and keep the clean file!
templates:
- "$hoverName($name) -> '<hover:show_text:'<dark_gray>Name: <white>$name<br><br>{rankDescription}<br>{joinDate}<br>{health}<br>{lvl}<br><br>{privateMessage}'><click:suggest_command:'/msg {displayname} '>{displayname}</click></hover>'"

# Mention system settings
mentions:
# When a player mentions another player with @playername, the mentioned player will hear a sound
enabled: true
# The sound to play when a player is mentioned
# Available sounds: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Sound.html
sound: "BLOCK_NOTE_BLOCK_PLING"
# The volume of the mention sound (0.0 to 1.0)
volume: 1.0
# The pitch of the mention sound (0.5 to 2.0)
pitch: 1.0
```


Expand Down
137 changes: 71 additions & 66 deletions build.gradle.kts
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
Expand All @@ -23,110 +24,114 @@ tasks.register<ShadowJar>("shadowChatFormatter") {
this.dependsOn("${targetProject.name}:shadowJar")
}

this.doLast {
this@register.mergeJars(
"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")
}
}
2 changes: 1 addition & 1 deletion buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ repositories {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.3.10")
implementation("com.gradleup.shadow:com.gradleup.shadow.gradle.plugin:9.3.1")
implementation("net.minecrell:plugin-yml:0.6.0")
implementation("de.eldoria.plugin-yml.bukkit:de.eldoria.plugin-yml.bukkit.gradle.plugin:0.8.0")
}
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/eternalcode.java.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ repositories {
maven { url = uri("https://repo.extendedclip.com/content/repositories/placeholderapi/") }
maven { url = uri("https://jitpack.io") }
maven { url = uri("https://repo.eternalcode.pl/releases") }
maven(url = "https://s01.oss.sonatype.org/content/repositories/snapshots/")
maven { url = uri("https://s01.oss.sonatype.org/content/repositories/snapshots/") }
}

java {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.eternalcode.formatter;

import com.eternalcode.formatter.mention.MentionService;
import com.eternalcode.formatter.rank.ChatRankProvider;
import com.eternalcode.formatter.template.TemplateService;
import com.eternalcode.formatter.placeholder.PlaceholderRegistry;
Expand All @@ -14,4 +15,6 @@ public interface ChatFormatterApi {

ChatHandler getChatHandler();

MentionService getMentionService();

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

import com.eternalcode.formatter.config.ConfigManager;
import com.eternalcode.formatter.config.PluginConfig;
import com.eternalcode.formatter.mention.MentionConfig;
import com.eternalcode.formatter.mention.MentionListener;
import com.eternalcode.formatter.mention.MentionService;
import com.eternalcode.formatter.placeholder.ConfiguredReplacer;
import com.eternalcode.formatter.placeholderapi.PlaceholderAPIInitializer;
import com.eternalcode.formatter.placeholder.PlaceholderRegistry;
import com.eternalcode.formatter.placeholderapi.PlaceholderAPIInitializer;
import com.eternalcode.formatter.rank.ChatRankProvider;
import com.eternalcode.formatter.rank.VaultInitializer;
import com.eternalcode.formatter.template.TemplateService;
Expand All @@ -26,6 +29,7 @@ public class ChatFormatterPlugin implements ChatFormatterApi {
private final TemplateService templateService;
private final ChatRankProvider rankProvider;
private final ChatHandler chatHandler;
private final MentionService mentionService;

public ChatFormatterPlugin(Plugin plugin) {
Server server = plugin.getServer();
Expand All @@ -36,6 +40,7 @@ public ChatFormatterPlugin(Plugin plugin) {

PluginConfig pluginConfig = configManager.getPluginConfig();

// PlaceholderAPI support
this.placeholderRegistry = new PlaceholderRegistry();
PlaceholderAPIInitializer.initialize(server, this.placeholderRegistry);
this.placeholderRegistry.addReplacer(new ConfiguredReplacer(pluginConfig));
Expand All @@ -52,6 +57,12 @@ public ChatFormatterPlugin(Plugin plugin) {
this.chatHandler = new ChatHandlerImpl(miniMessage, pluginConfig, this.rankProvider, this.placeholderRegistry, this.templateService);

server.getPluginCommand("chatformatter").setExecutor(new ChatFormatterCommand(configManager, audienceProvider, miniMessage));

// Mentions
this.mentionService = new MentionService(server, pluginConfig);
server.getPluginManager().registerEvents(new MentionListener(mentionService), plugin);

// Update checker
server.getPluginManager().registerEvents(new UpdaterController(updaterService, pluginConfig, audienceProvider, miniMessage), plugin);

ChatFormatterApiProvider.enable(this);
Expand Down Expand Up @@ -83,4 +94,9 @@ public ChatHandler getChatHandler() {
return this.chatHandler;
}

@Override
public MentionService getMentionService() {
return this.mentionService;
}

}
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;
Expand All @@ -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;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We dont use static imports


class ChatHandlerImpl implements ChatHandler {

Expand Down Expand Up @@ -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();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.eternalcode.formatter.config;

import com.eternalcode.formatter.mention.MentionConfig;
import com.eternalcode.formatter.template.Template;
import com.eternalcode.formatter.template.TemplateRepository;
import com.google.common.collect.ImmutableList;
Expand Down Expand Up @@ -83,6 +84,9 @@ public class PluginConfig implements ChatSettings, TemplateRepository {
.add(Template.of("hoverName", List.of("name"), "<hover:show_text:'<dark_gray>Name: <white>$name<br><br>{rankDescription}<br>{joinDate}<br>{health}<br>{lvl}<br><br>{privateMessage}'><click:suggest_command:'/msg {displayname} '>{displayname}</click></hover>"))
.build();

@Description({ " ", "# Mention system settings" })
public MentionConfig mentions = new MentionConfig();


@Override
public boolean isReceiveUpdates() {
Expand All @@ -98,4 +102,5 @@ public String getRawFormat(String rank) {
public List<Template> getTemplates() {
return this.templates;
}

}
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" })
@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" })
@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)" })
public float volume = 1.0f;

@Description({ " ", "# The pitch of the mention sound (0.5 to 2.0)" })
public float pitch = 1.0f;
}
Loading
Loading