1 /*************************************************************************/
2 /*  editor_export_godot3.cpp                                             */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */
10 /*                                                                       */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the       */
13 /* "Software"), to deal in the Software without restriction, including   */
14 /* without limitation the rights to use, copy, modify, merge, publish,   */
15 /* distribute, sublicense, and/or sell copies of the Software, and to    */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions:                                             */
18 /*                                                                       */
19 /* The above copyright notice and this permission notice shall be        */
20 /* included in all copies or substantial portions of the Software.       */
21 /*                                                                       */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29 /*************************************************************************/
30 #include "editor_export_godot3.h"
31 
32 #include "drivers/nrex/regex.h"
33 #include "editor_node.h"
34 #include "io/resource_format_binary.h"
35 #include "io/resource_format_xml.h"
36 #include "scene/resources/scene_format_text.h"
37 
38 static const char *globals_renames[][2] = {
39 	/* [application] */
40 	{ "application/name", "application/config/name" },
41 	{ "application/auto_accept_quit", "application/config/auto_accept_quit" },
42 	{ "application/boot_splash", "application/boot_splash/image" },
43 	{ "application/boot_splash_fullsize", "application/boot_splash/fullsize" },
44 	{ "application/icon", "application/config/icon" },
45 	{ "application/main_scene", "application/run/main_scene" },
46 	{ "application/main_loop_type", "application/run/main_loop_type" },
47 	{ "application/disable_stdout", "application/run/disable_stdout" },
48 	{ "application/disable_stderr", "application/run/disable_stderr" },
49 	{ "application/frame_delay_msec", "application/run/frame_delay_msec" },
50 
51 	/* [debug] */
52 	{ "debug/profiler_max_functions", "debug/settings/profiler/max_functions" },
53 	{ "debug/max_remote_stdout_chars_per_second", "network/limits/debugger_stdout/max_chars_per_second" },
54 	{ "debug/force_fps", "debug/settings/fps/force_fps" },
55 	{ "debug/verbose_stdout", "debug/settings/stdout/verbose_stdout" },
56 	//{ "debug/max_texture_size", "debug/" },
57 	//{ "debug/max_texture_size_alert", "debug/" },
58 	//{ "debug/image_load_times", "debug/" },
59 	{ "debug/script_max_call_stack", "debug/settings/gdscript/max_call_stack" },
60 	{ "debug/collision_shape_color", "debug/shapes/collision/shape_color" },
61 	{ "debug/collision_contact_color", "debug/shapes/collision/contact_color" },
62 	{ "debug/navigation_geometry_color", "debug/shapes/navigation/geometry_color" },
63 	{ "debug/navigation_disabled_geometry_color", "debug/shapes/navigation/disabled_geometry_color" },
64 	{ "debug/collision_max_contacts_displayed", "debug/shapes/collision/max_contacts_displayed" },
65 	//{ "debug/indicators_enabled", "debug/" },
66 	{ "debug/print_fps", "debug/settings/stdout/print_fps" },
67 	//{ "debug/print_metrics", "debug/" },
68 
69 	/* [display] */
70 	{ "display/driver", "display/driver/name" },
71 	{ "display/width", "display/window/size/width" },
72 	{ "display/height", "display/window/size/height" },
73 	{ "display/allow_hidpi", "display/window/dpi/allow_hidpi" },
74 	{ "display/fullscreen", "display/window/size/fullscreen" },
75 	{ "display/resizable", "display/window/size/resizable" },
76 	{ "display/borderless_window", "display/window/size/borderless" },
77 	{ "display/use_vsync", "display/window/vsync/use_vsync" },
78 	{ "display/test_width", "display/window/size/test_width" },
79 	{ "display/test_height", "display/window/size/test_height" },
80 	{ "display/use_2d_pixel_snap", "rendering/quality/2d/use_pixel_snap" },
81 	{ "display/keep_screen_on", "display/window/energy_saving/keep_screen_on" },
82 	{ "display/orientation", "display/window/handheld/orientation" },
83 	{ "display/emulate_touchscreen", "display/window/handheld/emulate_touchscreen" },
84 	{ "display/use_hidpi_theme", "gui/theme/use_hidpi" },
85 	{ "display/custom_theme", "gui/theme/custom" },
86 	{ "display/custom_theme_font", "gui/theme/custom_font" },
87 	{ "display/swap_ok_cancel", "gui/common/swap_ok_cancel" },
88 	{ "display/tooltip_delay", "gui/timers/tooltip_delay_sec" },
89 	{ "display/text_edit_idle_detect_sec", "gui/timers/text_edit_idle_detect_sec" },
90 	{ "display/stretch_mode", "display/window/stretch/mode" },
91 	{ "display/stretch_aspect", "display/window/stretch/aspect" },
92 
93 	/* [render] */
94 	{ "render/thread_model", "rendering/threads/thread_model" },
95 	//{ "render/mipmap_policy", "" },
96 	//{ "render/thread_textures_prealloc", "" },
97 	//{ "render/shadows_enabled", "" },
98 	//{ "render/aabb_random_points", "" },
99 	{ "render/default_clear_color", "rendering/environment/default_clear_color" },
100 	//{ "render/room_cull_enabled", "" },
101 	//{ "render/light_discard_enabled", "" },
102 
103 	/* [audio] */
104 	// partly unchanged
105 	//{ "audio/mixer_interp", "" },
106 	//{ "audio/use_chorus_reverb", "" },
107 	//{ "audio/stream_volume_scale", "" },
108 	//{ "audio/fx_volume_scale", "" },
109 	//{ "audio/event_voice_volume_scale", "" },
110 	//{ "audio/stream_buffering_ms", "" },
111 	//{ "audio/video_delay_compensation_ms", "" },
112 	//{ "audio/mixer_latency", "" },
113 
114 	/* [physics] */
115 	{ "physics/fixed_fps", "physics/common/physics_fps" },
116 	{ "physics/remove_collision_helpers_at_runtime", "physics/" },
117 	{ "physics/sleep_threshold_linear", "physics/3d/sleep_threshold_linear" },
118 	{ "physics/sleep_threshold_angular", "physics/3d/sleep_threshold_angular" },
119 	{ "physics/time_before_sleep", "physics/3d/time_before_sleep" },
120 	{ "physics/default_gravity", "physics/3d/default_gravity" },
121 	{ "physics/default_gravity_vector", "physics/3d/default_gravity_vector" },
122 	{ "physics/default_linear_damp", "physics/3d/default_linear_damp" },
123 	{ "physics/default_angular_damp", "physics/3d/default_angular_damp" },
124 	{ "physics/enable_object_picking", "physics/common/enable_object_picking" },
125 
126 	/* [core] */
127 	//{ "core/message_queue_size_kb", "" },
128 	//{ "core/rid_pool_prealloc", "" },
129 	//{ "core/thread_rid_pool_prealloc", "" },
130 	{ "core/packet_stream_peer_max_buffer_po2", "network/limits/packet_peer_stream/max_buffer_po2" },
131 
132 	/* [rasterizer.Android] */
133 	//{ "rasterizer.Android/use_fragment_lighting", "" },
134 	//{ "rasterizer.Android/fp16_framebuffer", "" },
135 
136 	/* [display.Android] */
137 	//{ "display.Android/driver", "" },
138 
139 	/* [rasterizer.iOS] */
140 	//{ "rasterizer.iOS/use_fragment_lighting", "" },
141 	//{ "rasterizer.iOS/fp16_framebuffer", "" },
142 
143 	/* [display.iOS] */
144 	//{ "display.iOS/driver", "" },
145 	//{ "display.iOS/use_cadisplaylink", "" },
146 
147 	/* [rasterizer] */
148 	// most don't have an equivalent or are not meaningful to port
149 	{ "rasterizer/anisotropic_filter_level", "rendering/quality/filter/anisotropic_filter_level" },
150 
151 	/* [physics_2d] */
152 	{ "physics_2d/thread_model", "physics/2d/thread_model" },
153 	//{ "physics_2d/motion_fix_enabled", "" },
154 	{ "physics_2d/sleep_threashold_linear", "physics/2d/sleep_threshold_linear" },
155 	{ "physics_2d/sleep_threshold_angular", "physics/2d/sleep_threshold_angular" },
156 	{ "physics_2d/time_before_sleep", "physics/2d/time_before_sleep" },
157 	{ "physics_2d/bp_hash_table_size", "physics/2d/bp_hash_table_size" },
158 	{ "physics_2d/cell_size", "physics/2d/cell_size" },
159 	{ "physics_2d/large_object_surface_treshold_in_cells", "physics/2d/large_object_surface_threshold_in_cells" },
160 	{ "physics_2d/default_gravity", "physics/2d/default_gravity" },
161 	{ "physics_2d/default_gravity_vector", "physics/2d/default_gravity_vector" },
162 	{ "physics_2d/default_linear_damp", "physics/2d/default_linear_damp" },
163 	{ "physics_2d/default_angular_damp", "physics/2d/default_angular_damp" },
164 
165 	/* [image_loader] */
166 	//{ "image_loader/filter", "" },
167 	//{ "image_loader/gen_mipmaps", "" },
168 	//{ "image_loader/repeat", "" },
169 
170 	/* [ssl] */
171 	{ "ssl/certificates", "network/ssl/certificates" },
172 	{ "ssl/config", "network/ssl/config" },
173 
174 	/* [locale] */
175 	// no change
176 
177 	/* [global] */
178 	{ "editor_active", "editor/active" },
179 
180 	/* [editor] */
181 	{ "editor/main_run_args", "editor/main_run_args" },
182 	//{ "editor/import_shared_textures", "" },
183 
184 	/* [gui] */
185 	{ "gui/incr_search_max_interval_msec", "gui/timers/incremental_search_max_interval_msec" },
186 
187 	{ NULL, NULL }
188 };
189 
190 static const char *prop_renames[][2] = {
191 	{ "anchor/bottom", "anchor_bottom" }, // Control
192 	{ "anchor/left", "anchor_left" }, // Control
193 	{ "anchor/right", "anchor_right" }, // Control
194 	{ "anchor/top", "anchor_top" }, // Control
195 	{ "bbcode/bbcode", "bbcode_text" }, // RichTextLabel
196 	{ "bbcode/enabled", "bbcode_enabled" }, // RichTextLabel
197 	{ "bias/bias", "bias" }, // Joints2D
198 	{ "caret/block_caret", "caret_block_mode" }, // TextEdit
199 	{ "caret/caret_blink", "caret_blink" }, // LineEdit, TextEdit
200 	{ "caret/caret_blink_speed", "caret_blink_speed" }, // LineEdit, TextEdit
201 	{ "cell/center_x", "cell_center_x" }, // GridMap
202 	{ "cell/center_y", "cell_center_y" }, // GridMap
203 	{ "cell/center_z", "cell_center_z" }, // GridMap
204 	{ "cell/custom_transform", "cell_custom_transform" }, // TileMap
205 	{ "cell/half_offset", "cell_half_offset" }, // TileMap
206 	{ "cell/octant_size", "cell_octant_size" }, // GridMap
207 	{ "cell/quadrant_size", "cell_quadrant_size" }, // TileMap
208 	{ "cell/scale", "cell_scale" }, // GridMap
209 	{ "cell/size", "cell_size" }, // GridMap, TileMap
210 	{ "cell/tile_origin", "cell_tile_origin" }, // TileMap
211 	{ "cell/y_sort", "cell_y_sort" }, // TileMap
212 	{ "collision/bounce", "collision_bounce" }, // TileMap
213 	//{ "collision/exclude_nodes", "disable_collision" }, // Joint, Joint2D // Joint2D can be converted, not Joint, handle manually
214 	{ "collision/friction", "collision_friction" }, // TileMap
215 	{ "collision/layers", "collision_layer" }, // Area, Area2D, PhysicsBody, PhysicsBody2D, TileMap
216 	{ "collision/margin", "collision/safe_margin" }, // PhysicsBody, PhysicsBody2D
217 	{ "collision/mask", "collision_mask" }, // Area, Area2D, PhysicsBody, PhysicsBody2D, TileMap
218 	{ "collision/use_kinematic", "collision_use_kinematic" }, // TileMap
219 	{ "config/amount", "amount" }, // Particles2D
220 	{ "config/emitting", "emitting" }, // Particles2D
221 	{ "config/explosiveness", "explosiveness" }, // Particles2D
222 	{ "config/h_frames", "h_frames" }, // Particles2D
223 	{ "config/lifetime", "lifetime" }, // Particles2D
224 	{ "config/local_space", "local_coords" }, // Particles2D
225 	{ "config/preprocess", "preprocess" }, // Particles2D
226 	{ "config/texture", "texture" }, // Particles2D
227 	{ "config/time_scale", "speed_scale" }, // Particles2D
228 	{ "config/v_frames", "v_frames" }, // Particles2D
229 	{ "content_margin/bottom", "content_margin_bottom" }, // StyleBox
230 	{ "content_margin/left", "content_margin_left" }, // StyleBox
231 	{ "content_margin/right", "content_margin_right" }, // StyleBox
232 	{ "content_margin/top", "content_margin_top" }, // StyleBox
233 	{ "damping/compression", "damping_compression" }, // VehicleWheel
234 	{ "damping/relaxation", "damping_relaxation" }, // VehicleWheel
235 	{ "damp_override/angular", "angular_damp" }, // PhysicsBody, PhysicsBody2D
236 	{ "damp_override/linear", "linear_damp" }, // PhysicsBody, PhysicsBody2D
237 	{ "dialog/hide_on_ok", "dialog_hide_on_ok" }, // AcceptDialog
238 	{ "dialog/text", "dialog_text" }, // AcceptDialog
239 	{ "drag_margin/bottom", "drag_margin_bottom" }, // Camera2D
240 	{ "drag_margin/h_enabled", "drag_margin_h_enabled" }, // Camera2D
241 	{ "drag_margin/left", "drag_margin_left" }, // Camera2D
242 	{ "drag_margin/right", "drag_margin_right" }, // Camera2D
243 	{ "drag_margin/top", "drag_margin_top" }, // Camera2D
244 	{ "drag_margin/v_enabled", "drag_margin_v_enabled" }, // Camera2D
245 	{ "enabler/fixed_process_parent", "physics_process_parent" }, // VisibilityEnabler2D
246 	{ "enabler/freeze_bodies", "freeze_bodies" }, // VisibilityEnabler, VisibilityEnabler2D
247 	{ "enabler/pause_animated_sprites", "pause_animated_sprites" }, // VisibilityEnabler2D
248 	{ "enabler/pause_animations", "pause_animations" }, // VisibilityEnabler, VisibilityEnabler2D
249 	{ "enabler/pause_particles", "pause_particles" }, // VisibilityEnabler2D
250 	{ "enabler/process_parent", "process_parent" }, // VisibilityEnabler2D
251 	{ "expand_margin/bottom", "expand_margin_bottom" }, // StyleBox
252 	{ "expand_margin/left", "expand_margin_left" }, // StyleBox
253 	{ "expand_margin/right", "expand_margin_right" }, // StyleBox
254 	{ "expand_margin/top", "expand_margin_top" }, // StyleBox
255 	{ "extra_spacing/bottom", "extra_spacing_bottom" }, // DynamicFont
256 	{ "extra_spacing/char", "extra_spacing_char" }, // DynamicFont
257 	{ "extra_spacing/space", "extra_spacing_space" }, // DynamicFont
258 	{ "extra_spacing/top", "extra_spacing_top" }, // DynamicFont
259 	{ "flags/alpha_cut", "alpha_cut" }, // Sprite3D
260 	{ "flags/double_sided", "double_sided" }, // Sprite3D
261 	{ "flags/shaded", "shaded" }, // Sprite3D
262 	{ "flags/transparent", "transparent" }, // Sprite3D
263 	{ "focus_neighbour/bottom", "focus_neighbour_bottom" }, // Control
264 	{ "focus_neighbour/left", "focus_neighbour_left" }, // Control
265 	{ "focus_neighbour/right", "focus_neighbour_right" }, // Control
266 	{ "focus_neighbour/top", "focus_neighbour_top" }, // Control
267 	{ "font/font", "font_data" }, // DynamicFont
268 	{ "font/size", "size" }, // DynamicFont
269 	{ "font/use_filter", "use_filter" }, // DynamicFont
270 	{ "font/use_mipmaps", "use_mipmaps" }, // DynamicFont
271 	{ "geometry/cast_shadow", "cast_shadow" }, // GeometryInstance
272 	{ "geometry/extra_cull_margin", "extra_cull_margin" }, // GeometryInstance
273 	{ "geometry/material_override", "material_override" }, // GeometryInstance
274 	{ "geometry/use_baked_light", "use_in_baked_light" }, // GeometryInstance
275 	{ "hint/tooltip", "hint_tooltip" }, // Control
276 	{ "input/capture_on_drag", "input_capture_on_drag" }, // CollisionObject
277 	{ "input/pickable", "input_pickable" }, // CollisionObject2D
278 	{ "input/ray_pickable", "input_ray_pickable" }, // CollisionObject
279 	{ "invert/border", "invert_border" }, // Polygon2D
280 	{ "invert/enable", "invert_enable" }, // Polygon2D
281 	{ "is_pressed", "pressed" }, // BaseButton
282 	{ "limit/bottom", "limit_bottom" }, // Camera2D
283 	{ "limit/left", "limit_left" }, // Camera2D
284 	{ "limit/right", "limit_right" }, // Camera2D
285 	{ "limit/top", "limit_top" }, // Camera2D
286 	{ "margin/bottom", "margin_bottom" }, // Control, StyleBox
287 	{ "margin/left", "margin_left" }, // Control, StyleBox
288 	{ "margin/right", "margin_right" }, // Control, StyleBox
289 	{ "margin/top", "margin_top" }, // Control, StyleBox
290 	{ "material/material", "material" }, // CanvasItem
291 	{ "material/use_parent", "use_parent_material" }, // CanvasItem
292 	{ "mesh/mesh", "mesh" }, // MeshInstance
293 	{ "mesh/skeleton", "skeleton" }, // MeshInstance
294 	//{ "mode", "fill_mode" }, // TextureProgress & others // Would break TileMap and others, handle manually
295 	{ "motion/brake", "brake" }, // VehicleBody
296 	{ "motion/engine_force", "engine_force" }, // VehicleBody
297 	{ "motion/mirroring", "motion_mirroring" }, // ParallaxLayer
298 	{ "motion/offset", "motion_offset" }, // ParallaxLayer
299 	{ "motion/scale", "motion_scale" }, // ParallaxLayer
300 	{ "motion/steering", "steering" }, // VehicleBody
301 	{ "occluder/light_mask", "occluder_light_mask" }, // TileMap
302 	{ "params/attenuation/distance_exp", "attenuation_distance_exp" },
303 	{ "params/attenuation/max_distance", "attenuation_max_distance" },
304 	{ "params/attenuation/min_distance", "attenuation_min_distance" },
305 	{ "params/emission_cone/attenuation_db", "emission_cone_attenuation_db" },
306 	{ "params/emission_cone/degrees", "emission_cone_degrees" },
307 	{ "params/modulate", "self_modulate" },
308 	{ "params/pitch_scale", "pitch_scale" },
309 	{ "params/scale", "texture_scale" },
310 	{ "params/volume_db", "volume_db" },
311 	{ "patch_margin/bottom", "patch_margin_bottom" }, // Patch9Frame
312 	{ "patch_margin/left", "patch_margin_left" }, // Patch9Frame
313 	{ "patch_margin/right", "patch_margin_right" }, // Patch9Frame
314 	{ "patch_margin/top", "patch_margin_top" }, // Patch9Frame
315 	{ "percent/visible", "percent_visible" }, // ProgressBar
316 	{ "placeholder/alpha", "placeholder_alpha" }, // LineEdit
317 	{ "placeholder/text", "placeholder_text" }, // LineEdit
318 	//{ "playback/active", "playback_active" }, // AnimationPlayer, AnimationTreePlayer // properly renamed for AnimationPlayer, but not AnimationTreePlayer, handle manually
319 	{ "playback/default_blend_time", "playback_default_blend_time" }, // AnimationPlayer
320 	{ "playback/process_mode", "playback_process_mode" }, // AnimationPlayer, AnimationTreePlayer, Tween
321 	{ "playback/speed", "playback_speed" }, // AnimationPlayer, Tween
322 	{ "playback/repeat", "playback_speed" }, // AnimationPlayer
323 	{ "popup/exclusive", "popup_exclusive" }, // Popup
324 	{ "process/pause_mode", "pause_mode" }, // Node
325 	{ "radial_fill/center_offset", "radial_center_offset" }, // TextureProgress
326 	{ "radial_fill/fill_degrees", "radial_fill_degrees" }, // TextureProgress
327 	{ "radial_fill/initial_angle", "radial_initial_angle" }, // TextureProgress
328 	{ "range/exp_edit", "exp_edit" }, // Range
329 	{ "range/height", "range_height" }, // Light2D
330 	{ "range/item_mask", "range_item_cull_mask" }, // Light2D
331 	{ "range/layer_max", "range_layer_max" }, // Light2D
332 	{ "range/layer_min", "range_layer_min" }, // Light2D
333 	{ "range/max", "max_value" }, // Range
334 	{ "range/min", "min_value" }, // Range
335 	{ "range/page", "page" }, // Range
336 	{ "range/rounded", "rounded" }, // Range
337 	{ "range/step", "step" }, // Range
338 	{ "range/value", "value" }, // Range
339 	{ "range/z_max", "range_z_max" }, // Light2D
340 	{ "range/z_min", "range_z_min" }, // Light2D
341 	{ "rect/min_size", "rect_min_size" }, // Control
342 	{ "rect/pos", "rect_position" }, // Control
343 	{ "rect/rotation", "rect_rotation" }, // Control
344 	{ "rect/scale", "rect_scale" }, // Control
345 	{ "rect/size", "rect_size" }, // Control
346 	//{ "region", "region_enabled" }, // Sprite, Sprite3D // Not renamed for Texture, handle manually
347 	{ "resource/name", "resource_name" }, // Resource
348 	{ "resource/path", "resource_path" }, // Resource
349 	{ "root/root", "root_node" }, // AnimationPlayer
350 	{ "script/script", "script" }, // Object
351 	{ "scroll/base_offset", "scroll_base_offset" }, // ParallaxBackground
352 	{ "scroll/base_scale", "scroll_base_scale" }, // ParallaxBackground
353 	{ "scroll/horizontal", "scroll_horizontal_enabled" }, // ScrollContainer
354 	{ "scroll/ignore_camera_zoom", "scroll_ignore_camera_zoom" }, // ParallaxBackground
355 	{ "scroll/limit_begin", "scroll_limit_begin" }, // ParallaxBackground
356 	{ "scroll/limit_end", "scroll_limit_end" }, // ParallaxBackground
357 	{ "scroll/offset", "scroll_offset" }, // ParallaxBackground
358 	{ "scroll/vertical", "scroll_vertical_enabled" }, // ScrollContainer
359 	{ "shadow/buffer_size", "shadow_buffer_size" }, // Light2D
360 	{ "shadow/color", "shadow_color" }, // Light2D
361 	{ "shadow/enabled", "shadow_enabled" }, // Light2D
362 	{ "shadow/item_mask", "shadow_item_cull_mask" }, // Light2D
363 	{ "size_flags/horizontal", "size_flags_horizontal" }, // Control // Enum order got inverted Expand,Fill -> Fill,Expand, handle manually after rename
364 	{ "size_flags/stretch_ratio", "size_flags_stretch_ratio" }, // Control
365 	{ "size_flags/vertical", "size_flags_vertical" }, // Control // Enum order got inverted Expand,Fill -> Fill,Expand, handle manually after rename
366 	{ "smoothing/enable", "smoothing_enabled" }, // Camera2D
367 	{ "smoothing/speed", "smoothing_speed" }, // Camera2D
368 	{ "sort/enabled", "sort_enabled" }, // YSort
369 	{ "split/collapsed", "collapsed" }, // SplitContainer
370 	{ "split/dragger_visibility", "dragger_visibility" }, // SplitContainer
371 	{ "split/offset", "split_offset" }, // SplitContainer
372 	{ "stream/audio_track", "audio_track" }, // VideoPlayer
373 	{ "stream/autoplay", "autoplay" }, // VideoPlayer
374 	{ "stream/buffering_ms", "buffering_msec" }, // VideoPlayer
375 	{ "stream/loop", "loop" }, // Audio*
376 	{ "stream/loop_restart_time", "loop_offset" }, // Audio*
377 	{ "stream/paused", "paused" }, // VideoPlayer
378 	{ "stream/pitch_scale", "pitch_scale" }, // Audio*
379 	{ "stream/play", "playing" }, // Audio*
380 	{ "stream/stream", "stream" }, // VideoPlayer
381 	{ "stream/volume_db", "volume_db" }, // VideoPlayer
382 	{ "suspension/max_force", "suspension_max_force" }, // VehicleWheel
383 	{ "suspension/stiffness", "suspension_stiffness" }, // VehicleWheel
384 	{ "suspension/travel", "suspension_travel" }, // VehicleWheel
385 	{ "texture/offset", "texture_offset" }, // Polygon2D
386 	{ "texture/over", "texture_over" }, // TextureProgress
387 	{ "texture/progress", "texture_progress" }, // TextureProgress
388 	{ "texture/rotation", "texture_rotation_degrees" }, // Polygon2D
389 	{ "texture/scale", "texture_scale" }, // Polygon2D
390 	{ "textures/click_mask", "texture_click_mask" }, // TextureButton
391 	{ "textures/disabled", "texture_disabled" }, // TextureButton
392 	{ "textures/focused", "texture_focused" }, // TextureButton
393 	{ "textures/hover", "texture_hover" }, // TextureButton
394 	{ "textures/normal", "texture_normal" }, // TextureButton
395 	{ "textures/pressed", "texture_pressed" }, // TextureButton
396 	{ "texture/texture", "texture" }, // Polygon2D
397 	{ "texture/under", "texture_under" }, // TextureProgress
398 	{ "theme/theme", "theme" }, // Control
399 	{ "transform/local", "transform" }, // Spatial
400 	{ "transform/pos", "position" }, // Node2D
401 	{ "transform/rotation", "rotation_degrees" }, // Spatial
402 	{ "transform/rotation_rad", "rotation" }, // Spatial
403 	{ "transform/rot", "rotation_degrees" }, // Node2D
404 	{ "transform/scale", "scale" }, // Node2D, Spatial
405 	{ "transform/translation", "translation" }, // Spatial
406 	{ "type/steering", "use_as_steering" }, // VehicleWheel
407 	{ "type/traction", "use_as_traction" }, // VehicleWheel
408 	{ "vars/lifetime", "lifetime" }, // Particles
409 	{ "velocity/angular", "angular_velocity" }, // PhysicsBody, PhysicsBody2D
410 	{ "velocity/linear", "linear_velocity" }, // PhysicsBody, PhysicsBody2D
411 	{ "visibility", "visibility_aabb" }, // Particles
412 	{ "visibility/behind_parent", "show_behind_parent" }, // CanvasItem
413 	{ "visibility/light_mask", "light_mask" }, // CanvasItem
414 	{ "visibility/on_top", "show_on_top" }, // CanvasItem
415 	//{ "visibility/opacity", "modulate" }, // CanvasItem // Can't be converted this way, handle manually
416 	//{ "visibility/self_opacity", "self_modulate" }, // CanvasItem // Can't be converted this way, handle manually
417 	{ "visibility/visible", "visible" }, // CanvasItem, Spatial
418 	{ "wheel/friction_slip", "wheel_friction_slip" }, // VehicleWheel
419 	{ "wheel/radius", "wheel_radius" }, // VehicleWheel
420 	{ "wheel/rest_length", "wheel_rest_length" }, // VehicleWheel
421 	{ "wheel/roll_influence", "wheel_roll_influence" }, // VehicleWheel
422 	{ "window/title", "window_title" }, // Dialogs
423 	{ "z/relative", "z_as_relative" }, // Node2D
424 	{ "z/z", "z_index" }, // Node2D
425 	{ NULL, NULL }
426 };
427 
428 static const char *type_renames[][2] = {
429 	{ "CanvasItemMaterial", "ShaderMaterial" },
430 	{ "CanvasItemShader", "Shader" },
431 	{ "ColorFrame", "ColorRect" },
432 	{ "ColorRamp", "Gradient" },
433 	{ "FixedMaterial", "SpatialMaterial" },
434 	{ "Patch9Frame", "NinePatchRect" },
435 	{ "ReferenceFrame", "ReferenceRect" },
436 	{ "SampleLibrary", "Resource" },
437 	{ "SamplePlayer2D", "AudioStreamPlayer2D" },
438 	{ "SamplePlayer", "Node" },
439 	{ "SoundPlayer2D", "Node2D" },
440 	{ "SpatialSamplePlayer", "AudioStreamPlayer3D" },
441 	{ "SpatialStreamPlayer", "AudioStreamPlayer3D" },
442 	{ "StreamPlayer", "AudioStreamPlayer" },
443 	{ "TestCube", "MeshInstance" },
444 	{ "TextureFrame", "TextureRect" },
445 	// Only for scripts
446 	{ "Matrix32", "Transform2D" },
447 	{ "Matrix3", "Basis" },
448 	{ "RawArray", "PoolByteArray" },
449 	{ "IntArray", "PoolIntArray" },
450 	{ "RealArray", "PoolRealArray" },
451 	{ "StringArray", "PoolStringArray" },
452 	{ "Vector2Array", "PoolVector2Array" },
453 	{ "Vector3Array", "PoolVector3Array" },
454 	{ "ColorArray", "PoolColorArray" },
455 	{ NULL, NULL }
456 };
457 
458 static const char *signal_renames[][2] = {
459 	{ "area_enter", "area_entered" }, // Area, Area2D
460 	{ "area_enter_shape", "area_shape_entered" }, // Area, Area2D
461 	{ "area_exit", "area_exited" }, // Area, Area2D
462 	{ "area_exit_shape", "area_shape_exited" }, // Area, Area2D
463 	{ "body_enter", "body_entered" }, // Area, Area2D, PhysicsBody, PhysicsBody2D
464 	{ "body_enter_shape", "body_shape_entered" }, // Area, Area2D, PhysicsBody, PhysicsBody2D
465 	{ "body_exit", "body_exited" }, // Area, Area2D, PhysicsBody, PhysicsBody2D
466 	{ "body_exit_shape", "body_shape_exited" }, // Area, Area2D, PhysicsBody, PhysicsBody2D
467 	{ "enter_camera", "camera_entered" }, // VisibilityNotifier
468 	{ "enter_screen", "screen_entered" }, // VisibilityNotifier, VisibilityNotifier2D
469 	{ "enter_tree", "tree_entered" }, // Node
470 	{ "enter_viewport", "viewport_entered" }, // VisibilityNotifier2D
471 	{ "exit_camera", "camera_exited" }, // VisibilityNotifier
472 	{ "exit_screen", "screen_exited" }, // VisibilityNotifier, VisibilityNotifier2D
473 	{ "exit_tree", "tree_exited" }, // Node
474 	{ "exit_viewport", "viewport_exited" }, // VisibilityNotifier2D
475 	//{ "finished", "animation_finished" }, // AnimationPlayer, AnimatedSprite, but not StreamPlayer, handle manually
476 	{ "fixed_frame", "physics_frame" }, // SceneTree
477 	{ "focus_enter", "focus_entered" }, // Control
478 	{ "focus_exit", "focus_exited" }, // Control
479 	{ "input_event", "gui_input" }, // Control // FIXME: but not CollisionObject and CollisionObject2D, it should be handled manually
480 	{ "item_pressed", "id_pressed" }, // PopupMenu
481 	{ "modal_close", "modal_closed" }, // Control
482 	{ "mouse_enter", "mouse_entered" }, // CollisionObject, CollisionObject2D, Control
483 	{ "mouse_exit", "mouse_exited" }, // CollisionObject, CollisionObject2D, Control
484 	{ "tween_start", "tween_started" }, // Tween
485 	{ "tween_complete", "tween_completed" }, // Tween
486 	{ NULL, NULL }
487 };
488 
_find_files(EditorFileSystemDirectory * p_dir,List<String> * r_files)489 void EditorExportGodot3::_find_files(EditorFileSystemDirectory *p_dir, List<String> *r_files) {
490 
491 	for (int i = 0; i < p_dir->get_subdir_count(); i++) {
492 		_find_files(p_dir->get_subdir(i), r_files);
493 	}
494 
495 	for (int i = 0; i < p_dir->get_file_count(); i++) {
496 
497 		r_files->push_back(p_dir->get_file_path(i));
498 	}
499 }
500 
_rename_properties(const String & p_type,List<ExportData::PropertyData> * p_props)501 void EditorExportGodot3::_rename_properties(const String &p_type, List<ExportData::PropertyData> *p_props) {
502 
503 	// We need specific hacks to fix compatibility breakage in the tracks of Animations
504 	bool fix_animation_tracks = (p_type == "Animation");
505 	String found_track_number = "";
506 
507 	// Anchors/margins changed in 3.0 from always-positive to relative to their ratio anchor,
508 	// so we need to flip the sign of margins based on their anchor mode.
509 	int flip_margin_left = false;
510 	int flip_margin_right = false;
511 	int flip_margin_top = false;
512 	int flip_margin_bottom = false;
513 
514 	for (List<ExportData::PropertyData>::Element *E = p_props->front(); E; E = E->next()) {
515 
516 		/* Fixes for 2D rotations */
517 
518 		// 2D rotations are now clockwise to match the downward Y base
519 		// Do this before the renaming, as afterwards we can't distinguish
520 		// between 2D and 3D rotations_degrees
521 		if (E->get().name == "transform/rot") {
522 			E->get().value = (real_t)E->get().value * -1.0;
523 		}
524 
525 		// To fix 2D rotations in the properties of Animation tracks (see below),
526 		// we need to locate stuff like this:
527 		// tracks/0/path = NodePath("Sprite:transform/rot")
528 		// And then modify the 'values' key of 'tracks/0/keys'.
529 		// This is going to be hacky.
530 		// We'll assume that we get properties in the correct order, so that the path will come before the keys
531 		// Otherwise we'd have to keep a stack of the track keys we found to later compare them to track paths
532 		// that match rotation_deg...
533 		if (fix_animation_tracks) {
534 			String prop_name = E->get().name;
535 			if (prop_name.begins_with("tracks/") && prop_name.ends_with("/path")) {
536 				String path_value = E->get().value;
537 
538 				// Check if it's a rotation and save the track number to fix its assigned values
539 				if (path_value.find("transform/rot") != -1) {
540 					// We found a track 'path' with a "transform/rot" NodePath, its 'keys' need to be fixed
541 					found_track_number = prop_name.get_slice("/", 1);
542 					print_line("Found Animation track with 2D rotations: " + prop_name + " = " + path_value);
543 				}
544 
545 				// In animation tracks, NodePaths can refer to properties that need to be renamed
546 				int sep = path_value.find(":");
547 				if (sep != -1) {
548 					String track_nodepath = path_value.substr(0, sep);
549 					String track_prop = path_value.substr(sep + 1, path_value.length());
550 					if (prop_rename_map.has(track_prop)) {
551 						track_prop = prop_rename_map[track_prop];
552 					}
553 
554 					// "[self_]opacity" was removed, and is replaced by the alpha component of "[self_]modulate"
555 					// "modulate" may already exist, but we posit that the "opacity" value is more important
556 					// Thankfully in NodePaths we can access the alpha property directly
557 					if (track_prop == "visibility/opacity") {
558 						track_prop = "modulate:a";
559 					} else if (track_prop == "visibility/self_opacity") {
560 						track_prop = "self_modulate:a";
561 					}
562 
563 					E->get().value = NodePath(track_nodepath + ":" + track_prop);
564 				}
565 			} else if (found_track_number != "" && prop_name == "tracks/" + found_track_number + "/keys") {
566 				// Bingo! We found keys matching the track number we had spotted
567 				print_line("Fixing sign of 2D rotations in animation track " + found_track_number);
568 				Dictionary track_keys = E->get().value;
569 				if (track_keys.has("values")) {
570 					Array values = track_keys["values"];
571 					for (int i = 0; i < values.size(); i++) {
572 						values[i] = (real_t)values[i] * -1.0;
573 					}
574 					track_keys["values"] = values;
575 					E->get().value = track_keys;
576 					found_track_number = "";
577 				} else {
578 					print_line("Tried to change rotation in Animation tracks, but no value set found.");
579 				}
580 			}
581 		}
582 
583 		/* Do the actual renaming */
584 
585 		if (prop_rename_map.has(E->get().name)) {
586 			E->get().name = prop_rename_map[E->get().name];
587 		}
588 
589 		/* Hardcoded fixups for properties that changed definition in 3.0 */
590 
591 		// Anchors changed from Begin,End,Ratio,Center to only a ratio
592 		if (E->get().name.begins_with("anchor_")) {
593 			String side = E->get().name.substr(7, E->get().name.length() - 1);
594 			int prop_value = (int)E->get().value;
595 			switch (prop_value) {
596 				case 0: { // Begin
597 					E->get().value = 0.0;
598 				} break;
599 				case 1: { // End
600 					E->get().value = 1.0;
601 					// Flip corresponding margin's sign
602 					if (side == "left")
603 						flip_margin_left = true;
604 					else if (side == "right")
605 						flip_margin_right = true;
606 					else if (side == "top")
607 						flip_margin_top = true;
608 					else if (side == "bottom")
609 						flip_margin_bottom = true;
610 				} break;
611 				case 2: { // Ratio
612 					E->get().value = 0.0;
613 					print_line("WARNING: Property '" + E->get().name + "' with value 'Ratio' cannot be converted to the format used in Godot 3. Convert it to 'Begin' or 'End' to avoid losing the corresponding margin value.");
614 				} break;
615 				case 3: { // Center
616 					E->get().value = 0.5;
617 					// Flip corresponding margin's sign
618 					if (side == "left")
619 						flip_margin_left = true;
620 					else if (side == "right")
621 						flip_margin_right = true;
622 					else if (side == "top")
623 						flip_margin_top = true;
624 					else if (side == "bottom")
625 						flip_margin_bottom = true;
626 				} break;
627 			}
628 		}
629 
630 		// Size flags enum changed ordering from "Expand,Fill" to "Fill,Expand,..."
631 		// So we swap 1 (Expand) and 2 (Fill), keep 0 (none) and 3 (Expand + Fill)
632 		if (E->get().name == "size_flags_horizontal" || E->get().name == "size_flags_vertical") {
633 			int prop_value = (int)E->get().value;
634 			switch (prop_value) {
635 				case 1: // Expand -> Fill
636 					E->get().value = 2;
637 				case 2: // Fill -> Expand
638 					E->get().value = 1;
639 				default: // none or both, keep
640 					break;
641 			}
642 		}
643 
644 		// "[self_]opacity" was removed, and is replaced by the alpha component of "[self_]modulate"
645 		// "modulate" may already exist, but we posit that the "opacity" value is more important
646 		if (E->get().name == "visibility/opacity" || E->get().name == "visibility/self_opacity") {
647 			if (E->get().name == "visibility/self_opacity") {
648 				E->get().name = "self_modulate";
649 			} else {
650 				E->get().name = "modulate";
651 			}
652 			E->get().value = Color(1.0, 1.0, 1.0, (float)E->get().value);
653 		}
654 
655 		// AnimationPlayer's "playback/active" was renamed to "playback_active", but not AnimationTreePlayer's
656 		if (p_type == "AnimationPlayer" && E->get().name == "playback/active") {
657 			E->get().name = "playback_active";
658 		}
659 
660 		// Joint2D's "collision/exclude_nodes" was renamed to "disable_collision", but not Joint's
661 		if (p_type == "Joint2D" && E->get().name == "collision/exclude_nodes") {
662 			E->get().name = "disable_collision";
663 		}
664 
665 		// TextureProgress' "mode" was renamed to "fill_mode", but not that of other nodes like TileMap
666 		if (p_type == "TextureProgress" && E->get().name == "mode") {
667 			E->get().name = "fill_mode";
668 		}
669 
670 		// Sprite and Sprite3D's "region" was renamed to "region_enabled", but not Texture's
671 		if ((p_type == "Sprite" || p_type == "Sprite3D") && E->get().name == "region") {
672 			E->get().name = "region_enabled";
673 		}
674 
675 		// "click_on_pressed" was renamed to "action_mode" and is now a enum
676 		if (E->get().name == "click_on_press") {
677 			E->get().name = "action_mode";
678 			if (E->get().value) {
679 				E->get().value = 0; // ACTION_MODE_BUTTON_PRESS
680 			} else {
681 				E->get().value = 1; // ACTION_MODE_BUTTON_RELEASE
682 			}
683 		}
684 	}
685 
686 	// Flip margins based on the previously fixed anchor modes
687 	if (flip_margin_left || flip_margin_right || flip_margin_top || flip_margin_bottom) {
688 		// Loop again and fix the margins
689 		for (List<ExportData::PropertyData>::Element *E = p_props->front(); E; E = E->next()) {
690 			if (!E->get().name.begins_with("margin_")) {
691 				continue;
692 			}
693 			if ((flip_margin_left && E->get().name == "margin_left") ||
694 					(flip_margin_right && E->get().name == "margin_right") ||
695 					(flip_margin_top && E->get().name == "margin_top") ||
696 					(flip_margin_bottom && E->get().name == "margin_bottom")) {
697 				E->get().value = (real_t)E->get().value * -1.0;
698 			}
699 		}
700 	}
701 }
702 
_add_new_properties(const String & p_type,List<ExportData::PropertyData> * p_props)703 void EditorExportGodot3::_add_new_properties(const String &p_type, List<ExportData::PropertyData> *p_props) {
704 	bool add_mouse_filter = false;
705 
706 	bool ignore_mouse = false;
707 	bool stop_mouse = false;
708 
709 	for (List<ExportData::PropertyData>::Element *E = p_props->front(); E; E = E->next()) {
710 		String prop_name = E->get().name;
711 		if (prop_name == "focus/ignore_mouse" || prop_name == "focus/stop_mouse") {
712 			add_mouse_filter = true;
713 
714 			if (prop_name == "focus/ignore_mouse") {
715 				ignore_mouse = E->get().value;
716 			} else if (prop_name == "focus/stop_mouse") {
717 				stop_mouse = E->get().value;
718 			}
719 		}
720 	}
721 
722 	if (add_mouse_filter) {
723 		ExportData::PropertyData pdata;
724 		pdata.name = "mouse_filter";
725 
726 		if (ignore_mouse && stop_mouse) {
727 			pdata.value = 1; // MOUSE_FILTER_PASS
728 		} else if (ignore_mouse && !stop_mouse) {
729 			pdata.value = 2; // MOUSE_FILTER_IGNORE
730 		} else {
731 			pdata.value = 0; // MOUSE_FILTER_STOP
732 		}
733 
734 		p_props->push_back(pdata);
735 	}
736 }
737 
_convert_resources(ExportData & resource)738 void EditorExportGodot3::_convert_resources(ExportData &resource) {
739 
740 	for (int i = 0; i < resource.resources.size(); i++) {
741 
742 		_add_new_properties(resource.resources[i].type, &resource.resources[i].properties);
743 		_rename_properties(resource.resources[i].type, &resource.resources[i].properties);
744 
745 		if (type_rename_map.has(resource.resources[i].type)) {
746 			resource.resources[i].type = type_rename_map[resource.resources[i].type];
747 		}
748 	}
749 
750 	for (int i = 0; i < resource.nodes.size(); i++) {
751 
752 		_add_new_properties(resource.nodes[i].type, &resource.nodes[i].properties);
753 		_rename_properties(resource.nodes[i].type, &resource.nodes[i].properties);
754 
755 		if (type_rename_map.has(resource.nodes[i].type)) {
756 			resource.nodes[i].type = type_rename_map[resource.nodes[i].type];
757 		}
758 	}
759 
760 	for (int i = 0; i < resource.connections.size(); i++) {
761 
762 		if (signal_rename_map.has(resource.connections[i].signal)) {
763 			resource.connections[i].signal = signal_rename_map[resource.connections[i].signal];
764 		}
765 
766 		/* Manual handling for signals which need to be conditionally renamed based on their Node's type */
767 
768 		// AnimationPlayer and AnimatedSprite's "finished" signal was renamed to "animation_finished",
769 		// but not that of StreamPlayer. Since node information is missing from the connection data
770 		// (we only have the NodePath), we'll have to compare against the nodes array to find out.
771 		if (resource.connections[i].signal == "finished") {
772 			String from = resource.connections[i].from;
773 			// NodePath "from" is relative to root node, can be direct child (no '/') or further down
774 			int slice_count = from.get_slice_count("/");
775 			String parent = ".";
776 			String nodename = from;
777 			if (slice_count > 1) {
778 				parent = from.get_slice("/", slice_count - 2);
779 				nodename = from.get_slice("/", slice_count - 1);
780 			}
781 
782 			for (int j = 0; j < resource.nodes.size(); j++) {
783 				if (resource.nodes[j].name == nodename && resource.nodes[j].parent == parent) {
784 					if (resource.nodes[j].type == "AnimationPlayer" || resource.nodes[j].type == "AnimatedSprite") {
785 						resource.connections[i].signal = "animation_finished";
786 						break;
787 					}
788 				}
789 			}
790 		}
791 	}
792 }
793 
_unpack_packed_scene(ExportData & resource)794 void EditorExportGodot3::_unpack_packed_scene(ExportData &resource) {
795 
796 	Dictionary d;
797 	for (List<ExportData::PropertyData>::Element *E = resource.resources[resource.resources.size() - 1].properties.front(); E; E = E->next()) {
798 		if (E->get().name == "_bundled") {
799 			d = E->get().value;
800 		}
801 	}
802 
803 	ERR_FAIL_COND(d.empty());
804 
805 	ERR_FAIL_COND(!d.has("names"));
806 	ERR_FAIL_COND(!d.has("variants"));
807 	ERR_FAIL_COND(!d.has("node_count"));
808 	ERR_FAIL_COND(!d.has("nodes"));
809 	ERR_FAIL_COND(!d.has("conn_count"));
810 	ERR_FAIL_COND(!d.has("conns"));
811 
812 	Vector<String> names;
813 
814 	DVector<String> snames = d["names"];
815 	if (snames.size()) {
816 
817 		int namecount = snames.size();
818 		names.resize(namecount);
819 		DVector<String>::Read r = snames.read();
820 		for (int i = 0; i < names.size(); i++)
821 			names[i] = r[i];
822 	}
823 
824 	Array variants = d["variants"];
825 
826 	resource.nodes.resize(d["node_count"]);
827 
828 	int nc = resource.nodes.size();
829 	if (nc) {
830 		DVector<int> snodes = d["nodes"];
831 		DVector<int>::Read r = snodes.read();
832 		int idx = 0;
833 		for (int i = 0; i < nc; i++) {
834 
835 			int parent = r[idx++];
836 			int owner = r[idx++];
837 			int type = r[idx++];
838 			int name = r[idx++];
839 			int instance = r[idx++];
840 
841 			ExportData::NodeData &node_data = resource.nodes[i];
842 
843 			node_data.text_data = false;
844 			node_data.name = names[name];
845 			if (type == 0x7FFFFFFF) {
846 				node_data.instanced = true;
847 			} else {
848 				node_data.instanced = false;
849 				node_data.type = names[type];
850 			}
851 
852 			node_data.parent_int = parent;
853 			node_data.owner_int = owner;
854 			if (instance >= 0) {
855 				node_data.instance_is_placeholder = instance & SceneState::FLAG_INSTANCE_IS_PLACEHOLDER;
856 				node_data.instance = variants[instance & SceneState::FLAG_MASK];
857 			}
858 
859 			int prop_count = r[idx++];
860 
861 			for (int j = 0; j < prop_count; j++) {
862 
863 				int prop_name = r[idx++];
864 				int prop_value = r[idx++];
865 
866 				ExportData::PropertyData pdata;
867 				pdata.name = names[prop_name];
868 				pdata.value = variants[prop_value];
869 				node_data.properties.push_back(pdata);
870 			}
871 
872 			int group_count = r[idx++];
873 			for (int j = 0; j < group_count; j++) {
874 
875 				int group_name = r[idx++];
876 				node_data.groups.push_back(names[group_name]);
877 			}
878 		}
879 	}
880 
881 	int cc = d["conn_count"];
882 
883 	if (cc) {
884 
885 		DVector<int> sconns = d["conns"];
886 		DVector<int>::Read r = sconns.read();
887 		int idx = 0;
888 		for (int i = 0; i < cc; i++) {
889 
890 			ExportData::Connection conn;
891 
892 			conn.from_int = r[idx++];
893 			conn.to_int = r[idx++];
894 			conn.signal = names[r[idx++]];
895 			conn.method = names[r[idx++]];
896 			conn.flags = r[idx++];
897 			int bindcount = r[idx++];
898 
899 			for (int j = 0; j < bindcount; j++) {
900 
901 				conn.binds.push_back(variants[r[idx++]]);
902 			}
903 
904 			resource.connections.push_back(conn);
905 		}
906 	}
907 
908 	Array np;
909 	if (d.has("node_paths")) {
910 		np = d["node_paths"];
911 	}
912 
913 	for (int i = 0; i < np.size(); i++) {
914 		resource.node_paths.push_back(np[i]);
915 	}
916 
917 	Array ei;
918 	if (d.has("editable_instances")) {
919 		ei = d["editable_instances"];
920 		for (int i = 0; i < ei.size(); i++) {
921 			resource.editables.push_back(ei[i]);
922 		}
923 	}
924 
925 	if (d.has("base_scene")) {
926 		resource.base_scene = variants[d["base_scene"]];
927 	}
928 
929 	resource.resources.resize(resource.resources.size() - 1); //erase packed
930 }
931 
_pack_packed_scene(ExportData & resource)932 void EditorExportGodot3::_pack_packed_scene(ExportData &resource) {
933 
934 	pack_names.clear();
935 	pack_values.clear();
936 
937 	Dictionary d;
938 
939 	d["node_count"] = resource.nodes.size();
940 
941 	Vector<int> node_data;
942 
943 	for (int i = 0; i < resource.nodes.size(); i++) {
944 
945 		const ExportData::NodeData &node = resource.nodes[i];
946 
947 		node_data.push_back(node.parent_int);
948 		node_data.push_back(node.owner_int);
949 		if (node.instanced) {
950 			node_data.push_back(0x7FFFFFFF);
951 		} else {
952 			int name = _pack_name(node.type);
953 			node_data.push_back(name);
954 		}
955 
956 		node_data.push_back(_pack_name(node.name));
957 		int instance = -1;
958 		if (node.instance != String()) {
959 			instance = _pack_value(node.instance);
960 			if (node.instance_is_placeholder) {
961 				instance |= SceneState::FLAG_INSTANCE_IS_PLACEHOLDER;
962 			}
963 		}
964 		node_data.push_back(instance);
965 
966 		node_data.push_back(node.properties.size());
967 
968 		for (int j = 0; j < node.properties.size(); j++) {
969 			node_data.push_back(_pack_name(node.properties[j].name));
970 			node_data.push_back(_pack_value(node.properties[j].value));
971 		}
972 
973 		node_data.push_back(node.groups.size());
974 
975 		for (int j = 0; j < node.groups.size(); j++) {
976 
977 			node_data.push_back(_pack_name(node.groups[j]));
978 		}
979 	}
980 
981 	d["nodes"] = node_data;
982 
983 	d["conn_count"] = resource.connections.size();
984 
985 	Vector<int> connections;
986 
987 	for (int i = 0; i < resource.connections.size(); i++) {
988 		const ExportData::Connection &conn = resource.connections[i];
989 
990 		connections.push_back(conn.from_int);
991 		connections.push_back(conn.to_int);
992 		connections.push_back(_pack_name(conn.signal));
993 		connections.push_back(_pack_name(conn.method));
994 		connections.push_back(conn.flags);
995 		connections.push_back(conn.binds.size());
996 		for (int j = 0; j < conn.binds.size(); j++) {
997 			connections.push_back(_pack_value(conn.binds[j]));
998 		}
999 	}
1000 
1001 	d["conns"] = connections;
1002 
1003 	Array np;
1004 	for (int i = 0; i < resource.node_paths.size(); i++) {
1005 		np.push_back(resource.node_paths[i]);
1006 	}
1007 
1008 	d["node_paths"] = np;
1009 
1010 	Array ei;
1011 	for (int i = 0; i < resource.editables.size(); i++) {
1012 		ei.push_back(resource.editables[i]);
1013 	}
1014 
1015 	d["editable_instances"] = ei;
1016 
1017 	if (resource.base_scene.get_type()) {
1018 
1019 		d["base_scene"] = _pack_value(resource.base_scene);
1020 	}
1021 
1022 	DVector<String> names;
1023 	names.resize(pack_names.size());
1024 	{
1025 		DVector<String>::Write w = names.write();
1026 		for (Map<String, int>::Element *E = pack_names.front(); E; E = E->next()) {
1027 			w[E->get()] = E->key();
1028 		}
1029 	}
1030 
1031 	d["names"] = names;
1032 
1033 	Array values;
1034 	values.resize(pack_values.size());
1035 
1036 	const Variant *K = NULL;
1037 	while ((K = pack_values.next(K))) {
1038 
1039 		int index = pack_values[*K];
1040 		values[index] = *K;
1041 	}
1042 
1043 	d["variants"] = values;
1044 
1045 	ExportData::ResourceData packed_scene;
1046 	packed_scene.type = "PackedScene";
1047 	packed_scene.index = -1;
1048 	ExportData::PropertyData pd;
1049 	pd.name = "_bundled";
1050 	pd.value = d;
1051 	packed_scene.properties.push_back(pd);
1052 
1053 	resource.resources.push_back(packed_scene);
1054 	resource.nodes.clear();
1055 	resource.connections.clear();
1056 	resource.editables.clear();
1057 	resource.node_paths.clear();
1058 	;
1059 	resource.base_scene = Variant();
1060 }
1061 
rtosfix(double p_value)1062 static String rtosfix(double p_value) {
1063 
1064 	if (p_value == 0.0)
1065 		return "0"; //avoid negative zero (-0) being written, which may annoy git, svn, etc. for changes when they don't exist.
1066 	else
1067 		return rtoss(p_value);
1068 }
1069 
_get_property_as_text(const Variant & p_variant,String & p_string)1070 Error EditorExportGodot3::_get_property_as_text(const Variant &p_variant, String &p_string) {
1071 
1072 	switch (p_variant.get_type()) {
1073 
1074 		case Variant::NIL: {
1075 			p_string += ("null");
1076 		} break;
1077 		case Variant::BOOL: {
1078 
1079 			p_string += (p_variant.operator bool() ? "true" : "false");
1080 		} break;
1081 		case Variant::INT: {
1082 
1083 			p_string += (itos(p_variant.operator int()));
1084 		} break;
1085 		case Variant::REAL: {
1086 
1087 			String s = rtosfix(p_variant.operator real_t());
1088 			if (s.find(".") == -1 && s.find("e") == -1)
1089 				s += ".0";
1090 			p_string += (s);
1091 		} break;
1092 		case Variant::STRING: {
1093 
1094 			String str = p_variant;
1095 			if (str.begins_with("@RESLOCAL:")) {
1096 				p_string += "SubResource( " + str.get_slice(":", 1) + " )";
1097 			} else if (str.begins_with("@RESEXTERNAL:")) {
1098 				p_string += "ExtResource( " + str.get_slice(":", 1) + " )";
1099 			} else {
1100 
1101 				// Call _replace_resource in case it's a path to a scene/resource
1102 				str = "\"" + _replace_resource(str).c_escape_multiline() + "\"";
1103 				p_string += (str);
1104 			}
1105 
1106 		} break;
1107 		case Variant::VECTOR2: {
1108 
1109 			Vector2 v = p_variant;
1110 			p_string += ("Vector2( " + rtosfix(v.x) + ", " + rtosfix(v.y) + " )");
1111 		} break;
1112 		case Variant::RECT2: {
1113 
1114 			Rect2 aabb = p_variant;
1115 			p_string += ("Rect2( " + rtosfix(aabb.pos.x) + ", " + rtosfix(aabb.pos.y) + ", " + rtosfix(aabb.size.x) + ", " + rtosfix(aabb.size.y) + " )");
1116 
1117 		} break;
1118 		case Variant::VECTOR3: {
1119 
1120 			Vector3 v = p_variant;
1121 			p_string += ("Vector3( " + rtosfix(v.x) + ", " + rtosfix(v.y) + ", " + rtosfix(v.z) + " )");
1122 		} break;
1123 		case Variant::PLANE: {
1124 
1125 			Plane p = p_variant;
1126 			p_string += ("Plane( " + rtosfix(p.normal.x) + ", " + rtosfix(p.normal.y) + ", " + rtosfix(p.normal.z) + ", " + rtosfix(p.d) + " )");
1127 
1128 		} break;
1129 		case Variant::_AABB: {
1130 
1131 			Rect3 aabb = p_variant;
1132 			p_string += ("Rect3( " + rtosfix(aabb.pos.x) + ", " + rtosfix(aabb.pos.y) + ", " + rtosfix(aabb.pos.z) + ", " + rtosfix(aabb.size.x) + ", " + rtosfix(aabb.size.y) + ", " + rtosfix(aabb.size.z) + " )");
1133 
1134 		} break;
1135 		case Variant::QUAT: {
1136 
1137 			Quat quat = p_variant;
1138 			p_string += ("Quat( " + rtosfix(quat.x) + ", " + rtosfix(quat.y) + ", " + rtosfix(quat.z) + ", " + rtosfix(quat.w) + " )");
1139 
1140 		} break;
1141 		case Variant::MATRIX32: {
1142 
1143 			String s = "Transform2D( ";
1144 			Matrix32 m3 = p_variant;
1145 			for (int i = 0; i < 3; i++) {
1146 				for (int j = 0; j < 2; j++) {
1147 
1148 					if (i != 0 || j != 0)
1149 						s += ", ";
1150 					s += rtosfix(m3.elements[i][j]);
1151 				}
1152 			}
1153 
1154 			p_string += (s + " )");
1155 
1156 		} break;
1157 		case Variant::MATRIX3: {
1158 
1159 			String s = "Basis( ";
1160 			Matrix3 m3 = p_variant;
1161 			for (int i = 0; i < 3; i++) {
1162 				for (int j = 0; j < 3; j++) {
1163 
1164 					if (i != 0 || j != 0)
1165 						s += ", ";
1166 					s += rtosfix(m3.elements[i][j]);
1167 				}
1168 			}
1169 
1170 			p_string += (s + " )");
1171 
1172 		} break;
1173 		case Variant::TRANSFORM: {
1174 
1175 			String s = "Transform( ";
1176 			Transform t = p_variant;
1177 			Matrix3 &m3 = t.basis;
1178 			for (int i = 0; i < 3; i++) {
1179 				for (int j = 0; j < 3; j++) {
1180 
1181 					if (i != 0 || j != 0)
1182 						s += ", ";
1183 					s += rtosfix(m3.elements[i][j]);
1184 				}
1185 			}
1186 
1187 			s = s + ", " + rtosfix(t.origin.x) + ", " + rtosfix(t.origin.y) + ", " + rtosfix(t.origin.z);
1188 
1189 			p_string += (s + " )");
1190 		} break;
1191 
1192 		// misc types
1193 		case Variant::COLOR: {
1194 
1195 			Color c = p_variant;
1196 			p_string += ("Color( " + rtosfix(c.r) + ", " + rtosfix(c.g) + ", " + rtosfix(c.b) + ", " + rtosfix(c.a) + " )");
1197 
1198 		} break;
1199 		case Variant::IMAGE: {
1200 
1201 			Image img = p_variant;
1202 
1203 			if (img.empty()) {
1204 				p_string += ("Image()");
1205 				break;
1206 			}
1207 
1208 			String imgstr = "Image()";
1209 			p_string += imgstr; //do not convert this for now
1210 
1211 			/*imgstr+=itos(img.get_width());
1212 			imgstr+=", "+itos(img.get_height());
1213 			imgstr+=", "+String(img.get_mipmaps()?"true":"false");
1214 			imgstr+=", "+Image::get_format_name(img.get_format());
1215 
1216 			String s;
1217 
1218 			DVector<uint8_t> data = img.get_data();
1219 			int len = data.size();
1220 			DVector<uint8_t>::Read r = data.read();
1221 			const uint8_t *ptr=r.ptr();
1222 			for (int i=0;i<len;i++) {
1223 
1224 				if (i>0)
1225 					s+=", ";
1226 				s+=itos(ptr[i]);
1227 			}
1228 
1229 			imgstr+=", ";
1230 			p_string+=(imgstr);
1231 			p_string+=(s);
1232 			p_string+=(" )");*/
1233 		} break;
1234 		case Variant::NODE_PATH: {
1235 
1236 			String str = p_variant;
1237 
1238 			str = "NodePath(\"" + str.c_escape() + "\")";
1239 			p_string += (str);
1240 
1241 		} break;
1242 
1243 		case Variant::OBJECT: {
1244 
1245 			//should never arrive here!
1246 			ERR_FAIL_V(ERR_BUG);
1247 		} break;
1248 		case Variant::INPUT_EVENT: {
1249 
1250 			String str = "InputEvent(";
1251 
1252 			InputEvent ev = p_variant;
1253 			switch (ev.type) {
1254 				case InputEvent::KEY: {
1255 
1256 					str += "KEY," + itos(ev.key.scancode);
1257 					String mod;
1258 					if (ev.key.mod.alt)
1259 						mod += "A";
1260 					if (ev.key.mod.shift)
1261 						mod += "S";
1262 					if (ev.key.mod.control)
1263 						mod += "C";
1264 					if (ev.key.mod.meta)
1265 						mod += "M";
1266 
1267 					if (mod != String())
1268 						str += "," + mod;
1269 				} break;
1270 				case InputEvent::MOUSE_BUTTON: {
1271 
1272 					str += "MBUTTON," + itos(ev.mouse_button.button_index);
1273 				} break;
1274 				case InputEvent::JOYSTICK_BUTTON: {
1275 					str += "JBUTTON," + itos(ev.joy_button.button_index);
1276 
1277 				} break;
1278 				case InputEvent::JOYSTICK_MOTION: {
1279 					str += "JAXIS," + itos(ev.joy_motion.axis) + "," + itos(ev.joy_motion.axis_value);
1280 				} break;
1281 				case InputEvent::NONE: {
1282 					str += "NONE";
1283 				} break;
1284 				default: {}
1285 			}
1286 
1287 			str += ")";
1288 
1289 			p_string += (str); //will be added later
1290 
1291 		} break;
1292 		case Variant::DICTIONARY: {
1293 
1294 			Dictionary dict = p_variant;
1295 
1296 			List<Variant> keys;
1297 			dict.get_key_list(&keys);
1298 			keys.sort();
1299 
1300 			p_string += ("{\n");
1301 			for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
1302 
1303 				/*
1304 				if (!_check_type(dict[E->get()]))
1305 					continue;
1306 				*/
1307 				_get_property_as_text(E->get(), p_string);
1308 				p_string += (": ");
1309 				_get_property_as_text(dict[E->get()], p_string);
1310 				if (E->next())
1311 					p_string += (",\n");
1312 			}
1313 
1314 			p_string += ("\n}");
1315 
1316 		} break;
1317 		case Variant::ARRAY: {
1318 
1319 			p_string += ("[ ");
1320 			Array array = p_variant;
1321 			int len = array.size();
1322 			for (int i = 0; i < len; i++) {
1323 
1324 				if (i > 0)
1325 					p_string += (", ");
1326 				_get_property_as_text(array[i], p_string);
1327 			}
1328 			p_string += (" ]");
1329 
1330 		} break;
1331 
1332 		case Variant::RAW_ARRAY: {
1333 
1334 			p_string += ("PoolByteArray( ");
1335 			String s;
1336 			DVector<uint8_t> data = p_variant;
1337 			int len = data.size();
1338 			DVector<uint8_t>::Read r = data.read();
1339 			const uint8_t *ptr = r.ptr();
1340 			for (int i = 0; i < len; i++) {
1341 
1342 				if (i > 0)
1343 					p_string += (", ");
1344 
1345 				p_string += (itos(ptr[i]));
1346 			}
1347 
1348 			p_string += (" )");
1349 
1350 		} break;
1351 		case Variant::INT_ARRAY: {
1352 
1353 			p_string += ("PoolIntArray( ");
1354 			DVector<int> data = p_variant;
1355 			int len = data.size();
1356 			DVector<int>::Read r = data.read();
1357 			const int *ptr = r.ptr();
1358 
1359 			for (int i = 0; i < len; i++) {
1360 
1361 				if (i > 0)
1362 					p_string += (", ");
1363 
1364 				p_string += (itos(ptr[i]));
1365 			}
1366 
1367 			p_string += (" )");
1368 
1369 		} break;
1370 		case Variant::REAL_ARRAY: {
1371 
1372 			p_string += ("PoolRealArray( ");
1373 			DVector<real_t> data = p_variant;
1374 			int len = data.size();
1375 			DVector<real_t>::Read r = data.read();
1376 			const real_t *ptr = r.ptr();
1377 
1378 			for (int i = 0; i < len; i++) {
1379 
1380 				if (i > 0)
1381 					p_string += (", ");
1382 				p_string += (rtosfix(ptr[i]));
1383 			}
1384 
1385 			p_string += (" )");
1386 
1387 		} break;
1388 		case Variant::STRING_ARRAY: {
1389 
1390 			p_string += ("PoolStringArray( ");
1391 			DVector<String> data = p_variant;
1392 			int len = data.size();
1393 			DVector<String>::Read r = data.read();
1394 			const String *ptr = r.ptr();
1395 			String s;
1396 			//write_string("\n");
1397 
1398 			for (int i = 0; i < len; i++) {
1399 
1400 				if (i > 0)
1401 					p_string += (", ");
1402 				String str = ptr[i];
1403 				p_string += ("\"" + str.c_escape() + "\"");
1404 			}
1405 
1406 			p_string += (" )");
1407 
1408 		} break;
1409 		case Variant::VECTOR2_ARRAY: {
1410 
1411 			p_string += ("PoolVector2Array( ");
1412 			DVector<Vector2> data = p_variant;
1413 			int len = data.size();
1414 			DVector<Vector2>::Read r = data.read();
1415 			const Vector2 *ptr = r.ptr();
1416 
1417 			for (int i = 0; i < len; i++) {
1418 
1419 				if (i > 0)
1420 					p_string += (", ");
1421 				p_string += (rtosfix(ptr[i].x) + ", " + rtosfix(ptr[i].y));
1422 			}
1423 
1424 			p_string += (" )");
1425 
1426 		} break;
1427 		case Variant::VECTOR3_ARRAY: {
1428 
1429 			p_string += ("PoolVector3Array( ");
1430 			DVector<Vector3> data = p_variant;
1431 			int len = data.size();
1432 			DVector<Vector3>::Read r = data.read();
1433 			const Vector3 *ptr = r.ptr();
1434 
1435 			for (int i = 0; i < len; i++) {
1436 
1437 				if (i > 0)
1438 					p_string += (", ");
1439 				p_string += (rtosfix(ptr[i].x) + ", " + rtosfix(ptr[i].y) + ", " + rtosfix(ptr[i].z));
1440 			}
1441 
1442 			p_string += (" )");
1443 
1444 		} break;
1445 		case Variant::COLOR_ARRAY: {
1446 
1447 			p_string += ("PoolColorArray( ");
1448 
1449 			DVector<Color> data = p_variant;
1450 			int len = data.size();
1451 			DVector<Color>::Read r = data.read();
1452 			const Color *ptr = r.ptr();
1453 
1454 			for (int i = 0; i < len; i++) {
1455 
1456 				if (i > 0)
1457 					p_string += (", ");
1458 
1459 				p_string += (rtosfix(ptr[i].r) + ", " + rtosfix(ptr[i].g) + ", " + rtosfix(ptr[i].b) + ", " + rtosfix(ptr[i].a));
1460 			}
1461 			p_string += (" )");
1462 
1463 		} break;
1464 		default: {}
1465 	}
1466 
1467 	return OK;
1468 }
1469 
_valprop(const String & p_name)1470 static String _valprop(const String &p_name) {
1471 
1472 	// Escape and quote strings with extended ASCII or further Unicode characters
1473 	// as well as '"', '=' or ' ' (32)
1474 	const CharType *cstr = p_name.c_str();
1475 	for (int i = 0; cstr[i]; i++) {
1476 		if (cstr[i] == '=' || cstr[i] == '"' || cstr[i] < 33 || cstr[i] > 126) {
1477 			return "\"" + p_name.c_escape_multiline() + "\"";
1478 		}
1479 	}
1480 	// Keep as is
1481 	return p_name;
1482 }
1483 
_save_text(const String & p_path,ExportData & resource)1484 void EditorExportGodot3::_save_text(const String &p_path, ExportData &resource) {
1485 
1486 	FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE);
1487 
1488 	if (resource.nodes.size()) {
1489 		f->store_line("[gd_scene load_steps=" + itos(resource.nodes.size() + resource.resources.size()) + " format=2]\n");
1490 	} else {
1491 		f->store_line("[gd_resource type=\"" + resource.resources[resource.resources.size() - 1].type + "\" load_steps=" + itos(resource.resources.size()) + " format=2]\n");
1492 	}
1493 
1494 	for (Map<int, ExportData::Dependency>::Element *E = resource.dependencies.front(); E; E = E->next()) {
1495 
1496 		f->store_line("[ext_resource path=\"" + resource_replace_map[E->get().path] + "\" type=\"" + E->get().type + "\" id=" + itos(E->key()) + "]");
1497 	}
1498 
1499 	for (int i = 0; i < resource.resources.size(); i++) {
1500 
1501 		if (resource.nodes.size() || i < resource.resources.size() - 1) {
1502 
1503 			f->store_line("\n[sub_resource type=\"" + resource.resources[i].type + "\" id=" + itos(resource.resources[i].index) + "]\n");
1504 		} else {
1505 			f->store_line("\n[resource]\n");
1506 		}
1507 
1508 		for (List<ExportData::PropertyData>::Element *E = resource.resources[i].properties.front(); E; E = E->next()) {
1509 
1510 			String prop;
1511 			_get_property_as_text(E->get().value, prop);
1512 			f->store_line(_valprop(E->get().name) + " = " + prop);
1513 		}
1514 	}
1515 
1516 	for (int i = 0; i < resource.nodes.size(); i++) {
1517 
1518 		String node_txt = "\n[node";
1519 
1520 		if (resource.nodes[i].name != String()) {
1521 			node_txt += " name=\"" + String(resource.nodes[i].name).c_escape() + "\"";
1522 		}
1523 
1524 		if (resource.nodes[i].owner != NodePath()) {
1525 			node_txt += " owner=\"" + String(resource.nodes[i].owner).c_escape() + "\"";
1526 		}
1527 
1528 		if (resource.nodes[i].type != String()) {
1529 			node_txt += " type=\"" + resource.nodes[i].type + "\"";
1530 		}
1531 
1532 		if (resource.nodes[i].parent != NodePath()) {
1533 			node_txt += " parent=\"" + String(resource.nodes[i].parent).c_escape() + "\"";
1534 		}
1535 
1536 		if (resource.nodes[i].instance != String()) {
1537 			String prop;
1538 			_get_property_as_text(resource.nodes[i].instance, prop);
1539 			node_txt += " instance=" + prop + "";
1540 		}
1541 
1542 		if (!resource.nodes[i].groups.empty()) {
1543 			node_txt += " groups=[\n";
1544 			for (int j = 0; j < resource.nodes[i].groups.size(); j++) {
1545 				node_txt += "\"" + resource.nodes[i].groups[j] + "\",\n";
1546 			}
1547 			node_txt += "]";
1548 		}
1549 
1550 		node_txt += "]\n";
1551 		f->store_line(node_txt);
1552 
1553 		for (List<ExportData::PropertyData>::Element *E = resource.nodes[i].properties.front(); E; E = E->next()) {
1554 
1555 			String prop;
1556 			_get_property_as_text(E->get().value, prop);
1557 			f->store_line(_valprop(E->get().name) + " = " + prop);
1558 		}
1559 	}
1560 
1561 	for (int i = 0; i < resource.connections.size(); i++) {
1562 
1563 		String binds_array;
1564 		_get_property_as_text(resource.connections[i].binds, binds_array);
1565 
1566 		f->store_line("\n[connection signal=\"" + resource.connections[i].signal + "\" from=\"" + String(resource.connections[i].from).c_escape() + "\" to=\"" + String(resource.connections[i].to).c_escape() + "\" method=\"" + resource.connections[i].method + "\" binds=" + binds_array + "]");
1567 	}
1568 
1569 	for (int i = 0; i < resource.editables.size(); i++) {
1570 
1571 		f->store_line("[editable path=\"" + String(resource.editables[i]).c_escape() + "\"]");
1572 	}
1573 }
1574 
1575 enum {
1576 
1577 	//numbering must be different from variant, in case new variant types are added (variant must be always contiguous for jumptable optimization)
1578 	VARIANT_NIL = 1,
1579 	VARIANT_BOOL = 2,
1580 	VARIANT_INT = 3,
1581 	VARIANT_REAL = 4,
1582 	VARIANT_STRING = 5,
1583 	VARIANT_VECTOR2 = 10,
1584 	VARIANT_RECT2 = 11,
1585 	VARIANT_VECTOR3 = 12,
1586 	VARIANT_PLANE = 13,
1587 	VARIANT_QUAT = 14,
1588 	VARIANT_AABB = 15,
1589 	VARIANT_MATRIX3 = 16,
1590 	VARIANT_TRANSFORM = 17,
1591 	VARIANT_MATRIX32 = 18,
1592 	VARIANT_COLOR = 20,
1593 	VARIANT_IMAGE = 21,
1594 	VARIANT_NODE_PATH = 22,
1595 	VARIANT_RID = 23,
1596 	VARIANT_OBJECT = 24,
1597 	VARIANT_INPUT_EVENT = 25,
1598 	VARIANT_DICTIONARY = 26,
1599 	VARIANT_ARRAY = 30,
1600 	VARIANT_RAW_ARRAY = 31,
1601 	VARIANT_INT_ARRAY = 32,
1602 	VARIANT_REAL_ARRAY = 33,
1603 	VARIANT_STRING_ARRAY = 34,
1604 	VARIANT_VECTOR3_ARRAY = 35,
1605 	VARIANT_COLOR_ARRAY = 36,
1606 	VARIANT_VECTOR2_ARRAY = 37,
1607 	VARIANT_INT64 = 40,
1608 	VARIANT_DOUBLE = 41,
1609 
1610 	IMAGE_ENCODING_EMPTY = 0,
1611 	IMAGE_ENCODING_RAW = 1,
1612 	IMAGE_ENCODING_LOSSLESS = 2,
1613 	IMAGE_ENCODING_LOSSY = 3,
1614 
1615 	OBJECT_EMPTY = 0,
1616 	OBJECT_EXTERNAL_RESOURCE = 1,
1617 	OBJECT_INTERNAL_RESOURCE = 2,
1618 	OBJECT_EXTERNAL_RESOURCE_INDEX = 3,
1619 	//version 2: added 64 bits support for float and int
1620 	FORMAT_VERSION = 2,
1621 	FORMAT_VERSION_CAN_RENAME_DEPS = 1
1622 
1623 };
1624 
1625 enum {
1626 	IMAGE_FORMAT_L8, //luminance
1627 	IMAGE_FORMAT_LA8, //luminance-alpha
1628 	IMAGE_FORMAT_R8,
1629 	IMAGE_FORMAT_RG8,
1630 	IMAGE_FORMAT_RGB8,
1631 	IMAGE_FORMAT_RGBA8,
1632 	IMAGE_FORMAT_RGB565, //16 bit
1633 	IMAGE_FORMAT_RGBA4444,
1634 	IMAGE_FORMAT_RGBA5551,
1635 	IMAGE_FORMAT_RF, //float
1636 	IMAGE_FORMAT_RGF,
1637 	IMAGE_FORMAT_RGBF,
1638 	IMAGE_FORMAT_RGBAF,
1639 	IMAGE_FORMAT_RH, //half float
1640 	IMAGE_FORMAT_RGH,
1641 	IMAGE_FORMAT_RGBH,
1642 	IMAGE_FORMAT_RGBAH,
1643 	IMAGE_FORMAT_DXT1, //s3tc bc1
1644 	IMAGE_FORMAT_DXT3, //bc2
1645 	IMAGE_FORMAT_DXT5, //bc3
1646 	IMAGE_FORMAT_ATI1, //bc4
1647 	IMAGE_FORMAT_ATI2, //bc5
1648 	IMAGE_FORMAT_BPTC_RGBA, //btpc bc6h
1649 	IMAGE_FORMAT_BPTC_RGBF, //float /
1650 	IMAGE_FORMAT_BPTC_RGBFU, //unsigned float
1651 	IMAGE_FORMAT_PVRTC2, //pvrtc
1652 	IMAGE_FORMAT_PVRTC2A,
1653 	IMAGE_FORMAT_PVRTC4,
1654 	IMAGE_FORMAT_PVRTC4A,
1655 	IMAGE_FORMAT_ETC, //etc1
1656 	IMAGE_FORMAT_ETC2_R11, //etc2
1657 	IMAGE_FORMAT_ETC2_R11S, //signed, NOT srgb.
1658 	IMAGE_FORMAT_ETC2_RG11,
1659 	IMAGE_FORMAT_ETC2_RG11S,
1660 	IMAGE_FORMAT_ETC2_RGB8,
1661 	IMAGE_FORMAT_ETC2_RGBA8,
1662 	IMAGE_FORMAT_ETC2_RGB8A1,
1663 
1664 };
1665 
_pad_buffer(int p_bytes,FileAccess * f)1666 static void _pad_buffer(int p_bytes, FileAccess *f) {
1667 
1668 	int extra = 4 - (p_bytes % 4);
1669 	if (extra < 4) {
1670 		for (int i = 0; i < extra; i++)
1671 			f->store_8(0); //pad to 32
1672 	}
1673 }
1674 
save_unicode_string(const String & p_string,FileAccess * f,bool p_hi_bit=false)1675 static void save_unicode_string(const String &p_string, FileAccess *f, bool p_hi_bit = false) {
1676 
1677 	CharString utf8 = p_string.utf8();
1678 	f->store_32(uint32_t(utf8.length() + 1) | (p_hi_bit ? 0x80000000 : 0));
1679 	f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1);
1680 }
1681 
_save_binary_property(const Variant & p_property,FileAccess * f)1682 void EditorExportGodot3::_save_binary_property(const Variant &p_property, FileAccess *f) {
1683 
1684 	switch (p_property.get_type()) {
1685 
1686 		case Variant::NIL: {
1687 
1688 			f->store_32(VARIANT_NIL);
1689 			// don't store anything
1690 		} break;
1691 		case Variant::BOOL: {
1692 
1693 			f->store_32(VARIANT_BOOL);
1694 			bool val = p_property;
1695 			f->store_32(val);
1696 		} break;
1697 		case Variant::INT: {
1698 
1699 			f->store_32(VARIANT_INT);
1700 			int val = p_property;
1701 			f->store_32(int32_t(val));
1702 
1703 		} break;
1704 		case Variant::REAL: {
1705 
1706 			f->store_32(VARIANT_REAL);
1707 			f->store_real(p_property);
1708 
1709 		} break;
1710 		case Variant::STRING: {
1711 
1712 			String str = p_property;
1713 			if (str.begins_with("@RESLOCAL:")) {
1714 				f->store_32(VARIANT_OBJECT);
1715 				f->store_32(OBJECT_INTERNAL_RESOURCE);
1716 				f->store_32(str.get_slice(":", 1).to_int());
1717 			} else if (str.begins_with("@RESEXTERNAL:")) {
1718 				f->store_32(VARIANT_OBJECT);
1719 				f->store_32(OBJECT_EXTERNAL_RESOURCE_INDEX);
1720 				f->store_32(str.get_slice(":", 1).to_int());
1721 			} else {
1722 
1723 				f->store_32(VARIANT_STRING);
1724 				save_unicode_string(str, f);
1725 			}
1726 		} break;
1727 		case Variant::VECTOR2: {
1728 
1729 			f->store_32(VARIANT_VECTOR2);
1730 			Vector2 val = p_property;
1731 			f->store_real(val.x);
1732 			f->store_real(val.y);
1733 
1734 		} break;
1735 		case Variant::RECT2: {
1736 
1737 			f->store_32(VARIANT_RECT2);
1738 			Rect2 val = p_property;
1739 			f->store_real(val.pos.x);
1740 			f->store_real(val.pos.y);
1741 			f->store_real(val.size.x);
1742 			f->store_real(val.size.y);
1743 
1744 		} break;
1745 		case Variant::VECTOR3: {
1746 
1747 			f->store_32(VARIANT_VECTOR3);
1748 			Vector3 val = p_property;
1749 			f->store_real(val.x);
1750 			f->store_real(val.y);
1751 			f->store_real(val.z);
1752 
1753 		} break;
1754 		case Variant::PLANE: {
1755 
1756 			f->store_32(VARIANT_PLANE);
1757 			Plane val = p_property;
1758 			f->store_real(val.normal.x);
1759 			f->store_real(val.normal.y);
1760 			f->store_real(val.normal.z);
1761 			f->store_real(val.d);
1762 
1763 		} break;
1764 		case Variant::QUAT: {
1765 
1766 			f->store_32(VARIANT_QUAT);
1767 			Quat val = p_property;
1768 			f->store_real(val.x);
1769 			f->store_real(val.y);
1770 			f->store_real(val.z);
1771 			f->store_real(val.w);
1772 
1773 		} break;
1774 		case Variant::_AABB: {
1775 
1776 			f->store_32(VARIANT_AABB);
1777 			Rect3 val = p_property;
1778 			f->store_real(val.pos.x);
1779 			f->store_real(val.pos.y);
1780 			f->store_real(val.pos.z);
1781 			f->store_real(val.size.x);
1782 			f->store_real(val.size.y);
1783 			f->store_real(val.size.z);
1784 
1785 		} break;
1786 		case Variant::MATRIX32: {
1787 
1788 			f->store_32(VARIANT_MATRIX32);
1789 			Matrix32 val = p_property;
1790 			f->store_real(val.elements[0].x);
1791 			f->store_real(val.elements[0].y);
1792 			f->store_real(val.elements[1].x);
1793 			f->store_real(val.elements[1].y);
1794 			f->store_real(val.elements[2].x);
1795 			f->store_real(val.elements[2].y);
1796 
1797 		} break;
1798 		case Variant::MATRIX3: {
1799 
1800 			f->store_32(VARIANT_MATRIX3);
1801 			Matrix3 val = p_property;
1802 			f->store_real(val.elements[0].x);
1803 			f->store_real(val.elements[0].y);
1804 			f->store_real(val.elements[0].z);
1805 			f->store_real(val.elements[1].x);
1806 			f->store_real(val.elements[1].y);
1807 			f->store_real(val.elements[1].z);
1808 			f->store_real(val.elements[2].x);
1809 			f->store_real(val.elements[2].y);
1810 			f->store_real(val.elements[2].z);
1811 
1812 		} break;
1813 		case Variant::TRANSFORM: {
1814 
1815 			f->store_32(VARIANT_TRANSFORM);
1816 			Transform val = p_property;
1817 			f->store_real(val.basis.elements[0].x);
1818 			f->store_real(val.basis.elements[0].y);
1819 			f->store_real(val.basis.elements[0].z);
1820 			f->store_real(val.basis.elements[1].x);
1821 			f->store_real(val.basis.elements[1].y);
1822 			f->store_real(val.basis.elements[1].z);
1823 			f->store_real(val.basis.elements[2].x);
1824 			f->store_real(val.basis.elements[2].y);
1825 			f->store_real(val.basis.elements[2].z);
1826 			f->store_real(val.origin.x);
1827 			f->store_real(val.origin.y);
1828 			f->store_real(val.origin.z);
1829 
1830 		} break;
1831 		case Variant::COLOR: {
1832 
1833 			f->store_32(VARIANT_COLOR);
1834 			Color val = p_property;
1835 			f->store_real(val.r);
1836 			f->store_real(val.g);
1837 			f->store_real(val.b);
1838 			f->store_real(val.a);
1839 
1840 		} break;
1841 		case Variant::IMAGE: {
1842 
1843 			f->store_32(VARIANT_IMAGE);
1844 			Image val = p_property;
1845 			if (val.empty()) {
1846 				f->store_32(IMAGE_ENCODING_EMPTY);
1847 				break;
1848 			}
1849 
1850 			f->store_32(IMAGE_ENCODING_RAW);
1851 
1852 			f->store_32(val.get_width());
1853 			f->store_32(val.get_height());
1854 			f->store_32(val.get_mipmaps() ? 1 : 0);
1855 			switch (val.get_format()) {
1856 				case Image::FORMAT_GRAYSCALE:
1857 					f->store_32(IMAGE_FORMAT_L8);
1858 					break; ///< one byte per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255
1859 				case Image::FORMAT_INTENSITY:
1860 					f->store_32(IMAGE_FORMAT_L8);
1861 					break; ///< one byte per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255
1862 				case Image::FORMAT_GRAYSCALE_ALPHA:
1863 					f->store_32(IMAGE_FORMAT_LA8);
1864 					break; ///< two bytes per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255. alpha 0-255
1865 				case Image::FORMAT_RGB:
1866 					f->store_32(IMAGE_FORMAT_RGB8);
1867 					break; ///< one byte R: f->store_32(IMAGE_FORMAT_ ); break; one byte G: f->store_32(IMAGE_FORMAT_ ); break; one byte B
1868 				case Image::FORMAT_RGBA:
1869 					f->store_32(IMAGE_FORMAT_RGBA8);
1870 					break; ///< one byte R: f->store_32(IMAGE_FORMAT_ ); break; one byte G: f->store_32(IMAGE_FORMAT_ ); break; one byte B: f->store_32(IMAGE_FORMAT_ ); break; one byte A
1871 				case Image::FORMAT_BC1:
1872 					f->store_32(IMAGE_FORMAT_DXT1);
1873 					break; // DXT1
1874 				case Image::FORMAT_BC2:
1875 					f->store_32(IMAGE_FORMAT_DXT3);
1876 					break; // DXT3
1877 				case Image::FORMAT_BC3:
1878 					f->store_32(IMAGE_FORMAT_DXT5);
1879 					break; // DXT5
1880 				case Image::FORMAT_BC4:
1881 					f->store_32(IMAGE_FORMAT_ATI1);
1882 					break; // ATI1
1883 				case Image::FORMAT_BC5:
1884 					f->store_32(IMAGE_FORMAT_ATI2);
1885 					break; // ATI2
1886 				case Image::FORMAT_PVRTC2: f->store_32(IMAGE_FORMAT_PVRTC2); break;
1887 				case Image::FORMAT_PVRTC2_ALPHA: f->store_32(IMAGE_FORMAT_PVRTC2A); break;
1888 				case Image::FORMAT_PVRTC4: f->store_32(IMAGE_FORMAT_PVRTC4); break;
1889 				case Image::FORMAT_PVRTC4_ALPHA: f->store_32(IMAGE_FORMAT_PVRTC4A); break;
1890 				case Image::FORMAT_ETC:
1891 					f->store_32(IMAGE_FORMAT_ETC);
1892 					break; // regular ETC: f->store_32(IMAGE_FORMAT_ ); break; no transparency
1893 				default: f->store_32(IMAGE_FORMAT_L8); break;
1894 			}
1895 
1896 			int dlen = val.get_data().size();
1897 			f->store_32(dlen);
1898 			DVector<uint8_t>::Read r = val.get_data().read();
1899 			f->store_buffer(r.ptr(), dlen);
1900 			_pad_buffer(dlen, f);
1901 
1902 		} break;
1903 		case Variant::NODE_PATH: {
1904 			f->store_32(VARIANT_NODE_PATH);
1905 			NodePath np = p_property;
1906 			f->store_16(np.get_name_count());
1907 			uint16_t snc = np.get_subname_count();
1908 			if (np.is_absolute())
1909 				snc |= 0x8000;
1910 			f->store_16(snc);
1911 			for (int i = 0; i < np.get_name_count(); i++) {
1912 				save_unicode_string(np.get_name(i), f, true);
1913 			}
1914 			for (int i = 0; i < np.get_subname_count(); i++) {
1915 				save_unicode_string(np.get_subname(i), f, true);
1916 			}
1917 
1918 			save_unicode_string(np.get_property(), f, true);
1919 
1920 		} break;
1921 		case Variant::_RID: {
1922 
1923 			f->store_32(VARIANT_RID);
1924 			WARN_PRINT("Can't save RIDs");
1925 			RID val = p_property;
1926 			f->store_32(val.get_id());
1927 		} break;
1928 		case Variant::OBJECT: {
1929 
1930 			ERR_FAIL();
1931 
1932 		} break;
1933 		case Variant::INPUT_EVENT: {
1934 
1935 			f->store_32(VARIANT_INPUT_EVENT);
1936 			//InputEvent event = p_property;
1937 			f->store_32(0); //event type none, nothing else supported for now.
1938 
1939 		} break;
1940 		case Variant::DICTIONARY: {
1941 
1942 			f->store_32(VARIANT_DICTIONARY);
1943 			Dictionary d = p_property;
1944 			f->store_32(uint32_t(d.size()));
1945 
1946 			List<Variant> keys;
1947 			d.get_key_list(&keys);
1948 
1949 			for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
1950 
1951 				/*
1952 				if (!_check_type(dict[E->get()]))
1953 					continue;
1954 				*/
1955 
1956 				_save_binary_property(E->get(), f);
1957 				_save_binary_property(d[E->get()], f);
1958 			}
1959 
1960 		} break;
1961 		case Variant::ARRAY: {
1962 
1963 			f->store_32(VARIANT_ARRAY);
1964 			Array a = p_property;
1965 			f->store_32(uint32_t(a.size()));
1966 			for (int i = 0; i < a.size(); i++) {
1967 
1968 				_save_binary_property(a[i], f);
1969 			}
1970 
1971 		} break;
1972 		case Variant::RAW_ARRAY: {
1973 
1974 			f->store_32(VARIANT_RAW_ARRAY);
1975 			DVector<uint8_t> arr = p_property;
1976 			int len = arr.size();
1977 			f->store_32(len);
1978 			DVector<uint8_t>::Read r = arr.read();
1979 			f->store_buffer(r.ptr(), len);
1980 			_pad_buffer(len, f);
1981 
1982 		} break;
1983 		case Variant::INT_ARRAY: {
1984 
1985 			f->store_32(VARIANT_INT_ARRAY);
1986 			DVector<int> arr = p_property;
1987 			int len = arr.size();
1988 			f->store_32(len);
1989 			DVector<int>::Read r = arr.read();
1990 			for (int i = 0; i < len; i++)
1991 				f->store_32(r[i]);
1992 
1993 		} break;
1994 		case Variant::REAL_ARRAY: {
1995 
1996 			f->store_32(VARIANT_REAL_ARRAY);
1997 			DVector<real_t> arr = p_property;
1998 			int len = arr.size();
1999 			f->store_32(len);
2000 			DVector<real_t>::Read r = arr.read();
2001 			for (int i = 0; i < len; i++) {
2002 				f->store_real(r[i]);
2003 			}
2004 
2005 		} break;
2006 		case Variant::STRING_ARRAY: {
2007 
2008 			f->store_32(VARIANT_STRING_ARRAY);
2009 			DVector<String> arr = p_property;
2010 			int len = arr.size();
2011 			f->store_32(len);
2012 			DVector<String>::Read r = arr.read();
2013 			for (int i = 0; i < len; i++) {
2014 				save_unicode_string(r[i], f);
2015 			}
2016 
2017 		} break;
2018 		case Variant::VECTOR3_ARRAY: {
2019 
2020 			f->store_32(VARIANT_VECTOR3_ARRAY);
2021 			DVector<Vector3> arr = p_property;
2022 			int len = arr.size();
2023 			f->store_32(len);
2024 			DVector<Vector3>::Read r = arr.read();
2025 			for (int i = 0; i < len; i++) {
2026 				f->store_real(r[i].x);
2027 				f->store_real(r[i].y);
2028 				f->store_real(r[i].z);
2029 			}
2030 
2031 		} break;
2032 		case Variant::VECTOR2_ARRAY: {
2033 
2034 			f->store_32(VARIANT_VECTOR2_ARRAY);
2035 			DVector<Vector2> arr = p_property;
2036 			int len = arr.size();
2037 			f->store_32(len);
2038 			DVector<Vector2>::Read r = arr.read();
2039 			for (int i = 0; i < len; i++) {
2040 				f->store_real(r[i].x);
2041 				f->store_real(r[i].y);
2042 			}
2043 
2044 		} break;
2045 		case Variant::COLOR_ARRAY: {
2046 
2047 			f->store_32(VARIANT_COLOR_ARRAY);
2048 			DVector<Color> arr = p_property;
2049 			int len = arr.size();
2050 			f->store_32(len);
2051 			DVector<Color>::Read r = arr.read();
2052 			for (int i = 0; i < len; i++) {
2053 				f->store_real(r[i].r);
2054 				f->store_real(r[i].g);
2055 				f->store_real(r[i].b);
2056 				f->store_real(r[i].a);
2057 			}
2058 
2059 		} break;
2060 		default: {
2061 
2062 			ERR_EXPLAIN("Invalid variant");
2063 			ERR_FAIL();
2064 		}
2065 	}
2066 }
2067 
_save_binary(const String & p_path,ExportData & resource)2068 void EditorExportGodot3::_save_binary(const String &p_path, ExportData &resource) {
2069 
2070 	FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE);
2071 	ERR_FAIL_COND(!f.operator->());
2072 
2073 	//save header compressed
2074 	static const uint8_t header[4] = { 'R', 'S', 'R', 'C' };
2075 	f->store_buffer(header, 4);
2076 	f->store_32(0);
2077 
2078 	f->store_32(0); //64 bits file, false for now
2079 	f->store_32(3); //major
2080 	f->store_32(0); //minor
2081 	f->store_32(2); //format version (2 is for 3.0)
2082 
2083 	//f->store_32(saved_resources.size()+external_resources.size()); // load steps -not needed
2084 	save_unicode_string(resource.resources[resource.resources.size() - 1].type, f.operator->());
2085 	for (int i = 0; i < 16; i++)
2086 		f->store_32(0); // unused
2087 
2088 	f->store_32(0); //no names saved
2089 
2090 	f->store_32(resource.dependencies.size()); //amount of external resources
2091 
2092 	for (Map<int, ExportData::Dependency>::Element *E = resource.dependencies.front(); E; E = E->next()) {
2093 
2094 		save_unicode_string(E->get().type, f.operator->());
2095 		save_unicode_string(resource_replace_map[E->get().path], f.operator->());
2096 	}
2097 
2098 	// save internal resource table
2099 	Vector<uint64_t> ofs_pos;
2100 	f->store_32(resource.resources.size()); //amount of internal resources
2101 	for (int i = 0; i < resource.resources.size(); i++) {
2102 
2103 		save_unicode_string("local://" + itos(resource.resources[i].index), f.operator->());
2104 		ofs_pos.push_back(f->get_pos());
2105 		f->store_64(0);
2106 	}
2107 
2108 	Vector<uint64_t> ofs_table;
2109 	//	int saved_idx=0;
2110 	//now actually save the resources
2111 
2112 	for (int i = 0; i < resource.resources.size(); i++) {
2113 
2114 		ofs_table.push_back(f->get_pos());
2115 		save_unicode_string(resource.resources[i].type, f.operator->());
2116 		f->store_32(resource.resources[i].properties.size());
2117 
2118 		for (List<ExportData::PropertyData>::Element *E = resource.resources[i].properties.front(); E; E = E->next()) {
2119 
2120 			save_unicode_string(E->get().name, f.operator->(), true);
2121 			_save_binary_property(E->get().value, f.operator->());
2122 		}
2123 	}
2124 
2125 	for (int i = 0; i < ofs_table.size(); i++) {
2126 		f->seek(ofs_pos[i]);
2127 		f->store_64(ofs_table[i]);
2128 	}
2129 
2130 	f->seek_end();
2131 
2132 	f->store_buffer((const uint8_t *)"RSRC", 4); //magic at end
2133 
2134 	ERR_FAIL_COND(f->get_error() != OK);
2135 }
2136 
_save_config(const String & p_path)2137 void EditorExportGodot3::_save_config(const String &p_path) {
2138 
2139 	// Parse existing config, convert persisting properties and store in ConfigFile
2140 	ConfigFile new_cfg = ConfigFile();
2141 
2142 	List<PropertyInfo> props;
2143 	Globals::get_singleton()->get_property_list(&props);
2144 
2145 	for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
2146 
2147 		if (!Globals::get_singleton()->has(E->get().name))
2148 			continue;
2149 
2150 		if (Globals::get_singleton()->is_persisting(E->get().name)) {
2151 			String newname;
2152 			if (globals_rename_map.has(E->get().name)) {
2153 				newname = globals_rename_map[E->get().name];
2154 			} else {
2155 				newname = E->get().name;
2156 			}
2157 
2158 			int sep = newname.find("/");
2159 			String section = newname.substr(0, sep);
2160 			String subname = newname.substr(sep + 1, newname.length());
2161 			String value;
2162 			_get_property_as_text(Globals::get_singleton()->get(E->get().name), value);
2163 			new_cfg.set_value(section, subname, value);
2164 		}
2165 	}
2166 
2167 	String str = "{\n\"flags/filter\": " + String(GLOBAL_DEF("image_loader/filter", true) ? "true" : "false");
2168 	str += ",\n\"flags/mipmaps\": " + String(GLOBAL_DEF("image_loader/gen_mipmaps", true) ? "true" : "false");
2169 	str += "\n}";
2170 	new_cfg.set_value("importer_defaults", "texture", str);
2171 
2172 	// Write the collected ConfigFile manually - we need to use _get_property_as_text()
2173 	// above, so we can't rely on ConfigFile.save() to properly store the raw strings.
2174 	FileAccessRef f = FileAccess::open(p_path.plus_file("project.godot"), FileAccess::WRITE);
2175 
2176 	List<String> sections;
2177 	new_cfg.get_sections(&sections);
2178 
2179 	for (List<String>::Element *E = sections.front(); E; E = E->next()) {
2180 
2181 		f->store_line("[" + E->get() + "]\n");
2182 
2183 		List<String> keys;
2184 		new_cfg.get_section_keys(E->get(), &keys);
2185 
2186 		for (List<String>::Element *F = keys.front(); F; F = F->next()) {
2187 
2188 			f->store_line(F->get() + " = " + new_cfg.get_value(E->get(), F->get()));
2189 		}
2190 		f->store_line("");
2191 	}
2192 
2193 	f->close();
2194 }
2195 
_convert_script(const String & p_path,const String & p_target_path,bool mark_converted_lines)2196 Error EditorExportGodot3::_convert_script(const String &p_path, const String &p_target_path, bool mark_converted_lines) {
2197 
2198 	FileAccessRef src = FileAccess::open(p_path, FileAccess::READ);
2199 	ERR_FAIL_COND_V(!src.operator->(), FAILED);
2200 	FileAccessRef dst = FileAccess::open(p_target_path, FileAccess::WRITE);
2201 	ERR_FAIL_COND_V(!dst.operator->(), FAILED);
2202 
2203 	String http_var = "";
2204 	const String note = "  #-- NOTE: Automatically converted by Godot 2 to 3 converter, please review";
2205 
2206 	while (!src->eof_reached()) {
2207 		String line = src->get_line();
2208 		String origline = line;
2209 
2210 		// Convert _fixed_process( => _physics_process(
2211 		RegEx regexp("(.*)_fixed_process\\((.*)");
2212 		int res = regexp.find(line);
2213 		if (res >= 0 && regexp.get_capture_count() == 3) {
2214 			line = regexp.get_capture(1) + "_physics_process(" + regexp.get_capture(2);
2215 		}
2216 		regexp.clear();
2217 
2218 		// Convert _input_event( => _gui_input(
2219 		regexp.compile("(.*)_input_event\\((.*)");
2220 		res = regexp.find(line);
2221 		if (res >= 0 && regexp.get_capture_count() == 3) {
2222 			line = regexp.get_capture(1) + "_gui_input(" + regexp.get_capture(2);
2223 		}
2224 		regexp.clear();
2225 
2226 		// Try to detect a HTTPClient object
2227 		regexp.compile("[ \t]*([a-zA-Z0-9_]*)[ ]*=[ ]*HTTPClient\\.new\\(\\)");
2228 		res = regexp.find(line);
2229 		if (res >= 0 && regexp.get_capture_count() == 2) {
2230 			http_var = regexp.get_capture(1).strip_edges();
2231 		}
2232 		regexp.clear();
2233 
2234 		if (http_var != "") {
2235 			// Convert .connect( => .connect_to_host(
2236 			regexp.compile("(.*)" + http_var + "\\.connect\\((.*)");
2237 			res = regexp.find(line);
2238 			if (res >= 0 && regexp.get_capture_count() == 3) {
2239 				line = regexp.get_capture(1) + http_var + ".connect_to_host(" + regexp.get_capture(2);
2240 			}
2241 			regexp.clear();
2242 		}
2243 
2244 		// The following replacements may be needed more than once per line, hence the loop
2245 		int count;
2246 		int tries = 0;
2247 		do {
2248 			count = 0;
2249 
2250 			// Convert all types to fix instances of renamed Nodes, or renamed core types (Pool*Array, Basis, etc.)
2251 			for (Map<String, String>::Element *E = type_rename_map.front(); E; E = E->next()) {
2252 				//regexp.compile("(.*[^a-zA-Z0-9_])" + E->key() + "([^a-zA-Z0-9_].*)");
2253 				regexp.compile("(.*\\b)" + E->key() + "(\\b.*)");
2254 				res = regexp.find(line);
2255 				if (res >= 0 && regexp.get_capture_count() == 3) {
2256 					line = regexp.get_capture(1) + E->get() + regexp.get_capture(2);
2257 					count++;
2258 				}
2259 				regexp.clear();
2260 			}
2261 
2262 			// Convert _pos( => _position(
2263 			regexp.compile("(.*)_pos\\((.*)");
2264 			res = regexp.find(line);
2265 			if (res >= 0 && regexp.get_capture_count() == 3) {
2266 				line = regexp.get_capture(1) + "_position(" + regexp.get_capture(2);
2267 				count++;
2268 			}
2269 			regexp.clear();
2270 
2271 			// Convert .pos => .position
2272 			regexp.compile("(.*)\\.pos([^a-zA-Z0-9_-].*)");
2273 			res = regexp.find(line);
2274 			if (res >= 0 && regexp.get_capture_count() == 3) {
2275 				line = regexp.get_capture(1) + ".position" + regexp.get_capture(2);
2276 				count++;
2277 			}
2278 			regexp.clear();
2279 
2280 			// Convert _rot( => _rotation(
2281 			regexp.compile("(.*)_rot\\((.*)");
2282 			res = regexp.find(line);
2283 			if (res >= 0 && regexp.get_capture_count() == 3) {
2284 				line = regexp.get_capture(1) + "_rotation(" + regexp.get_capture(2);
2285 				count++;
2286 			}
2287 			regexp.clear();
2288 
2289 			// Convert _speed( => _speed_scale(
2290 			regexp.compile("(.*)_speed\\((.*)");
2291 			res = regexp.find(line);
2292 			if (res >= 0 && regexp.get_capture_count() == 3) {
2293 				line = regexp.get_capture(1) + "_speed_scale(" + regexp.get_capture(2);
2294 				count++;
2295 			}
2296 			regexp.clear();
2297 
2298 			// Convert KEY_RETURN => KEY_ENTER
2299 			regexp.compile("(.*)KEY_RETURN(.*)");
2300 			res = regexp.find(line);
2301 			if (res >= 0 && regexp.get_capture_count() == 3) {
2302 				line = regexp.get_capture(1) + "KEY_ENTER" + regexp.get_capture(2);
2303 				count++;
2304 			}
2305 			regexp.clear();
2306 
2307 			// Convert get_opacity() => modulate.a
2308 			regexp.compile("(.*)get_opacity\\(\\)(.*)");
2309 			res = regexp.find(line);
2310 			if (res >= 0 && regexp.get_capture_count() == 3) {
2311 				line = regexp.get_capture(1) + "modulate.a" + regexp.get_capture(2);
2312 				count++;
2313 			}
2314 			regexp.clear();
2315 
2316 			// Convert set_opacity(var) => modulate.a = var
2317 			regexp.compile("(.*)set_opacity\\((.*)\\)(.*)");
2318 			res = regexp.find(line);
2319 			if (res >= 0 && regexp.get_capture_count() == 4) {
2320 				line = regexp.get_capture(1) + "modulate.a = " + regexp.get_capture(2) + regexp.get_capture(3);
2321 				count++;
2322 			}
2323 			regexp.clear();
2324 
2325 			// Convert get_self_opacity() => self_modulate.a
2326 			regexp.compile("(.*)get_self_opacity\\(\\)(.*)");
2327 			res = regexp.find(line);
2328 			if (res >= 0 && regexp.get_capture_count() == 3) {
2329 				line = regexp.get_capture(1) + "self_modulate.a" + regexp.get_capture(2);
2330 				count++;
2331 			}
2332 			regexp.clear();
2333 
2334 			// Convert set_self_opacity(var) => self_modulate.a = var
2335 			regexp.compile("(.*)set_self_opacity\\((.*)\\)(.*)");
2336 			res = regexp.find(line);
2337 			if (res >= 0 && regexp.get_capture_count() == 4) {
2338 				line = regexp.get_capture(1) + "self_modulate.a = " + regexp.get_capture(2) + regexp.get_capture(3);
2339 				count++;
2340 			}
2341 			regexp.clear();
2342 
2343 			// Convert set_hidden(var) => visible = !(var)
2344 			regexp.compile("(.*)set_hidden\\((.*)\\)(.*)");
2345 			res = regexp.find(line);
2346 			if (res >= 0 && regexp.get_capture_count() == 4) {
2347 				line = regexp.get_capture(1) + "visible = !(" + regexp.get_capture(2) + ")" + regexp.get_capture(3);
2348 				count++;
2349 			}
2350 			regexp.clear();
2351 
2352 			// Convert var.type == InputEvent.KEY => var is InputEventKey
2353 			regexp.compile("(.*)\\.type[ ]*==[ ]*InputEvent.KEY(.*)");
2354 			res = regexp.find(line);
2355 			if (res >= 0 && regexp.get_capture_count() == 3) {
2356 				line = regexp.get_capture(1) + " is InputEventKey" + regexp.get_capture(2);
2357 				count++;
2358 			}
2359 			regexp.clear();
2360 
2361 			// Convert var.type == InputEvent.MOUSE_MOTION => var is InputEventMouseMotion
2362 			regexp.compile("(.*)\\.type[ ]*==[ ]*InputEvent.MOUSE_MOTION(.*)");
2363 			res = regexp.find(line);
2364 			if (res >= 0 && regexp.get_capture_count() == 3) {
2365 				line = regexp.get_capture(1) + " is InputEventMouseMotion" + regexp.get_capture(2);
2366 				count++;
2367 			}
2368 			regexp.clear();
2369 
2370 			// Convert var.type == InputEvent.MOUSE_BUTTON => var is InputEventMouseButton
2371 			regexp.compile("(.*)\\.type[ ]*==[ ]*InputEvent.MOUSE_BUTTON(.*)");
2372 			res = regexp.find(line);
2373 			if (res >= 0 && regexp.get_capture_count() == 3) {
2374 				line = regexp.get_capture(1) + " is InputEventMouseButton" + regexp.get_capture(2);
2375 				count++;
2376 			}
2377 			regexp.clear();
2378 
2379 			// Convert var.type == InputEvent.JOYSTICK_MOTION => var is InputEventJoypadMotion
2380 			regexp.compile("(.*)\\.type[ ]*==[ ]*InputEvent.JOYSTICK_MOTION(.*)");
2381 			res = regexp.find(line);
2382 			if (res >= 0 && regexp.get_capture_count() == 3) {
2383 				line = regexp.get_capture(1) + " is InputEventJoypadMotion" + regexp.get_capture(2);
2384 				count++;
2385 			}
2386 			regexp.clear();
2387 
2388 			// Convert var.type == InputEvent.JOYSTICK_BUTTON => var is InputEventJoypadButton
2389 			regexp.compile("(.*)\\.type[ ]*==[ ]*InputEvent.JOYSTICK_BUTTON(.*)");
2390 			res = regexp.find(line);
2391 			if (res >= 0 && regexp.get_capture_count() == 3) {
2392 				line = regexp.get_capture(1) + " is InputEventJoypadButton" + regexp.get_capture(2);
2393 				count++;
2394 			}
2395 			regexp.clear();
2396 
2397 			// Convert var.type == InputEvent.SCREEN_TOUCH => var is InputEventScreenTouch
2398 			regexp.compile("(.*)\\.type[ ]*==[ ]*InputEvent.SCREEN_TOUCH(.*)");
2399 			res = regexp.find(line);
2400 			if (res >= 0 && regexp.get_capture_count() == 3) {
2401 				line = regexp.get_capture(1) + " is InputEventScreenTouch" + regexp.get_capture(2);
2402 				count++;
2403 			}
2404 			regexp.clear();
2405 
2406 			// Convert var.type == InputEvent.SCREEN_DRAG => var is InputEventScreenDrag
2407 			regexp.compile("(.*)\\.type[ ]*==[ ]*InputEvent.SCREEN_DRAG(.*)");
2408 			res = regexp.find(line);
2409 			if (res >= 0 && regexp.get_capture_count() == 3) {
2410 				line = regexp.get_capture(1) + " is InputEventScreenDrag" + regexp.get_capture(2);
2411 				count++;
2412 			}
2413 			regexp.clear();
2414 
2415 			// Convert move( => move_and_collide(
2416 			regexp.compile("(.*)move\\((.*)");
2417 			res = regexp.find(line);
2418 			if (res >= 0 && regexp.get_capture_count() == 3) {
2419 				line = regexp.get_capture(1) + "move_and_collide(" + regexp.get_capture(2);
2420 				count++;
2421 			}
2422 			regexp.clear();
2423 
2424 			// Convert is_move_and_slide_on_floor() => is_on_floor()
2425 			regexp.compile("(.*)is_move_and_slide_on_floor\\(\\)(.*)");
2426 			res = regexp.find(line);
2427 			if (res >= 0 && regexp.get_capture_count() == 3) {
2428 				line = regexp.get_capture(1) + "is_on_floor()" + regexp.get_capture(2);
2429 				count++;
2430 			}
2431 			regexp.clear();
2432 
2433 			// Convert is_move_and_slide_on_ceiling() => is_on_ceiling()
2434 			regexp.compile("(.*)is_move_and_slide_on_ceiling\\(\\)(.*)");
2435 			res = regexp.find(line);
2436 			if (res >= 0 && regexp.get_capture_count() == 3) {
2437 				line = regexp.get_capture(1) + "is_on_ceiling()" + regexp.get_capture(2);
2438 				count++;
2439 			}
2440 			regexp.clear();
2441 
2442 			// Convert is_move_and_slide_on_wall() => is_on_wall()
2443 			regexp.compile("(.*)is_move_and_slide_on_wall\\(\\)(.*)");
2444 			res = regexp.find(line);
2445 			if (res >= 0 && regexp.get_capture_count() == 3) {
2446 				line = regexp.get_capture(1) + "is_on_wall()" + regexp.get_capture(2);
2447 				count++;
2448 			}
2449 			regexp.clear();
2450 
2451 			// Convert <any chars but none> extends => <any chars but none> is
2452 			// The only case where we don't want to convert it is `^extends <Node>`
2453 			regexp.compile("(^.+ )extends(.*)");
2454 			res = regexp.find(line);
2455 			if (res >= 0 && regexp.get_capture_count() == 3) {
2456 				line = regexp.get_capture(1) + "is" + regexp.get_capture(2);
2457 				count++;
2458 			}
2459 			regexp.clear();
2460 
2461 		} while (count >= 1 && tries++ < 10);
2462 
2463 		if (mark_converted_lines && line != origline) {
2464 			// Add explanatory comment on the changed line
2465 			line += note;
2466 		}
2467 
2468 		dst->store_line(line);
2469 	}
2470 
2471 	return OK;
2472 }
2473 
export_godot3(const String & p_path,bool convert_scripts,bool mark_converted_lines)2474 Error EditorExportGodot3::export_godot3(const String &p_path, bool convert_scripts, bool mark_converted_lines) {
2475 
2476 	List<String> files;
2477 	_find_files(EditorFileSystem::get_singleton()->get_filesystem(), &files);
2478 
2479 	EditorProgress progress("exporting", "Exporting the project to Godot 3.0", files.size());
2480 
2481 	//find XML resources
2482 
2483 	resource_replace_map.clear();
2484 
2485 	Set<String> xml_extensions;
2486 	Set<String> binary_extensions;
2487 	Set<String> text_extensions;
2488 
2489 	{
2490 		List<String> xml_exts;
2491 		ResourceFormatLoaderXML::singleton->get_recognized_extensions(&xml_exts);
2492 		for (List<String>::Element *E = xml_exts.front(); E; E = E->next()) {
2493 			xml_extensions.insert(E->get());
2494 		}
2495 	}
2496 
2497 	{
2498 		List<String> binary_exts;
2499 		ResourceFormatLoaderBinary::singleton->get_recognized_extensions(&binary_exts);
2500 		for (List<String>::Element *E = binary_exts.front(); E; E = E->next()) {
2501 			binary_extensions.insert(E->get());
2502 		}
2503 	}
2504 
2505 	{
2506 		List<String> text_exts;
2507 		ResourceFormatLoaderText::singleton->get_recognized_extensions(&text_exts);
2508 		for (List<String>::Element *E = text_exts.front(); E; E = E->next()) {
2509 			text_extensions.insert(E->get());
2510 		}
2511 	}
2512 
2513 	for (List<String>::Element *E = files.front(); E; E = E->next()) {
2514 
2515 		String file = E->get();
2516 		String file_local = file.replace("res://", "");
2517 
2518 		resource_replace_map[file] = file;
2519 		resource_replace_map[file_local] = file_local;
2520 
2521 		if (xml_extensions.has(file.extension().to_lower())) {
2522 			if (ResourceLoader::get_resource_type(file) == "PackedScene") {
2523 				resource_replace_map[file] = file.basename() + ".tscn";
2524 				resource_replace_map[file_local] = file_local.basename() + ".tscn";
2525 			} else {
2526 				resource_replace_map[file] = file.basename() + ".tres";
2527 				resource_replace_map[file_local] = file_local.basename() + ".tres";
2528 			}
2529 		}
2530 
2531 		// Changing all the old extensions to new Godot 3.0 extensions.
2532 		// Refer PR #9201
2533 		String extension = file.extension().to_lower();
2534 		if (extension == "anm") {
2535 			resource_replace_map[file] = file.basename() + ".anim";
2536 			resource_replace_map[file_local] = file_local.basename() + ".anim";
2537 		} else if (extension == "asogg") {
2538 			resource_replace_map[file] = file.basename() + ".oggstr";
2539 			resource_replace_map[file_local] = file_local.basename() + ".oggstr";
2540 		} else if (extension == "atex") {
2541 			resource_replace_map[file] = file.basename() + ".atlastex";
2542 			resource_replace_map[file_local] = file_local.basename() + ".atlastex";
2543 		} else if (extension == "cbm") {
2544 			resource_replace_map[file] = file.basename() + ".cubemap";
2545 			resource_replace_map[file_local] = file_local.basename() + ".cubemap";
2546 		} else if (extension == "cvtex") {
2547 			resource_replace_map[file] = file.basename() + ".curvetex";
2548 			resource_replace_map[file_local] = file_local.basename() + ".curvetex";
2549 		} else if (extension == "fnt") {
2550 			resource_replace_map[file] = file.basename() + ".font";
2551 			resource_replace_map[file_local] = file_local.basename() + ".font";
2552 		} else if (extension == "gt") {
2553 			resource_replace_map[file] = file.basename() + ".meshlib";
2554 			resource_replace_map[file_local] = file_local.basename() + ".meshlib";
2555 		} else if (extension == "ltex") {
2556 			resource_replace_map[file] = file.basename() + ".largetex";
2557 			resource_replace_map[file_local] = file_local.basename() + ".largetex";
2558 		} else if (extension == "mmsh") {
2559 			resource_replace_map[file] = file.basename() + ".multimesh";
2560 			resource_replace_map[file_local] = file_local.basename() + ".multimesh";
2561 		} else if (extension == "msh") {
2562 			resource_replace_map[file] = file.basename() + ".mesh";
2563 			resource_replace_map[file_local] = file_local.basename() + ".mesh";
2564 		} else if (extension == "mtl") {
2565 			resource_replace_map[file] = file.basename() + ".material";
2566 			resource_replace_map[file_local] = file_local.basename() + ".material";
2567 		} else if (extension == "sbx") {
2568 			resource_replace_map[file] = file.basename() + ".stylebox";
2569 			resource_replace_map[file_local] = file_local.basename() + ".stylebox";
2570 		} else if (extension == "sgp") {
2571 			resource_replace_map[file] = file.basename() + ".vshader";
2572 			resource_replace_map[file_local] = file_local.basename() + ".vshader";
2573 		} else if (extension == "shd") {
2574 			resource_replace_map[file] = file.basename() + ".shader";
2575 			resource_replace_map[file_local] = file_local.basename() + ".shader";
2576 		} else if (extension == "shp") {
2577 			resource_replace_map[file] = file.basename() + ".shape";
2578 			resource_replace_map[file_local] = file_local.basename() + ".shape";
2579 		} else if (extension == "smp") {
2580 			resource_replace_map[file] = file.basename() + ".sample";
2581 			resource_replace_map[file_local] = file_local.basename() + ".sample";
2582 		} else if (extension == "tex") {
2583 			resource_replace_map[file] = file.basename() + ".texture";
2584 			resource_replace_map[file_local] = file_local.basename() + ".texture";
2585 		} else if (extension == "thm") {
2586 			resource_replace_map[file] = file.basename() + ".theme";
2587 			resource_replace_map[file_local] = file_local.basename() + ".theme";
2588 		} else if (extension == "wrd") {
2589 			resource_replace_map[file] = file.basename() + ".world";
2590 			resource_replace_map[file_local] = file_local.basename() + ".world";
2591 		} else if (extension == "xl") {
2592 			resource_replace_map[file] = file.basename() + ".translation";
2593 			resource_replace_map[file_local] = file_local.basename() + ".translation";
2594 		}
2595 	}
2596 
2597 	DirAccess *directory = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
2598 
2599 	if (directory->change_dir(p_path) != OK) {
2600 		memdelete(directory);
2601 		ERR_FAIL_V(ERR_CANT_OPEN);
2602 	}
2603 
2604 	int idx = 0;
2605 	for (List<String>::Element *E = files.front(); E; E = E->next()) {
2606 
2607 		String path = E->get();
2608 		String extension = path.extension().to_lower();
2609 
2610 		String target_path;
2611 		bool repack = false;
2612 
2613 		target_path = p_path.plus_file(path.replace("res://", ""));
2614 
2615 		// Changing all the old extensions to new Godot 3.0 extensions.
2616 		// Refer PR #9201
2617 		if (extension == "fnt") {
2618 			target_path = target_path.basename() + ".font";
2619 		} else if (extension == "asogg") {
2620 			target_path = target_path.basename() + ".oggstr";
2621 		} else if (extension == "atex") {
2622 			target_path = target_path.basename() + ".atlastex";
2623 		} else if (extension == "cbm") {
2624 			target_path = target_path.basename() + ".cubemap";
2625 		} else if (extension == "cvtex") {
2626 			target_path = target_path.basename() + ".curvetex";
2627 		} else if (extension == "fnt") {
2628 			target_path = target_path.basename() + ".font";
2629 		} else if (extension == "gt") {
2630 			target_path = target_path.basename() + ".meshlib";
2631 		} else if (extension == "ltex") {
2632 			target_path = target_path.basename() + ".largetex";
2633 		} else if (extension == "mmsh") {
2634 			target_path = target_path.basename() + ".multimesh";
2635 		} else if (extension == "msh") {
2636 			target_path = target_path.basename() + ".mesh";
2637 		} else if (extension == "mtl") {
2638 			target_path = target_path.basename() + ".material";
2639 		} else if (extension == "sbx") {
2640 			target_path = target_path.basename() + ".stylebox";
2641 		} else if (extension == "sgp") {
2642 			target_path = target_path.basename() + ".vshader";
2643 		} else if (extension == "shd") {
2644 			target_path = target_path.basename() + ".shader";
2645 		} else if (extension == "shp") {
2646 			target_path = target_path.basename() + ".shape";
2647 		} else if (extension == "smp") {
2648 			target_path = target_path.basename() + ".sample";
2649 		} else if (extension == "tex") {
2650 			target_path = target_path.basename() + ".texture";
2651 		} else if (extension == "thm") {
2652 			target_path = target_path.basename() + ".theme";
2653 		} else if (extension == "wrd") {
2654 			target_path = target_path.basename() + ".world";
2655 		} else if (extension == "xl") {
2656 			target_path = target_path.basename() + ".translation";
2657 		}
2658 
2659 		progress.step(target_path.get_file(), idx++);
2660 
2661 		print_line("-- Exporting file: " + target_path);
2662 
2663 		if (directory->make_dir_recursive(target_path.get_base_dir()) != OK) {
2664 			memdelete(directory);
2665 			ERR_FAIL_V(ERR_CANT_CREATE);
2666 		}
2667 
2668 		ExportData resource_data;
2669 
2670 		Error err;
2671 		bool cont = false;
2672 		if (xml_extensions.has(extension)) {
2673 
2674 			err = ResourceLoader::get_export_data(path, resource_data);
2675 		} else if (text_extensions.has(extension)) {
2676 
2677 			err = ResourceLoader::get_export_data(path, resource_data);
2678 		} else if (binary_extensions.has(extension)) {
2679 
2680 			err = ResourceLoader::get_export_data(path, resource_data);
2681 		} else {
2682 
2683 			if (convert_scripts && extension == "gd") {
2684 				err = _convert_script(path, target_path, mark_converted_lines);
2685 			} else {
2686 				//single file, copy it
2687 				err = directory->copy(path, target_path);
2688 			}
2689 
2690 			cont = true; //no longer needed to do anything, just copied the file!
2691 		}
2692 
2693 		if (err != OK) {
2694 			memdelete(directory);
2695 			ERR_FAIL_V(err);
2696 		}
2697 
2698 		if (cont) {
2699 			continue;
2700 		}
2701 
2702 		if (resource_data.nodes.size() == 0 && resource_data.resources[resource_data.resources.size() - 1].type == "PackedScene") {
2703 			//must unpack a PackedScene
2704 			_unpack_packed_scene(resource_data);
2705 			repack = true;
2706 		}
2707 
2708 		_convert_resources(resource_data);
2709 
2710 		if (repack) {
2711 
2712 			_pack_packed_scene(resource_data);
2713 		}
2714 
2715 		if (xml_extensions.has(extension)) {
2716 
2717 			String save_path = resource_replace_map[target_path];
2718 			_save_text(save_path, resource_data);
2719 		} else if (text_extensions.has(extension)) {
2720 			_save_text(target_path, resource_data);
2721 		} else if (binary_extensions.has(extension)) {
2722 			_save_binary(target_path, resource_data);
2723 		}
2724 	}
2725 
2726 	memdelete(directory);
2727 	_save_config(p_path);
2728 
2729 	return OK;
2730 }
2731 
EditorExportGodot3()2732 EditorExportGodot3::EditorExportGodot3() {
2733 
2734 	int idx = 0;
2735 	while (globals_renames[idx][0] != NULL) {
2736 
2737 		globals_rename_map[globals_renames[idx][0]] = globals_renames[idx][1];
2738 		idx++;
2739 	}
2740 
2741 	idx = 0;
2742 	while (prop_renames[idx][0] != NULL) {
2743 
2744 		prop_rename_map[prop_renames[idx][0]] = prop_renames[idx][1];
2745 		idx++;
2746 	}
2747 
2748 	idx = 0;
2749 	while (type_renames[idx][0] != NULL) {
2750 
2751 		type_rename_map[type_renames[idx][0]] = type_renames[idx][1];
2752 		idx++;
2753 	}
2754 
2755 	idx = 0;
2756 	while (signal_renames[idx][0] != NULL) {
2757 
2758 		signal_rename_map[signal_renames[idx][0]] = signal_renames[idx][1];
2759 		idx++;
2760 	}
2761 }
2762