9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-25 18:09:27 +00:00

Merge branch 'Xiao-MoMi:dev' into dev

This commit is contained in:
jhqwqmc
2025-04-10 02:41:14 +08:00
committed by GitHub
15 changed files with 288 additions and 77 deletions

View File

@@ -0,0 +1,26 @@
templates:
default:emoji/basic:
content: "<hover:show_text:'<i18n:emoji.tip>'><arg:emoji></hover>"
default:emoji/addition_info:
content: "<hover:show_text:'<i18n:emoji.tip>'>{text}<arg:emoji></hover>"
emoji:
default:emoji_location:
template: "default:emoji/addition_info"
arguments:
text: "<i18n:emoji.location>"
overrides:
image: "default:icons:0:0"
permission: emoji.location
keywords:
- ":location:"
- ":pos:"
default:emoji_time:
template: "default:emoji/addition_info"
arguments:
text: "<i18n:emoji.time>"
overrides:
image: "default:icons:0:1"
permission: emoji.time
keywords:
- ":time:"

View File

@@ -39,6 +39,9 @@ i18n:
category.topaz: "Topaz"
category.furniture: "Furniture"
category.misc: "Misc"
emoji.tip: "Use <yellow>'<arg:keyword>'</yellow> to send the '<arg:emoji>' emoji"
emoji.time: "<bold>Current time: <papi:player_world_time_12></bold>"
emoji.location: "<bold>Current coordinates: <papi:player_x>,<papi:player_y>,<papi:player_z></bold>"
zh_cn:
item.chinese_lantern: "灯笼"
item.fairy_flower: "仙灵花"
@@ -78,4 +81,7 @@ i18n:
category.palm_tree: "棕榈树"
category.topaz: "黄玉"
category.furniture: "家具"
category.misc: "杂项"
category.misc: "杂项"
emoji.tip: "使用<yellow>'<arg:keyword>'</yellow>来发送表情'<arg:emoji>'"
emoji.time: "<bold>当前时间: <papi:player_world_time_12></bold>"
emoji.location: "<bold>当前坐标: <papi:player_x>,<papi:player_y>,<papi:player_z></bold>"

View File

@@ -102,4 +102,7 @@ warning.config.block.state.model.lack_path: "<yellow>Issue found in file <arg:0>
warning.config.block.state.model.invalid_resource_location: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' has a 'path' argument [<arg:2>] that contains legal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters</yellow>"
warning.config.model.generation.conflict: "<yellow>Issue found in file <arg:0> - Failed to generate model for '<arg:1>' as two or more configurations attempt to generate different json models with the same path: '<arg:2>'</yellow>"
warning.config.model.generation.texture.invalid_resource_location: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' has a '<arg:2>' texture argument [<arg:3>] that contains legal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters</yellow>"
warning.config.model.generation.parent.invalid_resource_location: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' has a parent argument [<arg:2>] that contains legal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters</yellow>"
warning.config.model.generation.parent.invalid_resource_location: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' has a parent argument [<arg:2>] that contains legal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters</yellow>"
warning.config.emoji.lack_keywords: "<yellow>Issue found in file <arg:0> - The emoji '<arg:1>' is missing the required 'keywords' argument.</yellow>"
warning.config.emoji.duplicated: "<yellow>Issue found in file <arg:0> - Duplicated emoji '<arg:1>'.</yellow>"
warning.config.emoji.invalid_image: "<yellow>Issue found in file <arg:0> - The emoji '<arg:1>' has an invalid 'image' argument '<arg:2>'.</yellow>"

View File

