Create Conflict config gui. (#4)

This commit is contained in:
alexcrea 2024-03-31 00:06:49 +00:00 committed by GitHub
commit 19255809cb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
44 changed files with 2332 additions and 683 deletions

View file

@ -4,7 +4,7 @@ plugins {
} }
group = "xyz.alexcrea" group = "xyz.alexcrea"
version = "1.3.2-A1" version = "1.3.2-A2"
repositories { repositories {
mavenCentral() mavenCentral()

View file

@ -49,12 +49,15 @@ public abstract class ConfigHolder {
private static final File BACKUP_FOLDER = new File(CustomAnvil.instance.getDataFolder(), "backup"); private static final File BACKUP_FOLDER = new File(CustomAnvil.instance.getDataFolder(), "backup");
protected FileConfiguration configuration; protected FileConfiguration configuration;
protected ConfigHolder() { protected ConfigHolder() {
} }
public abstract boolean reloadFromDisk(boolean hardFail); public abstract boolean reloadFromDisk(boolean hardFail);
public abstract void reload(); public abstract void reload();
public FileConfiguration getConfig() { public FileConfiguration getConfig() {
return configuration; return configuration;
} }
@ -65,12 +68,15 @@ public abstract class ConfigHolder {
protected String getConfigFileExtension() { protected String getConfigFileExtension() {
return ".yml"; return ".yml";
} }
protected File getConfigFile() { protected File getConfigFile() {
return new File(CustomAnvil.instance.getDataFolder(), getConfigFileName() + getConfigFileExtension()); return new File(CustomAnvil.instance.getDataFolder(), getConfigFileName() + getConfigFileExtension());
} }
protected File getFirstBackup() { protected File getFirstBackup() {
return new File(BACKUP_FOLDER, getConfigFileName() + "-first" + getConfigFileExtension()); return new File(BACKUP_FOLDER, getConfigFileName() + "-first" + getConfigFileExtension());
} }
protected File getLastBackup() { protected File getLastBackup() {
return new File(BACKUP_FOLDER, getConfigFileName() + "-latest" + getConfigFileExtension()); return new File(BACKUP_FOLDER, getConfigFileName() + "-latest" + getConfigFileExtension());
} }
@ -150,7 +156,8 @@ public abstract class ConfigHolder {
} }
@Override @Override
public void reload() {}// Nothing to do public void reload() {
}// Nothing to do
} }
@ -158,6 +165,7 @@ public abstract class ConfigHolder {
public abstract static class ResourceConfigHolder extends ConfigHolder { public abstract static class ResourceConfigHolder extends ConfigHolder {
String resourceName; String resourceName;
private ResourceConfigHolder(String resourceName) { private ResourceConfigHolder(String resourceName) {
this.resourceName = resourceName; this.resourceName = resourceName;
} }
@ -184,6 +192,7 @@ public abstract class ConfigHolder {
private final static String FILE_NAME = "item_groups"; private final static String FILE_NAME = "item_groups";
ItemGroupManager itemGroupsManager; ItemGroupManager itemGroupsManager;
private ItemGroupConfigHolder() { private ItemGroupConfigHolder() {
super(FILE_NAME); super(FILE_NAME);
} }
@ -210,6 +219,7 @@ public abstract class ConfigHolder {
private final static String FILE_NAME = "enchant_conflict"; private final static String FILE_NAME = "enchant_conflict";
EnchantConflictManager conflictManager; EnchantConflictManager conflictManager;
private ConflictConfigHolder() { private ConflictConfigHolder() {
super(FILE_NAME); super(FILE_NAME);
} }
@ -235,8 +245,10 @@ public abstract class ConfigHolder {
private UnitRepairHolder() { private UnitRepairHolder() {
super(ITEM_GROUP_FILE_NAME); super(ITEM_GROUP_FILE_NAME);
} }
@Override @Override
public void reload() {} // Do nothing public void reload() {
} // Do nothing
} }

View file

@ -41,11 +41,10 @@ public enum EnchantmentProperties {
SWEEPING(EnchantmentRarity.RARE), SWEEPING(EnchantmentRarity.RARE),
THORNS(EnchantmentRarity.VERY_RARE), THORNS(EnchantmentRarity.VERY_RARE),
UNBREAKING(EnchantmentRarity.UNCOMMON), UNBREAKING(EnchantmentRarity.UNCOMMON),
VANISHING_CURSE(EnchantmentRarity.VERY_RARE) VANISHING_CURSE(EnchantmentRarity.VERY_RARE);
;
private final EnchantmentRarity rarity; private final EnchantmentRarity rarity;
EnchantmentProperties(EnchantmentRarity rarity) { EnchantmentProperties(EnchantmentRarity rarity) {
this.rarity = rarity; this.rarity = rarity;
} }

View file

@ -7,9 +7,7 @@ public enum EnchantmentRarity {
COMMON(1), COMMON(1),
UNCOMMON(2), UNCOMMON(2),
RARE(4), RARE(4),
VERY_RARE(8) VERY_RARE(8);
;
private final int itemValue; private final int itemValue;
private final int bookValue; private final int bookValue;
@ -18,6 +16,7 @@ public enum EnchantmentRarity {
this.itemValue = itemValue; this.itemValue = itemValue;
this.bookValue = bookValue; this.bookValue = bookValue;
} }
EnchantmentRarity(int itemValue) { EnchantmentRarity(int itemValue) {
this(itemValue, Math.max(1, itemValue / 2)); this(itemValue, Math.max(1, itemValue / 2));
} }

View file

@ -1,76 +1,41 @@
package xyz.alexcrea.cuanvil.gui.config; package xyz.alexcrea.cuanvil.gui.config;
import com.github.stefvanschie.inventoryframework.gui.GuiItem; import com.github.stefvanschie.inventoryframework.gui.GuiItem;
import com.github.stefvanschie.inventoryframework.gui.type.util.Gui;
import com.github.stefvanschie.inventoryframework.pane.Orientable; import com.github.stefvanschie.inventoryframework.pane.Orientable;
import com.github.stefvanschie.inventoryframework.pane.OutlinePane; import com.github.stefvanschie.inventoryframework.pane.OutlinePane;
import com.github.stefvanschie.inventoryframework.pane.Pane;
import com.github.stefvanschie.inventoryframework.pane.PatternPane;
import com.github.stefvanschie.inventoryframework.pane.util.Pattern;
import io.delilaheve.CustomAnvil; import io.delilaheve.CustomAnvil;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import xyz.alexcrea.cuanvil.gui.MainConfigGui;
import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui; import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui;
import xyz.alexcrea.cuanvil.gui.config.settings.AbstractSettingGui; import xyz.alexcrea.cuanvil.gui.config.settings.AbstractSettingGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems; import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List; import java.util.List;
/** /**
* Abstract Global Config gui for enchantment setting configuration. * Abstract Global Config gui for enchantment setting configuration.
*
* @param <T> Type of the factory of the type of setting the gui should edit. * @param <T> Type of the factory of the type of setting the gui should edit.
*/ */
public abstract class AbstractEnchantConfigGui<T extends AbstractSettingGui.SettingGuiFactory> extends ValueUpdatableGui { public abstract class AbstractEnchantConfigGui<T extends AbstractSettingGui.SettingGuiFactory> extends ValueUpdatableGui {
private final static Material SECONDARY_BACKGROUND_MATERIAL = Material.BLACK_STAINED_GLASS_PANE;
private final Gui backGui;
/**
* Constructor for a gui displaying available enchantment to edit a enchantment setting.
* @param title Title of the gui.
* @param backGui Gui to go back on click on the "back" button.
*/
protected AbstractEnchantConfigGui(String title, Gui backGui){
super(6, title, CustomAnvil.instance);
this.backGui = backGui;
}
/** /**
* Constructor for a gui displaying available enchantment to edit a enchantment setting. * Constructor for a gui displaying available enchantment to edit a enchantment setting.
*
* @param title Title of the gui. * @param title Title of the gui.
*/ */
protected AbstractEnchantConfigGui(String title) { protected AbstractEnchantConfigGui(String title) {
this(title, MainConfigGui.INSTANCE); super(6, title, CustomAnvil.instance);
} }
PatternPane backgroundItems; private OutlinePane filledEnchant;
OutlinePane filledEnchant;
// Why is called like it is rn
/** /**
* Initialise value updatable gui pattern * Initialise value updatable gui pattern
*/ */
protected void init() { protected void init() {
// Back item panel // Back item panel
Pattern pattern = new Pattern( addPane(GuiSharedConstant.BACK_TO_MAIN_MENU_BIG_LIST_DISPLAY_BACKGROUND_PANE);
"000000000",
"000000000",
"000000000",
"000000000",
"000000000",
"B11111111"
);
this.backgroundItems = new PatternPane(0, 0, 9, 6, Pane.Priority.LOW, pattern);
addPane(this.backgroundItems);
GuiGlobalItems.addBackItem(this.backgroundItems, this.backGui);
GuiGlobalItems.addBackgroundItem(this.backgroundItems);
this.backgroundItems.bindItem('1', GuiGlobalItems.backgroundItem(SECONDARY_BACKGROUND_MATERIAL));
// enchant item panel // enchant item panel
this.filledEnchant = new OutlinePane(0, 0, 9, 5); this.filledEnchant = new OutlinePane(0, 0, 9, 5);
@ -90,10 +55,7 @@ public abstract class AbstractEnchantConfigGui<T extends AbstractSettingGui.Sett
protected void prepareValues() { protected void prepareValues() {
bookItemFactoryList = new ArrayList<>(); bookItemFactoryList = new ArrayList<>();
List<Enchantment> enchantments = Arrays.asList(Enchantment.values()); for (Enchantment enchant : GuiSharedConstant.SORTED_ENCHANTMENT_LIST) {
enchantments.sort(Comparator.comparing(ench -> ench.getKey().getKey()));
for (Enchantment enchant : enchantments) {
T factory = getFactoryFromEnchant(enchant); T factory = getFactoryFromEnchant(enchant);
bookItemFactoryList.add(factory); bookItemFactoryList.add(factory);
@ -102,6 +64,7 @@ public abstract class AbstractEnchantConfigGui<T extends AbstractSettingGui.Sett
@Override @Override
public void updateGuiValues() { public void updateGuiValues() {
// probably not the most efficient but hey ! it do the work // probably not the most efficient but hey ! it do the work
// TODO optimise one day.. maybe // TODO optimise one day.. maybe

View file

@ -0,0 +1,94 @@
package xyz.alexcrea.cuanvil.gui.config;
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 com.github.stefvanschie.inventoryframework.pane.PatternPane;
import com.github.stefvanschie.inventoryframework.pane.util.Pattern;
import io.delilaheve.CustomAnvil;
import org.bukkit.Material;
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 java.util.Arrays;
import java.util.Collections;
import java.util.function.Supplier;
import java.util.logging.Level;
public class ConfirmActionGui extends ChestGui {
private static final ItemStack CANCEL_ITEM;
private static final ItemStack CONFIRM_ITEM;
static {
CANCEL_ITEM = new ItemStack(Material.RED_TERRACOTTA);
ItemMeta meta = CANCEL_ITEM.getItemMeta();
meta.setDisplayName("\u00A7cCancel");
meta.setLore(Collections.singletonList("\u00A77Cancel current action and return to previous menu."));
CANCEL_ITEM.setItemMeta(meta);
CONFIRM_ITEM = new ItemStack(Material.GREEN_TERRACOTTA);
meta = CONFIRM_ITEM.getItemMeta();
meta.setDisplayName("\u00A7aConfirm");
meta.setLore(Arrays.asList("\u00A77Confirm current action.",
"\u00A74Cation: This action can't be canceled."));
CONFIRM_ITEM.setItemMeta(meta);
}
public ConfirmActionGui(@NotNull String title, String actionDescription,
Gui backOnCancel, Gui backOnConfirm, Supplier<Boolean> onConfirm) {
super(3, title, CustomAnvil.instance);
Pattern pattern = new Pattern(
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
"00B0I0S00",
GuiSharedConstant.EMPTY_GUI_FULL_LINE
);
PatternPane pane = new PatternPane(0, 0, pattern.getLength(), pattern.getHeight(), pattern);
addPane(pane);
pane.bindItem('0', GuiGlobalItems.backgroundItem());
pane.bindItem('B', new GuiItem(CANCEL_ITEM, GuiGlobalActions.openGuiAction(backOnCancel), CustomAnvil.instance));
pane.bindItem('S', new GuiItem(CONFIRM_ITEM, event -> {
event.setCancelled(true);
HumanEntity player = event.getWhoClicked();
if (!player.hasPermission(CustomAnvil.editConfigPermission)) {
player.closeInventory();
player.sendMessage(GuiGlobalActions.NO_EDIT_PERM);
return;
}
boolean success;
try {
success = onConfirm.get();
} catch (Exception e) {
CustomAnvil.instance.getLogger().log(Level.WARNING, "Could not process confirmation supplier.", e);
success = false;
}
if (!success) {
event.getWhoClicked().sendMessage("\u00A7cAction could not be completed. ");
}
backOnConfirm.show(player);
}, CustomAnvil.instance));
ItemStack infoItem = new ItemStack(Material.PAPER);
ItemMeta infoMeta = infoItem.getItemMeta();
infoMeta.setDisplayName("\u00A7eAre you sure ?");
infoMeta.setLore(Arrays.asList(actionDescription.split("\n")));
infoItem.setItemMeta(infoMeta);
pane.bindItem('I', new GuiItem(infoItem, GuiGlobalActions.stayInPlace, CustomAnvil.instance));
}
}

View file

@ -0,0 +1,15 @@
package xyz.alexcrea.cuanvil.gui.config;
import org.bukkit.enchantments.Enchantment;
import java.util.Set;
public interface SelectEnchantmentContainer {
Set<Enchantment> getSelectedEnchantments();
boolean setSelectedEnchantments(Set<Enchantment> enchantments);
Set<Enchantment> illegalEnchantments();
}

View file

@ -0,0 +1,15 @@
package xyz.alexcrea.cuanvil.gui.config;
import xyz.alexcrea.cuanvil.group.AbstractMaterialGroup;
import java.util.Set;
public interface SelectGroupContainer {
Set<AbstractMaterialGroup> getSelectedGroups();
boolean setSelectedGroups(Set<AbstractMaterialGroup> groups);
Set<AbstractMaterialGroup> illegalGroups();
}

View file

@ -0,0 +1,15 @@
package xyz.alexcrea.cuanvil.gui.config;
import org.bukkit.Material;
import java.util.EnumSet;
public interface SelectMaterialContainer {
EnumSet<Material> getSelectedMaterials();
boolean setSelectedMaterials(EnumSet<Material> materials);
EnumSet<Material> illegalMaterials();
}

View file

@ -1,4 +1,4 @@
package xyz.alexcrea.cuanvil.gui.config; package xyz.alexcrea.cuanvil.gui.config.global;
import com.github.stefvanschie.inventoryframework.gui.GuiItem; import com.github.stefvanschie.inventoryframework.gui.GuiItem;
import com.github.stefvanschie.inventoryframework.pane.PatternPane; import com.github.stefvanschie.inventoryframework.pane.PatternPane;
@ -10,12 +10,12 @@ import org.bukkit.Material;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import xyz.alexcrea.cuanvil.config.ConfigHolder; import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.gui.MainConfigGui;
import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui; import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui;
import xyz.alexcrea.cuanvil.gui.config.settings.BoolSettingsGui; import xyz.alexcrea.cuanvil.gui.config.settings.BoolSettingsGui;
import xyz.alexcrea.cuanvil.gui.config.settings.IntSettingsGui; import xyz.alexcrea.cuanvil.gui.config.settings.IntSettingsGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import java.util.Collections; import java.util.Collections;
@ -44,7 +44,7 @@ public class BasicConfigGui extends ValueUpdatableGui {
*/ */
private void init() { private void init() {
Pattern pattern = new Pattern( Pattern pattern = new Pattern(
"000000000", GuiSharedConstant.EMPTY_GUI_FULL_LINE,
"012345670", "012345670",
"B00000000" "B00000000"
); );

View file

@ -0,0 +1,407 @@
package xyz.alexcrea.cuanvil.gui.config.global;
import com.github.stefvanschie.inventoryframework.gui.GuiItem;
import com.github.stefvanschie.inventoryframework.gui.type.ChestGui;
import com.github.stefvanschie.inventoryframework.pane.Orientable;
import com.github.stefvanschie.inventoryframework.pane.OutlinePane;
import com.github.stefvanschie.inventoryframework.pane.Pane;
import com.github.stefvanschie.inventoryframework.pane.PatternPane;
import com.github.stefvanschie.inventoryframework.pane.util.Pattern;
import io.delilaheve.CustomAnvil;
import org.bukkit.Material;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.HumanEntity;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.group.EnchantConflictGroup;
import xyz.alexcrea.cuanvil.group.IncludeGroup;
import xyz.alexcrea.cuanvil.gui.config.settings.subsetting.EnchantConflictSubSettingGui;
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.util.CasedStringUtil;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
public class EnchantConflictGui extends ChestGui {
public final static EnchantConflictGui INSTANCE = new EnchantConflictGui();
static {
INSTANCE.init();
}
private final HashMap<EnchantConflictGroup, EnchantConflictSubSettingGui> conflictGuiMap;
private EnchantConflictGui() {
super(6, "Conflict Config", CustomAnvil.instance);
this.conflictGuiMap = new HashMap<>();
}
private OutlinePane firstPage;
private ArrayList<OutlinePane> pages;
private HashMap<UUID, Integer> pageMap;
private PatternPane backgroundPane;
private void init() {
// Back item panel
Pattern pattern = new Pattern(
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
"B11L1R11C"
);
this.backgroundPane = new PatternPane(0, 0, 9, 6, Pane.Priority.LOW, pattern);
GuiGlobalItems.addBackItem(this.backgroundPane, MainConfigGui.INSTANCE);
GuiGlobalItems.addBackgroundItem(this.backgroundPane);
this.backgroundPane.bindItem('1', GuiSharedConstant.SECONDARY_BACKGROUND_ITEM);
addPane(this.backgroundPane);
// Page init
this.pages = new ArrayList<>();
this.pageMap = new HashMap<>();
// enchant item panel
this.firstPage = createEmptyPage();
this.pages.add(this.firstPage);
prepareOtherValues();
reloadValues();
}
private GuiItem goLeftItem;
private GuiItem goRightItem;
private void prepareOtherValues() {
// Left item creation for consumer & bind
this.goLeftItem = new GuiItem(new ItemStack(Material.RED_TERRACOTTA), event -> {
HumanEntity viewer = event.getWhoClicked();
UUID playerUUID = viewer.getUniqueId();
int page = this.pageMap.getOrDefault(playerUUID, 0);
this.pageMap.put(playerUUID, page - 1);
ItemStack cursor = viewer.getItemOnCursor();
viewer.setItemOnCursor(new ItemStack(Material.AIR));
show(viewer);
viewer.setItemOnCursor(cursor);
}, CustomAnvil.instance);
// Right item creation for consumer & bind
this.goRightItem = new GuiItem(new ItemStack(Material.GREEN_TERRACOTTA), event -> {
HumanEntity viewer = event.getWhoClicked();
UUID playerUUID = viewer.getUniqueId();
int page = pageMap.getOrDefault(playerUUID, 0);
this.pageMap.put(playerUUID, page + 1);
ItemStack cursor = viewer.getItemOnCursor();
viewer.setItemOnCursor(new ItemStack(Material.AIR));
show(viewer);
viewer.setItemOnCursor(cursor);
}, CustomAnvil.instance);
// Create new conflict item
ItemStack createItem = new ItemStack(Material.PAPER);
ItemMeta createMeta = createItem.getItemMeta();
createMeta.setDisplayName("\u00A7aCreate new conflict");
createMeta.setLore(Arrays.asList(
"\u00A77Create a new anvil restriction.",
"\u00A77You will be asked to name the conflict in chat.",
"\u00A77Then, you should edit the conflict config as you need"
));
createItem.setItemMeta(createMeta);
this.backgroundPane.bindItem('C', new GuiItem(createItem, (clickEvent) -> {
clickEvent.setCancelled(true);
HumanEntity player = clickEvent.getWhoClicked();
// check permission
if (!player.hasPermission(CustomAnvil.editConfigPermission)) {
player.closeInventory();
player.sendMessage(GuiGlobalActions.NO_EDIT_PERM);
return;
}
player.closeInventory();
player.sendMessage("\u00A7eWrite the conflict you want to create in the chat.\n" +
"\u00A7eOr write \u00A7ccancel \u00A7eto go back to conflict config menu");
CustomAnvil.Companion.getChatListener().setListenedCallback(player, prepareCreateItemConsumer(player));
}, CustomAnvil.instance));
}
private Consumer<String> prepareCreateItemConsumer(HumanEntity player) {
AtomicReference<Consumer<String>> selfRef = new AtomicReference<>();
Consumer<String> selfCallback = (message) -> {
if (message == null) return;
message = message.toLowerCase(Locale.ROOT);
if ("cancel".equalsIgnoreCase(message)) {
player.sendMessage("conflict creation cancelled...");
show(player);
return;
}
message = message.replace(' ', '_');
// Try to find if it already exists in a for loop
// Not the most efficient on large number of conflict, but it should not run often.
for (EnchantConflictGroup conflict : ConfigHolder.CONFLICT_HOLDER.getConflictManager().getConflictList()) {
if (conflict.getName().equalsIgnoreCase(message)) {
player.sendMessage("\u00A7cPlease enter a conflict name that do not already exist...");
// wait next message.
CustomAnvil.Companion.getChatListener().setListenedCallback(player, selfRef.get());
return;
}
}
// Create new empty conflict and display it to the admin
EnchantConflictGroup conflict = new EnchantConflictGroup(
message,
new IncludeGroup("new_group"),
0);
ConfigHolder.CONFLICT_HOLDER.getConflictManager().getConflictList().add(conflict);
updateValueForConflict(conflict, true);
// save empty conflict in config
String[] emptyStringArray = new String[0];
FileConfiguration config = ConfigHolder.CONFLICT_HOLDER.getConfig();
config.set(message + ".enchantments", emptyStringArray);
config.set(message + ".notAffectedGroups", emptyStringArray);
config.set(message + ".maxEnchantmentBeforeConflict", 0);
if (GuiSharedConstant.TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE) {
ConfigHolder.CONFLICT_HOLDER.saveToDisk(GuiSharedConstant.TEMPORARY_DO_BACKUP_EVERY_SAVE);
}
// show the new conflict config to the player
this.conflictGuiMap.get(conflict).show(player);
};
selfRef.set(selfCallback);
return selfCallback;
}
private OutlinePane createEmptyPage() {
OutlinePane page = new OutlinePane(0, 0, 9, 5);
page.align(OutlinePane.Alignment.BEGIN);
page.setOrientation(Orientable.Orientation.HORIZONTAL);
return page;
}
public void reloadValues() {
this.conflictGuiMap.forEach((conflict, gui) -> gui.cleanUnused());
this.conflictGuiMap.clear();
this.firstPage.clear();
this.pages.clear();
this.pages.add(this.firstPage);
for (EnchantConflictGroup conflict : ConfigHolder.CONFLICT_HOLDER.getConflictManager().getConflictList()) {
updateValueForConflict(conflict, false);
}
update();
}
public static ItemStack createItemForConflict(EnchantConflictGroup conflict) {
ItemStack item = new ItemStack(conflict.getRepresentativeMaterial());
ItemMeta meta = item.getItemMeta();
meta.setDisplayName("\u00A7e" + CasedStringUtil.snakeToUpperSpacedCase(conflict.getName()) + " \u00A7fConflict");
meta.setLore(Arrays.asList(
"\u00A77Enchantment count: \u00A7e" + conflict.getEnchants().size(),
"\u00A77Group count: \u00A7e" + conflict.getCantConflictGroup().getGroups().size(),
"\u00A77Min enchantments count: \u00A7e" + conflict.getMinBeforeBlock()
));
item.setItemMeta(meta);
return item;
}
public void updateValueForConflict(EnchantConflictGroup conflict, boolean shouldUpdate) {
EnchantConflictSubSettingGui gui = this.conflictGuiMap.get(conflict);
ItemStack item = createItemForConflict(conflict);
GuiItem guiItem;
if (gui == null) {
// Create new sub setting gui
guiItem = new GuiItem(item, CustomAnvil.instance);
gui = new EnchantConflictSubSettingGui(this, conflict, guiItem);
guiItem.setAction(GuiGlobalActions.openGuiAction(gui));
this.conflictGuiMap.put(conflict, gui);
addToPage(guiItem);
} else {
// Replace item with the updated one
guiItem = gui.getParentItemForThisGui();
guiItem.setItem(item);
}
gui.updateLocal();
if (shouldUpdate) {
update();
}
}
public void removeConflict(EnchantConflictGroup conflict) {
EnchantConflictSubSettingGui gui = this.conflictGuiMap.get(conflict);
if (gui == null) return;
this.conflictGuiMap.remove(conflict);
removeFromPage(gui.getParentItemForThisGui());
update();
}
private void addToPage(GuiItem guiItem) {
// Get first available page or create one
OutlinePane page = this.pages.get(this.pages.size() - 1);
if (page.getItems().size() >= 5 * 9) {
page = createEmptyPage();
this.pages.add(page);
}
page.addItem(guiItem);
}
private void removeFromPage(GuiItem guiItem) {
// get item page
OutlinePane page = null;
int pageID = 0;
while (pageID < this.pages.size()) {
OutlinePane tempPage = this.pages.get(pageID);
if (tempPage.getItems().contains(guiItem)) {
page = tempPage;
break;
}
pageID++;
}
if (page == null) {// Why...
return;
}
removeFromPage(page, pageID, guiItem);
}
private void removeFromPage(OutlinePane page, int pageID, GuiItem guiItem) {
page.removeItem(guiItem);
// There is now a slot available, let fill it if possible
if (pageID < (this.pages.size() - 1)) {
OutlinePane newPage = this.pages.get(pageID + 1);
GuiItem nextPageItem = newPage.getItems().get(0);
removeFromPage(newPage, pageID + 1, nextPageItem);
OutlinePane thisPage = this.pages.get(pageID);
thisPage.addItem(nextPageItem);
} else if (pageID > 0 && page.getItems().isEmpty()) {
this.pages.remove(pageID);
}
}
public int getPlayerPageID(UUID uuid) {
int pageId = this.pageMap.getOrDefault(uuid, 0);
if (pageId >= this.pages.size()) {
pageId = this.pages.size() - 1;
}
return pageId;
}
public void placeArrow(int page, boolean customise) {
// Place left arrow
addPane(this.backgroundPane);
if (page > 0) {
if (customise) {
ItemStack leftItem = this.goLeftItem.getItem();
ItemMeta leftMeta = leftItem.getItemMeta();
leftMeta.setDisplayName("\u00A7eReturn to page " + (page));
leftItem.setItemMeta(leftMeta);
this.goLeftItem.setItem(leftItem);
}
this.backgroundPane.bindItem('L', this.goLeftItem);
} else {
this.backgroundPane.bindItem('L', GuiSharedConstant.SECONDARY_BACKGROUND_ITEM);
}
// Place right arrow
if (page < pages.size() - 1) {
if (customise) {
ItemStack rightItem = this.goRightItem.getItem();
ItemMeta rightMeta = rightItem.getItemMeta();
rightMeta.setDisplayName("\u00A7eGo to page " + (page + 2));
rightItem.setItemMeta(rightMeta);
this.goRightItem.setItem(rightItem);
}
this.backgroundPane.bindItem('R', this.goRightItem);
} else {
this.backgroundPane.bindItem('R', GuiSharedConstant.SECONDARY_BACKGROUND_ITEM);
}
}
@Override // assume will not be called in multiple thread
public void show(@NotNull HumanEntity humanEntity) {
int pageID = getPlayerPageID(humanEntity.getUniqueId());
OutlinePane page = this.pages.get(pageID);
getPanes().clear();
// display the page arrow pane
placeArrow(pageID, true);
// and add actual page
addPane(page);
// set title
setTitle("Conflict Config (" + (pageID + 1) + "/" + (pages.size()) + ")");
super.show(humanEntity);
}
@Override // assume will not be called in multiple thread
public void click(@NotNull InventoryClickEvent event) {
int pageID = getPlayerPageID(event.getWhoClicked().getUniqueId());
OutlinePane page = this.pages.get(pageID);
getPanes().clear();
// set the page arrow pane
placeArrow(pageID, false);
// and add actual page
addPane(page);
super.click(event);
}
}

View file

@ -1,4 +1,4 @@
package xyz.alexcrea.cuanvil.gui.config; package xyz.alexcrea.cuanvil.gui.config.global;
import com.github.stefvanschie.inventoryframework.gui.GuiItem; import com.github.stefvanschie.inventoryframework.gui.GuiItem;
import org.bukkit.Material; import org.bukkit.Material;
@ -8,6 +8,7 @@ import org.bukkit.inventory.meta.ItemMeta;
import xyz.alexcrea.cuanvil.config.ConfigHolder; import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.enchant.EnchantmentProperties; import xyz.alexcrea.cuanvil.enchant.EnchantmentProperties;
import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity; import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity;
import xyz.alexcrea.cuanvil.gui.config.AbstractEnchantConfigGui;
import xyz.alexcrea.cuanvil.gui.config.settings.EnchantCostSettingsGui; import xyz.alexcrea.cuanvil.gui.config.settings.EnchantCostSettingsGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
import xyz.alexcrea.cuanvil.util.CasedStringUtil; import xyz.alexcrea.cuanvil.util.CasedStringUtil;
@ -45,7 +46,8 @@ public class EnchantCostConfigGui extends AbstractEnchantConfigGui<EnchantCostSe
EnchantmentRarity rarity = EnchantmentRarity.NO_RARITY; EnchantmentRarity rarity = EnchantmentRarity.NO_RARITY;
try { try {
rarity = EnchantmentProperties.valueOf(key.toUpperCase(Locale.ENGLISH)).getRarity(); rarity = EnchantmentProperties.valueOf(key.toUpperCase(Locale.ENGLISH)).getRarity();
}catch (IllegalArgumentException ignored){} } catch (IllegalArgumentException ignored) {
}
return EnchantCostSettingsGui.enchantCostFactory(prettyKey + " Level Cost", this, return EnchantCostSettingsGui.enchantCostFactory(prettyKey + " Level Cost", this,
SECTION_NAME + '.' + key, ConfigHolder.DEFAULT_CONFIG, 0, 255, SECTION_NAME + '.' + key, ConfigHolder.DEFAULT_CONFIG, 0, 255,
@ -58,13 +60,13 @@ public class EnchantCostConfigGui extends AbstractEnchantConfigGui<EnchantCostSe
// Get item properties // Get item properties
int itemCost = factory.getConfiguredValue(); int itemCost = factory.getConfiguredValue();
int bookCost = factory.getConfiguredBookValue(); int bookCost = factory.getConfiguredBookValue();
StringBuilder itemName = new StringBuilder("\u00A7a").append(factory.getTitle()); String itemName = "\u00A7a" + factory.getTitle();
// Create item // Create item
ItemStack item = new ItemStack(Material.ENCHANTED_BOOK); ItemStack item = new ItemStack(Material.ENCHANTED_BOOK);
ItemMeta itemMeta = item.getItemMeta(); ItemMeta itemMeta = item.getItemMeta();
// Edit name and lore // Edit name and lore
itemMeta.setDisplayName(itemName.toString()); itemMeta.setDisplayName(itemName);
itemMeta.setLore(Arrays.asList( itemMeta.setLore(Arrays.asList(
"\u00A77Item Cost: " + itemCost, "\u00A77Item Cost: " + itemCost,
"\u00A77Book Cost: " + bookCost)); "\u00A77Book Cost: " + bookCost));

View file

@ -1,9 +1,10 @@
package xyz.alexcrea.cuanvil.gui.config; package xyz.alexcrea.cuanvil.gui.config.global;
import com.github.stefvanschie.inventoryframework.gui.GuiItem; import com.github.stefvanschie.inventoryframework.gui.GuiItem;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import xyz.alexcrea.cuanvil.config.ConfigHolder; import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.gui.config.AbstractEnchantConfigGui;
import xyz.alexcrea.cuanvil.gui.config.settings.IntSettingsGui; import xyz.alexcrea.cuanvil.gui.config.settings.IntSettingsGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
import xyz.alexcrea.cuanvil.util.CasedStringUtil; import xyz.alexcrea.cuanvil.util.CasedStringUtil;

View file

@ -1,4 +1,4 @@
package xyz.alexcrea.cuanvil.gui; package xyz.alexcrea.cuanvil.gui.config.global;
import com.github.stefvanschie.inventoryframework.gui.GuiItem; import com.github.stefvanschie.inventoryframework.gui.GuiItem;
import com.github.stefvanschie.inventoryframework.gui.type.ChestGui; import com.github.stefvanschie.inventoryframework.gui.type.ChestGui;
@ -8,9 +8,6 @@ import io.delilaheve.CustomAnvil;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import xyz.alexcrea.cuanvil.gui.config.BasicConfigGui;
import xyz.alexcrea.cuanvil.gui.config.EnchantCostConfigGui;
import xyz.alexcrea.cuanvil.gui.config.EnchantLimitConfigGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
@ -23,6 +20,7 @@ public class MainConfigGui extends ChestGui {
static { static {
INSTANCE.init(); INSTANCE.init();
} }
private MainConfigGui() { private MainConfigGui() {
super(3, "\u00A78Anvil Config", CustomAnvil.instance); super(3, "\u00A78Anvil Config", CustomAnvil.instance);
@ -72,17 +70,26 @@ public class MainConfigGui extends ChestGui {
GuiItem enchantCostItem = GuiGlobalItems.goToGuiItem(enchantCostItemstack, EnchantCostConfigGui.INSTANCE); GuiItem enchantCostItem = GuiGlobalItems.goToGuiItem(enchantCostItemstack, EnchantCostConfigGui.INSTANCE);
pane.bindItem('3', enchantCostItem); pane.bindItem('3', enchantCostItem);
// Enchantment Conflicts
ItemStack EnchantConflictItemstack = new ItemStack(Material.OAK_FENCE);
ItemMeta enchantConflictMeta = EnchantConflictItemstack.getItemMeta();
enchantConflictMeta.setDisplayName("\u00A7aEnchantment Conflict");
enchantConflictMeta.setLore(Collections.singletonList("\u00A77Click here to open enchantment conflict menu"));
EnchantConflictItemstack.setItemMeta(enchantConflictMeta);
GuiItem enchantConflictItem = GuiGlobalItems.goToGuiItem(EnchantConflictItemstack, EnchantConflictGui.INSTANCE);
pane.bindItem('4', enchantConflictItem);
// WIP configuration items // WIP configuration items
ItemStack wipItemstack = new ItemStack(Material.BARRIER); ItemStack wipItemstack = new ItemStack(Material.BARRIER);
ItemMeta wipMeta = wipItemstack.getItemMeta(); ItemMeta wipMeta = wipItemstack.getItemMeta();
wipMeta.setDisplayName("\u00A7cWIP"); wipMeta.setDisplayName("\u00A7cWIP");
wipItemstack.setItemMeta(wipMeta); wipItemstack.setItemMeta(wipMeta);
GuiItem wip4 = new GuiItem(wipItemstack, GuiGlobalActions.stayInPlace, CustomAnvil.instance);
GuiItem wip5 = new GuiItem(wipItemstack, GuiGlobalActions.stayInPlace, CustomAnvil.instance); GuiItem wip5 = new GuiItem(wipItemstack, GuiGlobalActions.stayInPlace, CustomAnvil.instance);
GuiItem wip6 = new GuiItem(wipItemstack, GuiGlobalActions.stayInPlace, CustomAnvil.instance); GuiItem wip6 = new GuiItem(wipItemstack, GuiGlobalActions.stayInPlace, CustomAnvil.instance);
pane.bindItem('4', wip4);
pane.bindItem('5', wip5); pane.bindItem('5', wip5);
pane.bindItem('6', wip6); pane.bindItem('6', wip6);

View file

@ -20,16 +20,13 @@ import java.util.List;
*/ */
public abstract class AbstractSettingGui extends ChestGui { public abstract class AbstractSettingGui extends ChestGui {
// Temporary values, until I get something better.
public static final boolean TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE = true;
public static final boolean TEMPORARY_DO_BACKUP_EVERY_SAVE = true;
protected final static List<String> CLICK_LORE = Collections.singletonList("\u00A77Click Here to change the value"); protected final static List<String> CLICK_LORE = Collections.singletonList("\u00A77Click Here to change the value");
private PatternPane pane; private PatternPane pane;
/** /**
* Prepare necessary object for a setting gui. * Prepare necessary object for a setting gui.
*
* @param rows Number of row for this gui. * @param rows Number of row for this gui.
* @param title Title of this gui. * @param title Title of this gui.
* @param parent Parent gui to go back when completed. * @param parent Parent gui to go back when completed.
@ -41,6 +38,7 @@ public abstract class AbstractSettingGui extends ChestGui {
/** /**
* Prepare necessary object for a setting gui. * Prepare necessary object for a setting gui.
*
* @param rows Number of row for this gui. * @param rows Number of row for this gui.
* @param title Title of this gui. * @param title Title of this gui.
* @param parent Parent gui to go back when completed. * @param parent Parent gui to go back when completed.
@ -54,6 +52,7 @@ public abstract class AbstractSettingGui extends ChestGui {
/** /**
* Initialise and prepare value for this gui. * Initialise and prepare value for this gui.
*
* @param parent Parent gui to go back when completed. * @param parent Parent gui to go back when completed.
*/ */
private void initBase(ValueUpdatableGui parent) { private void initBase(ValueUpdatableGui parent) {
@ -79,6 +78,7 @@ public abstract class AbstractSettingGui extends ChestGui {
/** /**
* Get main pane for this setting gui. * Get main pane for this setting gui.
*
* @return Main pattern pain of this gui. * @return Main pattern pain of this gui.
*/ */
protected PatternPane getPane() { protected PatternPane getPane() {
@ -93,12 +93,14 @@ public abstract class AbstractSettingGui extends ChestGui {
* <li><b>B</b>: "back to previous gui" button.</li> * <li><b>B</b>: "back to previous gui" button.</li>
* <li><b>0</b>: default background item.</li> * <li><b>0</b>: default background item.</li>
* </ul> * </ul>
*
* @return The gui's pattern. * @return The gui's pattern.
*/ */
protected abstract Pattern getGuiPattern(); protected abstract Pattern getGuiPattern();
/** /**
* Called when the associated setting need to be saved. * Called when the associated setting need to be saved.
*
* @return true if the save was successful. false otherwise * @return true if the save was successful. false otherwise
*/ */
public abstract boolean onSave(); public abstract boolean onSave();
@ -106,6 +108,7 @@ public abstract class AbstractSettingGui extends ChestGui {
/** /**
* If this function return true * If this function return true
* the gui assume the associated setting can be saved. * the gui assume the associated setting can be saved.
*
* @return true if there is a change to the setting. false otherwise * @return true if there is a change to the setting. false otherwise
*/ */
public abstract boolean hadChange(); public abstract boolean hadChange();
@ -121,6 +124,7 @@ public abstract class AbstractSettingGui extends ChestGui {
/** /**
* Constructor for settings gui factory * Constructor for settings gui factory
*
* @param configPath Configuration path of this setting. * @param configPath Configuration path of this setting.
* @param config Configuration holder of this setting. * @param config Configuration holder of this setting.
*/ */
@ -145,6 +149,7 @@ public abstract class AbstractSettingGui extends ChestGui {
/** /**
* Create a gui using setting parameters and current setting value. * Create a gui using setting parameters and current setting value.
*
* @return A new instance of the implemented setting gui. * @return A new instance of the implemented setting gui.
*/ */
public abstract AbstractSettingGui create(); public abstract AbstractSettingGui create();

View file

@ -12,6 +12,7 @@ import org.jetbrains.annotations.NotNull;
import xyz.alexcrea.cuanvil.config.ConfigHolder; import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui; import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import xyz.alexcrea.cuanvil.util.MetricsUtil; import xyz.alexcrea.cuanvil.util.MetricsUtil;
import java.util.Collections; import java.util.Collections;
@ -28,6 +29,7 @@ public class BoolSettingsGui extends AbstractSettingGui{
/** /**
* Create a boolean setting config gui. * Create a boolean setting config gui.
*
* @param holder Configuration factory of this setting. * @param holder Configuration factory of this setting.
* @param now The defined value of this setting. * @param now The defined value of this setting.
*/ */
@ -45,7 +47,7 @@ public class BoolSettingsGui extends AbstractSettingGui{
@Override @Override
public Pattern getGuiPattern() { public Pattern getGuiPattern() {
return new Pattern( return new Pattern(
"000000000", GuiSharedConstant.EMPTY_GUI_FULL_LINE,
"D0-0v0+00", "D0-0v0+00",
"B0000000S" "B0000000S"
); );
@ -125,8 +127,8 @@ public class BoolSettingsGui extends AbstractSettingGui{
holder.config.getConfig().set(holder.configPath, now); holder.config.getConfig().set(holder.configPath, now);
MetricsUtil.INSTANCE.notifyChange(this.holder.config, this.holder.configPath); MetricsUtil.INSTANCE.notifyChange(this.holder.config, this.holder.configPath);
if(TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE){ if (GuiSharedConstant.TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE) {
return holder.config.saveToDisk(TEMPORARY_DO_BACKUP_EVERY_SAVE); return holder.config.saveToDisk(GuiSharedConstant.TEMPORARY_DO_BACKUP_EVERY_SAVE);
} }
return true; return true;
} }
@ -138,6 +140,7 @@ public class BoolSettingsGui extends AbstractSettingGui{
/** /**
* Create a bool setting factory from setting's parameters. * Create a bool setting factory from setting's parameters.
*
* @param title The title of the gui. * @param title The title of the gui.
* @param parent Parent gui to go back when completed. * @param parent Parent gui to go back when completed.
* @param configPath Configuration path of this setting. * @param configPath Configuration path of this setting.
@ -158,11 +161,14 @@ public class BoolSettingsGui extends AbstractSettingGui{
* A factory for a boolean setting gui that hold setting's information. * A factory for a boolean setting gui that hold setting's information.
*/ */
public static class BoolSettingFactory extends SettingGuiFactory { public static class BoolSettingFactory extends SettingGuiFactory {
@NotNull String title; ValueUpdatableGui parent; @NotNull
String title;
ValueUpdatableGui parent;
boolean defaultVal; boolean defaultVal;
/** /**
* Constructor for a boolean setting gui factory. * Constructor for a boolean setting gui factory.
*
* @param title The title of the gui. * @param title The title of the gui.
* @param parent Parent gui to go back when completed. * @param parent Parent gui to go back when completed.
* @param configPath Configuration path of this setting. * @param configPath Configuration path of this setting.

View file

@ -14,6 +14,7 @@ import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui; import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import xyz.alexcrea.cuanvil.util.MetricsUtil; import xyz.alexcrea.cuanvil.util.MetricsUtil;
import java.util.Arrays; import java.util.Arrays;
@ -33,6 +34,7 @@ public class EnchantCostSettingsGui extends IntSettingsGui {
/** /**
* Create an enchantment cost setting config gui. * Create an enchantment cost setting config gui.
*
* @param holder Configuration factory of this setting. * @param holder Configuration factory of this setting.
* @param nowItem The defined value of this setting item's value. * @param nowItem The defined value of this setting item's value.
*/ */
@ -80,7 +82,8 @@ public class EnchantCostSettingsGui extends IntSettingsGui {
bookMeta.setDisplayName("\u00A7aCost of an Enchantment by Book"); bookMeta.setDisplayName("\u00A7aCost of an Enchantment by Book");
bookMeta.setLore(Arrays.asList( bookMeta.setLore(Arrays.asList(
"\u00A77Cost per result item level of an sacrifice enchantment", "\u00A77Cost per result item level of an sacrifice enchantment",
"\u00A77Only apply if sacrificed item \u00A7cis \u00A77a book"));bookItemstack.setItemMeta(bookMeta); "\u00A77Only apply if sacrificed item \u00A7cis \u00A77a book"));
bookItemstack.setItemMeta(bookMeta);
// sword display // sword display
ItemStack swordItemstack = new ItemStack(Material.WOODEN_SWORD); ItemStack swordItemstack = new ItemStack(Material.WOODEN_SWORD);
@ -207,8 +210,8 @@ public class EnchantCostSettingsGui extends IntSettingsGui {
holder.config.getConfig().set(holder.configPath + BOOK_PATH, nowBook); holder.config.getConfig().set(holder.configPath + BOOK_PATH, nowBook);
MetricsUtil.INSTANCE.notifyChange(this.holder.config, this.holder.configPath); MetricsUtil.INSTANCE.notifyChange(this.holder.config, this.holder.configPath);
if(TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE){ if (GuiSharedConstant.TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE) {
return holder.config.saveToDisk(TEMPORARY_DO_BACKUP_EVERY_SAVE); return holder.config.saveToDisk(GuiSharedConstant.TEMPORARY_DO_BACKUP_EVERY_SAVE);
} }
return true; return true;
} }
@ -220,6 +223,7 @@ public class EnchantCostSettingsGui extends IntSettingsGui {
/** /**
* Create an int setting factory from setting's parameters. * Create an int setting factory from setting's parameters.
*
* @param title The title of the gui. * @param title The title of the gui.
* @param parent Parent gui to go back when completed. * @param parent Parent gui to go back when completed.
* @param configPath Configuration path of this setting. * @param configPath Configuration path of this setting.
@ -254,6 +258,7 @@ public class EnchantCostSettingsGui extends IntSettingsGui {
/** /**
* Constructor for an enchantment cost setting gui factory. * Constructor for an enchantment cost setting gui factory.
*
* @param title The title of the gui. * @param title The title of the gui.
* @param parent Parent gui to go back when completed. * @param parent Parent gui to go back when completed.
* @param configPath Configuration path of this setting. * @param configPath Configuration path of this setting.

View file

@ -0,0 +1,159 @@
package xyz.alexcrea.cuanvil.gui.config.settings;
import com.github.stefvanschie.inventoryframework.gui.GuiItem;
import com.github.stefvanschie.inventoryframework.pane.Orientable;
import com.github.stefvanschie.inventoryframework.pane.OutlinePane;
import com.github.stefvanschie.inventoryframework.pane.Pane;
import com.github.stefvanschie.inventoryframework.pane.util.Pattern;
import io.delilaheve.CustomAnvil;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui;
import xyz.alexcrea.cuanvil.gui.config.SelectEnchantmentContainer;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
public class EnchantSelectSettingGui extends AbstractSettingGui {
SelectEnchantmentContainer enchantContainer;
int page;
Set<Enchantment> selectedEnchant;
public EnchantSelectSettingGui(@NotNull String title, ValueUpdatableGui parent, SelectEnchantmentContainer enchantContainer, int page) {
super(6, title, parent);
this.enchantContainer = enchantContainer;
// Not used and not planned rn
this.page = page;
this.selectedEnchant = new HashSet<>(enchantContainer.getSelectedEnchantments());
// Add secondary background item
this.getPane().bindItem('1', GuiSharedConstant.SECONDARY_BACKGROUND_ITEM);
initGroups();
}
@Override
protected Pattern getGuiPattern() {
return new Pattern(
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
"B1111111S"
);
}
protected void initGroups() {
// Add enchantment gui item
OutlinePane filledEnchant = new OutlinePane(0, 0, 9, 5);
filledEnchant.setPriority(Pane.Priority.HIGH);
filledEnchant.align(OutlinePane.Alignment.BEGIN);
filledEnchant.setOrientation(Orientable.Orientation.HORIZONTAL);
Set<Enchantment> illegalEnchant = this.enchantContainer.illegalEnchantments();
for (Enchantment enchant : GuiSharedConstant.SORTED_ENCHANTMENT_LIST) {
if (illegalEnchant.contains(enchant)) {
return;
}
filledEnchant.addItem(getGuiItemFromEnchant(enchant));
}
addPane(filledEnchant);
}
private GuiItem getGuiItemFromEnchant(Enchantment enchantment) {
boolean isIn = this.selectedEnchant.contains(enchantment);
Material usedMaterial;
if (isIn) {
usedMaterial = Material.ENCHANTED_BOOK;
} else {
usedMaterial = Material.BOOK;
}
ItemStack item = new ItemStack(usedMaterial);
setEnchantItemMeta(item, enchantment.getKey().getKey(), isIn);
GuiItem guiItem = new GuiItem(item, CustomAnvil.instance);
guiItem.setAction(getEnchantItemConsumer(enchantment, guiItem));
return guiItem;
}
private static final List<String> TRUE_LORE = Collections.singletonList("\u00A77Value: \u00A7aSelected");
private static final List<String> FALSE_LORE = Collections.singletonList("\u00A77Value: \u00A7cNot Selected");
public void setEnchantItemMeta(ItemStack item, String name, boolean isIn) {
ItemMeta meta = item.getItemMeta();
if (meta == null) {
CustomAnvil.instance.getLogger().warning("Could not create item for enchantment: " + name + ":\n" +
"Item do not gave item meta: " + item + ". Using placeholder instead");
item.setType(Material.PAPER);
meta = item.getItemMeta();
assert meta != null;
}
meta.setDisplayName("\u00A7" + (isIn ? 'a' : 'c') + CasedStringUtil.snakeToUpperSpacedCase(name));
if (isIn) {
meta.addEnchant(Enchantment.DAMAGE_UNDEAD, 1, true);
meta.setLore(TRUE_LORE);
} else {
meta.removeEnchant(Enchantment.DAMAGE_UNDEAD);
meta.setLore(FALSE_LORE);
}
meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_ENCHANTS);
item.setItemMeta(meta);
}
private Consumer<InventoryClickEvent> getEnchantItemConsumer(Enchantment enchant, GuiItem guiItem) {
return event -> {
event.setCancelled(true);
ItemStack item = guiItem.getItem();
boolean isIn = this.selectedEnchant.contains(enchant);
if (isIn) {
this.selectedEnchant.remove(enchant);
item.setType(Material.BOOK);
} else {
this.selectedEnchant.add(enchant);
item.setType(Material.ENCHANTED_BOOK);
}
setEnchantItemMeta(item, enchant.getKey().getKey(), !isIn);
guiItem.setItem(item);// Just in case
update();
};
}
@Override
public boolean onSave() {
return this.enchantContainer.setSelectedEnchantments(this.selectedEnchant);
}
@Override
public boolean hadChange() {
Set<Enchantment> baseGroup = this.enchantContainer.getSelectedEnchantments();
return baseGroup.size() != this.selectedEnchant.size() ||
!baseGroup.containsAll(this.selectedEnchant);
}
}

View file

@ -0,0 +1,152 @@
package xyz.alexcrea.cuanvil.gui.config.settings;
import com.github.stefvanschie.inventoryframework.gui.GuiItem;
import com.github.stefvanschie.inventoryframework.pane.Orientable;
import com.github.stefvanschie.inventoryframework.pane.OutlinePane;
import com.github.stefvanschie.inventoryframework.pane.Pane;
import com.github.stefvanschie.inventoryframework.pane.util.Pattern;
import io.delilaheve.CustomAnvil;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.group.AbstractMaterialGroup;
import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui;
import xyz.alexcrea.cuanvil.gui.config.SelectGroupContainer;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
public class GroupSelectSettingGui extends AbstractSettingGui {
SelectGroupContainer groupContainer;
int page;
Set<AbstractMaterialGroup> selectedGroups;
public GroupSelectSettingGui(@NotNull String title, ValueUpdatableGui parent, SelectGroupContainer groupContainer, int page) {
super(6, title, parent);
this.groupContainer = groupContainer;
//Not used but planned
this.page = page;
this.selectedGroups = new HashSet<>(groupContainer.getSelectedGroups());
// Add secondary background item
this.getPane().bindItem('1', GuiSharedConstant.SECONDARY_BACKGROUND_ITEM);
initGroups();
}
@Override
protected Pattern getGuiPattern() {
return new Pattern(
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
"B1111111S"
);
}
protected void initGroups() {
// Add enchantment gui item
OutlinePane filledEnchant = new OutlinePane(0, 0, 9, 5);
filledEnchant.setPriority(Pane.Priority.HIGH);
filledEnchant.align(OutlinePane.Alignment.BEGIN);
filledEnchant.setOrientation(Orientable.Orientation.HORIZONTAL);
Set<AbstractMaterialGroup> illegalGroup = this.groupContainer.illegalGroups();
for (AbstractMaterialGroup group : ConfigHolder.ITEM_GROUP_HOLDER.getItemGroupsManager().getGroupMap().values()) {
if (illegalGroup.contains(group)) {
return;
}
filledEnchant.addItem(getGuiItemFromGroup(group));
}
addPane(filledEnchant);
}
private GuiItem getGuiItemFromGroup(AbstractMaterialGroup group) {
boolean isIn = this.selectedGroups.contains(group);
Material usedMaterial = group.getRepresentativeMaterial();
ItemStack item = new ItemStack(usedMaterial);
setGroupItemMeta(item, group.getName(), isIn);
GuiItem guiItem = new GuiItem(item, CustomAnvil.instance);
guiItem.setAction(getGroupItemConsumer(group, guiItem));
return guiItem;
}
private static final List<String> TRUE_LORE = Collections.singletonList("\u00A77Value: \u00A7aSelected");
private static final List<String> FALSE_LORE = Collections.singletonList("\u00A77Value: \u00A7cNot Selected");
public void setGroupItemMeta(ItemStack item, String name, boolean isIn) {
ItemMeta meta = item.getItemMeta();
if (meta == null) {
CustomAnvil.instance.getLogger().warning("Could not create item for group: " + name + ":\n" +
"Item do not gave item meta: " + item + ". Using placeholder instead");
item.setType(Material.PAPER);
meta = item.getItemMeta();
assert meta != null;
}
meta.setDisplayName("\u00A7" + (isIn ? 'a' : 'c') + CasedStringUtil.snakeToUpperSpacedCase(name));
if (isIn) {
meta.addEnchant(Enchantment.DAMAGE_UNDEAD, 1, true);
meta.setLore(TRUE_LORE);
} else {
meta.removeEnchant(Enchantment.DAMAGE_UNDEAD);
meta.setLore(FALSE_LORE);
}
meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_ENCHANTS);
item.setItemMeta(meta);
}
private Consumer<InventoryClickEvent> getGroupItemConsumer(AbstractMaterialGroup group, GuiItem guiItem) {
return event -> {
event.setCancelled(true);
boolean isIn = this.selectedGroups.contains(group);
if (isIn) {
this.selectedGroups.remove(group);
} else {
this.selectedGroups.add(group);
}
ItemStack item = guiItem.getItem();
setGroupItemMeta(item, group.getName(), !isIn);
guiItem.setItem(item);// Just in case
update();
};
}
@Override
public boolean onSave() {
return this.groupContainer.setSelectedGroups(this.selectedGroups);
}
@Override
public boolean hadChange() {
Set<AbstractMaterialGroup> baseGroup = this.groupContainer.getSelectedGroups();
return baseGroup.size() != this.selectedGroups.size() ||
!baseGroup.containsAll(this.selectedGroups);
}
}

View file

@ -13,6 +13,7 @@ import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui; import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import xyz.alexcrea.cuanvil.util.MetricsUtil; import xyz.alexcrea.cuanvil.util.MetricsUtil;
import java.util.Collections; import java.util.Collections;
@ -31,6 +32,7 @@ public class IntSettingsGui extends AbstractSettingGui{
/** /**
* Create an int setting config gui. * Create an int setting config gui.
*
* @param holder Configuration factory of this setting. * @param holder Configuration factory of this setting.
* @param now The defined value of this setting. * @param now The defined value of this setting.
*/ */
@ -58,6 +60,7 @@ public class IntSettingsGui extends AbstractSettingGui{
} }
protected GuiItem returnToDefault; protected GuiItem returnToDefault;
/** /**
* Prepare "return to default value" gui item. * Prepare "return to default value" gui item.
*/ */
@ -185,6 +188,7 @@ public class IntSettingsGui extends AbstractSettingGui{
/** /**
* Step use lower case character from 'a' to a certain char. * Step use lower case character from 'a' to a certain char.
*
* @return The middle value of the character set for steps. * @return The middle value of the character set for steps.
*/ */
protected char getMidStepChar() { protected char getMidStepChar() {
@ -193,6 +197,7 @@ public class IntSettingsGui extends AbstractSettingGui{
/** /**
* Create a step item from a step value. * Create a step item from a step value.
*
* @param stepIndex the index of the step item. * @param stepIndex the index of the step item.
* @return A step item corresponding to its index value. * @return A step item corresponding to its index value.
*/ */
@ -247,8 +252,8 @@ public class IntSettingsGui extends AbstractSettingGui{
holder.config.getConfig().set(holder.configPath, now); holder.config.getConfig().set(holder.configPath, now);
MetricsUtil.INSTANCE.notifyChange(this.holder.config, this.holder.configPath); MetricsUtil.INSTANCE.notifyChange(this.holder.config, this.holder.configPath);
if(TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE){ if (GuiSharedConstant.TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE) {
return holder.config.saveToDisk(TEMPORARY_DO_BACKUP_EVERY_SAVE); return holder.config.saveToDisk(GuiSharedConstant.TEMPORARY_DO_BACKUP_EVERY_SAVE);
} }
return true; return true;
} }
@ -260,6 +265,7 @@ public class IntSettingsGui extends AbstractSettingGui{
/** /**
* Create an int setting factory from setting's parameters. * Create an int setting factory from setting's parameters.
*
* @param title The title of the gui. * @param title The title of the gui.
* @param parent Parent gui to go back when completed. * @param parent Parent gui to go back when completed.
* @param configPath Configuration path of this setting. * @param configPath Configuration path of this setting.
@ -286,11 +292,17 @@ public class IntSettingsGui extends AbstractSettingGui{
* A factory for an int setting gui that hold setting's information. * A factory for an int setting gui that hold setting's information.
*/ */
public static class IntSettingFactory extends SettingGuiFactory { public static class IntSettingFactory extends SettingGuiFactory {
@NotNull String title; ValueUpdatableGui parent; @NotNull
int min; int max; int defaultVal; int[] steps; String title;
ValueUpdatableGui parent;
int min;
int max;
int defaultVal;
int[] steps;
/** /**
* Constructor for an int setting gui factory. * Constructor for an int setting gui factory.
*
* @param title The title of the gui. * @param title The title of the gui.
* @param parent Parent gui to go back when completed. * @param parent Parent gui to go back when completed.
* @param configPath Configuration path of this setting. * @param configPath Configuration path of this setting.

View file

@ -0,0 +1,350 @@
package xyz.alexcrea.cuanvil.gui.config.settings.subsetting;
import com.github.stefvanschie.inventoryframework.gui.GuiItem;
import com.github.stefvanschie.inventoryframework.pane.PatternPane;
import com.github.stefvanschie.inventoryframework.pane.util.Pattern;
import io.delilaheve.CustomAnvil;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
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.config.ConfigHolder;
import xyz.alexcrea.cuanvil.group.AbstractMaterialGroup;
import xyz.alexcrea.cuanvil.group.EnchantConflictGroup;
import xyz.alexcrea.cuanvil.group.EnchantConflictManager;
import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui;
import xyz.alexcrea.cuanvil.gui.config.ConfirmActionGui;
import xyz.alexcrea.cuanvil.gui.config.SelectEnchantmentContainer;
import xyz.alexcrea.cuanvil.gui.config.SelectGroupContainer;
import xyz.alexcrea.cuanvil.gui.config.global.EnchantConflictGui;
import xyz.alexcrea.cuanvil.gui.config.settings.EnchantSelectSettingGui;
import xyz.alexcrea.cuanvil.gui.config.settings.GroupSelectSettingGui;
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.util.CasedStringUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
import java.util.function.Supplier;
import java.util.logging.Level;
public class EnchantConflictSubSettingGui extends ValueUpdatableGui implements SelectEnchantmentContainer, SelectGroupContainer {
private final EnchantConflictGui parent;
private final EnchantConflictGroup enchantConflict;
private final GuiItem parentItemForThisGui;
private final PatternPane pane;
private boolean shouldWorld = true;
public EnchantConflictSubSettingGui(
@NotNull EnchantConflictGui parent,
@NotNull EnchantConflictGroup enchantConflict,
@NotNull GuiItem parentItemForThisGui) {
super(3,
"\u00A7e" + CasedStringUtil.snakeToUpperSpacedCase(enchantConflict.getName()) + " \u00A78Config",
CustomAnvil.instance);
this.parent = parent;
this.enchantConflict = enchantConflict;
this.parentItemForThisGui = parentItemForThisGui;
Pattern pattern = new Pattern(
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
"00EGM000D",
"B00000000"
);
this.pane = new PatternPane(0, 0, 9, 3, pattern);
addPane(this.pane);
prepareStaticValues();
}
private GuiItem enchantSettingItem;
private GuiItem groupSettingItem;
private IntSettingsGui.IntSettingFactory minBeforeActiveSettingFactory;
private void prepareStaticValues() {
GuiGlobalItems.addBackItem(this.pane, this.parent);
GuiGlobalItems.addBackgroundItem(this.pane);
// Delete item
ItemStack deleteItem = new ItemStack(Material.RED_TERRACOTTA);
ItemMeta deleteMeta = deleteItem.getItemMeta();
deleteMeta.setDisplayName("\u00A74DELETE CONFLICT");
deleteMeta.setLore(Collections.singletonList("\u00A7cCaution with this button !"));
deleteItem.setItemMeta(deleteMeta);
this.pane.bindItem('D', new GuiItem(deleteItem, GuiGlobalActions.openGuiAction(createDeleteGui()), CustomAnvil.instance));
// Displayed item will be updated later
this.enchantSettingItem = new GuiItem(new ItemStack(Material.ENCHANTED_BOOK), (event) -> {
event.setCancelled(true);
EnchantSelectSettingGui enchantGui = new EnchantSelectSettingGui(
"\u00A7e" + CasedStringUtil.snakeToUpperSpacedCase(enchantConflict.getName()) + " \u00A75Enchantments",
this, this, 0);
enchantGui.show(event.getWhoClicked());
}, CustomAnvil.instance);
this.groupSettingItem = new GuiItem(new ItemStack(Material.PAPER), (event) -> {
event.setCancelled(true);
GroupSelectSettingGui enchantGui = new GroupSelectSettingGui(
"\u00A7e" + CasedStringUtil.snakeToUpperSpacedCase(this.enchantConflict.getName()) + " \u00A73Groups",
this, this, 0);
enchantGui.show(event.getWhoClicked());
}, CustomAnvil.instance);
this.minBeforeActiveSettingFactory = IntSettingsGui.intFactory(
"\u00A78Minimum enchantment count",
this, this.enchantConflict.getName() + ".maxEnchantmentBeforeConflict", ConfigHolder.CONFLICT_HOLDER,
0, 255, 0, 1
);
this.pane.bindItem('E', this.enchantSettingItem);
this.pane.bindItem('G', this.groupSettingItem);
// Now we update the items
updateLocal();
}
private ConfirmActionGui createDeleteGui() {
Supplier<Boolean> deleteSupplier = () -> {
EnchantConflictManager manager = ConfigHolder.CONFLICT_HOLDER.getConflictManager();
// Remove from manager
for (Enchantment enchantment : this.enchantConflict.getEnchants()) {
manager.removeConflictFromMap(enchantment, this.enchantConflict);
}
manager.conflictList.remove(this.enchantConflict);
// Remove from parent
this.parent.removeConflict(this.enchantConflict);
// Remove self
cleanUnused();
// Update config file storage
ConfigHolder.CONFLICT_HOLDER.getConfig().set(this.enchantConflict.getName(), null);
// Save
boolean success = true;
if (GuiSharedConstant.TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE) {
success = ConfigHolder.CONFLICT_HOLDER.saveToDisk(GuiSharedConstant.TEMPORARY_DO_BACKUP_EVERY_SAVE);
}
return success;
};
return new ConfirmActionGui("\u00A7cDelete \u00A7e" + CasedStringUtil.snakeToUpperSpacedCase(enchantConflict.getName()) + "\u00A7c?",
"\u00A77Confirm that you want to delete this conflict.",
this, this.parent, deleteSupplier
);
}
@Override
public void updateGuiValues() {
this.parent.updateValueForConflict(this.enchantConflict, true);
// Parent should call updateLocal
}
public void updateLocal() {
if (!this.shouldWorld) return;
// Prepare enchantment lore
ArrayList<String> enchantLore = new ArrayList<>();
enchantLore.add("\u00A77Allow you to select a list of \u00A75Enchantments \u00A77that this conflict should include");
Set<Enchantment> enchants = getSelectedEnchantments();
if (enchants.isEmpty()) {
enchantLore.add("\u00A77There is no included enchantment for this conflict.");
} else {
enchantLore.add("\u00A77List of included enchantment for this conflict:");
Iterator<Enchantment> enchantIterator = enchants.iterator();
boolean greaterThanMax = enchants.size() > 5;
int maxindex = (greaterThanMax ? 4 : enchants.size());
for (int i = 0; i < maxindex; i++) {
// format string like "- Fire Protection"
String formattedName = CasedStringUtil.snakeToUpperSpacedCase(enchantIterator.next().getKey().getKey());
enchantLore.add("\u00A77- \u00A75" + formattedName);
}
if (greaterThanMax) {
enchantLore.add("\u00A77And " + (enchants.size() - 4) + " more...");
}
}
// Prepare group lore
ArrayList<String> groupLore = new ArrayList<>();
groupLore.add("\u00A77Allow you to select a list of \u00A73Groups \u00A77that this conflict should include");
Set<AbstractMaterialGroup> grouos = getSelectedGroups();
if (grouos.isEmpty()) {
groupLore.add("\u00A77There is no excluded groups for this conflict.");
} else {
groupLore.add("\u00A77List of excluded groups for this conflict:");
Iterator<AbstractMaterialGroup> groupIterator = grouos.iterator();
boolean greaterThanMax = grouos.size() > 5;
int maxindex = (greaterThanMax ? 4 : grouos.size());
for (int i = 0; i < maxindex; i++) {
// format string like "- Melee Weapons"
String formattedName = CasedStringUtil.snakeToUpperSpacedCase(groupIterator.next().getName());
groupLore.add("\u00A77- \u00A73" + formattedName);
}
if (greaterThanMax) {
groupLore.add("\u00A77And " + (grouos.size() - 4) + " more...");
}
}
// Configure enchant setting item
ItemStack enchantItem = this.enchantSettingItem.getItem();
ItemMeta enchantMeta = enchantItem.getItemMeta();
enchantMeta.setDisplayName("\u00A7aSelect included \u00A75Enchantments \u00A7aSettings");
enchantMeta.setLore(enchantLore);
enchantItem.setItemMeta(enchantMeta);
this.enchantSettingItem.setItem(enchantItem); // Just in case
// Configure group setting item
ItemStack groupItem = this.groupSettingItem.getItem();
ItemMeta groupMeta = groupItem.getItemMeta();
groupMeta.setDisplayName("\u00A7aSelect excluded \u00A73Groups \u00A7aSettings");
groupMeta.setLore(groupLore);
groupItem.setItemMeta(groupMeta);
this.groupSettingItem.setItem(groupItem); // Just in case
this.pane.bindItem('M', GuiGlobalItems.intSettingGuiItem(this.minBeforeActiveSettingFactory, Material.COMMAND_BLOCK));
update();
}
public void cleanUnused() {
for (HumanEntity viewer : getViewers()) {
this.parent.show(viewer);
}
this.shouldWorld = false;
// Just in case something is extremely wrong
GuiItem background = GuiGlobalItems.backgroundItem();
this.pane.bindItem('E', background);
this.pane.bindItem('G', background);
this.pane.bindItem('M', background);
this.pane.bindItem('D', background);
}
@Override
public void show(@NotNull HumanEntity humanEntity) {
if (this.shouldWorld) {
super.show(humanEntity);
} else {
this.parent.show(humanEntity);
}
}
public GuiItem getParentItemForThisGui() {
return parentItemForThisGui;
}
// Select enchantment container methods
@Override
public Set<Enchantment> getSelectedEnchantments() {
return this.enchantConflict.getEnchants();
}
@Override
public boolean setSelectedEnchantments(Set<Enchantment> enchantments) {
if (!this.shouldWorld) {
CustomAnvil.instance.getLogger().info("Trying to save " + enchantConflict.getName() + " enchants but sub config is destroyed");
return false;
}
// Set live configuration
this.enchantConflict.setEnchants(enchantments);
// Save on file configuration
String[] enchantKeys = new String[enchantments.size()];
int index = 0;
for (Enchantment enchantment : enchantments) {
enchantKeys[index++] = enchantment.getKey().getKey();
}
ConfigHolder.CONFLICT_HOLDER.getConfig().set(enchantConflict.getName() + ".enchantments", enchantKeys);
try {
updateGuiValues();
} catch (Exception e) {
CustomAnvil.instance.getLogger().log(Level.WARNING, "An error occurred while updating enchants for " + this.enchantConflict.getName(), e);
}
// Save file configuration to disk
if (GuiSharedConstant.TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE) {
return ConfigHolder.CONFLICT_HOLDER.saveToDisk(GuiSharedConstant.TEMPORARY_DO_BACKUP_EVERY_SAVE);
}
return true;
}
@Override
public Set<Enchantment> illegalEnchantments() {
return Collections.emptySet();
}
// Select group container methods
@Override
public Set<AbstractMaterialGroup> getSelectedGroups() {
return this.enchantConflict.getCantConflictGroup().getGroups();
}
@Override
public boolean setSelectedGroups(Set<AbstractMaterialGroup> groups) {
if (!this.shouldWorld) {
CustomAnvil.instance.getLogger().info("Trying to save " + enchantConflict.getName() + " groups but sub config is destroyed");
return false;
}
// Set live configuration
this.enchantConflict.getCantConflictGroup().setGroups(groups);
// Save on file configuration
String[] groupsNames = new String[groups.size()];
int index = 0;
for (AbstractMaterialGroup group : groups) {
groupsNames[index++] = group.getName();
}
ConfigHolder.CONFLICT_HOLDER.getConfig().set(this.enchantConflict.getName() + ".notAffectedGroups", groupsNames);
try {
updateGuiValues();
} catch (Exception e) {
CustomAnvil.instance.getLogger().log(Level.WARNING, "An error occurred while updating group for " + this.enchantConflict.getName(), e);
}
// Save file configuration to disk
if (GuiSharedConstant.TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE) {
return ConfigHolder.CONFLICT_HOLDER.saveToDisk(GuiSharedConstant.TEMPORARY_DO_BACKUP_EVERY_SAVE);
}
return true;
}
@Override
public Set<AbstractMaterialGroup> illegalGroups() {
return Collections.emptySet();
}
}

View file

@ -27,6 +27,7 @@ public class GuiGlobalActions {
/** /**
* Create a consumer to create and open a new GUI. * Create a consumer to create and open a new GUI.
* Used with InventoryClickEvent as the consumer argument as it is planned to be used on click on an GuiItem. * Used with InventoryClickEvent as the consumer argument as it is planned to be used on click on an GuiItem.
*
* @param clazz The class of the gui to open. * @param clazz The class of the gui to open.
* It is assumed this class contain a constructor requiring arguments of argClass in the same order as argClass array. * It is assumed this class contain a constructor requiring arguments of argClass in the same order as argClass array.
* @param argClass Classes of the argument that will be passed to the constructor of the GUI class. * @param argClass Classes of the argument that will be passed to the constructor of the GUI class.
@ -62,6 +63,7 @@ public class GuiGlobalActions {
/** /**
* Create a consumer to create and open a new GUI. * Create a consumer to create and open a new GUI.
* Used with InventoryClickEvent as the consumer argument as it is planned to be used on click on an GuiItem. * Used with InventoryClickEvent as the consumer argument as it is planned to be used on click on an GuiItem.
*
* @param clazz The class of the gui to open. * @param clazz The class of the gui to open.
* It is assumed this class contain a constructor with no argument. * It is assumed this class contain a constructor with no argument.
* @return A consumer to create a new gui and open it. * @return A consumer to create a new gui and open it.
@ -74,6 +76,7 @@ public class GuiGlobalActions {
/** /**
* Create a consumer to open a setting gui from a setting GUI factory. * Create a consumer to open a setting gui from a setting GUI factory.
* Used with InventoryClickEvent as the consumer argument as it is planned to be used on click on an GuiItem. * Used with InventoryClickEvent as the consumer argument as it is planned to be used on click on an GuiItem.
*
* @param factory The setting gui factory. * @param factory The setting gui factory.
* @return A consumer to create and open a new setting GUI. * @return A consumer to create and open a new setting GUI.
*/ */
@ -88,6 +91,7 @@ public class GuiGlobalActions {
/** /**
* Create a consumer to open a global GUI. * Create a consumer to open a global GUI.
* Used with InventoryClickEvent as the consumer argument as it is planned to be used on click on an GuiItem. * Used with InventoryClickEvent as the consumer argument as it is planned to be used on click on an GuiItem.
*
* @param goal The gui to open when consumer is run. * @param goal The gui to open when consumer is run.
* @return A consumer to open a global GUI. * @return A consumer to open a global GUI.
*/ */
@ -109,6 +113,7 @@ public class GuiGlobalActions {
* Create a consumer to update and open an updatable GUI. * Create a consumer to update and open an updatable GUI.
* Used with InventoryClickEvent as the consumer argument as it is planned to be used on click on an GuiItem. * Used with InventoryClickEvent as the consumer argument as it is planned to be used on click on an GuiItem.
* This consumer check if the player who interacted with the item have the permission to save before saving. * This consumer check if the player who interacted with the item have the permission to save before saving.
*
* @param setting The gui that contain the modified setting. * @param setting The gui that contain the modified setting.
* @param goal The gui to update and open when consumer is run. * @param goal The gui to update and open when consumer is run.
* @return A consumer to open a global GUI. * @return A consumer to open a global GUI.

View file

@ -23,6 +23,7 @@ public class GuiGlobalItems {
// statically create default back itemstack // statically create default back itemstack
private static final ItemStack BACK_ITEM; private static final ItemStack BACK_ITEM;
static { static {
BACK_ITEM = new ItemStack(Material.BARRIER); BACK_ITEM = new ItemStack(Material.BARRIER);
ItemMeta meta = BACK_ITEM.getItemMeta(); ItemMeta meta = BACK_ITEM.getItemMeta();
@ -32,6 +33,7 @@ public class GuiGlobalItems {
/** /**
* Create a GuiItem that open the given GUi. * Create a GuiItem that open the given GUi.
*
* @param item The item to display in the GUI. * @param item The item to display in the GUI.
* @param goal The GUI to open on click. * @param goal The GUI to open on click.
* @return An GuiItem that open goal on click. * @return An GuiItem that open goal on click.
@ -43,6 +45,7 @@ public class GuiGlobalItems {
/** /**
* Create back button item from default back GuiItem. * Create back button item from default back GuiItem.
* The back item will open the goal inventory when clicked. * The back item will open the goal inventory when clicked.
*
* @param goal The GUI to go back to. * @param goal The GUI to go back to.
* @return An GuiItem that go back to goal on click. * @return An GuiItem that go back to goal on click.
*/ */
@ -53,6 +56,7 @@ public class GuiGlobalItems {
/** /**
* Add default back item to a GUI pattern with the reserved character key <strong>B</strong>. * Add default back item to a GUI pattern with the reserved character key <strong>B</strong>.
* The back item will open the target inventory when clicked. * The back item will open the target inventory when clicked.
*
* @param target The pattern to add the back item. * @param target The pattern to add the back item.
* @param goal The GUI to go back to. * @param goal The GUI to go back to.
*/ */
@ -66,6 +70,7 @@ public class GuiGlobalItems {
/** /**
* Get a background item with backgroundMat as the displayed material. * Get a background item with backgroundMat as the displayed material.
* A background item is a GuiItem that do nothing when interacted with and have an empty name. * A background item is a GuiItem that do nothing when interacted with and have an empty name.
*
* @param backgroundMat The material to which the background item should be made of. * @param backgroundMat The material to which the background item should be made of.
* @return A background item with backgroundMat as material. * @return A background item with backgroundMat as material.
*/ */
@ -76,9 +81,11 @@ public class GuiGlobalItems {
item.setItemMeta(meta); item.setItemMeta(meta);
return new GuiItem(item, GuiGlobalActions.stayInPlace, CustomAnvil.instance); return new GuiItem(item, GuiGlobalActions.stayInPlace, CustomAnvil.instance);
} }
/** /**
* Get default background GuiItem. * Get default background GuiItem.
* A background item is a GuiItem that do nothing when interacted with and have an empty name. * A background item is a GuiItem that do nothing when interacted with and have an empty name.
*
* @return A new instance of the default background item. * @return A new instance of the default background item.
*/ */
public static GuiItem backgroundItem() { public static GuiItem backgroundItem() {
@ -88,6 +95,7 @@ public class GuiGlobalItems {
/** /**
* Add default background item to a GUI pattern with the reserved character key <strong>0</strong>. * Add default background item to a GUI pattern with the reserved character key <strong>0</strong>.
* A background item is a GuiItem that do nothing when interacted with and have an empty name. * A background item is a GuiItem that do nothing when interacted with and have an empty name.
*
* @param target The pattern to add the background item. * @param target The pattern to add the background item.
* @param backgroundMat The material of the background item. * @param backgroundMat The material of the background item.
*/ */
@ -99,6 +107,7 @@ public class GuiGlobalItems {
/** /**
* Add default background item to a GUI pattern with the reserved character key <strong>0</strong>. * Add default background item to a GUI pattern with the reserved character key <strong>0</strong>.
* A background item is a GuiItem that do nothing when interacted with and have an empty name. * A background item is a GuiItem that do nothing when interacted with and have an empty name.
*
* @param target The pattern to add the background item. * @param target The pattern to add the background item.
*/ */
public static void addBackgroundItem(@NotNull PatternPane target) { public static void addBackgroundItem(@NotNull PatternPane target) {
@ -112,6 +121,7 @@ public class GuiGlobalItems {
* Create a new save setting GuiItem. * Create a new save setting GuiItem.
* A save setting item is a GuiItem that save a changed setting when clicked. * A save setting item is a GuiItem that save a changed setting when clicked.
* This item also check if the player who interacted with the item have the permission to save before saving. * This item also check if the player who interacted with the item have the permission to save before saving.
*
* @param setting The setting to change. * @param setting The setting to change.
* @param goal Parent GUI of this setting GUI. as setting will be change the display of goal GUI will be updated. * @param goal Parent GUI of this setting GUI. as setting will be change the display of goal GUI will be updated.
* @return A save setting item. * @return A save setting item.
@ -131,6 +141,7 @@ public class GuiGlobalItems {
// Create static non change item // Create static non change item
private static final GuiItem NO_CHANGE_ITEM; private static final GuiItem NO_CHANGE_ITEM;
static { static {
ItemStack item = new ItemStack(DEFAULT_NO_CHANGE_ITEM); ItemStack item = new ItemStack(DEFAULT_NO_CHANGE_ITEM);
ItemMeta meta = item.getItemMeta(); ItemMeta meta = item.getItemMeta();
@ -142,6 +153,7 @@ public class GuiGlobalItems {
/** /**
* Get the global "no change" GuiItem. * Get the global "no change" GuiItem.
* The no change item do nothing when interacted, only the title is change to show there is no change. * The no change item do nothing when interacted, only the title is change to show there is no change.
*
* @return The global "no change" item. * @return The global "no change" item.
*/ */
public static GuiItem noChangeItem() { public static GuiItem noChangeItem() {
@ -151,6 +163,7 @@ public class GuiGlobalItems {
/** /**
* Create a new "create and go to the setting GUI" GuiItem. * Create a new "create and go to the setting GUI" GuiItem.
* This item will create and open a setting GUI from the factory. * This item will create and open a setting GUI from the factory.
*
* @param item The item that will be displayed. * @param item The item that will be displayed.
* @param factory The setting's GUI factory. * @param factory The setting's GUI factory.
* @return A formatted GuiItem that will create and open a GUI for the setting. * @return A formatted GuiItem that will create and open a GUI for the setting.
@ -169,6 +182,7 @@ public class GuiGlobalItems {
* Create a new Boolean setting GuiItem. * Create a new Boolean setting GuiItem.
* This item will create and open a boolean setting GUI from the factory. * This item will create and open a boolean setting GUI from the factory.
* The item will have its value written in the lore part of the item. * The item will have its value written in the lore part of the item.
*
* @param factory The setting's GUI factory. * @param factory The setting's GUI factory.
* @param name Name of the item. * @param name Name of the item.
* @return A formatted GuiItem that will create and open a GUI for the boolean setting. * @return A formatted GuiItem that will create and open a GUI for the boolean setting.
@ -199,6 +213,7 @@ public class GuiGlobalItems {
* This item will create and open a boolean setting GUI from the factory. * This item will create and open a boolean setting GUI from the factory.
* The item will have its value written in the lore part of the item. * The item will have its value written in the lore part of the item.
* Item's name will be the factory set title. * Item's name will be the factory set title.
*
* @param factory The setting's GUI factory. * @param factory The setting's GUI factory.
* @return A formatted GuiItem that will create and open a GUI for the boolean setting. * @return A formatted GuiItem that will create and open a GUI for the boolean setting.
*/ */
@ -213,6 +228,7 @@ public class GuiGlobalItems {
* Create a new int setting GuiItem. * Create a new int setting GuiItem.
* This item will create and open an int setting GUI from the factory. * This item will create and open an int setting GUI from the factory.
* The item will have its value written in the lore part of the item. * The item will have its value written in the lore part of the item.
*
* @param factory The setting's GUI factory. * @param factory The setting's GUI factory.
* @param itemMat Displayed material of the item. * @param itemMat Displayed material of the item.
* @param name Name of the item. * @param name Name of the item.
@ -235,6 +251,7 @@ public class GuiGlobalItems {
* This item will create and open an int setting GUI from the factory. * This item will create and open an int setting GUI from the factory.
* The item will have its value written in the lore part of the item. * The item will have its value written in the lore part of the item.
* Item's name will be the factory set title. * Item's name will be the factory set title.
*
* @param factory The setting's GUI factory. * @param factory The setting's GUI factory.
* @param itemMat Displayed material of the item. * @param itemMat Displayed material of the item.
* @return A formatted GuiItem that will create and open a GUI for the int setting. * @return A formatted GuiItem that will create and open a GUI for the int setting.
@ -244,11 +261,12 @@ public class GuiGlobalItems {
@NotNull Material itemMat @NotNull Material itemMat
) { ) {
String configPath = getConfigNameFromPath(factory.getConfigPath()); String configPath = getConfigNameFromPath(factory.getConfigPath());
return intSettingGuiItem(factory, itemMat, CasedStringUtil.snakeToUpperSpacedCase(configPath)); return intSettingGuiItem(factory, itemMat, CasedStringUtil.detectToUpperSpacedCase(configPath));
} }
/** /**
* Create an arbitrary GuiItem from a unique setting and item's property. * Create an arbitrary GuiItem from a unique setting and item's property.
*
* @param factory The setting's GUI factory. * @param factory The setting's GUI factory.
* @param itemMat Displayed material of the item. * @param itemMat Displayed material of the item.
* @param itemName Name of the item. * @param itemName Name of the item.
@ -277,6 +295,7 @@ public class GuiGlobalItems {
/** /**
* Get the setting name from the setting path. * Get the setting name from the setting path.
* For example: "gui.command.name" will return "name". * For example: "gui.command.name" will return "name".
*
* @param path The setting's path. * @param path The setting's path.
* @return The setting's name. * @return The setting's name.
*/ */

View file

@ -0,0 +1,53 @@
package xyz.alexcrea.cuanvil.gui.util;
import com.github.stefvanschie.inventoryframework.gui.GuiItem;
import com.github.stefvanschie.inventoryframework.pane.Pane;
import com.github.stefvanschie.inventoryframework.pane.PatternPane;
import com.github.stefvanschie.inventoryframework.pane.util.Pattern;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import xyz.alexcrea.cuanvil.gui.config.global.MainConfigGui;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class GuiSharedConstant {
public static final List<Enchantment> SORTED_ENCHANTMENT_LIST;
static {
SORTED_ENCHANTMENT_LIST = Arrays.asList(Enchantment.values());
SORTED_ENCHANTMENT_LIST.sort(Comparator.comparing(ench -> ench.getKey().getKey()));
}
public static final Material SECONDARY_BACKGROUND_MATERIAL = Material.BLACK_STAINED_GLASS_PANE;
public static final GuiItem SECONDARY_BACKGROUND_ITEM = GuiGlobalItems.backgroundItem(GuiSharedConstant.SECONDARY_BACKGROUND_MATERIAL);
public static final String EMPTY_GUI_FULL_LINE = "000000000";
// Temporary values, until I get something better.
public static final boolean TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE = true;
public static final boolean TEMPORARY_DO_BACKUP_EVERY_SAVE = true;
public static final PatternPane BACK_TO_MAIN_MENU_BIG_LIST_DISPLAY_BACKGROUND_PANE;
static {
Pattern pattern = new Pattern(
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
GuiSharedConstant.EMPTY_GUI_FULL_LINE,
"B11111111"
);
BACK_TO_MAIN_MENU_BIG_LIST_DISPLAY_BACKGROUND_PANE = new PatternPane(0, 0, 9, 6, Pane.Priority.LOW, pattern);
GuiGlobalItems.addBackItem(BACK_TO_MAIN_MENU_BIG_LIST_DISPLAY_BACKGROUND_PANE, MainConfigGui.INSTANCE);
GuiGlobalItems.addBackgroundItem(BACK_TO_MAIN_MENU_BIG_LIST_DISPLAY_BACKGROUND_PANE);
BACK_TO_MAIN_MENU_BIG_LIST_DISPLAY_BACKGROUND_PANE.bindItem('1', GuiSharedConstant.SECONDARY_BACKGROUND_ITEM);
}
}

View file

@ -9,6 +9,7 @@ public class CasedStringUtil {
* Transform a snake cased string to an upper-cased spaced string. * Transform a snake cased string to an upper-cased spaced string.
* <p> * <p>
* for example: if we use "hello_world" as an input this function will return "Hello World". * for example: if we use "hello_world" as an input this function will return "Hello World".
*
* @param snake_cased_string The input string. * @param snake_cased_string The input string.
* This argument NEED to be a snake cased string, or it will not work * This argument NEED to be a snake cased string, or it will not work
* @return The input as an upper-cased string with space separator. * @return The input as an upper-cased string with space separator.
@ -28,4 +29,30 @@ public class CasedStringUtil {
return result.substring(1); return result.substring(1);
} }
public static String camelCaseToUpperSpaceCase(String camelCasedString) {
if (camelCasedString.isEmpty()) return camelCasedString;
StringBuilder stb = new StringBuilder();
char[] chars = camelCasedString.toCharArray();
stb.append(chars[0]);
for (int i = 1; i < chars.length; i++) {
char chr = chars[i];
if (Character.isUpperCase(chr)) {
stb.append(" ");
}
stb.append(chr);
}
return stb.toString();
}
public static String detectToUpperSpacedCase(String toDetect) {
//not advanced detection
if (toDetect.contains("_")) {
return snakeToUpperSpacedCase(toDetect);
} else {
return camelCaseToUpperSpaceCase(toDetect);
}
}
} }

View file

@ -39,6 +39,7 @@ class AnvilEventListener : Listener {
private const val ANVIL_INPUT_LEFT = 0 private const val ANVIL_INPUT_LEFT = 0
private const val ANVIL_INPUT_RIGHT = 1 private const val ANVIL_INPUT_RIGHT = 1
private const val ANVIL_OUTPUT_SLOT = 2 private const val ANVIL_OUTPUT_SLOT = 2
// static slot container // static slot container
private val NO_SLOT = SlotContainer(SlotType.NO_SLOT, 0) private val NO_SLOT = SlotContainer(SlotType.NO_SLOT, 0)
private val CURSOR_SLOT = SlotContainer(SlotType.CURSOR, 0) private val CURSOR_SLOT = SlotContainer(SlotType.CURSOR, 0)
@ -64,6 +65,7 @@ class AnvilEventListener : Listener {
// Test/stop if nothing changed. // Test/stop if nothing changed.
if (first == resultItem) { if (first == resultItem) {
CustomAnvil.log("no right item, But input is same as output")
event.result = null event.result = null
return return
} }
@ -95,6 +97,7 @@ class AnvilEventListener : Listener {
// Test/stop if nothing changed. // Test/stop if nothing changed.
if (first == resultItem) { if (first == resultItem) {
CustomAnvil.log("Mergable with second, But input is same as output")
event.result = null event.result = null
return return
} }
@ -125,6 +128,7 @@ class AnvilEventListener : Listener {
// Test/stop if nothing changed. // Test/stop if nothing changed.
if (first == resultItem) { if (first == resultItem) {
CustomAnvil.log("unit repair, But input is same as output")
event.result = null event.result = null
return return
} }
@ -132,6 +136,7 @@ class AnvilEventListener : Listener {
handleAnvilXp(inventory, event, anvilCost) handleAnvilXp(inventory, event, anvilCost)
} else { } else {
CustomAnvil.log("no anvil fuse type found")
event.result = null event.result = null
} }
} }
@ -156,7 +161,9 @@ class AnvilEventListener : Listener {
val player = event.whoClicked as? Player ?: return val player = event.whoClicked as? Player ?: return
if (!player.hasPermission(CustomAnvil.affectedByPluginPermission)) return if (!player.hasPermission(CustomAnvil.affectedByPluginPermission)) return
val inventory = event.inventory as? AnvilInventory ?: return val inventory = event.inventory as? AnvilInventory ?: return
if (event.rawSlot != ANVIL_OUTPUT_SLOT) { return } if (event.rawSlot != ANVIL_OUTPUT_SLOT) {
return
}
val output = inventory.getItem(ANVIL_OUTPUT_SLOT) ?: return val output = inventory.getItem(ANVIL_OUTPUT_SLOT) ?: return
val leftItem = inventory.getItem(ANVIL_INPUT_LEFT) ?: return val leftItem = inventory.getItem(ANVIL_INPUT_LEFT) ?: return
val rightItem = inventory.getItem(ANVIL_INPUT_RIGHT) val rightItem = inventory.getItem(ANVIL_INPUT_RIGHT)
@ -169,7 +176,8 @@ class AnvilEventListener : Listener {
// True if there was no change or not allowed // True if there was no change or not allowed
if ((output == inventory.getItem(ANVIL_INPUT_LEFT)) if ((output == inventory.getItem(ANVIL_INPUT_LEFT))
|| !allowed){ || !allowed
) {
event.result = Event.Result.DENY event.result = Event.Result.DENY
return return
@ -181,23 +189,28 @@ class AnvilEventListener : Listener {
if (canMerge) { if (canMerge) {
event.result = Event.Result.ALLOW event.result = Event.Result.ALLOW
} else if (unitRepairResult != null) { } else if (unitRepairResult != null) {
onUnitRepairExtract(leftItem, rightItem, output, onUnitRepairExtract(
unitRepairResult, event, player, inventory) leftItem, rightItem, output,
unitRepairResult, event, player, inventory
)
return return
} }
} }
private fun onUnitRepairExtract(leftItem: ItemStack, private fun onUnitRepairExtract(
leftItem: ItemStack,
rightItem: ItemStack, rightItem: ItemStack,
output: ItemStack, output: ItemStack,
unitRepairResult: Double, unitRepairResult: Double,
event: InventoryClickEvent, event: InventoryClickEvent,
player: Player, player: Player,
inventory: AnvilInventory){ inventory: AnvilInventory
) {
val resultCopy = leftItem.clone() val resultCopy = leftItem.clone()
val resultAmount = resultCopy.unitRepair( val resultAmount = resultCopy.unitRepair(
rightItem.amount, unitRepairResult) rightItem.amount, unitRepairResult
)
// To avoid vanilla, we cancel the event for unit repair // To avoid vanilla, we cancel the event for unit repair
event.result = Event.Result.DENY event.result = Event.Result.DENY
@ -224,7 +237,8 @@ class AnvilEventListener : Listener {
repairCost += resultAmount * ConfigOptions.unitRepairCost repairCost += resultAmount * ConfigOptions.unitRepairCost
if ((inventory.maximumRepairCost < repairCost) if ((inventory.maximumRepairCost < repairCost)
|| (player.level < repairCost)) return || (player.level < repairCost)
) return
} }
// If not creative middle click... // If not creative middle click...
if (event.click != ClickType.MIDDLE) { if (event.click != ClickType.MIDDLE) {
@ -287,8 +301,11 @@ class AnvilEventListener : Listener {
// Calculate work penalty // Calculate work penalty
val leftPenalty = (left.itemMeta as? Repairable)?.repairCost ?: 0 val leftPenalty = (left.itemMeta as? Repairable)?.repairCost ?: 0
val rightPenalty = val rightPenalty =
if(right == null){ 0 } if (right == null) {
else{ (right.itemMeta as? Repairable)?.repairCost ?: 0 } 0
} else {
(right.itemMeta as? Repairable)?.repairCost ?: 0
}
// Try to set work penalty for the result item // Try to set work penalty for the result item
result.itemMeta?.let { result.itemMeta?.let {
@ -296,10 +313,12 @@ class AnvilEventListener : Listener {
result.itemMeta = it result.itemMeta = it
} }
CustomAnvil.log("Calculated penalty: " + CustomAnvil.log(
"Calculated penalty: " +
"leftPenalty: $leftPenalty, " + "leftPenalty: $leftPenalty, " +
"rightPenalty: $rightPenalty, " + "rightPenalty: $rightPenalty, " +
"result penalty: ${(result.itemMeta as? Repairable)?.repairCost ?: "none"}") "result penalty: ${(result.itemMeta as? Repairable)?.repairCost ?: "none"}"
)
return leftPenalty + rightPenalty return leftPenalty + rightPenalty
} }
@ -321,7 +340,11 @@ class AnvilEventListener : Listener {
// count enchant as illegal enchant if it conflicts with another enchant or not in result // count enchant as illegal enchant if it conflicts with another enchant or not in result
if ((enchantment.key !in resultEnchsKeys)) { if ((enchantment.key !in resultEnchsKeys)) {
resultEnchsKeys.add(enchantment.key) resultEnchsKeys.add(enchantment.key)
val conflictType = ConfigHolder.CONFLICT_HOLDER.conflictManager.isConflicting(resultEnchsKeys,result.type,enchantment.key) val conflictType = ConfigHolder.CONFLICT_HOLDER.conflictManager.isConflicting(
resultEnchsKeys,
result.type,
enchantment.key
)
resultEnchsKeys.remove(enchantment.key) resultEnchsKeys.remove(enchantment.key)
if (ConflictType.BIG_CONFLICT == conflictType) { if (ConflictType.BIG_CONFLICT == conflictType) {
@ -338,9 +361,11 @@ class AnvilEventListener : Listener {
rightValue += value rightValue += value
} }
CustomAnvil.log("Calculated right values: " + CustomAnvil.log(
"Calculated right values: " +
"rightValue: $rightValue, " + "rightValue: $rightValue, " +
"illegalPenalty: $illegalPenalty") "illegalPenalty: $illegalPenalty"
)
return rightValue + illegalPenalty return rightValue + illegalPenalty
} }
@ -348,15 +373,16 @@ class AnvilEventListener : Listener {
/** /**
* Display xp needed for the work on the anvil inventory * Display xp needed for the work on the anvil inventory
*/ */
private fun handleAnvilXp(inventory: AnvilInventory, private fun handleAnvilXp(
inventory: AnvilInventory,
event: PrepareAnvilEvent, event: PrepareAnvilEvent,
anvilCost: Int){ anvilCost: Int
) {
// Test repair cost limit // Test repair cost limit
val finalAnvilCost: Int val finalAnvilCost = if (ConfigOptions.limitRepairCost) {
if (ConfigOptions.limitRepairCost) { min(anvilCost, ConfigOptions.limitRepairValue)
finalAnvilCost = min(anvilCost, ConfigOptions.limitRepairValue)
} else { } else {
finalAnvilCost = anvilCost anvilCost
} }
/* Because Minecraft likes to have the final say in the repair cost displayed /* Because Minecraft likes to have the final say in the repair cost displayed

View file

@ -7,14 +7,14 @@ import org.bukkit.plugin.java.JavaPlugin
import xyz.alexcrea.cuanvil.command.EditConfigExecutor import xyz.alexcrea.cuanvil.command.EditConfigExecutor
import xyz.alexcrea.cuanvil.command.ReloadExecutor import xyz.alexcrea.cuanvil.command.ReloadExecutor
import xyz.alexcrea.cuanvil.config.ConfigHolder import xyz.alexcrea.cuanvil.config.ConfigHolder
import xyz.alexcrea.cuanvil.listener.ChatEventListener
import xyz.alexcrea.cuanvil.util.Metrics import xyz.alexcrea.cuanvil.util.Metrics
import xyz.alexcrea.cuanvil.util.MetricsUtil import xyz.alexcrea.cuanvil.util.MetricsUtil
import java.io.File import java.io.File
import java.io.FileReader import java.io.FileReader
/** /**
* Bukkit/Spigot/Paper plugin to alter enchantment max * Bukkit/Spigot/Paper plugin to alter anvil feature
* levels and allow unsafe enchantment combinations
*/ */
class CustomAnvil : JavaPlugin() { class CustomAnvil : JavaPlugin() {
@ -24,23 +24,31 @@ class CustomAnvil : JavaPlugin() {
// Permission string required to use the plugin's features // Permission string required to use the plugin's features
const val affectedByPluginPermission = "ca.affected" const val affectedByPluginPermission = "ca.affected"
// Permission string required to bypass enchantment conflicts test // Permission string required to bypass enchantment conflicts test
const val bypassFusePermission = "ca.bypass.fuse" const val bypassFusePermission = "ca.bypass.fuse"
// Permission string required to bypass enchantment conflicts test // Permission string required to bypass enchantment conflicts test
const val bypassLevelPermission = "ca.bypass.level" const val bypassLevelPermission = "ca.bypass.level"
// Permission string required to reload the config // Permission string required to reload the config
const val commandReloadPermission = "ca.command.reload" const val commandReloadPermission = "ca.command.reload"
// Permission string required to edit the plugin's config // Permission string required to edit the plugin's config
const val editConfigPermission = "ca.config.edit" const val editConfigPermission = "ca.config.edit"
// Command Name to reload the config // Command Name to reload the config
const val commandReloadName = "anvilconfigreload" const val commandReloadName = "anvilconfigreload"
// Test command name // Test command name
const val commandTestName = "customanvilconfig" const val commandTestName = "customanvilconfig"
// Current plugin instance // Current plugin instance
lateinit var instance: CustomAnvil lateinit var instance: CustomAnvil
// Chat message listener
lateinit var chatListener: ChatEventListener
/** /**
* Logging handler * Logging handler
*/ */
@ -49,6 +57,15 @@ class CustomAnvil : JavaPlugin() {
instance.logger.info(message) instance.logger.info(message)
} }
} }
/**
* Vebose Logging handler
*/
fun verboseLog(message: String) {
if (ConfigOptions.verboseDebugLog) {
instance.logger.info(message)
}
}
} }
/** /**
@ -65,8 +82,11 @@ class CustomAnvil : JavaPlugin() {
logger.warning("Please note CustomAnvil is a more recent version of UnsafeEnchantsPlus") logger.warning("Please note CustomAnvil is a more recent version of UnsafeEnchantsPlus")
} }
// Load config // Load chat listener
chatListener = ChatEventListener()
Bukkit.getPluginManager().registerEvents(chatListener, this)
// Load config
val success = ConfigHolder.loadConfig() val success = ConfigHolder.loadConfig()
if (!success) return if (!success) return
@ -83,8 +103,10 @@ class CustomAnvil : JavaPlugin() {
) )
} }
fun reloadResource(resourceName: String, fun reloadResource(
hardFailSafe:Boolean = true): YamlConfiguration?{ resourceName: String,
hardFailSafe: Boolean = true
): YamlConfiguration? {
// Save default resource // Save default resource
val file = File(dataFolder, resourceName) val file = File(dataFolder, resourceName)
if (!file.exists()) { if (!file.exists()) {

View file

@ -12,66 +12,97 @@ object ConfigOptions {
// Path for default enchantment limits // Path for default enchantment limits
private const val DEFAULT_LIMIT_PATH = "default_limit" private const val DEFAULT_LIMIT_PATH = "default_limit"
// Path for limiting repair cost // Path for limiting repair cost
const val LIMIT_REPAIR_COST = "limit_repair_cost" const val LIMIT_REPAIR_COST = "limit_repair_cost"
// Path for repair value limit // Path for repair value limit
const val LIMIT_REPAIR_VALUE = "limit_repair_value" const val LIMIT_REPAIR_VALUE = "limit_repair_value"
// Path for level cost on item repair // Path for level cost on item repair
const val ITEM_REPAIR_COST = "item_repair_cost" const val ITEM_REPAIR_COST = "item_repair_cost"
// Path for level cost on unit repair // Path for level cost on unit repair
const val UNIT_REPAIR_COST = "unit_repair_cost" const val UNIT_REPAIR_COST = "unit_repair_cost"
// Path for level cost on item renaming // Path for level cost on item renaming
const val ITEM_RENAME_COST = "item_rename_cost" const val ITEM_RENAME_COST = "item_rename_cost"
// Path for level cost on illegal enchantment on sacrifice // Path for level cost on illegal enchantment on sacrifice
const val SACRIFICE_ILLEGAL_COST = "sacrifice_illegal_enchant_cost" const val SACRIFICE_ILLEGAL_COST = "sacrifice_illegal_enchant_cost"
// Path for removing repair cost limits // Path for removing repair cost limits
const val REMOVE_REPAIR_LIMIT = "remove_repair_limit" const val REMOVE_REPAIR_LIMIT = "remove_repair_limit"
// Root path for enchantment limits // Root path for enchantment limits
const val ENCHANT_LIMIT_ROOT = "enchant_limits" const val ENCHANT_LIMIT_ROOT = "enchant_limits"
// Root path for enchantment values // Root path for enchantment values
const val ENCHANT_VALUES_ROOT = "enchant_values" const val ENCHANT_VALUES_ROOT = "enchant_values"
// Keys for specific enchantment values // Keys for specific enchantment values
private const val KEY_BOOK = "book" private const val KEY_BOOK = "book"
private const val KEY_ITEM = "item" private const val KEY_ITEM = "item"
// Debug logging toggle path // Debug logging toggle path
private const val DEBUG_LOGGING = "debug_log" private const val DEBUG_LOGGING = "debug_log"
// Debug verbose logging toggle path
private const val VERBOSE_DEBUG_LOGGING = "debug_log_verbose"
// Default value for enchantment limits // Default value for enchantment limits
private const val DEFAULT_ENCHANT_LIMIT = 5 private const val DEFAULT_ENCHANT_LIMIT = 5
// Default value for limiting repair cost // Default value for limiting repair cost
const val DEFAULT_LIMIT_REPAIR = false const val DEFAULT_LIMIT_REPAIR = false
// Default value for repair cost limit // Default value for repair cost limit
const val DEFAULT_LIMIT_REPAIR_VALUE = 39 const val DEFAULT_LIMIT_REPAIR_VALUE = 39
// Default value for level cost on item repair // Default value for level cost on item repair
const val DEFAULT_ITEM_REPAIR_COST = 2 const val DEFAULT_ITEM_REPAIR_COST = 2
// Default value for level cost per unit repair // Default value for level cost per unit repair
const val DEFAULT_UNIT_REPAIR_COST = 1 const val DEFAULT_UNIT_REPAIR_COST = 1
// Default value for level cost on item renaming // Default value for level cost on item renaming
const val DEFAULT_ITEM_RENAME_COST = 1 const val DEFAULT_ITEM_RENAME_COST = 1
// Default value for level cost on illegal enchantment on sacrifice // Default value for level cost on illegal enchantment on sacrifice
const val DEFAULT_SACRIFICE_ILLEGAL_COST = 1 const val DEFAULT_SACRIFICE_ILLEGAL_COST = 1
// Valid range for repair cost limit // Valid range for repair cost limit
@JvmField @JvmField
val REPAIR_LIMIT_RANGE = 1..39 val REPAIR_LIMIT_RANGE = 1..39
// Valid range for repair cost // Valid range for repair cost
@JvmField @JvmField
val REPAIR_COST_RANGE = 0..255 val REPAIR_COST_RANGE = 0..255
// Valid range for rename cost // Valid range for rename cost
@JvmField @JvmField
val ITEM_RENAME_COST_RANGE = 0..255 val ITEM_RENAME_COST_RANGE = 0..255
// Valid range for illegal enchantment conflict cost // Valid range for illegal enchantment conflict cost
@JvmField @JvmField
val SACRIFICE_ILLEGAL_COST_RANGE = 0..255 val SACRIFICE_ILLEGAL_COST_RANGE = 0..255
// Default for removing repair cost limits // Default for removing repair cost limits
const val DEFAULT_REMOVE_LIMIT = false const val DEFAULT_REMOVE_LIMIT = false
// Valid range for an enchantment limit // Valid range for an enchantment limit
@JvmField @JvmField
val ENCHANT_LIMIT_RANGE = 1..255 val ENCHANT_LIMIT_RANGE = 1..255
// Default value for an enchantment multiplier // Default value for an enchantment multiplier
private const val DEFAULT_ENCHANT_VALUE = 0 private const val DEFAULT_ENCHANT_VALUE = 0
// Default value for debug logging // Default value for debug logging
private const val DEFAULT_DEBUG_LOG = false private const val DEFAULT_DEBUG_LOG = false
// Default value for debug logging
private const val DEFAULT_VERBOSE_DEBUG_LOG = false
/** /**
* Default enchantment limit * Default enchantment limit
*/ */
@ -151,6 +182,7 @@ object ConfigOptions {
.takeIf { it in SACRIFICE_ILLEGAL_COST_RANGE } .takeIf { it in SACRIFICE_ILLEGAL_COST_RANGE }
?: DEFAULT_SACRIFICE_ILLEGAL_COST ?: DEFAULT_SACRIFICE_ILLEGAL_COST
} }
/** /**
* Whether to remove repair cost limit * Whether to remove repair cost limit
*/ */
@ -171,6 +203,16 @@ object ConfigOptions {
.getBoolean(DEBUG_LOGGING, DEFAULT_DEBUG_LOG) .getBoolean(DEBUG_LOGGING, DEFAULT_DEBUG_LOG)
} }
/**
* Whether to show verbose debug logging
*/
val verboseDebugLog: Boolean
get() {
return ConfigHolder.DEFAULT_CONFIG
.config
.getBoolean(VERBOSE_DEBUG_LOGGING, DEFAULT_VERBOSE_DEBUG_LOG)
}
/** /**
* Get the given [enchantment]'s limit * Get the given [enchantment]'s limit
*/ */
@ -204,7 +246,8 @@ object ConfigOptions {
* Get an array of key of basic config options * Get an array of key of basic config options
*/ */
fun getBasicConfigKeys(): Array<String> { fun getBasicConfigKeys(): Array<String> {
return arrayOf(DEFAULT_LIMIT_PATH, return arrayOf(
DEFAULT_LIMIT_PATH,
LIMIT_REPAIR_COST, LIMIT_REPAIR_COST,
LIMIT_REPAIR_VALUE, LIMIT_REPAIR_VALUE,
ITEM_REPAIR_COST, ITEM_REPAIR_COST,

View file

@ -32,10 +32,14 @@ object EnchantmentUtil {
other.forEach { (enchantment, level) -> other.forEach { (enchantment, level) ->
// Enchantment not yet in result list // Enchantment not yet in result list
if (!containsKey(enchantment)) { if (!containsKey(enchantment)) {
// Add the enchantment if it doesn't have conflicts, or, if player is allowed to bypass enchantment restrictions // Add the enchantment if it doesn't have conflicts, or if player is allowed to bypass enchantment restrictions
this[enchantment] = level this[enchantment] = level
val conflictType =
ConfigHolder.CONFLICT_HOLDER.conflictManager.isConflicting(this.keys, mat, enchantment)
if (!player.hasPermission(CustomAnvil.bypassFusePermission) && if (!player.hasPermission(CustomAnvil.bypassFusePermission) &&
(ConfigHolder.CONFLICT_HOLDER.conflictManager.isConflicting(this.keys,mat,enchantment) != ConflictType.NO_CONFLICT)){ (conflictType != ConflictType.NO_CONFLICT)
) {
CustomAnvil.verboseLog("Enchantment not yet in result list, but there is conflict (${enchantment.key}, conflict: $conflictType)")
this.remove(enchantment) this.remove(enchantment)
} }
@ -43,8 +47,12 @@ object EnchantmentUtil {
// Enchantment already in result list // Enchantment already in result list
else { else {
// ... and they are conflicting // ... and they are conflicting
if((ConfigHolder.CONFLICT_HOLDER.conflictManager.isConflicting(this.keys,mat,enchantment) != ConflictType.NO_CONFLICT) val conflictType =
&& !player.hasPermission(CustomAnvil.bypassFusePermission)){ ConfigHolder.CONFLICT_HOLDER.conflictManager.isConflicting(this.keys, mat, enchantment)
if ((conflictType != ConflictType.NO_CONFLICT)
&& !player.hasPermission(CustomAnvil.bypassFusePermission)
) {
CustomAnvil.verboseLog("Enchantment already in result list, and they are conflicting (${enchantment.key}, conflict: $conflictType)")
return@forEach return@forEach
} }
@ -52,7 +60,10 @@ object EnchantmentUtil {
if (this[enchantment] != other[enchantment]) { if (this[enchantment] != other[enchantment]) {
val newLevel = max(this[enchantment] ?: 0, other[enchantment] ?: 0) val newLevel = max(this[enchantment] ?: 0, other[enchantment] ?: 0)
// apply the greater of the two if non-zero // apply the greater of the two if non-zero
if (newLevel > 0) { this[enchantment] = newLevel }
if (newLevel > 0) {
this[enchantment] = newLevel
}
} }
// ... and they're the same level // ... and they're the same level
else { else {
@ -65,7 +76,9 @@ object EnchantmentUtil {
ConfigOptions.enchantLimit(enchantment) ConfigOptions.enchantLimit(enchantment)
} }
newLevel = min(newLevel, maxLevel) newLevel = min(newLevel, maxLevel)
if (newLevel > 0) { this[enchantment] = newLevel } if (newLevel > 0) {
this[enchantment] = newLevel
}
} }
} }
} }

View file

@ -5,7 +5,7 @@ import org.bukkit.command.Command
import org.bukkit.command.CommandExecutor import org.bukkit.command.CommandExecutor
import org.bukkit.command.CommandSender import org.bukkit.command.CommandSender
import org.bukkit.entity.HumanEntity import org.bukkit.entity.HumanEntity
import xyz.alexcrea.cuanvil.gui.MainConfigGui import xyz.alexcrea.cuanvil.gui.config.global.MainConfigGui
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions import xyz.alexcrea.cuanvil.gui.util.GuiGlobalActions
class EditConfigExecutor : CommandExecutor { class EditConfigExecutor : CommandExecutor {

View file

@ -5,9 +5,10 @@ import org.bukkit.command.Command
import org.bukkit.command.CommandExecutor import org.bukkit.command.CommandExecutor
import org.bukkit.command.CommandSender import org.bukkit.command.CommandSender
import xyz.alexcrea.cuanvil.config.ConfigHolder import xyz.alexcrea.cuanvil.config.ConfigHolder
import xyz.alexcrea.cuanvil.gui.config.BasicConfigGui import xyz.alexcrea.cuanvil.gui.config.global.BasicConfigGui
import xyz.alexcrea.cuanvil.gui.config.EnchantCostConfigGui import xyz.alexcrea.cuanvil.gui.config.global.EnchantConflictGui
import xyz.alexcrea.cuanvil.gui.config.EnchantLimitConfigGui import xyz.alexcrea.cuanvil.gui.config.global.EnchantCostConfigGui
import xyz.alexcrea.cuanvil.gui.config.global.EnchantLimitConfigGui
import xyz.alexcrea.cuanvil.util.MetricsUtil import xyz.alexcrea.cuanvil.util.MetricsUtil
class ReloadExecutor : CommandExecutor { class ReloadExecutor : CommandExecutor {
@ -41,6 +42,7 @@ class ReloadExecutor : CommandExecutor {
BasicConfigGui.INSTANCE.updateGuiValues() BasicConfigGui.INSTANCE.updateGuiValues()
EnchantCostConfigGui.INSTANCE.updateGuiValues() EnchantCostConfigGui.INSTANCE.updateGuiValues()
EnchantLimitConfigGui.INSTANCE.updateGuiValues() EnchantLimitConfigGui.INSTANCE.updateGuiValues()
EnchantConflictGui.INSTANCE.reloadValues()
// & update metric // & update metric
MetricsUtil.testIfConfigIsDefault() MetricsUtil.testIfConfigIsDefault()

View file

@ -14,8 +14,8 @@ abstract class AbstractMaterialGroup(private val name: String) {
/** /**
* Get if a material is allowed following the group policy * Get if a material is allowed following the group policy
*/ */
fun contain(mat : Material): Boolean { open fun contain(mat: Material): Boolean {
return mat in includedMaterial return mat in getMaterials()
} }
/** /**
@ -33,18 +33,59 @@ abstract class AbstractMaterialGroup(private val name: String) {
*/ */
abstract fun addToPolicy(other: AbstractMaterialGroup) abstract fun addToPolicy(other: AbstractMaterialGroup)
/**
* Get the group contained material as a set
*/
abstract fun getMaterials(): EnumSet<Material>
/**
* Get the group non-inherited material as a set
*/
open fun getNonGroupInheritedMaterials(): EnumSet<Material> {
return includedMaterial
}
/**
* Get the group non-inherited material as a set
*/
open fun setNonGroupInheritedMaterials(materials: EnumSet<Material>) {
this.includedMaterial.clear()
this.includedMaterial.addAll(materials)
}
/** /**
* Get the group name in case something is wrong * Get the group name in case something is wrong
*/ */
fun getName(): String { open fun getName(): String {
return name return name
} }
/** /**
* Get the group as a set * Update the contained groups of this group
*/ */
fun getSet(): Set<Material> { abstract fun setGroups(groups: MutableSet<AbstractMaterialGroup>)
return includedMaterial
/**
* Get the contained group of this material group
*/
abstract fun getGroups(): MutableSet<AbstractMaterialGroup>
open fun getRepresentativeMaterial(): Material {
// Test inner material
val matIterator = includedMaterial.iterator()
while (matIterator.hasNext()) {
val material = matIterator.next()
if (material.isAir) continue
return material
}
// Test included group representative material
val groupIterator = getGroups().iterator()
while (groupIterator.hasNext()) {
val groupMat = groupIterator.next().getRepresentativeMaterial()
if (groupMat.isAir) continue
return groupMat
}
return Material.PAPER
} }
} }

View file

@ -1,15 +1,21 @@
package xyz.alexcrea.cuanvil.group package xyz.alexcrea.cuanvil.group
import io.delilaheve.CustomAnvil
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.enchantments.Enchantment import org.bukkit.enchantments.Enchantment
class EnchantConflictGroup(private val cantConflict: AbstractMaterialGroup, private val minBeforeBlock: Int){ class EnchantConflictGroup(
val name: String,
private val cantConflict: AbstractMaterialGroup,
val minBeforeBlock: Int
) {
private val enchantments = HashSet<Enchantment>() private val enchantments = HashSet<Enchantment>()
fun addEnchantment(ench: Enchantment){ fun addEnchantment(enchant: Enchantment) {
enchantments.add(ench) enchantments.add(enchant)
} }
fun allowed(enchants: Set<Enchantment>, mat: Material): Boolean { fun allowed(enchants: Set<Enchantment>, mat: Material): Boolean {
if (enchantments.size < minBeforeBlock) { if (enchantments.size < minBeforeBlock) {
return true return true
@ -23,6 +29,7 @@ class EnchantConflictGroup(private val cantConflict: AbstractMaterialGroup, priv
var enchantAmount = 0 var enchantAmount = 0
for (enchantment in enchants) { for (enchantment in enchants) {
if (enchantment !in enchantments) continue if (enchantment !in enchantments) continue
CustomAnvil.verboseLog("Enchant ${enchantment.key} is in: ${enchantAmount + 1}/$minBeforeBlock ")
if (++enchantAmount > minBeforeBlock) { if (++enchantAmount > minBeforeBlock) {
return false return false
} }
@ -31,8 +38,28 @@ class EnchantConflictGroup(private val cantConflict: AbstractMaterialGroup, priv
return true return true
} }
fun getCantConflictGroup(): AbstractMaterialGroup {
return this.cantConflict
}
fun getEnchants(): HashSet<Enchantment> { fun getEnchants(): HashSet<Enchantment> {
return enchantments return enchantments
} }
fun setEnchants(enchants: Set<Enchantment>) {
enchantments.clear()
enchantments.addAll(enchants)
}
fun getRepresentativeMaterial(): Material {
val groups = getCantConflictGroup().getGroups()
val groupIterator = groups.iterator()
while (groupIterator.hasNext()) {
val mat = groupIterator.next().getRepresentativeMaterial()
if (mat != Material.ENCHANTED_BOOK) return mat
}
return Material.ENCHANTED_BOOK
}
} }

View file

@ -10,34 +10,37 @@ class EnchantConflictManager {
companion object { companion object {
// Path for the enchantments list // Path for the enchantments list
private const val ENCH_LIST_PATH = "enchantments" const val ENCH_LIST_PATH = "enchantments"
// Path for group list related to the conflict // Path for group list related to the conflict
private const val CONFLICT_GROUP_PATH = "notAffectedGroups" const val CONFLICT_GROUP_PATH = "notAffectedGroups"
// Path for the maximum number of enchantment before validating the conflict // Path for the maximum number of enchantment before validating the conflict
private const val ENCH_MAX_PATH = "maxEnchantmentBeforeConflict" const val ENCH_MAX_PATH = "maxEnchantmentBeforeConflict"
// Path for a flag: if the enchantment will be used in the last supported version // Path for a flag: if the enchantment will be used in the last supported version
// TODO maybe replace this system by a list of "future" enchantment. // TODO maybe replace this system by a list of "future" enchantment.
private const val FUTURE_USE_PATH = "useInFuture" private const val FUTURE_USE_PATH = "useInFuture"
// Default name for an empty Material group
private val DEFAULT_EMPTY_GROUP = IncludeGroup("empty")
// Default name for a joining group // Default name for a joining group
private const val DEFAULT_GROUP_NAME = "joinedGroup" private const val DEFAULT_GROUP_NAME = "joinedGroup"
} }
private lateinit var conflictMap: HashMap<Enchantment, ArrayList<EnchantConflictGroup>> private lateinit var conflictMap: HashMap<Enchantment, ArrayList<EnchantConflictGroup>>
lateinit var conflictList: ArrayList<EnchantConflictGroup>
// Read and prepare all conflict // Read and prepare all conflict
fun prepareConflicts(config: ConfigurationSection, itemManager: ItemGroupManager) { fun prepareConflicts(config: ConfigurationSection, itemManager: ItemGroupManager) {
conflictMap = HashMap() conflictMap = HashMap()
conflictList = ArrayList()
val keys = config.getKeys(false) val keys = config.getKeys(false)
for (key in keys) { for (key in keys) {
val section = config.getConfigurationSection(key)!! val section = config.getConfigurationSection(key)!!
val conflict = createConflict(section, itemManager, key) val conflict = createConflict(section, itemManager, key)
if(conflict != null){
addToMap(conflict)
}
addToMap(conflict)
conflictList.add(conflict)
} }
} }
@ -45,17 +48,27 @@ class EnchantConflictManager {
// Add the conflict to the map // Add the conflict to the map
private fun addToMap(conflict: EnchantConflictGroup) { private fun addToMap(conflict: EnchantConflictGroup) {
conflict.getEnchants().forEach { enchant -> conflict.getEnchants().forEach { enchant ->
addConflictToConflictMap(enchant, conflict)
}
}
fun addConflictToConflictMap(enchant: Enchantment, conflict: EnchantConflictGroup) {
if (!conflictMap.containsKey(enchant)) { if (!conflictMap.containsKey(enchant)) {
conflictMap[enchant] = ArrayList() conflictMap[enchant] = ArrayList()
} }
conflictMap[enchant]!!.add(conflict) conflictMap[enchant]!!.add(conflict)
} }
fun removeConflictFromMap(enchant: Enchantment, conflict: EnchantConflictGroup): Boolean {
return conflictMap[enchant]!!.remove(conflict)
} }
// create and read a conflict from a yaml section // create and read a conflict from a yaml section
private fun createConflict(section: ConfigurationSection, private fun createConflict(
section: ConfigurationSection,
itemManager: ItemGroupManager, itemManager: ItemGroupManager,
conflictName: String): EnchantConflictGroup? { conflictName: String
): EnchantConflictGroup {
// Is it planed for the future // Is it planed for the future
val futureUse = section.getBoolean(FUTURE_USE_PATH, false) val futureUse = section.getBoolean(FUTURE_USE_PATH, false)
// Create conflict // Create conflict
@ -75,17 +88,18 @@ class EnchantConflictManager {
} }
if (conflict.getEnchants().size == 0) { if (conflict.getEnchants().size == 0) {
if (!futureUse) { if (!futureUse) {
CustomAnvil.instance.logger.warning("Conflict $conflictName do not have valid enchantment, it will not work") CustomAnvil.instance.logger.warning("Conflict $conflictName do not have valid enchantment, it will not do anything")
} }
return null
} }
return conflict return conflict
} }
private fun createConflictObject(section: ConfigurationSection, private fun createConflictObject(
section: ConfigurationSection,
itemManager: ItemGroupManager, itemManager: ItemGroupManager,
conflictName: String): EnchantConflictGroup { conflictName: String
): EnchantConflictGroup {
// Get the maximum number of enchantment before validating the conflict // Get the maximum number of enchantment before validating the conflict
var minBeforeBlock = section.getInt(ENCH_MAX_PATH, 0) var minBeforeBlock = section.getInt(ENCH_MAX_PATH, 0)
if (minBeforeBlock < 0) { if (minBeforeBlock < 0) {
@ -95,39 +109,43 @@ class EnchantConflictManager {
} }
// Find or create the selected group for the conflict // Find or create the selected group for the conflict
val groupList = section.getStringList(CONFLICT_GROUP_PATH) val groupList = section.getStringList(CONFLICT_GROUP_PATH)
val finalGroup: AbstractMaterialGroup val finalGroup = IncludeGroup(DEFAULT_GROUP_NAME)
if(groupList.size < 1){
finalGroup = DEFAULT_EMPTY_GROUP
}else if(groupList.size == 1){
finalGroup = findGroup(groupList[0], itemManager, conflictName)
}else{
finalGroup = IncludeGroup(DEFAULT_GROUP_NAME)
for (groupName in groupList) { for (groupName in groupList) {
finalGroup.addToPolicy(findGroup(groupName, itemManager, conflictName)) finalGroup.addToPolicy(findGroup(groupName, itemManager, conflictName))
} }
}
// Return conflict // Return conflict
return EnchantConflictGroup(finalGroup, minBeforeBlock) return EnchantConflictGroup(conflictName, finalGroup, minBeforeBlock)
} }
private fun findGroup(groupName: String, itemManager: ItemGroupManager, conflictName: String): AbstractMaterialGroup { private fun findGroup(
groupName: String,
itemManager: ItemGroupManager,
conflictName: String
): AbstractMaterialGroup {
val group = itemManager.get(groupName) val group = itemManager.get(groupName)
if (group == null) { if (group == null) {
CustomAnvil.instance.logger.warning("Group $groupName do not exist but is ask by conflict $conflictName") CustomAnvil.instance.logger.warning("Group $groupName do not exist but is ask by conflict $conflictName")
return DEFAULT_EMPTY_GROUP return IncludeGroup("error_placeholder")
} }
return group return group
} }
fun isConflicting(base: Set<Enchantment>, mat: Material, newEnchant: Enchantment): ConflictType { fun isConflicting(base: Set<Enchantment>, mat: Material, newEnchant: Enchantment): ConflictType {
CustomAnvil.verboseLog("Testing conflict for ${newEnchant.key} on ${mat.key}")
val conflictList = conflictMap[newEnchant] ?: return ConflictType.NO_CONFLICT val conflictList = conflictMap[newEnchant] ?: return ConflictType.NO_CONFLICT
CustomAnvil.verboseLog("Did not get skipped")
var result = ConflictType.NO_CONFLICT var result = ConflictType.NO_CONFLICT
for (conflict in conflictList) { for (conflict in conflictList) {
if(!conflict.allowed(base,mat)) { CustomAnvil.verboseLog("Is against ${conflict.name}")
val conflicting = conflict.allowed(base, mat)
CustomAnvil.verboseLog("Was against ${conflict.name} and conflicting: $conflicting ")
if (!conflicting) {
if (conflict.getEnchants().size <= 1) { if (conflict.getEnchants().size <= 1) {
result = ConflictType.SMALL_CONFLICT result = ConflictType.SMALL_CONFLICT
CustomAnvil.verboseLog("Small conflict, continuing")
} else { } else {
return ConflictType.BIG_CONFLICT return ConflictType.BIG_CONFLICT
} }

View file

@ -8,7 +8,8 @@ class ExcludeGroup(name: String): AbstractMaterialGroup(name) {
return EnumSet.allOf(Material::class.java) return EnumSet.allOf(Material::class.java)
} }
private val includedGroup = HashSet<AbstractMaterialGroup>() private var includedGroup: MutableSet<AbstractMaterialGroup> = HashSet()
private val groupItems by lazy { createDefaultSet() }
override fun isReferencing(other: AbstractMaterialGroup): Boolean { override fun isReferencing(other: AbstractMaterialGroup): Boolean {
for (materialGroup in includedGroup.iterator()) { for (materialGroup in includedGroup.iterator()) {
@ -21,11 +22,33 @@ class ExcludeGroup(name: String): AbstractMaterialGroup(name) {
override fun addToPolicy(mat: Material) { override fun addToPolicy(mat: Material) {
includedMaterial.remove(mat) includedMaterial.remove(mat)
groupItems.remove(mat)
} }
override fun addToPolicy(other: AbstractMaterialGroup) { override fun addToPolicy(other: AbstractMaterialGroup) {
includedGroup.add(other) includedGroup.add(other)
includedMaterial.removeAll(other.getSet()) groupItems.removeAll(other.getMaterials())
}
override fun setGroups(groups: MutableSet<AbstractMaterialGroup>) {
groupItems.clear()
groupItems.addAll(includedMaterial)
includedGroup.clear()
groups.forEach { group ->
if (!group.isReferencing(this)) {
includedGroup.add(group)
groupItems.removeAll(group.getMaterials())
}
}
}
override fun getGroups(): MutableSet<AbstractMaterialGroup> {
return includedGroup
}
override fun getMaterials(): EnumSet<Material> {
return groupItems
} }

View file

@ -8,7 +8,8 @@ class IncludeGroup(name: String): AbstractMaterialGroup(name) {
return EnumSet.noneOf(Material::class.java) return EnumSet.noneOf(Material::class.java)
} }
private val includedGroup = HashSet<AbstractMaterialGroup>() private var includedGroup: MutableSet<AbstractMaterialGroup> = HashSet()
private val groupItems by lazy { createDefaultSet() }
override fun isReferencing(other: AbstractMaterialGroup): Boolean { override fun isReferencing(other: AbstractMaterialGroup): Boolean {
for (materialGroup in includedGroup.iterator()) { for (materialGroup in includedGroup.iterator()) {
@ -21,11 +22,45 @@ class IncludeGroup(name: String): AbstractMaterialGroup(name) {
override fun addToPolicy(mat: Material) { override fun addToPolicy(mat: Material) {
includedMaterial.add(mat) includedMaterial.add(mat)
groupItems.add(mat)
} }
override fun addToPolicy(other: AbstractMaterialGroup) { override fun addToPolicy(other: AbstractMaterialGroup) {
includedGroup.add(other) includedGroup.add(other)
includedMaterial.addAll(other.getSet()) groupItems.addAll(other.getMaterials())
} }
override fun setGroups(groups: MutableSet<AbstractMaterialGroup>) {
groupItems.clear()
groupItems.addAll(includedMaterial)
includedGroup.clear()
groups.forEach { group ->
if (!group.isReferencing(this)) {
includedGroup.add(group)
groupItems.addAll(group.getMaterials())
}
}
}
override fun setNonGroupInheritedMaterials(materials: EnumSet<Material>) {
super.setNonGroupInheritedMaterials(materials)
// Update group items
groupItems.clear()
groupItems.addAll(includedMaterial)
includedGroup.forEach { group ->
groupItems.addAll(group.getMaterials())
}
}
override fun getGroups(): MutableSet<AbstractMaterialGroup> {
return includedGroup
}
override fun getMaterials(): EnumSet<Material> {
return groupItems
}
} }

View file

@ -10,19 +10,22 @@ class ItemGroupManager {
companion object { companion object {
// Path for group type // Path for group type
private const val GROUP_TYPE_PATH = "type" private const val GROUP_TYPE_PATH = "type"
// Path for included items list // Path for included items list
private const val MATERIAL_LIST_PATH = "items" private const val MATERIAL_LIST_PATH = "items"
// Path for included groups list // Path for included groups list
private const val GROUP_LIST_PATH = "groups" private const val GROUP_LIST_PATH = "groups"
// Temporary list of elements in default config that are use in future // Temporary list of elements in default config that are use in future
private val FUTURE_MATERIAL = setOf("PIGLIN_HEAD", "BRUSH") private val FUTURE_MATERIAL = setOf("PIGLIN_HEAD", "BRUSH")
} }
private lateinit var groupMap : HashMap<String, AbstractMaterialGroup> lateinit var groupMap: LinkedHashMap<String, AbstractMaterialGroup>
// Read and create material groups // Read and create material groups
fun prepareGroups(config: ConfigurationSection) { fun prepareGroups(config: ConfigurationSection) {
groupMap = HashMap() groupMap = LinkedHashMap()
val keys = config.getKeys(false) val keys = config.getKeys(false)
for (key in keys) { for (key in keys) {
@ -33,9 +36,11 @@ class ItemGroupManager {
} }
// Create group by key // Create group by key
private fun createGroup(config: ConfigurationSection, private fun createGroup(
config: ConfigurationSection,
keys: Set<String>, keys: Set<String>,
key: String): AbstractMaterialGroup { key: String
): AbstractMaterialGroup {
val groupSection = config.getConfigurationSection(key)!! val groupSection = config.getConfigurationSection(key)!!
val groupType = groupSection.getString(GROUP_TYPE_PATH, null) val groupType = groupSection.getString(GROUP_TYPE_PATH, null)
@ -56,10 +61,12 @@ class ItemGroupManager {
} }
// Read Group elements // Read Group elements
private fun readGroup(group: AbstractMaterialGroup, private fun readGroup(
group: AbstractMaterialGroup,
groupSection: ConfigurationSection, groupSection: ConfigurationSection,
config: ConfigurationSection, config: ConfigurationSection,
keys: Set<String>){ keys: Set<String>
) {
// Read material to include in this group policy // Read material to include in this group policy
val materialList = groupSection.getStringList(MATERIAL_LIST_PATH) val materialList = groupSection.getStringList(MATERIAL_LIST_PATH)
for (materialTemp in materialList) { for (materialTemp in materialList) {
@ -69,7 +76,8 @@ class ItemGroupManager {
// Check if we should warn the user // Check if we should warn the user
if (materialName !in FUTURE_MATERIAL) { if (materialName !in FUTURE_MATERIAL) {
CustomAnvil.instance.logger.warning( CustomAnvil.instance.logger.warning(
"Unknown material $materialTemp on group ${group.getName()}") "Unknown material $materialTemp on group ${group.getName()}"
)
} }
continue continue
@ -83,7 +91,8 @@ class ItemGroupManager {
for (groupName in groupList) { for (groupName in groupList) {
if (groupName !in keys) { if (groupName !in keys) {
CustomAnvil.instance.logger.warning( CustomAnvil.instance.logger.warning(
"Group $groupName do not exist but is included in group ${group.getName()}") "Group $groupName do not exist but is included in group ${group.getName()}"
)
continue continue
} }
// Get other group or create it if not yet created // Get other group or create it if not yet created
@ -95,9 +104,11 @@ class ItemGroupManager {
// Avoid self reference or it will create an infinite loop // Avoid self reference or it will create an infinite loop
if (otherGroup.isReferencing(group)) { if (otherGroup.isReferencing(group)) {
CustomAnvil.instance.logger.warning( CustomAnvil.instance.logger.warning(
"Group $groupName is on a reference loop with group ${group.getName()} !") "Group $groupName is on a reference loop with group ${group.getName()} !"
)
CustomAnvil.instance.logger.warning( CustomAnvil.instance.logger.warning(
"Please fix it in your item_groups config or the plugin will probably not work as expected.") "Please fix it in your item_groups config or the plugin will probably not work as expected."
)
continue continue
} }

View file

@ -0,0 +1,47 @@
package xyz.alexcrea.cuanvil.listener
import io.delilaheve.CustomAnvil
import org.bukkit.Bukkit
import org.bukkit.entity.HumanEntity
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.player.AsyncPlayerChatEvent
import org.bukkit.event.player.PlayerQuitEvent
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.function.Consumer
class ChatEventListener : Listener {
private val playerListenMap: ConcurrentHashMap<UUID, Consumer<String?>> = ConcurrentHashMap()
fun setListenedCallback(playeruuid: UUID, callback: Consumer<String?>) {
playerListenMap[playeruuid] = callback
}
fun setListenedCallback(player: HumanEntity, callback: Consumer<String?>) {
setListenedCallback(player.uniqueId, callback)
}
@EventHandler
fun onQuit(event: PlayerQuitEvent) {
val eventCallback = playerListenMap.remove(event.player.uniqueId) ?: return
eventCallback.accept(null)
}
@EventHandler
fun onChat(event: AsyncPlayerChatEvent) {
if (event.isCancelled) return
val player = event.player
val eventCallback = playerListenMap.remove(player.uniqueId) ?: return
event.isCancelled = true
// sync callback with default server thread
Bukkit.getScheduler().runTask(CustomAnvil.instance, Runnable {
eventCallback.accept(event.message)
})
}
}

View file

@ -31,12 +31,11 @@ object MetricsUtil {
*/ */
private fun getHashFromKey(section: ConfigurationSection, key: String): Int { private fun getHashFromKey(section: ConfigurationSection, key: String): Int {
// Key is assumend to exist // Key is assumend to exist
val resultHash: Int val resultHash = if (section.isConfigurationSection(key)) {
if(section.isConfigurationSection(key)){
val sectionResult = getConfigurationHash(section.getConfigurationSection(key)!!) val sectionResult = getConfigurationHash(section.getConfigurationSection(key)!!)
resultHash = key.hashCode() xor sectionResult key.hashCode() xor sectionResult
} else { } else {
resultHash = key.hashCode() xor section.getString(key).hashCode() key.hashCode() xor section.getString(key).hashCode()
} }
return resultHash.hashCode() return resultHash.hashCode()
} }
@ -83,12 +82,24 @@ object MetricsUtil {
isDefaultUnitRepairItemConfig = unitRepairItemConfigHash == unitRepairConfig isDefaultUnitRepairItemConfig = unitRepairItemConfigHash == unitRepairConfig
// If not default and debug flag active, print the hash. // If not default and debug flag active, print the hash.
if (ConfigOptions.debugLog) { if (ConfigOptions.debugLog) {
if(!isDefaultBaseConfig){CustomAnvil.log("baseConfig: $baseConfig")} if (!isDefaultBaseConfig) {
if(!isDefaultEnchantLimitsConfig){CustomAnvil.log("limitEnchantConfig: $limitEnchantConfig")} CustomAnvil.log("baseConfig: $baseConfig")
if(!isDefaultEnchantValuesConfig){CustomAnvil.log("enchantValueConfig: $enchantValueConfig")} }
if(!isDefaultEnchantConflictConfig){CustomAnvil.log("enchantConflictConfig: $enchantConflictConfig")} if (!isDefaultEnchantLimitsConfig) {
if(!isDefaultItemGroupsConfig){CustomAnvil.log("itemGroupConfig: $itemGroupConfig")} CustomAnvil.log("limitEnchantConfig: $limitEnchantConfig")
if(!isDefaultUnitRepairItemConfig){CustomAnvil.log("unitRepairConfig: $unitRepairConfig")} }
if (!isDefaultEnchantValuesConfig) {
CustomAnvil.log("enchantValueConfig: $enchantValueConfig")
}
if (!isDefaultEnchantConflictConfig) {
CustomAnvil.log("enchantConflictConfig: $enchantConflictConfig")
}
if (!isDefaultItemGroupsConfig) {
CustomAnvil.log("itemGroupConfig: $itemGroupConfig")
}
if (!isDefaultUnitRepairItemConfig) {
CustomAnvil.log("unitRepairConfig: $unitRepairConfig")
}
} }
} }
@ -96,18 +107,18 @@ object MetricsUtil {
fun notifyChange(holder: ConfigHolder, path: String) { fun notifyChange(holder: ConfigHolder, path: String) {
if (ConfigHolder.DEFAULT_CONFIG.equals(holder)) { if (ConfigHolder.DEFAULT_CONFIG.equals(holder)) {
if (path.startsWith(ConfigOptions.ENCHANT_LIMIT_ROOT + ".")) { if (path.startsWith(ConfigOptions.ENCHANT_LIMIT_ROOT + ".")) {
isDefaultEnchantLimitsConfig = false; isDefaultEnchantLimitsConfig = false
} else if (path.startsWith(ConfigOptions.ENCHANT_VALUES_ROOT + ".")) { } else if (path.startsWith(ConfigOptions.ENCHANT_VALUES_ROOT + ".")) {
isDefaultEnchantValuesConfig = false; isDefaultEnchantValuesConfig = false
} else { } else {
isDefaultBaseConfig = false; isDefaultBaseConfig = false
} }
} else if (ConfigHolder.CONFLICT_HOLDER.equals(holder)) { } else if (ConfigHolder.CONFLICT_HOLDER.equals(holder)) {
isDefaultEnchantConflictConfig = false; isDefaultEnchantConflictConfig = false
} else if (ConfigHolder.ITEM_GROUP_HOLDER.equals(holder)) { } else if (ConfigHolder.ITEM_GROUP_HOLDER.equals(holder)) {
isDefaultItemGroupsConfig = false; isDefaultItemGroupsConfig = false
} else if (ConfigHolder.UNIT_REPAIR_HOLDER.equals(holder)) { } else if (ConfigHolder.UNIT_REPAIR_HOLDER.equals(holder)) {
isDefaultUnitRepairItemConfig = false; isDefaultUnitRepairItemConfig = false
} }
} }

View file

@ -8,6 +8,7 @@ object UnitRepairUtil {
// Default value for user set default unit repair % // Default value for user set default unit repair %
private const val DEFAULT_DEFAULT_UNIT_REPAIR = 0.25 private const val DEFAULT_DEFAULT_UNIT_REPAIR = 0.25
// Path to user default unit repair value // Path to user default unit repair value
private const val UNIT_REPAIR_DEFAULT_PATH = "default_repair_amount" private const val UNIT_REPAIR_DEFAULT_PATH = "default_repair_amount"

View file

@ -220,3 +220,6 @@ enchant_values:
# Whether to show debug logging # Whether to show debug logging
debug_log: false debug_log: false
# Whether to show verbose debug logging
debug_log_verbose: false

View file

@ -232,3 +232,7 @@ crossbow_conflict:
notAffectedGroups: [ ] notAffectedGroups: [ ]
maxEnchantmentBeforeConflict: 1 maxEnchantmentBeforeConflict: 1
# ----------------------------------------------------
# Bellow is for custom conflicts.
# This is also where conflict create from the gui will be placed.
# ----------------------------------------------------

View file

@ -1,7 +1,7 @@
main: io.delilaheve.CustomAnvil main: io.delilaheve.CustomAnvil
name: CustomAnvil name: CustomAnvil
prefix: "Custom Anvil" prefix: "Custom Anvil"
version: 1.3.2-A1 version: 1.3.2-A2
description: Allow to customise anvil mechanics description: Allow to customise anvil mechanics
api-version: 1.18 api-version: 1.18
load: POSTWORLD load: POSTWORLD