From 3127e8f9d72d9eecfccf963f5d3ddadd8fffb2ad Mon Sep 17 00:00:00 2001 From: bentahsin Date: Tue, 2 Dec 2025 21:56:51 +0300 Subject: [PATCH 1/2] Enhance ConfigMapper with resetToDefaults method and improve validation in item conversion --- .../configuration/Configuration.java | 4 + .../converter/impl/ItemStackConverter.java | 138 +++++++++---- .../converter/impl/LocationConverter.java | 45 ++--- .../converter/impl/TimeConverter.java | 42 +--- .../configuration/core/ConfigMapper.java | 181 ++++++++++++------ .../bentahsin/configuration/util/Cuboid.java | 60 +++--- 6 files changed, 289 insertions(+), 181 deletions(-) diff --git a/src/main/java/com/bentahsin/configuration/Configuration.java b/src/main/java/com/bentahsin/configuration/Configuration.java index e0b4723..33e1100 100644 --- a/src/main/java/com/bentahsin/configuration/Configuration.java +++ b/src/main/java/com/bentahsin/configuration/Configuration.java @@ -54,6 +54,10 @@ public void init(Object configInstance, String fileName) { return; } + if (!loadFailed) { + mapper.resetToDefaults(configInstance); + } + if (!loadFailed) { handleBackupOnMigration(configInstance, yamlConfig, file); } diff --git a/src/main/java/com/bentahsin/configuration/converter/impl/ItemStackConverter.java b/src/main/java/com/bentahsin/configuration/converter/impl/ItemStackConverter.java index 19375ed..7dd73fb 100644 --- a/src/main/java/com/bentahsin/configuration/converter/impl/ItemStackConverter.java +++ b/src/main/java/com/bentahsin/configuration/converter/impl/ItemStackConverter.java @@ -3,12 +3,15 @@ import com.bentahsin.configuration.converter.Converter; import org.bukkit.Bukkit; import org.bukkit.ChatColor; +import org.bukkit.Color; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.*; +import org.bukkit.potion.PotionData; +import org.bukkit.potion.PotionType; import java.lang.reflect.Method; import java.util.*; @@ -25,63 +28,104 @@ public ItemStack convertToField(Map source) { Material material = Material.getMaterial(matStr.toUpperCase()); if (material == null) material = Material.STONE; - int amount = (int) source.getOrDefault("amount", 1); + int amount = 1; + if (source.get("amount") instanceof Number) { + amount = ((Number) source.get("amount")).intValue(); + } + ItemStack item = new ItemStack(material, amount); ItemMeta meta = item.getItemMeta(); if (meta != null) { + // --- Name --- if (source.containsKey("name")) { - meta.setDisplayName(color((String) source.get("name"))); + meta.setDisplayName(color(String.valueOf(source.get("name")))); } - if (source.containsKey("lore")) { - Object loreObj = source.get("lore"); - if (loreObj instanceof List) { - @SuppressWarnings("unchecked") - List rawLore = (List) loreObj; - meta.setLore(rawLore.stream().map(this::color).collect(Collectors.toList())); + // --- Lore (Güvenli Liste Dönüşümü) --- + if (source.get("lore") instanceof List) { + List rawList = (List) source.get("lore"); + List lore = new ArrayList<>(); + for (Object obj : rawList) { + if (obj != null) { + lore.add(color(obj.toString())); + } } + meta.setLore(lore); } - if (source.containsKey("custom_model_data") && source.get("custom_model_data") instanceof Integer) { - int data = (int) source.get("custom_model_data"); - setCustomModelData(meta, data); + // --- Custom Model Data --- + if (source.get("custom_model_data") instanceof Number) { + setCustomModelData(meta, ((Number) source.get("custom_model_data")).intValue()); } - if (source.containsKey("flags")) { - Object flagsObj = source.get("flags"); - if (flagsObj instanceof List) { - @SuppressWarnings("unchecked") - List flags = (List) flagsObj; - for (String f : flags) { + // --- Unbreakable --- + if (source.containsKey("unbreakable") && source.get("unbreakable") instanceof Boolean) { + meta.setUnbreakable((boolean) source.get("unbreakable")); + } + + // --- Flags (Güvenli Liste Dönüşümü) --- + if (source.get("flags") instanceof List) { + List flags = (List) source.get("flags"); + for (Object obj : flags) { + if (obj instanceof String) { try { - meta.addItemFlags(ItemFlag.valueOf(f.toUpperCase())); + meta.addItemFlags(ItemFlag.valueOf(((String) obj).toUpperCase())); } catch (IllegalArgumentException ignored) {} } } } - if (source.containsKey("enchantments")) { - Object enchsObj = source.get("enchantments"); - if (enchsObj instanceof Map) { - @SuppressWarnings("unchecked") - Map enchs = (Map) enchsObj; - - for (Map.Entry entry : enchs.entrySet()) { - Enchantment ench = getEnchantment(entry.getKey()); - if (ench != null && entry.getValue() instanceof Integer) { - meta.addEnchant(ench, (int) entry.getValue(), true); + // --- Enchantments (Güvenli Map Dönüşümü) --- + if (source.get("enchantments") instanceof Map) { + Map enchs = (Map) source.get("enchantments"); + for (Map.Entry entry : enchs.entrySet()) { + if (entry.getKey() instanceof String && entry.getValue() instanceof Number) { + Enchantment ench = getEnchantment((String) entry.getKey()); + if (ench != null) { + meta.addEnchant(ench, ((Number) entry.getValue()).intValue(), true); } } } } + // --- ÖZEL META TİPLERİ --- + + // 1. Deri Zırh Boyası + if (meta instanceof LeatherArmorMeta && source.containsKey("color")) { + String hex = String.valueOf(source.get("color")); + if (hex.startsWith("#") && hex.length() == 7) { + try { + ((LeatherArmorMeta) meta).setColor(Color.fromRGB( + Integer.valueOf(hex.substring(1, 3), 16), + Integer.valueOf(hex.substring(3, 5), 16), + Integer.valueOf(hex.substring(5, 7), 16) + )); + } catch (Exception ignored) {} + } + } + + // 2. Oyuncu Kafası (Skull) + if (meta instanceof SkullMeta && source.containsKey("skull_owner")) { + ((SkullMeta) meta).setOwner(String.valueOf(source.get("skull_owner"))); + } + + // 3. İksirler (Potion) + if (meta instanceof PotionMeta && source.containsKey("potion_type")) { + try { + PotionType type = PotionType.valueOf(String.valueOf(source.get("potion_type")).toUpperCase()); + boolean extended = (boolean) source.getOrDefault("potion_extended", false); + boolean upgraded = (boolean) source.getOrDefault("potion_upgraded", false); + ((PotionMeta) meta).setBasePotionData(new PotionData(type, extended, upgraded)); + } catch (Exception ignored) {} + } + item.setItemMeta(meta); } return item; } catch (Exception e) { - Bukkit.getLogger().log(Level.WARNING, "[Configuration] Encountered an error while transforming ItemStack!", e); + Bukkit.getLogger().log(Level.WARNING, "[Configuration] Error loading ItemStack!", e); return new ItemStack(Material.AIR); } } @@ -107,10 +151,10 @@ public Map convertToConfig(ItemStack item) { .collect(Collectors.toList())); } - Integer customModelData = getCustomModelData(meta); - if (customModelData != null) { - map.put("custom_model_data", customModelData); - } + Integer cmd = getCustomModelData(meta); + if (cmd != null) map.put("custom_model_data", cmd); + + if (meta.isUnbreakable()) map.put("unbreakable", true); if (!meta.getItemFlags().isEmpty()) { List flags = new ArrayList<>(); @@ -121,11 +165,32 @@ public Map convertToConfig(ItemStack item) { if (meta.hasEnchants()) { Map enchs = new LinkedHashMap<>(); for (Map.Entry entry : meta.getEnchants().entrySet()) { - String enchName = getEnchantmentName(entry.getKey()); - enchs.put(enchName, entry.getValue()); + enchs.put(getEnchantmentName(entry.getKey()), entry.getValue()); } map.put("enchantments", enchs); } + + // --- ÖZEL META KAYITLARI --- + + if (meta instanceof LeatherArmorMeta) { + Color color = ((LeatherArmorMeta) meta).getColor(); + String hex = String.format("#%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue()); + map.put("color", hex); + } + + if (meta instanceof SkullMeta) { + SkullMeta skull = (SkullMeta) meta; + if (skull.hasOwner()) { + map.put("skull_owner", skull.getOwner()); + } + } + + if (meta instanceof PotionMeta) { + PotionData data = ((PotionMeta) meta).getBasePotionData(); + map.put("potion_type", data.getType().name()); + if (data.isExtended()) map.put("potion_extended", true); + if (data.isUpgraded()) map.put("potion_upgraded", true); + } } return map; } @@ -134,7 +199,6 @@ private String color(String s) { return ChatColor.translateAlternateColorCodes('&', s); } - private void setCustomModelData(ItemMeta meta, int data) { try { Method method = meta.getClass().getMethod("setCustomModelData", Integer.class); diff --git a/src/main/java/com/bentahsin/configuration/converter/impl/LocationConverter.java b/src/main/java/com/bentahsin/configuration/converter/impl/LocationConverter.java index 11135bd..4d713b4 100644 --- a/src/main/java/com/bentahsin/configuration/converter/impl/LocationConverter.java +++ b/src/main/java/com/bentahsin/configuration/converter/impl/LocationConverter.java @@ -10,38 +10,27 @@ @SuppressWarnings("unused") public class LocationConverter implements Converter { - /** - * Config'den gelen String veriyi (örn: "world,100,64,200,90,0") Location nesnesine çevirir. - */ @Override public Location convertToField(String source) { - if (source == null || !source.contains(",")) { - return null; - } + if (source == null || !source.contains(",")) return null; try { String[] parts = source.split(","); - - if (parts.length < 4) { - return null; - } + if (parts.length < 4) return null; String worldName = parts[0]; World world = Bukkit.getWorld(worldName); + if (world == null) { + Bukkit.getLogger().warning("[Configuration] World '" + worldName + "' not found for location!"); + return null; + } + double x = Double.parseDouble(parts[1]); double y = Double.parseDouble(parts[2]); double z = Double.parseDouble(parts[3]); - - float yaw = 0; - float pitch = 0; - - if (parts.length > 4) { - yaw = Float.parseFloat(parts[4]); - } - if (parts.length > 5) { - pitch = Float.parseFloat(parts[5]); - } + float yaw = parts.length > 4 ? Float.parseFloat(parts[4]) : 0; + float pitch = parts.length > 5 ? Float.parseFloat(parts[5]) : 0; return new Location(world, x, y, z, yaw, pitch); @@ -50,15 +39,11 @@ public Location convertToField(String source) { } } - /** - * Location nesnesini Config için sıkıştırılmış String formatına çevirir. - */ @Override public String convertToConfig(Location loc) { - if (loc == null) return null; + if (loc == null || loc.getWorld() == null) return null; - String worldName = (loc.getWorld() != null) ? loc.getWorld().getName() : "world"; - return worldName + "," + + return loc.getWorld().getName() + "," + format(loc.getX()) + "," + format(loc.getY()) + "," + format(loc.getZ()) + "," + @@ -66,14 +51,8 @@ public String convertToConfig(Location loc) { format(loc.getPitch()); } - /** - * Sayıları temiz formatlar. - * Örn: 10.0 -> "10", 10.5678 -> "10.57" - */ private String format(double d) { - if (d == (long) d) { - return String.format(Locale.ENGLISH, "%d", (long) d); - } + if (d == (long) d) return String.format(Locale.ENGLISH, "%d", (long) d); return String.format(Locale.ENGLISH, "%.2f", d); } } \ No newline at end of file diff --git a/src/main/java/com/bentahsin/configuration/converter/impl/TimeConverter.java b/src/main/java/com/bentahsin/configuration/converter/impl/TimeConverter.java index e45ca25..bb9526f 100644 --- a/src/main/java/com/bentahsin/configuration/converter/impl/TimeConverter.java +++ b/src/main/java/com/bentahsin/configuration/converter/impl/TimeConverter.java @@ -1,35 +1,25 @@ package com.bentahsin.configuration.converter.impl; import com.bentahsin.configuration.converter.Converter; - import java.util.concurrent.TimeUnit; @SuppressWarnings("unused") public class TimeConverter implements Converter { - /** - * Config'den gelen String süreyi (örn: "1h 10m") saniyeye (Long) çevirir. - */ @Override public Long convertToField(String source) { if (source == null || source.isEmpty()) return 0L; return parseTime(source); } - /** - * Sınıftaki saniye değerini (Long), Config için okunabilir formata (örn: "1h 5m 30s") çevirir. - */ @Override public String convertToConfig(Long source) { if (source == null || source == 0) return "0s"; - long seconds = source; long days = TimeUnit.SECONDS.toDays(seconds); seconds -= TimeUnit.DAYS.toSeconds(days); - long hours = TimeUnit.SECONDS.toHours(seconds); seconds -= TimeUnit.HOURS.toSeconds(hours); - long minutes = TimeUnit.SECONDS.toMinutes(seconds); seconds -= TimeUnit.MINUTES.toSeconds(minutes); @@ -38,42 +28,28 @@ public String convertToConfig(Long source) { if (hours > 0) sb.append(hours).append("h "); if (minutes > 0) sb.append(minutes).append("m "); if (seconds > 0) sb.append(seconds).append("s"); - return sb.toString().trim(); } - /** - * Zaman formatını ayrıştıran gelişmiş parser. - * Desteklenen formatlar: 1d, 10h, 30m, 45s ve bunların kombinasyonları. - * Örn: "1h 30m", "100s", "5m" - */ private long parseTime(String timeStr) { - long totalSeconds = 0; + double totalSeconds = 0; StringBuilder numberBuffer = new StringBuilder(); for (char c : timeStr.toLowerCase().toCharArray()) { if (Character.isWhitespace(c)) continue; - if (Character.isDigit(c)) { + if (Character.isDigit(c) || c == '.') { numberBuffer.append(c); } else if (Character.isLetter(c)) { if (numberBuffer.length() == 0) continue; try { - long val = Long.parseLong(numberBuffer.toString()); + double val = Double.parseDouble(numberBuffer.toString()); switch (c) { - case 'd': - totalSeconds += val * 86400; - break; - case 'h': - totalSeconds += val * 3600; - break; - case 'm': - totalSeconds += val * 60; - break; - case 's': - totalSeconds += val; - break; + case 'd': totalSeconds += val * 86400; break; + case 'h': totalSeconds += val * 3600; break; + case 'm': totalSeconds += val * 60; break; + case 's': totalSeconds += val; break; } } catch (NumberFormatException ignored) {} numberBuffer.setLength(0); @@ -82,10 +58,10 @@ private long parseTime(String timeStr) { if (numberBuffer.length() > 0) { try { - totalSeconds += Long.parseLong(numberBuffer.toString()); + totalSeconds += Double.parseDouble(numberBuffer.toString()); } catch (NumberFormatException ignored) {} } - return totalSeconds; + return (long) totalSeconds; } } \ No newline at end of file diff --git a/src/main/java/com/bentahsin/configuration/core/ConfigMapper.java b/src/main/java/com/bentahsin/configuration/core/ConfigMapper.java index e3bdba9..b5a7d8d 100644 --- a/src/main/java/com/bentahsin/configuration/core/ConfigMapper.java +++ b/src/main/java/com/bentahsin/configuration/core/ConfigMapper.java @@ -9,6 +9,7 @@ import java.lang.reflect.*; import java.util.*; import java.util.logging.Logger; +import java.util.regex.Pattern; public class ConfigMapper { @@ -18,6 +19,31 @@ public ConfigMapper(Logger logger) { this.logger = logger; } + public void resetToDefaults(Object instance) { + try { + Constructor constructor = instance.getClass().getDeclaredConstructor(); + if (!trySetAccessible(constructor)) return; + Object freshInstance = constructor.newInstance(); + + for (Field field : instance.getClass().getDeclaredFields()) { + if (!shouldProcess(field)) continue; + if (!trySetAccessible(field)) continue; + + Object defaultValue = field.get(freshInstance); + field.set(instance, defaultValue); + } + } catch (NoSuchMethodException e) { + if (instance.getClass().getEnclosingClass() != null && !Modifier.isStatic(instance.getClass().getModifiers())) { + logger.severe("CRITICAL ERROR: Config class '" + instance.getClass().getSimpleName() + "' is an Inner Class but NOT STATIC."); + logger.severe("Please make it static: 'public static class " + instance.getClass().getSimpleName() + "'"); + } else { + logger.severe("Config reset failed. Does '" + instance.getClass().getSimpleName() + "' have a no-args constructor?"); + } + } catch (Exception e) { + logger.severe("Error resetting config: " + e.getMessage()); + } + } + public void handleVersion(Object instance, ConfigurationSection config) { if (!instance.getClass().isAnnotationPresent(ConfigVersion.class)) return; @@ -187,9 +213,27 @@ private void handleListLoad(Object instance, Field field, ConfigurationSection c if (!config.contains(path)) return; Class genericType = getListType(field); + List rawList = config.getList(path); + + if (rawList == null) return; if (genericType == String.class || isPrimitive(genericType)) { - field.set(instance, config.getList(path)); + List validatedList = new ArrayList<>(); + Validate validate = field.getAnnotation(Validate.class); + + for (Object obj : rawList) { + if (validate != null && !isValid(field.getName() + " (List Element)", obj, validate)) { + continue; + } + + Object converted = convertPrimitive(obj, genericType); + if (converted != null) { + validatedList.add(converted); + } else { + validatedList.add(obj); + } + } + field.set(instance, validatedList); return; } @@ -198,10 +242,10 @@ private void handleListLoad(Object instance, Field field, ConfigurationSection c return; } - List> rawList = config.getMapList(path); + List> rawMapList = config.getMapList(path); List resultList = new ArrayList<>(); - for (Map rawMap : rawList) { + for (Map rawMap : rawMapList) { Object itemInstance = genericType.getDeclaredConstructor().newInstance(); MemoryConfiguration tempConfig = new MemoryConfiguration(); @@ -225,12 +269,18 @@ private void handleListSave(Field field, ConfigurationSection config, String pat Class genericType = getListType(field); if (genericType == String.class || isPrimitive(genericType) || Map.class.isAssignableFrom(genericType)) { - config.set(path, list); + List cleanList = new ArrayList<>(); + for (Object o : list) { + if (o != null) cleanList.add(o); + } + config.set(path, cleanList); return; } List> mapList = new ArrayList<>(); for (Object obj : list) { + if (obj == null) continue; + Map objectMap = new LinkedHashMap<>(); for (Field objField : obj.getClass().getDeclaredFields()) { if (!shouldProcess(objField)) continue; @@ -304,12 +354,18 @@ private Class getMapKeyType(Field field) { return String.class; } - @SuppressWarnings({"unchecked", "rawtypes"}) + @SuppressWarnings({"rawtypes"}) private Object convertKey(String key, Class targetType) { try { if (targetType == String.class) return key; if (targetType.isEnum()) { - return Enum.valueOf((Class) targetType, key.toUpperCase(Locale.ENGLISH)); + for (Object enumConstant : targetType.getEnumConstants()) { + if (((Enum) enumConstant).name().equalsIgnoreCase(key)) { + return enumConstant; + } + } + logger.warning("Enum key not found: " + key); + return null; } if (targetType == Integer.class || targetType == int.class) return Integer.parseInt(key); if (targetType == Long.class || targetType == long.class) return Long.parseLong(key); @@ -407,6 +463,7 @@ private boolean isComplexObject(Class type) { private boolean isPrimitive(Class type) { return type.isPrimitive() || type == String.class || + type == Character.class || Number.class.isAssignableFrom(type) || Boolean.class.isAssignableFrom(type); } @@ -419,76 +476,90 @@ private void applyConverter(Object instance, Field field, Object value) throws E field.set(instance, convertedValue); } - private void safeSetField(Object instance, Field field, Object value) throws IllegalAccessException { - Class type = field.getType(); - - if (field.isAnnotationPresent(Validate.class)) { - Validate validate = field.getAnnotation(Validate.class); - - if (value == null) { - if (validate.notNull()) { - logger.warning("Config Error: " + field.getName() + " cannot be null!"); - } - return; + private boolean isValid(String fieldName, Object value, Validate validate) { + if (value == null) { + if (validate.notNull()) { + logger.warning("Config Error: " + fieldName + " cannot be null!"); + return false; } + return true; + } - if (value instanceof Number) { - double val = ((Number) value).doubleValue(); - if (val < validate.min() || val > validate.max()) { - logger.warning(String.format("Config Limit Error (%s): %s (Min:%s Max:%s)", field.getName(), val, validate.min(), validate.max())); - return; - } + if (value instanceof Number) { + double val = ((Number) value).doubleValue(); + if (val < validate.min() || val > validate.max()) { + logger.warning(String.format("Config Limit Error (%s): %s (Min:%s Max:%s)", fieldName, val, validate.min(), validate.max())); + return false; } + } - if (value instanceof String && !validate.pattern().isEmpty()) { - String strVal = (String) value; - if (!strVal.matches(validate.pattern())) { - logger.warning("Config Format Error (" + field.getName() + "): Value '" + strVal + "' does not match format."); - logger.warning("Expected Regex: " + validate.pattern()); - return; + if (value instanceof String && !validate.pattern().isEmpty()) { + String strVal = (String) value; + try { + if (!Pattern.matches(validate.pattern(), strVal)) { + logger.warning("Config Format Error (" + fieldName + "): Value '" + strVal + "' does not match regex: " + validate.pattern()); + return false; } + } catch (Exception e) { + logger.warning("Invalid Regex pattern in code for field: " + fieldName); } } + return true; + } + private void safeSetField(Object instance, Field field, Object value) throws IllegalAccessException { + if (field.isAnnotationPresent(Validate.class)) { + if (!isValid(field.getName(), value, field.getAnnotation(Validate.class))) { + return; + } + } if (value == null) return; + Class type = field.getType(); - if (type.isEnum()) { - if (value instanceof String) { - try { - @SuppressWarnings({"unchecked", "rawtypes"}) - Enum enumValue = Enum.valueOf((Class) type, ((String) value).toUpperCase(Locale.ENGLISH)); - field.set(instance, enumValue); - } catch (IllegalArgumentException e) { - logger.warning("Enum Error: '" + field.getName() + "' invalid: " + value); + if (type.isEnum() && value instanceof String) { + boolean found = false; + for (Object enumConstant : type.getEnumConstants()) { + if (((Enum) enumConstant).name().equalsIgnoreCase((String) value)) { + field.set(instance, enumConstant); + found = true; + break; } } + if (!found) { + logger.warning("Enum Error: '" + field.getName() + "' invalid value: " + value); + } return; } - if (value instanceof Number) { - Number num = (Number) value; - if (type == int.class || type == Integer.class) field.set(instance, num.intValue()); - else if (type == long.class || type == Long.class) field.set(instance, num.longValue()); - else if (type == double.class || type == Double.class) field.set(instance, num.doubleValue()); - else if (type == float.class || type == Float.class) field.set(instance, num.floatValue()); - else if (type == short.class || type == Short.class) field.set(instance, num.shortValue()); - else if (type == byte.class || type == Byte.class) field.set(instance, num.byteValue()); - else if (type == String.class) field.set(instance, num.toString()); - return; - } - - if (type == String.class && !(value instanceof String)) { - field.set(instance, value.toString()); - return; - } - - if (type.isAssignableFrom(value.getClass())) { + Object converted = convertPrimitive(value, type); + if (converted != null) { + field.set(instance, converted); + } else if (type.isAssignableFrom(value.getClass())) { field.set(instance, value); } else { logger.warning("Type Mismatch: '" + field.getName() + "' Expected: " + type.getSimpleName() + ", Got: " + value.getClass().getSimpleName()); } } + private Object convertPrimitive(Object value, Class targetType) { + if (value instanceof Number) { + Number num = (Number) value; + if (targetType == int.class || targetType == Integer.class) return num.intValue(); + if (targetType == long.class || targetType == Long.class) return num.longValue(); + if (targetType == double.class || targetType == Double.class) return num.doubleValue(); + if (targetType == float.class || targetType == Float.class) return num.floatValue(); + if (targetType == short.class || targetType == Short.class) return num.shortValue(); + if (targetType == byte.class || targetType == Byte.class) return num.byteValue(); + if (targetType == String.class) return num.toString(); + } + if (targetType == String.class) return value.toString(); + if ((targetType == char.class || targetType == Character.class) && value instanceof String) { + String s = (String) value; + if (!s.isEmpty()) return s.charAt(0); + } + return null; + } + private boolean shouldProcess(Field field) { return !Modifier.isStatic(field.getModifiers()) && !Modifier.isFinal(field.getModifiers()) && diff --git a/src/main/java/com/bentahsin/configuration/util/Cuboid.java b/src/main/java/com/bentahsin/configuration/util/Cuboid.java index 6f1289f..6e117ba 100644 --- a/src/main/java/com/bentahsin/configuration/util/Cuboid.java +++ b/src/main/java/com/bentahsin/configuration/util/Cuboid.java @@ -2,9 +2,11 @@ import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.World; import java.util.Objects; +@SuppressWarnings("unused") public class Cuboid { private final String worldName; private final int x1, y1, z1; @@ -12,42 +14,54 @@ public class Cuboid { public Cuboid(String worldName, int x1, int y1, int z1, int x2, int y2, int z2) { this.worldName = worldName; - this.x1 = Math.min(x1, x2); - this.y1 = Math.min(y1, y2); - this.z1 = Math.min(z1, z2); - this.x2 = Math.max(x1, x2); - this.y2 = Math.max(y1, y2); - this.z2 = Math.max(z1, z2); + this.x1 = x1; + this.y1 = y1; + this.z1 = z1; + this.x2 = x2; + this.y2 = y2; + this.z2 = z2; } - @SuppressWarnings("unused") public Cuboid(Location l1, Location l2) { - if (!Objects.equals(l1.getWorld(), l2.getWorld())) throw new IllegalArgumentException("Locations must be in the same world"); + if (!Objects.equals(l1.getWorld(), l2.getWorld())) + throw new IllegalArgumentException("Locations must be in the same world"); this.worldName = Objects.requireNonNull(l1.getWorld()).getName(); - this.x1 = Math.min(l1.getBlockX(), l2.getBlockX()); - this.y1 = Math.min(l1.getBlockY(), l2.getBlockY()); - this.z1 = Math.min(l1.getBlockZ(), l2.getBlockZ()); - this.x2 = Math.max(l1.getBlockX(), l2.getBlockX()); - this.y2 = Math.max(l1.getBlockY(), l2.getBlockY()); - this.z2 = Math.max(l1.getBlockZ(), l2.getBlockZ()); + this.x1 = l1.getBlockX(); + this.y1 = l1.getBlockY(); + this.z1 = l1.getBlockZ(); + this.x2 = l2.getBlockX(); + this.y2 = l2.getBlockY(); + this.z2 = l2.getBlockZ(); } - @SuppressWarnings("unused") public boolean contains(Location loc) { if (!Objects.requireNonNull(loc.getWorld()).getName().equals(worldName)) return false; - return loc.getBlockX() >= x1 && loc.getBlockX() <= x2 && - loc.getBlockY() >= y1 && loc.getBlockY() <= y2 && - loc.getBlockZ() >= z1 && loc.getBlockZ() <= z2; + int minX = Math.min(x1, x2), maxX = Math.max(x1, x2); + int minY = Math.min(y1, y2), maxY = Math.max(y1, y2); + int minZ = Math.min(z1, z2), maxZ = Math.max(z1, z2); + + return loc.getBlockX() >= minX && loc.getBlockX() <= maxX && + loc.getBlockY() >= minY && loc.getBlockY() <= maxY && + loc.getBlockZ() >= minZ && loc.getBlockZ() <= maxZ; } - @SuppressWarnings("unused") public Location getCenter() { - return new Location(Bukkit.getWorld(worldName), - x1 + (x2 - x1) / 2.0, - y1 + (y2 - y1) / 2.0, - z1 + (z2 - z1) / 2.0); + World world = Bukkit.getWorld(worldName); + if (world == null) return null; + return new Location(world, + (x1 + x2) / 2.0, + (y1 + y2) / 2.0, + (z1 + z2) / 2.0); } + public String getWorldName() { return worldName; } + public int getX1() { return x1; } + public int getY1() { return y1; } + public int getZ1() { return z1; } + public int getX2() { return x2; } + public int getY2() { return y2; } + public int getZ2() { return z2; } + @Override public String toString() { return worldName + "," + x1 + "," + y1 + "," + z1 + "," + x2 + "," + y2 + "," + z2; From 7801838f9b9a5c19ac384023655844dd41b20638 Mon Sep 17 00:00:00 2001 From: bentahsin Date: Tue, 2 Dec 2025 22:08:31 +0300 Subject: [PATCH 2/2] Improve error handling and logging in ConfigMapper and ItemStackConverter --- .../converter/impl/ItemStackConverter.java | 21 ++++++------------- .../converter/impl/TimeConverter.java | 2 +- .../configuration/core/ConfigMapper.java | 2 ++ 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/bentahsin/configuration/converter/impl/ItemStackConverter.java b/src/main/java/com/bentahsin/configuration/converter/impl/ItemStackConverter.java index 7dd73fb..4510023 100644 --- a/src/main/java/com/bentahsin/configuration/converter/impl/ItemStackConverter.java +++ b/src/main/java/com/bentahsin/configuration/converter/impl/ItemStackConverter.java @@ -37,12 +37,10 @@ public ItemStack convertToField(Map source) { ItemMeta meta = item.getItemMeta(); if (meta != null) { - // --- Name --- if (source.containsKey("name")) { meta.setDisplayName(color(String.valueOf(source.get("name")))); } - // --- Lore (Güvenli Liste Dönüşümü) --- if (source.get("lore") instanceof List) { List rawList = (List) source.get("lore"); List lore = new ArrayList<>(); @@ -54,17 +52,14 @@ public ItemStack convertToField(Map source) { meta.setLore(lore); } - // --- Custom Model Data --- if (source.get("custom_model_data") instanceof Number) { setCustomModelData(meta, ((Number) source.get("custom_model_data")).intValue()); } - // --- Unbreakable --- if (source.containsKey("unbreakable") && source.get("unbreakable") instanceof Boolean) { meta.setUnbreakable((boolean) source.get("unbreakable")); } - // --- Flags (Güvenli Liste Dönüşümü) --- if (source.get("flags") instanceof List) { List flags = (List) source.get("flags"); for (Object obj : flags) { @@ -76,7 +71,6 @@ public ItemStack convertToField(Map source) { } } - // --- Enchantments (Güvenli Map Dönüşümü) --- if (source.get("enchantments") instanceof Map) { Map enchs = (Map) source.get("enchantments"); for (Map.Entry entry : enchs.entrySet()) { @@ -89,9 +83,6 @@ public ItemStack convertToField(Map source) { } } - // --- ÖZEL META TİPLERİ --- - - // 1. Deri Zırh Boyası if (meta instanceof LeatherArmorMeta && source.containsKey("color")) { String hex = String.valueOf(source.get("color")); if (hex.startsWith("#") && hex.length() == 7) { @@ -105,12 +96,10 @@ public ItemStack convertToField(Map source) { } } - // 2. Oyuncu Kafası (Skull) if (meta instanceof SkullMeta && source.containsKey("skull_owner")) { ((SkullMeta) meta).setOwner(String.valueOf(source.get("skull_owner"))); } - // 3. İksirler (Potion) if (meta instanceof PotionMeta && source.containsKey("potion_type")) { try { PotionType type = PotionType.valueOf(String.valueOf(source.get("potion_type")).toUpperCase()); @@ -170,12 +159,14 @@ public Map convertToConfig(ItemStack item) { map.put("enchantments", enchs); } - // --- ÖZEL META KAYITLARI --- - if (meta instanceof LeatherArmorMeta) { Color color = ((LeatherArmorMeta) meta).getColor(); - String hex = String.format("#%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue()); - map.put("color", hex); + Color defaultColor = Bukkit.getItemFactory().getDefaultLeatherColor(); + + if (!color.equals(defaultColor)) { + String hex = String.format("#%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue()); + map.put("color", hex); + } } if (meta instanceof SkullMeta) { diff --git a/src/main/java/com/bentahsin/configuration/converter/impl/TimeConverter.java b/src/main/java/com/bentahsin/configuration/converter/impl/TimeConverter.java index bb9526f..6adce37 100644 --- a/src/main/java/com/bentahsin/configuration/converter/impl/TimeConverter.java +++ b/src/main/java/com/bentahsin/configuration/converter/impl/TimeConverter.java @@ -62,6 +62,6 @@ private long parseTime(String timeStr) { } catch (NumberFormatException ignored) {} } - return (long) totalSeconds; + return Math.round(totalSeconds); } } \ No newline at end of file diff --git a/src/main/java/com/bentahsin/configuration/core/ConfigMapper.java b/src/main/java/com/bentahsin/configuration/core/ConfigMapper.java index b5a7d8d..dfb6d69 100644 --- a/src/main/java/com/bentahsin/configuration/core/ConfigMapper.java +++ b/src/main/java/com/bentahsin/configuration/core/ConfigMapper.java @@ -502,6 +502,7 @@ private boolean isValid(String fieldName, Object value, Validate validate) { } } catch (Exception e) { logger.warning("Invalid Regex pattern in code for field: " + fieldName); + return false; } } return true; @@ -556,6 +557,7 @@ private Object convertPrimitive(Object value, Class targetType) { if ((targetType == char.class || targetType == Character.class) && value instanceof String) { String s = (String) value; if (!s.isEmpty()) return s.charAt(0); + logger.warning("Character Conversion Warning: Empty string provided for Character field; returning null."); } return null; }