Skip to content
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

GH-125 expand default config and PlaceholderAPI support in internal placeholders #125

Merged
merged 7 commits into from
Jun 2, 2024
Merged
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
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();
}

}