└── addons
└── tile_bit_tools
├── LICENSE
├── README.md
├── controls
├── bit_data_draw
│ ├── bit_data_draw.gd
│ ├── bit_data_draw_node.gd
│ └── bit_data_draw_node.tscn
├── icons
│ ├── tile_bit_tools_16.svg
│ └── tile_bit_tools_16.svg.import
├── shared
│ ├── icon_button.gd
│ ├── inspector_section_button.gd
│ ├── inspector_section_button.tscn
│ ├── template_info_list.gd
│ └── template_info_list.tscn
├── tbt_plugin_control
│ ├── popups
│ │ ├── edit_template_dialog.gd
│ │ ├── edit_template_dialog.tscn
│ │ ├── save_template_dialog.gd
│ │ ├── save_template_dialog.tscn
│ │ └── template_dialog.gd
│ ├── tbt_plugin_control.gd
│ ├── tbt_plugin_control.tscn
│ ├── template_manager.gd
│ ├── theme_updater.gd
│ └── tiles_manager.gd
├── tiles_inspector
│ ├── template_section
│ │ ├── selected_tag.gd
│ │ ├── selected_tag.tscn
│ │ ├── selected_tag_stylebox.tres
│ │ ├── template_info_panel.gd
│ │ ├── template_info_panel.tscn
│ │ ├── templates_section.gd
│ │ ├── templates_section.tscn
│ │ ├── terrain_picker.gd
│ │ └── terrain_picker.tscn
│ ├── tiles_inspector.gd
│ ├── tiles_inspector.tscn
│ └── tool_buttons
│ │ ├── tool_buttons.gd
│ │ └── tool_buttons.tscn
└── tiles_preview
│ ├── terrain_opacity_slider.gd
│ ├── tiles_preview.gd
│ ├── tiles_preview.tscn
│ ├── tiles_view.gd
│ └── tiles_view.tscn
├── core
├── bit_data.gd
├── context.gd
├── editor_bit_data.gd
├── globals.gd
├── icons.gd
├── output.gd
├── template_bit_data.gd
├── template_loader.gd
├── template_tag_data.gd
└── texts.gd
├── examples
├── godot3_2x2
│ ├── ABOUT.txt
│ ├── godot3_2x2.png
│ └── godot3_2x2.png.import
├── godot3_3x3_16_tiles
│ ├── ABOUT.txt
│ ├── godot3_3x3_16_tiles.png
│ └── godot3_3x3_16_tiles.png.import
├── godot3_3x3_minimal
│ ├── ABOUT.txt
│ ├── godot3_3x3_minimal.png
│ └── godot3_3x3_minimal.png.import
├── simple_tilesets
│ ├── ABOUT.txt
│ ├── simple_9_and_4.png
│ ├── simple_9_and_4.png.import
│ ├── simple_9_and_9.png
│ └── simple_9_and_9.png.import
├── tilesetter_blob
│ ├── ABOUT.txt
│ ├── tilesetter_blob.png
│ └── tilesetter_blob.png.import
├── tilesetter_wang
│ ├── ABOUT.txt
│ ├── tilesetter_wang.png
│ └── tilesetter_wang.png.import
└── tilesetter_wang_3_terrains
│ ├── ABOUT.txt
│ ├── tilesetter_wang_3_terrain.png
│ └── tilesetter_wang_3_terrain.png.import
├── inspector_plugin.gd
├── plugin.cfg
├── plugin.gd
└── templates
├── godot3_2x2.tres
├── godot3_3x3_16_tiles.tres
├── godot3_3x3_minimal.tres
├── simple_4-tile_(inside_corners).tres
├── simple_9-tile_(inside_corners).tres
├── simple_9-tile_(outside_corners).tres
├── tilepipe2_256_tile_16x16.tres
├── tilepipe2_256_tile_32x8.tres
├── tilesetter_blob.tres
├── tilesetter_wang.tres
├── tilesetter_wang_3-terrain.tres
└── tilesetter_wang_3-terrain_transitions.tres
/addons/tile_bit_tools/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 dandeliondino
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | TileBitTools is a Godot 4 plugin for autotile templates and terrain bit editing.
4 |
5 | The terrain system in Godot 4 is powerful and extensible, and has a lot of untapped potential. The goal of this plugin is to enable fast iterations, to assist in migrating from Godot 3, and to speed up the learning process for new users.
6 |
7 | *Click on the screenshots below to expand*
8 |
9 | [](https://github.com/dandeliondino/tile_bit_tools/blob/main/assets/tutorials/apply_template.gif)
10 | [](https://github.com/dandeliondino/tile_bit_tools/blob/main/assets/tips_and_examples.png)
11 | [](https://github.com/dandeliondino/tile_bit_tools/blob/main/assets/save_custom_templates.png)
12 | [](https://github.com/dandeliondino/tile_bit_tools/blob/main/assets/terrain_transitions.png)
13 |
14 | ## Features
15 | - **Built-in autotile templates for all three Godot 4 terrain modes**
16 | - **3x3 minimal**, **3x3 16-tile** and **2x2** templates from Godot 3 documentation.
17 | - **Blob**, **Wang** and **Wang 3-terrain** templates to match Tilesetter's default export.
18 | - **Simple 9- and 4-tile** templates. These are modular corner-mode templates that match tile configurations commonly found in spritesheets.
19 | - **Tips and example tiles for all built-in templates**
20 | - **Terrain bit editing buttons** to make changes like 'Fill' and 'Clear' to multiple tiles or peering bits in one click
21 | - **Custom user template creation**
22 | - Save new templates from the terrain peering bits on existing tiles. Statistics and previews are automatically generated.
23 | - Use as a quick way to copy-paste terrain bits.
24 | - Or use to save complex, reusable templates to a shared directory accessible to all projects.
25 | - **Options in Project Settings**
26 | - Customize the template bit colors (default colors are from the color-blind-friendly 'bright' scheme from [Paul Tol](https://personal.sron.nl/~pault/))
27 | - Customize which messages appear in the Output log
28 | - Customize the template save folder location
29 |
30 |
31 | ## Limitations
32 | - Even using Godot 3 autotile templates, tile placement will not work exactly the same as it did in Godot 3, as the core matching algorithm is different
33 | - Hex and isometric tiles are not supported
34 | - Alternative tiles are not supported
35 |
36 |
37 | ## How to use
38 | *Please back up your project before making any changes. Godot 4 is still new, and TileBitTools is even newer, so unexpected behavior may occur.*
39 |
40 | TileBitTools is located in the bottom TileSet editor, in the Select tab. To access any of its functions, the first step is to select tiles.
41 |
42 | See the following pages for detailed directions:
43 |
44 | - [Installation](https://github.com/dandeliondino/tile_bit_tools/wiki/1.-Installation)
45 | - [Bulk terrain editing buttons](https://github.com/dandeliondino/tile_bit_tools/wiki/2.-Bulk-Terrain-Editing-Buttons)
46 | - Templates
47 | - [Applying templates](https://github.com/dandeliondino/tile_bit_tools/wiki/3.1-Applying-Templates)
48 | - [Saving templates](https://github.com/dandeliondino/tile_bit_tools/wiki/3.2-Saving-Templates) - ***If you are saving a significant amount of data in your templates, please make sure they are being backed up and/or added to a version control system. There are rare cases of [template data being deleted on editor startup](https://github.com/dandeliondino/tile_bit_tools/issues/49).***
49 | - [Editing templates](https://github.com/dandeliondino/tile_bit_tools/wiki/3.3-Editing-Templates)
50 | - [Warning regarding resource files](https://github.com/dandeliondino/tile_bit_tools/wiki/X.-Warning-Regarding-Resource-Files)
51 |
52 |
53 | ## Feedback
54 | Find a bug? -> [Known Bugs and Reports](https://github.com/dandeliondino/tile_bit_tools/issues/2)
55 |
56 | Have an autotile template that should be built-in? -> [Add More Built-in Terrain Templates](https://github.com/dandeliondino/tile_bit_tools/issues/4)
57 |
58 | Have an idea for a new feature? -> [Future Directions and Suggestions](https://github.com/dandeliondino/tile_bit_tools/issues/3)
59 |
60 |
61 | ## Credits
62 | Concept inspired by [Wareya's Godot Tile Setup Helper](https://github.com/wareya/godot-tile-setup-helper) for Godot 3.5
63 |
64 | Huge thanks to [YuriSizov's Godot Editor Theme Explorer](https://github.com/YuriSizov/godot-editor-theme-explorer) and [Zylann's Editor Debugger](https://github.com/Zylann/godot_editor_debugger_plugin)
65 |
66 | The example tilesets are adapted from [Kenney's Pixel Shmup](https://www.kenney.nl/assets/pixel-shmup) ([License: CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/))
67 |
68 | The TileBitTools icon is modified from [Kenney's Game Icons](https://www.kenney.nl/assets/game-icons) ([License: CCO 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/))
69 |
70 | The fonts in the header and images are [Lilita One](https://fonts.google.com/specimen/Lilita+One) (SIL Open Font License 1.1) and [Fira Code](https://github.com/tonsky/FiraCode) (SIL Open Font License 1.1).
71 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/bit_data_draw/bit_data_draw.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Control
3 |
4 |
5 | enum RectPoint {
6 | TOP_LEFT,
7 | TOP_CENTER,
8 | TOP_RIGHT,
9 | RIGHT_CENTER,
10 | BOTTOM_RIGHT,
11 | BOTTOM_CENTER,
12 | BOTTOM_LEFT,
13 | LEFT_CENTER,
14 | }
15 |
16 | var bit_shapes := {
17 | TileSet.TERRAIN_MODE_MATCH_SIDES: {
18 | BitData.TerrainBits.TOP_SIDE:
19 | func(rect : Rect2): return [
20 | _get_rect_point(rect, RectPoint.TOP_LEFT),
21 | _get_rect_point(rect, RectPoint.TOP_RIGHT),
22 | _get_center_rect_point(rect, RectPoint.TOP_RIGHT),
23 | _get_center_rect_point(rect, RectPoint.TOP_LEFT),
24 | ],
25 | BitData.TerrainBits.RIGHT_SIDE:
26 | func(rect : Rect2): return [
27 | _get_rect_point(rect, RectPoint.TOP_RIGHT),
28 | _get_rect_point(rect, RectPoint.BOTTOM_RIGHT),
29 | _get_center_rect_point(rect, RectPoint.BOTTOM_RIGHT),
30 | _get_center_rect_point(rect, RectPoint.TOP_RIGHT),
31 | ],
32 | BitData.TerrainBits.BOTTOM_SIDE:
33 | func(rect : Rect2): return [
34 | _get_rect_point(rect, RectPoint.BOTTOM_RIGHT),
35 | _get_rect_point(rect, RectPoint.BOTTOM_LEFT),
36 | _get_center_rect_point(rect, RectPoint.BOTTOM_LEFT),
37 | _get_center_rect_point(rect, RectPoint.BOTTOM_RIGHT),
38 | ],
39 | BitData.TerrainBits.LEFT_SIDE:
40 | func(rect : Rect2): return [
41 | _get_rect_point(rect, RectPoint.BOTTOM_LEFT),
42 | _get_rect_point(rect, RectPoint.TOP_LEFT),
43 | _get_center_rect_point(rect, RectPoint.TOP_LEFT),
44 | _get_center_rect_point(rect, RectPoint.BOTTOM_LEFT),
45 | ],
46 | BitData.TerrainBits.CENTER:
47 | func(rect : Rect2): return _get_center_rect(rect), #.grow(-3),
48 | },
49 | TileSet.TERRAIN_MODE_MATCH_CORNERS: {
50 | BitData.TerrainBits.TOP_LEFT_CORNER:
51 | func(rect : Rect2): return [
52 | _get_rect_point(rect, RectPoint.LEFT_CENTER),
53 | _get_rect_point(rect, RectPoint.TOP_LEFT),
54 | _get_rect_point(rect, RectPoint.TOP_CENTER),
55 | _get_center_rect_point(rect, RectPoint.TOP_CENTER),
56 | _get_center_rect_point(rect, RectPoint.TOP_LEFT),
57 | _get_center_rect_point(rect, RectPoint.LEFT_CENTER),
58 | ],
59 | BitData.TerrainBits.TOP_RIGHT_CORNER:
60 | func(rect : Rect2): return [
61 | _get_rect_point(rect, RectPoint.TOP_CENTER),
62 | _get_rect_point(rect, RectPoint.TOP_RIGHT),
63 | _get_rect_point(rect, RectPoint.RIGHT_CENTER),
64 | _get_center_rect_point(rect, RectPoint.RIGHT_CENTER),
65 | _get_center_rect_point(rect, RectPoint.TOP_RIGHT),
66 | _get_center_rect_point(rect, RectPoint.TOP_CENTER),
67 | ],
68 | BitData.TerrainBits.CENTER:
69 | func(rect : Rect2): return _get_center_rect(rect), #.grow(-3),
70 | # func(rect : Rect2):
71 | # var center_rect := _get_center_rect(rect).grow(-1)
72 | # var radius := center_rect.size.x/2
73 | # return {"position": center_rect.get_center(), "radius": radius},
74 | BitData.TerrainBits.BOTTOM_RIGHT_CORNER:
75 | func(rect : Rect2): return [
76 | _get_rect_point(rect, RectPoint.RIGHT_CENTER),
77 | _get_rect_point(rect, RectPoint.BOTTOM_RIGHT),
78 | _get_rect_point(rect, RectPoint.BOTTOM_CENTER),
79 | _get_center_rect_point(rect, RectPoint.BOTTOM_CENTER),
80 | _get_center_rect_point(rect, RectPoint.BOTTOM_RIGHT),
81 | _get_center_rect_point(rect, RectPoint.RIGHT_CENTER),
82 | ],
83 | BitData.TerrainBits.BOTTOM_LEFT_CORNER:
84 | func(rect : Rect2): return [
85 | _get_rect_point(rect, RectPoint.BOTTOM_CENTER),
86 | _get_rect_point(rect, RectPoint.BOTTOM_LEFT),
87 | _get_rect_point(rect, RectPoint.LEFT_CENTER),
88 | _get_center_rect_point(rect, RectPoint.LEFT_CENTER),
89 | _get_center_rect_point(rect, RectPoint.BOTTOM_LEFT),
90 | _get_center_rect_point(rect, RectPoint.BOTTOM_CENTER),
91 | ],
92 | },
93 | TileSet.TERRAIN_MODE_MATCH_CORNERS_AND_SIDES: {
94 | BitData.TerrainBits.TOP_LEFT_CORNER:
95 | func(rect : Rect2): return Rect2(
96 | rect.position,
97 | _get_bit_size(rect)
98 | ),
99 | BitData.TerrainBits.TOP_SIDE:
100 | func(rect : Rect2): return Rect2(
101 | Vector2(rect.position.x + rect.size.x/3, rect.position.y),
102 | _get_bit_size(rect)
103 | ),
104 | BitData.TerrainBits.TOP_RIGHT_CORNER:
105 | func(rect : Rect2): return Rect2(
106 | Vector2(rect.position.x + 2*rect.size.x/3, rect.position.y),
107 | _get_bit_size(rect)
108 | ),
109 | BitData.TerrainBits.LEFT_SIDE:
110 | func(rect : Rect2): return Rect2(
111 | Vector2(rect.position.x, rect.position.y + rect.size.y/3),
112 | _get_bit_size(rect)
113 | ),
114 | BitData.TerrainBits.CENTER:
115 | func(rect : Rect2): return Rect2(
116 | Vector2(rect.position.x + rect.size.x/3, rect.position.y + rect.size.y/3),
117 | _get_bit_size(rect)
118 | ),
119 | BitData.TerrainBits.RIGHT_SIDE:
120 | func(rect : Rect2): return Rect2(
121 | Vector2(rect.position.x + 2*rect.size.x/3, rect.position.y + rect.size.y/3),
122 | _get_bit_size(rect)
123 | ),
124 | BitData.TerrainBits.BOTTOM_LEFT_CORNER:
125 | func(rect : Rect2): return Rect2(
126 | Vector2(rect.position.x, rect.position.y + 2*rect.size.y/3),
127 | _get_bit_size(rect)
128 | ),
129 | BitData.TerrainBits.BOTTOM_SIDE:
130 | func(rect : Rect2): return Rect2(
131 | Vector2(rect.position.x + rect.size.x/3, rect.position.y + 2*rect.size.y/3),
132 | _get_bit_size(rect)
133 | ),
134 | BitData.TerrainBits.BOTTOM_RIGHT_CORNER:
135 | func(rect : Rect2): return Rect2(
136 | Vector2(rect.position.x + 2*rect.size.x/3, rect.position.y + 2*rect.size.y/3),
137 | _get_bit_size(rect)
138 | ),
139 | }
140 | }
141 |
142 | const BitData := preload("res://addons/tile_bit_tools/core/bit_data.gd")
143 |
144 | var bit_data : BitData :
145 | set(value):
146 | bit_data = value
147 | _update_properties()
148 | queue_redraw()
149 |
150 | var draw_size : Vector2i :
151 | set(value):
152 | draw_size = value
153 | _update_properties()
154 | queue_redraw()
155 |
156 | var spacing := 5
157 |
158 | var atlas_rect : Rect2i
159 | var atlas_offset : Vector2i
160 | var tile_size : Vector2
161 |
162 | var terrain_set : int
163 | var terrain_mode : TileSet.TerrainMode
164 | var terrain_colors := {}
165 |
166 |
167 |
168 |
169 | func _update_properties() -> void:
170 | if !bit_data or draw_size == Vector2i.ZERO:
171 | return
172 |
173 | atlas_rect = bit_data.get_atlas_rect()
174 |
175 | # changing to floats avoids rounding errors/gaps
176 | tile_size = Vector2(draw_size) / Vector2(atlas_rect.size)
177 | atlas_offset = atlas_rect.position
178 |
179 | terrain_set = bit_data.terrain_set
180 | terrain_mode = bit_data.terrain_mode
181 | terrain_colors = bit_data.get_terrain_colors_dict()
182 |
183 |
184 |
185 | func _draw() -> void:
186 | if !bit_data or draw_size == Vector2i.ZERO:
187 | return
188 |
189 | for coords in bit_data.get_coordinates_list():
190 | var adj_coords : Vector2 = coords - atlas_offset
191 | var tile_pos := adj_coords * tile_size
192 | var tile_rect := Rect2(tile_pos, tile_size).grow(-spacing)
193 |
194 | for bit in bit_data.get_terrain_bits_list(true):
195 | var terrain_index := bit_data.get_bit_terrain(coords, bit)
196 | var color = terrain_colors[terrain_index]
197 | var shape = bit_shapes[terrain_mode][bit].call(tile_rect)
198 |
199 | if typeof(shape) == TYPE_ARRAY:
200 | draw_colored_polygon(shape, color)
201 | elif typeof(shape) == TYPE_RECT2:
202 | draw_rect(shape, color)
203 | elif typeof(shape) == TYPE_DICTIONARY:
204 | draw_circle(shape.position, shape.radius, color)
205 |
206 |
207 |
208 | func _get_rect_point(rect : Rect2, point : RectPoint) -> Vector2:
209 | match point:
210 | RectPoint.TOP_LEFT:
211 | return rect.position
212 | RectPoint.TOP_CENTER:
213 | return Vector2(rect.get_center().x, rect.position.y)
214 | RectPoint.TOP_RIGHT:
215 | return Vector2(rect.end.x, rect.position.y)
216 | RectPoint.RIGHT_CENTER:
217 | return Vector2(rect.end.x, rect.get_center().y)
218 | RectPoint.BOTTOM_RIGHT:
219 | return rect.end
220 | RectPoint.BOTTOM_CENTER:
221 | return Vector2(rect.get_center().x, rect.end.y)
222 | RectPoint.BOTTOM_LEFT:
223 | return Vector2(rect.position.x, rect.end.y)
224 | RectPoint.LEFT_CENTER:
225 | return Vector2(rect.position.x, rect.get_center().y)
226 | return Vector2.ZERO
227 |
228 | func _get_center_rect_point(rect : Rect2, point : RectPoint) -> Vector2:
229 | return _get_rect_point(_get_center_rect(rect), point)
230 |
231 | func _get_center_rect(rect : Rect2) -> Rect2:
232 | return Rect2(rect.position + rect.size/3.0, rect.size/3.0)
233 |
234 | func _get_bit_size(rect : Rect2) -> Vector2:
235 | return rect.size/3.0
236 |
237 |
238 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/bit_data_draw/bit_data_draw_node.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends SubViewport
3 |
4 | const DEFAULT_TILE_SIZE := 16
5 |
6 | const BitData := preload("res://addons/tile_bit_tools/core/bit_data.gd")
7 |
8 | var drawing_size := Vector2i.ZERO
9 | var tile_size := 0
10 | var tile_spacing := 0
11 |
12 | @onready var bit_data_draw: Control = %BitDataDraw
13 |
14 |
15 | func get_bit_texture(bit_data : BitData) -> Texture2D:
16 | var tex_size := get_drawing_size(bit_data)
17 | size = tex_size
18 | bit_data_draw.draw_size = tex_size
19 | bit_data_draw.spacing = tile_spacing
20 | bit_data_draw.bit_data = bit_data
21 | render_target_update_mode = SubViewport.UPDATE_ONCE
22 | await RenderingServer.frame_post_draw
23 | var image := get_texture().get_image()
24 | return ImageTexture.create_from_image(image)
25 |
26 |
27 | func get_drawing_size(bit_data : BitData) -> Vector2i:
28 | if drawing_size != Vector2i.ZERO:
29 | return drawing_size
30 | var calc_tile_size : int = tile_size if tile_size > 0 else DEFAULT_TILE_SIZE
31 | return bit_data.get_atlas_rect().size * calc_tile_size
32 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/bit_data_draw/bit_data_draw_node.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/controls/bit_data_draw/bit_data_draw.gd" id="1_2rdsg"]
4 | [ext_resource type="Script" path="res://addons/tile_bit_tools/controls/bit_data_draw/bit_data_draw_node.gd" id="1_jpipc"]
5 |
6 | [node name="DrawViewport" type="SubViewport"]
7 | disable_3d = true
8 | gui_disable_input = true
9 | gui_snap_controls_to_pixels = false
10 | size = Vector2i(64, 96)
11 | render_target_update_mode = 1
12 | script = ExtResource("1_jpipc")
13 |
14 | [node name="BitDataDraw" type="Control" parent="."]
15 | unique_name_in_owner = true
16 | layout_mode = 3
17 | anchors_preset = 0
18 | offset_right = 40.0
19 | offset_bottom = 40.0
20 | script = ExtResource("1_2rdsg")
21 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/icons/tile_bit_tools_16.svg:
--------------------------------------------------------------------------------
1 |
2 |
96 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/icons/tile_bit_tools_16.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://cheop6l3022pn"
6 | path="res://.godot/imported/tile_bit_tools_16.svg-d3d960897b553a49b1b4c28f73a2a661.ctex"
7 | metadata={
8 | "editor_dark_theme": true,
9 | "editor_scale": 2.0,
10 | "has_editor_variant": true,
11 | "vram_texture": false
12 | }
13 |
14 | [deps]
15 |
16 | source_file="res://addons/tile_bit_tools/controls/icons/tile_bit_tools_16.svg"
17 | dest_files=["res://.godot/imported/tile_bit_tools_16.svg-d3d960897b553a49b1b4c28f73a2a661.ctex"]
18 |
19 | [params]
20 |
21 | compress/mode=0
22 | compress/high_quality=false
23 | compress/lossy_quality=0.7
24 | compress/hdr_compression=1
25 | compress/normal_map=0
26 | compress/channel_pack=0
27 | mipmaps/generate=false
28 | mipmaps/limit=-1
29 | roughness/mode=0
30 | roughness/src_normal=""
31 | process/fix_alpha_border=true
32 | process/premult_alpha=false
33 | process/normal_map_invert_y=false
34 | process/hdr_as_srgb=false
35 | process/hdr_clamp_exposure=false
36 | process/size_limit=0
37 | detect_3d/compress_to=1
38 | svg/scale=1.0
39 | editor/scale_with_editor_scale=true
40 | editor/convert_colors_with_editor_theme=true
41 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/shared/icon_button.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Button
3 |
4 |
5 | const TBTPlugin := preload("res://addons/tile_bit_tools/controls/tbt_plugin_control/tbt_plugin_control.gd")
6 |
7 | ## property name from icons.gd
8 | @export var icon_name : String
9 |
10 | ## string of icon name from editor theme
11 | @export var editor_name : String
12 |
13 | var tbt : TBTPlugin
14 |
15 | func _tbt_ready() -> void:
16 | if icon_name != "":
17 | icon = tbt.icons.get_icon_by_name(icon_name)
18 | elif editor_name != "":
19 | icon = tbt.icons.get_icon_by_editor_name(editor_name)
20 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/shared/inspector_section_button.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Button
3 |
4 |
5 | const LABEL_MARGIN_ADJUST := -6
6 |
7 | const TBTPlugin := preload("res://addons/tile_bit_tools/controls/tbt_plugin_control/tbt_plugin_control.gd")
8 |
9 |
10 | @export var label_text := "Inspector Section" :
11 | set(value):
12 | label_text = value
13 | if is_instance_valid(label):
14 | _update_label_text()
15 |
16 | @export var expand_container_path : NodePath
17 |
18 | var tbt : TBTPlugin
19 |
20 | var expand_container : Control
21 |
22 | var icon_expanded
23 | var icon_collapsed
24 |
25 | var normal_color : Color
26 | var hover_color : Color
27 |
28 | @onready var background_rect: ColorRect = %BackgroundRect
29 | @onready var arrow_rect: TextureRect = %ArrowRect
30 | @onready var label: Label = %Label
31 | @onready var arrow_margin_container: MarginContainer = $ArrowMarginContainer
32 | @onready var label_margin_container: MarginContainer = $LabelMarginContainer
33 |
34 |
35 |
36 | func _ready() -> void:
37 | _update_label_text()
38 |
39 |
40 | func _tbt_ready() -> void:
41 | expand_container = get_node_or_null(expand_container_path)
42 | if expand_container == null:
43 | tbt.output.error("Expand container null")
44 | return
45 |
46 | icon_expanded = tbt.icons.get_icon(tbt.icons.ARROW_EXPANDED)
47 | icon_collapsed = tbt.icons.get_icon(tbt.icons.ARROW_COLLAPSED)
48 | _toggle_expanded(false)
49 |
50 | normal_color = tbt.base_control.get_theme_color("prop_subsection", "Editor")
51 | normal_color.a = normal_color.a * 0.4
52 | hover_color = normal_color.lightened(0.2)
53 | _toggle_hover(false)
54 |
55 | var left_margin = round(2 * tbt.interface.get_editor_scale())
56 | arrow_margin_container.set("theme_override_constants/margin_left", left_margin)
57 |
58 | var label_margin = left_margin + icon_expanded.get_size().x + LABEL_MARGIN_ADJUST
59 | label_margin_container.set("theme_override_constants/margin_left", label_margin)
60 |
61 |
62 |
63 | func _update_label_text() -> void:
64 | label.text = label_text
65 |
66 |
67 | func _toggle_expanded(value : bool) -> void:
68 | if value:
69 | if is_instance_valid(expand_container):
70 | expand_container.show()
71 | arrow_rect.texture = icon_expanded
72 | else:
73 | if is_instance_valid(expand_container):
74 | expand_container.hide()
75 | arrow_rect.texture = icon_collapsed
76 |
77 |
78 | func _toggle_hover(value : bool) -> void:
79 | if value:
80 | background_rect.color = hover_color
81 | else:
82 | background_rect.color = normal_color
83 |
84 |
85 | func _on_mouse_entered() -> void:
86 | _toggle_hover(true)
87 |
88 |
89 | func _on_mouse_exited() -> void:
90 | _toggle_hover(false)
91 |
92 |
93 | func _on_toggled(p_button_pressed: bool) -> void:
94 | _toggle_expanded(p_button_pressed)
95 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/shared/inspector_section_button.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=7 format=3 uid="uid://dkmdolef567aa"]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/controls/shared/inspector_section_button.gd" id="1_nbqv8"]
4 |
5 | [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_mwoex"]
6 |
7 | [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_kmslc"]
8 |
9 | [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_e3ufk"]
10 |
11 | [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_lkr7c"]
12 |
13 | [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_bxs77"]
14 |
15 | [node name="InspectorSectionButton" type="Button" groups=["TBTSectionButton"]]
16 | custom_minimum_size = Vector2(0, 34)
17 | anchors_preset = 10
18 | anchor_right = 1.0
19 | grow_horizontal = 2
20 | theme_override_styles/normal = SubResource("StyleBoxEmpty_mwoex")
21 | theme_override_styles/hover = SubResource("StyleBoxEmpty_kmslc")
22 | theme_override_styles/pressed = SubResource("StyleBoxEmpty_e3ufk")
23 | theme_override_styles/disabled = SubResource("StyleBoxEmpty_lkr7c")
24 | theme_override_styles/focus = SubResource("StyleBoxEmpty_bxs77")
25 | toggle_mode = true
26 | flat = true
27 | script = ExtResource("1_nbqv8")
28 |
29 | [node name="BackgroundRect" type="ColorRect" parent="."]
30 | unique_name_in_owner = true
31 | layout_mode = 1
32 | anchors_preset = 15
33 | anchor_right = 1.0
34 | anchor_bottom = 1.0
35 | grow_horizontal = 2
36 | grow_vertical = 2
37 | color = Color(0.47451, 0.47451, 0.47451, 1)
38 |
39 | [node name="ArrowMarginContainer" type="MarginContainer" parent="."]
40 | layout_mode = 1
41 | anchors_preset = 15
42 | anchor_right = 1.0
43 | anchor_bottom = 1.0
44 | grow_horizontal = 2
45 | grow_vertical = 2
46 |
47 | [node name="ArrowRect" type="TextureRect" parent="ArrowMarginContainer"]
48 | unique_name_in_owner = true
49 | layout_mode = 2
50 | size_flags_horizontal = 0
51 | size_flags_vertical = 4
52 | stretch_mode = 2
53 |
54 | [node name="LabelMarginContainer" type="MarginContainer" parent="."]
55 | layout_mode = 1
56 | anchors_preset = 15
57 | anchor_right = 1.0
58 | anchor_bottom = 1.0
59 | grow_horizontal = 2
60 | grow_vertical = 2
61 |
62 | [node name="Label" type="Label" parent="LabelMarginContainer" groups=["TBTSectionLabel"]]
63 | unique_name_in_owner = true
64 | layout_mode = 2
65 | text = "Inspector Section"
66 |
67 | [connection signal="mouse_entered" from="." to="." method="_on_mouse_entered"]
68 | [connection signal="mouse_exited" from="." to="." method="_on_mouse_exited"]
69 | [connection signal="toggled" from="." to="." method="_on_toggled"]
70 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/shared/template_info_list.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends ItemList
3 |
4 | const TBTPlugin := preload("res://addons/tile_bit_tools/controls/tbt_plugin_control/tbt_plugin_control.gd")
5 |
6 | var tbt : TBTPlugin
7 |
8 | var show_custom_tags := true
9 |
10 | func update(template_bit_data : TBTPlugin.TemplateBitData) -> void:
11 | var item_list := []
12 | item_list.append({"text": "Tiles: %s" % template_bit_data.get_tile_count()})
13 | item_list.append({"text": "Terrains: %s" % template_bit_data.get_terrain_count()})
14 |
15 | var template_tag_data := preload("res://addons/tile_bit_tools/core/template_tag_data.gd").new()
16 | for tag in template_tag_data.tags.values():
17 | if tag.get_test_result(template_bit_data):
18 | item_list.append({"text": tag.text, "icon": tag.get_icon(tbt.base_control)})
19 |
20 | if show_custom_tags:
21 | for custom_tag_text in template_bit_data.get_custom_tags():
22 | var tag := template_tag_data.TemplateTag.new(custom_tag_text)
23 | item_list.append({"text": tag.text, "icon": tag.get_icon(tbt.base_control)})
24 |
25 | clear()
26 | for item in item_list:
27 | if item.has("icon"):
28 | var _err := add_item(item.text, item.icon, false)
29 | else:
30 | var _err := add_item(item.text, null, false)
31 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/shared/template_info_list.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://bscknm10ko78t"]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/controls/shared/template_info_list.gd" id="1_6r84n"]
4 |
5 | [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_n7nl4"]
6 |
7 | [node name="TemplateInfoList" type="ItemList"]
8 | size_flags_horizontal = 3
9 | focus_mode = 0
10 | mouse_filter = 2
11 | theme_override_styles/panel = SubResource("StyleBoxEmpty_n7nl4")
12 | auto_height = true
13 | item_count = 2
14 | item_0/text = "Tiles: 15"
15 | item_0/selectable = false
16 | item_1/text = "Terrains: 2"
17 | item_1/selectable = false
18 | script = ExtResource("1_6r84n")
19 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tbt_plugin_control/popups/edit_template_dialog.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends "res://addons/tile_bit_tools/controls/tbt_plugin_control/popups/template_dialog.gd"
3 |
4 |
5 | var save_path : String
6 |
7 | @onready var folder_label: Label = %FolderLabel
8 |
9 |
10 |
11 | func _setup_connections() -> void:
12 | var _err := tbt.edit_template_requested.connect(_on_edit_template_requested)
13 |
14 |
15 |
16 | func _setup_edit_dialog(p_template_bit_data : TBTPlugin.TemplateBitData) -> void:
17 | template_bit_data = p_template_bit_data
18 | save_path = template_bit_data.resource_path
19 |
20 | show_dialog()
21 |
22 |
23 |
24 | # overriden
25 | func _setup_initial_values() -> void:
26 | name_edit.text = template_bit_data.template_name
27 | description_edit.text = template_bit_data.template_description
28 | tags_edit.text = _custom_tags_to_string()
29 | _update_folder_label()
30 |
31 |
32 | # unable to get selecting option button item to work...
33 | # using label instead
34 | func _update_folder_label() -> void:
35 | var path = save_path.rsplit("/", true, 1)[0] + "/"
36 | for i in range(tbt.template_manager.template_folder_paths.size()):
37 | var folder_path : Dictionary = tbt.template_manager.template_folder_paths[i]
38 | if path == folder_path.path:
39 | folder_label.text = folder_path.name
40 | folder_label.tooltip_text = folder_path.tooltip + "\n" + folder_path.path
41 | return
42 | folder_label.text = path # if cannot find saved path, list path itself
43 | folder_label.tooltip_text = ""
44 |
45 |
46 |
47 | func _custom_tags_to_string() -> String:
48 | return ", ".join(template_bit_data._custom_tags)
49 |
50 |
51 | # overriden
52 | func _get_save_path(_valid_only := true) -> String:
53 | return save_path
54 |
55 |
56 |
57 |
58 | func _on_edit_template_requested(p_template_bit_data : TBTPlugin.TemplateBitData) -> void:
59 | if p_template_bit_data != null:
60 | _setup_edit_dialog(p_template_bit_data)
61 | else:
62 | tbt.output.warning("Edit requested without bit data")
63 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tbt_plugin_control/popups/edit_template_dialog.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://cyxr6y64lkue6"]
2 |
3 | [ext_resource type="PackedScene" uid="uid://job5gqt1xbrh" path="res://addons/tile_bit_tools/controls/tbt_plugin_control/popups/save_template_dialog.tscn" id="1_5jw1t"]
4 | [ext_resource type="Script" path="res://addons/tile_bit_tools/controls/tbt_plugin_control/popups/edit_template_dialog.gd" id="2_bgxlq"]
5 |
6 | [node name="EditTemplateDialog" instance=ExtResource("1_5jw1t")]
7 | title = "Edit Terrain Template"
8 | visible = false
9 | script = ExtResource("2_bgxlq")
10 | metadata/_edit_pinned_properties_ = [&"title"]
11 |
12 | [node name="FolderLabel" type="Label" parent="BackgroundPanel/MarginContainer/VBoxContainer/ForegroundPanel/MarginContainer/VBoxContainer/BottomPanel/MarginContainer/VBoxContainer/HBoxContainer6" index="1" groups=["TBTSubPropertyLabel"]]
13 | unique_name_in_owner = true
14 | layout_mode = 2
15 | size_flags_horizontal = 3
16 | size_flags_stretch_ratio = 2.0
17 | mouse_filter = 0
18 | text = "(save path)"
19 |
20 | [node name="FolderOptionButton" parent="BackgroundPanel/MarginContainer/VBoxContainer/ForegroundPanel/MarginContainer/VBoxContainer/BottomPanel/MarginContainer/VBoxContainer/HBoxContainer6" index="2"]
21 | visible = false
22 | metadata/_edit_pinned_properties_ = [&"visible"]
23 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tbt_plugin_control/popups/save_template_dialog.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends "res://addons/tile_bit_tools/controls/tbt_plugin_control/popups/template_dialog.gd"
3 |
4 |
5 |
6 |
7 |
8 | func _setup_connections() -> void:
9 | var _err := tbt.save_template_requested.connect(_on_save_template_requested)
10 |
11 |
12 | func _setup_save_dialog() -> void:
13 | template_bit_data = TBTPlugin.TemplateBitData.new()
14 |
15 | var result := template_bit_data.load_editor_bit_data(tbt.context.bit_data)
16 | if result != OK:
17 | tbt.output.user("Cannot create template from editor data", result)
18 | # TODO: message_box_requested not implemented
19 | # tbt.message_box_requested.emit("Cannot create template from editor data (ERR %s)" % result)
20 | hide()
21 |
22 | show_dialog()
23 |
24 |
25 |
26 |
27 |
28 | # overriden
29 | func _setup_initial_values() -> void:
30 | name_edit.text = DEFAULT_TEMPLATE_NAME
31 | description_edit.text = DEFAULT_TEMPLATE_DESCRIPTION
32 | tags_edit.text = DEFAULT_TEMPLATE_TAGS
33 |
34 |
35 |
36 | # overriden
37 | func _get_save_path(_valid_only := true) -> String:
38 | var dir := _get_save_dir()
39 | var file_name := _get_file_name(dir)
40 | var path : String = dir.get_current_dir() + "/" + file_name
41 |
42 | if !path.is_absolute_path():
43 | tbt.output.error("Unable to get valid save path: %s" % path)
44 | return ""
45 |
46 | return path
47 |
48 |
49 | func _get_save_dir() -> DirAccess:
50 | var folder_id := folder_option_button.get_selected_id()
51 | var path : String = tbt.template_manager.template_folder_paths[folder_id].path
52 | return DirAccess.open(path)
53 |
54 |
55 | func _get_file_name(dir : DirAccess) -> String:
56 | var template_name := name_edit.text
57 | if template_name == "":
58 | template_name = DEFAULT_TEMPLATE_NAME
59 |
60 | var s := template_name.to_lower().replace(" ", "_").validate_filename()
61 | var extension := ".tres"
62 | var file_name := s + extension
63 |
64 | var suffix := 0
65 |
66 | while dir.file_exists(file_name):
67 | suffix += 1
68 | file_name = s + str(suffix).pad_zeros(2) + extension
69 |
70 | return file_name
71 |
72 |
73 |
74 | func _on_save_template_requested() -> void:
75 | _setup_save_dialog()
76 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tbt_plugin_control/popups/template_dialog.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Window
3 |
4 | const MIN_WIDTH_PROPORTION := 0.3
5 | const MIN_HEIGHT_PROPORTION := 0.3
6 |
7 |
8 | # class extended by SaveTemplateDialog and EditTemplateDialog
9 |
10 | const DEFAULT_TEMPLATE_NAME := "User Template"
11 | const DEFAULT_TEMPLATE_DESCRIPTION := ""
12 | const DEFAULT_TEMPLATE_TAGS := ""
13 |
14 | var INFO_LABEL_TEXT := "Tiles: {tile_count}\nTerrains: {terrain_count}"
15 |
16 |
17 | const TBTPlugin := preload("res://addons/tile_bit_tools/controls/tbt_plugin_control/tbt_plugin_control.gd")
18 |
19 | const BitDataDrawNode := preload("res://addons/tile_bit_tools/controls/bit_data_draw/bit_data_draw_node.gd")
20 |
21 | var template_bit_data : TBTPlugin.TemplateBitData
22 |
23 |
24 | var tbt : TBTPlugin
25 |
26 | @onready var name_edit: LineEdit = %NameEdit
27 | @onready var description_edit: TextEdit = %DescriptionEdit
28 | @onready var tags_edit: LineEdit = %TagsEdit
29 |
30 |
31 | @onready var preview_rect: TextureRect = %PreviewRect
32 |
33 | @onready var folder_option_button: OptionButton = %FolderOptionButton
34 | @onready var template_info_list: ItemList = %TemplateInfoList
35 |
36 |
37 | func _ready() -> void:
38 | hide()
39 | var _err := close_requested.connect(close_dialog)
40 | template_info_list.show_custom_tags = false
41 |
42 |
43 | func _tbt_ready() -> void:
44 | _setup_connections()
45 |
46 |
47 | func _setup_connections() -> void:
48 | # override this
49 | pass
50 |
51 |
52 | # call after get template_bit_data
53 | func show_dialog() -> void:
54 | _setup_dialog()
55 | popup_centered()
56 |
57 |
58 | # connected to buttons/closing dialog,
59 | # do not need to call
60 | func close_dialog() -> void:
61 | template_bit_data = null
62 | hide()
63 |
64 |
65 | # ----------------------------------
66 | # COMMON SETUP
67 | # ----------------------------------
68 |
69 | func _setup_dialog() -> void:
70 | _set_size()
71 | _setup_texture()
72 | template_info_list.update(template_bit_data)
73 | _setup_folders_button()
74 | _setup_initial_values()
75 |
76 |
77 | func _set_size() -> void:
78 | set("min_size", Vector2i(Vector2(get_tree().root.size) * Vector2(MIN_WIDTH_PROPORTION, MIN_HEIGHT_PROPORTION)))
79 | # set("max_size", get_tree().root.size * 0.75)
80 |
81 |
82 | func _setup_texture() -> void:
83 | var bit_data_draw_node : BitDataDrawNode = tbt.template_manager.get_bit_data_draw()
84 | preview_rect.texture = await bit_data_draw_node.get_bit_texture(template_bit_data)
85 |
86 |
87 |
88 | func _setup_folders_button() -> void:
89 | folder_option_button.clear()
90 |
91 | for i in range(tbt.template_manager.template_folder_paths.size()):
92 | var folder_path : Dictionary = tbt.template_manager.template_folder_paths[i]
93 | if folder_path.type != tbt.G.TemplateTypes.USER:
94 | continue
95 | if !folder_path.has("name"):
96 | continue
97 | folder_option_button.add_item(folder_path.name, i)
98 |
99 | var tooltip : String = folder_path.tooltip + "\n" + folder_path.path
100 | var idx := folder_option_button.get_item_index(i)
101 | folder_option_button.set_item_tooltip(idx, tooltip)
102 |
103 | folder_option_button.get_popup().add_to_group("TBTPopupMenu")
104 |
105 |
106 |
107 |
108 | func _setup_initial_values() -> void:
109 | # override this
110 | # name
111 | # description
112 | # tags
113 | # save path label
114 | pass
115 |
116 |
117 | # ---------------------------
118 | # SAVE FUNCTIONS
119 | # ---------------------------
120 |
121 | func _save() -> void:
122 | _update_template_bit_data()
123 |
124 | var path := _get_save_path()
125 | var result := ResourceSaver.save(template_bit_data, path)
126 |
127 | if result != OK:
128 | tbt.output.user("Error saving template", tbt.G.Errors.FAILED)
129 | tbt.output.debug("ResourceSaver error: %s" % result)
130 | close_dialog()
131 | return
132 |
133 | tbt.output.user("Saved user template '%s' to %s " % [template_bit_data.template_name, path])
134 | tbt.templates_update_requested.emit()
135 | close_dialog()
136 |
137 |
138 | func _update_template_bit_data() -> void:
139 | if name_edit.text == "":
140 | template_bit_data.template_name = DEFAULT_TEMPLATE_NAME
141 | else:
142 | template_bit_data.template_name = name_edit.text
143 | template_bit_data.template_description = description_edit.text
144 | template_bit_data._custom_tags = _get_custom_tags()
145 | template_bit_data.version = tbt.G.VERSION
146 |
147 |
148 | func _get_custom_tags() -> Array:
149 | var tags := []
150 | var tag_texts := tags_edit.text.split(",")
151 | for text in tag_texts:
152 | text = text.strip_edges()
153 | if text == "":
154 | continue
155 | tags.append(text)
156 | return tags
157 |
158 |
159 | func _get_save_path() -> String:
160 | # override this function
161 | return ""
162 |
163 |
164 |
165 |
166 |
167 |
168 | func _on_save_button_pressed() -> void:
169 | _save()
170 |
171 |
172 | func _on_cancel_button_pressed() -> void:
173 | close_dialog()
174 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tbt_plugin_control/tbt_plugin_control.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Node
3 |
4 |
5 | signal tiles_inspector_added
6 | signal tiles_inspector_removed
7 |
8 | signal templates_updated
9 | signal templates_update_requested
10 |
11 | signal save_template_requested
12 | signal edit_template_requested(template_bit_data)
13 | signal message_box_requested(msg)
14 |
15 | signal preview_updated(preview_bit_data)
16 | signal reset_requested
17 | signal apply_changes_requested
18 |
19 | signal tiles_preview_collapse_requested
20 | signal tiles_preview_expand_requested
21 |
22 | signal theme_update_requested(node)
23 |
24 | const TBT_PROPERTY_NAME := "tbt"
25 | const TBT_READY_METHOD := "_tbt_ready"
26 | const TILES_INSPECTOR_ADDED_METHOD := "_tiles_inspector_added"
27 | const TILES_INSPECTOR_REMOVED_METHOD := "_tiles_inspector_removed"
28 |
29 | const G := preload("res://addons/tile_bit_tools/core/globals.gd")
30 | const Texts := preload("res://addons/tile_bit_tools/core/texts.gd")
31 | const Icons := preload("res://addons/tile_bit_tools/core/icons.gd")
32 | const Output := preload("res://addons/tile_bit_tools/core/output.gd")
33 |
34 | const BitData := preload("res://addons/tile_bit_tools/core/bit_data.gd")
35 | const EditorBitData := preload("res://addons/tile_bit_tools/core/editor_bit_data.gd")
36 | const TemplateBitData := preload("res://addons/tile_bit_tools/core/template_bit_data.gd")
37 |
38 | const TemplateManager := preload("res://addons/tile_bit_tools/controls/tbt_plugin_control/template_manager.gd")
39 | const TilesManager := preload("res://addons/tile_bit_tools/controls/tbt_plugin_control/tiles_manager.gd")
40 | const ThemeUpdater := preload("res://addons/tile_bit_tools/controls/tbt_plugin_control/theme_updater.gd")
41 | const Context := preload("res://addons/tile_bit_tools/core/context.gd")
42 |
43 | var output : Output = Output.new()
44 | var texts : Texts = Texts.new()
45 | var icons : Icons
46 |
47 | var interface : EditorInterface
48 | var atlas_source_editor : Node
49 | var base_control : Control
50 |
51 | var template_manager : TemplateManager
52 | var tiles_manager : TilesManager
53 | var theme_updater : ThemeUpdater
54 | var dialog_windows := []
55 |
56 | var context : Context :
57 | get:
58 | if !_is_reference_valid(context):
59 | return null
60 | return context
61 |
62 |
63 | var tiles_inspector : Control :
64 | get:
65 | if !_is_reference_valid(tiles_inspector):
66 | return null
67 | return tiles_inspector
68 |
69 |
70 | var tiles_preview : Control :
71 | get:
72 | if !_is_reference_valid(tiles_preview):
73 | return null
74 | return tiles_preview
75 |
76 |
77 | func _ready() -> void:
78 | set_process_input(false)
79 | var _err := child_entered_tree.connect(_assign_child_by_class)
80 | _setup_debug_signals()
81 | _setup_children()
82 |
83 |
84 | func setup(p_interface : EditorInterface, p_atlas_source_editor : Node, p_tiles_preview : Control) -> void:
85 | interface = p_interface
86 | base_control = interface.get_base_control()
87 | atlas_source_editor = p_atlas_source_editor
88 |
89 | icons = Icons.new(base_control)
90 |
91 | # here instead of _ready() so base_control is not null
92 | _inject_tbt_reference(self)
93 |
94 | tiles_preview = p_tiles_preview
95 | _inject_tbt_reference(tiles_preview, true)
96 |
97 |
98 | func notify_tiles_inspector_added(p_tiles_inspector : Control) -> void:
99 | tiles_inspector = p_tiles_inspector
100 | _inject_tbt_reference(tiles_inspector, true)
101 | _call_subtree(self, TILES_INSPECTOR_ADDED_METHOD)
102 | tiles_inspector_added.emit()
103 | var _err := tiles_inspector.visibility_changed.connect(_on_tiles_inspector_visibility_changed)
104 | _setup_dynamic_containers()
105 | set_process_input(true)
106 | tiles_preview_expand_requested.emit()
107 |
108 |
109 | func notify_tiles_inspector_removed() -> void:
110 | set_process_input(false)
111 | _call_subtree(self, TILES_INSPECTOR_REMOVED_METHOD)
112 | tiles_inspector_removed.emit()
113 |
114 | func is_dialog_popped_up() -> bool:
115 | for dialog in dialog_windows:
116 | if dialog.visible:
117 | return true
118 | return false
119 |
120 |
121 | func _setup_dynamic_containers() -> void:
122 | for node in get_tree().get_nodes_in_group(G.GROUP_DYNAMIC_CONTAINER):
123 | if !node.child_entered_tree.is_connected(_on_dynamic_container_child_added):
124 | var _err := node.child_entered_tree.connect(_on_dynamic_container_child_added)
125 |
126 |
127 | func _on_dynamic_container_child_added(node : Node) -> void:
128 | _inject_tbt_reference(node, true)
129 | theme_update_requested.emit(node)
130 |
131 |
132 | func _on_tiles_inspector_visibility_changed() -> void:
133 | if !is_instance_valid(tiles_inspector) or !tiles_inspector.is_visible_in_tree():
134 | tiles_preview.hide()
135 | set_process_input(false)
136 | else:
137 | tiles_preview.show()
138 | set_process_input(true)
139 |
140 |
141 | # while tiles inspector is visible, watch for mouse clicks and
142 | # collapse preview panel for clicks outside of this plugin
143 | func _input(event: InputEvent) -> void:
144 | if not event is InputEventMouseButton:
145 | return
146 | if not event.button_index in [MOUSE_BUTTON_LEFT, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MIDDLE]:
147 | return
148 |
149 | if is_dialog_popped_up():
150 | return
151 |
152 | var mouse_position = base_control.get_global_mouse_position()
153 |
154 | if tiles_inspector.get_parent_control().get_global_rect().has_point(mouse_position):
155 | if tiles_inspector.get_global_rect().has_point(mouse_position):
156 | if !tiles_preview.expanded:
157 | tiles_preview_expand_requested.emit()
158 | else:
159 | tiles_preview_collapse_requested.emit()
160 | return
161 |
162 | if !tiles_preview.expanded:
163 | return
164 |
165 | if tiles_preview.get_parent_control().get_global_rect().has_point(mouse_position):
166 | if !tiles_preview.get_mouse_input_rect().has_point(mouse_position):
167 | tiles_preview_collapse_requested.emit()
168 |
169 |
170 | func _setup_children() -> void:
171 | for child in _get_children_recursive(self):
172 | _assign_child_by_class(child)
173 |
174 |
175 | func _assign_child_by_class(child : Node) -> void:
176 | match child.get_script():
177 | TemplateManager:
178 | template_manager = child
179 | TilesManager:
180 | tiles_manager = child
181 | ThemeUpdater:
182 | theme_updater = child
183 | Context:
184 | context = child
185 | _:
186 | if child is Window:
187 | dialog_windows.append(child)
188 |
189 |
190 |
191 | func _inject_tbt_reference(node : Node, include_parent := false) -> void:
192 | _set_subtree(node, TBT_PROPERTY_NAME, self, include_parent)
193 | _call_subtree(node, TBT_READY_METHOD, include_parent)
194 |
195 |
196 | func _set_subtree(parent : Node, property_name : String, value : Variant, include_parent := false) -> void:
197 | var nodes_to_set := _get_children_recursive(parent)
198 | if include_parent:
199 | nodes_to_set.append(parent)
200 |
201 | for node in nodes_to_set:
202 | node.set(property_name, value)
203 |
204 |
205 | func _call_subtree(parent : Node, method_name : String, include_parent := false) -> void:
206 | var nodes_to_call := _get_children_recursive(parent)
207 | if include_parent:
208 | nodes_to_call.append(parent)
209 |
210 | for node in nodes_to_call:
211 | if node.has_method(method_name):
212 | node.call(method_name)
213 |
214 |
215 | func _get_children_recursive(node : Node) -> Array:
216 | return node.find_children("*", "", true, false)
217 |
218 |
219 | func _is_reference_valid(node) -> bool:
220 | if !is_instance_valid(node):
221 | return false
222 | if !node.is_inside_tree():
223 | output.warning("%s is not inside tree" % node)
224 | return false
225 | if node.is_queued_for_deletion():
226 | output.warning("%s is queued for deletion" % node)
227 | return false
228 | return true
229 | # return is_instance_valid(node) && node.is_inside_tree() && !node.is_queued_for_deletion()
230 |
231 |
232 | func _setup_debug_signals() -> void:
233 | for signal_data in get_signal_list():
234 | if signal_data.args.size() == 0:
235 | var _err := connect(signal_data.name, _on_signal_emitted.bind(signal_data.name))
236 | else:
237 | var _err := connect(signal_data.name, _on_signal_emitted_with_arg.bind(signal_data.name))
238 |
239 |
240 | func _on_signal_emitted(signal_name := "") -> void:
241 | output.debug("[TBTPlugin] Signal emitted: %s" % signal_name)
242 |
243 |
244 | func _on_signal_emitted_with_arg(arg = null, signal_name := "") -> void:
245 | output.debug("[TBTPlugin] Signal emitted: %s (%s)" % [signal_name, arg])
246 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tbt_plugin_control/tbt_plugin_control.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=8 format=3 uid="uid://bx6k2su2g3pj"]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/controls/tbt_plugin_control/tbt_plugin_control.gd" id="1_6xv2q"]
4 | [ext_resource type="Script" path="res://addons/tile_bit_tools/controls/tbt_plugin_control/template_manager.gd" id="2_aj7pp"]
5 | [ext_resource type="PackedScene" uid="uid://job5gqt1xbrh" path="res://addons/tile_bit_tools/controls/tbt_plugin_control/popups/save_template_dialog.tscn" id="3_p4ion"]
6 | [ext_resource type="PackedScene" uid="uid://cyxr6y64lkue6" path="res://addons/tile_bit_tools/controls/tbt_plugin_control/popups/edit_template_dialog.tscn" id="4_qymya"]
7 | [ext_resource type="Script" path="res://addons/tile_bit_tools/controls/tbt_plugin_control/tiles_manager.gd" id="5_v5epd"]
8 | [ext_resource type="Script" path="res://addons/tile_bit_tools/controls/tbt_plugin_control/theme_updater.gd" id="6_mie0u"]
9 |
10 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_3by6e"]
11 | content_margin_left = 24.0
12 | content_margin_top = 24.0
13 | content_margin_right = 24.0
14 | content_margin_bottom = 24.0
15 | bg_color = Color(0.21, 0.24, 0.29, 1)
16 | border_width_top = 48
17 | border_color = Color(0.21, 0.24, 0.29, 1)
18 | corner_detail = 5
19 | expand_margin_top = 48.0
20 | shadow_color = Color(0, 0, 0, 0.3)
21 | shadow_size = 8
22 | anti_aliasing = false
23 |
24 | [node name="TBTPlugin" type="Control"]
25 | layout_mode = 3
26 | anchors_preset = 0
27 | script = ExtResource("1_6xv2q")
28 |
29 | [node name="TemplateManager" type="Node" parent="."]
30 | script = ExtResource("2_aj7pp")
31 |
32 | [node name="TilesManager" type="Node" parent="."]
33 | script = ExtResource("5_v5epd")
34 |
35 | [node name="ThemeUpdater" type="Control" parent="."]
36 | anchors_preset = 0
37 | script = ExtResource("6_mie0u")
38 |
39 | [node name="SaveDialogContainer" type="Control" parent="."]
40 | anchors_preset = 0
41 |
42 | [node name="SaveTemplateDialog" parent="SaveDialogContainer" instance=ExtResource("3_p4ion")]
43 | visible = false
44 | theme_override_styles/embedded_border = SubResource("StyleBoxFlat_3by6e")
45 |
46 | [node name="EditDialogContainer" type="Control" parent="."]
47 | anchors_preset = 0
48 |
49 | [node name="EditTemplateDialog" parent="EditDialogContainer" instance=ExtResource("4_qymya")]
50 | theme_override_styles/embedded_border = SubResource("StyleBoxFlat_3by6e")
51 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tbt_plugin_control/template_manager.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Node
3 |
4 | const TEMPLATE_PREVIEW_TILE_WIDTH := 16
5 | const TEMPLATE_PREVIEW_TILE_SPACING := 0
6 |
7 | const TBTPlugin := preload("res://addons/tile_bit_tools/controls/tbt_plugin_control/tbt_plugin_control.gd")
8 |
9 | const TemplateLoader := preload("res://addons/tile_bit_tools/core/template_loader.gd")
10 | const BitDataDrawNode := preload("res://addons/tile_bit_tools/controls/bit_data_draw/bit_data_draw_node.tscn")
11 |
12 | var template_loader : TemplateLoader
13 | var bit_data_draw_node
14 |
15 | var tbt : TBTPlugin
16 |
17 |
18 | @onready var template_folder_paths : Array
19 |
20 |
21 |
22 | func _tbt_ready() -> void:
23 | var _err := tbt.templates_update_requested.connect(update_templates)
24 |
25 | _setup_bit_data_draw()
26 |
27 | # call deferred so editor will not pause on activating plugin
28 | _load_templates.call_deferred()
29 |
30 |
31 | func _setup_bit_data_draw() -> void:
32 | bit_data_draw_node = BitDataDrawNode.instantiate()
33 | add_child(bit_data_draw_node)
34 | bit_data_draw_node.tile_size = TEMPLATE_PREVIEW_TILE_WIDTH
35 | bit_data_draw_node.tile_spacing = TEMPLATE_PREVIEW_TILE_SPACING
36 |
37 |
38 | func _load_templates() -> void:
39 | _update_template_folder_paths()
40 |
41 | for folder_path in template_folder_paths:
42 | tbt.output.debug("Loading templates in %s: %s" % [folder_path.name, folder_path.path])
43 | if !DirAccess.dir_exists_absolute(folder_path.path):
44 | tbt.output.debug("making path to template folder: %s" % folder_path.path)
45 | var _err := DirAccess.make_dir_recursive_absolute(folder_path.path)
46 |
47 | template_loader = TemplateLoader.new(template_folder_paths)
48 | _create_template_textures.call_deferred()
49 | tbt.output.info("%s templates loaded" % template_loader.get_templates().size())
50 |
51 |
52 | func _create_template_textures() -> void:
53 | for template in template_loader.get_templates():
54 | template.preview_texture = await bit_data_draw_node.get_bit_texture(template)
55 | # tbt.output.debug("Created preview texture for %s" % template.template_name)
56 |
57 |
58 | func update_templates() -> void:
59 | _load_templates()
60 | tbt.templates_updated.emit()
61 |
62 |
63 | func get_bit_data_draw() -> SubViewport:
64 | return bit_data_draw_node
65 |
66 |
67 | func get_user_templates_path() -> String:
68 | var path : String = ProjectSettings.get_setting(TBTPlugin.G.Settings.user_templates_path.path)
69 | var dir := DirAccess.open(path)
70 | if dir:
71 | return dir.get_current_dir()
72 | return ""
73 |
74 |
75 | func _update_template_folder_paths() -> void:
76 | template_folder_paths = [
77 | {
78 | "type": TBTPlugin.G.TemplateTypes.BUILT_IN,
79 | "name": "Built-in Templates Folder",
80 | "path": TBTPlugin.G.BUILTIN_TEMPLATES_PATH,
81 | },
82 | {
83 | "type": TBTPlugin.G.TemplateTypes.USER,
84 | "name": "Project Templates Folder",
85 | "tooltip": "Templates saved here will only be available to this project",
86 | "path": TBTPlugin.G.PROJECT_TEMPLATES_PATH,
87 | },
88 | {
89 | "type": TBTPlugin.G.TemplateTypes.USER,
90 | "name": "Shared Templates Folder",
91 | "tooltip": "Templates saved here will be available to all projects on this computer",
92 | "path": OS.get_data_dir() + TBTPlugin.G.GODOT_TEMPLATES_FOLDER,
93 | },
94 | # default is the same as project templates folder
95 | {
96 | "type": TBTPlugin.G.TemplateTypes.USER,
97 | "name": "User Templates Folder",
98 | "tooltip": "Template will be saved to the folder set in Project Settings -> Tile Bit Tools",
99 | "path": get_user_templates_path(),
100 | },
101 | ]
102 |
103 | for i in range(template_folder_paths.size()-1, -1, -1):
104 | if template_folder_paths[i].path == "":
105 | template_folder_paths.remove_at(i)
106 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tbt_plugin_control/tiles_manager.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Node
3 |
4 |
5 |
6 | enum TerrainChanges {NONE, ERASE, FILL, BITS, TEMPLATE}
7 |
8 | const TBTPlugin := preload("res://addons/tile_bit_tools/controls/tbt_plugin_control/tbt_plugin_control.gd")
9 |
10 | # TODO: move to texts; currently unused
11 | var terrain_changes_texts := {
12 | TerrainChanges.NONE: "",
13 | TerrainChanges.ERASE: "Erase terrain",
14 | TerrainChanges.FILL: "Fill terrain",
15 | TerrainChanges.BITS: "Set terrain bits",
16 | TerrainChanges.TEMPLATE: "Apply terrain template",
17 | }
18 |
19 |
20 | var preview_bit_data : TBTPlugin.EditorBitData = null
21 | var current_terrain_change := TerrainChanges.NONE
22 |
23 | var tbt : TBTPlugin
24 |
25 |
26 |
27 | func _tbt_ready() -> void:
28 | var _err := tbt.reset_requested.connect(_on_reset_requested)
29 | _err = tbt.apply_changes_requested.connect(_on_apply_changes_requested)
30 |
31 |
32 | func get_preview_terrain_set() -> int:
33 | if preview_bit_data == null:
34 | return TBTPlugin.BitData.NULL_TERRAIN_SET
35 | return preview_bit_data.terrain_set
36 |
37 | func has_preview() -> bool:
38 | return preview_bit_data != null
39 |
40 |
41 | func has_preview_terrain_set() -> bool:
42 | if preview_bit_data == null:
43 | return false
44 | return preview_bit_data.terrain_set != preview_bit_data.NULL_TERRAIN_SET
45 |
46 |
47 | func clear_preview() -> void:
48 | preview_bit_data = null
49 | _emit_preview_updated()
50 |
51 |
52 | func erase_terrains() -> void:
53 | preview_bit_data = _get_new_preview_data()
54 | preview_bit_data.clear_all_tile_terrains()
55 | current_terrain_change = TerrainChanges.ERASE
56 | _emit_preview_updated()
57 |
58 |
59 | func fill_terrain(terrain_set : int, terrain_id : int) -> void:
60 | preview_bit_data = _get_new_preview_data()
61 | var terrain_mode : int = tbt.context.tile_set.get_terrain_set_mode(terrain_set)
62 | preview_bit_data.fill_all_tile_terrains(terrain_set, terrain_mode, terrain_id)
63 | current_terrain_change = TerrainChanges.FILL
64 | _emit_preview_updated()
65 |
66 |
67 | # sets specific terrain bit of all selected tiles
68 | # adds on to any changes already made
69 | func set_terrain_bits(terrain_bit : int, terrain_id : int) -> void:
70 | if !preview_bit_data:
71 | preview_bit_data = _get_new_preview_data()
72 | preview_bit_data.set_all_bit_terrains(terrain_bit, terrain_id)
73 | current_terrain_change = TerrainChanges.BITS
74 | _emit_preview_updated()
75 |
76 |
77 | func apply_template_terrains(template : TBTPlugin.TemplateBitData, terrain_set : int, terrain_mapping : Dictionary) -> void:
78 | if terrain_mapping.is_empty():
79 | preview_bit_data = null
80 | _emit_preview_updated()
81 | return
82 |
83 | preview_bit_data = _get_new_preview_data()
84 | var result := preview_bit_data.apply_template_bit_data(template, terrain_set, terrain_mapping)
85 | if result != OK:
86 | preview_bit_data = null
87 | current_terrain_change = TerrainChanges.NONE
88 | tbt.output.error("Unable to apply template data", result)
89 | _emit_preview_updated()
90 | return
91 |
92 | current_terrain_change = TerrainChanges.TEMPLATE
93 | _emit_preview_updated()
94 |
95 |
96 | ## Applies the changes to TileData object
97 | ## including terrain_set, terrain and terrain peering bits
98 | ## There is no undo
99 | func apply_bit_data() -> void:
100 | if !preview_bit_data:
101 | return
102 |
103 | tbt.output.info(terrain_changes_texts[current_terrain_change])
104 |
105 | if current_terrain_change == TerrainChanges.ERASE:
106 | tbt.output.user("Erasing terrain set assignments may cause error spam of Condition 'terrain_set < 0' is true. Data should save without corruption. Please ignore.")
107 |
108 | for coords in tbt.context.tiles.keys():
109 | var tile_data : TileData = tbt.context.tiles[coords]
110 | tile_data.terrain_set = preview_bit_data.terrain_set
111 | tile_data.terrain = preview_bit_data.get_tile_terrain(coords)
112 | for cell_neighbor in preview_bit_data.get_terrain_bits_list():
113 | var terrain := preview_bit_data.get_bit_terrain(coords, cell_neighbor)
114 | tile_data.set_terrain_peering_bit(cell_neighbor, terrain)
115 |
116 |
117 |
118 | func _emit_preview_updated() -> void:
119 | tbt.preview_updated.emit(preview_bit_data)
120 |
121 |
122 | func _get_new_preview_data() -> TBTPlugin.EditorBitData:
123 | var copy : TBTPlugin.EditorBitData = tbt.context.bit_data.make_copy()
124 | return copy
125 |
126 |
127 | func _on_reset_requested() -> void:
128 | tbt.output.debug("reset requested from tiles manager")
129 | clear_preview()
130 |
131 |
132 | func _on_apply_changes_requested() -> void:
133 | apply_bit_data()
134 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tiles_inspector/template_section/selected_tag.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends PanelContainer
3 |
4 | signal tag_removed
5 |
6 | const TemplateTagData := preload("res://addons/tile_bit_tools/core/template_tag_data.gd")
7 | const TemplateTag := TemplateTagData.TemplateTag
8 |
9 | var tag : TemplateTag
10 |
11 | @onready var icon_rect: TextureRect = %IconRect
12 | @onready var label: Label = %Label
13 | @onready var remove_button: Button = %RemoveButton
14 |
15 |
16 | func _ready() -> void:
17 | var _err := remove_button.pressed.connect(_on_remove_button_pressed)
18 |
19 |
20 | func setup(p_tag : TemplateTag, base_control : Control) -> void:
21 | tag = p_tag
22 |
23 | label.text = tag.text
24 |
25 | icon_rect.texture = tag.get_icon(base_control)
26 |
27 | var stylebox : StyleBoxFlat = base_control.get_theme_stylebox("selected", "ItemList").duplicate(true)
28 | stylebox.content_margin_left = 6
29 | stylebox.content_margin_right = 2
30 | stylebox.content_margin_top = 0
31 | stylebox.content_margin_bottom = 0
32 | set("theme_override_styles/panel", stylebox)
33 |
34 |
35 | # TODO: implement in future?
36 | # if tag.color:
37 | # var stylebox : StyleBoxFlat = get("theme_override_styles/panel")
38 | # stylebox.bg_color = tag.color
39 |
40 |
41 | func _on_remove_button_pressed() -> void:
42 | tag_removed.emit()
43 | queue_free()
44 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tiles_inspector/template_section/selected_tag.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=4 format=3 uid="uid://bco7r2se8g2hn"]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/controls/tiles_inspector/template_section/selected_tag.gd" id="1_n8esd"]
4 | [ext_resource type="Script" path="res://addons/tile_bit_tools/controls/shared/icon_button.gd" id="2_gjwm3"]
5 |
6 | [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_4fhay"]
7 |
8 | [node name="SelectedTag" type="PanelContainer"]
9 | script = ExtResource("1_n8esd")
10 |
11 | [node name="HBoxContainer" type="HBoxContainer" parent="."]
12 | layout_mode = 2
13 |
14 | [node name="IconRect" type="TextureRect" parent="HBoxContainer"]
15 | unique_name_in_owner = true
16 | layout_mode = 2
17 | stretch_mode = 3
18 |
19 | [node name="Label" type="Label" parent="HBoxContainer" groups=["TBTSubPropertyLabel"]]
20 | unique_name_in_owner = true
21 | layout_mode = 2
22 | text = "Mode: Corners and Sides"
23 |
24 | [node name="RemoveButton" type="Button" parent="HBoxContainer"]
25 | unique_name_in_owner = true
26 | layout_mode = 2
27 | theme_override_styles/focus = SubResource("StyleBoxEmpty_4fhay")
28 | flat = true
29 | script = ExtResource("2_gjwm3")
30 | editor_name = "Close"
31 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tiles_inspector/template_section/selected_tag_stylebox.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="StyleBoxFlat" format=3 uid="uid://c1i723a04fsg7"]
2 |
3 | [resource]
4 | resource_local_to_scene = true
5 | content_margin_left = 8.0
6 | content_margin_right = 2.0
7 | bg_color = Color(0.239216, 0.258824, 0.278431, 1)
8 | corner_radius_top_left = 8
9 | corner_radius_top_right = 8
10 | corner_radius_bottom_right = 8
11 | corner_radius_bottom_left = 8
12 | corner_detail = 16
13 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tiles_inspector/template_section/template_info_panel.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends PanelContainer
3 |
4 | const TBTPlugin := preload("res://addons/tile_bit_tools/controls/tbt_plugin_control/tbt_plugin_control.gd")
5 |
6 |
7 | var info_label_text := "Type: {type}\nMode: {terrain_mode}\nTiles: {tile_count}\nTerrains: {terrain_count}"
8 |
9 | var texts := preload("res://addons/tile_bit_tools/core/texts.gd").new()
10 | var example_folder_path : String
11 |
12 | var template_bit_data : TBTPlugin.TemplateBitData
13 |
14 | var tbt : TBTPlugin
15 |
16 |
17 | @onready var template_info_list: ItemList = $MarginContainer/VBoxContainer/HBoxContainer/TemplateInfoList
18 |
19 |
20 | @onready var template_rect: TextureRect = %TemplateRect
21 |
22 | @onready var description_container: PanelContainer = %DescriptionContainer
23 | @onready var expand_button: Button = %ExpandButton
24 | @onready var description_label: RichTextLabel = %DescriptionLabel
25 |
26 | @onready var example_button: Button = %ExampleButton
27 | @onready var edit_button: Button = %EditButton
28 | @onready var remove_button: Button = %RemoveButton
29 |
30 |
31 | func _ready() -> void:
32 | hide()
33 |
34 |
35 | func _tbt_ready() -> void:
36 | _toggle_description_expand_button(false)
37 |
38 |
39 | func update(p_template_bit_data : TBTPlugin.TemplateBitData) -> void:
40 | template_bit_data = p_template_bit_data
41 |
42 | if !template_bit_data:
43 | hide()
44 | return
45 |
46 | show()
47 |
48 | if template_bit_data.template_description == "":
49 | description_container.hide()
50 | else:
51 | description_container.show()
52 |
53 | description_label.text = template_bit_data.template_description
54 |
55 | template_info_list.update(template_bit_data)
56 |
57 |
58 | if template_bit_data.built_in:
59 | edit_button.hide()
60 | remove_button.hide()
61 | else:
62 | edit_button.show()
63 | remove_button.show()
64 |
65 | if template_bit_data.example_folder_path != "" && DirAccess.dir_exists_absolute(template_bit_data.example_folder_path):
66 | example_folder_path = template_bit_data.example_folder_path
67 | example_button.show()
68 | else:
69 | example_folder_path = ""
70 | example_button.hide()
71 |
72 | template_rect.texture = template_bit_data.preview_texture
73 |
74 |
75 |
76 |
77 |
78 |
79 | func _toggle_description_expand_button(value : bool) -> void:
80 | if value:
81 | expand_button.icon = tbt.icons.get_icon(tbt.icons.ARROW_EXPANDED)
82 | description_label.fit_content = true
83 | else:
84 | expand_button.icon = tbt.icons.get_icon(tbt.icons.ARROW_COLLAPSED)
85 | description_label.fit_content = false
86 |
87 |
88 |
89 |
90 | func _open_example_folder() -> void:
91 | var path := ProjectSettings.globalize_path(example_folder_path)
92 | var _err := OS.shell_open(path)
93 |
94 |
95 | # TODO: move to template_manager? make more generalized?
96 | func _remove_template() -> void:
97 | var confirm_dialog := ConfirmationDialog.new()
98 | confirm_dialog.title = "Confirm Delete Template"
99 | confirm_dialog.dialog_text = "Really delete template '%s'?" % template_bit_data.template_name
100 | confirm_dialog.ok_button_text = "Delete (no undo)"
101 | var _err := confirm_dialog.confirmed.connect(_on_delete_confirmed)
102 | add_child(confirm_dialog)
103 | confirm_dialog.popup_centered()
104 |
105 |
106 | func _on_delete_confirmed() -> void:
107 | var path := template_bit_data.resource_path
108 | var _err := DirAccess.remove_absolute(path)
109 | tbt.output.user("Deleted user template '%s'" % template_bit_data.template_name)
110 | tbt.templates_update_requested.emit()
111 |
112 |
113 | func _on_remove_button_pressed() -> void:
114 | _remove_template()
115 |
116 |
117 | func _on_edit_button_pressed() -> void:
118 | tbt.edit_template_requested.emit(template_bit_data)
119 |
120 |
121 | func _on_example_button_pressed() -> void:
122 | _open_example_folder()
123 |
124 |
125 | func _on_expand_button_toggled(button_pressed: bool) -> void:
126 | _toggle_description_expand_button(button_pressed)
127 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tiles_inspector/template_section/template_info_panel.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=7 format=3 uid="uid://bxhlehm73ligy"]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/controls/tiles_inspector/template_section/template_info_panel.gd" id="1_arkoa"]
4 | [ext_resource type="PackedScene" uid="uid://bscknm10ko78t" path="res://addons/tile_bit_tools/controls/shared/template_info_list.tscn" id="2_jg88n"]
5 | [ext_resource type="Script" path="res://addons/tile_bit_tools/controls/shared/icon_button.gd" id="5_7b1jd"]
6 |
7 | [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_kuq0c"]
8 |
9 | [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_kei5m"]
10 |
11 | [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_v7bmg"]
12 |
13 | [node name="TemplateInfoPanel" type="PanelContainer" groups=["TBTSubinspectorOverlayPanel"]]
14 | visible = false
15 | custom_minimum_size = Vector2(0, 48)
16 | anchors_preset = 10
17 | anchor_right = 1.0
18 | offset_bottom = 92.0
19 | grow_horizontal = 2
20 | size_flags_horizontal = 3
21 | script = ExtResource("1_arkoa")
22 |
23 | [node name="MarginContainer" type="MarginContainer" parent="."]
24 | layout_mode = 2
25 | theme_override_constants/margin_left = 8
26 | theme_override_constants/margin_top = 8
27 | theme_override_constants/margin_right = 8
28 | theme_override_constants/margin_bottom = 8
29 |
30 | [node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
31 | layout_mode = 2
32 | mouse_filter = 2
33 |
34 | [node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
35 | layout_mode = 2
36 | mouse_filter = 2
37 |
38 | [node name="TemplateInfoList" parent="MarginContainer/VBoxContainer/HBoxContainer" instance=ExtResource("2_jg88n")]
39 | layout_mode = 2
40 |
41 | [node name="TemplateRect" type="TextureRect" parent="MarginContainer/VBoxContainer/HBoxContainer"]
42 | unique_name_in_owner = true
43 | texture_filter = 1
44 | texture_repeat = 1
45 | layout_mode = 2
46 | size_flags_horizontal = 3
47 | expand_mode = 1
48 | stretch_mode = 5
49 |
50 | [node name="DescriptionContainer" type="PanelContainer" parent="MarginContainer/VBoxContainer" groups=["TBTInspectorMessagePanel"]]
51 | unique_name_in_owner = true
52 | layout_mode = 2
53 | theme_override_styles/panel = SubResource("StyleBoxEmpty_kuq0c")
54 |
55 | [node name="HBoxContainer2" type="HBoxContainer" parent="MarginContainer/VBoxContainer/DescriptionContainer"]
56 | layout_mode = 2
57 |
58 | [node name="ExpandButton" type="Button" parent="MarginContainer/VBoxContainer/DescriptionContainer/HBoxContainer2"]
59 | unique_name_in_owner = true
60 | layout_mode = 2
61 | size_flags_horizontal = 0
62 | size_flags_vertical = 0
63 | theme_override_styles/focus = SubResource("StyleBoxEmpty_kei5m")
64 | toggle_mode = true
65 | flat = true
66 |
67 | [node name="DescriptionLabel" type="RichTextLabel" parent="MarginContainer/VBoxContainer/DescriptionContainer/HBoxContainer2"]
68 | unique_name_in_owner = true
69 | layout_mode = 2
70 | size_flags_horizontal = 3
71 | theme_override_styles/normal = SubResource("StyleBoxEmpty_v7bmg")
72 | bbcode_enabled = true
73 | text = "Description of the template. Description of the template. Description of the template. Description of the template. Description of the template. Description of the template. Description of the template. Description of the template. Description of the template. Description of the template. Description of the template. "
74 | scroll_active = false
75 |
76 | [node name="Buttons" type="HBoxContainer" parent="MarginContainer"]
77 | layout_mode = 2
78 | size_flags_vertical = 0
79 | alignment = 2
80 |
81 | [node name="ExampleButton" type="Button" parent="MarginContainer/Buttons"]
82 | unique_name_in_owner = true
83 | layout_mode = 2
84 | tooltip_text = "Open example files folder"
85 | script = ExtResource("5_7b1jd")
86 | editor_name = "Image"
87 |
88 | [node name="EditButton" type="Button" parent="MarginContainer/Buttons"]
89 | unique_name_in_owner = true
90 | layout_mode = 2
91 | tooltip_text = "Edit User Template"
92 | script = ExtResource("5_7b1jd")
93 | editor_name = "Edit"
94 |
95 | [node name="RemoveButton" type="Button" parent="MarginContainer/Buttons"]
96 | unique_name_in_owner = true
97 | layout_mode = 2
98 | tooltip_text = "Delete User Template"
99 | script = ExtResource("5_7b1jd")
100 | editor_name = "Remove"
101 |
102 | [connection signal="toggled" from="MarginContainer/VBoxContainer/DescriptionContainer/HBoxContainer2/ExpandButton" to="." method="_on_expand_button_toggled"]
103 | [connection signal="pressed" from="MarginContainer/Buttons/ExampleButton" to="." method="_on_example_button_pressed"]
104 | [connection signal="pressed" from="MarginContainer/Buttons/EditButton" to="." method="_on_edit_button_pressed"]
105 | [connection signal="pressed" from="MarginContainer/Buttons/RemoveButton" to="." method="_on_remove_button_pressed"]
106 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tiles_inspector/template_section/templates_section.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Control
3 |
4 | const NULL_TERRAIN_SET_INDEX := 0
5 |
6 | const NULL_OPTION_ID := 999
7 |
8 | const TBTPlugin := preload("res://addons/tile_bit_tools/controls/tbt_plugin_control/tbt_plugin_control.gd")
9 |
10 |
11 | var TerrainPicker := preload("res://addons/tile_bit_tools/controls/tiles_inspector/template_section/terrain_picker.tscn")
12 | var SelectedTag := preload("res://addons/tile_bit_tools/controls/tiles_inspector/template_section/selected_tag.tscn")
13 |
14 | var templates := {}
15 |
16 | var terrain_pickers := []
17 | var terrain_sets := {}
18 |
19 | var selected_tags := []
20 | var selected_template_id := -1
21 | var selected_template : TBTPlugin.TemplateBitData
22 | var selected_terrain_set := -1
23 |
24 | var tbt : TBTPlugin
25 |
26 | @onready var tags_menu_button: MenuButton = %TagsMenuButton
27 | @onready var tags_popup := tags_menu_button.get_popup()
28 |
29 | @onready var tags_container: HFlowContainer = %TagsContainer
30 |
31 | @onready var templates_option_button: OptionButton = %TemplatesOptionButton
32 | @onready var template_info_panel: PanelContainer = %TemplateInfoPanel
33 | @onready var terrain_set_option_button: OptionButton = %TerrainSetOptionButton
34 | @onready var terrain_pickers_container: VBoxContainer = %TerrainPickersContainer
35 |
36 | @onready var terrain_container: PanelContainer = %TerrainContainer
37 |
38 | @onready var template_section_panel: PanelContainer = $TemplateSectionPanel
39 |
40 |
41 |
42 | func _tbt_ready() -> void:
43 |
44 | var _err := tbt.templates_updated.connect(_on_templates_updated)
45 | _err = tbt.reset_requested.connect(_on_reset_requested)
46 |
47 | _err = templates_option_button.item_selected.connect(_on_template_selected)
48 | _err = terrain_set_option_button.item_selected.connect(_on_terrain_set_selected)
49 |
50 | _err = tags_popup.id_pressed.connect(_add_tag)
51 | _reset_tags()
52 |
53 |
54 | # --------------------------------------
55 | # TAGS
56 | # --------------------------------------
57 |
58 | func _reset_tags() -> void:
59 | for child in tags_container.get_children():
60 | child.queue_free()
61 |
62 | selected_tags.clear()
63 | _update_tags_popup()
64 |
65 |
66 | func _update_tags_popup() -> void:
67 | tags_popup.clear()
68 | var item_list := tbt.template_manager.template_loader.get_tags_item_list(true, true, selected_tags)
69 |
70 | if item_list.size() == 0:
71 | tags_menu_button.disabled = true
72 | tags_menu_button.tooltip_text = "No additional filters available"
73 | return
74 |
75 | tags_menu_button.disabled = false
76 | tags_menu_button.tooltip_text = ""
77 |
78 | for item in item_list:
79 | var item_text : String = item.text + " (Templates: %s)" % item.count
80 | var icon = item.tag.get_icon(tbt.base_control)
81 | if icon:
82 | tags_popup.add_icon_item(icon, item_text, item.id)
83 | else:
84 | tags_popup.add_item(item_text, item.id)
85 |
86 | _update_templates_option_button()
87 |
88 |
89 | func _add_tag(tag_id : int) -> void:
90 | selected_tags.append(tag_id)
91 | var tag_control := SelectedTag.instantiate()
92 | var tag := tbt.template_manager.template_loader.get_tag(tag_id)
93 | tags_container.add_child(tag_control)
94 | tag_control.setup(tag, tbt.base_control)
95 | tag_control.tag_removed.connect(_on_tag_removed.bind(tag_id))
96 | _update_tags_popup()
97 |
98 |
99 | func _on_tag_removed(tag_id : int) -> void:
100 | selected_tags.erase(tag_id)
101 | _update_tags_popup()
102 |
103 |
104 |
105 | # --------------------------------------
106 | # TEMPLATES
107 | # --------------------------------------
108 |
109 | func _clear_templates_option_button() -> void:
110 | templates_option_button.clear()
111 | selected_template_id = -1
112 |
113 |
114 | func _update_templates_option_button() -> void:
115 | templates_option_button.clear()
116 | templates_option_button.add_item("", NULL_OPTION_ID)
117 |
118 | var templates_list := tbt.template_manager.template_loader.get_templates_item_list(selected_tags)
119 | for item in templates_list:
120 | templates_option_button.add_item(item.text, item.id)
121 |
122 | _force_select_template(NULL_OPTION_ID)
123 |
124 |
125 | func _force_select_template(id : int) -> void:
126 | var index := templates_option_button.get_item_index(id)
127 | templates_option_button.select(index)
128 | _on_template_selected(index) # selecting via script does not emit signal
129 |
130 |
131 | func _on_template_selected(index : int) -> void:
132 | selected_template_id = templates_option_button.get_item_id(index)
133 | selected_template = tbt.template_manager.template_loader.get_template(selected_template_id)
134 | _update_template_panel()
135 | _update_terrain_sets()
136 | _update_terrain_pickers_from_template()
137 | _update_template_info_panel()
138 | tbt.tiles_manager.clear_preview()
139 |
140 |
141 | func _update_template_info_panel() -> void:
142 | template_info_panel.update(selected_template)
143 |
144 |
145 | func _update_template_panel() -> void:
146 | if selected_template:
147 | template_section_panel.add_to_group("TBTSubinspectorPanel")
148 | tbt.theme_update_requested.emit(template_section_panel)
149 | else:
150 | template_section_panel.remove_from_group("TBTSubinspectorPanel")
151 | template_section_panel.set("theme_override_styles/panel", StyleBoxEmpty.new())
152 |
153 |
154 |
155 |
156 |
157 |
158 | # --------------------------------------
159 | # TERRAIN SET
160 | # --------------------------------------
161 |
162 |
163 | func _update_terrain_sets() -> void:
164 | if selected_template_id == NULL_OPTION_ID:
165 | terrain_container.hide()
166 | else:
167 | terrain_container.show()
168 | _update_terrain_set_option_button()
169 |
170 |
171 | func _update_terrain_set_option_button() -> void:
172 | var item_list := []
173 | if selected_template:
174 | item_list = tbt.context.get_terrain_sets_item_list(selected_template.terrain_mode)
175 |
176 | _update_option_button(terrain_set_option_button, item_list, false)
177 |
178 | if item_list.size() == 0:
179 | terrain_set_option_button.disabled = true
180 | terrain_set_option_button.tooltip_text = "No terrain sets found matching template mode. Create a new one in the TileSet."
181 | else:
182 | terrain_set_option_button.disabled = false
183 | terrain_set_option_button.tooltip_text = ""
184 | _force_select_terrain_set(item_list[0].id)
185 |
186 |
187 | func _force_select_terrain_set(id : int) -> void:
188 | var index := terrain_set_option_button.get_item_index(id)
189 | terrain_set_option_button.select(index)
190 | _on_terrain_set_selected(index) # selecting via script does not emit signal
191 |
192 |
193 | func _on_terrain_set_selected(index : int) -> void:
194 | selected_terrain_set = terrain_set_option_button.get_item_id(index)
195 | _update_terrain_pickers_from_terrain_set()
196 |
197 |
198 | # --------------------------------------
199 | # TERRAINS
200 | # --------------------------------------
201 |
202 |
203 | func _update_terrain_pickers_from_template() -> void:
204 | for child in terrain_pickers_container.get_children():
205 | terrain_pickers_container.remove_child(child)
206 |
207 | if !selected_template:
208 | return
209 |
210 | for i in range(selected_template.get_terrain_count()):
211 | terrain_pickers.append(_add_terrain_picker(i))
212 |
213 |
214 | func _update_terrain_pickers_from_terrain_set() -> void:
215 | for terrain_picker in terrain_pickers:
216 | terrain_picker.terrain_set = selected_terrain_set
217 |
218 |
219 | func _add_terrain_picker(index : int) -> Control:
220 | var terrain_picker := TerrainPicker.instantiate()
221 | terrain_pickers_container.add_child(terrain_picker)
222 | terrain_picker.setup(tbt, index, selected_template.get_terrain_color(index), selected_template.terrain_mode)
223 | var _err := terrain_set_option_button.item_selected.connect(terrain_picker._on_terrain_set_changed)
224 | terrain_picker.item_selected.connect(_request_preview)
225 | terrain_picker.terrain_set = selected_terrain_set
226 | return terrain_picker
227 |
228 |
229 |
230 | func _request_preview() -> void:
231 | var terrain_mapping := _get_terrain_mapping()
232 | tbt.tiles_manager.apply_template_terrains(selected_template, selected_terrain_set, terrain_mapping)
233 |
234 |
235 |
236 | func _update_option_button(option_button : OptionButton, item_list : Array, add_empty_item := false) -> void:
237 |
238 | option_button.clear()
239 | if add_empty_item:
240 | option_button.add_item("", NULL_OPTION_ID)
241 |
242 | for item in item_list:
243 | if item.has("icon"):
244 | option_button.add_icon_item(item.icon, item.text, item.id)
245 | else:
246 | option_button.add_item(item.text, item.id)
247 |
248 |
249 |
250 | ## Returns a dictionary
251 | ## key = template terrain id
252 | ## value = tileset terrain id
253 | func _get_terrain_mapping() -> Dictionary:
254 | var mapping := {}
255 | var has_data := false
256 |
257 | for picker in terrain_pickers:
258 | var terrain_id : int = picker.get_selected_item_id()
259 | if terrain_id != -1:
260 | has_data = true
261 | mapping[picker.index] = picker.get_selected_item_id()
262 |
263 | if has_data:
264 | return mapping
265 | else:
266 | return {}
267 |
268 |
269 |
270 | func _on_templates_updated() -> void:
271 | _reset_tags()
272 |
273 |
274 | func _on_reset_requested() -> void:
275 | _reset_tags()
276 |
277 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tiles_inspector/template_section/templates_section.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=4 format=3 uid="uid://dknch2tbr32yh"]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/controls/tiles_inspector/template_section/templates_section.gd" id="1_i6wsq"]
4 | [ext_resource type="PackedScene" uid="uid://bxhlehm73ligy" path="res://addons/tile_bit_tools/controls/tiles_inspector/template_section/template_info_panel.tscn" id="5_tlsqj"]
5 |
6 | [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_t8sf7"]
7 |
8 | [node name="TemplatesContainer" type="VBoxContainer"]
9 | anchors_preset = 10
10 | anchor_right = 1.0
11 | offset_bottom = 26.0
12 | grow_horizontal = 2
13 | script = ExtResource("1_i6wsq")
14 |
15 | [node name="HBoxContainer2" type="HBoxContainer" parent="."]
16 | layout_mode = 2
17 |
18 | [node name="TagsMenuButton" type="MenuButton" parent="HBoxContainer2"]
19 | unique_name_in_owner = true
20 | layout_mode = 2
21 | size_flags_horizontal = 3
22 | text = "Select Tag to Filter..."
23 |
24 | [node name="TagsContainer" type="HFlowContainer" parent="." groups=["TBTDynamicContainer"]]
25 | unique_name_in_owner = true
26 | layout_mode = 2
27 |
28 | [node name="TemplateSectionPanel" type="PanelContainer" parent="."]
29 | layout_mode = 2
30 | size_flags_horizontal = 3
31 | theme_override_styles/panel = SubResource("StyleBoxEmpty_t8sf7")
32 |
33 | [node name="VBoxContainer" type="VBoxContainer" parent="TemplateSectionPanel"]
34 | layout_mode = 2
35 | theme_override_constants/separation = 0
36 |
37 | [node name="HBoxContainer" type="HBoxContainer" parent="TemplateSectionPanel/VBoxContainer"]
38 | layout_mode = 2
39 |
40 | [node name="Label" type="Label" parent="TemplateSectionPanel/VBoxContainer/HBoxContainer"]
41 | layout_mode = 2
42 | size_flags_horizontal = 3
43 | text = "Template"
44 |
45 | [node name="TemplatesOptionButton" type="OptionButton" parent="TemplateSectionPanel/VBoxContainer/HBoxContainer"]
46 | unique_name_in_owner = true
47 | layout_mode = 2
48 | size_flags_horizontal = 3
49 | item_count = 4
50 | selected = 0
51 | popup/item_0/text = ""
52 | popup/item_0/id = 999
53 | popup/item_1/text = "2x2"
54 | popup/item_1/id = 0
55 | popup/item_2/text = "3x3 Minimal"
56 | popup/item_2/id = 1
57 | popup/item_3/text = "Generic 16 Tiles"
58 | popup/item_3/id = 2
59 |
60 | [node name="MarginContainer" type="MarginContainer" parent="TemplateSectionPanel/VBoxContainer"]
61 | layout_mode = 2
62 | theme_override_constants/margin_left = 8
63 | theme_override_constants/margin_top = 0
64 | theme_override_constants/margin_right = 8
65 | theme_override_constants/margin_bottom = 8
66 |
67 | [node name="VBoxContainer" type="VBoxContainer" parent="TemplateSectionPanel/VBoxContainer/MarginContainer"]
68 | layout_mode = 2
69 |
70 | [node name="TemplateInfoPanel" parent="TemplateSectionPanel/VBoxContainer/MarginContainer/VBoxContainer" instance=ExtResource("5_tlsqj")]
71 | unique_name_in_owner = true
72 | layout_mode = 2
73 |
74 | [node name="TerrainContainer" type="PanelContainer" parent="TemplateSectionPanel/VBoxContainer/MarginContainer/VBoxContainer" groups=["TBTSubinspectorPropertiesPanel"]]
75 | unique_name_in_owner = true
76 | layout_mode = 2
77 |
78 | [node name="MarginContainer" type="MarginContainer" parent="TemplateSectionPanel/VBoxContainer/MarginContainer/VBoxContainer/TerrainContainer"]
79 | layout_mode = 2
80 | theme_override_constants/margin_left = 16
81 |
82 | [node name="VBoxContainer" type="VBoxContainer" parent="TemplateSectionPanel/VBoxContainer/MarginContainer/VBoxContainer/TerrainContainer/MarginContainer"]
83 | layout_mode = 2
84 |
85 | [node name="HBoxContainer" type="HBoxContainer" parent="TemplateSectionPanel/VBoxContainer/MarginContainer/VBoxContainer/TerrainContainer/MarginContainer/VBoxContainer"]
86 | layout_mode = 2
87 |
88 | [node name="Label" type="Label" parent="TemplateSectionPanel/VBoxContainer/MarginContainer/VBoxContainer/TerrainContainer/MarginContainer/VBoxContainer/HBoxContainer" groups=["TBTPropertyLabel"]]
89 | layout_mode = 2
90 | size_flags_horizontal = 3
91 | text = "Terrain Set"
92 |
93 | [node name="TerrainSetOptionButton" type="OptionButton" parent="TemplateSectionPanel/VBoxContainer/MarginContainer/VBoxContainer/TerrainContainer/MarginContainer/VBoxContainer/HBoxContainer"]
94 | unique_name_in_owner = true
95 | layout_mode = 2
96 | size_flags_horizontal = 3
97 | tooltip_text = "No terrain sets found matching template mode. Create a new one in the TileSet."
98 | disabled = true
99 | fit_to_longest_item = false
100 |
101 | [node name="MarginContainer" type="MarginContainer" parent="TemplateSectionPanel/VBoxContainer/MarginContainer/VBoxContainer/TerrainContainer/MarginContainer/VBoxContainer"]
102 | layout_mode = 2
103 | theme_override_constants/margin_left = 16
104 |
105 | [node name="TerrainPickersContainer" type="VBoxContainer" parent="TemplateSectionPanel/VBoxContainer/MarginContainer/VBoxContainer/TerrainContainer/MarginContainer/VBoxContainer/MarginContainer" groups=["TBTDynamicContainer"]]
106 | unique_name_in_owner = true
107 | layout_mode = 2
108 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tiles_inspector/template_section/terrain_picker.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Control
3 |
4 | signal item_selected
5 |
6 |
7 | const TBTPlugin := preload("res://addons/tile_bit_tools/controls/tbt_plugin_control/tbt_plugin_control.gd")
8 |
9 | var EMPTY_ITEM_ID := -99
10 |
11 | var terrain_label_text := "Terrain %s"
12 |
13 | var index : int
14 | var color : Color
15 |
16 | var terrain_set : int :
17 | set(value):
18 | terrain_set = value
19 | _update_picker()
20 |
21 | var tbt : TBTPlugin
22 | var template_mode : TileSet.TerrainMode
23 |
24 | @onready var terrain_label: Label = %TerrainLabel
25 | @onready var terrain_color_rect: ColorRect = %TerrainColorRect
26 | @onready var terrain_option_button: OptionButton = %TerrainOptionButton
27 |
28 |
29 | func setup(p_tbt : TBTPlugin, p_index : int, p_color : Color, p_mode : TileSet.TerrainMode) -> void:
30 | tbt = p_tbt
31 | index = p_index
32 | color = p_color
33 | template_mode = p_mode
34 | _update_label()
35 |
36 |
37 | func _ready() -> void:
38 | var _err := terrain_option_button.item_selected.connect(_emit_item_selected)
39 |
40 |
41 | func get_selected_item_id() -> int:
42 | var id := terrain_option_button.get_selected_id()
43 | # id cannot be -1 in optionlist, so must be converted
44 | if id == EMPTY_ITEM_ID:
45 | return -1
46 | return id
47 |
48 |
49 | func disable_picker(value : bool) -> void:
50 | if value:
51 | terrain_option_button.disabled = true
52 | else:
53 | terrain_option_button.disabled = false
54 |
55 |
56 | func _update_label() -> void:
57 | terrain_label.text = terrain_label_text % index
58 | terrain_color_rect.color = color
59 |
60 |
61 | func _update_picker() -> void:
62 | terrain_option_button.clear()
63 | terrain_option_button.add_item(tbt.texts.EMPTY_ITEM, EMPTY_ITEM_ID)
64 |
65 | if terrain_set == -1:
66 | disable_picker(true)
67 | return
68 |
69 | var terrain_set_mode := tbt.context.tile_set.get_terrain_set_mode(terrain_set)
70 | if terrain_set_mode != template_mode:
71 | disable_picker(true)
72 | return
73 |
74 | disable_picker(false)
75 |
76 | var terrains_count := tbt.context.tile_set.get_terrains_count(terrain_set)
77 |
78 | for i in range(terrains_count):
79 | var terrain_name := tbt.context.tile_set.get_terrain_name(terrain_set, i)
80 | var terrain_color := tbt.context.tile_set.get_terrain_color(terrain_set, i)
81 | var icon : ImageTexture = tbt.context.get_terrain_icon(terrain_color)
82 | terrain_option_button.add_icon_item(icon, terrain_name, i)
83 |
84 |
85 | func _emit_item_selected(_index := -1) -> void:
86 | item_selected.emit()
87 |
88 |
89 | func _on_terrain_set_changed(id : int) -> void:
90 | terrain_set = id
91 |
92 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tiles_inspector/template_section/terrain_picker.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://1s77a4hdeubd"]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/controls/tiles_inspector/template_section/terrain_picker.gd" id="1_wswd4"]
4 |
5 | [node name="TerrainPicker" type="HBoxContainer"]
6 | anchors_preset = 10
7 | anchor_right = 1.0
8 | offset_bottom = 26.0
9 | grow_horizontal = 2
10 | script = ExtResource("1_wswd4")
11 |
12 | [node name="HBoxContainer" type="HBoxContainer" parent="."]
13 | layout_mode = 2
14 | size_flags_horizontal = 3
15 | theme_override_constants/separation = 12
16 |
17 | [node name="TerrainLabel" type="Label" parent="HBoxContainer" groups=["TBTPropertyLabel"]]
18 | unique_name_in_owner = true
19 | layout_mode = 2
20 | size_flags_horizontal = 0
21 | text = "Terrain 1"
22 |
23 | [node name="TerrainColorRect" type="ColorRect" parent="HBoxContainer"]
24 | unique_name_in_owner = true
25 | custom_minimum_size = Vector2(16, 16)
26 | layout_mode = 2
27 | size_flags_horizontal = 4
28 | size_flags_vertical = 4
29 |
30 | [node name="TerrainOptionButton" type="OptionButton" parent="."]
31 | unique_name_in_owner = true
32 | layout_mode = 2
33 | size_flags_horizontal = 3
34 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tiles_inspector/tiles_inspector.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Control
3 |
4 | const TBTPlugin := preload("res://addons/tile_bit_tools/controls/tbt_plugin_control/tbt_plugin_control.gd")
5 |
6 | var tbt : TBTPlugin
7 |
8 | var ready_complete := false
9 |
10 | @onready var save_button: Button = %SaveButton
11 |
12 | func _ready() -> void:
13 | ready_complete = true
14 |
15 |
16 | func _tbt_ready() -> void:
17 | if tbt.context.bit_data.has_terrain_set():
18 | save_button.disabled = false
19 | save_button.tooltip_text = ""
20 | else:
21 | save_button.disabled = true
22 | save_button.tooltip_text = "No terrain data to save in selected tiles"
23 |
24 |
25 |
26 | func _on_save_button_pressed() -> void:
27 | tbt.save_template_requested.emit()
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tiles_inspector/tiles_inspector.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=3 uid="uid://bijiosgd4td"]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/controls/tiles_inspector/tiles_inspector.gd" id="1_hyl5p"]
4 | [ext_resource type="Texture2D" uid="uid://cheop6l3022pn" path="res://addons/tile_bit_tools/controls/icons/tile_bit_tools_16.svg" id="3_pojdm"]
5 | [ext_resource type="PackedScene" uid="uid://dkmdolef567aa" path="res://addons/tile_bit_tools/controls/shared/inspector_section_button.tscn" id="4_2qwfq"]
6 | [ext_resource type="PackedScene" uid="uid://b5nbqr8ah0ay2" path="res://addons/tile_bit_tools/controls/tiles_inspector/tool_buttons/tool_buttons.tscn" id="4_vjqmp"]
7 | [ext_resource type="PackedScene" uid="uid://dknch2tbr32yh" path="res://addons/tile_bit_tools/controls/tiles_inspector/template_section/templates_section.tscn" id="6_xgtwo"]
8 |
9 | [node name="TilesInspector" type="VBoxContainer"]
10 | custom_minimum_size = Vector2(0, 64)
11 | anchors_preset = 15
12 | anchor_right = 1.0
13 | anchor_bottom = 1.0
14 | grow_horizontal = 2
15 | grow_vertical = 2
16 | theme_override_constants/separation = 0
17 | script = ExtResource("1_hyl5p")
18 |
19 | [node name="CategoryPanel" type="Panel" parent="." groups=["TBTCategoryPanel"]]
20 | custom_minimum_size = Vector2(0, 43)
21 | layout_mode = 2
22 | size_flags_vertical = 4
23 |
24 | [node name="HBoxContainer" type="HBoxContainer" parent="CategoryPanel"]
25 | layout_mode = 1
26 | anchors_preset = 14
27 | anchor_top = 0.5
28 | anchor_right = 1.0
29 | anchor_bottom = 0.5
30 | offset_top = -16.0
31 | offset_bottom = 16.0
32 | grow_horizontal = 2
33 | grow_vertical = 2
34 | size_flags_vertical = 4
35 | alignment = 1
36 |
37 | [node name="TextureRect" type="TextureRect" parent="CategoryPanel/HBoxContainer"]
38 | layout_mode = 2
39 | size_flags_horizontal = 4
40 | size_flags_vertical = 4
41 | texture = ExtResource("3_pojdm")
42 | stretch_mode = 3
43 |
44 | [node name="CategoryLabel" type="Label" parent="CategoryPanel/HBoxContainer" groups=["TBTCategoryLabel"]]
45 | layout_mode = 2
46 | text = "TileBitTools"
47 |
48 | [node name="MarginContainer3" type="MarginContainer" parent="."]
49 | layout_mode = 2
50 | theme_override_constants/margin_left = 8
51 | theme_override_constants/margin_top = 8
52 | theme_override_constants/margin_right = 8
53 | theme_override_constants/margin_bottom = 8
54 |
55 | [node name="ToolButtons" parent="MarginContainer3" instance=ExtResource("4_vjqmp")]
56 | layout_mode = 2
57 |
58 | [node name="ApplyTemplateSectionButton" parent="." instance=ExtResource("4_2qwfq")]
59 | custom_minimum_size = Vector2(0, 43)
60 | layout_mode = 2
61 | label_text = "Apply Terrain Template"
62 | expand_container_path = NodePath("../MarginContainer")
63 |
64 | [node name="MarginContainer" type="MarginContainer" parent="."]
65 | visible = false
66 | layout_mode = 2
67 | theme_override_constants/margin_left = 16
68 |
69 | [node name="TemplatesContainer" parent="MarginContainer" instance=ExtResource("6_xgtwo")]
70 | layout_mode = 2
71 |
72 | [node name="SaveTemplateSectionButton" parent="." instance=ExtResource("4_2qwfq")]
73 | custom_minimum_size = Vector2(0, 43)
74 | layout_mode = 2
75 | label_text = "Save Terrain Template"
76 | expand_container_path = NodePath("../MarginContainer2")
77 |
78 | [node name="MarginContainer2" type="MarginContainer" parent="."]
79 | layout_mode = 2
80 | theme_override_constants/margin_left = 16
81 |
82 | [node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer2"]
83 | layout_mode = 2
84 |
85 | [node name="PanelContainer" type="PanelContainer" parent="MarginContainer2/VBoxContainer" groups=["TBTInspectorMessagePanel"]]
86 | layout_mode = 2
87 |
88 | [node name="MarginContainer" type="MarginContainer" parent="MarginContainer2/VBoxContainer/PanelContainer"]
89 | layout_mode = 2
90 | theme_override_constants/margin_left = 8
91 | theme_override_constants/margin_top = 8
92 | theme_override_constants/margin_right = 8
93 | theme_override_constants/margin_bottom = 8
94 |
95 | [node name="Label" type="Label" parent="MarginContainer2/VBoxContainer/PanelContainer/MarginContainer"]
96 | layout_mode = 2
97 | text = "Save terrain from selected tiles as a user template.
98 |
99 | Choose to save in a project-specific or shared folder. Or set a custom location in Project Settings -> Addons -> TileBitTools."
100 | horizontal_alignment = 1
101 | vertical_alignment = 1
102 | autowrap_mode = 2
103 |
104 | [node name="SaveButton" type="Button" parent="MarginContainer2/VBoxContainer" groups=["TBTTextButton"]]
105 | unique_name_in_owner = true
106 | layout_mode = 2
107 | text = "Save Template"
108 |
109 | [connection signal="pressed" from="MarginContainer2/VBoxContainer/SaveButton" to="." method="_on_save_button_pressed"]
110 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tiles_inspector/tool_buttons/tool_buttons.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Control
3 |
4 | const TERRAIN_POPUP := "TerrainPopup"
5 |
6 | const TBTPlugin := preload("res://addons/tile_bit_tools/controls/tbt_plugin_control/tbt_plugin_control.gd")
7 |
8 | var EMPTY_TERRAIN_ID := 99
9 |
10 | var fill_menu_items := {}
11 |
12 | var bit_button_bit_id : int
13 | var bit_button_terrain_id : int
14 |
15 | var tbt : TBTPlugin
16 |
17 |
18 | @onready var fill_button: MenuButton = %FillButton
19 | @onready var bit_button: MenuButton = %BitButton
20 | @onready var bit_button_popup := bit_button.get_popup()
21 | @onready var clear_button: Button = %ClearButton
22 |
23 |
24 | func _tbt_ready() -> void:
25 | var _err := tbt.preview_updated.connect(_on_preview_updated)
26 | bit_button_popup.submenu_popup_delay = 0.0
27 | _setup_fill_button()
28 | _update_buttons()
29 |
30 |
31 | func _setup_fill_button() -> void:
32 | var _err := fill_button.get_popup().id_pressed.connect(_on_fill_button_popup_id_pressed)
33 | fill_button.custom_minimum_size.x = fill_button.size.x + 22
34 | _populate_fill_menu()
35 |
36 |
37 | func _update_buttons() -> void:
38 | _update_bit_button()
39 | _update_clear_button()
40 |
41 |
42 | func _update_clear_button() -> void:
43 | if tbt.tiles_manager.has_preview():
44 | if tbt.tiles_manager.has_preview_terrain_set():
45 | _enable_clear_button()
46 | else:
47 | _disable_clear_button()
48 | elif tbt.context.bit_data.has_terrain_set():
49 | _enable_clear_button()
50 | else:
51 | _disable_clear_button()
52 |
53 |
54 |
55 | func _disable_clear_button() -> void:
56 | clear_button.disabled = true
57 | clear_button.tooltip_text = "No terrain data to clear"
58 |
59 |
60 | func _enable_clear_button() -> void:
61 | clear_button.disabled = false
62 | clear_button.tooltip_text = "Clears all terrain data from selected tiles"
63 |
64 | # Creating individual sub-menus, as cannot tell which item is selected in PopupMenu()
65 | # PopupMenu.get_current_index() does not appear to exist in 4.0
66 | # https://github.com/godotengine/godot/pull/38520
67 | func _update_bit_button() -> void:
68 | bit_button_popup.clear()
69 | for child in bit_button_popup.get_children():
70 | child.queue_free()
71 |
72 | var terrain_bits_list : Array
73 | var terrain_set := tbt.BitData.NULL_TERRAIN_SET
74 |
75 | if tbt.tiles_manager.has_preview_terrain_set():
76 | terrain_set = tbt.tiles_manager.get_preview_terrain_set()
77 | terrain_bits_list = tbt.tiles_manager.preview_bit_data.get_terrain_bits_list(true)
78 | elif tbt.context.bit_data.has_terrain_set():
79 | terrain_set = tbt.context.bit_data.terrain_set
80 | terrain_bits_list = tbt.context.bit_data.get_terrain_bits_list(true)
81 | else:
82 | _disable_bit_button()
83 | return
84 |
85 | _enable_bit_button()
86 |
87 | var terrains_item_list := tbt.context.get_terrains_item_list(terrain_set)
88 |
89 | for terrain_bit in terrain_bits_list:
90 | var terrain_bit_name : String = tbt.texts.TERRAIN_BIT_TEXTS[terrain_bit]
91 | bit_button_popup.add_item(terrain_bit_name, terrain_bit)
92 | var idx := bit_button_popup.get_item_index(terrain_bit)
93 |
94 | var terrain_popup_name := _create_terrain_popup(terrain_bit, terrains_item_list)
95 |
96 | bit_button_popup.set_item_submenu(idx, terrain_popup_name)
97 |
98 |
99 | func _disable_bit_button() -> void:
100 | bit_button.disabled = true
101 | bit_button.tooltip_text = "Tiles must have a Terrain Set assigned"
102 |
103 |
104 | func _enable_bit_button() -> void:
105 | bit_button.disabled = false
106 | bit_button.tooltip_text = "Set a single terrain bit in selected tiles"
107 |
108 |
109 | func _create_terrain_popup(terrain_bit : int, item_list : Array) -> String:
110 | var terrain_popup := PopupMenu.new()
111 | terrain_popup.name = TERRAIN_POPUP + str(terrain_bit)
112 | bit_button_popup.add_child(terrain_popup)
113 | var _err := terrain_popup.id_pressed.connect(_on_bit_button_terrain_id_pressed.bind(terrain_bit))
114 |
115 | for item in item_list:
116 | terrain_popup.add_icon_item(item.icon, item.text, item.id)
117 | terrain_popup.add_item("", EMPTY_TERRAIN_ID)
118 |
119 | return terrain_popup.name
120 |
121 |
122 |
123 |
124 |
125 |
126 | func _populate_fill_menu() -> void:
127 | fill_button.get_popup().clear()
128 |
129 | var terrain_sets_count := tbt.context.tile_set.get_terrain_sets_count()
130 | if terrain_sets_count == 1:
131 | _populate_fill_menu_terrains(0)
132 | else:
133 | for i in range(terrain_sets_count):
134 | var id := fill_menu_items.size()
135 | fill_button.get_popup().add_item("Terrain Set [%s]" % i, id)
136 | fill_button.get_popup().set_item_disabled(id, true)
137 | fill_menu_items[id] = null
138 | _populate_fill_menu_terrains(i)
139 |
140 |
141 | func _populate_fill_menu_terrains(terrain_set : int) -> void:
142 | for i in range(tbt.context.tile_set.get_terrains_count(terrain_set)):
143 | var terrain_name := tbt.context.tile_set.get_terrain_name(terrain_set, i)
144 | var terrain_color := tbt.context.tile_set.get_terrain_color(terrain_set, i)
145 | var icon := _get_icon(terrain_color)
146 | var id := fill_menu_items.size()
147 | fill_button.get_popup().add_icon_item(icon, terrain_name, id)
148 | fill_menu_items[id] = {"terrain_set": terrain_set, "terrain": i}
149 |
150 |
151 | func _get_icon(p_color : Color) -> ImageTexture:
152 | var image := Image.create(16, 16, false, Image.FORMAT_RGB8)
153 | image.fill(p_color)
154 | return ImageTexture.create_from_image(image)
155 |
156 |
157 |
158 | func _on_fill_button_popup_id_pressed(id : int) -> void:
159 | if fill_menu_items[id] == null:
160 | return
161 | var terrain_set : int = fill_menu_items[id].terrain_set
162 | var terrain : int = fill_menu_items[id].terrain
163 | tbt.tiles_manager.fill_terrain(terrain_set, terrain)
164 |
165 |
166 | func _on_bit_button_terrain_id_pressed(terrain_id : int, terrain_bit : int) -> void:
167 | # print("terrain_bit=%s, terrain_id=%s" % [terrain_bit, terrain_id])
168 | if terrain_id == EMPTY_TERRAIN_ID:
169 | terrain_id = -1
170 | tbt.tiles_manager.set_terrain_bits(terrain_bit, terrain_id)
171 |
172 |
173 | func _on_erase_button_pressed() -> void:
174 | tbt.tiles_manager.erase_terrains()
175 |
176 | func _on_preview_updated(_arg) -> void:
177 | _update_buttons()
178 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tiles_inspector/tool_buttons/tool_buttons.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://b5nbqr8ah0ay2"]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/controls/tiles_inspector/tool_buttons/tool_buttons.gd" id="1_8r32g"]
4 | [ext_resource type="Script" path="res://addons/tile_bit_tools/controls/shared/icon_button.gd" id="3_hprs6"]
5 |
6 | [node name="ToolButtons" type="HFlowContainer"]
7 | anchors_preset = 10
8 | anchor_right = 1.0
9 | offset_bottom = 149.0
10 | grow_horizontal = 2
11 | theme_override_constants/h_separation = 16
12 | alignment = 1
13 | script = ExtResource("1_8r32g")
14 |
15 | [node name="FillButton" type="MenuButton" parent="." groups=["TBTToolButton"]]
16 | unique_name_in_owner = true
17 | custom_minimum_size = Vector2(123, 0)
18 | layout_mode = 2
19 | size_flags_horizontal = 4
20 | tooltip_text = "Fill all terrain bits in selected tiles"
21 | focus_mode = 2
22 | text = "Fill"
23 | flat = false
24 | alignment = 0
25 | script = ExtResource("3_hprs6")
26 | editor_name = "Bucket"
27 |
28 | [node name="BitButton" type="MenuButton" parent="." groups=["TBTToolButton"]]
29 | unique_name_in_owner = true
30 | custom_minimum_size = Vector2(123, 0)
31 | layout_mode = 2
32 | size_flags_horizontal = 4
33 | tooltip_text = "Fill all terrain bits with a single terrain"
34 | focus_mode = 2
35 | text = "Set Bits"
36 | flat = false
37 | alignment = 0
38 | script = ExtResource("3_hprs6")
39 | editor_name = "EditKey"
40 |
41 | [node name="ClearButton" type="Button" parent="." groups=["TBTToolButton"]]
42 | unique_name_in_owner = true
43 | layout_mode = 2
44 | size_flags_horizontal = 4
45 | size_flags_vertical = 0
46 | text = "Clear"
47 | alignment = 0
48 | script = ExtResource("3_hprs6")
49 | editor_name = "Clear"
50 |
51 | [connection signal="pressed" from="ClearButton" to="." method="_on_erase_button_pressed"]
52 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tiles_preview/terrain_opacity_slider.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends HSlider
3 |
4 |
5 | # exported nodes do not work in tool mode
6 | #@onready var current_bit_data_draw: Control = %CurrentBitDataDraw
7 | #@onready var preview_bit_data_draw: Control = %PreviewBitDataDraw
8 | #
9 | #
10 | #
11 | #func _ready() -> void:
12 | # value_changed.connect(_on_value_changed)
13 | # _update()
14 | #
15 | #
16 | #func _update() -> void:
17 | # _update_draw_layer_opacity(current_bit_data_draw)
18 | # _update_draw_layer_opacity(preview_bit_data_draw)
19 | #
20 | #
21 | #func _update_draw_layer_opacity(control : Control) -> void:
22 | # control.modulate.a = value
23 | # control.get_viewport().render_target_update_mode = SubViewport.UPDATE_ONCE
24 | #
25 | #func _on_value_changed(value : float) -> void:
26 | # _update()
27 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tiles_preview/tiles_preview.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Control
3 |
4 | const EMPTY_RECT := Rect2i(0,0,0,0)
5 | const FRAME_0 := 0
6 |
7 | const BACK_PANEL_MARGIN := 12
8 |
9 | const DEFAULT_TERRAIN_OPACITY := 0.75
10 |
11 | const TBTPlugin := preload("res://addons/tile_bit_tools/controls/tbt_plugin_control/tbt_plugin_control.gd")
12 |
13 |
14 | var tbt : TBTPlugin
15 |
16 | var preview_bit_data : TBTPlugin.EditorBitData
17 |
18 | var tile_rects : Dictionary
19 |
20 | var base_image : Image
21 |
22 | var image_crop_rect : Rect2i
23 |
24 | var initial_height : float
25 |
26 | var expanded := true
27 |
28 |
29 | @onready var back_panel: Panel = %BackPanel
30 | @onready var v_split_container: VSplitContainer = %VSplitContainer
31 | @onready var front_container: Container = %FrontContainer
32 |
33 |
34 | @onready var collapsed_controls: Control = %CollapsedControls
35 | @onready var expanded_controls: Control = %ExpandedControls
36 |
37 |
38 | @onready var preview_container: Container = %PreviewContainer
39 |
40 | @onready var current_tiles_view: Container = %CurrentTilesView
41 | @onready var preview_tiles_view: Container = %PreviewTilesView
42 | @onready var terrain_opacity_slider: HSlider = %TerrainOpacitySlider
43 |
44 | @onready var placeholder_label: RichTextLabel = %PlaceholderLabel
45 |
46 | @onready var reset_button: Button = %ResetButton
47 | @onready var apply_button: Button = %ApplyButton
48 |
49 | var ready_complete := false
50 |
51 |
52 |
53 | func _ready() -> void:
54 | ready_complete = true
55 | var _err := front_container.resized.connect(_on_front_container_resized)
56 | _connect_opacity_slider()
57 | _toggle_expanded_state(true)
58 |
59 |
60 | func _tbt_ready() -> void:
61 | var _err := tbt.tiles_inspector_added.connect(_on_tiles_inspector_added)
62 | _err = tbt.tiles_inspector_removed.connect(_on_tiles_inspector_removed)
63 | _err = tbt.preview_updated.connect(_on_preview_updated)
64 | _err = tbt.tiles_preview_expand_requested.connect(_on_tiles_preview_expand_requested)
65 | _err = tbt.tiles_preview_collapse_requested.connect(_on_tiles_preview_collapse_requested)
66 |
67 |
68 |
69 | # returns control to determine if mouse click is
70 | # in panel
71 | func get_mouse_input_rect() -> Rect2:
72 | var rect := back_panel.get_global_rect()
73 | rect.position = rect.position - Vector2(0, 6)
74 | rect.size = rect.size + Vector2(0, 6)
75 | return rect
76 |
77 |
78 | func _setup_textures() -> void:
79 | _update_base_texture()
80 | _update_current_terrain()
81 | _update_preview_terrain()
82 |
83 |
84 | func _clear_data() -> void:
85 | base_image = null
86 | preview_bit_data = null
87 | tile_rects.clear()
88 | image_crop_rect = EMPTY_RECT
89 | _update_preview_terrain()
90 |
91 |
92 | func _update_base_texture() -> void:
93 | _update_image_crop_rect()
94 | _create_base_image()
95 | var texture := ImageTexture.create_from_image(base_image)
96 | current_tiles_view.setup_base_tiles(texture, image_crop_rect.size)
97 | preview_tiles_view.setup_base_tiles(texture, image_crop_rect.size)
98 |
99 |
100 | func _connect_opacity_slider() -> void:
101 | var _err := terrain_opacity_slider.value_changed.connect(current_tiles_view.set_terrain_overlay_opacity)
102 | _err = terrain_opacity_slider.value_changed.connect(preview_tiles_view.set_terrain_overlay_opacity)
103 | terrain_opacity_slider.value = DEFAULT_TERRAIN_OPACITY
104 | terrain_opacity_slider.value_changed.emit(DEFAULT_TERRAIN_OPACITY)
105 |
106 |
107 | func _update_current_terrain() -> void:
108 | current_tiles_view.set_bit_data(tbt.context.bit_data)
109 |
110 |
111 |
112 | func _update_preview_terrain() -> void:
113 | if preview_bit_data:
114 | placeholder_label.hide()
115 | reset_button.show()
116 | preview_tiles_view.show()
117 | preview_tiles_view.set_bit_data(preview_bit_data)
118 | reset_button.disabled = false
119 | apply_button.disabled = false
120 |
121 | else:
122 | placeholder_label.show()
123 | reset_button.hide()
124 | preview_tiles_view.hide()
125 | preview_tiles_view.set_bit_data(null)
126 | reset_button.disabled = true
127 | apply_button.disabled = true
128 |
129 |
130 |
131 |
132 | func _create_base_image() -> void:
133 | var texture := tbt.context.source.texture
134 | base_image = texture.get_image().get_region(image_crop_rect)
135 |
136 |
137 | func _update_image_crop_rect() -> void:
138 | image_crop_rect = EMPTY_RECT
139 |
140 | for coords in tbt.context.tiles.keys():
141 | var rect := tbt.context.source.get_tile_texture_region(coords, FRAME_0)
142 | if image_crop_rect == EMPTY_RECT:
143 | image_crop_rect = rect
144 | else:
145 | image_crop_rect = image_crop_rect.merge(rect)
146 |
147 |
148 | func _on_preview_updated(bit_data : TBTPlugin.EditorBitData) -> void:
149 | preview_bit_data = bit_data
150 | _update_preview_terrain()
151 |
152 |
153 | func _on_front_container_resized() -> void:
154 | var front_height := front_container.size.y
155 | back_panel.custom_minimum_size.y = front_height + BACK_PANEL_MARGIN
156 |
157 |
158 | func _toggle_expanded_state(p_expanded : bool) -> void:
159 | if expanded == p_expanded:
160 | return
161 | expanded = p_expanded
162 | expanded_controls.visible = expanded
163 | collapsed_controls.visible = !expanded
164 |
165 |
166 | func _on_reset_button_pressed() -> void:
167 | tbt.reset_requested.emit()
168 |
169 |
170 | func _on_apply_button_pressed() -> void:
171 | tbt.apply_changes_requested.emit()
172 |
173 |
174 | func _on_expand_button_pressed() -> void:
175 | _toggle_expanded_state(true)
176 |
177 |
178 | func _on_collapse_button_pressed() -> void:
179 | _toggle_expanded_state(false)
180 |
181 |
182 | func _on_tiles_inspector_added() -> void:
183 | show()
184 | _setup_textures()
185 |
186 |
187 | func _on_tiles_inspector_removed() -> void:
188 | hide()
189 | _clear_data()
190 |
191 |
192 | func _on_tiles_preview_expand_requested() -> void:
193 | _toggle_expanded_state(true)
194 |
195 |
196 | func _on_tiles_preview_collapse_requested() -> void:
197 | _toggle_expanded_state(false)
198 |
199 |
200 | func _on_front_panel_collapsed_gui_input(event: InputEvent) -> void:
201 | if not event is InputEventMouseButton or !event.is_pressed():
202 | return
203 | if event.button_index != MOUSE_BUTTON_LEFT:
204 | return
205 | _toggle_expanded_state(true)
206 |
207 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tiles_preview/tiles_view.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Control
3 |
4 |
5 |
6 | const BitData := preload("res://addons/tile_bit_tools/core/bit_data.gd")
7 |
8 | var upscale_by_max_size := {
9 | 250 : 8,
10 | 500 : 4,
11 | 1000 : 2,
12 | }
13 |
14 |
15 |
16 | @onready var base_tiles_rect: TextureRect = %BaseTilesRect
17 | @onready var terrain_viewport: SubViewport = %TerrainViewport
18 | @onready var bit_data_draw: Control = %BitDataDraw
19 | @onready var terrain_overlay_rect: TextureRect = %TerrainOverlayRect
20 |
21 |
22 | func _ready() -> void:
23 | terrain_overlay_rect.texture = terrain_viewport.get_texture()
24 |
25 |
26 | func setup_base_tiles(texture : Texture2D, base_size : Vector2i) -> void:
27 | base_tiles_rect.texture = texture
28 | var upscale_factor := _get_upscale_factor(base_size)
29 | terrain_viewport.size = base_size * upscale_factor
30 | bit_data_draw.draw_size = base_size * upscale_factor
31 |
32 |
33 | func set_terrain_overlay_opacity(value : float) -> void:
34 | terrain_overlay_rect.modulate.a = value
35 |
36 |
37 | func set_bit_data(bit_data : BitData) -> void:
38 | bit_data_draw.bit_data = bit_data
39 | terrain_viewport.render_target_update_mode = SubViewport.UPDATE_ONCE
40 |
41 |
42 | func _get_upscale_factor(base_size : Vector2i) -> int:
43 | for max_size in upscale_by_max_size.keys():
44 | if base_size.x <= max_size && base_size.y <= max_size:
45 | return upscale_by_max_size[max_size]
46 | return 1
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/controls/tiles_preview/tiles_view.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=4 format=3 uid="uid://rt2lmg0mecbq"]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/controls/tiles_preview/tiles_view.gd" id="1_7t85k"]
4 | [ext_resource type="Script" path="res://addons/tile_bit_tools/controls/bit_data_draw/bit_data_draw.gd" id="1_kiwr1"]
5 |
6 | [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_d1ndd"]
7 |
8 | [node name="TilesView" type="PanelContainer"]
9 | size_flags_horizontal = 3
10 | theme_override_styles/panel = SubResource("StyleBoxEmpty_d1ndd")
11 | script = ExtResource("1_7t85k")
12 |
13 | [node name="TerrainViewport" type="SubViewport" parent="."]
14 | unique_name_in_owner = true
15 | disable_3d = true
16 | transparent_bg = true
17 | gui_snap_controls_to_pixels = false
18 | size = Vector2i(300, 300)
19 | render_target_update_mode = 1
20 |
21 | [node name="BitDataDraw" type="Control" parent="TerrainViewport"]
22 | unique_name_in_owner = true
23 | layout_mode = 3
24 | anchors_preset = 15
25 | anchor_right = 1.0
26 | anchor_bottom = 1.0
27 | grow_horizontal = 2
28 | grow_vertical = 2
29 | script = ExtResource("1_kiwr1")
30 |
31 | [node name="BaseTilesRect" type="TextureRect" parent="."]
32 | unique_name_in_owner = true
33 | layout_mode = 2
34 | stretch_mode = 5
35 |
36 | [node name="TerrainOverlayRect" type="TextureRect" parent="."]
37 | unique_name_in_owner = true
38 | layout_mode = 2
39 | expand_mode = 1
40 | stretch_mode = 5
41 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/core/bit_data.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Resource
3 |
4 |
5 | ## Redefined CellNeighbors enum to include center tile (terrain).
6 | ## Allows tile.terrain not to require separate logic when iterating.
7 | enum TerrainBits {
8 | CENTER=99,
9 | TOP_LEFT_CORNER=TileSet.CELL_NEIGHBOR_TOP_LEFT_CORNER,
10 | TOP_SIDE=TileSet.CELL_NEIGHBOR_TOP_SIDE,
11 | TOP_RIGHT_CORNER=TileSet.CELL_NEIGHBOR_TOP_RIGHT_CORNER,
12 | RIGHT_SIDE=TileSet.CELL_NEIGHBOR_RIGHT_SIDE,
13 | BOTTOM_RIGHT_CORNER=TileSet.CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER,
14 | BOTTOM_SIDE=TileSet.CELL_NEIGHBOR_BOTTOM_SIDE,
15 | BOTTOM_LEFT_CORNER=TileSet.CELL_NEIGHBOR_BOTTOM_LEFT_CORNER,
16 | LEFT_SIDE=TileSet.CELL_NEIGHBOR_LEFT_SIDE,
17 | }
18 |
19 | const NULL_TERRAIN_INDEX := -1
20 | const NULL_TERRAIN_SET := -1
21 | const NULL_TERRAIN_MODE := -1
22 |
23 | const BitData := preload("res://addons/tile_bit_tools/core/bit_data.gd")
24 |
25 | var CellNeighborsByMode := {
26 | TileSet.TerrainMode.TERRAIN_MODE_MATCH_CORNERS_AND_SIDES: [
27 | TileSet.CELL_NEIGHBOR_TOP_LEFT_CORNER,
28 | TileSet.CELL_NEIGHBOR_TOP_SIDE,
29 | TileSet.CELL_NEIGHBOR_TOP_RIGHT_CORNER,
30 | TileSet.CELL_NEIGHBOR_RIGHT_SIDE,
31 | TileSet.CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER,
32 | TileSet.CELL_NEIGHBOR_BOTTOM_SIDE,
33 | TileSet.CELL_NEIGHBOR_BOTTOM_LEFT_CORNER,
34 | TileSet.CELL_NEIGHBOR_LEFT_SIDE,
35 | ],
36 | TileSet.TerrainMode.TERRAIN_MODE_MATCH_CORNERS: [
37 | TileSet.CELL_NEIGHBOR_TOP_LEFT_CORNER,
38 | TileSet.CELL_NEIGHBOR_TOP_RIGHT_CORNER,
39 | TileSet.CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER,
40 | TileSet.CELL_NEIGHBOR_BOTTOM_LEFT_CORNER,
41 | ],
42 | TileSet.TerrainMode.TERRAIN_MODE_MATCH_SIDES: [
43 | TileSet.CELL_NEIGHBOR_TOP_SIDE,
44 | TileSet.CELL_NEIGHBOR_RIGHT_SIDE,
45 | TileSet.CELL_NEIGHBOR_BOTTOM_SIDE,
46 | TileSet.CELL_NEIGHBOR_LEFT_SIDE,
47 | ],
48 | }
49 |
50 |
51 | enum _TileKeys {TERRAIN, PEERING_BITS}
52 |
53 |
54 | # _tiles[coords : Vector2i][_TileKey]
55 | # TERRAIN = terrain_index
56 | # PEERING_BITS = Dictionary of {CellNeighbors : terrain_index}
57 | @export var _tiles := {}
58 |
59 | @export var terrain_set := NULL_TERRAIN_SET
60 | @export var terrain_mode := TileSet.TerrainMode.TERRAIN_MODE_MATCH_CORNERS_AND_SIDES
61 |
62 |
63 |
64 | # ITERATOR HELPERS
65 |
66 | # returns terrain bits in terrain_set's mode
67 | # center bit, if requested, will be listed first
68 | func get_terrain_bits_list(include_center_bit := false) -> Array:
69 | var list : Array = CellNeighborsByMode[terrain_mode].duplicate()
70 | if include_center_bit:
71 | list.push_front(TerrainBits.CENTER)
72 | return list
73 |
74 | # returns all terrain bits regardless of terrain_set's mode
75 | func get_all_terrain_bits(include_center_bit := false) -> Array:
76 | var list : Array = CellNeighborsByMode[TileSet.TerrainMode.TERRAIN_MODE_MATCH_CORNERS_AND_SIDES].duplicate()
77 | if include_center_bit:
78 | list.push_front(TerrainBits.CENTER)
79 | return list
80 |
81 |
82 | func get_coordinates_list() -> Array:
83 | return _tiles.keys()
84 |
85 |
86 | # RESOURCE DATA
87 | func has_data() -> bool:
88 | return get_tile_count() > 0
89 |
90 | func has_terrain_set() -> bool:
91 | return terrain_set != NULL_TERRAIN_SET
92 |
93 |
94 | func has_tile(coords : Vector2i) -> bool:
95 | return _tiles.has(coords)
96 |
97 |
98 | func get_tile_count() -> int:
99 | return _tiles.size()
100 |
101 |
102 | func get_terrain_count() -> int:
103 | return get_terrains().size()
104 |
105 |
106 | func get_terrains() -> Array:
107 | var terrains := []
108 | for coords in get_coordinates_list():
109 | for bit in get_terrain_bits_list(true):
110 | var terrain_index := get_bit_terrain(coords, bit)
111 | if !terrains.has(terrain_index):
112 | terrains.append(terrain_index)
113 | return terrains
114 |
115 |
116 | # ATLAS RECT
117 | func get_atlas_offset() -> Vector2i:
118 | return get_atlas_rect().position
119 |
120 |
121 | func get_atlas_rect() -> Rect2i:
122 | return _get_rect_from_points(_tiles.keys())
123 |
124 |
125 | func _get_rect_from_points(p_points : Array) -> Rect2i:
126 | var points := p_points.duplicate(true)
127 | points.sort_custom(func(a,b): return a.x < b.x)
128 | var x : int = points.front().x
129 | var width : int = points.back().x + 1 - x
130 | points.sort_custom(func(a,b): return a.y < b.y)
131 | var y : int = points.front().y
132 | var height : int = points.back().y + 1 - y
133 | return Rect2i(x,y,width,height)
134 |
135 |
136 |
137 | # TERRAIN DATA
138 | func set_tile_terrain(coords : Vector2i, terrain_index : int) -> void:
139 | _tiles[coords][_TileKeys.TERRAIN] = terrain_index
140 |
141 |
142 | func get_tile_terrain(coords : Vector2i) -> int:
143 | return _tiles[coords].get(_TileKeys.TERRAIN, NULL_TERRAIN_INDEX)
144 |
145 |
146 | func set_bit_terrain(coords : Vector2i, bit : TerrainBits, terrain_index : int) -> void:
147 | if bit == TerrainBits.CENTER:
148 | set_tile_terrain(coords, terrain_index)
149 | return
150 | _tiles[coords][_TileKeys.PEERING_BITS][bit] = terrain_index
151 |
152 |
153 | func get_bit_terrain(coords : Vector2i, bit : TerrainBits) -> int:
154 | if bit == TerrainBits.CENTER:
155 | return get_tile_terrain(coords)
156 | return _tiles[coords][_TileKeys.PEERING_BITS].get(bit, NULL_TERRAIN_INDEX)
157 |
158 |
159 | func get_bit_color(coords : Vector2i, bit : TerrainBits) -> Color:
160 | var terrain_index := get_bit_terrain(coords, bit)
161 | return get_terrain_color(terrain_index)
162 |
163 |
164 | func get_terrain_color(_terrain_index : int) -> Color:
165 | # override this function
166 | return Color.BLACK
167 |
168 |
169 | func get_terrain_colors_dict() -> Dictionary:
170 | var d := {}
171 | for i in get_terrains():
172 | d[i] = get_terrain_color(i)
173 | return d
174 |
175 |
176 |
177 | func _add_tile(coords : Vector2i, terrain_index := NULL_TERRAIN_INDEX) -> void:
178 | assert(!_tiles.has(coords))
179 |
180 | _tiles[coords] = {
181 | _TileKeys.TERRAIN: terrain_index,
182 | _TileKeys.PEERING_BITS: {},
183 | }
184 |
185 |
186 | # TERRAIN MANIPULATION
187 |
188 | ## Sets all tiles' terrain and peering_bits to terrain_index
189 | func fill_all_tile_terrains(p_terrain_set : int, p_terrain_mode : TileSet.TerrainMode, terrain_index : int) -> void:
190 | terrain_set = p_terrain_set
191 | terrain_mode = p_terrain_mode
192 |
193 | for coords in get_coordinates_list():
194 | fill_tile_terrains(coords, terrain_index)
195 |
196 |
197 | ## Sets a single tile's terrain and peering_bits to terrain_index
198 | func fill_tile_terrains(coords : Vector2i, terrain_index : int) -> void:
199 | _clear_tile_peering_bits(coords)
200 | set_tile_terrain(coords, terrain_index)
201 |
202 | if terrain_index == NULL_TERRAIN_INDEX:
203 | return
204 |
205 | for bit in get_terrain_bits_list():
206 | set_bit_terrain(coords, bit, terrain_index)
207 |
208 |
209 | func clear_all_tile_terrains() -> void:
210 | terrain_set = NULL_TERRAIN_SET
211 | # do not need to clear terrain_mode as it is only used internally
212 |
213 | for coords in get_coordinates_list():
214 | clear_tile_terrains(coords)
215 |
216 |
217 | func clear_tile_terrains(coords : Vector2i) -> void:
218 | set_tile_terrain(coords, NULL_TERRAIN_INDEX)
219 | _clear_tile_peering_bits(coords)
220 |
221 |
222 | func replace_all_tile_terrains(old_terrain_index : int, new_terrain_index : int) -> void:
223 | for coords in get_coordinates_list():
224 | replace_tile_terrains(coords, old_terrain_index, new_terrain_index)
225 |
226 |
227 | func replace_tile_terrains(coords : Vector2i, old_terrain_index : int, new_terrain_index : int) -> void:
228 | # includes tile.terrain
229 | for bit in get_terrain_bits_list(true):
230 | if get_bit_terrain(coords, bit) == old_terrain_index:
231 | set_bit_terrain(coords, bit, new_terrain_index)
232 |
233 |
234 | func set_all_bit_terrains(terrain_bit : TerrainBits, terrain_index : int) -> void:
235 | for coords in get_coordinates_list():
236 | set_bit_terrain(coords, terrain_bit, terrain_index)
237 |
238 |
239 |
240 | func _clear_tile_peering_bits(coords : Vector2i) -> void:
241 | _tiles[coords][_TileKeys.PEERING_BITS].clear()
242 |
243 |
244 |
245 |
246 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/core/context.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Node
3 |
4 |
5 | const G := preload("res://addons/tile_bit_tools/core/globals.gd")
6 | const EditorBitData := preload("res://addons/tile_bit_tools/core/editor_bit_data.gd")
7 |
8 | const Icons := preload("res://addons/tile_bit_tools/core/icons.gd")
9 |
10 | #var _print := preload("res://addons/tile_bit_tools/core/output.gd").new()
11 | var texts := preload("res://addons/tile_bit_tools/core/texts.gd").new()
12 |
13 |
14 | var tile_set : TileSet
15 | var source : TileSetAtlasSource
16 | var tiles : Dictionary
17 |
18 | var bit_data : EditorBitData
19 |
20 | var base_control : Control
21 |
22 | # {index : terrain_mode}
23 | var terrain_sets := {}
24 |
25 | # {terrain_set : [{
26 | # "index": terrain_index,
27 | # "color": color,
28 | # "name": name,
29 | #},...]}
30 | var terrains_by_set := {}
31 |
32 | var ready_complete := false
33 |
34 |
35 | func _ready() -> void:
36 | ready_complete = true
37 |
38 |
39 | func finish_setup() -> G.Errors:
40 | var validate_result := validate()
41 | if validate_result != OK:
42 | return validate_result
43 |
44 | bit_data = EditorBitData.new()
45 | var bit_data_result := bit_data.load_from_tile_data(tiles, tile_set)
46 | if bit_data_result != OK:
47 | return bit_data_result
48 |
49 | _populate_terrain_sets()
50 | _populate_terrains()
51 |
52 | return G.Errors.OK
53 |
54 |
55 | func validate() -> G.Errors:
56 | if tile_set.tile_shape != TileSet.TILE_SHAPE_SQUARE:
57 | return G.Errors.UNSUPPORTED_SHAPE
58 | return G.Errors.OK
59 |
60 |
61 | func _populate_terrain_sets() -> void:
62 | for i in range(tile_set.get_terrain_sets_count()):
63 | terrain_sets[i] = tile_set.get_terrain_set_mode(i)
64 |
65 |
66 | func _populate_terrains() -> void:
67 | for terrain_set in terrain_sets.keys():
68 | terrains_by_set[terrain_set] = []
69 | for i in range(tile_set.get_terrains_count(terrain_set)):
70 | terrains_by_set[terrain_set].append({
71 | "id": i,
72 | "text": tile_set.get_terrain_name(terrain_set, i),
73 | "color": tile_set.get_terrain_color(terrain_set, i),
74 | "icon": get_terrain_icon(tile_set.get_terrain_color(terrain_set, i))
75 | })
76 |
77 |
78 | func get_terrain_icon(color : Color) -> ImageTexture:
79 | var image := Image.create(16, 16, false, Image.FORMAT_RGB8)
80 | image.fill(color)
81 | return ImageTexture.create_from_image(image)
82 |
83 |
84 | func get_terrain_sets() -> Array:
85 | return terrain_sets.keys()
86 |
87 |
88 | func get_terrain_sets_by_mode(terrain_mode : TileSet.TerrainMode) -> Array:
89 | var terrain_set_list := []
90 | for index in terrain_sets.keys():
91 | if terrain_sets[index] == terrain_mode:
92 | terrain_set_list.append(index)
93 | return terrain_set_list
94 |
95 |
96 | func get_terrain_sets_item_list(terrain_mode : TileSet.TerrainMode) -> Array:
97 | var icons := Icons.new(base_control)
98 |
99 | var terrain_set_list := []
100 | for index in terrain_sets.keys():
101 | if terrain_sets[index] == terrain_mode:
102 | terrain_set_list.append({
103 | "id": index,
104 | "terrain_mode": terrain_mode,
105 | "text": "[%s]" % [index],
106 | "icon": icons.get_icon(icons.TERRAIN_MODE_ICONS[terrain_mode]),
107 | })
108 | return terrain_set_list
109 |
110 |
111 | func get_terrains_item_list(terrain_set : int) -> Array:
112 | return terrains_by_set[terrain_set]
113 |
114 |
115 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/core/editor_bit_data.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends "res://addons/tile_bit_tools/core/bit_data.gd"
3 |
4 | const G := preload("res://addons/tile_bit_tools/core/globals.gd")
5 | const TemplateBitData := preload("res://addons/tile_bit_tools/core/template_bit_data.gd")
6 | const EditorBitData := preload("res://addons/tile_bit_tools/core/editor_bit_data.gd")
7 |
8 | var output := preload("res://addons/tile_bit_tools/core/output.gd").new()
9 |
10 | var tile_set : TileSet
11 |
12 |
13 |
14 | func make_copy() -> EditorBitData:
15 | var bit_data_copy := self.duplicate()
16 | bit_data_copy._tiles = _tiles.duplicate(true)
17 | bit_data_copy.tile_set = tile_set
18 | return bit_data_copy
19 |
20 |
21 |
22 |
23 |
24 | func get_terrain_color(terrain_index : int) -> Color:
25 | if terrain_index == NULL_TERRAIN_INDEX:
26 | return Color.TRANSPARENT
27 | return tile_set.get_terrain_color(terrain_set, terrain_index)
28 |
29 |
30 |
31 |
32 | ## terrain_mapping: {template terrain_index : tile_set terrain_index}
33 | func apply_template_bit_data(template_bit_data : TemplateBitData, p_terrain_set : int, terrain_mapping : Dictionary) -> G.Errors:
34 | clear_all_tile_terrains()
35 |
36 | terrain_set = p_terrain_set
37 | terrain_mode = template_bit_data.terrain_mode
38 | if tile_set.get_terrain_set_mode(terrain_set) != terrain_mode:
39 | return G.Errors.FAILED
40 |
41 | var offset := get_atlas_offset()
42 |
43 | for coords in get_coordinates_list():
44 | var template_coords = coords - offset
45 | if !template_bit_data.has_tile(template_coords):
46 | continue
47 | for bit in get_terrain_bits_list(true):
48 | var template_terrain_index := template_bit_data.get_bit_terrain(template_coords, bit)
49 | var terrain_index = terrain_mapping[template_terrain_index]
50 | set_bit_terrain(coords, bit, terrain_index)
51 |
52 | return G.Errors.OK
53 |
54 |
55 |
56 | ## Loads TileData into BitData resource;
57 | ## p_tiles = Dict{coords : TileData}
58 | func load_from_tile_data(p_tiles : Dictionary, p_tile_set : TileSet) -> G.Errors:
59 | # only allow loading into empty resource
60 | if has_data():
61 | return G.Errors.FAILED
62 | if p_tiles.size() == 0:
63 | return G.Errors.MISSING_TILES
64 |
65 | tile_set = p_tile_set
66 |
67 | var result := _load_tiles(p_tiles)
68 | if terrain_set == NULL_TERRAIN_SET:
69 | # if there is only one terrain set, assign it to the bit data
70 | # this allows using the set bits button on tiles that don't have
71 | # any terrain data yet
72 | var terrain_sets_count := tile_set.get_terrain_sets_count()
73 | if terrain_sets_count == 1:
74 | terrain_set = 0
75 |
76 | return result
77 |
78 |
79 | func _load_tiles(p_tiles : Dictionary) -> G.Errors:
80 | # output.user("Fetching current terrain bits now. Unassigned terrain bits will result in [i]Condition '!is_valid_terrain_peering_bit(p_peering_bit)' is true.[/i] Please ignore.")
81 |
82 | for coords in p_tiles.keys():
83 | _add_tile(coords)
84 |
85 | var tile_data : TileData = p_tiles[coords]
86 | if tile_data.terrain_set == NULL_TERRAIN_SET:
87 | # editor does not allow adding terrain without terrain set
88 | # so TileData will not have any terrain data
89 | continue
90 |
91 | var error := _load_terrain_set(tile_data)
92 | if error:
93 | return error
94 |
95 | _load_terrain(coords, tile_data)
96 |
97 | return G.Errors.OK
98 |
99 |
100 | func _load_terrain_set(tile_data : TileData) -> G.Errors:
101 | # output.debug("terrain_set=%s, TileData terrain_set=%s" % [terrain_set, tile_data.terrain_set])
102 |
103 | if terrain_set == NULL_TERRAIN_SET:
104 | terrain_set = tile_data.terrain_set
105 | # output.debug("Assigning terrain_set => %s" % tile_data.terrain_set)
106 | terrain_mode = tile_set.get_terrain_set_mode(terrain_set)
107 | return G.Errors.OK
108 |
109 | if terrain_set != tile_data.terrain_set:
110 | # output.debug("Multiple terrain sets")
111 | return G.Errors.MULTIPLE_TERRAIN_SETS
112 |
113 | return G.Errors.OK
114 |
115 |
116 | # if a peering bit is unset, get_terrain_peering_bit() sometimes causes error spam
117 | # of "!is_valid_terrain_peering_bit(p_peering_bit)" is true"
118 | func _load_terrain(coords : Vector2i, tile_data : TileData) -> void:
119 | set_tile_terrain(coords, tile_data.terrain)
120 |
121 | for bit in get_terrain_bits_list():
122 | set_bit_terrain(coords, bit, tile_data.get_terrain_peering_bit(bit))
123 |
124 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/core/globals.gd:
--------------------------------------------------------------------------------
1 | extends RefCounted
2 |
3 | const VERSION := "1.1.0"
4 |
5 | # ------------------------
6 | # ENUMS
7 | # ------------------------
8 |
9 | enum Errors {
10 | NULL_ERROR = -999,
11 | OK = Error.OK,
12 | FAILED = Error.FAILED,
13 | MISSING_TILE_SET = 900,
14 | MISSING_SOURCE = 901,
15 | MISSING_TILES = 902,
16 | MISSING_BIT_DATA = 903,
17 | INVALID_TBT_PLUGIN_CONTROL=904,
18 | INVALID_TILES_PREVIEW=905,
19 | MULTIPLE_TERRAIN_SETS = 910,
20 | UNSUPPORTED_SHAPE = 911,
21 |
22 | }
23 |
24 |
25 | enum TemplateTypes {BUILT_IN, USER}
26 |
27 |
28 |
29 | # ------------------------
30 | # PATHS
31 | # ------------------------
32 |
33 | const BUILTIN_TEMPLATES_PATH := "res://addons/tile_bit_tools/templates/"
34 | const GODOT_TEMPLATES_FOLDER := "/Godot/tile_bit_tools_templates/"
35 | const PROJECT_TEMPLATES_PATH := "user://addons/tile_bit_tools/templates/"
36 |
37 | # ------------------------
38 | # USER SETTINGS
39 | # ------------------------
40 |
41 | const PROJECT_SETTINGS_PATH := "addons/tile_bit_tools/"
42 |
43 | const Settings := {
44 | "user_templates_path": {
45 | "path": PROJECT_SETTINGS_PATH + "paths/user_templates_path",
46 | "default": "",
47 | "type": TYPE_STRING,
48 | "hint_string": PROPERTY_HINT_DIR,
49 | },
50 | "output_show_user": {
51 | "path": PROJECT_SETTINGS_PATH + "output/show_user_messages",
52 | "default": true,
53 | "type": TYPE_BOOL,
54 | },
55 | "output_show_info": {
56 | "path": PROJECT_SETTINGS_PATH + "output/show_info_messages",
57 | "default": false,
58 | "type": TYPE_BOOL,
59 | },
60 | "output_show_debug": {
61 | "path": PROJECT_SETTINGS_PATH + "output/show_debug_messages",
62 | "default": false,
63 | "type": TYPE_BOOL,
64 | },
65 | # Default colors from the "bright" color scheme at
66 | # https://personal.sron.nl/~pault/
67 | "colors_terrain_01": {
68 | "path": PROJECT_SETTINGS_PATH + "colors/template_terrain_1",
69 | "default": Color("AA3377"), # pink
70 | "type": TYPE_COLOR,
71 | },
72 | "colors_terrain_02": {
73 | "path": PROJECT_SETTINGS_PATH + "colors/template_terrain_2",
74 | "default": Color("CCBB44"), # yellow
75 | "type": TYPE_COLOR,
76 | },
77 | "colors_terrain_03": {
78 | "path": PROJECT_SETTINGS_PATH + "colors/template_terrain_3",
79 | "default": Color("228833"), # green
80 | "type": TYPE_COLOR,
81 | },
82 | "colors_terrain_04": {
83 | "path": PROJECT_SETTINGS_PATH + "colors/template_terrain_4",
84 | "default": Color("66ccee"), # cyan
85 | "type": TYPE_COLOR,
86 | },
87 | }
88 |
89 |
90 | # ------------------------
91 | # GROUPS
92 | # ------------------------
93 |
94 |
95 | const GROUP_DYNAMIC_CONTAINER := "TBTDynamicContainer"
96 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/core/icons.gd:
--------------------------------------------------------------------------------
1 | extends RefCounted
2 |
3 |
4 | const TERRAIN_MODE_ICONS := {
5 | TileSet.TerrainMode.TERRAIN_MODE_MATCH_CORNERS_AND_SIDES : ["TerrainMatchCornersAndSides", "EditorIcons"],
6 | TileSet.TerrainMode.TERRAIN_MODE_MATCH_CORNERS : ["TerrainMatchCorners", "EditorIcons"],
7 | TileSet.TerrainMode.TERRAIN_MODE_MATCH_SIDES : ["TerrainMatchSides", "EditorIcons"],
8 | }
9 |
10 | const EXPAND_PANEL := ["ExpandTree", "EditorIcons"]
11 | const COLLAPSE_PANEL := ["CollapseTree", "EditorIcons"]
12 |
13 | const ARROW_EXPANDED := ["arrow", "Tree"]
14 | const ARROW_COLLAPSED := ["arrow_collapsed", "Tree"]
15 |
16 |
17 | var control : Control
18 |
19 | func _init(p_control : Control) -> void:
20 | control = p_control
21 |
22 |
23 | func get_icon(icon_data : Array) -> Texture2D:
24 | return control.get_theme_icon(icon_data[0], icon_data[1])
25 |
26 |
27 | func get_icon_by_name(icon_name : String) -> Texture2D:
28 | var icon_data = get(icon_name)
29 | if icon_data == null:
30 | return null
31 | return get_icon(icon_data)
32 |
33 |
34 | func get_icon_by_editor_name(editor_name : String) -> Texture2D:
35 | return control.get_theme_icon(editor_name, "EditorIcons")
36 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/core/output.gd:
--------------------------------------------------------------------------------
1 | extends RefCounted
2 |
3 |
4 |
5 | enum MessageTypes {USER, INFO, DEBUG}
6 |
7 |
8 | const OUTPUT_TEMPLATE := "[color=palegreen]TileBitTools:[/color] %s"
9 | const COLOR_TEMPLATE := "[color={color}]{msg}[/color]"
10 |
11 | const ERROR_TEXT_TEMPLATE := "{error_text} (ERR {error})"
12 | const ERROR_CODE_TEMPLATE := "(ERR {error})"
13 | const OK_CODE_TEMPLATE := "(OK)"
14 |
15 | const MESSAGE_ERROR_TEMPLATE := "{msg} ({error_string})"
16 |
17 | const DEFAULT_ERROR_TEXT := "An error occurred"
18 | const ERROR_COLOR := "salmon"
19 | const WARNING_COLOR := "yellow"
20 | const OK_COLOR := "palegreen"
21 |
22 | const G := preload("res://addons/tile_bit_tools/core/globals.gd")
23 |
24 | var texts := preload("res://addons/tile_bit_tools/core/texts.gd").new()
25 |
26 |
27 | var message_type_settings := {
28 | MessageTypes.USER: G.Settings.output_show_user.path,
29 | MessageTypes.INFO: G.Settings.output_show_info.path,
30 | MessageTypes.DEBUG: G.Settings.output_show_debug.path,
31 | }
32 |
33 | var message_type_text_color := {
34 | MessageTypes.INFO: "webgray",
35 | MessageTypes.DEBUG: "palegoldenrod",
36 | }
37 |
38 |
39 | func user(msg, p_error := G.Errors.NULL_ERROR) -> void:
40 | _print_msg(msg, p_error, MessageTypes.USER)
41 |
42 |
43 | func info(msg : String, p_error := G.Errors.NULL_ERROR) -> void:
44 | _print_msg(msg, p_error, MessageTypes.INFO)
45 |
46 |
47 | func debug(msg : String, p_error := G.Errors.NULL_ERROR) -> void:
48 | _print_msg(msg, p_error, MessageTypes.DEBUG)
49 |
50 |
51 | func error(msg : String, p_error : int = G.Errors.NULL_ERROR) -> void:
52 | if p_error != G.Errors.NULL_ERROR:
53 | msg = ERROR_TEXT_TEMPLATE.format({
54 | "error_text": msg,
55 | "error": error,
56 | })
57 | msg = COLOR_TEMPLATE.format({
58 | "color": ERROR_COLOR,
59 | "msg": msg,
60 | })
61 |
62 | _print_msg(msg, G.Errors.NULL_ERROR, MessageTypes.DEBUG)
63 |
64 |
65 | func warning(msg : String, p_error : int = G.Errors.NULL_ERROR) -> void:
66 | if p_error != G.Errors.NULL_ERROR:
67 | msg = ERROR_TEXT_TEMPLATE.format({
68 | "error_text": msg,
69 | "error": error,
70 | })
71 | msg = COLOR_TEMPLATE.format({
72 | "color": WARNING_COLOR,
73 | "msg": msg,
74 | })
75 |
76 | _print_msg(msg, G.Errors.NULL_ERROR, MessageTypes.DEBUG)
77 |
78 |
79 |
80 |
81 |
82 | func _print_msg(msg, p_error : G.Errors, msg_type : MessageTypes) -> void:
83 | if !_is_message_type_enabled(msg_type):
84 | return
85 |
86 | if msg is G.Errors:
87 | _print_error(msg, msg_type)
88 | return
89 |
90 | if p_error != G.Errors.NULL_ERROR:
91 | msg = MESSAGE_ERROR_TEMPLATE.format({
92 | "msg": msg,
93 | "error_string": _get_error_string(p_error, true),
94 | })
95 |
96 | _format_and_print(msg, msg_type)
97 |
98 |
99 |
100 | func _print_error(p_error : G.Errors, msg_type : MessageTypes) -> void:
101 | var msg := _get_error_string(p_error)
102 | _format_and_print(msg, msg_type)
103 |
104 |
105 | func _format_and_print(msg : String, msg_type : MessageTypes) -> void:
106 | msg = _format_color(msg, msg_type)
107 | print_rich(OUTPUT_TEMPLATE % msg)
108 |
109 |
110 | func _format_color(msg : String, msg_type : MessageTypes) -> String:
111 | if message_type_text_color.has(msg_type):
112 | msg = COLOR_TEMPLATE.format({
113 | "color": message_type_text_color[msg_type],
114 | "msg": msg,
115 | })
116 |
117 | return msg
118 |
119 |
120 | func _format_error(msg : String, p_error : G.Errors) -> String:
121 | msg = "TileBitTools: %s" % msg
122 | msg = msg + "(ERR %s)" % p_error if p_error != -1 else msg
123 | return msg
124 |
125 |
126 | func _is_message_type_enabled(msg_type : MessageTypes) -> bool:
127 | var value = ProjectSettings.get_setting(message_type_settings[msg_type])
128 | if value == null:
129 | return false
130 | return value
131 |
132 |
133 | func _get_error_string(p_error : G.Errors, skip_text_if_null := false) -> String:
134 | var error_text : String
135 | if skip_text_if_null:
136 | error_text = texts.ERROR_TEXTS.get(error, "")
137 | else:
138 | error_text = texts.ERROR_TEXTS.get(error, DEFAULT_ERROR_TEXT)
139 |
140 | var error_template : String
141 | if error_text == "":
142 | error_template = ERROR_CODE_TEMPLATE
143 | else:
144 | error_template = ERROR_TEXT_TEMPLATE
145 |
146 | var s := error_template.format({
147 | "error_text": error_text,
148 | "error": error,
149 | })
150 |
151 | var error_color : String
152 | if p_error == G.Errors.OK:
153 | error_color = OK_COLOR
154 | else:
155 | error_color = ERROR_COLOR
156 |
157 | return COLOR_TEMPLATE.format({
158 | "color": error_color,
159 | "msg": s,
160 | })
161 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/core/template_bit_data.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends "res://addons/tile_bit_tools/core/bit_data.gd"
3 |
4 | const additional_colors := [Color.RED, Color.BLUE, Color.YELLOW, Color.GREEN, Color.REBECCA_PURPLE, Color.WHEAT, Color.AQUA, Color.SALMON, Color.CHOCOLATE, Color.VIOLET, Color.CADET_BLUE, Color.NAVY_BLUE, Color.MAGENTA, Color.LAWN_GREEN, Color.KHAKI, Color.HOT_PINK, Color.FIREBRICK, Color.DARK_OLIVE_GREEN, Color.SADDLE_BROWN]
5 |
6 | const G := preload("res://addons/tile_bit_tools/core/globals.gd")
7 | const EditorBitData := preload("res://addons/tile_bit_tools/core/editor_bit_data.gd")
8 | const TemplateBitData := preload("res://addons/tile_bit_tools/core/template_bit_data.gd")
9 |
10 | var template_tag_data := preload("res://addons/tile_bit_tools/core/template_tag_data.gd").new()
11 |
12 | @export var version : String
13 | @export var template_name : String
14 | @export var template_description : String
15 | @export var _custom_tags := []
16 | @export var template_terrain_count : int
17 | @export var example_folder_path : String
18 |
19 | var built_in := false
20 | var preview_texture : Texture2D
21 |
22 | var terrain_colors := {
23 | -1: Color.TRANSPARENT,
24 | 0: ProjectSettings.get_setting(G.Settings.colors_terrain_01.path) if ProjectSettings.get_setting(G.Settings.colors_terrain_01.path) != null else additional_colors[0],
25 | 1: ProjectSettings.get_setting(G.Settings.colors_terrain_02.path) if ProjectSettings.get_setting(G.Settings.colors_terrain_02.path) != null else additional_colors[1],
26 | 2: ProjectSettings.get_setting(G.Settings.colors_terrain_03.path) if ProjectSettings.get_setting(G.Settings.colors_terrain_03.path) != null else additional_colors[2],
27 | 3: ProjectSettings.get_setting(G.Settings.colors_terrain_04.path) if ProjectSettings.get_setting(G.Settings.colors_terrain_04.path) != null else additional_colors[3],
28 | }
29 |
30 |
31 | ## Attempts to return the template terrain color set in Project Settings
32 | ## If index is too high, returns a color constant from additional_colors
33 | func get_terrain_color(terrain_index : int) -> Color:
34 | return terrain_colors.get(terrain_index, additional_colors[terrain_index])
35 |
36 |
37 | func get_custom_tags() -> Array:
38 | return _custom_tags
39 |
40 |
41 | func load_editor_bit_data(bit_data : EditorBitData) -> G.Errors:
42 | var result := _validate_editor_source(bit_data)
43 | if result != OK:
44 | return result
45 |
46 | # terrain_set will remain NULL_TERRAIN_SET (-1)
47 | terrain_mode = bit_data.terrain_mode
48 | var terrain_mapping := _get_terrain_mapping(bit_data)
49 | _load_tiles(bit_data, terrain_mapping)
50 |
51 | return G.Errors.OK
52 |
53 |
54 | func _validate_editor_source(bit_data : EditorBitData) -> G.Errors:
55 | if has_data():
56 | return G.Errors.FAILED
57 | if bit_data.get_tile_count() == 0:
58 | return G.Errors.FAILED
59 | if bit_data.get_terrain_count() == 0:
60 | return G.Errors.FAILED
61 | return G.Errors.OK
62 |
63 |
64 | ## Sort terrains by frequency and return mapping
65 | ## with highest frequency = 0
66 | func _get_terrain_mapping(bit_data : EditorBitData) -> Dictionary:
67 | var terrains_by_count := {}
68 | for coords in bit_data.get_coordinates_list():
69 | var terrain_index : int = bit_data.get_tile_terrain(coords)
70 | if terrains_by_count.has(terrain_index):
71 | terrains_by_count[terrain_index] += 1
72 | else:
73 | terrains_by_count[terrain_index] = 0
74 | var terrains := terrains_by_count.keys().duplicate()
75 | terrains.sort_custom(func(a, b): return terrains_by_count[a] > terrains_by_count[b])
76 | var terrain_mapping := {}
77 | for i in range(terrains.size()):
78 | terrain_mapping[terrains[i]] = i
79 | return terrain_mapping
80 |
81 |
82 | func _load_tiles(bit_data : EditorBitData, terrain_mapping : Dictionary) -> void:
83 | var offset := bit_data.get_atlas_offset()
84 | var next_template_terrain := terrain_mapping.size()
85 |
86 | for coords in bit_data.get_coordinates_list():
87 | var template_coords : Vector2i = coords - offset
88 | _add_tile(template_coords)
89 |
90 | for bit in bit_data.get_terrain_bits_list(true):
91 | var editor_terrain := bit_data.get_bit_terrain(coords, bit)
92 | if !terrain_mapping.has(editor_terrain):
93 | var template_terrain := next_template_terrain
94 | terrain_mapping[editor_terrain] = template_terrain
95 | next_template_terrain += 1
96 |
97 | set_bit_terrain(template_coords, bit, terrain_mapping[editor_terrain])
98 |
99 | template_terrain_count = terrain_mapping.keys().size()
100 |
101 |
102 |
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/core/template_loader.gd:
--------------------------------------------------------------------------------
1 | extends RefCounted
2 |
3 |
4 |
5 | const TAG_NOT_FOUND := null
6 |
7 | const G := preload("res://addons/tile_bit_tools/core/globals.gd")
8 |
9 | const TemplateBitData := preload("res://addons/tile_bit_tools/core/template_bit_data.gd")
10 | const TemplateTagData := preload("res://addons/tile_bit_tools/core/template_tag_data.gd")
11 | const TemplateTag := TemplateTagData.TemplateTag
12 |
13 | var _template_tag_data := TemplateTagData.new()
14 |
15 |
16 |
17 | var output := preload("res://addons/tile_bit_tools/core/output.gd").new()
18 |
19 | var _templates := []
20 | var _tags := []
21 |
22 | # {tag_id : [template_id, ...]}
23 | var _tags_to_templates := {}
24 | # {template_id : [tag_id, ...]}
25 | var _templates_to_tags := {}
26 |
27 | # {text : tag_id}
28 | var _custom_tags := {}
29 |
30 | var _display_tag_ids := []
31 |
32 |
33 |
34 | func _init(template_folder_paths : Array) -> void:
35 | _load_auto_tags()
36 | _load_templates(template_folder_paths)
37 | _setup_sorted_tag_ids()
38 |
39 |
40 | func _load_templates(template_folder_paths : Array) -> void:
41 | var paths_parsed := []
42 |
43 | for folder_path in template_folder_paths:
44 | # don't load from duplicate folders
45 | if folder_path in paths_parsed:
46 | continue
47 | paths_parsed.append(folder_path)
48 |
49 | _load_templates_in_directory(
50 | folder_path.path,
51 | folder_path.type == G.TemplateTypes.BUILT_IN
52 | )
53 |
54 |
55 | #func print_templates_by_tag() -> void:
56 | # for tag_id in _tags_to_templates.keys():
57 | # var tag : TemplateTag = _tags[tag_id]
58 | # print()
59 | # print(tag.text)
60 | # for template_id in _tags_to_templates[tag_id]:
61 | # var template : TemplateBitData = _templates[template_id]
62 | # print(template.template_name)
63 |
64 |
65 |
66 | # takes the auto tags in specified order (skipping any not in list),
67 | # then adds custom tags alphabetically
68 | func _setup_sorted_tag_ids() -> void:
69 | for tag_enum_id in _template_tag_data.tag_display:
70 | var tag_id := get_tag_id(_template_tag_data.tags[tag_enum_id])
71 | if tag_id == -1:
72 | output.error("Unable to find auto tag %s" % tag_enum_id)
73 | continue
74 | _display_tag_ids.append(tag_id)
75 |
76 | var sorted_custom_tag_texts := _custom_tags.keys().duplicate()
77 | sorted_custom_tag_texts.sort_custom(func(a,b): return a.to_lower() < b.to_lower())
78 |
79 | for tag_text in sorted_custom_tag_texts:
80 | _display_tag_ids.append(_custom_tags[tag_text])
81 |
82 |
83 | func get_tag(tag_id : int) -> TemplateTag:
84 | return _tags[tag_id]
85 |
86 |
87 | func get_tag_id(tag : TemplateTag) -> int:
88 | return _tags.find(tag)
89 |
90 |
91 | func get_tags_item_list(use_display_list := false, exclude_unused := false, filtered_tags := []) -> Array:
92 | if use_display_list:
93 | return _get_tags_item_list(_display_tag_ids, exclude_unused, false, filtered_tags)
94 | else:
95 | return _get_tags_item_list(range(_tags.size()), exclude_unused, true, filtered_tags)
96 |
97 |
98 | func get_template(template_id : int) -> TemplateBitData:
99 | if template_id in range(0, _templates.size()):
100 | return _templates[template_id]
101 | return null
102 |
103 | func get_templates() -> Array:
104 | return _templates
105 |
106 | func _get_tags_item_list(tag_ids : Array, exclude_unused := false, sort_alphabetically := false, filtered_tags := []) -> Array:
107 | var item_list := []
108 | for tag_id in tag_ids:
109 | if tag_id in filtered_tags:
110 | continue
111 |
112 | var item := _get_tag_as_item(tag_id, exclude_unused, filtered_tags)
113 | if item.is_empty():
114 | continue
115 | item_list.append(item)
116 |
117 | if sort_alphabetically:
118 | item_list.sort_custom(func(a,b): return a["text"].to_lower() < b["text"].to_lower())
119 |
120 | return item_list
121 |
122 |
123 | func _get_tag_as_item(tag_id : int, skip_if_unused := false, filtered_tags := []) -> Dictionary:
124 | var tags := filtered_tags.duplicate()
125 | tags.append(tag_id)
126 | var count : int = _get_filtered_templates_list(tags).size()
127 | if skip_if_unused && count == 0:
128 | return {}
129 |
130 | var tag : TemplateTag = _tags[tag_id]
131 |
132 | return({
133 | "id": tag_id,
134 | "text": tag.text,
135 | "count": count,
136 | "tag": tag,
137 | # "color": tag.color, # TODO: implement in future?
138 | })
139 |
140 |
141 | func _get_all_template_ids() -> Array:
142 | return range(_templates.size())
143 |
144 |
145 | func _get_filtered_templates_list(filter_by_tags := []) -> Array:
146 | var filtered_templates := _get_all_template_ids()
147 |
148 | for tag_id in filter_by_tags:
149 | var templates_by_tag : Array = _tags_to_templates[tag_id].duplicate()
150 | filtered_templates = filtered_templates.filter(func(id): return templates_by_tag.has(id))
151 | if filtered_templates.is_empty():
152 | return []
153 |
154 | return filtered_templates
155 |
156 |
157 |
158 | func get_templates_item_list(filter_by_tags := []) -> Array:
159 | var item_list := []
160 |
161 | for template_id in _get_filtered_templates_list(filter_by_tags):
162 | var template : TemplateBitData = _templates[template_id]
163 | var text := template.template_name
164 | item_list.append({"id": template_id, "text": text})
165 |
166 | # sort alphabetically
167 | item_list.sort_custom(func(a, b): return a["text"].to_lower() < b["text"].to_lower())
168 |
169 | return item_list
170 |
171 |
172 |
173 | func _load_auto_tags() -> void:
174 | for tag in _template_tag_data.tags.values():
175 | var _id := _add_tag(tag)
176 |
177 |
178 | func _load_templates_in_directory(path : String, mark_as_built_in := false) -> void:
179 | var dir := DirAccess.open(path)
180 | if !dir:
181 | output.user("No directory found at %s" % path)
182 | return
183 | for file in dir.get_files():
184 | if !file.ends_with("tres"):
185 | continue
186 |
187 | # use get_current_dir() instead of path + file to normalize slashes
188 | var file_path := dir.get_current_dir() + "/" + file
189 |
190 | var template := load(file_path)
191 | if !template or template.get_script() != TemplateBitData:
192 | output.user("Error loading template at %s" % file_path)
193 | continue
194 |
195 |
196 | if mark_as_built_in:
197 | template.built_in = true
198 |
199 | var _id := _add_template(template)
200 |
201 |
202 | func _get_or_add_custom_tag(tag_text : String) -> int:
203 | # output.debug("_get_or_add_custom_tag(): %s" % tag_text)
204 |
205 | var custom_tag_id = _custom_tags.get(tag_text, null)
206 | # output.debug("custom_tag_id=%s" % custom_tag_id)
207 | if custom_tag_id != TAG_NOT_FOUND:
208 | return custom_tag_id
209 |
210 | var tag := TemplateTag.new(tag_text)
211 | tag.custom_tag = true
212 | var tag_id := _add_tag(tag)
213 | _custom_tags[tag_text] = tag_id
214 | return tag_id
215 |
216 |
217 | # adds tag, returns id
218 | func _add_tag(tag : TemplateTag) -> int:
219 | _tags.append(tag)
220 | var tag_id := _tags.size() - 1
221 | _tags_to_templates[tag_id] = []
222 | return tag_id
223 |
224 |
225 | # adds template, assigns its _tags, returns id
226 | func _add_template(template : TemplateBitData) -> int:
227 | _templates.append(template)
228 | var template_id := _templates.size() - 1
229 | _templates_to_tags[template_id] = []
230 | _assign_template_auto_tags(template_id, template)
231 | _assign_template_custom_tags(template_id, template)
232 | return template_id
233 |
234 |
235 | func _assign_template_auto_tags(template_id : int, template : TemplateBitData) -> void:
236 | for tag_id in range(_tags.size()):
237 | var tag : TemplateTag = _tags[tag_id]
238 | if !tag.has_test():
239 | continue
240 | if tag.get_test_result(template):
241 | _assign_template_to_tag(template_id, tag_id)
242 |
243 |
244 | func _assign_template_custom_tags(template_id : int, template : TemplateBitData) -> void:
245 | for tag_text in template.get_custom_tags():
246 | # output.debug("Evaluating custom tag [%s] for template %s" % [tag_text, template.template_name])
247 | var tag_id := _get_or_add_custom_tag(tag_text)
248 | # output.debug("tag_id=%s" % tag_id)
249 | _assign_template_to_tag(template_id, tag_id)
250 |
251 |
252 | func _assign_template_to_tag(template_id : int, tag_id : int) -> void:
253 | if !_tags_to_templates[tag_id].has(template_id):
254 | _tags_to_templates[tag_id].append(template_id)
255 | if !_templates_to_tags[template_id].has(tag_id):
256 | _templates_to_tags[template_id].append(tag_id)
257 |
258 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/core/template_tag_data.gd:
--------------------------------------------------------------------------------
1 | extends RefCounted
2 |
3 | const SEPARATOR := 0
4 |
5 | const TemplateBitData := preload("res://addons/tile_bit_tools/core/template_bit_data.gd")
6 |
7 | enum Tags {
8 | BUILT_IN,
9 | USER,
10 | ONE_OR_TWO_TERRAINS,
11 | THREE_PLUS_TERRAINS,
12 | MATCH_CORNERS_AND_SIDES,
13 | MATCH_CORNERS,
14 | MATCH_SIDES,
15 | }
16 |
17 |
18 | class TemplateTag:
19 | var test_func : Callable
20 | var text : String
21 | var color : Color
22 | var icon := ""
23 | var custom_tag := false
24 |
25 | var id : int
26 |
27 | var custom_tag_icons := {
28 | "Godot 3": "Godot",
29 | "Incomplete Autotile": "NodeWarning",
30 | "Plugin Required": "NodeWarning",
31 | "TilePipe2": "TileSet",
32 | "Tilesetter": "TileSet",
33 |
34 | }
35 |
36 | func _init(p_text : String, p_test_func = null, p_icon = null, p_color = null):
37 | text = p_text
38 | if p_test_func:
39 | test_func = p_test_func
40 | if p_icon:
41 | icon = p_icon
42 | if p_color:
43 | color = p_color
44 |
45 | if icon == "":
46 | icon = custom_tag_icons.get(text, "")
47 |
48 |
49 | func get_template_has_tag(bit_data : TemplateBitData) -> bool:
50 | if test_func:
51 | return test_func.call(bit_data)
52 | else:
53 | return text in bit_data._custom_tags
54 |
55 | func get_test_result(bit_data : TemplateBitData) -> bool:
56 | return test_func.call(bit_data)
57 |
58 | func get_icon(base_control : Control) -> Texture2D:
59 | if icon == "":
60 | return null
61 | if icon.is_absolute_path():
62 | return load(icon)
63 | return base_control.get_theme_icon(icon, "EditorIcons")
64 |
65 | func has_test() -> bool:
66 | if test_func:
67 | return true
68 | return false
69 |
70 |
71 |
72 | var tags := {
73 | Tags.BUILT_IN: TemplateTag.new(
74 | "Type: Built-In",
75 | func(bit_data: TemplateBitData):
76 | return bit_data.built_in,
77 | "Tools",
78 | null,
79 | ),
80 | Tags.USER: TemplateTag.new(
81 | "Type: User",
82 | func(bit_data: TemplateBitData):
83 | return !bit_data.built_in,
84 | "File",
85 | Color.YELLOW,
86 | ),
87 | # Tags.ONE_OR_TWO_TERRAINS: TemplateTag.new(
88 | # "Terrains: 1-2",
89 | # func(bit_data: TemplateBitData):
90 | # return bit_data.template_terrain_count <= 2,
91 | # null,
92 | # null,
93 | # ),
94 | # Tags.THREE_PLUS_TERRAINS: TemplateTag.new(
95 | # "Terrains: 3+",
96 | # func(bit_data: TemplateBitData):
97 | # return bit_data.template_terrain_count >= 3,
98 | # null,
99 | # null,
100 | # ),
101 | Tags.MATCH_CORNERS_AND_SIDES: TemplateTag.new(
102 | "Mode: Corners and Sides",
103 | func(bit_data: TemplateBitData):
104 | return bit_data.terrain_mode == TileSet.TERRAIN_MODE_MATCH_CORNERS_AND_SIDES,
105 | "TerrainMatchCornersAndSides",
106 | null,
107 | ),
108 | Tags.MATCH_CORNERS: TemplateTag.new(
109 | "Mode: Corners",
110 | func(bit_data: TemplateBitData):
111 | return bit_data.terrain_mode == TileSet.TERRAIN_MODE_MATCH_CORNERS,
112 | "TerrainMatchCorners",
113 | null,
114 | ),
115 | Tags.MATCH_SIDES: TemplateTag.new(
116 | "Mode: Sides",
117 | func(bit_data: TemplateBitData):
118 | return bit_data.terrain_mode == TileSet.TERRAIN_MODE_MATCH_SIDES,
119 | "TerrainMatchSides",
120 | null,
121 | ),
122 | }
123 |
124 | var tag_display := [
125 | Tags.BUILT_IN,
126 | Tags.USER,
127 | Tags.MATCH_CORNERS_AND_SIDES,
128 | Tags.MATCH_CORNERS,
129 | Tags.MATCH_SIDES,
130 | # Tags.ONE_OR_TWO_TERRAINS,
131 | # Tags.THREE_PLUS_TERRAINS,
132 | ]
133 |
134 |
135 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/core/texts.gd:
--------------------------------------------------------------------------------
1 | extends RefCounted
2 |
3 | const G := preload("res://addons/tile_bit_tools/core/globals.gd")
4 | const BitData := preload("res://addons/tile_bit_tools/core/bit_data.gd")
5 |
6 |
7 | const ERROR_TEXTS := {
8 | # G.Errors.OK: "result=OK",
9 | G.Errors.MISSING_TILE_SET: "TileSet not found",
10 | G.Errors.MISSING_SOURCE: "TileSetAtlasSource not found",
11 | G.Errors.MISSING_TILES: "TileData not found",
12 | G.Errors.MISSING_BIT_DATA: "TileData failed to parse",
13 | G.Errors.INVALID_TBT_PLUGIN_CONTROL: "TBTPluginControl invalid",
14 | G.Errors.INVALID_TILES_PREVIEW: "TilesPreview invalid",
15 | G.Errors.MULTIPLE_TERRAIN_SETS: "Selected tiles contain more than one terrain set",
16 | G.Errors.UNSUPPORTED_SHAPE: "Current tile shape is not supported",
17 | }
18 |
19 |
20 | const TERRAIN_MODE_TEXTS := {
21 | TileSet.TerrainMode.TERRAIN_MODE_MATCH_CORNERS_AND_SIDES : "Corners and Sides",
22 | TileSet.TerrainMode.TERRAIN_MODE_MATCH_CORNERS : "Corners",
23 | TileSet.TerrainMode.TERRAIN_MODE_MATCH_SIDES : "Sides",
24 | }
25 |
26 | const TERRAIN_BIT_TEXTS := {
27 | BitData.TerrainBits.TOP_LEFT_CORNER: "Top Left Corner",
28 | BitData.TerrainBits.TOP_SIDE: "Top Side",
29 | BitData.TerrainBits.TOP_RIGHT_CORNER: "Top Right Corner",
30 | BitData.TerrainBits.RIGHT_SIDE: "Right Side",
31 | BitData.TerrainBits.BOTTOM_RIGHT_CORNER: "Bottom Right Corner",
32 | BitData.TerrainBits.BOTTOM_SIDE: "Bottom Side",
33 | BitData.TerrainBits.BOTTOM_LEFT_CORNER: "Bottom Left Corner",
34 | BitData.TerrainBits.LEFT_SIDE: "Left Side",
35 | BitData.TerrainBits.CENTER: "Tile Terrain (Center)",
36 | }
37 |
38 |
39 | const EMPTY_ITEM := ""
40 |
41 | const WELCOME_MESSAGE := "Welcome to TileBitTools. Please report bugs or suggestions to github.com/dandeliondino/tile_bit_tools. To change which messages you see here, go to Project Settings -> General -> Addons -> Tile Bit Tools (make sure 'Advanced' is enabled)"
42 | const WELCOME_MESSAGE2 := "Note: Please back up your project before applying any changes."
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/godot3_2x2/ABOUT.txt:
--------------------------------------------------------------------------------
1 | Tile size: 16px
2 | Credits: Tiles adapted from Kenney's Pixel Shmup (https://www.kenney.nl/assets/pixel-shmup)
3 | License: CC0 1.0 Universal (https://creativecommons.org/publicdomain/zero/1.0/)
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/godot3_2x2/godot3_2x2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dandeliondino/tile_bit_tools/0bbf10f27d492cdc5f7e227cf7946a705998e0d4/addons/tile_bit_tools/examples/godot3_2x2/godot3_2x2.png
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/godot3_2x2/godot3_2x2.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://c8jir47kkrfm"
6 | path="res://.godot/imported/godot3_2x2.png-aba8871ac93d513184f6173778d73edf.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/tile_bit_tools/examples/godot3_2x2/godot3_2x2.png"
14 | dest_files=["res://.godot/imported/godot3_2x2.png-aba8871ac93d513184f6173778d73edf.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/godot3_3x3_16_tiles/ABOUT.txt:
--------------------------------------------------------------------------------
1 | Tile size: 16px
2 | Credits: Tiles adapted from Kenney's Pixel Shmup (https://www.kenney.nl/assets/pixel-shmup)
3 | License: CC0 1.0 Universal (https://creativecommons.org/publicdomain/zero/1.0/)
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/godot3_3x3_16_tiles/godot3_3x3_16_tiles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dandeliondino/tile_bit_tools/0bbf10f27d492cdc5f7e227cf7946a705998e0d4/addons/tile_bit_tools/examples/godot3_3x3_16_tiles/godot3_3x3_16_tiles.png
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/godot3_3x3_16_tiles/godot3_3x3_16_tiles.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://pm2rgubsav6m"
6 | path="res://.godot/imported/godot3_3x3_16_tiles.png-ba2f03c9d65060269dfa240bc35aff35.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/tile_bit_tools/examples/godot3_3x3_16_tiles/godot3_3x3_16_tiles.png"
14 | dest_files=["res://.godot/imported/godot3_3x3_16_tiles.png-ba2f03c9d65060269dfa240bc35aff35.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/godot3_3x3_minimal/ABOUT.txt:
--------------------------------------------------------------------------------
1 | Tile size: 16px
2 | Credits: Tiles adapted from Kenney's Pixel Shmup (https://www.kenney.nl/assets/pixel-shmup)
3 | License: CC0 1.0 Universal (https://creativecommons.org/publicdomain/zero/1.0/)
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/godot3_3x3_minimal/godot3_3x3_minimal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dandeliondino/tile_bit_tools/0bbf10f27d492cdc5f7e227cf7946a705998e0d4/addons/tile_bit_tools/examples/godot3_3x3_minimal/godot3_3x3_minimal.png
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/godot3_3x3_minimal/godot3_3x3_minimal.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://d5ylbtvxy6ud"
6 | path="res://.godot/imported/godot3_3x3_minimal.png-5315b0ad1f1d21ffddf7293efb5522ab.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/tile_bit_tools/examples/godot3_3x3_minimal/godot3_3x3_minimal.png"
14 | dest_files=["res://.godot/imported/godot3_3x3_minimal.png-5315b0ad1f1d21ffddf7293efb5522ab.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/simple_tilesets/ABOUT.txt:
--------------------------------------------------------------------------------
1 | Tile size: 16px
2 | Credits: Tiles adapted from Kenney's Pixel Shmup (https://www.kenney.nl/assets/pixel-shmup)
3 | License: CC0 1.0 Universal (https://creativecommons.org/publicdomain/zero/1.0/)
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/simple_tilesets/simple_9_and_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dandeliondino/tile_bit_tools/0bbf10f27d492cdc5f7e227cf7946a705998e0d4/addons/tile_bit_tools/examples/simple_tilesets/simple_9_and_4.png
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/simple_tilesets/simple_9_and_4.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://d3rqw1kgi0m2l"
6 | path="res://.godot/imported/simple_9_and_4.png-ecaee0bcf09165d94bf9236cc212e887.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/tile_bit_tools/examples/simple_tilesets/simple_9_and_4.png"
14 | dest_files=["res://.godot/imported/simple_9_and_4.png-ecaee0bcf09165d94bf9236cc212e887.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/simple_tilesets/simple_9_and_9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dandeliondino/tile_bit_tools/0bbf10f27d492cdc5f7e227cf7946a705998e0d4/addons/tile_bit_tools/examples/simple_tilesets/simple_9_and_9.png
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/simple_tilesets/simple_9_and_9.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://eie8ec231nbx"
6 | path="res://.godot/imported/simple_9_and_9.png-dd97711fb9ab25ea25c4a4b71be2c566.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/tile_bit_tools/examples/simple_tilesets/simple_9_and_9.png"
14 | dest_files=["res://.godot/imported/simple_9_and_9.png-dd97711fb9ab25ea25c4a4b71be2c566.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/tilesetter_blob/ABOUT.txt:
--------------------------------------------------------------------------------
1 | Tile size: 16px
2 | Credits: Tiles adapted from Kenney's Pixel Shmup (https://www.kenney.nl/assets/pixel-shmup)
3 | License: CC0 1.0 Universal (https://creativecommons.org/publicdomain/zero/1.0/)
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/tilesetter_blob/tilesetter_blob.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dandeliondino/tile_bit_tools/0bbf10f27d492cdc5f7e227cf7946a705998e0d4/addons/tile_bit_tools/examples/tilesetter_blob/tilesetter_blob.png
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/tilesetter_blob/tilesetter_blob.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://207wwupug0tm"
6 | path="res://.godot/imported/tilesetter_blob.png-d6e1fabbd7fb279f1ee63f1ada8e0733.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/tile_bit_tools/examples/tilesetter_blob/tilesetter_blob.png"
14 | dest_files=["res://.godot/imported/tilesetter_blob.png-d6e1fabbd7fb279f1ee63f1ada8e0733.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/tilesetter_wang/ABOUT.txt:
--------------------------------------------------------------------------------
1 | Tile size: 16px
2 | Credits: Tiles adapted from Kenney's Pixel Shmup (https://www.kenney.nl/assets/pixel-shmup)
3 | License: CC0 1.0 Universal (https://creativecommons.org/publicdomain/zero/1.0/)
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/tilesetter_wang/tilesetter_wang.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dandeliondino/tile_bit_tools/0bbf10f27d492cdc5f7e227cf7946a705998e0d4/addons/tile_bit_tools/examples/tilesetter_wang/tilesetter_wang.png
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/tilesetter_wang/tilesetter_wang.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://djfsinobli1lr"
6 | path="res://.godot/imported/tilesetter_wang.png-d3f83fc7b5a9a46f3842d791cf7bf362.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/tile_bit_tools/examples/tilesetter_wang/tilesetter_wang.png"
14 | dest_files=["res://.godot/imported/tilesetter_wang.png-d3f83fc7b5a9a46f3842d791cf7bf362.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/tilesetter_wang_3_terrains/ABOUT.txt:
--------------------------------------------------------------------------------
1 | Tile size: 16px
2 | Credits: Tiles adapted from Kenney's Pixel Shmup (https://www.kenney.nl/assets/pixel-shmup)
3 | License: CC0 1.0 Universal (https://creativecommons.org/publicdomain/zero/1.0/)
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/tilesetter_wang_3_terrains/tilesetter_wang_3_terrain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dandeliondino/tile_bit_tools/0bbf10f27d492cdc5f7e227cf7946a705998e0d4/addons/tile_bit_tools/examples/tilesetter_wang_3_terrains/tilesetter_wang_3_terrain.png
--------------------------------------------------------------------------------
/addons/tile_bit_tools/examples/tilesetter_wang_3_terrains/tilesetter_wang_3_terrain.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://3tn7f0bc7wtl"
6 | path="res://.godot/imported/tilesetter_wang_3_terrain.png-ccf897dbb6ca5ad03088ec812e1fa06a.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/tile_bit_tools/examples/tilesetter_wang_3_terrains/tilesetter_wang_3_terrain.png"
14 | dest_files=["res://.godot/imported/tilesetter_wang_3_terrain.png-ccf897dbb6ca5ad03088ec812e1fa06a.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/plugin.cfg:
--------------------------------------------------------------------------------
1 | [plugin]
2 |
3 | name="TileBitTools"
4 | description="A Godot 4 plugin for autotile templates and terrain bit editing."
5 | author="dandeliondino"
6 | version="1.1.0"
7 | script="plugin.gd"
8 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/plugin.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends EditorPlugin
3 |
4 | const G := preload("res://addons/tile_bit_tools/core/globals.gd")
5 |
6 | const PLUGIN_NAME := "tile_bit_tools"
7 |
8 | var texts := preload("res://addons/tile_bit_tools/core/texts.gd").new()
9 | var output := preload("res://addons/tile_bit_tools/core/output.gd").new()
10 |
11 | var plugin : EditorInspectorPlugin
12 |
13 |
14 | func _enter_tree() -> void:
15 | output.debug("plugin.gd : _enter_tree()")
16 | output.info("Initializing TileBitTools v%s..." % G.VERSION)
17 |
18 | _setup_project_settings()
19 |
20 | plugin = preload("inspector_plugin.gd").new()
21 | add_inspector_plugin(plugin)
22 | var result : G.Errors = plugin.setup(get_editor_interface())
23 | if result != OK:
24 | output.user("Unable to initialize, disabling plugin")
25 | get_editor_interface().set_plugin_enabled(PLUGIN_NAME, false)
26 | return
27 | output.info("Initialization complete")
28 | output.user(texts.WELCOME_MESSAGE)
29 | output.user(texts.WELCOME_MESSAGE2)
30 |
31 |
32 | func _clear() -> void:
33 | output.debug("plugin.gd : _clear()")
34 | if plugin:
35 | plugin.clean_up()
36 |
37 |
38 | func _exit_tree() -> void:
39 | output.debug("plugin.gd : _exit_tree()")
40 | output.info("Cleaning up...")
41 | if plugin:
42 | plugin.clean_up()
43 | remove_inspector_plugin(plugin)
44 |
45 |
46 |
47 |
48 | func _setup_project_settings() -> void:
49 | for key in G.Settings.keys():
50 | var setting : Dictionary = G.Settings[key]
51 | if !ProjectSettings.has_setting(setting.path):
52 | ProjectSettings.set(setting.path, setting.default)
53 |
54 | ProjectSettings.set_initial_value(setting.path, setting.default)
55 | ProjectSettings.add_property_info({
56 | "name": setting.path,
57 | "type": setting.type,
58 | "hint_string": setting.get("hint_string", null),
59 | })
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/templates/godot3_2x2.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://dghepno5umy5j"]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/core/template_bit_data.gd" id="1_03oml"]
4 |
5 | [resource]
6 | script = ExtResource("1_03oml")
7 | version = "0.1.0"
8 | template_name = "2x2 (Godot 3)"
9 | template_description = "Like all corner-matching templates, it can be used for simple blocks of terrain or diagonal paths or walls. It cannot be drawn in a single-tile wide line. This configuration is based on the Godot 3 documentation (https://docs.godotengine.org/en/3.5/tutorials/2d/using_tilemaps.html)."
10 | _custom_tags = ["Godot 3", "TilePipe2"]
11 | template_terrain_count = 2
12 | example_folder_path = "res://addons/tile_bit_tools/examples/godot3_2x2/"
13 | _tiles = {
14 | Vector2i(0, 0): {
15 | 0: 0,
16 | 1: {
17 | 3: 1,
18 | 7: 0,
19 | 11: 1,
20 | 15: 1
21 | }
22 | },
23 | Vector2i(0, 1): {
24 | 0: 0,
25 | 1: {
26 | 3: 0,
27 | 7: 1,
28 | 11: 0,
29 | 15: 1
30 | }
31 | },
32 | Vector2i(0, 2): {
33 | 0: 0,
34 | 1: {
35 | 3: 1,
36 | 7: 1,
37 | 11: 1,
38 | 15: 0
39 | }
40 | },
41 | Vector2i(0, 3): {
42 | 0: 1,
43 | 1: {
44 | 3: 1,
45 | 7: 1,
46 | 11: 1,
47 | 15: 1
48 | }
49 | },
50 | Vector2i(1, 0): {
51 | 0: 0,
52 | 1: {
53 | 3: 0,
54 | 7: 1,
55 | 11: 1,
56 | 15: 0
57 | }
58 | },
59 | Vector2i(1, 1): {
60 | 0: 0,
61 | 1: {
62 | 3: 0,
63 | 7: 0,
64 | 11: 1,
65 | 15: 0
66 | }
67 | },
68 | Vector2i(1, 2): {
69 | 0: 0,
70 | 1: {
71 | 3: 1,
72 | 7: 1,
73 | 11: 0,
74 | 15: 0
75 | }
76 | },
77 | Vector2i(1, 3): {
78 | 0: 0,
79 | 1: {
80 | 3: 0,
81 | 7: 1,
82 | 11: 1,
83 | 15: 1
84 | }
85 | },
86 | Vector2i(2, 0): {
87 | 0: 0,
88 | 1: {
89 | 3: 0,
90 | 7: 0,
91 | 11: 0,
92 | 15: 1
93 | }
94 | },
95 | Vector2i(2, 1): {
96 | 0: 0,
97 | 1: {
98 | 3: 0,
99 | 7: 0,
100 | 11: 0,
101 | 15: 0
102 | }
103 | },
104 | Vector2i(2, 2): {
105 | 0: 0,
106 | 1: {
107 | 3: 0,
108 | 7: 1,
109 | 11: 0,
110 | 15: 0
111 | }
112 | },
113 | Vector2i(2, 3): {
114 | 0: 0,
115 | 1: {
116 | 3: 1,
117 | 7: 0,
118 | 11: 1,
119 | 15: 0
120 | }
121 | },
122 | Vector2i(3, 0): {
123 | 0: 0,
124 | 1: {
125 | 3: 0,
126 | 7: 0,
127 | 11: 1,
128 | 15: 1
129 | }
130 | },
131 | Vector2i(3, 1): {
132 | 0: 0,
133 | 1: {
134 | 3: 1,
135 | 7: 0,
136 | 11: 0,
137 | 15: 0
138 | }
139 | },
140 | Vector2i(3, 2): {
141 | 0: 0,
142 | 1: {
143 | 3: 1,
144 | 7: 0,
145 | 11: 0,
146 | 15: 1
147 | }
148 | },
149 | Vector2i(3, 3): {
150 | 0: 0,
151 | 1: {
152 | 3: 1,
153 | 7: 1,
154 | 11: 0,
155 | 15: 1
156 | }
157 | }
158 | }
159 | terrain_set = -1
160 | terrain_mode = 1
161 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/templates/godot3_3x3_16_tiles.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://dvhege7ynlv7t"]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/core/template_bit_data.gd" id="1_4fue2"]
4 |
5 | [resource]
6 | script = ExtResource("1_4fue2")
7 | version = "0.1.0"
8 | template_name = "3x3 16 Tiles (Godot 3)"
9 | template_description = "Like all side-matching templates, it can be used for paths or fences in straight lines. It cannot make diagonal lines or shapes wider than one tile. This configuration is based on the Godot 3 documentation (https://docs.godotengine.org/en/3.5/tutorials/2d/using_tilemaps.html)."
10 | _custom_tags = ["Godot 3"]
11 | template_terrain_count = 2
12 | example_folder_path = "res://addons/tile_bit_tools/examples/godot3_3x3_16_tiles/"
13 | _tiles = {
14 | Vector2i(0, 0): {
15 | 0: 0,
16 | 1: {
17 | 0: 1,
18 | 4: 0,
19 | 8: 1,
20 | 12: 1
21 | }
22 | },
23 | Vector2i(0, 1): {
24 | 0: 0,
25 | 1: {
26 | 0: 1,
27 | 4: 0,
28 | 8: 1,
29 | 12: 0
30 | }
31 | },
32 | Vector2i(0, 2): {
33 | 0: 0,
34 | 1: {
35 | 0: 1,
36 | 4: 1,
37 | 8: 1,
38 | 12: 0
39 | }
40 | },
41 | Vector2i(0, 3): {
42 | 0: 0,
43 | 1: {
44 | 0: 1,
45 | 4: 1,
46 | 8: 1,
47 | 12: 1
48 | }
49 | },
50 | Vector2i(1, 0): {
51 | 0: 0,
52 | 1: {
53 | 0: 0,
54 | 4: 0,
55 | 8: 1,
56 | 12: 1
57 | }
58 | },
59 | Vector2i(1, 1): {
60 | 0: 0,
61 | 1: {
62 | 0: 0,
63 | 4: 0,
64 | 8: 1,
65 | 12: 0
66 | }
67 | },
68 | Vector2i(1, 2): {
69 | 0: 0,
70 | 1: {
71 | 0: 0,
72 | 4: 1,
73 | 8: 1,
74 | 12: 0
75 | }
76 | },
77 | Vector2i(1, 3): {
78 | 0: 0,
79 | 1: {
80 | 0: 0,
81 | 4: 1,
82 | 8: 1,
83 | 12: 1
84 | }
85 | },
86 | Vector2i(2, 0): {
87 | 0: 0,
88 | 1: {
89 | 0: 0,
90 | 4: 0,
91 | 8: 0,
92 | 12: 1
93 | }
94 | },
95 | Vector2i(2, 1): {
96 | 0: 0,
97 | 1: {
98 | 0: 0,
99 | 4: 0,
100 | 8: 0,
101 | 12: 0
102 | }
103 | },
104 | Vector2i(2, 2): {
105 | 0: 0,
106 | 1: {
107 | 0: 0,
108 | 4: 1,
109 | 8: 0,
110 | 12: 0
111 | }
112 | },
113 | Vector2i(2, 3): {
114 | 0: 0,
115 | 1: {
116 | 0: 0,
117 | 4: 1,
118 | 8: 0,
119 | 12: 1
120 | }
121 | },
122 | Vector2i(3, 0): {
123 | 0: 0,
124 | 1: {
125 | 0: 1,
126 | 4: 0,
127 | 8: 0,
128 | 12: 1
129 | }
130 | },
131 | Vector2i(3, 1): {
132 | 0: 0,
133 | 1: {
134 | 0: 1,
135 | 4: 0,
136 | 8: 0,
137 | 12: 0
138 | }
139 | },
140 | Vector2i(3, 2): {
141 | 0: 0,
142 | 1: {
143 | 0: 1,
144 | 4: 1,
145 | 8: 0,
146 | 12: 0
147 | }
148 | },
149 | Vector2i(3, 3): {
150 | 0: 0,
151 | 1: {
152 | 0: 1,
153 | 4: 1,
154 | 8: 0,
155 | 12: 1
156 | }
157 | }
158 | }
159 | terrain_set = -1
160 | terrain_mode = 2
161 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/templates/godot3_3x3_minimal.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://bxsdvyv6ld25w"]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/core/template_bit_data.gd" id="1_dl8o4"]
4 |
5 | [resource]
6 | script = ExtResource("1_dl8o4")
7 | version = "0.1.0"
8 | template_name = "3x3 Minimal (Godot 3)"
9 | template_description = "Like all corner-and-side-matching templates, this 47/48-tile template has flexible uses and can make complex shapes. It is good for terrains, paths and walls. This configuration is based on the Godot 3 documentation (https://docs.godotengine.org/en/3.5/tutorials/2d/using_tilemaps.html)."
10 | _custom_tags = ["Godot 3", "TilePipe2"]
11 | template_terrain_count = 2
12 | example_folder_path = "res://addons/tile_bit_tools/examples/godot3_3x3_minimal/"
13 | _tiles = {
14 | Vector2i(0, 0): {
15 | 0: 0,
16 | 1: {
17 | 0: 1,
18 | 3: 1,
19 | 4: 0,
20 | 7: 1,
21 | 8: 1,
22 | 11: 1,
23 | 12: 1,
24 | 15: 1
25 | }
26 | },
27 | Vector2i(0, 1): {
28 | 0: 0,
29 | 1: {
30 | 0: 1,
31 | 3: 1,
32 | 4: 0,
33 | 7: 1,
34 | 8: 1,
35 | 11: 1,
36 | 12: 0,
37 | 15: 1
38 | }
39 | },
40 | Vector2i(0, 2): {
41 | 0: 0,
42 | 1: {
43 | 0: 1,
44 | 3: 1,
45 | 4: 1,
46 | 7: 1,
47 | 8: 1,
48 | 11: 1,
49 | 12: 0,
50 | 15: 1
51 | }
52 | },
53 | Vector2i(0, 3): {
54 | 0: 0,
55 | 1: {
56 | 0: 1,
57 | 3: 1,
58 | 4: 1,
59 | 7: 1,
60 | 8: 1,
61 | 11: 1,
62 | 12: 1,
63 | 15: 1
64 | }
65 | },
66 | Vector2i(1, 0): {
67 | 0: 0,
68 | 1: {
69 | 0: 0,
70 | 3: 1,
71 | 4: 0,
72 | 7: 1,
73 | 8: 1,
74 | 11: 1,
75 | 12: 1,
76 | 15: 1
77 | }
78 | },
79 | Vector2i(1, 1): {
80 | 0: 0,
81 | 1: {
82 | 0: 0,
83 | 3: 1,
84 | 4: 0,
85 | 7: 1,
86 | 8: 1,
87 | 11: 1,
88 | 12: 0,
89 | 15: 1
90 | }
91 | },
92 | Vector2i(1, 2): {
93 | 0: 0,
94 | 1: {
95 | 0: 0,
96 | 3: 1,
97 | 4: 1,
98 | 7: 1,
99 | 8: 1,
100 | 11: 1,
101 | 12: 0,
102 | 15: 1
103 | }
104 | },
105 | Vector2i(1, 3): {
106 | 0: 0,
107 | 1: {
108 | 0: 0,
109 | 3: 1,
110 | 4: 1,
111 | 7: 1,
112 | 8: 1,
113 | 11: 1,
114 | 12: 1,
115 | 15: 1
116 | }
117 | },
118 | Vector2i(2, 0): {
119 | 0: 0,
120 | 1: {
121 | 0: 0,
122 | 3: 1,
123 | 4: 0,
124 | 7: 1,
125 | 8: 0,
126 | 11: 1,
127 | 12: 1,
128 | 15: 1
129 | }
130 | },
131 | Vector2i(2, 1): {
132 | 0: 0,
133 | 1: {
134 | 0: 0,
135 | 3: 1,
136 | 4: 0,
137 | 7: 1,
138 | 8: 0,
139 | 11: 1,
140 | 12: 0,
141 | 15: 1
142 | }
143 | },
144 | Vector2i(2, 2): {
145 | 0: 0,
146 | 1: {
147 | 0: 0,
148 | 3: 1,
149 | 4: 1,
150 | 7: 1,
151 | 8: 0,
152 | 11: 1,
153 | 12: 0,
154 | 15: 1
155 | }
156 | },
157 | Vector2i(2, 3): {
158 | 0: 0,
159 | 1: {
160 | 0: 0,
161 | 3: 1,
162 | 4: 1,
163 | 7: 1,
164 | 8: 0,
165 | 11: 1,
166 | 12: 1,
167 | 15: 1
168 | }
169 | },
170 | Vector2i(3, 0): {
171 | 0: 0,
172 | 1: {
173 | 0: 1,
174 | 3: 1,
175 | 4: 0,
176 | 7: 1,
177 | 8: 0,
178 | 11: 1,
179 | 12: 1,
180 | 15: 1
181 | }
182 | },
183 | Vector2i(3, 1): {
184 | 0: 0,
185 | 1: {
186 | 0: 1,
187 | 3: 1,
188 | 4: 0,
189 | 7: 1,
190 | 8: 0,
191 | 11: 1,
192 | 12: 0,
193 | 15: 1
194 | }
195 | },
196 | Vector2i(3, 2): {
197 | 0: 0,
198 | 1: {
199 | 0: 1,
200 | 3: 1,
201 | 4: 1,
202 | 7: 1,
203 | 8: 0,
204 | 11: 1,
205 | 12: 0,
206 | 15: 1
207 | }
208 | },
209 | Vector2i(3, 3): {
210 | 0: 0,
211 | 1: {
212 | 0: 1,
213 | 3: 1,
214 | 4: 1,
215 | 7: 1,
216 | 8: 0,
217 | 11: 1,
218 | 12: 1,
219 | 15: 1
220 | }
221 | },
222 | Vector2i(4, 0): {
223 | 0: 0,
224 | 1: {
225 | 0: 0,
226 | 3: 1,
227 | 4: 0,
228 | 7: 1,
229 | 8: 0,
230 | 11: 0,
231 | 12: 0,
232 | 15: 1
233 | }
234 | },
235 | Vector2i(4, 1): {
236 | 0: 0,
237 | 1: {
238 | 0: 0,
239 | 3: 0,
240 | 4: 0,
241 | 7: 1,
242 | 8: 1,
243 | 11: 1,
244 | 12: 0,
245 | 15: 1
246 | }
247 | },
248 | Vector2i(4, 2): {
249 | 0: 0,
250 | 1: {
251 | 0: 0,
252 | 3: 1,
253 | 4: 0,
254 | 7: 1,
255 | 8: 1,
256 | 11: 1,
257 | 12: 0,
258 | 15: 0
259 | }
260 | },
261 | Vector2i(4, 3): {
262 | 0: 0,
263 | 1: {
264 | 0: 0,
265 | 3: 1,
266 | 4: 0,
267 | 7: 0,
268 | 8: 0,
269 | 11: 1,
270 | 12: 0,
271 | 15: 1
272 | }
273 | },
274 | Vector2i(5, 0): {
275 | 0: 0,
276 | 1: {
277 | 0: 0,
278 | 3: 0,
279 | 4: 0,
280 | 7: 1,
281 | 8: 0,
282 | 11: 1,
283 | 12: 1,
284 | 15: 1
285 | }
286 | },
287 | Vector2i(5, 1): {
288 | 0: 0,
289 | 1: {
290 | 0: 0,
291 | 3: 0,
292 | 4: 0,
293 | 7: 0,
294 | 8: 0,
295 | 11: 1,
296 | 12: 0,
297 | 15: 0
298 | }
299 | },
300 | Vector2i(5, 2): {
301 | 0: 0,
302 | 1: {
303 | 0: 0,
304 | 3: 0,
305 | 4: 0,
306 | 7: 1,
307 | 8: 0,
308 | 11: 0,
309 | 12: 0,
310 | 15: 0
311 | }
312 | },
313 | Vector2i(5, 3): {
314 | 0: 0,
315 | 1: {
316 | 0: 0,
317 | 3: 1,
318 | 4: 1,
319 | 7: 1,
320 | 8: 0,
321 | 11: 1,
322 | 12: 0,
323 | 15: 0
324 | }
325 | },
326 | Vector2i(6, 0): {
327 | 0: 0,
328 | 1: {
329 | 0: 0,
330 | 3: 1,
331 | 4: 0,
332 | 7: 0,
333 | 8: 0,
334 | 11: 1,
335 | 12: 1,
336 | 15: 1
337 | }
338 | },
339 | Vector2i(6, 1): {
340 | 0: 0,
341 | 1: {
342 | 0: 0,
343 | 3: 0,
344 | 4: 0,
345 | 7: 0,
346 | 8: 0,
347 | 11: 0,
348 | 12: 0,
349 | 15: 1
350 | }
351 | },
352 | Vector2i(6, 2): {
353 | 0: 0,
354 | 1: {
355 | 0: 0,
356 | 3: 1,
357 | 4: 0,
358 | 7: 0,
359 | 8: 0,
360 | 11: 0,
361 | 12: 0,
362 | 15: 0
363 | }
364 | },
365 | Vector2i(6, 3): {
366 | 0: 0,
367 | 1: {
368 | 0: 0,
369 | 3: 1,
370 | 4: 1,
371 | 7: 1,
372 | 8: 0,
373 | 11: 0,
374 | 12: 0,
375 | 15: 1
376 | }
377 | },
378 | Vector2i(7, 0): {
379 | 0: 0,
380 | 1: {
381 | 0: 0,
382 | 3: 1,
383 | 4: 0,
384 | 7: 1,
385 | 8: 0,
386 | 11: 1,
387 | 12: 0,
388 | 15: 0
389 | }
390 | },
391 | Vector2i(7, 1): {
392 | 0: 0,
393 | 1: {
394 | 0: 1,
395 | 3: 1,
396 | 4: 0,
397 | 7: 0,
398 | 8: 0,
399 | 11: 1,
400 | 12: 0,
401 | 15: 1
402 | }
403 | },
404 | Vector2i(7, 2): {
405 | 0: 0,
406 | 1: {
407 | 0: 1,
408 | 3: 1,
409 | 4: 0,
410 | 7: 1,
411 | 8: 0,
412 | 11: 0,
413 | 12: 0,
414 | 15: 1
415 | }
416 | },
417 | Vector2i(7, 3): {
418 | 0: 0,
419 | 1: {
420 | 0: 0,
421 | 3: 0,
422 | 4: 0,
423 | 7: 1,
424 | 8: 0,
425 | 11: 1,
426 | 12: 0,
427 | 15: 1
428 | }
429 | },
430 | Vector2i(8, 0): {
431 | 0: 0,
432 | 1: {
433 | 0: 0,
434 | 3: 0,
435 | 4: 0,
436 | 7: 1,
437 | 8: 1,
438 | 11: 1,
439 | 12: 1,
440 | 15: 1
441 | }
442 | },
443 | Vector2i(8, 1): {
444 | 0: 0,
445 | 1: {
446 | 0: 0,
447 | 3: 0,
448 | 4: 0,
449 | 7: 1,
450 | 8: 1,
451 | 11: 1,
452 | 12: 0,
453 | 15: 0
454 | }
455 | },
456 | Vector2i(8, 2): {
457 | 0: 0,
458 | 1: {
459 | 0: 0,
460 | 3: 0,
461 | 4: 0,
462 | 7: 1,
463 | 8: 0,
464 | 11: 1,
465 | 12: 0,
466 | 15: 0
467 | }
468 | },
469 | Vector2i(8, 3): {
470 | 0: 0,
471 | 1: {
472 | 0: 0,
473 | 3: 1,
474 | 4: 1,
475 | 7: 1,
476 | 8: 1,
477 | 11: 1,
478 | 12: 0,
479 | 15: 0
480 | }
481 | },
482 | Vector2i(9, 0): {
483 | 0: 0,
484 | 1: {
485 | 0: 0,
486 | 3: 0,
487 | 4: 0,
488 | 7: 0,
489 | 8: 0,
490 | 11: 1,
491 | 12: 0,
492 | 15: 1
493 | }
494 | },
495 | Vector2i(9, 1): {
496 | 0: 0,
497 | 1: {
498 | 0: 0,
499 | 3: 1,
500 | 4: 0,
501 | 7: 0,
502 | 8: 0,
503 | 11: 1,
504 | 12: 0,
505 | 15: 0
506 | }
507 | },
508 | Vector2i(9, 2): {
509 | 0: 0,
510 | 1: {
511 | 0: 0,
512 | 3: 0,
513 | 4: 0,
514 | 7: 0,
515 | 8: 0,
516 | 11: 0,
517 | 12: 0,
518 | 15: 0
519 | }
520 | },
521 | Vector2i(9, 3): {
522 | 0: 0,
523 | 1: {
524 | 0: 0,
525 | 3: 1,
526 | 4: 1,
527 | 7: 1,
528 | 8: 0,
529 | 11: 0,
530 | 12: 0,
531 | 15: 0
532 | }
533 | },
534 | Vector2i(10, 0): {
535 | 0: 0,
536 | 1: {
537 | 0: 0,
538 | 3: 0,
539 | 4: 0,
540 | 7: 0,
541 | 8: 0,
542 | 11: 1,
543 | 12: 1,
544 | 15: 1
545 | }
546 | },
547 | Vector2i(10, 1): {
548 | 0: 1,
549 | 1: {
550 | 0: 1,
551 | 3: 1,
552 | 4: 1,
553 | 7: 1,
554 | 8: 1,
555 | 11: 1,
556 | 12: 1,
557 | 15: 1
558 | }
559 | },
560 | Vector2i(10, 2): {
561 | 0: 0,
562 | 1: {
563 | 0: 0,
564 | 3: 0,
565 | 4: 0,
566 | 7: 1,
567 | 8: 0,
568 | 11: 0,
569 | 12: 0,
570 | 15: 1
571 | }
572 | },
573 | Vector2i(10, 3): {
574 | 0: 0,
575 | 1: {
576 | 0: 0,
577 | 3: 1,
578 | 4: 0,
579 | 7: 1,
580 | 8: 0,
581 | 11: 0,
582 | 12: 0,
583 | 15: 0
584 | }
585 | },
586 | Vector2i(11, 0): {
587 | 0: 0,
588 | 1: {
589 | 0: 1,
590 | 3: 1,
591 | 4: 0,
592 | 7: 0,
593 | 8: 0,
594 | 11: 1,
595 | 12: 1,
596 | 15: 1
597 | }
598 | },
599 | Vector2i(11, 1): {
600 | 0: 0,
601 | 1: {
602 | 0: 0,
603 | 3: 1,
604 | 4: 0,
605 | 7: 0,
606 | 8: 0,
607 | 11: 0,
608 | 12: 0,
609 | 15: 1
610 | }
611 | },
612 | Vector2i(11, 2): {
613 | 0: 0,
614 | 1: {
615 | 0: 1,
616 | 3: 1,
617 | 4: 0,
618 | 7: 0,
619 | 8: 0,
620 | 11: 0,
621 | 12: 0,
622 | 15: 1
623 | }
624 | },
625 | Vector2i(11, 3): {
626 | 0: 0,
627 | 1: {
628 | 0: 1,
629 | 3: 1,
630 | 4: 1,
631 | 7: 1,
632 | 8: 0,
633 | 11: 0,
634 | 12: 0,
635 | 15: 1
636 | }
637 | }
638 | }
639 | terrain_set = -1
640 | terrain_mode = 0
641 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/templates/simple_4-tile_(inside_corners).tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://c5o8gekgy74pn"]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/core/template_bit_data.gd" id="1_5cbea"]
4 |
5 | [resource]
6 | script = ExtResource("1_5cbea")
7 | version = "0.2.0"
8 | template_name = "Simple 4-Tile (Inside Corners)"
9 | template_description = "Use with Simple 9-Tile (Outside Corners). These simple autotiles are commonly found in spritesheets. Combining sets of inside and outside corners allows drawing a variety of over-lapping rectangles. However, the diagonal corners found in a full set of Corner tiles will be missing. And, like all Corner-mode autotiles, single-tile lines are not possible."
10 | _custom_tags = ["Incomplete Autotile", "Simple"]
11 | template_terrain_count = 2
12 | example_folder_path = "res://addons/tile_bit_tools/examples/simple_tilesets/"
13 | _tiles = {
14 | Vector2i(0, 0): {
15 | 0: 0,
16 | 1: {
17 | 3: 1,
18 | 7: 0,
19 | 11: 0,
20 | 15: 0
21 | }
22 | },
23 | Vector2i(0, 1): {
24 | 0: 0,
25 | 1: {
26 | 3: 0,
27 | 7: 0,
28 | 11: 0,
29 | 15: 1
30 | }
31 | },
32 | Vector2i(1, 0): {
33 | 0: 0,
34 | 1: {
35 | 3: 0,
36 | 7: 1,
37 | 11: 0,
38 | 15: 0
39 | }
40 | },
41 | Vector2i(1, 1): {
42 | 0: 0,
43 | 1: {
44 | 3: 0,
45 | 7: 0,
46 | 11: 1,
47 | 15: 0
48 | }
49 | }
50 | }
51 | terrain_set = -1
52 | terrain_mode = 1
53 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/templates/simple_9-tile_(inside_corners).tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://4x5kx54f54be"]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/core/template_bit_data.gd" id="1_00o4j"]
4 |
5 | [resource]
6 | script = ExtResource("1_00o4j")
7 | version = "0.2.0"
8 | template_name = "Simple 9-Tile (Inside Corners)"
9 | template_description = "Use with Simple 9-Tile (Outside Corners). These simple autotiles are commonly found in spritesheets. Combining sets of inside and outside corners allows drawing a variety of over-lapping rectangles. However, the diagonal corners found in a full set of Corner tiles will be missing. And, like all Corner-mode autotiles, single-tile lines are not possible."
10 | _custom_tags = ["Incomplete Autotile", "Simple"]
11 | template_terrain_count = 2
12 | example_folder_path = "res://addons/tile_bit_tools/examples/simple_tilesets/"
13 | _tiles = {
14 | Vector2i(0, 0): {
15 | 0: 0,
16 | 1: {
17 | 3: 1,
18 | 7: 0,
19 | 11: 0,
20 | 15: 0
21 | }
22 | },
23 | Vector2i(0, 1): {
24 | 0: 0,
25 | 1: {
26 | 3: 1,
27 | 7: 0,
28 | 11: 0,
29 | 15: 1
30 | }
31 | },
32 | Vector2i(0, 2): {
33 | 0: 0,
34 | 1: {
35 | 3: 0,
36 | 7: 0,
37 | 11: 0,
38 | 15: 1
39 | }
40 | },
41 | Vector2i(1, 0): {
42 | 0: 0,
43 | 1: {
44 | 3: 1,
45 | 7: 1,
46 | 11: 0,
47 | 15: 0
48 | }
49 | },
50 | Vector2i(1, 1): {
51 | 0: 1,
52 | 1: {
53 | 3: 1,
54 | 7: 1,
55 | 11: 1,
56 | 15: 1
57 | }
58 | },
59 | Vector2i(1, 2): {
60 | 0: 0,
61 | 1: {
62 | 3: 0,
63 | 7: 0,
64 | 11: 1,
65 | 15: 1
66 | }
67 | },
68 | Vector2i(2, 0): {
69 | 0: 0,
70 | 1: {
71 | 3: 0,
72 | 7: 1,
73 | 11: 0,
74 | 15: 0
75 | }
76 | },
77 | Vector2i(2, 1): {
78 | 0: 0,
79 | 1: {
80 | 3: 0,
81 | 7: 1,
82 | 11: 1,
83 | 15: 0
84 | }
85 | },
86 | Vector2i(2, 2): {
87 | 0: 0,
88 | 1: {
89 | 3: 0,
90 | 7: 0,
91 | 11: 1,
92 | 15: 0
93 | }
94 | }
95 | }
96 | terrain_set = -1
97 | terrain_mode = 1
98 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/templates/simple_9-tile_(outside_corners).tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://cs67cjf5v5e8m"]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/core/template_bit_data.gd" id="1_5bw30"]
4 |
5 | [resource]
6 | script = ExtResource("1_5bw30")
7 | version = "0.2.0"
8 | template_name = "Simple 9-Tile (Outside Corners)"
9 | template_description = "Use with Simple 4- or 9-Tile (Inside Corners). These simple autotiles are commonly found in spritesheets. Combining sets of inside and outside corners allows drawing a variety of over-lapping rectangles. However, the diagonal corners found in a full set of Corner tiles will be missing. And, like all Corner-mode autotiles, single-tile lines are not possible."
10 | _custom_tags = ["Incomplete Autotile", "Simple"]
11 | template_terrain_count = 2
12 | example_folder_path = "res://addons/tile_bit_tools/examples/simple_tilesets/"
13 | _tiles = {
14 | Vector2i(0, 0): {
15 | 0: 0,
16 | 1: {
17 | 3: 0,
18 | 7: 1,
19 | 11: 1,
20 | 15: 1
21 | }
22 | },
23 | Vector2i(0, 1): {
24 | 0: 0,
25 | 1: {
26 | 3: 0,
27 | 7: 1,
28 | 11: 1,
29 | 15: 0
30 | }
31 | },
32 | Vector2i(0, 2): {
33 | 0: 0,
34 | 1: {
35 | 3: 1,
36 | 7: 1,
37 | 11: 1,
38 | 15: 0
39 | }
40 | },
41 | Vector2i(1, 0): {
42 | 0: 0,
43 | 1: {
44 | 3: 0,
45 | 7: 0,
46 | 11: 1,
47 | 15: 1
48 | }
49 | },
50 | Vector2i(1, 1): {
51 | 0: 0,
52 | 1: {
53 | 3: 0,
54 | 7: 0,
55 | 11: 0,
56 | 15: 0
57 | }
58 | },
59 | Vector2i(1, 2): {
60 | 0: 0,
61 | 1: {
62 | 3: 1,
63 | 7: 1,
64 | 11: 0,
65 | 15: 0
66 | }
67 | },
68 | Vector2i(2, 0): {
69 | 0: 0,
70 | 1: {
71 | 3: 1,
72 | 7: 0,
73 | 11: 1,
74 | 15: 1
75 | }
76 | },
77 | Vector2i(2, 1): {
78 | 0: 0,
79 | 1: {
80 | 3: 1,
81 | 7: 0,
82 | 11: 0,
83 | 15: 1
84 | }
85 | },
86 | Vector2i(2, 2): {
87 | 0: 0,
88 | 1: {
89 | 3: 1,
90 | 7: 1,
91 | 11: 0,
92 | 15: 1
93 | }
94 | }
95 | }
96 | terrain_set = -1
97 | terrain_mode = 1
98 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/templates/tilesetter_blob.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://b304wbf3x68vn"]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/core/template_bit_data.gd" id="1_xoo0e"]
4 |
5 | [resource]
6 | script = ExtResource("1_xoo0e")
7 | version = "0.2.0"
8 | template_name = "Blob (Tilesetter)"
9 | template_description = "Corners-and-Sides autotile in Tilesetter's layout. In Tilesetter, select the center tile, build borders for 'Blob', then select the tiles and export as 'Image'. Does not include the stray single tile. Select that tile separately, and click 'Fill'."
10 | _custom_tags = ["Tilesetter"]
11 | template_terrain_count = 2
12 | example_folder_path = "res://addons/tile_bit_tools/examples/tilesetter_blob/"
13 | _tiles = {
14 | Vector2i(0, 0): {
15 | 0: 0,
16 | 1: {
17 | 0: 0,
18 | 3: 0,
19 | 4: 0,
20 | 7: 1,
21 | 8: 1,
22 | 11: 1,
23 | 12: 1,
24 | 15: 1
25 | }
26 | },
27 | Vector2i(0, 1): {
28 | 0: 0,
29 | 1: {
30 | 0: 0,
31 | 3: 0,
32 | 4: 0,
33 | 7: 1,
34 | 8: 1,
35 | 11: 1,
36 | 12: 0,
37 | 15: 0
38 | }
39 | },
40 | Vector2i(0, 2): {
41 | 0: 0,
42 | 1: {
43 | 0: 0,
44 | 3: 1,
45 | 4: 1,
46 | 7: 1,
47 | 8: 1,
48 | 11: 1,
49 | 12: 0,
50 | 15: 0
51 | }
52 | },
53 | Vector2i(0, 3): {
54 | 0: 0,
55 | 1: {
56 | 0: 0,
57 | 3: 1,
58 | 4: 1,
59 | 7: 1,
60 | 8: 1,
61 | 11: 1,
62 | 12: 1,
63 | 15: 1
64 | }
65 | },
66 | Vector2i(1, 0): {
67 | 0: 0,
68 | 1: {
69 | 0: 0,
70 | 3: 0,
71 | 4: 0,
72 | 7: 0,
73 | 8: 0,
74 | 11: 1,
75 | 12: 1,
76 | 15: 1
77 | }
78 | },
79 | Vector2i(1, 1): {
80 | 0: 0,
81 | 1: {
82 | 0: 0,
83 | 3: 0,
84 | 4: 0,
85 | 7: 0,
86 | 8: 0,
87 | 11: 0,
88 | 12: 0,
89 | 15: 0
90 | }
91 | },
92 | Vector2i(1, 2): {
93 | 0: 0,
94 | 1: {
95 | 0: 0,
96 | 3: 1,
97 | 4: 1,
98 | 7: 1,
99 | 8: 0,
100 | 11: 0,
101 | 12: 0,
102 | 15: 0
103 | }
104 | },
105 | Vector2i(1, 3): {
106 | 0: 0,
107 | 1: {
108 | 0: 0,
109 | 3: 1,
110 | 4: 1,
111 | 7: 1,
112 | 8: 0,
113 | 11: 1,
114 | 12: 1,
115 | 15: 1
116 | }
117 | },
118 | Vector2i(2, 0): {
119 | 0: 0,
120 | 1: {
121 | 0: 1,
122 | 3: 1,
123 | 4: 0,
124 | 7: 0,
125 | 8: 0,
126 | 11: 1,
127 | 12: 1,
128 | 15: 1
129 | }
130 | },
131 | Vector2i(2, 1): {
132 | 0: 0,
133 | 1: {
134 | 0: 1,
135 | 3: 1,
136 | 4: 0,
137 | 7: 0,
138 | 8: 0,
139 | 11: 0,
140 | 12: 0,
141 | 15: 1
142 | }
143 | },
144 | Vector2i(2, 2): {
145 | 0: 0,
146 | 1: {
147 | 0: 1,
148 | 3: 1,
149 | 4: 1,
150 | 7: 1,
151 | 8: 0,
152 | 11: 0,
153 | 12: 0,
154 | 15: 1
155 | }
156 | },
157 | Vector2i(2, 3): {
158 | 0: 0,
159 | 1: {
160 | 0: 1,
161 | 3: 1,
162 | 4: 1,
163 | 7: 1,
164 | 8: 0,
165 | 11: 1,
166 | 12: 1,
167 | 15: 1
168 | }
169 | },
170 | Vector2i(3, 0): {
171 | 0: 0,
172 | 1: {
173 | 0: 1,
174 | 3: 1,
175 | 4: 0,
176 | 7: 1,
177 | 8: 1,
178 | 11: 1,
179 | 12: 1,
180 | 15: 1
181 | }
182 | },
183 | Vector2i(3, 1): {
184 | 0: 0,
185 | 1: {
186 | 0: 1,
187 | 3: 1,
188 | 4: 0,
189 | 7: 1,
190 | 8: 1,
191 | 11: 1,
192 | 12: 0,
193 | 15: 1
194 | }
195 | },
196 | Vector2i(3, 2): {
197 | 0: 0,
198 | 1: {
199 | 0: 1,
200 | 3: 1,
201 | 4: 1,
202 | 7: 1,
203 | 8: 1,
204 | 11: 1,
205 | 12: 0,
206 | 15: 1
207 | }
208 | },
209 | Vector2i(3, 3): {
210 | 0: 0,
211 | 1: {
212 | 0: 1,
213 | 3: 1,
214 | 4: 1,
215 | 7: 1,
216 | 8: 1,
217 | 11: 1,
218 | 12: 1,
219 | 15: 1
220 | }
221 | },
222 | Vector2i(4, 0): {
223 | 0: 0,
224 | 1: {
225 | 0: 0,
226 | 3: 1,
227 | 4: 0,
228 | 7: 1,
229 | 8: 1,
230 | 11: 1,
231 | 12: 1,
232 | 15: 1
233 | }
234 | },
235 | Vector2i(4, 1): {
236 | 0: 0,
237 | 1: {
238 | 0: 0,
239 | 3: 1,
240 | 4: 0,
241 | 7: 1,
242 | 8: 1,
243 | 11: 1,
244 | 12: 0,
245 | 15: 0
246 | }
247 | },
248 | Vector2i(4, 2): {
249 | 0: 0,
250 | 1: {
251 | 0: 0,
252 | 3: 0,
253 | 4: 0,
254 | 7: 1,
255 | 8: 1,
256 | 11: 1,
257 | 12: 0,
258 | 15: 1
259 | }
260 | },
261 | Vector2i(4, 3): {
262 | 0: 0,
263 | 1: {
264 | 0: 0,
265 | 3: 1,
266 | 4: 1,
267 | 7: 1,
268 | 8: 1,
269 | 11: 1,
270 | 12: 0,
271 | 15: 1
272 | }
273 | },
274 | Vector2i(4, 4): {
275 | 0: 0,
276 | 1: {
277 | 0: 0,
278 | 3: 1,
279 | 4: 0,
280 | 7: 1,
281 | 8: 1,
282 | 11: 1,
283 | 12: 0,
284 | 15: 1
285 | }
286 | },
287 | Vector2i(5, 0): {
288 | 0: 0,
289 | 1: {
290 | 0: 0,
291 | 3: 1,
292 | 4: 0,
293 | 7: 0,
294 | 8: 0,
295 | 11: 1,
296 | 12: 1,
297 | 15: 1
298 | }
299 | },
300 | Vector2i(5, 1): {
301 | 0: 0,
302 | 1: {
303 | 0: 0,
304 | 3: 1,
305 | 4: 0,
306 | 7: 0,
307 | 8: 0,
308 | 11: 0,
309 | 12: 0,
310 | 15: 0
311 | }
312 | },
313 | Vector2i(5, 2): {
314 | 0: 0,
315 | 1: {
316 | 0: 0,
317 | 3: 0,
318 | 4: 0,
319 | 7: 0,
320 | 8: 0,
321 | 11: 0,
322 | 12: 0,
323 | 15: 1
324 | }
325 | },
326 | Vector2i(5, 3): {
327 | 0: 0,
328 | 1: {
329 | 0: 0,
330 | 3: 1,
331 | 4: 1,
332 | 7: 1,
333 | 8: 0,
334 | 11: 0,
335 | 12: 0,
336 | 15: 1
337 | }
338 | },
339 | Vector2i(5, 4): {
340 | 0: 0,
341 | 1: {
342 | 0: 0,
343 | 3: 1,
344 | 4: 0,
345 | 7: 0,
346 | 8: 0,
347 | 11: 0,
348 | 12: 0,
349 | 15: 1
350 | }
351 | },
352 | Vector2i(6, 0): {
353 | 0: 0,
354 | 1: {
355 | 0: 0,
356 | 3: 0,
357 | 4: 0,
358 | 7: 1,
359 | 8: 0,
360 | 11: 1,
361 | 12: 1,
362 | 15: 1
363 | }
364 | },
365 | Vector2i(6, 1): {
366 | 0: 0,
367 | 1: {
368 | 0: 0,
369 | 3: 0,
370 | 4: 0,
371 | 7: 1,
372 | 8: 0,
373 | 11: 0,
374 | 12: 0,
375 | 15: 0
376 | }
377 | },
378 | Vector2i(6, 2): {
379 | 0: 0,
380 | 1: {
381 | 0: 0,
382 | 3: 0,
383 | 4: 0,
384 | 7: 0,
385 | 8: 0,
386 | 11: 1,
387 | 12: 0,
388 | 15: 0
389 | }
390 | },
391 | Vector2i(6, 3): {
392 | 0: 0,
393 | 1: {
394 | 0: 0,
395 | 3: 1,
396 | 4: 1,
397 | 7: 1,
398 | 8: 0,
399 | 11: 1,
400 | 12: 0,
401 | 15: 0
402 | }
403 | },
404 | Vector2i(6, 4): {
405 | 0: 0,
406 | 1: {
407 | 0: 0,
408 | 3: 0,
409 | 4: 0,
410 | 7: 1,
411 | 8: 0,
412 | 11: 1,
413 | 12: 0,
414 | 15: 0
415 | }
416 | },
417 | Vector2i(7, 0): {
418 | 0: 0,
419 | 1: {
420 | 0: 1,
421 | 3: 1,
422 | 4: 0,
423 | 7: 1,
424 | 8: 0,
425 | 11: 1,
426 | 12: 1,
427 | 15: 1
428 | }
429 | },
430 | Vector2i(7, 1): {
431 | 0: 0,
432 | 1: {
433 | 0: 1,
434 | 3: 1,
435 | 4: 0,
436 | 7: 1,
437 | 8: 0,
438 | 11: 0,
439 | 12: 0,
440 | 15: 1
441 | }
442 | },
443 | Vector2i(7, 2): {
444 | 0: 0,
445 | 1: {
446 | 0: 1,
447 | 3: 1,
448 | 4: 0,
449 | 7: 0,
450 | 8: 0,
451 | 11: 1,
452 | 12: 0,
453 | 15: 1
454 | }
455 | },
456 | Vector2i(7, 3): {
457 | 0: 0,
458 | 1: {
459 | 0: 1,
460 | 3: 1,
461 | 4: 1,
462 | 7: 1,
463 | 8: 0,
464 | 11: 1,
465 | 12: 0,
466 | 15: 1
467 | }
468 | },
469 | Vector2i(7, 4): {
470 | 0: 0,
471 | 1: {
472 | 0: 1,
473 | 3: 1,
474 | 4: 0,
475 | 7: 1,
476 | 8: 0,
477 | 11: 1,
478 | 12: 0,
479 | 15: 1
480 | }
481 | },
482 | Vector2i(8, 0): {
483 | 0: 0,
484 | 1: {
485 | 0: 0,
486 | 3: 1,
487 | 4: 0,
488 | 7: 1,
489 | 8: 0,
490 | 11: 1,
491 | 12: 1,
492 | 15: 1
493 | }
494 | },
495 | Vector2i(8, 1): {
496 | 0: 0,
497 | 1: {
498 | 0: 0,
499 | 3: 1,
500 | 4: 0,
501 | 7: 1,
502 | 8: 0,
503 | 11: 0,
504 | 12: 0,
505 | 15: 0
506 | }
507 | },
508 | Vector2i(8, 2): {
509 | 0: 0,
510 | 1: {
511 | 0: 0,
512 | 3: 0,
513 | 4: 0,
514 | 7: 0,
515 | 8: 0,
516 | 11: 1,
517 | 12: 0,
518 | 15: 1
519 | }
520 | },
521 | Vector2i(8, 3): {
522 | 0: 0,
523 | 1: {
524 | 0: 0,
525 | 3: 1,
526 | 4: 1,
527 | 7: 1,
528 | 8: 0,
529 | 11: 1,
530 | 12: 0,
531 | 15: 1
532 | }
533 | },
534 | Vector2i(8, 4): {
535 | 0: 0,
536 | 1: {
537 | 0: 0,
538 | 3: 1,
539 | 4: 0,
540 | 7: 1,
541 | 8: 0,
542 | 11: 1,
543 | 12: 0,
544 | 15: 1
545 | }
546 | },
547 | Vector2i(9, 0): {
548 | 0: 0,
549 | 1: {
550 | 0: 0,
551 | 3: 0,
552 | 4: 0,
553 | 7: 1,
554 | 8: 0,
555 | 11: 0,
556 | 12: 0,
557 | 15: 1
558 | }
559 | },
560 | Vector2i(9, 1): {
561 | 0: 0,
562 | 1: {
563 | 0: 0,
564 | 3: 1,
565 | 4: 0,
566 | 7: 0,
567 | 8: 0,
568 | 11: 1,
569 | 12: 0,
570 | 15: 0
571 | }
572 | },
573 | Vector2i(9, 2): {
574 | 0: 0,
575 | 1: {
576 | 0: 0,
577 | 3: 0,
578 | 4: 0,
579 | 7: 1,
580 | 8: 0,
581 | 11: 1,
582 | 12: 0,
583 | 15: 1
584 | }
585 | },
586 | Vector2i(9, 3): {
587 | 0: 0,
588 | 1: {
589 | 0: 0,
590 | 3: 1,
591 | 4: 0,
592 | 7: 1,
593 | 8: 0,
594 | 11: 1,
595 | 12: 0,
596 | 15: 0
597 | }
598 | },
599 | Vector2i(10, 2): {
600 | 0: 0,
601 | 1: {
602 | 0: 0,
603 | 3: 1,
604 | 4: 0,
605 | 7: 0,
606 | 8: 0,
607 | 11: 1,
608 | 12: 0,
609 | 15: 1
610 | }
611 | },
612 | Vector2i(10, 3): {
613 | 0: 0,
614 | 1: {
615 | 0: 0,
616 | 3: 1,
617 | 4: 0,
618 | 7: 1,
619 | 8: 0,
620 | 11: 0,
621 | 12: 0,
622 | 15: 1
623 | }
624 | }
625 | }
626 | terrain_set = -1
627 | terrain_mode = 0
628 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/templates/tilesetter_wang.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://oenc7os41oe3"]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/core/template_bit_data.gd" id="1_dbw6t"]
4 |
5 | [resource]
6 | script = ExtResource("1_dbw6t")
7 | version = "0.2.0"
8 | template_name = "Wang (Tilesetter)"
9 | template_description = "Corners autotile in Tilesetter's layout. In Tilesetter, select the center tile, build borders for 'Wang', then select the tiles and export as 'Image'. Does not include the stray single tile. Select that tile separately, and click 'Fill'."
10 | _custom_tags = ["Tilesetter"]
11 | template_terrain_count = 2
12 | example_folder_path = "res://addons/tile_bit_tools/examples/tilesetter_wang/"
13 | _tiles = {
14 | Vector2i(0, 0): {
15 | 0: 0,
16 | 1: {
17 | 3: 0,
18 | 7: 1,
19 | 11: 1,
20 | 15: 1
21 | }
22 | },
23 | Vector2i(0, 1): {
24 | 0: 0,
25 | 1: {
26 | 3: 0,
27 | 7: 1,
28 | 11: 1,
29 | 15: 0
30 | }
31 | },
32 | Vector2i(0, 2): {
33 | 0: 0,
34 | 1: {
35 | 3: 1,
36 | 7: 1,
37 | 11: 1,
38 | 15: 0
39 | }
40 | },
41 | Vector2i(1, 0): {
42 | 0: 0,
43 | 1: {
44 | 3: 0,
45 | 7: 0,
46 | 11: 1,
47 | 15: 1
48 | }
49 | },
50 | Vector2i(1, 1): {
51 | 0: 0,
52 | 1: {
53 | 3: 0,
54 | 7: 0,
55 | 11: 0,
56 | 15: 0
57 | }
58 | },
59 | Vector2i(1, 2): {
60 | 0: 0,
61 | 1: {
62 | 3: 1,
63 | 7: 1,
64 | 11: 0,
65 | 15: 0
66 | }
67 | },
68 | Vector2i(2, 0): {
69 | 0: 0,
70 | 1: {
71 | 3: 1,
72 | 7: 0,
73 | 11: 1,
74 | 15: 1
75 | }
76 | },
77 | Vector2i(2, 1): {
78 | 0: 0,
79 | 1: {
80 | 3: 1,
81 | 7: 0,
82 | 11: 0,
83 | 15: 1
84 | }
85 | },
86 | Vector2i(2, 2): {
87 | 0: 0,
88 | 1: {
89 | 3: 1,
90 | 7: 1,
91 | 11: 0,
92 | 15: 1
93 | }
94 | },
95 | Vector2i(3, 0): {
96 | 0: 0,
97 | 1: {
98 | 3: 1,
99 | 7: 0,
100 | 11: 0,
101 | 15: 0
102 | }
103 | },
104 | Vector2i(3, 1): {
105 | 0: 0,
106 | 1: {
107 | 3: 0,
108 | 7: 0,
109 | 11: 0,
110 | 15: 1
111 | }
112 | },
113 | Vector2i(3, 2): {
114 | 0: 0,
115 | 1: {
116 | 3: 0,
117 | 7: 1,
118 | 11: 0,
119 | 15: 1
120 | }
121 | },
122 | Vector2i(4, 0): {
123 | 0: 0,
124 | 1: {
125 | 3: 0,
126 | 7: 1,
127 | 11: 0,
128 | 15: 0
129 | }
130 | },
131 | Vector2i(4, 1): {
132 | 0: 0,
133 | 1: {
134 | 3: 0,
135 | 7: 0,
136 | 11: 1,
137 | 15: 0
138 | }
139 | },
140 | Vector2i(4, 2): {
141 | 0: 0,
142 | 1: {
143 | 3: 1,
144 | 7: 0,
145 | 11: 1,
146 | 15: 0
147 | }
148 | }
149 | }
150 | terrain_set = -1
151 | terrain_mode = 1
152 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/templates/tilesetter_wang_3-terrain.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://da0d3b3822j63"]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/core/template_bit_data.gd" id="1_hxqib"]
4 |
5 | [resource]
6 | script = ExtResource("1_hxqib")
7 | version = "0.2.0"
8 | template_name = "Wang 3-Terrain (Tilesetter)"
9 | template_description = "Full autotile for 3-terrain Wang tilesets made in Tilesetter. In Tilesetter, select the center tiles for all three terrains at once, build borders for 'Wang', then select the tiles and export as 'Image'."
10 | _custom_tags = ["Tilesetter"]
11 | template_terrain_count = 3
12 | example_folder_path = "res://addons/tile_bit_tools/examples/tilesetter_wang_3_terrains/"
13 | _tiles = {
14 | Vector2i(0, 1): {
15 | 0: 1,
16 | 1: {
17 | 3: 1,
18 | 7: 1,
19 | 11: 1,
20 | 15: 1
21 | }
22 | },
23 | Vector2i(0, 4): {
24 | 0: 2,
25 | 1: {
26 | 3: 2,
27 | 7: 2,
28 | 11: 2,
29 | 15: 2
30 | }
31 | },
32 | Vector2i(1, 0): {
33 | 0: 0,
34 | 1: {
35 | 3: 0,
36 | 7: 1,
37 | 11: 1,
38 | 15: 1
39 | }
40 | },
41 | Vector2i(1, 1): {
42 | 0: 0,
43 | 1: {
44 | 3: 0,
45 | 7: 1,
46 | 11: 1,
47 | 15: 0
48 | }
49 | },
50 | Vector2i(1, 2): {
51 | 0: 0,
52 | 1: {
53 | 3: 1,
54 | 7: 1,
55 | 11: 1,
56 | 15: 0
57 | }
58 | },
59 | Vector2i(1, 3): {
60 | 0: 0,
61 | 1: {
62 | 3: 0,
63 | 7: 2,
64 | 11: 2,
65 | 15: 2
66 | }
67 | },
68 | Vector2i(1, 4): {
69 | 0: 0,
70 | 1: {
71 | 3: 0,
72 | 7: 2,
73 | 11: 2,
74 | 15: 0
75 | }
76 | },
77 | Vector2i(1, 5): {
78 | 0: 0,
79 | 1: {
80 | 3: 2,
81 | 7: 2,
82 | 11: 2,
83 | 15: 0
84 | }
85 | },
86 | Vector2i(1, 6): {
87 | 0: 1,
88 | 1: {
89 | 3: 1,
90 | 7: 2,
91 | 11: 2,
92 | 15: 2
93 | }
94 | },
95 | Vector2i(1, 7): {
96 | 0: 1,
97 | 1: {
98 | 3: 1,
99 | 7: 2,
100 | 11: 2,
101 | 15: 1
102 | }
103 | },
104 | Vector2i(1, 8): {
105 | 0: 1,
106 | 1: {
107 | 3: 2,
108 | 7: 2,
109 | 11: 2,
110 | 15: 1
111 | }
112 | },
113 | Vector2i(2, 0): {
114 | 0: 0,
115 | 1: {
116 | 3: 0,
117 | 7: 0,
118 | 11: 1,
119 | 15: 1
120 | }
121 | },
122 | Vector2i(2, 1): {
123 | 0: 0,
124 | 1: {
125 | 3: 0,
126 | 7: 0,
127 | 11: 0,
128 | 15: 0
129 | }
130 | },
131 | Vector2i(2, 2): {
132 | 0: 0,
133 | 1: {
134 | 3: 1,
135 | 7: 1,
136 | 11: 0,
137 | 15: 0
138 | }
139 | },
140 | Vector2i(2, 3): {
141 | 0: 0,
142 | 1: {
143 | 3: 0,
144 | 7: 0,
145 | 11: 2,
146 | 15: 2
147 | }
148 | },
149 | Vector2i(2, 5): {
150 | 0: 0,
151 | 1: {
152 | 3: 2,
153 | 7: 2,
154 | 11: 0,
155 | 15: 0
156 | }
157 | },
158 | Vector2i(2, 6): {
159 | 0: 1,
160 | 1: {
161 | 3: 1,
162 | 7: 1,
163 | 11: 2,
164 | 15: 2
165 | }
166 | },
167 | Vector2i(2, 8): {
168 | 0: 1,
169 | 1: {
170 | 3: 2,
171 | 7: 2,
172 | 11: 1,
173 | 15: 1
174 | }
175 | },
176 | Vector2i(3, 0): {
177 | 0: 0,
178 | 1: {
179 | 3: 1,
180 | 7: 0,
181 | 11: 1,
182 | 15: 1
183 | }
184 | },
185 | Vector2i(3, 1): {
186 | 0: 0,
187 | 1: {
188 | 3: 1,
189 | 7: 0,
190 | 11: 0,
191 | 15: 1
192 | }
193 | },
194 | Vector2i(3, 2): {
195 | 0: 0,
196 | 1: {
197 | 3: 1,
198 | 7: 1,
199 | 11: 0,
200 | 15: 1
201 | }
202 | },
203 | Vector2i(3, 3): {
204 | 0: 0,
205 | 1: {
206 | 3: 2,
207 | 7: 0,
208 | 11: 2,
209 | 15: 2
210 | }
211 | },
212 | Vector2i(3, 4): {
213 | 0: 0,
214 | 1: {
215 | 3: 2,
216 | 7: 0,
217 | 11: 0,
218 | 15: 2
219 | }
220 | },
221 | Vector2i(3, 5): {
222 | 0: 0,
223 | 1: {
224 | 3: 2,
225 | 7: 2,
226 | 11: 0,
227 | 15: 2
228 | }
229 | },
230 | Vector2i(3, 6): {
231 | 0: 1,
232 | 1: {
233 | 3: 2,
234 | 7: 1,
235 | 11: 2,
236 | 15: 2
237 | }
238 | },
239 | Vector2i(3, 7): {
240 | 0: 1,
241 | 1: {
242 | 3: 2,
243 | 7: 1,
244 | 11: 1,
245 | 15: 2
246 | }
247 | },
248 | Vector2i(3, 8): {
249 | 0: 1,
250 | 1: {
251 | 3: 2,
252 | 7: 2,
253 | 11: 1,
254 | 15: 2
255 | }
256 | },
257 | Vector2i(4, 0): {
258 | 0: 0,
259 | 1: {
260 | 3: 1,
261 | 7: 0,
262 | 11: 0,
263 | 15: 0
264 | }
265 | },
266 | Vector2i(4, 1): {
267 | 0: 0,
268 | 1: {
269 | 3: 0,
270 | 7: 0,
271 | 11: 0,
272 | 15: 1
273 | }
274 | },
275 | Vector2i(4, 2): {
276 | 0: 0,
277 | 1: {
278 | 3: 0,
279 | 7: 1,
280 | 11: 0,
281 | 15: 1
282 | }
283 | },
284 | Vector2i(4, 3): {
285 | 0: 0,
286 | 1: {
287 | 3: 2,
288 | 7: 0,
289 | 11: 0,
290 | 15: 0
291 | }
292 | },
293 | Vector2i(4, 4): {
294 | 0: 0,
295 | 1: {
296 | 3: 0,
297 | 7: 0,
298 | 11: 0,
299 | 15: 2
300 | }
301 | },
302 | Vector2i(4, 5): {
303 | 0: 0,
304 | 1: {
305 | 3: 0,
306 | 7: 2,
307 | 11: 0,
308 | 15: 2
309 | }
310 | },
311 | Vector2i(4, 6): {
312 | 0: 1,
313 | 1: {
314 | 3: 2,
315 | 7: 1,
316 | 11: 1,
317 | 15: 1
318 | }
319 | },
320 | Vector2i(4, 7): {
321 | 0: 1,
322 | 1: {
323 | 3: 1,
324 | 7: 1,
325 | 11: 1,
326 | 15: 2
327 | }
328 | },
329 | Vector2i(4, 8): {
330 | 0: 1,
331 | 1: {
332 | 3: 1,
333 | 7: 2,
334 | 11: 1,
335 | 15: 2
336 | }
337 | },
338 | Vector2i(5, 0): {
339 | 0: 0,
340 | 1: {
341 | 3: 0,
342 | 7: 1,
343 | 11: 0,
344 | 15: 0
345 | }
346 | },
347 | Vector2i(5, 1): {
348 | 0: 0,
349 | 1: {
350 | 3: 0,
351 | 7: 0,
352 | 11: 1,
353 | 15: 0
354 | }
355 | },
356 | Vector2i(5, 2): {
357 | 0: 0,
358 | 1: {
359 | 3: 1,
360 | 7: 0,
361 | 11: 1,
362 | 15: 0
363 | }
364 | },
365 | Vector2i(5, 3): {
366 | 0: 0,
367 | 1: {
368 | 3: 0,
369 | 7: 2,
370 | 11: 0,
371 | 15: 0
372 | }
373 | },
374 | Vector2i(5, 4): {
375 | 0: 0,
376 | 1: {
377 | 3: 0,
378 | 7: 0,
379 | 11: 2,
380 | 15: 0
381 | }
382 | },
383 | Vector2i(5, 5): {
384 | 0: 0,
385 | 1: {
386 | 3: 2,
387 | 7: 0,
388 | 11: 2,
389 | 15: 0
390 | }
391 | },
392 | Vector2i(5, 6): {
393 | 0: 1,
394 | 1: {
395 | 3: 1,
396 | 7: 2,
397 | 11: 1,
398 | 15: 1
399 | }
400 | },
401 | Vector2i(5, 7): {
402 | 0: 1,
403 | 1: {
404 | 3: 1,
405 | 7: 1,
406 | 11: 2,
407 | 15: 1
408 | }
409 | },
410 | Vector2i(5, 8): {
411 | 0: 1,
412 | 1: {
413 | 3: 2,
414 | 7: 1,
415 | 11: 2,
416 | 15: 1
417 | }
418 | },
419 | Vector2i(6, 6): {
420 | 0: 0,
421 | 1: {
422 | 3: 2,
423 | 7: 0,
424 | 11: 1,
425 | 15: 1
426 | }
427 | },
428 | Vector2i(6, 7): {
429 | 0: 0,
430 | 1: {
431 | 3: 1,
432 | 7: 1,
433 | 11: 0,
434 | 15: 2
435 | }
436 | },
437 | Vector2i(6, 8): {
438 | 0: 0,
439 | 1: {
440 | 3: 0,
441 | 7: 1,
442 | 11: 1,
443 | 15: 2
444 | }
445 | },
446 | Vector2i(6, 9): {
447 | 0: 0,
448 | 1: {
449 | 3: 2,
450 | 7: 1,
451 | 11: 1,
452 | 15: 0
453 | }
454 | },
455 | Vector2i(6, 10): {
456 | 0: 0,
457 | 1: {
458 | 3: 2,
459 | 7: 2,
460 | 11: 1,
461 | 15: 0
462 | }
463 | },
464 | Vector2i(6, 11): {
465 | 0: 0,
466 | 1: {
467 | 3: 0,
468 | 7: 1,
469 | 11: 2,
470 | 15: 2
471 | }
472 | },
473 | Vector2i(7, 6): {
474 | 0: 0,
475 | 1: {
476 | 3: 0,
477 | 7: 2,
478 | 11: 1,
479 | 15: 1
480 | }
481 | },
482 | Vector2i(7, 7): {
483 | 0: 0,
484 | 1: {
485 | 3: 1,
486 | 7: 1,
487 | 11: 2,
488 | 15: 0
489 | }
490 | },
491 | Vector2i(7, 8): {
492 | 0: 0,
493 | 1: {
494 | 3: 1,
495 | 7: 0,
496 | 11: 2,
497 | 15: 1
498 | }
499 | },
500 | Vector2i(7, 9): {
501 | 0: 0,
502 | 1: {
503 | 3: 1,
504 | 7: 2,
505 | 11: 0,
506 | 15: 1
507 | }
508 | },
509 | Vector2i(7, 10): {
510 | 0: 0,
511 | 1: {
512 | 3: 2,
513 | 7: 2,
514 | 11: 0,
515 | 15: 1
516 | }
517 | },
518 | Vector2i(7, 11): {
519 | 0: 0,
520 | 1: {
521 | 3: 1,
522 | 7: 0,
523 | 11: 2,
524 | 15: 2
525 | }
526 | },
527 | Vector2i(8, 6): {
528 | 0: 0,
529 | 1: {
530 | 3: 1,
531 | 7: 0,
532 | 11: 1,
533 | 15: 2
534 | }
535 | },
536 | Vector2i(8, 7): {
537 | 0: 0,
538 | 1: {
539 | 3: 2,
540 | 7: 1,
541 | 11: 0,
542 | 15: 1
543 | }
544 | },
545 | Vector2i(8, 8): {
546 | 0: 0,
547 | 1: {
548 | 3: 0,
549 | 7: 2,
550 | 11: 1,
551 | 15: 2
552 | }
553 | },
554 | Vector2i(8, 9): {
555 | 0: 0,
556 | 1: {
557 | 3: 2,
558 | 7: 1,
559 | 11: 2,
560 | 15: 0
561 | }
562 | },
563 | Vector2i(8, 10): {
564 | 0: 0,
565 | 1: {
566 | 3: 2,
567 | 7: 0,
568 | 11: 1,
569 | 15: 0
570 | }
571 | },
572 | Vector2i(8, 11): {
573 | 0: 0,
574 | 1: {
575 | 3: 0,
576 | 7: 1,
577 | 11: 0,
578 | 15: 2
579 | }
580 | },
581 | Vector2i(9, 6): {
582 | 0: 0,
583 | 1: {
584 | 3: 0,
585 | 7: 1,
586 | 11: 2,
587 | 15: 1
588 | }
589 | },
590 | Vector2i(9, 7): {
591 | 0: 0,
592 | 1: {
593 | 3: 1,
594 | 7: 2,
595 | 11: 1,
596 | 15: 0
597 | }
598 | },
599 | Vector2i(9, 8): {
600 | 0: 0,
601 | 1: {
602 | 3: 2,
603 | 7: 0,
604 | 11: 2,
605 | 15: 1
606 | }
607 | },
608 | Vector2i(9, 9): {
609 | 0: 0,
610 | 1: {
611 | 3: 1,
612 | 7: 2,
613 | 11: 0,
614 | 15: 2
615 | }
616 | },
617 | Vector2i(9, 10): {
618 | 0: 0,
619 | 1: {
620 | 3: 0,
621 | 7: 2,
622 | 11: 0,
623 | 15: 1
624 | }
625 | },
626 | Vector2i(9, 11): {
627 | 0: 0,
628 | 1: {
629 | 3: 1,
630 | 7: 0,
631 | 11: 2,
632 | 15: 0
633 | }
634 | },
635 | Vector2i(10, 6): {
636 | 0: 0,
637 | 1: {
638 | 3: 2,
639 | 7: 0,
640 | 11: 1,
641 | 15: 2
642 | }
643 | },
644 | Vector2i(10, 7): {
645 | 0: 0,
646 | 1: {
647 | 3: 2,
648 | 7: 1,
649 | 11: 0,
650 | 15: 2
651 | }
652 | },
653 | Vector2i(10, 8): {
654 | 0: 0,
655 | 1: {
656 | 3: 0,
657 | 7: 0,
658 | 11: 1,
659 | 15: 2
660 | }
661 | },
662 | Vector2i(10, 9): {
663 | 0: 0,
664 | 1: {
665 | 3: 2,
666 | 7: 1,
667 | 11: 0,
668 | 15: 0
669 | }
670 | },
671 | Vector2i(10, 10): {
672 | 0: 0,
673 | 1: {
674 | 3: 0,
675 | 7: 2,
676 | 11: 1,
677 | 15: 0
678 | }
679 | },
680 | Vector2i(10, 11): {
681 | 0: 0,
682 | 1: {
683 | 3: 0,
684 | 7: 1,
685 | 11: 2,
686 | 15: 0
687 | }
688 | },
689 | Vector2i(11, 6): {
690 | 0: 0,
691 | 1: {
692 | 3: 0,
693 | 7: 2,
694 | 11: 2,
695 | 15: 1
696 | }
697 | },
698 | Vector2i(11, 7): {
699 | 0: 0,
700 | 1: {
701 | 3: 1,
702 | 7: 2,
703 | 11: 2,
704 | 15: 0
705 | }
706 | },
707 | Vector2i(11, 8): {
708 | 0: 0,
709 | 1: {
710 | 3: 0,
711 | 7: 0,
712 | 11: 2,
713 | 15: 1
714 | }
715 | },
716 | Vector2i(11, 9): {
717 | 0: 0,
718 | 1: {
719 | 3: 1,
720 | 7: 2,
721 | 11: 0,
722 | 15: 0
723 | }
724 | },
725 | Vector2i(11, 10): {
726 | 0: 0,
727 | 1: {
728 | 3: 2,
729 | 7: 0,
730 | 11: 0,
731 | 15: 1
732 | }
733 | },
734 | Vector2i(11, 11): {
735 | 0: 0,
736 | 1: {
737 | 3: 1,
738 | 7: 0,
739 | 11: 0,
740 | 15: 2
741 | }
742 | }
743 | }
744 | terrain_set = -1
745 | terrain_mode = 1
746 |
--------------------------------------------------------------------------------
/addons/tile_bit_tools/templates/tilesetter_wang_3-terrain_transitions.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://cd8m38mk5xhiy"]
2 |
3 | [ext_resource type="Script" path="res://addons/tile_bit_tools/core/template_bit_data.gd" id="1_ubh4a"]
4 |
5 | [resource]
6 | script = ExtResource("1_ubh4a")
7 | version = "0.2.0"
8 | template_name = "Wang 3-Terrain Transition (Tilesetter)"
9 | template_description = "Transition tiles for 3-terrain Wang tilesets made in Tilesetter. Use in conjunction with 'Tilesetter Wang' to achieve the same results as 'Tilesetter Wang 3-Terrain'."
10 | _custom_tags = ["Tilesetter", "Incomplete Autotile"]
11 | template_terrain_count = 3
12 | example_folder_path = "res://addons/tile_bit_tools/examples/tilesetter_wang_3_terrains/"
13 | _tiles = {
14 | Vector2i(0, 0): {
15 | 0: 0,
16 | 1: {
17 | 3: 2,
18 | 7: 0,
19 | 11: 1,
20 | 15: 1
21 | }
22 | },
23 | Vector2i(0, 1): {
24 | 0: 0,
25 | 1: {
26 | 3: 1,
27 | 7: 1,
28 | 11: 0,
29 | 15: 2
30 | }
31 | },
32 | Vector2i(0, 2): {
33 | 0: 0,
34 | 1: {
35 | 3: 0,
36 | 7: 1,
37 | 11: 1,
38 | 15: 2
39 | }
40 | },
41 | Vector2i(0, 3): {
42 | 0: 0,
43 | 1: {
44 | 3: 2,
45 | 7: 1,
46 | 11: 1,
47 | 15: 0
48 | }
49 | },
50 | Vector2i(0, 4): {
51 | 0: 0,
52 | 1: {
53 | 3: 2,
54 | 7: 2,
55 | 11: 1,
56 | 15: 0
57 | }
58 | },
59 | Vector2i(0, 5): {
60 | 0: 0,
61 | 1: {
62 | 3: 0,
63 | 7: 1,
64 | 11: 2,
65 | 15: 2
66 | }
67 | },
68 | Vector2i(1, 0): {
69 | 0: 0,
70 | 1: {
71 | 3: 0,
72 | 7: 2,
73 | 11: 1,
74 | 15: 1
75 | }
76 | },
77 | Vector2i(1, 1): {
78 | 0: 0,
79 | 1: {
80 | 3: 1,
81 | 7: 1,
82 | 11: 2,
83 | 15: 0
84 | }
85 | },
86 | Vector2i(1, 2): {
87 | 0: 0,
88 | 1: {
89 | 3: 1,
90 | 7: 0,
91 | 11: 2,
92 | 15: 1
93 | }
94 | },
95 | Vector2i(1, 3): {
96 | 0: 0,
97 | 1: {
98 | 3: 1,
99 | 7: 2,
100 | 11: 0,
101 | 15: 1
102 | }
103 | },
104 | Vector2i(1, 4): {
105 | 0: 0,
106 | 1: {
107 | 3: 2,
108 | 7: 2,
109 | 11: 0,
110 | 15: 1
111 | }
112 | },
113 | Vector2i(1, 5): {
114 | 0: 0,
115 | 1: {
116 | 3: 1,
117 | 7: 0,
118 | 11: 2,
119 | 15: 2
120 | }
121 | },
122 | Vector2i(2, 0): {
123 | 0: 0,
124 | 1: {
125 | 3: 1,
126 | 7: 0,
127 | 11: 1,
128 | 15: 2
129 | }
130 | },
131 | Vector2i(2, 1): {
132 | 0: 0,
133 | 1: {
134 | 3: 2,
135 | 7: 1,
136 | 11: 0,
137 | 15: 1
138 | }
139 | },
140 | Vector2i(2, 2): {
141 | 0: 0,
142 | 1: {
143 | 3: 0,
144 | 7: 2,
145 | 11: 1,
146 | 15: 2
147 | }
148 | },
149 | Vector2i(2, 3): {
150 | 0: 0,
151 | 1: {
152 | 3: 2,
153 | 7: 1,
154 | 11: 2,
155 | 15: 0
156 | }
157 | },
158 | Vector2i(2, 4): {
159 | 0: 0,
160 | 1: {
161 | 3: 2,
162 | 7: 0,
163 | 11: 1,
164 | 15: 0
165 | }
166 | },
167 | Vector2i(2, 5): {
168 | 0: 0,
169 | 1: {
170 | 3: 0,
171 | 7: 1,
172 | 11: 0,
173 | 15: 2
174 | }
175 | },
176 | Vector2i(3, 0): {
177 | 0: 0,
178 | 1: {
179 | 3: 0,
180 | 7: 1,
181 | 11: 2,
182 | 15: 1
183 | }
184 | },
185 | Vector2i(3, 1): {
186 | 0: 0,
187 | 1: {
188 | 3: 1,
189 | 7: 2,
190 | 11: 1,
191 | 15: 0
192 | }
193 | },
194 | Vector2i(3, 2): {
195 | 0: 0,
196 | 1: {
197 | 3: 2,
198 | 7: 0,
199 | 11: 2,
200 | 15: 1
201 | }
202 | },
203 | Vector2i(3, 3): {
204 | 0: 0,
205 | 1: {
206 | 3: 1,
207 | 7: 2,
208 | 11: 0,
209 | 15: 2
210 | }
211 | },
212 | Vector2i(3, 4): {
213 | 0: 0,
214 | 1: {
215 | 3: 0,
216 | 7: 2,
217 | 11: 0,
218 | 15: 1
219 | }
220 | },
221 | Vector2i(3, 5): {
222 | 0: 0,
223 | 1: {
224 | 3: 1,
225 | 7: 0,
226 | 11: 2,
227 | 15: 0
228 | }
229 | },
230 | Vector2i(4, 0): {
231 | 0: 0,
232 | 1: {
233 | 3: 2,
234 | 7: 0,
235 | 11: 1,
236 | 15: 2
237 | }
238 | },
239 | Vector2i(4, 1): {
240 | 0: 0,
241 | 1: {
242 | 3: 2,
243 | 7: 1,
244 | 11: 0,
245 | 15: 2
246 | }
247 | },
248 | Vector2i(4, 2): {
249 | 0: 0,
250 | 1: {
251 | 3: 0,
252 | 7: 0,
253 | 11: 1,
254 | 15: 2
255 | }
256 | },
257 | Vector2i(4, 3): {
258 | 0: 0,
259 | 1: {
260 | 3: 2,
261 | 7: 1,
262 | 11: 0,
263 | 15: 0
264 | }
265 | },
266 | Vector2i(4, 4): {
267 | 0: 0,
268 | 1: {
269 | 3: 0,
270 | 7: 2,
271 | 11: 1,
272 | 15: 0
273 | }
274 | },
275 | Vector2i(4, 5): {
276 | 0: 0,
277 | 1: {
278 | 3: 0,
279 | 7: 1,
280 | 11: 2,
281 | 15: 0
282 | }
283 | },
284 | Vector2i(5, 0): {
285 | 0: 0,
286 | 1: {
287 | 3: 0,
288 | 7: 2,
289 | 11: 2,
290 | 15: 1
291 | }
292 | },
293 | Vector2i(5, 1): {
294 | 0: 0,
295 | 1: {
296 | 3: 1,
297 | 7: 2,
298 | 11: 2,
299 | 15: 0
300 | }
301 | },
302 | Vector2i(5, 2): {
303 | 0: 0,
304 | 1: {
305 | 3: 0,
306 | 7: 0,
307 | 11: 2,
308 | 15: 1
309 | }
310 | },
311 | Vector2i(5, 3): {
312 | 0: 0,
313 | 1: {
314 | 3: 1,
315 | 7: 2,
316 | 11: 0,
317 | 15: 0
318 | }
319 | },
320 | Vector2i(5, 4): {
321 | 0: 0,
322 | 1: {
323 | 3: 2,
324 | 7: 0,
325 | 11: 0,
326 | 15: 1
327 | }
328 | },
329 | Vector2i(5, 5): {
330 | 0: 0,
331 | 1: {
332 | 3: 1,
333 | 7: 0,
334 | 11: 0,
335 | 15: 2
336 | }
337 | }
338 | }
339 | terrain_set = -1
340 | terrain_mode = 1
341 |
--------------------------------------------------------------------------------