ldtk tileset import
@ -14,12 +14,13 @@ This section is a high level overview of what is being or can be worked on.
|
|||||||
|
|
||||||
## Vehicle Physics Model
|
## Vehicle Physics Model
|
||||||
|
|
||||||
|
- [ ] Kinematics low-speed model.
|
||||||
- [ ] Dynamics (force based) vehicle model.
|
- [ ] Dynamics (force based) vehicle model.
|
||||||
- [ ] Implement rear-wheel drive.
|
- [ ] Implement rear-wheel drive.
|
||||||
- [ ] Implement four-wheel drive.
|
- [ ] Implement four-wheel drive.
|
||||||
- [ ] Implement no-grip state (wheels have lost static grip on the road).
|
- [ ] Implement no-grip state (wheels have lost static grip on the road).
|
||||||
- [ ] Implement handbrake.
|
- [ ] Implement handbrake.
|
||||||
- [ ] Kinematics low-speed model.
|
- [ ] Weight shifting
|
||||||
- [ ] Export parameters to be configurable in Godot editor.
|
- [ ] Export parameters to be configurable in Godot editor.
|
||||||
|
|
||||||
## Audio
|
## Audio
|
||||||
@ -38,3 +39,7 @@ This section is a high level overview of what is being or can be worked on.
|
|||||||
## Multiplayer
|
## Multiplayer
|
||||||
|
|
||||||
- [ ] ?
|
- [ ] ?
|
||||||
|
|
||||||
|
## CI
|
||||||
|
|
||||||
|
- [ ] Build and host book
|
||||||
|
5
godot/addons/ldtk-importer/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# ldtk-importer / godot-ldtk
|
||||||
|
|
||||||
|
[LDtk](https://ldtk.io/) importer for [Godot 4](https://godotengine.org/)
|
||||||
|
|
||||||
|
[Github](https://github.com/heygleeson/godot-ldtk)
|
311
godot/addons/ldtk-importer/ldtk-importer.gd
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
@tool
|
||||||
|
extends EditorImportPlugin
|
||||||
|
|
||||||
|
const LDTK_LATEST_VERSION = "1.5.3"
|
||||||
|
|
||||||
|
enum Presets {DEFAULT}
|
||||||
|
|
||||||
|
const Util = preload("src/util/util.gd")
|
||||||
|
const World = preload("src/world.gd")
|
||||||
|
const Level = preload("src/level.gd")
|
||||||
|
const Tileset = preload("src/tileset.gd")
|
||||||
|
const DefinitionUtil = preload("src/util/definition_util.gd")
|
||||||
|
|
||||||
|
#region EditorImportPlugin Overrides
|
||||||
|
|
||||||
|
#region Simple
|
||||||
|
func _get_importer_name():
|
||||||
|
return "ldtk.import"
|
||||||
|
|
||||||
|
func _get_visible_name():
|
||||||
|
return "LDTK Scene"
|
||||||
|
|
||||||
|
func _get_priority():
|
||||||
|
return 1.0
|
||||||
|
|
||||||
|
func _get_import_order():
|
||||||
|
return IMPORT_ORDER_SCENE
|
||||||
|
|
||||||
|
func _get_resource_type():
|
||||||
|
return "PackedScene"
|
||||||
|
|
||||||
|
func _get_recognized_extensions():
|
||||||
|
return ["ldtk"]
|
||||||
|
|
||||||
|
func _get_save_extension():
|
||||||
|
return "scn"
|
||||||
|
|
||||||
|
func _get_preset_count():
|
||||||
|
return Presets.size()
|
||||||
|
|
||||||
|
func _get_preset_name(index):
|
||||||
|
match index:
|
||||||
|
Presets.DEFAULT:
|
||||||
|
return "Default"
|
||||||
|
_:
|
||||||
|
return "Unknown"
|
||||||
|
|
||||||
|
func _get_option_visibility(path, option_name, options):
|
||||||
|
match option_name:
|
||||||
|
_:
|
||||||
|
return true
|
||||||
|
return true
|
||||||
|
|
||||||
|
func _can_import_threaded() -> bool:
|
||||||
|
return false
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
func _get_import_options(path, index):
|
||||||
|
return [
|
||||||
|
# --- World --- #
|
||||||
|
{"name": "World", "default_value":"", "usage": PROPERTY_USAGE_GROUP},
|
||||||
|
{
|
||||||
|
# Group LDTKLevels in 'LDTKWorldLayer' nodes if using LDTK's WorldDepth.
|
||||||
|
"name": "group_world_layers",
|
||||||
|
"default_value": false,
|
||||||
|
},
|
||||||
|
# --- Levels --- #
|
||||||
|
{"name": "Level", "default_value":"", "usage": PROPERTY_USAGE_GROUP},
|
||||||
|
{
|
||||||
|
# Save LDTKLevels as PackedScenes.
|
||||||
|
"name": "pack_levels",
|
||||||
|
"default_value": true,
|
||||||
|
},
|
||||||
|
# --- Layers --- #
|
||||||
|
{"name": "Layer", "default_value":"", "usage": PROPERTY_USAGE_GROUP},
|
||||||
|
{
|
||||||
|
# Save LDTKLevels as PackedScenes.
|
||||||
|
"name": "layers_always_visible",
|
||||||
|
"default_value": false,
|
||||||
|
},
|
||||||
|
# --- Tileset --- #
|
||||||
|
{"name": "Tileset", "default_value":"", "usage": PROPERTY_USAGE_GROUP},
|
||||||
|
{
|
||||||
|
# Add LDTK Custom Data to Tilesets
|
||||||
|
"name": "tileset_custom_data",
|
||||||
|
"default_value": false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
# Create TileAtlasSources & TileMapLayers for IntGrid Layers
|
||||||
|
"name": "integer_grid_tilesets",
|
||||||
|
"default_value": false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
# Define default texture type for TilesetAtlasSource (e.g. to apply normal maps to tilesets after import)
|
||||||
|
"name": "atlas_texture_type",
|
||||||
|
"default_value": 0,
|
||||||
|
"property_hint": PROPERTY_HINT_ENUM,
|
||||||
|
"hint_string": "CompressedTexture2D,CanvasTexture",
|
||||||
|
},
|
||||||
|
# --- Entities --- #
|
||||||
|
{"name": "Entity", "default_value":"", "usage": PROPERTY_USAGE_GROUP},
|
||||||
|
{
|
||||||
|
#
|
||||||
|
"name": "resolve_entityrefs",
|
||||||
|
"default_value": true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
# Create LDTKEntityPlaceholder nodes to help debug importing.
|
||||||
|
"name": "use_entity_placeholders",
|
||||||
|
"default_value": false,
|
||||||
|
},
|
||||||
|
# --- Post Import --- #
|
||||||
|
{"name": "Post Import", "default_value":"", "usage": PROPERTY_USAGE_GROUP},
|
||||||
|
{
|
||||||
|
# Define a post-import script to apply on imported Tilesets.
|
||||||
|
"name": "tileset_post_import",
|
||||||
|
"default_value": "",
|
||||||
|
"property_hint": PROPERTY_HINT_FILE,
|
||||||
|
"hint_string": "*.gd;GDScript"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
# Define a post-import script to apply on imported Entities.
|
||||||
|
"name": "entities_post_import",
|
||||||
|
"default_value": "",
|
||||||
|
"property_hint": PROPERTY_HINT_FILE,
|
||||||
|
"hint_string": "*.gd;GDScript"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
# Define a post-import script to apply on imported Levels.
|
||||||
|
"name": "level_post_import",
|
||||||
|
"default_value": "",
|
||||||
|
"property_hint": PROPERTY_HINT_FILE,
|
||||||
|
"hint_string": "*.gd;GDScript"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
# Define a post-import script to apply on imported Worlds.
|
||||||
|
"name": "world_post_import",
|
||||||
|
"default_value": "",
|
||||||
|
"property_hint": PROPERTY_HINT_FILE,
|
||||||
|
"hint_string": "*.gd;GDScript"
|
||||||
|
},
|
||||||
|
# --- Debug --- #
|
||||||
|
{"name": "Debug", "default_value":"", "usage": PROPERTY_USAGE_GROUP},
|
||||||
|
{
|
||||||
|
# Force Tilesets to be recreated, resetting modifications (if experiencing import issues)
|
||||||
|
"name": "force_tileset_reimport",
|
||||||
|
"default_value": false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
# Debug: Enable Verbose Output (used by the importer)
|
||||||
|
"name": "verbose_output", "default_value": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
func _import(
|
||||||
|
source_file: String,
|
||||||
|
save_path: String,
|
||||||
|
options: Dictionary,
|
||||||
|
platform_variants: Array[String],
|
||||||
|
gen_files: Array[String]
|
||||||
|
) -> Error:
|
||||||
|
|
||||||
|
Util.timer_reset()
|
||||||
|
Util.timer_start(Util.DebugTime.TOTAL)
|
||||||
|
Util.print("import_start", source_file)
|
||||||
|
|
||||||
|
# Add options to static var in "Util", accessible from any script.
|
||||||
|
Util.options = options
|
||||||
|
|
||||||
|
# Parse source_file
|
||||||
|
var base_dir := source_file.get_base_dir() + "/"
|
||||||
|
var file_name := source_file.get_file()
|
||||||
|
var world_name := file_name.split(".")[0]
|
||||||
|
|
||||||
|
Util.timer_start(Util.DebugTime.LOAD)
|
||||||
|
var world_data := Util.parse_file(source_file)
|
||||||
|
Util.timer_finish("File parsed")
|
||||||
|
|
||||||
|
# Check version
|
||||||
|
if Util.check_version(world_data.jsonVersion, LDTK_LATEST_VERSION):
|
||||||
|
Util.print("item_ok", "LDTK VERSION (%s) OK" % [world_data.jsonVersion])
|
||||||
|
else:
|
||||||
|
return ERR_PARSE_ERROR
|
||||||
|
|
||||||
|
Util.timer_start(Util.DebugTime.GENERAL)
|
||||||
|
var definitions := DefinitionUtil.build_definitions(world_data)
|
||||||
|
var tileset_overrides := Tileset.get_tileset_overrides(world_data)
|
||||||
|
Util.timer_finish("Definitions Created")
|
||||||
|
|
||||||
|
# Build Tilesets and save as Resources
|
||||||
|
if Util.options.verbose_output: Util.print("block", "Tilesets")
|
||||||
|
var tileset_paths := Tileset.build_tilesets(definitions, base_dir, tileset_overrides)
|
||||||
|
gen_files.append_array(tileset_paths)
|
||||||
|
|
||||||
|
# Fetch EntityDef Tile textures
|
||||||
|
Tileset.get_entity_def_tiles(definitions, Util.tilesets)
|
||||||
|
|
||||||
|
# Detect Multi-Worlds
|
||||||
|
var external_levels: bool = world_data.externalLevels
|
||||||
|
var world_iid: String = world_data.iid
|
||||||
|
|
||||||
|
var world: LDTKWorld
|
||||||
|
if world_data.worldLayout == null:
|
||||||
|
var world_nodes: Array[LDTKWorld] = []
|
||||||
|
var world_instances: Array = world_data.worlds
|
||||||
|
# Build each world instance
|
||||||
|
for world_instance in world_instances:
|
||||||
|
var world_instance_name: String = world_instance.identifier
|
||||||
|
var world_instance_iid: String = world_instance.iid
|
||||||
|
var levels := Level.build_levels(world_instance, definitions, base_dir, external_levels)
|
||||||
|
var world_node := World.create_world(world_instance_name, world_instance_iid, levels, base_dir)
|
||||||
|
world_nodes.append(world_node)
|
||||||
|
|
||||||
|
world = World.create_multi_world(world_name, world_iid, world_nodes)
|
||||||
|
else:
|
||||||
|
if Util.options.verbose_output: Util.print("block", "Levels")
|
||||||
|
var levels := Level.build_levels(world_data, definitions, base_dir, external_levels)
|
||||||
|
|
||||||
|
# Save Levels (after Level Post-Import)
|
||||||
|
if (Util.options.pack_levels):
|
||||||
|
var levels_path := base_dir + 'levels/'
|
||||||
|
var directory = DirAccess.open(base_dir)
|
||||||
|
if not directory.dir_exists(levels_path):
|
||||||
|
directory.make_dir(levels_path)
|
||||||
|
|
||||||
|
# Resolve Refs + Cleanup Resolvers. We don't want to save 'NodePathResolver' in the Level scene.
|
||||||
|
#if (Util.options.verbose_output): Util.print("block", "References")
|
||||||
|
if (Util.options.verbose_output): Util.print("block", "Save Levels")
|
||||||
|
Util.handle_references()
|
||||||
|
var packed_levels = save_levels(levels, levels_path, gen_files)
|
||||||
|
|
||||||
|
if (Util.options.verbose_output): Util.print("block", "Save World")
|
||||||
|
world = World.create_world(world_name, world_iid, packed_levels, base_dir)
|
||||||
|
else:
|
||||||
|
if (Util.options.verbose_output): Util.print("block", "Save World")
|
||||||
|
world = World.create_world(world_name, world_iid, levels, base_dir)
|
||||||
|
|
||||||
|
Util.handle_references()
|
||||||
|
|
||||||
|
# Save World as PackedScene
|
||||||
|
Util.timer_start(Util.DebugTime.SAVE)
|
||||||
|
var err = save_world(world, save_path, gen_files)
|
||||||
|
Util.timer_finish("World Saved", 1)
|
||||||
|
|
||||||
|
if Util.options.verbose_output: Util.print("block", "Results")
|
||||||
|
|
||||||
|
Util.timer_finish("Completed.")
|
||||||
|
|
||||||
|
var total_time: int = Util.DebugTime.get_total_time()
|
||||||
|
var result_message: String = Util.DebugTime.get_result()
|
||||||
|
|
||||||
|
if Util.options.verbose_output: Util.print("item_info", result_message)
|
||||||
|
Util.print("import_finish", str(total_time))
|
||||||
|
|
||||||
|
return err
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
func save_world(
|
||||||
|
world: LDTKWorld,
|
||||||
|
save_path: String,
|
||||||
|
gen_files: Array[String]
|
||||||
|
) -> Error:
|
||||||
|
var packed_world = PackedScene.new()
|
||||||
|
packed_world.pack(world)
|
||||||
|
|
||||||
|
Util.print("item_save", "Saving World [color=#fe8019][i]'%s'[/i][/color]" % [save_path], 1)
|
||||||
|
|
||||||
|
var world_path = "%s.%s" % [save_path, _get_save_extension()]
|
||||||
|
var err = ResourceSaver.save(packed_world, world_path)
|
||||||
|
if err == OK:
|
||||||
|
gen_files.append(world_path)
|
||||||
|
return err
|
||||||
|
|
||||||
|
func save_levels(
|
||||||
|
levels: Array[LDTKLevel],
|
||||||
|
save_path: String,
|
||||||
|
gen_files: Array[String]
|
||||||
|
) -> Array[LDTKLevel]:
|
||||||
|
Util.timer_start(Util.DebugTime.SAVE)
|
||||||
|
var packed_levels: Array[LDTKLevel] = []
|
||||||
|
|
||||||
|
|
||||||
|
var level_names := levels.map(func(elem): return elem.name)
|
||||||
|
Util.print("item_save", "Saving Levels: [color=#fe8019]%s[/color]" % [level_names], 1)
|
||||||
|
|
||||||
|
for level in levels:
|
||||||
|
for child in level.get_children():
|
||||||
|
Util.recursive_set_owner(child, level)
|
||||||
|
var level_path = save_level(level, save_path, gen_files)
|
||||||
|
var packed_level = load(level_path).instantiate()
|
||||||
|
packed_levels.append(packed_level)
|
||||||
|
|
||||||
|
Util.timer_finish("%s Levels Saved" % [levels.size()], 1)
|
||||||
|
return packed_levels
|
||||||
|
|
||||||
|
func save_level(
|
||||||
|
level: LDTKLevel,
|
||||||
|
save_path: String,
|
||||||
|
gen_files: Array[String]
|
||||||
|
) -> String:
|
||||||
|
var packed_level = PackedScene.new()
|
||||||
|
packed_level.pack(level)
|
||||||
|
var level_path = "%s%s.%s" % [save_path, level.name, _get_save_extension()]
|
||||||
|
|
||||||
|
var err = ResourceSaver.save(packed_level, level_path)
|
||||||
|
if err == OK:
|
||||||
|
gen_files.append(level_path)
|
||||||
|
|
||||||
|
return level_path
|
1
godot/addons/ldtk-importer/ldtk-importer.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://lnqlil4dt4ca
|
7
godot/addons/ldtk-importer/plugin.cfg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[plugin]
|
||||||
|
|
||||||
|
name="LDTK"
|
||||||
|
description="LDtk Import plugin for Godot 4!"
|
||||||
|
author="Andy Gleeson (gleeson.dev)"
|
||||||
|
version="2.0.1"
|
||||||
|
script="plugin.gd"
|
19
godot/addons/ldtk-importer/plugin.gd
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
@tool
|
||||||
|
extends EditorPlugin
|
||||||
|
|
||||||
|
var ldtk_plugin
|
||||||
|
var config = ConfigFile.new()
|
||||||
|
|
||||||
|
func _enter_tree() -> void:
|
||||||
|
ldtk_plugin = preload("ldtk-importer.gd").new()
|
||||||
|
add_import_plugin(ldtk_plugin)
|
||||||
|
|
||||||
|
var config = ConfigFile.new()
|
||||||
|
var err = config.load("res://addons/ldtk-importer/plugin.cfg")
|
||||||
|
var version = config.get_value("plugin", "version", "0.0")
|
||||||
|
|
||||||
|
print_rich("[color=#ffcc00]█ Godot-LDtk-Importer █[/color] %s | [url=https://gleeson.dev]@gleeson.dev[/url] | [url=https://github.com/heygleeson/godot-ldtk-importer]View on Github[/url]" % [version])
|
||||||
|
|
||||||
|
func _exit_tree() -> void:
|
||||||
|
remove_import_plugin(ldtk_plugin)
|
||||||
|
ldtk_plugin = null
|
1
godot/addons/ldtk-importer/plugin.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://bqk4o57wsdal2
|
15
godot/addons/ldtk-importer/post-import/entity-template.gd
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
@tool
|
||||||
|
|
||||||
|
# Entity Post-Import Template for LDTK-Importer.
|
||||||
|
|
||||||
|
func post_import(entity_layer: LDTKEntityLayer) -> LDTKEntityLayer:
|
||||||
|
var definition: Dictionary = entity_layer.definition
|
||||||
|
var entities: Array = entity_layer.entities
|
||||||
|
|
||||||
|
#print("EntityLayer: ", entity_layer.name, " | Count: ", entities.size())
|
||||||
|
|
||||||
|
for entity in entities:
|
||||||
|
# Perform operations here
|
||||||
|
pass
|
||||||
|
|
||||||
|
return entity_layer
|
@ -0,0 +1 @@
|
|||||||
|
uid://c56fiui27y4ww
|
8
godot/addons/ldtk-importer/post-import/level-template.gd
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
@tool
|
||||||
|
|
||||||
|
# Level Post-Import Template for LDTK-Importer.
|
||||||
|
|
||||||
|
func post_import(level: LDTKLevel) -> LDTKLevel:
|
||||||
|
# Behaviour goes here
|
||||||
|
#print("Level: ", level)
|
||||||
|
return level
|
@ -0,0 +1 @@
|
|||||||
|
uid://05p0rgy0kklx
|
10
godot/addons/ldtk-importer/post-import/tileset-template.gd
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
@tool
|
||||||
|
|
||||||
|
# Tileset Post-Import Template for LDTK-Importer.
|
||||||
|
|
||||||
|
func post_import(tilesets: Dictionary) -> Dictionary:
|
||||||
|
# Behaviour goes here
|
||||||
|
for tileset: TileSet in tilesets.values():
|
||||||
|
#print("Tileset: ", tileset, tileset.tile_size)
|
||||||
|
pass
|
||||||
|
return tilesets
|
@ -0,0 +1 @@
|
|||||||
|
uid://bwex3re84r6o2
|
8
godot/addons/ldtk-importer/post-import/world-template.gd
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
@tool
|
||||||
|
|
||||||
|
# World Post-Import Template for LDTK-Importer.
|
||||||
|
|
||||||
|
func post_import(world: LDTKWorld) -> LDTKWorld:
|
||||||
|
# Behaviour goes here
|
||||||
|
#print("World: ", world)
|
||||||
|
return world
|
@ -0,0 +1 @@
|
|||||||
|
uid://bko7ojwy2jnl
|
@ -0,0 +1,8 @@
|
|||||||
|
@tool
|
||||||
|
@icon("ldtk-entity-layer.svg")
|
||||||
|
class_name LDTKEntityLayer
|
||||||
|
extends Node2D
|
||||||
|
|
||||||
|
@export var iid: String
|
||||||
|
@export var definition: Dictionary
|
||||||
|
@export var entities: Array
|
@ -0,0 +1 @@
|
|||||||
|
uid://c6umqvu1pttjk
|
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.a{fill:#fc0;}</style></defs><polygon class="a" points="8.47 12.55 8 12.79 7.53 12.55 2.05 9.8 0.85 10.4 8 14 15.15 10.4 13.95 9.8 8.47 12.55"/><polygon class="a" points="8.47 10.15 8 10.39 7.53 10.15 2.05 7.4 0.85 8 8 11.6 15.15 8 13.95 7.4 8.47 10.15"/><polygon class="a" points="8 2 0.85 5.6 8 9.2 15.15 5.6 8 2"/></svg>
|
After Width: | Height: | Size: 396 B |
@ -0,0 +1,37 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cjhytibfjjb2y"
|
||||||
|
path="res://.godot/imported/ldtk-entity-layer.svg-4429574458c1abbb5905ae9e6174fef3.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/ldtk-importer/src/components/ldtk-entity-layer.svg"
|
||||||
|
dest_files=["res://.godot/imported/ldtk-entity-layer.svg-4429574458c1abbb5905ae9e6174fef3.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
@ -0,0 +1,6 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://dndtl8sgpdo6m"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://addons/ldtk-importer/src/components/ldtk-entity-layer.gd" id="1_kdfje"]
|
||||||
|
|
||||||
|
[node name="LDTK Entity Layer" type="Node2D"]
|
||||||
|
script = ExtResource("1_kdfje")
|
96
godot/addons/ldtk-importer/src/components/ldtk-entity.gd
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
@icon("ldtk-entity.svg")
|
||||||
|
@tool
|
||||||
|
class_name LDTKEntity
|
||||||
|
extends Node2D
|
||||||
|
|
||||||
|
## Placeholder Node for importing LDTK maps.
|
||||||
|
## Used to demonstrate import functionality - please write an Entity Post-Import script to spawn
|
||||||
|
## your own instances when using this in your project.
|
||||||
|
|
||||||
|
@export var iid: String
|
||||||
|
@export var identifier := "EntityPlaceholder"
|
||||||
|
@export var fields := {}
|
||||||
|
@export var pivot := Vector2.ZERO
|
||||||
|
@export var size := Vector2.ZERO
|
||||||
|
@export var smart_color := Color.hex(0xffcc0088)
|
||||||
|
@export var definition := {}
|
||||||
|
|
||||||
|
@onready var sprite: Sprite2D = $Sprite
|
||||||
|
|
||||||
|
var _refs := []
|
||||||
|
var _points := []
|
||||||
|
var _drawPaths := false
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
_points.append(Vector2.ZERO)
|
||||||
|
for key in fields:
|
||||||
|
if fields[key] is NodePath:
|
||||||
|
_refs.append(fields[key])
|
||||||
|
elif fields[key] is Vector2i:
|
||||||
|
_points.append(fields[key])
|
||||||
|
elif fields[key] is Array:
|
||||||
|
for value in fields[key]:
|
||||||
|
if value is NodePath:
|
||||||
|
_refs.append(value)
|
||||||
|
elif value is Vector2i:
|
||||||
|
_points.append(value)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
_drawPaths = _refs.size() > 0 or _points.size() > 0
|
||||||
|
_points = _parse_points(_points)
|
||||||
|
queue_redraw()
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
if definition.is_empty():
|
||||||
|
return
|
||||||
|
|
||||||
|
match definition.renderMode:
|
||||||
|
"Ellipse":
|
||||||
|
if definition.hollow:
|
||||||
|
draw_arc((size * 0.5) + size * -pivot, size.x * 0.5, 0, TAU, 24, smart_color, 1.0)
|
||||||
|
else:
|
||||||
|
draw_circle((size * 0.5) + size * -pivot, size.x * 0.5, smart_color)
|
||||||
|
"Rectangle":
|
||||||
|
if definition.hollow:
|
||||||
|
draw_rect(Rect2(size * -pivot, size), smart_color, false, 1.0)
|
||||||
|
else:
|
||||||
|
draw_rect(Rect2(size * -pivot, size), smart_color, true)
|
||||||
|
"Cross":
|
||||||
|
draw_line(Vector2.ZERO, size, smart_color, 3.0)
|
||||||
|
draw_line(Vector2(0, size.y), Vector2(size.x, 0), smart_color, 3.0)
|
||||||
|
"Tile":
|
||||||
|
if definition.tile == null:
|
||||||
|
pass
|
||||||
|
if definition.tile is Texture2D:
|
||||||
|
sprite.texture = definition.tile
|
||||||
|
|
||||||
|
if _drawPaths:
|
||||||
|
for path in _refs:
|
||||||
|
if path is not NodePath:
|
||||||
|
continue
|
||||||
|
elif path.is_empty():
|
||||||
|
continue
|
||||||
|
var node = get_node(path)
|
||||||
|
if node != null:
|
||||||
|
draw_dashed_line(Vector2.ZERO, node.global_position - global_position, smart_color)
|
||||||
|
|
||||||
|
var previousPoint = _points[0]
|
||||||
|
for point in _points:
|
||||||
|
if point == previousPoint:
|
||||||
|
continue
|
||||||
|
draw_dashed_line(Vector2(previousPoint), Vector2(point), smart_color, 1.0, 4.0)
|
||||||
|
draw_arc(point, 4.0, 0, TAU, 5, smart_color, 1.0)
|
||||||
|
previousPoint = point
|
||||||
|
|
||||||
|
func _parse_points(points: Array) -> Array:
|
||||||
|
if points.size() == 0:
|
||||||
|
return points
|
||||||
|
if get_parent() is SubViewport:
|
||||||
|
return points
|
||||||
|
var origin = get_parent().global_position - global_position
|
||||||
|
var gridSize = get_parent().definition.gridSize
|
||||||
|
var cellOffset = gridSize * Vector2(0.5, 0.5)
|
||||||
|
for index in range(1, points.size()):
|
||||||
|
var pixelCoord = points[index] * gridSize
|
||||||
|
points[index] = origin + pixelCoord + cellOffset
|
||||||
|
return points
|
@ -0,0 +1 @@
|
|||||||
|
uid://ciskd8jyty7gq
|
14
godot/addons/ldtk-importer/src/components/ldtk-entity.svg
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 24.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:none;stroke:#FFCC00;stroke-width:2;stroke-linejoin:round;}
|
||||||
|
.st1{fill:#FFCC00;stroke:#FFCC00;stroke-miterlimit:10;}
|
||||||
|
</style>
|
||||||
|
<path class="st0" d="M3,2h10c0.6,0,1,0.4,1,1v10c0,0.6-0.4,1-1,1H3c-0.6,0-1-0.4-1-1V3C2,2.4,2.4,2,3,2z"/>
|
||||||
|
<rect x="5" y="4.5" class="st1" width="6" height="1"/>
|
||||||
|
<rect x="7" y="7.5" class="st1" width="2" height="1"/>
|
||||||
|
<rect x="5" y="10.5" class="st1" width="6" height="1"/>
|
||||||
|
<rect x="4.8" y="4.5" class="st1" width="1.5" height="7"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 842 B |
@ -0,0 +1,37 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://c8jokgcqymy8i"
|
||||||
|
path="res://.godot/imported/ldtk-entity.svg-0e9e158ef8dc55d8602ffe476bdddfa3.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/ldtk-importer/src/components/ldtk-entity.svg"
|
||||||
|
dest_files=["res://.godot/imported/ldtk-entity.svg-0e9e158ef8dc55d8602ffe476bdddfa3.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
@ -0,0 +1,9 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://c36l6fpttus66"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://addons/ldtk-importer/src/components/ldtk-entity.gd" id="1_hclg8"]
|
||||||
|
|
||||||
|
[node name="LDTK Entity" type="Node2D"]
|
||||||
|
script = ExtResource("1_hclg8")
|
||||||
|
smart_color = Color(1, 0.8, 0, 0.533333)
|
||||||
|
|
||||||
|
[node name="Sprite" type="Sprite2D" parent="."]
|
18
godot/addons/ldtk-importer/src/components/ldtk-level.gd
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
@icon("ldtk-level.svg")
|
||||||
|
@tool
|
||||||
|
class_name LDTKLevel
|
||||||
|
extends Node2D
|
||||||
|
|
||||||
|
@export var iid: String
|
||||||
|
@export var world_position: Vector2
|
||||||
|
@export var size: Vector2i
|
||||||
|
@export var fields: Dictionary
|
||||||
|
@export var neighbours: Array
|
||||||
|
@export var bg_color: Color
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
queue_redraw()
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
if Engine.is_editor_hint():
|
||||||
|
draw_rect(Rect2(Vector2.ZERO, size), bg_color, false, 2.0)
|
@ -0,0 +1 @@
|
|||||||
|
uid://devv1ueptyklo
|
1
godot/addons/ldtk-importer/src/components/ldtk-level.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.a{fill:#fc0;}</style></defs><path class="a" d="M8.61,14.27c1.32-1.65,4.33-5.65,4.33-7.9a4.94,4.94,0,1,0-9.88,0h0c0,2.25,3,6.25,4.33,7.9a.78.78,0,0,0,1.1.13ZM8,4.72A1.65,1.65,0,1,1,6.35,6.37,1.65,1.65,0,0,1,8,4.72Z"/></svg>
|
After Width: | Height: | Size: 296 B |
@ -0,0 +1,37 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bn8846b01v84"
|
||||||
|
path="res://.godot/imported/ldtk-level.svg-7c4c13bcdc12c18fc0e3338deb18be11.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/ldtk-importer/src/components/ldtk-level.svg"
|
||||||
|
dest_files=["res://.godot/imported/ldtk-level.svg-7c4c13bcdc12c18fc0e3338deb18be11.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
@ -0,0 +1,6 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://5jp4st4vnouy"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://addons/ldtk-importer/src/components/ldtk-level.gd" id="1_4fbyi"]
|
||||||
|
|
||||||
|
[node name="LDTK Level" type="Node2D"]
|
||||||
|
script = ExtResource("1_4fbyi")
|
@ -0,0 +1,9 @@
|
|||||||
|
@tool
|
||||||
|
@icon("ldtk-entity-layer.svg")
|
||||||
|
class_name LDTKWorldLayer
|
||||||
|
extends Node2D
|
||||||
|
|
||||||
|
@export var depth: int:
|
||||||
|
set(d):
|
||||||
|
depth = d
|
||||||
|
z_index = depth
|
@ -0,0 +1 @@
|
|||||||
|
uid://cvvkp8akfp51o
|
@ -0,0 +1,6 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://tiadjdf7bmjd"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://addons/ldtk-importer/src/components/ldtk-world-layer.gd" id="1_tla3i"]
|
||||||
|
|
||||||
|
[node name="World Layer" type="Node2D"]
|
||||||
|
script = ExtResource("1_tla3i")
|
22
godot/addons/ldtk-importer/src/components/ldtk-world.gd
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
@tool
|
||||||
|
@icon("ldtk-world.svg")
|
||||||
|
class_name LDTKWorld
|
||||||
|
extends Node2D
|
||||||
|
|
||||||
|
@export var iid: String
|
||||||
|
@export var rect: Rect2i
|
||||||
|
@export var levels: Array[LDTKLevel]
|
||||||
|
|
||||||
|
func _init() -> void:
|
||||||
|
child_order_changed.connect(_find_level_children)
|
||||||
|
|
||||||
|
func _find_level_children() -> void:
|
||||||
|
for child in get_children():
|
||||||
|
if child is LDTKLevel:
|
||||||
|
if not levels.has(child):
|
||||||
|
levels.append(child)
|
||||||
|
else:
|
||||||
|
for grandchild in child.get_children():
|
||||||
|
if grandchild is LDTKLevel:
|
||||||
|
if not levels.has(grandchild):
|
||||||
|
levels.append(grandchild)
|
@ -0,0 +1 @@
|
|||||||
|
uid://boyf0tvvercyb
|
1
godot/addons/ldtk-importer/src/components/ldtk-world.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.a{fill:none;stroke:#fc0;stroke-miterlimit:10;stroke-width:2px;}</style></defs><polygon class="a" points="10.93 2.92 5.07 2.92 2.13 8 5.07 13.08 10.93 13.08 13.87 8 10.93 2.92"/></svg>
|
After Width: | Height: | Size: 257 B |
@ -0,0 +1,37 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bhwcp2d8b7ofe"
|
||||||
|
path="res://.godot/imported/ldtk-world.svg-afb7a8fc57a903b71679a614011495e8.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/ldtk-importer/src/components/ldtk-world.svg"
|
||||||
|
dest_files=["res://.godot/imported/ldtk-world.svg-afb7a8fc57a903b71679a614011495e8.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
@ -0,0 +1,6 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://b5smuv4vq5lsp"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://addons/ldtk-importer/src/components/ldtk-world.gd" id="1_k4v0p"]
|
||||||
|
|
||||||
|
[node name="LDTK World" type="Node2D"]
|
||||||
|
script = ExtResource("1_k4v0p")
|
291
godot/addons/ldtk-importer/src/layer.gd
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
@tool
|
||||||
|
|
||||||
|
const Util = preload("util/util.gd")
|
||||||
|
const LayerUtil = preload("util/layer-util.gd")
|
||||||
|
const FieldUtil = preload("util/field-util.gd")
|
||||||
|
const TileUtil = preload("util/tile-util.gd")
|
||||||
|
|
||||||
|
# Used to display helpful error messages (which level we are in)
|
||||||
|
static var current_level: String = "N/A"
|
||||||
|
|
||||||
|
static func create_layers(
|
||||||
|
level_data: Dictionary,
|
||||||
|
layer_instances: Array,
|
||||||
|
definitions: Dictionary
|
||||||
|
) -> Array:
|
||||||
|
|
||||||
|
current_level = level_data.identifier
|
||||||
|
|
||||||
|
var layer_nodes := []
|
||||||
|
var layer_index: int = 0
|
||||||
|
|
||||||
|
for layer_instance in layer_instances:
|
||||||
|
var layer_def: Dictionary = definitions.layers[layer_instance.layerDefUid]
|
||||||
|
var layer_type: String = layer_instance.__type
|
||||||
|
|
||||||
|
match layer_type:
|
||||||
|
"Entities":
|
||||||
|
var layer = create_entity_layer(layer_instance, layer_def, definitions.entities)
|
||||||
|
layer_nodes.push_front(layer)
|
||||||
|
|
||||||
|
"IntGrid":
|
||||||
|
# Determines if this has an 'AutoLayer' assigned
|
||||||
|
var has_tileset := layer_instance.__tilesetDefUid != null
|
||||||
|
|
||||||
|
if has_tileset:
|
||||||
|
var layer = create_tile_layer(layer_instance, layer_def)
|
||||||
|
layer_nodes.push_front(layer)
|
||||||
|
if (not has_tileset or Util.options.integer_grid_tilesets):
|
||||||
|
var layer = create_intgrid_layer(layer_instance, layer_def)
|
||||||
|
layer_nodes.push_front(layer)
|
||||||
|
|
||||||
|
"Tiles", "AutoLayer":
|
||||||
|
var layer = create_tile_layer(layer_instance, layer_def)
|
||||||
|
layer_nodes.push_front(layer)
|
||||||
|
|
||||||
|
_:
|
||||||
|
push_warning("[LDtk] Tried importing an unsupported layer type: ", layer_type)
|
||||||
|
|
||||||
|
if (Util.options.verbose_output):
|
||||||
|
var layer_names = layer_nodes.map(func(elem): return elem.name)
|
||||||
|
Util.print("item_info", "Created Layers: [color=slategray]%s[/color]" % [layer_names], 2)
|
||||||
|
return layer_nodes
|
||||||
|
|
||||||
|
#region Layer Types
|
||||||
|
|
||||||
|
static func create_entity_layer(
|
||||||
|
layer_data: Dictionary,
|
||||||
|
layer_def: Dictionary,
|
||||||
|
entity_defs: Dictionary
|
||||||
|
) -> LDTKEntityLayer:
|
||||||
|
|
||||||
|
var layer = LDTKEntityLayer.new()
|
||||||
|
layer.name = layer_data.__identifier
|
||||||
|
layer.iid = layer_data.iid
|
||||||
|
layer.position = layer_def.offset
|
||||||
|
|
||||||
|
# Create a dummy child node so EntityRef fields get a correct NodePath
|
||||||
|
# I need to find a better way to do this, but there are lots of funny behaviours to deal with.
|
||||||
|
var pathResolver = Node2D.new()
|
||||||
|
pathResolver.name = "NodePathResolver"
|
||||||
|
layer.add_child(pathResolver)
|
||||||
|
Util.path_resolvers.append(pathResolver)
|
||||||
|
|
||||||
|
var entities: Array = LayerUtil.parse_entity_instances(
|
||||||
|
layer_data.entityInstances,
|
||||||
|
entity_defs,
|
||||||
|
pathResolver
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add instance references
|
||||||
|
layer.definition = layer_def
|
||||||
|
layer.entities = entities
|
||||||
|
|
||||||
|
if (Util.options.use_entity_placeholders):
|
||||||
|
LayerUtil.placeholder_counts.clear()
|
||||||
|
for entity in entities:
|
||||||
|
var placeholder: LDTKEntity = LayerUtil.create_entity_placeholder(layer, entity)
|
||||||
|
Util.update_instance_reference(placeholder.iid, placeholder)
|
||||||
|
#try_push_placeholder_ref(placeholder, pathResolver)
|
||||||
|
try_push_placeholder_ref(placeholder, placeholder)
|
||||||
|
|
||||||
|
return layer
|
||||||
|
|
||||||
|
static func create_intgrid_layer(
|
||||||
|
layer_data: Dictionary,
|
||||||
|
layer_def: Dictionary
|
||||||
|
) -> TileMapLayer:
|
||||||
|
|
||||||
|
# Create TileMapLayer
|
||||||
|
var tilemap: TileMapLayer = LayerUtil.create_layer_tilemap(layer_data)
|
||||||
|
tilemap.position = layer_def.offset
|
||||||
|
|
||||||
|
# Retrieve IntGrid values - these do not always match their array index
|
||||||
|
var values: Array = layer_def.intGridValues.map(
|
||||||
|
func(item): return item.value
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set layer properties on the Tilemap
|
||||||
|
var layer_name := str(layer_data.__identifier) + "-values"
|
||||||
|
tilemap.set_name(layer_name)
|
||||||
|
tilemap.set_modulate(Color(1, 1, 1, layer_data.__opacity))
|
||||||
|
|
||||||
|
# Get tile data
|
||||||
|
var tiles: Array = layer_data.intGridCsv
|
||||||
|
var tile_source_id: int = layer_data.layerDefUid
|
||||||
|
var columns: int = layer_data.__cWid
|
||||||
|
|
||||||
|
# Place IntGrid value tiles
|
||||||
|
for index in range(0, tiles.size()):
|
||||||
|
var value = tiles[index]
|
||||||
|
var value_index: int = values.find(value)
|
||||||
|
if value_index != -1:
|
||||||
|
var cell_coords := TileUtil.index_to_grid(index, columns)
|
||||||
|
var tile_coords := Vector2i(value_index, 0)
|
||||||
|
tilemap.set_cell(cell_coords, tile_source_id, tile_coords)
|
||||||
|
|
||||||
|
return tilemap
|
||||||
|
|
||||||
|
static func create_tile_layer(
|
||||||
|
layer_data: Dictionary,
|
||||||
|
layer_def: Dictionary
|
||||||
|
) -> TileMapLayer:
|
||||||
|
|
||||||
|
# Create Tilemap
|
||||||
|
var tilemap: TileMapLayer = LayerUtil.create_layer_tilemap(layer_data)
|
||||||
|
tilemap.position = layer_def.offset
|
||||||
|
|
||||||
|
# Set layer properties on the Tilemap
|
||||||
|
var layer_name := str(layer_data.__identifier)
|
||||||
|
tilemap.set_name(layer_name)
|
||||||
|
tilemap.set_modulate(Color(1, 1, 1, layer_data.__opacity))
|
||||||
|
|
||||||
|
if not Util.options.layers_always_visible:
|
||||||
|
tilemap.set_enabled(layer_data.visible)
|
||||||
|
|
||||||
|
# Get tile data
|
||||||
|
var tiles: Array
|
||||||
|
if (layer_data.__type == "Tiles"):
|
||||||
|
tiles = layer_data.gridTiles
|
||||||
|
else:
|
||||||
|
tiles = layer_data.autoLayerTiles
|
||||||
|
|
||||||
|
var tile_source_id = layer_data.__tilesetDefUid
|
||||||
|
var grid_size := Vector2(layer_data.__gridSize, layer_data.__gridSize)
|
||||||
|
|
||||||
|
if (tile_source_id == null):
|
||||||
|
Util.print("item_fail", "Null Tilemap on layerInstance: '%s'" % [layer_name], 2)
|
||||||
|
push_warning("Detected null tilemap on a level '%s' layer instance '%s'. Please fix this in your LDTK project file." % [current_level, layer_name])
|
||||||
|
return tilemap
|
||||||
|
|
||||||
|
__place_tiles(tilemap, tiles, tile_source_id, grid_size)
|
||||||
|
|
||||||
|
return tilemap
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
static func try_push_placeholder_ref(
|
||||||
|
placeholder: LDTKEntity,
|
||||||
|
entity: Node
|
||||||
|
) -> void:
|
||||||
|
if not Util.options.resolve_entityrefs: return
|
||||||
|
if not placeholder.fields: return
|
||||||
|
|
||||||
|
placeholder.fields = str_to_var(var_to_str(placeholder.fields))
|
||||||
|
var field_defs = {}
|
||||||
|
|
||||||
|
for key in placeholder.definition.field_defs:
|
||||||
|
var def = placeholder.definition.field_defs[key]
|
||||||
|
field_defs[def.identifier] = def
|
||||||
|
|
||||||
|
for key in placeholder.fields:
|
||||||
|
var def = field_defs[key]
|
||||||
|
if not def.type.contains("EntityRef"): continue
|
||||||
|
|
||||||
|
var field = placeholder.fields[key]
|
||||||
|
if not field: continue
|
||||||
|
|
||||||
|
if field is Array:
|
||||||
|
for index in range(field.size()):
|
||||||
|
Util.add_unresolved_reference(field, index, entity)
|
||||||
|
else:
|
||||||
|
Util.add_unresolved_reference(placeholder.fields, key, entity)
|
||||||
|
|
||||||
|
static func __place_tiles(
|
||||||
|
tilemap: TileMapLayer,
|
||||||
|
tiles: Array,
|
||||||
|
tile_source_id: int,
|
||||||
|
grid_size: Vector2,
|
||||||
|
layer_index: int = 0
|
||||||
|
) -> void:
|
||||||
|
|
||||||
|
var tile_source: TileSetAtlasSource
|
||||||
|
if tilemap.tile_set.has_source(tile_source_id):
|
||||||
|
tile_source = tilemap.tile_set.get_source(tile_source_id)
|
||||||
|
else:
|
||||||
|
push_error("TileSetAtlasSource missing")
|
||||||
|
return
|
||||||
|
|
||||||
|
var tile_size := Vector2(tile_source.texture_region_size)
|
||||||
|
|
||||||
|
# Place tiles
|
||||||
|
for tile in tiles:
|
||||||
|
var cell_px := Vector2(tile.px[0], tile.px[1])
|
||||||
|
var tile_px := Vector2(tile.src[0], tile.src[1])
|
||||||
|
var cell_grid := TileUtil.px_to_grid(cell_px, grid_size, Vector2i.ZERO)
|
||||||
|
var tile_grid := TileUtil.px_to_grid(tile_px, tile_size, tile_source.margins, tile_source.separation)
|
||||||
|
|
||||||
|
# Tile does not exist
|
||||||
|
if not tile_source.has_tile(tile_grid):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Handle flipped tiles
|
||||||
|
var alternative_tile: int = 0
|
||||||
|
var tile_flip := TileUtil.get_tile_flip_mask(int(tile.f))
|
||||||
|
|
||||||
|
if (tile_flip != 0):
|
||||||
|
alternative_tile = tile_flip
|
||||||
|
|
||||||
|
# Handle alpha
|
||||||
|
if tile.a < 1.0:
|
||||||
|
var alternative_index := 1
|
||||||
|
var alternative_exists := false
|
||||||
|
var alternative_count := tile_source.get_alternative_tiles_count(tile_grid)
|
||||||
|
|
||||||
|
# Find alternate tile with same alpha
|
||||||
|
if alternative_count > alternative_index:
|
||||||
|
for i in range(alternative_index, alternative_count):
|
||||||
|
var data = tile_source.get_tile_data(tile_grid, i)
|
||||||
|
if is_equal_approx(data.modulate.a, tile.a):
|
||||||
|
# Reverse flip bools back into an int
|
||||||
|
var flip = TileUtil.get_tile_flip_mask(int(data.flip_h) + int(data.flip_v) * 2)
|
||||||
|
if tile_flip == flip:
|
||||||
|
alternative_index = i
|
||||||
|
alternative_exists = true
|
||||||
|
break
|
||||||
|
|
||||||
|
# Create new tile
|
||||||
|
if not alternative_exists:
|
||||||
|
alternative_index = tile_source.create_alternative_tile(tile_grid, alternative_count)
|
||||||
|
var new_data = tile_source.get_tile_data(tile_grid, alternative_index)
|
||||||
|
TileUtil.copy_and_modify_tile_data(
|
||||||
|
new_data,
|
||||||
|
tile_source.get_tile_data(tile_grid, 0),
|
||||||
|
tilemap.tile_set.get_physics_layers_count(),
|
||||||
|
tilemap.tile_set.get_navigation_layers_count(),
|
||||||
|
tilemap.tile_set.get_occlusion_layers_count(),
|
||||||
|
tile_flip
|
||||||
|
)
|
||||||
|
new_data.modulate.a = tile.a
|
||||||
|
|
||||||
|
alternative_tile = alternative_index
|
||||||
|
|
||||||
|
if not tilemap.get_cell_tile_data(cell_grid):
|
||||||
|
tilemap.set_cell(cell_grid, tile_source_id, tile_grid, alternative_tile)
|
||||||
|
else:
|
||||||
|
__place_overlapping_tile(tilemap, cell_grid, tile_source_id, tile_grid, alternative_tile)
|
||||||
|
|
||||||
|
static func __place_overlapping_tile(
|
||||||
|
tilemap: TileMapLayer,
|
||||||
|
cell_grid: Vector2i,
|
||||||
|
tile_source_id: int,
|
||||||
|
tile_grid: Vector2i,
|
||||||
|
alternative_tile: int
|
||||||
|
) -> void:
|
||||||
|
var tilemap_child: TileMapLayer
|
||||||
|
var empty := false
|
||||||
|
|
||||||
|
# Loop through existing children to find empty cell
|
||||||
|
for child in tilemap.get_children():
|
||||||
|
if not child.get_cell_tile_data(cell_grid):
|
||||||
|
tilemap_child = child
|
||||||
|
empty = true
|
||||||
|
break
|
||||||
|
|
||||||
|
# Create new child if no empty cell (or child) could be found
|
||||||
|
if not empty:
|
||||||
|
tilemap_child = LayerUtil.create_tilemap_child(tilemap)
|
||||||
|
tilemap.add_child(tilemap_child)
|
||||||
|
|
||||||
|
# Set tile
|
||||||
|
tilemap_child.set_cell(cell_grid, tile_source_id, tile_grid, alternative_tile)
|
1
godot/addons/ldtk-importer/src/layer.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://46jgmlrl0r3s
|
125
godot/addons/ldtk-importer/src/level.gd
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
@tool
|
||||||
|
|
||||||
|
const Util = preload("util/util.gd")
|
||||||
|
const LevelUtil = preload("util/level-util.gd")
|
||||||
|
const FieldUtil = preload("util/field-util.gd")
|
||||||
|
const PostImport = preload("post-import.gd")
|
||||||
|
const Layer = preload("layer.gd")
|
||||||
|
|
||||||
|
static var base_directory: String
|
||||||
|
|
||||||
|
static func build_levels(
|
||||||
|
world_data: Dictionary,
|
||||||
|
definitions: Dictionary,
|
||||||
|
base_dir: String,
|
||||||
|
external_levels: bool
|
||||||
|
) -> Array[LDTKLevel]:
|
||||||
|
|
||||||
|
Util.timer_start(Util.DebugTime.GENERAL)
|
||||||
|
base_directory = base_dir
|
||||||
|
var levels: Array[LDTKLevel] = []
|
||||||
|
|
||||||
|
# Calculate level positions
|
||||||
|
var level_positions: Array
|
||||||
|
match world_data.worldLayout:
|
||||||
|
"LinearHorizontal":
|
||||||
|
var x = 0
|
||||||
|
for level in world_data.levels:
|
||||||
|
level_positions.append(Vector2i(x, 0))
|
||||||
|
x += level.pxWid
|
||||||
|
"LinearVertical":
|
||||||
|
var y := 0
|
||||||
|
for level in world_data.levels:
|
||||||
|
level_positions.append(Vector2i(0, y))
|
||||||
|
y += level.pxHei
|
||||||
|
"GridVania", "Free":
|
||||||
|
level_positions = world_data.levels.map(
|
||||||
|
func (current):
|
||||||
|
return Vector2i(current.worldX, current.worldY)
|
||||||
|
)
|
||||||
|
_:
|
||||||
|
printerr("World Layout not supported: ", world_data.worldLayout)
|
||||||
|
|
||||||
|
# Create levels
|
||||||
|
for level_index in range(world_data.levels.size()):
|
||||||
|
Util.timer_start(Util.DebugTime.GENERAL)
|
||||||
|
var level_data
|
||||||
|
var position: Vector2i = level_positions[level_index]
|
||||||
|
level_data = world_data.levels[level_index]
|
||||||
|
|
||||||
|
if external_levels:
|
||||||
|
level_data = LevelUtil.get_external_level(level_data, base_dir)
|
||||||
|
|
||||||
|
var level = create_level(level_data, position, definitions)
|
||||||
|
Util.timer_finish("Built Level", 2)
|
||||||
|
|
||||||
|
if (Util.options.entities_post_import):
|
||||||
|
level = PostImport.run_entity_post_import(level, Util.options.entities_post_import)
|
||||||
|
|
||||||
|
if (Util.options.level_post_import):
|
||||||
|
level = PostImport.run_level_post_import(level, Util.options.level_post_import)
|
||||||
|
|
||||||
|
levels.append(level)
|
||||||
|
|
||||||
|
Util.timer_finish("Built %s Levels" % levels.size(), 1)
|
||||||
|
return levels
|
||||||
|
|
||||||
|
static func create_level(
|
||||||
|
level_data: Dictionary,
|
||||||
|
position: Vector2i,
|
||||||
|
definitions: Dictionary
|
||||||
|
) -> LDTKLevel:
|
||||||
|
var level_name: String = level_data.identifier
|
||||||
|
var level := LDTKLevel.new()
|
||||||
|
level.name = level_name
|
||||||
|
level.iid = level_data.iid
|
||||||
|
level.world_position = position
|
||||||
|
level.size = Vector2i(level_data.pxWid, level_data.pxHei)
|
||||||
|
level.bg_color = level_data.__bgColor
|
||||||
|
level.z_index = level_data.worldDepth
|
||||||
|
|
||||||
|
if (Util.options.verbose_output): Util.print("block", level_name, 1)
|
||||||
|
Util.update_instance_reference(level_data.iid, level)
|
||||||
|
|
||||||
|
var neighbours = level_data.__neighbours
|
||||||
|
|
||||||
|
if not Util.options.pack_levels:
|
||||||
|
for neighbour in neighbours:
|
||||||
|
Util.add_unresolved_reference(neighbour, "levelIid", level)
|
||||||
|
|
||||||
|
level.neighbours = neighbours
|
||||||
|
|
||||||
|
# Create background image
|
||||||
|
if level_data.bgRelPath != null:
|
||||||
|
var path := "%s/%s" % [base_directory, level_data.bgRelPath]
|
||||||
|
var sprite := Sprite2D.new()
|
||||||
|
sprite.name = "BG Image"
|
||||||
|
sprite.centered = false
|
||||||
|
sprite.texture = load(path)
|
||||||
|
|
||||||
|
# Calculate BG Position
|
||||||
|
var bgData: Dictionary = level_data.__bgPos
|
||||||
|
var pos: Array = bgData.topLeftPx
|
||||||
|
var scale: Array = bgData.scale
|
||||||
|
var region: Array = bgData.cropRect
|
||||||
|
sprite.region_enabled = true
|
||||||
|
sprite.position = Vector2i(pos[0], pos[1])
|
||||||
|
sprite.scale = Vector2i(scale[0], scale[1])
|
||||||
|
sprite.region_rect = Rect2i(region[0], region[1], region[2], region[3])
|
||||||
|
|
||||||
|
level.add_child(sprite)
|
||||||
|
|
||||||
|
# Create fields
|
||||||
|
level.fields = FieldUtil.create_fields(level_data.fieldInstances, level)
|
||||||
|
|
||||||
|
var layer_instances = level_data.layerInstances
|
||||||
|
if not layer_instances is Array:
|
||||||
|
push_error("level '%s' has no layer instances." % [level_name])
|
||||||
|
return level
|
||||||
|
|
||||||
|
# Create layers
|
||||||
|
var layers = Layer.create_layers(level_data, layer_instances, definitions)
|
||||||
|
for layer in layers:
|
||||||
|
level.add_child(layer)
|
||||||
|
|
||||||
|
return level
|
1
godot/addons/ldtk-importer/src/level.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://w5et03vhdql6
|
60
godot/addons/ldtk-importer/src/post-import.gd
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
@tool
|
||||||
|
|
||||||
|
const Util = preload("util/util.gd")
|
||||||
|
|
||||||
|
static func run(element: Variant, script_path: String) -> Variant:
|
||||||
|
var element_type = typeof(element)
|
||||||
|
|
||||||
|
if not script_path.is_empty():
|
||||||
|
var script = load(script_path)
|
||||||
|
if not script or not script is GDScript:
|
||||||
|
printerr("Post-Import: '%s' is not a GDScript" % [script_path])
|
||||||
|
return ERR_INVALID_PARAMETER
|
||||||
|
|
||||||
|
script = script.new()
|
||||||
|
if not script.has_method("post_import"):
|
||||||
|
printerr("Post-Import: '%s' does not have a post_import() method" % [script_path])
|
||||||
|
return ERR_INVALID_PARAMETER
|
||||||
|
|
||||||
|
element = script.post_import(element)
|
||||||
|
|
||||||
|
if element == null or typeof(element) != element_type:
|
||||||
|
printerr("Post-Import: Invalid scene returned from script.")
|
||||||
|
return ERR_INVALID_DATA
|
||||||
|
|
||||||
|
return element
|
||||||
|
|
||||||
|
static func run_tileset_post_import(tilesets: Dictionary, script_path: String) -> Dictionary:
|
||||||
|
Util.timer_start(Util.DebugTime.POST_IMPORT)
|
||||||
|
Util.print("tileset_post_import", str(tilesets), 1)
|
||||||
|
tilesets = run(tilesets, Util.options.tileset_post_import)
|
||||||
|
Util.timer_finish("Tileset Post-Import: Complete", 1)
|
||||||
|
return tilesets
|
||||||
|
|
||||||
|
static func run_level_post_import(level: LDTKLevel, script_path: String) -> LDTKLevel:
|
||||||
|
Util.timer_start(Util.DebugTime.POST_IMPORT)
|
||||||
|
Util.print("level_post_import", level.name, 2)
|
||||||
|
level = run(level, Util.options.level_post_import)
|
||||||
|
Util.timer_finish("Level Post-Import: Complete", 2)
|
||||||
|
return level
|
||||||
|
|
||||||
|
static func run_entity_post_import(level: LDTKLevel, script_path: String) -> LDTKLevel:
|
||||||
|
Util.timer_start(Util.DebugTime.POST_IMPORT)
|
||||||
|
var layers = level.get_children()
|
||||||
|
for layer in layers:
|
||||||
|
if layer is not LDTKEntityLayer:
|
||||||
|
continue
|
||||||
|
|
||||||
|
var entityLayerName = layer.get_parent().name + "." + layer.name
|
||||||
|
Util.print("entity_post_import", entityLayerName, 3)
|
||||||
|
layer = run(layer, script_path)
|
||||||
|
|
||||||
|
Util.timer_finish("Entity Post-Import: Complete", 3)
|
||||||
|
return level
|
||||||
|
|
||||||
|
static func run_world_post_import(world: LDTKWorld, script_path: String) -> LDTKWorld:
|
||||||
|
Util.timer_start(Util.DebugTime.POST_IMPORT)
|
||||||
|
Util.print("world_post_import", world.name, 1)
|
||||||
|
world = run(world, Util.options.world_post_import)
|
||||||
|
Util.timer_finish("World Post-Import: Complete", 1)
|
||||||
|
return world
|
1
godot/addons/ldtk-importer/src/post-import.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://bv4fn2n2ncw12
|
330
godot/addons/ldtk-importer/src/tileset.gd
Normal file
@ -0,0 +1,330 @@
|
|||||||
|
@tool
|
||||||
|
|
||||||
|
const Util = preload("util/util.gd")
|
||||||
|
const TileUtil = preload("util/tile-util.gd")
|
||||||
|
const FieldUtil = preload("util/field-util.gd")
|
||||||
|
const PostImport = preload("post-import.gd")
|
||||||
|
|
||||||
|
enum AtlasTextureType {CompressedTexture2D, CanvasTexture}
|
||||||
|
|
||||||
|
static func build_tilesets(
|
||||||
|
definitions: Dictionary,
|
||||||
|
base_dir: String,
|
||||||
|
tileset_overrides: Dictionary
|
||||||
|
) -> Array:
|
||||||
|
Util.timer_start(Util.DebugTime.TILES)
|
||||||
|
var tilesets := {}
|
||||||
|
var tileset_sources := {}
|
||||||
|
|
||||||
|
# Reduce Layer Defs to find all unique layer grid sizes and create TileSets for each.
|
||||||
|
var layer_def_uids: Array = definitions.layers.keys()
|
||||||
|
|
||||||
|
tilesets = layer_def_uids.reduce(
|
||||||
|
func(accum: Dictionary, current: float):
|
||||||
|
var layer_def = definitions.layers[current]
|
||||||
|
var grid_size: int = layer_def.gridSize
|
||||||
|
|
||||||
|
if not accum.has(grid_size):
|
||||||
|
accum[grid_size] = get_tileset(grid_size, base_dir)
|
||||||
|
|
||||||
|
# Create TileSetSource for IntGrids
|
||||||
|
if (Util.options.integer_grid_tilesets):
|
||||||
|
if layer_def.type == "IntGrid" and layer_def.intGridValues.size() > 0:
|
||||||
|
var intgrid_uid = layer_def.uid
|
||||||
|
var intgrid_source = create_intgrid_source(layer_def)
|
||||||
|
tileset_sources[intgrid_uid] = intgrid_source
|
||||||
|
Util.add_tileset_reference(intgrid_uid, intgrid_source)
|
||||||
|
return accum
|
||||||
|
, tilesets)
|
||||||
|
|
||||||
|
# Create TileSetSources for each Tileset Def
|
||||||
|
var tileset_def_uids = definitions.tilesets.keys()
|
||||||
|
for uid in tileset_def_uids:
|
||||||
|
var tileset_def: Dictionary = definitions.tilesets[uid]
|
||||||
|
var source: TileSetSource = create_new_tileset_source(tileset_def, base_dir)
|
||||||
|
tileset_sources[uid] = source
|
||||||
|
Util.add_tileset_reference(tileset_def.uid, source)
|
||||||
|
|
||||||
|
# Add TileSetSources to TileSets
|
||||||
|
# NOTE: We also add Sources to mismatched TileSet sizes (if a layer uses that TilesetDef as an override)
|
||||||
|
for id in tilesets.keys():
|
||||||
|
var tileset: TileSet = tilesets[id]
|
||||||
|
var size: int = tileset.tile_size.x
|
||||||
|
|
||||||
|
for uid in tileset_sources.keys():
|
||||||
|
var source: TileSetAtlasSource = tileset_sources[uid]
|
||||||
|
if source == null: continue
|
||||||
|
var source_size: int = source.texture_region_size.x
|
||||||
|
|
||||||
|
# Check if override exists.
|
||||||
|
var has_override: bool = false
|
||||||
|
if (tileset_overrides.has(size)):
|
||||||
|
if (tileset_overrides[size].has(int(uid))):
|
||||||
|
has_override = true
|
||||||
|
|
||||||
|
# Include Source if size matches grid (or is an override found for this grid size)
|
||||||
|
if size == source_size or has_override:
|
||||||
|
if tileset.has_source(uid):
|
||||||
|
source = tileset.get_source(uid)
|
||||||
|
else:
|
||||||
|
source = source.duplicate()
|
||||||
|
tileset.add_source(source, uid)
|
||||||
|
|
||||||
|
if (Util.options.tileset_custom_data):
|
||||||
|
if definitions.tilesets.has(uid):
|
||||||
|
var tileset_def: Dictionary = definitions.tilesets[uid]
|
||||||
|
add_tileset_custom_data(tileset_def, tileset, source, tileset_def.__cWid)
|
||||||
|
|
||||||
|
# Post-Import
|
||||||
|
if (Util.options.tileset_post_import):
|
||||||
|
tilesets = PostImport.run_tileset_post_import(tilesets, Util.options.tileset_post_import)
|
||||||
|
|
||||||
|
# Store tilesets in Util
|
||||||
|
Util.tilesets = tilesets
|
||||||
|
|
||||||
|
Util.timer_finish("Tilesets Created", 1)
|
||||||
|
|
||||||
|
# Save tilesets
|
||||||
|
Util.timer_start(Util.DebugTime.SAVE)
|
||||||
|
var files = save_tilesets(tilesets, base_dir)
|
||||||
|
Util.timer_finish("Tilesets Saved", 1)
|
||||||
|
|
||||||
|
for key in tilesets.keys():
|
||||||
|
# reload tileset (improves performance)
|
||||||
|
var tileset = tilesets[key]
|
||||||
|
if tileset == null: continue
|
||||||
|
if not files.has(key): continue
|
||||||
|
tilesets[key] = ResourceLoader.load(files[key])
|
||||||
|
|
||||||
|
return files.values()
|
||||||
|
|
||||||
|
static func get_tileset(tile_size: int,base_dir: String) -> TileSet:
|
||||||
|
var tileset_name := "tileset_%spx" % [str(tile_size)]
|
||||||
|
var path := base_dir + "tilesets/" + tileset_name + ".res"
|
||||||
|
|
||||||
|
if not (Util.options.force_tileset_reimport):
|
||||||
|
if ResourceLoader.exists(path):
|
||||||
|
var tileset = ResourceLoader.load(path)
|
||||||
|
if tileset is TileSet:
|
||||||
|
return tileset
|
||||||
|
|
||||||
|
# Create new TileSet
|
||||||
|
var tileset := TileSet.new()
|
||||||
|
tileset.resource_name = tileset_name
|
||||||
|
tileset.tile_size = Vector2i(tile_size, tile_size)
|
||||||
|
|
||||||
|
if (Util.options.verbose_output):
|
||||||
|
Util.print("item_info", "Created new TileSet: \"%s\"" % [tileset_name], 1)
|
||||||
|
|
||||||
|
return tileset
|
||||||
|
|
||||||
|
# Create an AtlasSource using tileset definition
|
||||||
|
static func create_new_tileset_source(definition: Dictionary, base_dir: String) -> TileSetSource:
|
||||||
|
# No source texture defined
|
||||||
|
if definition.relPath == null:
|
||||||
|
Util.print("item_fail", "No texture defined for tileset '%s'" % [definition.identifier])
|
||||||
|
push_error("Tileset Definition '%s' has no source texture. Please fix this in your LDtk project file." % [definition.identifier])
|
||||||
|
return null
|
||||||
|
|
||||||
|
# Check if relPath is an absolute directory
|
||||||
|
var filepath: String
|
||||||
|
if definition.relPath.contains(":"):
|
||||||
|
push_warning("Absolute path detected for texture resource '%s'. This is not recommended. Please include this file in the Godot project." % [definition.identifier])
|
||||||
|
filepath = definition.relPath
|
||||||
|
else:
|
||||||
|
filepath = base_dir + definition.relPath
|
||||||
|
|
||||||
|
var texture := load(filepath)
|
||||||
|
|
||||||
|
# Cannot load texture
|
||||||
|
if texture == null:
|
||||||
|
push_error("Cannot access source texture: %s. Please include this file in the Godot project." % [filepath])
|
||||||
|
return null
|
||||||
|
|
||||||
|
var image: Image = texture.get_image()
|
||||||
|
|
||||||
|
# Convert texture from CompressedTexture2D to CanvasTexture
|
||||||
|
if (Util.options.atlas_texture_type == AtlasTextureType.CanvasTexture):
|
||||||
|
var canvas_texture = CanvasTexture.new()
|
||||||
|
canvas_texture.diffuse_texture = texture
|
||||||
|
texture = canvas_texture
|
||||||
|
|
||||||
|
var tile_size: int = definition.gridSize
|
||||||
|
var margin: int = definition.padding
|
||||||
|
var separation: int = definition.spacing
|
||||||
|
var grid_w: int = definition.__cWid
|
||||||
|
var grid_h: int = definition.__cHei
|
||||||
|
|
||||||
|
var source := TileSetAtlasSource.new()
|
||||||
|
|
||||||
|
# Apply TileSet properties
|
||||||
|
if source.texture == null or source.texture.get_class() != texture.get_class():
|
||||||
|
source.texture = texture
|
||||||
|
|
||||||
|
source.resource_name = definition.identifier
|
||||||
|
source.margins = Vector2i(margin, margin)
|
||||||
|
source.separation = Vector2i(separation, separation)
|
||||||
|
source.texture_region_size = Vector2(tile_size, tile_size)
|
||||||
|
source.use_texture_padding = false
|
||||||
|
|
||||||
|
# Create/remove tiles in non-empty/empty cells.
|
||||||
|
for y in range(0, grid_h):
|
||||||
|
for x in range(0, grid_w):
|
||||||
|
var coords := Vector2i(x,y)
|
||||||
|
var tile_region := TileUtil.get_tile_region(coords, tile_size, margin, separation, grid_w)
|
||||||
|
var tile_image := image.get_region(tile_region)
|
||||||
|
|
||||||
|
if not tile_image.is_invisible():
|
||||||
|
if source.get_tile_at_coords(coords) == Vector2i(-1,-1):
|
||||||
|
source.create_tile(coords)
|
||||||
|
elif not source.get_tile_at_coords(coords) == Vector2i(-1,-1):
|
||||||
|
# TODO: Make this an import flag
|
||||||
|
source.remove_tile(coords)
|
||||||
|
|
||||||
|
# Add definition UID to references
|
||||||
|
Util.add_tileset_reference(definition.uid, source)
|
||||||
|
|
||||||
|
return source
|
||||||
|
|
||||||
|
static func add_tileset_custom_data(
|
||||||
|
definition: Dictionary,
|
||||||
|
tileset: TileSet,
|
||||||
|
source: TileSetAtlasSource,
|
||||||
|
grid_w: int
|
||||||
|
) -> void:
|
||||||
|
|
||||||
|
if not definition.has("enumTags"):
|
||||||
|
return
|
||||||
|
|
||||||
|
var customData: Array = definition.customData
|
||||||
|
var custom_name: String = "LDTK Custom"
|
||||||
|
clear_custom_data(tileset, custom_name)
|
||||||
|
|
||||||
|
if not customData.is_empty():
|
||||||
|
ensure_custom_layer(tileset, custom_name)
|
||||||
|
for entry in customData:
|
||||||
|
var coords := TileUtil.tileid_to_grid(entry.tileId, grid_w)
|
||||||
|
var tile_data: TileData = source.get_tile_data(coords, 0)
|
||||||
|
if not tile_data == null:
|
||||||
|
tile_data.set_custom_data(custom_name, entry.data)
|
||||||
|
|
||||||
|
var custom_enum_name: String = "LDTK Custom Enum"
|
||||||
|
clear_custom_data(tileset, custom_enum_name)
|
||||||
|
|
||||||
|
var enumTags: Array = definition.enumTags
|
||||||
|
if not enumTags.is_empty():
|
||||||
|
ensure_custom_layer(tileset, custom_enum_name, TYPE_ARRAY)
|
||||||
|
|
||||||
|
for enumTag in enumTags:
|
||||||
|
for tileId in enumTag.tileIds:
|
||||||
|
var coords := TileUtil.tileid_to_grid(tileId, grid_w)
|
||||||
|
var tile_data: TileData = source.get_tile_data(coords, 0)
|
||||||
|
if not tile_data == null:
|
||||||
|
# Add to already existing tags
|
||||||
|
var tile_tags: Array = tile_data.get_custom_data(custom_enum_name)
|
||||||
|
tile_tags.append(enumTag.enumValueId)
|
||||||
|
tile_data.set_custom_data(custom_enum_name, tile_tags)
|
||||||
|
|
||||||
|
# Ensure custom data layer exists by name
|
||||||
|
static func ensure_custom_layer(
|
||||||
|
tileset: TileSet,
|
||||||
|
layer_name: String,
|
||||||
|
layer_type: int = TYPE_STRING
|
||||||
|
) -> void:
|
||||||
|
if tileset.get_custom_data_layer_by_name(layer_name) != -1:
|
||||||
|
return
|
||||||
|
var index_to_add = tileset.get_custom_data_layers_count()
|
||||||
|
tileset.add_custom_data_layer(index_to_add)
|
||||||
|
tileset.set_custom_data_layer_name(index_to_add, layer_name)
|
||||||
|
tileset.set_custom_data_layer_type(index_to_add, layer_type)
|
||||||
|
|
||||||
|
# Clear custom data by layer name
|
||||||
|
static func clear_custom_data(tileset: TileSet, layer_name: String) -> void:
|
||||||
|
var layer = tileset.get_custom_data_layer_by_name(layer_name)
|
||||||
|
if layer == -1:
|
||||||
|
return
|
||||||
|
tileset.remove_custom_data_layer(layer)
|
||||||
|
|
||||||
|
# Create an AtlasSource from IntGrid data
|
||||||
|
static func create_intgrid_source(definition: Dictionary) -> TileSetAtlasSource:
|
||||||
|
var values: Array = definition.intGridValues
|
||||||
|
var grid_size: int = definition.gridSize
|
||||||
|
|
||||||
|
# Create texture from IntGrid values
|
||||||
|
var width := grid_size * values.size()
|
||||||
|
var height := grid_size
|
||||||
|
var image := Image.create(width, height, false, Image.FORMAT_RGB8)
|
||||||
|
|
||||||
|
for index in range(0, values.size()):
|
||||||
|
var value: Dictionary = values[index]
|
||||||
|
var rect := Rect2i(index * grid_size, 0, grid_size, grid_size)
|
||||||
|
var color := Color.from_string(value.color, Color.MAGENTA)
|
||||||
|
image.fill_rect(rect, color)
|
||||||
|
|
||||||
|
var texture = ImageTexture.create_from_image(image)
|
||||||
|
|
||||||
|
var source := TileSetAtlasSource.new()
|
||||||
|
source.resource_name = definition.identifier + "_Tiles"
|
||||||
|
source.texture = texture
|
||||||
|
source.texture_region_size = Vector2i(grid_size, grid_size)
|
||||||
|
|
||||||
|
# Create tiles
|
||||||
|
for index in range(0, values.size()):
|
||||||
|
var coords := Vector2i(index, 0)
|
||||||
|
if not source.has_tile(coords):
|
||||||
|
source.create_tile(coords)
|
||||||
|
|
||||||
|
return source
|
||||||
|
|
||||||
|
# Save TileSets as Resources
|
||||||
|
static func save_tilesets(tilesets: Dictionary, base_dir: String) -> Dictionary:
|
||||||
|
var save_path = base_dir + "tilesets/"
|
||||||
|
var gen_files := {}
|
||||||
|
var directory = DirAccess.open(base_dir)
|
||||||
|
if not directory.dir_exists(save_path):
|
||||||
|
directory.make_dir_recursive(save_path)
|
||||||
|
|
||||||
|
var tileset_names = tilesets.values().map(func(elem): return elem.resource_name)
|
||||||
|
Util.print("item_save", "Saving Tilesets: [color=#fe8019]%s[/color]" % [tileset_names], 1)
|
||||||
|
|
||||||
|
for key in tilesets.keys():
|
||||||
|
var tileset: TileSet = tilesets.get(key)
|
||||||
|
if tileset.get_source_count() == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
var file_name = tileset.resource_name
|
||||||
|
var file_path = "%s%s.%s" % [save_path, file_name, "res"]
|
||||||
|
var err = ResourceSaver.save(tileset, file_path)
|
||||||
|
if err == OK:
|
||||||
|
gen_files[key] = file_path
|
||||||
|
|
||||||
|
return gen_files
|
||||||
|
|
||||||
|
static func get_entity_def_tiles(definitions: Dictionary, tilesets: Dictionary) -> Dictionary:
|
||||||
|
# TODO: Loop through EntityDefs, and turn 'Tile' into an Image.
|
||||||
|
for def in definitions.entities:
|
||||||
|
var entity: Dictionary = definitions.entities[def]
|
||||||
|
if (entity.tile == null):
|
||||||
|
continue
|
||||||
|
# Find associated TileSet
|
||||||
|
var texture = FieldUtil.__parse_tile(entity.tile)
|
||||||
|
entity.tile = texture
|
||||||
|
|
||||||
|
return definitions
|
||||||
|
|
||||||
|
# Collect all layer tileset overrides. Later we'll ensure these sources are included in TileSet resources.
|
||||||
|
static func get_tileset_overrides(world_data: Dictionary) -> Dictionary:
|
||||||
|
var overrides := {}
|
||||||
|
for level in world_data.levels:
|
||||||
|
for layer in level.layerInstances:
|
||||||
|
if layer.overrideTilesetUid == null:
|
||||||
|
continue
|
||||||
|
var gridSize: int = layer.__gridSize
|
||||||
|
var overrideUid: int = layer.overrideTilesetUid
|
||||||
|
if overrideUid != null:
|
||||||
|
if not overrides.has(gridSize):
|
||||||
|
overrides[gridSize] = []
|
||||||
|
var gridsize_overrides: Array = overrides[gridSize]
|
||||||
|
if not gridsize_overrides.has(overrideUid):
|
||||||
|
gridsize_overrides.append(overrideUid)
|
||||||
|
return overrides
|
1
godot/addons/ldtk-importer/src/tileset.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://etx2miclpo5a
|
108
godot/addons/ldtk-importer/src/util/definition_util.gd
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
@tool
|
||||||
|
|
||||||
|
const Util = preload("util.gd")
|
||||||
|
|
||||||
|
# When building definitions we are only collecting data we need and do some pre-parsing to make the next steps easier.
|
||||||
|
|
||||||
|
static func build_definitions(world_data: Dictionary) -> Dictionary:
|
||||||
|
var definitions := {
|
||||||
|
"enums": resolve_enum_definitions(world_data.defs.enums),
|
||||||
|
"entities": resolve_entity_definitions(world_data.defs.entities),
|
||||||
|
"layers": resolve_layer_definitions(world_data.defs.layers),
|
||||||
|
"tilesets": resolve_tileset_definitions(world_data.defs.tilesets, world_data.defs.layers),
|
||||||
|
"level_fields": resolve_level_field_definitions(world_data.defs.levelFields),
|
||||||
|
}
|
||||||
|
return definitions
|
||||||
|
|
||||||
|
static func resolve_layer_definitions(layer_defs: Array) -> Dictionary:
|
||||||
|
var resolved_layer_defs := {}
|
||||||
|
|
||||||
|
for layer_def in layer_defs:
|
||||||
|
resolved_layer_defs[layer_def.uid] = {
|
||||||
|
"uid": layer_def.uid,
|
||||||
|
"type": layer_def.type,
|
||||||
|
"identifier": layer_def.identifier,
|
||||||
|
"gridSize": layer_def.gridSize,
|
||||||
|
"offset": Vector2i(layer_def.pxOffsetX, layer_def.pxOffsetY),
|
||||||
|
"parallax": Vector2(layer_def.parallaxFactorX, layer_def.parallaxFactorY),
|
||||||
|
"parallaxScaling": layer_def.parallaxScaling,
|
||||||
|
"intGridValues": layer_def.intGridValues
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolved_layer_defs
|
||||||
|
|
||||||
|
static func resolve_entity_definitions(entity_defs: Array) -> Dictionary:
|
||||||
|
var resolved_entity_defs := {}
|
||||||
|
|
||||||
|
for entity_def in entity_defs:
|
||||||
|
resolved_entity_defs[entity_def.uid] = {
|
||||||
|
"identifier": entity_def.identifier,
|
||||||
|
"color": Color.from_string(entity_def.color, Color.MAGENTA),
|
||||||
|
"renderMode": entity_def.renderMode,
|
||||||
|
"hollow": entity_def.hollow,
|
||||||
|
"tags": entity_def.tags,
|
||||||
|
"field_defs": resolve_entity_field_defs(entity_def.fieldDefs),
|
||||||
|
"tile": entity_def.uiTileRect
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolved_entity_defs
|
||||||
|
|
||||||
|
static func resolve_entity_field_defs(field_defs: Array) -> Dictionary:
|
||||||
|
var resolved_entity_field_defs := {}
|
||||||
|
|
||||||
|
for field_def in field_defs:
|
||||||
|
resolved_entity_field_defs[int(field_def.uid)] = {
|
||||||
|
"identifier": field_def.identifier,
|
||||||
|
"type": field_def.__type,
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolved_entity_field_defs
|
||||||
|
|
||||||
|
static func resolve_tileset_definitions(tileset_defs: Array, layer_defs: Array) -> Dictionary:
|
||||||
|
var resolved_tileset_defs := {}
|
||||||
|
|
||||||
|
for tileset_def in tileset_defs:
|
||||||
|
resolved_tileset_defs[tileset_def.uid] = {
|
||||||
|
"uid": tileset_def.uid,
|
||||||
|
"identifier": tileset_def.identifier,
|
||||||
|
"relPath": tileset_def.relPath,
|
||||||
|
"gridSize": tileset_def.tileGridSize,
|
||||||
|
"pxWid": tileset_def.pxWid,
|
||||||
|
"pxHei": tileset_def.pxHei,
|
||||||
|
"spacing": tileset_def.spacing,
|
||||||
|
"padding": tileset_def.padding,
|
||||||
|
"tags": tileset_def.tags,
|
||||||
|
"enumTagUid": tileset_def.tagsSourceEnumUid,
|
||||||
|
"enumTags": tileset_def.enumTags,
|
||||||
|
"customData": tileset_def.customData,
|
||||||
|
"__cWid": tileset_def.__cWid,
|
||||||
|
"__cHei": tileset_def.__cHei,
|
||||||
|
}
|
||||||
|
return resolved_tileset_defs
|
||||||
|
|
||||||
|
static func resolve_enum_definitions(enum_defs: Array) -> Dictionary:
|
||||||
|
var resolved_enum_defs := {}
|
||||||
|
|
||||||
|
for enum_def in enum_defs:
|
||||||
|
var uid = enum_def.uid
|
||||||
|
var values := []
|
||||||
|
for value in enum_def.values:
|
||||||
|
values.append({
|
||||||
|
"value": value.id,
|
||||||
|
"color": Color.from_string(str(value.color), Color.MAGENTA),
|
||||||
|
"tileRect": value.tileRect
|
||||||
|
})
|
||||||
|
resolved_enum_defs[uid] = values
|
||||||
|
|
||||||
|
return resolved_enum_defs
|
||||||
|
|
||||||
|
static func resolve_level_field_definitions(level_field_defs: Array) -> Dictionary:
|
||||||
|
var resolved_level_field_defs := {}
|
||||||
|
|
||||||
|
for level_field_def in level_field_defs:
|
||||||
|
resolved_level_field_defs[level_field_def.uid] = {
|
||||||
|
"identifier": level_field_def.identifier,
|
||||||
|
"type": level_field_def.__type
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolved_level_field_defs
|
@ -0,0 +1 @@
|
|||||||
|
uid://10dqdfkkqwa2
|
126
godot/addons/ldtk-importer/src/util/field-util.gd
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
@tool
|
||||||
|
|
||||||
|
const Util = preload("util.gd")
|
||||||
|
const TileUtil = preload("tile-util.gd")
|
||||||
|
|
||||||
|
static var hitUnresolved := false
|
||||||
|
static var current_field_name: String = "N/A"
|
||||||
|
|
||||||
|
static func create_fields(fields: Array, entity: Variant = null) -> Dictionary:
|
||||||
|
var dict := {}
|
||||||
|
for field in fields:
|
||||||
|
var key: String = field.__identifier
|
||||||
|
current_field_name = key
|
||||||
|
dict[key] = parse_field(field)
|
||||||
|
|
||||||
|
if not Util.options.resolve_entityrefs:
|
||||||
|
hitUnresolved = false
|
||||||
|
continue
|
||||||
|
|
||||||
|
if hitUnresolved and entity != null:
|
||||||
|
if dict[key] is Array:
|
||||||
|
for index in range(dict[key].size()):
|
||||||
|
Util.add_unresolved_reference(dict[key], index, entity)
|
||||||
|
else:
|
||||||
|
Util.add_unresolved_reference(dict, key, entity)
|
||||||
|
hitUnresolved = false
|
||||||
|
|
||||||
|
return dict
|
||||||
|
|
||||||
|
static func parse_field(field: Dictionary) -> Variant:
|
||||||
|
var value: Variant = field.__value
|
||||||
|
if value == null:
|
||||||
|
return null
|
||||||
|
|
||||||
|
var type := field.__type as String
|
||||||
|
|
||||||
|
# Handle enum string
|
||||||
|
var localEnum: String
|
||||||
|
if type.contains("LocalEnum"):
|
||||||
|
var regex = RegEx.new()
|
||||||
|
regex.compile("(?<=\\.)\\w+")
|
||||||
|
localEnum = regex.search(type).get_string()
|
||||||
|
|
||||||
|
if type.begins_with("Array"):
|
||||||
|
type = "Array<LocalEnum>"
|
||||||
|
else:
|
||||||
|
type = "LocalEnum"
|
||||||
|
|
||||||
|
# Match field type
|
||||||
|
match type:
|
||||||
|
"Int":
|
||||||
|
return int(value) as int
|
||||||
|
"Color":
|
||||||
|
return Color.from_string(value, Color.MAGENTA) as Color
|
||||||
|
"Point":
|
||||||
|
return __parse_point(value.cx, value.cy) as Vector2i
|
||||||
|
"Tile":
|
||||||
|
return __parse_tile(value) as AtlasTexture
|
||||||
|
"EntityRef":
|
||||||
|
hitUnresolved = true
|
||||||
|
return value.entityIid as String
|
||||||
|
"LocalEnum":
|
||||||
|
return __parse_enum(localEnum, value) as String
|
||||||
|
"Array<Int>":
|
||||||
|
return value
|
||||||
|
"Array<Color>":
|
||||||
|
return value.map(
|
||||||
|
func (color):
|
||||||
|
return Color.from_string(color, Color.MAGENTA)
|
||||||
|
)
|
||||||
|
"Array<Point>":
|
||||||
|
return value.map(
|
||||||
|
func (point):
|
||||||
|
return Vector2i(point.cx, point.cy)
|
||||||
|
)
|
||||||
|
"Array<Tile>":
|
||||||
|
return value.map(
|
||||||
|
func(tile) -> AtlasTexture:
|
||||||
|
return __parse_tile(tile)
|
||||||
|
)
|
||||||
|
"Array<EntityRef>":
|
||||||
|
hitUnresolved = true
|
||||||
|
return value.map(
|
||||||
|
func (ref) -> String:
|
||||||
|
return ref.entityIid
|
||||||
|
)
|
||||||
|
"Array<LocalEnum>":
|
||||||
|
var enums: Array[String] = []
|
||||||
|
for index in range(value.size()):
|
||||||
|
var parsed_enum = __parse_enum(localEnum, value[index])
|
||||||
|
enums.append(parsed_enum)
|
||||||
|
return enums
|
||||||
|
_:
|
||||||
|
return value
|
||||||
|
|
||||||
|
static func __parse_point(x: int, y: int) -> Vector2i:
|
||||||
|
# NOTE: would convert gridcoords to pixelcoords here, but needs more data
|
||||||
|
# LDTKEntity currently converts it using LayerDefinition.
|
||||||
|
return Vector2i(x,y)
|
||||||
|
|
||||||
|
static func __parse_enum(enum_str: String, value: String) -> String:
|
||||||
|
var result: String = "%s.%s" % [enum_str, value]
|
||||||
|
return result
|
||||||
|
|
||||||
|
static func __parse_tile(value: Dictionary) -> AtlasTexture:
|
||||||
|
var texture := AtlasTexture.new()
|
||||||
|
var atlas: TileSetAtlasSource
|
||||||
|
|
||||||
|
if Util.tileset_refs.has(int(value.tilesetUid)):
|
||||||
|
atlas = Util.tileset_refs[int(value.tilesetUid)]
|
||||||
|
|
||||||
|
if atlas == null :
|
||||||
|
print("Tileset Refs: ", Util.tileset_refs)
|
||||||
|
print("FieldDef<Tile> '%s' could not find Tileset with UID '%s'. Using empty texture instead. Please fix this in your LDtk file." % [current_field_name, value.tilesetUid])
|
||||||
|
return texture
|
||||||
|
|
||||||
|
texture.atlas = atlas.texture
|
||||||
|
|
||||||
|
var coords = TileUtil.px_to_grid(
|
||||||
|
Vector2(value.x, value.y),
|
||||||
|
atlas.texture_region_size,
|
||||||
|
atlas.margins,
|
||||||
|
atlas.separation
|
||||||
|
)
|
||||||
|
texture.region = atlas.get_tile_texture_region(coords) as Rect2i
|
||||||
|
return texture
|
1
godot/addons/ldtk-importer/src/util/field-util.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://dp7qwjbyo1kx0
|
68
godot/addons/ldtk-importer/src/util/layer-util.gd
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
@tool
|
||||||
|
|
||||||
|
const Util = preload("util.gd")
|
||||||
|
const EntityPlaceHolder = preload("../components/ldtk-entity.tscn")
|
||||||
|
const FieldUtil = preload("field-util.gd")
|
||||||
|
|
||||||
|
# Counter reset per level, used when creating EntityPlacholders
|
||||||
|
static var placeholder_counts := {}
|
||||||
|
|
||||||
|
static func parse_entity_instances(
|
||||||
|
entities: Array,
|
||||||
|
entity_defs: Dictionary,
|
||||||
|
pathResolver: Node2D
|
||||||
|
) -> Array:
|
||||||
|
return entities.map(
|
||||||
|
func(entity):
|
||||||
|
var definition = entity_defs[entity.defUid]
|
||||||
|
return {
|
||||||
|
"iid": entity.iid,
|
||||||
|
"identifier": entity.__identifier,
|
||||||
|
"smart_color": Color.from_string(entity.__smartColor, Color.WHITE),
|
||||||
|
"size": Vector2i(entity.width, entity.height),
|
||||||
|
"position": Vector2i(entity.px[0], entity.px[1]),
|
||||||
|
"pivot": Vector2(entity.__pivot[0], entity.__pivot[1]),
|
||||||
|
"fields": FieldUtil.create_fields(entity.fieldInstances, pathResolver),
|
||||||
|
"definition": definition,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
static func create_entity_placeholder(layer: Node2D, data: Dictionary) -> LDTKEntity:
|
||||||
|
var placeholder: LDTKEntity = EntityPlaceHolder.instantiate()
|
||||||
|
var count: int = __placeholder_count(data.identifier)
|
||||||
|
placeholder.name = data.identifier
|
||||||
|
|
||||||
|
if count > 1:
|
||||||
|
placeholder.name += str(count)
|
||||||
|
|
||||||
|
# Set properties
|
||||||
|
for prop in data.keys():
|
||||||
|
placeholder[prop] = data[prop]
|
||||||
|
|
||||||
|
layer.add_child(placeholder)
|
||||||
|
return placeholder
|
||||||
|
|
||||||
|
static func __placeholder_count(name: String) -> int:
|
||||||
|
if not name in placeholder_counts:
|
||||||
|
placeholder_counts[name] = 1
|
||||||
|
else:
|
||||||
|
placeholder_counts[name] += 1
|
||||||
|
return placeholder_counts[name]
|
||||||
|
|
||||||
|
static func create_layer_tilemap(layer_data: Dictionary) -> TileMapLayer:
|
||||||
|
var grid_size = int(layer_data.__gridSize)
|
||||||
|
|
||||||
|
var tilemap := TileMapLayer.new()
|
||||||
|
tilemap.name = layer_data.__identifier
|
||||||
|
tilemap.tile_set = Util.tilesets.get(grid_size, null)
|
||||||
|
var offset = Vector2(layer_data.__pxTotalOffsetX, layer_data.__pxTotalOffsetY)
|
||||||
|
tilemap.position = offset
|
||||||
|
|
||||||
|
return tilemap
|
||||||
|
|
||||||
|
static func create_tilemap_child(tilemap: TileMapLayer) -> TileMapLayer:
|
||||||
|
var child := TileMapLayer.new()
|
||||||
|
var count := tilemap.get_child_count() + 1
|
||||||
|
child.name = tilemap.name + str(count)
|
||||||
|
child.tile_set = tilemap.tile_set
|
||||||
|
return child
|
1
godot/addons/ldtk-importer/src/util/layer-util.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://cm8kt5fyu4max
|
54
godot/addons/ldtk-importer/src/util/level-util.gd
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
@tool
|
||||||
|
|
||||||
|
const Util = preload("util.gd")
|
||||||
|
|
||||||
|
static func get_world_position(
|
||||||
|
world_data: Dictionary,
|
||||||
|
level_data: Dictionary
|
||||||
|
) -> Vector2i:
|
||||||
|
|
||||||
|
var layout = world_data.worldLayout
|
||||||
|
|
||||||
|
if layout == "GridVania" or layout == "Free":
|
||||||
|
return Vector2i(level_data.worldX, level_data.worldY)
|
||||||
|
elif layout == "LinearHorizontal" or layout == "LinearVertical":
|
||||||
|
# List level uids in order.
|
||||||
|
var level_uids: Array = world_data.levels.map(
|
||||||
|
func(item):
|
||||||
|
return item.uid
|
||||||
|
)
|
||||||
|
# Find level index
|
||||||
|
var index = level_uids.find(level_data.uid)
|
||||||
|
if index == 0:
|
||||||
|
return Vector2i(0,0)
|
||||||
|
|
||||||
|
if layout == "LinearHorizontal":
|
||||||
|
var x: int = world_data.levels.slice(0, index).reduce(
|
||||||
|
func (accum, current):
|
||||||
|
return accum + current.pxWid
|
||||||
|
, 0)
|
||||||
|
return Vector2i(x, 0)
|
||||||
|
else:
|
||||||
|
var y: int = world_data.levels.slice(0, index).reduce(
|
||||||
|
func (accum, current):
|
||||||
|
return accum + current.pHei
|
||||||
|
, 0)
|
||||||
|
return Vector2i(0, y)
|
||||||
|
else:
|
||||||
|
push_warning("World layout not supported", world_data.worldLayout)
|
||||||
|
return Vector2i.ZERO
|
||||||
|
|
||||||
|
|
||||||
|
static func get_external_level(
|
||||||
|
level_data: Dictionary,
|
||||||
|
base_dir: String
|
||||||
|
) -> Dictionary:
|
||||||
|
|
||||||
|
var level_file: String = base_dir + level_data.externalRelPath
|
||||||
|
var new_level_data: Dictionary = Util.parse_file(level_file)
|
||||||
|
if not new_level_data == null:
|
||||||
|
return new_level_data
|
||||||
|
else:
|
||||||
|
push_warning("Could not parse external level: ", level_file)
|
||||||
|
|
||||||
|
return level_data
|
1
godot/addons/ldtk-importer/src/util/level-util.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://oc513xtwqvf1
|
126
godot/addons/ldtk-importer/src/util/tile-util.gd
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
@tool
|
||||||
|
|
||||||
|
# Flip a vector based on a bitset
|
||||||
|
static func _flip_vector_array_with_bitset(
|
||||||
|
vecs: PackedVector2Array,
|
||||||
|
bitset: int
|
||||||
|
) -> PackedVector2Array:
|
||||||
|
var new_vecs = PackedVector2Array(vecs)
|
||||||
|
for point_idx in range(vecs.size()):
|
||||||
|
var new_vec = Vector2(vecs[point_idx])
|
||||||
|
if bitset & 1:
|
||||||
|
new_vec.x = -new_vec.x
|
||||||
|
if bitset & 2:
|
||||||
|
new_vec.y = -new_vec.y
|
||||||
|
new_vecs[point_idx] = new_vec
|
||||||
|
return new_vecs
|
||||||
|
|
||||||
|
# Copy over and rotate extra tiledata
|
||||||
|
static func copy_and_modify_tile_data(
|
||||||
|
tile_data: TileData,
|
||||||
|
orig_tile_data: TileData,
|
||||||
|
physics_layers_cnt: int,
|
||||||
|
navigation_layers_cnt: int,
|
||||||
|
occluder_layers_cnt: int,
|
||||||
|
bitset: int,
|
||||||
|
) -> void:
|
||||||
|
# Copy over physics
|
||||||
|
for pli in range(physics_layers_cnt):
|
||||||
|
var polygon_cnt = orig_tile_data.get_collision_polygons_count(pli)
|
||||||
|
if polygon_cnt == 0:
|
||||||
|
# We have no polygon for this layer
|
||||||
|
continue
|
||||||
|
for pi in range(polygon_cnt):
|
||||||
|
tile_data.add_collision_polygon(pli)
|
||||||
|
var points: PackedVector2Array = _flip_vector_array_with_bitset(orig_tile_data.get_collision_polygon_points(pli, pi), bitset)
|
||||||
|
tile_data.set_collision_polygon_points(pli, pi, points)
|
||||||
|
tile_data.set_constant_angular_velocity(pli, orig_tile_data.get_constant_angular_velocity(pli))
|
||||||
|
var linvel = Vector2(orig_tile_data.get_constant_linear_velocity(pli))
|
||||||
|
if bitset & TileSetAtlasSource.TRANSFORM_FLIP_H:
|
||||||
|
linvel.x = -linvel.x
|
||||||
|
if bitset & TileSetAtlasSource.TRANSFORM_FLIP_V:
|
||||||
|
linvel.y = -linvel.y
|
||||||
|
tile_data.set_constant_linear_velocity(pli, linvel)
|
||||||
|
|
||||||
|
# Copy over navigation
|
||||||
|
for navi in range(navigation_layers_cnt):
|
||||||
|
var nav_polygon: NavigationPolygon = orig_tile_data.get_navigation_polygon(navi)
|
||||||
|
if nav_polygon == null:
|
||||||
|
# We have no polygon for this layer
|
||||||
|
continue
|
||||||
|
var new_polygon = NavigationPolygon.new()
|
||||||
|
for outline_idx in range(nav_polygon.get_outline_count()):
|
||||||
|
var vertices = _flip_vector_array_with_bitset(nav_polygon.get_outline(outline_idx), bitset)
|
||||||
|
new_polygon.add_outline(vertices)
|
||||||
|
new_polygon.make_polygons_from_outlines()
|
||||||
|
tile_data.set_navigation_polygon(navi, new_polygon)
|
||||||
|
|
||||||
|
# Copy over occluder
|
||||||
|
for occi in range(occluder_layers_cnt):
|
||||||
|
var occluder: OccluderPolygon2D = orig_tile_data.get_occluder(occi)
|
||||||
|
if occluder == null:
|
||||||
|
# We have no polygon for this layer
|
||||||
|
continue
|
||||||
|
var new_occluder: OccluderPolygon2D = OccluderPolygon2D.new()
|
||||||
|
new_occluder.cull_mode = occluder.cull_mode
|
||||||
|
new_occluder.closed = occluder.closed
|
||||||
|
new_occluder.polygon = _flip_vector_array_with_bitset(occluder.polygon, bitset)
|
||||||
|
tile_data.set_occluder(occi, new_occluder)
|
||||||
|
|
||||||
|
# Flip depending on bitset
|
||||||
|
if bitset & TileSetAtlasSource.TRANSFORM_FLIP_H:
|
||||||
|
tile_data.set_flip_h(true)
|
||||||
|
if bitset & TileSetAtlasSource.TRANSFORM_FLIP_V:
|
||||||
|
tile_data.set_flip_v(true)
|
||||||
|
|
||||||
|
# Get Rect of Tile for an AtlasSource using LDTK tileset data
|
||||||
|
static func get_tile_region(
|
||||||
|
coords: Vector2i,
|
||||||
|
grid_size: int,
|
||||||
|
padding: int,
|
||||||
|
spacing: int,
|
||||||
|
grid_w: int
|
||||||
|
) -> Rect2i:
|
||||||
|
var pixel_coords = grid_to_px(coords, grid_size, padding, spacing)
|
||||||
|
return Rect2i(pixel_coords, Vector2i(grid_size, grid_size))
|
||||||
|
|
||||||
|
# Convert grid coords to pixel coords
|
||||||
|
static func grid_to_px(
|
||||||
|
grid_coords: Vector2i,
|
||||||
|
grid_size: int,
|
||||||
|
padding: int,
|
||||||
|
spacing: int
|
||||||
|
) -> Vector2i:
|
||||||
|
var x: int = padding + grid_coords.x * (grid_size + spacing)
|
||||||
|
var y: int = padding + grid_coords.y * (grid_size + spacing)
|
||||||
|
return Vector2i(x, y)
|
||||||
|
|
||||||
|
# Converts px coords to grid coords
|
||||||
|
static func px_to_grid(
|
||||||
|
px_coords: Vector2,
|
||||||
|
grid_size: Vector2,
|
||||||
|
padding: Vector2 = Vector2.ZERO,
|
||||||
|
spacing: Vector2 = Vector2.ZERO
|
||||||
|
) -> Vector2i:
|
||||||
|
var x: int = round((px_coords.x - padding.x) / (grid_size.x + spacing.x))
|
||||||
|
var y: int = round((px_coords.y - padding.y) / (grid_size.y + spacing.y))
|
||||||
|
return Vector2i(x, y)
|
||||||
|
|
||||||
|
# Convert TileId to grid coords
|
||||||
|
static func tileid_to_grid(tile_id: int, grid_w: int) -> Vector2i:
|
||||||
|
var y := int(tile_id / grid_w)
|
||||||
|
var x := tile_id % grid_w
|
||||||
|
return Vector2i(x, y)
|
||||||
|
|
||||||
|
static func index_to_grid(index: int, grid_w: int) -> Vector2i:
|
||||||
|
var x: int = floor(index % grid_w)
|
||||||
|
var y: int = floor(index / grid_w)
|
||||||
|
return Vector2i(x, y)
|
||||||
|
|
||||||
|
# Converts '1' to (TRANSFORM_FLIP_H), and so on.
|
||||||
|
static func get_tile_flip_mask(index: int) -> int:
|
||||||
|
# 0 -> 0
|
||||||
|
# 1 -> TileSetAtlasSource.TRANSFORM_FLIP_H (4096)
|
||||||
|
# 2 -> TileSetAtlasSource.TRANSFORM_FLIP_V (8192)
|
||||||
|
# 3 -> TileSetAtlasSource.TRANSFORM_FLIP_H | TileSetAtlasSource.TRANSFORM_FLIP_H (12_228)
|
||||||
|
return index << 12
|
1
godot/addons/ldtk-importer/src/util/tile-util.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://bp3rb0p6dsayi
|
48
godot/addons/ldtk-importer/src/util/time-util.gd
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
@tool
|
||||||
|
|
||||||
|
## Helper Script to track performance of the importer.
|
||||||
|
|
||||||
|
enum { SAVE, LOAD, GENERAL, TILES, POST_IMPORT, TOTAL }
|
||||||
|
|
||||||
|
static var category_time := {
|
||||||
|
SAVE: 0,
|
||||||
|
LOAD: 0,
|
||||||
|
GENERAL: 0,
|
||||||
|
TILES: 0,
|
||||||
|
POST_IMPORT: 0,
|
||||||
|
TOTAL : 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
static var category_name := {
|
||||||
|
SAVE: "save",
|
||||||
|
LOAD: "load",
|
||||||
|
GENERAL : "general",
|
||||||
|
TILES: "tiles",
|
||||||
|
POST_IMPORT: "post-import",
|
||||||
|
TOTAL: "total"
|
||||||
|
}
|
||||||
|
|
||||||
|
static func log_time(category: int, time: int = 0) -> void:
|
||||||
|
if category_time.has(category):
|
||||||
|
category_time[category] += time
|
||||||
|
else:
|
||||||
|
push_warning("No DebugTime Category '%s'" % [category_name[category]])
|
||||||
|
|
||||||
|
static func clear_time() -> void:
|
||||||
|
for category in category_time:
|
||||||
|
category_time[category] = 0
|
||||||
|
|
||||||
|
static func get_total_time() -> int:
|
||||||
|
var sum: int = 0
|
||||||
|
for category in category_time:
|
||||||
|
if category != TOTAL:
|
||||||
|
sum += category_time[category]
|
||||||
|
return sum
|
||||||
|
|
||||||
|
static func get_result() -> String:
|
||||||
|
var result: String = "Performance Results:"
|
||||||
|
for category in category_time:
|
||||||
|
if category != TOTAL:
|
||||||
|
result += "\n [color=#8ec07c]%s [color=slategray](%sms)[/color]" % [category_name[category], category_time[category]]
|
||||||
|
result.indent("\t")
|
||||||
|
return result
|
1
godot/addons/ldtk-importer/src/util/time-util.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://bynwlcmpnsjit
|
226
godot/addons/ldtk-importer/src/util/util.gd
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
@tool
|
||||||
|
|
||||||
|
const DebugTime = preload("time-util.gd")
|
||||||
|
|
||||||
|
enum LDTK_VERSION {
|
||||||
|
FUTURE,
|
||||||
|
v1_5,
|
||||||
|
v1_4,
|
||||||
|
v1_3,
|
||||||
|
v1_2,
|
||||||
|
v1_0,
|
||||||
|
UNSUPPORTED
|
||||||
|
}
|
||||||
|
static var file_version = LDTK_VERSION.UNSUPPORTED
|
||||||
|
|
||||||
|
# Stores import flags (used throughout the importer)
|
||||||
|
static var options := {}
|
||||||
|
|
||||||
|
static func parse_file(source_file: String) -> Dictionary:
|
||||||
|
var json := FileAccess.open(source_file, FileAccess.READ)
|
||||||
|
if json == null:
|
||||||
|
push_error("\nFailed to open file: ", source_file)
|
||||||
|
return {}
|
||||||
|
var data := JSON.parse_string(json.get_as_text())
|
||||||
|
return data
|
||||||
|
|
||||||
|
static func check_version(version: String, latest_version: String) -> bool:
|
||||||
|
if version.begins_with("0."):
|
||||||
|
push_error("LDTK version out of date. Please update LDtk to ", latest_version)
|
||||||
|
file_version = LDTK_VERSION.UNSUPPORTED
|
||||||
|
return false
|
||||||
|
|
||||||
|
var major_minor = version.substr(0, 3)
|
||||||
|
match major_minor:
|
||||||
|
"1.0", "1.1":
|
||||||
|
file_version = LDTK_VERSION.v1_0
|
||||||
|
"1.2":
|
||||||
|
file_version = LDTK_VERSION.v1_2
|
||||||
|
"1.3":
|
||||||
|
file_version = LDTK_VERSION.v1_3
|
||||||
|
"1.4":
|
||||||
|
file_version = LDTK_VERSION.v1_4
|
||||||
|
"1.5":
|
||||||
|
file_version = LDTK_VERSION.v1_5
|
||||||
|
_:
|
||||||
|
push_warning("LDtk file version is newer than what is supported. Errors may occur.")
|
||||||
|
file_version = LDTK_VERSION.FUTURE
|
||||||
|
return true
|
||||||
|
|
||||||
|
static func recursive_set_owner(node: Node, owner: Node) -> void:
|
||||||
|
node.set_owner(owner)
|
||||||
|
for child in node.get_children():
|
||||||
|
# Child is NOT an instantiated scene - this would otherwise cause errors
|
||||||
|
if child.scene_file_path == "":
|
||||||
|
recursive_set_owner(child, owner)
|
||||||
|
else:
|
||||||
|
child.set_owner(owner)
|
||||||
|
|
||||||
|
#region Performance Measurement
|
||||||
|
|
||||||
|
static var last_time: int = 0
|
||||||
|
static var time_history: Array[Dictionary] = []
|
||||||
|
|
||||||
|
static func timer_start(category: int = 0) -> int:
|
||||||
|
var t: int = Time.get_ticks_msec()
|
||||||
|
var d: int = t - last_time
|
||||||
|
last_time = t
|
||||||
|
|
||||||
|
if time_history.size() > 0:
|
||||||
|
# Entering subcategory - log prev category up to here
|
||||||
|
var last: Dictionary = time_history[-1]
|
||||||
|
DebugTime.log_time(last.category, d)
|
||||||
|
|
||||||
|
time_history.append({"category": category, "time": t, "init": t})
|
||||||
|
return t
|
||||||
|
|
||||||
|
static func timer_finish(message: String, indent: int = 0, doPrint: bool = true) -> int:
|
||||||
|
if time_history.size() == 0:
|
||||||
|
push_error("Unbalanced DebugTime stack")
|
||||||
|
var last: Dictionary = time_history.pop_back()
|
||||||
|
var t: int = Time.get_ticks_msec()
|
||||||
|
var d: int = t - last.time
|
||||||
|
last_time = t
|
||||||
|
DebugTime.log_time(last.category, d)
|
||||||
|
|
||||||
|
if time_history.size() > 0:
|
||||||
|
time_history[-1].time = t
|
||||||
|
|
||||||
|
if (doPrint and options.verbose_output):
|
||||||
|
# Print 'gross' duration for this block
|
||||||
|
var d2: int = t - last.init
|
||||||
|
print_time("item_info_time", message, d2, indent)
|
||||||
|
return d
|
||||||
|
|
||||||
|
static func timer_reset() -> void:
|
||||||
|
last_time = 0
|
||||||
|
time_history.clear()
|
||||||
|
DebugTime.clear_time()
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Debug Output
|
||||||
|
|
||||||
|
const PRINT_SNIPPET := {
|
||||||
|
"import_start": "[bgcolor=#ffcc00][color=black][LDTK][/color][/bgcolor][color=#ffcc00] Start Import: [color=#fe8019][i]'%s'[/i][/color]",
|
||||||
|
"import_finish": "[bgcolor=#ffcc00][color=black][LDTK][/color][/bgcolor][color=#ffcc00] Finished Import. [color=slategray](Total Time: %sms)[/color]",
|
||||||
|
"item_ok" : "[color=#b8bb26]• %s ✔[/color]",
|
||||||
|
"item_fail": "[color=#fb4934]• %s ✘[/color]",
|
||||||
|
"item_info": "[color=#8ec07c]• %s [/color]",
|
||||||
|
"item_save": "[color=#ffcc00]• %s [/color]",
|
||||||
|
"item_post_import": "[color=tomato]‣ %s[/color]",
|
||||||
|
"block": "[color=#ffcc00]█[/color] [color=#fe8019]%s[/color]",
|
||||||
|
"item_ok_time": "[color=#b8bb26]• %s ✔[/color]\t[color=slategray](%sms)[/color]",
|
||||||
|
"item_fail_time": "[color=#fb4934]• %s ✘[/color]\t[color=slategray](%sms)[/color]",
|
||||||
|
"item_info_time": "[color=#8ec07c]• %s [/color]\t[color=slategray](%sms)[/color]",
|
||||||
|
"world_post_import": "[color=tomato]‣ World Post-Import: %s[/color]",
|
||||||
|
"level_post_import": "[color=tomato]‣ Level Post-Import: %s[/color]",
|
||||||
|
"tileset_post_import": "[color=tomato]‣ Tileset Post-Import: %s[/color]",
|
||||||
|
"entity_post_import": "[color=tomato]‣ Entity Post-Import: %s[/color]",
|
||||||
|
}
|
||||||
|
|
||||||
|
static func nice_print(type: String, message: String, indent: int = 0) -> void:
|
||||||
|
if PRINT_SNIPPET.has(type):
|
||||||
|
var snippet: String = PRINT_SNIPPET[type]
|
||||||
|
snippet = snippet.indent(str("\t").repeat(indent))
|
||||||
|
print_rich(snippet % [message])
|
||||||
|
else:
|
||||||
|
print_rich(message)
|
||||||
|
|
||||||
|
static func print(type: String, message: String, indent: int = 0) -> void:
|
||||||
|
nice_print(type, message, indent)
|
||||||
|
|
||||||
|
static func print_time(type: String, message: String, time: int = -1, indent: int = 0) -> void:
|
||||||
|
if PRINT_SNIPPET.has(type):
|
||||||
|
var snippet: String = PRINT_SNIPPET[type]
|
||||||
|
snippet = snippet.indent(str("\t").repeat(indent))
|
||||||
|
print_rich(snippet % [message, time])
|
||||||
|
else:
|
||||||
|
print_rich(message)
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region References
|
||||||
|
static var tilesets := {}
|
||||||
|
static var tileset_refs := {}
|
||||||
|
static var instance_refs := {}
|
||||||
|
static var unresolved_refs := []
|
||||||
|
static var path_resolvers := []
|
||||||
|
|
||||||
|
static func update_instance_reference(iid: String, instance: Variant) -> void:
|
||||||
|
instance_refs[iid] = instance
|
||||||
|
|
||||||
|
static func add_tileset_reference(uid: int, atlas: TileSetAtlasSource) -> void:
|
||||||
|
tileset_refs[uid] = atlas
|
||||||
|
|
||||||
|
# This is useful for handling entity instances, as they might not exist yet when encountered
|
||||||
|
# or be overwritten at a later stage (e.g. post-import) when importing an LDTK level/world.
|
||||||
|
static func add_unresolved_reference(
|
||||||
|
object: Variant,
|
||||||
|
property: Variant,
|
||||||
|
node: Variant = object,
|
||||||
|
iid: String = str(object[property])
|
||||||
|
) -> void:
|
||||||
|
|
||||||
|
unresolved_refs.append({
|
||||||
|
"object": object,
|
||||||
|
"property": property,
|
||||||
|
"node": node,
|
||||||
|
"iid": iid
|
||||||
|
})
|
||||||
|
|
||||||
|
static func handle_references() -> void:
|
||||||
|
resolve_references()
|
||||||
|
clean_references()
|
||||||
|
clean_resolvers()
|
||||||
|
|
||||||
|
static func resolve_references() -> void:
|
||||||
|
var count := unresolved_refs.size()
|
||||||
|
if (count == 0 or not options.resolve_entityrefs):
|
||||||
|
if (options.verbose_output): nice_print("item_info", "No references to resolve", 1)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
if (options.verbose_output): nice_print("item_info", "Resolving %s references" % [count], 1)
|
||||||
|
|
||||||
|
var solved_refcount := 0
|
||||||
|
|
||||||
|
for ref in unresolved_refs:
|
||||||
|
var iid: String = ref.iid
|
||||||
|
var object: Variant = ref.object # Expected: Node, Dict or Array
|
||||||
|
var property: Variant = ref.property # Expected: String or Int
|
||||||
|
var node: Variant = ref.node # Expected: Node, but needs to accept null
|
||||||
|
|
||||||
|
if instance_refs.has(iid):
|
||||||
|
var instance = instance_refs[iid]
|
||||||
|
|
||||||
|
if instance is Node and node is Node:
|
||||||
|
# BUG: When using 'Pack Levels', external references cannot be resolved at import time. (e.g. Level_0 -> Level_1)
|
||||||
|
# Internal references can resolve, but Godot pushes the error: Parameter "common_parent" is null.
|
||||||
|
# Currently it's a choice between a bunch of errors (that suppress other messages), or no resolving.
|
||||||
|
if true: #instance.owner != null and node.owner != null:
|
||||||
|
var path = node.get_path_to(instance)
|
||||||
|
if path:
|
||||||
|
object[property] = path
|
||||||
|
else:
|
||||||
|
nice_print("item_fail", "Cannot resolve ref (out-of-bounds?) '%s' '%s'" % [instance.name, node.name], 1)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
object[property] = instance
|
||||||
|
|
||||||
|
solved_refcount += 1
|
||||||
|
|
||||||
|
var leftover_refcount: int = unresolved_refs.size() - solved_refcount
|
||||||
|
if leftover_refcount > 0:
|
||||||
|
nice_print("item_info", "Could not resolve %s references, most likely non-existent entities." % [leftover_refcount], 1)
|
||||||
|
|
||||||
|
static func clean_references() -> void:
|
||||||
|
tileset_refs.clear()
|
||||||
|
instance_refs.clear()
|
||||||
|
unresolved_refs.clear()
|
||||||
|
|
||||||
|
static func clean_resolvers() -> void:
|
||||||
|
for resolver in path_resolvers:
|
||||||
|
resolver.free()
|
||||||
|
path_resolvers.clear()
|
||||||
|
|
||||||
|
#endregion
|
1
godot/addons/ldtk-importer/src/util/util.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://ddr8yxjsfqgji
|
89
godot/addons/ldtk-importer/src/world.gd
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
@tool
|
||||||
|
|
||||||
|
const Util = preload("util/util.gd")
|
||||||
|
const PostImport = preload("post-import.gd")
|
||||||
|
|
||||||
|
static func create_world(
|
||||||
|
name: String,
|
||||||
|
iid: String,
|
||||||
|
levels: Array,
|
||||||
|
base_dir: String
|
||||||
|
) -> LDTKWorld:
|
||||||
|
|
||||||
|
Util.timer_start(Util.DebugTime.GENERAL)
|
||||||
|
var world = LDTKWorld.new()
|
||||||
|
world.name = name
|
||||||
|
world.iid = iid
|
||||||
|
|
||||||
|
# Update World_Rect
|
||||||
|
var x1 = world.rect.position.x
|
||||||
|
var x2 = world.rect.end.x
|
||||||
|
var y1 = world.rect.position.y
|
||||||
|
var y2 = world.rect.end.y
|
||||||
|
|
||||||
|
var worldDepths := {}
|
||||||
|
|
||||||
|
for level in levels:
|
||||||
|
level.position = level.world_position
|
||||||
|
|
||||||
|
if Util.options.group_world_layers:
|
||||||
|
var worldDepthLayer: LDTKWorldLayer
|
||||||
|
var z_index: int = level.z_index if (level is not PackedScene) else 0
|
||||||
|
if not z_index in worldDepths:
|
||||||
|
worldDepthLayer = LDTKWorldLayer.new()
|
||||||
|
worldDepthLayer.name = "WorldLayer_" + str(z_index)
|
||||||
|
worldDepthLayer.depth = z_index
|
||||||
|
world.add_child(worldDepthLayer)
|
||||||
|
worldDepthLayer.set_owner(world)
|
||||||
|
worldDepths[z_index] = worldDepthLayer
|
||||||
|
else:
|
||||||
|
worldDepthLayer = worldDepths[z_index]
|
||||||
|
worldDepthLayer.add_child(level)
|
||||||
|
else:
|
||||||
|
world.add_child(level)
|
||||||
|
|
||||||
|
x1 = min(x1, level.position.x)
|
||||||
|
y1 = min(y1, level.position.y)
|
||||||
|
x2 = max(x2, level.position.x + level.size.x)
|
||||||
|
y2 = max(y2, level.position.y + level.size.y)
|
||||||
|
|
||||||
|
# Set owner - this ensures nodes get saved correctly
|
||||||
|
level.set_owner(world)
|
||||||
|
if not (Util.options.pack_levels):
|
||||||
|
Util.recursive_set_owner(level, world)
|
||||||
|
|
||||||
|
# Sort WorldLayers based on depth
|
||||||
|
if not worldDepths.is_empty():
|
||||||
|
var keys = worldDepths.keys()
|
||||||
|
keys.sort_custom(func(a,b): return a < b)
|
||||||
|
for i in range(keys.size()):
|
||||||
|
world.move_child(worldDepths[keys[i]], i)
|
||||||
|
|
||||||
|
world.rect.position = Vector2i(x1, y1)
|
||||||
|
world.rect.end = Vector2i(x2, y2)
|
||||||
|
|
||||||
|
Util.timer_finish("World Created", 1)
|
||||||
|
|
||||||
|
# Post-Import
|
||||||
|
if (Util.options.world_post_import):
|
||||||
|
world = PostImport.run_world_post_import(world, Util.options.world_post_import)
|
||||||
|
|
||||||
|
return world
|
||||||
|
|
||||||
|
static func create_multi_world(
|
||||||
|
name: String,
|
||||||
|
iid: String,
|
||||||
|
worlds: Array[LDTKWorld]
|
||||||
|
) -> LDTKWorld:
|
||||||
|
|
||||||
|
var multi_world = LDTKWorld.new()
|
||||||
|
multi_world.name = name
|
||||||
|
multi_world.iid = iid
|
||||||
|
|
||||||
|
worlds.sort_custom(func(a, b): return a.depth < b.depth)
|
||||||
|
|
||||||
|
for world in worlds:
|
||||||
|
multi_world.add_child(world)
|
||||||
|
Util.recursive_set_owner(world, multi_world)
|
||||||
|
|
||||||
|
return multi_world
|
1
godot/addons/ldtk-importer/src/world.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://dxg0dj75iw7w8
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
34
godot/assets/processed/tilesets/sidewalk_128x128.png.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://d0k22dcuuv8uy"
|
||||||
|
path="res://.godot/imported/sidewalk_128x128.png-cde506a7daa48b45baa91d26762bc08d.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/processed/tilesets/sidewalk_128x128.png"
|
||||||
|
dest_files=["res://.godot/imported/sidewalk_128x128.png-cde506a7daa48b45baa91d26762bc08d.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
Before Width: | Height: | Size: 523 KiB After Width: | Height: | Size: 523 KiB |
34
godot/assets/processed/tilesets/sidewalk_512x512.png.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://b8sqa7vj6amn2"
|
||||||
|
path="res://.godot/imported/sidewalk_512x512.png-14776adf2872cddafc407ac4b59f47ee.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/processed/tilesets/sidewalk_512x512.png"
|
||||||
|
dest_files=["res://.godot/imported/sidewalk_512x512.png-14776adf2872cddafc407ac4b59f47ee.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.6 MiB |
34
godot/assets/raw/residential.png.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dm00rxmhhswnc"
|
||||||
|
path="res://.godot/imported/residential.png-262e0878b74a2d5b43ab285d83624e92.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/raw/residential.png"
|
||||||
|
dest_files=["res://.godot/imported/residential.png-262e0878b74a2d5b43ab285d83624e92.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
Before Width: | Height: | Size: 2.5 MiB After Width: | Height: | Size: 2.5 MiB |
34
godot/assets/raw/sidewalk.png.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://b5gsu4gxtaxrw"
|
||||||
|
path="res://.godot/imported/sidewalk.png-2c383e30cad907bc6b4c98e9b24edac2.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/raw/sidewalk.png"
|
||||||
|
dest_files=["res://.godot/imported/sidewalk.png-2c383e30cad907bc6b4c98e9b24edac2.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
@ -3,7 +3,7 @@ extends RigidBody2D
|
|||||||
@onready var cam = $Camera2D
|
@onready var cam = $Camera2D
|
||||||
|
|
||||||
# zoom range: from close-in to far-out
|
# zoom range: from close-in to far-out
|
||||||
var min_zoom = Vector2(1.0, 1.0)
|
var min_zoom = Vector2(0.5, 0.5)
|
||||||
var max_zoom = Vector2(0.2, 0.2)
|
var max_zoom = Vector2(0.2, 0.2)
|
||||||
var max_speed = 5000.0 # max expected speed
|
var max_speed = 5000.0 # max expected speed
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
[ext_resource type="Texture2D" uid="uid://cds01w4trqeei" path="res://assets/police_car.png" id="1_7822p"]
|
[ext_resource type="Texture2D" uid="uid://cds01w4trqeei" path="res://assets/police_car.png" id="1_7822p"]
|
||||||
|
|
||||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_37kl0"]
|
[sub_resource type="RectangleShape2D" id="RectangleShape2D_37kl0"]
|
||||||
size = Vector2(631, 1429)
|
size = Vector2(604, 1300)
|
||||||
|
|
||||||
[node name="Car" type="Car"]
|
[node name="Car" type="Car"]
|
||||||
mass = 1300.0
|
mass = 1300.0
|
||||||
@ -11,9 +11,9 @@ inertia = 5e+07
|
|||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
position = Vector2(0.5, -0.5)
|
position = Vector2(0.5, -0.5)
|
||||||
scale = Vector2(0.5, 0.5)
|
scale = Vector2(0.25, 0.25)
|
||||||
shape = SubResource("RectangleShape2D_37kl0")
|
shape = SubResource("RectangleShape2D_37kl0")
|
||||||
|
|
||||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||||
scale = Vector2(0.5, 0.5)
|
scale = Vector2(0.25, 0.25)
|
||||||
texture = ExtResource("1_7822p")
|
texture = ExtResource("1_7822p")
|
||||||
|
@ -1,39 +1,21 @@
|
|||||||
[gd_scene load_steps=5 format=3 uid="uid://7713s03g7nxw"]
|
[gd_scene load_steps=3 format=3 uid="uid://7713s03g7nxw"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://ukvcgdjxtkqw" path="res://car.tscn" id="1_80nbo"]
|
[ext_resource type="PackedScene" uid="uid://ukvcgdjxtkqw" path="res://car.tscn" id="1_80nbo"]
|
||||||
[ext_resource type="PackedScene" uid="uid://drkq82mmv8ofa" path="res://test_track.tscn" id="1_e2o6t"]
|
[ext_resource type="PackedScene" uid="uid://c38ikiqaivhh5" path="res://map.tscn" id="1_feb5d"]
|
||||||
[ext_resource type="Script" uid="uid://bic64vi6lpelp" path="res://car.gd" id="4_7jktm"]
|
|
||||||
[ext_resource type="Texture2D" uid="uid://bxwhirvk4jjpl" path="res://assets/textures/curb_1.png" id="4_fc0e3"]
|
|
||||||
|
|
||||||
[node name="Node2D" type="Node2D"]
|
[node name="Node2D" type="Node2D"]
|
||||||
|
|
||||||
[node name="Node2D" parent="." instance=ExtResource("1_e2o6t")]
|
[node name="test" parent="." instance=ExtResource("1_feb5d")]
|
||||||
position = Vector2(1024, -7680)
|
position = Vector2(-2048, -2560)
|
||||||
rotation = 1.57079
|
|
||||||
|
|
||||||
[node name="Node2D2" parent="." instance=ExtResource("1_e2o6t")]
|
|
||||||
position = Vector2(1024, -17920)
|
|
||||||
rotation = 1.57079
|
|
||||||
|
|
||||||
[node name="Node2D3" parent="." instance=ExtResource("1_e2o6t")]
|
|
||||||
position = Vector2(1024, -28160)
|
|
||||||
rotation = 1.57079
|
|
||||||
|
|
||||||
[node name="Curb1" type="Sprite2D" parent="."]
|
|
||||||
position = Vector2(-1024, 1022.44)
|
|
||||||
rotation = 1.57079
|
|
||||||
scale = Vector2(1.99747, 0.147406)
|
|
||||||
texture = ExtResource("4_fc0e3")
|
|
||||||
|
|
||||||
[node name="Car" parent="." instance=ExtResource("1_80nbo")]
|
[node name="Car" parent="." instance=ExtResource("1_80nbo")]
|
||||||
controlled_by_player = true
|
controlled_by_player = true
|
||||||
script = ExtResource("4_7jktm")
|
|
||||||
|
|
||||||
[node name="Camera2D" type="Camera2D" parent="Car"]
|
[node name="Camera2D" type="Camera2D" parent="Car"]
|
||||||
position = Vector2(0, -1)
|
position = Vector2(0, -1)
|
||||||
scale = Vector2(0.1, 0.1)
|
scale = Vector2(0.1, 0.1)
|
||||||
zoom = Vector2(0.36, 0.36)
|
zoom = Vector2(0.5, 0.5)
|
||||||
|
|
||||||
[node name="Car2" parent="." instance=ExtResource("1_80nbo")]
|
[node name="Car2" parent="." instance=ExtResource("1_80nbo")]
|
||||||
position = Vector2(512, -1536)
|
position = Vector2(-512, -1536)
|
||||||
rotation = -1.0472
|
rotation = -1.83259
|
||||||
|
BIN
godot/levels/Level_0.scn
Normal file
5
godot/map.tscn
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://c38ikiqaivhh5"]
|
||||||
|
|
||||||
|
[ext_resource type="PackedScene" uid="uid://bydclumuwqch8" path="res://test.ldtk" id="1_c7s6e"]
|
||||||
|
|
||||||
|
[node name="test" instance=ExtResource("1_c7s6e")]
|
@ -15,6 +15,10 @@ run/main_scene="uid://7713s03g7nxw"
|
|||||||
config/features=PackedStringArray("4.4", "Forward Plus")
|
config/features=PackedStringArray("4.4", "Forward Plus")
|
||||||
config/icon="res://icon.svg"
|
config/icon="res://icon.svg"
|
||||||
|
|
||||||
|
[editor_plugins]
|
||||||
|
|
||||||
|
enabled=PackedStringArray("res://addons/ldtk-importer/plugin.cfg")
|
||||||
|
|
||||||
[input]
|
[input]
|
||||||
|
|
||||||
move_forward={
|
move_forward={
|
||||||
|
@ -226,7 +226,7 @@
|
|||||||
"__cHei": 4,
|
"__cHei": 4,
|
||||||
"identifier": "Sidewalk_128x128",
|
"identifier": "Sidewalk_128x128",
|
||||||
"uid": 1,
|
"uid": 1,
|
||||||
"relPath": "../assets/processed/tilesets/sidewalk_128x128.png",
|
"relPath": "assets/processed/tilesets/sidewalk_128x128.png",
|
||||||
"embedAtlas": null,
|
"embedAtlas": null,
|
||||||
"pxWid": 128,
|
"pxWid": 128,
|
||||||
"pxHei": 128,
|
"pxHei": 128,
|
||||||
@ -245,7 +245,7 @@
|
|||||||
"__cHei": 1,
|
"__cHei": 1,
|
||||||
"identifier": "Residential",
|
"identifier": "Residential",
|
||||||
"uid": 6,
|
"uid": 6,
|
||||||
"relPath": "../assets/raw/residential.png",
|
"relPath": "assets/raw/residential.png",
|
||||||
"embedAtlas": null,
|
"embedAtlas": null,
|
||||||
"pxWid": 1024,
|
"pxWid": 1024,
|
||||||
"pxHei": 1024,
|
"pxHei": 1024,
|
||||||
@ -292,7 +292,7 @@
|
|||||||
"__pxTotalOffsetX": 0,
|
"__pxTotalOffsetX": 0,
|
||||||
"__pxTotalOffsetY": 0,
|
"__pxTotalOffsetY": 0,
|
||||||
"__tilesetDefUid": 6,
|
"__tilesetDefUid": 6,
|
||||||
"__tilesetRelPath": "../assets/raw/residential.png",
|
"__tilesetRelPath": "assets/raw/residential.png",
|
||||||
"iid": "2baa2510-3740-11f0-80fd-75b2b5fa7dd7",
|
"iid": "2baa2510-3740-11f0-80fd-75b2b5fa7dd7",
|
||||||
"levelId": 0,
|
"levelId": 0,
|
||||||
"layerDefUid": 9,
|
"layerDefUid": 9,
|
||||||
@ -317,7 +317,7 @@
|
|||||||
"__pxTotalOffsetX": 0,
|
"__pxTotalOffsetX": 0,
|
||||||
"__pxTotalOffsetY": 0,
|
"__pxTotalOffsetY": 0,
|
||||||
"__tilesetDefUid": 1,
|
"__tilesetDefUid": 1,
|
||||||
"__tilesetRelPath": "../assets/processed/tilesets/sidewalk_128x128.png",
|
"__tilesetRelPath": "assets/processed/tilesets/sidewalk_128x128.png",
|
||||||
"iid": "c0f40ef0-3740-11f0-80fd-29ce8cc19ef6",
|
"iid": "c0f40ef0-3740-11f0-80fd-29ce8cc19ef6",
|
||||||
"levelId": 0,
|
"levelId": 0,
|
||||||
"layerDefUid": 2,
|
"layerDefUid": 2,
|
37
godot/test.ldtk.import
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="ldtk.import"
|
||||||
|
type="PackedScene"
|
||||||
|
uid="uid://bydclumuwqch8"
|
||||||
|
path="res://.godot/imported/test.ldtk-e10b9543a89b321d04f19d9114d464c5.scn"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
files=["res:///tilesets/tileset_1024px.res", "res:///tilesets/tileset_32px.res", "res:///levels/Level_0.scn", "res://.godot/imported/test.ldtk-e10b9543a89b321d04f19d9114d464c5.scn"]
|
||||||
|
|
||||||
|
source_file="res://test.ldtk"
|
||||||
|
dest_files=["res://.godot/imported/test.ldtk-e10b9543a89b321d04f19d9114d464c5.scn", "res:///tilesets/tileset_1024px.res", "res:///tilesets/tileset_32px.res", "res:///levels/Level_0.scn", "res://.godot/imported/test.ldtk-e10b9543a89b321d04f19d9114d464c5.scn"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
World=""
|
||||||
|
group_world_layers=false
|
||||||
|
Level=""
|
||||||
|
pack_levels=true
|
||||||
|
Layer=""
|
||||||
|
layers_always_visible=false
|
||||||
|
Tileset=""
|
||||||
|
tileset_custom_data=false
|
||||||
|
integer_grid_tilesets=false
|
||||||
|
atlas_texture_type=0
|
||||||
|
Entity=""
|
||||||
|
resolve_entityrefs=true
|
||||||
|
use_entity_placeholders=false
|
||||||
|
Post Import=""
|
||||||
|
tileset_post_import=""
|
||||||
|
entities_post_import=""
|
||||||
|
level_post_import=""
|
||||||
|
world_post_import=""
|
||||||
|
Debug=""
|
||||||
|
force_tileset_reimport=false
|
||||||
|
verbose_output=false
|
BIN
godot/tilesets/tileset_1024px.res
Normal file
BIN
godot/tilesets/tileset_32px.res
Normal file
4
justfile
@ -36,10 +36,10 @@ rip-youtube-audio URL:
|
|||||||
|
|
||||||
# Listen to the radio
|
# Listen to the radio
|
||||||
radio:
|
radio:
|
||||||
mpv --shuffle radio/
|
mpv --shuffle audio/vehicle_radio
|
||||||
|
|
||||||
# Run assets pipeline
|
# Run assets pipeline
|
||||||
process-assets:
|
process-assets:
|
||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
cd assets
|
cd godot/assets
|
||||||
sh pipeline.sh
|
sh pipeline.sh
|
||||||
|