Skip to content

Commit

Permalink
Support for class properties (#283)
Browse files Browse the repository at this point in the history
  • Loading branch information
Deukhoofd authored Feb 26, 2024
1 parent 4d3f199 commit 98fbedb
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Add `text`, `width` and `height` members to `ObjectShape::Text`. (#278)
- Implement `ResourceReader` for appropiate functions. (#272) **Read the README's FAQ for more information about this change.**
- Support for custom type properties. (#283)

## Fixed
- `ObjectShape::Text::kerning`'s default value, which should have been set to `true` instead of `false`. (#278)
Expand Down
21 changes: 21 additions & 0 deletions assets/tiled_class_property.tmx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.10.2" orientation="orthogonal" renderorder="right-down" width="2" height="2" tilewidth="32" tileheight="32" infinite="0" nextlayerid="3" nextobjectid="4">
<layer id="1" name="Tile Layer 1" width="2" height="2">
<data encoding="csv">
0,0,
0,0
</data>
</layer>
<objectgroup id="2" name="Object Layer 1">
<object id="2" x="0" y="0" width="32" height="32">
<properties>
<property name="class property" type="class" propertytype="test_type">
<properties>
<property name="test_property_1" type="int" value="3"/>
</properties>
</property>
<property name="empty property" type="class" propertytype="empty_type"/>
</properties>
</object>
</objectgroup>
</map>
51 changes: 49 additions & 2 deletions src/properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ pub enum PropertyValue {
/// An object ID value. Corresponds to the `object` property type.
/// Holds the id of a referenced object, or 0 if unset.
ObjectValue(u32),
/// A class value. Corresponds to the `class` property type.
/// Holds the type name and a set of properties.
ClassValue {
/// The type name.
property_type: String,
/// A set of properties.
properties: Properties,
},
}

impl PropertyValue {
Expand Down Expand Up @@ -135,15 +143,31 @@ pub(crate) fn parse_properties(
let mut p = HashMap::new();
parse_tag!(parser, "properties", {
"property" => |attrs:Vec<OwnedAttribute>| {
let (t, v_attr, k) = get_attrs!(
let (t, v_attr, k, p_t) = get_attrs!(
for attr in attrs {
Some("type") => obj_type = attr,
Some("value") => value = attr,
Some("propertytype") => propertytype = attr,
"name" => name = attr
}
(obj_type, value, name)
(obj_type, value, name, propertytype)
);
let t = t.unwrap_or_else(|| "string".to_owned());
if t == "class" {
// Class properties will have their member values stored in a nested <properties>
// element. Only the actually set members are saved. When no members have been set
// the properties element is left out entirely.
let properties = if has_properties_tag_next(parser) {
parse_properties(parser)?
} else {
HashMap::new()
};
p.insert(k, PropertyValue::ClassValue {
property_type: p_t.unwrap_or_default(),
properties,
});
return Ok(());
}

let v: String = match v_attr {
Some(val) => val,
Expand All @@ -164,3 +188,26 @@ pub(crate) fn parse_properties(
});
Ok(p)
}

/// Checks if there is a properties tag next in the parser. Will consume any whitespace or comments.
fn has_properties_tag_next(parser: &mut impl Iterator<Item = XmlEventResult>) -> bool {
let mut peekable = parser.by_ref().peekable();
while let Some(Ok(next)) = peekable.peek() {
match next {
XmlEvent::StartElement { name, .. } if name.local_name == "properties" => return true,
// Ignore whitespace and comments
XmlEvent::Whitespace(_) => {
peekable.next();
}
XmlEvent::Comment(_) => {
peekable.next();
}
// If we encounter anything else than whitespace, comments or the properties tag, we
// assume there are no properties.
_ => {
return false;
}
}
}
false
}
36 changes: 32 additions & 4 deletions tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ fn test_object_group_property() {
};
assert!(prop_value);
}

#[test]
fn test_tileset_property() {
let r = Loader::new()
Expand Down Expand Up @@ -325,6 +326,33 @@ fn test_object_property() {
assert_eq!(3, prop_value);
}

#[test]
fn test_class_property() {
let r = Loader::new()
.load_tmx_map("assets/tiled_class_property.tmx")
.unwrap();
let layer = r.get_layer(1).unwrap();
if let Some(PropertyValue::ClassValue {
property_type,
properties,
}) = layer
.as_object_layer()
.unwrap()
.get_object(0)
.unwrap()
.properties
.get("class property")
{
assert_eq!(property_type, "test_type");
assert_eq!(
properties.get("test_property_1").unwrap(),
&PropertyValue::IntValue(3)
);
} else {
panic!("Expected class property");
};
}

#[test]
fn test_tint_color() {
let r = Loader::new()
Expand All @@ -336,7 +364,7 @@ fn test_tint_color() {
alpha: 0x12,
red: 0x34,
green: 0x56,
blue: 0x78
blue: 0x78,
})
);
assert_eq!(
Expand All @@ -345,7 +373,7 @@ fn test_tint_color() {
alpha: 0xFF,
red: 0x12,
green: 0x34,
blue: 0x56
blue: 0x56,
})
);
}
Expand All @@ -370,7 +398,7 @@ fn test_group_layers() {
alpha: 0x12,
red: 0x34,
green: 0x56,
blue: 0x78
blue: 0x78,
})),
layer_group_1.properties.get("key")
);
Expand Down Expand Up @@ -417,7 +445,7 @@ fn test_object_template_property() {
object.shape,
ObjectShape::Rect {
width: 32.0,
height: 32.0
height: 32.0,
}
);
assert_eq!(object.x, 32.0);
Expand Down

0 comments on commit 98fbedb

Please sign in to comment.