From 0b9cc66054c6ff4d93d734356a30f3ea866a6dda Mon Sep 17 00:00:00 2001 From: Wertik Date: Thu, 5 Dec 2024 01:01:35 +0100 Subject: [PATCH] fix: wrong node data syntax crashing the plugin fix: BlockFace enums in node data parser using int indices instead of specified enum names feat: improve error verbosity --- blockregen-ancient/pom.xml | 4 +- .../ancient/AncientNodeDataParser.java | 23 +---- blockregen-common/pom.xml | 2 +- .../java/nl/aurorion/blockregen/Pair.java | 11 +++ .../nl/aurorion/blockregen/ParseUtil.java | 3 +- blockregen-legacy/pom.xml | 4 +- .../version/legacy/LegacyNodeDataParser.java | 25 ++---- blockregen-plugin/pom.xml | 10 +-- .../system/material/MaterialManager.java | 26 +++--- .../parser/ItemsAdderMaterialParser.java | 6 +- .../parser/MMOItemsMaterialParser.java | 13 ++- .../material/parser/MaterialParser.java | 7 +- .../parser/MinecraftMaterialParser.java | 7 +- .../material/parser/OraxenMaterialParser.java | 5 +- .../system/preset/PresetManager.java | 4 - .../version/current/LatestNodeDataParser.java | 70 ++++----------- blockregen-version/pom.xml | 4 +- .../version/NodeDataDeserializer.java | 89 +++++++++++++++---- pom.xml | 2 +- 19 files changed, 156 insertions(+), 159 deletions(-) create mode 100644 blockregen-common/src/main/java/nl/aurorion/blockregen/Pair.java diff --git a/blockregen-ancient/pom.xml b/blockregen-ancient/pom.xml index b0d21a68..63bba82a 100644 --- a/blockregen-ancient/pom.xml +++ b/blockregen-ancient/pom.xml @@ -5,7 +5,7 @@ BlockRegen nl.aurorion.blockregen - 3.16.4 + 3.16.5-SNAPSHOT 4.0.0 @@ -20,7 +20,7 @@ nl.aurorion.blockregen blockregen-version - 3.16.4 + 3.16.5-SNAPSHOT compile diff --git a/blockregen-ancient/src/main/java/nl/aurorion/blockregen/version/ancient/AncientNodeDataParser.java b/blockregen-ancient/src/main/java/nl/aurorion/blockregen/version/ancient/AncientNodeDataParser.java index be6bb8fa..611125bd 100644 --- a/blockregen-ancient/src/main/java/nl/aurorion/blockregen/version/ancient/AncientNodeDataParser.java +++ b/blockregen-ancient/src/main/java/nl/aurorion/blockregen/version/ancient/AncientNodeDataParser.java @@ -10,25 +10,10 @@ public class AncientNodeDataParser implements NodeDataParser { private final NodeDataDeserializer nodeDataDeserializer = new NodeDataDeserializer() - .property("age", (nodeData, value) -> { - int age = Integer.parseInt(value); - CropState state = CropState.values()[age]; - nodeData.setCropState(state); - }) - .property("facing", (nodeData, value) -> { - int id = Integer.parseInt(value); - BlockFace facing = BlockFace.values()[id]; - nodeData.setFacing(facing); - }) - .property("species", (nodeData, value) -> { - int id = Integer.parseInt(value); - TreeSpecies species = TreeSpecies.values()[id]; - nodeData.setTreeSpecies(species); - }) - .property("inverted", (nodeData, value) -> { - boolean inverted = Boolean.parseBoolean(value); - nodeData.setInverted(inverted); - }) + .property("age", (nodeData, value) -> NodeDataDeserializer.tryParseEnum(value, CropState.class)) + .property("facing", (nodeData, value) -> NodeDataDeserializer.tryParseEnum(value, BlockFace.class)) + .property("species", (nodeData, value) -> NodeDataDeserializer.tryParseEnum(value, TreeSpecies.class)) + .property("inverted", (nodeData, value) -> nodeData.setInverted(Boolean.parseBoolean(value))) .property("skull", AncientNodeData::setSkull); @Override diff --git a/blockregen-common/pom.xml b/blockregen-common/pom.xml index f0a69d42..c36abfc8 100644 --- a/blockregen-common/pom.xml +++ b/blockregen-common/pom.xml @@ -5,7 +5,7 @@ BlockRegen nl.aurorion.blockregen - 3.16.4 + 3.16.5-SNAPSHOT 4.0.0 diff --git a/blockregen-common/src/main/java/nl/aurorion/blockregen/Pair.java b/blockregen-common/src/main/java/nl/aurorion/blockregen/Pair.java new file mode 100644 index 00000000..7916d921 --- /dev/null +++ b/blockregen-common/src/main/java/nl/aurorion/blockregen/Pair.java @@ -0,0 +1,11 @@ +package nl.aurorion.blockregen; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class Pair { + private final F first; + private final S second; +} diff --git a/blockregen-common/src/main/java/nl/aurorion/blockregen/ParseUtil.java b/blockregen-common/src/main/java/nl/aurorion/blockregen/ParseUtil.java index e2a4bf41..27145cbf 100644 --- a/blockregen-common/src/main/java/nl/aurorion/blockregen/ParseUtil.java +++ b/blockregen-common/src/main/java/nl/aurorion/blockregen/ParseUtil.java @@ -99,8 +99,9 @@ public > E parseEnum(String str, Class clazz) { public > E parseEnum(String str, Class clazz, Consumer exceptionCallback) { - if (Strings.isNullOrEmpty(str)) + if (Strings.isNullOrEmpty(str)) { return null; + } try { return E.valueOf(clazz, str.trim().toUpperCase()); diff --git a/blockregen-legacy/pom.xml b/blockregen-legacy/pom.xml index fbaa7798..b4a638b8 100644 --- a/blockregen-legacy/pom.xml +++ b/blockregen-legacy/pom.xml @@ -5,7 +5,7 @@ BlockRegen nl.aurorion.blockregen - 3.16.4 + 3.16.5-SNAPSHOT 4.0.0 @@ -14,7 +14,7 @@ nl.aurorion.blockregen blockregen-version - 3.16.4 + 3.16.5-SNAPSHOT compile diff --git a/blockregen-legacy/src/main/java/nl/aurorion/blockregen/version/legacy/LegacyNodeDataParser.java b/blockregen-legacy/src/main/java/nl/aurorion/blockregen/version/legacy/LegacyNodeDataParser.java index 11e66b44..21dd788b 100644 --- a/blockregen-legacy/src/main/java/nl/aurorion/blockregen/version/legacy/LegacyNodeDataParser.java +++ b/blockregen-legacy/src/main/java/nl/aurorion/blockregen/version/legacy/LegacyNodeDataParser.java @@ -12,26 +12,11 @@ public class LegacyNodeDataParser implements NodeDataParser { private final NodeDataDeserializer nodeDataDeserializer = new NodeDataDeserializer() - .property("age", (nodeData, value) -> { - int age = Integer.parseInt(value); - CropState state = CropState.values()[age]; - nodeData.setCropState(state); - }) - .property("facing", (nodeData, value) -> { - int id = Integer.parseInt(value); - BlockFace facing = BlockFace.values()[id]; - nodeData.setFacing(facing); - }) - .property("species", (nodeData, value) -> { - int id = Integer.parseInt(value); - TreeSpecies species = TreeSpecies.values()[id]; - nodeData.setTreeSpecies(species); - }) - .property("inverted", (nodeData, value) -> { - boolean inverted = Boolean.parseBoolean(value); - nodeData.setInverted(inverted); - }) - .property("skull", (LegacyNodeData::setSkull)); + .property("age", (nodeData, value) -> NodeDataDeserializer.tryParseEnum(value, CropState.class)) + .property("facing", (nodeData, value) -> NodeDataDeserializer.tryParseEnum(value, BlockFace.class)) + .property("species", (nodeData, value) -> NodeDataDeserializer.tryParseEnum(value, TreeSpecies.class)) + .property("inverted", (nodeData, value) -> nodeData.setInverted(Boolean.parseBoolean(value))) + .property("skull", LegacyNodeData::setSkull); @Override public NodeData parse(String input) { diff --git a/blockregen-plugin/pom.xml b/blockregen-plugin/pom.xml index eeb6f058..10b5365b 100644 --- a/blockregen-plugin/pom.xml +++ b/blockregen-plugin/pom.xml @@ -5,7 +5,7 @@ BlockRegen nl.aurorion.blockregen - 3.16.4 + 3.16.5-SNAPSHOT 4.0.0 @@ -112,25 +112,25 @@ nl.aurorion.blockregen blockregen-common - 3.16.4 + 3.16.5-SNAPSHOT compile nl.aurorion.blockregen blockregen-version - 3.16.4 + 3.16.5-SNAPSHOT compile nl.aurorion.blockregen blockregen-legacy - 3.16.4 + 3.16.5-SNAPSHOT compile nl.aurorion.blockregen blockregen-ancient - 3.16.4 + 3.16.5-SNAPSHOT compile diff --git a/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/MaterialManager.java b/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/MaterialManager.java index e8e27ad7..1bab2a20 100644 --- a/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/MaterialManager.java +++ b/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/MaterialManager.java @@ -1,9 +1,8 @@ package nl.aurorion.blockregen.system.material; -import lombok.AllArgsConstructor; -import lombok.Data; import lombok.extern.java.Log; import nl.aurorion.blockregen.BlockRegen; +import nl.aurorion.blockregen.Pair; import nl.aurorion.blockregen.system.material.parser.MaterialParser; import nl.aurorion.blockregen.system.preset.struct.material.DynamicMaterial; import nl.aurorion.blockregen.system.preset.struct.material.TargetMaterial; @@ -41,18 +40,13 @@ public void registerParser(@Nullable String prefix, @NotNull MaterialParser pars log.fine(String.format("Registered material parser with prefix %s", prefix)); } + @Nullable public MaterialParser getParser(@Nullable String prefix) { return this.registeredParsers.get((prefix == null ? null : prefix.toLowerCase())); } - @Data - @AllArgsConstructor - public static class Pair { - private final F first; - private final S second; - } - - private Pair parseMaterialAndChance(MaterialParser parser, String input) { + @NotNull + private Pair parseMaterialAndChance(MaterialParser parser, String input) throws IllegalArgumentException { // The part until the last colon that's not part of 'https://' Matcher matcher = Pattern.compile("(? parseMaterialAndChance(MaterialParser parse } } - public DynamicMaterial parseDynamicMaterial(String input) { + @NotNull + public DynamicMaterial parseDynamicMaterial(String input) throws IllegalArgumentException { List materials = Arrays.asList(input.split(";")); // Materials without a chance. @@ -142,8 +137,7 @@ public DynamicMaterial parseDynamicMaterial(String input) { parser = getParser(null); if (parser == null) { - log.warning(String.format("No valid parser found for material input %s", input)); - return null; + throw new IllegalArgumentException(String.format("Material '%s' is invalid. No valid material parser found.", input)); } log.fine("No prefix"); @@ -193,7 +187,8 @@ public DynamicMaterial parseDynamicMaterial(String input) { * @return Parsed material or null when no parser was found. * @throws IllegalArgumentException When the parser is unable to parse the material. */ - public @Nullable TargetMaterial parseMaterial(@NotNull String input) throws IllegalArgumentException { + @NotNull + public TargetMaterial parseMaterial(@NotNull String input) throws IllegalArgumentException { // Separate parts String[] parts = new String[]{input}; @@ -214,8 +209,7 @@ public DynamicMaterial parseDynamicMaterial(String input) { parser = getParser(null); if (parser == null) { - log.fine(String.format("No valid parser found for material input %s", input)); - return null; + throw new IllegalArgumentException(String.format("Material '%s' invalid. No valid parser found", input)); } } else { // remove parts[0] aka the parser prefix diff --git a/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/parser/ItemsAdderMaterialParser.java b/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/parser/ItemsAdderMaterialParser.java index e7dabeb1..7435c612 100644 --- a/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/parser/ItemsAdderMaterialParser.java +++ b/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/parser/ItemsAdderMaterialParser.java @@ -3,14 +3,14 @@ import dev.lone.itemsadder.api.CustomBlock; import nl.aurorion.blockregen.system.preset.struct.material.ItemsAdderMaterial; import nl.aurorion.blockregen.system.preset.struct.material.TargetMaterial; +import org.jetbrains.annotations.NotNull; public class ItemsAdderMaterialParser implements MaterialParser { @Override - public TargetMaterial parseMaterial(String input) throws IllegalArgumentException { - + public @NotNull TargetMaterial parseMaterial(String input) throws IllegalArgumentException { if (!CustomBlock.isInRegistry(input)) { - throw new IllegalArgumentException(input + " is not a valid ItemsAdder custom block."); + throw new IllegalArgumentException(String.format("'%s' is not a valid ItemsAdder custom block.", input)); } return new ItemsAdderMaterial(input); diff --git a/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/parser/MMOItemsMaterialParser.java b/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/parser/MMOItemsMaterialParser.java index a6ab1af8..0e771791 100644 --- a/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/parser/MMOItemsMaterialParser.java +++ b/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/parser/MMOItemsMaterialParser.java @@ -3,8 +3,9 @@ import nl.aurorion.blockregen.BlockRegen; import nl.aurorion.blockregen.system.preset.struct.material.MMOIItemsMaterial; import nl.aurorion.blockregen.system.preset.struct.material.TargetMaterial; +import org.jetbrains.annotations.NotNull; -public class MMOItemsMaterialParser implements MaterialParser{ +public class MMOItemsMaterialParser implements MaterialParser { private final BlockRegen plugin; @@ -13,14 +14,12 @@ public MMOItemsMaterialParser(BlockRegen plugin) { } @Override - public TargetMaterial parseMaterial(String input) throws IllegalArgumentException { - int id; + public @NotNull TargetMaterial parseMaterial(String input) throws IllegalArgumentException { try { - id = Integer.parseInt(input); + int id = Integer.parseInt(input); + return new MMOIItemsMaterial(plugin, id); } catch (NumberFormatException e) { - throw new IllegalArgumentException("Invalid MMOItem block id: " + input); + throw new IllegalArgumentException(String.format("Invalid MMOItem block id: '%s'.", input)); } - - return new MMOIItemsMaterial(plugin, id); } } diff --git a/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/parser/MaterialParser.java b/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/parser/MaterialParser.java index 4a8037b6..518176d2 100644 --- a/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/parser/MaterialParser.java +++ b/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/parser/MaterialParser.java @@ -1,6 +1,7 @@ package nl.aurorion.blockregen.system.material.parser; import nl.aurorion.blockregen.system.preset.struct.material.TargetMaterial; +import org.jetbrains.annotations.NotNull; public interface MaterialParser { @@ -9,12 +10,14 @@ public interface MaterialParser { * * @param input String to parse from with the material prefix already removed. (ex.: 'oraxen:caveblock', input = 'caveblock'). * @return Parsed TargetMaterial - * * @throws IllegalArgumentException if the provided {@code input} is not a valid oraxen block id */ + @NotNull TargetMaterial parseMaterial(String input) throws IllegalArgumentException; - // Return true if the material syntax contains colons. + /** + * @return True if the material syntax contains colons. + */ default boolean containsColon() { return false; } diff --git a/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/parser/MinecraftMaterialParser.java b/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/parser/MinecraftMaterialParser.java index da20b991..beb600b9 100644 --- a/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/parser/MinecraftMaterialParser.java +++ b/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/parser/MinecraftMaterialParser.java @@ -3,10 +3,11 @@ import com.cryptomorin.xseries.XMaterial; import lombok.extern.java.Log; import nl.aurorion.blockregen.BlockRegen; +import nl.aurorion.blockregen.ParseUtil; import nl.aurorion.blockregen.system.preset.struct.material.MinecraftMaterial; import nl.aurorion.blockregen.system.preset.struct.material.TargetMaterial; -import nl.aurorion.blockregen.ParseUtil; import nl.aurorion.blockregen.version.api.NodeData; +import org.jetbrains.annotations.NotNull; @Log public class MinecraftMaterialParser implements MaterialParser { @@ -18,7 +19,7 @@ public MinecraftMaterialParser(BlockRegen plugin) { } @Override - public TargetMaterial parseMaterial(String input) throws IllegalArgumentException { + public @NotNull TargetMaterial parseMaterial(String input) throws IllegalArgumentException { log.fine(String.format("Parsing MC material from %s", input)); boolean loadData = false; @@ -33,7 +34,7 @@ public TargetMaterial parseMaterial(String input) throws IllegalArgumentExceptio XMaterial xMaterial = ParseUtil.parseMaterial(materialPart, plugin.getVersionManager().isCurrentAbove("1.12.2", false)); if (xMaterial == null) { - throw new IllegalArgumentException("Could not parse minecraft material: " + materialPart); + throw new IllegalArgumentException("Could not parse minecraft material '" + materialPart + "'."); } if (loadData) { diff --git a/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/parser/OraxenMaterialParser.java b/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/parser/OraxenMaterialParser.java index 9332fe2a..8f6ebaf6 100644 --- a/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/parser/OraxenMaterialParser.java +++ b/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/material/parser/OraxenMaterialParser.java @@ -4,6 +4,7 @@ import nl.aurorion.blockregen.BlockRegen; import nl.aurorion.blockregen.system.preset.struct.material.OraxenMaterial; import nl.aurorion.blockregen.system.preset.struct.material.TargetMaterial; +import org.jetbrains.annotations.NotNull; public class OraxenMaterialParser implements MaterialParser { @@ -14,9 +15,9 @@ public OraxenMaterialParser(BlockRegen plugin) { } @Override - public TargetMaterial parseMaterial(String input) throws IllegalArgumentException { + public @NotNull TargetMaterial parseMaterial(String input) throws IllegalArgumentException { if (!OraxenBlocks.isOraxenBlock(input)) { - throw new IllegalArgumentException(input + " is not an Oraxen block"); + throw new IllegalArgumentException(String.format("'%s' is not an Oraxen block.", input)); } return new OraxenMaterial(this.plugin, input); diff --git a/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/preset/PresetManager.java b/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/preset/PresetManager.java index a389ecad..cdaaf111 100644 --- a/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/preset/PresetManager.java +++ b/blockregen-plugin/src/main/java/nl/aurorion/blockregen/system/preset/PresetManager.java @@ -100,10 +100,6 @@ public void load(String name) { TargetMaterial targetMaterial; try { targetMaterial = this.plugin.getMaterialManager().parseMaterial(targetMaterialInput); - if (targetMaterial == null) { - log.warning(String.format("Could not load preset %s, invalid target material %s.", name, targetMaterialInput)); - return; - } preset.setTargetMaterial(targetMaterial); } catch (IllegalArgumentException e) { log.warning(String.format("Could not load preset %s: %s", name, e.getMessage())); diff --git a/blockregen-plugin/src/main/java/nl/aurorion/blockregen/version/current/LatestNodeDataParser.java b/blockregen-plugin/src/main/java/nl/aurorion/blockregen/version/current/LatestNodeDataParser.java index a42ee795..24c6ceaf 100644 --- a/blockregen-plugin/src/main/java/nl/aurorion/blockregen/version/current/LatestNodeDataParser.java +++ b/blockregen-plugin/src/main/java/nl/aurorion/blockregen/version/current/LatestNodeDataParser.java @@ -1,7 +1,6 @@ package nl.aurorion.blockregen.version.current; import lombok.NoArgsConstructor; -import nl.aurorion.blockregen.ParseUtil; import nl.aurorion.blockregen.version.NodeDataDeserializer; import nl.aurorion.blockregen.version.api.NodeData; import nl.aurorion.blockregen.version.api.NodeDataParser; @@ -15,81 +14,48 @@ public class LatestNodeDataParser implements NodeDataParser { private final NodeDataDeserializer nodeDataDeserializer = new NodeDataDeserializer() - .property("age", (nodeData, value) -> { - int age = Integer.parseInt(value); - nodeData.setAge(age); - }) - .property("facing", (nodeData, value) -> { - int id = Integer.parseInt(value); - BlockFace facing = BlockFace.values()[id]; - nodeData.setFacing(facing); - }) - .property("rotation", (nodeData, value) -> { - int id = Integer.parseInt(value); - BlockFace facing = BlockFace.values()[id]; - nodeData.setRotation(facing); - }) - .property("axis", (nodeData, value) -> { - int id = Integer.parseInt(value); - Axis axis = Axis.values()[id]; - nodeData.setAxis(axis); - }) - .property("stairShape", (nodeData, value) -> { - int id = Integer.parseInt(value); - Stairs.Shape species = Stairs.Shape.values()[id]; - nodeData.setStairShape(species); - }) - .property("noteId", (nodeData, value) -> { - byte id = Byte.parseByte(value); - nodeData.setNoteId(id); - }) - .property("instrument", (nodeData, value) -> { - nodeData.setInstrument(ParseUtil.parseEnum(value, Instrument.class)); - }) - .property("octave", (nodeData, value) -> { - int octave = Integer.parseInt(value); - nodeData.setOctave(octave); - }) - .property("sharped", (nodeData, value) -> { - nodeData.setSharped(Boolean.parseBoolean(value)); - }) - .property("tone", (nodeData, value) -> { - nodeData.setTone(ParseUtil.parseEnum(value, Note.Tone.class)); - }) - .property("powered", (nodeData, value) -> { - nodeData.setPowered(Boolean.parseBoolean(value)); - }) + .property("age", (nodeData, value) -> nodeData.setAge(Integer.parseInt(value))) + .property("facing", (nodeData, value) -> nodeData.setFacing(NodeDataDeserializer.tryParseEnum(value, BlockFace.class))) + .property("rotation", (nodeData, value) -> nodeData.setRotation(NodeDataDeserializer.tryParseEnum(value, BlockFace.class))) + .property("axis", (nodeData, value) -> nodeData.setAxis(NodeDataDeserializer.tryParseEnum(value, Axis.class))) + .property("stairShape", (nodeData, value) -> nodeData.setStairShape(NodeDataDeserializer.tryParseEnum(value, Stairs.Shape.class))) + .property("noteId", (nodeData, value) -> nodeData.setNoteId(Byte.parseByte(value))) + .property("instrument", (nodeData, value) -> nodeData.setInstrument(NodeDataDeserializer.tryParseEnum(value, Instrument.class))) + .property("octave", (nodeData, value) -> nodeData.setOctave(Integer.parseInt(value))) + .property("sharped", (nodeData, value) -> nodeData.setSharped(Boolean.parseBoolean(value))) + .property("tone", (nodeData, value) -> nodeData.setTone(NodeDataDeserializer.tryParseEnum(value, Note.Tone.class))) + .property("powered", (nodeData, value) -> nodeData.setPowered(Boolean.parseBoolean(value))) .property("east", (nodeData, value) -> { - if ("true".equalsIgnoreCase(value)) { + if (Boolean.parseBoolean(value)) { nodeData.addFace(BlockFace.EAST); } }) .property("north", (nodeData, value) -> { - if ("true".equalsIgnoreCase(value)) { + if (Boolean.parseBoolean(value)) { nodeData.addFace(BlockFace.NORTH); } }) .property("south", (nodeData, value) -> { - if ("true".equalsIgnoreCase(value)) { + if (Boolean.parseBoolean(value)) { nodeData.addFace(BlockFace.SOUTH); } }) .property("west", (nodeData, value) -> { - if ("true".equalsIgnoreCase(value)) { + if (Boolean.parseBoolean(value)) { nodeData.addFace(BlockFace.WEST); } }) .property("up", (nodeData, value) -> { - if ("true".equalsIgnoreCase(value)) { + if (Boolean.parseBoolean(value)) { nodeData.addFace(BlockFace.UP); } }) .property("down", (nodeData, value) -> { - if ("true".equalsIgnoreCase(value)) { + if (Boolean.parseBoolean(value)) { nodeData.addFace(BlockFace.DOWN); } }) - .property("skull", (LatestNodeData::setSkull)); + .property("skull", LatestNodeData::setSkull); @Override public NodeData parse(String input) throws IllegalArgumentException { diff --git a/blockregen-version/pom.xml b/blockregen-version/pom.xml index 243033e7..2764f950 100644 --- a/blockregen-version/pom.xml +++ b/blockregen-version/pom.xml @@ -7,7 +7,7 @@ BlockRegen nl.aurorion.blockregen - 3.16.4 + 3.16.5-SNAPSHOT blockregen-version @@ -16,7 +16,7 @@ nl.aurorion.blockregen blockregen-common - 3.16.4 + 3.16.5-SNAPSHOT compile diff --git a/blockregen-version/src/main/java/nl/aurorion/blockregen/version/NodeDataDeserializer.java b/blockregen-version/src/main/java/nl/aurorion/blockregen/version/NodeDataDeserializer.java index ce888ef8..e35e8d8a 100644 --- a/blockregen-version/src/main/java/nl/aurorion/blockregen/version/NodeDataDeserializer.java +++ b/blockregen-version/src/main/java/nl/aurorion/blockregen/version/NodeDataDeserializer.java @@ -1,14 +1,23 @@ package nl.aurorion.blockregen.version; import lombok.extern.java.Log; +import nl.aurorion.blockregen.ParseUtil; import nl.aurorion.blockregen.version.api.NodeData; +import org.jetbrains.annotations.NotNull; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; +/** + * General deserializer for Node Data. All version specific parsers build a deserialized with different properties. + * + * @param Implementation of NodeData to produce. + */ @Log public class NodeDataDeserializer { @@ -16,34 +25,65 @@ public interface PropertyDeserializer { void deserialize(T nodeData, String value); } - private static final Pattern dataPattern = Pattern.compile("\\[(.*)]"); + private static final Pattern DATA_PATTERN = Pattern.compile("\\[(.*)]"); + private static final Pattern KEY_PATTERN = Pattern.compile("^(.*?)="); + private Pattern propertyEqualsPattern = null; private final Map> properties = new HashMap<>(); - public NodeDataDeserializer property(String key, PropertyDeserializer deserializer) { - properties.put(key, deserializer); - return this; + public static > E tryParseEnum(String value, Class clazz) { + E face = ParseUtil.parseEnum(value.trim(), clazz); + if (face == null) { + // Fall back to ordinals (might be used for age for ex. on old versions where it's an enum) + try { + int id = Integer.parseInt(value.trim()); + return clazz.getEnumConstants()[id]; + } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) { + throw new IllegalArgumentException(String.format("Invalid value '%s' for enum '%s'. Options: '%s'.", value, clazz.getSimpleName(), + Arrays.stream(clazz.getEnumConstants()) + .map(v -> v.name() + " (" + v.ordinal() + ")") + .collect(Collectors.joining("', '")))); + } + } + return face; } - private Pattern propertyEquals = null; + @NotNull + public NodeDataDeserializer property(@NotNull String key, @NotNull PropertyDeserializer deserializer) { + // Case-insensitive. + properties.put(key.toLowerCase(), deserializer); + return this; + } + @NotNull private Pattern generatePropertyEqualsPattern() { Set properties = this.properties.keySet(); - return Pattern.compile(String.format("(?<=%s)=", String.join("|", properties))); + // Allow property keys to be case-insensitive. Comfortable. + // Match against specific keys instead of any keys. Use this to avoid having to solve URLs in values. + return Pattern.compile(String.format("", String.join("|", properties)), Pattern.CASE_INSENSITIVE); } - public void deserialize(T nodeData, String input) throws IllegalArgumentException { + /** + * Deserialize NodeData from string form. + *

+ * Parse each property and call the assigned property deserializer. + * + * @param nodeData NodeData to call the assigned property deserialized on. + * @param input String input to deserialize from. + * @throws IllegalArgumentException If the input format is malformed in any way. + */ + public void deserialize(@NotNull T nodeData, @NotNull String input) throws IllegalArgumentException { log.fine("Deserializing " + input); - if (propertyEquals == null) { - this.propertyEquals = generatePropertyEqualsPattern(); + if (propertyEqualsPattern == null) { + this.propertyEqualsPattern = generatePropertyEqualsPattern(); } // Split out the [] section with actual data - Matcher matcher = dataPattern.matcher(input); + Matcher matcher = DATA_PATTERN.matcher(input); if (!matcher.find()) { - throw new IllegalArgumentException("Invalid node data format"); + throw new IllegalArgumentException("Malformed node data syntax. Most likely missing ']'."); } String dataString = matcher.group(1); @@ -51,18 +91,33 @@ public void deserialize(T nodeData, String input) throws IllegalArgumentExceptio String[] dataParts = dataString.split(","); for (String dataPart : dataParts) { - String[] entryParts = propertyEquals.split(dataPart); - String key = entryParts[0]; - String value = entryParts[1]; + if (dataPart.trim().isEmpty()) { + log.fine("Empty data part in '" + dataString + "'"); + continue; + } + + Matcher keyMatcher = KEY_PATTERN.matcher(dataPart); + + if (!keyMatcher.find()) { + throw new IllegalArgumentException(String.format("Malformed node data property part '%s'. Skipping.", dataPart)); + } + + String key = keyMatcher.group(1).substring(0, keyMatcher.end() - 1); + String value = dataPart.substring(keyMatcher.end()); + + log.fine("Key: " + key + ", value: " + value); PropertyDeserializer deserializer = properties.get(key); if (deserializer == null) { - log.warning(String.format("Unknown node data property %s", key)); - continue; + throw new IllegalArgumentException(String.format("Unknown node data property %s in part %s. Valid properties: '%s'.", key, dataPart, String.join("', '", this.properties.keySet()))); } - deserializer.deserialize(nodeData, value); + try { + deserializer.deserialize(nodeData, value); + } catch (Exception e) { + throw new IllegalArgumentException(String.format("Invalid value '%s' for property %s.", value, key), e); + } } } } diff --git a/pom.xml b/pom.xml index 57e77556..5ef3b2d2 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ nl.aurorion.blockregen BlockRegen - 3.16.4 + 3.16.5-SNAPSHOT blockregen-version blockregen-common