From 78a427314069bb4036b51bb913953fc68afb692e Mon Sep 17 00:00:00 2001 From: Pablete1234 Date: Thu, 22 Sep 2016 02:27:59 +0200 Subject: [PATCH] Improve module errors, and add ModuleReporter --- build.gradle | 2 + gradle/wrapper/gradle-wrapper.properties | 2 +- .../twizmwaz/cardinal/module/ModuleError.java | 32 +++ .../cardinal/module/ModuleReporter.java | 173 ++++++++++++++++ .../twizmwaz/cardinal/module/id/IdModule.java | 10 + .../cardinal/module/objective/Objective.java | 1 - .../cardinal/module/objective/core/Core.java | 5 +- .../module/objective/core/CoreModule.java | 2 +- .../objective/destroyable/Destroyable.java | 5 +- .../destroyable/DestroyableModule.java | 2 +- .../cardinal/module/objective/wool/Wool.java | 4 +- .../module/objective/wool/WoolModule.java | 191 ++++-------------- .../twizmwaz/cardinal/util/document/XML.java | 84 ++++++++ 13 files changed, 351 insertions(+), 162 deletions(-) create mode 100644 src/main/java/in/twizmwaz/cardinal/module/ModuleReporter.java create mode 100644 src/main/java/in/twizmwaz/cardinal/util/document/XML.java diff --git a/build.gradle b/build.gradle index 215afac..f7b328d 100644 --- a/build.gradle +++ b/build.gradle @@ -37,6 +37,7 @@ dependencies { compile 'ee.ellytr.command:EllyCommand:2.0.4' compile 'ee.ellytr.chat:EllyChat:1.2.6' compile 'org.jdom:jdom2:2.0.6' + compile 'org.jdom:jdom2-contrib:2.0.5' compile 'org.ow2.asm:asm-all:5.0.4' testCompile('junit:junit:4.12') @@ -57,6 +58,7 @@ shadowJar { append('LICENSE') dependencies { include(dependency('org.jdom:jdom2:2.0.6')) + include(dependency('org.jdom:jdom2-contrib:2.0.5')) relocate 'org.jdom2', 'in.twizmwaz.cardinal.libs.jdom2' include(dependency('org.ow2.asm:asm-all:5.0.4')) relocate 'org.objectweb.asm', 'in.twizmwaz.cardinal.libs.asm' diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0d876fc..939660a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Tue Apr 26 23:37:45 EDT 2016 +#Thu Sep 22 02:07:06 CEST 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/src/main/java/in/twizmwaz/cardinal/module/ModuleError.java b/src/main/java/in/twizmwaz/cardinal/module/ModuleError.java index be1c444..c275e77 100644 --- a/src/main/java/in/twizmwaz/cardinal/module/ModuleError.java +++ b/src/main/java/in/twizmwaz/cardinal/module/ModuleError.java @@ -26,9 +26,14 @@ package in.twizmwaz.cardinal.module; import in.twizmwaz.cardinal.module.repository.LoadedMap; +import lombok.AllArgsConstructor; import lombok.Data; +import org.jdom2.Attribute; +import org.jdom2.Element; +import org.jdom2.contrib.input.LineNumberElement; @Data +@AllArgsConstructor public final class ModuleError { private final Module module; @@ -36,4 +41,31 @@ public final class ModuleError { private final String[] message; private final boolean critical; + public ModuleError(Module module, LoadedMap map, boolean critical, String... message) { + this(module, map, message, critical); + } + + public ModuleError(Module module, LoadedMap map, Element element, String message, boolean critical) { + this(module, map, critical, getErrorLocation(element), message); + } + + public ModuleError(Module module, LoadedMap map, Attribute attr, String message, boolean critical) { + this(module, map, critical, getErrorLocation(attr), message); + } + + private static String getErrorLocation(Element element) { + String result = "'" + element.getName() + "' element"; + if (element instanceof LineNumberElement) { + LineNumberElement lineElement = (LineNumberElement) element; + result += lineElement.getStartLine() == lineElement.getEndLine() + ? " on line " + lineElement.getStartLine() + : " from line " + lineElement.getStartLine() + " to " + lineElement.getEndLine(); + } + return result; + } + + private static String getErrorLocation(Attribute attribute) { + return "'" + attribute.getName() + "' attribute in " + getErrorLocation(attribute.getParent()); + } + } diff --git a/src/main/java/in/twizmwaz/cardinal/module/ModuleReporter.java b/src/main/java/in/twizmwaz/cardinal/module/ModuleReporter.java new file mode 100644 index 0000000..5857de7 --- /dev/null +++ b/src/main/java/in/twizmwaz/cardinal/module/ModuleReporter.java @@ -0,0 +1,173 @@ +package in.twizmwaz.cardinal.module; + +import in.twizmwaz.cardinal.match.Match; +import in.twizmwaz.cardinal.module.id.IdModule; +import in.twizmwaz.cardinal.module.repository.LoadedMap; +import in.twizmwaz.cardinal.util.ParseUtil; +import in.twizmwaz.cardinal.util.document.XML; +import lombok.Getter; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.jdom2.Attribute; +import org.jdom2.Element; + +@RequiredArgsConstructor +public class ModuleReporter { + + private final Module module; + private final LoadedMap map; + @Getter + private final Match match; + + public ModuleReporter(Module module, Match match) { + this(module, match.getMap(), match); + } + + @Getter + private boolean canLoad = false; + + public void reset() { + canLoad = true; + } + + /** + * Gets an attribute value from an element. If it fails to get a value, en error will be thrown. + * @param element The element to get the attribute from. + * @param attr The attribute to get. + * @param type The class of the type to convert the attribute to. + * @param The type to convert the attribute value to. + * @return An object of the correct type, or null if argument is missing or invalid. + */ + public T getAttr(Element element, String attr, Class type) { + return getAttr(element, attr, type, null, true); + } + + /** + * Gets an attribute value from an element. Defaults to fallback if not found. + * @param element The element to get the attribute from. + * @param attr The attribute to get. + * @param type The class of the type to convert the attribute to. + * @param fallback The fallback in case it's null or an error is thrown, null can be used as fallback. + * @param The type to convert the attribute value to. + * @return An object of the correct type, or null if argument is missing or invalid. + */ + public T getAttr(Element element, String attr, Class type, T fallback) { + return getAttr(element, attr, type, fallback, false); + } + + private T getAttr(Element element, String attr, Class type, T fallback, boolean required) { + Attribute attribute = element.getAttribute(attr); + if (required && attribute == null) { + module.getErrors().add(new ModuleError(module, map, element, "Missing required attribute:'" + attr + "'", false)); + return null; + } + T result = getAttribute(attribute, type); + if (required && result == null) { + canLoad = false; + } + return result != null ? result : fallback; + } + + private T getAttribute(Attribute attr, Class type) { + try { + return XML.getAttribute(attr, type); + } catch (Exception e) { + module.getErrors().add(new ModuleError(module, map, attr, e.getMessage(), false)); + } + return null; + } + + /** + * Gets an attribute value from an element. If it fails to get a value, en error will be thrown. + * @param element The element to get the object from. + * @param type The class of the type to convert the element to. + * @param The type to convert the attribute value to. + * @return An object of the correct type, or null if argument is missing or invalid. + */ + public T getEl(Element element, Class type) { + return getEl(element, type, null, true); + } + + /** + * Gets an attribute value from an element. + * @param element The element to get the object from. + * @param type The class of the type to convert the element to. + * @param fallback The fallback in case it's null or an error is thrown, null can be used as fallback. + * @param The type to convert the attribute value to. + * @return An object of the correct type, or null if argument is missing or invalid. + */ + public T getEl(@NonNull Element element, Class type, T fallback) { + return getEl(element, type, fallback, false); + } + + private T getEl(@NonNull Element element, Class type, T fallback, boolean required) { + T result = getElement(element, type); + if (required && result == null) { + canLoad = false; + } + return result != null ? result : fallback; + } + + private T getElement(Element el, Class type) { + try { + return XML.getElementObject(el, type); + } catch (Exception e) { + module.getErrors().add(new ModuleError(module, map, el, e.getMessage(), false)); + } + return null; + } + + /** + * Gets a property value from an element. It will try to get the object from the attribute, + * if null, from child element. + * @param element The element to get the property from. + * @param prop The property to get. + * @param type The class of the type to convert the property to. + * @param The type to convert the attribute value to. + * @return An object of the correct type, or null if argument is missing or invalid. + */ + public T getProp(Element element, String prop, Class type) { + return getProp(element, prop, type, null, true); + } + + /** + * Gets a property value from an element. It will try to get the object from the attribute, + * if missing, from child element. + * @param element The element to get the property from. + * @param prop The property to get. + * @param type The class of the type to convert the property to. + * @param fallback The fallback in case it's null or an error is thrown, null can be used as fallback. + * @param The type to convert the attribute value to. + * @return An object of the correct type, or null if argument is missing or invalid. + */ + public T getProp(Element element, String prop, Class type, T fallback) { + return getProp(element, prop, type, fallback, false); + } + + private T getProp(Element element, String prop, Class type, T fallback, boolean required) { + T result; + Attribute attribute = element.getAttribute(prop); + Element child = element.getChild(prop); + if (attribute == null && child == null && required) { + module.getErrors().add(new ModuleError(module, map, element, "Missing required property:'" + prop + "'", false)); + return null; + } + if (attribute != null) { + result = getAttribute(attribute, type); + } else { + result = getElement(element, type); + } + if (required && result == null) { + canLoad = false; + } + return result != null ? result : fallback; + } + + public void checkId(Attribute attribute, String id) { + if (!IdModule.get().canAdd(match, id)) { + module.getErrors().add(new ModuleError(module, map, attribute, "Invalid or duplicated ID specified", false)); + canLoad = false; + } + } + +} diff --git a/src/main/java/in/twizmwaz/cardinal/module/id/IdModule.java b/src/main/java/in/twizmwaz/cardinal/module/id/IdModule.java index 7514dad..005c267 100644 --- a/src/main/java/in/twizmwaz/cardinal/module/id/IdModule.java +++ b/src/main/java/in/twizmwaz/cardinal/module/id/IdModule.java @@ -96,6 +96,16 @@ public boolean add(Match match, String id, Object object, boolean force) { return false; } + /** + * Checks if the id could be added to the match + * @param match The match to try the object to. + * @param id The id to check. + * @return if the object isn't null and isn't duplicated. + */ + public boolean canAdd(Match match, String id) { + return id != null && !ids.get(match).containsKey(id); + } + /** * Get an object with the given id. * @param match The match the object belongs to. diff --git a/src/main/java/in/twizmwaz/cardinal/module/objective/Objective.java b/src/main/java/in/twizmwaz/cardinal/module/objective/Objective.java index 1d6ee44..686398d 100644 --- a/src/main/java/in/twizmwaz/cardinal/module/objective/Objective.java +++ b/src/main/java/in/twizmwaz/cardinal/module/objective/Objective.java @@ -38,7 +38,6 @@ public abstract class Objective { @NonNull protected final Match match; - private final String id; private final boolean required; protected final boolean show; diff --git a/src/main/java/in/twizmwaz/cardinal/module/objective/core/Core.java b/src/main/java/in/twizmwaz/cardinal/module/objective/core/Core.java index 41edf70..7f63c04 100644 --- a/src/main/java/in/twizmwaz/cardinal/module/objective/core/Core.java +++ b/src/main/java/in/twizmwaz/cardinal/module/objective/core/Core.java @@ -83,7 +83,6 @@ public class Core extends Objective implements OwnedObjective, EntryUpdater { /** * @param match The match the core is part of. - * @param id The core's ID, for usage in code and XML. * @param name The core's name, for usage by the user. * @param required Determines if this objective is required to win the match. * @param region The region that contains this core. @@ -96,10 +95,10 @@ public class Core extends Objective implements OwnedObjective, EntryUpdater { * @param proximityHorizontal Determines if only horizontal distance is considered when * calculating proximity. */ - public Core(Match match, String id, String name, boolean required, Region region, int leak, + public Core(Match match, String name, boolean required, Region region, int leak, MaterialPattern material, Team owner, boolean modeChanges, boolean show, ProximityMetric proximityMetric, boolean proximityHorizontal) { - super(match, id, required, show); + super(match, required, show); this.name = name; this.leak = leak; this.material = material; diff --git a/src/main/java/in/twizmwaz/cardinal/module/objective/core/CoreModule.java b/src/main/java/in/twizmwaz/cardinal/module/objective/core/CoreModule.java index d3abe6c..b07c987 100644 --- a/src/main/java/in/twizmwaz/cardinal/module/objective/core/CoreModule.java +++ b/src/main/java/in/twizmwaz/cardinal/module/objective/core/CoreModule.java @@ -170,7 +170,7 @@ public boolean loadMatch(Match match) { boolean proximityHorizontal = proximityHorizontalValue != null && Numbers.parseBoolean(proximityHorizontalValue); - Core core = new Core(match, id, name, required, region, leak, material, team, modeChanges, show, + Core core = new Core(match, name, required, region, leak, material, team, modeChanges, show, proximityMetric, proximityHorizontal); if (!IdModule.get().add(match, id, core)) { errors.add(new ModuleError(this, match.getMap(), diff --git a/src/main/java/in/twizmwaz/cardinal/module/objective/destroyable/Destroyable.java b/src/main/java/in/twizmwaz/cardinal/module/objective/destroyable/Destroyable.java index 3175304..09fc47c 100644 --- a/src/main/java/in/twizmwaz/cardinal/module/objective/destroyable/Destroyable.java +++ b/src/main/java/in/twizmwaz/cardinal/module/objective/destroyable/Destroyable.java @@ -103,7 +103,6 @@ public class Destroyable extends Objective implements OwnedObjective, EntryUpdat /** * @param match The match the destroyable belongs to. - * @param id This destroyable's ID. * @param name This destroyable's name. * @param required Determines if this objective is required to win the match. * @param region The region that contains this destroyable. @@ -119,12 +118,12 @@ public class Destroyable extends Objective implements OwnedObjective, EntryUpdat * @param proximityHorizontal Determines if only horizontal distance is considered when * calculating proximity. */ - public Destroyable(Match match, String id, String name, boolean required, Region region, + public Destroyable(Match match, String name, boolean required, Region region, MaterialPattern materials, Team owner, double completion, boolean modeChanges, boolean showProgress, boolean repairable, boolean sparks, boolean show, ProximityMetric proximityMetric, boolean proximityHorizontal) { - super(match, id, required, show); + super(match, required, show); this.name = name; this.materials = materials; this.owner = owner; diff --git a/src/main/java/in/twizmwaz/cardinal/module/objective/destroyable/DestroyableModule.java b/src/main/java/in/twizmwaz/cardinal/module/objective/destroyable/DestroyableModule.java index d5538fe..a9c838c 100644 --- a/src/main/java/in/twizmwaz/cardinal/module/objective/destroyable/DestroyableModule.java +++ b/src/main/java/in/twizmwaz/cardinal/module/objective/destroyable/DestroyableModule.java @@ -164,7 +164,7 @@ public boolean loadMatch(Match match) { boolean proximityHorizontal = proximityHorizontalValue != null && Numbers.parseBoolean(proximityHorizontalValue); - Destroyable destroyable = new Destroyable(match, id, name, required, region, materials, owner, + Destroyable destroyable = new Destroyable(match, name, required, region, materials, owner, completion, modeChanges, showProgress, repairable, sparks, show, proximityMetric, proximityHorizontal); if (!IdModule.get().add(match, id, destroyable)) { errors.add(new ModuleError(this, match.getMap(), diff --git a/src/main/java/in/twizmwaz/cardinal/module/objective/wool/Wool.java b/src/main/java/in/twizmwaz/cardinal/module/objective/wool/Wool.java index cfbd55c..fe4d895 100644 --- a/src/main/java/in/twizmwaz/cardinal/module/objective/wool/Wool.java +++ b/src/main/java/in/twizmwaz/cardinal/module/objective/wool/Wool.java @@ -83,9 +83,9 @@ public class Wool extends Objective implements Listener, EntryUpdater { * @param monumentProximityRule The proximity rule that determines how to calculate proximity * after picking up the wool. */ - public Wool(Match match, String id, boolean required, Team team, DyeColor color, Region monument, boolean craftable, + public Wool(Match match, boolean required, Team team, DyeColor color, Region monument, boolean craftable, boolean show, Vector location, ProximityRule woolProximityRule, ProximityRule monumentProximityRule) { - super(match, id, required, show); + super(match, required, show); this.team = team; this.color = color; this.monument = monument; diff --git a/src/main/java/in/twizmwaz/cardinal/module/objective/wool/WoolModule.java b/src/main/java/in/twizmwaz/cardinal/module/objective/wool/WoolModule.java index 3dbe2ef..e17b6e2 100644 --- a/src/main/java/in/twizmwaz/cardinal/module/objective/wool/WoolModule.java +++ b/src/main/java/in/twizmwaz/cardinal/module/objective/wool/WoolModule.java @@ -34,6 +34,7 @@ import in.twizmwaz.cardinal.module.AbstractListenerModule; import in.twizmwaz.cardinal.module.ModuleEntry; import in.twizmwaz.cardinal.module.ModuleError; +import in.twizmwaz.cardinal.module.ModuleReporter; import in.twizmwaz.cardinal.module.apply.AppliedModule; import in.twizmwaz.cardinal.module.apply.AppliedRegion; import in.twizmwaz.cardinal.module.apply.ApplyType; @@ -73,7 +74,6 @@ import org.bukkit.util.Vector; import org.jdom2.Document; import org.jdom2.Element; -import org.jdom2.located.Located; import java.util.List; @@ -82,169 +82,60 @@ public class WoolModule extends AbstractListenerModule { @Override public boolean loadMatch(Match match) { + ModuleReporter reporter = new ModuleReporter(this, match); Document document = match.getMap().getDocument(); - for (Element woolsElement : document.getRootElement().getChildren("wools")) { - for (Element woolElement : woolsElement.getChildren("wool")) { - Located located = (Located) woolElement; - String colorValue = ParseUtil.getFirstAttribute("color", woolElement, woolsElement); - String id = ParseUtil.getFirstAttribute("id", woolElement, woolsElement); - if (id == null) { - id = colorValue; - } - - String requiredValue = ParseUtil.getFirstAttribute("required", woolElement, woolsElement); - boolean required = requiredValue == null || Numbers.parseBoolean(requiredValue); - - String teamValue = ParseUtil.getFirstAttribute("team", woolElement, woolsElement); - if (teamValue == null) { - errors.add(new ModuleError(this, match.getMap(), new String[]{"No team specified for wool", - "Element at " + located.getLine() + ", " + located.getColumn()}, false)); - continue; - } - Team team = Cardinal.getModule(TeamModule.class).getTeamById(match, teamValue); - if (team == null) { - errors.add(new ModuleError(this, match.getMap(), new String[]{"Invalid team specified for wool", - "Element at " + located.getLine() + ", " + located.getColumn()}, false)); - continue; - } - - if (colorValue == null) { - errors.add(new ModuleError(this, match.getMap(), new String[]{"No color specified for wool", - "Element at " + located.getLine() + ", " + located.getColumn()}, false)); - continue; - } - DyeColor color; - try { - color = DyeColor.valueOf(Strings.getTechnicalName(colorValue)); - } catch (IllegalArgumentException e) { - errors.add(new ModuleError(this, match.getMap(), new String[]{"Invalid color specified for wool", - "Element at " + located.getLine() + ", " + located.getColumn()}, false)); - continue; - } - - RegionModule regionModule = Cardinal.getModule(RegionModule.class); - Region monument; - try { - monument = regionModule.getRegion(match, woolElement, "monument"); - } catch (RegionException e) { - errors.add(new ModuleError(this, match.getMap(), - new String[]{RegionModule.getRegionError(e, "monument", "wool"), - "Element at " + located.getLine() + ", " + located.getColumn()}, false)); - continue; - } - if (monument == null && woolsElement.getAttribute("monument") != null) { - monument = regionModule.getRegionById(match, woolsElement.getAttributeValue("monument")); - } - if (monument == null) { - errors.add(new ModuleError(this, match.getMap(), new String[]{"No monument specified for wool", - "Element at " + located.getLine() + ", " + located.getColumn()}, false)); - continue; - } - - String craftableValue = ParseUtil.getFirstAttribute("craftable", woolElement, woolsElement); - boolean craftable = craftableValue != null && Numbers.parseBoolean(craftableValue); - - String showValue = ParseUtil.getFirstAttribute("show", woolElement, woolsElement); - boolean show = showValue == null || Numbers.parseBoolean(showValue); + for (Element woolElement : ParseUtil.getElementsIn(document.getRootElement(), "wools", "wool")) { + parseWool(reporter, woolElement); + reporter.reset(); + } + return true; + } - String locationValue = ParseUtil.getFirstAttribute("location", woolElement, woolsElement); - Proto proto = match.getMap().getProto(); - if (locationValue != null && proto.isBefore("1.4.0")) { - errors.add(new ModuleError(this, match.getMap(), - new String[]{"Attribute \"location\" is supported in proto 1.4.0 or later", - "Element at " + located.getLine() + ", " + located.getColumn()}, false)); - } else if (locationValue == null && proto.isAfterOrAt("1.4.0")) { - errors.add(new ModuleError(this, match.getMap(), - new String[]{"Attribute \"location\" should be specified for wool in proto 1.4.0 or later", - "Element at " + located.getLine() + ", " + located.getColumn()}, false)); - } - Vector location = null; - if (locationValue != null) { - String[] coordinates = locationValue.split(","); - if (coordinates.length != 3) { - errors.add(new ModuleError(this, match.getMap(), new String[]{"Invalid location format specified for wool", - "Element at " + located.getLine() + ", " + located.getColumn()}, false)); - continue; - } - try { - location = new Vector(Double.parseDouble(coordinates[0].trim()), - Double.parseDouble(coordinates[1].trim()), - Double.parseDouble(coordinates[2].trim())); - } catch (NumberFormatException e) { - errors.add(new ModuleError(this, match.getMap(), new String[]{"Invalid location specified for wool", - "Element at " + located.getLine() + ", " + located.getColumn()}, false)); - continue; - } - } + public static Wool parseWool(ModuleReporter reporter, Element element) { + String id = reporter.getAttr(element, "id", String.class, null); + if (id != null) { + reporter.checkId(element.getAttribute(id), id); + } - ProximityMetric woolProximityMetric = ProximityMetric.CLOSEST_KILL; - String woolProximityMetricValue = ParseUtil.getFirstAttribute("woolproximity-metric", - woolElement, woolsElement); - if (woolProximityMetricValue != null) { - try { - woolProximityMetric = ProximityMetric.valueOf(Strings.getTechnicalName(woolProximityMetricValue)); - } catch (IllegalArgumentException e) { - errors.add(new ModuleError(this, match.getMap(), - new String[]{"Invalid wool proximity metric specified for wool", - "Element at " + located.getLine() + ", " + located.getColumn()}, false)); - continue; - } - } + boolean required = reporter.getAttr(element, "required", Boolean.class, true); + Team team = reporter.getAttr(element, "team", Team.class); + DyeColor color = reporter.getAttr(element, "color", DyeColor.class); + Region monument = reporter.getProp(element, "monument", Region.class); + boolean craftable = reporter.getAttr(element, "craftable", Boolean.class, false); + boolean show = reporter.getAttr(element, "show", Boolean.class, true); - String woolProximityHorizontalValue = - ParseUtil.getFirstAttribute("woolproximity-horizontal", woolElement, woolsElement); - boolean woolProximityHorizontal = woolProximityHorizontalValue != null - && Numbers.parseBoolean(woolProximityHorizontalValue); + Vector location = reporter.getAttr(element, "location", Vector.class, null); - ProximityMetric monumentProximityMetric = ProximityMetric.CLOSEST_BLOCK; - String monumentProximityMetricValue = - ParseUtil.getFirstAttribute("monumentproximity-metric", woolElement, woolsElement); - if (monumentProximityMetricValue != null) { - try { - monumentProximityMetric = ProximityMetric.valueOf( - Strings.getTechnicalName(monumentProximityMetricValue)); - } catch (IllegalArgumentException e) { - errors.add(new ModuleError(this, match.getMap(), - new String[]{"Invalid monument proximity metric specified for wool", - "Element at " + located.getLine() + ", " + located.getColumn()}, false)); - continue; - } - } + ProximityRule woolProximity = new ProximityRule( + reporter.getAttr(element, "woolproximity-metric", ProximityMetric.class, ProximityMetric.CLOSEST_KILL), + reporter.getAttr(element, "woolproximity-horizontal", Boolean.class, false)); + ProximityRule monumentProximity = new ProximityRule( + reporter.getAttr(element, "monumentproximity-metric", ProximityMetric.class, ProximityMetric.CLOSEST_BLOCK), + reporter.getAttr(element, "monumentproximity-horizontal", Boolean.class, false)); - String monumentProximityHorizontalValue = - ParseUtil.getFirstAttribute("monumentproximity-horizontal", woolElement, woolsElement); - boolean monumentProximityHorizontal = monumentProximityHorizontalValue != null - && Numbers.parseBoolean(monumentProximityHorizontalValue); + if (reporter.isCanLoad()) { + Wool wool = new Wool(reporter.getMatch(), required, team, color, monument, craftable, + show, location, woolProximity, monumentProximity); + IdModule.get().add(reporter.getMatch(), null, wool, true); - Wool wool = new Wool( - match, id, required, team, color, monument, craftable, show, location, - new ProximityRule(woolProximityMetric, woolProximityHorizontal), - new ProximityRule(monumentProximityMetric, monumentProximityHorizontal) - ); - if (!IdModule.get().add(match, id, wool)) { - errors.add(new ModuleError(this, match.getMap(), - new String[]{"Wool id is not valid or already in use", - "Element at " + located.getLine() + ", " + located.getColumn()}, false)); - IdModule.get().add(match, null, wool, true); - } - AppliedModule appliedModule = Cardinal.getModule(AppliedModule.class); - appliedModule.add(match, new WoolMonumentPlace(wool), true); - appliedModule.add(match, - new AppliedRegion(ApplyType.BLOCK_BREAK, monument, new StaticFilter(FilterState.DENY), - new LocalizedComponentBuilder( - ChatConstant.getConstant("objective.wool.error.break"), - wool.getComponent() - ).color(ChatColor.RED).build()), true); - } + AppliedModule appliedModule = Cardinal.getModule(AppliedModule.class); + appliedModule.add(reporter.getMatch(), new WoolMonumentPlace(wool), true); + appliedModule.add(reporter.getMatch(), + new AppliedRegion(ApplyType.BLOCK_BREAK, monument, new StaticFilter(FilterState.DENY), + new LocalizedComponentBuilder( + ChatConstant.getConstant("objective.wool.error.break"), + wool.getComponent() + ).color(ChatColor.RED).build()), true); + return wool; + } else { + return null; } - return true; } public List getWools(@NonNull Match match) { return IdModule.get().getList(match, Wool.class); } - /** * Checks if the wool has been picked up when a player clicks on an item in their inventory. * diff --git a/src/main/java/in/twizmwaz/cardinal/util/document/XML.java b/src/main/java/in/twizmwaz/cardinal/util/document/XML.java new file mode 100644 index 0000000..fb3ab66 --- /dev/null +++ b/src/main/java/in/twizmwaz/cardinal/util/document/XML.java @@ -0,0 +1,84 @@ +package in.twizmwaz.cardinal.util.document; + +import com.google.common.collect.Maps; +import in.twizmwaz.cardinal.util.Numbers; +import in.twizmwaz.cardinal.util.Strings; +import lombok.NonNull; +import org.bukkit.DyeColor; +import org.jdom2.Attribute; +import org.jdom2.Element; + +import java.util.Map; +import java.util.function.Function; + +public class XML { + + private static Map> stringProviders = Maps.newHashMap(); + private static Map> elementParser = Maps.newHashMap(); + + static { + stringProviders.put(String.class, (String in) -> in); + stringProviders.put(Integer.class, Numbers::parseInteger); + stringProviders.put(Double.class, Numbers::parseDouble); + stringProviders.put(DyeColor.class, (String in) -> DyeColor.valueOf(Strings.getTechnicalName(in))); + + elementParser.put(String.class, Element::getText); + + /* + TODO: + Add Parsers: + boolean, team, regions, vector, ProximityMetric, ProximtiyRule + */ + } + + + /** + * Gets an object from an attribute. + * @param attr The attribute name. + * @param type The class you want. + * @param The type. + * @return An object of that type if possible, null otherwise. + */ + public static T getAttribute(@NonNull Attribute attr, Class type) throws Exception { + return getFromString(attr.getValue(), type); + } + + /** + * Gets an object from an element's text. + * @param el The Element. + * @param type The class you want. + * @param The type. + * @return An object of that type if possible, null otherwise. + */ + public static T getElementString(@NonNull Element el, Class type) throws Exception { + return getFromString(el.getText(), type); + } + + private static T getFromString(String in, Class type) { + if (in == null) { + return null; + } + if (XML.stringProviders.containsKey(type)) { + return (T) XML.stringProviders.get(type).apply(in); + } + throw new IllegalStateException("Missing ObjectProvider for class: " + type.getName()); + } + + /** + * Gets an object from an element. + * @param el The Element name. + * @param type The class you want. + * @param The type. + * @return An object of that type if possible, null otherwise. + */ + public static T getElementObject(@NonNull Element el, Class type) throws Exception { + if (el == null) { + return null; + } + if (XML.elementParser.containsKey(type)) { + return (T) XML.elementParser.get(type).apply(el); + } + throw new IllegalStateException("Missing ObjectProvider for class: " + type.getName()); + } + +} \ No newline at end of file