@@ -102,4 +102,7 @@ warning.config.block.state.model.lack_path: "<yellow>在文件 <arg:0> 中发现
warning.config.block.state.model.invalid_resource_location: "<yellow>在文件 <arg:0> 中发现问题 - 方块 '<arg:1>' 的 'path' 路径参数 [<arg:2>] 包含非法字符请参考资源路径规范https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6</yellow>"
warning.config.model.generation.conflict: "<yellow>在文件 <arg:0> 中发现问题 - 无法为 '<arg:1>' 生成模型,多个配置尝试用相同路径 '<arg:2>' 生成不同的JSON模型</yellow>"
warning.config.model.generation.texture.invalid_resource_location: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 的 '<arg:2>' 纹理参数 [<arg:3>] 包含非法字符请参考资源路径规范https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6</yellow>"
warning.config.model.generation.parent.invalid_resource_location: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 的父模型参数 [<arg:2>] 包含非法字符请参考资源路径规范https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6</yellow>"
warning.config.model.generation.parent.invalid_resource_location: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 的父模型参数 [<arg:2>] 包含非法字符请参考资源路径规范https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6</yellow>"
warning.config.emoji.lack_keywords: "<yellow>在文件 <arg:0> 中发现问题 - 表情 '<arg:1>' 缺少必要的 'keywords' 配置</yellow>"
warning.config.emoji.duplicated: "<yellow>在文件 <arg:0> 中发现问题 - 表情 '<arg:1>' 重复定义</yellow>"
warning.config.emoji.invalid_image: "<yellow>在文件 <arg:0> 中发现问题 - 表情 '<arg:1>' 使用了无效的 'image' 图片参数 '<arg:2>'.</yellow>"

View File

