mirror of
https://github.com/BentoBoxWorld/BentoBox.git
synced 2024-09-29 15:17:29 +02:00
Panel template (#1841)
* Implement basic functionality to read data from template panels. Create TemplateReader class that has static method which generates a PanelTemplateRecord. This record contains every necessary information from user created template file so everyone could use it to generate a functional panel. These classes are just for reading templates and do not create actual panel. * Add template clearing via bentobox reload command.
This commit is contained in:
parent
faf351fd59
commit
2607256c06
@ -0,0 +1,87 @@
|
|||||||
|
//
|
||||||
|
// Created by BONNe
|
||||||
|
// Copyright - 2021
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
package world.bentobox.bentobox.api.panels.reader;
|
||||||
|
|
||||||
|
|
||||||
|
import org.bukkit.event.inventory.ClickType;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This Record contains all necessary information about Item Template that can be used to craft panel item.
|
||||||
|
*
|
||||||
|
* @param icon ItemStack of the Item
|
||||||
|
* @param title Title of the item
|
||||||
|
* @param description Lore message of the item
|
||||||
|
* @param actions List of Actions for a button
|
||||||
|
* @param dataMap DataMap that links additional objects for a button.
|
||||||
|
* @param fallback FallBack item if current one is not possible to generate.
|
||||||
|
*
|
||||||
|
* @since 1.17.3
|
||||||
|
*/
|
||||||
|
public record ItemTemplateRecord(ItemStack icon,
|
||||||
|
String title,
|
||||||
|
String description,
|
||||||
|
List<ActionRecords> actions,
|
||||||
|
Map<String, Object> dataMap,
|
||||||
|
ItemTemplateRecord fallback)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Instantiates a new Item template record without actions and data map.
|
||||||
|
*
|
||||||
|
* @param icon the icon
|
||||||
|
* @param title the title
|
||||||
|
* @param description the description
|
||||||
|
* @param fallback the fallback
|
||||||
|
*/
|
||||||
|
public ItemTemplateRecord(ItemStack icon, String title, String description, ItemTemplateRecord fallback)
|
||||||
|
{
|
||||||
|
this(icon, title, description, new ArrayList<>(6), new HashMap<>(0), fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method adds given object associated with key into data map.
|
||||||
|
* @param key Key value of object.
|
||||||
|
* @param data Data that is associated with a key.
|
||||||
|
*/
|
||||||
|
public void addData(String key, Object data)
|
||||||
|
{
|
||||||
|
this.dataMap.put(key, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add action to the actions list.
|
||||||
|
*
|
||||||
|
* @param actionData the action data
|
||||||
|
*/
|
||||||
|
public void addAction(ActionRecords actionData)
|
||||||
|
{
|
||||||
|
this.actions.add(actionData);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// Section: Classes
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Action Records holds data about each action.
|
||||||
|
*
|
||||||
|
* @param clickType the click type
|
||||||
|
* @param actionType the string that represents action type
|
||||||
|
* @param content the content of the action
|
||||||
|
* @param tooltip the tooltip of action
|
||||||
|
*/
|
||||||
|
public record ActionRecords(ClickType clickType, String actionType, String content, String tooltip) {}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
//
|
||||||
|
// Created by BONNe
|
||||||
|
// Copyright - 2021
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
package world.bentobox.bentobox.api.panels.reader;
|
||||||
|
|
||||||
|
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import world.bentobox.bentobox.api.panels.Panel;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is template object for the panel reader. It contains data that can exist in the panel.
|
||||||
|
* PanelBuilder will use this to build panel.
|
||||||
|
*
|
||||||
|
* @param type the type of GUI
|
||||||
|
* @param title the title of GUI
|
||||||
|
* @param border the border block for GUI
|
||||||
|
* @param background the background block for GUI.
|
||||||
|
* @param content The 2D array of ItemTemplateRecords
|
||||||
|
*
|
||||||
|
* @since 1.17.3
|
||||||
|
*/
|
||||||
|
public record PanelTemplateRecord(Panel.Type type,
|
||||||
|
String title,
|
||||||
|
TemplateItem border,
|
||||||
|
TemplateItem background,
|
||||||
|
ItemTemplateRecord[][] content)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Instantiates a new Panel template record with empty content.
|
||||||
|
*
|
||||||
|
* @param type the type
|
||||||
|
* @param title the title
|
||||||
|
* @param border the border
|
||||||
|
* @param background the background
|
||||||
|
*/
|
||||||
|
public PanelTemplateRecord(Panel.Type type, String title, TemplateItem border, TemplateItem background)
|
||||||
|
{
|
||||||
|
this(type, title, border, background, new ItemTemplateRecord[6][9]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method adds give item template record in given slot.
|
||||||
|
* @param rowIndex row index of content array
|
||||||
|
* @param columnIndex column index of content array.
|
||||||
|
* @param panelItemTemplate item template record that must be added.
|
||||||
|
*/
|
||||||
|
public void addButtonTemplate(int rowIndex, int columnIndex, ItemTemplateRecord panelItemTemplate)
|
||||||
|
{
|
||||||
|
this.content[rowIndex][columnIndex] = panelItemTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// Section: Classes
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This record contains info about border and background item.
|
||||||
|
*/
|
||||||
|
public record TemplateItem(ItemStack icon, String title, String description)
|
||||||
|
{
|
||||||
|
public TemplateItem(ItemStack icon)
|
||||||
|
{
|
||||||
|
this(icon, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,324 @@
|
|||||||
|
//
|
||||||
|
// Created by BONNe
|
||||||
|
// Copyright - 2021
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
package world.bentobox.bentobox.api.panels.reader;
|
||||||
|
|
||||||
|
|
||||||
|
import com.google.common.base.Enums;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
import org.bukkit.configuration.InvalidConfigurationException;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.bukkit.event.inventory.ClickType;
|
||||||
|
import org.eclipse.jdt.annotation.NonNull;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import world.bentobox.bentobox.api.panels.Panel;
|
||||||
|
import world.bentobox.bentobox.util.ItemParser;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class manages Template file reading, creating PanelTemplateRecord object and storing it internally.
|
||||||
|
* This class just reads and returns given panel template. It does not create a functional panel.
|
||||||
|
*
|
||||||
|
* @since 1.17.3
|
||||||
|
*/
|
||||||
|
public class TemplateReader
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Read template panel panel template record.
|
||||||
|
*
|
||||||
|
* @param panelName the panel name
|
||||||
|
* @param panelLocation the panel location directory
|
||||||
|
* @return the panel template record
|
||||||
|
*/
|
||||||
|
public static PanelTemplateRecord readTemplatePanel(@NonNull String panelName, @NonNull File panelLocation)
|
||||||
|
{
|
||||||
|
if (!panelLocation.exists())
|
||||||
|
{
|
||||||
|
// Return null because folder does not exist.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
File file = new File(panelLocation, panelName.endsWith(".yml") ? panelName : panelName + ".yml");
|
||||||
|
|
||||||
|
if (!file.exists())
|
||||||
|
{
|
||||||
|
// Return as file does not exist.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if panel is already crafted.
|
||||||
|
if (TemplateReader.loadedPanels.containsKey(file.getAbsolutePath()))
|
||||||
|
{
|
||||||
|
return TemplateReader.loadedPanels.get(file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
PanelTemplateRecord record;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Load config
|
||||||
|
YamlConfiguration config = new YamlConfiguration();
|
||||||
|
config.load(file);
|
||||||
|
// Read panel
|
||||||
|
record = readPanelTemplate(config.getConfigurationSection(panelName));
|
||||||
|
// Put panel into memory
|
||||||
|
TemplateReader.loadedPanels.put(file.getAbsolutePath(), record);
|
||||||
|
}
|
||||||
|
catch (IOException | InvalidConfigurationException e)
|
||||||
|
{
|
||||||
|
record = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method reads panel template from given configuration section.
|
||||||
|
* @param configurationSection Section that contains panel template data.
|
||||||
|
* @return Panel Template.
|
||||||
|
*/
|
||||||
|
private static PanelTemplateRecord readPanelTemplate(@Nullable ConfigurationSection configurationSection)
|
||||||
|
{
|
||||||
|
if (configurationSection == null)
|
||||||
|
{
|
||||||
|
// No data to return.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String title = configurationSection.getString("title");
|
||||||
|
Panel.Type type = configurationSection.getObject("type", Panel.Type.class);
|
||||||
|
|
||||||
|
PanelTemplateRecord.TemplateItem borderItem = null;
|
||||||
|
|
||||||
|
// Read Border Icon.
|
||||||
|
if (configurationSection.isConfigurationSection("border"))
|
||||||
|
{
|
||||||
|
// Process border icon if it contains more options.
|
||||||
|
ConfigurationSection borderSection = configurationSection.getConfigurationSection("border");
|
||||||
|
|
||||||
|
if (borderSection != null)
|
||||||
|
{
|
||||||
|
borderItem = new PanelTemplateRecord.TemplateItem(
|
||||||
|
ItemParser.parse((borderSection.getString("icon", Material.AIR.name()))),
|
||||||
|
borderSection.getString("name", null),
|
||||||
|
borderSection.getString("description", null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (configurationSection.isString("border"))
|
||||||
|
{
|
||||||
|
// Process border icon if it contains only icon.
|
||||||
|
|
||||||
|
borderItem = new PanelTemplateRecord.TemplateItem(
|
||||||
|
ItemParser.parse((configurationSection.getString("border", Material.AIR.name()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
PanelTemplateRecord.TemplateItem backgroundItem = null;
|
||||||
|
|
||||||
|
// Read Background block
|
||||||
|
if (configurationSection.isConfigurationSection("background"))
|
||||||
|
{
|
||||||
|
// Process border icon if it contains more options.
|
||||||
|
ConfigurationSection backgroundSection = configurationSection.getConfigurationSection("background");
|
||||||
|
|
||||||
|
if (backgroundSection != null)
|
||||||
|
{
|
||||||
|
backgroundItem = new PanelTemplateRecord.TemplateItem(
|
||||||
|
ItemParser.parse((backgroundSection.getString("icon", Material.AIR.name()))),
|
||||||
|
backgroundSection.getString("name", null),
|
||||||
|
backgroundSection.getString("description", null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (configurationSection.isString("background"))
|
||||||
|
{
|
||||||
|
// Process background icon if it contains only icon.
|
||||||
|
|
||||||
|
backgroundItem = new PanelTemplateRecord.TemplateItem(
|
||||||
|
ItemParser.parse((configurationSection.getString("background", Material.AIR.name()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read reusable
|
||||||
|
Map<String, ItemTemplateRecord> panelItemDataMap = new HashMap<>();
|
||||||
|
ConfigurationSection reusable = configurationSection.getConfigurationSection("reusable");
|
||||||
|
|
||||||
|
if (reusable != null)
|
||||||
|
{
|
||||||
|
// Add all reusables to the local storage.
|
||||||
|
reusable.getKeys(false).forEach(key ->
|
||||||
|
readPanelItemTemplate(reusable.getConfigurationSection(key), key, panelItemDataMap));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create template record.
|
||||||
|
PanelTemplateRecord template = new PanelTemplateRecord(type, title, borderItem, backgroundItem);
|
||||||
|
|
||||||
|
// Read content
|
||||||
|
ConfigurationSection content = configurationSection.getConfigurationSection("content");
|
||||||
|
|
||||||
|
if (content == null)
|
||||||
|
{
|
||||||
|
// Return empty template.
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int rowIndex = 0; rowIndex < 6; rowIndex++)
|
||||||
|
{
|
||||||
|
// Read each line.
|
||||||
|
if (content.isConfigurationSection(String.valueOf(rowIndex + 1)))
|
||||||
|
{
|
||||||
|
ConfigurationSection line = content.getConfigurationSection(String.valueOf(rowIndex + 1));
|
||||||
|
|
||||||
|
if (line != null)
|
||||||
|
{
|
||||||
|
// Populate existing lines with items.
|
||||||
|
for (int columnIndex = 0; columnIndex < 9; columnIndex++)
|
||||||
|
{
|
||||||
|
if (line.isConfigurationSection(String.valueOf(columnIndex + 1)))
|
||||||
|
{
|
||||||
|
// If it contains a section, then build a new button template from it.
|
||||||
|
template.addButtonTemplate(rowIndex,
|
||||||
|
columnIndex,
|
||||||
|
readPanelItemTemplate(line.getConfigurationSection(String.valueOf(columnIndex + 1))));
|
||||||
|
}
|
||||||
|
else if (line.isString(String.valueOf(columnIndex + 1)))
|
||||||
|
{
|
||||||
|
// If it contains just a single word, assume it is a reusable.
|
||||||
|
template.addButtonTemplate(rowIndex,
|
||||||
|
columnIndex,
|
||||||
|
panelItemDataMap.get(line.getString(String.valueOf(columnIndex + 1))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Garbage collector.
|
||||||
|
panelItemDataMap.clear();
|
||||||
|
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method creates PanelItemTemplate from a given configuration section.
|
||||||
|
* @param section Section that should contain all information about the panel item template.
|
||||||
|
* @return PanelItemTemplate that should represent button from a section.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private static ItemTemplateRecord readPanelItemTemplate(@Nullable ConfigurationSection section)
|
||||||
|
{
|
||||||
|
return readPanelItemTemplate(section, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method creates PanelItemTemplate from a given configuration section.
|
||||||
|
* @param section Section that should contain all information about the panel item template.
|
||||||
|
* @return PanelItemTemplate that should represent button from a section.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private static ItemTemplateRecord readPanelItemTemplate(@Nullable ConfigurationSection section,
|
||||||
|
String itemKey,
|
||||||
|
Map<String, ItemTemplateRecord> reusableItemMap)
|
||||||
|
{
|
||||||
|
if (section == null)
|
||||||
|
{
|
||||||
|
// No section, no item.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemTemplateRecord fallback;
|
||||||
|
|
||||||
|
if (section.isConfigurationSection("fallback"))
|
||||||
|
{
|
||||||
|
fallback = readPanelItemTemplate(section.getConfigurationSection("fallback"));
|
||||||
|
}
|
||||||
|
else if (section.isString("fallback") && reusableItemMap != null)
|
||||||
|
{
|
||||||
|
fallback = reusableItemMap.get(section.getString("fallback"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fallback = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Item Record
|
||||||
|
ItemTemplateRecord itemRecord = new ItemTemplateRecord(ItemParser.parse(section.getString("icon")),
|
||||||
|
section.getString("title", null),
|
||||||
|
section.getString("description", null),
|
||||||
|
fallback);
|
||||||
|
|
||||||
|
// Read data
|
||||||
|
if (section.isConfigurationSection("data"))
|
||||||
|
{
|
||||||
|
ConfigurationSection dataSection = section.getConfigurationSection("data");
|
||||||
|
|
||||||
|
if (dataSection != null)
|
||||||
|
{
|
||||||
|
dataSection.getKeys(false).forEach(key -> itemRecord.addData(key, dataSection.get(key)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read Click data
|
||||||
|
if (section.isConfigurationSection("actions"))
|
||||||
|
{
|
||||||
|
ConfigurationSection actionSection = section.getConfigurationSection("actions");
|
||||||
|
|
||||||
|
if (actionSection != null)
|
||||||
|
{
|
||||||
|
actionSection.getKeys(false).forEach(actionKey -> {
|
||||||
|
ClickType clickType = Enums.getIfPresent(ClickType.class, actionKey.toUpperCase()).orNull();
|
||||||
|
|
||||||
|
if (clickType != null)
|
||||||
|
{
|
||||||
|
ConfigurationSection actionDataSection = actionSection.getConfigurationSection(actionKey);
|
||||||
|
|
||||||
|
if (actionDataSection != null)
|
||||||
|
{
|
||||||
|
ItemTemplateRecord.ActionRecords actionData =
|
||||||
|
new ItemTemplateRecord.ActionRecords(clickType,
|
||||||
|
actionDataSection.getString("type"),
|
||||||
|
actionDataSection.getString("content"),
|
||||||
|
actionDataSection.getString("tooltip"));
|
||||||
|
|
||||||
|
itemRecord.addAction(actionData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add item to the map
|
||||||
|
if (reusableItemMap != null && itemKey != null)
|
||||||
|
{
|
||||||
|
reusableItemMap.put(itemKey, itemRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
return itemRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method clears loaded panels from the cache.
|
||||||
|
*/
|
||||||
|
public static void clearPanels()
|
||||||
|
{
|
||||||
|
loadedPanels.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This map contains already read panels and their location.
|
||||||
|
* This improves performance for GUI opening, with a some memory usage.
|
||||||
|
*/
|
||||||
|
private static final Map<String, PanelTemplateRecord> loadedPanels = new HashMap<>();
|
||||||
|
}
|
@ -7,6 +7,7 @@ import org.bukkit.Bukkit;
|
|||||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||||
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
|
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
|
||||||
import world.bentobox.bentobox.api.events.BentoBoxReadyEvent;
|
import world.bentobox.bentobox.api.events.BentoBoxReadyEvent;
|
||||||
|
import world.bentobox.bentobox.api.panels.reader.TemplateReader;
|
||||||
import world.bentobox.bentobox.api.user.User;
|
import world.bentobox.bentobox.api.user.User;
|
||||||
import world.bentobox.bentobox.commands.reload.BentoBoxReloadLocalesCommand;
|
import world.bentobox.bentobox.commands.reload.BentoBoxReloadLocalesCommand;
|
||||||
import world.bentobox.bentobox.listeners.PanelListenerManager;
|
import world.bentobox.bentobox.listeners.PanelListenerManager;
|
||||||
@ -45,6 +46,8 @@ public class BentoBoxReloadCommand extends ConfirmableCommand {
|
|||||||
|
|
||||||
// Close all open panels
|
// Close all open panels
|
||||||
PanelListenerManager.closeAllPanels();
|
PanelListenerManager.closeAllPanels();
|
||||||
|
// Clear all template panels.
|
||||||
|
TemplateReader.clearPanels();
|
||||||
|
|
||||||
// Reload settings
|
// Reload settings
|
||||||
getPlugin().loadSettings();
|
getPlugin().loadSettings();
|
||||||
|
Loading…
Reference in New Issue
Block a user