mirror of
https://github.com/songoda/SongodaCore.git
synced 2024-11-23 18:45:34 +01:00
finish config editor
This commit is contained in:
parent
0008f54a9e
commit
927aee51bf
@ -45,7 +45,8 @@ public abstract class SongodaPlugin extends JavaPlugin {
|
||||
|
||||
@Override
|
||||
public ConfigFileConfigurationAdapter getConfig() {
|
||||
return config.getConfig();
|
||||
System.out.println("Plugin config adapter!");
|
||||
return config.getFileConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,7 +1,10 @@
|
||||
package com.songoda.core.compatibility;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
@ -1120,7 +1123,8 @@ public enum LegacyMaterials {
|
||||
* @return
|
||||
*/
|
||||
public boolean usesCompatibility() {
|
||||
return compatibleMaterial != null && ServerVersion.isServerVersionBelow(compatibleMaterial.versionLessThan);
|
||||
return compatibleMaterial != null && material == compatibleMaterial.material;
|
||||
//return compatibleMaterial != null && ServerVersion.isServerVersionBelow(compatibleMaterial.versionLessThan);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1179,6 +1183,20 @@ public enum LegacyMaterials {
|
||||
return m != null ? m : lookupMap.get(key + item.getDurability());
|
||||
}
|
||||
|
||||
static LinkedHashSet<LegacyMaterials> all = null;
|
||||
|
||||
public static Set<LegacyMaterials> getAllValidItemMaterials() {
|
||||
if (all == null) {
|
||||
all = new LinkedHashSet();
|
||||
for (LegacyMaterials mat : values()) {
|
||||
if (mat.isValidItem() && !mat.usesCompatibility()) {
|
||||
all.add(mat);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableSet(all);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup a Legacy Material by its modern id name and return its associated
|
||||
* Item. <br />
|
||||
|
@ -27,7 +27,9 @@ public class Comment {
|
||||
}
|
||||
|
||||
public Comment(List<String> lines) {
|
||||
this.lines.addAll(lines);
|
||||
if (lines != null) {
|
||||
this.lines.addAll(lines);
|
||||
}
|
||||
}
|
||||
|
||||
public Comment(CommentStyle commentStyle, String... lines) {
|
||||
@ -37,7 +39,9 @@ public class Comment {
|
||||
|
||||
public Comment(CommentStyle commentStyle, List<String> lines) {
|
||||
this.commentStyle = commentStyle;
|
||||
this.lines.addAll(lines);
|
||||
if (lines != null) {
|
||||
this.lines.addAll(lines);
|
||||
}
|
||||
}
|
||||
|
||||
public CommentStyle getCommentStyle() {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.songoda.core.configuration;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.songoda.core.utils.TextUtils;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
@ -14,6 +15,8 @@ import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
@ -130,7 +133,7 @@ public class Config extends ConfigSection {
|
||||
fileName = file;
|
||||
}
|
||||
|
||||
public ConfigFileConfigurationAdapter getConfig() {
|
||||
public ConfigFileConfigurationAdapter getFileConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
@ -317,44 +320,18 @@ public class Config extends ConfigSection {
|
||||
}
|
||||
|
||||
public boolean load() {
|
||||
if (getFile().exists()) {
|
||||
FileInputStream stream = null;
|
||||
try {
|
||||
stream = new FileInputStream(getFile());
|
||||
this.load(new InputStreamReader((InputStream) stream, Charsets.UTF_16));
|
||||
return true;
|
||||
} catch (IOException | InvalidConfigurationException ex) {
|
||||
(plugin != null ? plugin.getLogger() : Bukkit.getLogger()).log(Level.SEVERE, "Failed to load config file: " + file.getName(), ex);
|
||||
} finally {
|
||||
if (stream != null) {
|
||||
try {
|
||||
stream.close();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return load(getFile());
|
||||
}
|
||||
|
||||
public boolean load(@NotNull File file) {
|
||||
Validate.notNull(file, "File cannot be null");
|
||||
if (file.exists()) {
|
||||
FileInputStream stream = null;
|
||||
try {
|
||||
stream = new FileInputStream(file);
|
||||
this.load(new InputStreamReader((InputStream) stream, Charsets.UTF_16));
|
||||
try (BufferedInputStream stream = new BufferedInputStream(new FileInputStream(file))) {
|
||||
Charset charset = TextUtils.detectCharset(stream, StandardCharsets.UTF_8);
|
||||
this.load(new InputStreamReader(stream, charset));
|
||||
return true;
|
||||
} catch (IOException | InvalidConfigurationException ex) {
|
||||
(plugin != null ? plugin.getLogger() : Bukkit.getLogger()).log(Level.SEVERE, "Failed to load config file: " + file.getName(), ex);
|
||||
} finally {
|
||||
if (stream != null) {
|
||||
try {
|
||||
stream.close();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -363,9 +340,15 @@ public class Config extends ConfigSection {
|
||||
|
||||
public void load(@NotNull Reader reader) throws IOException, InvalidConfigurationException {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
try (BufferedReader input = reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader)) {
|
||||
String line;
|
||||
boolean firstLine = true;
|
||||
while ((line = input.readLine()) != null) {
|
||||
if(firstLine) {
|
||||
line = line.replaceAll("[\uFEFF\uFFFE\u200B]", ""); // clear BOM markers
|
||||
firstLine = false;
|
||||
}
|
||||
builder.append(line).append('\n');
|
||||
}
|
||||
}
|
||||
@ -410,8 +393,8 @@ public class Config extends ConfigSection {
|
||||
|
||||
public void deleteNonDefaultSettings() {
|
||||
// Delete old config values (thread-safe)
|
||||
List<String> defaultKeys = Arrays.asList((String[]) defaults.keySet().toArray());
|
||||
for(String key : (String[]) values.keySet().toArray()) {
|
||||
List<String> defaultKeys = Arrays.asList(defaults.keySet().toArray(new String[0]));
|
||||
for(String key : values.keySet().toArray(new String[0])) {
|
||||
if(!defaultKeys.contains(key)) {
|
||||
values.remove(key);
|
||||
}
|
||||
@ -470,7 +453,7 @@ public class Config extends ConfigSection {
|
||||
file.getParentFile().mkdirs();
|
||||
}
|
||||
String data = this.saveToString();
|
||||
try (OutputStreamWriter writer = new OutputStreamWriter((OutputStream) new FileOutputStream(file), Charsets.UTF_16);) {
|
||||
try (OutputStreamWriter writer = new OutputStreamWriter((OutputStream) new FileOutputStream(file), StandardCharsets.UTF_16);) {
|
||||
writer.write(data);
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
|
@ -1,6 +1,10 @@
|
||||
package com.songoda.core.configuration;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.bukkit.configuration.Configuration;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
|
||||
@ -13,7 +17,7 @@ public class ConfigFileConfigurationAdapter extends FileConfiguration {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public Config getConfig() {
|
||||
public Config getCoreConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
@ -36,4 +40,80 @@ public class ConfigFileConfigurationAdapter extends FileConfiguration {
|
||||
public ConfigOptionsAdapter options() {
|
||||
return new ConfigOptionsAdapter(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getKeys(boolean deep) {
|
||||
return config.getKeys(deep);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getValues(boolean deep) {
|
||||
return config.getValues(deep);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(String path) {
|
||||
return config.contains(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSet(String path) {
|
||||
return config.isSet(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentPath() {
|
||||
return config.getCurrentPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return config.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration getRoot() {
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationSection getParent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDefault(String path, Object value) {
|
||||
config.addDefault(path, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationSection getDefaultSection() {
|
||||
return config.getDefaultSection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(String path, Object value) {
|
||||
config.set(path, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(String path) {
|
||||
return config.get(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(String path, Object def) {
|
||||
return config.get(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationSection createSection(String path) {
|
||||
return config.createSection(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationSection createSection(String path, Map<?, ?> map) {
|
||||
return config.createSection(path, map);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -121,6 +121,17 @@ public class ConfigSection extends MemoryConfiguration {
|
||||
ConfigSection section = new ConfigSection(root, this, path, true);
|
||||
synchronized (root.lock) {
|
||||
root.defaults.put(fullPath + path, section);
|
||||
root.defaultComments.put(fullPath + path, new Comment(comment));
|
||||
}
|
||||
return section;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ConfigSection createDefaultSection(@NotNull String path, ConfigFormattingRules.CommentStyle commentStyle, String... comment) {
|
||||
ConfigSection section = new ConfigSection(root, this, path, true);
|
||||
synchronized (root.lock) {
|
||||
root.defaults.put(fullPath + path, section);
|
||||
root.defaultComments.put(fullPath + path, new Comment(commentStyle, comment));
|
||||
}
|
||||
return section;
|
||||
}
|
||||
@ -188,12 +199,24 @@ public class ConfigSection extends MemoryConfiguration {
|
||||
|
||||
@Override
|
||||
public void addDefault(@NotNull String path, @Nullable Object value) {
|
||||
root.defaults.put(fullPath + path, value);
|
||||
synchronized (root.lock) {
|
||||
// if any intermediate nodes don't exist, create them
|
||||
String[] pathParts = path.split(Pattern.quote(String.valueOf(root.pathChar)));
|
||||
String nodePath = "";
|
||||
for (int i = 0; i < pathParts.length - 1; ++i) {
|
||||
nodePath += (nodePath.isEmpty() ? pathParts[i] : root.pathChar + pathParts[i]);
|
||||
if (!(root.defaults.get(nodePath) instanceof ConfigSection)) {
|
||||
root.defaults.put(nodePath, new ConfigSection(root, this, nodePath, true));
|
||||
}
|
||||
}
|
||||
root.defaults.put(fullPath + path, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDefaults(@NotNull Map<String, Object> defaults) {
|
||||
defaults.entrySet().stream().forEach(m -> root.defaults.put(fullPath + m.getKey(), m.getValue()));
|
||||
//defaults.entrySet().stream().forEach(m -> root.defaults.put(fullPath + m.getKey(), m.getValue()));
|
||||
defaults.entrySet().stream().forEach(m -> addDefault(m.getKey(), m.getValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -10,15 +10,24 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.MemoryConfiguration;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
/**
|
||||
* Edit a configuration file for a specific plugin
|
||||
*
|
||||
* @since 2019-08-31
|
||||
* @author jascotty2
|
||||
*/
|
||||
public class ConfigEditorGui extends SimplePagedGui {
|
||||
|
||||
final JavaPlugin plugin;
|
||||
@ -53,7 +62,7 @@ public class ConfigEditorGui extends SimplePagedGui {
|
||||
this.setUseHeader(true);
|
||||
headerBackItem = footerBackItem = GuiUtils.getBorderItem(LegacyMaterials.GRAY_STAINED_GLASS_PANE.getItem());
|
||||
final String path = node.getCurrentPath();
|
||||
this.setItem(4, configItem(LegacyMaterials.FILLED_MAP, path, config, path, null));
|
||||
this.setItem(4, configItem(LegacyMaterials.FILLED_MAP, !path.isEmpty() ? path : file , config, !path.isEmpty() ? path : null, null));
|
||||
this.setButton(8, GuiUtils.createButtonItem(LegacyMaterials.OAK_DOOR, "Exit"), (event) -> event.player.closeInventory());
|
||||
|
||||
// compile list of settings
|
||||
@ -89,28 +98,98 @@ public class ConfigEditorGui extends SimplePagedGui {
|
||||
this.setButton(index, configItem(LegacyMaterials.CLOCK, ChatColor.YELLOW + settingKey, node, settingKey, String.valueOf((Number) val), "Click to edit this setting"),
|
||||
(event) -> {
|
||||
event.gui.exit();
|
||||
ChatPrompt prompt = ChatPrompt.showPrompt(plugin, event.player, "Enter your new value.", response -> {
|
||||
ChatPrompt.showPrompt(plugin, event.player, "Enter a new number value for " + settingKey + ":", response -> {
|
||||
if (!setNumber(event.slot, settingKey, response.getMessage().trim())) {
|
||||
event.player.sendMessage(ChatColor.RED + "Error: \"" + response.getMessage().trim() + "\" is not a number!");
|
||||
}
|
||||
});
|
||||
prompt.setOnClose(() -> event.manager.showGUI(event.player, this));
|
||||
}).setOnClose(() -> event.manager.showGUI(event.player, this))
|
||||
.setOnCancel(() -> {event.player.sendMessage(ChatColor.RED + "Edit canceled"); event.manager.showGUI(event.player, this);});
|
||||
});
|
||||
} else if (isMaterial(val)) {
|
||||
// changing a block
|
||||
// isMaterial is more of a guess, to be honest.
|
||||
this.setButton(index, configItem(LegacyMaterials.STONE, ChatColor.YELLOW + settingKey, node, settingKey, val.toString(), "Click to edit this setting"),
|
||||
(event) -> {
|
||||
SimplePagedGui paged = new SimplePagedGui(this);
|
||||
paged.setTitle(ChatColor.BLUE + settingKey);
|
||||
paged.setHeaderBackItem(headerBackItem).setFooterBackItem(footerBackItem).setDefaultItem(blankItem);
|
||||
paged.setItem(4, configItem(LegacyMaterials.FILLED_MAP, settingKey, node, settingKey, "Choose an item to change this value to"));
|
||||
int i = 9;
|
||||
for(LegacyMaterials mat : LegacyMaterials.getAllValidItemMaterials()) {
|
||||
paged.setButton(i++, GuiUtils.createButtonItem(mat, mat.name()), ClickType.LEFT, (matEvent) -> {
|
||||
setMaterial(event.slot, settingKey, matEvent.clickedItem);
|
||||
matEvent.player.closeInventory();
|
||||
});
|
||||
}
|
||||
event.manager.showGUI(event.player, paged);
|
||||
});
|
||||
|
||||
} else if (val instanceof String) {
|
||||
// changing a "string" value (or change to a feather for writing quill)
|
||||
this.setButton(index, configItem(LegacyMaterials.STRING, ChatColor.YELLOW + settingKey, node, settingKey, val.toString(), "Click to edit this setting"),
|
||||
(event) -> {
|
||||
event.gui.exit();
|
||||
ChatPrompt.showPrompt(plugin, event.player, "Enter a new value for " + settingKey + ":", response -> {
|
||||
node.set(settingKey, response.getMessage().trim());
|
||||
updateValue(event.slot, settingKey);
|
||||
}).setOnClose(() -> event.manager.showGUI(event.player, this))
|
||||
.setOnCancel(() -> {event.player.sendMessage(ChatColor.RED + "Edit canceled"); event.manager.showGUI(event.player, this);});
|
||||
});
|
||||
} else if (val instanceof List) {
|
||||
this.setButton(index, configItem(LegacyMaterials.WRITABLE_BOOK, ChatColor.YELLOW + settingKey, node, settingKey, String.format("(%d values)", ((List) val).size()), "Click to edit this setting"),
|
||||
(event) -> {
|
||||
event.manager.showGUI(event.player, (new ConfigEditorListEditorGui(this, settingKey, (List) val)).setOnClose((gui) -> {
|
||||
if(((ConfigEditorListEditorGui) gui.gui).saveChanges) {
|
||||
setList(event.slot, settingKey, ((ConfigEditorListEditorGui) gui.gui).value);
|
||||
}
|
||||
}));
|
||||
});
|
||||
} else {
|
||||
// idk. should we display uneditable values?
|
||||
}
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public ConfigurationSection getCurrentNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
protected void updateValue(int clickCell, String path) {
|
||||
ItemStack item = inventory.getItem(clickCell);
|
||||
if(item == null || item == AIR) return;
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
Object val = node.get(path);
|
||||
if (meta != null && val != null) {
|
||||
String valStr;
|
||||
if (val instanceof List) {
|
||||
valStr = String.format("(%d values)", ((List) val).size());
|
||||
} else {
|
||||
valStr = val.toString();
|
||||
}
|
||||
List<String> lore = meta.getLore();
|
||||
if (lore == null || lore.isEmpty()) {
|
||||
meta.setLore(Arrays.asList(valStr));
|
||||
} else {
|
||||
lore.set(0, valStr);
|
||||
meta.setLore(lore);
|
||||
}
|
||||
item.setItemMeta(meta);
|
||||
setItem(clickCell, item);
|
||||
}
|
||||
}
|
||||
|
||||
void toggle(int clickCell, String path) {
|
||||
boolean val = !node.getBoolean(path);
|
||||
node.set(path, val);
|
||||
if(val) {
|
||||
inventory.setItem(clickCell, ItemUtils.addGlow(inventory.getItem(clickCell)));
|
||||
setItem(clickCell, ItemUtils.addGlow(inventory.getItem(clickCell)));
|
||||
} else {
|
||||
removeHighlight(clickCell);
|
||||
setItem(clickCell, ItemUtils.removeGlow(inventory.getItem(clickCell)));
|
||||
}
|
||||
updateValue(clickCell, path);
|
||||
}
|
||||
|
||||
boolean setNumber(int clickCell, String path, String input) {
|
||||
@ -122,12 +201,28 @@ public class ConfigEditorGui extends SimplePagedGui {
|
||||
} else if (node.isLong(path)) {
|
||||
node.set(path, Long.parseLong(input));
|
||||
}
|
||||
updateValue(clickCell, path);
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void setMaterial(int clickCell, String path, ItemStack item) {
|
||||
LegacyMaterials mat = LegacyMaterials.getMaterial(item);
|
||||
if (mat == null) {
|
||||
node.set(path, LegacyMaterials.STONE.name());
|
||||
} else {
|
||||
node.set(path, mat.name());
|
||||
}
|
||||
updateValue(clickCell, path);
|
||||
}
|
||||
|
||||
void setList(int clickCell, String path, List<String> list) {
|
||||
node.set(path, list);
|
||||
updateValue(clickCell, path);
|
||||
}
|
||||
|
||||
void save() {
|
||||
// could also check and call saveChanges()
|
||||
if (config instanceof FileConfiguration) {
|
||||
@ -149,32 +244,38 @@ public class ConfigEditorGui extends SimplePagedGui {
|
||||
|| value instanceof Double);
|
||||
}
|
||||
|
||||
ItemStack configItem(LegacyMaterials type, String name, ConfigurationSection node, String path, String def) {
|
||||
private boolean isMaterial(Object value) {
|
||||
LegacyMaterials m;
|
||||
return value instanceof String && value.toString().equals(value.toString().toUpperCase())
|
||||
&& (m = LegacyMaterials.getMaterial(value.toString())) != null && m.isValidItem();
|
||||
}
|
||||
|
||||
protected ItemStack configItem(LegacyMaterials type, String name, ConfigurationSection node, String path, String def) {
|
||||
String[] info = null;
|
||||
if (configSection_getCommentString != null) {
|
||||
try {
|
||||
Object comment = configSection_getCommentString.invoke(config, path);
|
||||
Object comment = configSection_getCommentString.invoke(node, path);
|
||||
if (comment != null) {
|
||||
info = comment.toString().split("\n");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
}
|
||||
return GuiUtils.createButtonItem(LegacyMaterials.FILLED_MAP, path, info != null ? info : (def != null ? def.split("\n") : null));
|
||||
return GuiUtils.createButtonItem(type, name, info != null ? info : (def != null ? def.split("\n") : null));
|
||||
}
|
||||
|
||||
ItemStack configItem(LegacyMaterials type, String name, ConfigurationSection node, String path, String value, String def) {
|
||||
protected ItemStack configItem(LegacyMaterials type, String name, ConfigurationSection node, String path, String value, String def) {
|
||||
if(value == null) value = "";
|
||||
String[] info = null;
|
||||
if (configSection_getCommentString != null) {
|
||||
try {
|
||||
Object comment = configSection_getCommentString.invoke(config, path);
|
||||
Object comment = configSection_getCommentString.invoke(node, path);
|
||||
if (comment != null) {
|
||||
info = (value + "\n" + comment.toString()).split("\n");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
}
|
||||
return GuiUtils.createButtonItem(LegacyMaterials.FILLED_MAP, path, info != null ? info : (def != null ? (value + "\n" + def).split("\n") : null));
|
||||
return GuiUtils.createButtonItem(type, name, info != null ? info : (def != null ? (value + "\n" + def).split("\n") : null));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,72 @@
|
||||
package com.songoda.core.configuration.editor;
|
||||
|
||||
import com.songoda.core.compatibility.LegacyMaterials;
|
||||
import com.songoda.core.gui.GuiUtils;
|
||||
import com.songoda.core.gui.SimplePagedGui;
|
||||
import com.songoda.core.input.ChatPrompt;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
|
||||
/**
|
||||
* Edit a string list
|
||||
*
|
||||
* @since 2019-08-31
|
||||
* @author jascotty2
|
||||
*/
|
||||
public class ConfigEditorListEditorGui extends SimplePagedGui {
|
||||
|
||||
final ConfigEditorGui current;
|
||||
|
||||
public boolean saveChanges = false;
|
||||
public List<String> value;
|
||||
|
||||
public ConfigEditorListEditorGui(ConfigEditorGui current, String key, List<String> value) {
|
||||
this.current = current;
|
||||
this.blankItem = current.getDefaultItem();
|
||||
headerBackItem = footerBackItem = current.getHeaderBackItem();
|
||||
setTitle(ChatColor.DARK_BLUE + "String List Editor");
|
||||
this.setUseHeader(true);
|
||||
this.setItem(4, current.configItem(LegacyMaterials.FILLED_MAP, key, current.getCurrentNode(), key, null));
|
||||
this.setButton(8, GuiUtils.createButtonItem(LegacyMaterials.OAK_DOOR, "Exit"), (event) -> event.player.closeInventory());
|
||||
this.value = new ArrayList(value);
|
||||
|
||||
this.setButton(8, GuiUtils.createButtonItem(LegacyMaterials.LAVA_BUCKET, ChatColor.RED + "Discard Changes"), (event) -> event.player.closeInventory());
|
||||
this.setButton(0, GuiUtils.createButtonItem(LegacyMaterials.REDSTONE, ChatColor.GREEN + "Save"), (event) -> {
|
||||
saveChanges = true;
|
||||
event.player.closeInventory();
|
||||
});
|
||||
this.setButton(1, GuiUtils.createButtonItem(LegacyMaterials.CHEST, ChatColor.BLUE + "Add Item"),
|
||||
(event) -> {
|
||||
ChatPrompt.showPrompt(event.manager.getPlugin(), event.player, "Enter a new value to add:", response -> {
|
||||
value.add(response.getMessage().trim());
|
||||
redraw();
|
||||
}).setOnClose(() -> event.manager.showGUI(event.player, this))
|
||||
.setOnCancel(() -> {event.player.sendMessage(ChatColor.RED + "Edit canceled"); event.manager.showGUI(event.player, this);});
|
||||
});
|
||||
}
|
||||
|
||||
void redraw() {
|
||||
page = 1;
|
||||
// clear old display
|
||||
for (Integer oldI : (Integer[]) cellItems.keySet().toArray()) {
|
||||
if (oldI > 8) {
|
||||
cellItems.remove(oldI);
|
||||
}
|
||||
}
|
||||
// update items
|
||||
int i = 9;
|
||||
for (String item : value) {
|
||||
final int index = i - 9;
|
||||
setButton(i++, GuiUtils.createButtonItem(LegacyMaterials.PAPER, item, "Right-click to remove"), ClickType.RIGHT, (event) -> {
|
||||
value.remove(index);
|
||||
redraw();
|
||||
});
|
||||
}
|
||||
// update display
|
||||
showPage();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -36,7 +36,7 @@ public class PluginConfigGui extends SimplePagedGui {
|
||||
this.plugin = plugin;
|
||||
|
||||
// collect list of plugins
|
||||
configs.put(plugin.getConfig().getConfig().getFile().getName(), plugin.getConfig().getConfig());
|
||||
configs.put(plugin.getConfig().getCoreConfig().getFile().getName(), plugin.getConfig().getCoreConfig());
|
||||
List<Config> more = plugin.getExtraConfig();
|
||||
if (more != null && !more.isEmpty()) {
|
||||
for (Config cfg : more) {
|
||||
|
@ -14,6 +14,7 @@ public class LocaleModule implements PluginInfoModule {
|
||||
|
||||
@Override
|
||||
public void run(PluginInfo plugin) {
|
||||
if(plugin.getJavaPlugin() == null || plugin.getSongodaId() <= 0) return;
|
||||
JSONObject json = plugin.getJson();
|
||||
try {
|
||||
JSONArray files = (JSONArray) json.get("neededFiles");
|
||||
|
@ -136,9 +136,12 @@ public class Gui {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the GUI without calling onClose() and without opening any parent GUIs
|
||||
*/
|
||||
public void exit() {
|
||||
allowClose = true;
|
||||
parent = null;
|
||||
open = false;
|
||||
inventory.getViewers().stream()
|
||||
.filter(e -> e instanceof Player)
|
||||
.map(e -> (Player) e)
|
||||
@ -212,6 +215,10 @@ public class Gui {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStack getDefaultItem() {
|
||||
return blankItem;
|
||||
}
|
||||
|
||||
public Gui setItem(int cell, ItemStack item) {
|
||||
cellItems.put(cell, item);
|
||||
if (open && cell >= 0 && cell < inventory.getSize()) {
|
||||
|
@ -40,6 +40,10 @@ public class GuiManager {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public Plugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the GUI handlers
|
||||
*/
|
||||
|
@ -43,6 +43,24 @@ public class SimplePagedGui extends Gui {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStack getHeaderBackItem() {
|
||||
return headerBackItem;
|
||||
}
|
||||
|
||||
public SimplePagedGui setHeaderBackItem(ItemStack headerBackItem) {
|
||||
this.headerBackItem = headerBackItem;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStack getFooterBackItem() {
|
||||
return footerBackItem;
|
||||
}
|
||||
|
||||
public SimplePagedGui setFooterBackItem(ItemStack footerBackItem) {
|
||||
this.footerBackItem = footerBackItem;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimplePagedGui setNextPage(ItemStack item) {
|
||||
nextPage = item;
|
||||
return this;
|
||||
|
@ -5,12 +5,13 @@ import com.songoda.core.gui.GuiManager;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class GuiClickEvent extends GuiEvent {
|
||||
public final int slot;
|
||||
public final boolean guiClicked;
|
||||
public final ItemStack cursor;
|
||||
public final ItemStack cursor, clickedItem;
|
||||
public final ClickType clickType;
|
||||
public final InventoryClickEvent event;
|
||||
|
||||
@ -19,6 +20,8 @@ public class GuiClickEvent extends GuiEvent {
|
||||
this.slot = slot;
|
||||
this.guiClicked = guiClicked;
|
||||
this.cursor = event.getCursor();
|
||||
Inventory clicked = event.getClickedInventory();
|
||||
this.clickedItem = clicked == null ? null : clicked.getItem(event.getSlot());
|
||||
this.clickType = event.getClick();
|
||||
this.event = event;
|
||||
}
|
||||
|
@ -1,17 +1,16 @@
|
||||
package com.songoda.core.input;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
|
@ -1,21 +1,17 @@
|
||||
package com.songoda.core.locale;
|
||||
|
||||
import com.songoda.core.utils.TextUtils;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.CharacterCodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -30,7 +26,8 @@ import org.bukkit.plugin.java.JavaPlugin;
|
||||
/**
|
||||
* Assists in the utilization of localization files. <br>
|
||||
* Created to be used by the Songoda Team. <br>
|
||||
* NOTE: Using this class in multiple plugins requires shading!
|
||||
* NOTE: Using this class in multiple plugins requires shading! <br>
|
||||
* Updated 2019-09-01 to support UTF encoded lang files - jascotty2
|
||||
*
|
||||
* @author Brianna O'Keefe - Songoda
|
||||
*/
|
||||
@ -188,8 +185,8 @@ public class Locale {
|
||||
try (BufferedInputStream defaultIn = new BufferedInputStream(defaultFile);
|
||||
BufferedInputStream existingIn = new BufferedInputStream(new FileInputStream(existingFile))) {
|
||||
|
||||
Charset defaultCharset = Locale.detectCharset(defaultIn);
|
||||
Charset existingCharset = Locale.detectCharset(existingIn);
|
||||
Charset defaultCharset = TextUtils.detectCharset(defaultIn, StandardCharsets.UTF_8);
|
||||
Charset existingCharset = TextUtils.detectCharset(existingIn, StandardCharsets.UTF_8);
|
||||
|
||||
try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(existingFile, true), existingCharset);
|
||||
BufferedReader defaultReader = new BufferedReader(new InputStreamReader(defaultIn, defaultCharset));
|
||||
@ -254,9 +251,10 @@ public class Locale {
|
||||
this.nodes.clear(); // Clear previous data (if any)
|
||||
|
||||
// guess what encoding this file is in
|
||||
Charset charset = detectCharset(file);
|
||||
Charset charset = TextUtils.detectCharset(file, null);
|
||||
if(charset == null) {
|
||||
return false;
|
||||
plugin.getLogger().warning("Could not determine charset for locale \"" + this.name + "\"");
|
||||
charset = StandardCharsets.UTF_8;
|
||||
}
|
||||
|
||||
// load in the file!
|
||||
@ -291,80 +289,6 @@ public class Locale {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static final List<Charset> supportedCharsets = new ArrayList();
|
||||
|
||||
static {
|
||||
supportedCharsets.add(StandardCharsets.UTF_8); // UTF-8 BOM: EF BB BF
|
||||
supportedCharsets.add(StandardCharsets.ISO_8859_1); // also starts with EF BB BF
|
||||
//supportedCharsets.add(StandardCharsets.UTF_16LE); // FF FE
|
||||
//supportedCharsets.add(StandardCharsets.UTF_16BE); // FE FF
|
||||
//supportedCharsets.add(StandardCharsets.UTF_16);
|
||||
try {
|
||||
supportedCharsets.add(Charset.forName("windows-1253"));
|
||||
supportedCharsets.add(Charset.forName("ISO-8859-7"));
|
||||
} catch (Exception e) {
|
||||
} // UnsupportedCharsetException technically can be thrown, but can also be ignored
|
||||
supportedCharsets.add(StandardCharsets.US_ASCII);
|
||||
}
|
||||
|
||||
protected static Charset detectCharset(File f) {
|
||||
byte[] buffer = new byte[2048];
|
||||
int read = -1;
|
||||
// read the first 2kb of the file and test the file's encoding
|
||||
try (FileInputStream input = new FileInputStream(f)) {
|
||||
read = input.read(buffer);
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
return read != -1 ? detectCharset(buffer, read) : null;
|
||||
}
|
||||
|
||||
protected static Charset detectCharset(BufferedInputStream reader) {
|
||||
byte[] buffer = new byte[2048];
|
||||
int read;
|
||||
try {
|
||||
reader.mark(2048);
|
||||
read = reader.read(buffer);
|
||||
reader.reset();
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
return read != -1 ? detectCharset(buffer, read) : null;
|
||||
}
|
||||
|
||||
protected static Charset detectCharset(byte[] data, int len) {
|
||||
// check the file header
|
||||
if (len > 4) {
|
||||
if (data[0] == (byte) 0xFF && data[1] == (byte) 0xFE) {
|
||||
return StandardCharsets.UTF_16LE;
|
||||
// FF FE 00 00 is UTF-32LE
|
||||
} else if (data[0] == (byte) 0xFE && data[1] == (byte) 0xFF) {
|
||||
return StandardCharsets.UTF_16BE;
|
||||
// 00 00 FE FF is UTF-32BE
|
||||
} else if (data[0] == (byte) 0xEF && data[1] == (byte) 0xBB && data[2] == (byte) 0xBF) { // UTF-8 with BOM, same sig as ISO-8859-1
|
||||
return StandardCharsets.UTF_8;
|
||||
}
|
||||
}
|
||||
|
||||
// iterate through sets to test, and return the first that is ok
|
||||
for (Charset charset : supportedCharsets) {
|
||||
if (charset != null && isCharset(data, len, charset)) {
|
||||
return charset;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static boolean isCharset(byte[] data, int len, Charset charset) {
|
||||
try {
|
||||
CharsetDecoder decoder = charset.newDecoder();
|
||||
decoder.reset();
|
||||
decoder.decode(ByteBuffer.wrap(data));
|
||||
return true;
|
||||
} catch (CharacterCodingException e) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supply the Message object with the plugins prefix.
|
||||
|
@ -144,18 +144,23 @@ public class ItemUtils {
|
||||
* @return copy of the item without any enchantment tag
|
||||
*/
|
||||
public static ItemStack removeGlow(ItemStack item) {
|
||||
if (item != null && item.getType() != Material.AIR && cb_CraftItemStack_asCraftMirror != null) {
|
||||
try {
|
||||
Object nmsStack = cb_CraftItemStack_asNMSCopy.invoke(null, item);
|
||||
Object tag = mc_ItemStack_getTag.invoke(nmsStack);
|
||||
if (tag != null) {
|
||||
// remove enchantment list
|
||||
mc_NBTTagCompound_remove.invoke(tag, "ench");
|
||||
mc_ItemStack_setTag.invoke(nmsStack, tag);
|
||||
item = (ItemStack) cb_CraftItemStack_asCraftMirror.invoke(null, nmsStack);
|
||||
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11)) {
|
||||
item.removeEnchantment(Enchantment.DURABILITY);
|
||||
return item;
|
||||
} else {
|
||||
if (item != null && item.getType() != Material.AIR && cb_CraftItemStack_asCraftMirror != null) {
|
||||
try {
|
||||
Object nmsStack = cb_CraftItemStack_asNMSCopy.invoke(null, item);
|
||||
Object tag = mc_ItemStack_getTag.invoke(nmsStack);
|
||||
if (tag != null) {
|
||||
// remove enchantment list
|
||||
mc_NBTTagCompound_remove.invoke(tag, "ench");
|
||||
mc_ItemStack_setTag.invoke(nmsStack, tag);
|
||||
item = (ItemStack) cb_CraftItemStack_asCraftMirror.invoke(null, nmsStack);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "Failed to set glow enchantment on item: " + item, ex);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "Failed to set glow enchantment on item: " + item, ex);
|
||||
}
|
||||
}
|
||||
return item;
|
||||
|
@ -1,5 +1,15 @@
|
||||
package com.songoda.core.utils;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.CharacterCodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
public class TextUtils {
|
||||
@ -24,4 +34,78 @@ public class TextUtils {
|
||||
return hidden.toString();
|
||||
}
|
||||
|
||||
protected static final List<Charset> supportedCharsets = new ArrayList();
|
||||
|
||||
static {
|
||||
supportedCharsets.add(StandardCharsets.UTF_8); // UTF-8 BOM: EF BB BF
|
||||
supportedCharsets.add(StandardCharsets.ISO_8859_1); // also starts with EF BB BF
|
||||
//supportedCharsets.add(StandardCharsets.UTF_16LE); // FF FE
|
||||
//supportedCharsets.add(StandardCharsets.UTF_16BE); // FE FF
|
||||
//supportedCharsets.add(StandardCharsets.UTF_16);
|
||||
try {
|
||||
supportedCharsets.add(Charset.forName("windows-1253"));
|
||||
supportedCharsets.add(Charset.forName("ISO-8859-7"));
|
||||
} catch (Exception e) {
|
||||
} // UnsupportedCharsetException technically can be thrown, but can also be ignored
|
||||
supportedCharsets.add(StandardCharsets.US_ASCII);
|
||||
}
|
||||
|
||||
public static Charset detectCharset(File f, Charset def) {
|
||||
byte[] buffer = new byte[2048];
|
||||
int read = -1;
|
||||
// read the first 2kb of the file and test the file's encoding
|
||||
try (FileInputStream input = new FileInputStream(f)) {
|
||||
read = input.read(buffer);
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
return read != -1 ? detectCharset(buffer, read, def) : def;
|
||||
}
|
||||
|
||||
public static Charset detectCharset(BufferedInputStream reader, Charset def) {
|
||||
byte[] buffer = new byte[2048];
|
||||
int read;
|
||||
try {
|
||||
reader.mark(2048);
|
||||
read = reader.read(buffer);
|
||||
reader.reset();
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
return read != -1 ? detectCharset(buffer, read, def) : def;
|
||||
}
|
||||
|
||||
public static Charset detectCharset(byte[] data, int len, Charset def) {
|
||||
// check the file header
|
||||
if (len > 4) {
|
||||
if (data[0] == (byte) 0xFF && data[1] == (byte) 0xFE) {
|
||||
return StandardCharsets.UTF_16LE;
|
||||
// FF FE 00 00 is UTF-32LE
|
||||
} else if (data[0] == (byte) 0xFE && data[1] == (byte) 0xFF) {
|
||||
return StandardCharsets.UTF_16BE;
|
||||
// 00 00 FE FF is UTF-32BE
|
||||
} else if (data[0] == (byte) 0xEF && data[1] == (byte) 0xBB && data[2] == (byte) 0xBF) { // UTF-8 with BOM, same sig as ISO-8859-1
|
||||
return StandardCharsets.UTF_8;
|
||||
}
|
||||
}
|
||||
|
||||
// iterate through sets to test, and return the first that is ok
|
||||
for (Charset charset : supportedCharsets) {
|
||||
if (charset != null && isCharset(data, len, charset)) {
|
||||
return charset;
|
||||
}
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
public static boolean isCharset(byte[] data, int len, Charset charset) {
|
||||
try {
|
||||
CharsetDecoder decoder = charset.newDecoder();
|
||||
decoder.reset();
|
||||
decoder.decode(ByteBuffer.wrap(data));
|
||||
return true;
|
||||
} catch (CharacterCodingException e) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user