Compare commits

...

11 commits

Author SHA1 Message Date
fbd3bf2eb2
add lang debug command and fix found translation issue 2026-08-17 13:56:12 +02:00
f373cae100
ask gui translatable 2026-08-17 13:56:12 +02:00
1d402b1e76
a lot of progress inside the ui 2026-08-17 13:56:12 +02:00
ec40889118
progress on translation system 2026-08-17 13:56:12 +02:00
58d363c4c7
fix small translation issue 2026-08-17 13:56:12 +02:00
b0a34b6b14
rework multiline 2026-08-17 13:56:12 +02:00
47e38bd23b
finished adding command text to trans file 2026-08-17 13:56:12 +02:00
cb6040df10
better translation system 2026-08-17 13:56:12 +02:00
c636767078
translation key for load errors and warnings 2026-08-17 13:56:11 +02:00
1f00a32750
language backend logic 2026-08-17 13:56:11 +02:00
4b8e71c5e9
fix creating new unit repair not working
Some checks failed
Java CI with Gradle / build (push) Has been cancelled
2026-08-17 13:56:01 +02:00
52 changed files with 1416 additions and 364 deletions

View file

@ -2,7 +2,7 @@ package xyz.alexcrea.cuanvil.dependency.util
import net.kyori.adventure.text.Component
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer
import org.bukkit.inventory.ItemStack
import org.bukkit.command.CommandSender
import org.bukkit.inventory.meta.ItemMeta
// Mostly made for paper, spigot and folia support
@ -100,4 +100,39 @@ object PlatformUtil {
}
}
/**
* Try to send paper component to the player
*
* @param component The used component
* @return true if sent, else otherwise
*/
fun CommandSender.sendPaperMessage(component: Component): Boolean {
if(isPaper) {
this.sendMessage(component)
return true
}
return false
} /**
* Try to send paper component to the player
*
* @param component The used component
* @return true if sent, else otherwise
*/
/**
* Try to set component lore of an item
*
* @param components The used component lore
* @return true if sent, else otherwise
*/
fun ItemMeta.setPaperLore(components: List<Component>): Boolean {
if(isPaper) {
this.lore(components)
return true
}
return false
}
}

View file

