Skip to content
This repository has been archived by the owner on Jan 20, 2024. It is now read-only.

Commit

Permalink
Features: add custom advancement messages
Browse files Browse the repository at this point in the history
  • Loading branch information
TheFaser committed Aug 5, 2023
1 parent 086fe47 commit 3a3ee1d
Show file tree
Hide file tree
Showing 9 changed files with 451 additions and 78 deletions.
2 changes: 2 additions & 0 deletions src/main/java/net/flectone/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import net.flectone.integrations.supervanish.FSuperVanish;
import net.flectone.integrations.vault.FVault;
import net.flectone.integrations.voicechats.simplevoicechat.RegisterSimpleVoiceChat;
import net.flectone.listeners.PlayerAdvancementDoneListener;
import net.flectone.listeners.PlayerDeathEventListener;
import net.flectone.managers.FPlayerManager;
import net.flectone.managers.FileManager;
Expand Down Expand Up @@ -75,6 +76,7 @@ public void onEnable() {

TickerManager.start();
PlayerDeathEventListener.reload();
PlayerAdvancementDoneListener.reload();

info("✔ Plugin enabled");

Expand Down
2 changes: 2 additions & 0 deletions src/main/java/net/flectone/commands/CommandFlectonechat.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import net.flectone.Main;
import net.flectone.custom.FCommands;
import net.flectone.custom.FTabCompleter;
import net.flectone.listeners.PlayerAdvancementDoneListener;
import net.flectone.listeners.PlayerDeathEventListener;
import net.flectone.managers.FPlayerManager;
import net.flectone.managers.FileManager;
Expand Down Expand Up @@ -83,6 +84,7 @@ public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command
MessageBuilder.loadPatterns();

PlayerDeathEventListener.reload();
PlayerAdvancementDoneListener.reload();

fCommand.sendMeMessage("command.flectonechat.message");

Expand Down
25 changes: 25 additions & 0 deletions src/main/java/net/flectone/custom/AdvancementType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package net.flectone.custom;

import javax.annotation.Nullable;
import java.util.Arrays;

public enum AdvancementType {
UNKNOWN,
TASK,
GOAL,
CHALLENGE;

public static AdvancementType getType(@Nullable String name) {
if (name == null) return UNKNOWN;

return Arrays.stream(values()).parallel()
.filter(type -> type.toString().equalsIgnoreCase(name))
.findFirst()
.orElse(UNKNOWN);
}

@Override
public String toString(){
return name().toLowerCase();
}
}
159 changes: 159 additions & 0 deletions src/main/java/net/flectone/custom/FAdvancement.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package net.flectone.custom;

import net.flectone.utils.NMSUtil;
import org.bukkit.advancement.Advancement;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;

import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

// Thanks, @CroaBeast, for these methods
// Source https://github.com/CroaBeast/AdvancementInfo

public class FAdvancement {
private final Advancement adv;

private String toChat = null, hidden = null, parent = null;

private AdvancementType type = AdvancementType.UNKNOWN;

private Object requirements = null;

private ItemStack item = null;
private Object rewards = null, criteria = null;

private static final String COMP_CLASS = "IChatBaseComponent";

private String translateKey;
private String translateDesc;

private String title;

public FAdvancement(@NotNull Advancement adv) {
this.adv = adv;

Class<?> craftClass = net.flectone.utils.NMSUtil.getBukkitClass("advancement.CraftAdvancement");
if (craftClass == null) return;

Object nmsAdv = net.flectone.utils.NMSUtil.getObject(craftClass, craftClass.cast(adv), "getHandle");
Object display = net.flectone.utils.NMSUtil.getObject(nmsAdv, is_19_4() ? "d" : "c");
if (display == null) return;

Object rawTitle = net.flectone.utils.NMSUtil.getObject(display, "a");
Object rawDesc = net.flectone.utils.NMSUtil.getObject(display, "b");

translateKey = String.valueOf(net.flectone.utils.NMSUtil.getObject(net.flectone.utils.NMSUtil.getObject(rawTitle, "b"), "a"));
translateDesc = String.valueOf(net.flectone.utils.NMSUtil.getObject(net.flectone.utils.NMSUtil.getObject(rawDesc, "b"), "a"));

Field itemField = null;
try {
itemField = display.getClass().getDeclaredField("c");
} catch (Exception e) {
e.printStackTrace();
}

Object nmsItemStack = null;
if (itemField != null) {
try {
itemField.setAccessible(true);
nmsItemStack = itemField.get(display);
itemField.setAccessible(false);
} catch (Exception e) {
e.printStackTrace();
}
}

String typeName = net.flectone.utils.NMSUtil.checkValue(net.flectone.utils.NMSUtil.getObject(display, "e"), "PROGRESS");
this.type = AdvancementType.getType(typeName);

parent = net.flectone.utils.NMSUtil.checkValue(net.flectone.utils.NMSUtil.getObject(nmsAdv, "b", "getName"), "null");
toChat = net.flectone.utils.NMSUtil.checkValue(net.flectone.utils.NMSUtil.getObject(display, "i"));
hidden = NMSUtil.checkValue(net.flectone.utils.NMSUtil.getObject(display, "j"));

item = net.flectone.utils.NMSUtil.getBukkitItem(nmsItemStack);
requirements = net.flectone.utils.NMSUtil.getObject(nmsAdv, is_19_4() ? "j" : "i");
rewards = net.flectone.utils.NMSUtil.getObject(nmsAdv, is_19_4() ? "e" : "d");
criteria = net.flectone.utils.NMSUtil.getObject(nmsAdv, is_19_4() ? "g" :
(net.flectone.utils.NMSUtil.getVersion() < 18 ? "getCriteria" : "f"));

Class<?> chatClass = net.flectone.utils.NMSUtil.getVersion() >= 17 ?
net.flectone.utils.NMSUtil.getNMSClass("net.minecraft.network.chat", COMP_CLASS, false) :
net.flectone.utils.NMSUtil.getNMSClass(null, COMP_CLASS, true);

if (chatClass != null) {
String method = net.flectone.utils.NMSUtil.getVersion() < 13 ? "toPlainText" : "getString";
title = String.valueOf(net.flectone.utils.NMSUtil.getObject(chatClass, rawTitle, method));
}
}

public String getTitle() {
return title;
}

public String getTranslateKey() {
return translateKey;
}

public String getTranslateDesc() {
return translateDesc;
}

private static boolean is_19_4() {
return net.flectone.utils.NMSUtil.getVersion() >= 19.4;
}

@NotNull
public Advancement getBukkit() {
return adv;
}

@NotNull
public AdvancementType getType() {
return type;
}

private static boolean getBool(String string) {
return string.matches("(?i)true|false") && string.matches("(?i)true");
}

public boolean announceToChat() {
return getBool(toChat);
}

public boolean isHidden() {
return getBool(hidden);
}

@Nullable
public ItemStack getItem() {
return item;
}

@Nullable
public Object getRewards() {
return rewards;
}

@SuppressWarnings("unchecked")
@NotNull
public Map<String, Object> getCriteria() {
try {
return criteria == null ? new HashMap<>() : (Map<String, Object>) criteria;
} catch (Exception e) {
return new HashMap<>();
}
}

@Nullable
public String[][] getRequirements() {
try {
return (String[][]) requirements;
} catch (Exception e) {
return null;
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package net.flectone.listeners;

import net.flectone.Main;
import net.flectone.integrations.discordsrv.FDiscordSRV;
import net.flectone.integrations.supervanish.FSuperVanish;
import net.flectone.managers.FPlayerManager;
import net.flectone.utils.ObjectUtil;
import net.flectone.custom.AdvancementType;
import net.flectone.custom.FAdvancement;
import net.md_5.bungee.api.chat.*;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.GameRule;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerAdvancementDoneEvent;

import java.util.ArrayList;
import java.util.List;

public class PlayerAdvancementDoneListener implements Listener {

private static PlayerAdvancementDoneListener instance;

public PlayerAdvancementDoneListener() {
instance = this;
}

public static void unregister() {
if (instance == null) return;
PlayerAdvancementDoneEvent.getHandlerList().unregister(instance);
}

public static void register() {
if (instance != null) return;
Bukkit.getPluginManager().registerEvents(new PlayerAdvancementDoneListener(), Main.getInstance());
}

public static void reload() {
boolean isEnable = Main.config.getBoolean("advancement.message.enable");
if (isEnable) register();
else unregister();

Bukkit.getWorlds().stream()
.forEach(world -> setVisibleDefaultAnnounce(world, !isEnable));
}


@EventHandler
public void onPlayerAdvancementDone(PlayerAdvancementDoneEvent event){
String key = event.getAdvancement().getKey().getKey();
if (key.contains("recipe/") || key.contains("recipes/")) return;

Player player = event.getPlayer();

if(FSuperVanish.isVanished(player)) return;

FAdvancement fAdvancement = new FAdvancement(event.getAdvancement());
AdvancementType advancementType = fAdvancement.getType();

if(advancementType == AdvancementType.UNKNOWN || fAdvancement.isHidden() || !fAdvancement.announceToChat()) return;

String formatMessage = Main.locale.getString("advancement." + advancementType + ".name");
ArrayList<String> placeholders = new ArrayList<>(List.of("<player>", "<advancement>"));

FDiscordSRV.sendAdvancementMessage(player, fAdvancement, formatMessage);

Bukkit.getOnlinePlayers().parallelStream()
.filter(recipient -> !FPlayerManager.getPlayer(recipient).isIgnored(player))
.forEach(recipient -> {
String string = ObjectUtil.formatString(formatMessage, recipient, player);
ArrayList<String> finalPlaceholders = ObjectUtil.splitLine(string, placeholders);
recipient.spigot().sendMessage(createAdvancementComponent(finalPlaceholders, recipient, player, fAdvancement));
});
}

private BaseComponent[] createAdvancementComponent(ArrayList<String> placeholders, CommandSender recipient, CommandSender sender, FAdvancement fAdvancement){
String mainColor = "";
ComponentBuilder mainBuilder = new ComponentBuilder();
for (String mainPlaceholder : placeholders) {

switch(mainPlaceholder){
case "<player>":
mainBuilder.append(createClickableComponent(mainColor, sender, recipient));
break;
case "<advancement>":
TranslatableComponent translatableComponent = new TranslatableComponent(fAdvancement.getTranslateKey());

String hover = Main.locale.getFormatString("advancement." + fAdvancement.getType() + ".hover", recipient, sender);

String hoverColor = "";
ComponentBuilder hoverBuilder = new ComponentBuilder();

for(String hoverPlaceholder : ObjectUtil.splitLine(hover, new ArrayList<>(List.of("<name>", "<description>")))){
switch(hoverPlaceholder){
case "<name>":
hoverBuilder.append(TextComponent.fromLegacyText(hoverColor));
hoverBuilder.append(new TranslatableComponent(fAdvancement.getTranslateKey()));
hoverBuilder.append(TextComponent.fromLegacyText(hoverColor));
break;
case "<description>":
hoverBuilder.append(TextComponent.fromLegacyText(hoverColor));
hoverBuilder.append(new TranslatableComponent(fAdvancement.getTranslateDesc()));
hoverBuilder.append(TextComponent.fromLegacyText(hoverColor));
break;
default:
hoverBuilder.append(TextComponent.fromLegacyText(hoverColor + hoverPlaceholder), ComponentBuilder.FormatRetention.NONE);
break;
}

hoverColor = ChatColor.getLastColors(hoverColor + hoverBuilder.getCurrentComponent().toString());
}

translatableComponent.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, hoverBuilder.create()));

mainBuilder.append(TextComponent.fromLegacyText(mainColor));
mainBuilder.append(translatableComponent);
mainBuilder.append(TextComponent.fromLegacyText(mainColor));
break;
default:
mainBuilder.append(TextComponent.fromLegacyText(mainColor + mainPlaceholder), ComponentBuilder.FormatRetention.NONE);
break;
}

mainColor = ChatColor.getLastColors(mainColor + mainBuilder.getCurrentComponent().toString());

}

return mainBuilder.create();
}

private TextComponent createClickableComponent(String chatColor, CommandSender sender, CommandSender recipient) {
String playerName = sender.getName();
String suggestCommand = "/msg " + playerName + " ";
String showText = Main.locale.getFormatString("player.hover-message", recipient, sender)
.replace("<player>", playerName);

TextComponent textComponent = new TextComponent(TextComponent.fromLegacyText(chatColor + playerName));
textComponent.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, suggestCommand));
textComponent.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.fromLegacyText(showText)));
return textComponent;
}

private static void setVisibleDefaultAnnounce(World world, boolean visible){
Object value = world.getGameRuleValue(GameRule.ANNOUNCE_ADVANCEMENTS);
if(value == null) return;

world.setGameRule(GameRule.ANNOUNCE_ADVANCEMENTS, visible);
}
}

0 comments on commit 3a3ee1d

Please sign in to comment.