Skip to content

Commit

Permalink
Merge pull request #46 from eleniums/fix/project-root
Browse files Browse the repository at this point in the history
Revert breaking changes to projectRoot and automatically determine projectRoot
  • Loading branch information
eleniums authored Jul 23, 2022
2 parents 6327ac4 + 540ee8e commit a8a8067
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 41 deletions.
41 changes: 31 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,42 @@ If you prefer watching check the video in YouTube:

[How to export from Tiled To Godot 3.2](https://youtu.be/4jSFAXIa_Lo)

The exporter needs to know how to set resource paths correctly for Godot before exporting. There are several ways to do this:

- If your Tiled files exist in your Godot project structure alongside the exported files, the exporter can automatically determine the resource paths. There is also the option to use the `projectRoot` custom property if needed.
- If your Tiled files exist outside your Godot project structure, you will need to set the `relativePath` custom property so the exporter can determine resource paths.

**_!!! Pay attention to the "/" instead of standard windows "\\". Single Backslash "\\" is used for escaping special symbols._**

### Setting relativePath

The custom property `relativePath : string` contains the relative path to the exported files from the Godot project root.
The value of `relativePath` is transformed to a resource path which Godot uses.

* When placed on a Tiled TileMap (.tmx) object, it will define where the Tileset objects (.tres) are located in the exported TileMap (.tscn).
* When placed on a Tiled TileSet (.tsx) object, it will define where the Image is located in the exported TileMap (.tres).

Example:
If the location of an exported tileset is: `C:/project/maps/level1/tileset.tres`
Then the `relativePath` custom property would be: `/maps/level1`

### Setting projectRoot `res://`

The exporter needs to know where `res://` is. By default, it's in the same directory where the Tiled files are being saved.
You can override this path with a custom property `projectRoot : string` that is either relative to the file you are exporting (starting with a `.`), or absolute path,
Either way the value of projectRoot is transformed to a resource path which Godot use.
The exporter needs to know where `res://` is so when you export to a subfolder in your Godot project all the relative paths for the resources `(res://)` are set correctly and relative to the project root. `res://` is equivalent to the location of `project.godot` in your Godot project.

**By default, the exporter expects the Tiled files to be saved in a subfolder of your Godot project next to the exported files and will determine the project root automatically. Setting `projectRoot` is no longer required in this scenario.**

If needed, you can override this path with a custom property `projectRoot : string` that is either relative to the file you are exporting (starting with a `.`) or an absolute path.
Either way, the value of `projectRoot` is transformed to the `res://` resource path which Godot uses and should be equivalent to the location of `project.godot`.

* When placed on a Tiled TileMap (.tmx) object it will define where the Tileset objects (.tres) are located in the exported TileMap (.tscn).
* When placed on a Tiled TileSet (.tsx) object it will define where the Image is located in the exported TileMap (.tres).
* When placed on a Tiled TileMap (.tmx) object it will be used as the root to determine the relative resource path to the Tileset objects (.tres) used in the exported TileMap (.tscn).
* When placed on a Tiled TileSet (.tsx) object it will be used as the root to determine the relative resource path to the Image used in the exported TileMap (.tres).

**_!!! Pay attention to the "/" instead of standard windows "\\".
Single Backslash "\\" is used for escaping special symbols._**
Example:
If the location of an exported tileset is: `C:/project/maps/level1/tileset.tres`
Then the `projectRoot` custom property would be: `C:/project`

This is needed so when you export to a subfolder in your Godot project all the relative
paths for the resources `(res://)` are set correctly and relative to the custom property
you've added `"projectRoot"`;
### Exporting to Godot

If everything is fine when you go to _File -> Export As_, a new option should exist:

Expand Down
13 changes: 6 additions & 7 deletions export_to_godot_tilemap.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,9 @@ class GodotTilemapExporter {
const tileset = this.map.tilesets[index];
this.extResourceId = index + 1;
this.tilesetsIndex.set(tileset.name, this.extResourceId);
// noinspection JSUnresolvedVariable
let tilesetPath = getResPath(this.map.property("projectRoot"), tileset.asset.fileName);
let tilesetName = FileInfo.fileName(tileset.asset.fileName).replace('.tsx', '.tres');
this.tilesetsString += this.getTilesetResourceTemplate(this.extResourceId, FileInfo.joinPaths(tilesetPath, tilesetName), "TileSet");
// noinspection JSUnresolvedFunction
let tilesetPath = getResPath(this.map.property("projectRoot"), this.map.property("relativePath"), tileset.asset.fileName.replace('.tsx', '.tres'));
this.tilesetsString += this.getTilesetResourceTemplate(this.extResourceId, tilesetPath, "TileSet");
}

}
Expand Down Expand Up @@ -131,9 +130,9 @@ class GodotTilemapExporter {
this.extResourceId = this.extResourceId + 1;
textureResourceId = this.extResourceId;
this.tilesetsIndex.set(tilesetsIndexKey, this.extResourceId);
let tileImagePath = getResPath(this.map.property("projectRoot"), object.tile.tileset.image);
let tileImageName = FileInfo.fileName(object.tile.tileset.image);
this.tilesetsString += this.getTilesetResourceTemplate(this.extResourceId, FileInfo.joinPaths(tileImagePath, tileImageName), "Texture");
// noinspection JSUnresolvedFunction
let tilesetPath = getResPath(this.map.property("projectRoot"), this.map.property("relativePath"), object.tile.tileset.image);
this.tilesetsString += this.getTilesetResourceTemplate(this.extResourceId, tilesetPath, "Texture");
} else {
textureResourceId = this.tilesetsIndex.get(tilesetsIndexKey);
}
Expand Down
6 changes: 1 addition & 5 deletions export_to_godot_tileset.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ class GodotTilesetExporter {
this.tileset = tileset;
this.fileName = fileName;
// noinspection JSUnresolvedFunction
this.imagePath = getResPath(this.tileset.property("projectRoot"), this.tileset.image);
this.spriteImagePath = FileInfo.joinPaths(this.imagePath, FileInfo.fileName(this.tileset.image));

// Strip leading slashes to prevent invalid triple slashes in Godot res:// path:
this.spriteImagePath = this.spriteImagePath.replace(/^\/+/, '');
this.spriteImagePath = getResPath(this.tileset.property("projectRoot"), this.tileset.property("relativePath"), this.tileset.image);
this.shapesResources = "";
this.shapes = "";
this.navpolyMap = [];
Expand Down
78 changes: 59 additions & 19 deletions utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,65 @@ function logk(data) {
console.log(Object.keys(data));
}

function getResPath(projectRoot, outputPath) {
const p = outputPath.split('/').slice(0, -1)
// check for projectRoot
// If projectRoot is not set, set it to current file's location
if (!projectRoot) {
projectRoot = p.join('/')
}
projectRoot = projectRoot.replace(/\\/g, '/')
// Use it as absolute, if it doesn't start with ".", relative if it does
if (projectRoot[0] === '.') {
const out = p
projectRoot.split('/').forEach((segment, i) => {
if (segment === '..') {
out.pop()
}
})
projectRoot = out.join('/')
/**
* Returns a full res path to a file.
*
* If relativePath is defined, uses relativePath to determine the res path.
* If relativePath is undefined, uses projectRoot to determine the res path.
* If relativePath is undefined and projectRoot is undefined, automatically determines the res path.
*
* Information on file paths in Godot: https://docs.godotengine.org/en/stable/tutorials/io/data_paths.html
*
* @param {string} projectRoot desired project root path, which can be an absolute or relative path to the outputPath. Ex: 'C:/project' or './../..'
* @param {string} relativePath relative path to file. Ex: '/maps/level1'
* @param {string} outputPath full path and name of destination file. Ex: 'C:/project/maps/level1/tileset.tres'
* @returns {string} full relative path to file to be included in a 'res://' path. Ex: 'maps/level1/tileset.tres'
*/
function getResPath(projectRoot, relativePath, outputPath) {
let fullResPath = ''
if (relativePath) {
// Replace all backslashes with forward slashes
relativePath = relativePath.replace(/\\/g, '/');

fullResPath = FileInfo.joinPaths(relativePath, FileInfo.fileName(outputPath));
} else {
const p = outputPath.split('/').slice(0, -1)

// If projectRoot is not set, attempt to automatically determine projectRoot by searching for godot project file
if (!projectRoot) {
const out = p
outputPath.split('/').every(_ => {
let godotProjectFile = FileInfo.joinPaths(out.join('/'), 'project.godot');
if (!File.exists(godotProjectFile)) {
out.pop()
return true;
}
return false;
})
projectRoot = out.join('/')
}

// Replace all backslashes with forward slashes
projectRoot = projectRoot.replace(/\\/g, '/');

// Use projectRoot as absolute if it doesn't start with ".", relative if it does
if (projectRoot[0] === '.') {
const out = p
projectRoot.split('/').forEach((segment) => {
if (segment === '..') {
out.pop()
}
})
projectRoot = out.join('/')
}

fullResPath = outputPath.replace(projectRoot, "");
}
return projectRoot

// Strip leading slashes to prevent invalid triple slashes in Godot res:// path
fullResPath = fullResPath.replace(/^\/+/, '');

return fullResPath
}

/**
Expand Down Expand Up @@ -65,7 +105,7 @@ function splitCommaSeparated(str) {
* @param {object} nodeProperties pair key/values for the "node" properties
* @param {object} contentProperties pair key/values for the content properties
* @param {object} metaProperties pair key/values for the meta properties
* @return {string} TSCN scene node like so :
* @returns {string} TSCN scene node like so :
* ```
* [node key="value"]
* content_key = AnyValue
Expand Down

0 comments on commit a8a8067

Please sign in to comment.