@@ -2,7 +2,6 @@ package net.momirealms.craftengine.bukkit.font;
import io.papermc.paper.event.player.AsyncChatCommandDecorateEvent;
import io.papermc.paper.event.player.AsyncChatDecorateEvent;
import io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent;
import net.kyori.adventure.text.Component;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.util.ComponentUtils;
@@ -17,11 +16,10 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.function.Consumer;
public class BukkitFontManager extends AbstractFontManager implements Listener {
private final BukkitCraftEngine plugin;
@@ -59,10 +57,12 @@ public class BukkitFontManager extends AbstractFontManager implements Listener {
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onCommand(PlayerCommandPreprocessEvent event) {
if (!Config.filterCommand()) return;
if (event.getPlayer().hasPermission(FontManager.BYPASS_COMMAND)) {
return;
if (!event.getPlayer().hasPermission(FontManager.BYPASS_COMMAND)) {
IllegalCharacterProcessResult result = processIllegalCharacters(event.getMessage());
if (result.has()) {
event.setMessage(result.newText());
}
}
runIfContainsIllegalCharacter(event.getMessage(), event::setMessage);
}
@SuppressWarnings("UnstableApiUsage")
@@ -71,23 +71,28 @@ public class BukkitFontManager extends AbstractFontManager implements Listener {
if (player == null) return;
try {
Object originalMessage = Reflections.field$AsyncChatDecorateEvent$originalMessage.get(event);
String jsonMessage = ComponentUtils.paperAdventureToJson(originalMessage);
String rawJsonMessage = ComponentUtils.paperAdventureToJson(originalMessage);
String jsonMessage = replaceJsonEmoji(rawJsonMessage, this.plugin.adapt(player));
boolean hasChanged = !rawJsonMessage.equals(jsonMessage);
if (!player.hasPermission(FontManager.BYPASS_CHAT)) {
runIfContainsIllegalCharacter(jsonMessage, (json) -> {
Object component = ComponentUtils.jsonToPaperAdventure(json);
try {
Reflections.method$AsyncChatDecorateEvent$result.invoke(event, component);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
});
IllegalCharacterProcessResult result = processIllegalCharacters(jsonMessage);
if (result.has()) {
Object component = ComponentUtils.jsonToPaperAdventure(result.newText());
Reflections.method$AsyncChatDecorateEvent$result.invoke(event, component);
} else if (hasChanged) {
Object component = ComponentUtils.jsonToPaperAdventure(jsonMessage);
Reflections.method$AsyncChatDecorateEvent$result.invoke(event, component);
}
} else if (hasChanged) {
Object component = ComponentUtils.jsonToPaperAdventure(jsonMessage);
Reflections.method$AsyncChatDecorateEvent$result.invoke(event, component);
}
} catch (IllegalAccessException e) {
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
private void runIfContainsIllegalCharacter(String raw, Consumer<String> callback) {
private IllegalCharacterProcessResult processIllegalCharacters(String raw) {
boolean hasIllegal = false;
// replace illegal image usage
Map<String, Component> tokens = matchTags(raw);
@@ -113,11 +118,24 @@ public class BukkitFontManager extends AbstractFontManager implements Listener {
hasIllegal = true;
}
}
if (hasIllegal) {
callback.accept(new String(newCodepoints, 0, newCodepoints.length));
return IllegalCharacterProcessResult.has(new String(newCodepoints, 0, newCodepoints.length));
}
} else if (hasIllegal) {
callback.accept(raw);
return IllegalCharacterProcessResult.has(raw);
}
return IllegalCharacterProcessResult.not();
}
public record IllegalCharacterProcessResult(boolean has, String newText) {
public static IllegalCharacterProcessResult has(String newText) {
return new IllegalCharacterProcessResult(true, newText);
}
public static IllegalCharacterProcessResult not() {
return new IllegalCharacterProcessResult(false, null);
}
}
}

View File

@@ -1,6 +1,7 @@
package net.momirealms.craftengine.core.font;
import net.kyori.adventure.text.Component;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.pack.LoadingSequence;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.pack.ResourceLocation;
@@ -8,6 +9,8 @@ import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser;
import net.momirealms.craftengine.core.plugin.locale.TranslationManager;
import net.momirealms.craftengine.core.util.*;
import net.momirealms.craftengine.core.util.context.ContextHolder;
import net.momirealms.craftengine.core.util.context.PlayerContext;
import org.ahocorasick.trie.Token;
import org.ahocorasick.trie.Trie;
@@ -28,8 +31,10 @@ public abstract class AbstractFontManager implements FontManager {
private final EmojiParser emojiParser;
private OffsetFont offsetFont;
private Trie trie;
private Trie imageTagTrie;
private Trie emojiKeywordTrie;
private Map<String, Component> tagMapper;
private Map<String, Emoji> emojiMapper;
public AbstractFontManager(CraftEngine plugin) {
this.plugin = plugin;
@@ -49,15 +54,16 @@ public abstract class AbstractFontManager implements FontManager {
this.fonts.clear();
this.images.clear();
this.illegalChars.clear();
this.emojis.clear();
}
@Override
public Map<String, Component> matchTags(String json) {
if (this.trie == null) {
if (this.imageTagTrie == null) {
return Collections.emptyMap();
}
Map<String, Component> tags = new HashMap<>();
for (Token token : this.trie.tokenize(json)) {
for (Token token : this.imageTagTrie.tokenize(json)) {
if (token.isMatch()) {
tags.put(token.getFragment(), this.tagMapper.get(token.getFragment()));
}
@@ -67,11 +73,11 @@ public abstract class AbstractFontManager implements FontManager {
@Override
public String stripTags(String text) {
if (this.trie == null) {
if (this.imageTagTrie == null) {
return text;
}
StringBuilder builder = new StringBuilder();
for (Token token : this.trie.tokenize(text)) {
for (Token token : this.imageTagTrie.tokenize(text)) {
if (token.isMatch()) {
builder.append("*");
} else {
@@ -81,6 +87,58 @@ public abstract class AbstractFontManager implements FontManager {
return builder.toString();
}
@Override
public String replaceMiniMessageEmoji(String miniMessage, Player player) {
if (this.emojiKeywordTrie == null) {
return miniMessage;
}
for (Token token : this.emojiKeywordTrie.tokenize(miniMessage)) {
if (!token.isMatch()) continue;
Emoji emoji = this.emojiMapper.get(token.getFragment());
if (emoji == null) continue;
Component content = AdventureHelper.miniMessage().deserialize(
emoji.content(),
PlayerContext.of(player, ContextHolder.builder()
.withOptionalParameter(EmojiParameters.EMOJI, emoji.emojiImage())
.withParameter(EmojiParameters.KEYWORD, emoji.keywords().get(0))
.build()).tagResolvers()
);
miniMessage = miniMessage.replace(token.getFragment(), AdventureHelper.componentToMiniMessage(content));
}
return miniMessage;
}
@Override
public String replaceJsonEmoji(String jsonText, Player player) {
if (this.emojiKeywordTrie == null) {
return jsonText;
}
Map<String, Emoji> emojis = new HashMap<>();
for (Token token : this.emojiKeywordTrie.tokenize(jsonText)) {
if (token.isMatch()) {
emojis.put(token.getFragment(), this.emojiMapper.get(token.getFragment()));
}
}
if (emojis.isEmpty()) return jsonText;
Component component = AdventureHelper.jsonToComponent(jsonText);
for (Map.Entry<String, Emoji> entry : emojis.entrySet()) {
Emoji emoji = entry.getValue();
if (player != null && emoji.permission() != null && !player.hasPermission(emoji.permission())) {
continue;
}
component = component.replaceText(builder -> builder.matchLiteral(entry.getKey())
.replacement(
AdventureHelper.miniMessage().deserialize(
emoji.content(),
PlayerContext.of(player, ContextHolder.builder()
.withOptionalParameter(EmojiParameters.EMOJI, emoji.emojiImage())
.withParameter(EmojiParameters.KEYWORD, emoji.keywords().get(0))
.build()).tagResolvers())
));
}
return AdventureHelper.componentToJson(component);
}
@Override
public ConfigSectionParser[] parsers() {
return new ConfigSectionParser[] {this.imageParser, this.emojiParser};
@@ -89,10 +147,24 @@ public abstract class AbstractFontManager implements FontManager {
@Override
public void delayedLoad() {
Optional.ofNullable(this.fonts.get(DEFAULT_FONT)).ifPresent(font -> this.illegalChars.addAll(font.codepointsInUse()));
this.buildTrie();
this.buildImageTagTrie();
this.buildEmojiKeywordsTrie();
}
private void buildTrie() {
private void buildEmojiKeywordsTrie() {
this.emojiMapper = new HashMap<>();
for (Emoji emoji : this.emojis.values()) {
for (String keyword : emoji.keywords()) {
this.emojiMapper.put(keyword, emoji);
}
}
this.emojiKeywordTrie = Trie.builder()
.ignoreOverlaps()
.addKeywords(this.emojiMapper.keySet())
.build();
}
private void buildImageTagTrie() {
this.tagMapper = new HashMap<>();
for (BitmapImage image : this.images.values()) {
String id = image.id().toString();
@@ -109,7 +181,7 @@ public abstract class AbstractFontManager implements FontManager {
this.tagMapper.put("<shift:" + i + ">", AdventureHelper.miniMessage().deserialize(this.offsetFont.createOffset(i, FormatUtils::miniMessageFont)));
this.tagMapper.put("\\<shift:" + i + ">", Component.text("<shift:" + i + ">"));
}
this.trie = Trie.builder()
this.imageTagTrie = Trie.builder()
.ignoreOverlaps()
.addKeywords(this.tagMapper.keySet())
.build();
@@ -180,7 +252,47 @@ public abstract class AbstractFontManager implements FontManager {
@Override
public void parseSection(Pack pack, Path path, Key id, Map<String, Object> section) {
if (emojis.containsKey(id)) {
TranslationManager.instance().log("warning.config.emoji.duplicated", path.toString(), id.toString());
return;
}
String permission = (String) section.get("permission");
Object keywordsRaw = section.get("keywords");
if (keywordsRaw == null) {
TranslationManager.instance().log("warning.config.emoji.lack_keywords", path.toString(), id.toString());
return;
}
List<String> keywords = MiscUtils.getAsStringList(keywordsRaw);
String content = section.getOrDefault("content", "<arg:emoji>").toString();
String image = null;
if (section.containsKey("image")) {
String rawImage = section.get("image").toString();
String[] split = rawImage.split(":");
if (split.length == 2) {
Key imageId = new Key(split[0], split[1]);
Optional<BitmapImage> bitmapImage = bitmapImageByImageId(imageId);
if (bitmapImage.isPresent()) {
image = bitmapImage.get().miniMessage(0, 0);
} else {
TranslationManager.instance().log("warning.config.emoji.invalid_image", path.toString(), id.toString(), rawImage);
return;
}
} else if (split.length == 4) {
Key imageId = new Key(split[0], split[1]);
Optional<BitmapImage> bitmapImage = bitmapImageByImageId(imageId);
if (bitmapImage.isPresent()) {
image = bitmapImage.get().miniMessage(Integer.parseInt(split[2]), Integer.parseInt(split[3]));
} else {
TranslationManager.instance().log("warning.config.emoji.invalid_image", path.toString(), id.toString(), rawImage);
return;
}
} else {
TranslationManager.instance().log("warning.config.emoji.invalid_image", path.toString(), id.toString(), rawImage);
return;
}
}
Emoji emoji = new Emoji(content, permission, image, keywords);
emojis.put(id, emoji);
}
}

View File

@@ -1,25 +1,27 @@
package net.momirealms.craftengine.core.font;
import net.momirealms.craftengine.core.util.Key;
import javax.annotation.Nullable;
import java.util.List;
public class Emoji {
private final Key font;
private final String image;
private final String content;
private final String permission;
private final String image;
private final List<String> keywords;
public Emoji(Key font, String image, String permission) {
this.font = font;
public Emoji(String content, String permission, String image, List<String> keywords) {
this.content = content;
this.image = image;
this.permission = permission;
this.keywords = keywords;
}
public Key font() {
return font;
public String content() {
return content;
}
public String image() {
@Nullable
public String emojiImage() {
return image;
}
@@ -27,4 +29,8 @@ public class Emoji {
public String permission() {
return permission;
}
public List<String> keywords() {
return keywords;
}
}

View File

@@ -0,0 +1,9 @@
package net.momirealms.craftengine.core.font;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.context.ContextKey;
public class EmojiParameters {
public static final ContextKey<String> KEYWORD = new ContextKey<>(Key.of("keyword"));
public static final ContextKey<String> EMOJI = new ContextKey<>(Key.of("emoji"));
}

View File

@@ -1,6 +1,7 @@
package net.momirealms.craftengine.core.font;
import net.kyori.adventure.text.Component;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.plugin.Manageable;
import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser;
import net.momirealms.craftengine.core.util.CharacterUtils;
@@ -23,6 +24,10 @@ public interface FontManager extends Manageable {
ConfigSectionParser[] parsers();
String replaceMiniMessageEmoji(String miniMessage, Player player);
String replaceJsonEmoji(String jsonText, Player player);
boolean isDefaultFontInUse();
boolean isIllegalCodepoint(int codepoint);

View File

@@ -1,43 +1,20 @@
package net.momirealms.craftengine.core.item;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.plugin.text.minimessage.*;
import net.momirealms.craftengine.core.util.context.ContextHolder;
import net.momirealms.craftengine.core.util.context.PlayerContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ItemBuildContext implements MiniMessageTextContext {
public class ItemBuildContext extends PlayerContext {
public static final ItemBuildContext EMPTY = new ItemBuildContext(null, ContextHolder.EMPTY);
private final Player player;
private final ContextHolder contexts;
private TagResolver[] tagResolvers;
public ItemBuildContext(@Nullable Player player, @NotNull ContextHolder contexts) {
this.player = player;
this.contexts = contexts;
super(player, contexts);
}
@NotNull
public static ItemBuildContext of(@Nullable Player player, @NotNull ContextHolder contexts) {
return new ItemBuildContext(player, contexts);
}
@Nullable
public Player player() {
return this.player;
}
@NotNull
public ContextHolder contexts() {
return this.contexts;
}
@NotNull
public TagResolver[] tagResolvers() {
if (this.tagResolvers == null) {
this.tagResolvers = new TagResolver[]{ShiftTag.INSTANCE, ImageTag.INSTANCE, new PlaceholderTag(this.player), new I18NTag(this), new NamedArgumentTag(this)};
}
return this.tagResolvers;
}
}

View File

@@ -300,6 +300,8 @@ public abstract class AbstractPackManager implements PackManager {
plugin.saveResource("resources/default/resourcepack/pack.png");
// templates
plugin.saveResource("resources/default/configuration/templates.yml");
// emoji
plugin.saveResource("resources/default/configuration/emoji.yml");
// i18n
plugin.saveResource("resources/default/configuration/i18n.yml");
// block_name

View File

@@ -16,6 +16,7 @@ import net.momirealms.craftengine.core.util.AdventureHelper;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.context.ContextHolder;
import net.momirealms.craftengine.core.util.context.PlayerContext;
import java.nio.file.Path;
import java.util.*;
@@ -175,7 +176,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
}
})
.build()
.title(AdventureHelper.miniMessage().deserialize(Constants.BROWSER_TITLE, ItemBuildContext.of(player, ContextHolder.EMPTY).tagResolvers()))
.title(AdventureHelper.miniMessage().deserialize(Constants.BROWSER_TITLE, PlayerContext.of(player, ContextHolder.EMPTY).tagResolvers()))
.refresh()
.open(player);
}
@@ -290,7 +291,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
}
})
.build()
.title(AdventureHelper.miniMessage().deserialize(Constants.CATEGORY_TITLE, ItemBuildContext.of(player, ContextHolder.EMPTY).tagResolvers()))
.title(AdventureHelper.miniMessage().deserialize(Constants.CATEGORY_TITLE, PlayerContext.of(player, ContextHolder.EMPTY).tagResolvers()))
.refresh()
.open(player);
}
@@ -351,7 +352,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
}
})
.build()
.title(AdventureHelper.miniMessage().deserialize(Constants.RECIPE_NONE_TITLE, ItemBuildContext.of(player, ContextHolder.EMPTY).tagResolvers()))
.title(AdventureHelper.miniMessage().deserialize(Constants.RECIPE_NONE_TITLE, PlayerContext.of(player, ContextHolder.EMPTY).tagResolvers()))
.refresh()
.open(player);
}
@@ -576,7 +577,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
}
})
.build()
.title(AdventureHelper.miniMessage().deserialize(Constants.RECIPE_SMITHING_TRANSFORM_TITLE, ItemBuildContext.of(player, ContextHolder.EMPTY).tagResolvers()))
.title(AdventureHelper.miniMessage().deserialize(Constants.RECIPE_SMITHING_TRANSFORM_TITLE, PlayerContext.of(player, ContextHolder.EMPTY).tagResolvers()))
.refresh()
.open(player);
}
@@ -709,7 +710,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
}
})
.build()
.title(AdventureHelper.miniMessage().deserialize(Constants.RECIPE_STONECUTTING_TITLE, ItemBuildContext.of(player, ContextHolder.EMPTY).tagResolvers()))
.title(AdventureHelper.miniMessage().deserialize(Constants.RECIPE_STONECUTTING_TITLE, PlayerContext.of(player, ContextHolder.EMPTY).tagResolvers()))
.refresh()
.open(player);
}
@@ -859,7 +860,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
}
})
.build()
.title(AdventureHelper.miniMessage().deserialize(title, ItemBuildContext.of(player, ContextHolder.EMPTY).tagResolvers()))
.title(AdventureHelper.miniMessage().deserialize(title, PlayerContext.of(player, ContextHolder.EMPTY).tagResolvers()))
.refresh()
.open(player);
}
@@ -1054,7 +1055,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
}
})
.build()
.title(AdventureHelper.miniMessage().deserialize(Constants.RECIPE_CRAFTING_TITLE, ItemBuildContext.of(player, ContextHolder.EMPTY).tagResolvers()))
.title(AdventureHelper.miniMessage().deserialize(Constants.RECIPE_CRAFTING_TITLE, PlayerContext.of(player, ContextHolder.EMPTY).tagResolvers()))
.refresh()
.open(player);
}

View File

@@ -28,15 +28,12 @@ public class NamedArgumentTag implements TagResolver {
if (!has(name)) {
return null;
}
String argumentKey = arguments.popOr("No argument key provided").toString();
ContextKey<String> key = ContextKey.of(Key.of(argumentKey));
if (!this.context.contexts().has(key)) {
throw ctx.newException("Invalid argument key", arguments);
}
return Tag.inserting(AdventureHelper.miniMessage().deserialize(this.context.contexts().getOrThrow(key), this.context.tagResolvers()));
return Tag.selfClosingInserting(AdventureHelper.miniMessage().deserialize(this.context.contexts().getOrThrow(key), this.context.tagResolvers()));
}
@Override

View File

@@ -126,6 +126,10 @@ public class AdventureHelper {
return getInstance().miniMessageStrict.serialize(getInstance().gsonComponentSerializer.deserialize(json));
}
public static String componentToMiniMessage(Component component) {
return getInstance().miniMessageStrict.serialize(component);
}
/**
* Converts a JSON string to a Component.
*

View File

@@ -0,0 +1,42 @@
package net.momirealms.craftengine.core.util.context;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.plugin.text.minimessage.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class PlayerContext implements MiniMessageTextContext {
public static final PlayerContext EMPTY = new PlayerContext(null, ContextHolder.EMPTY);
private final Player player;
private final ContextHolder contexts;
private TagResolver[] tagResolvers;
public PlayerContext(@Nullable Player player, @NotNull ContextHolder contexts) {
this.player = player;
this.contexts = contexts;
}
@NotNull
public static PlayerContext of(@Nullable Player player, @NotNull ContextHolder contexts) {
return new PlayerContext(player, contexts);
}
@Nullable
public Player player() {
return this.player;
}
@NotNull
public ContextHolder contexts() {
return this.contexts;
}
@NotNull
public TagResolver[] tagResolvers() {
if (this.tagResolvers == null) {
this.tagResolvers = new TagResolver[]{ShiftTag.INSTANCE, ImageTag.INSTANCE, new PlaceholderTag(this.player), new I18NTag(this), new NamedArgumentTag(this)};
}
return this.tagResolvers;
}
}