/ddstyleconverter

Program that allows you to change the style of DungeonDraft maps with the help of conversion files.

Primary LanguagePythonMIT LicenseMIT

No further development

This project is a proof of concept. Although the approach proved to work quite well not enough interest was shown by the community during its prototyping and feedback phase. Adoption by the community is essential for this program to be useful as generating a useful set of conversion files can only be done by a community. For this reason no further development will be done.

About

This is a prototype of a program that allows you to change the style of DungeonDraft maps with the help of conversion files.

The underlying principle is that of a simple search and replace. You can replace materials with other materials, objects with other objects and so on. The program can be used for all kinds of things. For example:

  • Convert between asset styles like 2-Minute-Tabletop, Crosshead and Forgotten Adventures
  • Convert between summer, winter, spring and fall

A conversion file is a sort of look-up map which tells the program how the conversion should be done. For more information about creating conversion maps see "How to create conversion maps"

Installation: Windows

Step 1: Get the exe

Option 1: Download

Download one of the pre-built ddstyleconverter.exe files from Releases

Go to Step 2: Install program

Option 2: Build it yourself

Install python3 (version >= 3.8) and add it to your PATH system environment variable.

You can check the version via CMD or powershell with:

python --version

Download or clone the repo.

Open a CMD instance inside the project root folder and create a virtual environment.

python -m venv .\venv

Activate the venv:

.\venv\Scripts\activate

Install pyInstaller package:

pip install pyInstaller

Run the build file:

.\scripts\build_for_windows.cmd

You should now have a ddstyleconverter.exe file under dist. After the build succeeded you can delete the venv you previously created.

Go to Step 2: Install program

Step 2: Install program

Create an empty folder where you want to install the program for example C:\ddstyleconverter

Copy ddstyleconverter.exe into that folder.

Optional: Add the installation path to your PATH system environment variable. This enables you to execute the program from anywhere which makes it much easier to use.

Uninstallation: Windows

Delete ddstyleconverter.exe file from the installation directory.

Optional: Remove the path to the installation directory from the PATH system environment variable.

Installation: Ubuntu 16.04 - 20.04

Optional: Install Python

An up-to-date Ubuntu 20.04 should have python >= 3.8. Check it with:

python3 --version

From here on pythonX will be used as placeholder for the python you should use. Depending on your system you need to replace X with 3, 3.8, 3.9 or 3.10 .

Install python version>=3.8 if not yet installed.

sudo apt install pythonX

Step 1: Get the executable

Option 1: Download

Download one of the pre-built ddstyleconverter files from Releases

Go to Step 2: Install the files

Option 2: Build it yourself

Install python if haven't already.

Download or clone repo.

Create a venv inside the repo:

sudo apt install pythonX-venv

pythonX -m venv ./venv

Activate venv:

source venv/bin/activate

Install pyInstaller:

pythonX -m pip install pyInstaller

Now run the build script:

./scrips/build_for_ubuntu.sh

Step 2: Install the files

Copy the ddstyleconverter file either from dist from where you downloaded it to usr/bin/

Make the file executable:

sudo chmod ugo=rx usr/bin/ddstyleconverter

Uninstallation: Ubuntu

Delete the file /usr/bin/ddstyleconverter

Usage

IMPORTANT:
Add all the asset packs you need to the map before you do the conversion. If you try to open a map that has references to assets of an un-imported asset pack it will just load forever.

Syntax

ddstyleconverter [--verbose-info, --verbose-debug, --version, --help, --out output_path,--cmap conversion_map_path, --create-cmap] target_path

Arguments

target_path: Path to the file which should be processed.

--out output_path: Specify output_path as file path to where the result should be written. The file itself must not exist but the parent directory must.

--cmap conversion_map_path: Specify conversion_map_path as path to the conversion map file.

--verbose-info: Enables verbose output to console

--verbose-debug: Enables very verbose output to console

--version: Print version and exits

--help: Display help and exit

--create-cmap: If this option is used the target file is not converted. Instead the target file is used to automatically generate a conversion map. For more information about that see "How To create conversion maps". This option does does not require a --cmap argument but can be combined with a --out argument.

Examples

Converting a map:

Ubuntu: ddstyleconverter path/to/file.dungeondraft_map --out path/to/output_file.dungeondraft_map --cmap path/to/conversion_map.json

Windows: ddstyleconverter.exe path\to\file.dungeondraft_map --out path\to\output_file.dungeondraft_map --cmap path\to\conversion_map.json

Known Issues and Quirks

Windows

When one of the paths has \' at the end, the arguments will get mixed up. This is a problem with how python handles arguments and probably can't be fixed. For example on Windows ddstyleconverter.exe '\folder name with spaces\' will fail but ddstyleconverter.exe '\folder name with spaces' will succeed.

How To create conversion maps

Automatically with the help of DungeonDraft files