@ -10,13 +10,15 @@ import org.jetbrains.annotations.NotNull;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import xyz.alexcrea.cuanvil.lang.Message;
public abstract class AbstractAskGui extends ChestGui {
protected PatternPane pane;
AbstractAskGui(int rows, @NotNull String name,
AbstractAskGui(int rows,
@NotNull Message name, @NotNull String param,
Gui backOnCancel){
super(rows, name, CustomAnvil.instance);
super(rows, name.textHolder(param), CustomAnvil.instance);
Pattern pattern = getGuiPattern();
this.pane = new PatternPane(0, 0, pattern.getLength(), pattern.getHeight(), pattern);

View file

@ -9,20 +9,25 @@ import org.bukkit.entity.HumanEntity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import xyz.alexcrea.cuanvil.util.MetricsUtil;
import xyz.alexcrea.cuanvil.lang.Message;
import xyz.alexcrea.cuanvil.lang.MsgError;
import xyz.alexcrea.cuanvil.lang.MsgUI;
import xyz.alexcrea.cuanvil.util.ComponentUtil;
import java.util.Arrays;
import java.awt.*;
import java.util.function.Supplier;
import java.util.logging.Level;
public class ConfirmActionGui extends AbstractAskGui {
public ConfirmActionGui(@NotNull String title, String actionDescription,
public ConfirmActionGui(@NotNull Message title, @NotNull String titleParam,
@Nullable Message actionDescription, @NotNull String actionParam,
Gui backOnCancel, Gui backOnConfirm, Supplier<Boolean> onConfirm,
boolean permanent) {
super(3, title, backOnCancel);
super(3, title, titleParam, backOnCancel);
// Save item
this.pane.bindItem('S', new GuiItem(
@ -33,7 +38,7 @@ public class ConfirmActionGui extends AbstractAskGui {
if (!player.hasPermission(CustomAnvil.editConfigPermission)) {
player.closeInventory();
player.sendMessage(GuiGlobalActions.NO_EDIT_PERM);
MsgUI.INSTANCE.getSHARED_CONFIG_NO_EDIT_PERM().send(player);
return;
}
@ -41,13 +46,12 @@ public class ConfirmActionGui extends AbstractAskGui {
try {
success = onConfirm.get();
} catch (Exception e) {
CustomAnvil.instance.getLogger().log(Level.WARNING, "Could not process confirmation supplier.", e);
MetricsUtil.INSTANCE.trackError(e);
CustomAnvil.Companion.logError(MsgError.INSTANCE.getCONFIRM_ACTION_GENERIC().unformatted(), e, true, Level.WARNING);
success = false;
}
if (!success) {
event.getWhoClicked().sendMessage("§cAction could not be completed. ");
MsgUI.INSTANCE.getCONFIRM_ACTION_FAILED().send(player);
}
backOnConfirm.show(player);
@ -56,19 +60,21 @@ public class ConfirmActionGui extends AbstractAskGui {
// Info item
ItemStack infoItem = new ItemStack(Material.PAPER);
ItemMeta infoMeta = infoItem.getItemMeta();
assert infoMeta != null;
infoMeta.setDisplayName("§eAre you sure ?");
ComponentUtil.INSTANCE.setMessageName(infoMeta, MsgUI.INSTANCE.getCONFIRM_ACTION_ARE_YOU_SURE());
if(actionDescription != null){
infoMeta.setLore(Arrays.asList(actionDescription.split("\n")));
ComponentUtil.INSTANCE.applyLore(actionDescription.formatted(actionParam), infoMeta);
}
infoItem.setItemMeta(infoMeta);
pane.bindItem('I', new GuiItem(infoItem, GuiGlobalActions.stayInPlace, CustomAnvil.instance));
}
public ConfirmActionGui(@NotNull String title, String actionDescription,
public ConfirmActionGui(@NotNull Message title, @NotNull String titleParam,
@Nullable Message actionDescription, @NotNull String actionParam,
Gui backOnCancel, Gui backOnConfirm, Supplier<Boolean> onConfirm){
this(title, actionDescription, backOnCancel, backOnConfirm, onConfirm, true);
this(title, titleParam, actionDescription, actionParam, backOnCancel, backOnConfirm, onConfirm, true);
}

View file

@ -9,24 +9,27 @@ import org.bukkit.entity.HumanEntity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import xyz.alexcrea.cuanvil.lang.Message;
import xyz.alexcrea.cuanvil.lang.MsgUI;
import xyz.alexcrea.cuanvil.util.ComponentUtil;
import xyz.alexcrea.cuanvil.util.MaterialUtil;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
public class SelectItemTypeGui extends AbstractAskGui {
private ItemStack selectedItem;
public SelectItemTypeGui(@NotNull String title,
@NotNull String actionDescription,
public SelectItemTypeGui(@NotNull Message title,
@NotNull String titleParam,
@NotNull Message actionDescription,
@NotNull String descriptionParam,
@NotNull Gui backOnCancel,
@NotNull BiConsumer<ItemStack, HumanEntity> onSave,
boolean materialOnly) {
super(3, title, backOnCancel);
super(3, title, titleParam, backOnCancel);
this.selectedItem = null;
// Save item
@ -36,7 +39,7 @@ public class SelectItemTypeGui extends AbstractAskGui {
if (!player.hasPermission(CustomAnvil.editConfigPermission)) {
player.closeInventory();
player.sendMessage(GuiGlobalActions.NO_EDIT_PERM);
MsgUI.INSTANCE.getSHARED_CONFIG_NO_EDIT_PERM().send(player);
return;
}
@ -46,7 +49,7 @@ public class SelectItemTypeGui extends AbstractAskGui {
this.pane.bindItem('S', GuiGlobalItems.backgroundItem());
// Select item
ItemStack selectItem = setDisplayMeta(new ItemStack(Material.BARRIER), actionDescription);
ItemStack selectItem = setDisplayMeta(new ItemStack(Material.BARRIER), actionDescription, descriptionParam);
AtomicReference<GuiItem> selectGuiItem = new AtomicReference<>();
selectGuiItem.set(new GuiItem(selectItem, event -> {
@ -57,7 +60,7 @@ public class SelectItemTypeGui extends AbstractAskGui {
ItemStack finalItem;
if(materialOnly){
finalItem = setDisplayMeta(new ItemStack(cursor.getType()), actionDescription);
finalItem = setDisplayMeta(new ItemStack(cursor.getType()), actionDescription, descriptionParam);
}else{
finalItem = cursor.clone();
}
@ -75,14 +78,19 @@ public class SelectItemTypeGui extends AbstractAskGui {
GuiItem temporaryLeave = GuiGlobalItems.temporaryCloseGuiToSelectItem(Material.YELLOW_STAINED_GLASS_PANE, this);
this.pane.bindItem('s', temporaryLeave);
}
private ItemStack setDisplayMeta(ItemStack item, String actionDescription){
@NotNull
private ItemStack setDisplayMeta(
@NotNull ItemStack item,
@NotNull Message actionDescription,
@NotNull String param
){
ItemMeta meta = item.getItemMeta();
assert meta != null;
meta.setDisplayName("§ePlace an item here");
meta.setLore(Arrays.asList(actionDescription.split("\n")));
ComponentUtil.INSTANCE.setMessageName(meta, MsgUI.INSTANCE.getSELECT_ITEM_TYPE_PLACE_HERE());
ComponentUtil.INSTANCE.applyLore(actionDescription.formatted(param), meta);
item.setItemMeta(meta);
return item;

View file

@ -9,6 +9,7 @@ import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry;
import xyz.alexcrea.cuanvil.gui.config.list.SettingGuiListConfigGui;
import xyz.alexcrea.cuanvil.gui.config.settings.SettingGui;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import xyz.alexcrea.cuanvil.lang.Message;
import java.util.Collection;
import java.util.Collections;
@ -27,11 +28,11 @@ public abstract class AbstractEnchantConfigGui<T extends SettingGui.SettingGuiFa
*
* @param title Title of the gui.
*/
protected AbstractEnchantConfigGui(String title) {
protected AbstractEnchantConfigGui(Message title) {
super(title);
}
protected AbstractEnchantConfigGui(String title, Gui parent) {
protected AbstractEnchantConfigGui(Message title, Gui parent) {
super(title, parent);
}

View file

@ -12,6 +12,7 @@ import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.gui.config.list.MappedGuiListConfigGui;
import xyz.alexcrea.cuanvil.gui.config.list.elements.CustomRecipeSubSettingGui;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import xyz.alexcrea.cuanvil.lang.MsgUI;
import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe;
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
@ -36,13 +37,13 @@ public class CustomRecipeConfigGui extends MappedGuiListConfigGui<AnvilCustomRec
}
private CustomRecipeConfigGui() {
super("Custom Recipe Config");
super(MsgUI.INSTANCE.getCUSTOM_RECIPE_TITLE());
init();
}
public CustomRecipeConfigGui(Gui parent) {
super("Custom Recipe Config", parent);
super(MsgUI.INSTANCE.getCUSTOM_RECIPE_TITLE(), parent);
}
@Override
@ -60,7 +61,7 @@ public class CustomRecipeConfigGui extends MappedGuiListConfigGui<AnvilCustomRec
ItemMeta meta = displayedItem.getItemMeta();
assert meta != null;
meta.setDisplayName("§e" + CasedStringUtil.snakeToUpperSpacedCase(recipe.toString()) + " §fCustom recipe");
meta.setDisplayName("§e" + CasedStringUtil.snakeToUpperSpacedCase(recipe.toString()) + " §fCustom recipe");//TODO MESSAGE
meta.addItemFlags(ItemFlag.values());
meta.setLore(getRecipeLore(recipe));
@ -72,7 +73,7 @@ public class CustomRecipeConfigGui extends MappedGuiListConfigGui<AnvilCustomRec
private static @NotNull ArrayList<String> getRecipeLore(AnvilCustomRecipe recipe) {
boolean shouldWork = recipe.validate();
ArrayList<String> lore = new ArrayList<>();
ArrayList<String> lore = new ArrayList<>();//TODO MESSAGE
lore.add("§7Is valid: §" + (shouldWork ? "aYes" : "cNo"));
lore.add("§7Exact count: §" + (recipe.getExactCount() ? "aYes" : "cNo"));
lore.add("§7Recipe Level Cost: §e" + recipe.getLevelCostPerCraft());
@ -90,7 +91,7 @@ public class CustomRecipeConfigGui extends MappedGuiListConfigGui<AnvilCustomRec
@Override
protected String genericDisplayedName() {
return "custom recipe";
return "custom recipe";//TODO MESSAGE
}
@Override

View file

@ -14,6 +14,7 @@ import xyz.alexcrea.cuanvil.group.IncludeGroup;
import xyz.alexcrea.cuanvil.gui.config.list.MappedGuiListConfigGui;
import xyz.alexcrea.cuanvil.gui.config.list.elements.EnchantConflictSubSettingGui;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import xyz.alexcrea.cuanvil.lang.MsgUI;
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
import java.util.Arrays;
@ -38,11 +39,11 @@ public class EnchantConflictGui extends MappedGuiListConfigGui<EnchantConflictGr
// Need to init myself
public EnchantConflictGui(Gui parent) {
super("Conflict Config", parent);
super(MsgUI.INSTANCE.getENCHANTMENT_CONFLICT_TITLE(), parent);
}
private EnchantConflictGui() {
super("Conflict Config");
super(MsgUI.INSTANCE.getENCHANTMENT_CONFLICT_TITLE());
init();
}
@ -80,8 +81,8 @@ public class EnchantConflictGui extends MappedGuiListConfigGui<EnchantConflictGr
assert meta != null;
meta.addItemFlags(ItemFlag.values());
meta.setDisplayName("§e" + CasedStringUtil.snakeToUpperSpacedCase(conflict.toString()) + " §fConflict");
meta.setLore(Arrays.asList(
meta.setDisplayName("§e" + CasedStringUtil.snakeToUpperSpacedCase(conflict.toString()) + " §fConflict"); //TODO MESSAGE
meta.setLore(Arrays.asList(//TODO MESSAGE
"§7Enchantment count: §e" + conflict.getEnchants().size(),
"§7Group count: §e" + conflict.getCantConflictGroup().getGroups().size(),
"§7Min enchantments count: §e" + conflict.getMinBeforeBlock()
@ -98,7 +99,7 @@ public class EnchantConflictGui extends MappedGuiListConfigGui<EnchantConflictGr
@Override
protected String genericDisplayedName() {
return "conflict";
return "conflict";//TODO MESSAGE
}
@Override

View file

@ -11,6 +11,7 @@ import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui;
import xyz.alexcrea.cuanvil.gui.config.settings.EnchantCostSettingsGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
import xyz.alexcrea.cuanvil.lang.MsgUI;
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
import java.util.ArrayList;
@ -36,7 +37,7 @@ public class EnchantCostConfigGui extends AbstractEnchantConfigGui<EnchantCostSe
* Constructor of this Global gui for enchantment cost settings.
*/
public EnchantCostConfigGui() {
super("§8Enchantment Level Cost");
super(MsgUI.INSTANCE.getENCHANTMENT_LEVEL_COST_TITLE());
if (INSTANCE == null) INSTANCE = this;
init();
@ -46,7 +47,7 @@ public class EnchantCostConfigGui extends AbstractEnchantConfigGui<EnchantCostSe
* Constructor of this Global gui for enchantment cost settings.
*/
public EnchantCostConfigGui(Gui parent) {
super("§8Enchantment Level Cost", parent);
super(MsgUI.INSTANCE.getENCHANTMENT_LEVEL_COST_TITLE(), parent);
}
@Override
@ -58,6 +59,7 @@ public class EnchantCostConfigGui extends AbstractEnchantConfigGui<EnchantCostSe
String key = enchant.getKey().toString().toLowerCase(Locale.ENGLISH);
String prettyKey = CasedStringUtil.snakeToUpperSpacedCase(key.replace(":", "_"));
//TODO MESSAGE
return new EnchantCostSettingsGui.EnchantCostSettingFactory(prettyKey + " Cost", parent,
ENCHANT_VALUES_ROOT + '.' + key, ConfigHolder.DEFAULT_CONFIG,
Arrays.asList(

View file

@ -9,6 +9,7 @@ import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui;
import xyz.alexcrea.cuanvil.gui.config.settings.IntSettingsGui;
import xyz.alexcrea.cuanvil.lang.MsgUI;
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
import java.util.Collections;
@ -32,14 +33,14 @@ public class EnchantLimitConfigGui extends AbstractEnchantConfigGui<IntSettingsG
* Constructor of this Global gui for enchantment level limit settings.
*/
public EnchantLimitConfigGui() {
super("§8Enchantment Level Limit");
super(MsgUI.INSTANCE.getENCHANTMENT_LEVEL_LIMIT_TITLE());
if(INSTANCE == null) INSTANCE = this;
init();
}
public EnchantLimitConfigGui(Gui parent) {
super("§8Enchantment Level Limit", parent);
super(MsgUI.INSTANCE.getENCHANTMENT_LEVEL_LIMIT_TITLE(), parent);
}
@Override

View file

@ -9,6 +9,7 @@ import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.enchant.CAEnchantment;
import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui;
import xyz.alexcrea.cuanvil.gui.config.settings.IntSettingsGui;
import xyz.alexcrea.cuanvil.lang.MsgUI;
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
import java.util.Arrays;
@ -29,7 +30,7 @@ public class EnchantMergeLimitConfigGui extends AbstractEnchantConfigGui<IntSett
* Constructor of this Global gui for enchantment level limit settings.
*/
public EnchantMergeLimitConfigGui() {
super("§8Enchantment Maximum Merge Level");
super(MsgUI.INSTANCE.getENCHANTMENT_MERGE_LIMIT_TITLE());
if(INSTANCE == null) INSTANCE = this;
init();
@ -39,7 +40,7 @@ public class EnchantMergeLimitConfigGui extends AbstractEnchantConfigGui<IntSett
* Constructor of this Global gui for enchantment level limit settings.
*/
public EnchantMergeLimitConfigGui(Gui parent) {
super("§8Enchantment Maximum Merge Level", parent);
super(MsgUI.INSTANCE.getENCHANTMENT_MERGE_LIMIT_TITLE(), parent);
}
@ -52,6 +53,7 @@ public class EnchantMergeLimitConfigGui extends AbstractEnchantConfigGui<IntSett
String key = enchant.getKey().toString().toLowerCase(Locale.ROOT);
String prettyKey = CasedStringUtil.snakeToUpperSpacedCase(key.replace(":", "_"));
//TODO MESSAGE
return new IntSettingsGui.IntSettingFactory(prettyKey + " Merge Limit", parent,
SECTION_NAME + '.' + key, ConfigHolder.DEFAULT_CONFIG,
Arrays.asList(

View file

@ -15,6 +15,7 @@ import xyz.alexcrea.cuanvil.group.IncludeGroup;
import xyz.alexcrea.cuanvil.group.ItemGroupManager;
import xyz.alexcrea.cuanvil.gui.config.list.MappedGuiListConfigGui;
import xyz.alexcrea.cuanvil.gui.config.list.elements.GroupConfigSubSettingGui;
import xyz.alexcrea.cuanvil.lang.MsgUI;
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
import xyz.alexcrea.cuanvil.util.LazyValue;
@ -39,13 +40,13 @@ public class GroupConfigGui extends MappedGuiListConfigGui<IncludeGroup, MappedG
}
public GroupConfigGui() {
super("Group Config");
super(MsgUI.INSTANCE.getMATERIAL_GROUP_TITLE());
init();
}
public GroupConfigGui(Gui parent) {
super("Group Config", parent);
super(MsgUI.INSTANCE.getMATERIAL_GROUP_TITLE(), parent);
}
@Override

View file

@ -13,6 +13,7 @@ import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.gui.config.ask.SelectItemTypeGui;
import xyz.alexcrea.cuanvil.gui.config.list.MappedGuiListConfigGui;
import xyz.alexcrea.cuanvil.gui.config.list.UnitRepairElementListGui;
import xyz.alexcrea.cuanvil.lang.MsgUI;
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
import xyz.alexcrea.cuanvil.util.MaterialUtil;
@ -38,13 +39,13 @@ public class UnitRepairConfigGui extends
}
private UnitRepairConfigGui() {
super("Unit Repair Config");
super(MsgUI.INSTANCE.getUNIT_REPAIR_TITLE());
init();
}
public UnitRepairConfigGui(Gui parent) {
super("Unit Repair Config", parent);
super(MsgUI.INSTANCE.getUNIT_REPAIR_TITLE(), parent);
}
@Override
@ -128,9 +129,8 @@ public class UnitRepairConfigGui extends
clickEvent.setCancelled(true);
new SelectItemTypeGui(
"Select unit repair item.",
"§7Click here with an item to set the item\n" +
"§7You like to be an unit repair item",
MsgUI.INSTANCE.getUNIT_REPAIR_NEW_TITLE(), "",
MsgUI.INSTANCE.getUNIT_REPAIR_NEW_DESCRIPTION(), "",
this,
(itemStack, player) -> {
NamespacedKey type = MaterialUtil.INSTANCE.getCustomType(itemStack);

View file

@ -18,6 +18,7 @@ import org.jetbrains.annotations.NotNull;
import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import xyz.alexcrea.cuanvil.lang.Message;
import java.util.ArrayList;
import java.util.Collection;
@ -32,16 +33,18 @@ public abstract class ElementListConfigGui<T> extends ChestGui implements ValueU
public static final int LIST_FILLER_LENGTH = 7;
public static final int LIST_FILLER_HEIGHT = 4;
private final String namePrefix;
private final Message rawTitle;
private final String param;
protected PatternPane backgroundPane;
private Predicate<T> filter = (t) -> true;
private boolean hasDefaultFilter = true;
protected ElementListConfigGui(@NotNull String title, Gui parent) {
super(6, title, CustomAnvil.instance);
this.namePrefix = title;
protected ElementListConfigGui(@NotNull Message title, String param, Gui parent) {
super(6, title.textHolder(param, "", ""), CustomAnvil.instance);
this.rawTitle = title;
this.param = param;
// Back item panel
Pattern pattern = getBackgroundPattern();
@ -259,13 +262,10 @@ public abstract class ElementListConfigGui<T> extends ChestGui implements ValueU
// and add actual page
addPane(page);
// set title
StringBuilder title = new StringBuilder(this.namePrefix);
// intended parameter: (page/max_page) //TODO MESSAGE CHECK CHILDS
int pagesSize = this.pages.size();
if (pagesSize > 1) {
title.append(" (").append(pageID + 1).append('/').append(pagesSize).append(')');
}
setTitle(title.toString());
var title = this.rawTitle.textHolder(param, pageID + 1, pagesSize);
setTitle(title);
super.show(humanEntity);

View file

@ -10,6 +10,8 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import xyz.alexcrea.cuanvil.gui.config.MainConfigGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
import xyz.alexcrea.cuanvil.lang.Message;
import xyz.alexcrea.cuanvil.lang.MsgUI;
import java.util.Arrays;
import java.util.HashMap;
@ -19,14 +21,14 @@ public abstract class MappedElementListConfigGui<T, S> extends ElementListConfig
protected final HashMap<T, S> elementGuiMap;
protected MappedElementListConfigGui(@NotNull String title, @NotNull Gui parent) {
super(title, parent);
protected MappedElementListConfigGui(@NotNull Message title, @NotNull String param, @NotNull Gui parent) {
super(title, param, parent);
this.elementGuiMap = new HashMap<>();
}
protected MappedElementListConfigGui(@NotNull String title) {
this(title, MainConfigGui.getInstance());
protected MappedElementListConfigGui(@NotNull Message title, @NotNull String param) {
this(title, param, MainConfigGui.getInstance());
}
@Override
@ -52,13 +54,12 @@ public abstract class MappedElementListConfigGui<T, S> extends ElementListConfig
// check permission
if (!player.hasPermission(CustomAnvil.editConfigPermission)) {
player.closeInventory();
player.sendMessage(GuiGlobalActions.NO_EDIT_PERM);
MsgUI.INSTANCE.getSHARED_CONFIG_NO_EDIT_PERM().send(player);
return;
}
player.closeInventory();
player.sendMessage("§eWrite the " + genericDisplayedName() + " name you want to create in the chat.\n" +
"§eOr write §ccancel §eto go back to " + genericDisplayedName() + " config menu");
MsgUI.INSTANCE.getELEMENT_LIST_INSTRUCTION_NEW().send(player, genericDisplayedName());
CustomAnvil.Companion.getChatListener().setListenedCallback(player, prepareCreateItemConsumer(player));

View file

@ -8,6 +8,8 @@ import org.bukkit.event.inventory.InventoryClickEvent;
import org.jetbrains.annotations.NotNull;
import xyz.alexcrea.cuanvil.gui.config.list.elements.ElementMappedToListGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
import xyz.alexcrea.cuanvil.lang.Message;
import xyz.alexcrea.cuanvil.lang.MsgUI;
import xyz.alexcrea.cuanvil.util.LazyValue;
import java.util.Locale;
@ -18,12 +20,20 @@ import java.util.function.Supplier;
public abstract class MappedGuiListConfigGui<T, S extends MappedGuiListConfigGui.LazyElement<?>>
extends MappedElementListConfigGui<T, S> {
protected MappedGuiListConfigGui(@NotNull String title) {
super(title);
protected MappedGuiListConfigGui(@NotNull Message title, @NotNull String param) {
super(title, param);
}
protected MappedGuiListConfigGui(@NotNull String title, @NotNull Gui parent) {
super(title, parent);
protected MappedGuiListConfigGui(@NotNull Message title, @NotNull String param, @NotNull Gui parent) {
super(title, param, parent);
}
protected MappedGuiListConfigGui(@NotNull Message title) {
super(title, "");
}
protected MappedGuiListConfigGui(@NotNull Message title, @NotNull Gui parent) {
super(title, "", parent);
}
@Override
@ -69,13 +79,13 @@ public abstract class MappedGuiListConfigGui<T, S extends MappedGuiListConfigGui
// check permission
if (!player.hasPermission(CustomAnvil.editConfigPermission)) {
player.sendMessage(GuiGlobalActions.NO_EDIT_PERM);
MsgUI.INSTANCE.getSHARED_CONFIG_NO_EDIT_PERM().send(player);
return;
}
message = message.toLowerCase(Locale.ROOT);
if ("cancel".equalsIgnoreCase(message)) {
player.sendMessage(genericDisplayedName() + " creation cancelled...");
MsgUI.INSTANCE.getELEMENT_LIST_CANCELLED_NEW().send(player, genericDisplayedName());
show(player);
return;
}
@ -86,7 +96,7 @@ public abstract class MappedGuiListConfigGui<T, S extends MappedGuiListConfigGui
// Not the most efficient on large number of conflict, but it should not run often.
for (T generic : getDisplayableInstanceOfGeneric()) {
if (generic.toString().equalsIgnoreCase(message)) {
player.sendMessage("§cPlease enter a " + genericDisplayedName() + " name that do not already exist...");
MsgUI.INSTANCE.getELEMENT_LIST_DUPLICATED_NEW().send(player, genericDisplayedName());
// wait next message.
CustomAnvil.Companion.getChatListener().setListenedCallback(player, selfRef.get());
return;

View file

@ -10,6 +10,7 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import xyz.alexcrea.cuanvil.gui.config.MainConfigGui;
import xyz.alexcrea.cuanvil.gui.config.settings.SettingGui;
import xyz.alexcrea.cuanvil.lang.Message;
import java.util.HashMap;
import java.util.List;
@ -20,16 +21,26 @@ public abstract class SettingGuiListConfigGui<T, S extends SettingGui.SettingGui
protected HashMap<T, GuiItem> guiItemMap;
protected HashMap<T, S> factoryMap;
protected SettingGuiListConfigGui(@NotNull String title, Gui parent) {
super(title, parent);
protected SettingGuiListConfigGui(@NotNull Message title, Gui parent) {
super(title, "", parent);
this.guiItemMap = new HashMap<>();
this.factoryMap = new HashMap<>();
}
protected SettingGuiListConfigGui(@NotNull String title) {
protected SettingGuiListConfigGui(@NotNull Message title) {
this(title, MainConfigGui.getInstance());
}
protected SettingGuiListConfigGui(@NotNull Message title, @NotNull String param, Gui parent) {
super(title, param, parent);
this.guiItemMap = new HashMap<>();
this.factoryMap = new HashMap<>();
}
protected SettingGuiListConfigGui(@NotNull Message title, @NotNull String param) {
this(title, param, MainConfigGui.getInstance());
}
@Override
protected GuiItem prepareCreateNewItem() {
ItemStack createItem = new ItemStack(Material.PAPER);

View file

@ -18,6 +18,7 @@ import xyz.alexcrea.cuanvil.gui.config.list.elements.ElementMappedToListGui;
import xyz.alexcrea.cuanvil.gui.config.settings.DoubleSettingGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import xyz.alexcrea.cuanvil.lang.MsgUI;
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
import xyz.alexcrea.cuanvil.util.MaterialUtil;
@ -32,12 +33,16 @@ public class UnitRepairElementListGui extends SettingGuiListConfigGui<Namespaced
private boolean shouldWork = true;
private static String prettifiedName(NamespacedKey parentMaterial) {
return CasedStringUtil.snakeToUpperSpacedCase(parentMaterial.getKey().toLowerCase());
}
public UnitRepairElementListGui(@NotNull NamespacedKey parentMaterial,
@NotNull UnitRepairConfigGui parentGui) {
super("§e" + CasedStringUtil.snakeToUpperSpacedCase(parentMaterial.getKey().toLowerCase()) + " §rUnit repair");
super(MsgUI.INSTANCE.getUNIT_REPAIR_ELEMENT_TITLE(), prettifiedName(parentMaterial));
this.parentMaterial = parentMaterial;
this.parentGui = parentGui;
this.materialName = CasedStringUtil.snakeToUpperSpacedCase(parentMaterial.getKey().toLowerCase());
this.materialName = prettifiedName(parentMaterial);
GuiGlobalItems.addBackItem(this.backgroundPane, parentGui);
}
@ -61,20 +66,19 @@ public class UnitRepairElementListGui extends SettingGuiListConfigGui<Namespaced
event.setCancelled(true);
new SelectItemTypeGui(
"Select item to be repaired.",
"§7Click here with an item to set the item\n" +
"§7You like to be repaired by " + this.materialName,
MsgUI.INSTANCE.getUNIT_REPAIR_NEW_ELEMENT_TITLE(), this.materialName,
MsgUI.INSTANCE.getUNIT_REPAIR_NEW_ELEMENT_DESCRIPTION(), this.materialName,
this,
(itemStack, player) -> {
ItemMeta meta = itemStack.getItemMeta();
NamespacedKey type = MaterialUtil.INSTANCE.getCustomType(itemStack);
if (!(meta instanceof Damageable)) {
player.sendMessage("§cThis item can't be damaged, so it can't be repaired.");
MsgUI.INSTANCE.getUNIT_REPAIR_NEW_ELEMENT_CANNOT_REPAIR().send(player);
return;
}
if (type.equals(this.parentMaterial)) {
player.sendMessage("§cItem can't repair something of the same type.");
MsgUI.INSTANCE.getUNIT_REPAIR_NEW_ELEMENT_SAME_TYPE().send(player);
return;
}
@ -93,7 +97,7 @@ public class UnitRepairElementListGui extends SettingGuiListConfigGui<Namespaced
// Display material edit setting
this.factoryMap.get(materialName).create().show(player);
this.factoryMap.get(type).create().show(player);
},
true
).show(event.getWhoClicked());

View file

@ -19,6 +19,7 @@ import xyz.alexcrea.cuanvil.gui.config.settings.ItemSettingGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import xyz.alexcrea.cuanvil.lang.MsgUI;
import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe;
import xyz.alexcrea.cuanvil.recipe.CustomAnvilRecipeManager;
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
@ -36,7 +37,7 @@ public class CustomRecipeSubSettingGui extends MappedToListSubSettingGui {
public CustomRecipeSubSettingGui(
@NotNull CustomRecipeConfigGui parent,
@NotNull AnvilCustomRecipe anvilRecipe) {
super(4, "§e" + CasedStringUtil.snakeToUpperSpacedCase(anvilRecipe.toString()) + " §8Config");
super(4, CasedStringUtil.snakeToUpperSpacedCase(anvilRecipe.toString()));
this.parent = parent;
this.anvilRecipe = anvilRecipe;
@ -73,19 +74,19 @@ public class CustomRecipeSubSettingGui extends MappedToListSubSettingGui {
ItemMeta deleteMeta = deleteItem.getItemMeta();
assert deleteMeta != null;
deleteMeta.setDisplayName("§4DELETE RECIPE");
deleteMeta.setLore(Collections.singletonList("§cCaution with this button !"));
deleteMeta.setDisplayName("§4DELETE RECIPE");//TODO MESSAGE
deleteMeta.setLore(Collections.singletonList("§cCaution with this button !"));//TODO MESSAGE
deleteItem.setItemMeta(deleteMeta);
this.pane.bindItem('D', new GuiItem(deleteItem, GuiGlobalActions.openGuiAction(createDeleteGui()), CustomAnvil.instance));
// Displayed item will be updated later
IntRange costRange = AnvilCustomRecipe.Companion.getXP_COST_CONFIG_RANGE();
this.exactCountFactory = new BoolSettingsGui.BoolSettingFactory("§8Exact count ?", this,
this.exactCountFactory = new BoolSettingsGui.BoolSettingFactory("§8Exact count ?", this,//TODO MESSAGE
ConfigHolder.CUSTOM_RECIPE_HOLDER,
this.anvilRecipe + "." + AnvilCustomRecipe.EXACT_COUNT_CONFIG, AnvilCustomRecipe.DEFAULT_EXACT_COUNT_CONFIG);
this.removeExactLinearXpFactory = new BoolSettingsGui.BoolSettingFactory("§8Remove exact linear xp ?", this,
this.removeExactLinearXpFactory = new BoolSettingsGui.BoolSettingFactory("§8Remove exact linear xp ?", this,//TODO MESSAGE
ConfigHolder.CUSTOM_RECIPE_HOLDER,
this.anvilRecipe + "." + AnvilCustomRecipe.REMOVE_EXACT_XP_CONFIG, AnvilCustomRecipe.DEFAULT_REMOVE_EXACT_XP_CONFIG);
@ -93,18 +94,18 @@ public class CustomRecipeSubSettingGui extends MappedToListSubSettingGui {
ItemMeta meta = item.getItemMeta();
assert meta != null;
meta.setDisplayName("§cRemove exact linear xp ?");
meta.setLore(Collections.singletonList("§7Not usable if linear cost is 0"));
meta.setDisplayName("§cRemove exact linear xp ?");//TODO MESSAGE
meta.setLore(Collections.singletonList("§7Not usable if linear cost is 0"));//TODO MESSAGE
item.setItemMeta(meta);
this.noRemoveExactLinearXp = new GuiItem(item, GuiGlobalActions.stayInPlace, CustomAnvil.instance);
this.levelCostFactory = new IntSettingsGui.IntSettingFactory("§8Recipe Level Cost", this,
this.levelCostFactory = new IntSettingsGui.IntSettingFactory("§8Recipe Level Cost", this,//TODO MESSAGE
this.anvilRecipe + "." + AnvilCustomRecipe.XP_LEVEL_COST_CONFIG,
ConfigHolder.CUSTOM_RECIPE_HOLDER,
null,
costRange.getFirst(), costRange.getLast(), AnvilCustomRecipe.DEFAULT_XP_LEVEL_COST_CONFIG, 1, 5, 10);
this.linearXpCostFactory = new IntSettingsGui.IntSettingFactory("§8Recipe Linear Xp Cost", this,
this.linearXpCostFactory = new IntSettingsGui.IntSettingFactory("§8Recipe Linear Xp Cost", this,//TODO MESSAGE
this.anvilRecipe + "." + AnvilCustomRecipe.LINEAR_XP_COST_CONFIG,
ConfigHolder.CUSTOM_RECIPE_HOLDER,
null,
@ -117,21 +118,21 @@ public class CustomRecipeSubSettingGui extends MappedToListSubSettingGui {
ConfigHolder.CUSTOM_RECIPE_HOLDER,
AnvilCustomRecipe.Companion.getDEFAULT_LEFT_ITEM_CONFIG(),
"§7Set the left item of the custom craft",
"§7\u25A0 + \u25A1 = \u25A1");
"§7■ + □ = □");//TODO MESSAGE
this.rightItemFactory = new ItemSettingGui.ItemSettingFactory("§eRecipe Right §8Item", this,
this.anvilRecipe + "." + AnvilCustomRecipe.RIGHT_ITEM_CONFIG,
ConfigHolder.CUSTOM_RECIPE_HOLDER,
AnvilCustomRecipe.Companion.getDEFAULT_RIGHT_ITEM_CONFIG(),
"§7Set the right item of the custom craft",
"§7\u25A1 + \u25A0 = \u25A1");
"§7□ + ■ = □");//TODO MESSAGE
this.resultItemFactory = new ItemSettingGui.ItemSettingFactory("§aRecipe Result §8Item", this,
this.anvilRecipe + "." + AnvilCustomRecipe.RESULT_ITEM_CONFIG,
ConfigHolder.CUSTOM_RECIPE_HOLDER,
AnvilCustomRecipe.Companion.getDEFAULT_RESULT_ITEM_CONFIG(),
"§7Set the result item of the custom craft",
"§7\u25A1 + \u25A1 = \u25A0");
"§7□ + □ = ■");//TODO MESSAGE
// Now we update the items
updateLocal();
@ -162,8 +163,9 @@ public class CustomRecipeSubSettingGui extends MappedToListSubSettingGui {
return success;
};
return new ConfirmActionGui("§cDelete §e" + CasedStringUtil.snakeToUpperSpacedCase(this.anvilRecipe.toString()) + "§c?",
"§7Confirm that you want to delete this conflict.",
var type = CasedStringUtil.snakeToUpperSpacedCase(this.anvilRecipe.toString());
return new ConfirmActionGui(MsgUI.INSTANCE.getCUSTOM_RECIPE_ELEMENT_DELETE_TITLE(), type,
MsgUI.INSTANCE.getCUSTOM_RECIPE_ELEMENT_DELETE_DESCRIPTION(), type,
this, this.parent, deleteSupplier
);
}

View file

@ -24,6 +24,7 @@ import xyz.alexcrea.cuanvil.gui.config.settings.IntSettingsGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import xyz.alexcrea.cuanvil.lang.MsgUI;
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
import xyz.alexcrea.cuanvil.util.MetricsUtil;
@ -41,8 +42,7 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl
public EnchantConflictSubSettingGui(
@NotNull EnchantConflictGui parent,
@NotNull EnchantConflictGroup enchantConflict) {
super(3,
"§e" + CasedStringUtil.snakeToUpperSpacedCase(enchantConflict.toString()) + " §8Config");
super(3, CasedStringUtil.snakeToUpperSpacedCase(enchantConflict.toString()));
this.parent = parent;
this.enchantConflict = enchantConflict;
@ -71,8 +71,8 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl
ItemMeta deleteMeta = deleteItem.getItemMeta();
assert deleteMeta != null;
deleteMeta.setDisplayName("§4DELETE CONFLICT");
deleteMeta.setLore(Collections.singletonList("§cCaution with this button !"));
deleteMeta.setDisplayName("§4DELETE CONFLICT");//TODO MESSAGE
deleteMeta.setLore(Collections.singletonList("§cCaution with this button !"));//TODO MESSAGE
deleteItem.setItemMeta(deleteMeta);
this.pane.bindItem('D', new GuiItem(deleteItem, GuiGlobalActions.openGuiAction(createDeleteGui()), CustomAnvil.instance));
@ -80,22 +80,24 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl
// Displayed item will be updated later
this.enchantSettingItem = new GuiItem(new ItemStack(Material.ENCHANTED_BOOK), event -> {
event.setCancelled(true);
var type = CasedStringUtil.snakeToUpperSpacedCase(enchantConflict.toString());
EnchantSelectSettingGui enchantGui = new EnchantSelectSettingGui(
"§e" + CasedStringUtil.snakeToUpperSpacedCase(enchantConflict.toString()) + "§5",
MsgUI.INSTANCE.getENCHANTMENT_CONFLICT_ELEMENT_ENCHANTMENTS(), type,
this, this);
enchantGui.show(event.getWhoClicked());
}, CustomAnvil.instance);
this.groupSettingItem = new GuiItem(new ItemStack(Material.PAPER), event -> {
event.setCancelled(true);
var type = CasedStringUtil.snakeToUpperSpacedCase(this.enchantConflict.toString());
GroupSelectSettingGui enchantGui = new GroupSelectSettingGui(
"§e" + CasedStringUtil.snakeToUpperSpacedCase(this.enchantConflict.toString()) + " §3Groups",
MsgUI.INSTANCE.getENCHANTMENT_CONFLICT_ELEMENT_SUB_GROUPS(), type,
this, this, 0);
enchantGui.show(event.getWhoClicked());
}, CustomAnvil.instance);
this.minBeforeActiveSettingFactory = new IntSettingsGui.IntSettingFactory(
"§8Minimum enchantment count",
"§8Minimum enchantment count",//TODO MESSAGE
this, this.enchantConflict + ".maxEnchantmentBeforeConflict", ConfigHolder.CONFLICT_HOLDER,
Arrays.asList(
"§7Minimum enchantment count set to X mean only X enchantment can be put",
@ -137,8 +139,9 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl
return success;
};
return new ConfirmActionGui("§cDelete §e" + CasedStringUtil.snakeToUpperSpacedCase(this.enchantConflict.toString()) + "§c?",
"§7Confirm that you want to delete this conflict.",
var type = CasedStringUtil.snakeToUpperSpacedCase(this.enchantConflict.toString());
return new ConfirmActionGui(MsgUI.INSTANCE.getENCHANTMENT_CONFLICT_ELEMENT_DELETE_TITLE(), type,
MsgUI.INSTANCE.getENCHANTMENT_CONFLICT_ELEMENT_DELETE_DESCRIPTION(), type,
this, this.parent, deleteSupplier
);
}
@ -159,12 +162,12 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl
// Prepare enchantment lore
ArrayList<String> enchantLore = new ArrayList<>();
enchantLore.add("§7Allow you to select a list of §5Enchantments §7that this conflict should include");
enchantLore.add("§7Allow you to select a list of §5Enchantments §7that this conflict should include");//TODO MESSAGE
Set<CAEnchantment> enchants = getSelectedEnchantments();
if (enchants.isEmpty()) {
enchantLore.add("§7There is no included enchantment for this conflict.");
enchantLore.add("§7There is no included enchantment for this conflict.");//TODO MESSAGE
} else {
enchantLore.add("§7List of included enchantment for this conflict:");
enchantLore.add("§7List of included enchantment for this conflict:");//TODO MESSAGE
Iterator<CAEnchantment> enchantIterator = enchants.iterator();
boolean greaterThanMax = enchants.size() > 5;
@ -175,7 +178,7 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl
enchantLore.add("§7- §5" + formattedName);
}
if (greaterThanMax) {
enchantLore.add("§7And " + (enchants.size() - 4) + " more...");
enchantLore.add("§7And " + (enchants.size() - 4) + " more...");//TODO MESSAGE
}
}
@ -188,7 +191,7 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl
ItemMeta enchantMeta = enchantItem.getItemMeta();
assert enchantMeta != null;
enchantMeta.setDisplayName("§aSelect included §5Enchantments §aSettings");
enchantMeta.setDisplayName("§aSelect included §5Enchantments §aSettings");//TODO MESSAGE
enchantMeta.setLore(enchantLore);
enchantItem.setItemMeta(enchantMeta);
@ -200,7 +203,7 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl
ItemMeta groupMeta = groupItem.getItemMeta();
assert groupMeta != null;
groupMeta.setDisplayName("§aSelect Excluded §3Groups §aSettings");
groupMeta.setDisplayName("§aSelect Excluded §3Groups §aSettings");//TODO MESSAGE
groupMeta.setLore(groupLore);
groupItem.setItemMeta(groupMeta);
@ -208,7 +211,7 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl
this.groupSettingItem.setItem(groupItem); // Just in case
this.pane.bindItem('M', this.minBeforeActiveSettingFactory.getItem(Material.COMMAND_BLOCK,
"Minimum Enchantment Count"));
"Minimum Enchantment Count"));//TODO MESSAGE
update();
}
@ -246,7 +249,7 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl
@Override
public boolean setSelectedEnchantments(Set<CAEnchantment> enchantments) {
if (!this.shouldWork) {
CustomAnvil.instance.getLogger().info("Trying to save " + enchantConflict + " enchants but sub config is destroyed");
CustomAnvil.instance.getLogger().info("Trying to save " + enchantConflict + " enchants but sub config is destroyed");//TODO MESSAGE
return false;
}
@ -264,7 +267,7 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl
try {
updateGuiValues();
} catch (Exception e) {
CustomAnvil.instance.getLogger().log(Level.WARNING, "An error occurred while updating enchants for " + this.enchantConflict, e);
CustomAnvil.instance.getLogger().log(Level.WARNING, "An error occurred while updating enchants for " + this.enchantConflict, e);//TODO MESSAGE
MetricsUtil.INSTANCE.trackError(e);
}
@ -291,7 +294,7 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl
@Override
public boolean setSelectedGroups(Set<AbstractMaterialGroup> groups) {
if (!this.shouldWork) {
CustomAnvil.instance.getLogger().info("Trying to save " + enchantConflict.toString() + " groups but sub config is destroyed");
CustomAnvil.instance.getLogger().info("Trying to save " + enchantConflict.toString() + " groups but sub config is destroyed");//TODO MESSAGE
return false;
}
@ -309,7 +312,7 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl
try {
updateGuiValues();
} catch (Exception e) {
CustomAnvil.instance.getLogger().log(Level.WARNING, "An error occurred while updating group for " + this.enchantConflict, e);
CustomAnvil.instance.getLogger().log(Level.WARNING, "An error occurred while updating group for " + this.enchantConflict, e);//TODO MESSAGE
MetricsUtil.INSTANCE.trackError(e);
}

View file

@ -20,10 +20,11 @@ import xyz.alexcrea.cuanvil.gui.config.ask.ConfirmActionGui;
import xyz.alexcrea.cuanvil.gui.config.global.GroupConfigGui;
import xyz.alexcrea.cuanvil.gui.config.settings.GroupSelectSettingGui;
import xyz.alexcrea.cuanvil.gui.config.settings.MaterialSelectSettingGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import xyz.alexcrea.cuanvil.lang.MsgUI;
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
import xyz.alexcrea.cuanvil.util.ComponentUtil;
import java.util.*;
import java.util.function.Consumer;
@ -39,8 +40,7 @@ public class GroupConfigSubSettingGui extends MappedToListSubSettingGui implemen
public GroupConfigSubSettingGui(
@NotNull GroupConfigGui parent,
@NotNull IncludeGroup group) {
super(3,
"§e" + CasedStringUtil.snakeToUpperSpacedCase(group.getName()) + " §rConfig");
super(3, CasedStringUtil.snakeToUpperSpacedCase(group.getName()));
this.parent = parent;
this.group = group;
@ -64,39 +64,49 @@ public class GroupConfigSubSettingGui extends MappedToListSubSettingGui implemen
// Delete item
ItemStack deleteItem = new ItemStack(Material.RED_TERRACOTTA);
ItemMeta deleteMeta = deleteItem.getItemMeta();
assert deleteMeta != null;
deleteMeta.setDisplayName("§4DELETE GROUP");
deleteMeta.setLore(Collections.singletonList("§cCaution with this button !"));
ComponentUtil.INSTANCE.setMessageName(deleteMeta, MsgUI.INSTANCE.getMATERIAL_GROUP_ELEMENT_DELETE_BUTTON_NAME());
ComponentUtil.INSTANCE.applyLore(
MsgUI.INSTANCE.getMATERIAL_GROUP_ELEMENT_DELETE_BUTTON_LORE().formatted(),
deleteMeta
);
deleteItem.setItemMeta(deleteMeta);
this.pane.bindItem('D', new GuiItem(deleteItem, openGuiAndCheckAction(), CustomAnvil.instance));
// Displayed item will be updated later
String materialSelectionName = "§e" + CasedStringUtil.snakeToUpperSpacedCase(group.getName()) + " §rMaterials";
var materialSelectionName = MsgUI.INSTANCE.getMATERIAL_GROUP_ELEMENT_SELECTED_MATERIALS();
var name = CasedStringUtil.snakeToUpperSpacedCase(group.getName());
ItemStack selectItem = new ItemStack(Material.DIAMOND_SWORD);
ItemMeta selectItemMeta = selectItem.getItemMeta();
selectItemMeta.setDisplayName(materialSelectionName);
assert selectItemMeta != null;
ComponentUtil.INSTANCE.setMessageName(selectItemMeta, materialSelectionName, name);
selectItem.setItemMeta(selectItemMeta);
this.materialSelection = new GuiItem(selectItem, (event) -> {
event.setCancelled(true);
MaterialSelectSettingGui selectGui = new MaterialSelectSettingGui(this,
materialSelectionName
materialSelectionName, name
, this);
selectGui.show(event.getWhoClicked());
}, CustomAnvil.instance);
String selectGroupName = "§e" + CasedStringUtil.snakeToUpperSpacedCase(this.group.getName()) + " §rGroups";
var selectGroupName = MsgUI.INSTANCE.getMATERIAL_GROUP_ELEMENT_SELECTED_SUB_GROUPS();
ItemStack selectGroup = new ItemStack(Material.CHEST);
ItemMeta selectGroupMeta = selectGroup.getItemMeta();
selectGroupMeta.setDisplayName(selectGroupName);
assert selectGroupMeta != null;
ComponentUtil.INSTANCE.setMessageName(selectGroupMeta, selectGroupName, name);
selectGroup.setItemMeta(selectGroupMeta);
this.groupSelection = new GuiItem(selectGroup, (event) -> {
event.setCancelled(true);
GroupSelectSettingGui enchantGui = new GroupSelectSettingGui(
selectGroupName,
selectGroupName, name,
this, this, 0);
enchantGui.show(event.getWhoClicked());
}, CustomAnvil.instance);
@ -113,7 +123,7 @@ public class GroupConfigSubSettingGui extends MappedToListSubSettingGui implemen
// Do not allow to open inventory if player do not have edit configuration permission
if (!player.hasPermission(CustomAnvil.editConfigPermission)) {
player.closeInventory();
player.sendMessage(GuiGlobalActions.NO_EDIT_PERM);
MsgUI.INSTANCE.getSHARED_CONFIG_NO_EDIT_PERM().send(player);
return;
}
// test if group is used & cancel & warn user if so
@ -151,8 +161,9 @@ public class GroupConfigSubSettingGui extends MappedToListSubSettingGui implemen
return success;
};
return new ConfirmActionGui("§cDelete §e" + CasedStringUtil.snakeToUpperSpacedCase(this.group.toString()) + "§c?",
"§7Confirm that you want to delete this group.",
var type = CasedStringUtil.snakeToUpperSpacedCase(this.group.toString());
return new ConfirmActionGui(MsgUI.INSTANCE.getMATERIAL_GROUP_ELEMENT_DELETE_TITLE(), type,
MsgUI.INSTANCE.getMATERIAL_GROUP_ELEMENT_DELETE_DESCRIPTION(), type,
this, this.parent, deleteSupplier
);
}
@ -225,7 +236,8 @@ public class GroupConfigSubSettingGui extends MappedToListSubSettingGui implemen
ItemStack matSelectItem = this.materialSelection.getItem();
ItemMeta matSelectMeta = matSelectItem.getItemMeta();
matSelectMeta.setDisplayName("§aSelect included §eMaterials §aSettings");
assert matSelectMeta != null;
matSelectMeta.setDisplayName("§aSelect included §eMaterials §aSettings");//TODO MESSAGE
matSelectMeta.setLore(matLore);
matSelectMeta.addItemFlags(ItemFlag.values());
@ -237,7 +249,8 @@ public class GroupConfigSubSettingGui extends MappedToListSubSettingGui implemen
ItemStack groupSelectItem = this.groupSelection.getItem();
ItemMeta groupSelectMeta = groupSelectItem.getItemMeta();
groupSelectMeta.setDisplayName("§aSelect included §3Groups §aSettings");
assert groupSelectMeta != null;
groupSelectMeta.setDisplayName("§aSelect included §3Groups §aSettings");//TODO MESSAGE
groupSelectMeta.setLore(groupLore);
groupSelectItem.setItemMeta(groupSelectMeta);

View file

@ -1,18 +1,18 @@
package xyz.alexcrea.cuanvil.gui.config.list.elements;
import com.github.stefvanschie.inventoryframework.gui.GuiItem;
import com.github.stefvanschie.inventoryframework.gui.type.ChestGui;
import com.github.stefvanschie.inventoryframework.gui.type.util.Gui;
import io.delilaheve.CustomAnvil;
import org.jetbrains.annotations.NotNull;
import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui;
import xyz.alexcrea.cuanvil.lang.MsgUI;
public abstract class MappedToListSubSettingGui extends ChestGui implements ValueUpdatableGui, ElementMappedToListGui {
protected MappedToListSubSettingGui(
int rows,
@NotNull String title) {
super(rows, title, CustomAnvil.instance);
@NotNull String type) {
super(rows, MsgUI.INSTANCE.getSHARED_TYPED_CONFIG_TITLE().textHolder(type), CustomAnvil.instance);
}
@Override

View file

@ -20,6 +20,7 @@ import xyz.alexcrea.cuanvil.gui.config.SelectEnchantmentContainer;
import xyz.alexcrea.cuanvil.gui.config.list.SettingGuiListConfigGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import xyz.alexcrea.cuanvil.lang.Message;
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
import java.util.*;
@ -35,8 +36,10 @@ public class EnchantSelectSettingGui extends SettingGuiListConfigGui<CAEnchantme
private boolean displayUnselected;
public EnchantSelectSettingGui(@NotNull String title, ValueUpdatableGui parent, SelectEnchantmentContainer enchantContainer) {
super(title, parent instanceof Gui parentGui ? parentGui : MainConfigGui.getInstance()) ;
public EnchantSelectSettingGui(
@NotNull Message title, @NotNull String param,
ValueUpdatableGui parent, SelectEnchantmentContainer enchantContainer) {
super(title, param, parent instanceof Gui parentGui ? parentGui : MainConfigGui.getInstance()) ;
this.enchantContainer = enchantContainer;
this.selectedEnchant = new HashSet<>(enchantContainer.getSelectedEnchantments());

View file

@ -19,6 +19,7 @@ import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui;
import xyz.alexcrea.cuanvil.gui.config.SelectGroupContainer;
import xyz.alexcrea.cuanvil.gui.config.list.ElementListConfigGui;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import xyz.alexcrea.cuanvil.lang.Message;
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
import java.util.Collections;
@ -34,8 +35,10 @@ public class GroupSelectSettingGui extends AbstractSettingGui {
Set<AbstractMaterialGroup> selectedGroups;
public GroupSelectSettingGui(@NotNull String title, ValueUpdatableGui parent, SelectGroupContainer groupContainer, int page) {
super(6, title, parent);
public GroupSelectSettingGui(
@NotNull Message title, @NotNull String param,
ValueUpdatableGui parent, SelectGroupContainer groupContainer, int page) {
super(6, title.textHolder(param), parent);
this.groupContainer = groupContainer;
//Not used but planned
this.page = page;

View file

@ -18,6 +18,8 @@ import xyz.alexcrea.cuanvil.gui.config.list.MappedElementListConfigGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import xyz.alexcrea.cuanvil.lang.Message;
import xyz.alexcrea.cuanvil.lang.MsgUI;
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
import xyz.alexcrea.cuanvil.util.MaterialUtil;
@ -37,9 +39,10 @@ public class MaterialSelectSettingGui extends MappedElementListConfigGui<Namespa
public MaterialSelectSettingGui(
@NotNull SelectMaterialContainer selector,
@NotNull String title,
@NotNull Message title,
@NotNull String param,
@NotNull Gui backGui) {
super(title);
super(title, param);//TODO MESSAGE make param go down
this.selector = selector;
this.backGui = backGui;
this.instantRemove = false;
@ -156,7 +159,7 @@ public class MaterialSelectSettingGui extends MappedElementListConfigGui<Namespa
// Do not allow to save configuration if player do not have edit configuration permission
if (!player.hasPermission(CustomAnvil.editConfigPermission)) {
player.closeInventory();
player.sendMessage(GuiGlobalActions.NO_EDIT_PERM);
MsgUI.INSTANCE.getSHARED_CONFIG_NO_EDIT_PERM().send(player);
return;
}
if(testCantSave()) return;
@ -236,8 +239,8 @@ public class MaterialSelectSettingGui extends MappedElementListConfigGui<Namespa
// Create and show confirm remove gui.
ConfirmActionGui confirmGui = new ConfirmActionGui(
"Remove " + materialName,
"§7Confirm Remove " + materialName.toLowerCase() + " from this list.",
MsgUI.INSTANCE.getMATERIAL_SELECT_CONFIRM_TITLE(), materialName,
MsgUI.INSTANCE.getMATERIAL_SELECT_CONFIRM_DESCRIPTION(), materialName.toLowerCase(),
this, this,
() -> {
removeMaterial(material);

View file

@ -16,6 +16,7 @@ import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.config.WorkPenaltyType;
import xyz.alexcrea.cuanvil.gui.config.global.BasicConfigGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
import xyz.alexcrea.cuanvil.lang.MsgUI;
import java.util.ArrayList;
import java.util.EnumMap;
@ -73,7 +74,7 @@ public class WorkPenaltyTypeSettingGui extends AbstractSettingGui {
// Do not allow to open inventory if player do not have edit configuration permission
if (!player.hasPermission(CustomAnvil.editConfigPermission)) {
player.closeInventory();
player.sendMessage(GuiGlobalActions.NO_EDIT_PERM);
MsgUI.INSTANCE.getSHARED_CONFIG_NO_EDIT_PERM().send(player);
return;
}
new WorkPenaltyTypeSettingGui(parent).show(player);

View file

@ -7,6 +7,7 @@ import org.bukkit.event.inventory.InventoryClickEvent;
import org.jetbrains.annotations.NotNull;
import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui;
import xyz.alexcrea.cuanvil.gui.config.settings.SettingGui;
import xyz.alexcrea.cuanvil.lang.MsgUI;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@ -17,8 +18,6 @@ import java.util.function.Consumer;
*/
public class GuiGlobalActions {
public static final String NO_EDIT_PERM = "§cYou do not have permission to edit the config";
/**
* A Consumer that should be used if the item goal is to do nothing on click.
*/
@ -44,7 +43,7 @@ public class GuiGlobalActions {
// Do not allow to open inventory if player do not have edit configuration permission
if (!player.hasPermission(CustomAnvil.editConfigPermission)) {
player.closeInventory();
player.sendMessage(NO_EDIT_PERM);
MsgUI.INSTANCE.getSHARED_CONFIG_NO_EDIT_PERM().send(player);
return;
}
try {
@ -102,7 +101,7 @@ public class GuiGlobalActions {
// Do not allow to open inventory if player do not have edit configuration permission
if (!player.hasPermission(CustomAnvil.editConfigPermission)) {
player.closeInventory();
player.sendMessage(NO_EDIT_PERM);
MsgUI.INSTANCE.getSHARED_CONFIG_NO_EDIT_PERM().send(player);
return;
}
goal.show(player);
@ -127,7 +126,7 @@ public class GuiGlobalActions {
// Do not allow to save configuration if player do not have edit configuration permission
if (!player.hasPermission(CustomAnvil.editConfigPermission)) {
player.closeInventory();
player.sendMessage(NO_EDIT_PERM);
MsgUI.INSTANCE.getSHARED_CONFIG_NO_EDIT_PERM().send(player);
return;
}

View file

@ -1,14 +1,13 @@
package io.delilaheve
import io.delilaheve.util.ConfigOptions
import net.kyori.adventure.text.Component
import org.bukkit.Bukkit
import org.bukkit.configuration.file.YamlConfiguration
import org.bukkit.plugin.java.JavaPlugin
import xyz.alexcrea.cuanvil.api.event.CAConfigReadyEvent
import xyz.alexcrea.cuanvil.api.event.CAEnchantRegistryReadyEvent
import xyz.alexcrea.cuanvil.command.CustomAnvilCommand
import xyz.alexcrea.cuanvil.command.EditConfigExecutor
import xyz.alexcrea.cuanvil.command.ReloadExecutor
import xyz.alexcrea.cuanvil.config.ConfigHolder
import xyz.alexcrea.cuanvil.dependency.DependencyManager
import xyz.alexcrea.cuanvil.dependency.MinecraftVersionUtil
@ -17,6 +16,9 @@ import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil
import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry
import xyz.alexcrea.cuanvil.gui.config.MainConfigGui
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant
import xyz.alexcrea.cuanvil.lang.Lang
import xyz.alexcrea.cuanvil.lang.MsgError
import xyz.alexcrea.cuanvil.lang.MsgWarning
import xyz.alexcrea.cuanvil.listener.AnvilCloseListener
import xyz.alexcrea.cuanvil.listener.AnvilResultListener
import xyz.alexcrea.cuanvil.listener.ChatEventListener
@ -75,7 +77,7 @@ open class CustomAnvil : JavaPlugin() {
var latestVer: String? = null
// Debug
val debugStorageQueue = ArrayDeque<String>()
val debugStorageQueue = ArrayDeque<Component>()
private fun addToLogQueue(message: String) {
if(debugStorageQueue.size >= 200) {
@ -83,7 +85,7 @@ open class CustomAnvil : JavaPlugin() {
debugStorageQueue.removeFirst()
}
debugStorageQueue.addLast(message)
debugStorageQueue.addLast(Component.text(message))
}
/**
@ -108,11 +110,23 @@ open class CustomAnvil : JavaPlugin() {
}
}
/**
* Error Logging handler
*/
@JvmStatic fun logError(message: String, throwable: Throwable? = null, track: Boolean = true, level: Level = Level.SEVERE) {
instance.logger.log(level, message, throwable)
addToLogQueue("Error: $message")
if(track) {
MetricsUtil.trackError(message, throwable)
}
}
}
// stop plugin if we do not force a dirty start (true by default)
// Return true if start was stopped
private fun tryDirtyStart(): Boolean {
if(ConfigHolder.DEFAULT_CONFIG == null) return false
if(!ConfigHolder.DEFAULT_CONFIG.config.getBoolean("dirty_start", false)) {
Bukkit.getPluginManager().disablePlugin(this)
return true
@ -123,6 +137,7 @@ open class CustomAnvil : JavaPlugin() {
// stop plugin if we force a safe start (false by default)
// Return true if start was stopped
private fun trySafeStart(): Boolean {
if(ConfigHolder.DEFAULT_CONFIG == null) return false
if(ConfigHolder.DEFAULT_CONFIG.config.getBoolean("safe_start", false)) {
Bukkit.getPluginManager().disablePlugin(this)
return true
@ -135,39 +150,45 @@ open class CustomAnvil : JavaPlugin() {
*/
override fun onEnable() {
instance = this
try {
legacyCheck()
} catch (e: Exception) {
logger.log(Level.SEVERE, "error trying to check for legacy system", e)
MetricsUtil.trackError(e)
if(trySafeStart()) return
}
// Add commands
try {
CustomAnvilCommand(this)
} catch (e: Exception) {
logger.log(Level.SEVERE, "error trying to register commands", e)
MetricsUtil.trackError(e)
if(trySafeStart()) return
}
// Load default configuration
try {
if(!ConfigHolder.loadDefaultConfig())
throw RuntimeException("Error loading configuration file")
} catch (e: Exception) {
logger.log(Level.SEVERE, "error occurred loading default configuration", e)
MetricsUtil.trackError(e)
logError("error occurred loading default configuration", e)
if(tryDirtyStart()) return
}
// Load language
try {
Lang.loadDefault()
} catch (e: Exception) {
logError("error occurred loading language file", e)
if(tryDirtyStart()) return
}
try {
legacyCheck()
} catch (e: Exception) {
MsgError.LOAD_LEGACY_FAILED.log(e)
if(trySafeStart()) return
}
// Add commands
try {
CustomAnvilCommand(this)
} catch (e: Exception) {
MsgError.LOAD_COMMAND_REGISTER.log(e)
if(trySafeStart()) return
}
// Load dependency
try {
DependencyManager.loadDependency()
} catch (e: Exception) {
logger.log(Level.SEVERE, "error loading dependency compatibility", e)
MetricsUtil.trackError(e)
MsgError.LOAD_COMPATIBILITY.log(e)
if(tryDirtyStart()) return
}
@ -175,8 +196,7 @@ open class CustomAnvil : JavaPlugin() {
try {
registerListeners()
} catch (e: Exception) {
logger.log(Level.SEVERE, "error registering listeners", e)
MetricsUtil.trackError(e)
MsgError.LOAD_LISTENERS.log(e)
if(tryDirtyStart()) return
}
@ -192,33 +212,20 @@ open class CustomAnvil : JavaPlugin() {
MetricsUtil.shutdownMetrics()
}
private fun loadEnchantmentSystemDirty() {
try {
loadEnchantmentSystem()
} catch (e: Exception) {
logger.log(Level.SEVERE, "error initializing enchantment system", e)
MetricsUtil.trackError(e)
tryDirtyStart()
}
}
private fun legacyCheck() {
// Disable old plugin name if exist
val potentialPlugin = Bukkit.getPluginManager().getPlugin("UnsafeEnchantsPlus")
if (potentialPlugin != null) {
Bukkit.getPluginManager().disablePlugin(potentialPlugin)
logger.warning("An old version of this plugin was detected")
logger.warning("Please note CustomAnvil is a more recent version of UnsafeEnchantsPlus")
MsgWarning.LOAD_LEGACY_OLD_NAME.log()
}
val isPaper = PlatformUtil.isPaper
if(!isPaper) {
logger.warning("It seems you are using spigot")
logger.warning("Please take notice that spigot is less supported than paper and derivatives")
if(MinecraftVersionUtil.isTooNewForSpigot) {
logger.warning("If replace too expensive is not working this is likely because of spigot")
logger.warning("As native nms is not supported for spigot starting 26.1")
}
MsgWarning.LOAD_LEGACY_SPIGOT.log()
if(MinecraftVersionUtil.isTooNewForSpigot)
MsgWarning.LOAD_LEGACY_SPIGOT_OLD.log()
}
val loader = if(isPaper) "paper" else "spigot"
@ -230,13 +237,13 @@ open class CustomAnvil : JavaPlugin() {
UpdateUtils.currentMinecraftVersion().toString())
.setFeatured(featured)
.setOnError {
logger.log(Level.WARNING, "error trying to fetch latest update", it)
MsgError.LOAD_UPDATE_CHECK_FAIL.log(it, level = Level.WARNING, track = false)
}
.checkVersion { latestVer: String? ->
CustomAnvil.latestVer = latestVer
if(latestVer == null || version.contains(latestVer)) return@checkVersion
logger.warning("An update may be available: $latestVer")
MsgWarning.LOAD_UPDATE_AVAILABLE.log(latestVer)
}
}
@ -251,6 +258,15 @@ open class CustomAnvil : JavaPlugin() {
server.pluginManager.registerEvents(AnvilCloseListener(DependencyManager.packetManager), this)
}
private fun loadEnchantmentSystemDirty() {
try {
loadEnchantmentSystem()
} catch (e: Exception) {
MsgError.LOAD_ENCHANT_SYSTEM.log(e)
tryDirtyStart()
}
}
private fun loadEnchantmentSystem(){
// Register enchantments
CAEnchantmentRegistry.getInstance().registerBukkit()
@ -261,7 +277,7 @@ open class CustomAnvil : JavaPlugin() {
// Load config
if (!ConfigHolder.loadNonDefaultConfig()) {
logger.log(Level.SEVERE,"Plugin has an issue while trying to load non default config... exiting...")
MsgError.LOAD_NON_DEFAULT_CONFIG.log()
server.pluginManager.disablePlugin(this)
return
}
@ -315,16 +331,15 @@ open class CustomAnvil : JavaPlugin() {
try {
val configReader = FileReader(resourceFile)
yamlConfig.load(configReader)
} catch (test: Exception) {
} catch (e: Exception) {
MsgError.RELOAD_FAIL.log(e, resourceFile.path)
if (hardFailSafe) {
// This is important and may impact gameplay if it does not load.
// Failsafe is to stop the plugin
logger.severe("Resource ${resourceFile.path} Could not be load or reload.")
logger.severe("Disabling plugin.")
MsgError.RELOAD_HARD_FAIL.log()
Bukkit.getPluginManager().disablePlugin(this)
} else {
logger.warning("Resource ${resourceFile.path} Could not be load or reload.")
}
return null
}
return yamlConfig

View file

@ -22,9 +22,9 @@ import xyz.alexcrea.cuanvil.dialog.AnvilRenameDialog
import xyz.alexcrea.cuanvil.enchant.CAEnchantment
import xyz.alexcrea.cuanvil.recipe.AnvilCustomRecipe
import xyz.alexcrea.cuanvil.util.CasedStringUtil
import xyz.alexcrea.cuanvil.util.ComponentUtil.serializeLegacy
import xyz.alexcrea.cuanvil.util.CustomRecipeUtil
import xyz.alexcrea.cuanvil.util.MaterialUtil.isAir
import xyz.alexcrea.cuanvil.util.MiniMessageUtil
import xyz.alexcrea.cuanvil.util.UnitRepairUtil.getRepair
import xyz.alexcrea.cuanvil.util.anvil.AnvilColorUtil
import xyz.alexcrea.cuanvil.util.anvil.AnvilLoreEditUtil
@ -151,7 +151,7 @@ object AnvilMergeLogic {
)
if (component != null) {
renameText = MiniMessageUtil.legacy_mm.serialize(component)
renameText = component.serializeLegacy()
sumCost += ConfigOptions.useOfColorCost
useColor = true

View file

@ -3,6 +3,7 @@ package xyz.alexcrea.cuanvil.command
import org.bukkit.command.Command
import org.bukkit.command.CommandSender
import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry
import xyz.alexcrea.cuanvil.lang.Message
interface CASubCommand {
@ -21,7 +22,7 @@ interface CASubCommand {
list: MutableList<String>
)
fun description(): String
fun description(): Message
fun allEnchantmentsByName(): Collection<String> {
val names = mutableSetOf<String>()

View file

@ -6,7 +6,7 @@ import org.bukkit.command.Command
import org.bukkit.command.CommandExecutor
import org.bukkit.command.CommandSender
import org.bukkit.command.TabCompleter
import xyz.alexcrea.cuanvil.util.MetricsUtil
import xyz.alexcrea.cuanvil.lang.MsgCommand
class CustomAnvilCommand(plugin: CustomAnvil) : CommandExecutor, TabCompleter {
@ -57,15 +57,15 @@ class CustomAnvilCommand(plugin: CustomAnvil) : CommandExecutor, TabCompleter {
}
if (subcmd == null || !subcmd.allowed(sender)) {
sender.sendMessage("Invalid subcommand. run `$cmdstr help` to see available commands")
MsgCommand.ROOT_UNKNOWN_SUBCOMMAND.send(sender, cmdstr)
return true
}
try {
return subcmd.executeCommand(sender, cmd, subcmdStr, newargs)
} catch (e: Throwable) {
MetricsUtil.trackError(e)
sender.sendMessage("§cError running this command")
CustomAnvil.logError("Error running /$cmdstr ${args.joinToString(" ")}", e)
MsgCommand.ROOT_ERROR_SUBCOMMAND.send(sender)
return false
}
}

View file

@ -6,16 +6,22 @@ import net.md_5.bungee.api.chat.ClickEvent
import net.md_5.bungee.api.chat.HoverEvent
import net.md_5.bungee.api.chat.TextComponent
import net.md_5.bungee.api.chat.hover.content.Text
import org.bukkit.ChatColor
import org.bukkit.command.Command
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import xyz.alexcrea.cuanvil.command.DiagnosticExecutor.Companion.NO_DIAG_PERM
import xyz.alexcrea.cuanvil.lang.Lang
import xyz.alexcrea.cuanvil.lang.Message
import xyz.alexcrea.cuanvil.lang.MsgCommand
import xyz.alexcrea.cuanvil.lang.MsgError
import xyz.alexcrea.cuanvil.lang.MsgUI
import xyz.alexcrea.cuanvil.lang.MsgWarning
import xyz.alexcrea.cuanvil.util.ComponentUtil.serializePlain
import java.util.Locale
class DebugToggleExecutor: CASubCommand {
override fun description(): String {
return "Used to toggle debug logs and retrieve it"
override fun description(): Message {
return MsgCommand.DEBUG_DESCRIPTION
}
override fun allowed(sender: CommandSender): Boolean {
@ -26,15 +32,15 @@ class DebugToggleExecutor : CASubCommand {
sender: CommandSender,
cmd: Command,
cmdstr: String,
args: Array<out String>
args: Array<out String>,
): Boolean {
if(!allowed(sender)) {
sender.sendMessage(NO_DIAG_PERM)
MsgCommand.SHARED_NO_DIAG_PERM.send(sender)
return false
}
if(args.isEmpty()) {
sender.sendMessage("Need to specify a subcommand: \"toggle\" or \"get\"")
MsgCommand.SHARED_MISSING_SUBCOMMAND.send(sender, "\"toggle\"", "\"get\"")
return true
}
when(args[0].lowercase()) {
@ -47,52 +53,61 @@ class DebugToggleExecutor : CASubCommand {
"clear" -> {
CustomAnvil.debugStorageQueue.clear()
sender.sendMessage("Log Cleared")
MsgCommand.DEBUG_LOG_CLEARED.send(sender)
}
else -> return false
"lang" -> {
executeLanguageDebug(sender, args)
}
else -> {
MsgCommand.SHARED_UNKNOWN_SUB_COMMAND.send(sender)
return false
}
}
return true
}
private fun executeToggle(sender: CommandSender, args: Array<out String>) {
if(args.size < 2) {
sender.sendMessage("Need to specify which type of debug to toggle: \"default\" or \"verbose\"")
MsgCommand.DEBUG_WARNING_UNSPECIFIED_TYPE.send(sender)
return
}
when(args[1].lowercase()) {
"default" -> {
ConfigOptions.OVERRIDE_DEBUG_LOG = !ConfigOptions.debugLog
sender.sendMessage("Debug toggle to: ${ConfigOptions.debugLog}")
MsgCommand.DEBUG_TOGGLED.send(sender, ConfigOptions.debugLog)
}
"verbose" -> {
ConfigOptions.OVERRIDE_VERBOSE_DEBUG_LOG = !ConfigOptions.verboseDebugLog
sender.sendMessage("Debug toggle to: ${ConfigOptions.verboseDebugLog}")
MsgCommand.DEBUG_TOGGLED.send(sender, ConfigOptions.debugLog)
}
else -> sender.sendMessage("Invalid debug type: ${args[1]}")
else -> MsgCommand.DEBUG_WARNING_INVALID_TYPE.send(sender, ConfigOptions.debugLog)
}
}
private fun executeGet(sender: CommandSender) {
val stb = StringBuilder("Debug Log data:")
if(CustomAnvil.debugStorageQueue.isEmpty()) {
sender.sendMessage("No log to show ? make sure you tried with debug log toggled (/ca debug toggle)")
MsgCommand.DEBUG_WARNING_NO_LOG.send(sender, "/ca debug toggle")
return
}
stb.append("\nFound ${CustomAnvil.debugStorageQueue.size} lines\n")
val stb = StringBuilder(MsgCommand.DEBUG_DATA_HEADER.unformatted()).append(' ')
stb.append(MsgCommand.DEBUG_DATA_LINE_COUNT.unformatted(CustomAnvil.debugStorageQueue.size))
for(log in CustomAnvil.debugStorageQueue) {
stb.append('\n').append(log)
stb.append('\n').append(log.serializePlain())
}
if(sender is Player) {
val message = TextComponent(ChatColor.GREEN.toString() + "Click to copy log data")
val message = TextComponent(MsgCommand.DEBUG_COPY.legacy())
message.clickEvent = ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, stb.toString())
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, Text("§7Click to copy"))
message.hoverEvent = HoverEvent(
HoverEvent.Action.SHOW_TEXT,
Text(MsgCommand.SHARED_HOVER_COPY.legacy())
)
sender.spigot().sendMessage(message);
} else {
@ -100,14 +115,142 @@ class DebugToggleExecutor : CASubCommand {
}
}
private fun executeLanguageDebug(sender: CommandSender, args: Array<out String>) {
if(args.size > 1 && "details".contentEquals(args[1], ignoreCase = true))
detailedLangDebug(sender)
else
simpleLangDebug(sender)
}
private fun simpleLangDebug(sender: CommandSender) {
var validCount = 0
// load key from all provider class
MsgCommand.DEBUG_DATA_HEADER
MsgUI.SHARED_CONFIG_NO_EDIT_PERM
MsgError.LOAD_LISTENERS
MsgWarning.ANVIL_GENERIC_EXCEPTION
val registeredKeys = Message.getValues()
for(message in registeredKeys)
if(Lang.has(message.key)) validCount++
val valid = (100.0 * validCount) / registeredKeys.size
sender.sendMessage("Translated (${Lang.currentLang()}): ${"%.1f".format(Locale.ROOT, valid)}% ($validCount/${registeredKeys.size})")
}
private fun detailedLangDebug(sender: CommandSender) {
simpleLangDebug(sender)
val stb = StringBuilder("Report of potential issue for language ${Lang.currentLang()}:\n")
var hadAny = false
val keySet = mutableSetOf<String>()
val registeredKeys = Message.getValues()
for(message in registeredKeys) {
val key = message.key
if(!Lang.has(key)) {
stb.append("Missing key inside translation file: $key\n")
hadAny = true
} else if(hashParamIssue(message, stb))
hadAny = true
if(keySet.contains(key)) {
stb.append("Duplicate registered key: $key\n")
hadAny = true
} else keySet.add(key)
}
for(key in Lang.getKeys()) {
if(!keySet.contains(key)) {
stb.append("Found unregistered key: $key\n")
hadAny = true
}
}
if(hadAny) {
val message = TextComponent(MsgCommand.DEBUG_LANG_COPY.legacy())
message.clickEvent = ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, stb.toString())
message.hoverEvent = HoverEvent(
HoverEvent.Action.SHOW_TEXT,
Text(MsgCommand.SHARED_HOVER_COPY.legacy())
)
sender.spigot().sendMessage(message);
} else {
sender.sendMessage("No additional issue found")
}
}
private fun hashParamIssue(message: Message, stb: StringBuilder): Boolean {
val section = Lang.getSection(message.key)
val texts = if(section == null)
listOf(Lang.getTranslated(message.key))
else
section.getValues(false).map { it.value.toString() }
val textParams = ArrayList<String>()
for(text in texts) {
var index = 0
while(true) {
index = text.indexOf('%', index)
//TODO add \% to "ignore" % as param inside param finder
if(index > 0 && text[index-1] == '\\') {
index++
continue
}
if(index++ < 0) break
var end = text.indexOf(' ', index)
if(end == -1) end = text.length
val param = text.substring(index, end)
if(!textParams.contains(param)) textParams.add(param)
}
}
var hadIssue = false
// Check all parameter are valid
val usedParam = mutableSetOf<String>()
for(textParam in textParams) {
var found = false
for(param in message.params) {
if(param.isEmpty()) continue
if(textParam.startsWith(param)) {
found = true
usedParam.add(param)
break
}
}
if(!found) {
hadIssue = true
stb.append("Did not found param %$textParam in register list for ${message.key}\n")
}
}
for(param in message.params) {
if(usedParam.contains(param)) continue
if("unused".contentEquals(param)) continue
hadIssue = true
stb.append("Param %$param is not used for key ${message.key}\n")
}
return hadIssue
}
override fun tabCompleter(sender: CommandSender, args: Array<out String>, list: MutableList<String>) {
if(!allowed(sender)) return
list.addAll(
when(args.size) {
1 -> listOf("toggle", "get", "get-and-clear", "clear")
1 -> listOf("toggle", "get", "get-and-clear", "clear", "lang")
2 -> when(args[0].lowercase()) {
"toggle" -> listOf("default", "verbose")
"lang" -> listOf("details")
else -> listOf()
}

View file

@ -6,7 +6,6 @@ import net.md_5.bungee.api.chat.HoverEvent
import net.md_5.bungee.api.chat.TextComponent
import net.md_5.bungee.api.chat.hover.content.Text
import org.bukkit.Bukkit
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.command.Command
import org.bukkit.command.CommandSender
@ -25,15 +24,17 @@ import xyz.alexcrea.cuanvil.dependency.DependencyManager
import xyz.alexcrea.cuanvil.dependency.packet.NoPacketManager
import xyz.alexcrea.cuanvil.dependency.packet.ProtocoLibWrapper
import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry
import xyz.alexcrea.cuanvil.lang.Message
import xyz.alexcrea.cuanvil.lang.MsgCommand
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener
import xyz.alexcrea.cuanvil.util.MetricsUtil
import java.util.*
import java.util.stream.Collectors
@Suppress("UnstableApiUsage")
class DiagnosticExecutor : CASubCommand {
companion object {
const val NO_DIAG_PERM = "You do not have permission to diagnostic this server"
fun fetchNMSType(): String {
val packetManager = DependencyManager.packetManager
@ -101,7 +102,7 @@ class DiagnosticExecutor : CASubCommand {
args: Array<out String>
): Boolean {
if (!allowed(sender)) {
sender.sendMessage(NO_DIAG_PERM)
MsgCommand.SHARED_NO_DIAG_PERM.send(sender)
return false
}
@ -122,12 +123,11 @@ class DiagnosticExecutor : CASubCommand {
if (sender is HumanEntity) {
if (hasError)
sender.spigot()
.sendMessage(TextComponent(ChatColor.RED.toString() + "There was an error running the diagnostic"))
val message = TextComponent(ChatColor.GREEN.toString() + "Click to copy diagnostic data")
MsgCommand.DIAGNOSTIC_ERROR_GENERIC.send(sender)
val message = TextComponent(MsgCommand.DIAGNOSTIC_COPY.legacy())
message.clickEvent = ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, stb.toString())
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, Text("§7Click to copy"))
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, Text(MsgCommand.SHARED_HOVER_COPY.legacy()))
sender.spigot().sendMessage(message)
} else {
@ -214,8 +214,8 @@ class DiagnosticExecutor : CASubCommand {
return this.name + " v" + this.description.version
}
override fun description(): String {
return "Basic diagnostic of this plugin"
override fun description(): Message {
return MsgCommand.DIAGNOSTIC_DESCRIPTION
}
private fun pluginListDiag(sender: CommandSender, stb: StringBuilder) {

View file

@ -10,7 +10,9 @@ import xyz.alexcrea.cuanvil.enchant.CAEnchantment
import xyz.alexcrea.cuanvil.gui.config.MainConfigGui
import xyz.alexcrea.cuanvil.gui.config.global.EnchantConfigGui
import xyz.alexcrea.cuanvil.gui.config.global.ItemConfigGui
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions
import xyz.alexcrea.cuanvil.lang.Message
import xyz.alexcrea.cuanvil.lang.MsgCommand
import xyz.alexcrea.cuanvil.lang.MsgUI
import xyz.alexcrea.cuanvil.util.MaterialUtil.customType
import xyz.alexcrea.cuanvil.util.MaterialUtil.isAir
@ -20,33 +22,29 @@ class EditConfigExecutor : CASubCommand {
return sender.hasPermission(CustomAnvil.editConfigPermission)
}
override fun description(): String {
return "Gui to edit the plugin's config"
override fun description(): Message {
return MsgCommand.CONFIG_DESCRIPTION
}
override fun executeCommand(
sender: CommandSender,
cmd: Command,
cmdstr: String,
args: Array<out String>
args: Array<out String>,
): Boolean {
if(sender !is HumanEntity) return false
if(!allowed(sender)) {
sender.sendMessage(GuiGlobalActions.NO_EDIT_PERM)
MsgUI.SHARED_CONFIG_NO_EDIT_PERM.send(sender)
return false
}
if(PlatformUtil.isFolia) {
sender.sendMessage("§cIt look like you are using Folia. Sadly Custom Anvil do not support Config gui for Folia.")
sender.sendMessage("§eIt is may come in a future version.")
sender.sendMessage("")
sender.sendMessage("§eCurrently you need to edit manually the config or copy from another server (spigot or better)")
sender.sendMessage("§eThen /ca reload after config file is edited")
MsgCommand.CONFIG_FOLIA_ISSUE.send(sender)
return false
}
if("gui".equals(cmdstr, ignoreCase = true)) {
sender.sendMessage("§c/ca gui has been moved to /ca config")
MsgCommand.CONFIG_LEGACY_NAME_WARNING.send(sender)
}
if(args.isEmpty())
@ -55,7 +53,7 @@ class EditConfigExecutor : CASubCommand {
"open" -> processOpen(sender)
"enchant" -> processEnchant(sender, args)
"item" -> processItem(sender)
else -> sender.sendMessage("Unknown subcommand \"${args[0]}\"")
else -> MsgCommand.SHARED_UNKNOWN_SUB_COMMAND.send(sender)
}
return true
@ -68,26 +66,25 @@ class EditConfigExecutor : CASubCommand {
enchantToFilter = EnchantmentApi.getEnchantments(item).keys
if(enchantToFilter.isEmpty()) {
sender.sendMessage("No enchantment found in the item you are holding")
MsgCommand.CONFIG_ENCHANTMENT_NO_IN_HAND.send(sender)
return
}
} else {
enchantToFilter = HashSet(EnchantmentApi.getByName(args[1].lowercase()))
if(enchantToFilter.isEmpty()) {
sender.sendMessage("No enchantment found with the name \"${args[1]}\"")
MsgCommand.CONFIG_ENCHANTMENT_NO_NAME.send(sender, args[1])
return
}
}
EnchantConfigGui(enchantToFilter).show(sender)
}
private fun processItem(sender: HumanEntity) {
val item = sender.inventory.itemInMainHand
if(item.isAir) {
sender.sendMessage("Cannot configure the item in hand")
MsgCommand.CONFIG_CANNOT_CONFIGURE_WARNING.send(sender)
return
}

View file

@ -10,6 +10,8 @@ import org.bukkit.command.CommandSender
import org.bukkit.entity.HumanEntity
import xyz.alexcrea.cuanvil.api.EnchantmentApi
import xyz.alexcrea.cuanvil.enchant.CAEnchantment
import xyz.alexcrea.cuanvil.lang.Message
import xyz.alexcrea.cuanvil.lang.MsgCommand
import xyz.alexcrea.cuanvil.util.MaterialUtil.isAir
class EnchantExecutor : CASubCommand {
@ -19,33 +21,33 @@ class EnchantExecutor : CASubCommand {
return sender.hasPermission(CustomAnvil.giveEnchantmentPermission)
}
override fun description(): String {
return "Allows to set enchantment to holden item"
override fun description(): Message {
return MsgCommand.ENCHANT_DESCRIPTION
}
override fun executeCommand(
sender: CommandSender,
cmd: Command,
cmdstr: String,
args: Array<out String>
args: Array<out String>,
): Boolean {
if(sender !is HumanEntity) return true
if(!allowed(sender)) {
sender.sendMessage("No permission to execute this command")
MsgCommand.SHARED_NO_PERMISSION.send(sender)
return true
}
when(args.size) {
0 -> {
sender.sendMessage("Missing enchantment parameter")
MsgCommand.ENCHANT_MISSING_PARAMETER_WARNING.send(sender)
return true
}
}
val enchant = firstEnchantment(args[0])
if(enchant == null) {
sender.sendMessage("Enchantment not found: ${args[0]}")
MsgCommand.ENCHANT_NOT_FOUND_WARNING.send(sender, args[0])
return true
}
@ -54,13 +56,13 @@ class EnchantExecutor : CASubCommand {
else 1
if(level == null) {
sender.sendMessage("Invalid number: ${args[1]}")
MsgCommand.ENCHANT_MALFORMED_NUMBER_WARNING.send(sender, args[1])
return true
}
val inHand = sender.inventory.itemInMainHand
if(inHand.isAir) {
sender.sendMessage("Cannot enchant this item")
MsgCommand.ENCHANT_CANNOT_ENCHANT_WARNING.send(sender)
return true
}
@ -70,13 +72,13 @@ class EnchantExecutor : CASubCommand {
if(inHand.isEnchantedBook() && EnchantmentApi.getEnchantments(inHand).isEmpty())
inHand.type = Material.BOOK
sender.sendMessage("${enchant.prettyName} removed")
MsgCommand.ENCHANT_REMOVE.send(sender, enchant.prettyName)
} else {
if(Material.BOOK == inHand.type)
inHand.type = Material.ENCHANTED_BOOK
enchant.addEnchantmentUnsafe(inHand, level)
sender.sendMessage("${enchant.prettyName} set to level $level")
MsgCommand.ENCHANT_SET.send(sender, enchant.prettyName, level)
}
return true
@ -97,7 +99,7 @@ class EnchantExecutor : CASubCommand {
private fun findEnchantmentLevels(
sender: HumanEntity,
name: String
name: String,
): Collection<String> {
val enchant = firstEnchantment(name) ?: return listOf()

View file

@ -1,29 +1,37 @@
package xyz.alexcrea.cuanvil.command
import com.google.common.collect.ImmutableMap
import net.kyori.adventure.text.Component
import org.bukkit.command.Command
import org.bukkit.command.CommandSender
import xyz.alexcrea.cuanvil.lang.Message
import xyz.alexcrea.cuanvil.lang.MsgCommand
import xyz.alexcrea.cuanvil.util.ComponentUtil.send
class HelpExecutor : CASubCommand {
override fun description(): Message {
return MsgCommand.HELP_DESCRIPTION
}
lateinit var commands: ImmutableMap<String, CASubCommand>
override fun executeCommand(
sender: CommandSender,
cmd: Command,
cmdstr: String,
args: Array<out String>
args: Array<out String>,
): Boolean {
val stb = StringBuilder("List of available commands:")
var text = MsgCommand.HELP_HEADER.formatted().first()
for((key, cmd) in commands) {
if(!cmd.allowed(sender)) continue
stb.append("\n- $key: ").append(cmd.description())
text = text.appendNewline()
.append(Component.text("- $key: "))
.append(cmd.description().formatted())
}
sender.sendMessage(stb.toString())
text.send(sender)
return true
}
@ -34,12 +42,8 @@ class HelpExecutor : CASubCommand {
override fun tabCompleter(
sender: CommandSender,
args: Array<out String>,
list: MutableList<String>
list: MutableList<String>,
) {
}
override fun description(): String {
return "Help command"
}
}

View file

@ -8,29 +8,36 @@ import xyz.alexcrea.cuanvil.api.event.CAConfigReadyEvent
import xyz.alexcrea.cuanvil.config.ConfigHolder
import xyz.alexcrea.cuanvil.dependency.DependencyManager
import xyz.alexcrea.cuanvil.gui.config.global.*
import xyz.alexcrea.cuanvil.lang.Lang
import xyz.alexcrea.cuanvil.lang.Message
import xyz.alexcrea.cuanvil.lang.MsgCommand
import xyz.alexcrea.cuanvil.update.UpdateHandler
class ReloadExecutor : CASubCommand {
override fun description(): Message {
return MsgCommand.RELOAD_DESCRIPTION
}
override fun executeCommand(
sender: CommandSender,
cmd: Command,
cmdstr: String,
args: Array<out String>
args: Array<out String>,
): Boolean {
if(!allowed(sender)) {
sender.sendMessage("§cYou do not have permission to reload the config")
MsgCommand.SHARED_NO_PERMISSION.send(sender)
return false
}
sender.sendMessage("§eReloading config...")
MsgCommand.RELOAD_START.send(sender)
val hardfail = args.isNotEmpty() && ("hard".equals(args[0], true))
val commandSuccess = commandBody(hardfail)
if(commandSuccess) {
sender.sendMessage("§aConfig reloaded !")
MsgCommand.RELOAD_SUCCESS.send(sender)
} else {
sender.sendMessage("§cConfig was not able to be reloaded...")
MsgCommand.RELOAD_FAIL.send(sender)
if(hardfail) {
sender.sendMessage("§4Hard fail, plugin disabled")
MsgCommand.RELOAD_HARD_FAIL.send(sender)
}
}
return commandSuccess
@ -43,14 +50,10 @@ class ReloadExecutor : CASubCommand {
override fun tabCompleter(
sender: CommandSender,
args: Array<out String>,
list: MutableList<String>
list: MutableList<String>,
) {
}
override fun description(): String {
return "Reload the configuration of this plugin"
}
/**
* Execute the command, return true if success or false otherwise
*/
@ -58,6 +61,9 @@ class ReloadExecutor : CASubCommand {
try {
if(!ConfigHolder.reloadAllFromDisk(hardfail)) return false
// reload language config
if(!Lang.reload()) return false
// Then update all global gui containing value from config
BasicConfigGui.getInstance()?.updateGuiValues()
EnchantCostConfigGui.getInstance()?.updateGuiValues()

View file

@ -3,7 +3,6 @@ package xyz.alexcrea.cuanvil.dependency
import io.delilaheve.CustomAnvil
import net.kyori.adventure.text.Component
import org.bukkit.Bukkit
import org.bukkit.ChatColor
import org.bukkit.command.CommandSender
import org.bukkit.entity.HumanEntity
import org.bukkit.entity.Player
@ -28,10 +27,10 @@ import xyz.alexcrea.cuanvil.dependency.scheduler.FoliaScheduler
import xyz.alexcrea.cuanvil.dependency.scheduler.TaskScheduler
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil.componentLore
import xyz.alexcrea.cuanvil.lang.MsgWarning
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_OUTPUT_SLOT
import xyz.alexcrea.cuanvil.util.MetricsUtil.trackError
import java.lang.IllegalStateException
import java.util.logging.Level
@Suppress("UnstableApiUsage")
object DependencyManager {
@ -158,18 +157,14 @@ object DependencyManager {
}
private fun logException(target: CommandSender, e: Exception) {
CustomAnvil.instance.logger.log(
Level.SEVERE,
CustomAnvil.logError(
"Error while trying to handle custom anvil supported plugin: ",
e
)
trackError(e)
// Finally, warn the player
target.sendMessage(
"[" + ChatColor.YELLOW.toString() + "CustomAnvil" + ChatColor.WHITE.toString() + "] " +
ChatColor.RED.toString() + "Error while handling the anvil."
)
MsgWarning.ANVIL_GENERIC_EXCEPTION.send(target)
}
private fun logExceptionAndClear(view: AnvilView, e: Exception) {

View file

@ -0,0 +1,83 @@
package xyz.alexcrea.cuanvil.lang
import io.delilaheve.CustomAnvil
import org.bukkit.configuration.ConfigurationSection
import xyz.alexcrea.cuanvil.config.ConfigHolder
import java.util.stream.Stream
object Lang {
private lateinit var default: Language
private lateinit var lang: Language
fun loadDefault() {
default = Language(DEFAULT_LANG, false)
lang = default
reload()
}
fun reload(): Boolean {
try {
unsafeReload()
return true
} catch(e: Exception) {
CustomAnvil.logError("Error loading language $langID", e, false)
return false
}
}
private fun unsafeReload() {
val langID = langID
if(lang.name == langID && lang != default)
lang.reload()
else
lang = Language(langID)
if(default != lang) default.reload()
}
fun getTranslated(key: String): String {
val value = lang.get(key)
if(value != null) return value
CustomAnvil.log("Missing language data for ${lang.name} using default")
return default.get(key) ?: key
}
fun getSection(key: String): ConfigurationSection? {
val value = lang.getSection(key)
if(value != null) return value
return default.getSection(key)
}
fun currentLang(): String {
return lang.name
}
fun has(key: String): Boolean {
return lang.has(key)
}
fun getKeys(): Collection<String> {
return lang.getFilteredKeys()
}
/*
* Config Options & get
*/
const val LANG_PATH = "language"
const val DEFAULT_LANG = "en"
/**
* Value of an item rename
*/
private val langID: String
get() {
return ConfigHolder.DEFAULT_CONFIG
.config
.getString(LANG_PATH, DEFAULT_LANG)!!
}
}

View file

@ -0,0 +1,99 @@
package xyz.alexcrea.cuanvil.lang
import io.delilaheve.CustomAnvil
import org.bukkit.configuration.ConfigurationSection
import org.bukkit.configuration.file.FileConfiguration
import org.bukkit.configuration.file.YamlConfiguration
import java.io.File
import java.io.InputStreamReader
import java.util.logging.Level
class Language(private val id: String, private val default: Boolean = false) {
private val resourcePath: String
private val file: File
private val conf: FileConfiguration
init {
conf = YamlConfiguration()
resourcePath = "lang/$id.yml"
file = File(CustomAnvil.instance.dataFolder, resourcePath)
reload()
}
fun reload() {
if(file.exists() && !default) try {
conf.load(file)
return
} catch(e: Exception) {
CustomAnvil.instance.logger.log(
Level.SEVERE,
"Could not load custom Anvil config file. using to internal resource",
e
)
}
loadInternalResource()
}
private fun loadInternalResource() {
val input = CustomAnvil.instance.getResource(resourcePath)
if(input != null)
conf.load(InputStreamReader(input))
else
CustomAnvil.instance.logger.log(Level.SEVERE, "Language $id not found")
}
fun get(key: String): String? {
return conf.getString(key)
}
fun getSection(key: String): ConfigurationSection? {
return conf.getConfigurationSection(key)
}
fun has(key: String): Boolean {
if(conf.isString(key)) return true
// we want at all child key as valid numbers and valid key if claimed to be multi line
val section = getSection(key) ?: return false
for(key in section.getKeys(false)) {
if(key.toUIntOrNull() == null) return false
if(!section.isString(key)) return false
}
return true
}
fun getFilteredKeys(): Collection<String> {
val result = ArrayList<String>()
// First pass we ignore key from root
for(root in conf.getKeys(false)) {
val section = conf.getConfigurationSection(root) ?: continue
exploreDeeper(section, root, result)
}
return result
}
private fun exploreDeeper(section: ConfigurationSection, root: String, result: ArrayList<String>) {
for(key in section.getKeys(false)) {
val newRoot = "$root.$key"
if(has(key)) {
result.add(newRoot)
continue
}
val newSection = section.getConfigurationSection(key) ?: continue
exploreDeeper(newSection, newRoot, result)
}
}
val name: String
get() = conf.getString("name", id)!!
}

View file

@ -0,0 +1,180 @@
package xyz.alexcrea.cuanvil.lang
import com.github.stefvanschie.inventoryframework.adventuresupport.ComponentHolder
import com.github.stefvanschie.inventoryframework.adventuresupport.TextHolder
import io.delilaheve.CustomAnvil
import net.kyori.adventure.text.Component
import org.bukkit.command.CommandSender
import org.bukkit.configuration.ConfigurationSection
import xyz.alexcrea.cuanvil.util.ComponentUtil.send
import xyz.alexcrea.cuanvil.util.ComponentUtil.serializeLegacy
import xyz.alexcrea.cuanvil.util.ComponentUtil.serializePlain
import xyz.alexcrea.cuanvil.util.MiniMessageUtil
import java.util.Collections
import java.util.logging.Level
import kotlin.math.min
open class Message(val key: String, vararg val params: String, register: Boolean = true) {
companion object {
private val values = ArrayList<Message>()
fun getValues(): Collection<Message> {
return Collections.unmodifiableCollection(values)
}
}
init {
if(register) values.add(this)
}
protected fun replaceParameters(stb: StringBuilder, vararg values: Any) {
// replace all placeholder thingy %key -> value
if(params.size != values.size) {
CustomAnvil.log("Wrong number of argument for parameter for key $key (${params.size}/${values.size})")
}
for(i in 0 until min(params.size, values.size)) {
val key = params[i]
val replacement = values[i].toString()
if(replacement.isEmpty()) continue //May not be good but can be changed if cause an issue
var current = 0
while(true) {
current = stb.indexOf('%', current) + 1
if(current <= 0 || current + key.length > stb.length) break // may be able to be removed if bound checked in startsWith ?
if(!stb.startsWith(key, current, false)) continue
stb.replace(current - 1, current + key.length, replacement)
current = current - 1 + replacement.length
}
}
}
private fun unformattedMonoline(vararg params: Any): String {
val translated = Lang.getTranslated(key)
if(params.isEmpty() && this.params.isEmpty()) return translated
val stb = StringBuilder(translated)
replaceParameters(stb, *params)
return stb.toString()
}
private fun unformattedMultiline(section: ConfigurationSection, vararg params: Any): String {
val stb = StringBuilder()
for(key in section.getKeys(false)) {
if(!section.isString(key)) continue
if(!stb.isEmpty()) stb.append('\n')
stb.append(section.getString(key))
}
replaceParameters(stb, *params)
return stb.toString()
}
fun unformatted(vararg params: Any): String {
val section = Lang.getSection(key)
if(section != null) return unformattedMultiline(section, *params)
return unformattedMonoline(*params)
}
private fun formattedMultiline(section: ConfigurationSection, vararg params: Any): List<Component> {
val result = ArrayList<Component>()
for(key in section.getKeys(false)) {
if(!section.isString(key)) continue
val stb = StringBuilder(section.getString(key))
replaceParameters(stb, *params)
result.add(MiniMessageUtil.mm.deserialize(stb.toString()))
}
if(result.isEmpty()) return listOf(Component.text(key))
return result
}
// return a list of AT LEAST 1 element. calling first is safe
fun formatted(vararg params: Any): List<Component> {
val section = Lang.getSection(key)
if(section != null) return formattedMultiline(section, *params)
val translated = unformattedMonoline(*params)
return listOf(MiniMessageUtil.mm.deserialize(translated))
}
fun formattedConcatenated(vararg params: Any): Component {
val formated = formatted(*params)
var result = formated.first()
for(i in 1 until formated.size) {
result = result.appendNewline().append(formated[i])
}
return result
}
fun textHolder(vararg params: Any): TextHolder {
return ComponentHolder.of(formattedConcatenated(*params))
}
fun legacy(vararg params: Any): String {
val formated = formatted(*params)
val stb = StringBuilder()
for(component in formated) {
if(!stb.isEmpty()) stb.append('\n')
stb.append(component.serializeLegacy())
}
return stb.toString()
}
open fun log(vararg params: Any) {
val texts = formatted(*params)
for(component in texts) {
CustomAnvil.instance.logger.info(component.serializePlain())
}
}
open fun send(destination: CommandSender, vararg params: Any) {
formatted(*params).send(destination)
}
}
class WarningMessage(key: String, vararg params: String) : Message("warning.$key", *params) {
override fun log(vararg params: Any) {
val texts = formatted(*params)
for(component in texts) {
CustomAnvil.instance.logger.warning(component.serializePlain())
}
}
}
class ErrorMessage(key: String, vararg params: String) : Message("error.$key", *params) {
override fun log(vararg params: Any) {
val texts = formatted(*params)
for(component in texts) {
CustomAnvil.logError(component.serializePlain())
}
}
fun log(e: Throwable, vararg params: Any, level: Level = Level.SEVERE, track: Boolean = true) {
val texts = formatted(*params)
for(component in texts) {
CustomAnvil.logError(component.serializePlain(), e, track, level)
}
}
}
class CommandMessage(key: String, vararg params: String) : Message("command.$key", *params)
class UIMessage(key: String, vararg params: String) : Message("config-ui.$key", *params)

View file

@ -0,0 +1,69 @@
package xyz.alexcrea.cuanvil.lang
import xyz.alexcrea.cuanvil.lang.CommandMessage as Message
object MsgCommand {
// Root
val ROOT_UNKNOWN_SUBCOMMAND = Message("root.warning.unknown-sub", "command")
val ROOT_ERROR_SUBCOMMAND = Message("root.error.generic")
// Shared
val SHARED_NO_DIAG_PERM = Message("shared.no-diag-permission")
val SHARED_HOVER_COPY = Message("shared.hover-copy")
val SHARED_MISSING_SUBCOMMAND = Message("shared.warning.missing-subcmd", "example1", "example2")
val SHARED_UNKNOWN_SUB_COMMAND = Message("shared.unknown-subcmd", "command")
val SHARED_NO_PERMISSION = Message("shared.no-permission")
// Debug
val DEBUG_DESCRIPTION = Message("debug.description")
val DEBUG_LOG_CLEARED = Message("debug.log-cleared")
val DEBUG_TOGGLED = Message("debug.toggled", "type")
val DEBUG_COPY = Message("debug.copy")
val DEBUG_LANG_COPY = Message("debug.copy-lang")
val DEBUG_DATA_HEADER = Message("debug.data.header")
val DEBUG_DATA_LINE_COUNT = Message("debug.data.line-count", "count")
val DEBUG_WARNING_UNSPECIFIED_TYPE = Message("debug.warning.unspecified-type")
val DEBUG_WARNING_INVALID_TYPE = Message("debug.warning.invalid-type", "type")
val DEBUG_WARNING_NO_LOG = Message("debug.warning.no-log", "command")
// Diagnostic
val DIAGNOSTIC_DESCRIPTION = Message("diagnostic.description")
val DIAGNOSTIC_ERROR_GENERIC = Message("diagnostic.had-error")
val DIAGNOSTIC_COPY = Message("diagnostic.copy")
// Config
val CONFIG_DESCRIPTION = Message("config.description")
val CONFIG_LEGACY_NAME_WARNING = Message("config.warning.legacy-name")
val CONFIG_FOLIA_ISSUE = Message("config.folia-issue")
val CONFIG_ENCHANTMENT_NO_IN_HAND = Message("config.enchantment.no_hand")
val CONFIG_ENCHANTMENT_NO_NAME = Message("config.enchantment.no_name", "name")
val CONFIG_CANNOT_CONFIGURE_WARNING = Message("config.warning.cannot_configure")
// Enchant
val ENCHANT_DESCRIPTION = Message("enchant.description")
val ENCHANT_REMOVE = Message("enchant.removed", "name")
val ENCHANT_SET = Message("enchant.set", "name", "level")
val ENCHANT_MISSING_PARAMETER_WARNING = Message("enchant.warning.missing_parameter")
val ENCHANT_NOT_FOUND_WARNING = Message("enchant.warning.not_found", "path")
val ENCHANT_MALFORMED_NUMBER_WARNING = Message("enchant.warning.malformed_number", "num")
val ENCHANT_CANNOT_ENCHANT_WARNING = Message("enchant.warning.cannot_enchant")
// Help
val HELP_DESCRIPTION = Message("help.description")
val HELP_HEADER = Message("help.header")
// Reload
val RELOAD_DESCRIPTION = Message("reload.description")
val RELOAD_START = Message("reload.start")
val RELOAD_SUCCESS = Message("reload.success")
val RELOAD_FAIL = Message("reload.fail")
val RELOAD_HARD_FAIL = Message("reload.hard-fail")
}

View file

@ -0,0 +1,29 @@
package xyz.alexcrea.cuanvil.lang
object MsgError {
/*
* -----------------
* Load and reload
* -----------------
*/
val LOAD_UPDATE_CHECK_FAIL = ErrorMessage("load.update.check-fail")
val LOAD_LEGACY_FAILED = ErrorMessage("load.legacy.failed")
val LOAD_COMMAND_REGISTER = ErrorMessage("load.command-register")
val LOAD_COMPATIBILITY = ErrorMessage("load.compatibility")
val LOAD_LISTENERS = ErrorMessage("load.listeners")
val LOAD_ENCHANT_SYSTEM = ErrorMessage("load.enchant-system")
val LOAD_NON_DEFAULT_CONFIG = ErrorMessage("load.non-default-config")
val RELOAD_FAIL = ErrorMessage("reload.resource.fail", "path")
val RELOAD_HARD_FAIL = ErrorMessage("reload.resource.hard-fail")
/*
* ----
* UI
* ----
*/
val CONFIRM_ACTION_GENERIC = ErrorMessage("confirm-action.generic")
}

View file

@ -0,0 +1,59 @@
package xyz.alexcrea.cuanvil.lang
import xyz.alexcrea.cuanvil.lang.UIMessage as Message
object MsgUI {
val SHARED_CONFIG_NO_EDIT_PERM = Message("shared.no-permission")
val SHARED_TYPED_CONFIG_TITLE = Message("shared.typed-config-title", "type")
val CONFIRM_ACTION_FAILED = Message("confirm-action.fail")
val CONFIRM_ACTION_ARE_YOU_SURE = Message("confirm-action.is-user-sure")
val SELECT_ITEM_TYPE_PLACE_HERE = Message("select-item-type.place-here")
val ELEMENT_LIST_INSTRUCTION_NEW = Message("element-list.instruction-new", "type")
val ELEMENT_LIST_CANCELLED_NEW = Message("element-list.cancelled-new", "type")
val ELEMENT_LIST_DUPLICATED_NEW = Message("element-list.duplicated-new", "type")
val UNIT_REPAIR_TITLE = Message("unit-repair.title", "unused", "page", "max_page")
val UNIT_REPAIR_ELEMENT_TITLE = Message("unit-repair.element.title", "type", "page", "max_page")
val UNIT_REPAIR_NEW_TITLE = Message("unit-repair.new.title")
val UNIT_REPAIR_NEW_DESCRIPTION = Message("unit-repair.new.description")
val UNIT_REPAIR_NEW_ELEMENT_TITLE = Message("unit-repair.element.new.title", "unused")
val UNIT_REPAIR_NEW_ELEMENT_DESCRIPTION = Message("unit-repair.element.new.description", "name")
val UNIT_REPAIR_NEW_ELEMENT_CANNOT_REPAIR = Message("unit-repair.element.new.cannot-damage")
val UNIT_REPAIR_NEW_ELEMENT_SAME_TYPE = Message("unit-repair.element.new.same-type")
val CUSTOM_RECIPE_TITLE = Message("custom-recipe.title", "unused", "page", "max_page")
val CUSTOM_RECIPE_ELEMENT_DELETE_TITLE = Message("custom-recipe.element.delete.title", "type")
val CUSTOM_RECIPE_ELEMENT_DELETE_DESCRIPTION = Message("custom-recipe.element.delete.description", "unused")
val ENCHANTMENT_LEVEL_COST_TITLE = Message("enchant-level-cost.title", "unused", "page", "max_page")
val ENCHANTMENT_LEVEL_LIMIT_TITLE = Message("enchant-level-limit.title", "unused", "page", "max_page")
val ENCHANTMENT_MERGE_LIMIT_TITLE = Message("enchant-merge-limit.title", "unused", "page", "max_page")
val ENCHANTMENT_CONFLICT_TITLE = Message("enchant-conflict.title", "unused", "page", "max_page")
val ENCHANTMENT_CONFLICT_ELEMENT_ENCHANTMENTS = Message("enchant-conflict.element.selected-enchantments", "group")
val ENCHANTMENT_CONFLICT_ELEMENT_SUB_GROUPS = Message("enchant-conflict.element.selected-sub-groups", "group")
val ENCHANTMENT_CONFLICT_ELEMENT_DELETE_TITLE = Message("enchant-conflict.element.delete.title", "type")
val ENCHANTMENT_CONFLICT_ELEMENT_DELETE_DESCRIPTION = Message("enchant-conflict.element.delete.description", "unused")
val MATERIAL_GROUP_TITLE = Message("material-group.title", "unused", "page", "max_page")
val MATERIAL_GROUP_ELEMENT_SELECTED_MATERIALS = Message("material-group.element.selected-materials", "group")
val MATERIAL_GROUP_ELEMENT_SELECTED_SUB_GROUPS = Message("material-group.element.selected-sub-groups", "group")
val MATERIAL_GROUP_ELEMENT_DELETE_TITLE = Message("material-group.element.delete.title", "type")
val MATERIAL_GROUP_ELEMENT_DELETE_DESCRIPTION = Message("material-group.element.delete.description", "unused")
val MATERIAL_GROUP_ELEMENT_DELETE_BUTTON_NAME = Message("material-group.element.delete.button.name")
val MATERIAL_GROUP_ELEMENT_DELETE_BUTTON_LORE = Message("material-group.element.delete.button.lore")
val MATERIAL_SELECT_CONFIRM_TITLE = Message("material-select.new.confirm.title","name")
val MATERIAL_SELECT_CONFIRM_DESCRIPTION = Message("material-select.new.confirm.description","name")
}

View file

@ -0,0 +1,20 @@
package xyz.alexcrea.cuanvil.lang
import xyz.alexcrea.cuanvil.lang.WarningMessage as Message
object MsgWarning {
/*
* -----------------
* Load and reload
* -----------------
*/
val LOAD_UPDATE_AVAILABLE = Message("load.update.available", "version")
val LOAD_LEGACY_OLD_NAME = Message("load.legacy.old-name")
val LOAD_LEGACY_SPIGOT = Message("load.legacy.spigot")
val LOAD_LEGACY_SPIGOT_OLD = Message("load.legacy.spigot-old")
val ANVIL_GENERIC_EXCEPTION = Message("anvil.generic")
}

View file

@ -30,9 +30,9 @@ import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil.setComponentDisplayName
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_INPUT_LEFT
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_INPUT_RIGHT
import xyz.alexcrea.cuanvil.listener.PrepareAnvilListener.Companion.ANVIL_OUTPUT_SLOT
import xyz.alexcrea.cuanvil.util.ComponentUtil.serializePlain
import xyz.alexcrea.cuanvil.util.CustomRecipeUtil
import xyz.alexcrea.cuanvil.util.MaterialUtil.isAir
import xyz.alexcrea.cuanvil.util.MiniMessageUtil
import xyz.alexcrea.cuanvil.util.anvil.AnvilLoreEditUtil
import xyz.alexcrea.cuanvil.util.anvil.AnvilXpUtil
import xyz.alexcrea.cuanvil.util.config.LoreEditConfigUtil
@ -536,7 +536,7 @@ class AnvilResultListener : Listener {
if (bookPage.isNotEmpty()) bookPage.append('\n')
if (it == null) return@forEach
bookPage.append(MiniMessageUtil.plain_text_mm.serialize(it))
bookPage.append(it.serializePlain())
}
val resultPage = bookPage.toString()

View file

@ -0,0 +1,48 @@
package xyz.alexcrea.cuanvil.util
import net.kyori.adventure.text.Component
import org.bukkit.command.CommandSender
import org.bukkit.inventory.meta.ItemMeta
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil.sendPaperMessage
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil.setComponentDisplayName
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil.setPaperLore
import xyz.alexcrea.cuanvil.lang.Message
object ComponentUtil {
fun Component.serializeMM(): String {
return MiniMessageUtil.mm.serialize(this)
}
fun Component.serializeMMColor(): String {
return MiniMessageUtil.color_only_mm.serialize(this)
}
fun Component.serializeLegacy(): String {
return MiniMessageUtil.legacy_mm.serialize(this)
}
fun Component.serializePlain(): String {
return MiniMessageUtil.plain_text_mm.serialize(this)
}
fun Component.send(destination: CommandSender) {
if(!destination.sendPaperMessage(this))
destination.sendMessage(this.serializeLegacy())
}
fun List<Component>.send(destination: CommandSender) {
for(component in this)
component.send(destination)
}
fun List<Component>.applyLore(meta: ItemMeta) {
if(!meta.setPaperLore(this))
meta.lore = this.map {obj -> obj.serializeLegacy()}
}
fun ItemMeta.setMessageName(message: Message, vararg params: Any) {
this.setComponentDisplayName(message.formattedConcatenated(*params))
}
}

View file

@ -74,8 +74,8 @@ object MetricsUtil {
lastError = e
}
fun trackError(message: String) {
ERROR_TRACKER?.trackError(message)
fun trackError(message: String, cause: Throwable? = null) {
trackError(RuntimeException(message, cause))
}
}

View file

@ -25,9 +25,4 @@ object MiniMessageUtil {
val legacy_mm = LegacyComponentSerializer.legacySection()
val plain_text_mm = PlainTextComponentSerializer.plainText()
// Keeping track of this as most use of this can be replaced later on v2 with pure component alternative
fun fromLegacy(legacyText: String): TextComponent {
return legacy_mm.deserialize(legacyText)
}
}

View file

@ -3,6 +3,9 @@ package xyz.alexcrea.cuanvil.util.anvil
import io.delilaheve.util.ConfigOptions
import net.kyori.adventure.text.Component
import org.bukkit.permissions.Permissible
import xyz.alexcrea.cuanvil.util.ComponentUtil.serializeLegacy
import xyz.alexcrea.cuanvil.util.ComponentUtil.serializeMM
import xyz.alexcrea.cuanvil.util.ComponentUtil.serializePlain
import xyz.alexcrea.cuanvil.util.MiniMessageUtil
import java.util.regex.Matcher
import java.util.regex.Pattern
@ -103,10 +106,10 @@ object AnvilColorUtil {
var result: Component = MiniMessageUtil.legacy_mm.deserialize(previousStr)
if (permission.canUseMinimessage) {
// we dance with formats here
val toMinimessage = MiniMessageUtil.mm.serialize(result)
val toMinimessage = result.serializeMM()
val hackySolution = toMinimessage.replace("\\<", "<")
val fromMinimessage = MiniMessageUtil.mm.deserialize(hackySolution)
val asPlain = MiniMessageUtil.plain_text_mm.serialize(fromMinimessage)
val asPlain = fromMinimessage.serializePlain()
if (previousStr != asPlain) {
useColor = true
@ -145,8 +148,8 @@ object AnvilColorUtil {
): String? {
if (!permission.allowed() || component == null) return null
val transformed = MiniMessageUtil.mm.serialize(component)
val plainTransform = MiniMessageUtil.plain_text_mm.serialize(component)
val transformed = component.serializeMM()
val plainTransform = component.serializePlain()
if (transformed == plainTransform) return null
if (permission.onlyMinimessage()) {
return transformed
@ -154,7 +157,7 @@ object AnvilColorUtil {
// smol dance so we transform the component that may contain other tag into only decoration & color for legacy
val coloredMessage = MiniMessageUtil.color_only_mm.deserialize(transformed)
val legacyMessage = StringBuilder(MiniMessageUtil.legacy_mm.serialize(coloredMessage))
val legacyMessage = StringBuilder(coloredMessage.serializeLegacy())
// Reverse hex pattern
if (permission.canUseHexColor) {

View file

@ -10,6 +10,7 @@ import xyz.alexcrea.cuanvil.anvil.AnvilMergeLogic.LoreEditResult
import xyz.alexcrea.cuanvil.dependency.DependencyManager
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil.componentLore
import xyz.alexcrea.cuanvil.dependency.util.PlatformUtil.setComponentLore
import xyz.alexcrea.cuanvil.util.ComponentUtil.serializePlain
import xyz.alexcrea.cuanvil.util.MiniMessageUtil
import xyz.alexcrea.cuanvil.util.config.LoreEditConfigUtil
import xyz.alexcrea.cuanvil.util.config.LoreEditType
@ -320,7 +321,7 @@ object AnvilLoreEditUtil {
hasUndidColor = true
result = clearedLine
} else {
result = MiniMessageUtil.plain_text_mm.serialize(line)
result = line.serializePlain()
}
lines[index] = MiniMessageUtil.plain_text_mm.deserialize(result)
@ -354,7 +355,7 @@ object AnvilLoreEditUtil {
result = clearedLine
} else {
// Remove extra tags
result = MiniMessageUtil.plain_text_mm.serialize(coloredComponent)
result = coloredComponent.serializePlain()
}
line.set(MiniMessageUtil.plain_text_mm.deserialize(result))

View file

@ -16,6 +16,11 @@ metric_type: auto
# Accept true or false (true by default)
metric_collect_errors: true
# Which language should the plugin should be
# If you like to add language yourself see TODO link to guide
# Currently available languages: en
language: en
# All anvil cost will be capped to limit_repair_value if enabled.
#
# In other words:

View file

@ -0,0 +1,185 @@
name: English
last-updated: 2.1.0
warning:
load:
legacy:
old-name:
1: "An old version of this plugin was detected"
2: "Please note CustomAnvil is a more recent version of UnsafeEnchantsPlus"
spigot:
1: "It seems you are using spigot"
2: "Please take notice that spigot is less supported than paper and derivatives"
spigot-old:
1: "If replace too expensive is not working this is likely because of spigot"
2: "As native nms is not supported for spigot starting 26.1"
update.available: "An update may be available: %version"
anvil:
generic: "<white>[<yellow>CustomAnvil<white>] <red>Error while handling the anvil."
error:
load:
legacy.failed: "error trying to check for legacy system"
update.check-fail: "error trying to fetch latest update"
command-register: "error trying to register commands"
compatibility: "error loading dependency compatibility"
listeners: "error registering listeners"
enchant-system: "error initializing enchantment system"
non-default-config: "Plugin has an issue while trying to load non default config... exiting..."
reload:
resource:
fail: "Resource %path Could not be loaded or reloaded."
hard-fail: "Disabling plugin."
confirm-action:
generic: "Could not process confirmation supplier."
command:
shared:
no-diag-permission: "<red>You do not have permission to diagnostic this server"
hover-copy: "<gray>Click to copy"
unknown-subcmd: "Unknown subcommand %command"
no-permission: "No permission to execute this command"
warning:
missing-subcmd: "Need to specify a subcommand. for example %example1 or %example2"
root:
warning:
unknown-sub: "<red>Invalid subcommand. run <yellow>`%command help` <red>to see available commands"
error:
generic: "<red>Error running this command"
debug:
description: "Used to toggle debug logs and retrieve them"
log-cleared: "Log Cleared"
toggled: "Debug toggled to %type"
copy: "<green>Click to copy log data"
copy-lang: "<green>Click to copy detailed lang issues"
data:
header: "Debug Log data:"
line-count: "Found %count lines"
warning:
unspecified-type: "Need to specify which type of debug to toggle: \"default\" or \"verbose\""
invalid-type: "Invalid debug type \"%type\""
no-log: "No log to show ? make sure you tried with debug log toggled (%command)"
diagnostic:
description: "Basic diagnostic of this plugin"
had-error: "<red>There was an error running the diagnostic"
copy: "<green>Click to copy diagnostic data"
config:
description: "Used to edit the configuration of the plugin"
folia-issue:
1: "<red>It look like you are using Folia. Sadly Custom Anvil do not support Config gui for Folia."
2: "<yellow>It is may come in a future version."
3: ""
4: "<yellow>Currently you need to edit manually the config or copy from another server (spigot or better)"
5: "<yellow>Then /ca reload after config file is edited"
enchantment:
no_hand: "No enchantment found in the item you are holding"
no_name: "No enchantment found with the name %name"
warning:
legacy-name: "<red>/ca gui has been moved to /ca config"
cannot_configure: "Cannot configure the item in hand"
enchant:
description: "Allows to set enchantment to holden item"
warning:
missing_parameter: "Missing enchantment parameter"
not_found: "Enchantment not found: %path"
malformed_number: "Invalid number: %num"
cannot_enchant: "Cannot enchant this item"
removed: "%name removed"
set: "%name set to level %level"
help:
description: "Help command"
header: "List of available commands:"
reload:
description: "Reload the configuration of this plugin"
start: "<yellow>Reloading config..."
success: "<green>Config reloaded !"
fail: "<red>Config was not able to be reloaded..."
hard-fail: "<red>Hard fail, plugin disabled"
config-ui:
shared:
no-permission: "<red>You do not have permission to edit the config"
typed-config-title: "<yellow>%type <white>Config"
confirm-action:
fail: "<red>Action could not be completed."
is-user-sure: "<yellow>Are you sure ?"
select-item-type:
place-here: "<yellow>Place an item here"
element-list:
instruction-new:
1: "<yellow>Write the %type name you want to create in the chat."
2: "<yellow>Or write <red>cancel <yellow>to go back to %type config menu"
cancelled-new: "%type creation cancelled..."
duplicated-new: "<red>Please enter a %type name that do not already exist..."
unit-repair:
title: "Unit Repair Config <reset>(%page/%max_page)"
new:
title: "Select unit repair item."
description:
1: "<gray>Click here with an item to set the item"
2: "<gray>You like to be an unit repair item"
element:
title: "<yellow>%type <red>Unit repair <reset>(%page/%max_page)"
new:
title: "Select item to be repaired."
description:
1: "<gray>Click here with an item to set the item"
2: "<gray>You like to be repaired by %name"
cannot-damage: "<red>This item can't be damaged, so it can't be repaired."
same-type: "<red>Item can't repair something of the same type."
custom-recipe:
title: "Custom Recipe Config <reset>(%page/%max_page)"
element:
delete:
title: "<red>Delete <yellow>%type<red>?"
description: "<gray>Confirm that you want to delete this recipe."
enchant-level-cost:
title: "<dark_gray>Enchantment Level Limit <reset>(%page/%max_page)"
enchant-level-limit:
title: "<dark_gray>Enchantment Level Limit <reset>(%page/%max_page)"
enchant-merge-limit:
title: "<dark_gray>Enchantment Maximum Merge Level <reset>(%page/%max_page)"
enchant-conflict:
title: "Conflict Config <reset>(%page/%max_page)"
element:
selected-enchantments: "<yellow>%group<dark_purple>" # likely need page and max page
selected-sub-groups: "<yellow>%group <red>Groups"
delete:
title: "<red>Delete <yellow>%type<red>?"
description: "<gray>Confirm that you want to delete this conflict."
material-group:
title: "Group Config <reset>(%page/%max_page)"
element:
selected-materials: "<yellow>%group <red>Materials"
selected-sub-groups: "<yellow>%group <red>Groups"
delete:
title: "<red>Delete <yellow>%type<red>?"
description: "<gray>Confirm that you want to delete this group."
button:
name: "<dark_red>DELETE GROUP"
lore: "<red>Caution with this button !"
material-select:
new:
confirm:
title: "Remove %name"
description: "<dark_gray>Confirm Remove %name from this list."