Skip to content

Tiled 1.2.x object properties backwards compatibility issues #2034

Closed

Description

@Larkenx

I saw that properties were restructured into an array-like JSON format for object templates in #1868. This heavily breaks the way that my application was previously using properties, and is not at all intuitive for how one would use properties for in-game objects. Properties inherently should be a JSON object or map of properties -> values. I can't upgrade to Tiled 1.2.x with this break in backwards compatibility.

I understand that the specific use-case sited was Unity3d serialization, but for folks looking to parse Tiled objects, selecting properties.foo is much more intuitive than iterating over every single tile and creating a property map for each tile.

Here's an example use-case of an NPC, whose Tiled object properties defines its dialog & whether nor not that NPC wanders around the map.

{
  "gid": 4816,
  "height": 32,
  "id": 165,
  "name": "NPC",
  "properties": {
    "bubbleData": "8629,9469",
    "dialog": "BARTENDER",
    "dialogBubbleEnabled": true,
    "entity_type": "NPC",
    "wanders": false
  },
  "propertytypes": {
    "bubbleData": "string",
    "dialog": "string",
    "dialogBubbleEnabled": "bool",
    "entity_type": "string",
    "wanders": "bool"
  },
  "rotation": 0,
  "type": "",
  "visible": true,
  "width": 32,
  "x": 224,
  "y": 320
}

Here is the resulting object as a result of #1868.

{
    "gid":4816,
    "height":32,
    "id":165,
    "name":"NPC",
    "properties":[
           {
            "name":"bubbleData",
            "type":"string",
            "value":"8629,9469"
           }, 
           {
            "name":"dialog",
            "type":"string",
            "value":"BARTENDER"
           }, 
           {
            "name":"dialogBubbleEnabled",
            "type":"bool",
            "value":true
           }, 
           {
            "name":"entity_type",
            "type":"string",
            "value":"NPC"
           }, 
           {
            "name":"wanders",
            "type":"bool",
            "value":false
           }],
    "rotation":0,
    "type":"",
    "visible":true,
    "width":32,
    "x":224,
    "y":320
   }

At the very least, a visible warning and alert that this massively breaks backwards compatibility for those using Tiled objects would be appreciated!

Activity

  1. Larkenx commented on Nov 15, 2018

    @Larkenx
    Author

    Here's some more supporting examples of how I used the previous implementation of properties for objects. This is a code snippet that takes one of these objects, creates either an Actor or Item from the object, and places it in the game.

    createActorFromObject(object) {
    		const { gid, x, y, properties } = object
    		if (properties.entity_type === undefined) {
    			console.error(`No entity type given in properties for object ${object}`)
    			return
    		}
    		const { entity_type } = properties
    		let nx = x / 32
    		let ny = y / 32 - 1 // for some reason, TILED objects y position are 1-indexed..?
    		let entity = properties.item ? createItem(entity_type, nx, ny, gid - 1) : createActor(entity_type, nx, ny, gid - 1)
    		if (properties.item) entity.inInventory = false
    		if (properties.items !== undefined) {
    			let items = properties.items.split(',').map(i => createItem(i.trim(), nx, ny))
    			items.forEach(item => entity.addToInventory(item))
    		}
    		/* Post entity creation clean up... */
    		if (entity_type === 'NPC') {
    			// add NPC routines if any exist...
    			// NPCs may have items too!
    			entity.wanders = properties.wanders
    			if (properties.dialog !== undefined) {
    				const dialogID = properties.dialog
    				if (dialogID in DIALOGUES) {
    					entity.dialogData = DIALOGUES[dialogID]
    					entity.dialogBubbleEnabled = 'dialogBubbleEnabled' in properties ? properties.dialogBubbleEnabled : true
    					if ('bubbleData' in properties) {
    						let [id, animated_id] = properties.bubbleData.split(',')
    						entity.bubbleData = { id, animated_id }
    					} else {
    						entity.bubbleData = null
    					}
    				}
    			}
    		} else if (entity_type === 'LADDER' || entity_type === 'LEVEL_TRANSITION') {
    			// ladders & level transitions have portal ID's
    			entity.portal = properties.portalID
    			entity.createDungeon = properties.createDungeon
    			if (entity_type === 'LADDER') entity.direction = properties.direction
    		}
    		this.getTile(nx, ny).actors.push(entity)
    	}
  2. changed the title [-]Tiled 1.2.1 massive backwards compatibility issues[/-] [+]Tiled 1.2.x object properties massive backwards compatibility issues[/+] on Nov 15, 2018
  3. changed the title [-]Tiled 1.2.x object properties massive backwards compatibility issues[/-] [+]Tiled 1.2.x object properties backwards compatibility issues[/+] on Nov 15, 2018
  4. bjorn commented on Nov 15, 2018

    @bjorn
    Member

    I'm sorry that this compatibility change affected your project and likely wasted some of your time. I did mention it in the blog post about the Tiled 1.2 release under "Compatibility Notes" and provided details on the JSON format page.

    It wasn't only Unity that was having trouble parsing the old format, but generally all annotation-based automated parsing systems would have trouble dealing with JSON objects with arbitrary members. Also, the properties had become quite a mess with the additional propertytypes and tilepropertytypes members. Hence I'm reluctant to re-introduce support for the old format, even though I understand it was easier previously to access the properties in dynamically typed languages like JavaScript.

    Fortunately, it should be easy to support both formats in the map loader. After you have loaded the JSON, you could iterate your objects and perform the following kind of operation:

    function ensureObject(properties) {
        if (Array.isArray(properties)) {
            const array = properties;
            properties = {};
            for (const p of array)
                properties[p.name] = p.value;
        }
        return properties;
    }
    
    // For each object / tile / layer:
    something.properties = ensureObject(something.properties)

    I hope that helps you support Tiled 1.2 in your game.

  5. Larkenx commented on Nov 15, 2018

    @Larkenx
    Author

    Thanks for your swift response. I can see where this could present some issues across the board for other parsing systems, and where having the unified properties list with its respective type present can be really helpful. I'll be sure to do as you suggested above, and add an additional step to parse the properties array into a map as it was before.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions