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(§ions);
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