Skip to content

Commit

Permalink
GH-125 expand default config and PlaceholderAPI support in internal p…
Browse files Browse the repository at this point in the history
…laceholders (#125)

* add PlaceholderAPI support in internal placeholders
expand default config

* more config description

* literoofkey fix

* second lang fix

* Revert placeholder registry changes.

* Move papi dependency from config class (see revert) to ConfiguredPlaceholderAPIStack class.

* Fix bug, add unit tests.

---------

Co-authored-by: Rollczi <[email protected]>
  • Loading branch information
Kamicjusz and Rollczi authored Jun 2, 2024
1 parent 6236bfc commit 39cfdc9
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 37 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ runPaper {
}

tasks.runServer {
minecraftVersion("1.20.1")
minecraftVersion("1.20.4")
dependsOn("shadowAll")
pluginJars = files("/build/libs/ChatFormatter v${project.version}.jar")
}
5 changes: 5 additions & 0 deletions chatformatter-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ dependencies {

// JUnit 5
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.2")
testImplementation("org.junit.jupiter:junit-jupiter-params:5.10.2")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.2")
testImplementation("org.mockito:mockito-core:5.12.0")
testImplementation("org.mockito:mockito-junit-jupiter:5.12.0")
testImplementation("me.clip:placeholderapi:2.11.5")
testImplementation("org.assertj:assertj-core:3.26.0")
}

tasks {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.eternalcode.formatter.config.PluginConfig;
import com.eternalcode.formatter.legacy.LegacyPostProcessor;
import com.eternalcode.formatter.legacy.LegacyPreProcessor;
import com.eternalcode.formatter.placeholder.ConfiguredPlaceholderAPIStack;
import com.eternalcode.formatter.placeholder.PlaceholderAPIStack;
import com.eternalcode.formatter.placeholder.PlaceholderRegistry;
import com.eternalcode.formatter.rank.ChatRankProvider;
Expand Down Expand Up @@ -39,7 +40,7 @@ public ChatFormatterPlugin(Plugin plugin) {
PluginConfig pluginConfig = configManager.getPluginConfig();

this.placeholderRegistry = new PlaceholderRegistry();
this.placeholderRegistry.stack(pluginConfig);
this.placeholderRegistry.playerStack(new ConfiguredPlaceholderAPIStack(pluginConfig));
this.placeholderRegistry.playerStack(new PlaceholderAPIStack());
this.templateService = new TemplateService(pluginConfig);
this.rankProvider = new VaultRankProvider(server);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.eternalcode.formatter.ChatSettings;
import com.eternalcode.formatter.placeholder.PlaceholderStack;
import net.dzikoysk.cdn.entity.Description;

import java.util.List;
import java.util.Map;

public class PluginConfig implements ChatSettings, PlaceholderStack, TemplateRepository {
public class PluginConfig implements ChatSettings, TemplateRepository {

@Description(" ")
@Description("# ____ _ _ _____ ChatFormatter _ _ ")
Expand All @@ -28,8 +27,10 @@ public class PluginConfig implements ChatSettings, PlaceholderStack, TemplateRep
@Description({ " ", "# Chat format for ranks (Vault) Support mini-messages and legacy colors" })
@Description({ " ", "# We're recommending to use webui for mini-messages: https://webui.adventure.kyori.net/" })
@Description({ " ", "# documentation is here: https://docs.adventure.kyori.net/minimessage/format.html" })
@Description({ " ", "# You can check LuckPerms setup and placeholders here: https://luckperms.net/wiki/Placeholders" })

@Description({
"# ",
"# Example usages:",
"# ",
"# Hover message:",
Expand All @@ -44,31 +45,43 @@ public class PluginConfig implements ChatSettings, PlaceholderStack, TemplateRep
"# RGB and gradient message usage: ",
"# <color:#ff00ee>Example message</color>",
"# <gradient:#ff00ee:#f79459>Example message</gradient>",
" "
"# ",
"# You can use three more internal placeholders: <displayname> <name> <message>",
"# "
})
public String defaultFormat = "{displayname} {arrow_right} {message}";
public String defaultFormat = "{displayname} » {message}";
@Description({ " ", "# Here you can set different formats for each rank.",
"# Remember! Rank name must be exactly the same as in you permission plugin configuration.",
"# If player have more than one rank remember to correctly setup rank weight configuration" })
public Map<String, String> format = new ImmutableMap.Builder<String, String>()
.put("default", "{member} &f{displayname} &8{arrow_right} {message} ")
.put("admin", "$template({admin}, &c)")
.build();


@Description({ " ", "# It is used to shorten the text even more and keep the clean file!" })
public List<Template> templates = new ImmutableList.Builder<Template>()
.add(Template.of("template", List.of("rank", "color"), "$rank $color{displayname} &8{arrow_right} $color{message}"))
.build();

@Description({ " ", "# Placeholders, it allows you to make a shorter text, you can use some prefixes, characters etc. " })
.put("default", "{member} &7$hoverName({displayname}) &8» <gradient:#d4d4d4:white>{message} ")
.put("vip", "{vip} &f$hoverName({displayname}) <dark_gray>» <gradient:#ffd270:white>{message}")
.put("mod", "{mod} &f$hoverName({displayname}) <dark_gray>» <gradient:#a3ff9e:white>{message}")
.put("admin", "{admin} &f$hoverName({displayname}) <dark_gray>» <gradient:#bac8ff:white><b>{message}")
.put("owner", "{owner} &f$hoverName({displayname}) <dark_gray>» <gradient:#ff9195:white><b>{message}")
.build();

@Description({ " ", "# Placeholders, it allows you to make a shorter text, you can use some prefixes, characters etc. ", "# You can use here PAPI placeholders." })
public Map<String, String> placeholders = new ImmutableMap.Builder<String, String>()
.put("{displayname}", "<displayname>")
.put("{name}", "<name>")
.put("{message}", "<message>")
.put("{prefix}", "<b><gradient:#29fbff:#38b3ff>ChatFormatter</gradient></b>")
.put("{member}", "<b><color:#6e6764>Member</color></b>")
.put("{admin}", "<b><color:#ff4400>Admin</color></b>")
.put("{arrow_right}", "»")
.put("{arrow_left}", "«")
.build();
.put("{displayname}", "<displayname>")
.put("{name}", "<name>")
.put("{message}", "<message>")
.put("{member}", "<#6e6764>Member")
.put("{vip}", "<gold>VIP")
.put("{mod}", "<b><#00c900>Mod</b>")
.put("{admin}", "<b><#6e86ff>Admin</b>")
.put("{owner}", "<b><gradient:#c40000:#e04b4b>Owner</b>")
.put("{rankDescription}", "<dark_gray>Rank: <white>%vault_group%")
.put("{joinDate}", "<dark_gray>Joined: <white>%player_first_join_date%")
.put("{health}", "<dark_gray>Health: <red>%player_health%")
.put("{lvl}", "<dark_gray>LVL: <gold>%player_level%")
.put("{privateMessage}", "<gradient:#36ff39:#75ff75><i>Click to send private message</i></gradient>")
.build();

@Description({ " ", "# This section is made for experienced users" , "# It is used to shorten the text even more and keep the clean file!" })
public List<Template> templates = new ImmutableList.Builder<Template>()
.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();


@Override
Expand All @@ -81,17 +94,6 @@ public String getRawFormat(String rank) {
return this.format.getOrDefault(rank, this.defaultFormat);
}

@Override
public String apply(String text) {
String value = text;

for (Map.Entry<String, String> entry : this.placeholders.entrySet()) {
value = value.replace(entry.getKey(), entry.getValue());
}

return value;
}

@Override
public List<Template> getTemplates() {
return this.templates;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.eternalcode.formatter.placeholder;

import com.eternalcode.formatter.config.PluginConfig;
import java.util.Map;
import me.clip.placeholderapi.PlaceholderAPI;
import org.bukkit.entity.Player;

public class ConfiguredPlaceholderAPIStack implements PlayerPlaceholderStack {

private final PluginConfig pluginConfig;

public ConfiguredPlaceholderAPIStack(PluginConfig pluginConfig) {
this.pluginConfig = pluginConfig;
}

@Override
public String apply(String text, Player target) {
String value = text;

for (Map.Entry<String, String> entry : this.pluginConfig.placeholders.entrySet()) {
value = value.replace(entry.getKey(), entry.getValue());
}

value = PlaceholderAPI.setPlaceholders(target, value);

return value;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.eternalcode.formatter.placeholder;

import com.eternalcode.formatter.config.PluginConfig;
import com.eternalcode.formatter.template.TemplateService;
import me.clip.placeholderapi.PlaceholderAPI;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import org.bukkit.entity.Player;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.isNull;
import org.mockito.MockedStatic;
import static org.mockito.Mockito.mockStatic;

class PapiPlaceholdersTest {

private static MockedStatic<PlaceholderAPI> mockStatic;

private static PlaceholderRegistry registry;
private static TemplateService templateService;
private static PluginConfig pluginConfig;

@BeforeAll
static void setUpBeforeClass() {
pluginConfig = new PluginConfig();
registry = new PlaceholderRegistry();
templateService = new TemplateService(pluginConfig);

registry.playerStack(new ConfiguredPlaceholderAPIStack(pluginConfig));
registry.playerStack(new PlaceholderAPIStack());
}

@BeforeEach
void setUp() { // mock the PlaceholderAPI plugin (staic methods)
mockStatic = mockStatic(PlaceholderAPI.class);
mockStatic.when(() -> PlaceholderAPI.setPlaceholders(isNull(Player.class), anyString())).thenAnswer(invocation -> invocation.<String>getArgument(1)
.replace("%vault_group%", "--VIP--")
.replace("%player_first_join_date%", "2021-01-01")
.replace("%player_health%", "19")
.replace("%player_level%", "420"));
}

@Test
void test() {
String text = "Hello %player_name%, you joined on %player_first_join_date% and you are in the %vault_group% group. Your health is %player_health% and your level is %player_level%.";
String result = registry.format(text, null);

assertThat(result)
.isEqualTo("Hello %player_name%, you joined on 2021-01-01 and you are in the --VIP-- group. Your health is 19 and your level is 420.");
}


@ParameterizedTest
@ValueSource(strings = {"default", "vip", "mod", "admin", "owner"})
void testFormatFromConfig(String rank) {
String rawFormat = pluginConfig.getRawFormat(rank);
String formattedString = templateService.applyTemplates(rawFormat);
String result = registry.format(formattedString, null);

assertThat(result)
.contains("19", "420", "2021-01-01", "--VIP--")
.doesNotContain("%", "{", "}");
}


@Test
void testFormatFromConfigUnknown() {
String rawFormat = pluginConfig.getRawFormat("unknown");
String formattedString = templateService.applyTemplates(rawFormat);
String result = registry.format(formattedString, null);

assertThat(result)
.doesNotContain("%", "{", "}");
}

@AfterEach
void tearDownAfterClass() {
mockStatic.close();
}

}

0 comments on commit 39cfdc9

Please sign in to comment.