From b79792b34b64a3deeaa04da8e4f0b1e11041c31a Mon Sep 17 00:00:00 2001 From: Roland Helmerichs Date: Mon, 23 Dec 2024 11:31:16 +0100 Subject: [PATCH] Hotfix release 2.1.6 --- CHANGELOG.md | 5 ++ CSharp/addons/YATI/DictionaryFromXml.cs | 64 ++++++++++++++++------- CSharp/addons/YATI/TilemapCreator.cs | 5 +- CSharp/addons/YATI/plugin.cfg | 2 +- CSharp/runtime/DictionaryFromXml.cs | 62 +++++++++++++++------- CSharp/runtime/TilemapCreator.cs | 5 +- GDScript/addons/YATI/DictionaryFromXml.gd | 17 +++++- GDScript/addons/YATI/TilemapCreator.gd | 5 +- GDScript/addons/YATI/plugin.cfg | 2 +- GDScript/runtime/DictionaryFromXml.gd | 17 +++++- GDScript/runtime/TilemapCreator.gd | 5 +- README.md | 6 +-- Runtime.md | 2 +- 13 files changed, 140 insertions(+), 57 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97ac1ff..830ca19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.1.6] - 2024-12-23 + +### Fixed +- Fixed issue with nested groups (.tmx only) + ## [2.1.5] - 2024-12-20 ### Refactoring notes (no change in functionalitiy) diff --git a/CSharp/addons/YATI/DictionaryFromXml.cs b/CSharp/addons/YATI/DictionaryFromXml.cs index 907bc84..68b0ce4 100644 --- a/CSharp/addons/YATI/DictionaryFromXml.cs +++ b/CSharp/addons/YATI/DictionaryFromXml.cs @@ -35,6 +35,7 @@ public class DictionaryFromXml { private XmlParserCtrl _xml; private string _currentElement; + private int _currentGroupLevel; private readonly Dictionary _result = new Dictionary(); private Dictionary _currentDictionary; private Array _currentArray; @@ -61,17 +62,26 @@ public Dictionary Create(byte[] tiledFileContent, string sourceFileName) _isMap = _currentElement == "map"; var baseElement = _currentElement; - while ((err == Error.Ok) && ((!_xml.IsEnd() || (_currentElement != baseElement)))) + var baseGroupLevel = _currentGroupLevel; + while ((err == Error.Ok) && ((!_xml.IsEnd() || (_currentElement != baseElement) || + (baseElement == "group" && _currentElement == "group" && _currentGroupLevel == baseGroupLevel)))) { _currentElement = _xml.NextElement(); if (_currentElement == null) { err = Error.ParseError; break; } - if (_xml.IsEnd()) continue; + if (_xml.IsEnd()) + { + if (_currentElement == "group") + _currentGroupLevel--; + continue; + } + if (_currentElement == "group" && !_xml.IsEmpty()) + _currentGroupLevel++; var cAttributes = _xml.GetAttributes(); var dictionaryBookmark = _currentDictionary; err = _xml.IsEmpty() ? SimpleElement(_currentElement, cAttributes) : NestedElement(_currentElement, cAttributes); _currentDictionary = dictionaryBookmark; } - + if (err == Error.Ok) return _result; GD.PrintErr($"Import aborted with {err} error."); return null; @@ -220,30 +230,44 @@ private Error NestedElement(string elementName, Dictionary attri var arrayBookmark1 = _currentArray; var err = SimpleElement(elementName, attributes); var baseElement = _currentElement; - while ((err == Error.Ok) && ((!_xml.IsEnd() || (_currentElement != baseElement)))) + var baseGroupLevel = _currentGroupLevel; + while ((err == Error.Ok) && ((!_xml.IsEnd() || (_currentElement != baseElement) || + (baseElement == "group" && _currentElement == "group" && _currentGroupLevel == baseGroupLevel)))) { _currentElement = _xml.NextElement(); if (_currentElement == null) return Error.ParseError; - if (_xml.IsEnd()) continue; - if (_currentElement == "") + if (_xml.IsEnd()) { - Variant data = _xml.GetData(); - if (baseElement is "text" or "property") - _currentDictionary.Add(baseElement, (string)data); - else - { - data = ((string)data).Trim(); - if (_csvEncoded) + if (_currentElement == "group") + _currentGroupLevel--; + continue; + } + switch (_currentElement) + { + case "group" when !_xml.IsEmpty(): + _currentGroupLevel++; + break; + case "": + { + Variant data = _xml.GetData(); + if (baseElement is "text" or "property") + _currentDictionary.Add(baseElement, (string)data); + else { - var arr = new Array(); - foreach (var s in ((string)data).Split(',',StringSplitOptions.TrimEntries)) - arr.Add(uint.Parse(s)); - data = arr; + data = ((string)data).Trim(); + if (_csvEncoded) + { + var arr = new Array(); + foreach (var s in ((string)data).Split(',',StringSplitOptions.TrimEntries)) + arr.Add(uint.Parse(s)); + data = arr; + } + ((Dictionary)_currentArray[^1]).Add("data", data); } - ((Dictionary)_currentArray[^1]).Add("data", data); + continue; } - continue; } + var cAttributes = _xml.GetAttributes(); var dictionaryBookmark2 = _currentDictionary; var arrayBookmark2 = _currentArray; @@ -284,4 +308,4 @@ private void InsertAttributes(Dictionary targetDictionary, Dictionary)props); diff --git a/CSharp/addons/YATI/plugin.cfg b/CSharp/addons/YATI/plugin.cfg index 91a6576..678649f 100644 --- a/CSharp/addons/YATI/plugin.cfg +++ b/CSharp/addons/YATI/plugin.cfg @@ -3,5 +3,5 @@ name="YATI" description="" author="Roland Helmerichs" -version="2.1.5" +version="2.1.6" script="TiledImport.cs" diff --git a/CSharp/runtime/DictionaryFromXml.cs b/CSharp/runtime/DictionaryFromXml.cs index cb1bf34..b724fd1 100644 --- a/CSharp/runtime/DictionaryFromXml.cs +++ b/CSharp/runtime/DictionaryFromXml.cs @@ -33,6 +33,7 @@ public class DictionaryFromXml { private XmlParserCtrl _xml; private string _currentElement; + private int _currentGroupLevel; private readonly Dictionary _result = new Dictionary(); private Dictionary _currentDictionary; private Array _currentArray; @@ -59,17 +60,26 @@ public Dictionary Create(byte[] tiledFileContent, string sourceFileName) _isMap = _currentElement == "map"; var baseElement = _currentElement; - while ((err == Error.Ok) && ((!_xml.IsEnd() || (_currentElement != baseElement)))) + var baseGroupLevel = _currentGroupLevel; + while ((err == Error.Ok) && ((!_xml.IsEnd() || (_currentElement != baseElement) || + (baseElement == "group" && _currentElement == "group" && _currentGroupLevel == baseGroupLevel)))) { _currentElement = _xml.NextElement(); if (_currentElement == null) { err = Error.ParseError; break; } - if (_xml.IsEnd()) continue; + if (_xml.IsEnd()) + { + if (_currentElement == "group") + _currentGroupLevel--; + continue; + } + if (_currentElement == "group" && !_xml.IsEmpty()) + _currentGroupLevel++; var cAttributes = _xml.GetAttributes(); var dictionaryBookmark = _currentDictionary; err = _xml.IsEmpty() ? SimpleElement(_currentElement, cAttributes) : NestedElement(_currentElement, cAttributes); _currentDictionary = dictionaryBookmark; } - + if (err == Error.Ok) return _result; GD.PrintErr($"Import aborted with {err} error."); return null; @@ -218,30 +228,44 @@ private Error NestedElement(string elementName, Dictionary attri var arrayBookmark1 = _currentArray; var err = SimpleElement(elementName, attributes); var baseElement = _currentElement; - while ((err == Error.Ok) && ((!_xml.IsEnd() || (_currentElement != baseElement)))) + var baseGroupLevel = _currentGroupLevel; + while ((err == Error.Ok) && ((!_xml.IsEnd() || (_currentElement != baseElement) || + (baseElement == "group" && _currentElement == "group" && _currentGroupLevel == baseGroupLevel)))) { _currentElement = _xml.NextElement(); if (_currentElement == null) return Error.ParseError; - if (_xml.IsEnd()) continue; - if (_currentElement == "") + if (_xml.IsEnd()) { - Variant data = _xml.GetData(); - if (baseElement is "text" or "property") - _currentDictionary.Add(baseElement, (string)data); - else - { - data = ((string)data).Trim(); - if (_csvEncoded) + if (_currentElement == "group") + _currentGroupLevel--; + continue; + } + switch (_currentElement) + { + case "group" when !_xml.IsEmpty(): + _currentGroupLevel++; + break; + case "": + { + Variant data = _xml.GetData(); + if (baseElement is "text" or "property") + _currentDictionary.Add(baseElement, (string)data); + else { - var arr = new Array(); - foreach (var s in ((string)data).Split(',',StringSplitOptions.TrimEntries)) - arr.Add(uint.Parse(s)); - data = arr; + data = ((string)data).Trim(); + if (_csvEncoded) + { + var arr = new Array(); + foreach (var s in ((string)data).Split(',',StringSplitOptions.TrimEntries)) + arr.Add(uint.Parse(s)); + data = arr; + } + ((Dictionary)_currentArray[^1]).Add("data", data); } - ((Dictionary)_currentArray[^1]).Add("data", data); + continue; } - continue; } + var cAttributes = _xml.GetAttributes(); var dictionaryBookmark2 = _currentDictionary; var arrayBookmark2 = _currentArray; diff --git a/CSharp/runtime/TilemapCreator.cs b/CSharp/runtime/TilemapCreator.cs index 39ff5fb..287ff6c 100644 --- a/CSharp/runtime/TilemapCreator.cs +++ b/CSharp/runtime/TilemapCreator.cs @@ -405,8 +405,9 @@ private void HandleLayer(Dictionary layer, Node parent) // if (!_useDefaultFilter) // groupNode.TextureFilter = CanvasItem.TextureFilterEnum.Nearest; - foreach (Dictionary childLayer in (Array)layer["layers"]) - HandleLayer(childLayer, groupNode); + if (layer.TryGetValue("layers", out var lrs)) + foreach (Dictionary childLayer in (Array)lrs) + HandleLayer(childLayer, groupNode); if (layer.TryGetValue("properties", out var props)) HandleProperties(groupNode, (Array)props); diff --git a/GDScript/addons/YATI/DictionaryFromXml.gd b/GDScript/addons/YATI/DictionaryFromXml.gd index 2aea804..409dce3 100644 --- a/GDScript/addons/YATI/DictionaryFromXml.gd +++ b/GDScript/addons/YATI/DictionaryFromXml.gd @@ -25,6 +25,7 @@ extends RefCounted var _xml = preload("XmlParserCtrl.gd").new() var _current_element = "" +var _current_group_level: int = 0 var _result = {} var _current_dictionary = _result var _current_array = [] @@ -46,13 +47,19 @@ func create(tiled_file_content: PackedByteArray, source_file_name: String): _is_map = _current_element == "map" var base_element = _current_element - while (err == OK and (not _xml.is_end() or _current_element != base_element)): + var base_group_level = _current_group_level + while err == OK and (not _xml.is_end() or _current_element != base_element or + (base_element == "group" and _current_element == "group" and _current_group_level == base_group_level)): _current_element = _xml.next_element() if _current_element == null: err = ERR_PARSE_ERROR break if _xml.is_end(): + if _current_element == "group": + _current_group_level -= 1 continue + if _current_element == "group" and not _xml.is_empty(): + _current_group_level += 1 var c_attributes = _xml.get_attributes() var dictionary_bookmark = _current_dictionary if _xml.is_empty(): @@ -163,12 +170,18 @@ func nested_element(element_name: String, attribs: Dictionary): var array_bookmark_1 = _current_array err = simple_element(element_name, attribs) var base_element = _current_element - while err == OK and (_xml.is_end() == false or (_current_element != base_element)): + var base_group_level = _current_group_level + while err == OK and (not _xml.is_end() or _current_element != base_element or + (base_element == "group" and _current_element == "group" and _current_group_level == base_group_level)): _current_element = _xml.next_element() if _current_element == null: return ERR_PARSE_ERROR if _xml.is_end(): + if _current_element == "group": + _current_group_level -= 1 continue + if _current_element == "group" and not _xml.is_empty(): + _current_group_level += 1 if _current_element == "": var data = _xml.get_data() if base_element == "text" or base_element == "property": diff --git a/GDScript/addons/YATI/TilemapCreator.gd b/GDScript/addons/YATI/TilemapCreator.gd index 7ca9c3a..eaa819f 100644 --- a/GDScript/addons/YATI/TilemapCreator.gd +++ b/GDScript/addons/YATI/TilemapCreator.gd @@ -352,8 +352,9 @@ func handle_layer(layer: Dictionary, parent: Node2D): var layer_pos_y = layer.get("y", 0.0) group_node.position = Vector2(layer_pos_x + layer_offset_x, layer_pos_y + layer_offset_y) - for child_layer in layer["layers"]: - handle_layer(child_layer, group_node) + if layer.has("layers"): + for child_layer in layer["layers"]: + handle_layer(child_layer, group_node) if layer.has("properties"): handle_properties(group_node, layer["properties"]) diff --git a/GDScript/addons/YATI/plugin.cfg b/GDScript/addons/YATI/plugin.cfg index d96b44e..34e861d 100644 --- a/GDScript/addons/YATI/plugin.cfg +++ b/GDScript/addons/YATI/plugin.cfg @@ -3,5 +3,5 @@ name="YATI" description="" author="Roland Helmerichs" -version="2.1.5" +version="2.1.6" script="TiledImport.gd" diff --git a/GDScript/runtime/DictionaryFromXml.gd b/GDScript/runtime/DictionaryFromXml.gd index 2f36212..f7c46f6 100644 --- a/GDScript/runtime/DictionaryFromXml.gd +++ b/GDScript/runtime/DictionaryFromXml.gd @@ -24,6 +24,7 @@ extends RefCounted var _xml = preload("XmlParserCtrl.gd").new() var _current_element = "" +var _current_group_level: int = 0 var _result = {} var _current_dictionary = _result var _current_array = [] @@ -45,13 +46,19 @@ func create(tiled_file_content: PackedByteArray, source_file_name: String): _is_map = _current_element == "map" var base_element = _current_element - while (err == OK and (not _xml.is_end() or _current_element != base_element)): + var base_group_level = _current_group_level + while err == OK and (not _xml.is_end() or _current_element != base_element or + (base_element == "group" and _current_element == "group" and _current_group_level == base_group_level)): _current_element = _xml.next_element() if _current_element == null: err = ERR_PARSE_ERROR break if _xml.is_end(): + if _current_element == "group": + _current_group_level -= 1 continue + if _current_element == "group" and not _xml.is_empty(): + _current_group_level += 1 var c_attributes = _xml.get_attributes() var dictionary_bookmark = _current_dictionary if _xml.is_empty(): @@ -162,12 +169,18 @@ func nested_element(element_name: String, attribs: Dictionary): var array_bookmark_1 = _current_array err = simple_element(element_name, attribs) var base_element = _current_element - while err == OK and (_xml.is_end() == false or (_current_element != base_element)): + var base_group_level = _current_group_level + while err == OK and (not _xml.is_end() or _current_element != base_element or + (base_element == "group" and _current_element == "group" and _current_group_level == base_group_level)): _current_element = _xml.next_element() if _current_element == null: return ERR_PARSE_ERROR if _xml.is_end(): + if _current_element == "group": + _current_group_level -= 1 continue + if _current_element == "group" and not _xml.is_empty(): + _current_group_level += 1 if _current_element == "": var data = _xml.get_data() if base_element == "text" or base_element == "property": diff --git a/GDScript/runtime/TilemapCreator.gd b/GDScript/runtime/TilemapCreator.gd index 17aaff8..59eedcb 100644 --- a/GDScript/runtime/TilemapCreator.gd +++ b/GDScript/runtime/TilemapCreator.gd @@ -351,8 +351,9 @@ func handle_layer(layer: Dictionary, parent: Node2D): var layer_pos_y = layer.get("y", 0.0) group_node.position = Vector2(layer_pos_x + layer_offset_x, layer_pos_y + layer_offset_y) - for child_layer in layer["layers"]: - handle_layer(child_layer, group_node) + if layer.has("layers"): + for child_layer in layer["layers"]: + handle_layer(child_layer, group_node) if layer.has("properties"): handle_properties(group_node, layer["properties"]) diff --git a/README.md b/README.md index 36e3c23..b5002c3 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ created by the [Tiled Map Editor](http://www.mapeditor.org). Tested on Windows 10 with Godot 4.3/4.2.2 and Tiled 1.11.0 (Tiled maps from older Tiled versions may work too) -Latest version: 2.1.5 (needs Godot 4.3.0 or higher) -Downloads: [GDScript version](../../releases/download/v2.1.5/v2.1.5-gdscript.zip) / [CSharp version](../../releases/download/v2.1.5/v2.1.5-csharp.zip) +Latest version: 2.1.6 (needs Godot 4.3.0 or higher) +Downloads: [GDScript version](../../releases/download/v2.1.6/v2.1.6-gdscript.zip) / [CSharp version](../../releases/download/v2.1.6/v2.1.6-csharp.zip) Latest version for Godot 4.2.x: 1.7.1 Version 1.7.1 downloads: [GDScript version](../../releases/download/v1.7.1/v1.7.1-gdscript.zip) / [CSharp version](../../releases/download/v1.7.1/v1.7.1-csharp.zip) @@ -20,7 +20,7 @@ For installation and usage please refer to the [runtime document](Runtime.md) The addon is available in GDScript as well as in C# for the Mono version of Godot 4. -- Download either the [GDScript version](../../releases/download/v2.1.5/v2.1.5-gdscript.zip) or the [CSharp version](../../releases/download/v2.1.5/v2.1.5-csharp.zip) +- Download either the [GDScript version](../../releases/download/v2.1.6/v2.1.6-gdscript.zip) or the [CSharp version](../../releases/download/v2.1.6/v2.1.6-csharp.zip) - Move the unzipped addon folder with its entire content to your Godot project folder - After starting your project in Godot the plugin should appear at Project>>Project Settings...>>Plugins diff --git a/Runtime.md b/Runtime.md index 3b0caad..12e4b68 100644 --- a/Runtime.md +++ b/Runtime.md @@ -3,7 +3,7 @@ The YATI runtime package allows for importing Tiled maps during (game) runtime. To offer such a package was proposed by Jeff Brooks (see issue #16) as being of value for several users. -Like for the editor plugin there's a [GDScript version](../../releases/download/v2.1.5/runtime-v2.1.5-gdscript.zip) and a [CSharp version](../../releases/download/v2.1.5/runtime-v2.1.5-csharp.zip) available. +Like for the editor plugin there's a [GDScript version](../../releases/download/v2.1.6/runtime-v2.1.6-gdscript.zip) and a [CSharp version](../../releases/download/v2.1.6/runtime-v2.1.6-csharp.zip) available. (Runtime downloads for Godot 4.2.x: [GDScript version](../../releases/download/v1.7.1/runtime-v1.7.1-gdscript.zip) and a [CSharp version](../../releases/download/v1.7.1/runtime-v1.7.1-csharp.zip))