Conversion maps can be created from DungeonDraft maps. Currently, only object conversions are supported. The DungeonDraft map has to have at least two levels. Objects on the first level will get mapped to the closest object on the second level. Relative rotation, translation and scale will automatically be calculated. For an example of such a DungeonDraft map have a look at example_maps/vanilla_to_dungeondraft.dungeondraft_map. To create a conversion map from a DungeonDraft map use:
ddstyleconverter --create-cmap path/to/dd_map.dungeondraft_map on Ubuntu
ddstyleconverter.exe --create-cmap path\to\dd_map.dungeondraft_map on Windows

Manually by writing them

Conversion maps are simple json files. Don't give up if you're not familiar with the json format. The json syntax is really easy to understand and requires zero programming knowledge. I recommend downloading and installing a text editor that supports the json format, for example Notepad++.

Understanding the dungeondraft_map format

Before we can create a conversion map we need to understand the format of dungeondraft_map files. Don't worry, it's really simple. Open up a dungeondraft_map file with your chosen text editor. If you are using Notepad++ tell the program that it should interpret the text as json via Language > J > JSON. What you will see is text in json format. Take a while to understand the basic format. The important parts are under world/levels (reading: Under world and there under levels), here you see the contents of each level. The contents are conveniently split into: patterns, walls, portals, terrain, materials, paths, objects and roofs Have a look at each of those entries. Most of them are lists (surrounded by []) of simple sub-entries. For example an objects entry has the format:

{
    "position": "Vector2(1036, 1537.44)",
    "rotation": -0,
    "scale": "Vector2( 0.892452, 0.892356 )",
    "mirror": false,
    "texture": "res://packs/xjCzavyl/textures/objects/anvil_01.png",
    "layer": 100,
    "shadow": false,
    "block_light": false,
    "node_id": "26"
}

The important parts here is the texture entry. That is what we want to replace.

Creating new conversion maps

To create a conversion file create a new file and give it the file extension json. The basic format of a conversion map is:

{
    "style_maps": {
        "materials": [],
        "objects": [],
        "paths": [],
        "patterns": [],
        "portals": [],
        "roofs": [],
        "terrain": [],
        "walls": []
    }
}

Entries

All entry types extend the same base entry, which has the format:

{
    "from_texture": "",
    "to_texture": ""
}

The from_texture and to_texture entries have to contain values from the respective texture entries from the dungeondraft_map file. For example an entry under materials would look like this:

{
    "from_texture": "res://textures/materials/lava_tile.png",
    "to_texture": "res://packs/xjCzavyl/textures/materials/lava_tile.png"
}

Which reads as: Replace all texture values within materials entries that have the value res://textures/materials/lava_tile.png with res://packs/xjCzavyl/textures/materials/lava_tile.png

The easiest way to find those texture values is to have a dungeondraft_map file which contains exactly two things:

  1. The object/path/wall/etc you want to be replaced
  2. The respective object/path/wall/etc with what you want to replace the first thing. You can only replace a path with path and an object with an object and so on.

I recommend putting them on different levels to make it easier to compare them. Such a dungeondraft_map file would look something like this:

{
    "header": {
        "creation_build": "1.0.3.2 tricky vampire",
        "creation_date": {
            "year": 2022,
            "month": 4,
            "day": 21,
            "weekday": 4,
            "dst": false,
            "hour": 11,
            "minute": 24,
            "second": 25
        },
        "uses_default_assets": true,
        "asset_manifest": [
            {
                "name": "Crosshead",
                "id": "xjCzavyl",
                "version": "1",
                "author": "Crosshead",
                "custom_color_overrides": {
                    "enabled": false,
                    "min_redness": 0.1,
                    "min_saturation": 0,
                    "red_tolerance": 0.04
                }
            }
        ],
        ...
    },
    "world": {
        ...
        "levels": {
            "0": {
                "label": "Crosshead",
                ...
                "objects": [
                    {
                        "position": "Vector2( 1280, 2048 )",
                        "rotation": -0.698132,
                        "scale": "Vector2( 0.552237, 0.552487 )",
                        "mirror": false,
                        "texture": "res://packs/xjCzavyl/textures/objects/book_01.png",
                        "layer": 100,
                        "shadow": false,
                        "block_light": false,
                        "node_id": "2a"
                    }
                ]
                ...
            },
            "1": {
                "label": "Ground",
                ...
                "objects": [
                    {
                        "position": "Vector2( 1280, 2048 )",
                        "rotation": 0,
                        "scale": "Vector2( 1, 1 )",
                        "mirror": false,
                        "texture": "res://textures/objects/activities/administration/book_04.png",
                        "layer": 100,
                        "shadow": false,
                        "block_light": false,
                        "node_id": "3d"
                    }
                ],
                ...
            }
        }
    }
}

As you may notice both objects have completely different scales and rotations. Because of that the objects entries of the conversion maps supports rotation, translation and scale

The objects entry to replace "res://textures/objects/activities/administration/book_04.png" with "res://packs/xjCzavyl/textures/objects/book_01.png" would look like this:

{
    "from_texture": "res://textures/objects/activities/administration/book_04.png",
    "to_texture": "res://packs/xjCzavyl/textures/objects/book_01.png",
    "translation": "Vector2(-11.58, -1.95)",
    "rotation": -0.698132,
    "scale": "Vector2( 0.552237, 0.552237 )"
}