This repository has been archived by the owner on Jan 20, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Features: add custom advancement messages
- Loading branch information
Showing
9 changed files
with
451 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} | ||
} | ||
|
153 changes: 153 additions & 0 deletions
153
src/main/java/net/flectone/listeners/PlayerAdvancementDoneListener.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
Oops, something went wrong.