Last active
December 22, 2023 01:08
-
-
Save noobmobile/14bd0e83d129cd023f9505a5cddf1117 to your computer and use it in GitHub Desktop.
Classe para facilitar a transformação de ConfigurationSections, em YML, para objetos java. Possui sistema de adapters altamente flexíveis, adapters nativos: ItemStack, String (chat colors) e List
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.dont.modelo.utils; | |
import com.mojang.authlib.GameProfile; | |
import com.mojang.authlib.properties.Property; | |
import org.apache.commons.codec.binary.Base64; | |
import org.bukkit.*; | |
import org.bukkit.configuration.ConfigurationSection; | |
import org.bukkit.enchantments.Enchantment; | |
import org.bukkit.entity.EntityType; | |
import org.bukkit.inventory.ItemFlag; | |
import org.bukkit.inventory.ItemStack; | |
import org.bukkit.inventory.meta.ItemMeta; | |
import org.bukkit.inventory.meta.SkullMeta; | |
import java.lang.reflect.Constructor; | |
import java.lang.reflect.Field; | |
import java.util.*; | |
import java.util.stream.Collectors; | |
public class SectionBuilder<T> { | |
private static final Map<Class<?>, Adapter<?>> CLASS_ADAPTERS = new HashMap<>(); | |
static { | |
CLASS_ADAPTERS.put(ItemStack.class, new ItemAdapter()); | |
CLASS_ADAPTERS.put(String.class, new StringAdapter()); | |
CLASS_ADAPTERS.put(Material.class, new MaterialAdapter()); | |
CLASS_ADAPTERS.put(Location.class, new LocationAdapter()); | |
CLASS_ADAPTERS.put(StringList.class, new ListAdapter<>(new StringAdapter())); | |
CLASS_ADAPTERS.put(ItemList.class, new ListAdapter<>(new ItemAdapter())); | |
CLASS_ADAPTERS.put(Sound.class, new EnumAdapter<>(Sound.class)); | |
CLASS_ADAPTERS.put(EntityType.class, new EnumAdapter<>(EntityType.class)); | |
} | |
private final ConfigurationSection mainSection; | |
private final Class<T> clazz; | |
private final Constructor<T> constructor; | |
private final Map<String, Class<?>> parameters; | |
private final Map<String, Adapter<?>> parametersAdapters; | |
public static <E> SectionBuilder<E> of(Class<E> clazz, ConfigurationSection section) { | |
return new SectionBuilder<E>(clazz, section); | |
} | |
private SectionBuilder(Class<T> clazz, ConfigurationSection mainSection) { | |
this.mainSection = mainSection; | |
this.clazz = clazz; | |
this.constructor = (Constructor<T>) clazz.getConstructors()[0]; | |
this.parameters = new LinkedHashMap<>(); | |
this.parametersAdapters = new HashMap<>(); | |
} | |
public SectionBuilder<T> parameter(String key, Class<?> valueClass) { | |
this.parameters.put(key, valueClass); | |
return this; | |
} | |
public SectionBuilder<T> parameter(String key, Class<?> valueClass, Adapter<?> adapter) { | |
this.parameters.put(key, valueClass); | |
this.parametersAdapters.put(key, adapter); | |
return this; | |
} | |
public SectionBuilder<T> adapter(Class<?> clazz, Adapter<?> adapter) { | |
CLASS_ADAPTERS.put(clazz, adapter); | |
return this; | |
} | |
public List<T> build() { | |
if (constructor.getParameterCount() - 1 != parameters.size()) { // primeiro argumento é sempre a key, e não precisa ser passado pelo método parameter(String, Class) | |
throw new IllegalArgumentException("Constructor has " + (constructor.getParameterCount() - 1) + " parameters, but it was passed " + parameters.size() + " parameters."); | |
} | |
List<T> toReturn = new ArrayList<>(); | |
for (String key : mainSection.getKeys(false)) { | |
try { | |
ConfigurationSection section = mainSection.getConfigurationSection(key); | |
List<Object> constructorParameters = new ArrayList<>(); | |
constructorParameters.add(key); | |
for (Map.Entry<String, Class<?>> entry : parameters.entrySet()) { | |
String parameter = entry.getKey(); | |
Class<?> parameterClass = entry.getValue(); | |
Object object = section.get(parameter); | |
Adapter<?> adapter = parametersAdapters.getOrDefault(parameter, CLASS_ADAPTERS.get(parameterClass)); | |
constructorParameters.add(adapter == null ? object : adapter.supply(object)); | |
} | |
T instance = constructor.newInstance(constructorParameters.toArray()); | |
toReturn.add(instance); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
return toReturn; | |
} | |
public <E> Map<E, T> build(Function<T, E> extractor) { | |
return build().stream().collect(Collectors.toMap(extractor, Function.identity())); | |
} | |
public static interface Adapter<A> { | |
A supply(Object object); | |
} | |
public static class ItemAdapter implements Adapter<ItemStack> { | |
private final static MaterialAdapter MATERIAL_ADAPTER = new MaterialAdapter(); | |
private final static StringAdapter STRING_ADAPTER = new StringAdapter(); | |
/* O único atributo necessário é o material | |
Material: STONE | |
#Texture: http://textures.minecraft.net/texture/fa8887814578ce7c540d7ab8cc6b2a2e22a7492cc86c65a7e839c887b2ed62 # caso tenha essa propriedade, o item automaticamente ira ser uma skull com a textura setada (pode ser um nick também) | |
Data: 1 | |
Quantidade: 16 | |
Nome: "&5Nome Legal" | |
Lore: | |
- "&6Lore legal" | |
Enchants: | |
- "DAMAGE_ALL: 10" | |
Glow: false | |
*/ | |
@Override | |
public ItemStack supply(Object object) { | |
ConfigurationSection section = (ConfigurationSection) object; | |
String url = !section.isSet("Texture") ? null : section.getString("Texture"); | |
Material material = MATERIAL_ADAPTER.supply(section.get("Material")); | |
int data = !section.isSet("Data") ? 0 : section.getInt("Data"); | |
int amount = !section.isSet("Quantidade") ? 1 : section.getInt("Quantidade"); | |
String name = !section.isSet("Nome") ? null : STRING_ADAPTER.supply(section.getString("Nome")); | |
List<String> lore = !section.isSet("Lore") ? null : section.getStringList("Lore").stream().map(STRING_ADAPTER::supply).collect(Collectors.toList()); | |
Map<Enchantment, Integer> enchants = !section.isSet("Enchants") ? null : section.getStringList("Enchants").stream().map(string -> string.split(":")).collect(Collectors.toMap(array -> Enchantment.getByName(array[0]), array -> Integer.parseInt(array[1].trim()))); | |
boolean glow = section.isSet("Glow") && section.getBoolean("Glow"); | |
ItemStack itemStack = url == null ? new ItemStack(material, amount, (byte) data) : getCustomHead(url); | |
ItemMeta itemMeta = itemStack.getItemMeta(); | |
if (name != null) itemMeta.setDisplayName(name); | |
if (lore != null) itemMeta.setLore(lore); | |
if (glow) { | |
itemMeta.addEnchant(Enchantment.DURABILITY, 1, true); | |
itemMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS); | |
} | |
if (enchants != null) | |
enchants.forEach((enchantment, integer) -> itemMeta.addEnchant(enchantment, integer, true)); | |
itemStack.setItemMeta(itemMeta); | |
return itemStack; | |
} | |
private ItemStack getCustomHead(String url) { | |
ItemStack itemStack = new ItemStack(Material.SKULL_ITEM, 1, (short) 3); | |
SkullMeta skullMeta = (SkullMeta) itemStack.getItemMeta(); | |
if (url.length() <= 16) { | |
skullMeta.setOwner(url); | |
itemStack.setItemMeta(skullMeta); | |
return itemStack; | |
} | |
if (!url.startsWith("http://textures.minecraft.net/texture/")) { | |
url = "http://textures.minecraft.net/texture/" + url; | |
} | |
try { | |
GameProfile profile = new GameProfile(UUID.nameUUIDFromBytes(url.getBytes()), null); | |
profile.getProperties().put("textures", new Property("textures", new String(Base64.encodeBase64(String.format("{textures:{SKIN:{url:\"%s\"}}}", url).getBytes())))); | |
Field profileField = skullMeta.getClass().getDeclaredField("profile"); | |
profileField.setAccessible(true); | |
profileField.set(skullMeta, profile); | |
itemStack.setItemMeta(skullMeta); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
return itemStack; | |
} | |
} | |
private static class StringAdapter implements Adapter<String> { | |
@Override | |
public String supply(Object object) { | |
return ChatColor.translateAlternateColorCodes('&', (String) object); | |
} | |
} | |
private static class MaterialAdapter implements Adapter<Material> { | |
@Override | |
public Material supply(Object object) { | |
String value = object.toString(); | |
return isNumber(value) ? Material.getMaterial(Integer.parseInt(value)) : Material.valueOf(value.toUpperCase()); | |
} | |
private boolean isNumber(String string) { | |
try { | |
int i = Integer.parseInt(string); | |
return true; | |
} catch (NumberFormatException e) { | |
return false; | |
} | |
} | |
} | |
public static class ListAdapter<A> implements Adapter<List<A>> { | |
private final Adapter<A> adapter; | |
public ListAdapter(Adapter<A> adapter) { | |
this.adapter = adapter; | |
} | |
@Override | |
public List<A> supply(Object object) { | |
if (object instanceof ConfigurationSection) { | |
ConfigurationSection section = (ConfigurationSection) object; | |
return section.getKeys(false).stream().map(section::getConfigurationSection).map(adapter::supply).collect(Collectors.toList()); | |
} else { | |
List<Object> list = (List<Object>) object; | |
return list.stream().map(adapter::supply).collect(Collectors.toList()); | |
} | |
} | |
} | |
public static class LocationAdapter implements Adapter<Location> { | |
@Override | |
public Location supply(Object object) { | |
String value = (String) object; | |
if (!value.contains(";")) return null; | |
String[] parts = value.split(";"); | |
double x = Double.parseDouble(parts[0]); | |
double y = Double.parseDouble(parts[1]); | |
double z = Double.parseDouble(parts[2]); | |
float yaw = Float.parseFloat(parts[3]); | |
float pitch = Float.parseFloat(parts[4]); | |
World w = Bukkit.getServer().getWorld(parts[5]); | |
return new Location(w, x, y, z, yaw, pitch); | |
} | |
} | |
public static class EnumAdapter<A extends Enum<A>> implements Adapter<A> { | |
private final Class<A> enumClass; | |
public EnumAdapter(Class<A> aEnum) { | |
this.enumClass = aEnum; | |
} | |
@Override | |
public A supply(Object object) { | |
return Enum.valueOf(enumClass, (String) object); | |
} | |
} | |
public static class ItemList { | |
} | |
public static class StringList { | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
SectionBuilder.of(Categoria.class, getConfig().getConfigurationSection("Categorias")) | |
.parameter("Tamanho", int.class) | |
.parameter("Nome", String.class) | |
.parameter("Items", CategoriaItem.class, new SectionBuilder.ListAdapter<>(object -> { | |
ConfigurationSection section = (ConfigurationSection) object; | |
int slot = section.getInt("Slot"); | |
SectionBuilder.ItemAdapter itemAdapter = new SectionBuilder.ItemAdapter(); | |
ItemStack item = itemAdapter.supply(section); | |
return new CategoriaItem(section.getName(), slot, item); | |
})) | |
.build().forEach(categoria -> Bukkit.broadcastMessage(categoria.toString())); | |
public class Categoria { | |
private String key; | |
private int size; | |
private String name; | |
private List<CategoriaItem> categoriaItems; | |
public Categoria(String key, int size, String name, List<CategoriaItem> categoriaItems) { | |
this.key = key; | |
this.size = size; | |
this.name = name; | |
this.categoriaItems = categoriaItems; | |
} | |
public String getKey() { | |
return key; | |
} | |
public int getSize() { | |
return size; | |
} | |
public String getName() { | |
return name; | |
} | |
public List<CategoriaItem> getCategoriaItems() { | |
return categoriaItems; | |
} | |
@Override | |
public String toString() { | |
return "Categoria{" + | |
"key='" + key + '\'' + | |
", size=" + size + | |
", name='" + name + '\'' + | |
", categoriaItems=" + categoriaItems + | |
'}'; | |
} | |
} | |
public class CategoriaItem { | |
private String key; | |
private int slot; | |
private ItemStack item; | |
public CategoriaItem(String key, int slot, ItemStack item) { | |
this.key = key; | |
this.slot = slot; | |
this.item = item; | |
} | |
public String getKey() { | |
return key; | |
} | |
public int getSlot() { | |
return slot; | |
} | |
public ItemStack getItem() { | |
return item; | |
} | |
@Override | |
public String toString() { | |
return "CategoriaItem{" + | |
"key='" + key + '\'' + | |
", slot=" + slot + | |
", item=" + item + | |
'}'; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Categorias: | |
c1: | |
Tamanho: 27 | |
Nome: "&5Legal" | |
Items: | |
it1: | |
Slot: 10 | |
Material: CHEST | |
Nome: "&5Bau" | |
it2: | |
Slot: 11 | |
Material: DIAMOND | |
Nome: "&5Diamante" | |
c2: | |
Tamanho: 36 | |
Nome: "&5Legal +" | |
Items: | |
it1: | |
Slot: 10 | |
Material: IRON_INGOT | |
Nome: "&4Ferro" | |
it2: | |
Slot: 11 | |
Material: GOLD_INGOT | |
Nome: "&4Ouro" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public void onEnable() { | |
SectionBuilder.of(Combustivel.class, getConfig().getConfigurationSection("Combustiveis")) | |
.parameter("Icone", ItemStack.class) | |
.parameter("Litros", double.class) | |
.parameter("Infinito", boolean.class) | |
.parameter("Global", boolean.class) | |
.parameter("Delay", long.class) | |
.build().forEach(combustivel -> Bukkit.broadcastMessage(combustivel.toString())); | |
} | |
public class Combustivel { | |
private String id; | |
private ItemStack icon; | |
private double fuel; | |
private boolean infinite, global; | |
private long delay; | |
public Combustivel(String id, ItemStack icon, double fuel, boolean infinite, boolean global, long delay) { | |
this.id = id; | |
this.icon = icon; | |
this.fuel = fuel; | |
this.infinite = infinite; | |
this.global = global; | |
this.delay = delay; | |
} | |
public long getDelay() { | |
return delay; | |
} | |
public boolean isInfinite() { | |
return infinite; | |
} | |
public boolean isGlobal() { | |
return global; | |
} | |
public String getId() { | |
return id; | |
} | |
public ItemStack getCombustivel(double combustivel) { | |
if (combustivel <= 0) { | |
return new ItemStack(Material.AIR); | |
} | |
return new ItemComposer(icon.clone()).setLore(icon.getItemMeta().getLore().stream().map(lore -> lore.replace("<qntd>", "" + (combustivel))).collect(Collectors.toList())).toItemStack(); | |
} | |
public ItemStack getDefaultCombustivel() { | |
return getCombustivel(fuel); | |
} | |
public double getFuel() { | |
return fuel; | |
} | |
@Override | |
public String toString() { | |
return "Combustivel{" + | |
"id='" + id + '\'' + | |
", icon=" + icon + | |
", fuel=" + fuel + | |
", infinite=" + infinite + | |
", global=" + global + | |
", delay=" + delay + | |
'}'; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Combustiveis: | |
c1: | |
Infinito: false | |
Global: false | |
Delay: 0 | |
Litros: 50 | |
Icone: | |
Material: SKULL_ITEM | |
Texture: fa8887814578ce7c540d7ab8cc6b2a2e22a7492cc86c65a7e839c887b2ed62 | |
Nome: "&aCombustível" | |
Lore: | |
- "&7Utilize este item para" | |
- "&7abastecer suas máquinas." | |
- "" | |
- "&7 Este combustível possui" | |
- "&f <qntd>&7 litros!" | |
- "" | |
- "&aClique com o combustível em uma máquina." | |
c2: | |
Infinito: false | |
Global: false | |
Delay: 0 | |
Litros: 100 | |
Icone: | |
Material: MAGMA_CREAM | |
Nome: "&aCombustível" | |
Lore: | |
- "&7Utilize este item para" | |
- "&7abastecer suas máquinas." | |
- "" | |
- "&7 Este combustível possui" | |
- "&f <qntd>&7 litros!" | |
- "" | |
- "&aClique com o combustível em uma máquina." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment