summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/Camera3D.xml14
-rw-r--r--doc/classes/ClippedCamera3D.xml14
-rw-r--r--doc/classes/CollisionObject2D.xml26
-rw-r--r--doc/classes/CollisionObject3D.xml26
-rw-r--r--doc/classes/NavigationMesh.xml13
-rw-r--r--doc/classes/OccluderInstance3D.xml12
-rw-r--r--doc/classes/PhysicsDirectSpaceState2D.xml10
-rw-r--r--doc/classes/PhysicsDirectSpaceState3D.xml2
-rw-r--r--doc/classes/PhysicsShapeQueryParameters2D.xml4
-rw-r--r--doc/classes/PhysicsShapeQueryParameters3D.xml2
-rw-r--r--doc/classes/ProjectSettings.xml36
-rw-r--r--doc/classes/RayCast2D.xml12
-rw-r--r--doc/classes/RayCast3D.xml14
-rw-r--r--doc/classes/SoftBody3D.xml24
-rw-r--r--doc/classes/VisualInstance3D.xml14
-rw-r--r--editor/SCsub5
-rw-r--r--editor/editor_properties.cpp8
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp10
-rw-r--r--editor/translations/af.po100
-rw-r--r--editor/translations/ar.po107
-rw-r--r--editor/translations/az.po98
-rw-r--r--editor/translations/bg.po106
-rw-r--r--editor/translations/bn.po110
-rw-r--r--editor/translations/br.po98
-rw-r--r--editor/translations/ca.po107
-rw-r--r--editor/translations/cs.po107
-rw-r--r--editor/translations/da.po109
-rw-r--r--editor/translations/de.po1058
-rw-r--r--editor/translations/editor.pot97
-rw-r--r--editor/translations/el.po107
-rw-r--r--editor/translations/eo.po101
-rw-r--r--editor/translations/es.po1175
-rw-r--r--editor/translations/es_AR.po362
-rw-r--r--editor/translations/et.po101
-rw-r--r--editor/translations/eu.po100
-rw-r--r--editor/translations/fa.po108
-rw-r--r--editor/translations/fi.po348
-rw-r--r--editor/translations/fil.po98
-rw-r--r--editor/translations/fr.po1065
-rw-r--r--editor/translations/ga.po98
-rw-r--r--editor/translations/gl.po113
-rw-r--r--editor/translations/he.po105
-rw-r--r--editor/translations/hi.po100
-rw-r--r--editor/translations/hr.po99
-rw-r--r--editor/translations/hu.po103
-rw-r--r--editor/translations/id.po107
-rw-r--r--editor/translations/is.po99
-rw-r--r--editor/translations/it.po121
-rw-r--r--editor/translations/ja.po151
-rw-r--r--editor/translations/ka.po100
-rw-r--r--editor/translations/km.po97
-rw-r--r--editor/translations/ko.po472
-rw-r--r--editor/translations/lt.po99
-rw-r--r--editor/translations/lv.po99
-rw-r--r--editor/translations/mi.po97
-rw-r--r--editor/translations/mk.po97
-rw-r--r--editor/translations/ml.po99
-rw-r--r--editor/translations/mr.po98
-rw-r--r--editor/translations/ms.po100
-rw-r--r--editor/translations/nb.po107
-rw-r--r--editor/translations/nl.po153
-rw-r--r--editor/translations/or.po97
-rw-r--r--editor/translations/pl.po107
-rw-r--r--editor/translations/pr.po101
-rw-r--r--editor/translations/pt.po151
-rw-r--r--editor/translations/pt_BR.po273
-rw-r--r--editor/translations/ro.po106
-rw-r--r--editor/translations/ru.po1050
-rw-r--r--editor/translations/si.po99
-rw-r--r--editor/translations/sk.po102
-rw-r--r--editor/translations/sl.po108
-rw-r--r--editor/translations/sq.po100
-rw-r--r--editor/translations/sr_Cyrl.po110
-rw-r--r--editor/translations/sr_Latn.po98
-rw-r--r--editor/translations/sv.po156
-rw-r--r--editor/translations/ta.po98
-rw-r--r--editor/translations/te.po97
-rw-r--r--editor/translations/th.po107
-rw-r--r--editor/translations/tr.po107
-rw-r--r--editor/translations/tt.po97
-rw-r--r--editor/translations/tzm.po97
-rw-r--r--editor/translations/uk.po1061
-rw-r--r--editor/translations/ur_PK.po101
-rw-r--r--editor/translations/vi.po103
-rw-r--r--editor/translations/zh_CN.po1028
-rw-r--r--editor/translations/zh_HK.po108
-rw-r--r--editor/translations/zh_TW.po107
-rw-r--r--modules/csg/csg_shape.cpp48
-rw-r--r--modules/csg/csg_shape.h8
-rw-r--r--modules/csg/doc_classes/CSGShape3D.xml24
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml24
-rw-r--r--modules/gridmap/grid_map.cpp48
-rw-r--r--modules/gridmap/grid_map.h8
-rw-r--r--platform/android/export/export.cpp3016
-rw-r--r--platform/android/export/export_plugin.cpp2945
-rw-r--r--platform/android/export/export_plugin.h255
-rw-r--r--platform/android/export/godot_plugin_config.cpp (renamed from platform/android/plugin/godot_plugin_config.h)95
-rw-r--r--platform/android/export/godot_plugin_config.h106
-rw-r--r--platform/android/export/gradle_export_util.cpp252
-rw-r--r--platform/android/export/gradle_export_util.h210
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java1
-rw-r--r--platform/iphone/export/export.cpp2022
-rw-r--r--platform/iphone/export/export_plugin.cpp1792
-rw-r--r--platform/iphone/export/export_plugin.h296
-rw-r--r--platform/iphone/export/godot_plugin_config.cpp (renamed from platform/iphone/plugin/godot_plugin_config.h)111
-rw-r--r--platform/iphone/export/godot_plugin_config.h132
-rw-r--r--platform/javascript/export/export.cpp966
-rw-r--r--platform/javascript/export/export.h5
-rw-r--r--platform/javascript/export/export_plugin.cpp671
-rw-r--r--platform/javascript/export/export_plugin.h149
-rw-r--r--platform/javascript/export/export_server.h254
-rw-r--r--platform/osx/export/export.cpp1148
-rw-r--r--platform/osx/export/export_plugin.cpp1085
-rw-r--r--platform/osx/export/export_plugin.h128
-rw-r--r--platform/uwp/export/app_packager.cpp474
-rw-r--r--platform/uwp/export/app_packager.h150
-rw-r--r--platform/uwp/export/export.cpp1403
-rw-r--r--platform/uwp/export/export_plugin.cpp498
-rw-r--r--platform/uwp/export/export_plugin.h448
-rw-r--r--platform/windows/export/export.cpp311
-rw-r--r--platform/windows/export/export.h5
-rw-r--r--platform/windows/export/export_plugin.cpp323
-rw-r--r--platform/windows/export/export_plugin.h51
-rw-r--r--scene/2d/collision_object_2d.cpp40
-rw-r--r--scene/2d/collision_object_2d.h8
-rw-r--r--scene/2d/line_builder.cpp8
-rw-r--r--scene/2d/ray_cast_2d.cpp20
-rw-r--r--scene/2d/ray_cast_2d.h4
-rw-r--r--scene/3d/camera_3d.cpp44
-rw-r--r--scene/3d/camera_3d.h8
-rw-r--r--scene/3d/collision_object_3d.cpp40
-rw-r--r--scene/3d/collision_object_3d.h8
-rw-r--r--scene/3d/occluder_instance_3d.cpp24
-rw-r--r--scene/3d/occluder_instance_3d.h5
-rw-r--r--scene/3d/ray_cast_3d.cpp20
-rw-r--r--scene/3d/ray_cast_3d.h4
-rw-r--r--scene/3d/soft_body_3d.cpp48
-rw-r--r--scene/3d/soft_body_3d.h8
-rw-r--r--scene/3d/visual_instance_3d.cpp24
-rw-r--r--scene/3d/visual_instance_3d.h4
-rw-r--r--scene/register_scene_types.cpp12
-rw-r--r--scene/resources/navigation_mesh.cpp20
-rw-r--r--scene/resources/navigation_mesh.h4
-rw-r--r--scene/resources/visual_shader.cpp78
-rw-r--r--scene/resources/visual_shader_nodes.cpp5
-rw-r--r--servers/physics_server_2d.cpp12
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.cpp4
147 files changed, 20203 insertions, 14102 deletions
diff --git a/doc/classes/Camera3D.xml b/doc/classes/Camera3D.xml
index 2ada0c556d..8a91a91b22 100644
--- a/doc/classes/Camera3D.xml
+++ b/doc/classes/Camera3D.xml
@@ -29,11 +29,11 @@
Gets the camera transform. Subclassed cameras such as [ClippedCamera3D] may provide different transforms than the [Node] transform.
</description>
</method>
- <method name="get_cull_mask_bit" qualifiers="const">
+ <method name="get_cull_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns [code]true[/code] if the given [code]layer[/code] in the [member cull_mask] is enabled, [code]false[/code] otherwise.
+ Returns whether or not the specified layer of the [member cull_mask] is enabled, given a [code]layer_number[/code] between 1 and 20.
</description>
</method>
<method name="get_frustum" qualifiers="const">
@@ -92,12 +92,12 @@
Returns a 3D position in world space, that is the result of projecting a point on the [Viewport] rectangle by the camera projection. This is useful for casting rays in the form of (origin, normal) for object intersection or picking.
</description>
</method>
- <method name="set_cull_mask_bit">
+ <method name="set_cull_mask_value">
<return type="void" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="enable" type="bool" />
+ <argument index="0" name="layer_number" type="int" />
+ <argument index="1" name="value" type="bool" />
<description>
- Enables or disables the given [code]layer[/code] in the [member cull_mask].
+ Based on [code]value[/code], enables or disables the specified layer in the [member cull_mask], given a [code]layer_number[/code] between 1 and 20.
</description>
</method>
<method name="set_frustum">
diff --git a/doc/classes/ClippedCamera3D.xml b/doc/classes/ClippedCamera3D.xml
index 1a76412826..1a0d3499cd 100644
--- a/doc/classes/ClippedCamera3D.xml
+++ b/doc/classes/ClippedCamera3D.xml
@@ -35,12 +35,11 @@
Returns the distance the camera has been offset due to a collision.
</description>
</method>
- <method name="get_collision_mask_bit" qualifiers="const">
+ <method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns [code]true[/code] if the specified bit index is on.
- [b]Note:[/b] Bit indices range from 0-19.
+ Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="remove_exception">
@@ -57,13 +56,12 @@
Removes a collision exception with the specified [RID].
</description>
</method>
- <method name="set_collision_mask_bit">
+ <method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<argument index="1" name="value" type="bool" />
<description>
- Sets the specified bit index to the [code]value[/code].
- [b]Note:[/b] Bit indices range from 0-19.
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
</methods>
diff --git a/doc/classes/CollisionObject2D.xml b/doc/classes/CollisionObject2D.xml
index 6bb756ea2c..7129c72e7c 100644
--- a/doc/classes/CollisionObject2D.xml
+++ b/doc/classes/CollisionObject2D.xml
@@ -25,18 +25,18 @@
Creates a new shape owner for the given object. Returns [code]owner_id[/code] of the new owner for future reference.
</description>
</method>
- <method name="get_collision_layer_bit" qualifiers="const">
+ <method name="get_collision_layer_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified [code]bit[/code] of the [member collision_layer] is set.
+ Returns whether or not the specified layer of the [member collision_layer] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
- <method name="get_collision_mask_bit" qualifiers="const">
+ <method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified [code]bit[/code] of the [member collision_mask] is set.
+ Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="get_rid" qualifiers="const">
@@ -79,22 +79,20 @@
Removes the given shape owner.
</description>
</method>
- <method name="set_collision_layer_bit">
+ <method name="set_collision_layer_value">
<return type="void" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<argument index="1" name="value" type="bool" />
<description>
- If [code]value[/code] is [code]true[/code], sets the specified [code]bit[/code] in the the [member collision_layer].
- If [code]value[/code] is [code]false[/code], clears the specified [code]bit[/code] in the the [member collision_layer].
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_layer], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
- <method name="set_collision_mask_bit">
+ <method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<argument index="1" name="value" type="bool" />
<description>
- If [code]value[/code] is [code]true[/code], sets the specified [code]bit[/code] in the the [member collision_mask].
- If [code]value[/code] is [code]false[/code], clears the specified [code]bit[/code] in the the [member collision_mask].
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="shape_find_owner" qualifiers="const">
diff --git a/doc/classes/CollisionObject3D.xml b/doc/classes/CollisionObject3D.xml
index 0210f6297f..f9151a2c2f 100644
--- a/doc/classes/CollisionObject3D.xml
+++ b/doc/classes/CollisionObject3D.xml
@@ -27,18 +27,18 @@
Creates a new shape owner for the given object. Returns [code]owner_id[/code] of the new owner for future reference.
</description>
</method>
- <method name="get_collision_layer_bit" qualifiers="const">
+ <method name="get_collision_layer_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified [code]bit[/code] of the [member collision_layer] is set.
+ Returns whether or not the specified layer of the [member collision_layer] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
- <method name="get_collision_mask_bit" qualifiers="const">
+ <method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified [code]bit[/code] of the [member collision_mask] is set.
+ Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="get_rid" qualifiers="const">
@@ -67,22 +67,20 @@
Removes the given shape owner.
</description>
</method>
- <method name="set_collision_layer_bit">
+ <method name="set_collision_layer_value">
<return type="void" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<argument index="1" name="value" type="bool" />
<description>
- If [code]value[/code] is [code]true[/code], sets the specified [code]bit[/code] in the the [member collision_layer].
- If [code]value[/code] is [code]false[/code], clears the specified [code]bit[/code] in the the [member collision_layer].
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_layer], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
- <method name="set_collision_mask_bit">
+ <method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<argument index="1" name="value" type="bool" />
<description>
- If [code]value[/code] is [code]true[/code], sets the specified [code]bit[/code] in the the [member collision_mask].
- If [code]value[/code] is [code]false[/code], clears the specified [code]bit[/code] in the the [member collision_mask].
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="shape_find_owner" qualifiers="const">
diff --git a/doc/classes/NavigationMesh.xml b/doc/classes/NavigationMesh.xml
index 89a394ef6c..e476949360 100644
--- a/doc/classes/NavigationMesh.xml
+++ b/doc/classes/NavigationMesh.xml
@@ -30,11 +30,11 @@
Initializes the navigation mesh by setting the vertices and indices according to a [Mesh].
</description>
</method>
- <method name="get_collision_mask_bit" qualifiers="const">
+ <method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns whether the specified [code]bit[/code] of the [member geometry/collision_mask] is set.
+ Returns whether or not the specified layer of the [member geometry/collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="get_polygon">
@@ -56,13 +56,12 @@
Returns a [PackedVector3Array] containing all the vertices being used to create the polygons.
</description>
</method>
- <method name="set_collision_mask_bit">
+ <method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<argument index="1" name="value" type="bool" />
<description>
- If [code]value[/code] is [code]true[/code], sets the specified [code]bit[/code] in the [member geometry/collision_mask].
- If [code]value[/code] is [code]false[/code], clears the specified [code]bit[/code] in the [member geometry/collision_mask].
+ Based on [code]value[/code], enables or disables the specified layer in the [member geometry/collision_mask], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="set_vertices">
diff --git a/doc/classes/OccluderInstance3D.xml b/doc/classes/OccluderInstance3D.xml
index 150bfd9257..cc4bddc229 100644
--- a/doc/classes/OccluderInstance3D.xml
+++ b/doc/classes/OccluderInstance3D.xml
@@ -7,17 +7,19 @@
<tutorials>
</tutorials>
<methods>
- <method name="get_bake_mask_bit" qualifiers="const">
+ <method name="get_bake_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
+ Returns whether or not the specified layer of the [member bake_mask] is enabled, given a [code]layer_number[/code] between 1 and 20.
</description>
</method>
- <method name="set_bake_mask_bit">
+ <method name="set_bake_mask_value">
<return type="void" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="enabled" type="bool" />
+ <argument index="0" name="layer_number" type="int" />
+ <argument index="1" name="value" type="bool" />
<description>
+ Based on [code]value[/code], enables or disables the specified layer in the [member bake_mask], given a [code]layer_number[/code] between 1 and 20.
</description>
</method>
</methods>
diff --git a/doc/classes/PhysicsDirectSpaceState2D.xml b/doc/classes/PhysicsDirectSpaceState2D.xml
index 2a32bc1cb9..e84b3e0e49 100644
--- a/doc/classes/PhysicsDirectSpaceState2D.xml
+++ b/doc/classes/PhysicsDirectSpaceState2D.xml
@@ -47,7 +47,7 @@
<argument index="0" name="point" type="Vector2" />
<argument index="1" name="max_results" type="int" default="32" />
<argument index="2" name="exclude" type="Array" default="[]" />
- <argument index="3" name="collision_layer" type="int" default="2147483647" />
+ <argument index="3" name="collision_mask" type="int" default="2147483647" />
<argument index="4" name="collide_with_bodies" type="bool" default="true" />
<argument index="5" name="collide_with_areas" type="bool" default="false" />
<description>
@@ -57,7 +57,7 @@
[code]metadata[/code]: The intersecting shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method PhysicsServer2D.shape_set_data].
[code]rid[/code]: The intersecting object's [RID].
[code]shape[/code]: The shape index of the colliding shape.
- Additionally, the method can take an [code]exclude[/code] array of objects or [RID]s that are to be excluded from collisions, a [code]collision_mask[/code] bitmask representing the physics layers to check in, or booleans to determine if the ray should collide with [PhysicsBody2D]s or [Area2D]s, respectively.
+ Additionally, the method can take an [code]exclude[/code] array of objects or [RID]s that are to be excluded from collisions, a [code]collision_mask[/code] bitmask representing the physics layers to detect, or booleans to determine if the ray should collide with [PhysicsBody2D]s or [Area2D]s, respectively.
[b]Note:[/b] [ConcavePolygonShape2D]s and [CollisionPolygon2D]s in [code]Segments[/code] build mode are not solid shapes. Therefore, they will not be detected.
</description>
</method>
@@ -67,7 +67,7 @@
<argument index="1" name="canvas_instance_id" type="int" />
<argument index="2" name="max_results" type="int" default="32" />
<argument index="3" name="exclude" type="Array" default="[]" />
- <argument index="4" name="collision_layer" type="int" default="2147483647" />
+ <argument index="4" name="collision_mask" type="int" default="2147483647" />
<argument index="5" name="collide_with_bodies" type="bool" default="true" />
<argument index="6" name="collide_with_areas" type="bool" default="false" />
<description>
@@ -78,7 +78,7 @@
<argument index="0" name="from" type="Vector2" />
<argument index="1" name="to" type="Vector2" />
<argument index="2" name="exclude" type="Array" default="[]" />
- <argument index="3" name="collision_layer" type="int" default="2147483647" />
+ <argument index="3" name="collision_mask" type="int" default="2147483647" />
<argument index="4" name="collide_with_bodies" type="bool" default="true" />
<argument index="5" name="collide_with_areas" type="bool" default="false" />
<description>
@@ -91,7 +91,7 @@
[code]rid[/code]: The intersecting object's [RID].
[code]shape[/code]: The shape index of the colliding shape.
If the ray did not intersect anything, then an empty dictionary is returned instead.
- Additionally, the method can take an [code]exclude[/code] array of objects or [RID]s that are to be excluded from collisions, a [code]collision_mask[/code] bitmask representing the physics layers to check in, or booleans to determine if the ray should collide with [PhysicsBody2D]s or [Area2D]s, respectively.
+ Additionally, the method can take an [code]exclude[/code] array of objects or [RID]s that are to be excluded from collisions, a [code]collision_mask[/code] bitmask representing the physics layers to detect, or booleans to determine if the ray should collide with [PhysicsBody2D]s or [Area2D]s, respectively.
</description>
</method>
<method name="intersect_shape">
diff --git a/doc/classes/PhysicsDirectSpaceState3D.xml b/doc/classes/PhysicsDirectSpaceState3D.xml
index a6bfc8754d..13db50a2c7 100644
--- a/doc/classes/PhysicsDirectSpaceState3D.xml
+++ b/doc/classes/PhysicsDirectSpaceState3D.xml
@@ -59,7 +59,7 @@
[code]rid[/code]: The intersecting object's [RID].
[code]shape[/code]: The shape index of the colliding shape.
If the ray did not intersect anything, then an empty dictionary is returned instead.
- Additionally, the method can take an [code]exclude[/code] array of objects or [RID]s that are to be excluded from collisions, a [code]collision_mask[/code] bitmask representing the physics layers to check in, or booleans to determine if the ray should collide with [PhysicsBody3D]s or [Area3D]s, respectively.
+ Additionally, the method can take an [code]exclude[/code] array of objects or [RID]s that are to be excluded from collisions, a [code]collision_mask[/code] bitmask representing the physics layers to detect, or booleans to determine if the ray should collide with [PhysicsBody3D]s or [Area3D]s, respectively.
</description>
</method>
<method name="intersect_shape">
diff --git a/doc/classes/PhysicsShapeQueryParameters2D.xml b/doc/classes/PhysicsShapeQueryParameters2D.xml
index 229a40638a..8b006c68e7 100644
--- a/doc/classes/PhysicsShapeQueryParameters2D.xml
+++ b/doc/classes/PhysicsShapeQueryParameters2D.xml
@@ -17,8 +17,8 @@
<member name="collide_with_bodies" type="bool" setter="set_collide_with_bodies" getter="is_collide_with_bodies_enabled" default="true">
If [code]true[/code], the query will take [PhysicsBody2D]s into account.
</member>
- <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="2147483647">
- The physics layer(s) the query will take into account (as a bitmask). See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
+ <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="2147483647">
+ The physics layers the query will detect (as a bitmask). By default, all collision layers are detected. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="exclude" type="Array" setter="set_exclude" getter="get_exclude" default="[]">
The list of objects or object [RID]s that will be excluded from collisions.
diff --git a/doc/classes/PhysicsShapeQueryParameters3D.xml b/doc/classes/PhysicsShapeQueryParameters3D.xml
index 9ca892acb3..de9b623591 100644
--- a/doc/classes/PhysicsShapeQueryParameters3D.xml
+++ b/doc/classes/PhysicsShapeQueryParameters3D.xml
@@ -18,7 +18,7 @@
If [code]true[/code], the query will take [PhysicsBody3D]s into account.
</member>
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="2147483647">
- The physics layer(s) the query will take into account (as a bitmask). See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
+ The physics layers the query will detect (as a bitmask). By default, all collision layers are detected. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="exclude" type="Array" setter="set_exclude" getter="get_exclude" default="[]">
The list of objects or object [RID]s that will be excluded from collisions.
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 24caceec1c..f769ace836 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -777,9 +777,6 @@
<member name="internationalization/rendering/text_driver" type="String" setter="" getter="" default="&quot;&quot;">
Specifies the [TextServer] to use. If left empty, the default will be used.
</member>
- <member name="layer_names/2d_navigation/layer_0" type="String" setter="" getter="" default="&quot;&quot;">
- Optional name for the 2D navigation layer 0. If left empty, the layer will display as "Layer 0".
- </member>
<member name="layer_names/2d_navigation/layer_1" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 2D navigation layer 1. If left empty, the layer will display as "Layer 1".
</member>
@@ -855,6 +852,9 @@
<member name="layer_names/2d_navigation/layer_31" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 2D navigation layer 31. If left empty, the layer will display as "Layer 31".
</member>
+ <member name="layer_names/2d_navigation/layer_32" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 32. If left empty, the layer will display as "Layer 32".
+ </member>
<member name="layer_names/2d_navigation/layer_4" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 2D navigation layer 4. If left empty, the layer will display as "Layer 4".
</member>
@@ -873,9 +873,6 @@
<member name="layer_names/2d_navigation/layer_9" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 2D navigation layer 9. If left empty, the layer will display as "Layer 9".
</member>
- <member name="layer_names/2d_physics/layer_0" type="String" setter="" getter="" default="&quot;&quot;">
- Optional name for the 2D physics layer 0. If left empty, the layer will display as "Layer 0".
- </member>
<member name="layer_names/2d_physics/layer_1" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 2D physics layer 1. If left empty, the layer will display as "Layer 1".
</member>
@@ -951,6 +948,9 @@
<member name="layer_names/2d_physics/layer_31" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 2D physics layer 31. If left empty, the layer will display as "Layer 31".
</member>
+ <member name="layer_names/2d_physics/layer_32" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D physics layer 32. If left empty, the layer will display as "Layer 32".
+ </member>
<member name="layer_names/2d_physics/layer_4" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 2D physics layer 4. If left empty, the layer will display as "Layer 4".
</member>
@@ -969,9 +969,6 @@
<member name="layer_names/2d_physics/layer_9" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 2D physics layer 9. If left empty, the layer will display as "Layer 9".
</member>
- <member name="layer_names/2d_render/layer_0" type="String" setter="" getter="" default="&quot;&quot;">
- Optional name for the 2D render layer 0. If left empty, the layer will display as "Layer 0".
- </member>
<member name="layer_names/2d_render/layer_1" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 2D render layer 1. If left empty, the layer will display as "Layer 1".
</member>
@@ -1008,6 +1005,9 @@
<member name="layer_names/2d_render/layer_2" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 2D render layer 2. If left empty, the layer will display as "Layer 2".
</member>
+ <member name="layer_names/2d_render/layer_20" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D render layer 20. If left empty, the layer will display as "Layer 20".
+ </member>
<member name="layer_names/2d_render/layer_3" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 2D render layer 3. If left empty, the layer will display as "Layer 3".
</member>
@@ -1029,9 +1029,6 @@
<member name="layer_names/2d_render/layer_9" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 2D render layer 9. If left empty, the layer will display as "Layer 9".
</member>
- <member name="layer_names/3d_navigation/layer_0" type="String" setter="" getter="" default="&quot;&quot;">
- Optional name for the 3D navigation layer 0. If left empty, the layer will display as "Layer 0".
- </member>
<member name="layer_names/3d_navigation/layer_1" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 3D navigation layer 1. If left empty, the layer will display as "Layer 1".
</member>
@@ -1107,6 +1104,9 @@
<member name="layer_names/3d_navigation/layer_31" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 3D navigation layer 31. If left empty, the layer will display as "Layer 31".
</member>
+ <member name="layer_names/3d_navigation/layer_32" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 32. If left empty, the layer will display as "Layer 32".
+ </member>
<member name="layer_names/3d_navigation/layer_4" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 3D navigation layer 4. If left empty, the layer will display as "Layer 4".
</member>
@@ -1125,9 +1125,6 @@
<member name="layer_names/3d_navigation/layer_9" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 3D navigation layer 9. If left empty, the layer will display as "Layer 9".
</member>
- <member name="layer_names/3d_physics/layer_0" type="String" setter="" getter="" default="&quot;&quot;">
- Optional name for the 3D physics layer 0. If left empty, the layer will display as "Layer 0".
- </member>
<member name="layer_names/3d_physics/layer_1" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 3D physics layer 1. If left empty, the layer will display as "Layer 1".
</member>
@@ -1203,6 +1200,9 @@
<member name="layer_names/3d_physics/layer_31" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 3D physics layer 31. If left empty, the layer will display as "Layer 31".
</member>
+ <member name="layer_names/3d_physics/layer_32" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D physics layer 32. If left empty, the layer will display as "Layer 32".
+ </member>
<member name="layer_names/3d_physics/layer_4" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 3D physics layer 4. If left empty, the layer will display as "Layer 4".
</member>
@@ -1221,9 +1221,6 @@
<member name="layer_names/3d_physics/layer_9" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 3D physics layer 9. If left empty, the layer will display as "Layer 9".
</member>
- <member name="layer_names/3d_render/layer_0" type="String" setter="" getter="" default="&quot;&quot;">
- Optional name for the 2D render layer 0. If left empty, the layer will display as "Layer 0".
- </member>
<member name="layer_names/3d_render/layer_1" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 3D render layer 1. If left empty, the layer will display as "Layer 1".
</member>
@@ -1260,6 +1257,9 @@
<member name="layer_names/3d_render/layer_2" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 3D render layer 2. If left empty, the layer will display as "Layer 2".
</member>
+ <member name="layer_names/3d_render/layer_20" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D render layer 20. If left empty, the layer will display as "Layer 20".
+ </member>
<member name="layer_names/3d_render/layer_3" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 3D render layer 3. If left empty, the layer will display as "Layer 3".
</member>
diff --git a/doc/classes/RayCast2D.xml b/doc/classes/RayCast2D.xml
index d8a5fc8508..1d32db8078 100644
--- a/doc/classes/RayCast2D.xml
+++ b/doc/classes/RayCast2D.xml
@@ -53,11 +53,11 @@
Returns the shape ID of the first object that the ray intersects, or [code]0[/code] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]).
</description>
</method>
- <method name="get_collision_mask_bit" qualifiers="const">
+ <method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns an individual bit on the collision mask.
+ Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="get_collision_normal" qualifiers="const">
@@ -93,12 +93,12 @@
Removes a collision exception so the ray does report collisions with the specified [RID].
</description>
</method>
- <method name="set_collision_mask_bit">
+ <method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<argument index="1" name="value" type="bool" />
<description>
- Sets or clears individual bits on the collision mask. This makes selecting the areas scanned easier.
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
</methods>
diff --git a/doc/classes/RayCast3D.xml b/doc/classes/RayCast3D.xml
index 4e8eb960db..8628ab7dac 100644
--- a/doc/classes/RayCast3D.xml
+++ b/doc/classes/RayCast3D.xml
@@ -55,12 +55,11 @@
Returns the shape ID of the first object that the ray intersects, or [code]0[/code] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]).
</description>
</method>
- <method name="get_collision_mask_bit" qualifiers="const">
+ <method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns [code]true[/code] if the bit index passed is turned on.
- [b]Note:[/b] Bit indices range from 0-19.
+ Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="get_collision_normal" qualifiers="const">
@@ -96,13 +95,12 @@
Removes a collision exception so the ray does report collisions with the specified [RID].
</description>
</method>
- <method name="set_collision_mask_bit">
+ <method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<argument index="1" name="value" type="bool" />
<description>
- Sets the bit index passed to the [code]value[/code] passed.
- [b]Note:[/b] Bit indexes range from 0-19.
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
</methods>
diff --git a/doc/classes/SoftBody3D.xml b/doc/classes/SoftBody3D.xml
index 53bd7e67bf..ddfc14ceac 100644
--- a/doc/classes/SoftBody3D.xml
+++ b/doc/classes/SoftBody3D.xml
@@ -23,18 +23,18 @@
Returns an array of nodes that were added as collision exceptions for this body.
</description>
</method>
- <method name="get_collision_layer_bit" qualifiers="const">
+ <method name="get_collision_layer_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns an individual bit on the collision mask.
+ Returns whether or not the specified layer of the [member collision_layer] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
- <method name="get_collision_mask_bit" qualifiers="const">
+ <method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns an individual bit on the collision mask.
+ Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="get_physics_rid" qualifiers="const">
@@ -49,20 +49,20 @@
Removes a body from the list of bodies that this body can't collide with.
</description>
</method>
- <method name="set_collision_layer_bit">
+ <method name="set_collision_layer_value">
<return type="void" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<argument index="1" name="value" type="bool" />
<description>
- Sets individual bits on the layer mask. Use this if you only need to change one layer's value.
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_layer], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
- <method name="set_collision_mask_bit">
+ <method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<argument index="1" name="value" type="bool" />
<description>
- Sets individual bits on the collision mask. Use this if you only need to change one layer's value.
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
</methods>
diff --git a/doc/classes/VisualInstance3D.xml b/doc/classes/VisualInstance3D.xml
index 2d9c266f3c..f949fbe7c0 100644
--- a/doc/classes/VisualInstance3D.xml
+++ b/doc/classes/VisualInstance3D.xml
@@ -27,11 +27,11 @@
Returns the RID of this instance. This RID is the same as the RID returned by [method RenderingServer.instance_create]. This RID is needed if you want to call [RenderingServer] functions directly on this [VisualInstance3D].
</description>
</method>
- <method name="get_layer_mask_bit" qualifiers="const">
+ <method name="get_layer_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns [code]true[/code] when the specified layer is enabled in [member layers] and [code]false[/code] otherwise.
+ Returns whether or not the specified layer of the [member layers] is enabled, given a [code]layer_number[/code] between 1 and 20.
</description>
</method>
<method name="get_transformed_aabb" qualifiers="const">
@@ -48,12 +48,12 @@
Sets the resource that is instantiated by this [VisualInstance3D], which changes how the engine handles the [VisualInstance3D] under the hood. Equivalent to [method RenderingServer.instance_set_base].
</description>
</method>
- <method name="set_layer_mask_bit">
+ <method name="set_layer_mask_value">
<return type="void" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="enabled" type="bool" />
+ <argument index="0" name="layer_number" type="int" />
+ <argument index="1" name="value" type="bool" />
<description>
- Enables a particular layer in [member layers].
+ Based on [code]value[/code], enables or disables the specified layer in the [member layers], given a [code]layer_number[/code] between 1 and 20.
</description>
</method>
</methods>
diff --git a/editor/SCsub b/editor/SCsub
index a976c4ed12..d149cc6273 100644
--- a/editor/SCsub
+++ b/editor/SCsub
@@ -30,7 +30,10 @@ if env["tools"]:
reg_exporters_inc = '#include "register_exporters.h"\n'
reg_exporters = "void register_exporters() {\n"
for e in env.platform_exporters:
- env.add_source_files(env.editor_sources, "#platform/" + e + "/export/export.cpp")
+ # Glob all .cpp files in export folder
+ files = Glob("#platform/" + e + "/export/" + "*.cpp")
+ env.add_source_files(env.editor_sources, files)
+
reg_exporters += "\tregister_" + e + "_exporter();\n"
reg_exporters_inc += '#include "platform/' + e + '/export/export.h"\n'
reg_exporters += "}\n"
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index ecc11998ac..99619cfc40 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -837,7 +837,7 @@ public:
Vector2 offset;
offset.y = rect2.size.y * 0.75;
- draw_string(font, rect2.position + offset, itos(layer_index), HALIGN_CENTER, rect2.size.x, -1, on ? text_color_on : text_color);
+ draw_string(font, rect2.position + offset, itos(layer_index + 1), HALIGN_CENTER, rect2.size.x, -1, on ? text_color_on : text_color);
ofs.x += bsize + 1;
@@ -993,12 +993,12 @@ void EditorPropertyLayers::setup(LayerType p_layer_type) {
for (int i = 0; i < layer_count; i++) {
String name;
- if (ProjectSettings::get_singleton()->has_setting(basename + vformat("/layer_%d", i))) {
- name = ProjectSettings::get_singleton()->get(basename + vformat("/layer_%d", i));
+ if (ProjectSettings::get_singleton()->has_setting(basename + vformat("/layer_%d", i + 1))) {
+ name = ProjectSettings::get_singleton()->get(basename + vformat("/layer_%d", i + 1));
}
if (name == "") {
- name = vformat(TTR("Layer %d"), i);
+ name = vformat(TTR("Layer %d"), i + 1);
}
names.push_back(name);
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 37a04a1844..d6ac238414 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -592,6 +592,14 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
}
if (vsnode->is_use_prop_slots()) {
+ String error = vsnode->get_warning(visual_shader->get_mode(), p_type);
+ if (error != String()) {
+ Label *error_label = memnew(Label);
+ error_label->add_theme_color_override("font_color", VisualShaderEditor::get_singleton()->get_theme_color(SNAME("error_color"), SNAME("Editor")));
+ error_label->set_text(error);
+ node->add_child(error_label);
+ }
+
return;
}
custom_editor = nullptr;
@@ -2029,6 +2037,8 @@ void VisualShaderEditor::_uniform_line_edit_changed(const String &p_text, int p_
undo_redo->add_undo_method(node.ptr(), "set_uniform_name", node->get_uniform_name());
undo_redo->add_do_method(graph_plugin.ptr(), "set_uniform_name", type, p_node_id, validated_name);
undo_redo->add_undo_method(graph_plugin.ptr(), "set_uniform_name", type, p_node_id, node->get_uniform_name());
+ undo_redo->add_do_method(graph_plugin.ptr(), "update_node_deferred", type, p_node_id);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "update_node_deferred", type, p_node_id);
undo_redo->add_do_method(this, "_update_uniforms", true);
undo_redo->add_undo_method(this, "_update_uniforms", true);
diff --git a/editor/translations/af.po b/editor/translations/af.po
index 18ad28af62..70e016ee65 100644
--- a/editor/translations/af.po
+++ b/editor/translations/af.po
@@ -353,6 +353,7 @@ msgstr "Verander Anim Herspeel"
msgid "Remove Anim Track"
msgstr "Verwyder Anim Baan"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Skep NUWE baan vir %s en voeg sleutel by?"
@@ -377,10 +378,27 @@ msgstr "Skep"
msgid "Anim Insert"
msgstr "Anim Voeg In"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animasie Zoem."
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Eienskappe"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Anim Skep & Voeg by"
@@ -975,7 +993,7 @@ msgstr "Skep Nuwe"
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2363,6 +2381,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3157,10 +3186,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
#, fuzzy
msgid "Update Continuously"
msgstr "Deurlopend"
@@ -3782,6 +3807,15 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Open 'n Lêer"
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8694,6 +8728,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Hernoem AutoLaai"
@@ -8724,6 +8764,12 @@ msgid "Remove All StyleBox Items"
msgstr "Hernoem AutoLaai"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Gunstelinge:"
@@ -12290,6 +12336,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13942,6 +13996,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/ar.po b/editor/translations/ar.po
index 9093792ef8..eb11aa27b6 100644
--- a/editor/translations/ar.po
+++ b/editor/translations/ar.po
@@ -389,6 +389,7 @@ msgstr "تغيير وضع عقدة الحركة"
msgid "Remove Anim Track"
msgstr "حذ٠مسار التحريك"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "أنشئ مسار جديد Ù„ %s Ùˆ إدخال Ù…ÙØªØ§Ø­ØŸ"
@@ -413,10 +414,28 @@ msgstr "أنشئ"
msgid "Anim Insert"
msgstr "إدخال حركة"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "لا يمكن ÙØªØ­ '%s'."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "رسوم متحركة"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "اللأعب المتحرك لا يستطيع تحريك Ù†ÙØ³Ù‡ ,Ùقط اللاعبين الآخرين."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "لا خاصية '%s' موجودة."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "أنشي حركة وأدخلها"
@@ -988,7 +1007,7 @@ msgstr "إنشاء %s جديد"
msgid "No results for \"%s\"."
msgstr "لا نتائج من أجل \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2333,6 +2352,17 @@ msgid "New Window"
msgstr "Ù†Ø§ÙØ°Ø© جديدة"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "قم بالتدوير أثناء إعادة رسم Ù†Ø§ÙØ°Ø© المحرّر."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "لا يمكن Ø­ÙØ¸ الموارد المستوردة."
@@ -3187,10 +3217,6 @@ msgid "Save & Restart"
msgstr "Ø­ÙØ¸ Ùˆ إعادة تشغيل"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "قم بالتدوير أثناء إعادة رسم Ù†Ø§ÙØ°Ø© المحرّر."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "تحديث متواصل"
@@ -3851,6 +3877,16 @@ msgid "Download from:"
msgstr "خطأ ÙÙŠ التحميل"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "تشغيل ÙÙŠ Ø§Ù„Ù…ØªØµÙØ­"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "خطأ ÙÙŠ نسخ"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8708,6 +8744,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "إزالة جميع العناصر"
@@ -8738,6 +8780,12 @@ msgid "Remove All StyleBox Items"
msgstr "إزالة جميع العناصر"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Ø¥Ø¶Ø§ÙØ© بنود للصنÙ"
@@ -12401,6 +12449,16 @@ msgstr "تعديل Ø§Ø±ØªÙØ§Ø¹ الشكل الأسطواني"
msgid "Change Ray Shape Length"
msgstr "تعديل طول الشكل الشعاعي"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "حدد موقع نقطة الإنحناء"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "حدد موقع نقطة الإنحناء"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "تغيير نص٠قطر الاسطوانة"
@@ -14183,6 +14241,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr "سيتم تجاهل هذا الجسم حتى تضع تحدد له مجسمًا."
@@ -15136,9 +15230,6 @@ msgstr "لا يمكن تعديل الثوابت."
#~ msgid "I see..."
#~ msgstr "أنا أري..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "لا يمكن ÙØªØ­ '%s'."
-
#~ msgid "Ugh"
#~ msgstr "آخخ"
diff --git a/editor/translations/az.po b/editor/translations/az.po
index 4ac0ae6469..6c07f98d38 100644
--- a/editor/translations/az.po
+++ b/editor/translations/az.po
@@ -358,6 +358,7 @@ msgstr "Animasya Döngü Rejimini Dəyiş"
msgid "Remove Anim Track"
msgstr "Animasya İzini Sil"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "%s üçün YENİ iz yaradılsın və açar daxil edilsin?"
@@ -383,11 +384,27 @@ msgstr "Yarat"
msgid "Anim Insert"
msgstr "Animasiya Daxil Et"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animasiyanı Təmizləmə"
+
#: editor/animation_track_editor.cpp
#, fuzzy
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "AnimationPlayer özünü canlandıra bilməz, yalnız digər playerlər."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Animasiya yaradın və əlavə edin"
@@ -975,7 +992,7 @@ msgstr "Yeni %s yarat"
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2286,6 +2303,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3065,10 +3093,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr ""
@@ -3676,6 +3700,14 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+msgid "Open in Web Browser"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8367,6 +8399,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Color Items"
msgstr ""
@@ -8391,6 +8429,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
msgstr ""
@@ -11802,6 +11846,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13399,6 +13451,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/bg.po b/editor/translations/bg.po
index b0bf9a4d6c..3045c7b781 100644
--- a/editor/translations/bg.po
+++ b/editor/translations/bg.po
@@ -350,6 +350,7 @@ msgstr "ПромÑна на режима на повтарÑне на анима
msgid "Remove Anim Track"
msgstr ""
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Създаване на ÐОВРпътечка за %s и вмъкване на ключ?"
@@ -374,10 +375,28 @@ msgstr "Създаване"
msgid "Anim Insert"
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "Избиране на вÑичко"
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "ÐнимациÑ"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "СвойÑтво"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr ""
@@ -934,7 +953,7 @@ msgstr "Създаване на %s"
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2244,6 +2263,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3050,10 +3080,6 @@ msgid "Save & Restart"
msgstr "Запазване и реÑтартиране"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr ""
@@ -3677,6 +3703,16 @@ msgid "Download from:"
msgstr "Грешка при ÑвалÑнето"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "ОтварÑне във Ñ„Ð°Ð¹Ð»Ð¾Ð²Ð¸Ñ Ð¼ÐµÐ½Ð¸Ð´Ð¶ÑŠÑ€"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Копиране на грешката"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8462,6 +8498,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Премахване на вÑички елементи"
@@ -8492,6 +8534,12 @@ msgid "Remove All StyleBox Items"
msgstr "Премахване на вÑички елементи"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "ДобавÑне на вÑички елементи"
@@ -11965,6 +12013,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13637,6 +13693,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr "Това Ñ‚Ñло ще бъде игнорирано, докато не зададете полигонна мрежа."
@@ -14016,10 +14108,6 @@ msgstr "КонÑтантите не могат да бъдат промененÐ
#~ msgid "Select Mode (Q)"
#~ msgstr "Режим на Селектиране (Q)"
-#, fuzzy
-#~ msgid "Snap Mode (%s)"
-#~ msgstr "Избиране на вÑичко"
-
#~ msgid "Project List"
#~ msgstr "СпиÑък Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ð¸"
diff --git a/editor/translations/bn.po b/editor/translations/bn.po
index 384ea57f6c..6cd9e3a81c 100644
--- a/editor/translations/bn.po
+++ b/editor/translations/bn.po
@@ -345,6 +345,7 @@ msgstr "অà§à¦¯à¦¾à¦¨à¦¿à¦®à§‡à¦¶à¦¨à§‡à¦° লà§à¦ª মোড পরিবর
msgid "Remove Anim Track"
msgstr "অà§à¦¯à¦¾à¦¨à¦¿à¦®à§‡à¦¶à¦¨ (Anim) টà§à¦°à§à¦¯à¦¾à¦• রিমà§à¦­ করà§à¦¨"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "%s à¦à¦° জনà§à¦¯ নতà§à¦¨ টà§à¦°à§à¦¯à¦¾à¦•/পথ তৈরি করতে à¦à¦¬à¦‚ চাবি পà§à¦°à¦¬à§‡à¦¶ করাতে চান?"
@@ -369,10 +370,28 @@ msgstr "তৈরি করà§à¦¨"
msgid "Anim Insert"
msgstr "অà§à¦¯à¦¾à¦¨à¦¿à¦®à§‡à¦¶à¦¨à§‡ (Anim) অনà§à¦¤à¦°à§à¦­à§à¦•à§à¦¤ করà§à¦¨"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "'..' তে পরিচালনা করা সমà§à¦­à¦¬ নয়"
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "অà§à¦¯à¦¾à¦¨à¦¿à¦®à§‡à¦¶à¦¨"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "অà§à¦¯à¦¾à¦¨à¦¿à¦®à§‡à¦¶à¦¨à¦ªà§à¦²à§‡à¦¯à¦¼à¦¾à¦° নিজেই অà§à¦¯à¦¾à¦¨à¦¿à¦®à§‡à¦Ÿ করতে পারে না, কেবল অনà§à¦¯ পà§à¦²à§‡à§Ÿà¦¾à¦°à¥¤"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "পà§à¦°à¦ªà¦¾à¦°à§à¦Ÿà¦¿:"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "অà§à¦¯à¦¾à¦¨à¦¿à¦®à§‡à¦¶à¦¨ (Anim) তৈরি à¦à¦¬à¦‚ যোগ করà§à¦¨"
@@ -969,7 +988,7 @@ msgstr "নতà§à¦¨ তৈরি করà§à¦¨"
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2392,6 +2411,18 @@ msgid "New Window"
msgstr "উইনà§à¦¡à§‹"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+#, fuzzy
+msgid "Spins when the editor window redraws."
+msgstr "à¦à¦¡à¦¿à¦Ÿà¦°à§‡à¦° পà§à¦¨-অঙà§à¦•নে à¦à¦Ÿà¦¿ ঘূরà§à¦£à¦¨ করে!"
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3286,11 +3317,6 @@ msgstr "সংরকà§à¦·à¦£ à¦à¦¬à¦‚ পà§à¦¨-ইমà§à¦ªà§‹à¦°à§à¦Ÿ কà¦
#: editor/editor_node.cpp
#, fuzzy
-msgid "Spins when the editor window redraws."
-msgstr "à¦à¦¡à¦¿à¦Ÿà¦°à§‡à¦° পà§à¦¨-অঙà§à¦•নে à¦à¦Ÿà¦¿ ঘূরà§à¦£à¦¨ করে!"
-
-#: editor/editor_node.cpp
-#, fuzzy
msgid "Update Continuously"
msgstr "অবিচà§à¦›à¦¿à¦¨à§à¦¨/নিরবচà§à¦›à¦¿à¦¨à§à¦¨"
@@ -3979,6 +4005,16 @@ msgid "Download from:"
msgstr "নীচে"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "বà§à¦°à¦¾à¦‰à¦¸"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "ভà§à¦²/সমসà§à¦¯à¦¾-সমূহ লোড করà§à¦¨"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -9179,6 +9215,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "কà§à¦²à¦¾à¦¸à§‡à¦° আইটেম অপসারণ করà§à¦¨"
@@ -9209,6 +9251,12 @@ msgid "Remove All StyleBox Items"
msgstr "কà§à¦²à¦¾à¦¸à§‡à¦° আইটেম অপসারণ করà§à¦¨"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "কà§à¦²à¦¾à¦¸à§‡à¦° আইটেম যোগ করà§à¦¨"
@@ -13015,6 +13063,16 @@ msgstr "Capsule Shape à¦à¦° উচà§à¦šà¦¤à¦¾ পরিবরà§à¦¤à¦¨ করà
msgid "Change Ray Shape Length"
msgstr "Ray Shape à¦à¦° দৈরà§à¦˜à§à¦¯ পরিবরà§à¦¤à¦¨ করà§à¦¨"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "বকà§à¦°à¦°à§‡à¦–ার বিনà§à¦¦à§à¦° সà§à¦¥à¦¾à¦¨ নিরà§à¦§à¦¾à¦°à¦£ করà§à¦¨"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "বকà§à¦°à¦°à§‡à¦–ার বিনà§à¦¦à§à¦° সà§à¦¥à¦¾à¦¨ নিরà§à¦§à¦¾à¦°à¦£ করà§à¦¨"
+
#: modules/csg/csg_gizmos.cpp
#, fuzzy
msgid "Change Cylinder Radius"
@@ -14801,6 +14859,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
@@ -16018,10 +16112,6 @@ msgstr ""
#~ msgid "I see..."
#~ msgstr "বà§à¦à¦²à¦¾à¦®..."
-#, fuzzy
-#~ msgid "Can't open '%s'."
-#~ msgstr "'..' তে পরিচালনা করা সমà§à¦­à¦¬ নয়"
-
#~ msgid "Ugh"
#~ msgstr "আহà§â€Œ"
diff --git a/editor/translations/br.po b/editor/translations/br.po
index 0f61544190..adee6daaba 100644
--- a/editor/translations/br.po
+++ b/editor/translations/br.po
@@ -340,6 +340,7 @@ msgstr "Cheñch Mod Treiñ ar Fiñvskeudenn"
msgid "Remove Anim Track"
msgstr "Dilemel ar Roudenn Fiñvskeudenn"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Krouiñ ur roudenn NEVEZ evit %s ha enlakaat an alc'hwez ?"
@@ -364,12 +365,28 @@ msgstr "Krouiñ"
msgid "Anim Insert"
msgstr "Enlakaat Fiñvskeudenn"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Tro Fiñvskeudenn"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
"AnimationPlayer n'hall ket en em lakaat de fiñval, met nemet al lennerezhioù "
"all."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Krouiñ & Enlakaat Fiñvskeudenn"
@@ -934,7 +951,7 @@ msgstr ""
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2226,6 +2243,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3005,10 +3033,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr ""
@@ -3614,6 +3638,14 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+msgid "Open in Web Browser"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8294,6 +8326,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Color Items"
msgstr ""
@@ -8318,6 +8356,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
msgstr ""
@@ -11725,6 +11769,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13320,6 +13372,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/ca.po b/editor/translations/ca.po
index ab96816ec0..347fea679b 100644
--- a/editor/translations/ca.po
+++ b/editor/translations/ca.po
@@ -350,6 +350,7 @@ msgstr "Canviar Mode de bucle d'Animació"
msgid "Remove Anim Track"
msgstr "Treu la Pista"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Voleu crear una NOVA pista per a %s i inserir-hi una clau?"
@@ -374,11 +375,29 @@ msgstr "Crea"
msgid "Anim Insert"
msgstr "Insereix una Animació"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "No es pot obrir '%s' ."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animació"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
"Un AnimationPlayer no pot animar-se a si mateix, només altres reproductors."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "No existeix cap propietat '%s'."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Crea i Insereix"
@@ -958,7 +977,7 @@ msgstr "Crea Nou %s"
msgid "No results for \"%s\"."
msgstr "No hi ha cap resultat per a «%s»."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2315,6 +2334,17 @@ msgid "New Window"
msgstr "Finestra nova"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Gira quan la finestra de l'editor es redibuixa."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Els recursos importats no es poden desar."
@@ -3190,10 +3220,6 @@ msgid "Save & Restart"
msgstr "Desa i Reinicia"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Gira quan la finestra de l'editor es redibuixa."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Actualitzar contínuament"
@@ -3868,6 +3894,16 @@ msgid "Download from:"
msgstr "Error en la Baixada"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Executa-ho en el Navegador"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Copia l'error"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8863,6 +8899,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Treu tots els Elements"
@@ -8893,6 +8935,12 @@ msgid "Remove All StyleBox Items"
msgstr "Treu tots els Elements"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Afegeix Elements de Classe"
@@ -12713,6 +12761,16 @@ msgstr "Modifica l'alçada de la Forma Caixa"
msgid "Change Ray Shape Length"
msgstr "Modifica la longitud de la Forma Raig"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Estableix la Posició del Punt de la Corba"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Estableix la Posició del Punt de la Corba"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "Canviar Radi del Cilindre"
@@ -14528,6 +14586,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
#, fuzzy
msgid "This body will be ignored until you set a mesh."
@@ -15820,9 +15914,6 @@ msgstr "Les constants no es poden modificar."
#~ msgid "I see..."
#~ msgstr "Vaja..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "No es pot obrir '%s' ."
-
#~ msgid "Ugh"
#~ msgstr "Uf..."
diff --git a/editor/translations/cs.po b/editor/translations/cs.po
index 579289300b..266614bf96 100644
--- a/editor/translations/cs.po
+++ b/editor/translations/cs.po
@@ -362,6 +362,7 @@ msgstr "ZmÄ›nit mód smyÄky animace"
msgid "Remove Anim Track"
msgstr "Odstranit stopu animace"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "VytvoÅ™it NOVOU stopu pro %s a vložit klíÄ?"
@@ -386,10 +387,28 @@ msgstr "Vytvořit"
msgid "Anim Insert"
msgstr "Animace: vložit"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "Nelze otevřít '%s'."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animace"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "AnimationPlayer nemůže animovat sám sebe, pouze ostatní pÅ™ehrávaÄe."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Vlastnost '%s' neexistuje."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Animace: Vytvořit a vložit"
@@ -966,7 +985,7 @@ msgstr "Vytvořit nový %s"
msgid "No results for \"%s\"."
msgstr "Žádné výsledky pro \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2313,6 +2332,17 @@ msgid "New Window"
msgstr "Nové okno"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "ToÄí se, když se okno editoru pÅ™ekresluje."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Nelze uložit importované zdroje."
@@ -3165,10 +3195,6 @@ msgid "Save & Restart"
msgstr "Uložit a restartovat"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "ToÄí se, když se okno editoru pÅ™ekresluje."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Aktualizovat průběžně"
@@ -3831,6 +3857,16 @@ msgid "Download from:"
msgstr "Chyba při stahování"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Spustit v prohlížeÄi"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Kopírovat chybu"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8679,6 +8715,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Odstranit všechny položky"
@@ -8709,6 +8751,12 @@ msgid "Remove All StyleBox Items"
msgstr "Odstranit všechny položky"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Přidat položky třídy"
@@ -12353,6 +12401,16 @@ msgstr "Změnit výšku Cylinder Shape"
msgid "Change Ray Shape Length"
msgstr "Změnit délku Ray Shape"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Nastavit pozici bodu křivky"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Nastavit pozici bodu křivky"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "Změnit poloměr Cylinder"
@@ -14097,6 +14155,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr "Toto tělo bude ignorováno dokud nenastavíte síť."
@@ -15196,9 +15290,6 @@ msgstr "Konstanty není možné upravovat."
#~ msgid "I see..."
#~ msgstr "Chápu..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "Nelze otevřít '%s'."
-
#~ msgid "Ugh"
#~ msgstr "Ups"
diff --git a/editor/translations/da.po b/editor/translations/da.po
index 163eb546a0..2ab69b5f05 100644
--- a/editor/translations/da.po
+++ b/editor/translations/da.po
@@ -363,6 +363,7 @@ msgstr "Ændre Anim Løkke"
msgid "Remove Anim Track"
msgstr "Fjern Anim Spor"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Opret NYT spor til %s og indsæt nøgle?"
@@ -387,10 +388,28 @@ msgstr "Opret"
msgid "Anim Insert"
msgstr "Anim Indsæt"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "Kan ikke åbne '%s'."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animation"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "Animationsafspiller kan ikke animere sig selv, kun andre afspillere."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Egenskaber"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Anim Opret & Indsæt"
@@ -995,7 +1014,7 @@ msgstr "Opret Ny %s"
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2393,6 +2412,18 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+#, fuzzy
+msgid "Spins when the editor window redraws."
+msgstr "Snurrer når editor vinduer gentegnes!"
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3263,11 +3294,6 @@ msgstr "Gem & genstart"
#: editor/editor_node.cpp
#, fuzzy
-msgid "Spins when the editor window redraws."
-msgstr "Snurrer når editor vinduer gentegnes!"
-
-#: editor/editor_node.cpp
-#, fuzzy
msgid "Update Continuously"
msgstr "Kontinuerlig"
@@ -3914,6 +3940,16 @@ msgid "Download from:"
msgstr "Download"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Åbn i Filhåndtering"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Indlæs Fejl"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8912,6 +8948,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Fjern Alt"
@@ -8942,6 +8984,12 @@ msgid "Remove All StyleBox Items"
msgstr "Fjern Alt"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Favoritter:"
@@ -12597,6 +12645,16 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Fjern Kurve Punktets Position"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Fjern Kurve Punktets Position"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -14331,6 +14389,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
@@ -15089,9 +15183,6 @@ msgstr "Konstanter kan ikke ændres."
#~ msgid "I see..."
#~ msgstr "Jeg forstår..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "Kan ikke åbne '%s'."
-
#, fuzzy
#~ msgid "Ugh"
#~ msgstr "Ugh"
diff --git a/editor/translations/de.po b/editor/translations/de.po
index 38d565b1cd..6d57f3dcad 100644
--- a/editor/translations/de.po
+++ b/editor/translations/de.po
@@ -75,7 +75,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-07-29 02:33+0000\n"
+"PO-Revision-Date: 2021-08-06 06:47+0000\n"
"Last-Translator: So Wieso <sowieso@dukun.de>\n"
"Language-Team: German <https://hosted.weblate.org/projects/godot-engine/"
"godot/de/>\n"
@@ -84,7 +84,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.7.2-dev\n"
+"X-Generator: Weblate 4.8-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -406,6 +406,7 @@ msgstr "Animationswiederholungsmodus ändern"
msgid "Remove Anim Track"
msgstr "Spur entfernen"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "NEUE Spur für %s erstellen und Schlüsselbild hinzufügen?"
@@ -430,10 +431,28 @@ msgstr "Erstellen"
msgid "Anim Insert"
msgstr "Einfügen"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "‚%s‘ kann nicht geöffnet werden."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animation"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "AnimationPlayer kann sich nicht selbst animieren, nur andere Objekte."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Eigenschaft ‚%s‘ existiert nicht."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Animation Erstellen & Einfügen"
@@ -646,9 +665,8 @@ msgid "Go to Previous Step"
msgstr "Zum vorherigen Schritt"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Apply Reset"
-msgstr "Zurücksetzen"
+msgstr "Zurücksetzen durchführen"
#: editor/animation_track_editor.cpp
msgid "Optimize Animation"
@@ -667,9 +685,8 @@ msgid "Use Bezier Curves"
msgstr "Bezier-Kurven nutzen"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Create RESET Track(s)"
-msgstr "Spuren einfügen"
+msgstr "RESET Spur(en) erstellen"
#: editor/animation_track_editor.cpp
msgid "Anim. Optimizer"
@@ -994,7 +1011,6 @@ msgid "Edit..."
msgstr "Bearbeiten..."
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Go to Method"
msgstr "Zur Methode springen"
@@ -1014,9 +1030,9 @@ msgstr "%s erstellen"
msgid "No results for \"%s\"."
msgstr "Keine Ergebnisse für \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
-msgstr ""
+msgstr "Keine Beschreibung zu ‚%s‘ verfügbar."
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp
@@ -1116,7 +1132,6 @@ msgid "Owners Of:"
msgstr "Besitzer von:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove the selected files from the project? (Cannot be undone.)\n"
"Depending on your filesystem configuration, the files will either be moved "
@@ -1124,11 +1139,10 @@ msgid ""
msgstr ""
"Ausgewählte Dateien aus dem Projekt entfernen? (Kann nicht rückgängig "
"gemacht werden.)\n"
-"Die Dateien können möglicherweise aus dem Papierkorb des Betriebssystems "
-"wiederhergestellt werden."
+"Abhängig von den Betriebssystemeinstellungen werden die Dateien in den "
+"Papierkorb verschoben oder permanent gelöscht."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1139,8 +1153,8 @@ msgstr ""
"Andere Ressourcen benötigen die zu entfernenden Dateien, um richtig zu "
"funktionieren.\n"
"Trotzdem entfernen? (Kann nicht rückgängig gemacht werden.)\n"
-"Die Dateien können möglicherweise aus dem Papierkorb des Betriebssystems "
-"wiederhergestellt werden."
+"Abhängig von den Betriebssystemeinstellungen werden die Dateien in den "
+"Papierkorb verschoben oder permanent gelöscht."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1312,41 +1326,39 @@ msgid "Licenses"
msgstr "Lizenzen"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Error opening asset file for \"%s\" (not in ZIP format)."
-msgstr "Fehler beim Öffnen der Paketdatei (kein ZIP-Format)."
+msgstr "Fehler beim Öffnen der Nutzerinhaltsdatei „%s“ (kein ZIP-Format)."
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "%s (already exists)"
msgstr "%s (existiert bereits)"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - %d file(s) conflict with your project:"
msgstr ""
+"Nutzerinhalt „%s“ - %d Datei(en) stehen in Konflikt mit diesem Projekt:"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - No files conflict with your project:"
-msgstr ""
+msgstr "Nutzerinhalt „%s“ - Kein Konflikt mit diesem Projekt:"
#: editor/editor_asset_installer.cpp
msgid "Uncompressing Assets"
msgstr "Inhalte werden entpackt"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "The following files failed extraction from asset \"%s\":"
-msgstr "Die folgenden Dateien ließen sich nicht aus dem Paket extrahieren:"
+msgstr ""
+"Die folgenden Dateien ließen sich nicht aus dem Nutzerinhaltspaket „%s“ "
+"extrahieren:"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "(and %s more files)"
-msgstr "Und %s weitere Dateien."
+msgstr "(und %s weitere Dateien)"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset \"%s\" installed successfully!"
-msgstr "Paket wurde erfolgreich installiert!"
+msgstr "Nutzerinhaltspaket „%s“ wurde erfolgreich installiert!"
#: editor/editor_asset_installer.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -1358,9 +1370,8 @@ msgid "Install"
msgstr "Installieren"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset Installer"
-msgstr "Erweiterungenverwaltung"
+msgstr "Nutzerinhalteinstallation"
#: editor/editor_audio_buses.cpp
msgid "Speakers"
@@ -1423,7 +1434,6 @@ msgid "Bypass"
msgstr "Überbrückung"
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "Bus Options"
msgstr "Audiobusoptionen"
@@ -1591,13 +1601,12 @@ msgid "Can't add autoload:"
msgstr "Autoload konnte nicht hinzugefügt werden:"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "%s is an invalid path. File does not exist."
-msgstr "Datei existiert nicht."
+msgstr "%s ist ein ungültiger Pfad. Datei existiert nicht."
#: editor/editor_autoload_settings.cpp
msgid "%s is an invalid path. Not in resource path (res://)."
-msgstr ""
+msgstr "%s ist ein ungültiger Pfad. Liegt nicht im Ressourcen-Pfad (res://)."
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -1621,9 +1630,8 @@ msgid "Name"
msgstr "Name"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "Global Variable"
-msgstr "Variable"
+msgstr "Globale Variable"
#: editor/editor_data.cpp
msgid "Paste Params"
@@ -1799,48 +1807,56 @@ msgstr "Importleiste"
#: editor/editor_feature_profile.cpp
msgid "Allows to view and edit 3D scenes."
-msgstr ""
+msgstr "Ermöglicht das Betrachten und Bearbeiten von 3D-Szenen."
#: editor/editor_feature_profile.cpp
msgid "Allows to edit scripts using the integrated script editor."
msgstr ""
+"Ermöglicht das Bearbeiten von Skripten mithilfe des integrierten Skript-"
+"Editors."
#: editor/editor_feature_profile.cpp
msgid "Provides built-in access to the Asset Library."
-msgstr ""
+msgstr "Stellt Zugriff zur Nutzerinhaltebibliothek her."
#: editor/editor_feature_profile.cpp
msgid "Allows editing the node hierarchy in the Scene dock."
-msgstr ""
+msgstr "Ermöglicht das Bearbeiten der Node-Hierachie in der Szenenleiste."
#: editor/editor_feature_profile.cpp
msgid ""
"Allows to work with signals and groups of the node selected in the Scene "
"dock."
msgstr ""
+"Ermöglicht die Konfiguration von Signalen und Gruppen des ausgewählten Nodes "
+"in der Szenenleiste."
#: editor/editor_feature_profile.cpp
msgid "Allows to browse the local file system via a dedicated dock."
msgstr ""
+"Ermöglicht das Betrachten des lokalen Dateisystems in einer eigenen Leiste."
#: editor/editor_feature_profile.cpp
msgid ""
"Allows to configure import settings for individual assets. Requires the "
"FileSystem dock to function."
msgstr ""
+"Ermöglicht die Konfiguration von Importeinstellungen für individuelle "
+"Dateien. Benötigt die Dateisystemleiste zum Funktionieren."
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "(current)"
-msgstr "(Aktuell)"
+msgstr "(ausgewählt)"
#: editor/editor_feature_profile.cpp
msgid "(none)"
-msgstr ""
+msgstr "(keins)"
#: editor/editor_feature_profile.cpp
msgid "Remove currently selected profile, '%s'? Cannot be undone."
msgstr ""
+"Aktuell ausgewähltes Profil ‚%s‘ entfernen? Dies kann nicht rückgängig "
+"gemacht werden."
#: editor/editor_feature_profile.cpp
msgid "Profile must be a valid filename and must not contain '.'"
@@ -1872,19 +1888,16 @@ msgid "Enable Contextual Editor"
msgstr "Kontextsensitiven Editor aktivieren"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Class Properties:"
-msgstr "Eigenschaften:"
+msgstr "Klasseneigenschaften:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Main Features:"
-msgstr "Eigenschaften und Merkmale"
+msgstr "Wichtigste Funktionen:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Nodes and Classes:"
-msgstr "Aktivierte Klassen:"
+msgstr "Nodes und Klassen:"
#: editor/editor_feature_profile.cpp
msgid "File '%s' format is invalid, import aborted."
@@ -1903,7 +1916,6 @@ msgid "Error saving profile to path: '%s'."
msgstr "Fehler beim Speichern des Profils im Pfad: ‚%s‘."
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Reset to Default"
msgstr "Auf Standardwerte zurücksetzen"
@@ -1912,14 +1924,12 @@ msgid "Current Profile:"
msgstr "Aktuelles Profil:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Create Profile"
-msgstr "Profil löschen"
+msgstr "Profil erstellen"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Remove Profile"
-msgstr "Kachel entfernen"
+msgstr "Profil entfernen"
#: editor/editor_feature_profile.cpp
msgid "Available Profiles:"
@@ -1939,18 +1949,18 @@ msgid "Export"
msgstr "Exportieren"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Configure Selected Profile:"
-msgstr "Aktuelles Profil:"
+msgstr "Ausgewähltes Profil bearbeiten:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Extra Options:"
-msgstr "Textureinstellungen"
+msgstr "Zusatzoptionen:"
#: editor/editor_feature_profile.cpp
msgid "Create or import a profile to edit available classes and properties."
msgstr ""
+"Ein Profil erstellen oder importieren um verfügbare Klassen und "
+"Einstellungen zu bearbeiten."
#: editor/editor_feature_profile.cpp
msgid "New profile name:"
@@ -1977,9 +1987,8 @@ msgid "Select Current Folder"
msgstr "Gegenwärtigen Ordner auswählen"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
-#, fuzzy
msgid "File exists, overwrite?"
-msgstr "Datei existiert bereits. Überschreiben?"
+msgstr "Datei existiert bereits. Soll sie überschrieben werden?"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Select This Folder"
@@ -2372,6 +2381,17 @@ msgid "New Window"
msgstr "Neues Fenster"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Dreht sich, wenn das Editorfenster neu gezeichnet wird."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Importierte Ressourcen können nicht abgespeichert werden."
@@ -2604,13 +2624,16 @@ msgid ""
"The current scene has no root node, but %d modified external resource(s) "
"were saved anyway."
msgstr ""
+"Die aktuelle Szene hat keine Wurzel, dennoch wurden %d bearbeitete externe "
+"Ressource(n) gespeichert."
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"A root node is required to save the scene. You can add a root node using the "
"Scene tree dock."
-msgstr "Ein Wurzel-Node wird benötigt um diese Szene zu speichern."
+msgstr ""
+"Ein Wurzel-Node wird benötigt um diese Szene zu speichern. Ein Wurzel-Node "
+"kann in der Szenenbaumleiste hinzugefügt werden."
#: editor/editor_node.cpp
msgid "Save Scene As..."
@@ -3004,9 +3027,8 @@ msgid "Orphan Resource Explorer..."
msgstr "Verwaltung nicht verwendeter Ressourcen…"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reload Current Project"
-msgstr "Projekt umbenennen"
+msgstr "Aktuelles Projekt neu laden"
#: editor/editor_node.cpp
msgid "Quit to Project List"
@@ -3167,22 +3189,20 @@ msgid "Help"
msgstr "Hilfe"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Online Documentation"
-msgstr "Dokumentation öffnen"
+msgstr "Internet-Dokumentation"
#: editor/editor_node.cpp
msgid "Questions & Answers"
-msgstr ""
+msgstr "Fragen & Antworten"
#: editor/editor_node.cpp
msgid "Report a Bug"
msgstr "Fehler berichten"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Suggest a Feature"
-msgstr "Einen Wert setzen"
+msgstr "Neue Funktionalität vorschlagen"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
@@ -3190,12 +3210,11 @@ msgstr "Dokumentationsvorschläge senden"
#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
msgid "Community"
-msgstr "Community"
+msgstr "Gemeinschaft"
#: editor/editor_node.cpp
-#, fuzzy
msgid "About Godot"
-msgstr "Über"
+msgstr "Über Godot"
#: editor/editor_node.cpp
msgid "Support Godot Development"
@@ -3247,10 +3266,6 @@ msgid "Save & Restart"
msgstr "Speichern & Neu starten"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Dreht sich, wenn das Editorfenster neu gezeichnet wird."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Fortlaufend aktualisieren"
@@ -3292,14 +3307,12 @@ msgid "Manage Templates"
msgstr "Vorlagen verwalten"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Install from file"
-msgstr "Installiere aus Datei"
+msgstr "Aus Datei installieren"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Select android sources file"
-msgstr "Quell-Mesh auswählen:"
+msgstr "Android-Quelldateien auswählen"
#: editor/editor_node.cpp
msgid ""
@@ -3384,7 +3397,7 @@ msgstr "Auswählen"
#: editor/editor_node.cpp
#, fuzzy
msgid "Select Current"
-msgstr "Gegenwärtigen Ordner auswählen"
+msgstr "Aktuelles auswählen"
#: editor/editor_node.cpp
msgid "Open 2D Editor"
@@ -3419,9 +3432,8 @@ msgid "No sub-resources found."
msgstr "Keine Unter-Ressourcen gefunden."
#: editor/editor_path.cpp
-#, fuzzy
msgid "Open a list of sub-resources."
-msgstr "Keine Unter-Ressourcen gefunden."
+msgstr "Liste der Unter-Ressourcen öffnen."
#: editor/editor_plugin.cpp
msgid "Creating Mesh Previews"
@@ -3448,14 +3460,12 @@ msgid "Update"
msgstr "Update"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Version"
-msgstr "Version:"
+msgstr "Version"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Author"
-msgstr "Autoren"
+msgstr "Autor"
#: editor/editor_plugin_settings.cpp
#: editor/plugins/version_control_editor_plugin.cpp
@@ -3468,14 +3478,12 @@ msgid "Measure:"
msgstr "Messung:"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Frame Time (ms)"
-msgstr "Renderzeit (Sek)"
+msgstr "Frame-Zeit (ms)"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Average Time (ms)"
-msgstr "Renderzeit ⌀ (sek)"
+msgstr "Durchschnittszeit (ms)"
#: editor/editor_profiler.cpp
msgid "Frame %"
@@ -3502,6 +3510,13 @@ msgid ""
"functions called by that function.\n"
"Use this to find individual functions to optimize."
msgstr ""
+"Inklusive: Beinhaltet Zeiten von anderen Funktionen die von dieser "
+"aufgerufen wurden.\n"
+"Brauchbar um Flaschenhälse zu finden.\n"
+"\n"
+"Eigen: Zählt nur die Zeit in dieser Funktion, nicht die Zeiten von ihr "
+"aufgerufener Funktionen.\n"
+"Brauchbar um einzelne Funktionen zum Optimieren zu finden."
#: editor/editor_profiler.cpp
msgid "Frame #:"
@@ -3624,7 +3639,6 @@ msgid "Paste"
msgstr "Einfügen"
#: editor/editor_resource_picker.cpp editor/property_editor.cpp
-#, fuzzy
msgid "Convert to %s"
msgstr "Umwandeln zu %s"
@@ -3674,10 +3688,9 @@ msgid "Did you forget the '_run' method?"
msgstr "Hast du die '_run' Methode vergessen?"
#: editor/editor_spin_slider.cpp
-#, fuzzy
msgid "Hold %s to round to integers. Hold Shift for more precise changes."
msgstr ""
-"Strg-Taste halten um auf Ganzzahlen zu runden. Umschalt-Taste halten für "
+"%s-Taste halten um auf Ganzzahlen zu runden. Umschalt-Taste halten für "
"präzisere Änderungen."
#: editor/editor_sub_scene.cpp
@@ -3698,49 +3711,43 @@ msgstr "Aus Node importieren:"
#: editor/export_template_manager.cpp
msgid "Open the folder containing these templates."
-msgstr ""
+msgstr "Den Ordner der diese Exportvorlagen enthält öffnen."
#: editor/export_template_manager.cpp
msgid "Uninstall these templates."
-msgstr ""
+msgstr "Diese Exportvorlage deinstallieren."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "There are no mirrors available."
-msgstr "Datei ‚%s‘ existiert nicht."
+msgstr "Keine Mirrors verfügbar."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Retrieving the mirror list..."
-msgstr "Mirrors werden geladen, bitte warten..."
+msgstr "Mirror-Liste werden abgerufen…"
#: editor/export_template_manager.cpp
msgid "Starting the download..."
-msgstr ""
+msgstr "Download wird begonnen…"
#: editor/export_template_manager.cpp
msgid "Error requesting URL:"
msgstr "Fehler beim Abrufen der URL:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Connecting to the mirror..."
-msgstr "Verbinde mit Mirror..."
+msgstr "Verbindung mit Mirror wird hergestellt..."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't resolve the requested address."
-msgstr "Kann Hostnamen nicht auflösen:"
+msgstr "Angefragte Adresse konnte nicht aufgelöst werden."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't connect to the mirror."
-msgstr "Kann nicht zu Host verbinden:"
+msgstr "Verbindung zu Mirror konnte nicht hergestellt werden."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "No response from the mirror."
-msgstr "Keine Antwort von Host:"
+msgstr "Keine Antwort des Mirrors."
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -3748,18 +3755,16 @@ msgid "Request failed."
msgstr "Anfrage fehlgeschlagen."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Request ended up in a redirect loop."
-msgstr "Anfrage fehlgeschlagen, zu viele Weiterleitungen"
+msgstr "Anfrage in Weiterleitungsschleife gefangen."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Request failed:"
-msgstr "Anfrage fehlgeschlagen."
+msgstr "Anfrage fehlgeschlagen:"
#: editor/export_template_manager.cpp
msgid "Download complete; extracting templates..."
-msgstr ""
+msgstr "Download abgeschlossen; Exportvorlagen werden extrahiert…"
#: editor/export_template_manager.cpp
msgid "Cannot remove temporary file:"
@@ -3778,7 +3783,6 @@ msgid "Error getting the list of mirrors."
msgstr "Fehler beim Laden der Spiegelserver."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Error parsing JSON with the list of mirrors. Please report this issue!"
msgstr ""
"Fehler beim Einlesen des JSON-Formats der Spiegelserverliste. Bitte diesen "
@@ -3786,7 +3790,7 @@ msgstr ""
#: editor/export_template_manager.cpp
msgid "Best available mirror"
-msgstr ""
+msgstr "Bester verfügbarer Mirror"
#: editor/export_template_manager.cpp
msgid ""
@@ -3839,24 +3843,20 @@ msgid "SSL Handshake Error"
msgstr "SSL-Handshake-Fehler"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't open the export templates file."
-msgstr "Exportvorlagen-ZIP-Datei konnte nicht geöffnet werden."
+msgstr "Exportvorlagendatei konnte nicht geöffnet werden."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Invalid version.txt format inside the export templates file: %s."
-msgstr "Ungültiges version.txt-Format in Templates: %s."
+msgstr "Ungültiges version.txt-Format in der Exportvorlagendatei: %s."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "No version.txt found inside the export templates file."
-msgstr "Keine version.txt in Templates gefunden."
+msgstr "Keine version.txt in Exportvorlagendatei gefunden."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Error creating path for extracting templates:"
-msgstr "Fehler bei Erzeugen des Pfads für die Vorlagen:"
+msgstr "Fehler bei Erzeugen des Pfads zum Extrahieren der Exportvorlagen:"
#: editor/export_template_manager.cpp
msgid "Extracting Export Templates"
@@ -3867,9 +3867,8 @@ msgid "Importing:"
msgstr "Importiere:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Remove templates for the version '%s'?"
-msgstr "Template-Version ‚%s‘ entfernen?"
+msgstr "Exportvorlagenversion ‚%s‘ entfernen?"
#: editor/export_template_manager.cpp
msgid "Uncompressing Android Build Sources"
@@ -3885,44 +3884,54 @@ msgstr "Aktuelle Version:"
#: editor/export_template_manager.cpp
msgid "Export templates are missing. Download them or install from a file."
-msgstr ""
+msgstr "Exportvorlagen fehlen. Download oder Installation aus Datei nötig."
#: editor/export_template_manager.cpp
msgid "Export templates are installed and ready to be used."
-msgstr ""
+msgstr "Exportvorlagen sind installiert und bereit zum Verwenden."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Open Folder"
-msgstr "Datei öffnen"
+msgstr "Ordner öffnen"
#: editor/export_template_manager.cpp
msgid "Open the folder containing installed templates for the current version."
msgstr ""
+"Order mit den installierten Exportvorlagen der aktuellen Version öffnen."
#: editor/export_template_manager.cpp
msgid "Uninstall"
msgstr "Deinstallieren"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Uninstall templates for the current version."
-msgstr "Anfangswert für Zähler"
+msgstr "Exportvorlagen der aktuellen Version deinstallieren."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Download from:"
-msgstr "Downloadfehler"
+msgstr "Herunterladen von:"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Im Browser ausführen"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Fehlermeldung kopieren"
#: editor/export_template_manager.cpp
msgid "Download and Install"
-msgstr ""
+msgstr "Herunterladen und installieren"
#: editor/export_template_manager.cpp
msgid ""
"Download and install templates for the current version from the best "
"possible mirror."
msgstr ""
+"Exportvorlagen der aktuellen Version vom bestmöglichen Mirror herunterladen "
+"und installieren."
#: editor/export_template_manager.cpp
msgid "Official export templates aren't available for development builds."
@@ -3931,14 +3940,12 @@ msgstr ""
"gestellt."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Install from File"
-msgstr "Installiere aus Datei"
+msgstr "Aus Datei installieren"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Install templates from a local file."
-msgstr "Vorlagen aus ZIP-Datei importieren"
+msgstr "Exportvorlagen aus lokaler Datei installieren."
#: editor/export_template_manager.cpp editor/find_in_files.cpp
#: editor/progress_dialog.cpp scene/gui/dialogs.cpp
@@ -3946,19 +3953,16 @@ msgid "Cancel"
msgstr "Abbrechen"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Cancel the download of the templates."
-msgstr "Exportvorlagen-ZIP-Datei konnte nicht geöffnet werden."
+msgstr "Herunterladen der Exportvorlagen abbrechen."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Other Installed Versions:"
-msgstr "Installierte Versionen:"
+msgstr "Andere installierte Versionen:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Uninstall Template"
-msgstr "Deinstallieren"
+msgstr "Exportvorlage deinstallieren"
#: editor/export_template_manager.cpp
msgid "Select Template File"
@@ -3973,6 +3977,8 @@ msgid ""
"The templates will continue to download.\n"
"You may experience a short editor freeze when they finish."
msgstr ""
+"Download der Exportvorlage wird fortgesetzt.\n"
+"Der Editor kann nach Ende des Downloads kurzfristig stocken."
#: editor/filesystem_dock.cpp
msgid "Favorites"
@@ -4119,35 +4125,32 @@ msgid "Collapse All"
msgstr "Alle einklappen"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort files"
-msgstr "Dateien suchen"
+msgstr "Dateien sortieren"
#: editor/filesystem_dock.cpp
msgid "Sort by Name (Ascending)"
-msgstr ""
+msgstr "Nach Name sortieren (aufsteigend)"
#: editor/filesystem_dock.cpp
msgid "Sort by Name (Descending)"
-msgstr ""
+msgstr "Nach Name sortieren (absteigend)"
#: editor/filesystem_dock.cpp
msgid "Sort by Type (Ascending)"
-msgstr ""
+msgstr "Nach Typ sortieren (aufsteigend)"
#: editor/filesystem_dock.cpp
msgid "Sort by Type (Descending)"
-msgstr ""
+msgstr "Nach Typ sortieren (absteigend)"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort by Last Modified"
-msgstr "Zuletzt bearbeitet"
+msgstr "Nach Bearbeitungszeit sortieren (Aktuelles zuerst)"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort by First Modified"
-msgstr "Zuletzt bearbeitet"
+msgstr "Nach Bearbeitungszeit sortieren (Aktuelles zuletzt)"
#: editor/filesystem_dock.cpp
msgid "Duplicate..."
@@ -4159,7 +4162,7 @@ msgstr "Umbenennen..."
#: editor/filesystem_dock.cpp
msgid "Focus the search box"
-msgstr ""
+msgstr "Suchfeld auswählen"
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -4471,14 +4474,12 @@ msgid "Failed to load resource."
msgstr "Laden der Ressource gescheitert."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Copy Properties"
-msgstr "Eigenschaften"
+msgstr "Eigenschaften kopieren"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Paste Properties"
-msgstr "Eigenschaften"
+msgstr "Eigenschaften einfügen"
#: editor/inspector_dock.cpp
msgid "Make Sub-Resources Unique"
@@ -4503,23 +4504,20 @@ msgid "Save As..."
msgstr "Speichern als..."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Extra resource options."
-msgstr "Nicht im Ressourcen-Pfad."
+msgstr "Zusatz-Ressourcenoptionen."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Edit Resource from Clipboard"
-msgstr "Ressourcen-Zwischenablage bearbeiten"
+msgstr "Ressource in Zwischenablage bearbeiten"
#: editor/inspector_dock.cpp
msgid "Copy Resource"
msgstr "Ressource kopieren"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Make Resource Built-In"
-msgstr "Einbetten"
+msgstr "Ressource zu Built-In konvertieren"
#: editor/inspector_dock.cpp
msgid "Go to the previous edited object in history."
@@ -4534,9 +4532,8 @@ msgid "History of recently edited objects."
msgstr "Verlauf der zuletzt bearbeiteten Objekte."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Open documentation for this object."
-msgstr "Dokumentation öffnen"
+msgstr "Dokumentation zu diesem Objekt öffnen."
#: editor/inspector_dock.cpp editor/scene_tree_dock.cpp
msgid "Open Documentation"
@@ -4547,9 +4544,8 @@ msgid "Filter properties"
msgstr "Eigenschaften filtern"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Manage object properties."
-msgstr "Objekteigenschaften."
+msgstr "Objekteigenschaften verwalten."
#: editor/inspector_dock.cpp
msgid "Changes may be lost!"
@@ -4795,9 +4791,8 @@ msgid "Blend:"
msgstr "Blende:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Parameter Changed:"
-msgstr "Parameter geändert"
+msgstr "Parameter geändert:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
@@ -5527,11 +5522,11 @@ msgstr "Alle"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Search templates, projects, and demos"
-msgstr ""
+msgstr "Vorlagen, Projekte und Demos durchsuchen"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Search assets (excluding templates, projects, and demos)"
-msgstr ""
+msgstr "Assets durchsuchen (ausgenommen Vorlagen, Projekte und Demos)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Import..."
@@ -5575,7 +5570,7 @@ msgstr "Nutzerinhalte als ZIP-Datei"
#: editor/plugins/audio_stream_editor_plugin.cpp
msgid "Audio Preview Play/Pause"
-msgstr ""
+msgstr "Audiovorschau abspielen/pausieren"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
@@ -5836,13 +5831,13 @@ msgstr "Ankerpunkte ändern"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid ""
"Project Camera Override\n"
"Overrides the running project's camera with the editor viewport camera."
msgstr ""
-"Spielekamera überschreiben\n"
-"Überschreibt die Spielekamera mit der Kamera des Anzeigefensters des Editors."
+"Projektkamera überbrücken\n"
+"Überbrückt die Kamera des laufenden Projekts mit der Kamera des "
+"Anzeigefensters des Editors."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5851,6 +5846,9 @@ msgid ""
"No project instance running. Run the project from the editor to use this "
"feature."
msgstr ""
+"Projektkamera überbrücken\n"
+"Es wird zur Zeit keine Projektinstanz ausgeführt. Um diese Funktion zu "
+"nutzen muss ein Projekt durch den Editor gestartet werden."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5918,32 +5916,27 @@ msgstr "Auswahlmodus"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Drag: Rotate selected node around pivot."
-msgstr "Ausgewählten Node oder Übergang entfernen."
+msgstr "Ziehen: Ausgewähltes Node um Pivotpunkt rotieren."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Alt+Drag: Move selected node."
-msgstr "Alt+Ziehen = Verschieben"
+msgstr "Alt+Ziehen = Ausgewähltes Node verschieben."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "V: Set selected node's pivot position."
-msgstr "Ausgewählten Node oder Übergang entfernen."
+msgstr "V: Pivotpunkt des ausgewählten Nodes festlegen."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Alt+RMB: Show list of all nodes at position clicked, including locked."
msgstr ""
-"Zeige eine Liste aller Objekte, die sich an der angeklickten Position "
-"befinden\n"
-"(equivalent zu Alt+RMT im Auswahlmodus)."
+"Alt+RMT: Liste aller Nodes an Klickposition anzeigen, einschließlich "
+"gesperrter."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "RMB: Add node at position clicked."
-msgstr ""
+msgstr "RMT: Node an Klickposition hinzufügen."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -6183,14 +6176,12 @@ msgid "Clear Pose"
msgstr "Pose/Stellung löschen"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Add Node Here"
-msgstr "Node hinzufügen"
+msgstr "Node hier hinzufügen"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Instance Scene Here"
-msgstr "Instanz-Szene(n)"
+msgstr "Szene hier instantiieren"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Multiply grid step by 2"
@@ -6206,49 +6197,43 @@ msgstr "Sicht verschieben"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 3.125%"
-msgstr ""
+msgstr "Auf 3.125% vergrößern"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 6.25%"
-msgstr ""
+msgstr "Auf 6.25% vergrößern"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 12.5%"
-msgstr ""
+msgstr "Auf 12.5% vergrößern"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 25%"
-msgstr "Verkleinern"
+msgstr "Auf 25% vergrößern"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 50%"
-msgstr "Verkleinern"
+msgstr "Auf 50% vergrößern"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 100%"
-msgstr "Verkleinern"
+msgstr "Auf 100% vergrößern"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 200%"
-msgstr "Verkleinern"
+msgstr "Auf 200% vergrößern"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 400%"
-msgstr "Verkleinern"
+msgstr "Auf 400% vergrößern"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 800%"
-msgstr "Verkleinern"
+msgstr "Auf 800% vergrößern"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 1600%"
-msgstr ""
+msgstr "Auf 1600% vergrößern"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Add %s"
@@ -6495,9 +6480,8 @@ msgid "Couldn't create a single convex collision shape."
msgstr "Ein einzelnes konvexes Kollisionselement konnte nicht erzeugt werden."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Create Simplified Convex Shape"
-msgstr "Einzelne konvexe Form erstellen"
+msgstr "Vereinfachte konvexe Form erstellen"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Single Convex Shape"
@@ -6535,9 +6519,8 @@ msgid "No mesh to debug."
msgstr "Kein Mesh zu debuggen."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Mesh has no UV in layer %d."
-msgstr "Modell besitzt kein UV in dieser Schicht"
+msgstr "Mesh hat kein UV in Schicht %d."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "MeshInstance lacks a Mesh!"
@@ -6602,16 +6585,19 @@ msgstr ""
"Dies ist die schnellste (aber ungenauste) Methode für Kollisionsberechnungen."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Create Simplified Convex Collision Sibling"
-msgstr "Ein einzelnes konvexes Kollisionsnachbarelement erzeugen"
+msgstr "Vereinfachtes konvexes Kollisionsnachbarelement erzeugen"
#: editor/plugins/mesh_instance_editor_plugin.cpp
+#, fuzzy
msgid ""
"Creates a simplified convex collision shape.\n"
"This is similar to single collision shape, but can result in a simpler "
"geometry in some cases, at the cost of accuracy."
msgstr ""
+"Erzeugt ein vereinfachtes konvexes Collision Shape.\n"
+"Dies ist ähnlich zu einem einzigen Collision Shape, kann allerdings manchmal "
+"zu einfacherer Geometrie führen, auf Kosten der Genauigkeit."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Multiple Convex Collision Siblings"
@@ -6624,8 +6610,9 @@ msgid ""
"This is a performance middle-ground between a single convex collision and a "
"polygon-based collision."
msgstr ""
-"Erstellt ein polygon-basiertes Kollisionselement.\n"
-"Dies liegt von der Geschwindigkeit in der Mitte der beiden anderen Methoden."
+"Erstellt ein polygon-basiertes Collision Shape.\n"
+"Dies liegt von der Geschwindigkeit in der Mitte zwischen einer einzelnen "
+"konvexen Kollision und einer polygon-basierten Kollision."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Outline Mesh..."
@@ -7271,24 +7258,20 @@ msgid "ResourcePreloader"
msgstr "Ressourcen-Vorlader"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Flip Portals"
-msgstr "Horizontal umdrehen"
+msgstr "Portale umdrehen"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Room Generate Points"
-msgstr "Anzahl generierter Punkte:"
+msgstr "Generiere Punkte mittels Room"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Generate Points"
-msgstr "Anzahl generierter Punkte:"
+msgstr "Generiere Punkte"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Flip Portal"
-msgstr "Horizontal umdrehen"
+msgstr "Portal umdrehen"
#: editor/plugins/root_motion_editor_plugin.cpp
msgid "AnimationTree has no path set to an AnimationPlayer"
@@ -7854,20 +7837,17 @@ msgid "None"
msgstr "Nichts"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Rotate"
-msgstr "Status"
+msgstr "Rotierung"
#. TRANSLATORS: This refers to the movement that changes the position of an object.
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Translate"
-msgstr "Translation:"
+msgstr "Verschiebung"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Scale"
-msgstr "Skalierung:"
+msgstr "Skalierung"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scaling: "
@@ -7890,52 +7870,44 @@ msgid "Animation Key Inserted."
msgstr "Animationsschlüsselbild eingefügt."
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Pitch:"
-msgstr "Neigen"
+msgstr "Neigung:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Yaw:"
-msgstr ""
+msgstr "Gierung:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size:"
-msgstr "Größe: "
+msgstr "Größe:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Objects Drawn:"
-msgstr "Gezeichnete Objekte"
+msgstr "Gezeichnete Objekte:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Material Changes:"
-msgstr "Materialänderungen"
+msgstr "Materialänderungen:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Shader Changes:"
-msgstr "Shader-Änderungen"
+msgstr "Shader-Änderungen:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Surface Changes:"
-msgstr "Oberflächen-Änderungen"
+msgstr "Oberflächen-Änderungen:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Draw Calls:"
-msgstr "Zeichenaufrufe"
+msgstr "Zeichenaufrufe:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Vertices:"
-msgstr "Eckpunkte"
+msgstr "Eckpunkte:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "FPS: %d (%s ms)"
-msgstr ""
+msgstr "FPS: %d (%s ms)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Top View."
@@ -8091,9 +8063,8 @@ msgid "Freelook Slow Modifier"
msgstr "Freisicht Trägheitsregler"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Toggle Camera Preview"
-msgstr "Ändere Kameragröße"
+msgstr "Kameravorschau umschalten"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Rotation Locked"
@@ -8115,9 +8086,8 @@ msgstr ""
"Sie ist kein zuverlässiger Vergleichswert für die In-Spiel-Leistung."
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Convert Rooms"
-msgstr "Umwandeln zu %s"
+msgstr "Räume umwandeln"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "XForm Dialog"
@@ -8139,7 +8109,6 @@ msgstr ""
"(\"Röntgenblick\")."
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Snap Nodes to Floor"
msgstr "Nodes am Boden einrasten"
@@ -8159,7 +8128,7 @@ msgstr "Einrasten aktivieren"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Converts rooms for portal culling."
-msgstr ""
+msgstr "Räume für Portal-Culling konvertieren."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Bottom View"
@@ -8255,9 +8224,8 @@ msgid "View Grid"
msgstr "Zeige Gitter"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "View Portal Culling"
-msgstr "Einstellungen für Ansichten"
+msgstr "Portal-Culling anzeigen"
#: editor/plugins/spatial_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
@@ -8579,221 +8547,196 @@ msgid "TextureRegion"
msgstr "Texturbereich"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Colors"
-msgstr "Farbe"
+msgstr "Farben"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Fonts"
-msgstr "Schriftart"
+msgstr "Schriftarten"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Icons"
-msgstr "Symbol"
+msgstr "Symbole"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Styleboxes"
-msgstr "Style-Box"
+msgstr "Style-Boxen"
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} color(s)"
-msgstr ""
+msgstr "{num} Farbe(n)"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No colors found."
-msgstr "Keine Unter-Ressourcen gefunden."
+msgstr "Keine Farben gefunden."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "{num} constant(s)"
-msgstr "Konstanten"
+msgstr "{num} Konstante(n)"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No constants found."
-msgstr "Farbkonstante."
+msgstr "Keine Konstanten gefunden."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} font(s)"
-msgstr ""
+msgstr "{num} Schriftart(en)"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No fonts found."
-msgstr "Nicht gefunden!"
+msgstr "Keine Schriftarten gefunden."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} icon(s)"
-msgstr ""
+msgstr "{num} Symbol(e)"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No icons found."
-msgstr "Nicht gefunden!"
+msgstr "Keine Symbole gefunden."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} stylebox(es)"
-msgstr ""
+msgstr "{num} Style-Box(en)"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No styleboxes found."
-msgstr "Keine Unter-Ressourcen gefunden."
+msgstr "Keine Style-Boxen gefunden."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} currently selected"
-msgstr ""
+msgstr "{num} zurzeit ausgewählt"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Nothing was selected for the import."
-msgstr ""
+msgstr "Es wurde nichts zum Importieren ausgewählt."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Importing Theme Items"
-msgstr "Theme importieren"
+msgstr "Am Importieren von Thema-Elementen"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Importing items {n}/{n}"
-msgstr ""
+msgstr "Am Importieren von Elementen {n}/{n}"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Updating the editor"
-msgstr "Editor verlassen?"
+msgstr "Den Editor aktualisieren?"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Finalizing"
-msgstr "Analysiere"
+msgstr "Fertigstellen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Filter:"
-msgstr "Filter: "
+msgstr "Filter:"
#: editor/plugins/theme_editor_plugin.cpp
msgid "With Data"
-msgstr ""
+msgstr "Mit Daten"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select by data type:"
-msgstr "Node auswählen"
+msgstr "Nach Datentyp auswählen:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible color items."
-msgstr "Teilung zum Löschen auswählen."
+msgstr "Alle sichtbaren Farbelemente auswählen."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible color items and their data."
-msgstr ""
+msgstr "Alle sichtbaren Farbelemente und deren Daten auswählen."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible color items."
-msgstr ""
+msgstr "Alle sichtbaren Farbelemente abwählen."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible constant items."
-msgstr "Zuerst Einstellungspunkt auswählen!"
+msgstr "Alle sichtbaren konstanten Elemente auswählen."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible constant items and their data."
-msgstr ""
+msgstr "Alle sichtbaren konstanten Elemente und ihre Daten auswählen."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible constant items."
-msgstr ""
+msgstr "Alle sichtbaren konstanten Elemente abwählen."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible font items."
-msgstr "Zuerst Einstellungspunkt auswählen!"
+msgstr "Alle sichtbaren Schriftart-Elemente auswählen."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible font items and their data."
-msgstr ""
+msgstr "Alle sichtbaren Schriftart-Elemente und ihre Daten auswählen."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible font items."
-msgstr ""
+msgstr "Alle sichtbaren Schriftart-Elemente abwählen."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible icon items."
-msgstr "Zuerst Einstellungspunkt auswählen!"
+msgstr "Alle sichtbaren Symbolelemente auswählen."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible icon items and their data."
-msgstr "Zuerst Einstellungspunkt auswählen!"
+msgstr "Alle sichtbaren Symbolelemente und ihre Daten auswählen."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Deselect all visible icon items."
-msgstr "Zuerst Einstellungspunkt auswählen!"
+msgstr "Alle sichtbaren Symbolelemente abwählen."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible stylebox items."
-msgstr ""
+msgstr "Alle sichtbaren Style-Box-Elemente auswählen."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible stylebox items and their data."
-msgstr ""
+msgstr "Alle sichtbaren Style-Box-Elemente und ihre Daten auswählen."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible stylebox items."
-msgstr ""
+msgstr "Alle sichtbaren Style-Box-Elemente abwählen."
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
"Caution: Adding icon data may considerably increase the size of your Theme "
"resource."
msgstr ""
+"Vorsicht: Das Hinzufügen von Symbolelement-Daten kann die Thema-Ressource "
+"erheblich vergrößern."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Collapse types."
-msgstr "Alle einklappen"
+msgstr "Typen einklappen."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Expand types."
-msgstr "Alle ausklappen"
+msgstr "Typen ausklappen."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all Theme items."
-msgstr "Vorlagendatei auswählen"
+msgstr "Alle Thema-Elemente auswählen."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select With Data"
-msgstr "Punkte auswählen"
+msgstr "Mit Daten auswählen"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all Theme items with item data."
-msgstr ""
+msgstr "Alle Thema-Elemente mit Element-Daten auswählen."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Deselect All"
-msgstr "Alles auswählen"
+msgstr "Alles abwählen"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all Theme items."
-msgstr ""
+msgstr "Alle Themen-Elemente abwählen."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Import Selected"
-msgstr "Szene importieren"
+msgstr "Ausgewähltes importieren"
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
@@ -8801,271 +8744,245 @@ msgid ""
"closing this window.\n"
"Close anyway?"
msgstr ""
+"Es sind Elemente im „Elemente importieren“-Tab ausgewählt. Diese Auswahl "
+"wird beim Schließen des Fensters verloren gehen.\n"
+"Trotzdem schließen?"
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Color Items"
-msgstr "Alle Elemente entfernen"
+msgstr "Alle Farbelemente entfernen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Item"
-msgstr "Entferne Element"
+msgstr "Element umbenennen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Constant Items"
-msgstr "Alle Elemente entfernen"
+msgstr "Alle konstanten Elemente entfernen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Font Items"
-msgstr "Alle Elemente entfernen"
+msgstr "Alle Schriftart-Elemente entfernen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Icon Items"
-msgstr "Alle Elemente entfernen"
+msgstr "Alle Symbol-Elemente entfernen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All StyleBox Items"
-msgstr "Alle Elemente entfernen"
+msgstr "Alle StyleBox-Elemente entfernen"
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Color Item"
-msgstr "Füge Klassen-Element hinzu"
+msgstr "Farbelement hinzufügen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Constant Item"
-msgstr "Füge Klassen-Element hinzu"
+msgstr "Konstantes Element hinzufügen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Font Item"
-msgstr "Element hinzufügen"
+msgstr "Schriftart-Element hinzufügen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Icon Item"
-msgstr "Element hinzufügen"
+msgstr "Symbol-Element hinzufügen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Stylebox Item"
-msgstr "Alle Elemente hinzufügen"
+msgstr "StyleBox-Element hinzufügen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Color Item"
-msgstr "Entferne Klassen-Element"
+msgstr "Farbelement umbenennen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Constant Item"
-msgstr "Entferne Klassen-Element"
+msgstr "Konstantes Element umbenennen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Font Item"
-msgstr "Node umbenennen"
+msgstr "Schriftart-Element umbenennen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Icon Item"
-msgstr "Node umbenennen"
+msgstr "Symbol-Element umbenennen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Stylebox Item"
-msgstr "Ausgewähltes Element entfernen"
+msgstr "StyleBox-Element umbenennen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Invalid file, not a Theme resource."
-msgstr "Ungültige Datei, kein Audiobus-Layout."
+msgstr "Ungültige Datei, keine Thema-Ressource."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Invalid file, same as the edited Theme resource."
-msgstr ""
+msgstr "Ungültige Datei, ist identisch mit der bearbeiteten Thema-Ressource."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Manage Theme Items"
-msgstr "Vorlagen verwalten"
+msgstr "Thema-Elemente verwalten"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Edit Items"
-msgstr "Bearbeitbares Element"
+msgstr "Element bearbeiten"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Types:"
-msgstr "Typ:"
+msgstr "Typen:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Type:"
-msgstr "Typ:"
+msgstr "Typ hinzufügen:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Item:"
-msgstr "Element hinzufügen"
+msgstr "Element hinzufügen:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add StyleBox Item"
-msgstr "Alle Elemente hinzufügen"
+msgstr "StyleBox-Element hinzufügen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove Items:"
-msgstr "Entferne Element"
+msgstr "Elemente entfernen:"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove Class Items"
msgstr "Entferne Klassen-Element"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove Custom Items"
-msgstr "Entferne Klassen-Element"
+msgstr "Eigene Elemente entfernen"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Items"
msgstr "Alle Elemente entfernen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Theme Item"
-msgstr "GUI-Thema-Elemente"
+msgstr "Thema-Element hinzufügen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Old Name:"
-msgstr "Node-Name:"
+msgstr "Alter Name:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Import Items"
-msgstr "Theme importieren"
+msgstr "Elemente importieren"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Default Theme"
-msgstr "Standard"
+msgstr "Standard-Thema"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Editor Theme"
-msgstr "Thema bearbeiten"
+msgstr "Editor-Motiv"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select Another Theme Resource:"
-msgstr "Ressource löschen"
+msgstr "Andere Thema-Ressource auswählen:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Another Theme"
-msgstr "Theme importieren"
+msgstr "Anderes Design"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Confirm Item Rename"
-msgstr "Spur umbenennen"
+msgstr "Elementumbenennung bestätigen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Cancel Item Rename"
-msgstr "Stapelweise Umbenennung"
+msgstr "Elementumbenennung abbrechen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Override Item"
-msgstr "Überschreibungen"
+msgstr "Element überbrücken"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Unpin this StyleBox as a main style."
-msgstr ""
+msgstr "Diese StyleBox nicht mehr als Hauptstil markieren."
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
"Pin this StyleBox as a main style. Editing its properties will update the "
"same properties in all other StyleBoxes of this type."
msgstr ""
+"Diese StyleBox als Hauptstil markieren. Geänderte Eigenschaften dieser "
+"StyleBox werden ebenfalls in allen StyleBoxen des gleichen Typs geändert."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Type"
-msgstr "Art"
+msgstr "Typ hinzufügen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Item Type"
-msgstr "Element hinzufügen"
+msgstr "Elementtyp hinzufügen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Node Types:"
-msgstr "Node-Typ"
+msgstr "Node-Typen:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Show Default"
-msgstr "Standard laden"
+msgstr "Standard anzeigen"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Show default type items alongside items that have been overridden."
-msgstr ""
+msgstr "Standard Typelemente zusammen mit überbrückten Elementen anzeigen."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Override All"
-msgstr "Überschreibungen"
+msgstr "Alle überbrücken"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Override all default type items."
-msgstr ""
+msgstr "Alle Standard-Typelemente überbrücken."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Theme:"
-msgstr "Designvorlagen (Thema)"
+msgstr "Thema:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Manage Items..."
-msgstr "Exportvorlagen verwalten…"
+msgstr "Elemente verwalten…"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add, remove, organize and import Theme items."
-msgstr ""
+msgstr "Themenelemente hinzufügen, entfernen, verwalten und importieren."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Preview"
-msgstr "Vorschau"
+msgstr "Vorschau hinzufügen"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Default Preview"
-msgstr "Vorschau aktualisieren"
+msgstr "Standard-Vorschau"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select UI Scene:"
-msgstr "Quell-Mesh auswählen:"
+msgstr "UI-Szene auswählen:"
#: editor/plugins/theme_editor_preview.cpp
msgid ""
"Toggle the control picker, allowing to visually select control types for "
"edit."
msgstr ""
+"Auswahlmodus für Control-Nodes umschalten. Erlaubt das visuelle Auswählen "
+"von Control-Nodes zum Bearbeiten."
#: editor/plugins/theme_editor_preview.cpp
msgid "Toggle Button"
@@ -9100,9 +9017,8 @@ msgid "Checked Radio Item"
msgstr "Markiertes Element der Auswahl"
#: editor/plugins/theme_editor_preview.cpp
-#, fuzzy
msgid "Named Separator"
-msgstr "Ben. Trenner."
+msgstr "Benannter Trenner"
#: editor/plugins/theme_editor_preview.cpp
msgid "Submenu"
@@ -9155,19 +9071,21 @@ msgstr "Hat,Mehrere,Einstellungen"
#: editor/plugins/theme_editor_preview.cpp
msgid "Invalid path, the PackedScene resource was probably moved or removed."
msgstr ""
+"Ungültiger Pfad. Die PackedScene-Ressource wurde vermutlich verschoben oder "
+"gelöscht."
#: editor/plugins/theme_editor_preview.cpp
msgid "Invalid PackedScene resource, must have a Control node at its root."
msgstr ""
+"Ungültige PackedScene-Ressource. Muss ein Control-Node als Wurzel haben."
#: editor/plugins/theme_editor_preview.cpp
-#, fuzzy
msgid "Invalid file, not a PackedScene resource."
-msgstr "Ungültige Datei, kein Audiobus-Layout."
+msgstr "Ungültige Datei, keine PackedScene-Ressource."
#: editor/plugins/theme_editor_preview.cpp
msgid "Reload the scene to reflect its most actual state."
-msgstr ""
+msgstr "Die Szene neu laden um ihren aktuellsten Status widerzuspiegeln."
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Erase Selection"
@@ -10574,9 +10492,8 @@ msgid "VisualShader"
msgstr "VisuellerShader"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Edit Visual Property:"
-msgstr "Visuelle Eigenschaft bearbeiten"
+msgstr "Visuelle Eigenschaft bearbeiten:"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Visual Shader Mode Changed"
@@ -10701,9 +10618,8 @@ msgid "Script"
msgstr "Skript"
#: editor/project_export.cpp
-#, fuzzy
msgid "GDScript Export Mode:"
-msgstr "Skript-Exportmodus:"
+msgstr "GDScript-Exportmodus:"
#: editor/project_export.cpp
msgid "Text"
@@ -10711,21 +10627,21 @@ msgstr "Text"
#: editor/project_export.cpp
msgid "Compiled Bytecode (Faster Loading)"
-msgstr ""
+msgstr "Kompilierter Bytecode (schnelleres Laden)"
#: editor/project_export.cpp
msgid "Encrypted (Provide Key Below)"
msgstr "Verschlüsselt (Schlüssel unten angeben)"
#: editor/project_export.cpp
-#, fuzzy
msgid "Invalid Encryption Key (must be 64 hexadecimal characters long)"
-msgstr "Ungültiger Schlüssel für Verschlüsselung (muss 64 Zeichen lang sein)"
+msgstr ""
+"Ungültiger Schlüssel für Verschlüsselung (muss aus 64 hexadezimalen Zeichen "
+"bestehen)"
#: editor/project_export.cpp
-#, fuzzy
msgid "GDScript Encryption Key (256-bits as hexadecimal):"
-msgstr "Skript-Schlüssel (256 Bit hexadezimal):"
+msgstr "Schlüssel zur GDScript-Verschlüsselung (256 bit, hexadezimal):"
#: editor/project_export.cpp
msgid "Export PCK/Zip"
@@ -10797,7 +10713,6 @@ msgid "Imported Project"
msgstr "Importiertes Projekt"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Invalid project name."
msgstr "Ungültiger Projektname."
@@ -11027,14 +10942,12 @@ msgid "Are you sure to run %d projects at once?"
msgstr "Sollen wirklich %d Projekte gleichzeitig ausgeführt werden?"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove %d projects from the list?"
-msgstr "Gerät aus Liste auswählen"
+msgstr "%d Projekte aus Liste entfernen?"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove this project from the list?"
-msgstr "Gerät aus Liste auswählen"
+msgstr "Dieses Projekt von Liste entfernen?"
#: editor/project_manager.cpp
msgid ""
@@ -11067,9 +10980,8 @@ msgid "Project Manager"
msgstr "Projektverwaltung"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Local Projects"
-msgstr "Projekte"
+msgstr "Lokale Projekte"
#: editor/project_manager.cpp
msgid "Loading, please wait..."
@@ -11080,23 +10992,20 @@ msgid "Last Modified"
msgstr "Zuletzt bearbeitet"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Edit Project"
-msgstr "Projekt exportieren"
+msgstr "Projekt bearbeiten"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Run Project"
-msgstr "Projekt umbenennen"
+msgstr "Projekt ausführen"
#: editor/project_manager.cpp
msgid "Scan"
msgstr "Scannen"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Scan Projects"
-msgstr "Projekte"
+msgstr "Nach Projekten suchen"
#: editor/project_manager.cpp
msgid "Select a Folder to Scan"
@@ -11107,14 +11016,12 @@ msgid "New Project"
msgstr "Neues Projekt"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Import Project"
-msgstr "Importiertes Projekt"
+msgstr "Projekt importieren"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove Project"
-msgstr "Projekt umbenennen"
+msgstr "Projekt entfernen"
#: editor/project_manager.cpp
msgid "Remove Missing"
@@ -11125,9 +11032,8 @@ msgid "About"
msgstr "Über"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Asset Library Projects"
-msgstr "Bestandsbibliothek (AssetLib)"
+msgstr "Nutzerinhalte-Projekte"
#: editor/project_manager.cpp
msgid "Restart Now"
@@ -11139,7 +11045,7 @@ msgstr "Alles entfernen"
#: editor/project_manager.cpp
msgid "Also delete project contents (no undo!)"
-msgstr ""
+msgstr "Ebenfalls Projektinhalte löschen (nicht rückgängig machbar!)"
#: editor/project_manager.cpp
msgid "Can't run project"
@@ -11155,21 +11061,19 @@ msgstr ""
"werden?"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Filter projects"
-msgstr "Eigenschaften filtern"
+msgstr "Projekte filtern"
#: editor/project_manager.cpp
-#, fuzzy
msgid ""
"This field filters projects by name and last path component.\n"
"To filter projects by name and full path, the query must contain at least "
"one `/` character."
msgstr ""
-"Die Suchmaske filtert Projekte nach ihrem Namen oder der letzten Komponente "
-"ihres Pfadnamens.\n"
-"Um den Filter auf den gesamten Pfadnamen anzuwenden muss mindestens ein ‚/‘-"
-"Zeichen in der Suchanfrage vorhanden sein."
+"Diese Suchmaske filtert Projekte nach ihrem Namen oder der letzten "
+"Komponente ihres Pfadnamens.\n"
+"Um nach dem kompletten Pfad zu filtern muss mindestens ein ‚/‘-Zeichen in "
+"der Suchanfrage vorhanden sein."
#: editor/project_settings_editor.cpp
msgid "Key "
@@ -11177,7 +11081,7 @@ msgstr "Taste "
#: editor/project_settings_editor.cpp
msgid "Physical Key"
-msgstr ""
+msgstr "Physische Taste"
#: editor/project_settings_editor.cpp
msgid "Joy Button"
@@ -11225,7 +11129,7 @@ msgstr "Gerät"
#: editor/project_settings_editor.cpp
msgid " (Physical)"
-msgstr ""
+msgstr " (physisch)"
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "Press a Key..."
@@ -11368,23 +11272,20 @@ msgid "Override for Feature"
msgstr "Für Funktion überschreiben"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Add %d Translations"
-msgstr "Übersetzung hinzufügen"
+msgstr "%d Übersetzungen hinzufügen"
#: editor/project_settings_editor.cpp
msgid "Remove Translation"
msgstr "Übersetzung entfernen"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Translation Resource Remap: Add %d Path(s)"
-msgstr "Ressourcen-Umleitung hinzufügen"
+msgstr "Übersetzungsressourcenumschreibung: %d Pfad(e) hinzufügen"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Translation Resource Remap: Add %d Remap(s)"
-msgstr "Ressourcen-Umleitung hinzufügen"
+msgstr "Übersetzungsressourcenumschreibung: %d Umschreibung(en) hinzufügen"
#: editor/project_settings_editor.cpp
msgid "Change Resource Remap Language"
@@ -11831,12 +11732,16 @@ msgstr "Node „%s“ löschen?"
msgid ""
"Saving the branch as a scene requires having a scene open in the editor."
msgstr ""
+"Um den Zweig als Szene speichern zu können muss eine Szene im Editor "
+"geöffnet sein."
#: editor/scene_tree_dock.cpp
msgid ""
"Saving the branch as a scene requires selecting only one node, but you have "
"selected %d nodes."
msgstr ""
+"Um den Zweig als Szene speichern zu können darf nur ein Node ausgewählt "
+"sein. Es sind allerdings %d Nodes ausgewählt."
#: editor/scene_tree_dock.cpp
msgid ""
@@ -11845,6 +11750,11 @@ msgid ""
"FileSystem dock context menu\n"
"or create an inherited scene using Scene > New Inherited Scene... instead."
msgstr ""
+"Der Wurzel-Node-Zweig kann nicht als instantiierte Szene gespeichert "
+"werden.\n"
+"Eine bearbeitbare Kopie der aktuellen Szene kann im Kontextmenü der "
+"Dateisystemleiste\n"
+"oder im Menü unter „Szene > Neue geerbte Szene…“ erstellt werden."
#: editor/scene_tree_dock.cpp
msgid ""
@@ -11852,6 +11762,10 @@ msgid ""
"To create a variation of a scene, you can make an inherited scene based on "
"the instanced scene using Scene > New Inherited Scene... instead."
msgstr ""
+"Zeig einer bereits instantiierten Szene kann nicht gespeichert werden.\n"
+"Ein Abwandlung der Szene zu erstellen, kann eine geerbten Szene, basiert auf "
+"der instantiierten Szene, im Menü unter „Szene > Neue geerbte Szene…“ "
+"erzeugt werden."
#: editor/scene_tree_dock.cpp
msgid "Save New Scene As..."
@@ -12260,6 +12174,8 @@ msgid ""
"Warning: Having the script name be the same as a built-in type is usually "
"not desired."
msgstr ""
+"Hinweis: Der Skriptname ist identisch mit dem Name eines Built-In-Typs, "
+"üblicherweise ein Fehler."
#: editor/script_create_dialog.cpp
msgid "Class Name:"
@@ -12331,7 +12247,7 @@ msgstr "Fehlermeldung kopieren"
#: editor/script_editor_debugger.cpp
msgid "Open C++ Source on GitHub"
-msgstr ""
+msgstr "C++-Quelldatei auf GitHub aufrufen"
#: editor/script_editor_debugger.cpp
msgid "Video RAM"
@@ -12509,6 +12425,16 @@ msgstr "Zylinderformhöhe ändern"
msgid "Change Ray Shape Length"
msgstr "Ändere Länge der Strahlenform"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Kurvenpunktposition festlegen"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Kurvenpunktposition festlegen"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "Zylinderradius ändern"
@@ -12620,14 +12546,12 @@ msgid "Object can't provide a length."
msgstr "Objekt kann keine Länge vorweisen."
#: modules/gltf/editor_scene_exporter_gltf_plugin.cpp
-#, fuzzy
msgid "Export Mesh GLTF2"
-msgstr "MeshLibrary exportieren"
+msgstr "GLTF2-Mesh exportieren"
#: modules/gltf/editor_scene_exporter_gltf_plugin.cpp
-#, fuzzy
msgid "Export GLTF..."
-msgstr "Exportieren..."
+msgstr "GLTF exportieren..."
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Next Plane"
@@ -12670,9 +12594,8 @@ msgid "GridMap Paint"
msgstr "GridMap zeichnen"
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "GridMap Selection"
-msgstr "GridMap-Auswahl füllen"
+msgstr "GridMap-Auswahl"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Grid Map"
@@ -12925,14 +12848,12 @@ msgid "Add Output Port"
msgstr "Ausgangsschnittstelle hinzufügen"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Change Port Type"
-msgstr "Typ ändern"
+msgstr "Schnittstellentyp ändern"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Change Port Name"
-msgstr "Eingangsschnittstellenname ändern"
+msgstr "Schnittstellenname ändern"
#: modules/visual_script/visual_script_editor.cpp
msgid "Override an existing built-in function."
@@ -13047,9 +12968,8 @@ msgid "Add Preload Node"
msgstr "Preload-Node hinzufügen"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Node(s)"
-msgstr "Node hinzufügen"
+msgstr "Node(s) hinzufügen"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Node(s) From Tree"
@@ -13316,37 +13236,31 @@ msgstr "Gerät aus Liste auswählen"
#: platform/android/export/export.cpp
msgid "Running on %s"
-msgstr ""
+msgstr "Läuft auf %s"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Exporting APK..."
-msgstr "Exportiere alles"
+msgstr "APK exportieren…"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Uninstalling..."
-msgstr "Deinstallieren"
+msgstr "Am Deinstallieren…"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Installing to device, please wait..."
-msgstr "Projekte werden geladen, bitte warten..."
+msgstr "Am Installieren auf Gerät, bitte warten..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not install to device: %s"
-msgstr "Konnte Szene nicht instantiieren!"
+msgstr "Konnte Installation auf Gerät nicht durchführen: %s"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Running on device..."
-msgstr "Angepasstes Skript wird ausgeführt..."
+msgstr "Auf Gerät ausführen…"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not execute on device."
-msgstr "Ordner konnte nicht erstellt werden."
+msgstr "Ließ sich nicht auf Gerät ausführen."
#: platform/android/export/export.cpp
msgid "Unable to find the 'apksigner' tool."
@@ -13475,40 +13389,37 @@ msgid ""
"directory.\n"
"The resulting %s is unsigned."
msgstr ""
+"‚apksigner‘ konnte nicht gefunden werden.\n"
+"Ist das Programm im Android SDK build-tools-Verzeichnis vorhanden?\n"
+"Das resultierende %s ist nicht signiert."
#: platform/android/export/export.cpp
msgid "Signing debug %s..."
-msgstr ""
+msgstr "Signiere Debug-Build %s…"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Signing release %s..."
-msgstr ""
-"Lese Dateien,\n"
-"Bitte warten..."
+msgstr "Signiere Release-Build %s…"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not find keystore, unable to export."
-msgstr "Konnte Vorlage nicht zum Export öffnen:"
+msgstr "Keystore konnte nicht gefunden werden, Export fehlgeschlagen."
#: platform/android/export/export.cpp
msgid "'apksigner' returned with error #%d"
-msgstr ""
+msgstr "‚apksigner‘ gab Fehlercode #%d zurück"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Verifying %s..."
-msgstr "%s hinzufügen…"
+msgstr "Verifiziere %s…"
#: platform/android/export/export.cpp
msgid "'apksigner' verification of %s failed."
-msgstr ""
+msgstr "‚apksigner‘-Verifizierung von %s fehlgeschlagen."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Exporting for Android"
-msgstr "Exportiere alles"
+msgstr "Exportiere für Android"
#: platform/android/export/export.cpp
msgid "Invalid filename! Android App Bundle requires the *.aab extension."
@@ -13527,7 +13438,7 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "Unsupported export format!\n"
-msgstr ""
+msgstr "Nicht unterstütztes Exportformat!\n"
#: platform/android/export/export.cpp
msgid ""
@@ -13554,16 +13465,16 @@ msgstr ""
msgid ""
"Unable to overwrite res://android/build/res/*.xml files with project name"
msgstr ""
+"Kann res://android/build/res/*.xml Dateien nicht mit Projektnamen "
+"überschreiben"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not export project files to gradle project\n"
-msgstr "project.godot konnte nicht im Projektpfad gefunden werden."
+msgstr "Konnte Projektdateien nicht als Gradle-Projekt exportieren\n"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not write expansion package file!"
-msgstr "Konnte Datei nicht schreiben:"
+msgstr "Konnte Expansion-Package-Datei nicht schreiben!"
#: platform/android/export/export.cpp
msgid "Building Android Project (gradle)"
@@ -13592,21 +13503,20 @@ msgstr ""
"im Gradle Projektverzeichnis erscheinen."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Package not found: %s"
-msgstr "Animation nicht gefunden: ‚%s‘"
+msgstr "Paket nicht gefunden: %s"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Creating APK..."
-msgstr "Konturen erzeugen..."
+msgstr "Erzeuge APK…"
#: platform/android/export/export.cpp
-#, fuzzy
msgid ""
"Could not find template APK to export:\n"
"%s"
-msgstr "Konnte Vorlage nicht zum Export öffnen:"
+msgstr ""
+"Konnte keine APK-Vorlage zum Exportieren finden:\n"
+"%s"
#: platform/android/export/export.cpp
msgid ""
@@ -13615,16 +13525,18 @@ msgid ""
"Please build a template with all required libraries, or uncheck the missing "
"architectures in the export preset."
msgstr ""
+"Fehlende Bibliotheken in Exportvorlage für die ausgewählten Architekturen: "
+"%s.\n"
+"Es muss entweder eine Exportvorlage mit den allen benötigten Bibliotheken "
+"gebaut werden oder die angegebenen Architekturen müssen abgewählt werden."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Adding files..."
-msgstr "%s hinzufügen…"
+msgstr "Füge Dateien hinzu…"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not export project files"
-msgstr "Konnte Datei nicht schreiben:"
+msgstr "Projektdateien konnten nicht exportiert werden"
#: platform/android/export/export.cpp
msgid "Aligning APK..."
@@ -13632,7 +13544,7 @@ msgstr "Richte APK aus..."
#: platform/android/export/export.cpp
msgid "Could not unzip temporary unaligned APK."
-msgstr ""
+msgstr "Temporäres unausgerichtetes APK konnte nicht entpackt werden."
#: platform/iphone/export/export.cpp platform/osx/export/export.cpp
msgid "Identifier is missing."
@@ -13680,45 +13592,40 @@ msgid "Could not write file:"
msgstr "Konnte Datei nicht schreiben:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not read file:"
-msgstr "Konnte Datei nicht schreiben:"
+msgstr "Konnte Datei nicht lesen:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not read HTML shell:"
-msgstr "Konnte benutzerdefinierte HTML-Shell nicht lesen:"
+msgstr "Konnte HTML-Shell nicht lesen:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not create HTTP server directory:"
-msgstr "Ordner konnte nicht erstellt werden."
+msgstr "Konnte HTTP-Server-Verzeichnis nicht erstellen:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Error starting HTTP server:"
-msgstr "Fehler beim Speichern der Szene."
+msgstr "Fehler beim Starten des HTTP-Servers:"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Invalid bundle identifier:"
-msgstr "Ungültiger Bezeichner:"
+msgstr "Ungültiger Bundle-Bezeichner:"
#: platform/osx/export/export.cpp
msgid "Notarization: code signing required."
-msgstr ""
+msgstr "Beglaubigung: Code-Signierung wird benötigt."
#: platform/osx/export/export.cpp
msgid "Notarization: hardened runtime required."
-msgstr ""
+msgstr "Beglaubigung: Abgehärtete Ausführungsumgebung wird benötigt."
#: platform/osx/export/export.cpp
msgid "Notarization: Apple ID name not specified."
-msgstr ""
+msgstr "Beglaubigung: Apple-ID-Name nicht angegeben."
#: platform/osx/export/export.cpp
msgid "Notarization: Apple ID password not specified."
-msgstr ""
+msgstr "Beglaubigung: Apple-ID-Passwort nicht angegeben."
#: platform/uwp/export/export.cpp
msgid "Invalid package short name."
@@ -14162,6 +14069,9 @@ msgid ""
"longer has any effect.\n"
"To remove this warning, disable the GIProbe's Compress property."
msgstr ""
+"Die Compress-Option von GIProbe gilt als veraltet wegen vorhandener Fehler "
+"und hat keinen Effekt mehr.\n"
+"Um diese Warnung zu deaktivieren, muss die Option deaktiviert werden."
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
@@ -14255,14 +14165,16 @@ msgstr "Node A und Node B müssen unterschiedliche PhysicsBody-Nodes sein"
#: scene/3d/portal.cpp
msgid "The RoomManager should not be a child or grandchild of a Portal."
msgstr ""
+"RoomManager darf kein direktes oder indirektes Unterelement von Portal sein."
#: scene/3d/portal.cpp
msgid "A Room should not be a child or grandchild of a Portal."
-msgstr ""
+msgstr "Room darf kein direktes oder indirektes Unterelement von Portal sein."
#: scene/3d/portal.cpp
msgid "A RoomGroup should not be a child or grandchild of a Portal."
msgstr ""
+"RoomGroup darf kein direktes oder indirektes Unterelement von Portal sein."
#: scene/3d/remote_transform.cpp
msgid ""
@@ -14275,41 +14187,85 @@ msgstr ""
#: scene/3d/room.cpp
msgid "A Room cannot have another Room as a child or grandchild."
msgstr ""
+"Room darf kein direktes oder indirektes Unterelement von einem anderen Room "
+"sein."
#: scene/3d/room.cpp
msgid "The RoomManager should not be placed inside a Room."
-msgstr ""
+msgstr "RoomManager darf nicht in einem Room platziert werden."
#: scene/3d/room.cpp
msgid "A RoomGroup should not be placed inside a Room."
-msgstr ""
+msgstr "RoomGroup darf nicht in einem Room platziert werden."
#: scene/3d/room.cpp
msgid ""
"Room convex hull contains a large number of planes.\n"
"Consider simplifying the room bound in order to increase performance."
msgstr ""
+"Die konvexe Hülle von Room enthält viele Ebenen.\n"
+"Es bietet sich an Room-Hülle zu vereinfachen um die Leistung zu steigern."
#: scene/3d/room_group.cpp
msgid "The RoomManager should not be placed inside a RoomGroup."
-msgstr ""
+msgstr "RoomManager darf nicht in einer RoomGroup platziert werden."
#: scene/3d/room_manager.cpp
msgid "The RoomList has not been assigned."
-msgstr ""
+msgstr "RoomList wurde nicht zugewiesen."
#: scene/3d/room_manager.cpp
msgid "The RoomList node should be a Spatial (or derived from Spatial)."
msgstr ""
+"Das RoomList-Node muss ein Spatial (oder ein von Spatial abgeleitetes Node) "
+"sein."
#: scene/3d/room_manager.cpp
msgid ""
"Portal Depth Limit is set to Zero.\n"
"Only the Room that the Camera is in will render."
msgstr ""
+"Die Portal-Tiefengrenze liegt bei Null.\n"
+"Nur der Raum, der die Kamera enthält, wird gerendert werden."
#: scene/3d/room_manager.cpp
msgid "There should only be one RoomManager in the SceneTree."
+msgstr "Es darf nur ein RoomManager im Szenenbaum vorhanden sein."
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
msgstr ""
#: scene/3d/soft_body.cpp
@@ -14378,7 +14334,7 @@ msgstr "Animation nicht gefunden: ‚%s‘"
#: scene/animation/animation_player.cpp
msgid "Anim Apply Reset"
-msgstr ""
+msgstr "Anim Reset anwenden"
#: scene/animation/animation_tree.cpp
msgid "In node '%s', invalid animation: '%s'."
@@ -14562,25 +14518,30 @@ msgid "Invalid comparison function for that type."
msgstr "Ungültige Vergleichsfunktion für diesen Typ."
#: servers/visual/shader_language.cpp
-#, fuzzy
msgid "Varying may not be assigned in the '%s' function."
-msgstr "Varyings können nur in Vertex-Funktion zugewiesen werden."
+msgstr "Varyings dürfen nicht in Funktion ‚%s‘ zugewiesen werden."
#: servers/visual/shader_language.cpp
msgid ""
"Varyings which assigned in 'vertex' function may not be reassigned in "
"'fragment' or 'light'."
msgstr ""
+"Varyings, welche in der ‚vertex‘-Funktion zugewiesen wurden, können nicht "
+"erneut in der ‚fragment‘- oder ‚light‘-Funktion zugewiesen werden."
#: servers/visual/shader_language.cpp
msgid ""
"Varyings which assigned in 'fragment' function may not be reassigned in "
"'vertex' or 'light'."
msgstr ""
+"Varyings, welche in der ‚fragment‘-Funktion zugewiesen wurden, können nicht "
+"erneut in der ‚vertex‘- oder ‚light‘-Funktion zugewiesen werden."
#: servers/visual/shader_language.cpp
msgid "Fragment-stage varying could not been accessed in custom function!"
msgstr ""
+"Varying aus Fragment-Phase konnte nicht in gesonderter Funktion abgerufen "
+"werden!"
#: servers/visual/shader_language.cpp
msgid "Assignment to function."
@@ -15780,9 +15741,6 @@ msgstr "Konstanten können nicht verändert werden."
#~ msgid "I see..."
#~ msgstr "Verstehe..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "‚%s‘ kann nicht geöffnet werden."
-
#~ msgid "Ugh"
#~ msgstr "Ähm"
diff --git a/editor/translations/editor.pot b/editor/translations/editor.pot
index bbd0bf9a6a..0f3b125484 100644
--- a/editor/translations/editor.pot
+++ b/editor/translations/editor.pot
@@ -331,6 +331,7 @@ msgstr ""
msgid "Remove Anim Track"
msgstr ""
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr ""
@@ -355,10 +356,25 @@ msgstr ""
msgid "Anim Insert"
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "animation"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr ""
@@ -913,7 +929,7 @@ msgstr ""
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2204,6 +2220,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -2983,10 +3010,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr ""
@@ -3591,6 +3614,14 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+msgid "Open in Web Browser"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8268,6 +8299,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Color Items"
msgstr ""
@@ -8292,6 +8329,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
msgstr ""
@@ -11699,6 +11742,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13293,6 +13344,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/el.po b/editor/translations/el.po
index b26b28b5d4..93b5941f64 100644
--- a/editor/translations/el.po
+++ b/editor/translations/el.po
@@ -350,6 +350,7 @@ msgstr "Αλλαγή λειτουÏγίας επανάληψης κίνησης"
msgid "Remove Anim Track"
msgstr "ΑφαίÏεση ÎšÎ¿Î¼Î¼Î±Ï„Î¹Î¿Ï ÎšÎ¯Î½Î·ÏƒÎ·Ï‚"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "ΔημιουÏγία νέου ÎºÎ¿Î¼Î¼Î±Ï„Î¹Î¿Ï Î³Î¹Î± %s και εισαγωγή κλειδιοÏ;"
@@ -374,10 +375,28 @@ msgstr "ΔημιουÏγία"
msgid "Anim Insert"
msgstr "Εισαγωγή Κίνησης"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "ΑδÏνατο το άνοιγμα του '%s'."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Κίνηση"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "Ένα AnimationPlayer δεν μποÏεί να κινήσει τον εαυτό του."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Η ιδιότητα '%s' δεν υπάÏχει."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "ΔημιουÏγία & Εισαγωγή Κίνησης"
@@ -960,7 +979,7 @@ msgstr "ΔημιουÏγία νέου %s"
msgid "No results for \"%s\"."
msgstr "Κανένα αποτέλεσμα για \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2312,6 +2331,17 @@ msgid "New Window"
msgstr "Îέο ΠαÏάθυÏο"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "ΠεÏιστÏέφεται όταν το παÏάθυÏο του επεξεÏγαστή επαναχÏωματίζεται."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Οι εισαγμένοι πόÏοι δεν μποÏοÏν να αποθηκευτοÏν."
@@ -3190,10 +3220,6 @@ msgid "Save & Restart"
msgstr "Αποθήκευση & Επανεκκίνηση"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "ΠεÏιστÏέφεται όταν το παÏάθυÏο του επεξεÏγαστή επαναχÏωματίζεται."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Συνεχόμενη Ανανέωση"
@@ -3859,6 +3885,16 @@ msgid "Download from:"
msgstr "Σφάλμα λήψης"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Εκτέλεση στον πεÏιηγητή"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "ΑντιγÏαφή σφάλματος"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8759,6 +8795,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "ΑφαίÏεση όλων των στοιχείων"
@@ -8789,6 +8831,12 @@ msgid "Remove All StyleBox Items"
msgstr "ΑφαίÏεση όλων των στοιχείων"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "ΠÏοσθήκη στοιχείων κλάσης"
@@ -12470,6 +12518,16 @@ msgstr "Αλλαγή Ύψους Σχήματος ΚυλίνδÏου"
msgid "Change Ray Shape Length"
msgstr "Αλλαγή μήκους ακτίνας"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "ΟÏισμός θέσης σημείου καμπÏλης"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "ΟÏισμός θέσης σημείου καμπÏλης"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "Αλλαγή Ακτίνας ΚυλίνδÏου"
@@ -14265,6 +14323,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr "Το σώμα αυτό δε θα ληφθεί υπόψιν μέχÏι να οÏίσετε ένα πλέγμα (mesh)."
@@ -15708,9 +15802,6 @@ msgstr "Οι σταθεÏές δεν μποÏοÏν να Ï„ÏοποποιηθοÏ
#~ msgid "I see..."
#~ msgstr "Εντάξει..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "ΑδÏνατο το άνοιγμα του '%s'."
-
#~ msgid "Ugh"
#~ msgstr "α..."
diff --git a/editor/translations/eo.po b/editor/translations/eo.po
index 51c69266cb..9f8c869bee 100644
--- a/editor/translations/eo.po
+++ b/editor/translations/eo.po
@@ -346,6 +346,7 @@ msgstr "Aliigi Animadon Iteracion Modon"
msgid "Remove Anim Track"
msgstr "Forigi animacian trakon"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Krei NOVAN trakon por %s kaj enmeti Ålosilon?"
@@ -370,10 +371,27 @@ msgstr "Krei"
msgid "Anim Insert"
msgstr "Animado Enmetu"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animacio"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "AnimationPlayer ne povas animi si mem, nur aliajn ludantojn."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Atributo"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Animado Krei & Enmeti"
@@ -949,7 +967,7 @@ msgstr "Kreu novan %s"
msgid "No results for \"%s\"."
msgstr "Ne rezultoj por \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2299,6 +2317,17 @@ msgid "New Window"
msgstr "Nova Fenestro"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Rotacius kiam la fenestron de la redaktilo redesegniÄi."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Enportitaj risurcoj ne povas konservi."
@@ -3169,10 +3198,6 @@ msgid "Save & Restart"
msgstr "Konservi kaj rekomenci"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Rotacius kiam la fenestron de la redaktilo redesegniÄi."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Äœisdatigi kontinue"
@@ -3827,6 +3852,16 @@ msgid "Download from:"
msgstr "ElÅuta eraro"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Ruli en foliumilo"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Kopii eraro"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8655,6 +8690,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Forigi elementon"
@@ -8685,6 +8726,12 @@ msgid "Remove All StyleBox Items"
msgstr "Forigi elementon"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Aldoni al favoritaj"
@@ -12208,6 +12255,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13839,6 +13894,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/es.po b/editor/translations/es.po
index 6f0b9cd14f..eef4affde3 100644
--- a/editor/translations/es.po
+++ b/editor/translations/es.po
@@ -68,11 +68,12 @@
# hiking <joaquinfc@protonmail.com>, 2021.
# pabloggomez <pgg2733@gmail.com>, 2021.
# Erick Figueroa <querecuto@hotmail.com>, 2021.
+# jonagamerpro1234 ss <js398704@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-07-29 02:33+0000\n"
+"PO-Revision-Date: 2021-08-12 14:48+0000\n"
"Last-Translator: Javier Ocampos <xavier.ocampos@gmail.com>\n"
"Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/"
"godot/es/>\n"
@@ -81,7 +82,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.7.2-dev\n"
+"X-Generator: Weblate 4.8-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -405,6 +406,7 @@ msgstr "Cambiar Modo Loop de Animación"
msgid "Remove Anim Track"
msgstr "Eliminar Pista de Animación"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "¿Crear nueva pista para %s e insertar clave?"
@@ -429,10 +431,28 @@ msgstr "Crear"
msgid "Anim Insert"
msgstr "Insertar Animación"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "No se puede abrir '%s'."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animación"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "Un AnimationPlayer no puede animarse a sí mismo, solo a otros players."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "No existe la propiedad '%s'."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Crear e Insertar Animación"
@@ -645,9 +665,8 @@ msgid "Go to Previous Step"
msgstr "Ir al Paso Anterior"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Apply Reset"
-msgstr "Resetear"
+msgstr "Aplicar Restablecer"
#: editor/animation_track_editor.cpp
msgid "Optimize Animation"
@@ -666,9 +685,8 @@ msgid "Use Bezier Curves"
msgstr "Usar Curvas Bezier"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Create RESET Track(s)"
-msgstr "Pegar Pistas"
+msgstr "Crear pista(s) RESET"
#: editor/animation_track_editor.cpp
msgid "Anim. Optimizer"
@@ -777,7 +795,7 @@ msgstr "%d coincidencias."
#: editor/code_editor.cpp editor/find_in_files.cpp
msgid "Match Case"
-msgstr "Coincidir Mayús./Minús."
+msgstr "Distinguir mayúsculas y minúsculas"
#: editor/code_editor.cpp editor/find_in_files.cpp
msgid "Whole Words"
@@ -995,9 +1013,8 @@ msgid "Edit..."
msgstr "Editar..."
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Go to Method"
-msgstr "Ir Al Método"
+msgstr "Ir al Método"
#: editor/create_dialog.cpp
msgid "Change %s Type"
@@ -1015,9 +1032,9 @@ msgstr "Crear Nuevo %s"
msgid "No results for \"%s\"."
msgstr "No hay resultados para \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
-msgstr ""
+msgstr "No hay descripción disponible para %s."
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp
@@ -1117,18 +1134,16 @@ msgid "Owners Of:"
msgstr "Propietarios De:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove the selected files from the project? (Cannot be undone.)\n"
"Depending on your filesystem configuration, the files will either be moved "
"to the system trash or deleted permanently."
msgstr ""
-"¿Eliminar los archivos seleccionados del proyecto? (irreversible)\n"
-"Puedes encontrar los archivos eliminados en la papelera de reciclaje del "
-"sistema para restaurarlos."
+"¿Eliminar los archivos seleccionados del proyecto? (No se puede deshacer).\n"
+"Dependiendo de la configuración de su sistema de archivos, los archivos se "
+"moverán a la papelera del sistema o se eliminarán permanentemente."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1136,11 +1151,10 @@ msgid ""
"Depending on your filesystem configuration, the files will either be moved "
"to the system trash or deleted permanently."
msgstr ""
-"Otros recursos necesitan los archivos que estás intentando quitar para "
-"funcionar.\n"
-"¿Eliminarlos de todos modos? (irreversible)\n"
-"Puedes encontrar los archivos eliminados en la papelera de reciclaje del "
-"sistema para restaurarlos."
+"Otros recursos requieren los archivos que se eliminan para que funcionen.\n"
+"¿Eliminarlos de todos modos? (No se puede deshacer).\n"
+"Dependiendo de la configuración de su sistema de archivos, los archivos se "
+"moverán a la papelera del sistema o se eliminarán permanentemente."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1172,7 +1186,7 @@ msgstr "¡Errores al cargar!"
#: editor/dependency_editor.cpp
msgid "Permanently delete %d item(s)? (No undo!)"
-msgstr "¿Eliminar permanentemente %d ítem(s)? (¡No se puede deshacer!)"
+msgstr "¿Eliminar permanentemente %d elemento(s)? (¡No se puede deshacer!)"
#: editor/dependency_editor.cpp
msgid "Show Dependencies"
@@ -1310,41 +1324,39 @@ msgid "Licenses"
msgstr "Licencias"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Error opening asset file for \"%s\" (not in ZIP format)."
-msgstr "Error al abrir el archivo del paquete (no está en formato ZIP)."
+msgstr ""
+"Error al abrir el archivo de assets para \"%s\" (no se encuentra en formato "
+"ZIP)."
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "%s (already exists)"
-msgstr "%s (Ya existe)"
+msgstr "%s (ya existe)"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - %d file(s) conflict with your project:"
-msgstr ""
+msgstr "El contenido del asset \"%s\" - %d entra en conflicto con el proyecto:"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - No files conflict with your project:"
msgstr ""
+"Contenido del asset \"%s\" - No hay archivos en conflicto con el proyecto:"
#: editor/editor_asset_installer.cpp
msgid "Uncompressing Assets"
-msgstr "Descomprimiendo Assets"
+msgstr "Descomprimir Assets"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "The following files failed extraction from asset \"%s\":"
-msgstr "Los siguientes archivos no se pudieron extraer del paquete:"
+msgstr "Ha fallado la extracción de los siguientes archivos del asset \"%s\":"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "(and %s more files)"
-msgstr "Y %d archivos más."
+msgstr "(y %s archivos más)"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset \"%s\" installed successfully!"
-msgstr "¡Paquete instalado con éxito!"
+msgstr "¡El asset \"%s\" ha sido instalado con éxito!"
#: editor/editor_asset_installer.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -1356,9 +1368,8 @@ msgid "Install"
msgstr "Instalar"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset Installer"
-msgstr "Instalador de paquetes"
+msgstr "Instalador de Assets"
#: editor/editor_audio_buses.cpp
msgid "Speakers"
@@ -1421,7 +1432,6 @@ msgid "Bypass"
msgstr "Omitir"
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "Bus Options"
msgstr "Opciones de Bus"
@@ -1589,13 +1599,12 @@ msgid "Can't add autoload:"
msgstr "No se puede añadir un autoload:"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "%s is an invalid path. File does not exist."
msgstr "El archivo no existe."
#: editor/editor_autoload_settings.cpp
msgid "%s is an invalid path. Not in resource path (res://)."
-msgstr ""
+msgstr "%s es una ruta inválida. No está en la ruta del recurso (res://)."
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -1619,7 +1628,6 @@ msgid "Name"
msgstr "Nombre"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "Global Variable"
msgstr "Variable"
@@ -1778,7 +1786,7 @@ msgstr "Editor de Script"
#: editor/editor_feature_profile.cpp
msgid "Asset Library"
-msgstr "Biblioteca de Assets"
+msgstr "Librería de Assets"
#: editor/editor_feature_profile.cpp
msgid "Scene Tree Editing"
@@ -1798,48 +1806,54 @@ msgstr "Importación"
#: editor/editor_feature_profile.cpp
msgid "Allows to view and edit 3D scenes."
-msgstr ""
+msgstr "Permite ver y editar escenas 3D."
#: editor/editor_feature_profile.cpp
msgid "Allows to edit scripts using the integrated script editor."
-msgstr ""
+msgstr "Permite editar scripts utilizando el editor de scripts integrado."
#: editor/editor_feature_profile.cpp
msgid "Provides built-in access to the Asset Library."
-msgstr ""
+msgstr "Proporciona acceso integrado a la Librería de Assets."
#: editor/editor_feature_profile.cpp
msgid "Allows editing the node hierarchy in the Scene dock."
-msgstr ""
+msgstr "Permite editar la jerarquía de nodos en el dock de Escena."
#: editor/editor_feature_profile.cpp
msgid ""
"Allows to work with signals and groups of the node selected in the Scene "
"dock."
msgstr ""
+"Permite trabajar con señales y grupos del nodo seleccionado en el dock de "
+"Escena."
#: editor/editor_feature_profile.cpp
msgid "Allows to browse the local file system via a dedicated dock."
msgstr ""
+"Permite navegar por el sistema de archivos local a través de un dock "
+"dedicado."
#: editor/editor_feature_profile.cpp
msgid ""
"Allows to configure import settings for individual assets. Requires the "
"FileSystem dock to function."
msgstr ""
+"Permite configurar los ajustes de importación para assets individuales. "
+"Requiere el dock FileSystem para funcionar."
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "(current)"
-msgstr "(Actual)"
+msgstr "(actual)"
#: editor/editor_feature_profile.cpp
msgid "(none)"
-msgstr ""
+msgstr "(ninguno)"
#: editor/editor_feature_profile.cpp
msgid "Remove currently selected profile, '%s'? Cannot be undone."
msgstr ""
+"¿Eliminar el perfil seleccionado en este momento, '%s'? No se puede deshacer."
#: editor/editor_feature_profile.cpp
msgid "Profile must be a valid filename and must not contain '.'"
@@ -1871,19 +1885,16 @@ msgid "Enable Contextual Editor"
msgstr "Activar el Editor Contextual"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Class Properties:"
-msgstr "Propiedades:"
+msgstr "Propiedades de Clase:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Main Features:"
-msgstr "Características"
+msgstr "Características principales:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Nodes and Classes:"
-msgstr "Clases Activadas:"
+msgstr "Clases y Nodos:"
#: editor/editor_feature_profile.cpp
msgid "File '%s' format is invalid, import aborted."
@@ -1903,7 +1914,6 @@ msgid "Error saving profile to path: '%s'."
msgstr "Error al guardar el perfil en la ruta: '%s'."
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Reset to Default"
msgstr "Restablecer Valores por Defecto"
@@ -1912,14 +1922,12 @@ msgid "Current Profile:"
msgstr "Perfil Actual:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Create Profile"
-msgstr "Borrar Perfil"
+msgstr "Crear perfil"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Remove Profile"
-msgstr "Eliminar Tile"
+msgstr "Eliminar perfil"
#: editor/editor_feature_profile.cpp
msgid "Available Profiles:"
@@ -1939,18 +1947,17 @@ msgid "Export"
msgstr "Exportar"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Configure Selected Profile:"
-msgstr "Perfil Actual:"
+msgstr "Configurar el perfil seleccionado:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Extra Options:"
-msgstr "Opciones de textura"
+msgstr "Opciones adicionales:"
#: editor/editor_feature_profile.cpp
msgid "Create or import a profile to edit available classes and properties."
msgstr ""
+"Crea o importa un perfil para editar las clases y propiedades disponibles."
#: editor/editor_feature_profile.cpp
msgid "New profile name:"
@@ -1977,9 +1984,8 @@ msgid "Select Current Folder"
msgstr "Seleccionar Carpeta Actual"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
-#, fuzzy
msgid "File exists, overwrite?"
-msgstr "El archivo ya existe ¿Quieres sobreescribirlo?"
+msgstr "El archivo existe, ¿sobrescribirlo?"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Select This Folder"
@@ -2105,11 +2111,11 @@ msgstr "Mostrar/Ocultar archivos ocultos."
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "View items as a grid of thumbnails."
-msgstr "Ver ítems como una cuadrícula de miniaturas."
+msgstr "Ver elementos como una cuadrícula de miniaturas."
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "View items as a list."
-msgstr "Ver ítems como una lista."
+msgstr "Ver elementos como una lista."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Directories & Files:"
@@ -2138,7 +2144,7 @@ msgstr ""
#: editor/editor_file_system.cpp
msgid "(Re)Importing Assets"
-msgstr "(Re)Importando Assets"
+msgstr "(Re)Importación de Assets"
#: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp
msgid "Top"
@@ -2183,7 +2189,7 @@ msgstr "Métodos"
#: editor/editor_help.cpp
msgid "Theme Properties"
-msgstr "Propiedades de Temas"
+msgstr "Propiedades del Theme"
#: editor/editor_help.cpp
msgid "Enumerations"
@@ -2260,7 +2266,7 @@ msgstr "Solo Propiedades"
#: editor/editor_help_search.cpp
msgid "Theme Properties Only"
-msgstr "Solo Propiedades del Tema"
+msgstr "Solo Propiedades del Theme"
#: editor/editor_help_search.cpp
msgid "Member Type"
@@ -2288,7 +2294,7 @@ msgstr "Propiedad"
#: editor/editor_help_search.cpp
msgid "Theme Property"
-msgstr "Propiedades del Tema"
+msgstr "Propiedades del Theme"
#: editor/editor_inspector.cpp editor/project_settings_editor.cpp
msgid "Property:"
@@ -2372,6 +2378,17 @@ msgid "New Window"
msgstr "Nueva Ventana"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Gira cuando la ventana del editor se redibuja."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Los recursos importados no se pueden guardar."
@@ -2604,13 +2621,16 @@ msgid ""
"The current scene has no root node, but %d modified external resource(s) "
"were saved anyway."
msgstr ""
+"La escena actual no tiene un nodo raíz, pero %d recurso(s) externo(s) "
+"modificado(s) fueron guardados igualmente."
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"A root node is required to save the scene. You can add a root node using the "
"Scene tree dock."
-msgstr "Se necesita un nodo raíz para guardar la escena."
+msgstr ""
+"Se requiere un nodo raíz para guardar la escena. Puede agregar un nodo raíz "
+"utilizando el muelle de árbol de escenas."
#: editor/editor_node.cpp
msgid "Save Scene As..."
@@ -2937,7 +2957,7 @@ msgstr "Convertir a..."
#: editor/editor_node.cpp
msgid "MeshLibrary..."
-msgstr "MeshLibrary..."
+msgstr "Biblioteca de malla..."
#: editor/editor_node.cpp
msgid "TileSet..."
@@ -2999,9 +3019,8 @@ msgid "Orphan Resource Explorer..."
msgstr "Explorador de Recursos Huérfanos..."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reload Current Project"
-msgstr "Renombrar Proyecto"
+msgstr "Recargar proyecto actual"
#: editor/editor_node.cpp
msgid "Quit to Project List"
@@ -3163,22 +3182,20 @@ msgid "Help"
msgstr "Ayuda"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Online Documentation"
-msgstr "Abrir Documentación"
+msgstr "Documentación en línea"
#: editor/editor_node.cpp
msgid "Questions & Answers"
-msgstr ""
+msgstr "Preguntas & Respuestas"
#: editor/editor_node.cpp
msgid "Report a Bug"
msgstr "Reportar un Bug"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Suggest a Feature"
-msgstr "Establecer valor"
+msgstr "Sugerir una característica"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
@@ -3189,9 +3206,8 @@ msgid "Community"
msgstr "Comunidad"
#: editor/editor_node.cpp
-#, fuzzy
msgid "About Godot"
-msgstr "Acerca de"
+msgstr "Sobre Godot"
#: editor/editor_node.cpp
msgid "Support Godot Development"
@@ -3243,10 +3259,6 @@ msgid "Save & Restart"
msgstr "Guardar y Reiniciar"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Gira cuando la ventana del editor se redibuja."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Actualizar Continuamente"
@@ -3289,14 +3301,12 @@ msgid "Manage Templates"
msgstr "Administrar Plantillas"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Install from file"
-msgstr "Instalar Desde Archivo"
+msgstr "Instalar desde archivo"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Select android sources file"
-msgstr "Selecciona una Malla de Origen:"
+msgstr "Seleccionar el archivo fuente de Android"
#: editor/editor_node.cpp
msgid ""
@@ -3380,9 +3390,8 @@ msgid "Select"
msgstr "Seleccionar"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Select Current"
-msgstr "Seleccionar Carpeta Actual"
+msgstr "Seleccionar actual"
#: editor/editor_node.cpp
msgid "Open 2D Editor"
@@ -3398,7 +3407,7 @@ msgstr "Abrir Editor de Script"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "Open Asset Library"
-msgstr "Abrir Biblioteca de Assets"
+msgstr "Abrir Librería de Assets"
#: editor/editor_node.cpp
msgid "Open the next Editor"
@@ -3417,9 +3426,8 @@ msgid "No sub-resources found."
msgstr "No se encontró ningún sub-recurso."
#: editor/editor_path.cpp
-#, fuzzy
msgid "Open a list of sub-resources."
-msgstr "No se encontró ningún sub-recurso."
+msgstr "Abra una lista de sub-recursos."
#: editor/editor_plugin.cpp
msgid "Creating Mesh Previews"
@@ -3446,14 +3454,12 @@ msgid "Update"
msgstr "Actualizar"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Version"
-msgstr "Versión:"
+msgstr "Versión"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Author"
-msgstr "Autores"
+msgstr "Autor"
#: editor/editor_plugin_settings.cpp
#: editor/plugins/version_control_editor_plugin.cpp
@@ -3466,14 +3472,12 @@ msgid "Measure:"
msgstr "Medida:"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Frame Time (ms)"
-msgstr "Duración de Fotogramas (seg)"
+msgstr "Duración de Fotogramas (ms)"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Average Time (ms)"
-msgstr "Tiempo Promedio (seg)"
+msgstr "Tiempo Promedio (ms)"
#: editor/editor_profiler.cpp
msgid "Frame %"
@@ -3500,6 +3504,12 @@ msgid ""
"functions called by that function.\n"
"Use this to find individual functions to optimize."
msgstr ""
+"Inclusivo: Incluye el tiempo de otras funciones llamadas por esta función.\n"
+"Utilízalo para detectar cuellos de botella.\n"
+"\n"
+"Propio: Sólo contabiliza el tiempo empleado en la propia función, no en "
+"otras funciones llamadas por esa función.\n"
+"Utilízalo para buscar funciones individuales que optimizar."
#: editor/editor_profiler.cpp
msgid "Frame #:"
@@ -3581,7 +3591,7 @@ msgstr "Página: "
#: editor/editor_properties_array_dict.cpp
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove Item"
-msgstr "Eliminar Ãtem"
+msgstr "Eliminar Elemento"
#: editor/editor_properties_array_dict.cpp
msgid "New Key:"
@@ -3622,7 +3632,6 @@ msgid "Paste"
msgstr "Pegar"
#: editor/editor_resource_picker.cpp editor/property_editor.cpp
-#, fuzzy
msgid "Convert to %s"
msgstr "Convertir a %s"
@@ -3674,11 +3683,10 @@ msgid "Did you forget the '_run' method?"
msgstr "Te olvidaste del método '_run'?"
#: editor/editor_spin_slider.cpp
-#, fuzzy
msgid "Hold %s to round to integers. Hold Shift for more precise changes."
msgstr ""
-"Mantén pulsado Ctrl para redondear a enteros. Mantén pulsado Shift para "
-"cambios más precisos."
+"Mantenga presionado %s para redondear a números enteros. Mantenga presionada "
+"la tecla Mayús para cambios más precisos."
#: editor/editor_sub_scene.cpp
msgid "Select Node(s) to Import"
@@ -3698,49 +3706,43 @@ msgstr "Importar Desde Nodo:"
#: editor/export_template_manager.cpp
msgid "Open the folder containing these templates."
-msgstr ""
+msgstr "Abra la carpeta que contiene estas plantillas."
#: editor/export_template_manager.cpp
msgid "Uninstall these templates."
-msgstr ""
+msgstr "Desinstalar estas plantillas."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "There are no mirrors available."
-msgstr "No hay ningún archivo `%s'."
+msgstr "No hay espejos disponibles."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Retrieving the mirror list..."
-msgstr "Obteniendo mirrors, por favor espera..."
+msgstr "Recuperar la lista de espejos..."
#: editor/export_template_manager.cpp
msgid "Starting the download..."
-msgstr ""
+msgstr "Comenzando la descarga..."
#: editor/export_template_manager.cpp
msgid "Error requesting URL:"
msgstr "Error al solicitar la URL:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Connecting to the mirror..."
-msgstr "Conectando con Mirror...."
+msgstr "Conectando con el espejo..."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't resolve the requested address."
-msgstr "No se ha podido resolver el nombre de dominio:"
+msgstr "No se puede resolver la dirección solicitada."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't connect to the mirror."
-msgstr "No se puede conectar al host:"
+msgstr "No se puede conectar al espejo."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "No response from the mirror."
-msgstr "No hay respuesta desde el host:"
+msgstr "No hay respuesta del espejo."
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -3748,18 +3750,16 @@ msgid "Request failed."
msgstr "Petición fallida."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Request ended up in a redirect loop."
-msgstr "Petición fallida, demasiadas redirecciones"
+msgstr "La solicitud terminó en un bucle de redirección."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Request failed:"
-msgstr "Petición fallida."
+msgstr "Petición fallida:"
#: editor/export_template_manager.cpp
msgid "Download complete; extracting templates..."
-msgstr ""
+msgstr "Descarga completa; extracción de plantillas..."
#: editor/export_template_manager.cpp
msgid "Cannot remove temporary file:"
@@ -3775,18 +3775,17 @@ msgstr ""
#: editor/export_template_manager.cpp
msgid "Error getting the list of mirrors."
-msgstr "Error al obtener la lista de mirrors."
+msgstr "Error al obtener la lista de espejos."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Error parsing JSON with the list of mirrors. Please report this issue!"
msgstr ""
-"Error al analizar el JSON de la lista de mirrors. ¡Por favor, informa de "
-"este problema!"
+"Error al analizar el JSON con la lista de espejos ¡Por favor, reporta este "
+"problema!"
#: editor/export_template_manager.cpp
msgid "Best available mirror"
-msgstr ""
+msgstr "El mejor espejo disponible"
#: editor/export_template_manager.cpp
msgid ""
@@ -3839,22 +3838,18 @@ msgid "SSL Handshake Error"
msgstr "Error de Negociación SSL"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't open the export templates file."
-msgstr "No se puede abir el zip de plantillas de exportación."
+msgstr "No se puede abrir el archivo de plantillas de exportación."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Invalid version.txt format inside the export templates file: %s."
msgstr "Formato de version.txt inválido dentro de plantillas: %s."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "No version.txt found inside the export templates file."
msgstr "No se ha encontrado el archivo version.txt dentro de las plantillas."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Error creating path for extracting templates:"
msgstr "Error al crear ruta para las plantillas:"
@@ -3867,9 +3862,8 @@ msgid "Importing:"
msgstr "Importando:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Remove templates for the version '%s'?"
-msgstr "¿Eliminar plantilla versión '%s'?"
+msgstr "¿Eliminar plantilla de la versión '%s'?"
#: editor/export_template_manager.cpp
msgid "Uncompressing Android Build Sources"
@@ -3886,43 +3880,57 @@ msgstr "Versión Actual:"
#: editor/export_template_manager.cpp
msgid "Export templates are missing. Download them or install from a file."
msgstr ""
+"Faltan las plantillas de exportación. Puede descargarlas o instalarlas desde "
+"un archivo."
#: editor/export_template_manager.cpp
msgid "Export templates are installed and ready to be used."
msgstr ""
+"Las plantillas de exportación están instaladas y listas para ser utilizadas."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Open Folder"
-msgstr "Abrir Archivo"
+msgstr "Abrir carpeta"
#: editor/export_template_manager.cpp
msgid "Open the folder containing installed templates for the current version."
msgstr ""
+"Abre la carpeta que contiene las plantillas instaladas para la versión "
+"actual."
#: editor/export_template_manager.cpp
msgid "Uninstall"
msgstr "Desinstalar"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Uninstall templates for the current version."
-msgstr "Valor inicial para el contador"
+msgstr "Desinstalar las plantillas de la versión actual."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Download from:"
-msgstr "Error de descarga"
+msgstr "Descargar desde:"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Ejecutar en Navegador"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Copiar Error"
#: editor/export_template_manager.cpp
msgid "Download and Install"
-msgstr ""
+msgstr "Descargar e instalar"
#: editor/export_template_manager.cpp
msgid ""
"Download and install templates for the current version from the best "
"possible mirror."
msgstr ""
+"Descarga e instala las plantillas de la versión actual desde el mejor espejo "
+"posible."
#: editor/export_template_manager.cpp
msgid "Official export templates aren't available for development builds."
@@ -3931,14 +3939,12 @@ msgstr ""
"versiones de desarrollo."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Install from File"
-msgstr "Instalar Desde Archivo"
+msgstr "Instalar desde un archivo"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Install templates from a local file."
-msgstr "Importar plantillas desde un archivo ZIP"
+msgstr "Instalar plantillas desde un archivo local."
#: editor/export_template_manager.cpp editor/find_in_files.cpp
#: editor/progress_dialog.cpp scene/gui/dialogs.cpp
@@ -3946,23 +3952,20 @@ msgid "Cancel"
msgstr "Cancelar"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Cancel the download of the templates."
-msgstr "No se puede abir el zip de plantillas de exportación."
+msgstr "Cancele la descarga de las plantillas."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Other Installed Versions:"
-msgstr "Versiones Instaladas:"
+msgstr "Otras versiones instaladas:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Uninstall Template"
-msgstr "Desinstalar"
+msgstr "Desinstalar plantilla"
#: editor/export_template_manager.cpp
msgid "Select Template File"
-msgstr "Selecciona un Archivo de Plantilla"
+msgstr "Seleccionar el archivo de la plantilla"
#: editor/export_template_manager.cpp
msgid "Godot Export Templates"
@@ -3973,6 +3976,8 @@ msgid ""
"The templates will continue to download.\n"
"You may experience a short editor freeze when they finish."
msgstr ""
+"Las plantillas seguirán descargándose.\n"
+"Es posible que experimente una breve congelación del editor cuando terminen."
#: editor/filesystem_dock.cpp
msgid "Favorites"
@@ -4120,35 +4125,32 @@ msgid "Collapse All"
msgstr "Colapsar Todo"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort files"
-msgstr "Buscar archivos"
+msgstr "Ordenar archivos"
#: editor/filesystem_dock.cpp
msgid "Sort by Name (Ascending)"
-msgstr ""
+msgstr "Ordenar por Nombre (Ascendente)"
#: editor/filesystem_dock.cpp
msgid "Sort by Name (Descending)"
-msgstr ""
+msgstr "Ordenar por Nombre (Descendente)"
#: editor/filesystem_dock.cpp
msgid "Sort by Type (Ascending)"
-msgstr ""
+msgstr "Ordenar por Tipo (Ascendente)"
#: editor/filesystem_dock.cpp
msgid "Sort by Type (Descending)"
-msgstr ""
+msgstr "Ordenar por Tipo (Descendente)"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort by Last Modified"
-msgstr "Ultima Modificación"
+msgstr "Ordenar por Última Modificación"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort by First Modified"
-msgstr "Ultima Modificación"
+msgstr "Ordenar por Primera Modificación"
#: editor/filesystem_dock.cpp
msgid "Duplicate..."
@@ -4160,7 +4162,7 @@ msgstr "Renombrar..."
#: editor/filesystem_dock.cpp
msgid "Focus the search box"
-msgstr ""
+msgstr "Enfocar el cuadro de búsqueda"
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -4461,22 +4463,20 @@ msgstr "Cambiar el tipo de un archivo importado requiere reiniciar el editor."
msgid ""
"WARNING: Assets exist that use this resource, they may stop loading properly."
msgstr ""
-"ADVERTENCIA: Existen recursos que utilizan este recurso, pueden dejar de "
-"cargar correctamente."
+"ADVERTENCIA: Existen assets que utilizan este recurso, pueden dejar de "
+"cargarse correctamente."
#: editor/inspector_dock.cpp
msgid "Failed to load resource."
msgstr "Error al cargar el recurso."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Copy Properties"
-msgstr "Propiedades"
+msgstr "Copiar Propiedades"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Paste Properties"
-msgstr "Propiedades"
+msgstr "Pegar Propiedades"
#: editor/inspector_dock.cpp
msgid "Make Sub-Resources Unique"
@@ -4501,23 +4501,20 @@ msgid "Save As..."
msgstr "Guardar como..."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Extra resource options."
-msgstr "No está en la ruta de recursos."
+msgstr "Opciones de recursos extra."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Edit Resource from Clipboard"
-msgstr "Editar Portapapeles de Recursos"
+msgstr "Editar Recurso desde el Portapapeles"
#: editor/inspector_dock.cpp
msgid "Copy Resource"
msgstr "Copiar Recurso"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Make Resource Built-In"
-msgstr "Crear Integrado"
+msgstr "Crear Recursos Integrados"
#: editor/inspector_dock.cpp
msgid "Go to the previous edited object in history."
@@ -4532,9 +4529,8 @@ msgid "History of recently edited objects."
msgstr "Historial de objetos recientemente editados."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Open documentation for this object."
-msgstr "Abrir Documentación"
+msgstr "Abrir la documentación de este objeto."
#: editor/inspector_dock.cpp editor/scene_tree_dock.cpp
msgid "Open Documentation"
@@ -4545,9 +4541,8 @@ msgid "Filter properties"
msgstr "Filtrar propiedades"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Manage object properties."
-msgstr "Propiedades del objeto."
+msgstr "Administrar propiedades de los objetos."
#: editor/inspector_dock.cpp
msgid "Changes may be lost!"
@@ -4793,9 +4788,8 @@ msgid "Blend:"
msgstr "Mezcla:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Parameter Changed:"
-msgstr "Parámetro Modificado"
+msgstr "Parámetro Modificado:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
@@ -5445,7 +5439,7 @@ msgstr "Fallo en la comprobación del hash SHA-256"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
-msgstr "Error en la descarga del asset:"
+msgstr "Error de Descarga de Assets:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Downloading (%s / %s)..."
@@ -5481,7 +5475,7 @@ msgstr "Error de descarga"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Download for this asset is already in progress!"
-msgstr "¡Éste asset ya está descargándose!"
+msgstr "¡La descarga de este asset ya está en proceso!"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Recently Updated"
@@ -5529,11 +5523,11 @@ msgstr "Todos"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Search templates, projects, and demos"
-msgstr ""
+msgstr "Buscar plantillas, proyectos y demostraciones"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Search assets (excluding templates, projects, and demos)"
-msgstr ""
+msgstr "Buscar assets (excluyendo plantillas, proyectos y demos)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Import..."
@@ -5573,11 +5567,11 @@ msgstr "Cargar..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Assets ZIP File"
-msgstr "Archivo ZIP de elementos"
+msgstr "Archivo ZIP de assets"
#: editor/plugins/audio_stream_editor_plugin.cpp
msgid "Audio Preview Play/Pause"
-msgstr ""
+msgstr "Previsualización de Audio Reproducir/Pausar"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
@@ -5838,13 +5832,13 @@ msgstr "Cambiar Anclas"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid ""
"Project Camera Override\n"
"Overrides the running project's camera with the editor viewport camera."
msgstr ""
-"Reemplazar Cámara del Juego\n"
-"Reemplaza la cámara del juego por la cámara del viewport del editor."
+"Anulación de la Cámara del Proyecto\n"
+"Anula la cámara del proyecto en ejecución por la cámara del viewport del "
+"editor."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5853,6 +5847,9 @@ msgid ""
"No project instance running. Run the project from the editor to use this "
"feature."
msgstr ""
+"Anulación de la Cámara del Proyecto\n"
+"No se está ejecutando ninguna instancia del proyecto. Ejecuta el proyecto "
+"desde el editor para utilizar esta función."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5920,32 +5917,27 @@ msgstr "Modo de Selección"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Drag: Rotate selected node around pivot."
-msgstr "Eliminar el nodo o transición seleccionado/a."
+msgstr "Arrastrar: Girar el nodo seleccionado alrededor del pivote."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Alt+Drag: Move selected node."
-msgstr "Alt+Arrastrar: Mover"
+msgstr "Alt+Arrastrar: Mover el nodo seleccionado."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "V: Set selected node's pivot position."
-msgstr "Eliminar el nodo o transición seleccionado/a."
+msgstr "V: Establecer la posición de pivote del nodo seleccionado."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Alt+RMB: Show list of all nodes at position clicked, including locked."
msgstr ""
-"Mostrar una lista de todos los objetos en la posición en la que se ha hecho "
-"clic\n"
-"(igual que Alt + Clic Derecho en modo selección)."
+"Alt + RMB: Muestra la lista de todos los nodos en la posición en la que se "
+"hizo clic, incluido el bloqueado."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "RMB: Add node at position clicked."
-msgstr ""
+msgstr "RMB: Añade un nodo en la posición seleccionada."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -6184,14 +6176,12 @@ msgid "Clear Pose"
msgstr "Limpiar Pose"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Add Node Here"
-msgstr "Añadir Nodo"
+msgstr "Añadir Nodo Aquí"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Instance Scene Here"
-msgstr "Instanciar Escena(s)"
+msgstr "Instanciar Escena Aquí"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Multiply grid step by 2"
@@ -6207,49 +6197,43 @@ msgstr "Vista Panorámica"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 3.125%"
-msgstr ""
+msgstr "Zoom al 3,125%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 6.25%"
-msgstr ""
+msgstr "Zoom al 6.25%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 12.5%"
-msgstr ""
+msgstr "Zoom al 12.5%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 25%"
-msgstr "Alejar Zoom"
+msgstr "Zoom al 25%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 50%"
-msgstr "Alejar Zoom"
+msgstr "Zoom al 50%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 100%"
-msgstr "Alejar Zoom"
+msgstr "Zoom al 100%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 200%"
-msgstr "Alejar Zoom"
+msgstr "Zoom al 200%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 400%"
-msgstr "Alejar Zoom"
+msgstr "Zoom al 400%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 800%"
-msgstr "Alejar Zoom"
+msgstr "Zoom al 800%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 1600%"
-msgstr ""
+msgstr "Zoom al 1600%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Add %s"
@@ -6451,15 +6435,15 @@ msgstr "Degradado Editado"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "Item %d"
-msgstr "Ãtem %d"
+msgstr "Elemento %d"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "Items"
-msgstr "Ãtems"
+msgstr "Elementos"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "Item List Editor"
-msgstr "Editor de Lista de Ãtems"
+msgstr "Editor de Lista de Elementos"
#: editor/plugins/light_occluder_2d_editor_plugin.cpp
msgid "Create Occluder Polygon"
@@ -6496,9 +6480,8 @@ msgid "Couldn't create a single convex collision shape."
msgstr "No pudo crear una única forma de colisión convexa."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Create Simplified Convex Shape"
-msgstr "Crear una Única Forma Convexa"
+msgstr "Crear Forma Convexa Simplificada"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Single Convex Shape"
@@ -6535,9 +6518,8 @@ msgid "No mesh to debug."
msgstr "No hay mallas para depurar."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Mesh has no UV in layer %d."
-msgstr "El modelo no tiene UV en esta capa"
+msgstr "La malla no tiene UV en la capa %d."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "MeshInstance lacks a Mesh!"
@@ -6602,9 +6584,8 @@ msgstr ""
"Es la opción más rápida (pero menos precisa) para la detección de colisiones."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Create Simplified Convex Collision Sibling"
-msgstr "Crear Collider Convexo Único Hermano"
+msgstr "Crear Forma de Colisión Conexa Hermana"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid ""
@@ -6612,20 +6593,23 @@ msgid ""
"This is similar to single collision shape, but can result in a simpler "
"geometry in some cases, at the cost of accuracy."
msgstr ""
+"Crea una forma de colisión convexa simplificada.\n"
+"Esto es similar a la forma de colisión simple, pero puede resultar en una "
+"geometría más simple en algunos casos, a costa de la precisión."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Multiple Convex Collision Siblings"
msgstr "Crear Múltiples Collider Convexos Hermanos"
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid ""
"Creates a polygon-based collision shape.\n"
"This is a performance middle-ground between a single convex collision and a "
"polygon-based collision."
msgstr ""
"Crea una forma de colisión basada en polígonos.\n"
-"Este es un punto medio de rendimiento entre las dos opciones anteriores."
+"Se trata de un punto intermedio de rendimiento entre una colisión convexa "
+"única y una colisión basada en polígonos."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Outline Mesh..."
@@ -6669,7 +6653,7 @@ msgstr "Depuración del Canal UV"
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Remove item %d?"
-msgstr "¿Eliminar el ítem %d?"
+msgstr "¿Eliminar el elemento %d?"
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid ""
@@ -6685,11 +6669,11 @@ msgstr "Librería de Mallas"
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Add Item"
-msgstr "Añadir Ãtem"
+msgstr "Añadir Elemento"
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Remove Selected Item"
-msgstr "Eliminar Ãtem Seleccionado"
+msgstr "Eliminar Elemento Seleccionado"
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Import from Scene"
@@ -6742,7 +6726,7 @@ msgstr "El origen de la superficie no es correcto (sin caras)."
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Select a Source Mesh:"
-msgstr "Selecciona una Malla de Origen:"
+msgstr "Seleccionar una Malla de Origen:"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Select a Target Surface:"
@@ -7275,24 +7259,20 @@ msgid "ResourcePreloader"
msgstr "Precargador de Recursos"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Flip Portals"
-msgstr "Voltear Horizontalmente"
+msgstr "Voltear Portales"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Room Generate Points"
-msgstr "Conteo de Puntos Generados:"
+msgstr "Generar Puntos en la Room"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Generate Points"
-msgstr "Conteo de Puntos Generados:"
+msgstr "Generar puntos"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Flip Portal"
-msgstr "Voltear Horizontalmente"
+msgstr "Voltear Portal"
#: editor/plugins/root_motion_editor_plugin.cpp
msgid "AnimationTree has no path set to an AnimationPlayer"
@@ -7324,7 +7304,7 @@ msgstr "¡Error guardando archivo!"
#: editor/plugins/script_editor_plugin.cpp
msgid "Error while saving theme."
-msgstr "Error al guardar el tema."
+msgstr "Error al guardar el theme."
#: editor/plugins/script_editor_plugin.cpp
msgid "Error Saving"
@@ -7332,7 +7312,7 @@ msgstr "Error al Guardar"
#: editor/plugins/script_editor_plugin.cpp
msgid "Error importing theme."
-msgstr "Error al importar el tema."
+msgstr "Error al importar el theme."
#: editor/plugins/script_editor_plugin.cpp
msgid "Error Importing"
@@ -7371,11 +7351,11 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Import Theme"
-msgstr "Importar Tema"
+msgstr "Importar Theme"
#: editor/plugins/script_editor_plugin.cpp
msgid "Error while saving theme"
-msgstr "Error al guardar el tema"
+msgstr "Error al guardar el theme"
#: editor/plugins/script_editor_plugin.cpp
msgid "Error saving"
@@ -7383,7 +7363,7 @@ msgstr "Error al guardar"
#: editor/plugins/script_editor_plugin.cpp
msgid "Save Theme As..."
-msgstr "Guardar Tema Como..."
+msgstr "Guardar Theme Como..."
#: editor/plugins/script_editor_plugin.cpp
msgid "%s Class Reference"
@@ -7470,19 +7450,19 @@ msgstr "Siguiente en el Historial"
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp
msgid "Theme"
-msgstr "Tema"
+msgstr "Theme"
#: editor/plugins/script_editor_plugin.cpp
msgid "Import Theme..."
-msgstr "Importar Tema..."
+msgstr "Importar Theme..."
#: editor/plugins/script_editor_plugin.cpp
msgid "Reload Theme"
-msgstr "Recargar Tema"
+msgstr "Recargar Theme"
#: editor/plugins/script_editor_plugin.cpp
msgid "Save Theme"
-msgstr "Guardar Tema"
+msgstr "Guardar Theme"
#: editor/plugins/script_editor_plugin.cpp
msgid "Close All"
@@ -7855,20 +7835,17 @@ msgid "None"
msgstr "Ninguno"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Rotate"
-msgstr "Estado:"
+msgstr "Rotar"
#. TRANSLATORS: This refers to the movement that changes the position of an object.
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Translate"
-msgstr "Trasladar:"
+msgstr "Mover"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Scale"
-msgstr "Escala:"
+msgstr "Escala"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scaling: "
@@ -7891,52 +7868,44 @@ msgid "Animation Key Inserted."
msgstr "Clave de animación insertada."
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Pitch:"
-msgstr "Altura"
+msgstr "Eje de paso:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Yaw:"
-msgstr ""
+msgstr "Eje de guiñada:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size:"
-msgstr "Tamaño: "
+msgstr "Tamaño:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Objects Drawn:"
-msgstr "Objetos Dibujados"
+msgstr "Objetos Dibujados:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Material Changes:"
-msgstr "Cambios del Material"
+msgstr "Cambios del Material:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Shader Changes:"
-msgstr "Cambios del Shader"
+msgstr "Cambios de sombreado:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Surface Changes:"
-msgstr "Cambios de Superficie"
+msgstr "Cambios de superficie:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Draw Calls:"
-msgstr "Llamadas de Dibujado"
+msgstr "Llamadas de Dibujado:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Vertices:"
-msgstr "Vértices"
+msgstr "Vértices:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "FPS: %d (%s ms)"
-msgstr ""
+msgstr "FPS: %d (%s ms)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Top View."
@@ -8091,9 +8060,8 @@ msgid "Freelook Slow Modifier"
msgstr "Modificador de Velocidad de Vista Libre"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Toggle Camera Preview"
-msgstr "Cambiar Tamaño de Cámara"
+msgstr "Alternar Vista Previa de la Cámara"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Rotation Locked"
@@ -8115,9 +8083,8 @@ msgstr ""
"No se puede utilizar como un indicador fiable del rendimiento en el juego."
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Convert Rooms"
-msgstr "Convertir a %s"
+msgstr "Convertir Rooms"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "XForm Dialog"
@@ -8139,7 +8106,6 @@ msgstr ""
"opacas (\"x-ray\")."
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Snap Nodes to Floor"
msgstr "Ajustar Nodos al Suelo"
@@ -8157,7 +8123,7 @@ msgstr "Usar Snap"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Converts rooms for portal culling."
-msgstr ""
+msgstr "Convertir rooms para eliminar portales."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Bottom View"
@@ -8253,9 +8219,8 @@ msgid "View Grid"
msgstr "Ver Cuadrícula"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "View Portal Culling"
-msgstr "Configuración de ventanilla"
+msgstr "Ver Eliminación de Portales"
#: editor/plugins/spatial_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
@@ -8576,221 +8541,196 @@ msgid "TextureRegion"
msgstr "Región de Textura"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Colors"
-msgstr "Color"
+msgstr "Colores"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Fonts"
-msgstr "Tipografía"
+msgstr "Fonts"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Icons"
-msgstr "Icono"
+msgstr "Icons"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Styleboxes"
-msgstr "Caja de estilos"
+msgstr "Styleboxes"
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} color(s)"
-msgstr ""
+msgstr "{num} color(es)"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No colors found."
-msgstr "No se encontró ningún sub-recurso."
+msgstr "No se encontraron colores."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "{num} constant(s)"
-msgstr "Constantes"
+msgstr "{num} constant(s)"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No constants found."
-msgstr "Constante de color."
+msgstr "No se encontraron constants."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} font(s)"
-msgstr ""
+msgstr "{num} font(s)"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No fonts found."
-msgstr "¡No se ha encontrado!"
+msgstr "No se han encontrado fonts."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} icon(s)"
-msgstr ""
+msgstr "{num} icon(s)"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No icons found."
-msgstr "¡No se ha encontrado!"
+msgstr "No se han encontrado icons."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} stylebox(es)"
-msgstr ""
+msgstr "{num} stylebox(es)"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No styleboxes found."
-msgstr "No se encontró ningún sub-recurso."
+msgstr "No se encontraron styleboxes."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} currently selected"
-msgstr ""
+msgstr "{num} seleccionado actualmente"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Nothing was selected for the import."
-msgstr ""
+msgstr "No se ha seleccionado nada para la importación."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Importing Theme Items"
-msgstr "Importar Tema"
+msgstr "Importar Elementos del Theme"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Importing items {n}/{n}"
-msgstr ""
+msgstr "Importación de elementos {n}/{n}"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Updating the editor"
-msgstr "¿Salir del editor?"
+msgstr "Actualización del editor"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Finalizing"
-msgstr "Analizando"
+msgstr "Finalizando"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Filter:"
-msgstr "Filtro: "
+msgstr "Filtro:"
#: editor/plugins/theme_editor_plugin.cpp
msgid "With Data"
-msgstr ""
+msgstr "Con Datos"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select by data type:"
-msgstr "Selecciona un Nodo"
+msgstr "Seleccionar por tipo de datos:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible color items."
-msgstr "Selecciona una división para borrarla."
+msgstr "Seleccionar todos los elementos color visibles."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible color items and their data."
-msgstr ""
+msgstr "Seleccionar todos los elementos color visibles y sus datos."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible color items."
-msgstr ""
+msgstr "Deseleccionar todos los elementos color visibles."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible constant items."
-msgstr "¡Selecciona un ítem primero!"
+msgstr "Seleccionar todos elementos constant visibles."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible constant items and their data."
-msgstr ""
+msgstr "Seleccionar todos los elementos constant visibles y sus datos."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible constant items."
-msgstr ""
+msgstr "Deseleccionar todos los elementos constant visibles."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible font items."
-msgstr "¡Selecciona un ítem primero!"
+msgstr "Seleccionar todos los elementos font visibles."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible font items and their data."
-msgstr ""
+msgstr "Seleccionar todos los elementos font visibles y sus datos."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible font items."
-msgstr ""
+msgstr "Deseleccionar todos los elementos font visibles."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible icon items."
-msgstr "¡Selecciona un ítem primero!"
+msgstr "Seleccionar todos los elementos icon visibles."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible icon items and their data."
-msgstr "¡Selecciona un ítem primero!"
+msgstr "Seleccionar todos los elementos icon visibles y sus datos."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Deselect all visible icon items."
-msgstr "¡Selecciona un ítem primero!"
+msgstr "Deseleccionar todos los elementos icon visibles."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible stylebox items."
-msgstr ""
+msgstr "Seleccionar todos los elementos stylebox visibles."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible stylebox items and their data."
-msgstr ""
+msgstr "Seleccionar todos los elementos stylebox visibles y sus datos."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible stylebox items."
-msgstr ""
+msgstr "Deseleccionar todos los elementos stylebox visibles."
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
"Caution: Adding icon data may considerably increase the size of your Theme "
"resource."
msgstr ""
+"Precaución: Añadir datos de iconos puede aumentar considerablemente el "
+"tamaño de su recurso Theme."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Collapse types."
-msgstr "Colapsar Todo"
+msgstr "Tipos de colapso."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Expand types."
-msgstr "Expandir Todo"
+msgstr "Expandir tipos."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all Theme items."
-msgstr "Selecciona un Archivo de Plantilla"
+msgstr "Seleccionar todos los elementos del Theme."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select With Data"
-msgstr "Seleccionar Puntos"
+msgstr "Seleccionar Con Datos"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all Theme items with item data."
-msgstr ""
+msgstr "Seleccionar todos los elementos del Theme con los datos del elemento."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Deselect All"
-msgstr "Seleccionar Todo"
+msgstr "Deseleccionar Todo"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all Theme items."
-msgstr ""
+msgstr "Deseleccionar todos los elementos del Theme."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Import Selected"
-msgstr "Importar Escena"
+msgstr "Importar Seleccionado"
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
@@ -8798,271 +8738,248 @@ msgid ""
"closing this window.\n"
"Close anyway?"
msgstr ""
+"En la pestaña de Elementos de Importación se han seleccionado algunos "
+"elementos. La selección se perderá al cerrar esta ventana.\n"
+"¿Cerrar de todos modos?"
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Color Items"
-msgstr "Eliminar Todos los Ãtems"
+msgstr "Eliminar Todos los Elementos de Color"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Item"
-msgstr "Eliminar Ãtem"
+msgstr "Cambiar Nombre de Elemento"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Constant Items"
-msgstr "Eliminar Todos los Ãtems"
+msgstr "Eliminar Todos los Elementos Constant"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Font Items"
-msgstr "Eliminar Todos los Ãtems"
+msgstr "Eliminar Todos los Elementos Font"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Icon Items"
-msgstr "Eliminar Todos los Ãtems"
+msgstr "Eliminar Todos los Elementos de Iconos"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All StyleBox Items"
-msgstr "Eliminar Todos los Ãtems"
+msgstr "Eliminar Todos los Elementos de StyleBox"
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Color Item"
-msgstr "Añadir Clases de Ãtems"
+msgstr "Añadir Elemento Color"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Constant Item"
-msgstr "Añadir Clases de Ãtems"
+msgstr "Añadir Elemento Constant"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Font Item"
-msgstr "Añadir Ãtem"
+msgstr "Añadir Elemento Font"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Icon Item"
-msgstr "Añadir Ãtem"
+msgstr "Añadir Elemento Icono"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Stylebox Item"
-msgstr "Añadir Todos los Ãtems"
+msgstr "Añadir Elemento Stylebox"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Color Item"
-msgstr "Eliminar Clases de Ãtems"
+msgstr "Cambiar Nombre del Elemento Color"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Constant Item"
-msgstr "Eliminar Clases de Ãtems"
+msgstr "Cambiar Nombre del Elemento Constant"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Font Item"
-msgstr "Renombrar Nodo"
+msgstr "Renombrar Elemento Font"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Icon Item"
-msgstr "Renombrar Nodo"
+msgstr "Renombrar Elemento Icon"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Stylebox Item"
-msgstr "Eliminar Ãtem Seleccionado"
+msgstr "Renombrar Elemento Stylebox"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Invalid file, not a Theme resource."
-msgstr "Archivo inválido. No es un layout de bus de audio."
+msgstr "Archivo inválido, no es un recurso del Theme."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Invalid file, same as the edited Theme resource."
-msgstr ""
+msgstr "Archivo inválido, igual que el recurso del Theme editado."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Manage Theme Items"
-msgstr "Administrar Plantillas"
+msgstr "Administrar Elementos del Theme"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Edit Items"
-msgstr "Ãtem Editable"
+msgstr "Editar Elementos"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Types:"
-msgstr "Tipo:"
+msgstr "Tipos:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Type:"
-msgstr "Tipo:"
+msgstr "Añadir Tipo:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Item:"
-msgstr "Añadir Ãtem"
+msgstr "Añadir Elemento:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add StyleBox Item"
-msgstr "Añadir Todos los Ãtems"
+msgstr "Añadir Elemento StyleBox"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove Items:"
-msgstr "Eliminar Ãtem"
+msgstr "Eliminar Elemento:"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove Class Items"
-msgstr "Eliminar Clases de Ãtems"
+msgstr "Eliminar Clases de Elementos"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove Custom Items"
-msgstr "Eliminar Clases de Ãtems"
+msgstr "Eliminar Elementos Personalizados"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Items"
-msgstr "Eliminar Todos los Ãtems"
+msgstr "Eliminar Todos los Elementos"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Theme Item"
-msgstr "Elementos del tema de interfaz"
+msgstr "Añadir Elemento del Theme"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Old Name:"
-msgstr "Nombre del Nodo:"
+msgstr "Nombre Antiguo:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Import Items"
-msgstr "Importar Tema"
+msgstr "Importar Elementos"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Default Theme"
-msgstr "Predeterminado"
+msgstr "Theme Predeterminado"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Editor Theme"
-msgstr "Editar Tema"
+msgstr "Editor de Themes"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select Another Theme Resource:"
-msgstr "Eliminar Recurso"
+msgstr "Seleccionar Otro Recurso del Theme:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Another Theme"
-msgstr "Importar Tema"
+msgstr "Otro Theme"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Confirm Item Rename"
-msgstr "Renombrar pista de animación"
+msgstr "Confirmar Cambio de Nombre del Elemento"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Cancel Item Rename"
-msgstr "Renombrar por lote"
+msgstr "Cancelar Cambio de Nombre del Elemento"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Override Item"
-msgstr "Anulaciones"
+msgstr "Elemento de Anulación"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Unpin this StyleBox as a main style."
-msgstr ""
+msgstr "Quitar este StyleBox como estilo principal."
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
"Pin this StyleBox as a main style. Editing its properties will update the "
"same properties in all other StyleBoxes of this type."
msgstr ""
+"Establecer este StyleBox como un estilo principal. La edición de sus "
+"propiedades actualizará las mismas propiedades en todos los demás StyleBoxes "
+"de este tipo."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Type"
-msgstr "Tipo"
+msgstr "Añadir Tipo"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Item Type"
-msgstr "Añadir Ãtem"
+msgstr "Añadir Tipo de Elemento"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Node Types:"
-msgstr "Tipo de nodo"
+msgstr "Tipo de nodo:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Show Default"
-msgstr "Cargar Valores por Defecto"
+msgstr "Mostrar Por Defecto"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Show default type items alongside items that have been overridden."
msgstr ""
+"Mostrar los elementos de tipo por defecto junto a los elementos que han sido "
+"anulados."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Override All"
-msgstr "Anulaciones"
+msgstr "Anular Todo"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Override all default type items."
-msgstr ""
+msgstr "Anular todos los elementos de tipo por defecto."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Theme:"
-msgstr "Tema"
+msgstr "Theme:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Manage Items..."
-msgstr "Administrar Plantillas de Exportación..."
+msgstr "Administrar Elementos..."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add, remove, organize and import Theme items."
-msgstr ""
+msgstr "Añadir, eliminar, organizar e importar elementos del Theme."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Preview"
-msgstr "Vista Previa"
+msgstr "Añadir Vista Previa"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Default Preview"
-msgstr "Actualizar Vista Previa"
+msgstr "Vista Previa Por Defecto"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select UI Scene:"
-msgstr "Selecciona una Malla de Origen:"
+msgstr "Seleccionar Escena UI:"
#: editor/plugins/theme_editor_preview.cpp
msgid ""
"Toggle the control picker, allowing to visually select control types for "
"edit."
msgstr ""
+"Activar el selector de controles, lo que permite seleccionar visualmente los "
+"tipos de control para su edición."
#: editor/plugins/theme_editor_preview.cpp
msgid "Toggle Button"
@@ -9074,32 +8991,31 @@ msgstr "Botón Desactivado"
#: editor/plugins/theme_editor_preview.cpp
msgid "Item"
-msgstr "Ãtem"
+msgstr "Elemento"
#: editor/plugins/theme_editor_preview.cpp
msgid "Disabled Item"
-msgstr "Desactivar Ãtem"
+msgstr "Desactivar Elemento"
#: editor/plugins/theme_editor_preview.cpp
msgid "Check Item"
-msgstr "Activar Ãtem"
+msgstr "Activar Elemento"
#: editor/plugins/theme_editor_preview.cpp
msgid "Checked Item"
-msgstr "Ãtem Activado"
+msgstr "Elemento Activado"
#: editor/plugins/theme_editor_preview.cpp
msgid "Radio Item"
-msgstr "Radio Ãtem"
+msgstr "Radio Elemento"
#: editor/plugins/theme_editor_preview.cpp
msgid "Checked Radio Item"
-msgstr "Radio Ãtem Activo"
+msgstr "Radio Elemento Activo"
#: editor/plugins/theme_editor_preview.cpp
-#, fuzzy
msgid "Named Separator"
-msgstr "Separador con nombre."
+msgstr "Separador con nombre"
#: editor/plugins/theme_editor_preview.cpp
msgid "Submenu"
@@ -9107,11 +9023,11 @@ msgstr "Submenú"
#: editor/plugins/theme_editor_preview.cpp
msgid "Subitem 1"
-msgstr "Subítem 1"
+msgstr "Subelemento 1"
#: editor/plugins/theme_editor_preview.cpp
msgid "Subitem 2"
-msgstr "Subítem 2"
+msgstr "Subelemento 2"
#: editor/plugins/theme_editor_preview.cpp
msgid "Has"
@@ -9139,7 +9055,7 @@ msgstr "Tab 3"
#: editor/plugins/theme_editor_preview.cpp
msgid "Editable Item"
-msgstr "Ãtem Editable"
+msgstr "Elemento Editable"
#: editor/plugins/theme_editor_preview.cpp
msgid "Subtree"
@@ -9152,19 +9068,19 @@ msgstr "Tienes, muchas, opciones"
#: editor/plugins/theme_editor_preview.cpp
msgid "Invalid path, the PackedScene resource was probably moved or removed."
msgstr ""
+"Ruta inválida, el recurso PackedScene probablemente fue movido o eliminado."
#: editor/plugins/theme_editor_preview.cpp
msgid "Invalid PackedScene resource, must have a Control node at its root."
-msgstr ""
+msgstr "Recurso PackedScene inválido, debe tener un nodo Control en raíz."
#: editor/plugins/theme_editor_preview.cpp
-#, fuzzy
msgid "Invalid file, not a PackedScene resource."
-msgstr "Archivo inválido. No es un layout de bus de audio."
+msgstr "Archivo inválido, no es un recurso PackedScene."
#: editor/plugins/theme_editor_preview.cpp
msgid "Reload the scene to reflect its most actual state."
-msgstr ""
+msgstr "Recargar la escena para reflejar su estado actual."
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Erase Selection"
@@ -10569,9 +10485,8 @@ msgid "VisualShader"
msgstr "VisualShader"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Edit Visual Property:"
-msgstr "Editar Propiedad Visual"
+msgstr "Editar Propiedad Visual:"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Visual Shader Mode Changed"
@@ -10698,9 +10613,8 @@ msgid "Script"
msgstr "Script"
#: editor/project_export.cpp
-#, fuzzy
msgid "GDScript Export Mode:"
-msgstr "Modo de exportación de scripts:"
+msgstr "Modo de Exportación GDScript:"
#: editor/project_export.cpp
msgid "Text"
@@ -10708,21 +10622,20 @@ msgstr "Texto"
#: editor/project_export.cpp
msgid "Compiled Bytecode (Faster Loading)"
-msgstr ""
+msgstr "Bytecode Compilado (Carga Más Rápida)"
#: editor/project_export.cpp
msgid "Encrypted (Provide Key Below)"
msgstr "Encriptado (Proveer la Clave Debajo)"
#: editor/project_export.cpp
-#, fuzzy
msgid "Invalid Encryption Key (must be 64 hexadecimal characters long)"
-msgstr "Llave de Encriptación Inválida (debe tener 64 caracteres de largo)"
+msgstr ""
+"Llave de Encriptación Inválida (debe tener 64 caracteres hexadecimales)"
#: editor/project_export.cpp
-#, fuzzy
msgid "GDScript Encryption Key (256-bits as hexadecimal):"
-msgstr "Clave de cifrado de scripts (256-bits en hexadecimal):"
+msgstr "Llave de Encriptación GDScript (256-bits en hexadecimal):"
#: editor/project_export.cpp
msgid "Export PCK/Zip"
@@ -10796,7 +10709,6 @@ msgid "Imported Project"
msgstr "Proyecto Importado"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Invalid project name."
msgstr "Nombre de Proyecto Inválido."
@@ -11015,7 +10927,7 @@ msgid ""
"Can't run project: Assets need to be imported.\n"
"Please edit the project to trigger the initial import."
msgstr ""
-"No se puede ejecutar el proyecto: los assets necesitan ser importados.\n"
+"No se puede ejecutar el proyecto: Los assets necesitan ser importados.\n"
"Por favor, edita el proyecto para activar el importado inicial."
#: editor/project_manager.cpp
@@ -11023,14 +10935,12 @@ msgid "Are you sure to run %d projects at once?"
msgstr "¿Estás seguro de que vas a ejecutar %d proyectos a la vez?"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove %d projects from the list?"
-msgstr "Seleccionar dispositivo de la lista"
+msgstr "¿Quitar %d proyectos de la lista?"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove this project from the list?"
-msgstr "Seleccionar dispositivo de la lista"
+msgstr "¿Quitar este proyecto de la lista?"
#: editor/project_manager.cpp
msgid ""
@@ -11064,9 +10974,8 @@ msgid "Project Manager"
msgstr "Administrador de Proyectos"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Local Projects"
-msgstr "Proyectos"
+msgstr "Proyectos Locales"
#: editor/project_manager.cpp
msgid "Loading, please wait..."
@@ -11077,23 +10986,20 @@ msgid "Last Modified"
msgstr "Ultima Modificación"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Edit Project"
-msgstr "Exportar Proyecto"
+msgstr "Editar Proyecto"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Run Project"
-msgstr "Renombrar Proyecto"
+msgstr "Reproducir Proyecto"
#: editor/project_manager.cpp
msgid "Scan"
msgstr "Escanear"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Scan Projects"
-msgstr "Proyectos"
+msgstr "Escanear Proyectos"
#: editor/project_manager.cpp
msgid "Select a Folder to Scan"
@@ -11104,14 +11010,12 @@ msgid "New Project"
msgstr "Nuevo Proyecto"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Import Project"
-msgstr "Proyecto Importado"
+msgstr "Importar Proyecto"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove Project"
-msgstr "Renombrar Proyecto"
+msgstr "Eliminar Proyecto"
#: editor/project_manager.cpp
msgid "Remove Missing"
@@ -11122,9 +11026,8 @@ msgid "About"
msgstr "Acerca de"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Asset Library Projects"
-msgstr "Biblioteca de Assets"
+msgstr "Proyectos de la Librería de Assets"
#: editor/project_manager.cpp
msgid "Restart Now"
@@ -11136,7 +11039,7 @@ msgstr "Eliminar Todos"
#: editor/project_manager.cpp
msgid "Also delete project contents (no undo!)"
-msgstr ""
+msgstr "También eliminar el contenido del proyecto (¡no se puede deshacer!)"
#: editor/project_manager.cpp
msgid "Can't run project"
@@ -11148,24 +11051,22 @@ msgid ""
"Would you like to explore official example projects in the Asset Library?"
msgstr ""
"Actualmente no tienes ningún proyecto.\n"
-"¿Quieres explorar proyectos de ejemplo oficiales en la Biblioteca de Assets?"
+"¿Quieres explorar proyectos de ejemplo oficiales en la Librería de Assets?"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Filter projects"
-msgstr "Filtrar propiedades"
+msgstr "Filtrar proyectos"
#: editor/project_manager.cpp
-#, fuzzy
msgid ""
"This field filters projects by name and last path component.\n"
"To filter projects by name and full path, the query must contain at least "
"one `/` character."
msgstr ""
-"La casilla de búsqueda filtra los proyectos por nombre y el último "
-"componente de la ruta.\n"
-"Para filtrar los proyectos por nombre y ruta completa, la consulta debe "
-"contener al menos un carácter `/`."
+"Este campo filtra los proyectos por nombre y por el último componente de la "
+"ruta.\n"
+"Para filtrar proyectos por nombre y ruta completa, la consulta debe contener "
+"al menos un carácter `/`."
#: editor/project_settings_editor.cpp
msgid "Key "
@@ -11173,7 +11074,7 @@ msgstr "Tecla "
#: editor/project_settings_editor.cpp
msgid "Physical Key"
-msgstr ""
+msgstr "Tecla Física"
#: editor/project_settings_editor.cpp
msgid "Joy Button"
@@ -11221,7 +11122,7 @@ msgstr "Dispositivo"
#: editor/project_settings_editor.cpp
msgid " (Physical)"
-msgstr ""
+msgstr " (Física)"
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "Press a Key..."
@@ -11321,7 +11222,7 @@ msgstr "Añadir Propiedad Global"
#: editor/project_settings_editor.cpp
msgid "Select a setting item first!"
-msgstr "¡Selecciona un ítem primero!"
+msgstr "¡Selecciona un elemento primero!"
#: editor/project_settings_editor.cpp
msgid "No property '%s' exists."
@@ -11333,7 +11234,7 @@ msgstr "El ajuste '%s' es interno y no puede ser eliminado."
#: editor/project_settings_editor.cpp
msgid "Delete Item"
-msgstr "Eliminar Ãtem"
+msgstr "Eliminar Elemento"
#: editor/project_settings_editor.cpp
msgid ""
@@ -11364,23 +11265,20 @@ msgid "Override for Feature"
msgstr "Anulación de la Característica"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Add %d Translations"
-msgstr "Añadir Traducción"
+msgstr "Añadir %d Traducciones"
#: editor/project_settings_editor.cpp
msgid "Remove Translation"
msgstr "Eliminar Traducción"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Translation Resource Remap: Add %d Path(s)"
-msgstr "Añadir Remapeo de Recursos"
+msgstr "Remapeo de Recursos de Traducción: Añadir %d Ruta(s)"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Translation Resource Remap: Add %d Remap(s)"
-msgstr "Añadir Remapeo de Recursos"
+msgstr "Remapeo de Recursos de Traducción: Añadir %d Remapeo(s)"
#: editor/project_settings_editor.cpp
msgid "Change Resource Remap Language"
@@ -11825,12 +11723,16 @@ msgstr "¿Eliminar nodo \"%s\"?"
msgid ""
"Saving the branch as a scene requires having a scene open in the editor."
msgstr ""
+"Guardar la rama como una escena requiere tener una escena abierta en el "
+"editor."
#: editor/scene_tree_dock.cpp
msgid ""
"Saving the branch as a scene requires selecting only one node, but you have "
"selected %d nodes."
msgstr ""
+"Guardar la rama como una escena requiere seleccionar sólo un nodo, pero has "
+"seleccionado %d nodos."
#: editor/scene_tree_dock.cpp
msgid ""
@@ -11839,6 +11741,11 @@ msgid ""
"FileSystem dock context menu\n"
"or create an inherited scene using Scene > New Inherited Scene... instead."
msgstr ""
+"No se puede guardar la rama del nodo raíz como una escena instanciada.\n"
+"Para crear una copia editable de la escena actual, duplícala usando el menú "
+"contextual del dock Sistema de Archivos\n"
+"o crea una escena heredada usando Escena > Nueva Escena Heredada... en su "
+"lugar."
#: editor/scene_tree_dock.cpp
msgid ""
@@ -11846,6 +11753,10 @@ msgid ""
"To create a variation of a scene, you can make an inherited scene based on "
"the instanced scene using Scene > New Inherited Scene... instead."
msgstr ""
+"No se puede guardar la rama de una escena ya instanciada.\n"
+"Para crear una variación de una escena, puedes hacer una escena heredada "
+"basada en la escena instanciada usando Escena > Nueva Escena Heredada... en "
+"su lugar."
#: editor/scene_tree_dock.cpp
msgid "Save New Scene As..."
@@ -12254,6 +12165,8 @@ msgid ""
"Warning: Having the script name be the same as a built-in type is usually "
"not desired."
msgstr ""
+"Advertencia: No es recomendable que el nombre del script sea el mismo que el "
+"de un tipo integrado."
#: editor/script_create_dialog.cpp
msgid "Class Name:"
@@ -12325,7 +12238,7 @@ msgstr "Copiar Error"
#: editor/script_editor_debugger.cpp
msgid "Open C++ Source on GitHub"
-msgstr ""
+msgstr "Código Abierto C++ en GitHub"
#: editor/script_editor_debugger.cpp
msgid "Video RAM"
@@ -12369,7 +12282,7 @@ msgstr "Monitores"
#: editor/script_editor_debugger.cpp
msgid "Pick one or more items from the list to display the graph."
-msgstr "Elige uno o más ítems de la lista para mostrar el gráfico."
+msgstr "Elige uno o más elementos de la lista para mostrar el gráfico."
#: editor/script_editor_debugger.cpp
msgid "List of Video Memory Usage by Resource:"
@@ -12503,6 +12416,16 @@ msgstr "Cambiar Altura de la Forma del Cilindro"
msgid "Change Ray Shape Length"
msgstr "Cambiar Longitud de la Forma del Rayo"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Establecer Posición de Punto de Curva"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Establecer Posición de Punto de Curva"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "Cambiar Radio de Cylinder"
@@ -12616,14 +12539,12 @@ msgid "Object can't provide a length."
msgstr "El objeto no puede proporcionar una longitud."
#: modules/gltf/editor_scene_exporter_gltf_plugin.cpp
-#, fuzzy
msgid "Export Mesh GLTF2"
-msgstr "Exportar Librería de Mallas"
+msgstr "Exportar Malla GLTF2"
#: modules/gltf/editor_scene_exporter_gltf_plugin.cpp
-#, fuzzy
msgid "Export GLTF..."
-msgstr "Exportar…"
+msgstr "Exportar GLTF..."
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Next Plane"
@@ -12666,9 +12587,8 @@ msgid "GridMap Paint"
msgstr "Pintar GridMap"
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "GridMap Selection"
-msgstr "Rellenar Selección en GridMap"
+msgstr "Seleccionar GridMap"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Grid Map"
@@ -12922,14 +12842,12 @@ msgid "Add Output Port"
msgstr "Añadir Puerto de Salida"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Change Port Type"
-msgstr "Cambiar Tipo"
+msgstr "Cambiar Tipo de Puerto"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Change Port Name"
-msgstr "Cambiar nombre del puerto de entrada"
+msgstr "Cambiar Nombre de Puerto"
#: modules/visual_script/visual_script_editor.cpp
msgid "Override an existing built-in function."
@@ -13044,9 +12962,8 @@ msgid "Add Preload Node"
msgstr "Añadir Nodo Preload"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Node(s)"
-msgstr "Añadir Nodo"
+msgstr "Añadir Nodo(s)"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Node(s) From Tree"
@@ -13313,37 +13230,31 @@ msgstr "Seleccionar dispositivo de la lista"
#: platform/android/export/export.cpp
msgid "Running on %s"
-msgstr ""
+msgstr "Ejecutar en %s"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Exporting APK..."
-msgstr "Exportar Todo"
+msgstr "Exportar APK..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Uninstalling..."
-msgstr "Desinstalar"
+msgstr "Desinstalando..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Installing to device, please wait..."
-msgstr "Cargando, espera por favor..."
+msgstr "Instalando en el dispositivo, espera por favor..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not install to device: %s"
-msgstr "¡No se pudo instanciar la escena!"
+msgstr "No se pudo instalar en el dispositivo: %s"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Running on device..."
-msgstr "Ejecutando Script Personalizado..."
+msgstr "Ejecutando en el dispositivo..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not execute on device."
-msgstr "No se pudo crear la carpeta."
+msgstr "No se ha podido ejecutar en el dispositivo."
#: platform/android/export/export.cpp
msgid "Unable to find the 'apksigner' tool."
@@ -13473,45 +13384,43 @@ msgid ""
"directory.\n"
"The resulting %s is unsigned."
msgstr ""
+"No se ha encontrado 'apksigner'.\n"
+"Por favor, compruebe que el comando está disponible en el directorio Android "
+"SDK build-tools.\n"
+"El resultado %s es sin firma."
#: platform/android/export/export.cpp
msgid "Signing debug %s..."
-msgstr ""
+msgstr "Firma de depuración %s..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Signing release %s..."
-msgstr ""
-"Escaneando archivos,\n"
-"Por favor, espere..."
+msgstr "Firmando liberación %s..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not find keystore, unable to export."
-msgstr "No se pudo abrir la plantilla para exportar:"
+msgstr "No se pudo encontrar la keystore, no se puedo exportar."
#: platform/android/export/export.cpp
msgid "'apksigner' returned with error #%d"
-msgstr ""
+msgstr "'apksigner' ha retornado con error #%d"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Verifying %s..."
-msgstr "Añadiendo %s..."
+msgstr "Verificando %s..."
#: platform/android/export/export.cpp
msgid "'apksigner' verification of %s failed."
-msgstr ""
+msgstr "La verificación de 'apksigner' de %s ha fallado."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Exporting for Android"
-msgstr "Exportar Todo"
+msgstr "Exportando para Android"
#: platform/android/export/export.cpp
msgid "Invalid filename! Android App Bundle requires the *.aab extension."
msgstr ""
-"¡Nombre de archivo inválido! Android App Bundle requiere la extensión *.aab."
+"¡Nombre del archivo inválido! Android App Bundle requiere la extensión *.aab."
#: platform/android/export/export.cpp
msgid "APK Expansion not compatible with Android App Bundle."
@@ -13523,7 +13432,7 @@ msgstr "¡Nombre de archivo inválido! Android APK requiere la extensión *.apk.
#: platform/android/export/export.cpp
msgid "Unsupported export format!\n"
-msgstr ""
+msgstr "¡Formato de exportación no compatible!\n"
#: platform/android/export/export.cpp
msgid ""
@@ -13551,16 +13460,16 @@ msgstr ""
msgid ""
"Unable to overwrite res://android/build/res/*.xml files with project name"
msgstr ""
+"No se puede sobrescribir los archivos res://android/build/res/*.xml con el "
+"nombre del proyecto"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not export project files to gradle project\n"
-msgstr "No se encontró project.godot en la ruta del proyecto."
+msgstr "No se pueden exportar los archivos del proyecto a un proyecto gradle\n"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not write expansion package file!"
-msgstr "No se puede escribir en el archivo:"
+msgstr "¡No se pudo escribir el archivo del paquete de expansión!"
#: platform/android/export/export.cpp
msgid "Building Android Project (gradle)"
@@ -13588,21 +13497,20 @@ msgstr ""
"directorio del proyecto de gradle para ver los resultados."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Package not found: %s"
-msgstr "No se encontró la animación: '%s'"
+msgstr "Paquete no encontrado:% s"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Creating APK..."
-msgstr "Creando contornos..."
+msgstr "Creando APK..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid ""
"Could not find template APK to export:\n"
"%s"
-msgstr "No se pudo abrir la plantilla para exportar:"
+msgstr ""
+"No se pudo encontrar la plantilla APK para exportar:\n"
+"%s"
#: platform/android/export/export.cpp
msgid ""
@@ -13611,16 +13519,18 @@ msgid ""
"Please build a template with all required libraries, or uncheck the missing "
"architectures in the export preset."
msgstr ""
+"Faltan bibliotecas en la plantilla de exportación para las arquitecturas "
+"seleccionadas: %s.\n"
+"Por favor, construya una plantilla con todas las bibliotecas necesarias, o "
+"desmarque las arquitecturas que faltan en el preajuste de exportación."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Adding files..."
-msgstr "Añadiendo %s..."
+msgstr "Añadiendo archivos ..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not export project files"
-msgstr "No se puede escribir en el archivo:"
+msgstr "No se pudieron exportar los archivos del proyecto"
#: platform/android/export/export.cpp
msgid "Aligning APK..."
@@ -13628,15 +13538,15 @@ msgstr "Alineando APK..."
#: platform/android/export/export.cpp
msgid "Could not unzip temporary unaligned APK."
-msgstr ""
+msgstr "No se pudo descomprimir el APK no alineado temporal."
#: platform/iphone/export/export.cpp platform/osx/export/export.cpp
msgid "Identifier is missing."
-msgstr "Identificador no encontrado."
+msgstr "Falta el identificador."
#: platform/iphone/export/export.cpp platform/osx/export/export.cpp
msgid "The character '%s' is not allowed in Identifier."
-msgstr "El carácter '%s' no esta permitido como identificador."
+msgstr "El carácter '% s' no está permitido en el Identificador."
#: platform/iphone/export/export.cpp
msgid "App Store Team ID not specified - cannot configure the project."
@@ -13676,45 +13586,40 @@ msgid "Could not write file:"
msgstr "No se puede escribir en el archivo:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not read file:"
-msgstr "No se puede escribir en el archivo:"
+msgstr "No se pudo leer el archivo:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not read HTML shell:"
-msgstr "No se puede leer shell HTML personalizada:"
+msgstr "No se pudo leer el shell HTML:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not create HTTP server directory:"
-msgstr "No se pudo crear la carpeta."
+msgstr "No se pudo crear el directorio del servidor HTTP:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Error starting HTTP server:"
-msgstr "Error al guardar escena."
+msgstr "Error al iniciar el servidor HTTP:"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Invalid bundle identifier:"
-msgstr "Identificador inválido:"
+msgstr "Identificador de paquete no válido:"
#: platform/osx/export/export.cpp
msgid "Notarization: code signing required."
-msgstr ""
+msgstr "Notarización: se requiere firma de código."
#: platform/osx/export/export.cpp
msgid "Notarization: hardened runtime required."
-msgstr ""
+msgstr "Notarización: se requiere tiempo de ejecución reforzado."
#: platform/osx/export/export.cpp
msgid "Notarization: Apple ID name not specified."
-msgstr ""
+msgstr "Notarización: nombre de ID de Apple no especificado."
#: platform/osx/export/export.cpp
msgid "Notarization: Apple ID password not specified."
-msgstr ""
+msgstr "Notarización: contraseña de ID de Apple no especificada."
#: platform/uwp/export/export.cpp
msgid "Invalid package short name."
@@ -14162,6 +14067,9 @@ msgid ""
"longer has any effect.\n"
"To remove this warning, disable the GIProbe's Compress property."
msgstr ""
+"La propiedad Compress de GIProbe ha quedado obsoleta debido a errores "
+"conocidos y ya no tiene ningún efecto.\n"
+"Para eliminar esta advertencia, desactiva la propiedad Compress de GIProbe."
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
@@ -14253,15 +14161,15 @@ msgstr "El nodo A y el nodo B deben ser diferentes PhysicsBody"
#: scene/3d/portal.cpp
msgid "The RoomManager should not be a child or grandchild of a Portal."
-msgstr ""
+msgstr "El RoomManager no debe ser hijo o nieto de un Portal."
#: scene/3d/portal.cpp
msgid "A Room should not be a child or grandchild of a Portal."
-msgstr ""
+msgstr "Una Room no debe ser hijo o nieto de un Portal."
#: scene/3d/portal.cpp
msgid "A RoomGroup should not be a child or grandchild of a Portal."
-msgstr ""
+msgstr "Un RoomGroup no debe ser hijo o nieto de un Portal."
#: scene/3d/remote_transform.cpp
msgid ""
@@ -14273,42 +14181,83 @@ msgstr ""
#: scene/3d/room.cpp
msgid "A Room cannot have another Room as a child or grandchild."
-msgstr ""
+msgstr "Una Room no puede tener otra Room como hija o nieta."
#: scene/3d/room.cpp
msgid "The RoomManager should not be placed inside a Room."
-msgstr ""
+msgstr "El RoomManager no debe ubicarse dentro de una Room."
#: scene/3d/room.cpp
msgid "A RoomGroup should not be placed inside a Room."
-msgstr ""
+msgstr "Un RoomGroup no debe colocarse dentro de una Room."
#: scene/3d/room.cpp
msgid ""
"Room convex hull contains a large number of planes.\n"
"Consider simplifying the room bound in order to increase performance."
msgstr ""
+"El cuerpo convexo de la room contiene un gran número de planos.\n"
+"Considera la posibilidad de simplificar los límites de la room para aumentar "
+"el rendimiento."
#: scene/3d/room_group.cpp
msgid "The RoomManager should not be placed inside a RoomGroup."
-msgstr ""
+msgstr "El RoomManager no debe colocarse dentro de un RoomGroup."
#: scene/3d/room_manager.cpp
msgid "The RoomList has not been assigned."
-msgstr ""
+msgstr "La RoomList no ha sido asignada."
#: scene/3d/room_manager.cpp
msgid "The RoomList node should be a Spatial (or derived from Spatial)."
-msgstr ""
+msgstr "El nodo RoomList debe ser un Spatial (o derivado de Spatial)."
#: scene/3d/room_manager.cpp
msgid ""
"Portal Depth Limit is set to Zero.\n"
"Only the Room that the Camera is in will render."
msgstr ""
+"El Límite de Profundidad del Portal está ajustado a cero.\n"
+"Sólo se renderizará la room en la que se encuentra la cámara."
#: scene/3d/room_manager.cpp
msgid "There should only be one RoomManager in the SceneTree."
+msgstr "Sólo debe haber un RoomManager en el SceneTree."
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
msgstr ""
#: scene/3d/soft_body.cpp
@@ -14375,7 +14324,7 @@ msgstr "No se encontró la animación: '%s'"
#: scene/animation/animation_player.cpp
msgid "Anim Apply Reset"
-msgstr ""
+msgstr "Aplicar Reset de la Animación"
#: scene/animation/animation_tree.cpp
msgid "In node '%s', invalid animation: '%s'."
@@ -14553,25 +14502,30 @@ msgid "Invalid comparison function for that type."
msgstr "Función de comparación inválida para este tipo."
#: servers/visual/shader_language.cpp
-#, fuzzy
msgid "Varying may not be assigned in the '%s' function."
-msgstr "Solo se pueden asignar variaciones en funciones de vértice."
+msgstr "No se puede asignar la variable en la función '%s'."
#: servers/visual/shader_language.cpp
msgid ""
"Varyings which assigned in 'vertex' function may not be reassigned in "
"'fragment' or 'light'."
msgstr ""
+"Las variaciones asignadas en función 'vértice' no pueden reasignarse en "
+"'fragmento' o 'luz'."
#: servers/visual/shader_language.cpp
msgid ""
"Varyings which assigned in 'fragment' function may not be reassigned in "
"'vertex' or 'light'."
msgstr ""
+"Varyings Cuál asignó en 'fragmento' la función no puede ser reasignada en "
+"'vértice' o 'ligero'."
#: servers/visual/shader_language.cpp
msgid "Fragment-stage varying could not been accessed in custom function!"
msgstr ""
+"¡No se pudo acceder a la variación de la etapa de fragmento en la función "
+"personalizada!"
#: servers/visual/shader_language.cpp
msgid "Assignment to function."
@@ -15771,9 +15725,6 @@ msgstr "Las constantes no pueden modificarse."
#~ msgid "I see..."
#~ msgstr "Ya veo..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "No se puede abrir '%s'."
-
#~ msgid "Ugh"
#~ msgstr "Vaya"
diff --git a/editor/translations/es_AR.po b/editor/translations/es_AR.po
index 53041c74fd..d5c955a347 100644
--- a/editor/translations/es_AR.po
+++ b/editor/translations/es_AR.po
@@ -21,7 +21,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-07-29 02:33+0000\n"
+"PO-Revision-Date: 2021-08-06 06:47+0000\n"
"Last-Translator: Lisandro Lorea <lisandrolorea@gmail.com>\n"
"Language-Team: Spanish (Argentina) <https://hosted.weblate.org/projects/"
"godot-engine/godot/es_AR/>\n"
@@ -30,7 +30,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.7.2-dev\n"
+"X-Generator: Weblate 4.8-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -353,6 +353,7 @@ msgstr "Cambiar Modo de Bucle de Animación"
msgid "Remove Anim Track"
msgstr "Quitar pista de animación"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Crear NUEVO track para %s e insertar clave?"
@@ -377,10 +378,28 @@ msgstr "Crear"
msgid "Anim Insert"
msgstr "Insertar Anim"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "No se puede abrir '%s'."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animación"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "Un AnimationPlayer no puede animarse a sí mismo, solo a otros players."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "No existe la propiedad '%s'."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Crear e Insertar Animación"
@@ -591,9 +610,8 @@ msgid "Go to Previous Step"
msgstr "Ir a Paso Previo"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Apply Reset"
-msgstr "Resetear"
+msgstr "Aplicar Reset"
#: editor/animation_track_editor.cpp
msgid "Optimize Animation"
@@ -612,9 +630,8 @@ msgid "Use Bezier Curves"
msgstr "Usar Curvas Bezier"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Create RESET Track(s)"
-msgstr "Pegar Pistas"
+msgstr "Crear RESET Track(s)"
#: editor/animation_track_editor.cpp
msgid "Anim. Optimizer"
@@ -940,9 +957,8 @@ msgid "Edit..."
msgstr "Editar..."
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Go to Method"
-msgstr "Ir Al Método"
+msgstr "Ir al Método"
#: editor/create_dialog.cpp
msgid "Change %s Type"
@@ -960,9 +976,9 @@ msgstr "Crear Nuevo %s"
msgid "No results for \"%s\"."
msgstr "No hay resultados para \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
-msgstr ""
+msgstr "No hay descripción disponible para %s."
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp
@@ -1260,9 +1276,8 @@ msgid "Error opening asset file for \"%s\" (not in ZIP format)."
msgstr "Error al abrir el archivo de paquete (no esta en formato ZIP)."
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "%s (already exists)"
-msgstr "%s (Ya existe)"
+msgstr "%s (ya existe)"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - %d file(s) conflict with your project:"
@@ -1277,19 +1292,16 @@ msgid "Uncompressing Assets"
msgstr "Descomprimiendo Assets"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "The following files failed extraction from asset \"%s\":"
-msgstr "Los siguientes archivos no se pudieron extraer del paquete:"
+msgstr "Falló la extracción de los siguientes archivos del asset \"%s\":"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "(and %s more files)"
-msgstr "Y %d archivos más."
+msgstr "(y %s archivos más)"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset \"%s\" installed successfully!"
-msgstr "El Paquete se instaló exitosamente!"
+msgstr "El asset \"%s\" se instaló exitosamente!"
#: editor/editor_asset_installer.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -1301,9 +1313,8 @@ msgid "Install"
msgstr "Instalar"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset Installer"
-msgstr "Instalador de Paquetes"
+msgstr "Instalador de Assets"
#: editor/editor_audio_buses.cpp
msgid "Speakers"
@@ -1366,7 +1377,6 @@ msgid "Bypass"
msgstr "Bypass"
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "Bus Options"
msgstr "Opciones de Bus"
@@ -1491,7 +1501,7 @@ msgstr "No debe coincidir con el nombre de una clase ya existente del motor."
#: editor/editor_autoload_settings.cpp
msgid "Must not collide with an existing built-in type name."
-msgstr "No debe coincidir con el nombre de un tipo built-in ya existente."
+msgstr "No debe coincidir con el nombre de un tipo integrado ya existente."
#: editor/editor_autoload_settings.cpp
msgid "Must not collide with an existing global constant name."
@@ -1534,13 +1544,12 @@ msgid "Can't add autoload:"
msgstr "No se puede agregar autoload:"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "%s is an invalid path. File does not exist."
-msgstr "El archivo existe."
+msgstr "%s es una ruta inválida. El archivo no existe."
#: editor/editor_autoload_settings.cpp
msgid "%s is an invalid path. Not in resource path (res://)."
-msgstr ""
+msgstr "%s es una ruta inválida. No esta en la ruta de recursos (res://)."
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -1564,9 +1573,8 @@ msgid "Name"
msgstr "Nombre"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "Global Variable"
-msgstr "Variable"
+msgstr "Variable Global"
#: editor/editor_data.cpp
msgid "Paste Params"
@@ -1742,29 +1750,32 @@ msgstr "Dock de Importación"
#: editor/editor_feature_profile.cpp
msgid "Allows to view and edit 3D scenes."
-msgstr ""
+msgstr "Permite ver y editar escenas 3D."
#: editor/editor_feature_profile.cpp
msgid "Allows to edit scripts using the integrated script editor."
-msgstr ""
+msgstr "Permite editar scripts usando el editor de scripts integrado."
#: editor/editor_feature_profile.cpp
msgid "Provides built-in access to the Asset Library."
-msgstr ""
+msgstr "Provee acceso integrado a la Biblioteca de Assets."
#: editor/editor_feature_profile.cpp
msgid "Allows editing the node hierarchy in the Scene dock."
-msgstr ""
+msgstr "Permite editar la jerarquía de nodos en el panel de Escena."
#: editor/editor_feature_profile.cpp
msgid ""
"Allows to work with signals and groups of the node selected in the Scene "
"dock."
msgstr ""
+"Permite trabajar con señales y grupos del nodo seleccionado en el panel de "
+"Escena."
#: editor/editor_feature_profile.cpp
msgid "Allows to browse the local file system via a dedicated dock."
msgstr ""
+"Permite explorar el sistema de archivos local a través de un panel dedicado."
#: editor/editor_feature_profile.cpp
msgid ""
@@ -1773,13 +1784,12 @@ msgid ""
msgstr ""
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "(current)"
-msgstr "(Actual)"
+msgstr "(actual)"
#: editor/editor_feature_profile.cpp
msgid "(none)"
-msgstr ""
+msgstr "(ninguno)"
#: editor/editor_feature_profile.cpp
msgid "Remove currently selected profile, '%s'? Cannot be undone."
@@ -1815,19 +1825,16 @@ msgid "Enable Contextual Editor"
msgstr "Activar el Editor Contextual"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Class Properties:"
-msgstr "Propiedades:"
+msgstr "Propiedades de Clase:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Main Features:"
-msgstr "Características"
+msgstr "Características Principales:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Nodes and Classes:"
-msgstr "Clases Activadas:"
+msgstr "Nodos y Clases:"
#: editor/editor_feature_profile.cpp
msgid "File '%s' format is invalid, import aborted."
@@ -1847,23 +1854,20 @@ msgid "Error saving profile to path: '%s'."
msgstr "Error al guardar el perfil en la ruta: '%s'."
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Reset to Default"
-msgstr "Restablecer Valores Por Defecto"
+msgstr "Restablecer a Valores Por Defecto"
#: editor/editor_feature_profile.cpp
msgid "Current Profile:"
msgstr "Perfil Actual:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Create Profile"
-msgstr "Borrar Perfil"
+msgstr "Crear Perfil"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Remove Profile"
-msgstr "Remover Tile"
+msgstr "Remover Perfil"
#: editor/editor_feature_profile.cpp
msgid "Available Profiles:"
@@ -1883,14 +1887,12 @@ msgid "Export"
msgstr "Exportar"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Configure Selected Profile:"
-msgstr "Perfil Actual:"
+msgstr "Configurar Perfil Seleccionado:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Extra Options:"
-msgstr "Opciones de Textura"
+msgstr "Opciones Extra:"
#: editor/editor_feature_profile.cpp
msgid "Create or import a profile to edit available classes and properties."
@@ -1921,9 +1923,8 @@ msgid "Select Current Folder"
msgstr "Seleccionar Carpeta Actual"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
-#, fuzzy
msgid "File exists, overwrite?"
-msgstr "El Archivo Existe, Sobreescribir?"
+msgstr "El archivo existe, sobrescribir?"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Select This Folder"
@@ -2316,6 +2317,17 @@ msgid "New Window"
msgstr "Nueva Ventana"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Gira cuando la ventana del editor se redibuja."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Los recursos importados no se pueden guardar."
@@ -2944,9 +2956,8 @@ msgid "Orphan Resource Explorer..."
msgstr "Explorador de Recursos Huérfanos..."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reload Current Project"
-msgstr "Renombrar Proyecto"
+msgstr "Volver a Cargar el Proyecto Actual"
#: editor/editor_node.cpp
msgid "Quit to Project List"
@@ -3106,22 +3117,20 @@ msgid "Help"
msgstr "Ayuda"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Online Documentation"
-msgstr "Abrir Documentación"
+msgstr "Documentación En Línea"
#: editor/editor_node.cpp
msgid "Questions & Answers"
-msgstr ""
+msgstr "Preguntas y Respuestas"
#: editor/editor_node.cpp
msgid "Report a Bug"
msgstr "Reportar un Bug"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Suggest a Feature"
-msgstr "Setear un Valor"
+msgstr "Sugerir una Feature"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
@@ -3132,9 +3141,8 @@ msgid "Community"
msgstr "Comunidad"
#: editor/editor_node.cpp
-#, fuzzy
msgid "About Godot"
-msgstr "Acerca de"
+msgstr "Acerca de Godot"
#: editor/editor_node.cpp
msgid "Support Godot Development"
@@ -3186,10 +3194,6 @@ msgid "Save & Restart"
msgstr "Guardar y Reiniciar"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Gira cuando la ventana del editor se redibuja."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Actualizar Continuamente"
@@ -3232,9 +3236,8 @@ msgid "Manage Templates"
msgstr "Administrar Plantillas"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Install from file"
-msgstr "Instalar Desde Archivo"
+msgstr "Instalar desde archivo"
#: editor/editor_node.cpp
#, fuzzy
@@ -3323,9 +3326,8 @@ msgid "Select"
msgstr "Seleccionar"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Select Current"
-msgstr "Seleccionar Carpeta Actual"
+msgstr "Seleccionar Actual"
#: editor/editor_node.cpp
msgid "Open 2D Editor"
@@ -3389,14 +3391,12 @@ msgid "Update"
msgstr "Actualizar"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Version"
-msgstr "Version:"
+msgstr "Version"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Author"
-msgstr "Autores"
+msgstr "Autor"
#: editor/editor_plugin_settings.cpp
#: editor/plugins/version_control_editor_plugin.cpp
@@ -3414,7 +3414,6 @@ msgid "Frame Time (ms)"
msgstr "Duración de Frame (seg)"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Average Time (ms)"
msgstr "Tiempo Promedio (seg)"
@@ -3564,9 +3563,8 @@ msgid "Paste"
msgstr "Pegar"
#: editor/editor_resource_picker.cpp editor/property_editor.cpp
-#, fuzzy
msgid "Convert to %s"
-msgstr "Convertir A %s"
+msgstr "Convertir a %s"
#: editor/editor_resource_picker.cpp editor/property_editor.cpp
msgid "New %s"
@@ -3640,49 +3638,43 @@ msgstr "Importar Desde Nodo:"
#: editor/export_template_manager.cpp
msgid "Open the folder containing these templates."
-msgstr ""
+msgstr "Abrir la carpeta que contiene estas plantillas."
#: editor/export_template_manager.cpp
msgid "Uninstall these templates."
-msgstr ""
+msgstr "Desinstalar estas plantillas."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "There are no mirrors available."
-msgstr "No hay ningún archivo '%s'."
+msgstr "No hay mirrors disponibles."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Retrieving the mirror list..."
-msgstr "Recuperando mirrors, esperá, por favor..."
+msgstr "Obteniendo la lista de mirrors..."
#: editor/export_template_manager.cpp
msgid "Starting the download..."
-msgstr ""
+msgstr "Iniciando la descarga..."
#: editor/export_template_manager.cpp
msgid "Error requesting URL:"
msgstr "Error al solicitar la URL:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Connecting to the mirror..."
-msgstr "Conectando al Mirror..."
+msgstr "Conectando al mirror..."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't resolve the requested address."
-msgstr "No se ha podido resolver el nombre del host:"
+msgstr "No se pudo resolver la dirección indicada."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't connect to the mirror."
-msgstr "No se puede conectar al host:"
+msgstr "No se puede conectar al mirror."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "No response from the mirror."
-msgstr "No hay respuesta desde el host:"
+msgstr "No hubo respuesta desde el mirror."
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -3690,18 +3682,16 @@ msgid "Request failed."
msgstr "Solicitud fallida."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Request ended up in a redirect loop."
-msgstr "Solicitud fallida, demasiadas redireccinoes"
+msgstr "La solicitud termino en un bucle de redirecciones."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Request failed:"
-msgstr "Solicitud fallida."
+msgstr "Solicitud fallida:"
#: editor/export_template_manager.cpp
msgid "Download complete; extracting templates..."
-msgstr ""
+msgstr "Descarga completada; extrayendo plantillas..."
#: editor/export_template_manager.cpp
msgid "Cannot remove temporary file:"
@@ -3728,7 +3718,7 @@ msgstr ""
#: editor/export_template_manager.cpp
msgid "Best available mirror"
-msgstr ""
+msgstr "Mejor mirror disponible"
#: editor/export_template_manager.cpp
msgid ""
@@ -3828,15 +3818,17 @@ msgstr "Version Actual:"
#: editor/export_template_manager.cpp
msgid "Export templates are missing. Download them or install from a file."
msgstr ""
+"Faltan las plantillas de exportación. Descargalas o instalalas desde un "
+"archivo."
#: editor/export_template_manager.cpp
msgid "Export templates are installed and ready to be used."
msgstr ""
+"Las plantillas de exportación están instaladas y listas para ser usadas."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Open Folder"
-msgstr "Abrir Archivo"
+msgstr "Abrir Carpeta"
#: editor/export_template_manager.cpp
msgid "Open the folder containing installed templates for the current version."
@@ -3852,13 +3844,22 @@ msgid "Uninstall templates for the current version."
msgstr "Valor inicial para el contador"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Download from:"
-msgstr "Error de Descarga"
+msgstr "Descargar desde:"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Ejecutar en el Navegador"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Copiar Error"
#: editor/export_template_manager.cpp
msgid "Download and Install"
-msgstr ""
+msgstr "Descargar e Instalar"
#: editor/export_template_manager.cpp
msgid ""
@@ -3873,14 +3874,12 @@ msgstr ""
"versiones de desarrollo."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Install from File"
-msgstr "Instalar Desde Archivo"
+msgstr "Instalar desde Archivo"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Install templates from a local file."
-msgstr "Importar Plantillas Desde Archivo ZIP"
+msgstr "Instalar plantillas desde un archivo local."
#: editor/export_template_manager.cpp editor/find_in_files.cpp
#: editor/progress_dialog.cpp scene/gui/dialogs.cpp
@@ -3888,19 +3887,16 @@ msgid "Cancel"
msgstr "Cancelar"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Cancel the download of the templates."
-msgstr "No se puede abir el zip de plantillas de exportación."
+msgstr "Cancelar la descarga de las plantillas."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Other Installed Versions:"
-msgstr "Versiones Instaladas:"
+msgstr "Otras Versiones Instaladas:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Uninstall Template"
-msgstr "Desinstalar"
+msgstr "Desinstalar Plantilla"
#: editor/export_template_manager.cpp
msgid "Select Template File"
@@ -4062,35 +4058,32 @@ msgid "Collapse All"
msgstr "Colapsar Todos"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort files"
-msgstr "Buscar archivos"
+msgstr "Ordenar archivos"
#: editor/filesystem_dock.cpp
msgid "Sort by Name (Ascending)"
-msgstr ""
+msgstr "Ordenar por Nombre (Ascendente)"
#: editor/filesystem_dock.cpp
msgid "Sort by Name (Descending)"
-msgstr ""
+msgstr "Ordenar por Nombre (Descendente)"
#: editor/filesystem_dock.cpp
msgid "Sort by Type (Ascending)"
-msgstr ""
+msgstr "Ordenar por Tipo (Ascendente)"
#: editor/filesystem_dock.cpp
msgid "Sort by Type (Descending)"
-msgstr ""
+msgstr "Ordenar por Tipo (Descendente)"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort by Last Modified"
-msgstr "Ultima Modificación"
+msgstr "Ordenar por Ultima Modificación"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort by First Modified"
-msgstr "Ultima Modificación"
+msgstr "Ordenar por Primera Modificación"
#: editor/filesystem_dock.cpp
msgid "Duplicate..."
@@ -4102,7 +4095,7 @@ msgstr "Renombrar..."
#: editor/filesystem_dock.cpp
msgid "Focus the search box"
-msgstr ""
+msgstr "Ubicar foco en la caja de búsqueda"
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -4412,14 +4405,12 @@ msgid "Failed to load resource."
msgstr "Fallo al cargar recurso."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Copy Properties"
-msgstr "Propiedades"
+msgstr "Copiar Propiedades"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Paste Properties"
-msgstr "Propiedades"
+msgstr "Pegar Propiedades"
#: editor/inspector_dock.cpp
msgid "Make Sub-Resources Unique"
@@ -4444,23 +4435,20 @@ msgid "Save As..."
msgstr "Guardar Como..."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Extra resource options."
-msgstr "No está en la ruta de recursos."
+msgstr "Opciones de recursos extra."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Edit Resource from Clipboard"
-msgstr "Editar Portapapeles de Recursos"
+msgstr "Editar Recurso desde el Portapapeles"
#: editor/inspector_dock.cpp
msgid "Copy Resource"
msgstr "Copiar Recurso"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Make Resource Built-In"
-msgstr "Crear Built-In"
+msgstr "Convertir en Recurso Integrado"
#: editor/inspector_dock.cpp
msgid "Go to the previous edited object in history."
@@ -4475,9 +4463,8 @@ msgid "History of recently edited objects."
msgstr "Historial de objetos recientemente editados."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Open documentation for this object."
-msgstr "Abrir Documentación"
+msgstr "Abrir la documentación para este objeto."
#: editor/inspector_dock.cpp editor/scene_tree_dock.cpp
msgid "Open Documentation"
@@ -4488,9 +4475,8 @@ msgid "Filter properties"
msgstr "Filtrar propiedades"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Manage object properties."
-msgstr "Propiedades del objeto."
+msgstr "Administrar propiedades del objeto."
#: editor/inspector_dock.cpp
msgid "Changes may be lost!"
@@ -4735,9 +4721,8 @@ msgid "Blend:"
msgstr "Blend:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Parameter Changed:"
-msgstr "Parámetro Modificado"
+msgstr "Parámetro Modificado:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
@@ -5471,11 +5456,11 @@ msgstr "Todos"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Search templates, projects, and demos"
-msgstr ""
+msgstr "Buscar plantillas, proyectos y demos"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Search assets (excluding templates, projects, and demos)"
-msgstr ""
+msgstr "Buscar assets (excluyendo plantillas, proyectos y demos)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Import..."
@@ -6124,14 +6109,12 @@ msgid "Clear Pose"
msgstr "Restablecer Pose"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Add Node Here"
-msgstr "Agregar Nodo"
+msgstr "Agregar Nodo Acá"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Instance Scene Here"
-msgstr "Instanciar Escena(s)"
+msgstr "Instanciar Escena Acá"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Multiply grid step by 2"
@@ -6147,49 +6130,43 @@ msgstr "Panear Vista"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 3.125%"
-msgstr ""
+msgstr "Zoom a 3.125%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 6.25%"
-msgstr ""
+msgstr "Zoom a 6.25%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 12.5%"
-msgstr ""
+msgstr "Zoom a 12.5%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 25%"
-msgstr "Alejar Zoom"
+msgstr "Zoom a 25%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 50%"
-msgstr "Alejar Zoom"
+msgstr "Zoom a 50%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 100%"
-msgstr "Alejar Zoom"
+msgstr "Zoom a 100%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 200%"
-msgstr "Alejar Zoom"
+msgstr "Zoom a 200%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 400%"
-msgstr "Alejar Zoom"
+msgstr "Zoom a 400%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 800%"
-msgstr "Alejar Zoom"
+msgstr "Zoom a 800%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 1600%"
-msgstr ""
+msgstr "Zoom a 1600%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Add %s"
@@ -8734,6 +8711,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Quitar Todos los Ãtems"
@@ -8764,6 +8747,12 @@ msgid "Remove All StyleBox Items"
msgstr "Quitar Todos los Ãtems"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Agregar Items de Clases"
@@ -12188,6 +12177,8 @@ msgid ""
"Warning: Having the script name be the same as a built-in type is usually "
"not desired."
msgstr ""
+"Advertencia: Usualmente no se recomienda que un script tenga el mismo nombre "
+"que un tipo integrado."
#: editor/script_create_dialog.cpp
msgid "Class Name:"
@@ -12437,6 +12428,16 @@ msgstr "Cambiar Altura de Shape Cilindro"
msgid "Change Ray Shape Length"
msgstr "Cambiar Largo de Shape Rayo"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Setear Posición de Punto de Curva"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Setear Posición de Punto de Curva"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "Cambiar Radio de Cilindro"
@@ -14233,6 +14234,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr "Este cuerpo será ignorado hasta que se establezca un mesh."
@@ -15498,9 +15535,6 @@ msgstr "Las constantes no pueden modificarse."
#~ msgid "I see..."
#~ msgstr "Ya Veo..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "No se puede abrir '%s'."
-
#~ msgid "Ugh"
#~ msgstr "Ugh"
diff --git a/editor/translations/et.po b/editor/translations/et.po
index 6f8561f8ab..13019cd9e3 100644
--- a/editor/translations/et.po
+++ b/editor/translations/et.po
@@ -340,6 +340,7 @@ msgstr "Muuda animatsiooni silmuse režiimi"
msgid "Remove Anim Track"
msgstr "Eemalda animatsiooni rada"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Loo uus rada %s-le ja sisesta võti?"
@@ -364,10 +365,27 @@ msgstr "Loo"
msgid "Anim Insert"
msgstr "Animatsiooni sisestus"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animatsioon"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "AnimationPlayer ei saa ennast animeerida, ainult teise mänijaid."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Atribuut"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Loo ja sisesta animatsioon"
@@ -930,7 +948,7 @@ msgstr ""
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2261,6 +2279,17 @@ msgid "New Window"
msgstr "Uus aken"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Imporditud ressursse ei saa salvestada."
@@ -3057,10 +3086,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr ""
@@ -3673,6 +3698,16 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Ava failihalduris"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Kopeeri viga"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8388,6 +8423,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Eemalda kõik katkepunktid"
@@ -8418,6 +8459,12 @@ msgid "Remove All StyleBox Items"
msgstr "Eemalda kõik katkepunktid"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Lisa lemmikutesse"
@@ -11868,6 +11915,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13479,6 +13534,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/eu.po b/editor/translations/eu.po
index 018f65b79e..7b6934ff33 100644
--- a/editor/translations/eu.po
+++ b/editor/translations/eu.po
@@ -340,6 +340,7 @@ msgstr "Animazioaren Loop Modua Aldatu"
msgid "Remove Anim Track"
msgstr "Ezabatu Animazio Pista"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "%s-rentzat pista berria sortu eta giltza sartu?"
@@ -364,10 +365,27 @@ msgstr "Sortu"
msgid "Anim Insert"
msgstr "Animazioa Sartu"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Kargatu animazioa"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "AnimationPlayer bat ezin da norbera animatu, soilik beste playerrak."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Propietateak"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Animazioa Sortu eta Txertatu"
@@ -929,7 +947,7 @@ msgstr ""
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2242,6 +2260,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3025,10 +3054,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr ""
@@ -3648,6 +3673,15 @@ msgid "Download from:"
msgstr "Jaitsiera errorea"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Ireki fitxategi-kudeatzailean"
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8355,6 +8389,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Kendu elementu guztiak"
@@ -8385,6 +8425,12 @@ msgid "Remove All StyleBox Items"
msgstr "Kendu elementu guztiak"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
msgstr ""
@@ -11835,6 +11881,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13441,6 +13495,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/fa.po b/editor/translations/fa.po
index 09cc83a73b..bb761cf137 100644
--- a/editor/translations/fa.po
+++ b/editor/translations/fa.po
@@ -357,6 +357,7 @@ msgstr "تغییر حالت تکررار (Loop) انیمیشن"
msgid "Remove Anim Track"
msgstr "حذ٠ترک انیمشین"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "یک ترک جدید برای s% بساز و کلید را درج کن؟"
@@ -381,10 +382,28 @@ msgstr "تولید"
msgid "Anim Insert"
msgstr "در انیمیشن درج کن"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "در حال اتصال..."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "انیمیشن"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "انیمیشن پلیر نمی تواند خود را انیمیت کند. Ùقط پلیر دیگر."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "ویژگی '%s' موجود نیست."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "ساختن و درج انیمیشن"
@@ -959,7 +978,7 @@ msgstr "ساختن %s جدید"
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2282,6 +2301,17 @@ msgid "New Window"
msgstr "چارچوب جدید"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3075,10 +3105,6 @@ msgid "Save & Restart"
msgstr "ذخیره و خروج"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
#, fuzzy
msgid "Update Continuously"
msgstr "مستمر"
@@ -3722,6 +3748,16 @@ msgid "Download from:"
msgstr "خطاهای بارگیری"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "گشودن در مدیر پرونده"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "خطاهای بارگذاری"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8726,6 +8762,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "برداشتن انتخاب شده"
@@ -8756,6 +8798,12 @@ msgid "Remove All StyleBox Items"
msgstr "برداشتن انتخاب شده"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Ø§ÙØ²ÙˆØ¯Ù† مورد"
@@ -12427,6 +12475,16 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "برداشتن موج"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "برداشتن موج"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -14176,6 +14234,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
@@ -14873,10 +14967,6 @@ msgstr "ثوابت قابل تغییر نیستند."
#~ msgid "Thanks!"
#~ msgstr "با تشکر !"
-#, fuzzy
-#~ msgid "Can't open '%s'."
-#~ msgstr "در حال اتصال..."
-
#~ msgid "Run Script"
#~ msgstr "اجرای اسکریپت"
diff --git a/editor/translations/fi.po b/editor/translations/fi.po
index f0b5ff0457..ffedccec28 100644
--- a/editor/translations/fi.po
+++ b/editor/translations/fi.po
@@ -16,7 +16,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-07-29 21:48+0000\n"
+"PO-Revision-Date: 2021-08-10 21:40+0000\n"
"Last-Translator: Tapani Niemi <tapani.niemi@kapsi.fi>\n"
"Language-Team: Finnish <https://hosted.weblate.org/projects/godot-engine/"
"godot/fi/>\n"
@@ -25,7 +25,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.7.2-dev\n"
+"X-Generator: Weblate 4.8-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -347,6 +347,7 @@ msgstr "Vaihda animaation toistotilaa"
msgid "Remove Anim Track"
msgstr "Poista animaatioraita"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Luo kohteelle %s UUSI raita ja lisää avain?"
@@ -371,10 +372,28 @@ msgstr "Luo"
msgid "Anim Insert"
msgstr "Animaatio: lisää"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "Ei voida avata tiedostoa '%s'."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animaatio"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "AnimationPlayer ei voi animoida itseään, vain muita toistimia."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Ominaisuutta '%s' ei löytynyt."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Animaatio: luo ja lisää"
@@ -580,9 +599,8 @@ msgid "Go to Previous Step"
msgstr "Mene edelliseen askeleeseen"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Apply Reset"
-msgstr "Palauta"
+msgstr "Tee palautus"
#: editor/animation_track_editor.cpp
msgid "Optimize Animation"
@@ -601,9 +619,8 @@ msgid "Use Bezier Curves"
msgstr "Käytä Bezier-käyriä"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Create RESET Track(s)"
-msgstr "Liitä raidat"
+msgstr "Luo palautusraidat"
#: editor/animation_track_editor.cpp
msgid "Anim. Optimizer"
@@ -927,7 +944,6 @@ msgid "Edit..."
msgstr "Muokkaa..."
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Go to Method"
msgstr "Mene metodiin"
@@ -947,9 +963,9 @@ msgstr "Luo uusi %s"
msgid "No results for \"%s\"."
msgstr "Ei tuloksia haulle \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
-msgstr ""
+msgstr "%s kuvaus ei ole saatavilla."
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp
@@ -1049,18 +1065,16 @@ msgid "Owners Of:"
msgstr "Omistajat kohteelle:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove the selected files from the project? (Cannot be undone.)\n"
"Depending on your filesystem configuration, the files will either be moved "
"to the system trash or deleted permanently."
msgstr ""
-"Poista valitut tiedostot projektista? (ei voida kumota)\n"
-"Löydät poistetut tiedostot järjestelmän roskakorista, mikäli haluat "
-"palauttaa ne."
+"Poista valitut tiedostot projektista? (Ei voida kumota.)\n"
+"Riippuen tiedostojärjestelmäsi asetuksista, tiedostot siirretään joko "
+"järjestelmän roskakoriin tai poistetaan pysyvästi."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1069,9 +1083,9 @@ msgid ""
"to the system trash or deleted permanently."
msgstr ""
"Poistettavia tiedostoja tarvitaan muiden resurssien toimivuuteen.\n"
-"Poistetaanko silti? (ei voida kumota)\n"
-"Löydät poistetut tiedostot järjestelmän roskakorista, mikäli haluat "
-"palauttaa ne."
+"Poistetaanko ne silti? (Ei voida kumota.)\n"
+"Riippuen tiedostojärjestelmäsi asetuksista, tiedostot siirretään joko "
+"järjestelmän roskakoriin tai poistetaan pysyvästi."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1241,41 +1255,39 @@ msgid "Licenses"
msgstr "Lisenssit"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Error opening asset file for \"%s\" (not in ZIP format)."
-msgstr "Virhe avattaessa pakettitiedostoa (se ei ole ZIP-muodossa)."
+msgstr "Virhe avattaessa \"%s\" asset-tiedostoa (se ei ole ZIP-muodossa)."
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "%s (already exists)"
msgstr "%s (on jo olemassa)"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - %d file(s) conflict with your project:"
msgstr ""
+"Assetin \"%s\"sisältö - %d tiedostoa on ristiriidassa projektisi kanssa:"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - No files conflict with your project:"
msgstr ""
+"Assetin \"%s\" sisältö - Yksikään tiedosto ei ole ristiriidassa projektisi "
+"kanssa:"
#: editor/editor_asset_installer.cpp
msgid "Uncompressing Assets"
msgstr "Puretaan assetteja"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "The following files failed extraction from asset \"%s\":"
-msgstr "Seuraavien tiedostojen purku paketista epäonnistui:"
+msgstr "Seuraavien tiedostojen purku assetista \"%s\" epäonnistui:"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "(and %s more files)"
-msgstr "Ja vielä %s tiedostoa."
+msgstr "(ja vielä %s tiedostoa)"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset \"%s\" installed successfully!"
-msgstr "Paketti asennettu onnistuneesti!"
+msgstr "Asset \"%s\" asennettu onnistuneesti!"
#: editor/editor_asset_installer.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -1287,9 +1299,8 @@ msgid "Install"
msgstr "Asenna"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset Installer"
-msgstr "Pakettien asentaja"
+msgstr "Assettien asentaja"
#: editor/editor_audio_buses.cpp
msgid "Speakers"
@@ -1352,7 +1363,6 @@ msgid "Bypass"
msgstr "Ohita"
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "Bus Options"
msgstr "Väylän asetukset"
@@ -1523,13 +1533,12 @@ msgid "Can't add autoload:"
msgstr "Ei voida lisätä automaattisesti ladattavaa:"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "%s is an invalid path. File does not exist."
-msgstr "Tiedostoa ei ole olemassa."
+msgstr "%s on virheellinen polku. Tiedostoa ei ole olemassa."
#: editor/editor_autoload_settings.cpp
msgid "%s is an invalid path. Not in resource path (res://)."
-msgstr ""
+msgstr "%s on virheellinen polku. Ei löydy resurssipolusta (res://)."
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -1553,9 +1562,8 @@ msgid "Name"
msgstr "Nimi"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "Global Variable"
-msgstr "Muuttuja"
+msgstr "Globaali muuttuja"
#: editor/editor_data.cpp
msgid "Paste Params"
@@ -1728,48 +1736,51 @@ msgstr "Tuontitelakka"
#: editor/editor_feature_profile.cpp
msgid "Allows to view and edit 3D scenes."
-msgstr ""
+msgstr "Antaa katsella ja muokata 3D-skenejä."
#: editor/editor_feature_profile.cpp
msgid "Allows to edit scripts using the integrated script editor."
-msgstr ""
+msgstr "Antaa muokata skriptejä käyttäen integroitua skriptieditoria."
#: editor/editor_feature_profile.cpp
msgid "Provides built-in access to the Asset Library."
-msgstr ""
+msgstr "Tarjoaa valmiin pääsyn Asset-kirjastoon."
#: editor/editor_feature_profile.cpp
msgid "Allows editing the node hierarchy in the Scene dock."
-msgstr ""
+msgstr "Antaa muokata solmuhierarkiaa Skene-telakassa."
#: editor/editor_feature_profile.cpp
msgid ""
"Allows to work with signals and groups of the node selected in the Scene "
"dock."
msgstr ""
+"Antaa työskennellä valitun solmun signaalien ja ryhmien kanssa Skene-"
+"telakassa."
#: editor/editor_feature_profile.cpp
msgid "Allows to browse the local file system via a dedicated dock."
-msgstr ""
+msgstr "Antaa selata paikallista tiedostojärjestelmää erillisellä telakalla."
#: editor/editor_feature_profile.cpp
msgid ""
"Allows to configure import settings for individual assets. Requires the "
"FileSystem dock to function."
msgstr ""
+"Antaa konfiguroida tuontiasetuksia yksittäiselle assetille. Edellyttää "
+"Tiedostojärjestelmä-telakkaa toimiakseen."
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "(current)"
-msgstr "(Nykyinen)"
+msgstr "(nykyinen)"
#: editor/editor_feature_profile.cpp
msgid "(none)"
-msgstr ""
+msgstr "(ei mikään)"
#: editor/editor_feature_profile.cpp
msgid "Remove currently selected profile, '%s'? Cannot be undone."
-msgstr ""
+msgstr "Poistetaanko nykyinen valittu profiili, '%s'? Ei voida kumota."
#: editor/editor_feature_profile.cpp
msgid "Profile must be a valid filename and must not contain '.'"
@@ -1802,19 +1813,16 @@ msgid "Enable Contextual Editor"
msgstr "Ota asiayhteydellinen editori käyttöön"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Class Properties:"
-msgstr "Ominaisuudet:"
+msgstr "Luokan ominaisuudet:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Main Features:"
-msgstr "Ominaisuudet"
+msgstr "Pääominaisuudet:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Nodes and Classes:"
-msgstr "Käytössä olevat luokat:"
+msgstr "Solmut ja luokat:"
#: editor/editor_feature_profile.cpp
msgid "File '%s' format is invalid, import aborted."
@@ -1833,7 +1841,6 @@ msgid "Error saving profile to path: '%s'."
msgstr "Virhe tallennettaessa profiilia polkuun: '%s'."
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Reset to Default"
msgstr "Palauta oletusarvoihin"
@@ -1842,14 +1849,12 @@ msgid "Current Profile:"
msgstr "Nykyinen profiili:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Create Profile"
-msgstr "Tyhjennä profiili"
+msgstr "Luo profiili"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Remove Profile"
-msgstr "Poista laatta"
+msgstr "Poista profiili"
#: editor/editor_feature_profile.cpp
msgid "Available Profiles:"
@@ -1869,18 +1874,17 @@ msgid "Export"
msgstr "Vie"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Configure Selected Profile:"
-msgstr "Nykyinen profiili:"
+msgstr "Konfiguroi valittu profiili:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Extra Options:"
-msgstr "Tekstuurin asetukset"
+msgstr "Ylimääräiset asetukset:"
#: editor/editor_feature_profile.cpp
msgid "Create or import a profile to edit available classes and properties."
msgstr ""
+"Luo tai tuo profiili muokataksesi saatavilla olevia luokkia ja ominaisuuksia."
#: editor/editor_feature_profile.cpp
msgid "New profile name:"
@@ -1907,9 +1911,8 @@ msgid "Select Current Folder"
msgstr "Valitse nykyinen kansio"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
-#, fuzzy
msgid "File exists, overwrite?"
-msgstr "Tiedosto on jo olemassa, korvaa?"
+msgstr "Tiedosto on jo olemassa, korvataanko?"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Select This Folder"
@@ -2301,6 +2304,17 @@ msgid "New Window"
msgstr "Uusi ikkuna"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Pyörii kun editorin ikkuna päivittyy."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Tuotuja resursseja ei voida tallentaa."
@@ -2530,13 +2544,16 @@ msgid ""
"The current scene has no root node, but %d modified external resource(s) "
"were saved anyway."
msgstr ""
+"Nykyisellä skenellä ei ole juurisolmua, mutta %d muokattua ulkoista "
+"resurssia tallennettiin silti."
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"A root node is required to save the scene. You can add a root node using the "
"Scene tree dock."
-msgstr "Skenen tallentaminen edellyttää, että sillä on juurisolmu."
+msgstr ""
+"Skenen tallentaminen edellyttää, että sillä on juurisolmu. Voit lisätä "
+"juurisolmun Skene-telakasta."
#: editor/editor_node.cpp
msgid "Save Scene As..."
@@ -2914,9 +2931,8 @@ msgid "Orphan Resource Explorer..."
msgstr "Irrallisten resurssien hallinta..."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reload Current Project"
-msgstr "Nimetä projekti"
+msgstr "Lataa uudelleen nykyinen projekti"
#: editor/editor_node.cpp
msgid "Quit to Project List"
@@ -3076,22 +3092,20 @@ msgid "Help"
msgstr "Ohje"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Online Documentation"
-msgstr "Avaa dokumentaatio"
+msgstr "Online-dokumentaatio"
#: editor/editor_node.cpp
msgid "Questions & Answers"
-msgstr ""
+msgstr "Kysymykset & vastaukset"
#: editor/editor_node.cpp
msgid "Report a Bug"
msgstr "Raportoi bugi"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Suggest a Feature"
-msgstr "Aseta arvo"
+msgstr "Ehdota ominaisuutta"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
@@ -3102,9 +3116,8 @@ msgid "Community"
msgstr "Yhteisö"
#: editor/editor_node.cpp
-#, fuzzy
msgid "About Godot"
-msgstr "Tietoja"
+msgstr "Tietoja Godotista"
#: editor/editor_node.cpp
msgid "Support Godot Development"
@@ -3156,10 +3169,6 @@ msgid "Save & Restart"
msgstr "Tallenna & käynnistä uudelleen"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Pyörii kun editorin ikkuna päivittyy."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Päivitä jatkuvasti"
@@ -3200,14 +3209,12 @@ msgid "Manage Templates"
msgstr "Hallinnoi malleja"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Install from file"
msgstr "Asenna tiedostosta"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Select android sources file"
-msgstr "Valitse lähdemesh:"
+msgstr "Valitse android-lähdetiedosto"
#: editor/editor_node.cpp
msgid ""
@@ -3290,9 +3297,8 @@ msgid "Select"
msgstr "Valitse"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Select Current"
-msgstr "Valitse nykyinen kansio"
+msgstr "Valitse nykyinen"
#: editor/editor_node.cpp
msgid "Open 2D Editor"
@@ -3327,9 +3333,8 @@ msgid "No sub-resources found."
msgstr "Aliresursseja ei löydetty."
#: editor/editor_path.cpp
-#, fuzzy
msgid "Open a list of sub-resources."
-msgstr "Aliresursseja ei löydetty."
+msgstr "Avaa aliresurssien luettelo."
#: editor/editor_plugin.cpp
msgid "Creating Mesh Previews"
@@ -3356,14 +3361,12 @@ msgid "Update"
msgstr "Päivitä"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Version"
-msgstr "Versio:"
+msgstr "Versio"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Author"
-msgstr "Tekijät"
+msgstr "Tekijä"
#: editor/editor_plugin_settings.cpp
#: editor/plugins/version_control_editor_plugin.cpp
@@ -3376,14 +3379,12 @@ msgid "Measure:"
msgstr "Mittaa:"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Frame Time (ms)"
-msgstr "Kuvaruudun aika (sek)"
+msgstr "Kuvaruudun aika (ms)"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Average Time (ms)"
-msgstr "Keskimääräinen aika (sek)"
+msgstr "Keskimääräinen aika (ms)"
#: editor/editor_profiler.cpp
msgid "Frame %"
@@ -3410,6 +3411,13 @@ msgid ""
"functions called by that function.\n"
"Use this to find individual functions to optimize."
msgstr ""
+"Sisältävä: Sisältää muissa tämän funktion kutsumissa funktioissa kuluneen "
+"ajan.\n"
+"Käytä tätä löytääksesi pullonkaulat.\n"
+"\n"
+"Itse: Lasketaan ainoastaan funktiossa itsessään kulunut aika, eikä muissa "
+"tuon funktion kutsumissa funktioissa käytettyä aikaa.\n"
+"Käytä tätä löytääksesi yksittäiset optimointia vaativat funktiot."
#: editor/editor_profiler.cpp
msgid "Frame #:"
@@ -3532,7 +3540,6 @@ msgid "Paste"
msgstr "Liitä"
#: editor/editor_resource_picker.cpp editor/property_editor.cpp
-#, fuzzy
msgid "Convert to %s"
msgstr "Muunna muotoon %s"
@@ -3625,31 +3632,27 @@ msgstr "Noudetaan peilipalvelimia, hetkinen..."
#: editor/export_template_manager.cpp
msgid "Starting the download..."
-msgstr ""
+msgstr "Aloitetaan lataus..."
#: editor/export_template_manager.cpp
msgid "Error requesting URL:"
msgstr "Virhe pyydettäessä osoitetta:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Connecting to the mirror..."
msgstr "Yhdistetään peilipalvelimeen..."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't resolve the requested address."
-msgstr "Palvelinta ei löytynyt:"
+msgstr "Pyydetyn osoitteen selvitys ei onnistunut."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't connect to the mirror."
-msgstr "Isäntään yhdistäminen epäonnistui:"
+msgstr "Peilipalvelimeen yhdistäminen epäonnistui."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "No response from the mirror."
-msgstr "Ei vastausta isännältä:"
+msgstr "Ei vastausta peilipalvelimelta."
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -3657,18 +3660,16 @@ msgid "Request failed."
msgstr "Pyyntö epäonnistui."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Request ended up in a redirect loop."
-msgstr "Pyyntö epäonnistui, liikaa uudelleenohjauksia"
+msgstr "Pyyntö päätyi uudelleenohjaussilmukkaan."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Request failed:"
-msgstr "Pyyntö epäonnistui."
+msgstr "Pyyntö epäonnistui:"
#: editor/export_template_manager.cpp
msgid "Download complete; extracting templates..."
-msgstr ""
+msgstr "Lataaminen valmis; puretaan malleja..."
#: editor/export_template_manager.cpp
msgid "Cannot remove temporary file:"
@@ -3695,7 +3696,7 @@ msgstr ""
#: editor/export_template_manager.cpp
msgid "Best available mirror"
-msgstr ""
+msgstr "Paras saatavilla oleva peilipalvelin"
#: editor/export_template_manager.cpp
msgid ""
@@ -3748,9 +3749,8 @@ msgid "SSL Handshake Error"
msgstr "Virhe SSL kättelyssä"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't open the export templates file."
-msgstr "Vientimallien zip-tiedostoa ei voitu avata."
+msgstr "Vientimallien tiedostoa ei voida avata."
#: editor/export_template_manager.cpp
#, fuzzy
@@ -3801,9 +3801,8 @@ msgid "Export templates are installed and ready to be used."
msgstr ""
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Open Folder"
-msgstr "Avaa tiedosto"
+msgstr "Avaa kansio"
#: editor/export_template_manager.cpp
msgid "Open the folder containing installed templates for the current version."
@@ -3819,33 +3818,42 @@ msgid "Uninstall templates for the current version."
msgstr "Laskurin alkuarvo"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Download from:"
-msgstr "Latausvirhe"
+msgstr "Lataa sijannista:"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Suorita selaimessa"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Kopioi virhe"
#: editor/export_template_manager.cpp
msgid "Download and Install"
-msgstr ""
+msgstr "Lataa ja asenna"
#: editor/export_template_manager.cpp
msgid ""
"Download and install templates for the current version from the best "
"possible mirror."
msgstr ""
+"Lataa ja asenna mallit nykyiselle versiolle parhaasta mahdollisesta "
+"peilipalvelimesta."
#: editor/export_template_manager.cpp
msgid "Official export templates aren't available for development builds."
msgstr "Viralliset vientimallit eivät ole saatavilla kehityskäännöksille."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Install from File"
msgstr "Asenna tiedostosta"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Install templates from a local file."
-msgstr "Tuo mallit ZIP-tiedostosta"
+msgstr "Asenna mallit paikallisesta tiedostosta."
#: editor/export_template_manager.cpp editor/find_in_files.cpp
#: editor/progress_dialog.cpp scene/gui/dialogs.cpp
@@ -3853,19 +3861,16 @@ msgid "Cancel"
msgstr "Peruuta"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Cancel the download of the templates."
-msgstr "Vientimallien zip-tiedostoa ei voitu avata."
+msgstr "Keskeytä mallien lataus."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Other Installed Versions:"
-msgstr "Asennetut versiot:"
+msgstr "Muut asennetut versiot:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Uninstall Template"
-msgstr "Poista asennus"
+msgstr "Poista malli"
#: editor/export_template_manager.cpp
msgid "Select Template File"
@@ -3880,6 +3885,8 @@ msgid ""
"The templates will continue to download.\n"
"You may experience a short editor freeze when they finish."
msgstr ""
+"Mallien lataus jatkuu.\n"
+"Saatat kokea lyhyitä editorin jähmettymisiä niiden tullessa valmiiksi."
#: editor/filesystem_dock.cpp
msgid "Favorites"
@@ -4026,35 +4033,32 @@ msgid "Collapse All"
msgstr "Tiivistä kaikki"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort files"
-msgstr "Etsi tiedostoista"
+msgstr "Lajittele tiedostot"
#: editor/filesystem_dock.cpp
msgid "Sort by Name (Ascending)"
-msgstr ""
+msgstr "Lajittele nimen mukaan (nouseva)"
#: editor/filesystem_dock.cpp
msgid "Sort by Name (Descending)"
-msgstr ""
+msgstr "Lajittele nimen mukaan (laskeva)"
#: editor/filesystem_dock.cpp
msgid "Sort by Type (Ascending)"
-msgstr ""
+msgstr "Lajittele tyypin mukaan (nouseva)"
#: editor/filesystem_dock.cpp
msgid "Sort by Type (Descending)"
-msgstr ""
+msgstr "Lajittele tyypin mukaan (laskeva)"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort by Last Modified"
-msgstr "Viimeksi muutettu"
+msgstr "Lajittele viimeksi muokatun mukaan"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort by First Modified"
-msgstr "Viimeksi muutettu"
+msgstr "Lajittele ensiksi muokatun mukaan"
#: editor/filesystem_dock.cpp
msgid "Duplicate..."
@@ -4378,14 +4382,12 @@ msgid "Failed to load resource."
msgstr "Resurssin lataaminen epäonnistui."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Copy Properties"
-msgstr "Ominaisuudet"
+msgstr "Kopioi ominaisuudet"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Paste Properties"
-msgstr "Ominaisuudet"
+msgstr "Liitä ominaisuudet"
#: editor/inspector_dock.cpp
msgid "Make Sub-Resources Unique"
@@ -4410,9 +4412,8 @@ msgid "Save As..."
msgstr "Tallenna nimellä..."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Extra resource options."
-msgstr "Ei löytynyt resurssipolusta."
+msgstr "Ylimääräiset resurssivalinnat."
#: editor/inspector_dock.cpp
#, fuzzy
@@ -5437,7 +5438,7 @@ msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Search assets (excluding templates, projects, and demos)"
-msgstr ""
+msgstr "Etsi assetteja (poislukien mallit, projektit ja demot)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Import..."
@@ -5481,7 +5482,7 @@ msgstr "Assettien zip-tiedosto"
#: editor/plugins/audio_stream_editor_plugin.cpp
msgid "Audio Preview Play/Pause"
-msgstr ""
+msgstr "Äänen esikuuntelun toisto/keskeytys"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
@@ -5741,13 +5742,12 @@ msgstr "Muuta ankkureita"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid ""
"Project Camera Override\n"
"Overrides the running project's camera with the editor viewport camera."
msgstr ""
-"Pelikameran ohitus\n"
-"Ohittaa pelikameran editorin näyttöruutukameralla."
+"Projektikameran ohitus\n"
+"Ohittaa käynnissä olevan projektin kameran editorin näyttöruutukameralla."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5756,6 +5756,9 @@ msgid ""
"No project instance running. Run the project from the editor to use this "
"feature."
msgstr ""
+"Projektikameran ohitus\n"
+"Mikään projekti ei ole käynnissä. Aja projekti editorista käyttääksesi tätä "
+"ominaisuutta."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -8692,6 +8695,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Poista kaikki"
@@ -8722,6 +8731,12 @@ msgid "Remove All StyleBox Items"
msgstr "Poista kaikki"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Lisää luokka"
@@ -12384,6 +12399,16 @@ msgstr "Muuta sylinterimuodon korkeutta"
msgid "Change Ray Shape Length"
msgstr "Vaihda säteen muodon pituutta"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Aseta käyräpisteen sijainti"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Aseta käyräpisteen sijainti"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "Muuta sylinterin sädettä"
@@ -14163,6 +14188,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr "Tämä kappale sivuutetaan, kunnes asetat meshin."
@@ -15490,9 +15551,6 @@ msgstr "Vakioita ei voi muokata."
#~ msgid "I see..."
#~ msgstr "Ymmärrän..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "Ei voida avata tiedostoa '%s'."
-
#~ msgid "Ugh"
#~ msgstr "Äh"
diff --git a/editor/translations/fil.po b/editor/translations/fil.po
index aacdf9c442..e53b7bb1a7 100644
--- a/editor/translations/fil.po
+++ b/editor/translations/fil.po
@@ -345,6 +345,7 @@ msgstr ""
msgid "Remove Anim Track"
msgstr ""
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr ""
@@ -369,10 +370,26 @@ msgstr "Lumikha"
msgid "Anim Insert"
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Pagulit ng Animation"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr ""
@@ -928,7 +945,7 @@ msgstr ""
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2222,6 +2239,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3002,10 +3030,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
#, fuzzy
msgid "Update Continuously"
msgstr "Tuloy-tuloy"
@@ -3615,6 +3639,14 @@ msgid "Download from:"
msgstr "Kumpleto ang pag-Download."
#: editor/export_template_manager.cpp
+msgid "Open in Web Browser"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8303,6 +8335,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Color Items"
msgstr ""
@@ -8329,6 +8367,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
msgstr ""
@@ -11749,6 +11793,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13350,6 +13402,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/fr.po b/editor/translations/fr.po
index 9be7d406dd..e6e2c9021e 100644
--- a/editor/translations/fr.po
+++ b/editor/translations/fr.po
@@ -42,7 +42,7 @@
# Xananax <xananax@yelostudio.com>, 2017-2018.
# Perrier Mathis <mathis.perrier73@gmail.com>, 2018.
# Ewan Lehnebach <ewan.lehnebach@gmail.com>, 2018.
-# Hugo Locurcio <hugo.locurcio@hugo.pro>, 2018, 2019, 2020.
+# Hugo Locurcio <hugo.locurcio@hugo.pro>, 2018, 2019, 2020, 2021.
# Grigore Antoniuc <grisa181@gmail.com>, 2018.
# x2f <x.defoy@gmail.com>, 2018.
# LittleWhite <lw.demoscene@googlemail.com>, 2018.
@@ -81,12 +81,14 @@
# ASTRALE <jules.cercy@etu.univ-lyon1.fr>, 2021.
# Julien Vanelian <julienvanelian@hotmail.com>, 2021.
# Clément Topy <topy72.mine@gmail.com>, 2021.
+# Cold <coldragon78@gmail.com>, 2021.
+# Blackiris <divjvc@free.fr>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-07-16 05:47+0000\n"
-"Last-Translator: Pierre Caye <pierrecaye@laposte.net>\n"
+"PO-Revision-Date: 2021-08-12 14:48+0000\n"
+"Last-Translator: Blackiris <divjvc@free.fr>\n"
"Language-Team: French <https://hosted.weblate.org/projects/godot-engine/"
"godot/fr/>\n"
"Language: fr\n"
@@ -94,7 +96,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 4.7.2-dev\n"
+"X-Generator: Weblate 4.8-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -416,6 +418,7 @@ msgstr "Modifier le mode de boucle d’animation"
msgid "Remove Anim Track"
msgstr "Supprimer la piste d’animation"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Créer une NOUVELLE piste pour %s et insérer une clé ?"
@@ -440,11 +443,29 @@ msgstr "Créer"
msgid "Anim Insert"
msgstr "Insérer une animation"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "Mode d'aimantation (%s)"
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animation"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
"Un AnimationPlayer ne peut s’animer lui-même, seulement les autres lecteurs."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Il n'y a pas de propriété « %s »."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Créer et insérer une animation"
@@ -660,9 +681,8 @@ msgid "Go to Previous Step"
msgstr "Aller à l'étape précédente"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Apply Reset"
-msgstr "Réinitialiser"
+msgstr "Appliquer la réinitialisation"
#: editor/animation_track_editor.cpp
msgid "Optimize Animation"
@@ -681,9 +701,8 @@ msgid "Use Bezier Curves"
msgstr "Utiliser les courbes de Bézier"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Create RESET Track(s)"
-msgstr "Coller pistes"
+msgstr "Créer des pistes RESET"
#: editor/animation_track_editor.cpp
msgid "Anim. Optimizer"
@@ -1008,7 +1027,6 @@ msgid "Edit..."
msgstr "Édition..."
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Go to Method"
msgstr "Aller à la méthode"
@@ -1028,9 +1046,9 @@ msgstr "Créer un nouveau %s"
msgid "No results for \"%s\"."
msgstr "Aucun résultats pour \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
-msgstr ""
+msgstr "Pas de description disponible pour %s."
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp
@@ -1130,18 +1148,16 @@ msgid "Owners Of:"
msgstr "Propriétaires de :"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove the selected files from the project? (Cannot be undone.)\n"
"Depending on your filesystem configuration, the files will either be moved "
"to the system trash or deleted permanently."
msgstr ""
-"Supprimer les fichiers sélectionnés du projet ? (annulation impossible)\n"
-"Vous pouvez retrouver les fichiers supprimés dans la corbeille du système "
-"pour les restaurer."
+"Supprimer les fichiers sélectionnés du projet ? (Annulation impossible.)\n"
+"En fonction de la configuration de votre système, les fichiers seront soient "
+"déplacés vers la corbeille du système, soit supprimés définitivement."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1151,9 +1167,9 @@ msgid ""
msgstr ""
"Les fichiers qui vont être supprimés sont utilisés par d'autres ressources "
"pour leur fonctionnement.\n"
-"Les supprimer tout de même ? (annulation impossible)\n"
-"Vous pouvez retrouver les fichiers supprimés dans la corbeille du système "
-"pour les restaurer."
+"Les supprimer tout de même ? (Annulation impossible.)\n"
+"En fonction de la configuration de votre système, les fichiers seront soient "
+"déplacés vers la corbeille du système, soit supprimés définitivement."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1323,42 +1339,41 @@ msgid "Licenses"
msgstr "Licences"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Error opening asset file for \"%s\" (not in ZIP format)."
msgstr ""
-"Erreur lors de l'ouverture du fichier package (il n'est pas au format ZIP)."
+"Erreur lors de l'ouverture du fichier d'asset « %s » (il n'est pas au format "
+"ZIP)."
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "%s (already exists)"
msgstr "%s (existe déjà)"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - %d file(s) conflict with your project:"
msgstr ""
+"Contenus de l'asset « %s » - %d fichier(s) sont en conflit avec votre "
+"projet :"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - No files conflict with your project:"
msgstr ""
+"Contenus de l'asset « %s » - Pas de fichiers en conflit avec votre projet :"
#: editor/editor_asset_installer.cpp
msgid "Uncompressing Assets"
msgstr "Décompression des assets"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "The following files failed extraction from asset \"%s\":"
-msgstr "L'extraction des fichiers suivants depuis le paquetage a échoué :"
+msgstr "L'extraction des fichiers suivants depuis l'asset « %s » a échoué :"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "(and %s more files)"
-msgstr "Et %s fichiers supplémentaires."
+msgstr "(et %s fichiers supplémentaires)"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset \"%s\" installed successfully!"
-msgstr "Paquetage installé avec succès !"
+msgstr "Asset « %s » installé avec succès !"
#: editor/editor_asset_installer.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -1370,9 +1385,8 @@ msgid "Install"
msgstr "Installer"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset Installer"
-msgstr "Installeur de paquetage"
+msgstr "Installateur d'asset"
#: editor/editor_audio_buses.cpp
msgid "Speakers"
@@ -1435,7 +1449,6 @@ msgid "Bypass"
msgstr "Contourner"
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "Bus Options"
msgstr "Options de bus"
@@ -1605,28 +1618,29 @@ msgid "Can't add autoload:"
msgstr "Impossible d'ajouter le chargement automatique :"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "%s is an invalid path. File does not exist."
-msgstr "Le fichier n'existe pas."
+msgstr "%s est un chemin invalide. Le fichier n'existe pas."
#: editor/editor_autoload_settings.cpp
msgid "%s is an invalid path. Not in resource path (res://)."
msgstr ""
+"%s est un chemin invalide. Il n'est pas dans le chemin des ressources "
+"(res://)."
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
-msgstr "Ajouter le chargement automatique"
+msgstr "Ajouter chargement automatique"
#: editor/editor_autoload_settings.cpp editor/editor_file_dialog.cpp
#: editor/editor_plugin_settings.cpp
#: editor/plugins/animation_tree_editor_plugin.cpp
#: editor/script_create_dialog.cpp scene/gui/file_dialog.cpp
msgid "Path:"
-msgstr "Chemin :"
+msgstr "Chemin :"
#: editor/editor_autoload_settings.cpp
msgid "Node Name:"
-msgstr "Nom de nœud :"
+msgstr "Nom de nœud :"
#: editor/editor_autoload_settings.cpp editor/editor_help_search.cpp
#: editor/editor_plugin_settings.cpp editor/editor_profiler.cpp
@@ -1635,9 +1649,8 @@ msgid "Name"
msgstr "Nom"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "Global Variable"
-msgstr "Renommer la variable"
+msgstr "Variable globale"
#: editor/editor_data.cpp
msgid "Paste Params"
@@ -1811,48 +1824,55 @@ msgstr "Dock d'importation"
#: editor/editor_feature_profile.cpp
msgid "Allows to view and edit 3D scenes."
-msgstr ""
+msgstr "Permet de visualiser et modifier des scènes 3D."
#: editor/editor_feature_profile.cpp
msgid "Allows to edit scripts using the integrated script editor."
msgstr ""
+"Permet de modifier des scripts à l'aide de l'éditeur de script intégré."
#: editor/editor_feature_profile.cpp
msgid "Provides built-in access to the Asset Library."
-msgstr ""
+msgstr "Fournit un accès à l'Asset Library."
#: editor/editor_feature_profile.cpp
msgid "Allows editing the node hierarchy in the Scene dock."
-msgstr ""
+msgstr "Permet de visualiser la hiérarchie des nœuds dans le dock Scène."
#: editor/editor_feature_profile.cpp
msgid ""
"Allows to work with signals and groups of the node selected in the Scene "
"dock."
msgstr ""
+"Permet de travailler avec les signaux et groupes d'un nœud sélectionné dans "
+"le dock Scène."
#: editor/editor_feature_profile.cpp
msgid "Allows to browse the local file system via a dedicated dock."
msgstr ""
+"Permet de naviguer le système de fichiers local à l'aide d'un dock dédié."
#: editor/editor_feature_profile.cpp
msgid ""
"Allows to configure import settings for individual assets. Requires the "
"FileSystem dock to function."
msgstr ""
+"Permet de configurer les paramètres d'importation pour des ressources "
+"individuelles. Nécessite le dock Système de fichiers pour fonctionner."
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "(current)"
-msgstr "(Actuel)"
+msgstr "(actuel)"
#: editor/editor_feature_profile.cpp
msgid "(none)"
-msgstr ""
+msgstr "(aucun)"
#: editor/editor_feature_profile.cpp
msgid "Remove currently selected profile, '%s'? Cannot be undone."
msgstr ""
+"Supprimer le profil actuellement sélectionné « %s » ? Cette suppression ne "
+"peut être annulée."
#: editor/editor_feature_profile.cpp
msgid "Profile must be a valid filename and must not contain '.'"
@@ -1884,19 +1904,16 @@ msgid "Enable Contextual Editor"
msgstr "Ouvrir l'éditeur contextuel"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Class Properties:"
-msgstr "Propriétés :"
+msgstr "Propriétés de la classe :"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Main Features:"
-msgstr "Fonctionnalités"
+msgstr "Fonctionnalités principales :"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Nodes and Classes:"
-msgstr "Classes activées :"
+msgstr "Nœuds et classes :"
#: editor/editor_feature_profile.cpp
msgid "File '%s' format is invalid, import aborted."
@@ -1915,23 +1932,20 @@ msgid "Error saving profile to path: '%s'."
msgstr "Erreur lors de l'enregistrement du profil au chemin : « %s »."
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Reset to Default"
-msgstr "Réinitialiser"
+msgstr "Réinitialiser aux valeurs par défaut"
#: editor/editor_feature_profile.cpp
msgid "Current Profile:"
msgstr "Profil actuel :"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Create Profile"
-msgstr "Effacer le profil"
+msgstr "Créer un profil"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Remove Profile"
-msgstr "Supprimer la tuile"
+msgstr "Supprimer le profil"
#: editor/editor_feature_profile.cpp
msgid "Available Profiles:"
@@ -1951,18 +1965,18 @@ msgid "Export"
msgstr "Exporter"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Configure Selected Profile:"
-msgstr "Profil actuel :"
+msgstr "Configurer le profil sélectionné :"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Extra Options:"
-msgstr "Options de classe :"
+msgstr "Options additionnelles :"
#: editor/editor_feature_profile.cpp
msgid "Create or import a profile to edit available classes and properties."
msgstr ""
+"Créer ou importer un profil pour modifier les classes et propriétés "
+"disponibles."
#: editor/editor_feature_profile.cpp
msgid "New profile name:"
@@ -1989,9 +2003,8 @@ msgid "Select Current Folder"
msgstr "Sélectionner le dossier courant"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
-#, fuzzy
msgid "File exists, overwrite?"
-msgstr "Le fichier existe, l'écraser ?"
+msgstr "Le fichier existe, l'écraser ?"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Select This Folder"
@@ -2384,6 +2397,17 @@ msgid "New Window"
msgstr "Nouvelle Fenêtre"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Tourne lorsque la fenêtre de l'éditeur est redessinée."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Les ressources importées ne peuvent pas être sauvegardées."
@@ -2620,13 +2644,16 @@ msgid ""
"The current scene has no root node, but %d modified external resource(s) "
"were saved anyway."
msgstr ""
+"La scène actuelle n'a pas de nœud racine, mais %d ressources externes "
+"modifiées ont tout de même été enregistrées."
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"A root node is required to save the scene. You can add a root node using the "
"Scene tree dock."
-msgstr "Un nœud racine est nécessaire pour sauvegarder la scène."
+msgstr ""
+"Un nœud racine est nécessaire pour enregistrer la scène. Vous pouvez ajouter "
+"un nœud racine en utilisant le dock Scène."
#: editor/editor_node.cpp
msgid "Save Scene As..."
@@ -3018,9 +3045,8 @@ msgid "Orphan Resource Explorer..."
msgstr "Explorateur de ressources orphelines..."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reload Current Project"
-msgstr "Renommer le projet"
+msgstr "Recharger le projet actuel"
#: editor/editor_node.cpp
msgid "Quit to Project List"
@@ -3183,13 +3209,12 @@ msgid "Help"
msgstr "Aide"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Online Documentation"
-msgstr "Ouvrir la documentation"
+msgstr "Documentation en ligne"
#: editor/editor_node.cpp
msgid "Questions & Answers"
-msgstr ""
+msgstr "Questions et réponses"
#: editor/editor_node.cpp
msgid "Report a Bug"
@@ -3197,7 +3222,7 @@ msgstr "Signaler un bug"
#: editor/editor_node.cpp
msgid "Suggest a Feature"
-msgstr ""
+msgstr "Suggérer une fonctionnalité"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
@@ -3208,9 +3233,8 @@ msgid "Community"
msgstr "Communauté"
#: editor/editor_node.cpp
-#, fuzzy
msgid "About Godot"
-msgstr "À propos"
+msgstr "À propos de Godot"
#: editor/editor_node.cpp
msgid "Support Godot Development"
@@ -3262,10 +3286,6 @@ msgid "Save & Restart"
msgstr "Enregistrer et redémarrer"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Tourne lorsque la fenêtre de l'éditeur est redessinée."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Mettre à jour en continu"
@@ -3308,14 +3328,12 @@ msgid "Manage Templates"
msgstr "Gérer les modèles"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Install from file"
-msgstr "Installer depuis fichier"
+msgstr "Installer depuis un fichier"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Select android sources file"
-msgstr "Sélectionnez un maillage source :"
+msgstr "Sélectionner un fichier de sources Android"
#: editor/editor_node.cpp
msgid ""
@@ -3398,9 +3416,8 @@ msgid "Select"
msgstr "Sélectionner"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Select Current"
-msgstr "Sélectionner le dossier courant"
+msgstr "Sélectionner le dossier actuel"
#: editor/editor_node.cpp
msgid "Open 2D Editor"
@@ -3435,9 +3452,8 @@ msgid "No sub-resources found."
msgstr "Aucune sous-ressource n'a été trouvée."
#: editor/editor_path.cpp
-#, fuzzy
msgid "Open a list of sub-resources."
-msgstr "Aucune sous-ressource n'a été trouvée."
+msgstr "Ouvrir une liste de sous-ressources."
#: editor/editor_plugin.cpp
msgid "Creating Mesh Previews"
@@ -3464,14 +3480,12 @@ msgid "Update"
msgstr "Mettre à jour"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Version"
-msgstr "Version :"
+msgstr "Version"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Author"
-msgstr "Auteurs"
+msgstr "Auteur"
#: editor/editor_plugin_settings.cpp
#: editor/plugins/version_control_editor_plugin.cpp
@@ -3481,25 +3495,23 @@ msgstr "État"
#: editor/editor_profiler.cpp
msgid "Measure:"
-msgstr "Mesure :"
+msgstr "Mesurer :"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Frame Time (ms)"
-msgstr "Temps par trame (seconde)"
+msgstr "Temps par image (ms)"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Average Time (ms)"
-msgstr "Temps moyen (seconde)"
+msgstr "Temps moyen (ms)"
#: editor/editor_profiler.cpp
msgid "Frame %"
-msgstr "Trame %"
+msgstr "Image %"
#: editor/editor_profiler.cpp
msgid "Physics Frame %"
-msgstr "Trame physique %"
+msgstr "Image physique %"
#: editor/editor_profiler.cpp
msgid "Inclusive"
@@ -3518,10 +3530,17 @@ msgid ""
"functions called by that function.\n"
"Use this to find individual functions to optimize."
msgstr ""
+"Inclusif : Inclut le temps passé dans les fonctions appelées par cette "
+"fonction.\n"
+"Utilisez ce mode pour repérer les goulots d'étranglement.\n"
+"\n"
+"Self : N'inclure que le temps passé dans la fonction elle-même, et non le "
+"temps passé dans d'autres fonctions appelées par cette fonction.\n"
+"Utilisez ce mode pour trouver des fonctions individuelles à optimiser."
#: editor/editor_profiler.cpp
msgid "Frame #:"
-msgstr "Trame # :"
+msgstr "Image # :"
#: editor/editor_profiler.cpp
msgid "Time"
@@ -3640,9 +3659,8 @@ msgid "Paste"
msgstr "Coller"
#: editor/editor_resource_picker.cpp editor/property_editor.cpp
-#, fuzzy
msgid "Convert to %s"
-msgstr "Convertir en %s"
+msgstr "Convertir vers %s"
#: editor/editor_resource_picker.cpp editor/property_editor.cpp
msgid "New %s"
@@ -3690,11 +3708,10 @@ msgid "Did you forget the '_run' method?"
msgstr "Avez-vous oublié la méthode « _run » ?"
#: editor/editor_spin_slider.cpp
-#, fuzzy
msgid "Hold %s to round to integers. Hold Shift for more precise changes."
msgstr ""
-"Maintenir Ctrl pour arrondir à l'entier. Maintenir Maj pour des changements "
-"plus précis."
+"Maintenir %s pour arrondir à l'entier près. Maintenir Maj. pour des "
+"changements plus précis."
#: editor/editor_sub_scene.cpp
msgid "Select Node(s) to Import"
@@ -3714,49 +3731,43 @@ msgstr "Importer à partir d'un nœud :"
#: editor/export_template_manager.cpp
msgid "Open the folder containing these templates."
-msgstr ""
+msgstr "Ouvrir le dossier contenant ces modèles."
#: editor/export_template_manager.cpp
msgid "Uninstall these templates."
-msgstr ""
+msgstr "Désinstaller ces modèles."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "There are no mirrors available."
-msgstr "'%s' n'existe pas."
+msgstr "Il n'y a pas de miroirs disponibles."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Retrieving the mirror list..."
-msgstr "Récupération des miroirs, veuillez patienter..."
+msgstr "Récupération des miroirs…"
#: editor/export_template_manager.cpp
msgid "Starting the download..."
-msgstr ""
+msgstr "Démarrage du téléchargement…"
#: editor/export_template_manager.cpp
msgid "Error requesting URL:"
msgstr "Erreur lors de la demande de l’URL :"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Connecting to the mirror..."
-msgstr "Connexion au Miroir..."
+msgstr "Connexion au miroir…"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't resolve the requested address."
-msgstr "Impossible de résoudre le nom de l'hôte :"
+msgstr "Impossible de résoudre l'adresse demandée."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't connect to the mirror."
-msgstr "Connexion à l'hôte impossible :"
+msgstr "Impossible de se connecter au miroir."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "No response from the mirror."
-msgstr "Pas de réponse de l'hôte :"
+msgstr "Pas de réponse du miroir."
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -3764,22 +3775,20 @@ msgid "Request failed."
msgstr "La requête a échoué."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Request ended up in a redirect loop."
-msgstr "La requête a échoué, trop de redirections"
+msgstr "La requête a échoué car il y a eu trop de redirections."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Request failed:"
-msgstr "La requête a échoué."
+msgstr "La requête a échoué :"
#: editor/export_template_manager.cpp
msgid "Download complete; extracting templates..."
-msgstr ""
+msgstr "Téléchargement terminé, extraction des modèles…"
#: editor/export_template_manager.cpp
msgid "Cannot remove temporary file:"
-msgstr "Impossible de supprimer le fichier temporaire :"
+msgstr "Impossible de supprimer le fichier temporaire :"
#: editor/export_template_manager.cpp
msgid ""
@@ -3787,14 +3796,13 @@ msgid ""
"The problematic templates archives can be found at '%s'."
msgstr ""
"L'installation des modèles a échoué.\n"
-"Les archives des modèles problématiques se trouvent dans '%s'."
+"Les archives des modèles problématiques se trouvent dans « %s »."
#: editor/export_template_manager.cpp
msgid "Error getting the list of mirrors."
msgstr "Erreur lors du téléchargement de la liste des miroirs."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Error parsing JSON with the list of mirrors. Please report this issue!"
msgstr ""
"Erreur lors de la lecture de la liste JSON des miroirs. Merci de signaler ce "
@@ -3802,7 +3810,7 @@ msgstr ""
#: editor/export_template_manager.cpp
msgid "Best available mirror"
-msgstr ""
+msgstr "Meilleur miroir disponible"
#: editor/export_template_manager.cpp
msgid ""
@@ -3855,25 +3863,20 @@ msgid "SSL Handshake Error"
msgstr "Erreurs de la négociation SSL"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't open the export templates file."
-msgstr ""
-"Impossible d'ouvrir le fichier ZIP contenant les modèles d'exportation."
+msgstr "Impossible d'ouvrir le fichier contenant les modèles d'exportation."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Invalid version.txt format inside the export templates file: %s."
-msgstr "Format de version.txt invalide dans les modèles : %s."
+msgstr "Format de version.txt invalide dans le fichier de modèles : %s."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "No version.txt found inside the export templates file."
-msgstr "Aucun version.txt n'a été trouvé dans les modèles."
+msgstr "Aucun fichier version.txt n'a été trouvé dans le fichier des modèles."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Error creating path for extracting templates:"
-msgstr "Erreur lors de la création du chemin pour les modèles :"
+msgstr "Erreur lors de la création du chemin pour l'extraction des modèles :"
#: editor/export_template_manager.cpp
msgid "Extracting Export Templates"
@@ -3884,9 +3887,8 @@ msgid "Importing:"
msgstr "Importation :"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Remove templates for the version '%s'?"
-msgstr "Supprimer la version « %s » du modèle ?"
+msgstr "Supprimer les modèles pour la version « %s » ?"
#: editor/export_template_manager.cpp
msgid "Uncompressing Android Build Sources"
@@ -3903,43 +3905,56 @@ msgstr "Version courante :"
#: editor/export_template_manager.cpp
msgid "Export templates are missing. Download them or install from a file."
msgstr ""
+"Les modèles d'exportation sont manquants. Téléchargez-les ou installez-les "
+"depuis un fichier."
#: editor/export_template_manager.cpp
msgid "Export templates are installed and ready to be used."
-msgstr ""
+msgstr "Les modèles d'exportation sont installés et prêts à être utilisés."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Open Folder"
-msgstr "Ouvrir le fichier"
+msgstr "Ouvrir le dossier"
#: editor/export_template_manager.cpp
msgid "Open the folder containing installed templates for the current version."
msgstr ""
+"Ouvrir le dossier contenant les modèles d'exportation pour la version "
+"actuelle."
#: editor/export_template_manager.cpp
msgid "Uninstall"
msgstr "Désinstaller"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Uninstall templates for the current version."
-msgstr "Valeur initiale pour le compteur"
+msgstr "Désinstaller les modèles d'exportation pour la version actuelle."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Download from:"
-msgstr "Erreur de téléchargement"
+msgstr "Télécharger depuis :"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Exécuter dans le navigateur"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Copier l'erreur"
#: editor/export_template_manager.cpp
msgid "Download and Install"
-msgstr ""
+msgstr "Télécharger et installer"
#: editor/export_template_manager.cpp
msgid ""
"Download and install templates for the current version from the best "
"possible mirror."
msgstr ""
+"Télécharger et installer les modèles d'exportation pour la version actuelle "
+"depuis le meilleur miroir disponible."
#: editor/export_template_manager.cpp
msgid "Official export templates aren't available for development builds."
@@ -3948,14 +3963,12 @@ msgstr ""
"versions de développement."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Install from File"
-msgstr "Installer depuis fichier"
+msgstr "Installer depuis un fichier"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Install templates from a local file."
-msgstr "Importer des modèles depuis un fichier ZIP"
+msgstr "Installer des modèles d'exportation depuis un fichier local."
#: editor/export_template_manager.cpp editor/find_in_files.cpp
#: editor/progress_dialog.cpp scene/gui/dialogs.cpp
@@ -3963,24 +3976,20 @@ msgid "Cancel"
msgstr "Annuler"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Cancel the download of the templates."
-msgstr ""
-"Impossible d'ouvrir le fichier ZIP contenant les modèles d'exportation."
+msgstr "Annuler le téléchargement des modèles d'exportation."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Other Installed Versions:"
-msgstr "Versions installées :"
+msgstr "Autres versions installées :"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Uninstall Template"
-msgstr "Désinstaller"
+msgstr "Désinstaller le modèle"
#: editor/export_template_manager.cpp
msgid "Select Template File"
-msgstr "Sélectionner le fichier de modèle"
+msgstr "Sélectionner le fichier de modèles"
#: editor/export_template_manager.cpp
msgid "Godot Export Templates"
@@ -3991,6 +4000,10 @@ msgid ""
"The templates will continue to download.\n"
"You may experience a short editor freeze when they finish."
msgstr ""
+"Les modèles d'exportation vont continuer à être téléchargés en arrière-"
+"plan.\n"
+"Vous pourrez peut-être remarquer un court gel de l'éditeur lorsque le "
+"téléchargement est terminé."
#: editor/filesystem_dock.cpp
msgid "Favorites"
@@ -4138,35 +4151,32 @@ msgid "Collapse All"
msgstr "Réduire tout"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort files"
-msgstr "Rechercher des fichiers"
+msgstr "Trier les fichiers"
#: editor/filesystem_dock.cpp
msgid "Sort by Name (Ascending)"
-msgstr ""
+msgstr "Trier par nom (ascendant)"
#: editor/filesystem_dock.cpp
msgid "Sort by Name (Descending)"
-msgstr ""
+msgstr "Trier par nom (descendant)"
#: editor/filesystem_dock.cpp
msgid "Sort by Type (Ascending)"
-msgstr ""
+msgstr "Trier par type (ascendant)"
#: editor/filesystem_dock.cpp
msgid "Sort by Type (Descending)"
-msgstr ""
+msgstr "Trier par type (descendant)"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort by Last Modified"
-msgstr "Dernière modification"
+msgstr "Trier par date de modification (plus récent au moins récent)"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort by First Modified"
-msgstr "Dernière modification"
+msgstr "Trier par date de modification (moins récent au plus récent)"
#: editor/filesystem_dock.cpp
msgid "Duplicate..."
@@ -4178,7 +4188,7 @@ msgstr "Renommer..."
#: editor/filesystem_dock.cpp
msgid "Focus the search box"
-msgstr ""
+msgstr "Mettre la boîte de recherche en surbrillance"
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -4488,14 +4498,12 @@ msgid "Failed to load resource."
msgstr "Impossible de charger la ressource."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Copy Properties"
-msgstr "Propriétés"
+msgstr "Copier les propriétés"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Paste Properties"
-msgstr "Propriétés"
+msgstr "Coller les propriétés"
#: editor/inspector_dock.cpp
msgid "Make Sub-Resources Unique"
@@ -4520,23 +4528,20 @@ msgid "Save As..."
msgstr "Enregistrer sous…"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Extra resource options."
-msgstr "Pas dans le chemin de la ressource."
+msgstr "Options de ressource additionnelles."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Edit Resource from Clipboard"
-msgstr "Modifier le Presse-papiers de la ressource"
+msgstr "Modifier la ressource depuis le presse-papiers"
#: editor/inspector_dock.cpp
msgid "Copy Resource"
msgstr "Copier la ressource"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Make Resource Built-In"
-msgstr "Rendre intégré"
+msgstr "Rendre la ressource intégrée"
#: editor/inspector_dock.cpp
msgid "Go to the previous edited object in history."
@@ -4551,9 +4556,8 @@ msgid "History of recently edited objects."
msgstr "Historique des objets récemment édités."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Open documentation for this object."
-msgstr "Ouvrir la documentation"
+msgstr "Ouvrir la documentation pour cet objet."
#: editor/inspector_dock.cpp editor/scene_tree_dock.cpp
msgid "Open Documentation"
@@ -4564,9 +4568,8 @@ msgid "Filter properties"
msgstr "Filtrer les propriétés"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Manage object properties."
-msgstr "Propriétés de l'objet."
+msgstr "Gérer les propriétés de l'objet."
#: editor/inspector_dock.cpp
msgid "Changes may be lost!"
@@ -4814,9 +4817,8 @@ msgid "Blend:"
msgstr "Mélange :"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Parameter Changed:"
-msgstr "Paramètre modifié"
+msgstr "Paramètre modifié :"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
@@ -5550,11 +5552,11 @@ msgstr "All"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Search templates, projects, and demos"
-msgstr ""
+msgstr "Rechercher modèles, projets et démos"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Search assets (excluding templates, projects, and demos)"
-msgstr ""
+msgstr "Rechercher des assets (à l'exception des modèles, projets et démos)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Import..."
@@ -5598,7 +5600,7 @@ msgstr "Fichier ZIP de données"
#: editor/plugins/audio_stream_editor_plugin.cpp
msgid "Audio Preview Play/Pause"
-msgstr ""
+msgstr "Aperçu audio lecture/pause"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
@@ -5859,13 +5861,12 @@ msgstr "Modifier les ancres"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid ""
"Project Camera Override\n"
"Overrides the running project's camera with the editor viewport camera."
msgstr ""
-"Remplacement de la Caméra du Jeu\n"
-"Remplace la caméra du jeu par la caméra de la fenêtre d'affichage de "
+"Remplacement de la caméra du projet\n"
+"Remplace la caméra du projet par la caméra de la fenêtre d'affichage de "
"l'editeur."
#: editor/plugins/canvas_item_editor_plugin.cpp
@@ -5875,6 +5876,9 @@ msgid ""
"No project instance running. Run the project from the editor to use this "
"feature."
msgstr ""
+"Remplacement de la caméra du projet\n"
+"Pas d'instance du projet en cours d'exécution. Lancez le projet depuis "
+"l'éditeur afin d'utiliser cette fonctionnalité."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5942,31 +5946,27 @@ msgstr "Mode sélection"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Drag: Rotate selected node around pivot."
-msgstr "Supprimer le nœud sélectionné ou la transition."
+msgstr "Glisser : Tourner le nœud sélectionné autour du pivot."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Alt+Drag: Move selected node."
-msgstr "Alt+Glisser : déplacer"
+msgstr "Alt + Glisser : Déplacer le nœud sélectionné."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "V: Set selected node's pivot position."
-msgstr "Supprimer le nœud sélectionné ou la transition."
+msgstr "V : Définir la position du pivot pour le nœud sélectionné."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Alt+RMB: Show list of all nodes at position clicked, including locked."
msgstr ""
-"Afficher une liste de tous les objets à la position cliquée\n"
-"(identique à Alt+Bouton droit en mode sélection)."
+"Alt + Clic droit : Afficher une liste de tous les nœuds à la position "
+"cliquée, y compris les nœuds verrouillés."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "RMB: Add node at position clicked."
-msgstr ""
+msgstr "Clic droit : Ajouter un nœud à la position cliquée."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -6204,14 +6204,12 @@ msgid "Clear Pose"
msgstr "Vider la pose"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Add Node Here"
-msgstr "Ajouter un nœud"
+msgstr "Ajouter un nœud ici"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Instance Scene Here"
-msgstr "Instancier scène(s)"
+msgstr "Instancer une scène ici"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Multiply grid step by 2"
@@ -6227,49 +6225,43 @@ msgstr "Vue panoramique"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 3.125%"
-msgstr ""
+msgstr "Zoomer à 3.125%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 6.25%"
-msgstr ""
+msgstr "Zoomer à 6.25%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 12.5%"
-msgstr ""
+msgstr "Zoomer à 12.5%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 25%"
-msgstr "Dézoomer"
+msgstr "Zoomer à 25%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 50%"
-msgstr "Dézoomer"
+msgstr "Zoomer à 50%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 100%"
-msgstr "Dézoomer"
+msgstr "Zoomer à 100%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 200%"
-msgstr "Dézoomer"
+msgstr "Zoomer à 200%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 400%"
-msgstr "Dézoomer"
+msgstr "Zoomer à 400%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 800%"
-msgstr "Dézoomer"
+msgstr "Zoomer à 800%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 1600%"
-msgstr ""
+msgstr "Zoomer à 1600%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Add %s"
@@ -6516,9 +6508,8 @@ msgid "Couldn't create a single convex collision shape."
msgstr "Impossible de créer une forme de collision convexe unique."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Create Simplified Convex Shape"
-msgstr "Créer une forme convexe unique"
+msgstr "Créer une forme convexe simplifiée"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Single Convex Shape"
@@ -6557,9 +6548,8 @@ msgid "No mesh to debug."
msgstr "Aucun maillage à déboguer."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Mesh has no UV in layer %d."
-msgstr "Le modèle n'a pas d'UV dans cette couche"
+msgstr "Le maillage n'a pas d'UV dans la couche %d."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "MeshInstance lacks a Mesh!"
@@ -6628,9 +6618,8 @@ msgstr ""
"collisions."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Create Simplified Convex Collision Sibling"
-msgstr "Créer une seule collision convexe sœur"
+msgstr "Créer une collision sœur convexe simplifiée"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid ""
@@ -6638,20 +6627,23 @@ msgid ""
"This is similar to single collision shape, but can result in a simpler "
"geometry in some cases, at the cost of accuracy."
msgstr ""
+"Créé une forme de collision complexe simplifiée.\n"
+"Cela est similaire à une forme de collision, mais peut résulter en une "
+"géométrie plus simple mais moins précise."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Multiple Convex Collision Siblings"
msgstr "Créer plusieurs collisions convexes sœurs"
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid ""
"Creates a polygon-based collision shape.\n"
"This is a performance middle-ground between a single convex collision and a "
"polygon-based collision."
msgstr ""
-"Crée une forme de collision basée sur les polygones.\n"
-"Il s'agit d'une performance à mi-chemin entre les deux options ci-dessus."
+"Crée une forme de collision basée sur des polygones.\n"
+"Il s'agit d'une performance à mi-chemin entre une forme unique de collision "
+"convexe et une collision basée sur des polygones."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Outline Mesh..."
@@ -7301,24 +7293,20 @@ msgid "ResourcePreloader"
msgstr "ResourcePreloader"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Flip Portals"
-msgstr "Retourner horizontalement"
+msgstr "Retourner les Portals"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Room Generate Points"
-msgstr "Compte de Points Générés :"
+msgstr "Générer des points Room"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Generate Points"
-msgstr "Compte de Points Générés :"
+msgstr "Générer des points"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Flip Portal"
-msgstr "Retourner horizontalement"
+msgstr "Retourner le Portal"
#: editor/plugins/root_motion_editor_plugin.cpp
msgid "AnimationTree has no path set to an AnimationPlayer"
@@ -7882,20 +7870,17 @@ msgid "None"
msgstr "Aucun"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Rotate"
-msgstr "Mode rotation"
+msgstr "Rotation"
#. TRANSLATORS: This refers to the movement that changes the position of an object.
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Translate"
-msgstr "Translater :"
+msgstr "Translation"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Scale"
-msgstr "Échelle :"
+msgstr "Mode mise à l'échelle"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scaling: "
@@ -7918,52 +7903,44 @@ msgid "Animation Key Inserted."
msgstr "Clé d'animation insérée."
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Pitch:"
-msgstr "Tangage (latéral)"
+msgstr "Tangage :"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Yaw:"
-msgstr ""
+msgstr "Azimuth :"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size:"
-msgstr "Taille : "
+msgstr "Taille :"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Objects Drawn:"
-msgstr "Objets dessinés"
+msgstr "Objets dessinés :"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Material Changes:"
-msgstr "Modifications de materiau"
+msgstr "Changements de matériau :"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Shader Changes:"
-msgstr "Modification de shader"
+msgstr "Changements de shader :"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Surface Changes:"
-msgstr "Modifications de surface"
+msgstr "Changements de surface :"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Draw Calls:"
-msgstr "Appels de graphes"
+msgstr "Appels de dessin :"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Vertices:"
-msgstr "Vertex"
+msgstr "Sommets :"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "FPS: %d (%s ms)"
-msgstr ""
+msgstr "FPS : %d (%s ms)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Top View."
@@ -8120,9 +8097,8 @@ msgid "Freelook Slow Modifier"
msgstr "Ralentissement de la vue libre"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Toggle Camera Preview"
-msgstr "Changer la taille d'une caméra"
+msgstr "Activer la prévisualisation de la caméra"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Rotation Locked"
@@ -8145,9 +8121,8 @@ msgstr ""
"performance en jeu."
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Convert Rooms"
-msgstr "Convertir en %s"
+msgstr "Convertir les salles"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "XForm Dialog"
@@ -8169,7 +8144,6 @@ msgstr ""
"(« rayon x »)."
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Snap Nodes to Floor"
msgstr "Aligner les nœuds avec le sol"
@@ -8187,7 +8161,7 @@ msgstr "Utiliser l’aimantation"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Converts rooms for portal culling."
-msgstr ""
+msgstr "Convertit des salles pour l'occlusion culling à l'aide de portails."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Bottom View"
@@ -8283,9 +8257,8 @@ msgid "View Grid"
msgstr "Afficher la grille"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "View Portal Culling"
-msgstr "Paramètres de la vue"
+msgstr "Afficher le Portal culling"
#: editor/plugins/spatial_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
@@ -8599,230 +8572,208 @@ msgid "Step:"
msgstr "Pas (s) :"
#: editor/plugins/texture_region_editor_plugin.cpp
-#, fuzzy
msgid "Separation:"
-msgstr "Recensements :"
+msgstr "Séparation :"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "TextureRegion"
msgstr "RegionDeTexture"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Colors"
-msgstr "Couleur"
+msgstr "Couleurs"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Fonts"
-msgstr "Police"
+msgstr "Polices"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Icons"
-msgstr "Icône"
+msgstr "Icônes"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Styleboxes"
-msgstr "Style"
+msgstr "Styleboxes"
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} color(s)"
-msgstr ""
+msgstr "{num} couleur(s)"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No colors found."
-msgstr "Aucune sous-ressource n'a été trouvée."
+msgstr "Pas de couleurs trouvées."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "{num} constant(s)"
-msgstr "Constantes"
+msgstr "{num} constante(s)"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No constants found."
-msgstr "Constante de couleur."
+msgstr "Pas de constantes trouvées."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} font(s)"
-msgstr ""
+msgstr "{num} police(s)"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No fonts found."
-msgstr "Aucune sous-ressource n'a été trouvée."
+msgstr "Pas de polices trouvées."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} icon(s)"
-msgstr ""
+msgstr "{num} icône(s)"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No icons found."
-msgstr "Aucune sous-ressource n'a été trouvée."
+msgstr "Pas d'icônes trouvées."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} stylebox(es)"
-msgstr ""
+msgstr "{num} stylebox(es)"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No styleboxes found."
-msgstr "Aucune sous-ressource n'a été trouvée."
+msgstr "Pas de styleboxes trouvées."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} currently selected"
-msgstr ""
+msgstr "{num} actuellement sélectionné(s)"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Nothing was selected for the import."
-msgstr ""
+msgstr "Rien n'a été sélectionné pour l'importation."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Importing Theme Items"
-msgstr "Importer un thème"
+msgstr "Importation des items de thème"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Importing items {n}/{n}"
-msgstr ""
+msgstr "Importation de l'item {n}/{n}"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Updating the editor"
-msgstr "Quitter l'éditeur ?"
+msgstr "Mise à jour de l'éditeur"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Finalizing"
-msgstr "Analyse"
+msgstr "Finalisation"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Filter:"
-msgstr "Filtres :"
+msgstr "Filtre :"
#: editor/plugins/theme_editor_plugin.cpp
msgid "With Data"
-msgstr ""
+msgstr "Avec données"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select by data type:"
-msgstr "Sélectionner un nœud"
+msgstr "Sélectionner par type de données :"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible color items."
-msgstr "Sélectionnez un fractionnement à effacer."
+msgstr "Sélectionner tous les items de couleur visibles."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible color items and their data."
msgstr ""
+"Sélectionner tous les items de couleur visibles ainsi que leurs données."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible color items."
-msgstr ""
+msgstr "Désélectionner tous les items de couleur visibles."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible constant items."
-msgstr "Sélectionnez d'abord un élément à configurer !"
+msgstr "Sélectionner tous les items de constantes visibles."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible constant items and their data."
msgstr ""
+"Sélectionner tous les items de constantes visibles ainsi que leurs données."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible constant items."
-msgstr ""
+msgstr "Désélectionner tous les items de constantes visibles."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible font items."
-msgstr "Sélectionnez d'abord un élément à configurer !"
+msgstr "Sélectionner tous les items de police visibles."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible font items and their data."
msgstr ""
+"Sélectionner tous les items de police visibles ainsi que leurs données."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible font items."
-msgstr ""
+msgstr "Désélectionner tous les items de police visibles."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible icon items."
-msgstr "Sélectionnez d'abord un élément à configurer !"
+msgstr "Sélectionner tous les items d'icône visibles."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible icon items and their data."
-msgstr "Sélectionnez d'abord un élément à configurer !"
+msgstr "Sélectionner tous les items d'icône visibles ainsi que leurs données."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Deselect all visible icon items."
-msgstr "Sélectionnez d'abord un élément à configurer !"
+msgstr "Désélectionner tous les items d'icône visibles."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible stylebox items."
-msgstr ""
+msgstr "Sélectionner tous les items de stylebox visibles."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible stylebox items and their data."
msgstr ""
+"Sélectionner tous les items de stylebox visibles ainsi que leurs données."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible stylebox items."
-msgstr ""
+msgstr "Désélectionner tous les items de stylebox visibles."
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
"Caution: Adding icon data may considerably increase the size of your Theme "
"resource."
msgstr ""
+"Attention : Ajouter des données d'icônes peut augmenter considérablement la "
+"taille de votre ressource Theme."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Collapse types."
-msgstr "Réduire tout"
+msgstr "Réduire les types."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Expand types."
-msgstr "Développer tout"
+msgstr "Développer les types."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all Theme items."
-msgstr "Sélectionner le fichier de modèle"
+msgstr "Sélectionner tous les items du Theme."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select With Data"
-msgstr "Sélectionner des points"
+msgstr "Sélectionner avec les données"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all Theme items with item data."
-msgstr ""
+msgstr "Sélectionne tous les items de thème avec les données d'item."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Deselect All"
-msgstr "Tout sélectionner"
+msgstr "Tout déselectionner"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all Theme items."
-msgstr ""
+msgstr "Déselectionne tous les items du Theme."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Import Selected"
-msgstr "Importer une scène"
+msgstr "Importer la sélection"
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
@@ -8830,275 +8781,253 @@ msgid ""
"closing this window.\n"
"Close anyway?"
msgstr ""
+"L'onglet Importer des items a des items sélectionnés. La sélection sera "
+"perdue si vous fermez cette fenêtre.\n"
+"Fermer tout de même ?"
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Color Items"
-msgstr "Supprimer tous"
+msgstr "Supprimer tous les items de couleur"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Item"
-msgstr "Supprimer l'item"
+msgstr "Renommer l'item"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Constant Items"
-msgstr "Supprimer tous"
+msgstr "Supprimer tous les items de constante"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Font Items"
-msgstr "Supprimer tous"
+msgstr "Supprimer tous les items de police"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Icon Items"
-msgstr "Supprimer tous"
+msgstr "Supprimer tous les items d'icône"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All StyleBox Items"
-msgstr "Supprimer tous"
+msgstr "Supprimer tous les items de stylebox"
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Color Item"
-msgstr "Ajouter des items de classe"
+msgstr "Ajouter un item de couleur"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Constant Item"
-msgstr "Ajouter des items de classe"
+msgstr "Ajouter un item de constante"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Font Item"
-msgstr "Ajouter un item"
+msgstr "Ajouter un item de police"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Icon Item"
-msgstr "Ajouter un item"
+msgstr "Ajouter un item d'icône"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Stylebox Item"
-msgstr "Ajouter tous les items"
+msgstr "Ajouter un item de stylebox"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Color Item"
-msgstr "Supprimer des items de classe"
+msgstr "Renommer l'item de couleur"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Constant Item"
-msgstr "Supprimer des items de classe"
+msgstr "Renommer l'item de constante"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Font Item"
-msgstr "Renommer le nœud"
+msgstr "Renommer l'item de police"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Icon Item"
-msgstr "Renommer le nœud"
+msgstr "Renommer l'item d'icône"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Stylebox Item"
-msgstr "Supprimer l'élément sélectionné"
+msgstr "Renommer l'item de stylebox"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Invalid file, not a Theme resource."
-msgstr "Fichier invalide, pas une disposition de bus audio."
+msgstr "Fichier invalide, car ce n'est pas une ressource de type Theme."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Invalid file, same as the edited Theme resource."
msgstr ""
+"Fichier invalide, car il est identique à la ressource Theme actuellement en "
+"cours de modification."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Manage Theme Items"
-msgstr "Gérer les modèles"
+msgstr "Gérer les items de thème"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Edit Items"
-msgstr "Élément modifiable"
+msgstr "Modifier les items"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Types:"
-msgstr "Type :"
+msgstr "Types :"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Type:"
-msgstr "Type :"
+msgstr "Ajouter un type :"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Item:"
-msgstr "Ajouter un item"
+msgstr "Ajouter un item :"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add StyleBox Item"
-msgstr "Ajouter tous les items"
+msgstr "Ajouter un item de stylebox"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove Items:"
-msgstr "Supprimer l'item"
+msgstr "Supprimer items :"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove Class Items"
-msgstr "Supprimer des items de classe"
+msgstr "Supprimer les items de classe"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove Custom Items"
-msgstr "Supprimer des items de classe"
+msgstr "Supprimer les items personnalisés"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Items"
-msgstr "Supprimer tous"
+msgstr "Supprimer tous les items"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Theme Item"
-msgstr "Ajouter un item"
+msgstr "Ajouter un item de thème"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Old Name:"
-msgstr "Nom de nœud :"
+msgstr "Ancien nom :"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Import Items"
-msgstr "Importer un thème"
+msgstr "Importer des items"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Default Theme"
-msgstr "Par défaut"
+msgstr "Thème par défaut"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Editor Theme"
-msgstr "Modifier le thème"
+msgstr "Thème de l'éditeur"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select Another Theme Resource:"
-msgstr "Supprimer une ressource"
+msgstr "Sélectionnez une autre ressource Theme :"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Another Theme"
-msgstr "Importer un thème"
+msgstr "Autre thème"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Confirm Item Rename"
-msgstr "Configurer la grille"
+msgstr "Confirmer le renommage d'item"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Cancel Item Rename"
-msgstr "Renommer par lot"
+msgstr "Annuler le renommage d'item"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Override Item"
-msgstr "Redéfinition"
+msgstr "Remplacer l'item"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Unpin this StyleBox as a main style."
-msgstr ""
+msgstr "Désépingler cette StyleBox comme style principal."
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
"Pin this StyleBox as a main style. Editing its properties will update the "
"same properties in all other StyleBoxes of this type."
msgstr ""
+"Épingler cette StyleBox comme style principal. Modifier ses propriétés "
+"mettra à jour les mêmes propriétés dans toutes les autres StyleBoxes "
+"appartenant à ce type."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Type"
-msgstr "Type"
+msgstr "Ajouter un type"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Item Type"
-msgstr "Ajouter un item"
+msgstr "Ajouter un item de type"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Node Types:"
-msgstr "Type de nœud"
+msgstr "Types de nœud :"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Show Default"
-msgstr "Charger défaut"
+msgstr "Afficher par défaut"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Show default type items alongside items that have been overridden."
msgstr ""
+"Afficher les items de type par défaut à côté de ceux qui ont été surchargés."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Override All"
-msgstr "Redéfinition"
+msgstr "Tout surcharger"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Override all default type items."
-msgstr ""
+msgstr "Surcharge tous les items de type par défaut."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Theme:"
-msgstr "Thème"
+msgstr "Thème :"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Manage Items..."
-msgstr "Gérer les modèles d'exportation..."
+msgstr "Gérer les items…"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add, remove, organize and import Theme items."
-msgstr ""
+msgstr "Ajoute, supprime, organise et importe des items de thème."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Preview"
-msgstr "Aperçu"
+msgstr "Ajouter un aperçu"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Default Preview"
-msgstr "Aperçu de la mise à jour"
+msgstr "Aperçu par défaut"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select UI Scene:"
-msgstr "Sélectionnez un maillage source :"
+msgstr "Sélectionner une scène UI :"
#: editor/plugins/theme_editor_preview.cpp
msgid ""
"Toggle the control picker, allowing to visually select control types for "
"edit."
msgstr ""
+"Active le sélectionneur de contrôle, qui permet de sélectionner visuellement "
+"des types de contrôles à modifier."
#: editor/plugins/theme_editor_preview.cpp
msgid "Toggle Button"
-msgstr "Activer / Désactiver bouton"
+msgstr "Bouton à bascule (toggle)"
#: editor/plugins/theme_editor_preview.cpp
msgid "Disabled Button"
@@ -9110,7 +9039,7 @@ msgstr "Item"
#: editor/plugins/theme_editor_preview.cpp
msgid "Disabled Item"
-msgstr "Élément Désactivé"
+msgstr "Item désactivé"
#: editor/plugins/theme_editor_preview.cpp
msgid "Check Item"
@@ -9129,9 +9058,8 @@ msgid "Checked Radio Item"
msgstr "Item radio coché"
#: editor/plugins/theme_editor_preview.cpp
-#, fuzzy
msgid "Named Separator"
-msgstr "Séparateur nommé."
+msgstr "Séparateur nommé"
#: editor/plugins/theme_editor_preview.cpp
msgid "Submenu"
@@ -9184,19 +9112,22 @@ msgstr "Possède,Plusieurs,Options"
#: editor/plugins/theme_editor_preview.cpp
msgid "Invalid path, the PackedScene resource was probably moved or removed."
msgstr ""
+"Chemin invalide. La ressource PackedScene a probablement été déplacée ou "
+"supprimée."
#: editor/plugins/theme_editor_preview.cpp
msgid "Invalid PackedScene resource, must have a Control node at its root."
msgstr ""
+"Ressource PackedScene invalide. La scène doit avoir un nœud de type Control "
+"à sa racine."
#: editor/plugins/theme_editor_preview.cpp
-#, fuzzy
msgid "Invalid file, not a PackedScene resource."
-msgstr "Fichier invalide, pas une disposition de bus audio."
+msgstr "Fichier invalide, pas une ressource PackedScene."
#: editor/plugins/theme_editor_preview.cpp
msgid "Reload the scene to reflect its most actual state."
-msgstr ""
+msgstr "Recharge la scène pour refléter son état le plus actuel."
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Erase Selection"
@@ -10605,9 +10536,8 @@ msgid "VisualShader"
msgstr "VisualShader"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Edit Visual Property:"
-msgstr "Modifier la propriété visuelle"
+msgstr "Modifier la propriété visuelle :"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Visual Shader Mode Changed"
@@ -10733,9 +10663,8 @@ msgid "Script"
msgstr "Script"
#: editor/project_export.cpp
-#, fuzzy
msgid "GDScript Export Mode:"
-msgstr "Mode d'exportation des scripts :"
+msgstr "Mode d'exportation GDScript :"
#: editor/project_export.cpp
msgid "Text"
@@ -10743,21 +10672,20 @@ msgstr "Texte"
#: editor/project_export.cpp
msgid "Compiled Bytecode (Faster Loading)"
-msgstr ""
+msgstr "Bytecode compilé (chargement plus rapide)"
#: editor/project_export.cpp
msgid "Encrypted (Provide Key Below)"
msgstr "Chiffré (fournir clé ci-dessous)"
#: editor/project_export.cpp
-#, fuzzy
msgid "Invalid Encryption Key (must be 64 hexadecimal characters long)"
-msgstr "Clé de chiffrement invalide (doit comporter 64 caractères)"
+msgstr ""
+"Clé de chiffrement invalide (doit comporter 64 caractères hexadécimaux)"
#: editor/project_export.cpp
-#, fuzzy
msgid "GDScript Encryption Key (256-bits as hexadecimal):"
-msgstr "Clé de chiffrement des scripts (256 bits en hexadécimal) :"
+msgstr "Clé de chiffrement GDScript (256 bits en hexadécimal) :"
#: editor/project_export.cpp
msgid "Export PCK/Zip"
@@ -10832,7 +10760,6 @@ msgid "Imported Project"
msgstr "Projet importé"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Invalid project name."
msgstr "Nom du projet invalide."
@@ -11061,14 +10988,12 @@ msgid "Are you sure to run %d projects at once?"
msgstr "Voulez-vous vraiment lancer %d projets à la fois ?"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove %d projects from the list?"
-msgstr "Sélectionner appareil depuis la liste"
+msgstr "Retirer %d projets de la liste ?"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove this project from the list?"
-msgstr "Sélectionner appareil depuis la liste"
+msgstr "Retirer ce projet de la liste ?"
#: editor/project_manager.cpp
msgid ""
@@ -11102,9 +11027,8 @@ msgid "Project Manager"
msgstr "Gestionnaire de projets"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Local Projects"
-msgstr "Projets"
+msgstr "Projets locaux"
#: editor/project_manager.cpp
msgid "Loading, please wait..."
@@ -11115,23 +11039,20 @@ msgid "Last Modified"
msgstr "Dernière modification"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Edit Project"
-msgstr "Exporter le projet"
+msgstr "Modifier le projet"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Run Project"
-msgstr "Renommer le projet"
+msgstr "Lancer le projet"
#: editor/project_manager.cpp
msgid "Scan"
msgstr "Scanner"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Scan Projects"
-msgstr "Projets"
+msgstr "Scanner des projets"
#: editor/project_manager.cpp
msgid "Select a Folder to Scan"
@@ -11142,14 +11063,12 @@ msgid "New Project"
msgstr "Nouveau projet"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Import Project"
-msgstr "Projet importé"
+msgstr "Importer un projet"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove Project"
-msgstr "Renommer le projet"
+msgstr "Retirer le projet"
#: editor/project_manager.cpp
msgid "Remove Missing"
@@ -11160,9 +11079,8 @@ msgid "About"
msgstr "À propos"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Asset Library Projects"
-msgstr "Bibliothèque d'assets"
+msgstr "Projets de l'Asset Library"
#: editor/project_manager.cpp
msgid "Restart Now"
@@ -11174,7 +11092,7 @@ msgstr "Supprimer tout"
#: editor/project_manager.cpp
msgid "Also delete project contents (no undo!)"
-msgstr ""
+msgstr "Supprimer les contenus du projet également (pas d'annulation !)"
#: editor/project_manager.cpp
msgid "Can't run project"
@@ -11189,12 +11107,10 @@ msgstr ""
"Voulez-vous explorer des exemples de projets officiels dans l'Asset Library ?"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Filter projects"
-msgstr "Filtrer les propriétés"
+msgstr "Filtrer parmi les projets"
#: editor/project_manager.cpp
-#, fuzzy
msgid ""
"This field filters projects by name and last path component.\n"
"To filter projects by name and full path, the query must contain at least "
@@ -11211,7 +11127,7 @@ msgstr "Touche "
#: editor/project_settings_editor.cpp
msgid "Physical Key"
-msgstr ""
+msgstr "Touche physique"
#: editor/project_settings_editor.cpp
msgid "Joy Button"
@@ -11259,7 +11175,7 @@ msgstr "Périphérique"
#: editor/project_settings_editor.cpp
msgid " (Physical)"
-msgstr ""
+msgstr " (physique)"
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "Press a Key..."
@@ -11402,23 +11318,23 @@ msgid "Override for Feature"
msgstr "Écrasement d'un paramètre, dédié à un tag de fonctionnalité"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Add %d Translations"
-msgstr "Ajouter une traduction"
+msgstr "Ajouter %d traductions"
#: editor/project_settings_editor.cpp
msgid "Remove Translation"
msgstr "Supprimer la traduction"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Translation Resource Remap: Add %d Path(s)"
-msgstr "Réaffectation (remap) des ressources ; Ajouter une réaffectation"
+msgstr ""
+"Réaffectation (remap) des ressources par traduction : Ajouter %d chemin(s)"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Translation Resource Remap: Add %d Remap(s)"
-msgstr "Réaffectation (remap) des ressources ; Ajouter une réaffectation"
+msgstr ""
+"Réaffectation (remap) des ressources par traduction : Ajouter %d "
+"réaffectation(s)"
#: editor/project_settings_editor.cpp
msgid "Change Resource Remap Language"
@@ -11450,7 +11366,7 @@ msgstr "Général"
#: editor/project_settings_editor.cpp
msgid "Override For..."
-msgstr "Surcharge pour…"
+msgstr "Surcharger pour…"
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "The editor must be restarted for changes to take effect."
@@ -11862,12 +11778,16 @@ msgstr "Supprimer le noeud \"%s\" ?"
msgid ""
"Saving the branch as a scene requires having a scene open in the editor."
msgstr ""
+"Pour sauvegarder la branche en tant que scène, il faut qu'une scène soit "
+"ouverte dans l'éditeur."
#: editor/scene_tree_dock.cpp
msgid ""
"Saving the branch as a scene requires selecting only one node, but you have "
"selected %d nodes."
msgstr ""
+"Pour sauvegarder la branche en tant que scène, il faut sélectionner "
+"seulement un nœud, mais vous avez sélectionné %d nœuds."
#: editor/scene_tree_dock.cpp
msgid ""
@@ -11876,6 +11796,12 @@ msgid ""
"FileSystem dock context menu\n"
"or create an inherited scene using Scene > New Inherited Scene... instead."
msgstr ""
+"Impossible de sauvegarder la branche du nœud racine comme une scène "
+"instanciée.\n"
+"Pour créer une copie modifiable de la scène actuelle, dupliquez-la à l'aide "
+"du menu contextuel du dock Système de fichiers\n"
+"ou créez une scène héritée en utilisant Scène > Nouvelle scène héritée... à "
+"la place."
#: editor/scene_tree_dock.cpp
msgid ""
@@ -11883,6 +11809,10 @@ msgid ""
"To create a variation of a scene, you can make an inherited scene based on "
"the instanced scene using Scene > New Inherited Scene... instead."
msgstr ""
+"Impossible de sauvegarder la branche d'une scène déjà instanciée.\n"
+"Pour créer une variation d'une scène, vous pouvez créer une scène héritée "
+"basée sur la scène instanciée en utilisant Scène > Nouvelle scène héritée... "
+"à la place."
#: editor/scene_tree_dock.cpp
msgid "Save New Scene As..."
@@ -12291,6 +12221,8 @@ msgid ""
"Warning: Having the script name be the same as a built-in type is usually "
"not desired."
msgstr ""
+"Avertissement : Il n'est généralement pas souhaitable que le nom du script "
+"soit le même que celui d'un type intégré."
#: editor/script_create_dialog.cpp
msgid "Class Name:"
@@ -12362,7 +12294,7 @@ msgstr "Copier l'erreur"
#: editor/script_editor_debugger.cpp
msgid "Open C++ Source on GitHub"
-msgstr ""
+msgstr "Ouvrir les sources C++ sur GitHub"
#: editor/script_editor_debugger.cpp
msgid "Video RAM"
@@ -12541,6 +12473,16 @@ msgstr "Changer la hauteur de la forme du cylindre"
msgid "Change Ray Shape Length"
msgstr "Changer la longueur d'une forme en rayon"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Définir la position du point de la courbe"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Définir la position du point de la courbe"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "Changer le rayon du cylindre"
@@ -12656,12 +12598,11 @@ msgstr "L'objet ne peut fournir une longueur."
#: modules/gltf/editor_scene_exporter_gltf_plugin.cpp
#, fuzzy
msgid "Export Mesh GLTF2"
-msgstr "Exporter une bibliothèque de maillages"
+msgstr "Exporter le Maillage GLTF2"
#: modules/gltf/editor_scene_exporter_gltf_plugin.cpp
-#, fuzzy
msgid "Export GLTF..."
-msgstr "Exporter..."
+msgstr "Exporter en GLTF..."
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Next Plane"
@@ -12704,9 +12645,8 @@ msgid "GridMap Paint"
msgstr "Peinture GridMap"
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "GridMap Selection"
-msgstr "Remplissage de la sélection de GridMap"
+msgstr "Sélection de la GridMap"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Grid Map"
@@ -12960,14 +12900,12 @@ msgid "Add Output Port"
msgstr "Ajouter un port de sortie"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Change Port Type"
-msgstr "Changer le type"
+msgstr "Changer le Type de Port"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Change Port Name"
-msgstr "Changer le nom du port d'entrée"
+msgstr "Changer le Nom du Port"
#: modules/visual_script/visual_script_editor.cpp
msgid "Override an existing built-in function."
@@ -13353,38 +13291,33 @@ msgid "Select device from the list"
msgstr "Sélectionner appareil depuis la liste"
#: platform/android/export/export.cpp
+#, fuzzy
msgid "Running on %s"
-msgstr ""
+msgstr "En cours d'exécution sur %s"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Exporting APK..."
-msgstr "Tout exporter"
+msgstr "Exportation de l'APK..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Uninstalling..."
-msgstr "Désinstaller"
+msgstr "Désinstallation..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Installing to device, please wait..."
-msgstr "Chargement en cours, veuillez patienter..."
+msgstr "Installation sur l'appareil, veuillez patienter..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not install to device: %s"
-msgstr "Impossible de démarrer le sous-processus !"
+msgstr "Impossible d'installer sur l'appareil : %s"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Running on device..."
-msgstr "Lancement du script personnalisé…"
+msgstr "En cours d'exécution sur l'appareil..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not execute on device."
-msgstr "Impossible de créer le dossier."
+msgstr "Impossible d'exécuter sur l'appareil."
#: platform/android/export/export.cpp
msgid "Unable to find the 'apksigner' tool."
@@ -13509,46 +13442,49 @@ msgstr ""
"est activée."
#: platform/android/export/export.cpp
+#, fuzzy
msgid ""
"'apksigner' could not be found.\n"
"Please check the command is available in the Android SDK build-tools "
"directory.\n"
"The resulting %s is unsigned."
msgstr ""
+"Impossible de trouver 'apksigner'.\n"
+"Veuillez vérifier que la commande est disponible dans le dossier build-tools "
+"du SDK Android.\n"
+"Le paquet sortant %s est non signé."
#: platform/android/export/export.cpp
+#, fuzzy
msgid "Signing debug %s..."
-msgstr ""
+msgstr "Signature du debug %s..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Signing release %s..."
-msgstr ""
-"Analyse des fichiers en cours,\n"
-"Veuillez patienter..."
+msgstr "Signature de la version %s..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not find keystore, unable to export."
-msgstr "Impossible d'ouvrir le modèle pour exportation :"
+msgstr "Impossible de trouver le keystore, impossible d'exporter."
#: platform/android/export/export.cpp
+#, fuzzy
msgid "'apksigner' returned with error #%d"
-msgstr ""
+msgstr "'apksigner' a terminé avec l'erreur #%d"
#: platform/android/export/export.cpp
#, fuzzy
msgid "Verifying %s..."
-msgstr "Ajout de %s..."
+msgstr "Vérification de %s..."
#: platform/android/export/export.cpp
+#, fuzzy
msgid "'apksigner' verification of %s failed."
-msgstr ""
+msgstr "La vérification de %s avec 'apksigner' a échoué."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Exporting for Android"
-msgstr "Tout exporter"
+msgstr "Exportation vers Android"
#: platform/android/export/export.cpp
msgid "Invalid filename! Android App Bundle requires the *.aab extension."
@@ -13570,7 +13506,7 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "Unsupported export format!\n"
-msgstr ""
+msgstr "Format d'export non supporté !\n"
#: platform/android/export/export.cpp
msgid ""
@@ -13594,20 +13530,20 @@ msgstr ""
"Veuillez réinstaller la version d'Android depuis le menu 'Projet'."
#: platform/android/export/export.cpp
+#, fuzzy
msgid ""
"Unable to overwrite res://android/build/res/*.xml files with project name"
msgstr ""
+"Impossible d'écraser les fichiers res://android/build/res/*.xml avec le nom "
+"du projet"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not export project files to gradle project\n"
-msgstr ""
-"Impossible de modifier le fichier project.godot dans le chemin du projet."
+msgstr "Impossible d'exporter les fichiers du projet vers le projet gradle\n"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not write expansion package file!"
-msgstr "Impossible d'écrire le fichier :"
+msgstr "Impossible d'écrire le fichier du paquet d'expansion !"
#: platform/android/export/export.cpp
msgid "Building Android Project (gradle)"
@@ -13638,37 +13574,42 @@ msgstr ""
#: platform/android/export/export.cpp
#, fuzzy
msgid "Package not found: %s"
-msgstr "Animation introuvable : « %s »"
+msgstr "Paquet introuvable : « %s »"
#: platform/android/export/export.cpp
#, fuzzy
msgid "Creating APK..."
-msgstr "Création des contours..."
+msgstr "Création du fichier APK..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid ""
"Could not find template APK to export:\n"
"%s"
-msgstr "Impossible d'ouvrir le modèle pour exportation :"
+msgstr ""
+"Impossible de trouver le modèle de l'APK à exporter :\n"
+"%s"
#: platform/android/export/export.cpp
+#, fuzzy
msgid ""
"Missing libraries in the export template for the selected architectures: "
"%s.\n"
"Please build a template with all required libraries, or uncheck the missing "
"architectures in the export preset."
msgstr ""
+"Bibliothèques manquantes dans le modèle d'export pour les architectures "
+"sélectionnées : %s.\n"
+"Veuillez construire un modèle avec toutes les bibliothèques requises, ou "
+"désélectionner les architectures manquantes dans le préréglage de l'export."
#: platform/android/export/export.cpp
#, fuzzy
msgid "Adding files..."
-msgstr "Ajout de %s..."
+msgstr "Ajout de fichiers..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not export project files"
-msgstr "Impossible d'écrire le fichier :"
+msgstr "Impossible d'exporter les fichiers du projet"
#: platform/android/export/export.cpp
msgid "Aligning APK..."
@@ -13676,7 +13617,7 @@ msgstr "Alignement de l'APK…"
#: platform/android/export/export.cpp
msgid "Could not unzip temporary unaligned APK."
-msgstr ""
+msgstr "Impossible de décompresser l'APK temporaire non aligné."
#: platform/iphone/export/export.cpp platform/osx/export/export.cpp
msgid "Identifier is missing."
@@ -13723,9 +13664,8 @@ msgid "Could not write file:"
msgstr "Impossible d'écrire le fichier :"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not read file:"
-msgstr "Impossible d'écrire le fichier :"
+msgstr "Impossible de lire le fichier :"
#: platform/javascript/export/export.cpp
#, fuzzy
@@ -13733,14 +13673,12 @@ msgid "Could not read HTML shell:"
msgstr "Impossible de lire le shell HTML personnalisé :"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not create HTTP server directory:"
-msgstr "Impossible de créer le dossier."
+msgstr "Impossible de créer le répertoire du serveur HTTP :"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Error starting HTTP server:"
-msgstr "Erreur d'enregistrement de la scène."
+msgstr "Erreur de démarrage du serveur HTTP :"
#: platform/osx/export/export.cpp
#, fuzzy
@@ -13748,8 +13686,9 @@ msgid "Invalid bundle identifier:"
msgstr "Identifiant invalide :"
#: platform/osx/export/export.cpp
+#, fuzzy
msgid "Notarization: code signing required."
-msgstr ""
+msgstr "Certification : signature du code requise."
#: platform/osx/export/export.cpp
msgid "Notarization: hardened runtime required."
@@ -14206,11 +14145,16 @@ msgstr ""
"A la place utilisez une BakedLightMap."
#: scene/3d/gi_probe.cpp
+#, fuzzy
msgid ""
"The GIProbe Compress property has been deprecated due to known bugs and no "
"longer has any effect.\n"
"To remove this warning, disable the GIProbe's Compress property."
msgstr ""
+"La propriété GIProbe Compress a été déclarée comme obsolète à cause de bugs "
+"connus et n'a plus aucun effet.\n"
+"Pour supprimer cette avertissement, désactivez la propriété Compress du "
+"GIProbe."
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
@@ -14304,15 +14248,15 @@ msgstr "Node A et Node B doivent être des PhysicsBody différents"
#: scene/3d/portal.cpp
msgid "The RoomManager should not be a child or grandchild of a Portal."
-msgstr ""
+msgstr "Le RoomManager ne doit pas être enfant ou grand-enfant d'un Portal."
#: scene/3d/portal.cpp
msgid "A Room should not be a child or grandchild of a Portal."
-msgstr ""
+msgstr "Un Room ne doit pas être enfant ou petit-enfant d'un Portal."
#: scene/3d/portal.cpp
msgid "A RoomGroup should not be a child or grandchild of a Portal."
-msgstr ""
+msgstr "Un RoomGroup ne doit pas être enfant ou petit-enfant d'un Portal."
#: scene/3d/remote_transform.cpp
msgid ""
@@ -14362,6 +14306,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr "Ce corps sera ignoré jusqu'à ce que vous définissiez un maillage."
@@ -15125,9 +15105,6 @@ msgstr "Les constantes ne peuvent être modifiées."
#~ msgid "Local Coords"
#~ msgstr "Coordonnées locales"
-#~ msgid "Snap Mode (%s)"
-#~ msgstr "Mode d'aimantation (%s)"
-
#~ msgid "Tool Select"
#~ msgstr "Outil sélection"
diff --git a/editor/translations/ga.po b/editor/translations/ga.po
index 98fe774878..872463b1a9 100644
--- a/editor/translations/ga.po
+++ b/editor/translations/ga.po
@@ -337,6 +337,7 @@ msgstr ""
msgid "Remove Anim Track"
msgstr ""
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr ""
@@ -361,10 +362,26 @@ msgstr "Cruthaigh"
msgid "Anim Insert"
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "CrannBeochan"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr ""
@@ -920,7 +937,7 @@ msgstr ""
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2214,6 +2231,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -2994,10 +3022,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr ""
@@ -3602,6 +3626,14 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+msgid "Open in Web Browser"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8288,6 +8320,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Color Items"
msgstr ""
@@ -8313,6 +8351,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
msgstr ""
@@ -11730,6 +11774,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13330,6 +13382,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/gl.po b/editor/translations/gl.po
index 9b97e45e8a..054b62690d 100644
--- a/editor/translations/gl.po
+++ b/editor/translations/gl.po
@@ -6,18 +6,19 @@
# Andy Barcia <andybarcia4@gmail.com>, 2021.
# PokeGalaico <abloodyfreaks@gmail.com>, 2021.
# Kkai <kaieltroll@gmail.com>, 2021.
+# davidrogel <david.rogel.pernas@icloud.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
-"PO-Revision-Date: 2021-04-26 22:32+0000\n"
-"Last-Translator: Kkai <kaieltroll@gmail.com>\n"
+"PO-Revision-Date: 2021-08-12 14:48+0000\n"
+"Last-Translator: davidrogel <david.rogel.pernas@icloud.com>\n"
"Language-Team: Galician <https://hosted.weblate.org/projects/godot-engine/"
"godot/gl/>\n"
"Language: gl\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8-bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.7-dev\n"
+"X-Generator: Weblate 4.8-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -339,6 +340,7 @@ msgstr "Cambiar Modo de Bucle da Animación"
msgid "Remove Anim Track"
msgstr "Eliminar Pista de Animación"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Crear nova pista para %s e engadir chave?"
@@ -363,10 +365,27 @@ msgstr "Crear"
msgid "Anim Insert"
msgstr "Engadir Animación"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animación"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "Un AnimationPlayer non pode animarse a si mesmo, só a outros players."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Non existe a propiedade '%s'."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Crear e Engadir Animación"
@@ -943,9 +962,9 @@ msgstr "Crear Novo %s"
msgid "No results for \"%s\"."
msgstr "Non houbo resultado para \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
-msgstr ""
+msgstr "Non hai descrición dispoñible para %s."
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp
@@ -1140,7 +1159,7 @@ msgstr "Moitas grazas de parte da comunidade de Godot!"
#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
msgid "Click to copy."
-msgstr ""
+msgstr "Clic para copiar."
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
@@ -1724,7 +1743,7 @@ msgstr "Importación"
#: editor/editor_feature_profile.cpp
msgid "Allows to view and edit 3D scenes."
-msgstr ""
+msgstr "Permite ver e editar escenas 3D."
#: editor/editor_feature_profile.cpp
msgid "Allows to edit scripts using the integrated script editor."
@@ -2293,6 +2312,17 @@ msgid "New Window"
msgstr "Nova Xanela"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Xira cando o editor actualiza a pantalla."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Os recursos importados non se poden gardar."
@@ -3161,10 +3191,6 @@ msgid "Save & Restart"
msgstr "Gardar e Reinicar"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Xira cando o editor actualiza a pantalla."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Actualizar de Maneira Continua"
@@ -3797,6 +3823,15 @@ msgid "Download from:"
msgstr "Erro na Descarga"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Abrir no Explorador de Arquivos"
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8606,6 +8641,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Eliminar Tódolos Marcapáxinas"
@@ -8636,6 +8677,12 @@ msgid "Remove All StyleBox Items"
msgstr "Eliminar Tódolos Marcapáxinas"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Engadir Elemento"
@@ -12185,6 +12232,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13860,6 +13915,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr "Este corpo será ignorado ata que se lle sea asignado unha malla."
diff --git a/editor/translations/he.po b/editor/translations/he.po
index bbe0ebbe08..d0a09565de 100644
--- a/editor/translations/he.po
+++ b/editor/translations/he.po
@@ -355,6 +355,7 @@ msgstr "שינוי מצב לול×ת הנפשה"
msgid "Remove Anim Track"
msgstr "מחיקת רצועת הנפשה"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "×”×× ×œ×™×¦×•×¨ רצועה חדשה ל%s ולהכניס מפתח?"
@@ -379,10 +380,28 @@ msgstr "יצירה"
msgid "Anim Insert"
msgstr "הוסף הנפשה"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "מצב הצמדה (%s)"
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "הנפשה"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "נגן ההנפשות ×œ× ×™×›×•×œ להנפיש ×ת עצמו, רק ×©×—×§× ×™× ×חרי×."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "×œ× ×§×™×™× ×ž×פיין ‚%s’."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "יצירה והוספה של הנפשה"
@@ -960,7 +979,7 @@ msgstr "יצירת %s חדש"
msgid "No results for \"%s\"."
msgstr "×ין תוצ×ות עבור \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2309,6 +2328,17 @@ msgid "New Window"
msgstr "חלון חדש"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "מסתובב ×›×שר חלון העורך מצויר מחדש."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "מש××‘×™× ×ž×™×•×‘××™× ×œ× × ×©×ž×¨×•."
@@ -3143,10 +3173,6 @@ msgid "Save & Restart"
msgstr "שמירה והפעלה מחדש"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "מסתובב ×›×שר חלון העורך מצויר מחדש."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "עדכון רציף"
@@ -3789,6 +3815,16 @@ msgid "Download from:"
msgstr "שגי×ת הורדה"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "הפעלה בדפדפן"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "שגי×ת העתקה"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8747,6 +8783,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "הסרת כל נקודות העצירה"
@@ -8777,6 +8819,12 @@ msgid "Remove All StyleBox Items"
msgstr "הסרת כל נקודות העצירה"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "מועדפי×:"
@@ -12388,6 +12436,14 @@ msgstr "שינוי גובה לצורת גליל"
msgid "Change Ray Shape Length"
msgstr "שינוי ×ורך לצורת קרן"
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "שינוי רדיוס גליל"
@@ -14113,6 +14169,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr "תהיה התעלמות מגוף זה עד שתקבע רשת."
@@ -14643,9 +14735,6 @@ msgstr "××™ ×פשר לשנות קבועי×."
#~ msgid "Local Coords"
#~ msgstr "נקודות ציון מקומיות"
-#~ msgid "Snap Mode (%s)"
-#~ msgstr "מצב הצמדה (%s)"
-
#~ msgid "Project List"
#~ msgstr "רשימת המיזמי×"
diff --git a/editor/translations/hi.po b/editor/translations/hi.po
index a4e7d4ae72..916e6fd01d 100644
--- a/editor/translations/hi.po
+++ b/editor/translations/hi.po
@@ -348,6 +348,7 @@ msgstr "à¤à¤¨à¤¿à¤®à¥‡à¤¶à¤¨ लूप मोड बदलें"
msgid "Remove Anim Track"
msgstr "अनीम टà¥à¤°à¥ˆà¤• निकालें"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "% à¤à¤¸ के लिठनया टà¥à¤°à¥ˆà¤• बनाà¤à¤‚ और कà¥à¤‚जी डालें?"
@@ -372,10 +373,27 @@ msgstr "बनाना"
msgid "Anim Insert"
msgstr "अनीम डालें"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "कारà¥à¤¯à¥‹à¤‚:"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "à¤à¤¨à¤¿à¤®à¥‡à¤¶à¤¨à¤ªà¥à¤²à¥‡à¤¯à¤° खà¥à¤¦ को चेतन नहीं कर सकता, केवल अनà¥à¤¯ खिलाड़ी।"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "पà¥à¤°à¥‹à¤ªà¤°à¥à¤Ÿà¥€"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "अनीम बनाà¤à¤‚ और डालें"
@@ -947,7 +965,7 @@ msgstr "नया%s बनाà¤à¤‚"
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2289,6 +2307,17 @@ msgid "New Window"
msgstr "नया विंडो"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "जब संपादक खिड़की फिर से खींचता है तो सà¥à¤ªà¤¿à¤¨ करता है।"
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "इंपोरà¥à¤Ÿà¥‡à¤¡ रेसोरà¥à¤¸à¥‡à¤¸ सेव नहीं कर सकते."
@@ -3130,10 +3159,6 @@ msgid "Save & Restart"
msgstr "सहेजें और पà¥à¤¨à¤ƒ आरंभ करें"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "जब संपादक खिड़की फिर से खींचता है तो सà¥à¤ªà¤¿à¤¨ करता है।"
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "लगातार अपडेट करें"
@@ -3785,6 +3810,15 @@ msgid "Download from:"
msgstr "डाउनलोड"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "फ़ाइल मैनेजर में खोलिये"
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8561,6 +8595,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "आइटम निकालें"
@@ -8591,6 +8631,12 @@ msgid "Remove All StyleBox Items"
msgstr "आइटम निकालें"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "पसंदीदा में जोड़ें"
@@ -12124,6 +12170,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13771,6 +13825,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/hr.po b/editor/translations/hr.po
index ea48ef0246..37d517cba0 100644
--- a/editor/translations/hr.po
+++ b/editor/translations/hr.po
@@ -340,6 +340,7 @@ msgstr "Promijeni NaÄin Ponavljanja Animacije"
msgid "Remove Anim Track"
msgstr "Ukloni Stazu Animacije"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Stvori NOVU stazu za %s i umetni kljuÄ?"
@@ -364,10 +365,26 @@ msgstr "Stvori"
msgid "Anim Insert"
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animacija"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "Animator ne može animirati sebe, samo druge animatore."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Anim Stvori & Umetni"
@@ -927,7 +944,7 @@ msgstr "Napravi novi %s"
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2240,6 +2257,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3021,10 +3049,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Kontinuirano ažuriraj"
@@ -3635,6 +3659,15 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Otvori u Inspektoru"
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8337,6 +8370,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Color Items"
msgstr ""
@@ -8364,6 +8403,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
msgstr ""
@@ -11805,6 +11850,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13413,6 +13466,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/hu.po b/editor/translations/hu.po
index 3af983ff18..c822f5bd53 100644
--- a/editor/translations/hu.po
+++ b/editor/translations/hu.po
@@ -351,6 +351,7 @@ msgstr "Animáció Összefűzés Módjának Változtatása"
msgid "Remove Anim Track"
msgstr "Animáció Sáv Eltávolítása"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Létrehoz ÚJ sávot a következőhöz: %s, és beszúrja a kulcsot?"
@@ -375,12 +376,29 @@ msgstr "Létrehozás"
msgid "Anim Insert"
msgstr "Animáció - Beszúrás"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animáció"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
"AnimationPlayer nem tudja önmagát animálni, csak más AnimationPlayer "
"elemeket."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Tulajdonság"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Animáció - Létrehozás és Beillesztés"
@@ -959,7 +977,7 @@ msgstr "Új %s létrehozása"
msgid "No results for \"%s\"."
msgstr "Nincs találat a következőre: \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2309,6 +2327,17 @@ msgid "New Window"
msgstr "Új ablak"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Pörög, amikor a szerkesztőablak újrarajzolódik."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Az importált erőforrások nem menthetők."
@@ -3178,10 +3207,6 @@ msgid "Save & Restart"
msgstr "Mentés és újraindítás"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Pörög, amikor a szerkesztőablak újrarajzolódik."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Folyamatos frissítés"
@@ -3825,6 +3850,16 @@ msgid "Download from:"
msgstr "Letöltési Hiba"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Megnyitás a Fájlkezelőben"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Hiba Másolása"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8609,6 +8644,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Összes könyvjelző eltávolítása"
@@ -8639,6 +8680,12 @@ msgid "Remove All StyleBox Items"
msgstr "Összes könyvjelző eltávolítása"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Elem Hozzáadása"
@@ -12104,6 +12151,16 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Görbe Pont Pozíció Beállítása"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Görbe Pont Pozíció Beállítása"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13734,6 +13791,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/id.po b/editor/translations/id.po
index ccc5865b85..3426bd0962 100644
--- a/editor/translations/id.po
+++ b/editor/translations/id.po
@@ -368,6 +368,7 @@ msgstr "Ubah Mode Perulangan Animasi"
msgid "Remove Anim Track"
msgstr "Hapus Trek Anim"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Buat track BARU untuk %s dan masukkan tombol?"
@@ -392,11 +393,29 @@ msgstr "Buat"
msgid "Anim Insert"
msgstr "Sisipkan Anim"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "Tidak dapat membuka '%s'."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animasi"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
"AnimationPlayer tidak bisa menganimasikan diri sendiri, gunakan pemutar lain."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Tidak ada properti '%s'."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Buat & Sisipkan Anim"
@@ -972,7 +991,7 @@ msgstr "Buat %s baru"
msgid "No results for \"%s\"."
msgstr "Tidak ada hasil untuk \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2322,6 +2341,17 @@ msgid "New Window"
msgstr "Jendela Baru"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Putar ketika jendela editor digambar ulang."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Resource yang diimpor tidak dapat disimpan."
@@ -3180,10 +3210,6 @@ msgid "Save & Restart"
msgstr "Simpan & Mulai Ulang"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Putar ketika jendela editor digambar ulang."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Perbarui Terus-menerus"
@@ -3845,6 +3871,16 @@ msgid "Download from:"
msgstr "Unduhan Gagal"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Jalankan di Peramban"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Salin Galat"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8712,6 +8748,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Hapus Semua Item"
@@ -8742,6 +8784,12 @@ msgid "Remove All StyleBox Items"
msgstr "Hapus Semua Item"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Tambah Item Kelas"
@@ -12412,6 +12460,16 @@ msgstr "Ubah Tinggi Bentuk Silinder"
msgid "Change Ray Shape Length"
msgstr "Ubah Panjang Shape Ray"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Atur Posisi Titik Kurva"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Atur Posisi Titik Kurva"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "Ubah Radius Silinder"
@@ -14186,6 +14244,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr "Body ini akan diabaikan hingga Anda mengatur mesh-nya."
@@ -15242,9 +15336,6 @@ msgstr "Konstanta tidak dapat dimodifikasi."
#~ msgid "I see..."
#~ msgstr "Mengerti..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "Tidak dapat membuka '%s'."
-
#~ msgid "Ugh"
#~ msgstr "Duh"
diff --git a/editor/translations/is.po b/editor/translations/is.po
index 916be97fb4..e536b0a8f6 100644
--- a/editor/translations/is.po
+++ b/editor/translations/is.po
@@ -360,6 +360,7 @@ msgstr ""
msgid "Remove Anim Track"
msgstr "Fjarlægja Anim track"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr ""
@@ -384,10 +385,26 @@ msgstr ""
msgid "Anim Insert"
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Stillið breyting á:"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr ""
@@ -954,7 +971,7 @@ msgstr ""
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2253,6 +2270,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3036,10 +3064,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
#, fuzzy
msgid "Update Continuously"
msgstr "Samfellt"
@@ -3648,6 +3672,15 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Opna Verkefna Stjóra?"
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8376,6 +8409,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Color Items"
msgstr ""
@@ -8403,6 +8442,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
msgstr ""
@@ -11873,6 +11918,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13487,6 +13540,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/it.po b/editor/translations/it.po
index cec4cf1beb..c3aa84d4b6 100644
--- a/editor/translations/it.po
+++ b/editor/translations/it.po
@@ -37,7 +37,7 @@
# Stefano Merazzi <asso99@hotmail.com>, 2019.
# Sinapse X <sinapsex13@gmail.com>, 2019.
# Micila Micillotto <micillotto@gmail.com>, 2019, 2020, 2021.
-# Mirko Soppelsa <miknsop@gmail.com>, 2019, 2020.
+# Mirko Soppelsa <miknsop@gmail.com>, 2019, 2020, 2021.
# No <kingofwizards.kw7@gmail.com>, 2019.
# StarFang208 <polaritymanx@yahoo.it>, 2019.
# Katia Piazza <gydey@ridiculousglitch.com>, 2019.
@@ -64,8 +64,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-07-26 14:18+0000\n"
-"Last-Translator: Riteo Siuga <riteo@posteo.net>\n"
+"PO-Revision-Date: 2021-08-10 21:39+0000\n"
+"Last-Translator: Mirko <miknsop@gmail.com>\n"
"Language-Team: Italian <https://hosted.weblate.org/projects/godot-engine/"
"godot/it/>\n"
"Language: it\n"
@@ -73,7 +73,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.7.2-dev\n"
+"X-Generator: Weblate 4.8-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -394,6 +394,7 @@ msgstr "Cambia la modalità del ciclo di un'animazione"
msgid "Remove Anim Track"
msgstr "Rimuovi una traccia d'animazione"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Creare una NUOVA traccia per %s e inserire la chiave?"
@@ -418,10 +419,28 @@ msgstr "Crea"
msgid "Anim Insert"
msgstr "Inserisci un'animazione"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "Impossibile aprire '%s'."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animazione"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "AnimationPlayer non può animare se stesso, solo altri nodi."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Non esiste nessuna proprietà \"%s\"."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Crea un'animazione e inserisci un fotogramma chiave"
@@ -1005,7 +1024,7 @@ msgstr "Crea un nuovo %s"
msgid "No results for \"%s\"."
msgstr "Nessun risultato per \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2372,6 +2391,17 @@ msgid "New Window"
msgstr "Nuova Finestra"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Gira quando la finestra dell'editor viene ridisegnata."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Le risorse importate non possono essere salvate."
@@ -3248,10 +3278,6 @@ msgid "Save & Restart"
msgstr "Salva e riavvia"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Gira quando la finestra dell'editor viene ridisegnata."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Aggiorna continuamente"
@@ -3499,7 +3525,6 @@ msgid "Inclusive"
msgstr "Inclusivo"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Self"
msgstr "Se stesso"
@@ -3930,6 +3955,16 @@ msgid "Download from:"
msgstr "Errore durante il download"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Esegui nel Browser"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Copia Errore"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -7908,9 +7943,8 @@ msgid "Translate"
msgstr "Trasla:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Scale"
-msgstr "Scala:"
+msgstr "Scala"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scaling: "
@@ -8855,6 +8889,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Rimuovi tutti gli elementi"
@@ -8885,6 +8925,12 @@ msgid "Remove All StyleBox Items"
msgstr "Rimuovi tutti gli elementi"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Aggiungi Elementi di Classe"
@@ -12574,6 +12620,16 @@ msgstr "Modifica Altezza di Forma del Cilindro"
msgid "Change Ray Shape Length"
msgstr "Cambia lunghezza Ray Shape"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Imposta Posizione Punto Curva"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Imposta Posizione Punto Curva"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "Modifica Raggio del Cilindro"
@@ -13569,7 +13625,7 @@ msgstr ""
#: platform/android/export/export.cpp
#, fuzzy
msgid "Exporting for Android"
-msgstr "Esportando Tutto"
+msgstr "Esportazione per Android"
#: platform/android/export/export.cpp
msgid "Invalid filename! Android App Bundle requires the *.aab extension."
@@ -14377,6 +14433,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr "Questo corpo verrà ignorato fino a quando non imposterai una mesh."
@@ -15641,9 +15733,6 @@ msgstr "Le constanti non possono essere modificate."
#~ msgid "I see..."
#~ msgstr "Capisco..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "Impossibile aprire '%s'."
-
#~ msgid "Ugh"
#~ msgstr "Ugh"
diff --git a/editor/translations/ja.po b/editor/translations/ja.po
index 83e544e5b5..3ee6d0b49d 100644
--- a/editor/translations/ja.po
+++ b/editor/translations/ja.po
@@ -15,7 +15,7 @@
# Tohru Ike (rokujyouhitoma) <rokujyouhitomajp@gmail.com>, 2017-2018.
# yu tang <0011solo@gmail.com>, 2018.
# zukkun <zukkun@gmail.com>, 2018.
-# sugusan <sugusan.development@gmail.com>, 2018, 2019.
+# sugusan <sugusan.development@gmail.com>, 2018, 2019, 2021.
# Nathan Lovato <nathan.lovato.art@gmail.com>, 2018.
# nyanode <akaruooyagi@yahoo.co.jp>, 2018.
# nitenook <admin@alterbaum.net>, 2018, 2019, 2020, 2021.
@@ -37,8 +37,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-07-29 02:33+0000\n"
-"Last-Translator: nitenook <admin@alterbaum.net>\n"
+"PO-Revision-Date: 2021-08-12 14:48+0000\n"
+"Last-Translator: sugusan <sugusan.development@gmail.com>\n"
"Language-Team: Japanese <https://hosted.weblate.org/projects/godot-engine/"
"godot/ja/>\n"
"Language: ja\n"
@@ -46,7 +46,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.7.2-dev\n"
+"X-Generator: Weblate 4.8-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -367,6 +367,7 @@ msgstr "アニメーションã®ãƒ«ãƒ¼ãƒ—モードを変更"
msgid "Remove Anim Track"
msgstr "アニメーショントラックを除去"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "%s ã®æ–°è¦ãƒˆãƒ©ãƒƒã‚¯ã‚’作æˆã—ã€ã‚­ãƒ¼ã‚’挿入ã—ã¾ã™ã‹ï¼Ÿ"
@@ -391,12 +392,30 @@ msgstr "作æˆ"
msgid "Anim Insert"
msgstr "アニメーション挿入"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "'..'を処ç†ã§ãã¾ã›ã‚“"
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "アニメーション"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
"アニメーションプレイヤーã¯ä»–ã®ãƒ—レイヤーã ã‘をアニメーション化ã™ã‚‹ã“ã¨ã¯ã§ã"
"ã¾ã›ã‚“。"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "プロパティ '%s' ã¯å­˜åœ¨ã—ã¾ã›ã‚“。"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "アニメーションã®ä½œæˆã¨æŒ¿å…¥"
@@ -972,9 +991,9 @@ msgstr "%s ã‚’æ–°è¦ä½œæˆ"
msgid "No results for \"%s\"."
msgstr "\"%s\" ã®çµæžœã¯ã‚りã¾ã›ã‚“。"
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
-msgstr ""
+msgstr "%s ã«ã¤ã„ã¦ã®èª¬æ˜Žã¯ã‚りã¾ã›ã‚“。"
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp
@@ -1166,7 +1185,7 @@ msgstr "Godot コミュニティより感è¬ã‚’ï¼"
#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
msgid "Click to copy."
-msgstr ""
+msgstr "クリックã—ã¦ã‚³ãƒ”ーã—ã¾ã™ã€‚"
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
@@ -2325,6 +2344,17 @@ msgid "New Window"
msgstr "æ–°è¦ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "エディタ ウィンドウã®å†æç”»æ™‚ã«ã‚¹ãƒ”ンã—ã¾ã™ã€‚"
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "インãƒãƒ¼ãƒˆã—ãŸãƒªã‚½ãƒ¼ã‚¹ã¯ä¿å­˜ã§ãã¾ã›ã‚“。"
@@ -3185,10 +3215,6 @@ msgid "Save & Restart"
msgstr "ä¿å­˜ã—ã¦å†èµ·å‹•"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "エディタ ウィンドウã®å†æç”»æ™‚ã«ã‚¹ãƒ”ンã—ã¾ã™ã€‚"
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "ç¶™ç¶šçš„ã«æ›´æ–°"
@@ -3634,11 +3660,11 @@ msgstr "ノードã‹ã‚‰ã‚¤ãƒ³ãƒãƒ¼ãƒˆ:"
#: editor/export_template_manager.cpp
msgid "Open the folder containing these templates."
-msgstr ""
+msgstr "ã“れらã®ãƒ†ãƒ³ãƒ—レートãŒã‚るフォルダを開ãã¾ã™ã€‚"
#: editor/export_template_manager.cpp
msgid "Uninstall these templates."
-msgstr ""
+msgstr "ã“れらã®ãƒ†ãƒ³ãƒ—レートをアンインストールã—ã¾ã™ã€‚"
#: editor/export_template_manager.cpp
#, fuzzy
@@ -3652,7 +3678,7 @@ msgstr "ミラーをå–å¾—ã—ã¦ã„ã¾ã™ã€‚ã—ã°ã‚‰ããŠå¾…ã¡ãã ã•ã„...
#: editor/export_template_manager.cpp
msgid "Starting the download..."
-msgstr ""
+msgstr "ダウンロードを開始ã—ã¦ã„ã¾ã™..."
#: editor/export_template_manager.cpp
msgid "Error requesting URL:"
@@ -3695,7 +3721,7 @@ msgstr "リクエストã¯å¤±æ•—ã—ã¾ã—ãŸã€‚"
#: editor/export_template_manager.cpp
msgid "Download complete; extracting templates..."
-msgstr ""
+msgstr "ダウンロードãŒå®Œäº†ã—ã¾ã—ãŸã€‚テンプレートを展開ã—ã¦ã„ã¾ã™..."
#: editor/export_template_manager.cpp
msgid "Cannot remove temporary file:"
@@ -3820,10 +3846,12 @@ msgstr "ç¾åœ¨ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³:"
#: editor/export_template_manager.cpp
msgid "Export templates are missing. Download them or install from a file."
msgstr ""
+"エクスãƒãƒ¼ãƒˆ テンプレートãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。ダウンロードã™ã‚‹ã‹ãƒ•ァイルã‹ã‚‰ã‚¤ãƒ³"
+"ストールã—ã¦ãã ã•ã„。"
#: editor/export_template_manager.cpp
msgid "Export templates are installed and ready to be used."
-msgstr ""
+msgstr "エクスãƒãƒ¼ãƒˆ テンプレートã¯ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•れã¦ãŠã‚Šã€åˆ©ç”¨ã§ãã¾ã™ã€‚"
#: editor/export_template_manager.cpp
#, fuzzy
@@ -3849,8 +3877,18 @@ msgid "Download from:"
msgstr "ダウンロードエラー"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "ブラウザã§å®Ÿè¡Œ"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "エラーをコピー"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
-msgstr ""
+msgstr "ダウンロードã—ã¦ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«"
#: editor/export_template_manager.cpp
msgid ""
@@ -4052,35 +4090,32 @@ msgid "Collapse All"
msgstr "ã™ã¹ã¦æŠ˜ã‚ŠãŸãŸã‚€"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort files"
-msgstr "ファイル検索"
+msgstr "ファイルã®ä¸¦ã³æ›¿ãˆ"
#: editor/filesystem_dock.cpp
msgid "Sort by Name (Ascending)"
-msgstr ""
+msgstr "åå‰ (昇順) ã§ä¸¦ã³æ›¿ãˆ"
#: editor/filesystem_dock.cpp
msgid "Sort by Name (Descending)"
-msgstr ""
+msgstr "åå‰ (é™é †) ã§ä¸¦ã³æ›¿ãˆ"
#: editor/filesystem_dock.cpp
msgid "Sort by Type (Ascending)"
-msgstr ""
+msgstr "種類 (昇順) ã§ä¸¦ã³æ›¿ãˆ"
#: editor/filesystem_dock.cpp
msgid "Sort by Type (Descending)"
-msgstr ""
+msgstr "種類 (é™é †) ã§ä¸¦ã³æ›¿ãˆ"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort by Last Modified"
-msgstr "最終更新"
+msgstr "æ›´æ–°æ—¥æ™‚ãŒæ–°ã—ã„é †ã§ä¸¦ã³æ›¿ãˆ"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort by First Modified"
-msgstr "最終更新"
+msgstr "更新日時ãŒå¤ã„é †ã§ä¸¦ã³æ›¿ãˆ"
#: editor/filesystem_dock.cpp
msgid "Duplicate..."
@@ -8708,6 +8743,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "ã™ã¹ã¦ã®ã‚¢ã‚¤ãƒ†ãƒ ã‚’除去"
@@ -8738,6 +8779,12 @@ msgid "Remove All StyleBox Items"
msgstr "ã™ã¹ã¦ã®ã‚¢ã‚¤ãƒ†ãƒ ã‚’除去"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "クラスアイテム追加"
@@ -12390,6 +12437,16 @@ msgstr "円柱シェイプã®é«˜ã•を変更"
msgid "Change Ray Shape Length"
msgstr "レイシェイプã®é•·ã•を変更"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "カーブãƒã‚¤ãƒ³ãƒˆã®ä½ç½®ã‚’設定"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "カーブãƒã‚¤ãƒ³ãƒˆã®ä½ç½®ã‚’設定"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "円柱ã®åŠå¾„を変更"
@@ -14160,6 +14217,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr "ã“ã®ãƒœãƒ‡ã‚£ã¯ã€ãƒ¡ãƒƒã‚·ãƒ¥ã‚’設定ã™ã‚‹ã¾ã§ç„¡è¦–ã•れã¾ã™ã€‚"
@@ -15444,10 +15537,6 @@ msgstr "定数ã¯å¤‰æ›´ã§ãã¾ã›ã‚“。"
#~ msgstr "ã‚ã‹ã£ãŸ..."
#, fuzzy
-#~ msgid "Can't open '%s'."
-#~ msgstr "'..'を処ç†ã§ãã¾ã›ã‚“"
-
-#, fuzzy
#~ msgid "Ugh"
#~ msgstr "ã†ã‡"
diff --git a/editor/translations/ka.po b/editor/translations/ka.po
index 144ef77158..7abc89b216 100644
--- a/editor/translations/ka.po
+++ b/editor/translations/ka.po
@@ -366,6 +366,7 @@ msgstr "áƒáƒœáƒ˜áƒ› ლუპის შეცვლáƒ"
msgid "Remove Anim Track"
msgstr "áƒáƒœáƒ˜áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ თრექის წáƒáƒ¨áƒšáƒ"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
#, fuzzy
msgid "Create NEW track for %s and insert key?"
@@ -391,6 +392,17 @@ msgstr "შექმნáƒ"
msgid "Anim Insert"
msgstr "áƒáƒœáƒ˜áƒ› ჩáƒáƒ§áƒ”ნებáƒ"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "ფუნქციები:"
+
#: editor/animation_track_editor.cpp
#, fuzzy
msgid "AnimationPlayer can't animate itself, only other players."
@@ -398,6 +410,12 @@ msgstr ""
"áƒáƒœáƒ˜áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ გáƒáƒ›áƒ¨áƒ•ები ვერ ჩáƒáƒáƒ¢áƒáƒ áƒ”ბს ცდებს სáƒáƒ™áƒ£áƒ—áƒáƒ  თáƒáƒ•ზე, მხáƒáƒšáƒáƒ“ სხვრ"
"მáƒáƒ—áƒáƒ›áƒáƒ¨áƒ”ებზე."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "áƒáƒ‘იექტზე დáƒáƒ™áƒ•ირვებáƒ"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "áƒáƒœáƒ˜áƒ› შექმნრ& ჩáƒáƒ§áƒ”ნებáƒ"
@@ -988,7 +1006,7 @@ msgstr "áƒáƒ®áƒáƒšáƒ˜ %s შექმნáƒ"
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2331,6 +2349,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3120,10 +3149,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
#, fuzzy
msgid "Update Continuously"
msgstr "უწყვეტი"
@@ -3741,6 +3766,15 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "გáƒáƒ®áƒ¡áƒœáƒ˜áƒšáƒ˜"
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8578,6 +8612,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "სáƒáƒ§áƒ•áƒáƒ áƒšáƒ”ბი:"
@@ -8606,6 +8646,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "სáƒáƒ§áƒ•áƒáƒ áƒšáƒ”ბი:"
@@ -12141,6 +12187,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13772,6 +13826,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/km.po b/editor/translations/km.po
index e18a778132..187307bc17 100644
--- a/editor/translations/km.po
+++ b/editor/translations/km.po
@@ -337,6 +337,7 @@ msgstr ""
msgid "Remove Anim Track"
msgstr ""
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr ""
@@ -361,10 +362,25 @@ msgstr ""
msgid "Anim Insert"
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "animation"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr ""
@@ -919,7 +935,7 @@ msgstr ""
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2210,6 +2226,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -2989,10 +3016,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr ""
@@ -3597,6 +3620,14 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+msgid "Open in Web Browser"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8277,6 +8308,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Color Items"
msgstr ""
@@ -8301,6 +8338,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
msgstr ""
@@ -11708,6 +11751,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13302,6 +13353,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/ko.po b/editor/translations/ko.po
index eda096e4ce..1f24eb1b1d 100644
--- a/editor/translations/ko.po
+++ b/editor/translations/ko.po
@@ -27,7 +27,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-07-16 05:47+0000\n"
+"PO-Revision-Date: 2021-08-12 14:48+0000\n"
"Last-Translator: Myeongjin Lee <aranet100@gmail.com>\n"
"Language-Team: Korean <https://hosted.weblate.org/projects/godot-engine/"
"godot/ko/>\n"
@@ -36,7 +36,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.7.2-dev\n"
+"X-Generator: Weblate 4.8-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -358,6 +358,7 @@ msgstr "애니메ì´ì…˜ 루프 모드 바꾸기"
msgid "Remove Anim Track"
msgstr "애니메ì´ì…˜ 트랙 ì‚­ì œ"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "%sì„(를) 위해 새 íŠ¸ëž™ì„ ë§Œë“¤ê³  키를 삽입할까요?"
@@ -382,12 +383,30 @@ msgstr "만들기"
msgid "Anim Insert"
msgstr "애니메ì´ì…˜ 삽입"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "'%s' 열수 ì—†ìŒ."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "애니메ì´ì…˜"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
"AnimationPlayer는 ìžì‹ ì´ 아닌 다른 플레ì´ì–´ì—ë§Œ 애니메ì´ì…˜ì„ 부여할 수 있습니"
"다."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "'%s' ì†ì„±ì´ 없습니다."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "애니메ì´ì…˜ 만들기 & 삽입"
@@ -961,9 +980,9 @@ msgstr "새 %s 만들기"
msgid "No results for \"%s\"."
msgstr "\"%s\"ì— ëŒ€í•œ 결과가 없습니다."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
-msgstr ""
+msgstr "%sì˜ ì‚¬ìš© 가능한 ì„¤ëª…ì´ ì—†ìŠµë‹ˆë‹¤."
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp
@@ -1263,11 +1282,11 @@ msgstr "%s (ì´ë¯¸ 존재함)"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - %d file(s) conflict with your project:"
-msgstr ""
+msgstr "ì• ì…‹ \"%s\"ì˜ ë‚´ìš© - íŒŒì¼ %d개가 프로ì íŠ¸ì™€ ì¶©ëŒí•©ë‹ˆë‹¤:"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - No files conflict with your project:"
-msgstr ""
+msgstr "ì• ì…‹ \"%s\"ì˜ ë‚´ìš© - 프로ì íŠ¸ì™€ ì¶©ëŒí•˜ëŠ” 파ì¼ì´ 없습니다:"
#: editor/editor_asset_installer.cpp
msgid "Uncompressing Assets"
@@ -1279,9 +1298,8 @@ msgid "The following files failed extraction from asset \"%s\":"
msgstr "ë‹¤ìŒ íŒŒì¼ì„ 패키지ì—서 ì¶”ì¶œí•˜ëŠ”ë° ì‹¤íŒ¨í•¨:"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "(and %s more files)"
-msgstr "외 %d ê°œì˜ íŒŒì¼."
+msgstr "(ë° ë” ë§Žì€ íŒŒì¼ %sê°œ)"
#: editor/editor_asset_installer.cpp
#, fuzzy
@@ -1531,13 +1549,12 @@ msgid "Can't add autoload:"
msgstr "오토로드를 추가할 수 ì—†ìŒ:"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "%s is an invalid path. File does not exist."
-msgstr "파ì¼ì´ 존재하지 않습니다."
+msgstr "%s는 ìž˜ëª»ëœ ê²½ë¡œìž…ë‹ˆë‹¤. 파ì¼ì´ 존재하지 않습니다."
#: editor/editor_autoload_settings.cpp
msgid "%s is an invalid path. Not in resource path (res://)."
-msgstr ""
+msgstr "%s는 ìž˜ëª»ëœ ê²½ë¡œìž…ë‹ˆë‹¤. 리소스 경로(res://)ì— ìžˆì§€ 않습니다."
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -1814,9 +1831,8 @@ msgid "Class Properties:"
msgstr "ì†ì„±:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Main Features:"
-msgstr "기능"
+msgstr "주요 기능:"
#: editor/editor_feature_profile.cpp
#, fuzzy
@@ -1876,14 +1892,12 @@ msgid "Export"
msgstr "내보내기"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Configure Selected Profile:"
-msgstr "현재 프로필:"
+msgstr "ì„ íƒëœ 프로필 구성:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Extra Options:"
-msgstr "í…ìŠ¤ì³ ì˜µì…˜"
+msgstr "별ë„ì˜ ì˜µì…˜:"
#: editor/editor_feature_profile.cpp
msgid "Create or import a profile to edit available classes and properties."
@@ -2307,6 +2321,17 @@ msgid "New Window"
msgstr "새 창"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "편집기 ì°½ì— ë³€í™”ê°€ ìžˆì„ ë•Œë§ˆë‹¤ 회전합니다."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "가져온 리소스를 저장할 수 없습니다."
@@ -2448,9 +2473,9 @@ msgid ""
"Please read the documentation relevant to importing scenes to better "
"understand this workflow."
msgstr ""
-"ì´ ë¦¬ì†ŒìŠ¤ëŠ” 가져온 ì”¬ì— ì†í•œ 리소스ì´ë¯€ë¡œ 편집할 수 없습니다.\n"
-"ì´ ì›Œí¬í”Œë¡œë¥¼ ì´í•´í•˜ë ¤ë©´ 씬 가져오기(Importing Scenes)와 ê´€ë ¨ëœ ë¬¸ì„œë¥¼ ì½ì–´ì£¼"
-"세요."
+"`ì´ ë¦¬ì†ŒìŠ¤ëŠ” 가져온 ì”¬ì— ì†í•œ 리소스ì´ë¯€ë¡œ 편집할 수 없습니다.\n"
+"ì´ ì›Œí¬í”Œë¡œë¥¼ ì´í•´í•˜ë ¤ë©´ 씬 가져오기(Importing Scenes)와 ê´€ë ¨ëœ ì„¤ëª…ë¬¸ì„œë¥¼ ì½"
+"어주세요."
#: editor/editor_node.cpp
msgid ""
@@ -2477,8 +2502,8 @@ msgid ""
msgstr ""
"ì´ ì”¬ì€ ê°€ì ¸ì˜¨ 것ì´ë¯€ë¡œ 변경 ì‚¬í•­ì´ ìœ ì§€ë˜ì§€ 않습니다.\n"
"ì´ ì”¬ì„ ì¸ìŠ¤í„´ìŠ¤í™”í•˜ê±°ë‚˜ ìƒì†í•˜ë©´ 편집할 수 있습니다.\n"
-"ì´ ì›Œí¬í”Œë¡œë¥¼ ì´í•´í•˜ë ¤ë©´ 씬 가져오기(Importing Scenes)와 ê´€ë ¨ëœ ë¬¸ì„œë¥¼ ì½ì–´ì£¼"
-"세요."
+"ì´ ì›Œí¬í”Œë¡œë¥¼ ì´í•´í•˜ë ¤ë©´ 씬 가져오기(Importing Scenes)와 ê´€ë ¨ëœ ì„¤ëª…ë¬¸ì„œë¥¼ ì½"
+"어주세요."
#: editor/editor_node.cpp
msgid ""
@@ -2487,7 +2512,7 @@ msgid ""
"this workflow."
msgstr ""
"ì›ê²© ê°ì²´ëŠ” ë³€ê²½ì‚¬í•­ì´ ì ìš©ë˜ì§€ 않습니다.\n"
-"ì´ ì›Œí¬í”Œë¡œë¥¼ ì´í•´í•˜ë ¤ë©´ 디버깅(Debugging)ê³¼ ê´€ë ¨ëœ ë¬¸ì„œë¥¼ ì½ì–´ì£¼ì„¸ìš”."
+"ì´ ì›Œí¬í”Œë¡œë¥¼ ì´í•´í•˜ë ¤ë©´ 디버깅(Debugging)ê³¼ ê´€ë ¨ëœ ì„¤ëª…ë¬¸ì„œë¥¼ ì½ì–´ì£¼ì„¸ìš”."
#: editor/editor_node.cpp
msgid "There is no defined scene to run."
@@ -2568,7 +2593,7 @@ msgstr "ì´ ìž‘ì—…ì—는 ì„ íƒí•œ 노드가 필요합니다."
#: editor/editor_node.cpp
msgid "Current scene not saved. Open anyway?"
-msgstr "현재 ì”¬ì„ ì €ìž¥í•˜ì§€ 않았습니다. 무시하고 열까요?"
+msgstr "현재 ì”¬ì´ ì €ìž¥ë˜ì–´ 있지 않습니다. 무시하고 여시겠습니까?"
#: editor/editor_node.cpp
msgid "Can't reload a scene that was never saved."
@@ -2600,11 +2625,11 @@ msgstr "예"
#: editor/editor_node.cpp
msgid "Exit the editor?"
-msgstr "편집기를 ëŒê¹Œìš”?"
+msgstr "편집기를 나가시겠습니까?"
#: editor/editor_node.cpp
msgid "Open Project Manager?"
-msgstr "프로ì íЏ 매니저를 열까요?"
+msgstr "프로ì íЏ 매니저를 여시겠습니까?"
#: editor/editor_node.cpp
msgid "Save & Quit"
@@ -2612,11 +2637,11 @@ msgstr "저장 & 종료"
#: editor/editor_node.cpp
msgid "Save changes to the following scene(s) before quitting?"
-msgstr "ë„기 ì „ì— í•´ë‹¹ ì”¬ì˜ ë³€ê²½ ì‚¬í•­ì„ ì €ìž¥í• ê¹Œìš”?"
+msgstr "종료하기 ì „ì— í•´ë‹¹ ì”¬ì˜ ë³€ê²½ ì‚¬í•­ì„ ì €ìž¥í•˜ì‹œê² ìŠµë‹ˆê¹Œ?"
#: editor/editor_node.cpp
msgid "Save changes to the following scene(s) before opening Project Manager?"
-msgstr "프로ì íЏ 매니저를 열기 ì „ì— í•´ë‹¹ ì”¬ì˜ ë³€ê²½ ì‚¬í•­ì„ ì €ìž¥í• ê¹Œìš”?"
+msgstr "프로ì íЏ 매니터를 열기 ì „ì— í•´ë‹¹ ì”¬ì˜ ë³€ê²½ ì‚¬í•­ì„ ì €ìž¥í•˜ì‹œê² ìŠµë‹ˆê¹Œ?"
#: editor/editor_node.cpp
msgid ""
@@ -2949,7 +2974,7 @@ msgid ""
msgstr ""
"ì´ ì˜µì…˜ì´ í™œì„±í™” ëœ ê²½ìš° ì› í´ë¦­ ë°°í¬ë¥¼ 사용하면 ì‹¤í–‰ì¤‘ì¸ í”„ë¡œì íŠ¸ë¥¼ 디버깅 "
"í•  수 있ë„ë¡ì´ ì»´í“¨í„°ì˜ IPì— ì—°ê²°ì„ ì‹œë„합니다.\n"
-"ì´ ì˜µì…˜ì€ ì›ê²© 디버깅 (ì¼ë°˜ì ìœ¼ë¡œ ëª¨ë°”ì¼ ìž¥ì¹˜ 사용)ì— ì‚¬ìš©í•˜ê¸°ìœ„í•œ 것입니"
+"ì´ ì˜µì…˜ì€ ì›ê²© 디버깅 (ì¼ë°˜ì ìœ¼ë¡œ ëª¨ë°”ì¼ ê¸°ê¸° 사용)ì— ì‚¬ìš©í•˜ê¸° 위한 것입니"
"다.\n"
"GDScript 디버거를 로컬ì—서 사용하기 위해 활성화 í•  필요는 없습니다."
@@ -3009,8 +3034,8 @@ msgid ""
msgstr ""
"ì´ ì„¤ì •ì´ í™œì„±í™”ëœ ê²½ìš°, 편집기ì—서 ì”¬ì„ ìˆ˜ì •í•˜ë©´ ì‹¤í–‰ì¤‘ì¸ í”„ë¡œì íŠ¸ì— ë°˜ì˜ë©"
"니다.\n"
-"ì›ê²©ìž¥ì¹˜ì—서 ì‚¬ìš©ì¤‘ì¸ ê²½ìš° ë„¤íŠ¸ì›Œí¬ íŒŒì¼ ì‹œìŠ¤í…œ ê¸°ëŠ¥ì„ í™œì„±í™”í•˜ë©´ ë”ìš± 효율ì "
-"입니다."
+"기기ì—서 ì›ê²©ìœ¼ë¡œ ì‚¬ìš©ì¤‘ì¸ ê²½ìš° ë„¤íŠ¸ì›Œí¬ íŒŒì¼ ì‹œìŠ¤í…œ ê¸°ëŠ¥ì„ í™œì„±í™”í•˜ë©´ ë”ìš± "
+"효율ì ìž…니다."
#: editor/editor_node.cpp
msgid "Synchronize Script Changes"
@@ -3081,9 +3106,8 @@ msgid "Help"
msgstr "ë„움ë§"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Online Documentation"
-msgstr "문서 열기"
+msgstr "온ë¼ì¸ 설명문서"
#: editor/editor_node.cpp
msgid "Questions & Answers"
@@ -3161,10 +3185,6 @@ msgid "Save & Restart"
msgstr "저장 & 다시 시작"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "편집기 ì°½ì— ë³€í™”ê°€ ìžˆì„ ë•Œë§ˆë‹¤ 회전합니다."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "ìƒì‹œ ì—…ë°ì´íЏ"
@@ -3210,9 +3230,8 @@ msgid "Install from file"
msgstr "파ì¼ì—서 설치"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Select android sources file"
-msgstr "소스 메시를 ì„ íƒí•˜ì„¸ìš”:"
+msgstr "Android 소스 íŒŒì¼ ì„ íƒ"
#: editor/editor_node.cpp
msgid ""
@@ -3358,9 +3377,8 @@ msgid "Update"
msgstr "ì—…ë°ì´íЏ"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Version"
-msgstr "버전:"
+msgstr "버전"
#: editor/editor_plugin_settings.cpp
#, fuzzy
@@ -3609,7 +3627,7 @@ msgstr ""
#: editor/export_template_manager.cpp
msgid "Uninstall these templates."
-msgstr ""
+msgstr "ì´ í…œí”Œë¦¿ì„ ì œê±°í•©ë‹ˆë‹¤."
#: editor/export_template_manager.cpp
#, fuzzy
@@ -3635,42 +3653,37 @@ msgid "Connecting to the mirror..."
msgstr "ë¯¸ëŸ¬ì— ì—°ê²° 중..."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't resolve the requested address."
-msgstr "호스트 ì´ë¦„ì„ ì°¾ì„ ìˆ˜ ì—†ìŒ:"
+msgstr "ìš”ì²­ëœ ì£¼ì†Œë¥¼ í•´ê²°í•  수 없습니다."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't connect to the mirror."
-msgstr "í˜¸ìŠ¤íŠ¸ì— ì—°ê²°í•  수 ì—†ìŒ:"
+msgstr "ë¯¸ëŸ¬ì— ì—°ê²°í•  수 없습니다."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "No response from the mirror."
-msgstr "í˜¸ìŠ¤íŠ¸ì˜ ì‘답 ì—†ìŒ:"
+msgstr "미러로부터 ì‘ë‹´ì´ ì—†ìŠµë‹ˆë‹¤."
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Request failed."
-msgstr "요청 실패함."
+msgstr "ìš”ì²­ì— ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Request ended up in a redirect loop."
-msgstr "요청 실패. 너무 ë§Žì€ ë¦¬ë‹¤ì´ë ‰íЏ"
+msgstr "ìš”ì²­ì´ ë¦¬ë””ë ‰ì…˜ 루프로 ë났습니다."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Request failed:"
-msgstr "요청 실패함."
+msgstr "요청 실패ë¨:"
#: editor/export_template_manager.cpp
msgid "Download complete; extracting templates..."
-msgstr ""
+msgstr "다운로드를 완료하여 í…œí”Œë¦¿ì„ ì••ì¶• í•´ì œ 중..."
#: editor/export_template_manager.cpp
msgid "Cannot remove temporary file:"
-msgstr "임시 파ì¼ì„ 저장할 수 ì—†ìŒ:"
+msgstr "임시 파ì¼ì„ 삭제할 수 ì—†ìŒ:"
#: editor/export_template_manager.cpp
msgid ""
@@ -3691,7 +3704,7 @@ msgstr "미러 목ë¡ì˜ JSON 구문 ë¶„ì„ ì¤‘ 오류. ì´ ë¬¸ì œë¥¼ ì‹ ê³ í•´ì
#: editor/export_template_manager.cpp
msgid "Best available mirror"
-msgstr ""
+msgstr "최ìƒì˜ 사용 가능한 미러"
#: editor/export_template_manager.cpp
msgid ""
@@ -3807,17 +3820,26 @@ msgstr ""
#: editor/export_template_manager.cpp
msgid "Uninstall"
-msgstr "삭제"
+msgstr "제거"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Uninstall templates for the current version."
-msgstr "ì¹´ìš´í„°ì˜ ì´ˆê¸° ê°’"
+msgstr "현재 ë²„ì „ì„ ìœ„í•œ í…œí”Œë¦¿ì„ ì œê±°í•©ë‹ˆë‹¤."
#: editor/export_template_manager.cpp
#, fuzzy
msgid "Download from:"
-msgstr "다운로드 오류"
+msgstr "ë‹¤ìŒ ìœ„ì¹˜ì—서 다운로드:"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "브ë¼ìš°ì €ì—서 실행"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "복사 오류"
#: editor/export_template_manager.cpp
msgid "Download and Install"
@@ -3839,9 +3861,8 @@ msgid "Install from File"
msgstr "파ì¼ì—서 설치"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Install templates from a local file."
-msgstr "ZIP 파ì¼ì—서 템플릿 가져오기"
+msgstr "로컬 파ì¼ë¡œë¶€í„° í…œí”Œë¦¿ì„ ì„¤ì¹˜í•©ë‹ˆë‹¤."
#: editor/export_template_manager.cpp editor/find_in_files.cpp
#: editor/progress_dialog.cpp scene/gui/dialogs.cpp
@@ -3859,9 +3880,8 @@ msgid "Other Installed Versions:"
msgstr "ì„¤ì¹˜ëœ ë²„ì „:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Uninstall Template"
-msgstr "삭제"
+msgstr "템플릿 제거"
#: editor/export_template_manager.cpp
msgid "Select Template File"
@@ -4401,9 +4421,8 @@ msgid "Save As..."
msgstr "다른 ì´ë¦„으로 저장..."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Extra resource options."
-msgstr "리소스 ê²½ë¡œì— ì—†ìŠµë‹ˆë‹¤."
+msgstr "별ë„ì˜ ë¦¬ì†ŒìŠ¤ 옵션."
#: editor/inspector_dock.cpp
#, fuzzy
@@ -4432,13 +4451,12 @@ msgid "History of recently edited objects."
msgstr "ìµœê·¼ì— íŽ¸ì§‘í•œ ê°ì²´ 기ë¡ìž…니다."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Open documentation for this object."
-msgstr "문서 열기"
+msgstr "ì´ ê°ì²´ë¥¼ 위한 설명문서를 엽니다."
#: editor/inspector_dock.cpp editor/scene_tree_dock.cpp
msgid "Open Documentation"
-msgstr "문서 열기"
+msgstr "설명문서 열기"
#: editor/inspector_dock.cpp
msgid "Filter properties"
@@ -4690,9 +4708,8 @@ msgid "Blend:"
msgstr "혼합:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Parameter Changed:"
-msgstr "매개변수 변경ë¨"
+msgstr "매개변수 변경ë¨:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
@@ -5526,7 +5543,7 @@ msgstr "미리 보기"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Configure Snap"
-msgstr "스냅 설정"
+msgstr "스냅 구성"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Grid Offset:"
@@ -5802,27 +5819,22 @@ msgstr "모드 ì„ íƒ"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Drag: Rotate selected node around pivot."
-msgstr "ì„ íƒí•œ 노드나 ì „í™˜ì„ ì‚­ì œí•©ë‹ˆë‹¤."
+msgstr "드래그: 피벗 ì£¼ìœ„ì— ì„ íƒëœ 노드를 회전합니다."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Alt+Drag: Move selected node."
-msgstr "Alt+드래그: ì´ë™"
+msgstr "Alt+드래그: ì„ íƒëœ 노드를 ì´ë™í•©ë‹ˆë‹¤."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "V: Set selected node's pivot position."
-msgstr "ì„ íƒí•œ 노드나 ì „í™˜ì„ ì‚­ì œí•©ë‹ˆë‹¤."
+msgstr "V: ì„ íƒëœ ë…¸ë“œì˜ í”¼ë²— 위치를 설정합니다."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Alt+RMB: Show list of all nodes at position clicked, including locked."
msgstr ""
-"í´ë¦­í•œ ìœ„ì¹˜ì— ìžˆëŠ” 모든 ê°ì²´ 목ë¡ì„ 보여줘요\n"
-"(ì„ íƒ ëª¨ë“œì—서 Alt+ìš°í´ë¦­ê³¼ ê°™ìŒ)."
+"Alt+ìš°í´ë¦­: í´ë¦­ëœ ìœ„ì¹˜ì— ìžˆëŠ” ìž ê¸ˆì„ í¬í•¨í•œ 모든 ë…¸ë“œì˜ ëª©ë¡ì„ ë³´ì—¬ì¤ë‹ˆë‹¤."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "RMB: Add node at position clicked."
@@ -5831,12 +5843,12 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Move Mode"
-msgstr "ì´ë™ëª¨ë“œ"
+msgstr "ì´ë™ 모드"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotate Mode"
-msgstr "회전모드"
+msgstr "회전 모드"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5866,7 +5878,7 @@ msgstr "ìž ëª¨ë“œ"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Toggle smart snapping."
-msgstr "스마트 스냅 토글."
+msgstr "스마트 ìŠ¤ëƒ…ì„ í† ê¸€í•©ë‹ˆë‹¤."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Smart Snap"
@@ -5874,7 +5886,7 @@ msgstr "스마트 스냅 사용"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Toggle grid snapping."
-msgstr "ê²©ìž ìŠ¤ëƒ… 토글."
+msgstr "ê²©ìž ìŠ¤ëƒ…ì„ í† ê¸€í•©ë‹ˆë‹¤."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Grid Snap"
@@ -5907,7 +5919,7 @@ msgstr "스마트 스냅"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Configure Snap..."
-msgstr "스냅 설정..."
+msgstr "스냅 구성..."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Parent"
@@ -6410,9 +6422,8 @@ msgid "No mesh to debug."
msgstr "디버그할 메시가 없습니다."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Mesh has no UV in layer %d."
-msgstr "ì´ ë ˆì´ì–´ì—서 모ë¸ì€ UVê°€ 없습니다"
+msgstr "ë ˆì´ì–´ %dì—서 ë©”ì‹œì— UVê°€ 없습니다."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "MeshInstance lacks a Mesh!"
@@ -7068,7 +7079,7 @@ msgstr "ê²©ìž ë³´ì´ê¸°"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Configure Grid:"
-msgstr "ê²©ìž ì„¤ì •:"
+msgstr "ê²©ìž êµ¬ì„±:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid Offset X:"
@@ -7146,14 +7157,12 @@ msgid "Flip Portals"
msgstr "수í‰ìœ¼ë¡œ 뒤집기"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Room Generate Points"
-msgstr "ìƒì„±í•œ ì  ê°œìˆ˜:"
+msgstr "ë°© ìƒì„±í•œ ì  ê°œìˆ˜"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Generate Points"
-msgstr "ìƒì„±í•œ ì  ê°œìˆ˜:"
+msgstr "ìƒì„±í•œ ì  ê°œìˆ˜"
#: editor/plugins/room_manager_editor_plugin.cpp
#, fuzzy
@@ -7402,11 +7411,11 @@ msgstr "온ë¼ì¸ 문서"
#: editor/plugins/script_editor_plugin.cpp
msgid "Open Godot online documentation."
-msgstr "Godot 온ë¼ì¸ 문서를 엽니다."
+msgstr "Godot 온ë¼ì¸ 설명문서를 엽니다."
#: editor/plugins/script_editor_plugin.cpp
msgid "Search the reference documentation."
-msgstr "참조 문서를 검색합니다."
+msgstr "참조 설명문서를 검색합니다."
#: editor/plugins/script_editor_plugin.cpp
msgid "Go to previous edited document."
@@ -7607,7 +7616,7 @@ msgstr "ì´ì „ ë¶ë§ˆí¬ë¡œ ì´ë™"
#: editor/plugins/script_text_editor.cpp
msgid "Remove All Bookmarks"
-msgstr "모든 ë¶ë§ˆí¬ 제거"
+msgstr "모든 ë¶ë§ˆí¬ ì‚­ì œ"
#: editor/plugins/script_text_editor.cpp
msgid "Go to Function..."
@@ -7624,7 +7633,7 @@ msgstr "ì¤‘ë‹¨ì  í† ê¸€"
#: editor/plugins/script_text_editor.cpp
msgid "Remove All Breakpoints"
-msgstr "ì¤‘ë‹¨ì  ëª¨ë‘ ì œê±°"
+msgstr "모든 ì¤‘ë‹¨ì  ì‚­ì œ"
#: editor/plugins/script_text_editor.cpp
msgid "Go to Next Breakpoint"
@@ -7721,20 +7730,17 @@ msgid "None"
msgstr "ì—†ìŒ"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Rotate"
-msgstr "주(State)"
+msgstr "회전"
#. TRANSLATORS: This refers to the movement that changes the position of an object.
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Translate"
-msgstr "ì´ë™:"
+msgstr "ì´ë™"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Scale"
-msgstr "í¬ê¸°:"
+msgstr "í¬ê¸°"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scaling: "
@@ -7757,48 +7763,40 @@ msgid "Animation Key Inserted."
msgstr "애니메ì´ì…˜ 키를 삽입했습니다."
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Pitch:"
-msgstr "피치"
+msgstr "피치:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Yaw:"
msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size:"
-msgstr "í¬ê¸°: "
+msgstr "í¬ê¸°:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Objects Drawn:"
-msgstr "그려진 ê°ì²´"
+msgstr "그려진 ê°ì²´:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Material Changes:"
-msgstr "머티리얼 바꾸기"
+msgstr "머티리얼 바꾸기:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Shader Changes:"
-msgstr "ì…°ì´ë” 바꾸기"
+msgstr "ì…°ì´ë” 바꾸기:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Surface Changes:"
-msgstr "표면 바꾸기"
+msgstr "표면 바꾸기:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Draw Calls:"
-msgstr "드로우 콜"
+msgstr "드로우 콜:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Vertices:"
-msgstr "ì "
+msgstr "ì •ì :"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "FPS: %d (%s ms)"
@@ -8459,71 +8457,63 @@ msgstr "ìŠ¤íƒ€ì¼ ë°•ìŠ¤"
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} color(s)"
-msgstr ""
+msgstr "{num}색"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No colors found."
-msgstr "하위 리소스를 ì°¾ì„ ìˆ˜ 없습니다."
+msgstr "ìƒ‰ì„ ì°¾ì„ ìˆ˜ 없습니다."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "{num} constant(s)"
-msgstr "ìƒìˆ˜"
+msgstr "ìƒìˆ˜ {num}ê°œ"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No constants found."
-msgstr "ìƒ‰ìƒ ìƒìˆ˜."
+msgstr "ìƒìˆ˜ë¥¼ ì°¾ì„ ìˆ˜ 없습니다."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} font(s)"
-msgstr ""
+msgstr "글꼴 {num}개"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No fonts found."
-msgstr "ì°¾ì„ ìˆ˜ ì—†ìŒ!"
+msgstr "ê¸€ê¼´ì„ ì°¾ì„ ìˆ˜ 없습니다."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} icon(s)"
-msgstr ""
+msgstr "ì•„ì´ì½˜ {num}ê°œ"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No icons found."
-msgstr "ì°¾ì„ ìˆ˜ ì—†ìŒ!"
+msgstr "ì•„ì´ì½˜ì„ ì°¾ì„ ìˆ˜ 없습니다."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} stylebox(es)"
-msgstr ""
+msgstr "스타ì¼ë°•스 {num}ê°œ"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No styleboxes found."
-msgstr "하위 리소스를 ì°¾ì„ ìˆ˜ 없습니다."
+msgstr "스타ì¼ë°•스를 ì°¾ì„ ìˆ˜ 없습니다."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} currently selected"
-msgstr ""
+msgstr "현재 ì„ íƒ {num}ê°œ"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Nothing was selected for the import."
-msgstr ""
+msgstr "가져올 ê²ƒì´ ì„ íƒë˜ì§€ 않았습니다."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Importing Theme Items"
-msgstr "테마 가져오기"
+msgstr "테마 í•­ëª©ì„ ê°€ì ¸ì˜¤ëŠ” 중"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Importing items {n}/{n}"
-msgstr ""
+msgstr "항목 {n}/{n} 가져오는 중"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Updating the editor"
-msgstr "편집기를 ëŒê¹Œìš”?"
+msgstr "편집기를 ì—…ë°ì´íЏ 중"
#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
@@ -8531,18 +8521,16 @@ msgid "Finalizing"
msgstr "ë¶„ì„ ì¤‘"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Filter:"
-msgstr "í•„í„°: "
+msgstr "í•„í„°:"
#: editor/plugins/theme_editor_plugin.cpp
msgid "With Data"
-msgstr ""
+msgstr "ë°ì´í„°ì™€ 함께"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select by data type:"
-msgstr "노드를 ì„ íƒí•˜ì„¸ìš”"
+msgstr "ë°ì´í„° 유형 별 ì„ íƒ:"
#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
@@ -8558,9 +8546,8 @@ msgid "Deselect all visible color items."
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible constant items."
-msgstr "먼저 설정 í•­ëª©ì„ ì„ íƒí•˜ì„¸ìš”!"
+msgstr "ë³´ì´ëŠ” 모든 ìƒìˆ˜ í•­ëª©ì„ ì„ íƒí•©ë‹ˆë‹¤."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible constant items and their data."
@@ -8571,9 +8558,8 @@ msgid "Deselect all visible constant items."
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible font items."
-msgstr "먼저 설정 í•­ëª©ì„ ì„ íƒí•˜ì„¸ìš”!"
+msgstr "ë³´ì´ëŠ” 모든 글꼴 í•­ëª©ì„ ì„ íƒí•©ë‹ˆë‹¤."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible font items and their data."
@@ -8584,19 +8570,16 @@ msgid "Deselect all visible font items."
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible icon items."
-msgstr "먼저 설정 í•­ëª©ì„ ì„ íƒí•˜ì„¸ìš”!"
+msgstr "ë³´ì´ëŠ” 모든 ì•„ì´ì½˜ í•­ëª©ì„ ì„ íƒí•©ë‹ˆë‹¤."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible icon items and their data."
-msgstr "먼저 설정 í•­ëª©ì„ ì„ íƒí•˜ì„¸ìš”!"
+msgstr "ë³´ì´ëŠ” 모든 ì•„ì´ì½˜ 항목과 ê·¸ í•­ëª©ì˜ ë°ì´í„°ë¥¼ ì„ íƒí•©ë‹ˆë‹¤."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Deselect all visible icon items."
-msgstr "먼저 설정 í•­ëª©ì„ ì„ íƒí•˜ì„¸ìš”!"
+msgstr "ë³´ì´ëŠ” 모든 ì•„ì´ì½˜ í•­ëª©ì„ ì„ íƒ í•´ì œí•©ë‹ˆë‹¤."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible stylebox items."
@@ -8617,19 +8600,16 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Collapse types."
-msgstr "ëª¨ë‘ ì ‘ê¸°"
+msgstr "ìœ í˜•ì„ ì ‘ìŠµë‹ˆë‹¤."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Expand types."
-msgstr "ëª¨ë‘ íŽ¼ì¹˜ê¸°"
+msgstr "ìœ í˜•ì„ íŽ¼ì¹©ë‹ˆë‹¤."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all Theme items."
-msgstr "템플릿 íŒŒì¼ ì„ íƒ"
+msgstr "모든 테마 í•­ëª©ì„ ì„ íƒí•©ë‹ˆë‹¤."
#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
@@ -8662,6 +8642,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "모든 항목 삭제"
@@ -8692,6 +8678,12 @@ msgid "Remove All StyleBox Items"
msgstr "모든 항목 삭제"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "í´ëž˜ìФ 항목 추가"
@@ -8771,9 +8763,8 @@ msgid "Add Type:"
msgstr "유형:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Item:"
-msgstr "항목 추가"
+msgstr "항목 추가:"
#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
@@ -8781,9 +8772,8 @@ msgid "Add StyleBox Item"
msgstr "모든 항목 추가"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove Items:"
-msgstr "항목 삭제"
+msgstr "항목 삭제:"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove Class Items"
@@ -8824,9 +8814,8 @@ msgid "Editor Theme"
msgstr "테마 편집"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select Another Theme Resource:"
-msgstr "리소스 삭제"
+msgstr "다른 테마 리소스 ì„ íƒ:"
#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
@@ -8869,9 +8858,8 @@ msgid "Add Item Type"
msgstr "항목 추가"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Node Types:"
-msgstr "노드 유형"
+msgstr "노드 유형:"
#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
@@ -8892,9 +8880,8 @@ msgid "Override all default type items."
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Theme:"
-msgstr "테마"
+msgstr "테마:"
#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
@@ -8959,9 +8946,8 @@ msgid "Checked Radio Item"
msgstr "ì²´í¬ëœ ë¼ë””오 항목"
#: editor/plugins/theme_editor_preview.cpp
-#, fuzzy
msgid "Named Separator"
-msgstr "ì´ë¦„있는 구분ìž."
+msgstr "ì´ë¦„ 있는 구분ìž"
#: editor/plugins/theme_editor_preview.cpp
msgid "Submenu"
@@ -9135,7 +9121,7 @@ msgstr "TileSetì— í…스처를 추가합니다."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Remove selected Texture from TileSet."
-msgstr "ì„ íƒí•œ í…스처를 TileSetì—서 제거합니다."
+msgstr "ì„ íƒëœ í…스처를 TileSetì—서 삭제합니다."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create from Scene"
@@ -10399,9 +10385,8 @@ msgid "VisualShader"
msgstr "비주얼 ì…°ì´ë”"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Edit Visual Property:"
-msgstr "비주얼 ì†ì„± 편집"
+msgstr "비주얼 ì†ì„± 편집:"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Visual Shader Mode Changed"
@@ -10844,14 +10829,12 @@ msgid "Are you sure to run %d projects at once?"
msgstr "한 ë²ˆì— %dê°œì˜ í”„ë¡œì íŠ¸ë¥¼ 실행할 건가요?"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove %d projects from the list?"
-msgstr "목ë¡ì—서 기기 ì„ íƒ"
+msgstr "목ë¡ì—서 프로ì íЏ %d개를 삭제하시겠습니까?"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove this project from the list?"
-msgstr "목ë¡ì—서 기기 ì„ íƒ"
+msgstr "목ë¡ì—서 ì´ í”„ë¡œì íŠ¸ë¥¼ 삭제하시겠습니까?"
#: editor/project_manager.cpp
msgid ""
@@ -12312,6 +12295,16 @@ msgstr "ìº¡ìŠ ëª¨ì–‘ ë†’ì´ ë°”ê¾¸ê¸°"
msgid "Change Ray Shape Length"
msgstr "ê´‘ì„  모양 ê¸¸ì´ ë°”ê¾¸ê¸°"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "곡선 ì  ìœ„ì¹˜ 설정"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "곡선 ì  ìœ„ì¹˜ 설정"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "ì›ê¸°ë‘¥ 반지름 바꾸기"
@@ -13109,17 +13102,15 @@ msgstr "목ë¡ì—서 기기 ì„ íƒ"
#: platform/android/export/export.cpp
msgid "Running on %s"
-msgstr ""
+msgstr "%sì—서 실행"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Exporting APK..."
-msgstr "ëª¨ë‘ ë‚´ë³´ë‚´ê¸°"
+msgstr "APK로 내보내는 중..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Uninstalling..."
-msgstr "삭제"
+msgstr "제거 중..."
#: platform/android/export/export.cpp
#, fuzzy
@@ -13127,14 +13118,12 @@ msgid "Installing to device, please wait..."
msgstr "로드 중, 기다려 주세요..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not install to device: %s"
-msgstr "ì”¬ì„ ì¸ìŠ¤í„´ìŠ¤ í•  수 없습니다!"
+msgstr "ê¸°ê¸°ì— ì„¤ì¹˜í•  수 ì—†ìŒ: %s"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Running on device..."
-msgstr "맞춤 스í¬ë¦½íЏ 실행 중..."
+msgstr "기기ì—서 실행 중..."
#: platform/android/export/export.cpp
#, fuzzy
@@ -13163,7 +13152,7 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
-msgstr "Debug keystore를 편집기 설정과 í”„ë¦¬ì…‹ì— ì„¤ì •í•˜ì§€ 않았습니다."
+msgstr "Debug keystore를 편집기 설정과 í”„ë¦¬ì…‹ì— êµ¬ì„±í•˜ì§€ 않았습니다."
#: platform/android/export/export.cpp
msgid ""
@@ -13175,7 +13164,7 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
-msgstr "내보내기 í”„ë¦¬ì…‹ì— ë°°í¬ keystorkeê°€ 잘못 설정ë˜ì–´ 있습니다."
+msgstr "내보내기 í”„ë¦¬ì…‹ì— ì¶œì‹œ keystorkeê°€ 잘못 구성ë˜ì–´ 있습니다."
#: platform/android/export/export.cpp
msgid "A valid Android SDK path is required in Editor Settings."
@@ -13187,7 +13176,7 @@ msgstr "편집기 설정ì—서 ìž˜ëª»ëœ Android SDK 경로입니다."
#: platform/android/export/export.cpp
msgid "Missing 'platform-tools' directory!"
-msgstr "'platform-tools' 디렉터리가 없습니다!"
+msgstr "'platform-tools' 디렉토리가 없습니다!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK platform-tools' adb command."
@@ -13195,11 +13184,11 @@ msgstr "Android SDK platform-toolsì˜ adb ëª…ë ¹ì„ ì°¾ì„ ìˆ˜ 없습니다."
#: platform/android/export/export.cpp
msgid "Please check in the Android SDK directory specified in Editor Settings."
-msgstr "편집기 설정ì—서 ì§€ì •ëœ Android SDK 디렉터리를 확ì¸í•´ì£¼ì„¸ìš”."
+msgstr "편집기 설정ì—서 ì§€ì •ëœ Android SDK 디렉토리를 확ì¸í•´ì£¼ì„¸ìš”."
#: platform/android/export/export.cpp
msgid "Missing 'build-tools' directory!"
-msgstr "'build-tools' 디렉터리가 없습니다!"
+msgstr "'build-tools' 디렉토리가 없습니다!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK build-tools' apksigner command."
@@ -13263,16 +13252,12 @@ msgid "Signing debug %s..."
msgstr ""
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Signing release %s..."
-msgstr ""
-"íŒŒì¼ ìŠ¤ìº”ì¤‘.\n"
-"기다려주십시오..."
+msgstr "출시 %sì— ì„œëª… 중..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not find keystore, unable to export."
-msgstr "내보내기 í…œí”Œë¦¿ì„ ì—´ 수 ì—†ìŒ:"
+msgstr "keystore를 ì°¾ì„ ìˆ˜ 없어, 내보낼 수 없었습니다."
#: platform/android/export/export.cpp
msgid "'apksigner' returned with error #%d"
@@ -13288,9 +13273,8 @@ msgid "'apksigner' verification of %s failed."
msgstr ""
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Exporting for Android"
-msgstr "ëª¨ë‘ ë‚´ë³´ë‚´ê¸°"
+msgstr "Android용으로 내보내는 중"
#: platform/android/export/export.cpp
msgid "Invalid filename! Android App Bundle requires the *.aab extension."
@@ -13334,14 +13318,12 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not export project files to gradle project\n"
-msgstr "프로ì íЏ ê²½ë¡œì— project.godot 파ì¼ì„ ì°¾ì„ ìˆ˜ 없습니다."
+msgstr "프로ì íЏ 파ì¼ì„ gradle 프로ì íŠ¸ë¡œ 내보낼 수 없었습니다\n"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not write expansion package file!"
-msgstr "파ì¼ì— 쓸 수 ì—†ìŒ:"
+msgstr "확장 패키지 파ì¼ì„ 쓸 수 없었습니다!"
#: platform/android/export/export.cpp
msgid "Building Android Project (gradle)"
@@ -13353,7 +13335,7 @@ msgid ""
"Alternatively visit docs.godotengine.org for Android build documentation."
msgstr ""
"Android 프로ì íŠ¸ì˜ ë¹Œë“œì— ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤, ì¶œë ¥ëœ ì˜¤ë¥˜ë¥¼ 확ì¸í•˜ì„¸ìš”.\n"
-"ë˜ëŠ” docs.godotengine.orgì—서 Andoid 빌드 문서를 찾아보세요."
+"ë˜ëŠ” docs.godotengine.orgì—서 Android 빌드 설명문서를 찾아보세요."
#: platform/android/export/export.cpp
msgid "Moving output"
@@ -13365,7 +13347,7 @@ msgid ""
"outputs."
msgstr ""
"내보내기 파ì¼ì„ 복사하고 ì´ë¦„ì„ ë°”ê¿€ 수 없습니다, ì¶œë ¥ì— ëŒ€í•œ gradle 프로ì "
-"트 디렉터리를 확ì¸í•˜ì„¸ìš”."
+"트 디렉토리를 확ì¸í•˜ì„¸ìš”."
#: platform/android/export/export.cpp
#, fuzzy
@@ -13373,16 +13355,16 @@ msgid "Package not found: %s"
msgstr "애니메ì´ì…˜ì„ ì°¾ì„ ìˆ˜ ì—†ìŒ: '%s'"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Creating APK..."
-msgstr "윤곽선 만드는 중..."
+msgstr "APK를 만드는 중..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid ""
"Could not find template APK to export:\n"
"%s"
-msgstr "내보내기 í…œí”Œë¦¿ì„ ì—´ 수 ì—†ìŒ:"
+msgstr ""
+"내보낼 템플릿 APK를 ì°¾ì„ ìˆ˜ ì—†ìŒ:\n"
+"%s"
#: platform/android/export/export.cpp
msgid ""
@@ -13393,14 +13375,12 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Adding files..."
-msgstr "%s 추가하는 중..."
+msgstr "파ì¼ì„ 추가하는 중..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not export project files"
-msgstr "파ì¼ì— 쓸 수 ì—†ìŒ:"
+msgstr "프로ì íЏ 파ì¼ì„ 내보낼 수 없었습니다"
#: platform/android/export/export.cpp
msgid "Aligning APK..."
@@ -13455,29 +13435,24 @@ msgid "Could not write file:"
msgstr "파ì¼ì— 쓸 수 ì—†ìŒ:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not read file:"
-msgstr "파ì¼ì— 쓸 수 ì—†ìŒ:"
+msgstr "파ì¼ì„ ì½ì„ 수 ì—†ìŒ:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not read HTML shell:"
-msgstr "맞춤 HTML shellì„ ì½ì„ 수 ì—†ìŒ:"
+msgstr "HTML shellì„ ì½ì„ 수 ì—†ìŒ:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not create HTTP server directory:"
-msgstr "í´ë”를 만들 수 없습니다."
+msgstr "HTTP 서버 디렉토리를 만들 수 ì—†ìŒ:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Error starting HTTP server:"
-msgstr "씬 저장 중 오류."
+msgstr "HTTP 서버를 시작하는 중 오류:"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Invalid bundle identifier:"
-msgstr "ìž˜ëª»ëœ ì‹ë³„ìž:"
+msgstr "ìž˜ëª»ëœ bundle ì‹ë³„ìž:"
#: platform/osx/export/export.cpp
msgid "Notarization: code signing required."
@@ -14052,6 +14027,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr "ì´ ë°”ë””ëŠ” 메시를 설정할 때까지 무시ë©ë‹ˆë‹¤."
@@ -14158,7 +14169,7 @@ msgid ""
msgstr ""
"색ìƒ: #%s\n"
"좌í´ë¦­: ìƒ‰ìƒ ì„¤ì •\n"
-"ìš°í´ë¦­: 프리셋 제거"
+"ìš°í´ë¦­: 프리셋 ì‚­ì œ"
#: scene/gui/color_picker.cpp
msgid "Pick a color from the editor window."
@@ -15474,9 +15485,6 @@ msgstr "ìƒìˆ˜ëŠ” 수정할 수 없습니다."
#~ msgid "I see..."
#~ msgstr "알겠습니다..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "'%s' 열수 ì—†ìŒ."
-
#~ msgid "Ugh"
#~ msgstr "오우"
diff --git a/editor/translations/lt.po b/editor/translations/lt.po
index ab98c9b156..f8bc356023 100644
--- a/editor/translations/lt.po
+++ b/editor/translations/lt.po
@@ -349,6 +349,7 @@ msgstr "Keiskite animacijos ciklo režimą"
msgid "Remove Anim Track"
msgstr "Animacija: panaikinti įrašą"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr ""
@@ -373,10 +374,26 @@ msgstr "Sukurti"
msgid "Anim Insert"
msgstr "Animacija: įterpti"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animacija"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr ""
@@ -962,7 +979,7 @@ msgstr "Sukurti NaujÄ…"
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2288,6 +2305,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3079,10 +3107,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr ""
@@ -3710,6 +3734,15 @@ msgid "Download from:"
msgstr "Atsisiuntimo Klaida"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Atidaryti"
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8555,6 +8588,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "MÄ—gstamiausi:"
@@ -8583,6 +8622,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "MÄ—gstamiausi:"
@@ -12121,6 +12166,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13758,6 +13811,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/lv.po b/editor/translations/lv.po
index 3c6ab5cb19..180cd1be1c 100644
--- a/editor/translations/lv.po
+++ b/editor/translations/lv.po
@@ -344,6 +344,7 @@ msgstr "IzmainÄ«t AnimÄcijas AtkÄrtoÅ¡anÄs Režīmu"
msgid "Remove Anim Track"
msgstr "Noņemt Anim. Celiņu"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Izveidot JAUNU celiņu priekš %s un ievietot atslēgievietni?"
@@ -368,10 +369,26 @@ msgstr "Izveidot"
msgid "Anim Insert"
msgstr "Anim ievietot"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Funkcijas:"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "AnimationPlayer nevar animÄ“t pats sevi, tikai citus spÄ“lÄ“tÄjus."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Anim Izveidot un Ievietot"
@@ -950,7 +967,7 @@ msgstr "Izveidot Jaunu %s"
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2270,6 +2287,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3051,10 +3079,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "NepÄrtraukti Atjaunot"
@@ -3665,6 +3689,15 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "AtvÄ“rt Failu PÄrlÅ«kÄ"
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8410,6 +8443,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Noņemt no Favorītiem"
@@ -8438,6 +8477,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Pievienot Favorītiem"
@@ -11935,6 +11980,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13556,6 +13609,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/mi.po b/editor/translations/mi.po
index 021c55f38b..3a70aade1a 100644
--- a/editor/translations/mi.po
+++ b/editor/translations/mi.po
@@ -329,6 +329,7 @@ msgstr ""
msgid "Remove Anim Track"
msgstr ""
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr ""
@@ -353,10 +354,25 @@ msgstr ""
msgid "Anim Insert"
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "animation"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr ""
@@ -911,7 +927,7 @@ msgstr ""
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2202,6 +2218,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -2981,10 +3008,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr ""
@@ -3589,6 +3612,14 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+msgid "Open in Web Browser"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8266,6 +8297,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Color Items"
msgstr ""
@@ -8290,6 +8327,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
msgstr ""
@@ -11697,6 +11740,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13291,6 +13342,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/mk.po b/editor/translations/mk.po
index a437ddf1c7..bf449381bb 100644
--- a/editor/translations/mk.po
+++ b/editor/translations/mk.po
@@ -336,6 +336,7 @@ msgstr ""
msgid "Remove Anim Track"
msgstr ""
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr ""
@@ -360,10 +361,25 @@ msgstr ""
msgid "Anim Insert"
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "animation"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr ""
@@ -918,7 +934,7 @@ msgstr ""
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2210,6 +2226,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -2989,10 +3016,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr ""
@@ -3598,6 +3621,14 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+msgid "Open in Web Browser"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8281,6 +8312,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Color Items"
msgstr ""
@@ -8305,6 +8342,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
msgstr ""
@@ -11712,6 +11755,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13306,6 +13357,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/ml.po b/editor/translations/ml.po
index 8213c2251c..b0d3a5a8d7 100644
--- a/editor/translations/ml.po
+++ b/editor/translations/ml.po
@@ -339,6 +339,7 @@ msgstr ""
msgid "Remove Anim Track"
msgstr ""
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr ""
@@ -363,10 +364,27 @@ msgstr ""
msgid "Anim Insert"
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "ചലനം à´šàµà´±àµà´±àµ½"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "à´—àµà´£à´‚ നോകàµà´•àµà´•"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr ""
@@ -921,7 +939,7 @@ msgstr ""
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2215,6 +2233,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -2994,10 +3023,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr ""
@@ -3602,6 +3627,14 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+msgid "Open in Web Browser"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8287,6 +8320,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Color Items"
msgstr ""
@@ -8311,6 +8350,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
msgstr ""
@@ -11719,6 +11764,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13315,6 +13368,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/mr.po b/editor/translations/mr.po
index b459ca23f3..af59635c8a 100644
--- a/editor/translations/mr.po
+++ b/editor/translations/mr.po
@@ -336,6 +336,7 @@ msgstr ""
msgid "Remove Anim Track"
msgstr ""
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr ""
@@ -360,10 +361,26 @@ msgstr ""
msgid "Anim Insert"
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "अâ€à¥…निमेशन टà¥à¤°à¥€"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr ""
@@ -918,7 +935,7 @@ msgstr ""
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2209,6 +2226,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -2989,10 +3017,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr ""
@@ -3597,6 +3621,14 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+msgid "Open in Web Browser"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8279,6 +8311,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Color Items"
msgstr ""
@@ -8303,6 +8341,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
msgstr ""
@@ -11713,6 +11757,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13308,6 +13360,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/ms.po b/editor/translations/ms.po
index 51a09d2e24..5fd2547bcb 100644
--- a/editor/translations/ms.po
+++ b/editor/translations/ms.po
@@ -344,6 +344,7 @@ msgstr "Tukar Mod Gelung Animasi"
msgid "Remove Anim Track"
msgstr "Keluarkan Trek Anim"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Cipta trek BARU untuk %s dan masukkan kunci?"
@@ -368,10 +369,27 @@ msgstr "Cipta"
msgid "Anim Insert"
msgstr "Masukkan Anim"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Set Peralihan ke:"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "AnimationPlayer tidak animasikan dirinya sendiri, hanya pemain lain."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Sifat"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Anim Cipta & Masukkan"
@@ -950,7 +968,7 @@ msgstr "Cipta %s Baru"
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2302,6 +2320,17 @@ msgid "New Window"
msgstr "Tetingkap Baru"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Berputar apabila tingkap editor dilukis semula."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Sumber yang diimport tidak dapat disimpan."
@@ -3165,10 +3194,6 @@ msgid "Save & Restart"
msgstr "Simpan & Mula Semula"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Berputar apabila tingkap editor dilukis semula."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Kemas Kini Secara Berterusan"
@@ -3828,6 +3853,15 @@ msgid "Download from:"
msgstr "Muat turun"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Buka dalam Pengurus Fail"
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8593,6 +8627,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Keluarkan Item"
@@ -8623,6 +8663,12 @@ msgid "Remove All StyleBox Items"
msgstr "Keluarkan Item"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Tambah ke Kegemaran"
@@ -12087,6 +12133,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13712,6 +13766,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/nb.po b/editor/translations/nb.po
index efbca6253d..02f32b055b 100644
--- a/editor/translations/nb.po
+++ b/editor/translations/nb.po
@@ -353,6 +353,7 @@ msgstr "Endre løkkemodus for animasjon"
msgid "Remove Anim Track"
msgstr "Fjern Anim-Spor"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Lag NYTT spor for %s og sett inn nøkkel?"
@@ -377,10 +378,28 @@ msgstr "Lag"
msgid "Anim Insert"
msgstr "Anim Sett inn"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "Kan ikke åpne '%s'."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animasjon"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "AnimasjonAvspiller kan ikke animere seg selv, kun andre avspillere."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Egenskapen «%s» eksisterer ikke."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Anim Lag og Sett Inn"
@@ -971,7 +990,7 @@ msgstr "Lag ny %s"
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2384,6 +2403,17 @@ msgid "New Window"
msgstr "Nytt vindu"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Snurrer når redigeringsvinduet tegner opp på nytt."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Importerte ressurser kan ikke lagres."
@@ -3260,10 +3290,6 @@ msgid "Save & Restart"
msgstr "Lagre & Avslutt"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Snurrer når redigeringsvinduet tegner opp på nytt."
-
-#: editor/editor_node.cpp
#, fuzzy
msgid "Update Continuously"
msgstr "Kontinuerlig"
@@ -3931,6 +3957,16 @@ msgid "Download from:"
msgstr "Nedlastningsfeil"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Vis I Filutforsker"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Kopier feil"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8990,6 +9026,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Fjern Funksjon"
@@ -9020,6 +9062,12 @@ msgid "Remove All StyleBox Items"
msgstr "Fjern Funksjon"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Legg til Element"
@@ -12688,6 +12736,16 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Fjern Funksjon"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Fjern Funksjon"
+
#: modules/csg/csg_gizmos.cpp
#, fuzzy
msgid "Change Cylinder Radius"
@@ -14382,6 +14440,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
@@ -15259,9 +15353,6 @@ msgstr "Konstanter kan ikke endres."
#~ msgid "I see..."
#~ msgstr "Jeg forstår..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "Kan ikke åpne '%s'."
-
#~ msgid "Ugh"
#~ msgstr "Æsj"
diff --git a/editor/translations/nl.po b/editor/translations/nl.po
index 2f16b90840..00f87ef79c 100644
--- a/editor/translations/nl.po
+++ b/editor/translations/nl.po
@@ -48,12 +48,13 @@
# Arthur de Roos <arthur.de.roos@gmail.com>, 2021.
# Vancha March <tjipkevdh@gmail.com>, 2021.
# Hugo van de Kuilen <hugo.vandekuilen1234567890@gmail.com>, 2021.
+# tobeqz <vanveenjorik+tobeqz@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-08-02 02:00+0000\n"
-"Last-Translator: Hugo van de Kuilen <hugo.vandekuilen1234567890@gmail.com>\n"
+"PO-Revision-Date: 2021-08-06 19:42+0000\n"
+"Last-Translator: tobeqz <vanveenjorik+tobeqz@gmail.com>\n"
"Language-Team: Dutch <https://hosted.weblate.org/projects/godot-engine/godot/"
"nl/>\n"
"Language: nl\n"
@@ -384,6 +385,7 @@ msgstr "Animatielusmodus veranderen"
msgid "Remove Anim Track"
msgstr "Verwijder Anim Track"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "NIEUW spoor aanmaken voor %s en sleutel invoegen?"
@@ -408,10 +410,28 @@ msgstr "Maken"
msgid "Anim Insert"
msgstr "Anim Invoegen"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "Kan '%s' niet openen."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animatie"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "Animatie-Speler kan zichzelf niet animeren, alleen andere spelers."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Eigenschap '%s' bestaat niet."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Anim Maken & Invoegen"
@@ -622,9 +642,8 @@ msgid "Go to Previous Step"
msgstr "Ga naar Vorige Stap"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Apply Reset"
-msgstr "Resetten"
+msgstr "Reset"
#: editor/animation_track_editor.cpp
msgid "Optimize Animation"
@@ -643,9 +662,8 @@ msgid "Use Bezier Curves"
msgstr "Gebruik Bezier Curves"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Create RESET Track(s)"
-msgstr "Plak sporen"
+msgstr "Creëer RESET Track(s)"
#: editor/animation_track_editor.cpp
msgid "Anim. Optimizer"
@@ -992,9 +1010,9 @@ msgstr "%s opstellen"
msgid "No results for \"%s\"."
msgstr "Geen resultaten voor \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
-msgstr ""
+msgstr "Geen beschrijving beschikbaar voor %s."
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp
@@ -1094,7 +1112,6 @@ msgid "Owners Of:"
msgstr "Eigenaren van:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove the selected files from the project? (Cannot be undone.)\n"
"Depending on your filesystem configuration, the files will either be moved "
@@ -1102,11 +1119,10 @@ msgid ""
msgstr ""
"Geselecteerde bestanden uit het project verwijderen? (Kan niet ongedaan "
"gemaakt worden)\n"
-"De bestanden kunnen mogelijk vanuit de prullenbak van het systeem hersteld "
-"worden."
+"Bestanden kunnen naar de prullenbak gestuurd worden of permanent verwijderd "
+"worden, afhankelijk van uw bestandssysteem."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1117,8 +1133,8 @@ msgstr ""
"De bestanden die verwijderd worden zijn nodig om andere bronnen te laten "
"werken.\n"
"Toch verwijderen? (Onomkeerbaar)\n"
-"De bestanden kunnen mogelijk vanuit de prullenbak van het systeem hersteld "
-"worden."
+"De bestanden kunnen naar de prullenbak gestuurd worden of permanent "
+"verwijderd worden, afhankelijk van uw bestandssysteem."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1288,7 +1304,6 @@ msgid "Licenses"
msgstr "Licenties"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Error opening asset file for \"%s\" (not in ZIP format)."
msgstr "Fout bij het openen van het pakketbestand, geen zip-formaat."
@@ -1300,29 +1315,28 @@ msgstr "%s (bestaat al)"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - %d file(s) conflict with your project:"
msgstr ""
+"Inhoud van asset \"%s\" - %d bestand(en) zijn in conflict met uw project:"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - No files conflict with your project:"
msgstr ""
+"Inhoud van asset \"%s\" - Geen bestanden hebben een conflict met uw project:"
#: editor/editor_asset_installer.cpp
msgid "Uncompressing Assets"
msgstr "Bronnen aan het uitpakken"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "The following files failed extraction from asset \"%s\":"
-msgstr "De volgende bestanden konden niet worden uitgepakt:"
+msgstr "De volgende bestanden konden niet worden uitgepakt uit \"%s\":"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "(and %s more files)"
-msgstr "En nog %s bestand(en)."
+msgstr "(en nog %s bestanden)"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset \"%s\" installed successfully!"
-msgstr "Pakket succesvol geïnstalleerd!"
+msgstr "Asset \"%s\" succesvol geïnstalleerd!"
#: editor/editor_asset_installer.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -1334,9 +1348,8 @@ msgid "Install"
msgstr "Installeer"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset Installer"
-msgstr "Pakketinstalleerder"
+msgstr "Assetinstalleerder"
#: editor/editor_audio_buses.cpp
msgid "Speakers"
@@ -1399,7 +1412,6 @@ msgid "Bypass"
msgstr "Omleiden"
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "Bus Options"
msgstr "Audiobusopties"
@@ -1567,13 +1579,12 @@ msgid "Can't add autoload:"
msgstr "Autoload kan niet toevoegd worden:"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "%s is an invalid path. File does not exist."
-msgstr "Bestand bestaat niet."
+msgstr "%s is een ongeldig pad. Bestand bestaat niet."
#: editor/editor_autoload_settings.cpp
msgid "%s is an invalid path. Not in resource path (res://)."
-msgstr ""
+msgstr "%s is een ongeldig pad. Niet in bron pad (res://)."
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -1773,7 +1784,7 @@ msgstr "Importtabblad"
#: editor/editor_feature_profile.cpp
msgid "Allows to view and edit 3D scenes."
-msgstr ""
+msgstr "Laat u 3D scenes weergeven en bewerken."
#: editor/editor_feature_profile.cpp
msgid "Allows to edit scripts using the integrated script editor."
@@ -2345,6 +2356,17 @@ msgid "New Window"
msgstr "Nieuw Venster"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Draait wanneer het editor venster wordt hertekend."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Geïmporteerde bronnen kunnen niet opgeslagen worden."
@@ -3205,10 +3227,6 @@ msgid "Save & Restart"
msgstr "Opslaan & Herstarten"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Draait wanneer het editor venster wordt hertekend."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Continu Bijwerken"
@@ -3874,6 +3892,16 @@ msgid "Download from:"
msgstr "Downloadfout"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Uitvoeren in Browser"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Kopieer Fout"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8745,6 +8773,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Verwijder Alle Items"
@@ -8775,6 +8809,12 @@ msgid "Remove All StyleBox Items"
msgstr "Verwijder Alle Items"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Class Items Toevoegen"
@@ -12447,6 +12487,16 @@ msgstr "Wijzig Cylinder Vorm Hoogte"
msgid "Change Ray Shape Length"
msgstr "Wijzig Ray Vorm Lengte"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Zet Curve Punt Positie"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Zet Curve Punt Positie"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "Wijzig Cylinder Straal"
@@ -14216,6 +14266,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr "Dit lichaam zal worden genegeerd totdat je een mesh instelt."
@@ -15415,9 +15501,6 @@ msgstr "Constanten kunnen niet worden aangepast."
#~ msgid "I see..."
#~ msgstr "Ik snap het..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "Kan '%s' niet openen."
-
#~ msgid "Ugh"
#~ msgstr "Oeps"
diff --git a/editor/translations/or.po b/editor/translations/or.po
index 89cbdfbf2b..8bee62f8d5 100644
--- a/editor/translations/or.po
+++ b/editor/translations/or.po
@@ -335,6 +335,7 @@ msgstr ""
msgid "Remove Anim Track"
msgstr ""
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr ""
@@ -359,10 +360,25 @@ msgstr ""
msgid "Anim Insert"
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "animation"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr ""
@@ -917,7 +933,7 @@ msgstr ""
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2208,6 +2224,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -2987,10 +3014,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr ""
@@ -3595,6 +3618,14 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+msgid "Open in Web Browser"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8272,6 +8303,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Color Items"
msgstr ""
@@ -8296,6 +8333,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
msgstr ""
@@ -11703,6 +11746,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13297,6 +13348,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/pl.po b/editor/translations/pl.po
index edaf8ab701..24ad379ad0 100644
--- a/editor/translations/pl.po
+++ b/editor/translations/pl.po
@@ -384,6 +384,7 @@ msgstr "Zmień sposób zapętlania animacji"
msgid "Remove Anim Track"
msgstr "Usuń ścieżkę animacji"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Utworzyć NOWĄ ścieżkę dla %s i wstawić klucz?"
@@ -408,11 +409,29 @@ msgstr "Utwórz"
msgid "Anim Insert"
msgstr "Wstaw animacjÄ™"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "Nie można otworzyć '%s'."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animacja"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
"AnimationPlayer nie może animować sam siebie, tylko inne węzły tego typu."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Właściwość \"%s\" nie istnieje."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Utwórz i wstaw"
@@ -987,7 +1006,7 @@ msgstr "Utwórz nowy %s"
msgid "No results for \"%s\"."
msgstr "Brak wyników dla \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2333,6 +2352,17 @@ msgid "New Window"
msgstr "Nowe okno"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Obraca siÄ™, gdy okno edytora jest przerysowywane."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Zaimportowane zasoby nie mogą być zapisane."
@@ -3192,10 +3222,6 @@ msgid "Save & Restart"
msgstr "Zapisz i zrestartuj"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Obraca siÄ™, gdy okno edytora jest przerysowywane."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Aktualizuj ciÄ…gle"
@@ -3856,6 +3882,16 @@ msgid "Download from:"
msgstr "Błąd pobierania"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Uruchom w przeglÄ…darce"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Kopiuj błąd"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8727,6 +8763,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Usuń wszystkie elementy"
@@ -8757,6 +8799,12 @@ msgid "Remove All StyleBox Items"
msgstr "Usuń wszystkie elementy"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Dodaj klasę elementów"
@@ -12419,6 +12467,16 @@ msgstr "Zmień wysokość kształtu cylindra"
msgid "Change Ray Shape Length"
msgstr "Zmień długość Ray Shape"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Ustaw pozycje punktu krzywej"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Ustaw pozycje punktu krzywej"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "Zmień promień cylindra"
@@ -14200,6 +14258,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr "To ciało będzie ignorowane, dopóki nie ustawisz siatki."
@@ -15477,9 +15571,6 @@ msgstr "Stałe nie mogą być modyfikowane."
#~ msgid "I see..."
#~ msgstr "WidzÄ™..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "Nie można otworzyć '%s'."
-
#~ msgid "Ugh"
#~ msgstr "Błąd"
diff --git a/editor/translations/pr.po b/editor/translations/pr.po
index 1bcfe47610..96fab899cd 100644
--- a/editor/translations/pr.po
+++ b/editor/translations/pr.po
@@ -360,6 +360,7 @@ msgstr ""
msgid "Remove Anim Track"
msgstr ""
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr ""
@@ -384,10 +385,26 @@ msgstr ""
msgid "Anim Insert"
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Yer functions:"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr ""
@@ -962,7 +979,7 @@ msgstr ""
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2291,6 +2308,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3086,10 +3114,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr ""
@@ -3720,6 +3744,15 @@ msgid "Download from:"
msgstr "Discharge ye' Variable"
#: editor/export_template_manager.cpp
+msgid "Open in Web Browser"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Slit th' Node"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8562,6 +8595,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Discharge ye' Variable"
@@ -8592,6 +8631,12 @@ msgid "Remove All StyleBox Items"
msgstr "Discharge ye' Variable"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Add Node"
@@ -12150,6 +12195,16 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Discharge ye' Signal"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Discharge ye' Signal"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13820,6 +13875,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/pt.po b/editor/translations/pt.po
index e51c7a3b77..1c8e2476a3 100644
--- a/editor/translations/pt.po
+++ b/editor/translations/pt.po
@@ -23,8 +23,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-07-03 10:33+0000\n"
-"Last-Translator: André Silva <andre.olivais@gmail.com>\n"
+"PO-Revision-Date: 2021-08-06 06:48+0000\n"
+"Last-Translator: João Lopes <linux-man@hotmail.com>\n"
"Language-Team: Portuguese <https://hosted.weblate.org/projects/godot-engine/"
"godot/pt/>\n"
"Language: pt\n"
@@ -354,6 +354,7 @@ msgstr "Mudar Modo do Loop da Animação"
msgid "Remove Anim Track"
msgstr "Remover Pista de Animação"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Criar NOVA pista para %s e inserir chave?"
@@ -378,12 +379,30 @@ msgstr "Criar"
msgid "Anim Insert"
msgstr "Anim Inserir"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "Impossível abrir '%s'."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animação"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
"AnimationPlayer não se pode animar a ele próprio, apenas a outros "
"executantes."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Não existe a Propriedade '%s'."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Anim Criar & Inserir"
@@ -591,9 +610,8 @@ msgid "Go to Previous Step"
msgstr "Ir para Passo Anterior"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Apply Reset"
-msgstr "Repor"
+msgstr "Aplicar Reinicialização"
#: editor/animation_track_editor.cpp
msgid "Optimize Animation"
@@ -612,9 +630,8 @@ msgid "Use Bezier Curves"
msgstr "Usar Curvas Bezier"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Create RESET Track(s)"
-msgstr "Colar Pistas"
+msgstr "Criar Pista(s) RESET"
#: editor/animation_track_editor.cpp
msgid "Anim. Optimizer"
@@ -939,7 +956,6 @@ msgid "Edit..."
msgstr "Editar..."
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Go to Method"
msgstr "Ir para Método"
@@ -959,9 +975,9 @@ msgstr "Criar Novo %s"
msgid "No results for \"%s\"."
msgstr "Nenhum resultado para \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
-msgstr ""
+msgstr "Nenhuma descrição disponível para %s."
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp
@@ -1061,17 +1077,16 @@ msgid "Owners Of:"
msgstr "Proprietários de:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove the selected files from the project? (Cannot be undone.)\n"
"Depending on your filesystem configuration, the files will either be moved "
"to the system trash or deleted permanently."
msgstr ""
-"Remover ficheiros selecionados do Projeto? (sem desfazer)\n"
-"Pode encontrar os ficheiros removidos na Reciclagem do sistema."
+"Remover ficheiros selecionados do Projeto? (Sem desfazer.)\n"
+"Dependendo da configuração, pode encontrar os ficheiros removidos na "
+"Reciclagem do sistema ou apagados permanentemente."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1081,8 +1096,9 @@ msgid ""
msgstr ""
"Os ficheiros a serem removidos são necessários para que outros recursos "
"funcionem.\n"
-"Remover mesmo assim? (sem desfazer)\n"
-"Pode encontrar os ficheiros removidos na Reciclagem do sistema."
+"Remover mesmo assim? (Sem desfazer.)\n"
+"Dependendo da configuração, pode encontrar os ficheiros removidos na "
+"Reciclagem do sistema ou apagados permanentemente."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1252,14 +1268,13 @@ msgid "Licenses"
msgstr "Licenças"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Error opening asset file for \"%s\" (not in ZIP format)."
-msgstr "Erro ao abrir ficheiro comprimido (não está no formato ZIP)."
+msgstr ""
+"Erro ao abrir ficheiro de recurso para \"%s\" (não está no formato ZIP)."
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "%s (already exists)"
-msgstr "%s (Já Existe)"
+msgstr "%s (já existe)"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - %d file(s) conflict with your project:"
@@ -1274,19 +1289,16 @@ msgid "Uncompressing Assets"
msgstr "A Descomprimir Ativos"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "The following files failed extraction from asset \"%s\":"
-msgstr "Falhou a extração dos seguintes Ficheiros do pacote:"
+msgstr "Falhou a extração dos seguintes ficheiros do recurso \"%s\":"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "(and %s more files)"
-msgstr "E mais %s ficheiros."
+msgstr "(e mais %s ficheiros)"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset \"%s\" installed successfully!"
-msgstr "Pacote Instalado com sucesso!"
+msgstr "Recurso \"%s\" instalado com sucesso!"
#: editor/editor_asset_installer.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -1298,9 +1310,8 @@ msgid "Install"
msgstr "Instalar"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset Installer"
-msgstr "Instalador de Pacotes"
+msgstr "Instalador de Recursos"
#: editor/editor_audio_buses.cpp
msgid "Speakers"
@@ -2310,6 +2321,17 @@ msgid "New Window"
msgstr "Nova Janela"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Roda quando a janela do editor atualiza."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Recursos importados não podem ser guardados."
@@ -3171,10 +3193,6 @@ msgid "Save & Restart"
msgstr "Guardar & Reiniciar"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Roda quando a janela do editor atualiza."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Atualização Contínua"
@@ -3839,6 +3857,16 @@ msgid "Download from:"
msgstr "Erro na transferência"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Executar no Navegador"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Copiar Erro"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8698,6 +8726,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Remover Todos os Itens"
@@ -8728,6 +8762,12 @@ msgid "Remove All StyleBox Items"
msgstr "Remover Todos os Itens"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Adicionar Itens de Classe"
@@ -12385,6 +12425,16 @@ msgstr "Mudar Altura da Forma Cilindro"
msgid "Change Ray Shape Length"
msgstr "Mudar comprimento da forma raio"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Definir posição do Ponto da curva"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Definir posição do Ponto da curva"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "Mudar Raio do Cilindro"
@@ -14158,6 +14208,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr "Este corpo será ignorado até se definir uma malha."
@@ -15596,9 +15682,6 @@ msgstr "Constantes não podem ser modificadas."
#~ msgid "I see..."
#~ msgstr "Eu vejo..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "Impossível abrir '%s'."
-
#~ msgid "Ugh"
#~ msgstr "Ugh"
diff --git a/editor/translations/pt_BR.po b/editor/translations/pt_BR.po
index c11e4f347b..b7bb7ce0c4 100644
--- a/editor/translations/pt_BR.po
+++ b/editor/translations/pt_BR.po
@@ -95,14 +95,14 @@
# Felipe Jesus Macedo <fmacedo746@gmail.com>, 2020.
# José Paulo <jose.paulo1919@gmail.com>, 2020.
# Necco <necco@outlook.com>, 2020.
-# Marcelo Silveira Hayden <mshayden.1998@gmail.com>, 2020.
+# Marcelo Silveira Hayden <mshayden.1998@gmail.com>, 2020, 2021.
# GUILHERME SOUZA REIS DE MELO LOPES <guilhermesrml@unipam.edu.br>, 2020.
# Gabriela Araújo <Gabirin@outlook.com.br>, 2020.
# Jairo Tuboi <tuboi.jairo@gmail.com>, 2020.
# Felipe Fetter <felipetfetter@gmail.com>, 2020.
# Rafael Henrique Capati <rhcapati@gmail.com>, 2020.
# NogardRyuu <nogardryuu@gmail.com>, 2020, 2021.
-# Elton <eltondeoliveira@outlook.com>, 2020.
+# Elton <eltondeoliveira@outlook.com>, 2020, 2021.
# ThiagoCTN <thiagocampostn@gmail.com>, 2020.
# Alec Santos <alecsantos96@gmail.com>, 2020.
# Augusto Milão <augusto.milao01@gmail.com>, 2021.
@@ -118,12 +118,14 @@
# Gustavo HM 102 <gustavohm102@gmail.com>, 2021.
# Douglas Leão <djlsplays@gmail.com>, 2021.
# PauloFRs <paulofr1@hotmail.com>, 2021.
+# Diego Bloise <diego-dev@outlook.com>, 2021.
+# Alkoarism <Alkoarism@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: 2016-05-30\n"
-"PO-Revision-Date: 2021-06-29 08:04+0000\n"
-"Last-Translator: PauloFRs <paulofr1@hotmail.com>\n"
+"PO-Revision-Date: 2021-08-06 06:47+0000\n"
+"Last-Translator: Alkoarism <Alkoarism@gmail.com>\n"
"Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/"
"godot-engine/godot/pt_BR/>\n"
"Language: pt_BR\n"
@@ -131,7 +133,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 4.7.1-dev\n"
+"X-Generator: Weblate 4.8-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -452,6 +454,7 @@ msgstr "Alterar Modo Repetição da Animação"
msgid "Remove Anim Track"
msgstr "Remover Trilha da Anim"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Criar NOVA faixa para %s e inserir chave?"
@@ -476,10 +479,28 @@ msgstr "Criar"
msgid "Anim Insert"
msgstr "Inserir Anim"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "Não é possível abrir '%s'."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animação"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "AnimationPlayer não pode animar a si mesmo, apenas outros jogadores."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Nenhuma propriedade '%s' existe."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Criar e Inserir Anim"
@@ -689,9 +710,8 @@ msgid "Go to Previous Step"
msgstr "Ir ao Passo Anterior"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Apply Reset"
-msgstr "Recompor"
+msgstr "Redefinir"
#: editor/animation_track_editor.cpp
msgid "Optimize Animation"
@@ -710,9 +730,8 @@ msgid "Use Bezier Curves"
msgstr "Usar Curvas de Bezier"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Create RESET Track(s)"
-msgstr "Colar Trilhas"
+msgstr "Criar RESET Track(s)"
#: editor/animation_track_editor.cpp
msgid "Anim. Optimizer"
@@ -785,7 +804,7 @@ msgstr "Mudar Deslocamento do Início do Clip de Trilha de Audio"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip End Offset"
-msgstr "Alterar Deslocamento de Fim do Clipe de Faixa de Ãudio"
+msgstr "Alterar fim da Trilha de Aúdio"
#: editor/array_property_edit.cpp
msgid "Resize Array"
@@ -1056,9 +1075,9 @@ msgstr "Criar Novo %s"
msgid "No results for \"%s\"."
msgstr "Sem resultados para \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
-msgstr ""
+msgstr "Sem descrição disponível para %s."
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp
@@ -1158,18 +1177,16 @@ msgid "Owners Of:"
msgstr "Donos De:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove the selected files from the project? (Cannot be undone.)\n"
"Depending on your filesystem configuration, the files will either be moved "
"to the system trash or deleted permanently."
msgstr ""
-"Remover arquivos selecionados do projeto? (irreversível)\n"
-"Você pode encontrar os arquivos removidos na lixeira do sistema para "
-"restaurá-los."
+"Remover arquivos selecionados do projeto? (Irreversível.)\n"
+"Dependendo da configuração do seu sistema, os arquivos serão movidos para a "
+"lixeira do sistema ou apagados permanentemente."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1177,11 +1194,11 @@ msgid ""
"Depending on your filesystem configuration, the files will either be moved "
"to the system trash or deleted permanently."
msgstr ""
-"Os arquivos sendo removidos são requeridos por outros recursos para que "
-"funcionem.\n"
-"Removê-los mesmo assim? (irreversível)\n"
-"Você pode encontrar os arquivos removidos na lixeira do sistema para "
-"restaurá-los."
+"Os arquivos que estão sendo removidos são necessários por outros recursos "
+"para que funcionem.\n"
+"Removê-los mesmo assim? (Irreversível.)\n"
+"Dependendo da configuração do seu sistema, os arquivos serão movidos para a "
+"lixeira do sistema ou apagados permanentemente."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1351,9 +1368,8 @@ msgid "Licenses"
msgstr "Licenças"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Error opening asset file for \"%s\" (not in ZIP format)."
-msgstr "Erro ao abrir arquivo compactado (não está em formato ZIP)."
+msgstr "Erro ao abrir o pacote \"%s\" (não está em formato ZIP)."
#: editor/editor_asset_installer.cpp
#, fuzzy
@@ -1362,30 +1378,30 @@ msgstr "%s (Já existe)"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - %d file(s) conflict with your project:"
-msgstr ""
+msgstr "Conteúdo do asset \"%s\" - %d arquivo(s) conflita(m) com seu projeto:"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - No files conflict with your project:"
msgstr ""
+"Conteúdo do asset \"%s\" - Nenhum arquivo entra em conflito com o seu "
+"projeto:"
#: editor/editor_asset_installer.cpp
msgid "Uncompressing Assets"
msgstr "Descompactando Assets"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "The following files failed extraction from asset \"%s\":"
-msgstr "Os arquivos a seguir falharam ao serem extraídos do pacote:"
+msgstr "Os seguintes arquivos falharam na extração do asset \"% s\":"
#: editor/editor_asset_installer.cpp
#, fuzzy
msgid "(and %s more files)"
-msgstr "%s mais arquivo(s)."
+msgstr "(e %s mais arquivos)"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset \"%s\" installed successfully!"
-msgstr "Pacote instalado com sucesso!"
+msgstr "Asset \"%s\" instalados com sucesso!"
#: editor/editor_asset_installer.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -1397,9 +1413,8 @@ msgid "Install"
msgstr "Instalar"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset Installer"
-msgstr "Instalador de Pacotes"
+msgstr "Instalador de Assets"
#: editor/editor_audio_buses.cpp
msgid "Speakers"
@@ -1632,11 +1647,11 @@ msgstr "Não pode adicionar autoload:"
#: editor/editor_autoload_settings.cpp
#, fuzzy
msgid "%s is an invalid path. File does not exist."
-msgstr "O arquivo não existe."
+msgstr "O %s é um caminho inválido. O arquivo não existe."
#: editor/editor_autoload_settings.cpp
msgid "%s is an invalid path. Not in resource path (res://)."
-msgstr ""
+msgstr "%s é um caminho inválido. Não está no caminho dos recursos (res://)."
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -1662,7 +1677,7 @@ msgstr "Nome"
#: editor/editor_autoload_settings.cpp
#, fuzzy
msgid "Global Variable"
-msgstr "Variável"
+msgstr "Variável Global"
#: editor/editor_data.cpp
msgid "Paste Params"
@@ -1763,8 +1778,8 @@ msgid ""
"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
"'Import Pvrtc' in Project Settings."
msgstr ""
-"A plataforma alvo requer compressão de texturas 'PVRTC' para GLES2. Habilite "
-"'Importar Pvrtc' nas Configurações de Projeto."
+"A plataforma de destino requer compressão de texturas 'PVRTC' para GLES2. "
+"Habilite 'Importar Pvrtc' nas Configurações de Projeto."
#: editor/editor_export.cpp
msgid ""
@@ -1836,36 +1851,43 @@ msgid "Import Dock"
msgstr "Importar Dock"
#: editor/editor_feature_profile.cpp
+#, fuzzy
msgid "Allows to view and edit 3D scenes."
-msgstr ""
+msgstr "Permite visualizar e editar cenas 3D."
#: editor/editor_feature_profile.cpp
+#, fuzzy
msgid "Allows to edit scripts using the integrated script editor."
-msgstr ""
+msgstr "Permite editar scripts usando o editor de script integrado."
#: editor/editor_feature_profile.cpp
msgid "Provides built-in access to the Asset Library."
-msgstr ""
+msgstr "Fornece acesso integrado à Biblioteca de Assets."
#: editor/editor_feature_profile.cpp
msgid "Allows editing the node hierarchy in the Scene dock."
-msgstr ""
+msgstr "Permite editar a hierarquia de nó na doca Cena."
#: editor/editor_feature_profile.cpp
+#, fuzzy
msgid ""
"Allows to work with signals and groups of the node selected in the Scene "
"dock."
-msgstr ""
+msgstr "Permite trabalhar com sinais e grupos do nó selecionado na doca Cena."
#: editor/editor_feature_profile.cpp
+#, fuzzy
msgid "Allows to browse the local file system via a dedicated dock."
msgstr ""
+"Permite navegar pelo sistema de arquivos local através de uma doca dedicada."
#: editor/editor_feature_profile.cpp
msgid ""
"Allows to configure import settings for individual assets. Requires the "
"FileSystem dock to function."
msgstr ""
+"Permite definir as configurações de importação para assets individualmente. "
+"Requer a doca FileSystem para funcionar."
#: editor/editor_feature_profile.cpp
#, fuzzy
@@ -1874,11 +1896,11 @@ msgstr "(Atual)"
#: editor/editor_feature_profile.cpp
msgid "(none)"
-msgstr ""
+msgstr "(Nenhum(a))"
#: editor/editor_feature_profile.cpp
msgid "Remove currently selected profile, '%s'? Cannot be undone."
-msgstr ""
+msgstr "Remover o perfil selecionado, '%s'? Não pode ser desfeita."
#: editor/editor_feature_profile.cpp
msgid "Profile must be a valid filename and must not contain '.'"
@@ -1911,17 +1933,16 @@ msgstr "Habilitar Editor Contextual"
#: editor/editor_feature_profile.cpp
#, fuzzy
msgid "Class Properties:"
-msgstr "Propriedades:"
+msgstr "Propriedades de Classe:"
#: editor/editor_feature_profile.cpp
#, fuzzy
msgid "Main Features:"
-msgstr "Funcionalidades"
+msgstr "Características principais:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Nodes and Classes:"
-msgstr "Classes Ativadas:"
+msgstr "Nós e Classes:"
#: editor/editor_feature_profile.cpp
msgid "File '%s' format is invalid, import aborted."
@@ -1939,9 +1960,8 @@ msgid "Error saving profile to path: '%s'."
msgstr "Erro ao salvar perfil no caminho: '%s'."
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Reset to Default"
-msgstr "Redefinir para os padrões"
+msgstr "Redefinir padrões"
#: editor/editor_feature_profile.cpp
msgid "Current Profile:"
@@ -1950,12 +1970,12 @@ msgstr "Perfil Atual:"
#: editor/editor_feature_profile.cpp
#, fuzzy
msgid "Create Profile"
-msgstr "Apagar Perfil"
+msgstr "Criar Perfil"
#: editor/editor_feature_profile.cpp
#, fuzzy
msgid "Remove Profile"
-msgstr "Remover Telha"
+msgstr "Remover Perfil"
#: editor/editor_feature_profile.cpp
msgid "Available Profiles:"
@@ -1977,16 +1997,19 @@ msgstr "Exportação"
#: editor/editor_feature_profile.cpp
#, fuzzy
msgid "Configure Selected Profile:"
-msgstr "Perfil Atual:"
+msgstr "Configurar Perfil Selecionado:"
#: editor/editor_feature_profile.cpp
#, fuzzy
msgid "Extra Options:"
-msgstr "Opções da Textura"
+msgstr "Opções Extra:"
#: editor/editor_feature_profile.cpp
+#, fuzzy
msgid "Create or import a profile to edit available classes and properties."
msgstr ""
+"Criar ou importar um perfil para editar as classes e propriedades "
+"disponíveis."
#: editor/editor_feature_profile.cpp
msgid "New profile name:"
@@ -2015,7 +2038,7 @@ msgstr "Selecionar a Pasta Atual"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
#, fuzzy
msgid "File exists, overwrite?"
-msgstr "O arquivo existe. Sobrescrever?"
+msgstr "O arquivo já existe. Sobrescrever?"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Select This Folder"
@@ -2408,6 +2431,17 @@ msgid "New Window"
msgstr "Nova Janela"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Gira quando a janela do editor atualiza."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Recursos Importados não podem ser salvos."
@@ -2638,13 +2672,16 @@ msgid ""
"The current scene has no root node, but %d modified external resource(s) "
"were saved anyway."
msgstr ""
+"A cena atual não tem um nó raiz, mas %d recurso(s) externo(s) modificado(s) "
+"foram salvos de qualquer forma."
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"A root node is required to save the scene. You can add a root node using the "
"Scene tree dock."
-msgstr "Um nó raiz é requerido para salvar a cena."
+msgstr ""
+"Um nó-raiz é necessário para salvar a cena. Você pode adicionar um nó-raiz "
+"usando a doca da árvore de cenas."
#: editor/editor_node.cpp
msgid "Save Scene As..."
@@ -2752,9 +2789,7 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Unable to find script field for addon plugin at: '%s'."
-msgstr ""
-"Não foi possível localizar a área do script para o complemento do plugin em: "
-"'%s'."
+msgstr "Não foi possível encontrar o campo de script para o plugin em: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -3035,7 +3070,7 @@ msgstr "Explorador de Recursos Órfãos..."
#: editor/editor_node.cpp
#, fuzzy
msgid "Reload Current Project"
-msgstr "Renomear Projeto"
+msgstr "Recarregar o projeto atual"
#: editor/editor_node.cpp
msgid "Quit to Project List"
@@ -3197,11 +3232,12 @@ msgstr "Ajuda"
#: editor/editor_node.cpp
#, fuzzy
msgid "Online Documentation"
-msgstr "Abrir Documentação"
+msgstr "Documentação Online"
#: editor/editor_node.cpp
+#, fuzzy
msgid "Questions & Answers"
-msgstr ""
+msgstr "Perguntas & Respostas"
#: editor/editor_node.cpp
msgid "Report a Bug"
@@ -3210,7 +3246,7 @@ msgstr "Reportar bug"
#: editor/editor_node.cpp
#, fuzzy
msgid "Suggest a Feature"
-msgstr "Defina um Valor"
+msgstr "Sugira um recurso"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
@@ -3223,7 +3259,7 @@ msgstr "Comunidade"
#: editor/editor_node.cpp
#, fuzzy
msgid "About Godot"
-msgstr "Sobre"
+msgstr "Sobre Godot"
#: editor/editor_node.cpp
msgid "Support Godot Development"
@@ -3275,10 +3311,6 @@ msgid "Save & Restart"
msgstr "Salvar e Reiniciar"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Gira quando a janela do editor atualiza."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Atualizar Continuamente"
@@ -3323,12 +3355,12 @@ msgstr "Gerenciar Templates"
#: editor/editor_node.cpp
#, fuzzy
msgid "Install from file"
-msgstr "Instalar a Partir do Arquivo"
+msgstr "Instalar do arquivo"
#: editor/editor_node.cpp
#, fuzzy
msgid "Select android sources file"
-msgstr "Selecione uma Malha de origem:"
+msgstr "Selecione o arquivo de fontes do Android"
#: editor/editor_node.cpp
msgid ""
@@ -3412,7 +3444,7 @@ msgstr "Selecionar"
#: editor/editor_node.cpp
#, fuzzy
msgid "Select Current"
-msgstr "Selecionar a Pasta Atual"
+msgstr "Selecione Atual"
#: editor/editor_node.cpp
msgid "Open 2D Editor"
@@ -3449,7 +3481,7 @@ msgstr "Nenhum sub-recurso encontrado."
#: editor/editor_path.cpp
#, fuzzy
msgid "Open a list of sub-resources."
-msgstr "Nenhum sub-recurso encontrado."
+msgstr "Abra uma lista de sub-recursos."
#: editor/editor_plugin.cpp
msgid "Creating Mesh Previews"
@@ -3478,12 +3510,12 @@ msgstr "Atualizar"
#: editor/editor_plugin_settings.cpp
#, fuzzy
msgid "Version"
-msgstr "Versão:"
+msgstr "Versão"
#: editor/editor_plugin_settings.cpp
#, fuzzy
msgid "Author"
-msgstr "Autores"
+msgstr "Autor"
#: editor/editor_plugin_settings.cpp
#: editor/plugins/version_control_editor_plugin.cpp
@@ -3496,14 +3528,12 @@ msgid "Measure:"
msgstr "Medida:"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Frame Time (ms)"
-msgstr "Tempo do Frame (seg)"
+msgstr "Tempo do Frame (ms)"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Average Time (ms)"
-msgstr "Tempo Médio (seg)"
+msgstr "Tempo Médio (ms)"
#: editor/editor_profiler.cpp
msgid "Frame %"
@@ -3945,6 +3975,16 @@ msgid "Download from:"
msgstr "Erro ao baixar"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Rodar no Navegador"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Copiar Erro"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -4294,15 +4334,15 @@ msgstr "Procurando..."
#: editor/find_in_files.cpp
msgid "%d match in %d file."
-msgstr "%d correspondência em %d arquivo."
+msgstr "%d correspondências no arquivo %d."
#: editor/find_in_files.cpp
msgid "%d matches in %d file."
-msgstr "%d correspondências em %d arquivo."
+msgstr "%d correspondências no arquivo %d."
#: editor/find_in_files.cpp
msgid "%d matches in %d files."
-msgstr "%d correspondências em %d arquivos."
+msgstr "%d correspondências no arquivo %d."
#: editor/groups_editor.cpp
msgid "Add to Group"
@@ -4444,11 +4484,11 @@ msgstr "Selecione o arquivo para importar"
#: editor/import_defaults_editor.cpp
msgid "Importer:"
-msgstr "Importar:"
+msgstr "Importador:"
#: editor/import_defaults_editor.cpp
msgid "Reset to Defaults"
-msgstr "Redefinir para os padrões"
+msgstr "Redefinir padrões"
#: editor/import_dock.cpp
msgid "Keep File (No Import)"
@@ -4766,7 +4806,7 @@ msgstr "Abrir Editor"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Open Animation Node"
-msgstr "Abrir Animação de Nós"
+msgstr "Abrir Nó de Animação"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Triangle already exists."
@@ -4833,7 +4873,7 @@ msgstr "Editar Filtros"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Output node can't be added to the blend tree."
-msgstr "Nós de saída não pode ser adicionado à árvore de mistura."
+msgstr "Nó de Saída não pode ser adicionado à árvore de mistura."
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Add Node to BlendTree"
@@ -8818,6 +8858,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Remover Todos os Itens"
@@ -8848,6 +8894,12 @@ msgid "Remove All StyleBox Items"
msgstr "Remover Todos os Itens"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Adicionar Itens de Classe"
@@ -12508,6 +12560,16 @@ msgstr "Alterar a Altura da Forma do Cilindro"
msgid "Change Ray Shape Length"
msgstr "Alterar o Comprimento da Forma do Raio"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Definir Posição do Ponto da Curva"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Definir Posição do Ponto da Curva"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "Alterar Raio do Cilindro"
@@ -14289,6 +14351,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr "Este corpo será ignorado até você definir uma malha."
@@ -15546,9 +15644,6 @@ msgstr "Constantes não podem serem modificadas."
#~ msgid "I see..."
#~ msgstr "Entendo..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "Não é possível abrir '%s'."
-
#~ msgid "Ugh"
#~ msgstr "Ugh"
diff --git a/editor/translations/ro.po b/editor/translations/ro.po
index f1d65384fc..2b1626bfe2 100644
--- a/editor/translations/ro.po
+++ b/editor/translations/ro.po
@@ -351,6 +351,7 @@ msgstr "Schimbați Bucla Animației"
msgid "Remove Anim Track"
msgstr "Elimină Pista Anim"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Creați pistă NOUA pentru %s și inserați cheie?"
@@ -375,10 +376,28 @@ msgstr "Creați"
msgid "Anim Insert"
msgstr "Anim Inserați"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "Mod Snap (%s)"
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animație"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "AnimationPlayer nu se poate anima singur, doar alți jucători."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Proprietate"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Anim Creați și Inserați"
@@ -955,7 +974,7 @@ msgstr "Creați %s Nou"
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2315,6 +2334,17 @@ msgid "New Window"
msgstr "Fereastră Nouă"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Se rotește când fereastra editorului se redeschide."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Resursele importate nu pot fi salvate."
@@ -3179,10 +3209,6 @@ msgid "Save & Restart"
msgstr "Salvează și Restartează"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Se rotește când fereastra editorului se redeschide."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Actualizare continuă"
@@ -3821,6 +3847,15 @@ msgid "Download from:"
msgstr "Eroare Descărcare"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Execută în Browser"
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8780,6 +8815,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Eliminați Autoload"
@@ -8810,6 +8851,12 @@ msgid "Remove All StyleBox Items"
msgstr "Eliminați Autoload"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Adaugă Obiect"
@@ -12407,6 +12454,16 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Setare poziție punct de curbă"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Setare poziție punct de curbă"
+
#: modules/csg/csg_gizmos.cpp
#, fuzzy
msgid "Change Cylinder Radius"
@@ -14064,6 +14121,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
@@ -14580,9 +14673,6 @@ msgstr ""
#~ msgid "Scale Mode (R)"
#~ msgstr "Mod Redimensionare (R)"
-#~ msgid "Snap Mode (%s)"
-#~ msgstr "Mod Snap (%s)"
-
#~ msgid "Tool Scale"
#~ msgstr "Unealtă Dimensiune"
diff --git a/editor/translations/ru.po b/editor/translations/ru.po
index a5d8b4ea1c..50d4484e4b 100644
--- a/editor/translations/ru.po
+++ b/editor/translations/ru.po
@@ -102,7 +102,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-07-29 02:33+0000\n"
+"PO-Revision-Date: 2021-08-10 21:40+0000\n"
"Last-Translator: Danil Alexeev <danil@alexeev.xyz>\n"
"Language-Team: Russian <https://hosted.weblate.org/projects/godot-engine/"
"godot/ru/>\n"
@@ -112,7 +112,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.7.2-dev\n"
+"X-Generator: Weblate 4.8-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -435,6 +435,7 @@ msgstr "Изменить режим цикла анимации"
msgid "Remove Anim Track"
msgstr "Удалить дорожку"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Создать новую дорожку Ð´Ð»Ñ %s и вÑтавить ключ?"
@@ -459,10 +460,28 @@ msgstr "Создать"
msgid "Anim Insert"
msgstr "Ð’Ñтавить"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "Ðе удаётÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ '%s'."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "ÐнимациÑ"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "AnimationPlayer не может анимировать Ñам ÑебÑ, только других."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "СвойÑтво «%s» не ÑущеÑтвует."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Создать и вÑтавить"
@@ -672,9 +691,8 @@ msgid "Go to Previous Step"
msgstr "Перейти к предыдущему шагу"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Apply Reset"
-msgstr "СброÑить"
+msgstr "Применить ÑброÑ"
#: editor/animation_track_editor.cpp
msgid "Optimize Animation"
@@ -693,9 +711,8 @@ msgid "Use Bezier Curves"
msgstr "ИÑпользовать кривые Безье"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Create RESET Track(s)"
-msgstr "Ð’Ñтавить треки"
+msgstr "Создать дорожку(и) СБРОСÐ"
#: editor/animation_track_editor.cpp
msgid "Anim. Optimizer"
@@ -1020,7 +1037,6 @@ msgid "Edit..."
msgstr "Редактировать..."
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Go to Method"
msgstr "Перейти к методу"
@@ -1040,9 +1056,9 @@ msgstr "Создать %s"
msgid "No results for \"%s\"."
msgstr "Ðет результатов Ð´Ð»Ñ Â«%s»."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
-msgstr ""
+msgstr "Ðет опиÑÐ°Ð½Ð¸Ñ Ð´Ð»Ñ Â«%s»."
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp
@@ -1142,17 +1158,16 @@ msgid "Owners Of:"
msgstr "Владельцы:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove the selected files from the project? (Cannot be undone.)\n"
"Depending on your filesystem configuration, the files will either be moved "
"to the system trash or deleted permanently."
msgstr ""
-"Удалить выбранные файлы из проекта? (ÐÐµÐ»ÑŒÐ·Ñ Ð¾Ñ‚Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ)\n"
-"Ð’Ñ‹ можете найти удалённые файлы в корзине, чтобы воÑÑтановить их."
+"Удалить выбранные файлы из проекта? (ÐÐµÐ»ÑŒÐ·Ñ Ð¾Ñ‚Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ.)\n"
+"Ð’ завиÑимоÑти от конфигурации вашей файловой ÑиÑтемы файлы будут перемещены "
+"в ÑиÑтемную корзину или удалены навÑегда."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1161,8 +1176,9 @@ msgid ""
"to the system trash or deleted permanently."
msgstr ""
"УдалÑемые файлы требуютÑÑ Ð´Ð»Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ð¾Ð¹ работы других реÑурÑов.\n"
-"Ð’ÑÑ‘ равно удалить их? (ÐÐµÐ»ÑŒÐ·Ñ Ð¾Ñ‚Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ)\n"
-"Ð’Ñ‹ можете найти удалённые файлы в корзине, чтобы воÑÑтановить их."
+"Ð’ÑÑ‘ равно удалить их? (ÐÐµÐ»ÑŒÐ·Ñ Ð¾Ñ‚Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ.)\n"
+"Ð’ завиÑимоÑти от конфигурации вашей файловой ÑиÑтемы файлы будут перемещены "
+"в ÑиÑтемную корзину или удалены навÑегда."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1332,41 +1348,36 @@ msgid "Licenses"
msgstr "Лицензии"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Error opening asset file for \"%s\" (not in ZIP format)."
-msgstr "Ошибка при открытии файла пакета (Ðе ÑвлÑетÑÑ ZIP форматом)."
+msgstr "Ошибка при открытии файла реÑурÑа «%s» (не в формате ZIP)."
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "%s (already exists)"
-msgstr "%s (Уже ÑущеÑтвует)"
+msgstr "%s (уже ÑущеÑтвует)"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - %d file(s) conflict with your project:"
-msgstr ""
+msgstr "Содержимое реÑурÑа «%s» - %d файл(ов) конфликтуют Ñ Ð²Ð°ÑˆÐ¸Ð¼ проектом:"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - No files conflict with your project:"
-msgstr ""
+msgstr "Содержимое реÑурÑа «%s» - Ðет файлов, конфликтующих Ñ Ð²Ð°ÑˆÐ¸Ð¼ проектом:"
#: editor/editor_asset_installer.cpp
msgid "Uncompressing Assets"
msgstr "РаÑпаковка аÑÑетов"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "The following files failed extraction from asset \"%s\":"
-msgstr "Следующие файлы не удалоÑÑŒ извлечь из пакета:"
+msgstr "Следующие файлы не удалоÑÑŒ извлечь из пакета «%s»:"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "(and %s more files)"
-msgstr "Ещё %d файла(ов)."
+msgstr "(ещё %d файла(ов))"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset \"%s\" installed successfully!"
-msgstr "Пакет уÑпешно уÑтановлен!"
+msgstr "РеÑÑƒÑ€Ñ Â«%s» уÑпешно уÑтановлен!"
#: editor/editor_asset_installer.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -1378,9 +1389,8 @@ msgid "Install"
msgstr "УÑтановить"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset Installer"
-msgstr "УÑтановщик пакетов"
+msgstr "УÑтановщик реÑурÑов"
#: editor/editor_audio_buses.cpp
msgid "Speakers"
@@ -1443,7 +1453,6 @@ msgid "Bypass"
msgstr "Обход"
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "Bus Options"
msgstr "Параметры шины"
@@ -1611,13 +1620,12 @@ msgid "Can't add autoload:"
msgstr "Ðе удаётÑÑ Ð´Ð¾Ð±Ð°Ð²Ð¸Ñ‚ÑŒ автозагрузку:"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "%s is an invalid path. File does not exist."
-msgstr "Файл не ÑущеÑтвует."
+msgstr "Ðеверный путь «%s». Файл не ÑущеÑтвует."
#: editor/editor_autoload_settings.cpp
msgid "%s is an invalid path. Not in resource path (res://)."
-msgstr ""
+msgstr "%s — недопуÑтимый путь. Ðужен реÑурÑный путь (res://)."
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -1641,9 +1649,8 @@ msgid "Name"
msgstr "Ðазвание"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "Global Variable"
-msgstr "ПеременнаÑ"
+msgstr "Ð“Ð»Ð¾Ð±Ð°Ð»ÑŒÐ½Ð°Ñ Ð¿ÐµÑ€ÐµÐ¼ÐµÐ½Ð½Ð°Ñ"
#: editor/editor_data.cpp
msgid "Paste Params"
@@ -1817,48 +1824,52 @@ msgstr "Панель «Импорт»"
#: editor/editor_feature_profile.cpp
msgid "Allows to view and edit 3D scenes."
-msgstr ""
+msgstr "ПозволÑет проÑматривать и редактировать 3D-Ñцены."
#: editor/editor_feature_profile.cpp
msgid "Allows to edit scripts using the integrated script editor."
msgstr ""
+"ПозволÑет редактировать Ñкрипты Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ вÑтроенного редактора Ñкриптов."
#: editor/editor_feature_profile.cpp
msgid "Provides built-in access to the Asset Library."
-msgstr ""
+msgstr "ПредоÑтавлÑет вÑтроенный доÑтуп к Библиотеке реÑурÑов."
#: editor/editor_feature_profile.cpp
msgid "Allows editing the node hierarchy in the Scene dock."
-msgstr ""
+msgstr "ПозволÑет редактировать иерархию узлов в панели «Сцена»."
#: editor/editor_feature_profile.cpp
msgid ""
"Allows to work with signals and groups of the node selected in the Scene "
"dock."
msgstr ""
+"ПозволÑет работать Ñ Ñигналами и группами узла, выбранного в панели «Сцена»."
#: editor/editor_feature_profile.cpp
msgid "Allows to browse the local file system via a dedicated dock."
msgstr ""
+"ПозволÑет проÑматривать локальную файловую ÑиÑтему через Ñпециальную панель."
#: editor/editor_feature_profile.cpp
msgid ""
"Allows to configure import settings for individual assets. Requires the "
"FileSystem dock to function."
msgstr ""
+"ПозволÑет наÑтраивать параметры импорта Ð´Ð»Ñ Ð¾Ñ‚Ð´ÐµÐ»ÑŒÐ½Ñ‹Ñ… реÑурÑов. Ð”Ð»Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ "
+"требуетÑÑ Ð¿Ð°Ð½ÐµÐ»ÑŒ Â«Ð¤Ð°Ð¹Ð»Ð¾Ð²Ð°Ñ ÑиÑтема»."
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "(current)"
-msgstr "(Текущий)"
+msgstr "(текущий)"
#: editor/editor_feature_profile.cpp
msgid "(none)"
-msgstr ""
+msgstr "(нет)"
#: editor/editor_feature_profile.cpp
msgid "Remove currently selected profile, '%s'? Cannot be undone."
-msgstr ""
+msgstr "Удалить текущий выбранный профиль, «%s»? Ðе может быть отменено."
#: editor/editor_feature_profile.cpp
msgid "Profile must be a valid filename and must not contain '.'"
@@ -1890,19 +1901,16 @@ msgid "Enable Contextual Editor"
msgstr "Включить контекÑтный редактор"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Class Properties:"
-msgstr "СвойÑтва:"
+msgstr "СвойÑтва клаÑÑа:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Main Features:"
-msgstr "ВозможноÑти"
+msgstr "ОÑновные возможноÑти:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Nodes and Classes:"
-msgstr "ДоÑтупные клаÑÑÑ‹:"
+msgstr "Узлы и клаÑÑÑ‹:"
#: editor/editor_feature_profile.cpp
msgid "File '%s' format is invalid, import aborted."
@@ -1921,7 +1929,6 @@ msgid "Error saving profile to path: '%s'."
msgstr "Ошибка ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ñ Ð² «%s»."
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Reset to Default"
msgstr "СброÑить наÑтройки"
@@ -1930,14 +1937,12 @@ msgid "Current Profile:"
msgstr "Текущий профиль:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Create Profile"
-msgstr "Стереть профиль"
+msgstr "Создать профиль"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Remove Profile"
-msgstr "Удалить тайл"
+msgstr "Удалить профиль"
#: editor/editor_feature_profile.cpp
msgid "Available Profiles:"
@@ -1957,18 +1962,18 @@ msgid "Export"
msgstr "ЭкÑпорт"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Configure Selected Profile:"
-msgstr "Текущий профиль:"
+msgstr "ÐаÑтроить выбранный профиль:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Extra Options:"
-msgstr "Параметры текÑтуры"
+msgstr "Дополнительные параметры:"
#: editor/editor_feature_profile.cpp
msgid "Create or import a profile to edit available classes and properties."
msgstr ""
+"Создайте или импортируйте профиль Ð´Ð»Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð¾Ñтупных клаÑÑов и "
+"ÑвойÑтв."
#: editor/editor_feature_profile.cpp
msgid "New profile name:"
@@ -1995,7 +2000,6 @@ msgid "Select Current Folder"
msgstr "Выбрать текущую папку"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
-#, fuzzy
msgid "File exists, overwrite?"
msgstr "Файл ÑущеÑтвует, перезапиÑать?"
@@ -2390,6 +2394,17 @@ msgid "New Window"
msgstr "Ðовое окно"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "ВращаетÑÑ, когда окно редактора перериÑовываетÑÑ."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Импортированные реÑурÑÑ‹ не могут быть Ñохранены."
@@ -2621,13 +2636,16 @@ msgid ""
"The current scene has no root node, but %d modified external resource(s) "
"were saved anyway."
msgstr ""
+"Ð¢ÐµÐºÑƒÑ‰Ð°Ñ Ñцена не имеет корневого узла, но %d изменённых внешних реÑурÑов вÑÑ‘ "
+"равно были Ñохранены."
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"A root node is required to save the scene. You can add a root node using the "
"Scene tree dock."
-msgstr "Ð”Ð»Ñ ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ñцены требуетÑÑ ÐºÐ¾Ñ€Ð½ÐµÐ²Ð¾Ð¹ узел."
+msgstr ""
+"Ð”Ð»Ñ ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ñцены требуетÑÑ ÐºÐ¾Ñ€Ð½ÐµÐ²Ð¾Ð¹ узел. Ð’Ñ‹ можете добавить его, "
+"иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ð¿Ð°Ð½ÐµÐ»ÑŒ «Сцена»."
#: editor/editor_node.cpp
msgid "Save Scene As..."
@@ -3010,9 +3028,8 @@ msgid "Orphan Resource Explorer..."
msgstr "Обзор реÑурÑов-Ñирот..."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reload Current Project"
-msgstr "Переименовать проект"
+msgstr "Перезагрузить текущий проект"
#: editor/editor_node.cpp
msgid "Quit to Project List"
@@ -3171,22 +3188,20 @@ msgid "Help"
msgstr "Справка"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Online Documentation"
-msgstr "Открыть документацию"
+msgstr "Онлайн-документациÑ"
#: editor/editor_node.cpp
msgid "Questions & Answers"
-msgstr ""
+msgstr "ВопроÑÑ‹ и ответы"
#: editor/editor_node.cpp
msgid "Report a Bug"
msgstr "Сообщить об ошибке"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Suggest a Feature"
-msgstr "УÑтановить значение"
+msgstr "Предложить функцию"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
@@ -3197,9 +3212,8 @@ msgid "Community"
msgstr "СообщеÑтво"
#: editor/editor_node.cpp
-#, fuzzy
msgid "About Godot"
-msgstr "О Godot Engine"
+msgstr "О Godot"
#: editor/editor_node.cpp
msgid "Support Godot Development"
@@ -3251,10 +3265,6 @@ msgid "Save & Restart"
msgstr "Сохранить и перезапуÑтить"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "ВращаетÑÑ, когда окно редактора перериÑовываетÑÑ."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Ðепрерывное обновление"
@@ -3297,14 +3307,12 @@ msgid "Manage Templates"
msgstr "Управление шаблонами"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Install from file"
msgstr "УÑтановить из файла"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Select android sources file"
-msgstr "Выберите иÑточник полиÑетки:"
+msgstr "Выберите файл иÑходников android"
#: editor/editor_node.cpp
msgid ""
@@ -3387,9 +3395,8 @@ msgid "Select"
msgstr "Выделение"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Select Current"
-msgstr "Выбрать текущую папку"
+msgstr "Выбрать текущий"
#: editor/editor_node.cpp
msgid "Open 2D Editor"
@@ -3424,9 +3431,8 @@ msgid "No sub-resources found."
msgstr "Вложенные реÑурÑÑ‹ не найдены."
#: editor/editor_path.cpp
-#, fuzzy
msgid "Open a list of sub-resources."
-msgstr "Вложенные реÑурÑÑ‹ не найдены."
+msgstr "Открыть ÑпиÑок вложенных реÑурÑов."
#: editor/editor_plugin.cpp
msgid "Creating Mesh Previews"
@@ -3453,14 +3459,12 @@ msgid "Update"
msgstr "Обновление"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Version"
-msgstr "ВерÑиÑ:"
+msgstr "ВерÑиÑ"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Author"
-msgstr "Ðвторы"
+msgstr "Ðвтор"
#: editor/editor_plugin_settings.cpp
#: editor/plugins/version_control_editor_plugin.cpp
@@ -3473,14 +3477,12 @@ msgid "Measure:"
msgstr "Единица измерениÑ:"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Frame Time (ms)"
-msgstr "Ð’Ñ€ÐµÐ¼Ñ ÐºÐ°Ð´Ñ€Ð° (Ñек.)"
+msgstr "Ð’Ñ€ÐµÐ¼Ñ ÐºÐ°Ð´Ñ€Ð° (мÑ)"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Average Time (ms)"
-msgstr "Среднее Ð²Ñ€ÐµÐ¼Ñ (Ñек.)"
+msgstr "Среднее Ð²Ñ€ÐµÐ¼Ñ (мÑ)"
#: editor/editor_profiler.cpp
msgid "Frame %"
@@ -3507,6 +3509,12 @@ msgid ""
"functions called by that function.\n"
"Use this to find individual functions to optimize."
msgstr ""
+"Включительно: Включает Ð²Ñ€ÐµÐ¼Ñ Ð´Ñ€ÑƒÐ³Ð¸Ñ… функций, вызываемых Ñтой функцией.\n"
+"ИÑпользуйте Ð´Ð»Ñ Ð²Ñ‹ÑÐ²Ð»ÐµÐ½Ð¸Ñ ÑƒÐ·ÐºÐ¸Ñ… меÑÑ‚.\n"
+"\n"
+"Субъект: учитывает только времÑ, затраченное в Ñамой функции, а не в других "
+"функциÑÑ…, вызываемых Ñтой функцией.\n"
+"ИÑпользуйте Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка отдельных функций Ð´Ð»Ñ Ð¾Ð¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ð¸."
#: editor/editor_profiler.cpp
msgid "Frame #:"
@@ -3628,7 +3636,6 @@ msgid "Paste"
msgstr "Ð’Ñтавить"
#: editor/editor_resource_picker.cpp editor/property_editor.cpp
-#, fuzzy
msgid "Convert to %s"
msgstr "Преобразовать в %s"
@@ -3679,10 +3686,9 @@ msgid "Did you forget the '_run' method?"
msgstr "Быть может вы забыли метод _run()?"
#: editor/editor_spin_slider.cpp
-#, fuzzy
msgid "Hold %s to round to integers. Hold Shift for more precise changes."
msgstr ""
-"Зажмите Ctrl, чтобы округлить до целых. Зажмите Shift Ð´Ð»Ñ Ð±Ð¾Ð»ÐµÐµ точных "
+"Зажмите %s, чтобы округлить до целых. Зажмите Shift Ð´Ð»Ñ Ð±Ð¾Ð»ÐµÐµ точных "
"изменений."
#: editor/editor_sub_scene.cpp
@@ -3703,49 +3709,43 @@ msgstr "Импортировать из узла:"
#: editor/export_template_manager.cpp
msgid "Open the folder containing these templates."
-msgstr ""
+msgstr "Открыть папку, Ñодержащую Ñти шаблоны."
#: editor/export_template_manager.cpp
msgid "Uninstall these templates."
-msgstr ""
+msgstr "Удалить Ñти шаблоны."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "There are no mirrors available."
-msgstr "Файла «%s» не ÑущеÑтвует."
+msgstr "Ðет доÑтупных зеркал."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Retrieving the mirror list..."
-msgstr "Получение зеркал, пожалуйÑта, ждите..."
+msgstr "Получение ÑпиÑка зеркал..."
#: editor/export_template_manager.cpp
msgid "Starting the download..."
-msgstr ""
+msgstr "Ðачало загрузки..."
#: editor/export_template_manager.cpp
msgid "Error requesting URL:"
msgstr "Ошибка при запроÑе URL:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Connecting to the mirror..."
msgstr "Подключение к зеркалу..."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't resolve the requested address."
-msgstr "Ðевозможно определить Ð¸Ð¼Ñ Ñ…Ð¾Ñта:"
+msgstr "Ðе удалоÑÑŒ разрешить запрошенный адреÑ."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't connect to the mirror."
-msgstr "Ðе удаётÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡Ð¸Ñ‚ÑŒÑÑ Ðº хоÑту:"
+msgstr "Ðе удалоÑÑŒ подключитьÑÑ Ðº зеркалу."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "No response from the mirror."
-msgstr "Ðет ответа от хоÑта:"
+msgstr "Ðет ответа от зеркала."
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -3753,18 +3753,16 @@ msgid "Request failed."
msgstr "Ðе удалоÑÑŒ выполнить запроÑ."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Request ended up in a redirect loop."
-msgstr "Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð½Ðµ прошёл, Ñлишком много перенаправлений"
+msgstr "Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐ¸Ð»ÑÑ Ð¸Ð·-за цикличеÑких перенаправлений."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Request failed:"
-msgstr "Ðе удалоÑÑŒ выполнить запроÑ."
+msgstr "Ðе удалоÑÑŒ выполнить запроÑ:"
#: editor/export_template_manager.cpp
msgid "Download complete; extracting templates..."
-msgstr ""
+msgstr "Загрузка завершена; извлечение шаблонов..."
#: editor/export_template_manager.cpp
msgid "Cannot remove temporary file:"
@@ -3783,14 +3781,14 @@ msgid "Error getting the list of mirrors."
msgstr "Ошибка при получении ÑпиÑка зеркал."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Error parsing JSON with the list of mirrors. Please report this issue!"
msgstr ""
-"Ошибка парÑинга JSON ÑпиÑка зеркал. ПожалуйÑта, Ñообщите об Ñтой проблеме!"
+"Ошибка при разборе JSON Ñо ÑпиÑком зеркал. ПожалуйÑта, Ñообщите об Ñтой "
+"проблеме!"
#: editor/export_template_manager.cpp
msgid "Best available mirror"
-msgstr ""
+msgstr "Лучшее доÑтупное зеркало"
#: editor/export_template_manager.cpp
msgid ""
@@ -3843,24 +3841,20 @@ msgid "SSL Handshake Error"
msgstr "Ошибка Ñ€ÑƒÐºÐ¾Ð¿Ð¾Ð¶Ð°Ñ‚Ð¸Ñ SSH"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't open the export templates file."
-msgstr "Ðе удаётÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ архив шаблонов ÑкÑпорта."
+msgstr "Ðе удалоÑÑŒ открыть архив шаблонов ÑкÑпорта."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Invalid version.txt format inside the export templates file: %s."
-msgstr "Ðеверный формат version.txt файла внутри шаблонов: %s."
+msgstr "Ðеверный формат version.txt внутри файла шаблонов ÑкÑпорта: %s."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "No version.txt found inside the export templates file."
-msgstr "Файл version.txt не найден в шаблонах."
+msgstr "Файл version.txt не найден внутри файла шаблонов ÑкÑпорта."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Error creating path for extracting templates:"
-msgstr "Ошибка ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¿ÑƒÑ‚Ð¸ Ð´Ð»Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ð¾Ð²:"
+msgstr "Ошибка при Ñоздании пути Ð´Ð»Ñ Ð¸Ð·Ð²Ð»ÐµÑ‡ÐµÐ½Ð¸Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ð¾Ð²:"
#: editor/export_template_manager.cpp
msgid "Extracting Export Templates"
@@ -3871,9 +3865,8 @@ msgid "Importing:"
msgstr "ИмпортируетÑÑ:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Remove templates for the version '%s'?"
-msgstr "Удалить верÑию шаблона «%s»?"
+msgstr "Удалить шаблоны Ð´Ð»Ñ Ð²ÐµÑ€Ñии «%s»?"
#: editor/export_template_manager.cpp
msgid "Uncompressing Android Build Sources"
@@ -3889,58 +3882,65 @@ msgstr "Ð¢ÐµÐºÑƒÑ‰Ð°Ñ Ð²ÐµÑ€ÑиÑ:"
#: editor/export_template_manager.cpp
msgid "Export templates are missing. Download them or install from a file."
-msgstr ""
+msgstr "Шаблоны ÑкÑпорта отÑутÑтвуют. Загрузите их или уÑтановите из файла."
#: editor/export_template_manager.cpp
msgid "Export templates are installed and ready to be used."
-msgstr ""
+msgstr "Шаблоны ÑкÑпорта уÑтановлены и готовы к иÑпользованию."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Open Folder"
-msgstr "Открыть файл"
+msgstr "Открыть папку"
#: editor/export_template_manager.cpp
msgid "Open the folder containing installed templates for the current version."
-msgstr ""
+msgstr "Открывает папку, Ñодержащую уÑтановленные шаблоны Ð´Ð»Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ¹ верÑии."
#: editor/export_template_manager.cpp
msgid "Uninstall"
msgstr "Удалить"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Uninstall templates for the current version."
-msgstr "Ðачальное значение Ð´Ð»Ñ Ñчетчика"
+msgstr "Удалить шаблоны Ð´Ð»Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ¹ верÑии."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Download from:"
-msgstr "Ошибка загрузки"
+msgstr "Загрузить из:"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "ЗапуÑтить в браузере"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Копировать ошибку"
#: editor/export_template_manager.cpp
msgid "Download and Install"
-msgstr ""
+msgstr "Загрузить и уÑтановить"
#: editor/export_template_manager.cpp
msgid ""
"Download and install templates for the current version from the best "
"possible mirror."
msgstr ""
+"Загружает и уÑтанавливает шаблоны Ð´Ð»Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ¹ верÑии Ñ Ð»ÑƒÑ‡ÑˆÐµÐ³Ð¾ из доÑтупных "
+"зеркал."
#: editor/export_template_manager.cpp
msgid "Official export templates aren't available for development builds."
msgstr "Официальные шаблоны ÑкÑпорта недоÑтупны Ð´Ð»Ñ Ñ€Ð°Ð±Ð¾Ñ‡Ð¸Ñ… Ñборок."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Install from File"
msgstr "УÑтановить из файла"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Install templates from a local file."
-msgstr "Импортировать шаблоны из ZIP файла"
+msgstr "УÑтановить шаблоны из локального файла."
#: editor/export_template_manager.cpp editor/find_in_files.cpp
#: editor/progress_dialog.cpp scene/gui/dialogs.cpp
@@ -3948,19 +3948,16 @@ msgid "Cancel"
msgstr "Отмена"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Cancel the download of the templates."
-msgstr "Ðе удаётÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ архив шаблонов ÑкÑпорта."
+msgstr "Отменить загрузку шаблонов."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Other Installed Versions:"
-msgstr "УÑтановленные верÑии:"
+msgstr "Другие уÑтановленные верÑии:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Uninstall Template"
-msgstr "Удалить"
+msgstr "Удалить шаблон"
#: editor/export_template_manager.cpp
msgid "Select Template File"
@@ -3975,6 +3972,9 @@ msgid ""
"The templates will continue to download.\n"
"You may experience a short editor freeze when they finish."
msgstr ""
+"Шаблоны будут продолжать загружатьÑÑ.\n"
+"ПоÑле Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ¸ может произойти кратковременное завиÑание "
+"редактора."
#: editor/filesystem_dock.cpp
msgid "Favorites"
@@ -4122,35 +4122,32 @@ msgid "Collapse All"
msgstr "Свернуть вÑе"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort files"
-msgstr "ПоиÑк файлов"
+msgstr "Сортировать файлы"
#: editor/filesystem_dock.cpp
msgid "Sort by Name (Ascending)"
-msgstr ""
+msgstr "Сортировать по имени (по возраÑтанию)"
#: editor/filesystem_dock.cpp
msgid "Sort by Name (Descending)"
-msgstr ""
+msgstr "Сортировать по имени (по убыванию)"
#: editor/filesystem_dock.cpp
msgid "Sort by Type (Ascending)"
-msgstr ""
+msgstr "Сортировать по типу (по возраÑтанию)"
#: editor/filesystem_dock.cpp
msgid "Sort by Type (Descending)"
-msgstr ""
+msgstr "Сортировать по типу (по убыванию)"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort by Last Modified"
-msgstr "ПоÑледнее изменение"
+msgstr "Сортировать по поÑледнему изменению"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort by First Modified"
-msgstr "ПоÑледнее изменение"
+msgstr "Сортировать по первому изменению"
#: editor/filesystem_dock.cpp
msgid "Duplicate..."
@@ -4162,7 +4159,7 @@ msgstr "Переименовать..."
#: editor/filesystem_dock.cpp
msgid "Focus the search box"
-msgstr ""
+msgstr "СфокуÑироватьÑÑ Ð½Ð° поле поиÑка"
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -4470,14 +4467,12 @@ msgid "Failed to load resource."
msgstr "Ðе удалоÑÑŒ загрузить реÑурÑ."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Copy Properties"
-msgstr "СвойÑтва"
+msgstr "Копировать ÑвойÑтва"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Paste Properties"
-msgstr "СвойÑтва"
+msgstr "Ð’Ñтавить ÑвойÑтва"
#: editor/inspector_dock.cpp
msgid "Make Sub-Resources Unique"
@@ -4502,23 +4497,20 @@ msgid "Save As..."
msgstr "Сохранить как..."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Extra resource options."
-msgstr "Ðе в пути реÑурÑов."
+msgstr "Дополнительные параметры реÑурÑа."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Edit Resource from Clipboard"
-msgstr "Редактировать реÑÑƒÑ€Ñ Ð² буфере обмена"
+msgstr "Редактировать реÑÑƒÑ€Ñ Ð¸Ð· буфера обмена"
#: editor/inspector_dock.cpp
msgid "Copy Resource"
msgstr "Копировать параметры"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Make Resource Built-In"
-msgstr "Сделать вÑтроенным"
+msgstr "Сделать реÑÑƒÑ€Ñ Ð²Ñтроенным"
#: editor/inspector_dock.cpp
msgid "Go to the previous edited object in history."
@@ -4533,9 +4525,8 @@ msgid "History of recently edited objects."
msgstr "ИÑÑ‚Ð¾Ñ€Ð¸Ñ Ð½ÐµÐ´Ð°Ð²Ð½Ð¾ отредактированных объектов."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Open documentation for this object."
-msgstr "Открыть документацию"
+msgstr "Открыть документацию Ð´Ð»Ñ Ñтого объекта."
#: editor/inspector_dock.cpp editor/scene_tree_dock.cpp
msgid "Open Documentation"
@@ -4546,9 +4537,8 @@ msgid "Filter properties"
msgstr "Фильтр ÑвойÑтв"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Manage object properties."
-msgstr "СвойÑтва объекта."
+msgstr "Управление ÑвойÑтвами объекта."
#: editor/inspector_dock.cpp
msgid "Changes may be lost!"
@@ -4793,9 +4783,8 @@ msgid "Blend:"
msgstr "Смешивание:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Parameter Changed:"
-msgstr "Параметр изменён"
+msgstr "Параметр изменён:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
@@ -5525,11 +5514,11 @@ msgstr "Ð’Ñе"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Search templates, projects, and demos"
-msgstr ""
+msgstr "ПоиÑк шаблонов, проектов и демо"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Search assets (excluding templates, projects, and demos)"
-msgstr ""
+msgstr "ПоиÑк реÑурÑов (иÑÐºÐ»ÑŽÑ‡Ð°Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ñ‹, проекты и демо)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Import..."
@@ -5573,7 +5562,7 @@ msgstr "ZIP файл аÑÑетов"
#: editor/plugins/audio_stream_editor_plugin.cpp
msgid "Audio Preview Play/Pause"
-msgstr ""
+msgstr "Ðудио превью Старт/Пауза"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
@@ -5830,13 +5819,12 @@ msgstr "Изменить привÑзку"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid ""
"Project Camera Override\n"
"Overrides the running project's camera with the editor viewport camera."
msgstr ""
"Переопределение игровой камеры\n"
-"ПереопределÑет игровую камеру камерой редактора viewport."
+"ПереопределÑет игровую камеру запущенного проекта камерой viewport редактора."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5845,6 +5833,9 @@ msgid ""
"No project instance running. Run the project from the editor to use this "
"feature."
msgstr ""
+"Переопределение игровой камеры\n"
+"ЭкземплÑÑ€ проекта не запущен. ЗапуÑтите проект из редактора, чтобы "
+"иÑпользовать Ñту функцию."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5912,31 +5903,27 @@ msgstr "Режим выделениÑ"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Drag: Rotate selected node around pivot."
-msgstr "Удалить выделенный узел или переход."
+msgstr "Тащить: Вращать выделенный узел вокруг pivot."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Alt+Drag: Move selected node."
-msgstr "Alt+Тащить: Перемещение"
+msgstr "Alt+Тащить: перемещение выбранного узла."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "V: Set selected node's pivot position."
-msgstr "Удалить выделенный узел или переход."
+msgstr "V: Задать положение pivot выделенного узла."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Alt+RMB: Show list of all nodes at position clicked, including locked."
msgstr ""
-"Показывает ÑпиÑок вÑех объектов нажатой позиции,\n"
-"(так же как и Alt+ПКМ в режиме выделениÑ)."
+"Alt+ПКМ: Показать ÑпиÑок вÑех узлов в выбранной позиции, Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ "
+"заблокированные."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "RMB: Add node at position clicked."
-msgstr ""
+msgstr "ПКМ: Добавить узел в выбранной позиции."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -6174,14 +6161,12 @@ msgid "Clear Pose"
msgstr "ОчиÑтить позу"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Add Node Here"
-msgstr "Добавить узел"
+msgstr "Добавить узел Ñюда"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Instance Scene Here"
-msgstr "Дополнить Ñценой(ами)"
+msgstr "ИнÑтанцировать Ñцену Ñюда"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Multiply grid step by 2"
@@ -6197,49 +6182,43 @@ msgstr "Панорамировать вид"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 3.125%"
-msgstr ""
+msgstr "МаÑштаб 3,125%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 6.25%"
-msgstr ""
+msgstr "МаÑштаб 6.25%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 12.5%"
-msgstr ""
+msgstr "МаÑштаб 12.5%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 25%"
-msgstr "Отдалить"
+msgstr "МаÑштаб 25%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 50%"
-msgstr "Отдалить"
+msgstr "МаÑштаб 50%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 100%"
-msgstr "Отдалить"
+msgstr "МаÑштаб 100%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 200%"
-msgstr "Отдалить"
+msgstr "МаÑштаб 200%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 400%"
-msgstr "Отдалить"
+msgstr "МаÑштаб 400%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 800%"
-msgstr "Отдалить"
+msgstr "МаÑштаб 800%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 1600%"
-msgstr ""
+msgstr "МаÑштаб 1600%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Add %s"
@@ -6484,9 +6463,8 @@ msgid "Couldn't create a single convex collision shape."
msgstr "Ðе удалоÑÑŒ Ñоздать ни одной выпуклой формы ÑтолкновениÑ."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Create Simplified Convex Shape"
-msgstr "Создать одну выпуклую форму"
+msgstr "Создать упрощённую выпуклую форму"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Single Convex Shape"
@@ -6522,9 +6500,8 @@ msgid "No mesh to debug."
msgstr "Ðет полиÑетки Ð´Ð»Ñ Ð¾Ñ‚Ð»Ð°Ð´ÐºÐ¸."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Mesh has no UV in layer %d."
-msgstr "У модели нет UV в Ñтом Ñлое"
+msgstr "ПолиÑетка не имеет UV в Ñлое %d."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "MeshInstance lacks a Mesh!"
@@ -6589,9 +6566,8 @@ msgstr ""
"Это Ñамый быÑтрый (но наименее точный) ÑпоÑоб Ð¾Ð±Ð½Ð°Ñ€ÑƒÐ¶ÐµÐ½Ð¸Ñ Ñтолкновений."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Create Simplified Convex Collision Sibling"
-msgstr "Создать одну выпуклую облаÑть ÑтолкновениÑ"
+msgstr "Создать ÑоÑеднюю упрощённую выпуклую коллизию"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid ""
@@ -6599,20 +6575,23 @@ msgid ""
"This is similar to single collision shape, but can result in a simpler "
"geometry in some cases, at the cost of accuracy."
msgstr ""
+"Создает упрощенную выпуклую форму ÑтолкновениÑ.\n"
+"Она похожа на одиночную форму ÑтолкновениÑ, но в некоторых ÑлучаÑÑ… может "
+"получитьÑÑ Ð±Ð¾Ð»ÐµÐµ проÑÑ‚Ð°Ñ Ð³ÐµÐ¾Ð¼ÐµÑ‚Ñ€Ð¸Ñ, ценой ÑÐ½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ñ‚Ð¾Ñ‡Ð½Ð¾Ñти."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Multiple Convex Collision Siblings"
msgstr "Создать выпуклую облаÑть ÑтолкновениÑ"
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid ""
"Creates a polygon-based collision shape.\n"
"This is a performance middle-ground between a single convex collision and a "
"polygon-based collision."
msgstr ""
"Создает форму ÑÑ‚Ð¾Ð»ÐºÐ½Ð¾Ð²ÐµÐ½Ð¸Ñ Ð½Ð° оÑнове полигона.\n"
-"Это Ñредний по производительноÑти вариант между Ð´Ð²ÑƒÐ¼Ñ Ð¿Ñ€ÐµÐ´Ñ‹Ð´ÑƒÑ‰Ð¸Ð¼Ð¸."
+"Это Ñредний по производительноÑти вариант между одиночным выпуклым "
+"Ñтолкновением и Ñтолкновением на оÑнове полигонов."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Outline Mesh..."
@@ -7255,24 +7234,20 @@ msgid "ResourcePreloader"
msgstr "Предзагрузчик реÑурÑов"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Flip Portals"
-msgstr "Перевернуть по горизонтали"
+msgstr "Перевернуть порталы"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Room Generate Points"
-msgstr "КоличеÑтво Ñоздаваемых точек:"
+msgstr "Точки генерации комнаты"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Generate Points"
-msgstr "КоличеÑтво Ñоздаваемых точек:"
+msgstr "Генерировать точки"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Flip Portal"
-msgstr "Перевернуть по горизонтали"
+msgstr "Перевернуть портал"
#: editor/plugins/root_motion_editor_plugin.cpp
msgid "AnimationTree has no path set to an AnimationPlayer"
@@ -7836,20 +7811,17 @@ msgid "None"
msgstr "ПуÑто"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Rotate"
-msgstr "ГоÑударÑтво"
+msgstr "Повернуть"
#. TRANSLATORS: This refers to the movement that changes the position of an object.
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Translate"
-msgstr "Перемещение:"
+msgstr "Сдвинуть"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Scale"
-msgstr "МаÑштаб:"
+msgstr "МаÑштабировать"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scaling: "
@@ -7872,52 +7844,44 @@ msgid "Animation Key Inserted."
msgstr "Ключ анимации вÑтавлен."
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Pitch:"
-msgstr "Ð’Ñ‹Ñота"
+msgstr "Ð’Ñ‹Ñота:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Yaw:"
-msgstr ""
+msgstr "РыÑкание:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size:"
-msgstr "Размер: "
+msgstr "Размер:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Objects Drawn:"
-msgstr "ÐариÑовано объектов"
+msgstr "ОтриÑовано объектов:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Material Changes:"
-msgstr "Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¼Ð°Ñ‚ÐµÑ€Ð¸Ð°Ð»Ð°"
+msgstr "Материалов изменено:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Shader Changes:"
-msgstr "Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ ÑˆÐµÐ¹Ð´ÐµÑ€Ð¾Ð²"
+msgstr "Шейдеров изменено:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Surface Changes:"
-msgstr "Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¿Ð¾Ð²ÐµÑ€Ñ…Ð½Ð¾Ñти"
+msgstr "ПоверхноÑтей изменено:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Draw Calls:"
-msgstr "Вызовы отриÑовки"
+msgstr "Вызовов отриÑовки:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Vertices:"
-msgstr "Вершины"
+msgstr "Вершины:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "FPS: %d (%s ms)"
-msgstr ""
+msgstr "FPS: %d (%s мÑ)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Top View."
@@ -8072,9 +8036,8 @@ msgid "Freelook Slow Modifier"
msgstr "Модификатор Ð·Ð°Ð¼ÐµÐ´Ð»ÐµÐ½Ð¸Ñ Ñвободного вида"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Toggle Camera Preview"
-msgstr "Изменить размер камеры"
+msgstr "Переключить превью камеры"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Rotation Locked"
@@ -8097,9 +8060,8 @@ msgstr ""
"игры."
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Convert Rooms"
-msgstr "Преобразовать в %s"
+msgstr "Преобразовать комнаты"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "XForm Dialog"
@@ -8121,7 +8083,6 @@ msgstr ""
"(«рентген»)."
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Snap Nodes to Floor"
msgstr "ПривÑзать узлы к полу"
@@ -8139,7 +8100,7 @@ msgstr "ИÑпользовать привÑзки"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Converts rooms for portal culling."
-msgstr ""
+msgstr "Преобразует комнаты Ð´Ð»Ñ portal culling."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Bottom View"
@@ -8235,9 +8196,8 @@ msgid "View Grid"
msgstr "Отображать Ñетку"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "View Portal Culling"
-msgstr "ÐаÑтройки окна проÑмотра"
+msgstr "Отображать portal culling"
#: editor/plugins/spatial_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
@@ -8559,221 +8519,196 @@ msgid "TextureRegion"
msgstr "ОблаÑть текÑтуры"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Colors"
-msgstr "Цвет"
+msgstr "Цвета"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Fonts"
-msgstr "Шрифт"
+msgstr "Шрифты"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Icons"
-msgstr "Иконка"
+msgstr "Иконки"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Styleboxes"
-msgstr "Стиль"
+msgstr "Стили"
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} color(s)"
-msgstr ""
+msgstr "{num} цвет(ов)"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No colors found."
-msgstr "Вложенные реÑурÑÑ‹ не найдены."
+msgstr "Цвета не найдены."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "{num} constant(s)"
-msgstr "КонÑтанты"
+msgstr "{num} конÑтанта(Ñ‹)"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No constants found."
-msgstr "Ð¦Ð²ÐµÑ‚Ð¾Ð²Ð°Ñ ÐºÐ¾Ð½Ñтанта."
+msgstr "КонÑтанты не найдены."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} font(s)"
-msgstr ""
+msgstr "{num} шрифт(ов)"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No fonts found."
-msgstr "Ðе найдено!"
+msgstr "Шрифты не найдены."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} icon(s)"
-msgstr ""
+msgstr "{num} иконка(ок)"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No icons found."
-msgstr "Ðе найдено!"
+msgstr "Иконки не найдены."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} stylebox(es)"
-msgstr ""
+msgstr "{num} Ñтиль(ей)"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No styleboxes found."
-msgstr "Вложенные реÑурÑÑ‹ не найдены."
+msgstr "Стили не найдены."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} currently selected"
-msgstr ""
+msgstr "{num} выбрано в данный момент"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Nothing was selected for the import."
-msgstr ""
+msgstr "Ð”Ð»Ñ Ð¸Ð¼Ð¿Ð¾Ñ€Ñ‚Ð° ничего не выбрано."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Importing Theme Items"
-msgstr "Импортировать тему"
+msgstr "Импортировать Ñлементы темы"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Importing items {n}/{n}"
-msgstr ""
+msgstr "Импорт Ñлементов {n}/{n}"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Updating the editor"
-msgstr "Выйти из редактора?"
+msgstr "Обновление редактора"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Finalizing"
-msgstr "Ðнализ"
+msgstr "Завершение"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Filter:"
-msgstr "Фильтр: "
+msgstr "Фильтр:"
#: editor/plugins/theme_editor_plugin.cpp
msgid "With Data"
-msgstr ""
+msgstr "С данными"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select by data type:"
-msgstr "Выбрать узел"
+msgstr "Выбрать по типу данных:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible color items."
-msgstr "Выберите разделение, чтобы Ñтереть его."
+msgstr "Выбрать вÑе видимые цвета."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible color items and their data."
-msgstr ""
+msgstr "Выделить вÑе видимые цвета и их данные."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible color items."
-msgstr ""
+msgstr "СнÑть выделение Ñо вÑех видимых цветов."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible constant items."
-msgstr "Сначала выберите Ñлемент наÑтроек!"
+msgstr "Выбрать вÑе видимые конÑтанты."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible constant items and their data."
-msgstr ""
+msgstr "Выделить вÑе видимые конÑтанты и их данные."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible constant items."
-msgstr ""
+msgstr "СнÑть выделение Ñо вÑех видимых конÑтант."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible font items."
-msgstr "Сначала выберите Ñлемент наÑтроек!"
+msgstr "Выбрать вÑе видимые шрифты."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible font items and their data."
-msgstr ""
+msgstr "Выделить вÑе видимые шрифты и их данные."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible font items."
-msgstr ""
+msgstr "СнÑть выделение Ñо вÑех видимых шрифтов."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible icon items."
-msgstr "Сначала выберите Ñлемент наÑтроек!"
+msgstr "Выбрать вÑе видимые иконки."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible icon items and their data."
-msgstr "Сначала выберите Ñлемент наÑтроек!"
+msgstr "Выбрать вÑе видимые иконки и их данные."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Deselect all visible icon items."
-msgstr "Сначала выберите Ñлемент наÑтроек!"
+msgstr "СнÑть выделение Ñо вÑех видимых иконок."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible stylebox items."
-msgstr ""
+msgstr "Выделить вÑе видимые Ñтили."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible stylebox items and their data."
-msgstr ""
+msgstr "Выделить вÑе видимые Ñтили и их данные."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible stylebox items."
-msgstr ""
+msgstr "СнÑть выделение Ñо вÑех видимых Ñтилей."
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
"Caution: Adding icon data may considerably increase the size of your Theme "
"resource."
msgstr ""
+"Внимание: Добавление данных об иконках может значительно увеличить размер "
+"реÑурÑа вашей темы."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Collapse types."
-msgstr "Свернуть вÑе"
+msgstr "Свернуть типы."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Expand types."
-msgstr "Развернуть вÑе"
+msgstr "Развернуть типы."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all Theme items."
-msgstr "Выбрать файл шаблона"
+msgstr "Выбрать вÑе Ñлементы темы."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select With Data"
-msgstr "Выбрать точки"
+msgstr "Выделить Ñ Ð´Ð°Ð½Ð½Ñ‹Ð¼Ð¸"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all Theme items with item data."
-msgstr ""
+msgstr "Выделить вÑе Ñлементы темы Ñ Ð¸Ñ… данными."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Deselect All"
-msgstr "Выделить вÑÑ‘"
+msgstr "СнÑть выделение Ñо вÑего"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all Theme items."
-msgstr ""
+msgstr "СнÑть выделение Ñо вÑех Ñлементов темы."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Import Selected"
-msgstr "Импортировать Ñцену"
+msgstr "Импортировать выделенное"
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
@@ -8781,271 +8716,248 @@ msgid ""
"closing this window.\n"
"Close anyway?"
msgstr ""
+"Ðа вкладке «Импорт Ñлементов» выбраны некоторые Ñлементы. При закрытии Ñтого "
+"окна выбор будет потерÑн.\n"
+"Ð’ÑÑ‘ равно закрыть?"
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Color Items"
-msgstr "Удалить вÑе Ñлементы"
+msgstr "Удалить вÑе цвета"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Item"
-msgstr "Удалить Ñлемент"
+msgstr "Переименовать Ñлемент"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Constant Items"
-msgstr "Удалить вÑе Ñлементы"
+msgstr "Удалить вÑе конÑтанты"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Font Items"
-msgstr "Удалить вÑе Ñлементы"
+msgstr "Удалить вÑе шрифты"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Icon Items"
-msgstr "Удалить вÑе Ñлементы"
+msgstr "Удалить вÑе иконки"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All StyleBox Items"
-msgstr "Удалить вÑе Ñлементы"
+msgstr "Удалить вÑе Ñтили"
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Color Item"
-msgstr "Добавить Ñлемент клаÑÑа"
+msgstr "Добавить цвет"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Constant Item"
-msgstr "Добавить Ñлемент клаÑÑа"
+msgstr "Добавить конÑтанту"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Font Item"
-msgstr "Добавить Ñлемент"
+msgstr "Добавить шрифт"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Icon Item"
-msgstr "Добавить Ñлемент"
+msgstr "Добавить иконку"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Stylebox Item"
-msgstr "Добавить вÑе Ñлементы"
+msgstr "Добавить Ñтиль"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Color Item"
-msgstr "Удалить Ñлемент клаÑÑа"
+msgstr "Переименовать цвет"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Constant Item"
-msgstr "Удалить Ñлемент клаÑÑа"
+msgstr "Переименовать конÑтанту"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Font Item"
-msgstr "Переименовать узел"
+msgstr "Переименовать шрифт"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Icon Item"
-msgstr "Переименовать узел"
+msgstr "Переименовать иконку"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Stylebox Item"
-msgstr "Удалить выбранный Ñлемент"
+msgstr "Удалить Ñтиль"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Invalid file, not a Theme resource."
-msgstr "ÐедопуÑтимый файл, не раÑкладка аудио шины."
+msgstr "Ðеверный файл, не реÑÑƒÑ€Ñ Ñ‚ÐµÐ¼Ñ‹."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Invalid file, same as the edited Theme resource."
-msgstr ""
+msgstr "ÐедопуÑтимый файл, так же, как и редактируемый реÑÑƒÑ€Ñ Ñ‚ÐµÐ¼Ñ‹."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Manage Theme Items"
-msgstr "Управление шаблонами"
+msgstr "Управление Ñлементами темы"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Edit Items"
-msgstr "Редактируемый Ñлемент"
+msgstr "Редактировать Ñлементы"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Types:"
-msgstr "Тип:"
+msgstr "Типы:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Type:"
-msgstr "Тип:"
+msgstr "Добавить тип:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Item:"
-msgstr "Добавить Ñлемент"
+msgstr "Добавить Ñлемент:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add StyleBox Item"
-msgstr "Добавить вÑе Ñлементы"
+msgstr "Добавить Ñтиль"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove Items:"
-msgstr "Удалить Ñлемент"
+msgstr "Удалить Ñлементы:"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove Class Items"
msgstr "Удалить Ñлемент клаÑÑа"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove Custom Items"
-msgstr "Удалить Ñлемент клаÑÑа"
+msgstr "Удалить пользовательÑкие Ñлементы"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Items"
msgstr "Удалить вÑе Ñлементы"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Theme Item"
-msgstr "Тема Ñлементов GUI"
+msgstr "Добавить Ñлемент темы"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Old Name:"
-msgstr "Ð˜Ð¼Ñ ÑƒÐ·Ð»Ð°:"
+msgstr "Старое имÑ:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Import Items"
-msgstr "Импортировать тему"
+msgstr "Импортировать Ñлементы"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Default Theme"
-msgstr "По умолчанию"
+msgstr "Тема по умолчанию"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Editor Theme"
-msgstr "Редактировать тему"
+msgstr "Тема редактора"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select Another Theme Resource:"
-msgstr "Удалить реÑурÑ"
+msgstr "Выбрать другой реÑÑƒÑ€Ñ Ñ‚ÐµÐ¼Ñ‹:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Another Theme"
-msgstr "Импортировать тему"
+msgstr "Ð”Ñ€ÑƒÐ³Ð°Ñ Ñ‚ÐµÐ¼Ð°"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Confirm Item Rename"
-msgstr "Переименовать дорожку"
+msgstr "Подтвердить переименование Ñлемента"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Cancel Item Rename"
-msgstr "Групповое переименование"
+msgstr "Отменить переименование Ñлемента"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Override Item"
-msgstr "Переопределить"
+msgstr "Переопределить Ñлемент"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Unpin this StyleBox as a main style."
-msgstr ""
+msgstr "Открепить Ñтот StyleBox в качеÑтве оÑновного ÑтилÑ."
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
"Pin this StyleBox as a main style. Editing its properties will update the "
"same properties in all other StyleBoxes of this type."
msgstr ""
+"Закрепить Ñтот StyleBox в качеÑтве оÑновного ÑтилÑ. При редактировании его "
+"ÑвойÑтв будут обновлены те же ÑвойÑтва во вÑех других объектах StyleBoxes "
+"Ñтого типа."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Type"
-msgstr "Тип"
+msgstr "Добавить тип"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Item Type"
-msgstr "Добавить Ñлемент"
+msgstr "Добавить тип Ñлемента"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Node Types:"
-msgstr "Тип узла"
+msgstr "Типы узлов:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Show Default"
-msgstr "Загрузить по умолчанию"
+msgstr "Показать по умолчанию"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Show default type items alongside items that have been overridden."
msgstr ""
+"Показывать Ñлементы типа по умолчанию Ñ€Ñдом Ñ Ñлементами, которые были "
+"переопределены."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Override All"
-msgstr "Переопределить"
+msgstr "Переопределить вÑÑ‘"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Override all default type items."
-msgstr ""
+msgstr "Переопределить вÑе Ñлементы типа по умолчанию."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Theme:"
-msgstr "Тема"
+msgstr "Тема:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Manage Items..."
-msgstr "Управление шаблонами ÑкÑпорта..."
+msgstr "Управление Ñлементами..."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add, remove, organize and import Theme items."
-msgstr ""
+msgstr "Добавление, удаление, упорÑдочивание и импорт Ñлементов темы."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Preview"
-msgstr "ПредпроÑмотр"
+msgstr "Добавить превью"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Default Preview"
-msgstr "Обновить предварительный проÑмотр"
+msgstr "Превью по умолчанию"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select UI Scene:"
-msgstr "Выберите иÑточник полиÑетки:"
+msgstr "Выбрать UI-Ñцену:"
#: editor/plugins/theme_editor_preview.cpp
msgid ""
"Toggle the control picker, allowing to visually select control types for "
"edit."
msgstr ""
+"Переключает ÑредÑтво выбора Control, позволÑÑ Ð²Ð¸Ð·ÑƒÐ°Ð»ÑŒÐ½Ð¾ выбирать типы "
+"Control Ð´Ð»Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ."
#: editor/plugins/theme_editor_preview.cpp
msgid "Toggle Button"
@@ -9080,9 +8992,8 @@ msgid "Checked Radio Item"
msgstr "Отмеченный переключатель"
#: editor/plugins/theme_editor_preview.cpp
-#, fuzzy
msgid "Named Separator"
-msgstr "Имен. раздел."
+msgstr "Именованный разделитель"
#: editor/plugins/theme_editor_preview.cpp
msgid "Submenu"
@@ -9135,19 +9046,20 @@ msgstr "ЕÑть,Много,Вариантов"
#: editor/plugins/theme_editor_preview.cpp
msgid "Invalid path, the PackedScene resource was probably moved or removed."
msgstr ""
+"ÐедопуÑтимый путь, реÑÑƒÑ€Ñ PackedScene, вероÑтно, был перемещен или удален."
#: editor/plugins/theme_editor_preview.cpp
msgid "Invalid PackedScene resource, must have a Control node at its root."
msgstr ""
+"ÐедопуÑтимый реÑÑƒÑ€Ñ PackedScene, он должен иметь корневой узел Control."
#: editor/plugins/theme_editor_preview.cpp
-#, fuzzy
msgid "Invalid file, not a PackedScene resource."
-msgstr "ÐедопуÑтимый файл, не раÑкладка аудио шины."
+msgstr "Ðеверный файл, не реÑÑƒÑ€Ñ PackedScene."
#: editor/plugins/theme_editor_preview.cpp
msgid "Reload the scene to reflect its most actual state."
-msgstr ""
+msgstr "Перезагрузите Ñцену, чтобы отразить её наиболее актуальное ÑоÑтоÑние."
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Erase Selection"
@@ -10545,9 +10457,8 @@ msgid "VisualShader"
msgstr "Визуальный шейдер"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Edit Visual Property:"
-msgstr "Редактировать визуальное ÑвойÑтво"
+msgstr "Редактировать визуальное ÑвойÑтво:"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Visual Shader Mode Changed"
@@ -10673,9 +10584,8 @@ msgid "Script"
msgstr "Скрипт"
#: editor/project_export.cpp
-#, fuzzy
msgid "GDScript Export Mode:"
-msgstr "Режим ÑкÑÐ¿Ð¾Ñ€Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñкриптов:"
+msgstr "Режим ÑкÑпорта GDScript:"
#: editor/project_export.cpp
msgid "Text"
@@ -10683,22 +10593,20 @@ msgstr "ТекÑтовый"
#: editor/project_export.cpp
msgid "Compiled Bytecode (Faster Loading)"
-msgstr ""
+msgstr "Скомпилированный байткод (более быÑÑ‚Ñ€Ð°Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ°)"
#: editor/project_export.cpp
msgid "Encrypted (Provide Key Below)"
msgstr "Зашифрованный (Ðапишите ключ ниже)"
#: editor/project_export.cpp
-#, fuzzy
msgid "Invalid Encryption Key (must be 64 hexadecimal characters long)"
msgstr ""
-"ÐедейÑтвительный ключ ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ (длина ключа должна ÑоÑтавлÑть 64 Ñимвола)"
+"Ðеверный ключ ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ (должен ÑоÑтоÑть из 64 шеÑтнадцатеричных Ñимволов)"
#: editor/project_export.cpp
-#, fuzzy
msgid "GDScript Encryption Key (256-bits as hexadecimal):"
-msgstr "Ключ ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñкрипта (256-бит, в шеÑтнадцатеричном виде):"
+msgstr "Ключ ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ GDScript (256 бит, в шеÑтнадцатеричном виде):"
#: editor/project_export.cpp
msgid "Export PCK/Zip"
@@ -10770,7 +10678,6 @@ msgid "Imported Project"
msgstr "Импортированный проект"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Invalid project name."
msgstr "ÐедопуÑтимое Ð¸Ð¼Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ð°."
@@ -10996,14 +10903,12 @@ msgid "Are you sure to run %d projects at once?"
msgstr "Ð’Ñ‹ уверены, что хотите запуÑтить %d проектов одновременно?"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove %d projects from the list?"
-msgstr "Выберите уÑтройÑтво из ÑпиÑка"
+msgstr "Удалить %d проектов из ÑпиÑка?"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove this project from the list?"
-msgstr "Выберите уÑтройÑтво из ÑпиÑка"
+msgstr "Удалить Ñтот проект из ÑпиÑка?"
#: editor/project_manager.cpp
msgid ""
@@ -11035,9 +10940,8 @@ msgid "Project Manager"
msgstr "Менеджер проектов"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Local Projects"
-msgstr "Проекты"
+msgstr "Локальные проекты"
#: editor/project_manager.cpp
msgid "Loading, please wait..."
@@ -11048,23 +10952,20 @@ msgid "Last Modified"
msgstr "ПоÑледнее изменение"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Edit Project"
-msgstr "ЭкÑпортировать проект"
+msgstr "Редактировать проект"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Run Project"
-msgstr "Переименовать проект"
+msgstr "ЗапуÑтить проект"
#: editor/project_manager.cpp
msgid "Scan"
msgstr "Сканировать"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Scan Projects"
-msgstr "Проекты"
+msgstr "Сканировать проекты"
#: editor/project_manager.cpp
msgid "Select a Folder to Scan"
@@ -11075,12 +10976,10 @@ msgid "New Project"
msgstr "Ðовый проект"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Import Project"
-msgstr "Импортированный проект"
+msgstr "Импортировать проект"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove Project"
msgstr "Переименовать проект"
@@ -11093,9 +10992,8 @@ msgid "About"
msgstr "О Godot Engine"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Asset Library Projects"
-msgstr "Библиотека реÑурÑов"
+msgstr "Проекты Библиотеки реÑурÑов"
#: editor/project_manager.cpp
msgid "Restart Now"
@@ -11107,7 +11005,7 @@ msgstr "Удалить вÑе"
#: editor/project_manager.cpp
msgid "Also delete project contents (no undo!)"
-msgstr ""
+msgstr "Также удалить Ñодержимое проекта (Ð½ÐµÐ»ÑŒÐ·Ñ Ð¾Ñ‚Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ!)"
#: editor/project_manager.cpp
msgid "Can't run project"
@@ -11122,18 +11020,16 @@ msgstr ""
"Хотите изучить официальные примеры в Библиотеке реÑурÑов?"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Filter projects"
-msgstr "Фильтр ÑвойÑтв"
+msgstr "Фильтр проектов"
#: editor/project_manager.cpp
-#, fuzzy
msgid ""
"This field filters projects by name and last path component.\n"
"To filter projects by name and full path, the query must contain at least "
"one `/` character."
msgstr ""
-"Поле поиÑка фильтрует проекты по имени и поÑледнему компоненту пути\n"
+"Это поле фильтрует проекты по имени и поÑледнему компоненту пути.\n"
"Чтобы отфильтровать проекты по имени и полному пути, Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð´Ð¾Ð»Ð¶ÐµÐ½ Ñодержать "
"Ñ…Ð¾Ñ‚Ñ Ð±Ñ‹ один Ñимвол `/`."
@@ -11143,7 +11039,7 @@ msgstr "Клавиша "
#: editor/project_settings_editor.cpp
msgid "Physical Key"
-msgstr ""
+msgstr "ФизичеÑÐºÐ°Ñ ÐºÐ»Ð°Ð²Ð¸ÑˆÐ°"
#: editor/project_settings_editor.cpp
msgid "Joy Button"
@@ -11191,7 +11087,7 @@ msgstr "УÑтройÑтво"
#: editor/project_settings_editor.cpp
msgid " (Physical)"
-msgstr ""
+msgstr " (ФизичеÑкаÑ)"
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "Press a Key..."
@@ -11334,23 +11230,20 @@ msgid "Override for Feature"
msgstr "Переопределение ÑвойÑтва"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Add %d Translations"
-msgstr "Добавить перевод"
+msgstr "Добавить %d переводов"
#: editor/project_settings_editor.cpp
msgid "Remove Translation"
msgstr "Удалить перевод"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Translation Resource Remap: Add %d Path(s)"
-msgstr "Перенаправлен реÑÑƒÑ€Ñ Ð¿ÐµÑ€ÐµÐ½Ð°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ"
+msgstr "Переназначение реÑурÑов перевода: Добавить %d путь(ей)"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Translation Resource Remap: Add %d Remap(s)"
-msgstr "Перенаправлен реÑÑƒÑ€Ñ Ð¿ÐµÑ€ÐµÐ½Ð°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ"
+msgstr "Переназначение реÑурÑов перевода: Добавить %d переназначение(ий)"
#: editor/project_settings_editor.cpp
msgid "Change Resource Remap Language"
@@ -11766,7 +11659,7 @@ msgstr "Узел должен принадлежать редактируемоÐ
#: editor/scene_tree_dock.cpp
msgid "Instantiated scenes can't become root"
-msgstr "ИнÑтанцированные Ñцены не могут Ñтать корневыми"
+msgstr "ИнÑтанцированные Ñцены не могут Ñтать корнем"
#: editor/scene_tree_dock.cpp
msgid "Make node as Root"
@@ -11796,12 +11689,16 @@ msgstr "Удалить узел «%s»?"
msgid ""
"Saving the branch as a scene requires having a scene open in the editor."
msgstr ""
+"Ð”Ð»Ñ ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð²ÐµÑ‚ÐºÐ¸ как Ñцены необходимо, чтобы Ñцена была открыта в "
+"редакторе."
#: editor/scene_tree_dock.cpp
msgid ""
"Saving the branch as a scene requires selecting only one node, but you have "
"selected %d nodes."
msgstr ""
+"Ð”Ð»Ñ ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð²ÐµÑ‚Ð²Ð¸ как Ñцены требуетÑÑ Ð²Ñ‹Ð±Ñ€Ð°Ñ‚ÑŒ только один узел, но вы "
+"выбрали %d узлов."
#: editor/scene_tree_dock.cpp
msgid ""
@@ -11810,6 +11707,12 @@ msgid ""
"FileSystem dock context menu\n"
"or create an inherited scene using Scene > New Inherited Scene... instead."
msgstr ""
+"Ðевозможно Ñохранить ветку корневого узла в качеÑтве инÑтанцированной "
+"Ñцены.\n"
+"Чтобы Ñоздать редактируемую копию текущей Ñцены, продублируйте её Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ "
+"контекÑтного меню панели Â«Ð¤Ð°Ð¹Ð»Ð¾Ð²Ð°Ñ ÑиÑтема»\n"
+"или Ñоздайте унаÑледованную Ñцену, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ð²Ð¼ÐµÑто Ñтого Сцена > ÐÐ¾Ð²Ð°Ñ "
+"унаÑÐ»ÐµÐ´Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ñцена..."
#: editor/scene_tree_dock.cpp
msgid ""
@@ -11817,6 +11720,10 @@ msgid ""
"To create a variation of a scene, you can make an inherited scene based on "
"the instanced scene using Scene > New Inherited Scene... instead."
msgstr ""
+"Ðевозможно Ñохранить ветку уже инÑтанцированной Ñцены.\n"
+"Чтобы Ñоздать вариант Ñцены, вы можете Ñоздать унаÑледованную Ñцену на "
+"оÑнове инÑтанцированной Ñцены, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ð²Ð¼ÐµÑто Ñтого Сцена > ÐÐ¾Ð²Ð°Ñ "
+"унаÑÐ»ÐµÐ´Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ñцена..."
#: editor/scene_tree_dock.cpp
msgid "Save New Scene As..."
@@ -12225,6 +12132,8 @@ msgid ""
"Warning: Having the script name be the same as a built-in type is usually "
"not desired."
msgstr ""
+"Предупреждение: Обычно нежелательно, чтобы Ð¸Ð¼Ñ Ñкрипта Ñовпадало Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ "
+"вÑтроенного типа."
#: editor/script_create_dialog.cpp
msgid "Class Name:"
@@ -12296,7 +12205,7 @@ msgstr "Копировать ошибку"
#: editor/script_editor_debugger.cpp
msgid "Open C++ Source on GitHub"
-msgstr ""
+msgstr "Открытый иÑходный код C++ на GitHub"
#: editor/script_editor_debugger.cpp
msgid "Video RAM"
@@ -12475,6 +12384,16 @@ msgstr "Изменить выÑоту цилиндра"
msgid "Change Ray Shape Length"
msgstr "Изменить длину луча"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "УÑтановить положение точки кривой"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "УÑтановить положение точки кривой"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "Изменить Ñ€Ð°Ð´Ð¸ÑƒÑ Ñ†Ð¸Ð»Ð¸Ð½Ð´Ñ€Ð°"
@@ -12585,14 +12504,12 @@ msgid "Object can't provide a length."
msgstr "Объект не может предоÑтавить длину."
#: modules/gltf/editor_scene_exporter_gltf_plugin.cpp
-#, fuzzy
msgid "Export Mesh GLTF2"
-msgstr "ЭкÑпортировать библиотеку полиÑеток"
+msgstr "ЭкÑпорт полиÑетки GLTF2"
#: modules/gltf/editor_scene_exporter_gltf_plugin.cpp
-#, fuzzy
msgid "Export GLTF..."
-msgstr "ЭкÑпортировать..."
+msgstr "ЭкÑпорт GLTF..."
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Next Plane"
@@ -12624,20 +12541,19 @@ msgstr "Удалить выделенную Ñетку"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "GridMap Fill Selection"
-msgstr "Залить выделенную GridMap"
+msgstr "Залить выделенную Ñетку"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "GridMap Paste Selection"
-msgstr "Ð’Ñтавка выделенной Ñетки"
+msgstr "Ð’Ñтавить выделенную Ñетку"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "GridMap Paint"
msgstr "РиÑование Ñетки"
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "GridMap Selection"
-msgstr "Залить выделенную GridMap"
+msgstr "Выделение Ñетки"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Grid Map"
@@ -12653,11 +12569,11 @@ msgstr "Отключить обрезку"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Clip Above"
-msgstr "Отрезать Ñверху"
+msgstr "Обрезать Ñверху"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Clip Below"
-msgstr "Отрезать Ñнизу"
+msgstr "Обрезать Ñнизу"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Edit X Axis"
@@ -12889,14 +12805,12 @@ msgid "Add Output Port"
msgstr "Добавить выходной порт"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Change Port Type"
-msgstr "Изменить тип"
+msgstr "Изменить тип порта"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Change Port Name"
-msgstr "Изменить Ð¸Ð¼Ñ Ð²Ñ…Ð¾Ð´Ð½Ð¾Ð³Ð¾ порта"
+msgstr "Изменить Ð¸Ð¼Ñ Ð¿Ð¾Ñ€Ñ‚Ð°"
#: modules/visual_script/visual_script_editor.cpp
msgid "Override an existing built-in function."
@@ -13011,9 +12925,8 @@ msgid "Add Preload Node"
msgstr "Добавить предзагрузочный узел"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Node(s)"
-msgstr "Добавить узел"
+msgstr "Добавить узел(узлы)"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Node(s) From Tree"
@@ -13276,37 +13189,31 @@ msgstr "Выберите уÑтройÑтво из ÑпиÑка"
#: platform/android/export/export.cpp
msgid "Running on %s"
-msgstr ""
+msgstr "ВыполнÑетÑÑ Ð½Ð° %s"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Exporting APK..."
-msgstr "ЭкÑпорт вÑех"
+msgstr "ЭкÑпорт APK..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Uninstalling..."
-msgstr "Удалить"
+msgstr "Удаление..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Installing to device, please wait..."
-msgstr "Загрузка, пожалуйÑта, ждите..."
+msgstr "УÑтановка на уÑтройÑтво, пожалуйÑта, ждите..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not install to device: %s"
-msgstr "Ðе возможно добавить Ñцену!"
+msgstr "Ðе удалоÑÑŒ уÑтановить на уÑтройÑтво: %s"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Running on device..."
-msgstr "ЗапуÑк пользовательÑкого Ñкрипта..."
+msgstr "ЗапуÑк на уÑтройÑтве..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not execute on device."
-msgstr "Ðевозможно Ñоздать папку."
+msgstr "Ðе удалоÑÑŒ выполнить на уÑтройÑтве."
#: platform/android/export/export.cpp
msgid "Unable to find the 'apksigner' tool."
@@ -13431,40 +13338,37 @@ msgid ""
"directory.\n"
"The resulting %s is unsigned."
msgstr ""
+"Ðе удалоÑÑŒ найти команду «apksigner».\n"
+"ПожалуйÑта, проверьте наличие программы в каталоге Android SDK build-tools.\n"
+"Результат %s не подпиÑан."
#: platform/android/export/export.cpp
msgid "Signing debug %s..."
-msgstr ""
+msgstr "ПодпиÑание отладочного %s..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Signing release %s..."
-msgstr ""
-"Сканирование файлов,\n"
-"пожалуйÑта, ждите..."
+msgstr "ПодпиÑание релиза %s..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not find keystore, unable to export."
-msgstr "Ðе удалоÑÑŒ открыть шаблон Ð´Ð»Ñ ÑкÑпорта:"
+msgstr "Ðе удалоÑÑŒ найти хранилище ключей, невозможно ÑкÑпортировать."
#: platform/android/export/export.cpp
msgid "'apksigner' returned with error #%d"
-msgstr ""
+msgstr "«apksigner» завершилÑÑ Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ¾Ð¹ #%d"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Verifying %s..."
-msgstr "Добавление %s..."
+msgstr "Проверка %s..."
#: platform/android/export/export.cpp
msgid "'apksigner' verification of %s failed."
-msgstr ""
+msgstr "Проверка «apksigner» «%s» не удалаÑÑŒ."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Exporting for Android"
-msgstr "ЭкÑпорт вÑех"
+msgstr "ЭкÑпорт Ð´Ð»Ñ Android"
#: platform/android/export/export.cpp
msgid "Invalid filename! Android App Bundle requires the *.aab extension."
@@ -13480,7 +13384,7 @@ msgstr "Ðеверное Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°! Android APK требует раÑшÐ
#: platform/android/export/export.cpp
msgid "Unsupported export format!\n"
-msgstr ""
+msgstr "Ðеподдерживаемый формат ÑкÑпорта!\n"
#: platform/android/export/export.cpp
msgid ""
@@ -13506,16 +13410,15 @@ msgstr ""
msgid ""
"Unable to overwrite res://android/build/res/*.xml files with project name"
msgstr ""
+"Ðевозможно перезапиÑать файлы res://android/build/res/*.xml Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ проекта"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not export project files to gradle project\n"
-msgstr "ОтÑутÑтвует project.godot в папке проекта."
+msgstr "Ðе удалоÑÑŒ ÑкÑпортировать файлы проекта в проект gradle\n"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not write expansion package file!"
-msgstr "Ðе удалоÑÑŒ запиÑать файл:"
+msgstr "Ðе удалоÑÑŒ запиÑать раÑширение файла пакета!"
#: platform/android/export/export.cpp
msgid "Building Android Project (gradle)"
@@ -13543,21 +13446,20 @@ msgstr ""
"проекта gradle на наличие выходных данных."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Package not found: %s"
-msgstr "ÐÐ½Ð¸Ð¼Ð°Ñ†Ð¸Ñ Ð½Ðµ найдена: %s"
+msgstr "Пакет не найден: %s"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Creating APK..."
-msgstr "Создание контуров..."
+msgstr "Создание APK..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid ""
"Could not find template APK to export:\n"
"%s"
-msgstr "Ðе удалоÑÑŒ открыть шаблон Ð´Ð»Ñ ÑкÑпорта:"
+msgstr ""
+"Ðе удалоÑÑŒ найти шаблон APK Ð´Ð»Ñ ÑкÑпорта:\n"
+"%s"
#: platform/android/export/export.cpp
msgid ""
@@ -13566,16 +13468,17 @@ msgid ""
"Please build a template with all required libraries, or uncheck the missing "
"architectures in the export preset."
msgstr ""
+"Ð’ шаблоне ÑкÑпорта отÑутÑтвуют библиотеки Ð´Ð»Ñ Ð²Ñ‹Ð±Ñ€Ð°Ð½Ð½Ñ‹Ñ… архитектур: %s.\n"
+"ПожалуйÑта, Ñоздайте шаблон Ñо вÑеми необходимыми библиотеками или Ñнимите "
+"флажки Ñ Ð¾Ñ‚ÑутÑтвующих архитектур в преÑете ÑкÑпорта."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Adding files..."
-msgstr "Добавление %s..."
+msgstr "Добавление файлов..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not export project files"
-msgstr "Ðе удалоÑÑŒ запиÑать файл:"
+msgstr "Ðе удалоÑÑŒ ÑкÑпортировать файлы проекта"
#: platform/android/export/export.cpp
msgid "Aligning APK..."
@@ -13583,7 +13486,7 @@ msgstr "Выравнивание APK..."
#: platform/android/export/export.cpp
msgid "Could not unzip temporary unaligned APK."
-msgstr ""
+msgstr "Ðе удалоÑÑŒ раÑпаковать временный невыровненный APK."
#: platform/iphone/export/export.cpp platform/osx/export/export.cpp
msgid "Identifier is missing."
@@ -13630,45 +13533,40 @@ msgid "Could not write file:"
msgstr "Ðе удалоÑÑŒ запиÑать файл:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not read file:"
-msgstr "Ðе удалоÑÑŒ запиÑать файл:"
+msgstr "Ðе удалоÑÑŒ прочитать файл:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not read HTML shell:"
-msgstr "Ðе удалоÑÑŒ прочитать пользовательÑкую HTML оболочку:"
+msgstr "Ðе удалоÑÑŒ прочитать HTML-оболочку:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not create HTTP server directory:"
-msgstr "Ðевозможно Ñоздать папку."
+msgstr "Ðе удалоÑÑŒ Ñоздать каталог HTTP-Ñервера:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Error starting HTTP server:"
-msgstr "Ошибка ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ñцены."
+msgstr "Ошибка запуÑка HTTP-Ñервера:"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Invalid bundle identifier:"
-msgstr "Ðеверный идентификатор:"
+msgstr "Ðеверный идентификатор пакета:"
#: platform/osx/export/export.cpp
msgid "Notarization: code signing required."
-msgstr ""
+msgstr "Предупреждение: требуетÑÑ Ð¿Ð¾Ð´Ð¿Ð¸Ñание кода."
#: platform/osx/export/export.cpp
msgid "Notarization: hardened runtime required."
-msgstr ""
+msgstr "Предупреждение: требуетÑÑ ÑƒÑиленный рантайм."
#: platform/osx/export/export.cpp
msgid "Notarization: Apple ID name not specified."
-msgstr ""
+msgstr "Предупреждение: Ð¸Ð¼Ñ Apple ID не указано."
#: platform/osx/export/export.cpp
msgid "Notarization: Apple ID password not specified."
-msgstr ""
+msgstr "Предупреждение: пароль Apple ID не указан."
#: platform/uwp/export/export.cpp
msgid "Invalid package short name."
@@ -14102,6 +14000,9 @@ msgid ""
"longer has any effect.\n"
"To remove this warning, disable the GIProbe's Compress property."
msgstr ""
+"СвойÑтво GIProbe Compress было объÑвлено уÑтаревшим из-за извеÑтных ошибок и "
+"больше не имеет никакого Ñффекта.\n"
+"Чтобы убрать Ñто предупреждение, отключите ÑвойÑтво Compress в GIProbe."
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
@@ -14187,15 +14088,15 @@ msgstr "Узел Ри Узел В должны быть различными о
#: scene/3d/portal.cpp
msgid "The RoomManager should not be a child or grandchild of a Portal."
-msgstr ""
+msgstr "RoomManager не должен быть ребёнком или внуком Portal."
#: scene/3d/portal.cpp
msgid "A Room should not be a child or grandchild of a Portal."
-msgstr ""
+msgstr "Room не должен быть ребёнком или внуком Portal."
#: scene/3d/portal.cpp
msgid "A RoomGroup should not be a child or grandchild of a Portal."
-msgstr ""
+msgstr "RoomGroup не должен быть ребёнком или внуком Portal."
#: scene/3d/remote_transform.cpp
msgid ""
@@ -14207,42 +14108,83 @@ msgstr ""
#: scene/3d/room.cpp
msgid "A Room cannot have another Room as a child or grandchild."
-msgstr ""
+msgstr "Room не должен быть ребёнком или внуком другого Room."
#: scene/3d/room.cpp
msgid "The RoomManager should not be placed inside a Room."
-msgstr ""
+msgstr "RoomManager не должен раÑполагатьÑÑ Ð²Ð½ÑƒÑ‚Ñ€Ð¸ Room."
#: scene/3d/room.cpp
msgid "A RoomGroup should not be placed inside a Room."
-msgstr ""
+msgstr "RoomGroup не должен раÑполагатьÑÑ Ð²Ð½ÑƒÑ‚Ñ€Ð¸ Room."
#: scene/3d/room.cpp
msgid ""
"Room convex hull contains a large number of planes.\n"
"Consider simplifying the room bound in order to increase performance."
msgstr ""
+"Выпуклый ÐºÐ¾Ñ€Ð¿ÑƒÑ ÐºÐ¾Ð¼Ð½Ð°Ñ‚Ñ‹ Ñодержит большое количеÑтво плоÑкоÑтей.\n"
+"РаÑÑмотрите возможноÑть ÑƒÐ¿Ñ€Ð¾Ñ‰ÐµÐ½Ð¸Ñ Ð³Ñ€Ð°Ð½Ð¸Ñ†Ñ‹ комнаты Ð´Ð»Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐµÐ½Ð¸Ñ "
+"производительноÑти."
#: scene/3d/room_group.cpp
msgid "The RoomManager should not be placed inside a RoomGroup."
-msgstr ""
+msgstr "RoomManager не должен раÑполагатьÑÑ Ð²Ð½ÑƒÑ‚Ñ€Ð¸ RoomGroup."
#: scene/3d/room_manager.cpp
msgid "The RoomList has not been assigned."
-msgstr ""
+msgstr "RoomList не был назначен."
#: scene/3d/room_manager.cpp
msgid "The RoomList node should be a Spatial (or derived from Spatial)."
-msgstr ""
+msgstr "Узел RoomList должен быть Spatial (или унаÑледован от Spatial)."
#: scene/3d/room_manager.cpp
msgid ""
"Portal Depth Limit is set to Zero.\n"
"Only the Room that the Camera is in will render."
msgstr ""
+"Portal Depth Limit уÑтановлено на ноль.\n"
+"Будет отриÑовыватьÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ комната, в которой находитÑÑ ÐºÐ°Ð¼ÐµÑ€Ð°."
#: scene/3d/room_manager.cpp
msgid "There should only be one RoomManager in the SceneTree."
+msgstr "В SceneTree должен быть только один RoomManager."
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
msgstr ""
#: scene/3d/soft_body.cpp
@@ -14309,7 +14251,7 @@ msgstr "ÐÐ½Ð¸Ð¼Ð°Ñ†Ð¸Ñ Ð½Ðµ найдена: %s"
#: scene/animation/animation_player.cpp
msgid "Anim Apply Reset"
-msgstr ""
+msgstr "ÐÐ½Ð¸Ð¼Ð°Ñ†Ð¸Ñ - Применить ÑброÑ"
#: scene/animation/animation_tree.cpp
msgid "In node '%s', invalid animation: '%s'."
@@ -14484,25 +14426,28 @@ msgid "Invalid comparison function for that type."
msgstr "ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ ÑÑ€Ð°Ð²Ð½ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ñтого типа."
#: servers/visual/shader_language.cpp
-#, fuzzy
msgid "Varying may not be assigned in the '%s' function."
-msgstr "Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ быть назначены только в функции вершины."
+msgstr "Varying не может быть задано в функции «%s»."
#: servers/visual/shader_language.cpp
msgid ""
"Varyings which assigned in 'vertex' function may not be reassigned in "
"'fragment' or 'light'."
msgstr ""
+"Varying, заданные в функции «vertex», не могут быть изменены в «fragment» "
+"или «light»."
#: servers/visual/shader_language.cpp
msgid ""
"Varyings which assigned in 'fragment' function may not be reassigned in "
"'vertex' or 'light'."
msgstr ""
+"Varying, заданные в функции «fragment», не могут быть изменены в «vertex» "
+"или «light»."
#: servers/visual/shader_language.cpp
msgid "Fragment-stage varying could not been accessed in custom function!"
-msgstr ""
+msgstr "Varying Ñтадии fragment не доÑтупны из пользовательÑких функций!"
#: servers/visual/shader_language.cpp
msgid "Assignment to function."
@@ -15507,9 +15452,6 @@ msgstr "КонÑтанты не могут быть изменены."
#~ msgid "I see..."
#~ msgstr "ЯÑно..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "Ðе удаётÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ '%s'."
-
#~ msgid "Ugh"
#~ msgstr "ЯÑно"
diff --git a/editor/translations/si.po b/editor/translations/si.po
index 94841d0879..595e0041a9 100644
--- a/editor/translations/si.po
+++ b/editor/translations/si.po
@@ -348,6 +348,7 @@ msgstr "සජීවීකරණ පුනරà·à·€à¶»à·Šà¶®à¶±à¶º"
msgid "Remove Anim Track"
msgstr "Anim ලුහුබදින්න෠ඉවත් කරන්න"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "%s සදහ෠නව ලුහුබදින්නෙත් à·ƒà·à¶¯à· යතුරක් ඇතුලත් කරන්න?"
@@ -372,10 +373,27 @@ msgstr "à·ƒà·à¶¯à¶±à·Šà¶±"
msgid "Anim Insert"
msgstr "Anim ඇතුලත් කරන්න"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "à·à·Šâ€à¶»à·’à¶­:"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "සජීවීකරණ à¶°à·à·€à¶šà¶º තමà·à¶§à¶¸ සජීවීකරණය à¶šà¶½ නොහà·à¶š, අනෙක් à¶°à·à·€à¶š පමණි."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "ලක්ෂණය ලුහුබදින්න"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Anim à·ƒà·à¶¯à¶±à·Šà¶± සහ ඇතුලත් කරන්න"
@@ -942,7 +960,7 @@ msgstr ""
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2237,6 +2255,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3017,10 +3046,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
#, fuzzy
msgid "Update Continuously"
msgstr "අඛණ්ඩව"
@@ -3627,6 +3652,14 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+msgid "Open in Web Browser"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8341,6 +8374,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Color Items"
msgstr ""
@@ -8367,6 +8406,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
msgstr ""
@@ -11809,6 +11854,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13418,6 +13471,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/sk.po b/editor/translations/sk.po
index 6deda77711..54736cff85 100644
--- a/editor/translations/sk.po
+++ b/editor/translations/sk.po
@@ -346,6 +346,7 @@ msgstr "Zmeniť Loop Mode Animacie"
msgid "Remove Anim Track"
msgstr "Vymazať Track Animácie"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "VytvoriÅ¥ NOVà track za %s a vložiÅ¥ kľúÄ?"
@@ -370,10 +371,27 @@ msgstr "Vytvoriť"
msgid "Anim Insert"
msgstr "Animácia Vložiť"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animácie"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "AnimationPlayer nemôže animovaÅ¥ sám seba, iba ostatný hráÄi."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Vlastnosť"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Animácia Vytvoriť & Vložiť"
@@ -945,7 +963,7 @@ msgstr "Vytvoriť Nový %s"
msgid "No results for \"%s\"."
msgstr "Žiadne výsledky pre \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2295,6 +2313,17 @@ msgid "New Window"
msgstr "Nové Okno"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "OtáÄa sa, keÄ sa okno editora redistribuuje."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Importované zdroje nemôžu byť uložené."
@@ -3150,10 +3179,6 @@ msgid "Save & Restart"
msgstr "Uložiť & Reštartovať"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "OtáÄa sa, keÄ sa okno editora redistribuuje."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Aktualizovať priebežne"
@@ -3812,6 +3837,15 @@ msgid "Download from:"
msgstr "Chyba SÅ¥ahovania"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Otvoriť v File Manažérovy"
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8677,6 +8711,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Všetky vybrané"
@@ -8707,6 +8747,12 @@ msgid "Remove All StyleBox Items"
msgstr "Všetky vybrané"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Pridať do Obľúbených"
@@ -12299,6 +12345,16 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Všetky vybrané"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Všetky vybrané"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13978,6 +14034,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/sl.po b/editor/translations/sl.po
index 53b4bca499..725f88f0ab 100644
--- a/editor/translations/sl.po
+++ b/editor/translations/sl.po
@@ -369,6 +369,7 @@ msgstr "Spremeni Zanko Animacije"
msgid "Remove Anim Track"
msgstr "Odstrani animacijsko sled"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Ustvarim NOVO sled za %s in vstavi kljuÄ?"
@@ -393,10 +394,28 @@ msgstr "Ustvari"
msgid "Anim Insert"
msgstr "Vstavi Animacijo"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "NaÄin Zaskoka (%s)"
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animacija"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Lastnosti"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Ustvari & Vstavi Animacijo"
@@ -998,7 +1017,7 @@ msgstr "Ustvari Nov %s"
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2397,6 +2416,18 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+#, fuzzy
+msgid "Spins when the editor window redraws."
+msgstr "Vrti se ob spremembi okna urejevalnika!"
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3270,11 +3301,6 @@ msgstr "Shrani & Zapri"
#: editor/editor_node.cpp
#, fuzzy
-msgid "Spins when the editor window redraws."
-msgstr "Vrti se ob spremembi okna urejevalnika!"
-
-#: editor/editor_node.cpp
-#, fuzzy
msgid "Update Continuously"
msgstr "Neprekinjeno"
@@ -3922,6 +3948,15 @@ msgid "Download from:"
msgstr "Napaka Pri Prenosu"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Pokaži V Upravitelju Datotek"
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8959,6 +8994,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Odstrani Vse Stvari"
@@ -8989,6 +9030,12 @@ msgid "Remove All StyleBox Items"
msgstr "Odstrani Vse Stvari"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Priljubljene:"
@@ -12643,6 +12690,16 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Nastavi Položaj Krivuljne ToÄke"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Nastavi Položaj Krivuljne ToÄke"
+
#: modules/csg/csg_gizmos.cpp
#, fuzzy
msgid "Change Cylinder Radius"
@@ -14339,6 +14396,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
@@ -14856,9 +14949,6 @@ msgstr "Konstante ni možno spreminjati."
#~ msgid "Scale Mode (R)"
#~ msgstr "NaÄin Obsega (R)"
-#~ msgid "Snap Mode (%s)"
-#~ msgstr "NaÄin Zaskoka (%s)"
-
#~ msgid "Tool Select"
#~ msgstr "Izbira Orodja"
diff --git a/editor/translations/sq.po b/editor/translations/sq.po
index f843d97c4e..ded08d5532 100644
--- a/editor/translations/sq.po
+++ b/editor/translations/sq.po
@@ -342,6 +342,7 @@ msgstr "Ndrysho Metodën e Përsëritjes së Animacionit"
msgid "Remove Anim Track"
msgstr ""
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr ""
@@ -366,10 +367,27 @@ msgstr "Krijo"
msgid "Anim Insert"
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animacionet:"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Vetitë:"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr ""
@@ -938,7 +956,7 @@ msgstr "Krijo %s të ri"
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2330,6 +2348,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Rrotullohet kur dritarja e editorit rivizaton."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Resurset e importuara nuk mund të ruhen."
@@ -3207,10 +3236,6 @@ msgid "Save & Restart"
msgstr "Ruaj & Rifillo"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Rrotullohet kur dritarja e editorit rivizaton."
-
-#: editor/editor_node.cpp
#, fuzzy
msgid "Update Continuously"
msgstr "I Vazhdueshëm"
@@ -3863,6 +3888,15 @@ msgid "Download from:"
msgstr "Shkarko"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Hap në Menaxherin e Skedarëve"
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8684,6 +8718,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Hiq Autoload-in"
@@ -8714,6 +8754,12 @@ msgid "Remove All StyleBox Items"
msgstr "Hiq Autoload-in"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Shto te të preferuarat"
@@ -12247,6 +12293,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13891,6 +13945,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/sr_Cyrl.po b/editor/translations/sr_Cyrl.po
index f95781bd70..0a915e03bf 100644
--- a/editor/translations/sr_Cyrl.po
+++ b/editor/translations/sr_Cyrl.po
@@ -382,6 +382,7 @@ msgstr "Промени Ñ†Ð¸ÐºÐ»ÑƒÑ Ð°Ð½Ð¸Ð¼Ð°Ñ†Ð¸Ñ˜Ðµ"
msgid "Remove Anim Track"
msgstr "Обриши траку анимације"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Ðаправите нову траку за %s и убаците кључ?"
@@ -406,11 +407,29 @@ msgstr "Ðаправи"
msgid "Anim Insert"
msgstr "Ðалепи"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "Режим лепљења:"
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Ðнимација"
+
#: editor/animation_track_editor.cpp
#, fuzzy
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "AnimationPlayer не може Ñам Ñебе да анимира, Ñамо друге плејере."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "ОÑобина %s' не поÑтоји."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Ðаправи анимацију и убаци"
@@ -1051,7 +1070,7 @@ msgstr "Ðаправи нов"
msgid "No results for \"%s\"."
msgstr "Ðема резултата за \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2502,6 +2521,18 @@ msgid "New Window"
msgstr "Ðов Прозор"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+#, fuzzy
+msgid "Spins when the editor window redraws."
+msgstr "Окрене Ñе кад Ñе едиторÑки прозор поново обоји!"
+
+#: editor/editor_node.cpp
#, fuzzy
msgid "Imported resources can't be saved."
msgstr "Увезени реÑурÑи не могу бити упамћени."
@@ -3397,11 +3428,6 @@ msgstr "Сачувај и изађи"
#: editor/editor_node.cpp
#, fuzzy
-msgid "Spins when the editor window redraws."
-msgstr "Окрене Ñе кад Ñе едиторÑки прозор поново обоји!"
-
-#: editor/editor_node.cpp
-#, fuzzy
msgid "Update Continuously"
msgstr "Трајан"
@@ -4106,6 +4132,16 @@ msgid "Download from:"
msgstr "Грешка при преузимању"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Покрени у Претраживачу"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Копирај Грешку"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -9423,6 +9459,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Обриши Ñве Ñтавке"
@@ -9453,6 +9495,12 @@ msgid "Remove All StyleBox Items"
msgstr "Обриши Ñве Ñтавке"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Додај Ñтавке клаÑе"
@@ -13751,6 +13799,16 @@ msgstr "Промени ВиÑину Цилиндар Облика"
msgid "Change Ray Shape Length"
msgstr "Промени Дужину Зрак Облика"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "ПоÑтави позицију тачке криве"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "ПоÑтави позицију тачке криве"
+
#: modules/csg/csg_gizmos.cpp
#, fuzzy
msgid "Change Cylinder Radius"
@@ -15695,6 +15753,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
#, fuzzy
msgid "This body will be ignored until you set a mesh."
@@ -16456,10 +16550,6 @@ msgstr "КонÑтанте није могуће мењати."
#~ msgid "Local Coords"
#~ msgstr "Локалне координате"
-#, fuzzy
-#~ msgid "Snap Mode (%s)"
-#~ msgstr "Режим лепљења:"
-
#~ msgid "Tool Select"
#~ msgstr "Избор алатки"
diff --git a/editor/translations/sr_Latn.po b/editor/translations/sr_Latn.po
index 877149b6ea..76982c0b00 100644
--- a/editor/translations/sr_Latn.po
+++ b/editor/translations/sr_Latn.po
@@ -356,6 +356,7 @@ msgstr "Optimizuj Animaciju"
msgid "Remove Anim Track"
msgstr "Odstrani Kanal Animacije"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Napravi Novi kanal za %s i dodaj kljuÄ?"
@@ -380,10 +381,26 @@ msgstr "Napravi"
msgid "Anim Insert"
msgstr "Animacija Umetni"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Optimizuj Animaciju"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Animacija Napravi i Dodaj"
@@ -950,7 +967,7 @@ msgstr ""
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2250,6 +2267,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3033,10 +3061,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
#, fuzzy
msgid "Update Continuously"
msgstr "Neprekidna"
@@ -3646,6 +3670,14 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+msgid "Open in Web Browser"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8405,6 +8437,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Color Items"
msgstr ""
@@ -8432,6 +8470,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
msgstr ""
@@ -11915,6 +11959,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13530,6 +13582,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/sv.po b/editor/translations/sv.po
index 7433664d25..373e3aad36 100644
--- a/editor/translations/sv.po
+++ b/editor/translations/sv.po
@@ -14,7 +14,7 @@
# Mattias Münster <mattiasmun@gmail.com>, 2019.
# Anonymous <noreply@weblate.org>, 2020.
# Joakim Lundberg <joakim@joakimlundberg.com>, 2020.
-# Kristoffer Grundström <swedishsailfishosuser@tutanota.com>, 2020.
+# Kristoffer Grundström <swedishsailfishosuser@tutanota.com>, 2020, 2021.
# Jonas Robertsson <jonas.robertsson@posteo.net>, 2020, 2021.
# André Andersson <andre.eric.andersson@gmail.com>, 2020.
# Andreas Westrell <andreas.westrell@gmail.com>, 2020.
@@ -27,8 +27,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-07-13 06:13+0000\n"
-"Last-Translator: Leon <joel.lundborg@gmail.com>\n"
+"PO-Revision-Date: 2021-08-10 21:40+0000\n"
+"Last-Translator: Kristoffer Grundström <swedishsailfishosuser@tutanota.com>\n"
"Language-Team: Swedish <https://hosted.weblate.org/projects/godot-engine/"
"godot/sv/>\n"
"Language: sv\n"
@@ -36,7 +36,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.7.2-dev\n"
+"X-Generator: Weblate 4.8-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -357,6 +357,7 @@ msgstr "Ändra Animationsslingläge"
msgid "Remove Anim Track"
msgstr "Ta bort Anim spår"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Skapa NYTT spår för %s och infoga nyckel?"
@@ -381,11 +382,29 @@ msgstr "Skapa"
msgid "Anim Insert"
msgstr "Anim Infoga"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "Kan inte öppna '%s'."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animation"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
"Animationsspelaren kan inte animera sig själv, utan bara andra spelare."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Egenskaper"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Anim Skapa & Infoga"
@@ -473,7 +492,7 @@ msgstr "Anim Flytta Nycklar"
#: editor/animation_track_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Clipboard is empty!"
-msgstr ""
+msgstr "Klippbordet är tomt!"
#: editor/animation_track_editor.cpp
msgid "Paste Tracks"
@@ -943,9 +962,8 @@ msgid "Edit..."
msgstr "Ändra..."
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Go to Method"
-msgstr "GÃ¥ Till Metod"
+msgstr "GÃ¥ till metod"
#: editor/create_dialog.cpp
msgid "Change %s Type"
@@ -963,9 +981,9 @@ msgstr "Skapa Ny %s"
msgid "No results for \"%s\"."
msgstr "Inga resultat för \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
-msgstr ""
+msgstr "Ingen beskrivning tillgänglig för %s."
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp
@@ -1075,7 +1093,6 @@ msgstr ""
"Du kan hitta de borttagna filerna i systemets papperskorg."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1083,9 +1100,10 @@ msgid ""
"Depending on your filesystem configuration, the files will either be moved "
"to the system trash or deleted permanently."
msgstr ""
-"Filerna som tas bort krävs av andra resurser för att de ska fungera.\n"
-"Ta bort dem ändå? (går inte ångra)\n"
-"Du kan hitta de borttagna filerna i systemets papperskorg."
+"Filerna som ska tas bort krävs av andra resurser för att de ska fungera.\n"
+"Ta bort dem ändå? (Går inte ångra.)\n"
+"Beroende på hur ditt filsystem är inställt så kommer filerna antingen "
+"flyttas till systemets papperskorg eller tas bort permanent."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1260,9 +1278,8 @@ msgid "Error opening asset file for \"%s\" (not in ZIP format)."
msgstr "Fel vid öppning av paketetfil, inte i zip-format."
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "%s (already exists)"
-msgstr "%s (Existerar Redan)"
+msgstr "%s (existerar redan)"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - %d file(s) conflict with your project:"
@@ -1282,9 +1299,8 @@ msgid "The following files failed extraction from asset \"%s\":"
msgstr "Följande filer misslyckades att packas upp från paketet:"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "(and %s more files)"
-msgstr "%d fler filer."
+msgstr "(och %s fler filer)"
#: editor/editor_asset_installer.cpp
#, fuzzy
@@ -1534,9 +1550,8 @@ msgid "Can't add autoload:"
msgstr "Kunde inte lägga till autoladdning:"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "%s is an invalid path. File does not exist."
-msgstr "Fil existerar inte."
+msgstr "%s är en ogiltig genväg. Filen existerar inte."
#: editor/editor_autoload_settings.cpp
msgid "%s is an invalid path. Not in resource path (res://)."
@@ -1564,9 +1579,8 @@ msgid "Name"
msgstr "Namn"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "Global Variable"
-msgstr "Variabel"
+msgstr "Global variabel"
#: editor/editor_data.cpp
msgid "Paste Params"
@@ -1663,22 +1677,20 @@ msgstr ""
"Fallback Enabled'."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
"'Import Pvrtc' in Project Settings."
msgstr ""
-"Målplattformen kräver 'ETC' texturkomprimering för GLES2. Aktivera 'Import "
-"Etc' i Projektinställningarna."
+"Målplattformen kräver 'PVRTC'-texturkomprimering för GLES2. Aktivera 'Import "
+"Pvrtc' i projektinställningarna."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. "
"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
msgstr ""
-"Målplattformen kräver 'ETC2' texturkomprimering för GLES3. Aktivera 'Import "
-"Etc 2' i Projektinställningarna."
+"Målplattformen kräver 'ETC2' eller 'PVRTC'-texturkomprimering för GLES3. "
+"Aktivera 'Import Etc 2' eller 'Import Pvrtc' i projektinställningarna."
#: editor/editor_export.cpp
msgid ""
@@ -1742,11 +1754,11 @@ msgstr "Importera"
#: editor/editor_feature_profile.cpp
msgid "Allows to view and edit 3D scenes."
-msgstr ""
+msgstr "Tillåter att visa och redigera 3D-scener."
#: editor/editor_feature_profile.cpp
msgid "Allows to edit scripts using the integrated script editor."
-msgstr ""
+msgstr "Tillåter att redigera skript via den integrerade skript-redigeraren."
#: editor/editor_feature_profile.cpp
msgid "Provides built-in access to the Asset Library."
@@ -2341,6 +2353,17 @@ msgid "New Window"
msgstr "Nytt Fönster"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Importerade resurser kan inte sparas."
@@ -3198,10 +3221,6 @@ msgid "Save & Restart"
msgstr "Spara & Avsluta"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
#, fuzzy
msgid "Update Continuously"
msgstr "Kontinuerlig"
@@ -3844,6 +3863,16 @@ msgid "Download from:"
msgstr "Ladda ner"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Kör i Webbläsare"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Fel"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -6348,7 +6377,7 @@ msgstr ""
#: editor/plugins/curve_editor_plugin.cpp
msgid "Flat 1"
-msgstr ""
+msgstr "Platt 1"
#: editor/plugins/curve_editor_plugin.cpp editor/property_editor.cpp
msgid "Ease In"
@@ -8789,6 +8818,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Ta bort Alla"
@@ -8819,6 +8854,12 @@ msgid "Remove All StyleBox Items"
msgstr "Ta bort Alla"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Lägg till i Favoriter"
@@ -12425,6 +12466,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -14103,6 +14152,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
@@ -14878,9 +14963,6 @@ msgstr ""
#~ msgid "I see..."
#~ msgstr "Jag förstår..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "Kan inte öppna '%s'."
-
#, fuzzy
#~ msgid "Ugh"
#~ msgstr "Ugh"
diff --git a/editor/translations/ta.po b/editor/translations/ta.po
index 5b4e249318..2ad954b971 100644
--- a/editor/translations/ta.po
+++ b/editor/translations/ta.po
@@ -355,6 +355,7 @@ msgstr ""
msgid "Remove Anim Track"
msgstr "அசைவூடà¯à®Ÿà¯ பாதையை நீகà¯à®•à¯"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr ""
@@ -379,10 +380,26 @@ msgstr ""
msgid "Anim Insert"
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "மாறà¯à®±à®™à¯à®•ளை இதறà¯à®•௠அமை:"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr ""
@@ -945,7 +962,7 @@ msgstr ""
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2241,6 +2258,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3022,10 +3050,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr ""
@@ -3633,6 +3657,14 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+msgid "Open in Web Browser"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8343,6 +8375,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Color Items"
msgstr ""
@@ -8370,6 +8408,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
msgstr ""
@@ -11815,6 +11859,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13423,6 +13475,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/te.po b/editor/translations/te.po
index 6a4e076543..74998009cd 100644
--- a/editor/translations/te.po
+++ b/editor/translations/te.po
@@ -338,6 +338,7 @@ msgstr ""
msgid "Remove Anim Track"
msgstr ""
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr ""
@@ -362,10 +363,25 @@ msgstr ""
msgid "Anim Insert"
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "animation"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr ""
@@ -920,7 +936,7 @@ msgstr ""
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2211,6 +2227,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -2991,10 +3018,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr ""
@@ -3599,6 +3622,14 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+msgid "Open in Web Browser"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8276,6 +8307,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Color Items"
msgstr ""
@@ -8300,6 +8337,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
msgstr ""
@@ -11708,6 +11751,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13302,6 +13353,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/th.po b/editor/translations/th.po
index ce5e4952f1..231051313a 100644
--- a/editor/translations/th.po
+++ b/editor/translations/th.po
@@ -356,6 +356,7 @@ msgstr "เปลี่ยนโหมดà¸à¸²à¸£à¸§à¸™à¸‹à¹‰à¸³à¹à¸­à¸™à¸´à¹€
msgid "Remove Anim Track"
msgstr "ลบà¹à¸—ร็à¸à¹à¸­à¸™à¸´à¹€à¸¡à¸Šà¸±à¸™"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "เพิ่มà¹à¸—ร็à¸à¹ƒà¸«à¸¡à¹ˆà¸ªà¸³à¸«à¸£à¸±à¸š %s à¹à¸¥à¸°à¹€à¸žà¸´à¹ˆà¸¡à¸„ีย์?"
@@ -380,10 +381,28 @@ msgstr "สร้าง"
msgid "Anim Insert"
msgstr "à¹à¸—รà¸à¹à¸­à¸™à¸´à¹€à¸¡à¸Šà¸±à¸™"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "เปิด '%s' ไม่ได้"
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "à¹à¸­à¸™à¸´à¹€à¸¡à¸Šà¸±à¸™"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "ตัวเล่นอนิเมชั่นไม่สามารถเล่นอนิเมชั่นด้วยตัวมันเองได้ เล่นได้เฉพาะตัวเล่นอื่นเท่านั้น"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "ไม่พบคุณสมบัติ '%s'"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "สร้างà¹à¸¥à¸°à¹à¸—รà¸à¹à¸­à¸™à¸´à¹€à¸¡à¸Šà¸±à¸™"
@@ -954,7 +973,7 @@ msgstr "สร้าง %s ใหม่"
msgid "No results for \"%s\"."
msgstr "ไม่มีผลลัพธ์สำหรับ \"%s\""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2290,6 +2309,17 @@ msgid "New Window"
msgstr "หน้าต่างใหม่"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "หมุนเมื่อมีà¸à¸²à¸£à¸§à¸²à¸”หน้าต่างโปรà¹à¸à¸£à¸¡à¹ƒà¸«à¸¡"
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "ทรัพยาà¸à¸£à¸—ี่นำเข้ามา ไม่สามารถบันทึà¸à¹„ด้"
@@ -3122,10 +3152,6 @@ msgid "Save & Restart"
msgstr "บันทึà¸à¹à¸¥à¸°à¹€à¸£à¸´à¹ˆà¸¡à¹ƒà¸«à¸¡à¹ˆ"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "หมุนเมื่อมีà¸à¸²à¸£à¸§à¸²à¸”หน้าต่างโปรà¹à¸à¸£à¸¡à¹ƒà¸«à¸¡"
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "อัพเดทอย่างต่อเนื่อง"
@@ -3776,6 +3802,16 @@ msgid "Download from:"
msgstr "ดาวน์โหลดผิดพลาด"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "รันในเบราเซอร์"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "คัดลอà¸à¸œà¸´à¸”พลาด"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8592,6 +8628,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "ลบทั้งหมด"
@@ -8622,6 +8664,12 @@ msgid "Remove All StyleBox Items"
msgstr "ลบทั้งหมด"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "เพิ่มไอเทมคลาส"
@@ -12217,6 +12265,16 @@ msgstr "ปรับความสูงทรงà¹à¸„ปซูล"
msgid "Change Ray Shape Length"
msgstr "ปรับความยาวรังสี"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "à¸à¸³à¸«à¸™à¸”พิà¸à¸±à¸”จุดเส้นโค้ง"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "à¸à¸³à¸«à¸™à¸”พิà¸à¸±à¸”จุดเส้นโค้ง"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "ปรับรัศมีทรงà¸à¸£à¸°à¸šà¸­à¸"
@@ -13909,6 +13967,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr "วัตถุนี้จะถูà¸à¸¥à¸°à¹€à¸§à¹‰à¸™à¸ˆà¸™à¸à¸§à¹ˆà¸²à¸ˆà¸°à¸•ั้ง mesh"
@@ -15120,9 +15214,6 @@ msgstr "ค่าคงที่ไม่สามารถà¹à¸à¹‰à¹„ขได
#~ msgid "I see..."
#~ msgstr "ตà¸à¸¥à¸‡..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "เปิด '%s' ไม่ได้"
-
#~ msgid "Ugh"
#~ msgstr "เออะ"
diff --git a/editor/translations/tr.po b/editor/translations/tr.po
index 8a735113cc..69a7ef73a2 100644
--- a/editor/translations/tr.po
+++ b/editor/translations/tr.po
@@ -395,6 +395,7 @@ msgstr "Animasyon Döngü Kipini Değiştir"
msgid "Remove Anim Track"
msgstr "Animasyon İzini Kaldır"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "%s için YENİ iz oluştur ve anahtar gir?"
@@ -419,11 +420,29 @@ msgstr "OluÅŸtur"
msgid "Anim Insert"
msgstr "Animasyon Ekle"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "'%s' açılamıyor."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Animasyon"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
"Animasyon Oynatıcısı kendisini oynatamaz, sadece diğer oynatıcılar yapabilir."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "'%s' özelliği mevcut değil."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Animasyon OluÅŸtur & Ekle"
@@ -999,7 +1018,7 @@ msgstr "Yeni %s OluÅŸtur"
msgid "No results for \"%s\"."
msgstr "\"%s\" için sonuç yok."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2350,6 +2369,17 @@ msgid "New Window"
msgstr "Yeni Pencere"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Düzenleyici penceresi yeniden boyandığında döner."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "İçe aktarılmış kaynaklar kaydedilemez."
@@ -3212,10 +3242,6 @@ msgid "Save & Restart"
msgstr "Kaydet ve BaÅŸtan BaÅŸlat"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Düzenleyici penceresi yeniden boyandığında döner."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Sürekli Güncelle"
@@ -3878,6 +3904,16 @@ msgid "Download from:"
msgstr "İndirme Hatası"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Tarayıcıda Çalıştır"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Hatayı Kopyala"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8740,6 +8776,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Bütün Öğeleri Kaldır"
@@ -8770,6 +8812,12 @@ msgid "Remove All StyleBox Items"
msgstr "Bütün Öğeleri Kaldır"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Sınıf Öğeleri Ekle"
@@ -12426,6 +12474,16 @@ msgstr "Silindir Şekli Yüksekliğini Değiştir"
msgid "Change Ray Shape Length"
msgstr "Işın Şeklinin Uzunluğunu Değiştir"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Eğri Noktası Konumu Ayarla"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Eğri Noktası Konumu Ayarla"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "Silindir Yarıçapını Değiştir"
@@ -14194,6 +14252,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr "Bir model ayarlanana kadar bu gövde yok sayılır."
@@ -15449,9 +15543,6 @@ msgstr "Sabit deÄŸerler deÄŸiÅŸtirilemez."
#~ msgid "I see..."
#~ msgstr "Anlıyorum..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "'%s' açılamıyor."
-
#~ msgid "Ugh"
#~ msgstr "Öff"
diff --git a/editor/translations/tt.po b/editor/translations/tt.po
index 4ff5555363..e7b37069b7 100644
--- a/editor/translations/tt.po
+++ b/editor/translations/tt.po
@@ -338,6 +338,7 @@ msgstr ""
msgid "Remove Anim Track"
msgstr ""
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr ""
@@ -362,10 +363,25 @@ msgstr ""
msgid "Anim Insert"
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "animation"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr ""
@@ -920,7 +936,7 @@ msgstr ""
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2211,6 +2227,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -2990,10 +3017,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr ""
@@ -3598,6 +3621,14 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+msgid "Open in Web Browser"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8275,6 +8306,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Color Items"
msgstr ""
@@ -8299,6 +8336,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
msgstr ""
@@ -11706,6 +11749,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13300,6 +13351,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/tzm.po b/editor/translations/tzm.po
index 7d41f508ee..8c7d3f272c 100644
--- a/editor/translations/tzm.po
+++ b/editor/translations/tzm.po
@@ -336,6 +336,7 @@ msgstr ""
msgid "Remove Anim Track"
msgstr ""
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr ""
@@ -360,10 +361,25 @@ msgstr ""
msgid "Anim Insert"
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "animation"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr ""
@@ -918,7 +934,7 @@ msgstr ""
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2209,6 +2225,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -2988,10 +3015,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr ""
@@ -3596,6 +3619,14 @@ msgid "Download from:"
msgstr ""
#: editor/export_template_manager.cpp
+msgid "Open in Web Browser"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8273,6 +8304,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Color Items"
msgstr ""
@@ -8297,6 +8334,12 @@ msgid "Remove All StyleBox Items"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
msgstr ""
@@ -11704,6 +11747,14 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Room Point Position"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Set Portal Point Position"
+msgstr ""
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13298,6 +13349,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/uk.po b/editor/translations/uk.po
index adccdfd91f..a889e83e19 100644
--- a/editor/translations/uk.po
+++ b/editor/translations/uk.po
@@ -21,8 +21,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Ukrainian (Godot Engine)\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-08-02 02:00+0000\n"
-"Last-Translator: IllusiveMan196 <hamsterrv@gmail.com>\n"
+"PO-Revision-Date: 2021-08-04 12:10+0000\n"
+"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
"Language-Team: Ukrainian <https://hosted.weblate.org/projects/godot-engine/"
"godot/uk/>\n"
"Language: uk\n"
@@ -356,6 +356,7 @@ msgstr "Змінити режим циклу анімації"
msgid "Remove Anim Track"
msgstr "Видалити доріжку"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Створити нову доріжку Ð´Ð»Ñ %s Ñ– вÑтавити ключ?"
@@ -380,10 +381,28 @@ msgstr "Створити"
msgid "Anim Insert"
msgstr "Ð’Ñтавити анімацію"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "Ðеможливо відкрити '%s'."
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "ÐнімаціÑ"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "AnimationPlayer не може анімувати Ñебе, лише інших відтворювачів."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "ВлаÑтивоÑті «%s» не Ñ–Ñнує."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Створити Ñ– вÑтавити анімацію"
@@ -596,9 +615,8 @@ msgid "Go to Previous Step"
msgstr "До попереднього кроку"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Apply Reset"
-msgstr "Скинути"
+msgstr "ЗаÑтоÑувати ÑкиданнÑ"
#: editor/animation_track_editor.cpp
msgid "Optimize Animation"
@@ -617,9 +635,8 @@ msgid "Use Bezier Curves"
msgstr "ВикориÑтовувати криві Безьє"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Create RESET Track(s)"
-msgstr "Ð’Ñтавити доріжки"
+msgstr "Створити доріжки RESET"
#: editor/animation_track_editor.cpp
msgid "Anim. Optimizer"
@@ -944,7 +961,6 @@ msgid "Edit..."
msgstr "Змінити…"
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Go to Method"
msgstr "Перейти до методу"
@@ -964,9 +980,9 @@ msgstr "Створити новий %s"
msgid "No results for \"%s\"."
msgstr "Ðічого не знайдено Ð´Ð»Ñ Â«%s»."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
-msgstr ""
+msgstr "Ðемає опиÑу Ð´Ð»Ñ %s."
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp
@@ -1066,17 +1082,16 @@ msgid "Owners Of:"
msgstr "ВлаÑники:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove the selected files from the project? (Cannot be undone.)\n"
"Depending on your filesystem configuration, the files will either be moved "
"to the system trash or deleted permanently."
msgstr ""
"Вилучити позначені файли з проєкту? (без можливоÑті ÑкаÑувати)\n"
-"Вилучені файли можна буде знайти Ñ– відновити у теці Ñмітника ÑиÑтеми."
+"Залежно від конфігурації вашої файлової ÑиÑтеми, вилучені файли буде або "
+"переÑунуто до теки Ñмітника, або вилучено оÑтаточно."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1087,7 +1102,8 @@ msgstr ""
"Файли, Ñкі ви вилучаєте, потрібні Ð´Ð»Ñ Ð·Ð°Ð±ÐµÐ·Ð¿ÐµÑ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ð°Ñ†ÐµÐ·Ð´Ð°Ñ‚Ð½Ð¾Ñті інших "
"реÑурÑів.\n"
"Вилучити Ñ—Ñ… попри це? (без ÑкаÑуваннÑ)\n"
-"Вилучені файли можна знайти Ñ– відновити у теці Ñмітника ÑиÑтеми."
+"Залежно від конфігурації вашої файлової ÑиÑтеми, вилучені файли буде або "
+"переÑунуто до теки Ñмітника, або вилучено оÑтаточно."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1257,41 +1273,37 @@ msgid "Licenses"
msgstr "Ліцензії"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Error opening asset file for \"%s\" (not in ZIP format)."
-msgstr "Помилка під Ñ‡Ð°Ñ Ñпроби відкрити файл пакунка (дані не у форматі ZIP)."
+msgstr ""
+"Помилка під Ñ‡Ð°Ñ Ñпроби відкрити файл пакунка Ð´Ð»Ñ Â«%s» (не у форматі ZIP)."
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "%s (already exists)"
msgstr "%s (вже Ñ–Ñнує)"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - %d file(s) conflict with your project:"
-msgstr ""
+msgstr "ВміÑÑ‚ пакунка «%s» — конфлікт %d файлів із вашим проєктом:"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - No files conflict with your project:"
-msgstr ""
+msgstr "ВміÑÑ‚ пакунка «%s» — немає конфліктів файлів із вашим проєктом:"
#: editor/editor_asset_installer.cpp
msgid "Uncompressing Assets"
msgstr "Ð Ð¾Ð·Ð¿Ð°ÐºÐ¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÑурÑів"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "The following files failed extraction from asset \"%s\":"
-msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð´Ð¾Ð±ÑƒÑ‚Ð¸ такі файли з пакунка:"
+msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð´Ð¾Ð±ÑƒÑ‚Ð¸ з пакунка «%s» такі файли:"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "(and %s more files)"
-msgstr "І ще %s файлів."
+msgstr "(і ще %s файлів)"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset \"%s\" installed successfully!"
-msgstr "Пакунок уÑпішно вÑтановлено!"
+msgstr "Пакунок «%s» уÑпішно вÑтановлено!"
#: editor/editor_asset_installer.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -1303,9 +1315,8 @@ msgid "Install"
msgstr "Ð’Ñтановити"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset Installer"
-msgstr "Ð’Ñтановлювач пакета"
+msgstr "Ð’Ñтановлювач пакукнків"
#: editor/editor_audio_buses.cpp
msgid "Speakers"
@@ -1368,9 +1379,8 @@ msgid "Bypass"
msgstr "Обхід"
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "Bus Options"
-msgstr "Опції шини"
+msgstr "Параметри шини"
#: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/scene_tree_dock.cpp
@@ -1536,13 +1546,12 @@ msgid "Can't add autoload:"
msgstr "Ðе вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ автозавантаженнÑ:"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "%s is an invalid path. File does not exist."
-msgstr "Файл не Ñ–Ñнує."
+msgstr "%s не Ñ” коректним шлÑхом. Файла не Ñ–Ñнує."
#: editor/editor_autoload_settings.cpp
msgid "%s is an invalid path. Not in resource path (res://)."
-msgstr ""
+msgstr "%s Ñ” некоректним шлÑхом. Його немає у шлÑху реÑурÑів (res://)."
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -1566,9 +1575,8 @@ msgid "Name"
msgstr "Ðазва"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "Global Variable"
-msgstr "Змінна"
+msgstr "Загальна змінна"
#: editor/editor_data.cpp
msgid "Paste Params"
@@ -1724,7 +1732,7 @@ msgstr "Редактор Ñкриптів"
#: editor/editor_feature_profile.cpp
msgid "Asset Library"
-msgstr "Бібліотека реÑурÑів"
+msgstr "Бібліотека пакунків"
#: editor/editor_feature_profile.cpp
msgid "Scene Tree Editing"
@@ -1744,48 +1752,55 @@ msgstr "Бічна панель імпортуваннÑ"
#: editor/editor_feature_profile.cpp
msgid "Allows to view and edit 3D scenes."
-msgstr ""
+msgstr "Ðадає змогу переглÑдати Ñ– редагувати проÑторові Ñцени."
#: editor/editor_feature_profile.cpp
msgid "Allows to edit scripts using the integrated script editor."
msgstr ""
+"Ðадає змогу редагувати Ñкрипти за допомогою вбудованого редактора Ñкриптів."
#: editor/editor_feature_profile.cpp
msgid "Provides built-in access to the Asset Library."
-msgstr ""
+msgstr "Ðадає вбудований доÑтупу до бібліотеки пакунків."
#: editor/editor_feature_profile.cpp
msgid "Allows editing the node hierarchy in the Scene dock."
-msgstr ""
+msgstr "Ðадає змогу редагувати ієрархію вузлів на бічній панелі Ñцени."
#: editor/editor_feature_profile.cpp
msgid ""
"Allows to work with signals and groups of the node selected in the Scene "
"dock."
msgstr ""
+"Ðадає змогу працювати із Ñигналами Ñ– групами вузла, Ñкий позначено на бічній "
+"панелі Ñцени."
#: editor/editor_feature_profile.cpp
msgid "Allows to browse the local file system via a dedicated dock."
msgstr ""
+"Ðадає змогу здійÑнювати навігацію локальною файловою ÑиÑтемою за допомогою "
+"відповідної бічної панелі."
#: editor/editor_feature_profile.cpp
msgid ""
"Allows to configure import settings for individual assets. Requires the "
"FileSystem dock to function."
msgstr ""
+"Ðадає змогу налаштувати параметри Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð¾ÐºÑ€ÐµÐ¼Ð¸Ñ… пакунків. "
+"Потребує Ð´Ð»Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸ бічної панелі FileSystem."
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "(current)"
-msgstr "(Поточний)"
+msgstr "(поточний)"
#: editor/editor_feature_profile.cpp
msgid "(none)"
-msgstr ""
+msgstr "(немає)"
#: editor/editor_feature_profile.cpp
msgid "Remove currently selected profile, '%s'? Cannot be undone."
msgstr ""
+"Вилучити поточний позначений профіль, «%s»? Дію не може бути ÑкаÑовано."
#: editor/editor_feature_profile.cpp
msgid "Profile must be a valid filename and must not contain '.'"
@@ -1816,19 +1831,16 @@ msgid "Enable Contextual Editor"
msgstr "Увімкнути контекÑтуальний редактор"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Class Properties:"
-msgstr "ВлаÑтивоÑті:"
+msgstr "ВлаÑтивоÑті клаÑу:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Main Features:"
-msgstr "МожливоÑті"
+msgstr "ОÑновні можливоÑті:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Nodes and Classes:"
-msgstr "Увімкнені клаÑи:"
+msgstr "Вузли Ñ– клаÑи:"
#: editor/editor_feature_profile.cpp
msgid "File '%s' format is invalid, import aborted."
@@ -1847,23 +1859,20 @@ msgid "Error saving profile to path: '%s'."
msgstr "Помилка під Ñ‡Ð°Ñ Ñпроби зберегти профіль до каталогу: «%s»."
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Reset to Default"
-msgstr "Відновити типові параметри"
+msgstr "ПовернутиÑÑ Ð´Ð¾ типового"
#: editor/editor_feature_profile.cpp
msgid "Current Profile:"
msgstr "Поточний профіль:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Create Profile"
-msgstr "Витерти профіль"
+msgstr "Створити профіль"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Remove Profile"
-msgstr "Вилучити плитку"
+msgstr "Вилучити профіль"
#: editor/editor_feature_profile.cpp
msgid "Available Profiles:"
@@ -1883,18 +1892,18 @@ msgid "Export"
msgstr "ЕкÑпортуваннÑ"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Configure Selected Profile:"
-msgstr "Поточний профіль:"
+msgstr "Ðалаштувати позначений профіль:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Extra Options:"
-msgstr "Параметри клаÑу:"
+msgstr "Додаткові параметри:"
#: editor/editor_feature_profile.cpp
msgid "Create or import a profile to edit available classes and properties."
msgstr ""
+"Створіть або імпортуйте профіль Ð´Ð»Ñ Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупних клаÑів Ñ– "
+"влаÑтивоÑтей."
#: editor/editor_feature_profile.cpp
msgid "New profile name:"
@@ -1921,9 +1930,8 @@ msgid "Select Current Folder"
msgstr "Вибрати поточну теку"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
-#, fuzzy
msgid "File exists, overwrite?"
-msgstr "Файл Ñ–Ñнує, перезапиÑати його?"
+msgstr "Файл вже Ñ–Ñнує. ПерезапиÑати?"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Select This Folder"
@@ -2316,6 +2324,17 @@ msgid "New Window"
msgstr "Ðове вікно"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "ОбертаєтьÑÑ, коли перемальовуєтьÑÑ Ð²Ñ–ÐºÐ½Ð¾ редактора."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Ðеможливо зберегти імпортовані реÑурÑи."
@@ -2545,13 +2564,16 @@ msgid ""
"The current scene has no root node, but %d modified external resource(s) "
"were saved anyway."
msgstr ""
+"У поточної Ñцени немає кореневого вузла, але %d змінених зовнішніх реÑурÑів "
+"було збережено попри це."
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"A root node is required to save the scene. You can add a root node using the "
"Scene tree dock."
-msgstr "Ð”Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб можна було зберегти Ñцену, потрібен кореневий вузол."
+msgstr ""
+"Ð”Ð»Ñ Ð·Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ñцени потрібен кореневий вузол. Ви можете додати кореневий "
+"вузол за допомогою бічної панелі ієрархії Ñцени."
#: editor/editor_node.cpp
msgid "Save Scene As..."
@@ -2937,9 +2959,8 @@ msgid "Orphan Resource Explorer..."
msgstr "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¾Ñиротілими реÑурÑами…"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reload Current Project"
-msgstr "Перейменувати проєкт"
+msgstr "Перезавантажити поточний проєкт"
#: editor/editor_node.cpp
msgid "Quit to Project List"
@@ -3100,13 +3121,12 @@ msgid "Help"
msgstr "Довідка"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Online Documentation"
-msgstr "Відкрити документацію"
+msgstr "Ð”Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°Ñ†Ñ–Ñ Ð² інтернеті"
#: editor/editor_node.cpp
msgid "Questions & Answers"
-msgstr ""
+msgstr "Ð—Ð°Ð¿Ð¸Ñ‚Ð°Ð½Ð½Ñ Ñ– відповіді"
#: editor/editor_node.cpp
msgid "Report a Bug"
@@ -3114,7 +3134,7 @@ msgstr "Повідомити про ваду"
#: editor/editor_node.cpp
msgid "Suggest a Feature"
-msgstr ""
+msgstr "Запропонувати можливіÑть"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
@@ -3125,9 +3145,8 @@ msgid "Community"
msgstr "Спільнота"
#: editor/editor_node.cpp
-#, fuzzy
msgid "About Godot"
-msgstr "Про"
+msgstr "Про Godot"
#: editor/editor_node.cpp
msgid "Support Godot Development"
@@ -3179,10 +3198,6 @@ msgid "Save & Restart"
msgstr "Зберегти Ñ– перезапуÑтити"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "ОбертаєтьÑÑ, коли перемальовуєтьÑÑ Ð²Ñ–ÐºÐ½Ð¾ редактора."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Оновлювати неперервно"
@@ -3225,14 +3240,12 @@ msgid "Manage Templates"
msgstr "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ð°Ð¼Ð¸"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Install from file"
-msgstr "Ð’Ñтановити з файлу"
+msgstr "Ð’Ñтановити з файла"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Select android sources file"
-msgstr "Виберіть джерело Ñітки:"
+msgstr "Виберіть файл початкових кодів android"
#: editor/editor_node.cpp
msgid ""
@@ -3314,9 +3327,8 @@ msgid "Select"
msgstr "Виділити"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Select Current"
-msgstr "Вибрати поточну теку"
+msgstr "Вибрати поточний"
#: editor/editor_node.cpp
msgid "Open 2D Editor"
@@ -3351,9 +3363,8 @@ msgid "No sub-resources found."
msgstr "Підлеглих реÑурÑів не знайдено."
#: editor/editor_path.cpp
-#, fuzzy
msgid "Open a list of sub-resources."
-msgstr "Підлеглих реÑурÑів не знайдено."
+msgstr "Відкрити ÑпиÑок підлеглих реÑурÑів."
#: editor/editor_plugin.cpp
msgid "Creating Mesh Previews"
@@ -3380,14 +3391,12 @@ msgid "Update"
msgstr "Оновити"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Version"
-msgstr "ВерÑÑ–Ñ:"
+msgstr "ВерÑÑ–Ñ"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Author"
-msgstr "Ðвтори"
+msgstr "Ðвтор"
#: editor/editor_plugin_settings.cpp
#: editor/plugins/version_control_editor_plugin.cpp
@@ -3400,14 +3409,12 @@ msgid "Measure:"
msgstr "Вимірювати:"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Frame Time (ms)"
-msgstr "Ð§Ð°Ñ ÐºÐ°Ð´Ñ€Ñƒ (Ñек)"
+msgstr "Ð§Ð°Ñ ÐºÐ°Ð´Ñ€Ñƒ (мÑ)"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Average Time (ms)"
-msgstr "Середній Ñ‡Ð°Ñ (Ñек)"
+msgstr "Середній Ñ‡Ð°Ñ (мÑ)"
#: editor/editor_profiler.cpp
msgid "Frame %"
@@ -3434,6 +3441,12 @@ msgid ""
"functions called by that function.\n"
"Use this to find individual functions to optimize."
msgstr ""
+"Включно: включає Ñ‡Ð°Ñ Ð· інших функцій, Ñкі викликає Ñ†Ñ Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ.\n"
+"СкориÑтайтеÑÑ Ñ†Ð¸Ð¼ варіантом Ð´Ð»Ñ Ð²Ð¸ÑÐ²Ð»ÐµÐ½Ð½Ñ Ð²ÑƒÐ·ÑŒÐºÐ¸Ñ… міÑць.\n"
+"\n"
+"Цей об'єкт: визначати витрачений Ñ‡Ð°Ñ Ñƒ Ñамій функції, не в інших функціÑÑ…, "
+"Ñкі Ñ†Ñ Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ Ð²Ð¸ÐºÐ»Ð¸ÐºÐ°Ñ”.\n"
+"СкориÑтайтеÑÑ Ñ†Ð¸Ð¼ варіантом Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ окремих функцій Ð´Ð»Ñ Ð¾Ð¿Ñ‚Ð¸Ð¼Ñ–Ð·Ð°Ñ†Ñ–Ñ—."
#: editor/editor_profiler.cpp
msgid "Frame #:"
@@ -3556,9 +3569,8 @@ msgid "Paste"
msgstr "Ð’Ñтавити"
#: editor/editor_resource_picker.cpp editor/property_editor.cpp
-#, fuzzy
msgid "Convert to %s"
-msgstr "Перетворити на %s"
+msgstr "Перетворити до %s"
#: editor/editor_resource_picker.cpp editor/property_editor.cpp
msgid "New %s"
@@ -3608,10 +3620,9 @@ msgid "Did you forget the '_run' method?"
msgstr "Ви забули метод '_run'?"
#: editor/editor_spin_slider.cpp
-#, fuzzy
msgid "Hold %s to round to integers. Hold Shift for more precise changes."
msgstr ""
-"Утримуйте натиÑнутою Ctrl, щоб заокруглити до цілих. Утримуйте натиÑнутою "
+"Утримуйте натиÑнутою %s, щоб заокруглити до цілих. Утримуйте натиÑнутою "
"Shift, щоб зміни були точнішими."
#: editor/editor_sub_scene.cpp
@@ -3632,49 +3643,43 @@ msgstr "Імпортувати з вузла:"
#: editor/export_template_manager.cpp
msgid "Open the folder containing these templates."
-msgstr ""
+msgstr "Відкрити теку, Ñка міÑтить ці шаблони."
#: editor/export_template_manager.cpp
msgid "Uninstall these templates."
-msgstr ""
+msgstr "Вилучити ці шаблони."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "There are no mirrors available."
-msgstr "Ðемає файла «%s»."
+msgstr "Ðемає доÑтупних дзеркал."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Retrieving the mirror list..."
-msgstr "ÐžÑ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð·ÐµÑ€ÐºÐ°Ð», будь лаÑка, зачекайте..."
+msgstr "Отримуємо ÑпиÑок дзеркал…"
#: editor/export_template_manager.cpp
msgid "Starting the download..."
-msgstr ""
+msgstr "Розпочинаємо Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ…â€¦"
#: editor/export_template_manager.cpp
msgid "Error requesting URL:"
msgstr "Помилка під Ñ‡Ð°Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ за такою адреÑою:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Connecting to the mirror..."
-msgstr "ÐŸÑ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ð´Ð¾ дзеркала..."
+msgstr "Ð’Ñтановлюємо з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ñ–Ð· дзеркалом…"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't resolve the requested address."
-msgstr "Ðеможливо розпізнати ім'Ñ Ñ…Ð¾Ñта:"
+msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚Ð¸ вузол за бажаною адреÑою."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't connect to the mirror."
-msgstr "Ðе вдалоÑÑ Ð¿Ñ–Ð´ÐºÐ»ÑŽÑ‡Ð¸Ñ‚Ð¸ÑÑ Ð´Ð¾ хоÑту:"
+msgstr "Ðе вдалоÑÑ Ð²Ñтановити з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ñ–Ð· дзеркалом."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "No response from the mirror."
-msgstr "Ðемає відповіді від хоÑта:"
+msgstr "Ðемає відповіді від дзеркала."
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -3682,18 +3687,16 @@ msgid "Request failed."
msgstr "Ðе вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ запит."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Request ended up in a redirect loop."
-msgstr "Запит не вдавÑÑ, забагато перенаправлень"
+msgstr "Спроба виконати запит завершилаÑÑ Ñ†Ð¸ÐºÐ»Ñ–Ñ‡Ð½Ð¸Ð¼ переÑпрÑмовуваннÑм."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Request failed:"
-msgstr "Ðе вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ запит."
+msgstr "Ðе вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ запит:"
#: editor/export_template_manager.cpp
msgid "Download complete; extracting templates..."
-msgstr ""
+msgstr "ÐžÑ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… завершено; видобуваємо шаблони…"
#: editor/export_template_manager.cpp
msgid "Cannot remove temporary file:"
@@ -3712,15 +3715,14 @@ msgid "Error getting the list of mirrors."
msgstr "Помилка під Ñ‡Ð°Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ ÑпиÑку дзеркал."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Error parsing JSON with the list of mirrors. Please report this issue!"
msgstr ""
-"Помилка під Ñ‡Ð°Ñ Ð¾Ð±Ñ€Ð¾Ð±ÐºÐ¸ JSON ÑпиÑку дзеркал. Будь лаÑка, повідомте про цю "
-"ваду!"
+"Помилка під Ñ‡Ð°Ñ Ñпроби обробити JSON зі ÑпиÑком дзеркал. Будь лаÑка, "
+"повідомте розробникам про цю помилку!"
#: editor/export_template_manager.cpp
msgid "Best available mirror"
-msgstr ""
+msgstr "Ðайкраще доÑтупне дзеркало"
#: editor/export_template_manager.cpp
msgid ""
@@ -3773,24 +3775,21 @@ msgid "SSL Handshake Error"
msgstr "Помилка SSL РукоÑтиÑканнÑ"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't open the export templates file."
-msgstr "Ðеможливо відкрити ZIP-файл шаблону екÑпорту."
+msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ файл шаблонів екÑпортуваннÑ."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Invalid version.txt format inside the export templates file: %s."
-msgstr "Ðеправильний формат version.txt у шаблонах: %s."
+msgstr ""
+"Ðекоректне Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ version.txt у файлі шаблонів екÑпортуваннÑ: %s."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "No version.txt found inside the export templates file."
-msgstr "Файл version.txt не знайдено у шаблонах."
+msgstr "У файлі шаблонів екÑÐ¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð½ÐµÐ¼Ð°Ñ” version.txt."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Error creating path for extracting templates:"
-msgstr "Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÑˆÐ»Ñху Ð´Ð»Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ñ–Ð²:"
+msgstr "Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÑˆÐ»Ñху Ð´Ð»Ñ Ð²Ð¸Ð´Ð¾Ð±ÑƒÑ‚Ð¸Ñ… шаблонів:"
#: editor/export_template_manager.cpp
msgid "Extracting Export Templates"
@@ -3801,9 +3800,8 @@ msgid "Importing:"
msgstr "ІмпортуваннÑ:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Remove templates for the version '%s'?"
-msgstr "Вилучити верÑÑ–ÑŽ шаблону '%s'?"
+msgstr "Вилучити шаблони Ð´Ð»Ñ Ð²ÐµÑ€ÑÑ–Ñ— «%s»?"
#: editor/export_template_manager.cpp
msgid "Uncompressing Android Build Sources"
@@ -3820,57 +3818,65 @@ msgstr "Поточна верÑÑ–Ñ:"
#: editor/export_template_manager.cpp
msgid "Export templates are missing. Download them or install from a file."
msgstr ""
+"Ðе виÑтачає шаблонів екÑпортуваннÑ. Отримайте Ñ—Ñ… або вÑтановіть з файла."
#: editor/export_template_manager.cpp
msgid "Export templates are installed and ready to be used."
-msgstr ""
+msgstr "Шаблони екÑÐ¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ñтановлено Ñ– приготовано до викориÑтаннÑ."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Open Folder"
-msgstr "Відкрити файл"
+msgstr "Відкрити теку"
#: editor/export_template_manager.cpp
msgid "Open the folder containing installed templates for the current version."
-msgstr ""
+msgstr "Відкрити теку, що міÑтить вÑтановлені шаблони Ð´Ð»Ñ Ð¿Ð¾Ñ‚Ð¾Ñ‡Ð½Ð¾Ñ— верÑÑ–Ñ—."
#: editor/export_template_manager.cpp
msgid "Uninstall"
msgstr "Видалити"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Uninstall templates for the current version."
-msgstr "Початкове Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð»Ñ–Ñ‡Ð¸Ð»ÑŒÐ½Ð¸ÐºÐ°"
+msgstr "Вилучити шаблони Ð´Ð»Ñ Ð¿Ð¾Ñ‚Ð¾Ñ‡Ð½Ð¾Ñ— верÑÑ–Ñ—."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Download from:"
-msgstr "Помилка завантаженнÑ"
+msgstr "Джерело отриманнÑ:"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "ЗапуÑтити в браузері"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Помилка копіюваннÑ"
#: editor/export_template_manager.cpp
msgid "Download and Install"
-msgstr ""
+msgstr "Отримати Ñ– вÑтановити"
#: editor/export_template_manager.cpp
msgid ""
"Download and install templates for the current version from the best "
"possible mirror."
msgstr ""
+"Отримати Ñ– вÑтановити шаблони Ð´Ð»Ñ Ð¿Ð¾Ñ‚Ð¾Ñ‡Ð½Ð¾Ñ— верÑÑ–Ñ— із найкращого можливого "
+"дзеркала."
#: editor/export_template_manager.cpp
msgid "Official export templates aren't available for development builds."
msgstr "Ð”Ð»Ñ Ñ‚ÐµÑтових збірок не передбачено офіційних шаблонів екÑпортуваннÑ."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Install from File"
-msgstr "Ð’Ñтановити з файлу"
+msgstr "Ð’Ñтановити з файла"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Install templates from a local file."
-msgstr "Імпортувати шаблони з ZIP-файлу"
+msgstr "Ð’Ñтановити шаблони з локального файла."
#: editor/export_template_manager.cpp editor/find_in_files.cpp
#: editor/progress_dialog.cpp scene/gui/dialogs.cpp
@@ -3878,19 +3884,16 @@ msgid "Cancel"
msgstr "СкаÑувати"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Cancel the download of the templates."
-msgstr "Ðеможливо відкрити ZIP-файл шаблону екÑпорту."
+msgstr "СкаÑувати Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ñ–Ð²."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Other Installed Versions:"
-msgstr "Ð’Ñтановлені верÑÑ–Ñ—:"
+msgstr "Інші вÑтановлені верÑÑ–Ñ—:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Uninstall Template"
-msgstr "Видалити"
+msgstr "Вилучити шаблон"
#: editor/export_template_manager.cpp
msgid "Select Template File"
@@ -3905,6 +3908,8 @@ msgid ""
"The templates will continue to download.\n"
"You may experience a short editor freeze when they finish."
msgstr ""
+"ÐžÑ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ñ–Ð² буде продовжено.\n"
+"Під Ñ‡Ð°Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ð¼Ð¾Ð¶Ð»Ð¸Ð²Ðµ тимчаÑове «замерзаннÑ» редактора."
#: editor/filesystem_dock.cpp
msgid "Favorites"
@@ -4052,35 +4057,32 @@ msgid "Collapse All"
msgstr "Згорнути вÑе"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort files"
-msgstr "Шукати файли"
+msgstr "УпорÑдкувати файли"
#: editor/filesystem_dock.cpp
msgid "Sort by Name (Ascending)"
-msgstr ""
+msgstr "УпорÑдкувати за назвою (зроÑтаннÑ)"
#: editor/filesystem_dock.cpp
msgid "Sort by Name (Descending)"
-msgstr ""
+msgstr "УпорÑдкувати за назвою (ÑпаданнÑ)"
#: editor/filesystem_dock.cpp
msgid "Sort by Type (Ascending)"
-msgstr ""
+msgstr "УпорÑдкувати за типом (зроÑтаннÑ)"
#: editor/filesystem_dock.cpp
msgid "Sort by Type (Descending)"
-msgstr ""
+msgstr "УпорÑдкувати за типом (ÑпаданнÑ)"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort by Last Modified"
-msgstr "ВоÑтаннє змінено"
+msgstr "УпорÑдкувати за оÑтаннім внеÑеннÑм змін"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort by First Modified"
-msgstr "ВоÑтаннє змінено"
+msgstr "УпорÑдкувати за початковим внеÑеннÑм змін"
#: editor/filesystem_dock.cpp
msgid "Duplicate..."
@@ -4092,7 +4094,7 @@ msgstr "Перейменувати..."
#: editor/filesystem_dock.cpp
msgid "Focus the search box"
-msgstr ""
+msgstr "ФокуÑувати поле Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ"
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -4400,14 +4402,12 @@ msgid "Failed to load resource."
msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ реÑурÑ."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Copy Properties"
-msgstr "ВлаÑтивоÑті"
+msgstr "Копіювати влаÑтивоÑті"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Paste Properties"
-msgstr "ВлаÑтивоÑті"
+msgstr "Ð’Ñтавити влаÑтивоÑті"
#: editor/inspector_dock.cpp
msgid "Make Sub-Resources Unique"
@@ -4432,23 +4432,20 @@ msgid "Save As..."
msgstr "Зберегти Ñк..."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Extra resource options."
-msgstr "Ðе в реÑурÑному шлÑху."
+msgstr "Додаткові параметри реÑурÑу."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Edit Resource from Clipboard"
-msgstr "Редагувати буфер реÑурÑів"
+msgstr "Редагувати реÑÑƒÑ€Ñ Ð· буфера обміну"
#: editor/inspector_dock.cpp
msgid "Copy Resource"
msgstr "Копіювати реÑурÑ"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Make Resource Built-In"
-msgstr "Зробити вбудованим"
+msgstr "Зробити реÑÑƒÑ€Ñ Ð²Ð±ÑƒÐ´Ð¾Ð²Ð°Ð½Ð¸Ð¼"
#: editor/inspector_dock.cpp
msgid "Go to the previous edited object in history."
@@ -4463,9 +4460,8 @@ msgid "History of recently edited objects."
msgstr "ІÑÑ‚Ð¾Ñ€Ñ–Ñ Ð½ÐµÑ‰Ð¾Ð´Ð°Ð²Ð½Ð¾ відредагованих об'єктів."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Open documentation for this object."
-msgstr "Відкрити документацію"
+msgstr "Відкрити документацію Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ об'єкта."
#: editor/inspector_dock.cpp editor/scene_tree_dock.cpp
msgid "Open Documentation"
@@ -4476,9 +4472,8 @@ msgid "Filter properties"
msgstr "Фільтрувати влаÑтивоÑті"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Manage object properties."
-msgstr "ВлаÑтивоÑті об'єкта."
+msgstr "Керувати влаÑтивоÑÑ‚Ñми об'єкта."
#: editor/inspector_dock.cpp
msgid "Changes may be lost!"
@@ -4726,9 +4721,8 @@ msgid "Blend:"
msgstr "Змішувати:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Parameter Changed:"
-msgstr "Змінено параметр"
+msgstr "Змінено параметр:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
@@ -5460,11 +5454,11 @@ msgstr "Ð’Ñе"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Search templates, projects, and demos"
-msgstr ""
+msgstr "Шукати шаблони, проєкти та демонÑтрації"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Search assets (excluding templates, projects, and demos)"
-msgstr ""
+msgstr "Пошук пакунків (із виключеннÑм шаблонів, проєктів та демонÑтрацій)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Import..."
@@ -5508,7 +5502,7 @@ msgstr "ZIP файл реÑурÑів"
#: editor/plugins/audio_stream_editor_plugin.cpp
msgid "Audio Preview Play/Pause"
-msgstr ""
+msgstr "ПуÑк/Пауза проÑÐ»ÑƒÑ…Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð²ÑƒÐºÑƒ"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
@@ -5769,13 +5763,12 @@ msgstr "Змінити прив'Ñзки"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid ""
"Project Camera Override\n"
"Overrides the running project's camera with the editor viewport camera."
msgstr ""
-"ÐŸÐµÑ€ÐµÐ²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ ÐºÐ°Ð¼ÐµÑ€Ð¸ гри\n"
-"Замінює камеру гри камерою видимої облаÑті редактора."
+"ÐŸÐµÑ€ÐµÐ²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ ÐºÐ°Ð¼ÐµÑ€Ð¸ проєкту\n"
+"Замінює поточну камеру проєкту камерою видимої облаÑті редактора."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5784,6 +5777,9 @@ msgid ""
"No project instance running. Run the project from the editor to use this "
"feature."
msgstr ""
+"ÐŸÐµÑ€ÐµÐ²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ ÐºÐ°Ð¼ÐµÑ€Ð¸ проєкту\n"
+"Ðемає запущеного екземплÑра проєкту. ЗапуÑтіть проєкт з вікна редактора, щоб "
+"ÑкориÑтатиÑÑ Ñ†Ñ–Ñ”ÑŽ можливіÑтю."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5851,31 +5847,27 @@ msgstr "Режим виділеннÑ"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Drag: Rotate selected node around pivot."
-msgstr "Вилучити позначений вузол або перехід."
+msgstr "ПеретÑгуваннÑ: обертати позначений вузол навколо опорної точки."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Alt+Drag: Move selected node."
-msgstr "Alt+ПеретÑгнути: переміÑтити"
+msgstr "Alt+ПеретÑгнути: переміÑтити позначений вузол."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "V: Set selected node's pivot position."
-msgstr "Вилучити позначений вузол або перехід."
+msgstr "V: вÑтановити позицію опорної точки позначеного вузла."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Alt+RMB: Show list of all nodes at position clicked, including locked."
msgstr ""
-"Показати ÑпиÑок уÑÑ–Ñ… об'єктів, натиÑнутих на позицію\n"
-"(так Ñамо, Ñк Ðльт+ПКМ у режимі вибору)."
+"Alt+ПКМ: показати ÑпиÑок уÑÑ–Ñ… вузлів у позиції клацаннÑ, включно із "
+"заблокованими."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "RMB: Add node at position clicked."
-msgstr ""
+msgstr "ПКМ: додати вузол у позиції клацаннÑ."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -6113,14 +6105,12 @@ msgid "Clear Pose"
msgstr "ОчиÑтити позу"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Add Node Here"
-msgstr "Додати вузол"
+msgstr "Додати вузол тут"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Instance Scene Here"
-msgstr "Сцени екземплÑра"
+msgstr "ЕкземплÑÑ€ Ñцени тут"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Multiply grid step by 2"
@@ -6136,49 +6126,43 @@ msgstr "ÐŸÐ°Ð½Ð¾Ñ€Ð°Ð¼ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 3.125%"
-msgstr ""
+msgstr "МаÑштаб у 3,125%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 6.25%"
-msgstr ""
+msgstr "МаÑштаб у 6,25%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 12.5%"
-msgstr ""
+msgstr "МаÑштаб у 12,5%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 25%"
-msgstr "ЗменшеннÑ"
+msgstr "МаÑштаб у 25%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 50%"
-msgstr "ЗменшеннÑ"
+msgstr "МаÑштаб у 50%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 100%"
-msgstr "ЗменшеннÑ"
+msgstr "МаÑштаб у 100%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 200%"
-msgstr "ЗменшеннÑ"
+msgstr "МаÑштаб у 200%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 400%"
-msgstr "ЗменшеннÑ"
+msgstr "МаÑштаб у 400%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 800%"
-msgstr "ЗменшеннÑ"
+msgstr "МаÑштаб у 800%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 1600%"
-msgstr ""
+msgstr "МаÑштаб у 1600%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Add %s"
@@ -6424,9 +6408,8 @@ msgid "Couldn't create a single convex collision shape."
msgstr "Ðе вдалоÑÑ Ñтворити єдину опуклу форму зіткненнÑ."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Create Simplified Convex Shape"
-msgstr "Створити єдину опуклу форму"
+msgstr "Створити Ñпрощену опуклу форму"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Single Convex Shape"
@@ -6461,9 +6444,8 @@ msgid "No mesh to debug."
msgstr "Ðемає Ñітки Ð´Ð»Ñ Ð½Ð°Ð»Ð°Ð³Ð¾Ð´Ð¶ÐµÐ½Ð½Ñ."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Mesh has no UV in layer %d."
-msgstr "Модель не має UV на цьому шарі"
+msgstr "Сітка не має UV у шарі %d."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "MeshInstance lacks a Mesh!"
@@ -6528,9 +6510,8 @@ msgstr ""
"Цей найшвидший (але найменш точний) варіант Ð´Ð»Ñ Ð²Ð¸ÑÐ²Ð»ÐµÐ½Ð½Ñ Ð·Ñ–Ñ‚ÐºÐ½ÐµÐ½ÑŒ."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Create Simplified Convex Collision Sibling"
-msgstr "Створити єдину опуклу облаÑть зіткненнÑ"
+msgstr "Створити Ñпрощену опуклу облаÑть зіткненнÑ"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid ""
@@ -6538,20 +6519,23 @@ msgid ""
"This is similar to single collision shape, but can result in a simpler "
"geometry in some cases, at the cost of accuracy."
msgstr ""
+"Створює Ñпрощену опуклу форму зіткненнÑ.\n"
+"Це Ñхоже на єдину форму зіткненнÑ, але може призвеÑти у деÑких випадках до "
+"проÑтішої геометрії ціною точноÑті."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Multiple Convex Collision Siblings"
msgstr "Створити декілька опуклих облаÑтей зіткненнÑ"
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid ""
"Creates a polygon-based collision shape.\n"
"This is a performance middle-ground between a single convex collision and a "
"polygon-based collision."
msgstr ""
"Створює заÑновану на багатокутниках форму зіткненнÑ.\n"
-"Цей проміжний за швидкіÑтю варіант між наведеними вище двома варіантами."
+"Цей проміжний за швидкодією варіант між єдиною опуклою формою Ð·Ñ–Ñ‚ÐºÐ½ÐµÐ½Ð½Ñ Ñ– "
+"заÑнованою на багатокутниках формою зіткненнÑ."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Outline Mesh..."
@@ -7195,24 +7179,20 @@ msgid "ResourcePreloader"
msgstr "Передзавантажувач реÑурÑів"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Flip Portals"
-msgstr "Віддзеркалити горизонтально"
+msgstr "Віддзеркалити портали"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Room Generate Points"
-msgstr "КількіÑть генерованих точок:"
+msgstr "Створити точки кімнати"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Generate Points"
-msgstr "КількіÑть генерованих точок:"
+msgstr "Створити точки"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Flip Portal"
-msgstr "Віддзеркалити горизонтально"
+msgstr "Віддзеркалити портал"
#: editor/plugins/root_motion_editor_plugin.cpp
msgid "AnimationTree has no path set to an AnimationPlayer"
@@ -7778,20 +7758,17 @@ msgid "None"
msgstr "Ðемає"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Rotate"
-msgstr "Режим повороту"
+msgstr "Обертати"
#. TRANSLATORS: This refers to the movement that changes the position of an object.
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Translate"
-msgstr "ПеренеÑеннÑ:"
+msgstr "ПереÑунути"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Scale"
-msgstr "МаÑштаб:"
+msgstr "МаÑштаб"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scaling: "
@@ -7814,52 +7791,44 @@ msgid "Animation Key Inserted."
msgstr "Ð’Ñтавлено ключ анімації."
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Pitch:"
-msgstr "ХилитаннÑ"
+msgstr "Тон:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Yaw:"
-msgstr ""
+msgstr "РиÑканнÑ:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size:"
-msgstr "Розмір: "
+msgstr "Розмір:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Objects Drawn:"
-msgstr "Ðамальовано об'єктів"
+msgstr "Ðамальовано об'єктів:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Material Changes:"
-msgstr "Зміни матеріалу"
+msgstr "Зміни матеріалу:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Shader Changes:"
-msgstr "Зміни шейдерів"
+msgstr "Зміни шейдерів:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Surface Changes:"
-msgstr "Зміни поверхонь"
+msgstr "Зміни поверхонь:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Draw Calls:"
-msgstr "Виклики заÑобу малюваннÑ"
+msgstr "Ðамалювати виклики:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Vertices:"
-msgstr "Вершини"
+msgstr "Вершини:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "FPS: %d (%s ms)"
-msgstr ""
+msgstr "ЧаÑтота кадрів: %d (%s мÑ)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Top View."
@@ -8014,9 +7983,8 @@ msgid "Freelook Slow Modifier"
msgstr "Модифікатор швидкоÑті довільного оглÑду"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Toggle Camera Preview"
-msgstr "Змінити розмір камери"
+msgstr "Перемкнути попередній переглÑд камери"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Rotation Locked"
@@ -8039,9 +8007,8 @@ msgstr ""
"грі."
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Convert Rooms"
-msgstr "Перетворити на %s"
+msgstr "Перетворити кімнати"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "XForm Dialog"
@@ -8062,7 +8029,6 @@ msgstr ""
"Ðапівзакрите око: Gizmo Ñ” також видимим крізь непрозорі поверхні («рентген»)."
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Snap Nodes to Floor"
msgstr "Приліпити вузли до підлоги"
@@ -8080,7 +8046,7 @@ msgstr "За допомогою функції прив'Ñзки"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Converts rooms for portal culling."
-msgstr ""
+msgstr "Перетворює кімнати Ð´Ð»Ñ Ð²Ñ–Ð´Ð±Ñ€Ð°ÐºÐ¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾Ñ€Ñ‚Ð°Ð»Ñƒ."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Bottom View"
@@ -8176,9 +8142,8 @@ msgid "View Grid"
msgstr "ПереглÑд ґратки"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "View Portal Culling"
-msgstr "Параметри панелі переглÑду"
+msgstr "ПереглÑнути Ð²Ñ–Ð´Ð±Ñ€Ð°ÐºÐ¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Portal"
#: editor/plugins/spatial_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
@@ -8500,221 +8465,196 @@ msgid "TextureRegion"
msgstr "TextureRegion"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Colors"
-msgstr "Колір"
+msgstr "Кольори"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Fonts"
-msgstr "Шрифт"
+msgstr "Шрифти"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Icons"
-msgstr "Піктограма"
+msgstr "Піктограми"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Styleboxes"
-msgstr "Style Box"
+msgstr "Стильові панелі"
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} color(s)"
-msgstr ""
+msgstr "{num} кольорів"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No colors found."
-msgstr "Підлеглих реÑурÑів не знайдено."
+msgstr "Кольорів не знайдено."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "{num} constant(s)"
-msgstr "КонÑтанти"
+msgstr "{num} Ñталих"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No constants found."
-msgstr "Сталий колір."
+msgstr "Сталих не знайдено."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} font(s)"
-msgstr ""
+msgstr "{num} шрифтів"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No fonts found."
-msgstr "Ðе знайдено!"
+msgstr "Шрифтів не знайдено."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} icon(s)"
-msgstr ""
+msgstr "{num} піктограм"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No icons found."
-msgstr "Ðе знайдено!"
+msgstr "Піктограм не знайдено."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} stylebox(es)"
-msgstr ""
+msgstr "{num} панелей Ñтилів"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No styleboxes found."
-msgstr "Підлеглих реÑурÑів не знайдено."
+msgstr "Панелей Ñтилів не знайдено."
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} currently selected"
-msgstr ""
+msgstr "{num} зараз позначених"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Nothing was selected for the import."
-msgstr ""
+msgstr "Ðічого не позначено Ð´Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Importing Theme Items"
-msgstr "Імпортувати тему"
+msgstr "Ð†Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñів теми"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Importing items {n}/{n}"
-msgstr ""
+msgstr "Ð†Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñів, {n} з {n}"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Updating the editor"
-msgstr "Вийти з редактора?"
+msgstr "ÐžÐ½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¾Ñ€Ð°"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Finalizing"
-msgstr "Ðналіз"
+msgstr "ЗакріпленнÑ"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Filter:"
-msgstr "Фільтри:"
+msgstr "Фільтр:"
#: editor/plugins/theme_editor_plugin.cpp
msgid "With Data"
-msgstr ""
+msgstr "З даними"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select by data type:"
-msgstr "Виберіть вузол"
+msgstr "Вибір за типом даних:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible color items."
-msgstr "Виберіть поділ Ð´Ð»Ñ Ð¹Ð¾Ð³Ð¾ витираннÑ."
+msgstr "Вибрати уÑÑ– видимі запиÑи кольорів."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible color items and their data."
-msgstr ""
+msgstr "Вибрати уÑÑ– видимі запиÑи кольорів та їхні дані."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible color items."
-msgstr ""
+msgstr "СкаÑувати вибір уÑÑ–Ñ… видимих запиÑів кольорів."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible constant items."
-msgstr "Спочатку виберіть елемент параметра!"
+msgstr "Вибрати уÑÑ– видимі запиÑи Ñталих."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible constant items and their data."
-msgstr ""
+msgstr "Вибрати уÑÑ– запиÑи уÑÑ–Ñ… видимих Ñталих та їхні дані."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible constant items."
-msgstr ""
+msgstr "СкаÑувати вибір уÑÑ–Ñ… видимих запиÑів Ñталих."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible font items."
-msgstr "Спочатку виберіть елемент параметра!"
+msgstr "Вибрати уÑÑ– видимі запиÑи шрифтів."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible font items and their data."
-msgstr ""
+msgstr "Вибрати уÑÑ– видимі запиÑи шрифтів та їхні дані."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible font items."
-msgstr ""
+msgstr "СкаÑувати вибір уÑÑ–Ñ… видимих запиÑів шрифтів."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible icon items."
-msgstr "Спочатку виберіть елемент параметра!"
+msgstr "Вибрати уÑÑ– видимі запиÑи піктограм."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible icon items and their data."
-msgstr "Спочатку виберіть елемент параметра!"
+msgstr "Вибрати уÑÑ– видимі запиÑи піктограм та їхні дані."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Deselect all visible icon items."
-msgstr "Спочатку виберіть елемент параметра!"
+msgstr "СкаÑувати вибір уÑÑ–Ñ… видимих запиÑів піктограм."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible stylebox items."
-msgstr ""
+msgstr "Вибрати уÑÑ– видимі запиÑи панелей Ñтилів."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible stylebox items and their data."
-msgstr ""
+msgstr "Вибрати уÑÑ– видимі запиÑи панелей Ñтилів та їхні дані."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible stylebox items."
-msgstr ""
+msgstr "СкаÑувати вибір уÑÑ–Ñ… видимих запиÑів панелей Ñтилів."
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
"Caution: Adding icon data may considerably increase the size of your Theme "
"resource."
msgstr ""
+"ПопередженнÑ: Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… піктограм може значно збільшити розмір вашого "
+"реÑурÑу теми."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Collapse types."
-msgstr "Згорнути вÑе"
+msgstr "Згорнути типи."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Expand types."
-msgstr "Розгорнути вÑе"
+msgstr "Розгорнути типи."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all Theme items."
-msgstr "Виберіть файл шаблону"
+msgstr "Вибрати уÑÑ– запиÑи тем."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select With Data"
-msgstr "Виберіть пункти"
+msgstr "Вибрати з даними"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all Theme items with item data."
-msgstr ""
+msgstr "Вибрати уÑÑ– запиÑи тем із даними запиÑу."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Deselect All"
-msgstr "Виділити вÑе"
+msgstr "ЗнÑти Ð¿Ð¾Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð· уÑÑ–Ñ…"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all Theme items."
-msgstr ""
+msgstr "СкаÑувати вибір уÑÑ–Ñ… запиÑів тем."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Import Selected"
-msgstr "Імпортувати Ñцену"
+msgstr "Імпортувати позначене"
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
@@ -8722,271 +8662,247 @@ msgid ""
"closing this window.\n"
"Close anyway?"
msgstr ""
+"Ðа панелі Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñів позначено деÑкі запиÑи. Якщо закрити це "
+"вікно, Ð¿Ð¾Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð±ÑƒÐ´Ðµ знÑто.\n"
+"Закрити вікно попри це?"
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Color Items"
-msgstr "Вилучити уÑÑ– елементи"
+msgstr "Вилучити уÑÑ– запиÑи кольорів"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Item"
-msgstr "Вилучити елемент"
+msgstr "Перейменувати запиÑ"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Constant Items"
-msgstr "Вилучити уÑÑ– елементи"
+msgstr "Вилучити уÑÑ– запиÑи Ñталих"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Font Items"
-msgstr "Вилучити уÑÑ– елементи"
+msgstr "Вилучити уÑÑ– запиÑи шрифтів"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Icon Items"
-msgstr "Вилучити уÑÑ– елементи"
+msgstr "Вилучити уÑÑ– запиÑи піктограм"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All StyleBox Items"
-msgstr "Вилучити уÑÑ– елементи"
+msgstr "Вилучити уÑÑ– запиÑи панелей Ñтилів"
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Color Item"
-msgstr "Додати елементи клаÑу"
+msgstr "Додати Ð·Ð°Ð¿Ð¸Ñ ÐºÐ¾Ð»ÑŒÐ¾Ñ€Ñƒ"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Constant Item"
-msgstr "Додати елементи клаÑу"
+msgstr "Додати Ð·Ð°Ð¿Ð¸Ñ Ñталої"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Font Item"
-msgstr "Додати елемент"
+msgstr "Додати Ð·Ð°Ð¿Ð¸Ñ ÑˆÑ€Ð¸Ñ„Ñ‚Ñƒ"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Icon Item"
-msgstr "Додати елемент"
+msgstr "Додати Ð·Ð°Ð¿Ð¸Ñ Ð¿Ñ–ÐºÑ‚Ð¾Ð³Ñ€Ð°Ð¼Ð¸"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Stylebox Item"
-msgstr "Додати уÑÑ– елементи"
+msgstr "Додати Ð·Ð°Ð¿Ð¸Ñ Ð¿Ð°Ð½ÐµÐ»Ñ– Ñтилів"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Color Item"
-msgstr "Вилучити елементи клаÑу"
+msgstr "Перейменувати Ð·Ð°Ð¿Ð¸Ñ ÐºÐ¾Ð»ÑŒÐ¾Ñ€Ñƒ"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Constant Item"
-msgstr "Вилучити елементи клаÑу"
+msgstr "Перейменувати Ð·Ð°Ð¿Ð¸Ñ Ñталої"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Font Item"
-msgstr "Перейменувати вузол"
+msgstr "Перейменувати Ð·Ð°Ð¿Ð¸Ñ ÑˆÑ€Ð¸Ñ„Ñ‚Ñƒ"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Icon Item"
-msgstr "Перейменувати вузол"
+msgstr "Перейменувати Ð·Ð°Ð¿Ð¸Ñ Ð¿Ñ–ÐºÑ‚Ð¾Ð³Ñ€Ð°Ð¼Ð¸"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Stylebox Item"
-msgstr "Вилучити вибраний елемент"
+msgstr "Перейменувати Ð·Ð°Ð¿Ð¸Ñ Ð¿Ð°Ð½ÐµÐ»Ñ– Ñтилів"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Invalid file, not a Theme resource."
-msgstr "ÐеприпуÑтимий файл, це не ÐºÐ¾Ð¼Ð¿Ð¾Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð°ÑƒÐ´Ñ–Ð¾-шини."
+msgstr "Ðекоректний файл. Файл не Ñ” реÑурÑом теми."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Invalid file, same as the edited Theme resource."
-msgstr ""
+msgstr "Ðекоректний файл. Файл збігаєтьÑÑ Ñ–Ð· редагованим реÑурÑом теми."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Manage Theme Items"
-msgstr "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ð°Ð¼Ð¸"
+msgstr "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñами теми"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Edit Items"
-msgstr "Редагований елемент"
+msgstr "Редагувати запиÑи"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Types:"
-msgstr "Тип:"
+msgstr "Типи:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Type:"
-msgstr "Тип:"
+msgstr "Додати тип:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Item:"
-msgstr "Додати елемент"
+msgstr "Додати запиÑ:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add StyleBox Item"
-msgstr "Додати уÑÑ– елементи"
+msgstr "Додати Ð·Ð°Ð¿Ð¸Ñ Ð¿Ð°Ð½ÐµÐ»Ñ– Ñтилів"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove Items:"
-msgstr "Вилучити елемент"
+msgstr "Вилучити запиÑи:"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove Class Items"
-msgstr "Вилучити елементи клаÑу"
+msgstr "Вилучити запиÑи клаÑу"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove Custom Items"
-msgstr "Вилучити елементи клаÑу"
+msgstr "Вилучити нетипові запиÑи"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Items"
msgstr "Вилучити уÑÑ– елементи"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Theme Item"
-msgstr "Тема елементів ГІК"
+msgstr "Додати Ð·Ð°Ð¿Ð¸Ñ Ñ‚ÐµÐ¼Ð¸"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Old Name:"
-msgstr "Ім'Ñ Ð’ÑƒÐ·Ð»Ð°:"
+msgstr "Стара назва:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Import Items"
-msgstr "Імпортувати тему"
+msgstr "Імпортовані пункти"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Default Theme"
-msgstr "Типовий"
+msgstr "Типова тема"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Editor Theme"
-msgstr "Редагувати тему"
+msgstr "Тема редактора"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select Another Theme Resource:"
-msgstr "Вилучити реÑурÑ"
+msgstr "Виберіть реÑÑƒÑ€Ñ Ñ–Ð½ÑˆÐ¾Ñ— теми:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Another Theme"
-msgstr "Імпортувати тему"
+msgstr "Інша тема"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Confirm Item Rename"
-msgstr "Перейменувати доріжку"
+msgstr "Підтвердити Ð¿ÐµÑ€ÐµÐ¹Ð¼ÐµÐ½ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Cancel Item Rename"
-msgstr "Пакетне перейменуваннÑ"
+msgstr "СкаÑувати Ð¿ÐµÑ€ÐµÐ¹Ð¼ÐµÐ½ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Override Item"
-msgstr "ПеревизначеннÑ"
+msgstr "Перевизначити запиÑ"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Unpin this StyleBox as a main style."
-msgstr ""
+msgstr "Відшпилити цю панель Ñтилів Ñк головний Ñтиль."
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
"Pin this StyleBox as a main style. Editing its properties will update the "
"same properties in all other StyleBoxes of this type."
msgstr ""
+"Пришпилити цю панель Ñтилів Ñк оÑновний Ñтиль. Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ð¹Ð¾Ð³Ð¾ влаÑтивоÑтей "
+"призведе до Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ‚Ð¸Ñ… Ñами влаÑтивоÑтей в уÑÑ–Ñ… інших панелÑÑ… Ñтилів "
+"цього типу."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Type"
-msgstr "Тип"
+msgstr "Додати тип"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Item Type"
-msgstr "Додати елемент"
+msgstr "Додати тип запиÑу"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Node Types:"
-msgstr "Тип вузлів"
+msgstr "Типи вузлів:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Show Default"
-msgstr "Завантажити типовий"
+msgstr "Показати типовий"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Show default type items alongside items that have been overridden."
msgstr ""
+"Показати запиÑи Ñтандартних типів разом із запиÑами, Ñкі було перевизначено."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Override All"
-msgstr "ПеревизначеннÑ"
+msgstr "Перевизначити уÑе"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Override all default type items."
-msgstr ""
+msgstr "Перевизначити уÑÑ– запиÑи Ñтандартних типів."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Theme:"
-msgstr "Тема"
+msgstr "Тема:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Manage Items..."
-msgstr "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ð°Ð¼Ð¸ екÑпортуваннÑ…"
+msgstr "Керувати запиÑами…"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add, remove, organize and import Theme items."
-msgstr ""
+msgstr "Додати, вилучити, упорÑдкувати або імпортувати запиÑи тем."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Preview"
-msgstr "Попередній переглÑд"
+msgstr "Додати Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Default Preview"
-msgstr "Оновити переглÑд"
+msgstr "Типове Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select UI Scene:"
-msgstr "Виберіть джерело Ñітки:"
+msgstr "Виберіть Ñцену графічного інтерфейÑу:"
#: editor/plugins/theme_editor_preview.cpp
msgid ""
"Toggle the control picker, allowing to visually select control types for "
"edit."
msgstr ""
+"Перемкнути заÑіб вибору керуваннÑ, Ñкий уможливлює візуальний вибір типів "
+"ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ."
#: editor/plugins/theme_editor_preview.cpp
msgid "Toggle Button"
@@ -9021,9 +8937,8 @@ msgid "Checked Radio Item"
msgstr "Позначений пункт варіанта"
#: editor/plugins/theme_editor_preview.cpp
-#, fuzzy
msgid "Named Separator"
-msgstr "Імен. розд."
+msgstr "Іменований роздільник"
#: editor/plugins/theme_editor_preview.cpp
msgid "Submenu"
@@ -9076,19 +8991,21 @@ msgstr "Має,Багато,Параметрів"
#: editor/plugins/theme_editor_preview.cpp
msgid "Invalid path, the PackedScene resource was probably moved or removed."
msgstr ""
+"Ðекоректний шлÑÑ…. Ймовірно, реÑÑƒÑ€Ñ PackedScene було переÑунуто або вилучено."
#: editor/plugins/theme_editor_preview.cpp
msgid "Invalid PackedScene resource, must have a Control node at its root."
msgstr ""
+"Ðекоректний реÑÑƒÑ€Ñ PackedScene. Кореневим вузлом реÑурÑу має бути вузол "
+"Control."
#: editor/plugins/theme_editor_preview.cpp
-#, fuzzy
msgid "Invalid file, not a PackedScene resource."
-msgstr "ÐеприпуÑтимий файл, це не ÐºÐ¾Ð¼Ð¿Ð¾Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð°ÑƒÐ´Ñ–Ð¾-шини."
+msgstr "Ðекоректний файл. Файл не Ñ” реÑурÑом PackedScene."
#: editor/plugins/theme_editor_preview.cpp
msgid "Reload the scene to reflect its most actual state."
-msgstr ""
+msgstr "Перезавантажити Ñцену Ð´Ð»Ñ Ð²Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ—Ñ— найактуальнішого Ñтану."
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Erase Selection"
@@ -10493,9 +10410,8 @@ msgid "VisualShader"
msgstr "VisualShader"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Edit Visual Property:"
-msgstr "Змінити візуальну влаÑтивіÑть"
+msgstr "Змінити візуальну влаÑтивіÑть:"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Visual Shader Mode Changed"
@@ -10621,9 +10537,8 @@ msgid "Script"
msgstr "Скрипт"
#: editor/project_export.cpp
-#, fuzzy
msgid "GDScript Export Mode:"
-msgstr "Режим екÑÐ¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñкрипту:"
+msgstr "Режим екÑÐ¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ GDScript:"
#: editor/project_export.cpp
msgid "Text"
@@ -10631,21 +10546,20 @@ msgstr "ТекÑÑ‚"
#: editor/project_export.cpp
msgid "Compiled Bytecode (Faster Loading)"
-msgstr ""
+msgstr "Зібраний байткод (швидше завантаженнÑ)"
#: editor/project_export.cpp
msgid "Encrypted (Provide Key Below)"
msgstr "Зашифровано (ключ можна вказати нижче)"
#: editor/project_export.cpp
-#, fuzzy
msgid "Invalid Encryption Key (must be 64 hexadecimal characters long)"
-msgstr "Ðекоректний ключ ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ (ключ має ÑкладатиÑÑ Ñ–Ð· 64 Ñимволів)"
+msgstr ""
+"Ðекоректний ключ ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ (ключ має ÑкладатиÑÑ Ñ–Ð· 64 шіÑтнадцÑткових цифр)"
#: editor/project_export.cpp
-#, fuzzy
msgid "GDScript Encryption Key (256-bits as hexadecimal):"
-msgstr "Ключ ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñкрипту (256-бітове шіÑтнадцÑткове чиÑло):"
+msgstr "Ключ ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ GDScript (256-бітове шіÑтнадцÑткове чиÑло):"
#: editor/project_export.cpp
msgid "Export PCK/Zip"
@@ -10717,7 +10631,6 @@ msgid "Imported Project"
msgstr "Імпортований проєкт"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Invalid project name."
msgstr "Ðекоректна назва проєкту."
@@ -10945,14 +10858,12 @@ msgid "Are you sure to run %d projects at once?"
msgstr "Ви Ñправді хочете запуÑтити %d проєктів одночаÑно?"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove %d projects from the list?"
-msgstr "Вибрати приÑтрій зі ÑпиÑку"
+msgstr "Вилучити зі ÑпиÑку %d проєктів?"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove this project from the list?"
-msgstr "Вибрати приÑтрій зі ÑпиÑку"
+msgstr "Вилучити цей проєкт зі ÑпиÑку?"
#: editor/project_manager.cpp
msgid ""
@@ -10985,9 +10896,8 @@ msgid "Project Manager"
msgstr "Керівник проєкту"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Local Projects"
-msgstr "Проєкти"
+msgstr "Локальні проєкти"
#: editor/project_manager.cpp
msgid "Loading, please wait..."
@@ -10998,23 +10908,20 @@ msgid "Last Modified"
msgstr "ВоÑтаннє змінено"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Edit Project"
-msgstr "ЕкÑпортувати проєкт"
+msgstr "Редагувати проєкт"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Run Project"
-msgstr "Перейменувати проєкт"
+msgstr "ЗапуÑтити проєкт"
#: editor/project_manager.cpp
msgid "Scan"
msgstr "Сканувати"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Scan Projects"
-msgstr "Проєкти"
+msgstr "Сканувати проєкти"
#: editor/project_manager.cpp
msgid "Select a Folder to Scan"
@@ -11025,14 +10932,12 @@ msgid "New Project"
msgstr "Ðовий проєкт"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Import Project"
-msgstr "Імпортований проєкт"
+msgstr "Імпортувати проєкт"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove Project"
-msgstr "Перейменувати проєкт"
+msgstr "Вилучити проєкт"
#: editor/project_manager.cpp
msgid "Remove Missing"
@@ -11040,12 +10945,11 @@ msgstr "Вилучити пропущене"
#: editor/project_manager.cpp
msgid "About"
-msgstr "Про"
+msgstr "ВідомоÑті"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Asset Library Projects"
-msgstr "Бібліотека реÑурÑів"
+msgstr "Проєкти бібліотеки пакунків"
#: editor/project_manager.cpp
msgid "Restart Now"
@@ -11057,7 +10961,7 @@ msgstr "Вилучити уÑÑ–"
#: editor/project_manager.cpp
msgid "Also delete project contents (no undo!)"
-msgstr ""
+msgstr "Також вилучити вміÑÑ‚ проєкту (без можливоÑті ÑкаÑуваннÑ!)"
#: editor/project_manager.cpp
msgid "Can't run project"
@@ -11072,20 +10976,18 @@ msgstr ""
"Бажаєте переглÑнути офіційні приклади проєктів з бібліотеки реÑурÑів?"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Filter projects"
-msgstr "Фільтрувати влаÑтивоÑті"
+msgstr "Фільтр проєктів"
#: editor/project_manager.cpp
-#, fuzzy
msgid ""
"This field filters projects by name and last path component.\n"
"To filter projects by name and full path, the query must contain at least "
"one `/` character."
msgstr ""
-"Поле пошуку фільтрує проєкти за назвою Ñ– оÑтаннім компонентом шлÑху.\n"
+"Це поле фільтрує проєкти за назвою Ñ– оÑтаннім компонентом шлÑху.\n"
"Щоб виконати Ñ„Ñ–Ð»ÑŒÑ‚Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñ–Ð² за назвою Ñ– повним шлÑхом, у запиті має "
-"бути принаймні один Ñимвол `/`."
+"бути принаймні один Ñимвол «/»."
#: editor/project_settings_editor.cpp
msgid "Key "
@@ -11093,7 +10995,7 @@ msgstr "Клавіша "
#: editor/project_settings_editor.cpp
msgid "Physical Key"
-msgstr ""
+msgstr "Фізична клавіша"
#: editor/project_settings_editor.cpp
msgid "Joy Button"
@@ -11141,7 +11043,7 @@ msgstr "ПриÑтрій"
#: editor/project_settings_editor.cpp
msgid " (Physical)"
-msgstr ""
+msgstr " (фізичний)"
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "Press a Key..."
@@ -11284,23 +11186,21 @@ msgid "Override for Feature"
msgstr "Перевизначено Ð´Ð»Ñ Ð¼Ð¾Ð¶Ð»Ð¸Ð²Ð¾Ñті"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Add %d Translations"
-msgstr "Додати переклад"
+msgstr "Додати %d перекладів"
#: editor/project_settings_editor.cpp
msgid "Remove Translation"
msgstr "Вилучити переклад"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Translation Resource Remap: Add %d Path(s)"
-msgstr "ПереÑпрÑÐ¼ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÑурÑу додає переÑпрÑмуваннÑ"
+msgstr "Повторна прив'Ñзка реÑурÑів перекладу: Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ %d шлÑхів"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Translation Resource Remap: Add %d Remap(s)"
-msgstr "ПереÑпрÑÐ¼ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÑурÑу додає переÑпрÑмуваннÑ"
+msgstr ""
+"Повторна прив'Ñзка реÑурÑів перекладу: Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ %d повторних прив'Ñзок"
#: editor/project_settings_editor.cpp
msgid "Change Resource Remap Language"
@@ -11746,12 +11646,15 @@ msgstr "Вилучити вузол «%s»?"
msgid ""
"Saving the branch as a scene requires having a scene open in the editor."
msgstr ""
+"Щоб можна було зберегти гілку Ñк Ñцену, Ñцену має бути відкрито у редакторі."
#: editor/scene_tree_dock.cpp
msgid ""
"Saving the branch as a scene requires selecting only one node, but you have "
"selected %d nodes."
msgstr ""
+"Щоб можна було зберегти гілку Ñк Ñцену, має бути позначено лише один вузол, "
+"а у Ð²Ð°Ñ Ð¿Ð¾Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¾ %d."
#: editor/scene_tree_dock.cpp
msgid ""
@@ -11760,6 +11663,11 @@ msgid ""
"FileSystem dock context menu\n"
"or create an inherited scene using Scene > New Inherited Scene... instead."
msgstr ""
+"Ðе вдалоÑÑ Ð·Ð±ÐµÑ€ÐµÐ³Ñ‚Ð¸ гілку кореневого вузла Ñк екземплÑÑ€ Ñцени.\n"
+"Щоб Ñтворити редаговану копію поточної Ñцени, здублюйте Ñ—Ñ— за допомогою "
+"контекÑтного меню бічної панелі файлової ÑиÑтеми\n"
+"або Ñтворіть уÑпадковану Ñцену за допомогою пункту меню «Сцена > Створити "
+"уÑпадковану Ñцену...»."
#: editor/scene_tree_dock.cpp
msgid ""
@@ -11767,6 +11675,10 @@ msgid ""
"To create a variation of a scene, you can make an inherited scene based on "
"the instanced scene using Scene > New Inherited Scene... instead."
msgstr ""
+"Ðе вдалоÑÑ Ð·Ð±ÐµÑ€ÐµÐ³Ñ‚Ð¸ гілку вже Ñтвореного екземплÑра Ñцени.\n"
+"Щоб Ñтворити варіацію Ñцени, ви можете Ñтворити уÑпадковану Ñцену на оÑнові "
+"екземплÑра Ñцени за допомогою пункту меню «Сцена > Створити уÑпадковану "
+"Ñцену...»."
#: editor/scene_tree_dock.cpp
msgid "Save New Scene As..."
@@ -12174,6 +12086,8 @@ msgid ""
"Warning: Having the script name be the same as a built-in type is usually "
"not desired."
msgstr ""
+"ПопередженнÑ: викориÑÑ‚Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ñкрипту назви, Ñка збігаєтьÑÑ Ñ–Ð· назвою "
+"вбудованого типу, зазвичай, є небажаним."
#: editor/script_create_dialog.cpp
msgid "Class Name:"
@@ -12245,7 +12159,7 @@ msgstr "Помилка копіюваннÑ"
#: editor/script_editor_debugger.cpp
msgid "Open C++ Source on GitHub"
-msgstr ""
+msgstr "Відкрити початковий код C++ на GitHub"
#: editor/script_editor_debugger.cpp
msgid "Video RAM"
@@ -12423,6 +12337,16 @@ msgstr "Змінити виÑоту форми циліндра"
msgid "Change Ray Shape Length"
msgstr "Змінити довжину форми променÑ"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Задати Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð½Ñ Ñ‚Ð¾Ñ‡ÐºÐ¸ кривої"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Задати Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð½Ñ Ñ‚Ð¾Ñ‡ÐºÐ¸ кривої"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "Змінити Ñ€Ð°Ð´Ñ–ÑƒÑ Ñ†Ð¸Ð»Ñ–Ð½Ð´Ñ€Ð°"
@@ -12534,14 +12458,12 @@ msgid "Object can't provide a length."
msgstr "Об'єкт не може надавати довжину."
#: modules/gltf/editor_scene_exporter_gltf_plugin.cpp
-#, fuzzy
msgid "Export Mesh GLTF2"
-msgstr "ЕкÑпортувати бібліотеку Ñіті"
+msgstr "ЕкÑпортувати GLTF2 Ñітки"
#: modules/gltf/editor_scene_exporter_gltf_plugin.cpp
-#, fuzzy
msgid "Export GLTF..."
-msgstr "ЕкÑпортувати…"
+msgstr "ЕкÑпортувати GLTF…"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Next Plane"
@@ -12584,9 +12506,8 @@ msgid "GridMap Paint"
msgstr "Малюнок GridMap"
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "GridMap Selection"
-msgstr "Вибір Ð·Ð°Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ GridMap"
+msgstr "Вибір GridMap"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Grid Map"
@@ -12838,14 +12759,12 @@ msgid "Add Output Port"
msgstr "Додати вихідний порт"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Change Port Type"
-msgstr "Змінити тип"
+msgstr "Змірити тип порту"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Change Port Name"
-msgstr "Змінити назву вхідного порту"
+msgstr "Змінити назву порту"
#: modules/visual_script/visual_script_editor.cpp
msgid "Override an existing built-in function."
@@ -12960,9 +12879,8 @@ msgid "Add Preload Node"
msgstr "Додати попередньо завантажений вузол"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Node(s)"
-msgstr "Додати вузол"
+msgstr "Додати вузли"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Node(s) From Tree"
@@ -13227,37 +13145,31 @@ msgstr "Вибрати приÑтрій зі ÑпиÑку"
#: platform/android/export/export.cpp
msgid "Running on %s"
-msgstr ""
+msgstr "Запущено на %s"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Exporting APK..."
-msgstr "ЕкÑÐ¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ ÑƒÑього"
+msgstr "ЕкÑÐ¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ APK…"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Uninstalling..."
-msgstr "Видалити"
+msgstr "ВилученнÑ…"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Installing to device, please wait..."
-msgstr "ЗавантаженнÑ. Будь лаÑка, зачекайте..."
+msgstr "Ð’ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð½Ð° приÑтрій. Будь лаÑка, зачекайте..."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not install to device: %s"
-msgstr "Ðе вдалоÑÑ Ð·Ð°Ð¿ÑƒÑтити підпроцеÑ!"
+msgstr "Ðе вдалоÑÑ Ð²Ñтановити на приÑтрій: %s"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Running on device..."
-msgstr "ЗапуÑк кориÑтувацького Ñкрипту..."
+msgstr "ЗапуÑк на приÑтрої…"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not execute on device."
-msgstr "Ðеможливо Ñтворити теку."
+msgstr "Ðе вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ на приÑтрої."
#: platform/android/export/export.cpp
msgid "Unable to find the 'apksigner' tool."
@@ -13388,40 +13300,38 @@ msgid ""
"directory.\n"
"The resulting %s is unsigned."
msgstr ""
+"Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ «apksigner».\n"
+"Будь лаÑка, перевірте, чи Ñ” програма доÑтупною у каталозі build-tools набору "
+"заÑобів Ð´Ð»Ñ Ñ€Ð¾Ð·Ñ€Ð¾Ð±ÐºÐ¸ Android.\n"
+"Отриманий у результаті %s не підпиÑано."
#: platform/android/export/export.cpp
msgid "Signing debug %s..."
-msgstr ""
+msgstr "ПідпиÑÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ñ–Ð°Ð³Ð½Ð¾Ñтики %s…"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Signing release %s..."
-msgstr ""
-"Ð¡ÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñ–Ð²,\n"
-"будь лаÑка, зачекайте..."
+msgstr "ПідпиÑÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸Ð¿ÑƒÑку %s…"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not find keystore, unable to export."
-msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ шаблон Ð´Ð»Ñ ÐµÐºÑпорту:"
+msgstr "Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ Ñховище ключів. Ðеможливо виконати екÑпортуваннÑ."
#: platform/android/export/export.cpp
msgid "'apksigner' returned with error #%d"
-msgstr ""
+msgstr "«apksigner» повернуто Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ помилку із номером %d"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Verifying %s..."
-msgstr "Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ %s..."
+msgstr "ПеревірÑємо %s…"
#: platform/android/export/export.cpp
msgid "'apksigner' verification of %s failed."
-msgstr ""
+msgstr "%s не пройдено перевірку за допомогою «apksigner»."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Exporting for Android"
-msgstr "ЕкÑÐ¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ ÑƒÑього"
+msgstr "ЕкÑпорт на Android"
#: platform/android/export/export.cpp
msgid "Invalid filename! Android App Bundle requires the *.aab extension."
@@ -13440,7 +13350,7 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "Unsupported export format!\n"
-msgstr ""
+msgstr "Ðепідтримуваний формат екÑпортуваннÑ!\n"
#: platform/android/export/export.cpp
msgid ""
@@ -13468,16 +13378,15 @@ msgstr ""
msgid ""
"Unable to overwrite res://android/build/res/*.xml files with project name"
msgstr ""
+"Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ·Ð°Ð¿Ð¸Ñати файли res://android/build/res/*.xml із назвою проєкту"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not export project files to gradle project\n"
-msgstr "Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ project.godot у каталозі проекту."
+msgstr "Ðе вдалоÑÑ ÐµÐºÑпортувати файли проєкту до проєкту gradle\n"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not write expansion package file!"
-msgstr "Ðе вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати файл:"
+msgstr "Ðе вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати файл пакунка розширеннÑ!"
#: platform/android/export/export.cpp
msgid "Building Android Project (gradle)"
@@ -13506,21 +13415,20 @@ msgstr ""
"дані можна знайти у каталозі проєкту gradle."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Package not found: %s"
-msgstr "Ðе знайдено анімації: «%s»"
+msgstr "Пакунок не знайдено: %s"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Creating APK..."
-msgstr "Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÐºÐ¾Ð½Ñ‚ÑƒÑ€Ñ–Ð²..."
+msgstr "Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ APK…"
#: platform/android/export/export.cpp
-#, fuzzy
msgid ""
"Could not find template APK to export:\n"
"%s"
-msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ шаблон Ð´Ð»Ñ ÐµÐºÑпорту:"
+msgstr ""
+"Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ шаблон APK Ð´Ð»Ñ ÐµÐºÑпортуваннÑ:\n"
+"%s"
#: platform/android/export/export.cpp
msgid ""
@@ -13529,16 +13437,17 @@ msgid ""
"Please build a template with all required libraries, or uncheck the missing "
"architectures in the export preset."
msgstr ""
+"Ðе виÑтачає бібліотек у шаблоні екÑÐ¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð²Ð¸Ð±Ñ€Ð°Ð½Ð¸Ñ… архітектур: %s.\n"
+"Будь лаÑка, Ñтворіть шаблон з уÑіма необхідними бібліотеками або зніміть "
+"позначку з архітектур із пропущеними бібліотеками у Ñтилі екÑпортуваннÑ."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Adding files..."
-msgstr "Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ %s..."
+msgstr "Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñ–Ð²â€¦"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not export project files"
-msgstr "Ðе вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати файл:"
+msgstr "Ðе вдалоÑÑ ÐµÐºÑпортувати файли проєкту"
#: platform/android/export/export.cpp
msgid "Aligning APK..."
@@ -13546,7 +13455,7 @@ msgstr "Вирівнюємо APK..."
#: platform/android/export/export.cpp
msgid "Could not unzip temporary unaligned APK."
-msgstr ""
+msgstr "Ðе вдалоÑÑ Ñ€Ð¾Ð·Ð¿Ð°ÐºÑƒÐ²Ð°Ñ‚Ð¸ тимчаÑовий невирівнÑний APK."
#: platform/iphone/export/export.cpp platform/osx/export/export.cpp
msgid "Identifier is missing."
@@ -13594,45 +13503,40 @@ msgid "Could not write file:"
msgstr "Ðе вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати файл:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not read file:"
-msgstr "Ðе вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати файл:"
+msgstr "Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ файл:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not read HTML shell:"
-msgstr "Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ Ñпеціальну оболонку HTML:"
+msgstr "Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ оболонку HTML:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not create HTTP server directory:"
-msgstr "Ðеможливо Ñтворити теку."
+msgstr "Ðе вдалоÑÑ Ñтворити каталог на Ñервері HTTP:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Error starting HTTP server:"
-msgstr "Помилка Ð·Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ñцени."
+msgstr "Помилка під Ñ‡Ð°Ñ Ñпроби запуÑку Ñервера HTTP:"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Invalid bundle identifier:"
-msgstr "Ðекоректний ідентифікатор:"
+msgstr "Ðекоректний ідентифікатор пакунка:"
#: platform/osx/export/export.cpp
msgid "Notarization: code signing required."
-msgstr ""
+msgstr "ЗаÑвідченнÑ: потрібен код підпиÑуваннÑ."
#: platform/osx/export/export.cpp
msgid "Notarization: hardened runtime required."
-msgstr ""
+msgstr "ЗаÑвідченнÑ: потрібне Ñтійке Ñередовище запуÑку."
#: platform/osx/export/export.cpp
msgid "Notarization: Apple ID name not specified."
-msgstr ""
+msgstr "ЗаÑвідченнÑ: не вказано назву ідентифікатора Apple."
#: platform/osx/export/export.cpp
msgid "Notarization: Apple ID password not specified."
-msgstr ""
+msgstr "ЗаÑвідченнÑ: не вказано пароль до ідентифікатора Apple."
#: platform/uwp/export/export.cpp
msgid "Invalid package short name."
@@ -14074,6 +13978,9 @@ msgid ""
"longer has any effect.\n"
"To remove this warning, disable the GIProbe's Compress property."
msgstr ""
+"ВлаÑтивіÑть GIProbe Compress було визначено заÑтарілою через відомі помилки. "
+"Вона більше ні на що не впливає.\n"
+"Щоб уÑунути це попередженнÑ, вимкніть влаÑтивіÑть Compress у GIProbe."
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
@@ -14163,14 +14070,20 @@ msgstr "Вузол A і вузол B має бути різними PhysicsBody"
#: scene/3d/portal.cpp
msgid "The RoomManager should not be a child or grandchild of a Portal."
msgstr ""
+"RoomManager не повинен бути дочірнім об'єктом першого або другого Ñ€Ñ–Ð²Ð½Ñ Ð´Ð»Ñ "
+"Portal."
#: scene/3d/portal.cpp
msgid "A Room should not be a child or grandchild of a Portal."
msgstr ""
+"Ð—Ð°Ð¿Ð¸Ñ Room не повинен бути дочірнім об'єктом першого або другого Ñ€Ñ–Ð²Ð½Ñ Ð´Ð»Ñ "
+"Portal."
#: scene/3d/portal.cpp
msgid "A RoomGroup should not be a child or grandchild of a Portal."
msgstr ""
+"Ð—Ð°Ð¿Ð¸Ñ RoomGroup не повинен бути дочірнім об'єктом першого або другого Ñ€Ñ–Ð²Ð½Ñ "
+"Ð´Ð»Ñ Portal."
#: scene/3d/remote_transform.cpp
msgid ""
@@ -14183,41 +14096,83 @@ msgstr ""
#: scene/3d/room.cpp
msgid "A Room cannot have another Room as a child or grandchild."
msgstr ""
+"Ð—Ð°Ð¿Ð¸Ñ Room не може міÑтити дочірнього об'єкта Room першого або другого Ñ€Ñ–Ð²Ð½Ñ "
+"вкладеноÑті."
#: scene/3d/room.cpp
msgid "The RoomManager should not be placed inside a Room."
-msgstr ""
+msgstr "RoomManager не можна розташовувати у Room."
#: scene/3d/room.cpp
msgid "A RoomGroup should not be placed inside a Room."
-msgstr ""
+msgstr "RoomGroup не можна розташовувати у Room."
#: scene/3d/room.cpp
msgid ""
"Room convex hull contains a large number of planes.\n"
"Consider simplifying the room bound in order to increase performance."
msgstr ""
+"Опукла оболонка кімнати міÑтить велику кількіÑть площин.\n"
+"Вам варто ÑпроÑтити межу кімнати, щоб підвищити швидкодію."
#: scene/3d/room_group.cpp
msgid "The RoomManager should not be placed inside a RoomGroup."
-msgstr ""
+msgstr "RoomManager не можна розташовувати у RoomGroup."
#: scene/3d/room_manager.cpp
msgid "The RoomList has not been assigned."
-msgstr ""
+msgstr "RoomList не надано значеннÑ."
#: scene/3d/room_manager.cpp
msgid "The RoomList node should be a Spatial (or derived from Spatial)."
-msgstr ""
+msgstr "Вузол RoomList не може бути Spatial (або походити від Spatial)."
#: scene/3d/room_manager.cpp
msgid ""
"Portal Depth Limit is set to Zero.\n"
"Only the Room that the Camera is in will render."
msgstr ""
+"Ð”Ð»Ñ Â«ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ð³Ð»Ð¸Ð±Ð¸Ð½Ð¸ порталу» вÑтановлено нульове значеннÑ.\n"
+"Буде оброблено лише Room, у Ñкій перебуває Camera."
#: scene/3d/room_manager.cpp
msgid "There should only be one RoomManager in the SceneTree."
+msgstr "У SceneTree має бути лише один Ð·Ð°Ð¿Ð¸Ñ RoomManager."
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
msgstr ""
#: scene/3d/soft_body.cpp
@@ -14283,7 +14238,7 @@ msgstr "Ðе знайдено анімації: «%s»"
#: scene/animation/animation_player.cpp
msgid "Anim Apply Reset"
-msgstr ""
+msgstr "Скинути заÑтоÑÑƒÐ²Ð°Ð½Ð½Ñ Ð°Ð½Ñ–Ð¼Ð°Ñ†Ñ–Ñ—"
#: scene/animation/animation_tree.cpp
msgid "In node '%s', invalid animation: '%s'."
@@ -14461,25 +14416,30 @@ msgid "Invalid comparison function for that type."
msgstr "Ðекоректна Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ Ð¿Ð¾Ñ€Ñ–Ð²Ð½ÑÐ½Ð½Ñ Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ типу."
#: servers/visual/shader_language.cpp
-#, fuzzy
msgid "Varying may not be assigned in the '%s' function."
-msgstr "Змінні величини можна пов'Ñзувати лише із функцією вузлів."
+msgstr "У функції «%s» не може бути надано змінне значеннÑ."
#: servers/visual/shader_language.cpp
msgid ""
"Varyings which assigned in 'vertex' function may not be reassigned in "
"'fragment' or 'light'."
msgstr ""
+"Змінним, Ñким надано Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñƒ функції «vertex», не можна повторно надавати "
+"Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñƒ «fragment» або «light»."
#: servers/visual/shader_language.cpp
msgid ""
"Varyings which assigned in 'fragment' function may not be reassigned in "
"'vertex' or 'light'."
msgstr ""
+"Змінним, Ñким надано Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñƒ функції «fragment», не можна повторно "
+"надавати Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñƒ «vertex» або «light»."
#: servers/visual/shader_language.cpp
msgid "Fragment-stage varying could not been accessed in custom function!"
msgstr ""
+"ДоÑтуп до змінного Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð½Ð° кроці фрагментації у нетиповій функції "
+"неможливий!"
#: servers/visual/shader_language.cpp
msgid "Assignment to function."
@@ -15669,9 +15629,6 @@ msgstr "Сталі не можна змінювати."
#~ msgid "I see..."
#~ msgstr "Бачу..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "Ðеможливо відкрити '%s'."
-
#~ msgid "Ugh"
#~ msgstr "Тьху"
diff --git a/editor/translations/ur_PK.po b/editor/translations/ur_PK.po
index 5c5a6baa8e..fb70bc5703 100644
--- a/editor/translations/ur_PK.po
+++ b/editor/translations/ur_PK.po
@@ -345,6 +345,7 @@ msgstr ""
msgid "Remove Anim Track"
msgstr ""
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr ""
@@ -369,10 +370,26 @@ msgstr ""
msgid "Anim Insert"
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "سب سکریپشن بنائیں"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "property '%s'"
+msgstr ""
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr ""
@@ -939,7 +956,7 @@ msgstr "سب سکریپشن بنائیں"
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2261,6 +2278,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3048,10 +3076,6 @@ msgid "Save & Restart"
msgstr ""
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr ""
@@ -3669,6 +3693,15 @@ msgid "Download from:"
msgstr ".تمام کا انتخاب"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "سب سکریپشن بنائیں"
+
+#: editor/export_template_manager.cpp
+msgid "Copy Mirror URL"
+msgstr ""
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8486,6 +8519,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr ".تمام کا انتخاب"
@@ -8516,6 +8555,12 @@ msgid "Remove All StyleBox Items"
msgstr ".تمام کا انتخاب"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Ù¾Ø³Ù†Ø¯ÛŒØ¯Û Ø§ÙˆÙ¾Ø± منتقل کریں"
@@ -12045,6 +12090,16 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr ".تمام کا انتخاب"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr ".تمام کا انتخاب"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -13682,6 +13737,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/vi.po b/editor/translations/vi.po
index 531488e640..d50d622215 100644
--- a/editor/translations/vi.po
+++ b/editor/translations/vi.po
@@ -355,6 +355,7 @@ msgstr "Äổi chế độ vòng lặp hoạt ảnh"
msgid "Remove Anim Track"
msgstr "Xóa Anim Track"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "Tạo track mới cho %s và chèn key?"
@@ -379,10 +380,27 @@ msgstr "Tạo"
msgid "Anim Insert"
msgstr "Chèn Anim"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+msgid "node '%s'"
+msgstr ""
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "Hoạt ảnh"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "AnimationPlayer không thể tự tạo hoạt ảnh, phải nhỠcác Player khác."
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "Thuộc tính '%s' không tồn tại."
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "Tạo & Chèn Hoạt ảnh"
@@ -954,7 +972,7 @@ msgstr "Tạo %s mới"
msgid "No results for \"%s\"."
msgstr "Không tìm thấy kết quả cho \"%s\"."
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2299,6 +2317,17 @@ msgid "New Window"
msgstr "Cửa sổ mới"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "Xoay khi cửa sổ trình chỉnh sửa được vẽ lại."
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "Tài nguyên đã nhập không thể lưu."
@@ -3141,10 +3170,6 @@ msgid "Save & Restart"
msgstr "Lưu & Khởi động lại"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "Xoay khi cửa sổ trình chỉnh sửa được vẽ lại."
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "Cập nhật Liên tục"
@@ -3796,6 +3821,16 @@ msgid "Download from:"
msgstr "Lỗi tải"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "Chạy trong Trình duyệt web"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "Sao chép lỗi"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8623,6 +8658,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "Xóa tất cả các mục"
@@ -8653,6 +8694,12 @@ msgid "Remove All StyleBox Items"
msgstr "Xóa tất cả các mục"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "Thêm mục Lớp"
@@ -12282,6 +12329,16 @@ msgstr "Chỉnh chiá»u cao hình trụ"
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "Äặt vị trí Ä‘iểm uốn"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "Äặt vị trí Ä‘iểm uốn"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "Thay Äổi Bán Kính Hình Trụ"
@@ -14000,6 +14057,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
diff --git a/editor/translations/zh_CN.po b/editor/translations/zh_CN.po
index dbbd935854..8284ac605e 100644
--- a/editor/translations/zh_CN.po
+++ b/editor/translations/zh_CN.po
@@ -83,7 +83,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Chinese (Simplified) (Godot Engine)\n"
"POT-Creation-Date: 2018-01-20 12:15+0200\n"
-"PO-Revision-Date: 2021-08-01 12:02+0000\n"
+"PO-Revision-Date: 2021-08-12 14:48+0000\n"
"Last-Translator: Haoyu Qiu <timothyqiu32@gmail.com>\n"
"Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/"
"godot-engine/godot/zh_Hans/>\n"
@@ -413,6 +413,7 @@ msgstr "更改动画循环模å¼"
msgid "Remove Anim Track"
msgstr "移除动画轨é“"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "是å¦ä¸º %s 新建轨é“å¹¶æ’入关键帧?"
@@ -437,10 +438,28 @@ msgstr "创建"
msgid "Anim Insert"
msgstr "æ’入动画"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "无法打开 \"%s\"。"
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "动画"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "AnimationPlayer ä¸èƒ½åŠ¨ç”»åŒ–è‡ªå·±ï¼Œåªå¯åŠ¨ç”»åŒ–å…¶å®ƒ Player。"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "ä¸å­˜åœ¨å±žæ€§â€œ%sâ€ã€‚"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "创建并æ’入动画"
@@ -644,9 +663,8 @@ msgid "Go to Previous Step"
msgstr "返回上一步"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Apply Reset"
-msgstr "é‡ç½®"
+msgstr "应用é‡ç½®"
#: editor/animation_track_editor.cpp
msgid "Optimize Animation"
@@ -665,9 +683,8 @@ msgid "Use Bezier Curves"
msgstr "使用è´å¡žå°”曲线"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Create RESET Track(s)"
-msgstr "粘贴轨é“"
+msgstr "创建 RESET 轨é“"
#: editor/animation_track_editor.cpp
msgid "Anim. Optimizer"
@@ -988,7 +1005,6 @@ msgid "Edit..."
msgstr "编辑..."
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Go to Method"
msgstr "跳转到方法"
@@ -1008,9 +1024,9 @@ msgstr "创建 %s"
msgid "No results for \"%s\"."
msgstr "未找到 “%sâ€ã€‚"
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
-msgstr ""
+msgstr "没有针对 %s çš„æè¿°ã€‚"
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp
@@ -1110,17 +1126,15 @@ msgid "Owners Of:"
msgstr "拥有者:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove the selected files from the project? (Cannot be undone.)\n"
"Depending on your filesystem configuration, the files will either be moved "
"to the system trash or deleted permanently."
msgstr ""
-"是å¦ä»Žé¡¹ç›®ä¸­åˆ é™¤æ‰€é€‰æ–‡ä»¶ï¼Ÿï¼ˆæ— æ³•撤销)\n"
-"ä½ å¯ä»¥åœ¨ç³»ç»Ÿå›žæ”¶ç«™ä¸­æ¢å¤è¢«åˆ é™¤çš„æ–‡ä»¶ã€‚"
+"是å¦ä»Žé¡¹ç›®ä¸­åˆ é™¤æ‰€é€‰æ–‡ä»¶ï¼Ÿï¼ˆæ— æ³•撤销。)\n"
+"æ ¹æ®ä½ çš„æ–‡ä»¶ç³»ç»Ÿè®¾ç½®ï¼Œæ–‡ä»¶ä¼šè¢«ç§»åŠ¨è‡³ç³»ç»Ÿå›žæ”¶ç«™æˆ–æ°¸ä¹…åˆ é™¤ã€‚"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1128,9 +1142,9 @@ msgid ""
"Depending on your filesystem configuration, the files will either be moved "
"to the system trash or deleted permanently."
msgstr ""
-"è¦åˆ é™¤çš„æ–‡ä»¶è¢«å…¶ä»–èµ„æºæ‰€ä¾èµ–。\n"
-"ä»ç„¶è¦åˆ é™¤å—?(无法撤销)\n"
-"ä½ å¯ä»¥åœ¨ç³»ç»Ÿå›žæ”¶ç«™ä¸­æ¢å¤è¢«åˆ é™¤çš„æ–‡ä»¶ã€‚"
+"其它资æºéœ€è¦è¿™äº›å³å°†è¢«åˆ é™¤çš„æ–‡ä»¶æ‰èƒ½æ­£å¸¸å·¥ä½œã€‚\n"
+"ä»ç„¶è¦åˆ é™¤å—?(无法撤销。)\n"
+"æ ¹æ®ä½ çš„æ–‡ä»¶ç³»ç»Ÿè®¾ç½®ï¼Œæ–‡ä»¶ä¼šè¢«ç§»åŠ¨è‡³ç³»ç»Ÿå›žæ”¶ç«™æˆ–æ°¸ä¹…åˆ é™¤ã€‚"
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1298,41 +1312,36 @@ msgid "Licenses"
msgstr "许å¯è¯"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Error opening asset file for \"%s\" (not in ZIP format)."
-msgstr "æ‰“å¼€åŒ…æ–‡ä»¶æ—¶å‡ºé”™ï¼ˆéž ZIP æ ¼å¼ï¼‰ã€‚"
+msgstr "打开“%sâ€çš„ç´ ææ–‡ä»¶æ—¶å‡ºé”™ï¼ˆéž ZIP æ ¼å¼ï¼‰ã€‚"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "%s (already exists)"
msgstr "%s(已存在)"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - %d file(s) conflict with your project:"
-msgstr ""
+msgstr "ç´ æâ€œ%sâ€çš„内容 - %d 个文件与你的项目冲çªï¼š"
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - No files conflict with your project:"
-msgstr ""
+msgstr "ç´ æâ€œ%sâ€çš„内容 - 没有文件与你的项目冲çªï¼š"
#: editor/editor_asset_installer.cpp
msgid "Uncompressing Assets"
msgstr "正在解压素æ"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "The following files failed extraction from asset \"%s\":"
-msgstr "以下文件无法从包中æå–:"
+msgstr "以下文件无法从素æâ€œ%sâ€ä¸­æå–:"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "(and %s more files)"
-msgstr "以åŠå…¶å®ƒ %s 个文件。"
+msgstr "(以åŠå…¶å®ƒ %s 个文件)"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset \"%s\" installed successfully!"
-msgstr "软件包安装æˆåŠŸï¼"
+msgstr "ç´ æâ€œ%sâ€å®‰è£…æˆåŠŸï¼"
#: editor/editor_asset_installer.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -1344,9 +1353,8 @@ msgid "Install"
msgstr "安装"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Asset Installer"
-msgstr "程åºåŒ…安装程åº"
+msgstr "ç´ æå®‰è£…器"
#: editor/editor_audio_buses.cpp
msgid "Speakers"
@@ -1409,7 +1417,6 @@ msgid "Bypass"
msgstr "æ—通"
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "Bus Options"
msgstr "总线选项"
@@ -1577,13 +1584,12 @@ msgid "Can't add autoload:"
msgstr "无法加载 Autoload:"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "%s is an invalid path. File does not exist."
-msgstr "文件ä¸å­˜åœ¨ã€‚"
+msgstr "%s 是无效路径。文件ä¸å­˜åœ¨ã€‚"
#: editor/editor_autoload_settings.cpp
msgid "%s is an invalid path. Not in resource path (res://)."
-msgstr ""
+msgstr "%s æ˜¯æ— æ•ˆè·¯å¾„ã€‚ä¸æ˜¯èµ„æºè·¯å¾„(res://)。"
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -1607,9 +1613,8 @@ msgid "Name"
msgstr "åç§°"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "Global Variable"
-msgstr "å˜é‡"
+msgstr "全局å˜é‡"
#: editor/editor_data.cpp
msgid "Paste Params"
@@ -1775,48 +1780,47 @@ msgstr "坼入颿¿"
#: editor/editor_feature_profile.cpp
msgid "Allows to view and edit 3D scenes."
-msgstr ""
+msgstr "å…许查看并编辑 3D 场景。"
#: editor/editor_feature_profile.cpp
msgid "Allows to edit scripts using the integrated script editor."
-msgstr ""
+msgstr "å…许使用内置脚本编辑器编辑脚本。"
#: editor/editor_feature_profile.cpp
msgid "Provides built-in access to the Asset Library."
-msgstr ""
+msgstr "æä¾›å¯¹ç´ æåº“的内置访问。"
#: editor/editor_feature_profile.cpp
msgid "Allows editing the node hierarchy in the Scene dock."
-msgstr ""
+msgstr "å…è®¸åœ¨åœºæ™¯é¢æ¿ä¸­ç¼–辑节点层级。"
#: editor/editor_feature_profile.cpp
msgid ""
"Allows to work with signals and groups of the node selected in the Scene "
"dock."
-msgstr ""
+msgstr "å…è®¸åœ¨åœºæ™¯é¢æ¿æ“作所选节点的信å·å’Œåˆ†ç»„。"
#: editor/editor_feature_profile.cpp
msgid "Allows to browse the local file system via a dedicated dock."
-msgstr ""
+msgstr "å…è®¸ä½¿ç”¨ä¸“é—¨çš„é¢æ¿æµè§ˆæœ¬åœ°æ–‡ä»¶ç³»ç»Ÿã€‚"
#: editor/editor_feature_profile.cpp
msgid ""
"Allows to configure import settings for individual assets. Requires the "
"FileSystem dock to function."
-msgstr ""
+msgstr "å…许为å„个素æé…ç½®å¯¼å…¥è®¾ç½®ã€‚æ–‡ä»¶ç³»ç»Ÿé¢æ¿éœ€è¦å¯ç”¨ã€‚"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "(current)"
msgstr "(当å‰ï¼‰"
#: editor/editor_feature_profile.cpp
msgid "(none)"
-msgstr ""
+msgstr "(无)"
#: editor/editor_feature_profile.cpp
msgid "Remove currently selected profile, '%s'? Cannot be undone."
-msgstr ""
+msgstr "è¦åˆ é™¤å½“剿‰€é€‰çš„é…置文件“%sâ€å—?无法撤销。"
#: editor/editor_feature_profile.cpp
msgid "Profile must be a valid filename and must not contain '.'"
@@ -1847,19 +1851,16 @@ msgid "Enable Contextual Editor"
msgstr "å¯ç”¨ä¸Šä¸‹æ–‡ç¼–辑器"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Class Properties:"
-msgstr "属性:"
+msgstr "类属性:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Main Features:"
-msgstr "特性"
+msgstr "主è¦ç‰¹æ€§ï¼š"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Nodes and Classes:"
-msgstr "å¯ç”¨çš„类:"
+msgstr "节点和类:"
#: editor/editor_feature_profile.cpp
msgid "File '%s' format is invalid, import aborted."
@@ -1876,7 +1877,6 @@ msgid "Error saving profile to path: '%s'."
msgstr "å°†é…置文件ä¿å­˜åˆ°è·¯å¾„ “%s†时出错。"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Reset to Default"
msgstr "é‡ç½®ä¸ºé»˜è®¤å€¼"
@@ -1885,14 +1885,12 @@ msgid "Current Profile:"
msgstr "当å‰é…置文件:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Create Profile"
-msgstr "删除é…置文件"
+msgstr "创建é…置文件"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Remove Profile"
-msgstr "移除图å—"
+msgstr "删除é…置文件"
#: editor/editor_feature_profile.cpp
msgid "Available Profiles:"
@@ -1912,18 +1910,16 @@ msgid "Export"
msgstr "导出"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Configure Selected Profile:"
-msgstr "当å‰é…置文件:"
+msgstr "é…置所选é…置文件:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Extra Options:"
-msgstr "纹ç†é€‰é¡¹"
+msgstr "更多选项:"
#: editor/editor_feature_profile.cpp
msgid "Create or import a profile to edit available classes and properties."
-msgstr ""
+msgstr "创建或导入é…置文件以编辑å¯ç”¨çš„类和属性。"
#: editor/editor_feature_profile.cpp
msgid "New profile name:"
@@ -1950,7 +1946,6 @@ msgid "Select Current Folder"
msgstr "é€‰æ‹©å½“å‰æ–‡ä»¶å¤¹"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
-#, fuzzy
msgid "File exists, overwrite?"
msgstr "文件已存在,是å¦è¦†ç›–?"
@@ -2343,6 +2338,17 @@ msgid "New Window"
msgstr "新窗å£"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "编辑器窗å£é‡ç»˜æ—¶æ—‹è½¬ã€‚"
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "å¯¼å…¥çš„èµ„æºæ— æ³•ä¿å­˜ã€‚"
@@ -2503,9 +2509,9 @@ msgid ""
"Please read the documentation relevant to importing scenes to better "
"understand this workflow."
msgstr ""
-"场景已被导入,所åšçš„æ›´æ”¹å°†ä¸ä¼šä¿ç•™ã€‚\n"
-"请实例化或继承该场景以å…许对其进行更改。\n"
-"请阅读与导入场景相关的文档,以更佳ç†è§£æ­¤å·¥ä½œæµã€‚"
+"该场景是被导入的场景,ä¸ä¼šä¿ç•™å¯¹å®ƒçš„æ›´æ”¹ã€‚\n"
+"实例化或继承该场景就å¯ä»¥å¯¹å…¶è¿›è¡Œæ›´æ”¹ã€‚\n"
+"请阅读与导入场景相关的文档,以便更好地ç†è§£æ­¤å·¥ä½œæµã€‚"
#: editor/editor_node.cpp
msgid ""
@@ -2560,14 +2566,13 @@ msgstr "是å¦åœ¨å…³é—­å‰ä¿å­˜å¯¹ “%s†的更改?"
msgid ""
"The current scene has no root node, but %d modified external resource(s) "
"were saved anyway."
-msgstr ""
+msgstr "当å‰åœºæ™¯æ²¡æœ‰æ ¹èŠ‚ç‚¹ï¼Œä¸è¿‡ä¿å­˜äº† %d 个已修改的外部资æºã€‚"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"A root node is required to save the scene. You can add a root node using the "
"Scene tree dock."
-msgstr "必须有根节点æ‰å¯ä¿å­˜åœºæ™¯ã€‚"
+msgstr "必须有根节点æ‰èƒ½ä¿å­˜åœºæ™¯ã€‚ä½ å¯ä»¥é€šè¿‡åœºæ™¯é¢æ¿æ·»åŠ æ ¹èŠ‚ç‚¹ã€‚"
#: editor/editor_node.cpp
msgid "Save Scene As..."
@@ -2938,9 +2943,8 @@ msgid "Orphan Resource Explorer..."
msgstr "å­¤ç«‹èµ„æºæµè§ˆå™¨..."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reload Current Project"
-msgstr "é‡å‘½å项目"
+msgstr "釿–°åŠ è½½å½“å‰é¡¹ç›®"
#: editor/editor_node.cpp
msgid "Quit to Project List"
@@ -3088,22 +3092,20 @@ msgid "Help"
msgstr "帮助"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Online Documentation"
-msgstr "打开文档"
+msgstr "在线文档"
#: editor/editor_node.cpp
msgid "Questions & Answers"
-msgstr ""
+msgstr "问与答"
#: editor/editor_node.cpp
msgid "Report a Bug"
msgstr "报告问题"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Suggest a Feature"
-msgstr "设置值"
+msgstr "æäº¤æ–°ç‰¹æ€§å»ºè®®"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
@@ -3114,9 +3116,8 @@ msgid "Community"
msgstr "社区"
#: editor/editor_node.cpp
-#, fuzzy
msgid "About Godot"
-msgstr "关于"
+msgstr "关于 Godot"
#: editor/editor_node.cpp
msgid "Support Godot Development"
@@ -3168,10 +3169,6 @@ msgid "Save & Restart"
msgstr "ä¿å­˜å¹¶é‡å¯"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "编辑器窗å£é‡ç»˜æ—¶æ—‹è½¬ã€‚"
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "æŒç»­æ›´æ–°"
@@ -3212,14 +3209,12 @@ msgid "Manage Templates"
msgstr "ç®¡ç†æ¨¡æ¿"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Install from file"
msgstr "从文件安装"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Select android sources file"
-msgstr "选择æºç½‘格:"
+msgstr "选择 Android æºæ–‡ä»¶"
#: editor/editor_node.cpp
msgid ""
@@ -3299,9 +3294,8 @@ msgid "Select"
msgstr "选择"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Select Current"
-msgstr "é€‰æ‹©å½“å‰æ–‡ä»¶å¤¹"
+msgstr "选择当å‰"
#: editor/editor_node.cpp
msgid "Open 2D Editor"
@@ -3336,9 +3330,8 @@ msgid "No sub-resources found."
msgstr "找ä¸åˆ°å­èµ„æºã€‚"
#: editor/editor_path.cpp
-#, fuzzy
msgid "Open a list of sub-resources."
-msgstr "找ä¸åˆ°å­èµ„æºã€‚"
+msgstr "打开å­èµ„æºåˆ—表。"
#: editor/editor_plugin.cpp
msgid "Creating Mesh Previews"
@@ -3365,12 +3358,10 @@ msgid "Update"
msgstr "æ›´æ–°"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Version"
-msgstr "版本:"
+msgstr "版本"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Author"
msgstr "作者"
@@ -3385,14 +3376,12 @@ msgid "Measure:"
msgstr "测é‡ï¼š"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Frame Time (ms)"
-msgstr "帧时间(秒)"
+msgstr "帧时间(毫秒)"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Average Time (ms)"
-msgstr "平凿—¶é—´ï¼ˆç§’)"
+msgstr "平凿—¶é—´ï¼ˆæ¯«ç§’)"
#: editor/editor_profiler.cpp
msgid "Frame %"
@@ -3419,6 +3408,11 @@ msgid ""
"functions called by that function.\n"
"Use this to find individual functions to optimize."
msgstr ""
+"全部:包括该函数调用的其它函数的时间。\n"
+"使用该选项寻找瓶颈。\n"
+"\n"
+"仅自己:åªè®¡ç®—消耗在该函数本身的时间,ä¸åŒ…å«è¯¥å‡½æ•°æ‰€è°ƒç”¨çš„其它函数。\n"
+"使用该选项寻找需è¦ä¼˜åŒ–的函数。"
#: editor/editor_profiler.cpp
msgid "Frame #:"
@@ -3536,7 +3530,6 @@ msgid "Paste"
msgstr "粘贴"
#: editor/editor_resource_picker.cpp editor/property_editor.cpp
-#, fuzzy
msgid "Convert to %s"
msgstr "转æ¢ä¸º %s"
@@ -3586,9 +3579,8 @@ msgid "Did you forget the '_run' method?"
msgstr "是å¦é—æ¼äº† _run() 方法?"
#: editor/editor_spin_slider.cpp
-#, fuzzy
msgid "Hold %s to round to integers. Hold Shift for more precise changes."
-msgstr "æŒ‰ä½ Ctrl é”®æ¥å–整。 æŒ‰ä½ Shift é”®èŽ·å–æ›´ç²¾ç¡®çš„å˜åŒ–。"
+msgstr "æŒ‰ä½ %s å–æ•´ã€‚ æŒ‰ä½ Shift èŽ·å–æ›´ç²¾ç¡®çš„å˜åŒ–。"
#: editor/editor_sub_scene.cpp
msgid "Select Node(s) to Import"
@@ -3608,49 +3600,43 @@ msgstr "从节点中导入:"
#: editor/export_template_manager.cpp
msgid "Open the folder containing these templates."
-msgstr ""
+msgstr "打开包å«è¿™äº›æ¨¡æ¿çš„æ–‡ä»¶å¤¹ã€‚"
#: editor/export_template_manager.cpp
msgid "Uninstall these templates."
-msgstr ""
+msgstr "å¸è½½è¿™äº›æ¨¡æ¿ã€‚"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "There are no mirrors available."
-msgstr "文件 “%s†ä¸å­˜åœ¨ã€‚"
+msgstr "没有å¯ç”¨çš„镜åƒã€‚"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Retrieving the mirror list..."
-msgstr "检索镜åƒï¼Œè¯·ç­‰å¾…..."
+msgstr "正在获å–镜åƒåˆ—表……"
#: editor/export_template_manager.cpp
msgid "Starting the download..."
-msgstr ""
+msgstr "正在开始下载……"
#: editor/export_template_manager.cpp
msgid "Error requesting URL:"
msgstr "请求 URL 时出错:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Connecting to the mirror..."
-msgstr "正在连接镜åƒç½‘ç«™..."
+msgstr "正在连接镜åƒâ€¦â€¦"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't resolve the requested address."
-msgstr "无法解æžä¸»æœºå:"
+msgstr "无法解æžè¯·æ±‚地å€ã€‚"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't connect to the mirror."
-msgstr "无法连接到主机:"
+msgstr "无法连接到镜åƒã€‚"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "No response from the mirror."
-msgstr "主机无å“应:"
+msgstr "é•œåƒæ— å“应。"
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -3658,18 +3644,16 @@ msgid "Request failed."
msgstr "请求失败。"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Request ended up in a redirect loop."
-msgstr "请求失败,é‡å®šå‘次数过多"
+msgstr "请求进入了é‡å®šå‘循环。"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Request failed:"
-msgstr "请求失败。"
+msgstr "请求失败:"
#: editor/export_template_manager.cpp
msgid "Download complete; extracting templates..."
-msgstr ""
+msgstr "下载完æˆï¼›æ­£åœ¨è§£åŽ‹æ¨¡æ¿â€¦â€¦"
#: editor/export_template_manager.cpp
msgid "Cannot remove temporary file:"
@@ -3688,13 +3672,12 @@ msgid "Error getting the list of mirrors."
msgstr "获å–镜åƒåˆ—表时出错。"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Error parsing JSON with the list of mirrors. Please report this issue!"
msgstr "è§£æžé•œåƒåˆ—表 JSON 时出错。请æäº¤æ­¤é—®é¢˜ï¼"
#: editor/export_template_manager.cpp
msgid "Best available mirror"
-msgstr ""
+msgstr "最佳å¯ç”¨é•œåƒ"
#: editor/export_template_manager.cpp
msgid ""
@@ -3745,24 +3728,20 @@ msgid "SSL Handshake Error"
msgstr "SSL æ¡æ‰‹é”™è¯¯"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Can't open the export templates file."
-msgstr "无法打开 ZIP 导出模æ¿ã€‚"
+msgstr "æ— æ³•æ‰“å¼€å¯¼å‡ºæ¨¡æ¿æ–‡ä»¶ã€‚"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Invalid version.txt format inside the export templates file: %s."
-msgstr "模æ¿ä¸­çš„ version.txt æ ¼å¼æ— æ•ˆï¼š%s。"
+msgstr "导出模æ¿ä¸­çš„ version.txt æ ¼å¼æ— æ•ˆï¼š%s。"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "No version.txt found inside the export templates file."
-msgstr "模æ¿ä¸­æ²¡æœ‰æ‰¾åˆ° version.txt。"
+msgstr "导出模æ¿ä¸­æ²¡æœ‰ version.txt。"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Error creating path for extracting templates:"
-msgstr "创建模æ¿è·¯å¾„出错:"
+msgstr "为解压模æ¿åˆ›å»ºè·¯å¾„时出错:"
#: editor/export_template_manager.cpp
msgid "Extracting Export Templates"
@@ -3773,9 +3752,8 @@ msgid "Importing:"
msgstr "正在导入:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Remove templates for the version '%s'?"
-msgstr "是å¦ç§»é™¤æ¨¡æ¿ç‰ˆæœ¬ “%sâ€ï¼Ÿ"
+msgstr "是å¦ç§»é™¤æ¨¡æ¿ç‰ˆæœ¬â€œ%sâ€ï¼Ÿ"
#: editor/export_template_manager.cpp
msgid "Uncompressing Android Build Sources"
@@ -3791,58 +3769,63 @@ msgstr "当å‰ç‰ˆæœ¬ï¼š"
#: editor/export_template_manager.cpp
msgid "Export templates are missing. Download them or install from a file."
-msgstr ""
+msgstr "缺失导出模æ¿ã€‚请下载或从文件安装。"
#: editor/export_template_manager.cpp
msgid "Export templates are installed and ready to be used."
-msgstr ""
+msgstr "导出模æ¿å·²å®‰è£…就绪。"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Open Folder"
-msgstr "打开文件"
+msgstr "打开文件夹"
#: editor/export_template_manager.cpp
msgid "Open the folder containing installed templates for the current version."
-msgstr ""
+msgstr "打开包å«å½“å‰ç‰ˆæœ¬å·²å®‰è£…模æ¿çš„æ–‡ä»¶å¤¹ã€‚"
#: editor/export_template_manager.cpp
msgid "Uninstall"
msgstr "å¸è½½"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Uninstall templates for the current version."
-msgstr "计数器åˆå§‹å€¼"
+msgstr "å¸è½½å½“å‰ç‰ˆæœ¬çš„æ¨¡æ¿ã€‚"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Download from:"
-msgstr "下载错误"
+msgstr "下载:"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "在æµè§ˆå™¨ä¸­è¿è¡Œ"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "å¤åˆ¶é”™è¯¯ä¿¡æ¯"
#: editor/export_template_manager.cpp
msgid "Download and Install"
-msgstr ""
+msgstr "下载并安装"
#: editor/export_template_manager.cpp
msgid ""
"Download and install templates for the current version from the best "
"possible mirror."
-msgstr ""
+msgstr "从最佳的镜åƒä¸‹è½½å½“å‰ç‰ˆæœ¬çš„æ¨¡æ¿å¹¶å®‰è£…。"
#: editor/export_template_manager.cpp
msgid "Official export templates aren't available for development builds."
msgstr "开呿ž„建下官方导出模æ¿ä¸å¯ç”¨ã€‚"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Install from File"
msgstr "从文件安装"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Install templates from a local file."
-msgstr "从 ZIP 文件中导入模æ¿"
+msgstr "从本地文件安装模æ¿ã€‚"
#: editor/export_template_manager.cpp editor/find_in_files.cpp
#: editor/progress_dialog.cpp scene/gui/dialogs.cpp
@@ -3850,19 +3833,16 @@ msgid "Cancel"
msgstr "å–æ¶ˆ"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Cancel the download of the templates."
-msgstr "无法打开 ZIP 导出模æ¿ã€‚"
+msgstr "å–æ¶ˆä¸‹è½½æ¨¡æ¿ã€‚"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Other Installed Versions:"
-msgstr "已安装版本:"
+msgstr "其它已安装版本:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Uninstall Template"
-msgstr "å¸è½½"
+msgstr "å¸è½½æ¨¡æ¿"
#: editor/export_template_manager.cpp
msgid "Select Template File"
@@ -3877,6 +3857,8 @@ msgid ""
"The templates will continue to download.\n"
"You may experience a short editor freeze when they finish."
msgstr ""
+"模æ¿ä¸‹è½½ä»ä¼šç»§ç»­ã€‚\n"
+"å®Œæˆæ—¶ä½ å¯èƒ½ä¼šæ„Ÿå—到编辑器的短暂冻结。"
#: editor/filesystem_dock.cpp
msgid "Favorites"
@@ -3972,7 +3954,7 @@ msgstr "打开场景"
#: editor/filesystem_dock.cpp
msgid "Instance"
-msgstr "实例"
+msgstr "实例化"
#: editor/filesystem_dock.cpp
msgid "Add to Favorites"
@@ -4019,35 +4001,32 @@ msgid "Collapse All"
msgstr "全部折å "
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort files"
-msgstr "æœç´¢æ–‡ä»¶"
+msgstr "文件排åº"
#: editor/filesystem_dock.cpp
msgid "Sort by Name (Ascending)"
-msgstr ""
+msgstr "按å称(å‡åºï¼‰"
#: editor/filesystem_dock.cpp
msgid "Sort by Name (Descending)"
-msgstr ""
+msgstr "按å称(é™åºï¼‰"
#: editor/filesystem_dock.cpp
msgid "Sort by Type (Ascending)"
-msgstr ""
+msgstr "按类型(å‡åºï¼‰"
#: editor/filesystem_dock.cpp
msgid "Sort by Type (Descending)"
-msgstr ""
+msgstr "按类型(é™åºï¼‰"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort by Last Modified"
-msgstr "修改时间"
+msgstr "按最近修改"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Sort by First Modified"
-msgstr "修改时间"
+msgstr "按最早修改"
#: editor/filesystem_dock.cpp
msgid "Duplicate..."
@@ -4059,7 +4038,7 @@ msgstr "é‡å‘½å为..."
#: editor/filesystem_dock.cpp
msgid "Focus the search box"
-msgstr ""
+msgstr "èšç„¦æœç´¢æ¡†"
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
@@ -4363,14 +4342,12 @@ msgid "Failed to load resource."
msgstr "加载资æºå¤±è´¥ã€‚"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Copy Properties"
-msgstr "属性"
+msgstr "å¤åˆ¶å±žæ€§"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Paste Properties"
-msgstr "属性"
+msgstr "粘贴属性"
#: editor/inspector_dock.cpp
msgid "Make Sub-Resources Unique"
@@ -4395,23 +4372,20 @@ msgid "Save As..."
msgstr "å¦å­˜ä¸º..."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Extra resource options."
-msgstr "ä¸åœ¨èµ„æºè·¯å¾„下。"
+msgstr "更多资æºé€‰é¡¹ã€‚"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Edit Resource from Clipboard"
-msgstr "编辑资æºå‰ªè´´æ¿"
+msgstr "编辑剪贴æ¿ä¸­çš„资æº"
#: editor/inspector_dock.cpp
msgid "Copy Resource"
msgstr "å¤åˆ¶èµ„æº"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Make Resource Built-In"
-msgstr "转为内置"
+msgstr "将资æºè½¬ä¸ºå†…ç½®"
#: editor/inspector_dock.cpp
msgid "Go to the previous edited object in history."
@@ -4426,9 +4400,8 @@ msgid "History of recently edited objects."
msgstr "最近编辑历å²å¯¹è±¡ã€‚"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Open documentation for this object."
-msgstr "打开文档"
+msgstr "打开该对象的文档。"
#: editor/inspector_dock.cpp editor/scene_tree_dock.cpp
msgid "Open Documentation"
@@ -4439,9 +4412,8 @@ msgid "Filter properties"
msgstr "筛选属性"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Manage object properties."
-msgstr "对象属性。"
+msgstr "管ç†å¯¹è±¡å±žæ€§ã€‚"
#: editor/inspector_dock.cpp
msgid "Changes may be lost!"
@@ -4684,9 +4656,8 @@ msgid "Blend:"
msgstr "æ··åˆï¼š"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Parameter Changed:"
-msgstr "傿•°å·²æ›´æ”¹"
+msgstr "ä¿®æ”¹å‚æ•°ï¼š"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
@@ -5408,11 +5379,11 @@ msgstr "全部"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Search templates, projects, and demos"
-msgstr ""
+msgstr "æœç´¢æ¨¡æ¿ã€é¡¹ç›®ã€æ¼”示"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Search assets (excluding templates, projects, and demos)"
-msgstr ""
+msgstr "æœç´¢ç´ æï¼ˆä¸åŒ…嫿¨¡æ¿ã€é¡¹ç›®ã€æ¼”示)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Import..."
@@ -5456,7 +5427,7 @@ msgstr "ç´ æ ZIP 文件"
#: editor/plugins/audio_stream_editor_plugin.cpp
msgid "Audio Preview Play/Pause"
-msgstr ""
+msgstr "音频预览播放/æš‚åœ"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
@@ -5705,13 +5676,12 @@ msgstr "编辑锚点"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid ""
"Project Camera Override\n"
"Overrides the running project's camera with the editor viewport camera."
msgstr ""
-"游æˆç›¸æœºè¦†ç›–\n"
-"使用编辑器视图相机覆盖游æˆç›¸æœºã€‚"
+"项目相机覆盖\n"
+"使用编辑器视图相机覆盖正在è¿è¡Œçš„项目中的相机。"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5720,6 +5690,8 @@ msgid ""
"No project instance running. Run the project from the editor to use this "
"feature."
msgstr ""
+"项目相机覆盖\n"
+"没有正在è¿è¡Œçš„项目实例。请先在编辑器中è¿è¡Œé¡¹ç›®å†ä½¿ç”¨æœ¬åŠŸèƒ½ã€‚"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5785,31 +5757,25 @@ msgstr "选择模å¼"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Drag: Rotate selected node around pivot."
-msgstr "移除选中的节点或过渡动画。"
+msgstr "拖动:围绕中心点旋转所选节点。"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Alt+Drag: Move selected node."
-msgstr "Alt+拖动:移动"
+msgstr "Alt+拖动:移动所选节点。"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "V: Set selected node's pivot position."
-msgstr "移除选中的节点或过渡动画。"
+msgstr "V:设置所选节点的中心点ä½ç½®ã€‚"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Alt+RMB: Show list of all nodes at position clicked, including locked."
-msgstr ""
-"显示鼠标点击ä½ç½®çš„æ‰€æœ‰èŠ‚ç‚¹\n"
-"ï¼ˆåŒ Alt + é¼ æ ‡å³é”®ï¼‰ã€‚"
+msgstr "Alt+å³é”®ï¼šæ˜¾ç¤ºç‚¹å‡»ä½ç½®çš„æ‰€æœ‰èŠ‚ç‚¹åˆ—è¡¨ï¼ŒåŒ…å«å·²é”定节点。"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "RMB: Add node at position clicked."
-msgstr ""
+msgstr "å³é”®ï¼šåœ¨ç‚¹å‡»ä½ç½®æ·»åŠ èŠ‚ç‚¹ã€‚"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -6045,14 +6011,12 @@ msgid "Clear Pose"
msgstr "清除姿势"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Add Node Here"
-msgstr "添加节点"
+msgstr "在此处添加节点"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Instance Scene Here"
-msgstr "实例化场景"
+msgstr "在此处实例化场景"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Multiply grid step by 2"
@@ -6068,49 +6032,43 @@ msgstr "平移视图"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 3.125%"
-msgstr ""
+msgstr "缩放至 3.125%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 6.25%"
-msgstr ""
+msgstr "缩放至 6.25%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 12.5%"
-msgstr ""
+msgstr "缩放至 12.5%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 25%"
-msgstr "缩å°"
+msgstr "缩放至 25%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 50%"
-msgstr "缩å°"
+msgstr "缩放至 50%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 100%"
-msgstr "缩å°"
+msgstr "缩放至 100%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 200%"
-msgstr "缩å°"
+msgstr "缩放至 200%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 400%"
-msgstr "缩å°"
+msgstr "缩放至 400%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 800%"
-msgstr "缩å°"
+msgstr "缩放至 800%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 1600%"
-msgstr ""
+msgstr "缩放至 1600%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Add %s"
@@ -6355,9 +6313,8 @@ msgid "Couldn't create a single convex collision shape."
msgstr "无法创建å•一凸碰撞形状。"
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Create Simplified Convex Shape"
-msgstr "创建å•一凸形状"
+msgstr "创建简化凸形状"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Single Convex Shape"
@@ -6392,9 +6349,8 @@ msgid "No mesh to debug."
msgstr "没有å¯è°ƒè¯•的网格。"
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Mesh has no UV in layer %d."
-msgstr "模型在此层上没有 UV"
+msgstr "网格在层 %d 上没有 UV。"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "MeshInstance lacks a Mesh!"
@@ -6458,9 +6414,8 @@ msgstr ""
"这是最快(但是最ä¸ç²¾ç¡®ï¼‰çš„碰撞检测手段。"
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Create Simplified Convex Collision Sibling"
-msgstr "创建å•一凸碰撞åŒçº§"
+msgstr "创建简化凸碰撞åŒçº§"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid ""
@@ -6468,20 +6423,21 @@ msgid ""
"This is similar to single collision shape, but can result in a simpler "
"geometry in some cases, at the cost of accuracy."
msgstr ""
+"创建简化凸碰撞åŒçº§ã€‚\n"
+"与å•一碰撞形状类似,但æŸäº›æƒ…况下产生的形状更简å•,代价是牺牲准确性。"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Multiple Convex Collision Siblings"
msgstr "创建多个凸碰撞åŒçº§"
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid ""
"Creates a polygon-based collision shape.\n"
"This is a performance middle-ground between a single convex collision and a "
"polygon-based collision."
msgstr ""
"创建基于多边形的碰撞形状。\n"
-"这是性能ä½äºŽä¸Šè¿°ä¸¤ç§ä¹‹é—´çš„碰撞检测手段。"
+"性能ä½äºŽå•一凸形碰撞和多边形碰撞之间。"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Outline Mesh..."
@@ -7117,24 +7073,20 @@ msgid "ResourcePreloader"
msgstr "预加载资æº"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Flip Portals"
-msgstr "水平翻转"
+msgstr "翻转门户"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Room Generate Points"
-msgstr "生æˆé¡¶ç‚¹è®¡æ•°:"
+msgstr "房间生æˆç‚¹"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Generate Points"
-msgstr "生æˆé¡¶ç‚¹è®¡æ•°:"
+msgstr "生æˆç‚¹"
#: editor/plugins/room_manager_editor_plugin.cpp
-#, fuzzy
msgid "Flip Portal"
-msgstr "水平翻转"
+msgstr "翻转门户"
#: editor/plugins/root_motion_editor_plugin.cpp
msgid "AnimationTree has no path set to an AnimationPlayer"
@@ -7692,20 +7644,17 @@ msgid "None"
msgstr "æ— "
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Rotate"
-msgstr "å·ž(State)"
+msgstr "旋转"
#. TRANSLATORS: This refers to the movement that changes the position of an object.
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Translate"
-msgstr "移动:"
+msgstr "平移"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Scale"
-msgstr "缩放:"
+msgstr "缩放"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scaling: "
@@ -7728,52 +7677,44 @@ msgid "Animation Key Inserted."
msgstr "æ’入动画键。"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Pitch:"
-msgstr "俯仰角"
+msgstr "俯仰角:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Yaw:"
-msgstr ""
+msgstr "å航角:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size:"
-msgstr "大å°ï¼š "
+msgstr "大å°ï¼š"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Objects Drawn:"
-msgstr "绘制对象"
+msgstr "绘制对象:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Material Changes:"
-msgstr "æè´¨å˜æ›´"
+msgstr "æè´¨å˜æ›´ï¼š"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Shader Changes:"
-msgstr "ç€è‰²å™¨å˜æ›´"
+msgstr "ç€è‰²å™¨å˜æ›´ï¼š"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Surface Changes:"
-msgstr "表é¢å˜æ›´"
+msgstr "表é¢å˜æ›´ï¼š"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Draw Calls:"
-msgstr "绘制调用"
+msgstr "绘制调用:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Vertices:"
-msgstr "顶点"
+msgstr "顶点:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "FPS: %d (%s ms)"
-msgstr ""
+msgstr "FPS:%d(%s 毫秒)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Top View."
@@ -7928,9 +7869,8 @@ msgid "Freelook Slow Modifier"
msgstr "缓慢自由视图速度"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Toggle Camera Preview"
-msgstr "ä¿®æ”¹æ‘„åƒæœºå°ºå¯¸"
+msgstr "å¼€å…³æ‘„åƒæœºé¢„览"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Rotation Locked"
@@ -7950,9 +7890,8 @@ msgstr ""
"ä¸èƒ½å馈出实际游æˆä¸­çš„æ€§èƒ½ã€‚"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Convert Rooms"
-msgstr "转æ¢ä¸º %s"
+msgstr "è½¬æ¢æˆ¿é—´"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "XForm Dialog"
@@ -7973,7 +7912,6 @@ msgstr ""
"åŠç眼:Gizmo 也å¯ç©¿è¿‡ä¸é€æ˜Žçš„表é¢å¯è§ï¼ˆâ€œX å…‰â€ï¼‰ã€‚"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Snap Nodes to Floor"
msgstr "将节点å¸é™„至地é¢"
@@ -7991,7 +7929,7 @@ msgstr "使用å¸é™„"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Converts rooms for portal culling."
-msgstr ""
+msgstr "ä¸ºé—¨æˆ·å‰”é™¤è½¬æ¢æˆ¿é—´ã€‚"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Bottom View"
@@ -8087,9 +8025,8 @@ msgid "View Grid"
msgstr "显示网格"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "View Portal Culling"
-msgstr "视å£è®¾ç½®"
+msgstr "显示门户剔除"
#: editor/plugins/spatial_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
@@ -8409,221 +8346,194 @@ msgid "TextureRegion"
msgstr "纹ç†åŒºåŸŸ"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Colors"
msgstr "颜色"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Fonts"
msgstr "字体"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Icons"
msgstr "图标"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Styleboxes"
-msgstr "æ ·å¼"
+msgstr "æ ·å¼ç›’"
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} color(s)"
-msgstr ""
+msgstr "{num} 个颜色"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No colors found."
-msgstr "找ä¸åˆ°å­èµ„æºã€‚"
+msgstr "没有颜色。"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "{num} constant(s)"
-msgstr "常é‡"
+msgstr "{num} 个常é‡"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No constants found."
-msgstr "颜色常é‡ã€‚"
+msgstr "没有常é‡ã€‚"
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} font(s)"
-msgstr ""
+msgstr "{num} 个字体"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No fonts found."
-msgstr "未找到ï¼"
+msgstr "没有字体。"
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} icon(s)"
-msgstr ""
+msgstr "{num} 个图标"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No icons found."
-msgstr "未找到ï¼"
+msgstr "没有图标。"
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} stylebox(es)"
-msgstr ""
+msgstr "{num} 个样å¼ç›’"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "No styleboxes found."
-msgstr "找ä¸åˆ°å­èµ„æºã€‚"
+msgstr "没有样å¼ç›’。"
#: editor/plugins/theme_editor_plugin.cpp
msgid "{num} currently selected"
-msgstr ""
+msgstr "当å‰é€‰ä¸­ {num} 个"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Nothing was selected for the import."
-msgstr ""
+msgstr "没有选中导入任何东西。"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Importing Theme Items"
-msgstr "导入主题"
+msgstr "正在导入主题项目"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Importing items {n}/{n}"
-msgstr ""
+msgstr "正在导入项目 {n}/{n}"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Updating the editor"
-msgstr "确定è¦é€€å‡ºç¼–辑器å—?"
+msgstr "正在更新编辑器"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Finalizing"
-msgstr "正在分æž"
+msgstr "正在收尾"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Filter:"
-msgstr "过滤: "
+msgstr "筛选:"
#: editor/plugins/theme_editor_plugin.cpp
msgid "With Data"
-msgstr ""
+msgstr "嫿•°æ®"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select by data type:"
-msgstr "选择一个节点"
+msgstr "按数æ®ç±»åž‹é€‰æ‹©ï¼š"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible color items."
-msgstr "选择一个拆分以擦除它。"
+msgstr "选择所有å¯è§çš„颜色项目。"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible color items and their data."
-msgstr ""
+msgstr "选择所有å¯è§çš„颜色项目和它们的数æ®ã€‚"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible color items."
-msgstr ""
+msgstr "å–æ¶ˆé€‰æ‹©æ‰€æœ‰å¯è§çš„颜色项目。"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible constant items."
-msgstr "请先选择一个设置项ï¼"
+msgstr "选择所有å¯è§çš„常é‡é¡¹ç›®ã€‚"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible constant items and their data."
-msgstr ""
+msgstr "选择所有å¯è§çš„常é‡é¡¹ç›®å’Œå®ƒä»¬çš„æ•°æ®ã€‚"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible constant items."
-msgstr ""
+msgstr "å–æ¶ˆé€‰æ‹©æ‰€æœ‰å¯è§çš„常é‡é¡¹ç›®ã€‚"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible font items."
-msgstr "请先选择一个设置项ï¼"
+msgstr "选择所有å¯è§çš„字体项目。"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible font items and their data."
-msgstr ""
+msgstr "选择所有å¯è§çš„字体项目和它们的数æ®ã€‚"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible font items."
-msgstr ""
+msgstr "å–æ¶ˆé€‰æ‹©æ‰€æœ‰å¯è§çš„字体项目。"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible icon items."
-msgstr "请先选择一个设置项ï¼"
+msgstr "选择所有å¯è§çš„图标项目。"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all visible icon items and their data."
-msgstr "请先选择一个设置项ï¼"
+msgstr "选择所有å¯è§çš„图标项目和它们的数æ®ã€‚"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Deselect all visible icon items."
-msgstr "请先选择一个设置项ï¼"
+msgstr "å–æ¶ˆé€‰æ‹©æ‰€æœ‰å¯è§çš„图标项目。"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible stylebox items."
-msgstr ""
+msgstr "选择所有å¯è§çš„æ ·å¼ç›’项目。"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all visible stylebox items and their data."
-msgstr ""
+msgstr "选择所有å¯è§çš„æ ·å¼ç›’项目和它们的数æ®ã€‚"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all visible stylebox items."
-msgstr ""
+msgstr "å–æ¶ˆé€‰æ‹©æ‰€æœ‰å¯è§çš„æ ·å¼ç›’项目。"
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
"Caution: Adding icon data may considerably increase the size of your Theme "
"resource."
-msgstr ""
+msgstr "注æ„:添加图标数æ®å¯èƒ½æ˜¾è‘—增加主题资æºçš„大å°ã€‚"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Collapse types."
-msgstr "全部折å "
+msgstr "折å ç±»åž‹ã€‚"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Expand types."
-msgstr "全部展开"
+msgstr "展开类型。"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select all Theme items."
-msgstr "é€‰æ‹©æ¨¡æ¿æ–‡ä»¶"
+msgstr "选择所有主题项目。"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select With Data"
-msgstr "选择顶点"
+msgstr "é€‰æ‹©å«æ•°æ®"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select all Theme items with item data."
-msgstr ""
+msgstr "选择所有主题项目åŠé¡¹ç›®æ•°æ®ã€‚"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Deselect All"
-msgstr "全选"
+msgstr "å–æ¶ˆå…¨é€‰"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Deselect all Theme items."
-msgstr ""
+msgstr "å–æ¶ˆé€‰æ‹©æ‰€æœ‰ä¸»é¢˜é¡¹ç›®ã€‚"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Import Selected"
-msgstr "导入场景"
+msgstr "导入所选项"
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
@@ -8631,271 +8541,241 @@ msgid ""
"closing this window.\n"
"Close anyway?"
msgstr ""
+"导入项目选项å¡è¿˜æœ‰é€‰ä¸­çš„项目。关闭本窗å£ä¼šä¸¢å¤±é€‰é¡¹ã€‚\n"
+"ä»ç„¶å…³é—­å—?"
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Color Items"
-msgstr "移除所有项目"
+msgstr "移除所有颜色项目"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Item"
-msgstr "移除项目"
+msgstr "é‡å‘½å项目"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Constant Items"
-msgstr "移除所有项目"
+msgstr "移除所有常é‡é¡¹ç›®"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Font Items"
-msgstr "移除所有项目"
+msgstr "移除所有字体项目"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All Icon Items"
-msgstr "移除所有项目"
+msgstr "移除所有图标项目"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove All StyleBox Items"
-msgstr "移除所有项目"
+msgstr "移除所有样å¼ç›’项目"
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Color Item"
-msgstr "添加类项目"
+msgstr "添加颜色项目"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Constant Item"
-msgstr "添加类项目"
+msgstr "添加常é‡é¡¹ç›®"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Font Item"
-msgstr "添加项目"
+msgstr "添加字体项目"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Icon Item"
-msgstr "添加项目"
+msgstr "添加图标项目"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Stylebox Item"
-msgstr "添加所有项目"
+msgstr "添加样å¼ç›’项目"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Color Item"
-msgstr "移除类项目"
+msgstr "é‡å‘½å颜色项目"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Constant Item"
-msgstr "移除类项目"
+msgstr "é‡å‘½å常é‡é¡¹ç›®"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Font Item"
-msgstr "é‡å‘½å节点"
+msgstr "é‡å‘½å字体项目"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Icon Item"
-msgstr "é‡å‘½å节点"
+msgstr "é‡å‘½å图标项目"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Rename Stylebox Item"
-msgstr "移除选中项目"
+msgstr "é‡å‘½åæ ·å¼ç›’项目"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Invalid file, not a Theme resource."
-msgstr "æ— æ•ˆæ–‡ä»¶ï¼Œä¸æ˜¯éŸ³é¢‘总线布局。"
+msgstr "æ— æ•ˆæ–‡ä»¶ï¼Œä¸æ˜¯ Theme 资æºã€‚"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Invalid file, same as the edited Theme resource."
-msgstr ""
+msgstr "无效文件,与正在编辑的 Theme 资æºç›¸åŒã€‚"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Manage Theme Items"
-msgstr "ç®¡ç†æ¨¡æ¿"
+msgstr "管ç†ä¸»é¢˜é¡¹ç›®"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Edit Items"
-msgstr "å¯ç¼–辑的项目"
+msgstr "编辑项目"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Types:"
msgstr "类型:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Type:"
-msgstr "类型:"
+msgstr "添加类型:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Item:"
-msgstr "添加项目"
+msgstr "添加项目:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add StyleBox Item"
-msgstr "添加所有项目"
+msgstr "添加样å¼ç›’项目"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove Items:"
-msgstr "移除项目"
+msgstr "移除项目:"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove Class Items"
msgstr "移除类项目"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove Custom Items"
-msgstr "移除类项目"
+msgstr "移除自定义项目"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Items"
msgstr "移除所有项目"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Theme Item"
-msgstr "GUI主题项目"
+msgstr "添加主题项目"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Old Name:"
-msgstr "节点å称:"
+msgstr "æ—§å称:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Import Items"
-msgstr "导入主题"
+msgstr "导入项目"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Default Theme"
-msgstr "默认"
+msgstr "默认主题"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Editor Theme"
-msgstr "编辑主题"
+msgstr "编辑器主题"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select Another Theme Resource:"
-msgstr "删除资æº"
+msgstr "选择其它主题资æºï¼š"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Another Theme"
-msgstr "导入主题"
+msgstr "其它主题"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Confirm Item Rename"
-msgstr "é‡å‘½å轨é“"
+msgstr "确认项目é‡å‘½å"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Cancel Item Rename"
-msgstr "批é‡é‡å‘½å"
+msgstr "å–æ¶ˆé¡¹ç›®é‡å‘½å"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Override Item"
-msgstr "é‡å†™"
+msgstr "覆盖项目"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Unpin this StyleBox as a main style."
-msgstr ""
+msgstr "å–æ¶ˆå°†æ­¤æ ·å¼ç›’置顶为主样å¼ã€‚"
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
"Pin this StyleBox as a main style. Editing its properties will update the "
"same properties in all other StyleBoxes of this type."
msgstr ""
+"将此样å¼ç›’置顶为主样å¼ã€‚编辑其属性会更新该类型下其它所有样å¼ç›’的相åŒå±žæ€§ã€‚"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Type"
-msgstr "类型"
+msgstr "添加类型"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Item Type"
-msgstr "添加项目"
+msgstr "添加项目类型"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Node Types:"
-msgstr "节点类型"
+msgstr "节点类型:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Show Default"
-msgstr "加载默认"
+msgstr "显示默认"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Show default type items alongside items that have been overridden."
-msgstr ""
+msgstr "将默认类型项目与覆盖åŽçš„一起显示。"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Override All"
-msgstr "é‡å†™"
+msgstr "全部覆盖"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Override all default type items."
-msgstr ""
+msgstr "覆盖所有默认类型项目。"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Theme:"
-msgstr "主题"
+msgstr "主题:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Manage Items..."
-msgstr "管ç†å¯¼å‡ºæ¨¡æ¿..."
+msgstr "管ç†é¡¹ç›®..."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add, remove, organize and import Theme items."
-msgstr ""
+msgstr "添加ã€ç§»é™¤ã€ç»„织和导入 Theme 项目。"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Preview"
-msgstr "预览"
+msgstr "添加预览"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Default Preview"
-msgstr "更新预览"
+msgstr "默认预览"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Select UI Scene:"
-msgstr "选择æºç½‘格:"
+msgstr "选择 UI 场景:"
#: editor/plugins/theme_editor_preview.cpp
msgid ""
"Toggle the control picker, allowing to visually select control types for "
"edit."
-msgstr ""
+msgstr "开关控件拾å–器,å¯ä»¥å¯è§†åŒ–地选择所需编辑的控件类型。"
#: editor/plugins/theme_editor_preview.cpp
msgid "Toggle Button"
@@ -8930,7 +8810,6 @@ msgid "Checked Radio Item"
msgstr "已选å•选项目"
#: editor/plugins/theme_editor_preview.cpp
-#, fuzzy
msgid "Named Separator"
msgstr "带å称的分隔线"
@@ -8984,20 +8863,19 @@ msgstr "有, 很多, 选项"
#: editor/plugins/theme_editor_preview.cpp
msgid "Invalid path, the PackedScene resource was probably moved or removed."
-msgstr ""
+msgstr "无效路径,PackedScene 资æºå¯èƒ½å·²è¢«ç§»åŠ¨æˆ–ç§»é™¤ã€‚"
#: editor/plugins/theme_editor_preview.cpp
msgid "Invalid PackedScene resource, must have a Control node at its root."
-msgstr ""
+msgstr "无效 PackedScene 资æºï¼Œæ ¹èŠ‚ç‚¹å¿…é¡»æ˜¯ Control 节点。"
#: editor/plugins/theme_editor_preview.cpp
-#, fuzzy
msgid "Invalid file, not a PackedScene resource."
-msgstr "æ— æ•ˆæ–‡ä»¶ï¼Œä¸æ˜¯éŸ³é¢‘总线布局。"
+msgstr "æ— æ•ˆæ–‡ä»¶ï¼Œä¸æ˜¯ PackedScene 资æºã€‚"
#: editor/plugins/theme_editor_preview.cpp
msgid "Reload the scene to reflect its most actual state."
-msgstr ""
+msgstr "釿–°åŠ è½½åœºæ™¯ï¼Œåæ˜ æœ€æ–°çжæ€ã€‚"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Erase Selection"
@@ -10354,9 +10232,8 @@ msgid "VisualShader"
msgstr "å¯è§†ç€è‰²å™¨"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Edit Visual Property:"
-msgstr "编辑å¯è§†å±žæ€§"
+msgstr "编辑å¯è§†å±žæ€§ï¼š"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Visual Shader Mode Changed"
@@ -10480,9 +10357,8 @@ msgid "Script"
msgstr "脚本"
#: editor/project_export.cpp
-#, fuzzy
msgid "GDScript Export Mode:"
-msgstr "脚本导出模å¼:"
+msgstr "GDScript 导出模å¼ï¼š"
#: editor/project_export.cpp
msgid "Text"
@@ -10490,21 +10366,19 @@ msgstr "文本"
#: editor/project_export.cpp
msgid "Compiled Bytecode (Faster Loading)"
-msgstr ""
+msgstr "编译åŽçš„字节ç ï¼ˆåŠ è½½æ›´å¿«ï¼‰"
#: editor/project_export.cpp
msgid "Encrypted (Provide Key Below)"
msgstr "åŠ å¯†ï¼ˆåœ¨ä¸‹é¢æä¾›å¯†é’¥ï¼‰"
#: editor/project_export.cpp
-#, fuzzy
msgid "Invalid Encryption Key (must be 64 hexadecimal characters long)"
-msgstr "无效的加密密钥(长度必须为 64 个字符)"
+msgstr "无效的加密密钥(长度必须为 64 个å六进制字符)"
#: editor/project_export.cpp
-#, fuzzy
msgid "GDScript Encryption Key (256-bits as hexadecimal):"
-msgstr "脚本加密密钥(256 ä½ 16 进制ç ï¼‰:"
+msgstr "GDScript 加密密钥(256 ä½å六进制ç ï¼‰:"
#: editor/project_export.cpp
msgid "Export PCK/Zip"
@@ -10576,7 +10450,6 @@ msgid "Imported Project"
msgstr "已导入的项目"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Invalid project name."
msgstr "项目å称无效。"
@@ -10792,14 +10665,12 @@ msgid "Are you sure to run %d projects at once?"
msgstr "确定è¦åŒæ—¶è¿è¡Œ %d 个项目å—?"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove %d projects from the list?"
-msgstr "从列表中选择设备"
+msgstr "是å¦ä»Žåˆ—表中移除 %d 个项目?"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove this project from the list?"
-msgstr "从列表中选择设备"
+msgstr "是å¦ä»Žåˆ—表中移除该项目?"
#: editor/project_manager.cpp
msgid ""
@@ -10831,9 +10702,8 @@ msgid "Project Manager"
msgstr "项目管ç†å™¨"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Local Projects"
-msgstr "项目"
+msgstr "本地项目"
#: editor/project_manager.cpp
msgid "Loading, please wait..."
@@ -10844,23 +10714,20 @@ msgid "Last Modified"
msgstr "修改时间"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Edit Project"
-msgstr "导出项目"
+msgstr "编辑项目"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Run Project"
-msgstr "é‡å‘½å项目"
+msgstr "è¿è¡Œé¡¹ç›®"
#: editor/project_manager.cpp
msgid "Scan"
msgstr "扫æ"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Scan Projects"
-msgstr "项目"
+msgstr "扫æé¡¹ç›®"
#: editor/project_manager.cpp
msgid "Select a Folder to Scan"
@@ -10871,14 +10738,12 @@ msgid "New Project"
msgstr "新建项目"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Import Project"
-msgstr "已导入的项目"
+msgstr "导入项目"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove Project"
-msgstr "é‡å‘½å项目"
+msgstr "移除项目"
#: editor/project_manager.cpp
msgid "Remove Missing"
@@ -10889,9 +10754,8 @@ msgid "About"
msgstr "关于"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Asset Library Projects"
-msgstr "ç´ æåº“"
+msgstr "ç´ æåº“项目"
#: editor/project_manager.cpp
msgid "Restart Now"
@@ -10903,7 +10767,7 @@ msgstr "移除全部"
#: editor/project_manager.cpp
msgid "Also delete project contents (no undo!)"
-msgstr ""
+msgstr "åŒæ—¶åˆ é™¤é¡¹ç›®å†…容(无法撤销ï¼ï¼‰"
#: editor/project_manager.cpp
msgid "Can't run project"
@@ -10918,19 +10782,17 @@ msgstr ""
"æ˜¯å¦æŸ¥çœ‹ç´ æåº“中的官方示例项目?"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Filter projects"
-msgstr "筛选属性"
+msgstr "筛选项目"
#: editor/project_manager.cpp
-#, fuzzy
msgid ""
"This field filters projects by name and last path component.\n"
"To filter projects by name and full path, the query must contain at least "
"one `/` character."
msgstr ""
-"æœç´¢æ¡†æ ¹æ®å称和路径的末尾部分æ¥è¿‡æ»¤é¡¹ç›®ã€‚\n"
-"å¦‚æžœè¦æ ¹æ®å称和完整路径过滤,æœç´¢å†…容应至少包å«ä¸€ä¸ª `/` 字符。"
+"该æœç´¢æ¡†æ ¹æ®å称和路径的末尾部分æ¥ç­›é€‰é¡¹ç›®ã€‚\n"
+"å¦‚æžœè¦æ ¹æ®å称和完整路径筛选,æœç´¢å†…容应至少包å«ä¸€ä¸ªâ€œ/â€å­—符。"
#: editor/project_settings_editor.cpp
msgid "Key "
@@ -10938,7 +10800,7 @@ msgstr "按键 "
#: editor/project_settings_editor.cpp
msgid "Physical Key"
-msgstr ""
+msgstr "ç‰©ç†æŒ‰é”®"
#: editor/project_settings_editor.cpp
msgid "Joy Button"
@@ -10984,7 +10846,7 @@ msgstr "设备"
#: editor/project_settings_editor.cpp
msgid " (Physical)"
-msgstr ""
+msgstr " (物ç†ï¼‰"
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "Press a Key..."
@@ -11126,23 +10988,20 @@ msgid "Override for Feature"
msgstr "é‡å†™åŠŸèƒ½"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Add %d Translations"
-msgstr "添加翻译"
+msgstr "添加 %d 个翻译"
#: editor/project_settings_editor.cpp
msgid "Remove Translation"
msgstr "移除翻译"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Translation Resource Remap: Add %d Path(s)"
-msgstr "添加资æºé‡å®šå‘"
+msgstr "翻译资æºé‡å®šå‘:添加 %d 个路径"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Translation Resource Remap: Add %d Remap(s)"
-msgstr "添加资æºé‡å®šå‘"
+msgstr "翻译资æºé‡å®šå‘:添加 %d 个é‡å®šå‘"
#: editor/project_settings_editor.cpp
msgid "Change Resource Remap Language"
@@ -11581,13 +11440,13 @@ msgstr "是å¦åˆ é™¤èŠ‚ç‚¹ “%sâ€ï¼Ÿ"
#: editor/scene_tree_dock.cpp
msgid ""
"Saving the branch as a scene requires having a scene open in the editor."
-msgstr ""
+msgstr "将分支ä¿å­˜ä¸ºåœºæ™¯éœ€è¦ç¼–辑器打开场景。"
#: editor/scene_tree_dock.cpp
msgid ""
"Saving the branch as a scene requires selecting only one node, but you have "
"selected %d nodes."
-msgstr ""
+msgstr "将分支ä¿å­˜ä¸ºåœºæ™¯éœ€è¦ä»…选择一个节点,但你选了 %d 个。"
#: editor/scene_tree_dock.cpp
msgid ""
@@ -11596,6 +11455,9 @@ msgid ""
"FileSystem dock context menu\n"
"or create an inherited scene using Scene > New Inherited Scene... instead."
msgstr ""
+"无法将根节点ä¿å­˜ä¸ºå®žä¾‹åŒ–节点。\n"
+"如果è¦åˆ›å»ºå½“å‰åœºæ™¯çš„å¯ç¼–è¾‘å‰¯æœ¬ï¼Œè¯·åœ¨æ–‡ä»¶ç³»ç»Ÿé¢æ¿çš„上下文èœå•中å¤åˆ¶\n"
+"或者使用场景 > 新建继承场景... 创建继承场景。"
#: editor/scene_tree_dock.cpp
msgid ""
@@ -11603,6 +11465,9 @@ msgid ""
"To create a variation of a scene, you can make an inherited scene based on "
"the instanced scene using Scene > New Inherited Scene... instead."
msgstr ""
+"无法ä¿å­˜å®žä¾‹åŒ–场景分支。\n"
+"如果è¦åˆ›å»ºåœºæ™¯çš„å˜ç§ï¼Œè¯·ä½¿ç”¨åœºæ™¯ > 新建继承场景... 创建基于该实例化场景的继承"
+"场景。"
#: editor/scene_tree_dock.cpp
msgid "Save New Scene As..."
@@ -11998,7 +11863,7 @@ msgstr "注æ„ï¼šå†…ç½®è„šæœ¬æœ‰å…¶å±€é™æ€§ï¼Œå¹¶ä¸”ä¸èƒ½ä½¿ç”¨å¤–部编辑器
msgid ""
"Warning: Having the script name be the same as a built-in type is usually "
"not desired."
-msgstr ""
+msgstr "警告:脚本å称通常ä¸èƒ½ä¸Žå†…置类型一致。"
#: editor/script_create_dialog.cpp
msgid "Class Name:"
@@ -12070,7 +11935,7 @@ msgstr "å¤åˆ¶é”™è¯¯ä¿¡æ¯"
#: editor/script_editor_debugger.cpp
msgid "Open C++ Source on GitHub"
-msgstr ""
+msgstr "在 GitHub 打开 C++ æºç "
#: editor/script_editor_debugger.cpp
msgid "Video RAM"
@@ -12142,7 +12007,7 @@ msgstr "æ ¼å¼"
#: editor/script_editor_debugger.cpp
msgid "Usage"
-msgstr "用法"
+msgstr "å ç”¨"
#: editor/script_editor_debugger.cpp
msgid "Misc"
@@ -12248,6 +12113,16 @@ msgstr "修改圆柱体高度"
msgid "Change Ray Shape Length"
msgstr "修改射线形状长度"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "è®¾ç½®æ›²çº¿çš„é¡¶ç‚¹åæ ‡"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "è®¾ç½®æ›²çº¿çš„é¡¶ç‚¹åæ ‡"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "改å˜åœ†æŸ±ä½“åŠå¾„"
@@ -12357,14 +12232,12 @@ msgid "Object can't provide a length."
msgstr "对象无法æä¾›é•¿åº¦ã€‚"
#: modules/gltf/editor_scene_exporter_gltf_plugin.cpp
-#, fuzzy
msgid "Export Mesh GLTF2"
-msgstr "导出网格库"
+msgstr "导出网格 GLTF2"
#: modules/gltf/editor_scene_exporter_gltf_plugin.cpp
-#, fuzzy
msgid "Export GLTF..."
-msgstr "导出..."
+msgstr "导出 GLTF..."
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Next Plane"
@@ -12404,12 +12277,11 @@ msgstr "网格地图粘贴所选项"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "GridMap Paint"
-msgstr "绘制栅格图"
+msgstr "网格地图绘制"
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "GridMap Selection"
-msgstr "网格地图填充所选项"
+msgstr "网格地图选择"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Grid Map"
@@ -12656,14 +12528,12 @@ msgid "Add Output Port"
msgstr "增加输出端å£"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Change Port Type"
-msgstr "更改类型"
+msgstr "更改端å£ç±»åž‹"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Change Port Name"
-msgstr "更改输入端å£åç§°"
+msgstr "更改端å£åç§°"
#: modules/visual_script/visual_script_editor.cpp
msgid "Override an existing built-in function."
@@ -12774,7 +12644,6 @@ msgid "Add Preload Node"
msgstr "添加预载 (Preload) 节点"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Node(s)"
msgstr "添加节点"
@@ -13034,37 +12903,31 @@ msgstr "从列表中选择设备"
#: platform/android/export/export.cpp
msgid "Running on %s"
-msgstr ""
+msgstr "æ­£è¿è¡ŒäºŽ %d"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Exporting APK..."
-msgstr "全部导出"
+msgstr "正在导出 APK……"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Uninstalling..."
-msgstr "å¸è½½"
+msgstr "正在å¸è½½â€¦â€¦"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Installing to device, please wait..."
-msgstr "正在加载,请ç¨å€™â€¦â€¦"
+msgstr "正在安装到设备,请ç¨å€™â€¦â€¦"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not install to device: %s"
-msgstr "无法实例化场景ï¼"
+msgstr "无法安装到设备:%s"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Running on device..."
-msgstr "执行自定义脚本..."
+msgstr "正在设备上è¿è¡Œâ€¦â€¦"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not execute on device."
-msgstr "无法创建文件夹。"
+msgstr "无法在设备上è¿è¡Œã€‚"
#: platform/android/export/export.cpp
msgid "Unable to find the 'apksigner' tool."
@@ -13173,40 +13036,37 @@ msgid ""
"directory.\n"
"The resulting %s is unsigned."
msgstr ""
+"无法找到“apksignerâ€ã€‚\n"
+"请检查 Android SDK çš„ build-tools ç›®å½•ä¸­æ˜¯å¦æœ‰æ­¤å‘½ä»¤ã€‚\n"
+"生æˆçš„ %s 未签å。"
#: platform/android/export/export.cpp
msgid "Signing debug %s..."
-msgstr ""
+msgstr "正在签å调试 %s……"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Signing release %s..."
-msgstr ""
-"æ­£åœ¨æ‰«ææ–‡ä»¶ï¼Œ\n"
-"请ç¨å€™â€¦â€¦"
+msgstr "正在签åå‘布 %s……"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not find keystore, unable to export."
-msgstr "无法打开导出模æ¿ï¼š"
+msgstr "找ä¸åˆ°å¯†é’¥åº“,无法导出。"
#: platform/android/export/export.cpp
msgid "'apksigner' returned with error #%d"
-msgstr ""
+msgstr "“apksignerâ€è¿”回错误 #%d"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Verifying %s..."
-msgstr "正在添加 %s..."
+msgstr "正在校验 %s……"
#: platform/android/export/export.cpp
msgid "'apksigner' verification of %s failed."
-msgstr ""
+msgstr "“apksignerâ€æ ¡éªŒ %s 失败。"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Exporting for Android"
-msgstr "全部导出"
+msgstr "正在为 Android 导出"
#: platform/android/export/export.cpp
msgid "Invalid filename! Android App Bundle requires the *.aab extension."
@@ -13222,7 +13082,7 @@ msgstr "无效文件åï¼Android APK 必须有 *.apk 扩展。"
#: platform/android/export/export.cpp
msgid "Unsupported export format!\n"
-msgstr ""
+msgstr "䏿”¯æŒçš„导出格å¼ï¼\n"
#: platform/android/export/export.cpp
msgid ""
@@ -13246,17 +13106,15 @@ msgstr ""
#: platform/android/export/export.cpp
msgid ""
"Unable to overwrite res://android/build/res/*.xml files with project name"
-msgstr ""
+msgstr "无法使用项目å称覆盖 res://android/build/res/*.xml 文件"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not export project files to gradle project\n"
-msgstr "无法在项目目录下找到project.godot文件。"
+msgstr "无法将项目文件导出至 gradle 项目\n"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not write expansion package file!"
-msgstr "无法写入文件:"
+msgstr "无法写入扩展包文件ï¼"
#: platform/android/export/export.cpp
msgid "Building Android Project (gradle)"
@@ -13281,21 +13139,20 @@ msgid ""
msgstr "无法å¤åˆ¶ä¸Žæ›´å导出文件,请在 Gradle 项目文件夹内确认输出。"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Package not found: %s"
-msgstr "没有动画: “%sâ€"
+msgstr "包ä¸å­˜åœ¨ï¼š%s"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Creating APK..."
-msgstr "正在创建轮廓..."
+msgstr "正在创建 APK……"
#: platform/android/export/export.cpp
-#, fuzzy
msgid ""
"Could not find template APK to export:\n"
"%s"
-msgstr "无法打开导出模æ¿ï¼š"
+msgstr ""
+"找ä¸åˆ°å¯¼å‡ºæ¨¡æ¿ APK:\n"
+"%s"
#: platform/android/export/export.cpp
msgid ""
@@ -13304,24 +13161,24 @@ msgid ""
"Please build a template with all required libraries, or uncheck the missing "
"architectures in the export preset."
msgstr ""
+"导出模æ¿ç¼ºå¤±æ‰€é€‰æž¶æž„的库:%s。\n"
+"请使用全部所需的库构建模æ¿ï¼Œæˆ–è€…åœ¨å¯¼å‡ºé¢„è®¾ä¸­å–æ¶ˆå¯¹ç¼ºå¤±æž¶æž„的选择。"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Adding files..."
-msgstr "正在添加 %s..."
+msgstr "正在添加文件……"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Could not export project files"
-msgstr "无法写入文件:"
+msgstr "无法导出项目文件"
#: platform/android/export/export.cpp
msgid "Aligning APK..."
-msgstr "å¯¹é½ APK..."
+msgstr "æ­£åœ¨å¯¹é½ APK……"
#: platform/android/export/export.cpp
msgid "Could not unzip temporary unaligned APK."
-msgstr ""
+msgstr "无法解压未对é½çš„临时 APK。"
#: platform/iphone/export/export.cpp platform/osx/export/export.cpp
msgid "Identifier is missing."
@@ -13368,45 +13225,40 @@ msgid "Could not write file:"
msgstr "无法写入文件:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not read file:"
-msgstr "无法写入文件:"
+msgstr "æ— æ³•è¯»å–æ–‡ä»¶ï¼š"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not read HTML shell:"
-msgstr "无法读å–自定义 HTML 壳层:"
+msgstr "æ— æ³•è¯»å– HTML 壳:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not create HTTP server directory:"
-msgstr "无法创建文件夹。"
+msgstr "无法创建 HTTP æœåŠ¡å™¨ç›®å½•ï¼š"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Error starting HTTP server:"
-msgstr "ä¿å­˜åœºæ™¯å‡ºé”™ã€‚"
+msgstr "å¯åЍ HTTP æœåŠ¡å™¨æ—¶å‡ºé”™ï¼š"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Invalid bundle identifier:"
-msgstr "无效的标识符:"
+msgstr "无效的包标识符:"
#: platform/osx/export/export.cpp
msgid "Notarization: code signing required."
-msgstr ""
+msgstr "å…¬è¯ï¼šéœ€è¦ä»£ç ç­¾å。"
#: platform/osx/export/export.cpp
msgid "Notarization: hardened runtime required."
-msgstr ""
+msgstr "å…¬è¯ï¼šéœ€è¦åŠ å¼ºçš„è¿è¡Œæ—¶çŽ¯å¢ƒã€‚"
#: platform/osx/export/export.cpp
msgid "Notarization: Apple ID name not specified."
-msgstr ""
+msgstr "å…¬è¯ï¼šæœªæŒ‡å®š Apple ID å称。"
#: platform/osx/export/export.cpp
msgid "Notarization: Apple ID password not specified."
-msgstr ""
+msgstr "å…¬è¯ï¼šæœªæŒ‡å®š Apple ID 密ç ã€‚"
#: platform/uwp/export/export.cpp
msgid "Invalid package short name."
@@ -13799,6 +13651,8 @@ msgid ""
"longer has any effect.\n"
"To remove this warning, disable the GIProbe's Compress property."
msgstr ""
+"因为存在已知问题,GIProbe Compress 属性已被å¯ç”¨ï¼Œä¸ä¼šå†èµ·ä»»ä½•作用。\n"
+"如果è¦ç§»é™¤æœ¬è­¦å‘Šï¼Œè¯·ç¦ç”¨ GIProbe çš„ Compress 属性。"
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
@@ -13882,15 +13736,15 @@ msgstr "Node A 与 Node B 必须为ä¸åŒçš„ PhysicsBody"
#: scene/3d/portal.cpp
msgid "The RoomManager should not be a child or grandchild of a Portal."
-msgstr ""
+msgstr "RoomManager ä¸åº”该是 Portal çš„å­èŠ‚ç‚¹æˆ–å­™èŠ‚ç‚¹ã€‚"
#: scene/3d/portal.cpp
msgid "A Room should not be a child or grandchild of a Portal."
-msgstr ""
+msgstr "Room ä¸åº”该是 Portal çš„å­èŠ‚ç‚¹æˆ–å­™èŠ‚ç‚¹ã€‚"
#: scene/3d/portal.cpp
msgid "A RoomGroup should not be a child or grandchild of a Portal."
-msgstr ""
+msgstr "RoomGroup ä¸åº”该是 Portal çš„å­èŠ‚ç‚¹æˆ–å­™èŠ‚ç‚¹ã€‚"
#: scene/3d/remote_transform.cpp
msgid ""
@@ -13901,42 +13755,82 @@ msgstr ""
#: scene/3d/room.cpp
msgid "A Room cannot have another Room as a child or grandchild."
-msgstr ""
+msgstr "Room ä¸èƒ½æ˜¯å¦ä¸€ä¸ª Room çš„å­èŠ‚ç‚¹æˆ–å­™èŠ‚ç‚¹ã€‚"
#: scene/3d/room.cpp
msgid "The RoomManager should not be placed inside a Room."
-msgstr ""
+msgstr "RoomManager ä¸åº”该被放置在 Room 中。"
#: scene/3d/room.cpp
msgid "A RoomGroup should not be placed inside a Room."
-msgstr ""
+msgstr "RoomGroup ä¸åº”该被放置在 Room 中。"
#: scene/3d/room.cpp
msgid ""
"Room convex hull contains a large number of planes.\n"
"Consider simplifying the room bound in order to increase performance."
msgstr ""
+"房间的凸包中包å«å¤§é‡å¹³é¢ã€‚\n"
+"为了æå‡æ€§èƒ½ï¼Œè¯·è€ƒè™‘简化房间的边界。"
#: scene/3d/room_group.cpp
msgid "The RoomManager should not be placed inside a RoomGroup."
-msgstr ""
+msgstr "RoomManager ä¸åº”该被放置在 RoomGroup 中。"
#: scene/3d/room_manager.cpp
msgid "The RoomList has not been assigned."
-msgstr ""
+msgstr "RoomList 尚未赋值。"
#: scene/3d/room_manager.cpp
msgid "The RoomList node should be a Spatial (or derived from Spatial)."
-msgstr ""
+msgstr "RoomList 节点应该是 Spatial(或者派生自 Spatial)。"
#: scene/3d/room_manager.cpp
msgid ""
"Portal Depth Limit is set to Zero.\n"
"Only the Room that the Camera is in will render."
msgstr ""
+"Portal Depth Limit 被设置为零。\n"
+"ä»…ä¼šæ¸²æŸ“æ‘„åƒæœºæ‰€åœ¨æˆ¿é—´ã€‚"
#: scene/3d/room_manager.cpp
msgid "There should only be one RoomManager in the SceneTree."
+msgstr "场景树中仅能存在一个 RoomManager。"
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
msgstr ""
#: scene/3d/soft_body.cpp
@@ -13999,7 +13893,7 @@ msgstr "没有动画: “%sâ€"
#: scene/animation/animation_player.cpp
msgid "Anim Apply Reset"
-msgstr ""
+msgstr "动画应用é‡ç½®"
#: scene/animation/animation_tree.cpp
msgid "In node '%s', invalid animation: '%s'."
@@ -14165,25 +14059,24 @@ msgid "Invalid comparison function for that type."
msgstr "该类型的比较功能无效。"
#: servers/visual/shader_language.cpp
-#, fuzzy
msgid "Varying may not be assigned in the '%s' function."
-msgstr "å˜é‡åªèƒ½åœ¨é¡¶ç‚¹å‡½æ•°ä¸­æŒ‡å®šã€‚"
+msgstr "Varying ä¸èƒ½åœ¨â€œ%sâ€å‡½æ•°ä¸­èµ‹å€¼ã€‚"
#: servers/visual/shader_language.cpp
msgid ""
"Varyings which assigned in 'vertex' function may not be reassigned in "
"'fragment' or 'light'."
-msgstr ""
+msgstr "已在“vertexâ€å‡½æ•°ä¸­èµ‹å€¼çš„ varying ä¸èƒ½åœ¨â€œfragmentâ€æˆ–“lightâ€ä¸­é‡æ–°èµ‹å€¼ã€‚"
#: servers/visual/shader_language.cpp
msgid ""
"Varyings which assigned in 'fragment' function may not be reassigned in "
"'vertex' or 'light'."
-msgstr ""
+msgstr "已在“fragmentâ€å‡½æ•°ä¸­èµ‹å€¼çš„ varying ä¸èƒ½åœ¨â€œvertexâ€æˆ–“lightâ€ä¸­é‡æ–°èµ‹å€¼ã€‚"
#: servers/visual/shader_language.cpp
msgid "Fragment-stage varying could not been accessed in custom function!"
-msgstr ""
+msgstr "ä¸èƒ½åœ¨è‡ªå®šä¹‰å‡½æ•°ä¸­è®¿é—®ç‰‡æ®µ varyingï¼"
#: servers/visual/shader_language.cpp
msgid "Assignment to function."
@@ -15184,9 +15077,6 @@ msgstr "ä¸å…许修改常é‡ã€‚"
#~ msgid "I see..."
#~ msgstr "好å§..."
-#~ msgid "Can't open '%s'."
-#~ msgstr "无法打开 \"%s\"。"
-
#~ msgid "Ugh"
#~ msgstr "呃"
diff --git a/editor/translations/zh_HK.po b/editor/translations/zh_HK.po
index 9cae040eb4..e5327f79d9 100644
--- a/editor/translations/zh_HK.po
+++ b/editor/translations/zh_HK.po
@@ -361,6 +361,7 @@ msgstr "更改動畫循環"
msgid "Remove Anim Track"
msgstr "移除動畫軌跡"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
#, fuzzy
msgid "Create NEW track for %s and insert key?"
@@ -389,10 +390,28 @@ msgstr "新增"
msgid "Anim Insert"
msgstr "æ’入動畫"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "ä¸èƒ½é€£æŽ¥ã€‚"
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "新增動畫"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr ""
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "內容"
+
#: editor/animation_track_editor.cpp
#, fuzzy
msgid "Anim Create & Insert"
@@ -990,7 +1009,7 @@ msgstr "新增"
msgid "No results for \"%s\"."
msgstr ""
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2367,6 +2386,17 @@ msgid "New Window"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr ""
@@ -3209,10 +3239,6 @@ msgid "Save & Restart"
msgstr "儲存檔案"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr ""
-
-#: editor/editor_node.cpp
#, fuzzy
msgid "Update Continuously"
msgstr "連續"
@@ -3873,6 +3899,16 @@ msgid "Download from:"
msgstr "下載出ç¾éŒ¯èª¤"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "ç€è¦½"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "載入錯誤"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8886,6 +8922,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "移除é¸é …"
@@ -8916,6 +8958,12 @@ msgid "Remove All StyleBox Items"
msgstr "移除é¸é …"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "加到最愛"
@@ -12581,6 +12629,16 @@ msgstr ""
msgid "Change Ray Shape Length"
msgstr ""
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "åªé™é¸ä¸­"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "åªé™é¸ä¸­"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr ""
@@ -14267,6 +14325,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr ""
@@ -14917,10 +15011,6 @@ msgstr ""
#~ msgstr "多è¬!"
#, fuzzy
-#~ msgid "Can't open '%s'."
-#~ msgstr "ä¸èƒ½é€£æŽ¥ã€‚"
-
-#, fuzzy
#~ msgid "Ugh"
#~ msgstr "å—¯......"
diff --git a/editor/translations/zh_TW.po b/editor/translations/zh_TW.po
index 2b4dd0fc03..4fc48abd03 100644
--- a/editor/translations/zh_TW.po
+++ b/editor/translations/zh_TW.po
@@ -360,6 +360,7 @@ msgstr "更改動畫循環模å¼"
msgid "Remove Anim Track"
msgstr "刪除動畫軌"
+#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
msgstr "確定è¦ç‚º %s 建立動畫軌並æ’入關éµç•«æ ¼å—Žï¼Ÿ"
@@ -384,10 +385,28 @@ msgstr "建立"
msgid "Anim Insert"
msgstr "æ’入動畫"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "node '%s'"
+msgstr "無法開啟 \"%s\"。"
+
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "animation"
+msgstr "å‹•ç•«"
+
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
msgstr "AnimationPlayer ä¸èƒ½æ’­æ”¾è‡ªå·±ï¼Œåªå¯æ’­æ”¾å…¶ä»– Player。"
+#. TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "property '%s'"
+msgstr "屬性「%sã€ä¸å­˜åœ¨ã€‚"
+
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
msgstr "新增並æ’入動畫"
@@ -955,7 +974,7 @@ msgstr "建立新的 %s"
msgid "No results for \"%s\"."
msgstr "找ä¸åˆ°èˆ‡ã€Œ%sã€ç›¸é—œçš„çµæžœã€‚"
-#: editor/create_dialog.cpp
+#: editor/create_dialog.cpp editor/property_selector.cpp
msgid "No description available for %s."
msgstr ""
@@ -2292,6 +2311,17 @@ msgid "New Window"
msgstr "新視窗"
#: editor/editor_node.cpp
+msgid ""
+"Spins when the editor window redraws.\n"
+"Update Continuously is enabled, which can increase power usage. Click to "
+"disable it."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr "ç·¨è¼¯å™¨è¦–çª—é‡æ–°ç¹ªè£½æ™‚旋轉。"
+
+#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
msgstr "匯入的資æºç„¡æ³•ä¿å­˜ã€‚"
@@ -3115,10 +3145,6 @@ msgid "Save & Restart"
msgstr "ä¿å­˜ä¸¦é‡æ–°å•Ÿå‹•"
#: editor/editor_node.cpp
-msgid "Spins when the editor window redraws."
-msgstr "ç·¨è¼¯å™¨è¦–çª—é‡æ–°ç¹ªè£½æ™‚旋轉。"
-
-#: editor/editor_node.cpp
msgid "Update Continuously"
msgstr "æŒçºŒæ›´æ–°"
@@ -3768,6 +3794,16 @@ msgid "Download from:"
msgstr "下載錯誤"
#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Open in Web Browser"
+msgstr "在ç€è¦½å™¨ä¸­åŸ·è¡Œ"
+
+#: editor/export_template_manager.cpp
+#, fuzzy
+msgid "Copy Mirror URL"
+msgstr "複製錯誤"
+
+#: editor/export_template_manager.cpp
msgid "Download and Install"
msgstr ""
@@ -8581,6 +8617,12 @@ msgid ""
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"Select a theme type from the list to edit its items.\n"
+"You can add a custom type or import a type with its items from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Remove All Color Items"
msgstr "移除所有項目"
@@ -8611,6 +8653,12 @@ msgid "Remove All StyleBox Items"
msgstr "移除所有項目"
#: editor/plugins/theme_editor_plugin.cpp
+msgid ""
+"This theme type is empty.\n"
+"Add more items to it manually or by importing from another theme."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
msgid "Add Color Item"
msgstr "新增類別項目"
@@ -12194,6 +12242,16 @@ msgstr "更改圓柱形高度"
msgid "Change Ray Shape Length"
msgstr "更改射線形長度"
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Room Point Position"
+msgstr "設定曲線控制點ä½ç½®"
+
+#: editor/spatial_editor_gizmos.cpp
+#, fuzzy
+msgid "Set Portal Point Position"
+msgstr "設定曲線控制點ä½ç½®"
+
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
msgstr "更改圓柱體åŠå¾‘"
@@ -13887,6 +13945,42 @@ msgstr ""
msgid "There should only be one RoomManager in the SceneTree."
msgstr ""
+#: scene/3d/room_manager.cpp
+msgid ""
+"RoomList path is invalid.\n"
+"Please check the RoomList branch has been assigned in the RoomManager."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "RoomList contains no Rooms, aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Misnamed nodes detected, check output log for details. Aborting."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid "Portal link room not found, check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Portal autolink failed, check output log for details.\n"
+"Check the portal is facing outwards from the source room."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
+"Check output log for details."
+msgstr ""
+
+#: scene/3d/room_manager.cpp
+msgid ""
+"Error calculating room bounds.\n"
+"Ensure all rooms contain geometry or manual bounds."
+msgstr ""
+
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
msgstr "該形體在設定網格å‰éƒ½å°‡è¢«å¿½ç•¥ã€‚"
@@ -14806,9 +14900,6 @@ msgstr "ä¸å¯ä¿®æ”¹å¸¸æ•¸ã€‚"
#~ msgid "Thanks!"
#~ msgstr "è¬è¬!"
-#~ msgid "Can't open '%s'."
-#~ msgstr "無法開啟 \"%s\"。"
-
#~ msgid "Ugh"
#~ msgstr "呃"
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index 91465bcfea..bf11cc7f68 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -88,36 +88,40 @@ uint32_t CSGShape3D::get_collision_mask() const {
return collision_mask;
}
-void CSGShape3D::set_collision_mask_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
- uint32_t mask = get_collision_mask();
+void CSGShape3D::set_collision_layer_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
+ uint32_t collision_layer = get_collision_layer();
if (p_value) {
- mask |= 1 << p_bit;
+ collision_layer |= 1 << (p_layer_number - 1);
} else {
- mask &= ~(1 << p_bit);
+ collision_layer &= ~(1 << (p_layer_number - 1));
}
- set_collision_mask(mask);
+ set_collision_layer(collision_layer);
}
-bool CSGShape3D::get_collision_mask_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
- return get_collision_mask() & (1 << p_bit);
+bool CSGShape3D::get_collision_layer_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_layer() & (1 << (p_layer_number - 1));
}
-void CSGShape3D::set_collision_layer_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
- uint32_t layer = get_collision_layer();
+void CSGShape3D::set_collision_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
+ uint32_t mask = get_collision_mask();
if (p_value) {
- layer |= 1 << p_bit;
+ mask |= 1 << (p_layer_number - 1);
} else {
- layer &= ~(1 << p_bit);
+ mask &= ~(1 << (p_layer_number - 1));
}
- set_collision_layer(layer);
+ set_collision_mask(mask);
}
-bool CSGShape3D::get_collision_layer_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
- return get_collision_layer() & (1 << p_bit);
+bool CSGShape3D::get_collision_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_mask() & (1 << (p_layer_number - 1));
}
bool CSGShape3D::is_root_shape() const {
@@ -605,11 +609,11 @@ void CSGShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &CSGShape3D::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &CSGShape3D::get_collision_mask);
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &CSGShape3D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CSGShape3D::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &CSGShape3D::set_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &CSGShape3D::get_collision_mask_value);
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &CSGShape3D::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CSGShape3D::get_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &CSGShape3D::set_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &CSGShape3D::get_collision_layer_value);
ClassDB::bind_method(D_METHOD("set_calculate_tangents", "enabled"), &CSGShape3D::set_calculate_tangents);
ClassDB::bind_method(D_METHOD("is_calculating_tangents"), &CSGShape3D::is_calculating_tangents);
diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h
index 5814ce4c83..5cf371665e 100644
--- a/modules/csg/csg_shape.h
+++ b/modules/csg/csg_shape.h
@@ -137,11 +137,11 @@ public:
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
- void set_collision_layer_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
+ void set_collision_layer_value(int p_layer_number, bool p_value);
+ bool get_collision_layer_value(int p_layer_number) const;
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
+ void set_collision_mask_value(int p_layer_number, bool p_value);
+ bool get_collision_mask_value(int p_layer_number) const;
void set_snap(float p_snap);
float get_snap() const;
diff --git a/modules/csg/doc_classes/CSGShape3D.xml b/modules/csg/doc_classes/CSGShape3D.xml
index f42ce8c379..446269f3f0 100644
--- a/modules/csg/doc_classes/CSGShape3D.xml
+++ b/modules/csg/doc_classes/CSGShape3D.xml
@@ -9,18 +9,18 @@
<tutorials>
</tutorials>
<methods>
- <method name="get_collision_layer_bit" qualifiers="const">
+ <method name="get_collision_layer_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns an individual bit on the collision mask.
+ Returns whether or not the specified layer of the [member collision_layer] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
- <method name="get_collision_mask_bit" qualifiers="const">
+ <method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns an individual bit on the collision mask.
+ Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="get_meshes" qualifiers="const">
@@ -35,20 +35,20 @@
Returns [code]true[/code] if this is a root shape and is thus the object that is rendered.
</description>
</method>
- <method name="set_collision_layer_bit">
+ <method name="set_collision_layer_value">
<return type="void" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<argument index="1" name="value" type="bool" />
<description>
- Sets individual bits on the layer mask. Use this if you only need to change one layer's value.
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_layer], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
- <method name="set_collision_mask_bit">
+ <method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<argument index="1" name="value" type="bool" />
<description>
- Sets individual bits on the collision mask. Use this if you only need to change one layer's value.
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
</methods>
diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index 8ea7384658..c1dbe63628 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -53,18 +53,18 @@
The orientation of the cell at the given grid coordinates. [code]-1[/code] is returned if the cell is empty.
</description>
</method>
- <method name="get_collision_layer_bit" qualifiers="const">
+ <method name="get_collision_layer_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns an individual bit on the [member collision_layer].
+ Returns whether or not the specified layer of the [member collision_layer] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
- <method name="get_collision_mask_bit" qualifiers="const">
+ <method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns an individual bit on the [member collision_mask].
+ Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="get_meshes">
@@ -119,20 +119,20 @@
<description>
</description>
</method>
- <method name="set_collision_layer_bit">
+ <method name="set_collision_layer_value">
<return type="void" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<argument index="1" name="value" type="bool" />
<description>
- Sets an individual bit on the [member collision_layer].
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_layer], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
- <method name="set_collision_mask_bit">
+ <method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="bit" type="int" />
+ <argument index="0" name="layer_number" type="int" />
<argument index="1" name="value" type="bool" />
<description>
- Sets an individual bit on the [member collision_mask].
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="world_to_map" qualifiers="const">
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index fea513c820..8e8b6f14ad 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -151,36 +151,40 @@ uint32_t GridMap::get_collision_mask() const {
return collision_mask;
}
-void GridMap::set_collision_mask_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
- uint32_t mask = get_collision_mask();
+void GridMap::set_collision_layer_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
+ uint32_t collision_layer = get_collision_layer();
if (p_value) {
- mask |= 1 << p_bit;
+ collision_layer |= 1 << (p_layer_number - 1);
} else {
- mask &= ~(1 << p_bit);
+ collision_layer &= ~(1 << (p_layer_number - 1));
}
- set_collision_mask(mask);
+ set_collision_layer(collision_layer);
}
-bool GridMap::get_collision_mask_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
- return get_collision_mask() & (1 << p_bit);
+bool GridMap::get_collision_layer_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_layer() & (1 << (p_layer_number - 1));
}
-void GridMap::set_collision_layer_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
- uint32_t layer = get_collision_layer();
+void GridMap::set_collision_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
+ uint32_t mask = get_collision_mask();
if (p_value) {
- layer |= 1 << p_bit;
+ mask |= 1 << (p_layer_number - 1);
} else {
- layer &= ~(1 << p_bit);
+ mask &= ~(1 << (p_layer_number - 1));
}
- set_collision_layer(layer);
+ set_collision_mask(mask);
}
-bool GridMap::get_collision_layer_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
- return get_collision_layer() & (1 << p_bit);
+bool GridMap::get_collision_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_mask() & (1 << (p_layer_number - 1));
}
void GridMap::set_bake_navigation(bool p_bake_navigation) {
@@ -794,11 +798,11 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &GridMap::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &GridMap::get_collision_mask);
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &GridMap::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &GridMap::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &GridMap::set_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &GridMap::get_collision_mask_value);
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &GridMap::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &GridMap::get_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &GridMap::set_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &GridMap::get_collision_layer_value);
ClassDB::bind_method(D_METHOD("set_bake_navigation", "bake_navigation"), &GridMap::set_bake_navigation);
ClassDB::bind_method(D_METHOD("is_baking_navigation"), &GridMap::is_baking_navigation);
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index 8cd82e1f4c..879489fc70 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -217,11 +217,11 @@ public:
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
- void set_collision_layer_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
+ void set_collision_layer_value(int p_layer_number, bool p_value);
+ bool get_collision_layer_value(int p_layer_number) const;
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
+ void set_collision_mask_value(int p_layer_number, bool p_value);
+ bool get_collision_mask_value(int p_layer_number) const;
void set_bake_navigation(bool p_bake_navigation);
bool is_baking_navigation();
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index 1795bbe523..fc86abb6f1 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -30,3021 +30,7 @@
#include "export.h"
-#include "core/config/project_settings.h"
-#include "core/io/dir_access.h"
-#include "core/io/file_access.h"
-#include "core/io/image_loader.h"
-#include "core/io/json.h"
-#include "core/io/marshalls.h"
-#include "core/io/zip_io.h"
-#include "core/os/os.h"
-#include "core/templates/safe_refcount.h"
-#include "core/version.h"
-#include "drivers/png/png_driver_common.h"
-#include "editor/editor_export.h"
-#include "editor/editor_log.h"
-#include "editor/editor_node.h"
-#include "editor/editor_settings.h"
-#include "main/splash.gen.h"
-#include "platform/android/export/gradle_export_util.h"
-#include "platform/android/logo.gen.h"
-#include "platform/android/plugin/godot_plugin_config.h"
-#include "platform/android/run_icon.gen.h"
-
-#include <string.h>
-
-static const char *android_perms[] = {
- "ACCESS_CHECKIN_PROPERTIES",
- "ACCESS_COARSE_LOCATION",
- "ACCESS_FINE_LOCATION",
- "ACCESS_LOCATION_EXTRA_COMMANDS",
- "ACCESS_MOCK_LOCATION",
- "ACCESS_NETWORK_STATE",
- "ACCESS_SURFACE_FLINGER",
- "ACCESS_WIFI_STATE",
- "ACCOUNT_MANAGER",
- "ADD_VOICEMAIL",
- "AUTHENTICATE_ACCOUNTS",
- "BATTERY_STATS",
- "BIND_ACCESSIBILITY_SERVICE",
- "BIND_APPWIDGET",
- "BIND_DEVICE_ADMIN",
- "BIND_INPUT_METHOD",
- "BIND_NFC_SERVICE",
- "BIND_NOTIFICATION_LISTENER_SERVICE",
- "BIND_PRINT_SERVICE",
- "BIND_REMOTEVIEWS",
- "BIND_TEXT_SERVICE",
- "BIND_VPN_SERVICE",
- "BIND_WALLPAPER",
- "BLUETOOTH",
- "BLUETOOTH_ADMIN",
- "BLUETOOTH_PRIVILEGED",
- "BRICK",
- "BROADCAST_PACKAGE_REMOVED",
- "BROADCAST_SMS",
- "BROADCAST_STICKY",
- "BROADCAST_WAP_PUSH",
- "CALL_PHONE",
- "CALL_PRIVILEGED",
- "CAMERA",
- "CAPTURE_AUDIO_OUTPUT",
- "CAPTURE_SECURE_VIDEO_OUTPUT",
- "CAPTURE_VIDEO_OUTPUT",
- "CHANGE_COMPONENT_ENABLED_STATE",
- "CHANGE_CONFIGURATION",
- "CHANGE_NETWORK_STATE",
- "CHANGE_WIFI_MULTICAST_STATE",
- "CHANGE_WIFI_STATE",
- "CLEAR_APP_CACHE",
- "CLEAR_APP_USER_DATA",
- "CONTROL_LOCATION_UPDATES",
- "DELETE_CACHE_FILES",
- "DELETE_PACKAGES",
- "DEVICE_POWER",
- "DIAGNOSTIC",
- "DISABLE_KEYGUARD",
- "DUMP",
- "EXPAND_STATUS_BAR",
- "FACTORY_TEST",
- "FLASHLIGHT",
- "FORCE_BACK",
- "GET_ACCOUNTS",
- "GET_PACKAGE_SIZE",
- "GET_TASKS",
- "GET_TOP_ACTIVITY_INFO",
- "GLOBAL_SEARCH",
- "HARDWARE_TEST",
- "INJECT_EVENTS",
- "INSTALL_LOCATION_PROVIDER",
- "INSTALL_PACKAGES",
- "INSTALL_SHORTCUT",
- "INTERNAL_SYSTEM_WINDOW",
- "INTERNET",
- "KILL_BACKGROUND_PROCESSES",
- "LOCATION_HARDWARE",
- "MANAGE_ACCOUNTS",
- "MANAGE_APP_TOKENS",
- "MANAGE_DOCUMENTS",
- "MASTER_CLEAR",
- "MEDIA_CONTENT_CONTROL",
- "MODIFY_AUDIO_SETTINGS",
- "MODIFY_PHONE_STATE",
- "MOUNT_FORMAT_FILESYSTEMS",
- "MOUNT_UNMOUNT_FILESYSTEMS",
- "NFC",
- "PERSISTENT_ACTIVITY",
- "PROCESS_OUTGOING_CALLS",
- "READ_CALENDAR",
- "READ_CALL_LOG",
- "READ_CONTACTS",
- "READ_EXTERNAL_STORAGE",
- "READ_FRAME_BUFFER",
- "READ_HISTORY_BOOKMARKS",
- "READ_INPUT_STATE",
- "READ_LOGS",
- "READ_PHONE_STATE",
- "READ_PROFILE",
- "READ_SMS",
- "READ_SOCIAL_STREAM",
- "READ_SYNC_SETTINGS",
- "READ_SYNC_STATS",
- "READ_USER_DICTIONARY",
- "REBOOT",
- "RECEIVE_BOOT_COMPLETED",
- "RECEIVE_MMS",
- "RECEIVE_SMS",
- "RECEIVE_WAP_PUSH",
- "RECORD_AUDIO",
- "REORDER_TASKS",
- "RESTART_PACKAGES",
- "SEND_RESPOND_VIA_MESSAGE",
- "SEND_SMS",
- "SET_ACTIVITY_WATCHER",
- "SET_ALARM",
- "SET_ALWAYS_FINISH",
- "SET_ANIMATION_SCALE",
- "SET_DEBUG_APP",
- "SET_ORIENTATION",
- "SET_POINTER_SPEED",
- "SET_PREFERRED_APPLICATIONS",
- "SET_PROCESS_LIMIT",
- "SET_TIME",
- "SET_TIME_ZONE",
- "SET_WALLPAPER",
- "SET_WALLPAPER_HINTS",
- "SIGNAL_PERSISTENT_PROCESSES",
- "STATUS_BAR",
- "SUBSCRIBED_FEEDS_READ",
- "SUBSCRIBED_FEEDS_WRITE",
- "SYSTEM_ALERT_WINDOW",
- "TRANSMIT_IR",
- "UNINSTALL_SHORTCUT",
- "UPDATE_DEVICE_STATS",
- "USE_CREDENTIALS",
- "USE_SIP",
- "VIBRATE",
- "WAKE_LOCK",
- "WRITE_APN_SETTINGS",
- "WRITE_CALENDAR",
- "WRITE_CALL_LOG",
- "WRITE_CONTACTS",
- "WRITE_EXTERNAL_STORAGE",
- "WRITE_GSERVICES",
- "WRITE_HISTORY_BOOKMARKS",
- "WRITE_PROFILE",
- "WRITE_SECURE_SETTINGS",
- "WRITE_SETTINGS",
- "WRITE_SMS",
- "WRITE_SOCIAL_STREAM",
- "WRITE_SYNC_SETTINGS",
- "WRITE_USER_DICTIONARY",
- nullptr
-};
-
-static const char *SPLASH_IMAGE_EXPORT_PATH = "res/drawable-nodpi/splash.png";
-static const char *LEGACY_BUILD_SPLASH_IMAGE_EXPORT_PATH = "res/drawable-nodpi-v4/splash.png";
-static const char *SPLASH_BG_COLOR_PATH = "res/drawable-nodpi/splash_bg_color.png";
-static const char *LEGACY_BUILD_SPLASH_BG_COLOR_PATH = "res/drawable-nodpi-v4/splash_bg_color.png";
-static const char *SPLASH_CONFIG_PATH = "res://android/build/res/drawable/splash_drawable.xml";
-static const char *GDNATIVE_LIBS_PATH = "res://android/build/libs/gdnativelibs.json";
-
-const String SPLASH_CONFIG_XML_CONTENT = R"SPLASH(<?xml version="1.0" encoding="utf-8"?>
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/splash_bg_color" />
- <item>
- <bitmap
- android:gravity="center"
- android:filter="%s"
- android:src="@drawable/splash" />
- </item>
-</layer-list>
-)SPLASH";
-
-struct LauncherIcon {
- const char *export_path;
- int dimensions = 0;
-};
-
-static const int icon_densities_count = 6;
-static const char *launcher_icon_option = "launcher_icons/main_192x192";
-static const char *launcher_adaptive_icon_foreground_option = "launcher_icons/adaptive_foreground_432x432";
-static const char *launcher_adaptive_icon_background_option = "launcher_icons/adaptive_background_432x432";
-
-static const LauncherIcon launcher_icons[icon_densities_count] = {
- { "res/mipmap-xxxhdpi-v4/icon.png", 192 },
- { "res/mipmap-xxhdpi-v4/icon.png", 144 },
- { "res/mipmap-xhdpi-v4/icon.png", 96 },
- { "res/mipmap-hdpi-v4/icon.png", 72 },
- { "res/mipmap-mdpi-v4/icon.png", 48 },
- { "res/mipmap/icon.png", 192 }
-};
-
-static const LauncherIcon launcher_adaptive_icon_foregrounds[icon_densities_count] = {
- { "res/mipmap-xxxhdpi-v4/icon_foreground.png", 432 },
- { "res/mipmap-xxhdpi-v4/icon_foreground.png", 324 },
- { "res/mipmap-xhdpi-v4/icon_foreground.png", 216 },
- { "res/mipmap-hdpi-v4/icon_foreground.png", 162 },
- { "res/mipmap-mdpi-v4/icon_foreground.png", 108 },
- { "res/mipmap/icon_foreground.png", 432 }
-};
-
-static const LauncherIcon launcher_adaptive_icon_backgrounds[icon_densities_count] = {
- { "res/mipmap-xxxhdpi-v4/icon_background.png", 432 },
- { "res/mipmap-xxhdpi-v4/icon_background.png", 324 },
- { "res/mipmap-xhdpi-v4/icon_background.png", 216 },
- { "res/mipmap-hdpi-v4/icon_background.png", 162 },
- { "res/mipmap-mdpi-v4/icon_background.png", 108 },
- { "res/mipmap/icon_background.png", 432 }
-};
-
-static const int EXPORT_FORMAT_APK = 0;
-static const int EXPORT_FORMAT_AAB = 1;
-
-class EditorExportPlatformAndroid : public EditorExportPlatform {
- GDCLASS(EditorExportPlatformAndroid, EditorExportPlatform);
-
- Ref<ImageTexture> logo;
- Ref<ImageTexture> run_icon;
-
- struct Device {
- String id;
- String name;
- String description;
- int api_level = 0;
- };
-
- struct APKExportData {
- zipFile apk;
- EditorProgress *ep = nullptr;
- };
-
- struct CustomExportData {
- bool debug;
- Vector<String> libs;
- };
-
- Vector<PluginConfigAndroid> plugins;
- String last_plugin_names;
- uint64_t last_custom_build_time = 0;
- SafeFlag plugins_changed;
- Mutex plugins_lock;
- Vector<Device> devices;
- SafeFlag devices_changed;
- Mutex device_lock;
- Thread check_for_changes_thread;
- SafeFlag quit_request;
-
- static void _check_for_changes_poll_thread(void *ud) {
- EditorExportPlatformAndroid *ea = (EditorExportPlatformAndroid *)ud;
-
- while (!ea->quit_request.is_set()) {
- // Check for plugins updates
- {
- // Nothing to do if we already know the plugins have changed.
- if (!ea->plugins_changed.is_set()) {
- Vector<PluginConfigAndroid> loaded_plugins = get_plugins();
-
- MutexLock lock(ea->plugins_lock);
-
- if (ea->plugins.size() != loaded_plugins.size()) {
- ea->plugins_changed.set();
- } else {
- for (int i = 0; i < ea->plugins.size(); i++) {
- if (ea->plugins[i].name != loaded_plugins[i].name) {
- ea->plugins_changed.set();
- break;
- }
- }
- }
-
- if (ea->plugins_changed.is_set()) {
- ea->plugins = loaded_plugins;
- }
- }
- }
-
- // Check for devices updates
- String adb = get_adb_path();
- if (FileAccess::exists(adb)) {
- String devices;
- List<String> args;
- args.push_back("devices");
- int ec;
- OS::get_singleton()->execute(adb, args, &devices, &ec);
-
- Vector<String> ds = devices.split("\n");
- Vector<String> ldevices;
- for (int i = 1; i < ds.size(); i++) {
- String d = ds[i];
- int dpos = d.find("device");
- if (dpos == -1) {
- continue;
- }
- d = d.substr(0, dpos).strip_edges();
- ldevices.push_back(d);
- }
-
- MutexLock lock(ea->device_lock);
-
- bool different = false;
-
- if (ea->devices.size() != ldevices.size()) {
- different = true;
- } else {
- for (int i = 0; i < ea->devices.size(); i++) {
- if (ea->devices[i].id != ldevices[i]) {
- different = true;
- break;
- }
- }
- }
-
- if (different) {
- Vector<Device> ndevices;
-
- for (int i = 0; i < ldevices.size(); i++) {
- Device d;
- d.id = ldevices[i];
- for (int j = 0; j < ea->devices.size(); j++) {
- if (ea->devices[j].id == ldevices[i]) {
- d.description = ea->devices[j].description;
- d.name = ea->devices[j].name;
- d.api_level = ea->devices[j].api_level;
- }
- }
-
- if (d.description == "") {
- //in the oven, request!
- args.clear();
- args.push_back("-s");
- args.push_back(d.id);
- args.push_back("shell");
- args.push_back("getprop");
- int ec2;
- String dp;
-
- OS::get_singleton()->execute(adb, args, &dp, &ec2);
-
- Vector<String> props = dp.split("\n");
- String vendor;
- String device;
- d.description = "Device ID: " + d.id + "\n";
- d.api_level = 0;
- for (int j = 0; j < props.size(); j++) {
- // got information by `shell cat /system/build.prop` before and its format is "property=value"
- // it's now changed to use `shell getporp` because of permission issue with Android 8.0 and above
- // its format is "[property]: [value]" so changed it as like build.prop
- String p = props[j];
- p = p.replace("]: ", "=");
- p = p.replace("[", "");
- p = p.replace("]", "");
-
- if (p.begins_with("ro.product.model=")) {
- device = p.get_slice("=", 1).strip_edges();
- } else if (p.begins_with("ro.product.brand=")) {
- vendor = p.get_slice("=", 1).strip_edges().capitalize();
- } else if (p.begins_with("ro.build.display.id=")) {
- d.description += "Build: " + p.get_slice("=", 1).strip_edges() + "\n";
- } else if (p.begins_with("ro.build.version.release=")) {
- d.description += "Release: " + p.get_slice("=", 1).strip_edges() + "\n";
- } else if (p.begins_with("ro.build.version.sdk=")) {
- d.api_level = p.get_slice("=", 1).to_int();
- } else if (p.begins_with("ro.product.cpu.abi=")) {
- d.description += "CPU: " + p.get_slice("=", 1).strip_edges() + "\n";
- } else if (p.begins_with("ro.product.manufacturer=")) {
- d.description += "Manufacturer: " + p.get_slice("=", 1).strip_edges() + "\n";
- } else if (p.begins_with("ro.board.platform=")) {
- d.description += "Chipset: " + p.get_slice("=", 1).strip_edges() + "\n";
- } else if (p.begins_with("ro.opengles.version=")) {
- uint32_t opengl = p.get_slice("=", 1).to_int();
- d.description += "OpenGL: " + itos(opengl >> 16) + "." + itos((opengl >> 8) & 0xFF) + "." + itos((opengl)&0xFF) + "\n";
- }
- }
-
- d.name = vendor + " " + device;
- if (device == String()) {
- continue;
- }
- }
-
- ndevices.push_back(d);
- }
-
- ea->devices = ndevices;
- ea->devices_changed.set();
- }
- }
-
- uint64_t sleep = 200;
- uint64_t wait = 3000000;
- uint64_t time = OS::get_singleton()->get_ticks_usec();
- while (OS::get_singleton()->get_ticks_usec() - time < wait) {
- OS::get_singleton()->delay_usec(1000 * sleep);
- if (ea->quit_request.is_set()) {
- break;
- }
- }
- }
-
- if (EditorSettings::get_singleton()->get("export/android/shutdown_adb_on_exit")) {
- String adb = get_adb_path();
- if (!FileAccess::exists(adb)) {
- return; //adb not configured
- }
-
- List<String> args;
- args.push_back("kill-server");
- OS::get_singleton()->execute(adb, args);
- };
- }
-
- String get_project_name(const String &p_name) const {
- String aname;
- if (p_name != "") {
- aname = p_name;
- } else {
- aname = ProjectSettings::get_singleton()->get("application/config/name");
- }
-
- if (aname == "") {
- aname = VERSION_NAME;
- }
-
- return aname;
- }
-
- String get_package_name(const String &p_package) const {
- String pname = p_package;
- String basename = ProjectSettings::get_singleton()->get("application/config/name");
- basename = basename.to_lower();
-
- String name;
- bool first = true;
- for (int i = 0; i < basename.length(); i++) {
- char32_t c = basename[i];
- if (c >= '0' && c <= '9' && first) {
- continue;
- }
- if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) {
- name += String::chr(c);
- first = false;
- }
- }
- if (name == "") {
- name = "noname";
- }
-
- pname = pname.replace("$genname", name);
-
- return pname;
- }
-
- bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const {
- String pname = p_package;
-
- if (pname.length() == 0) {
- if (r_error) {
- *r_error = TTR("Package name is missing.");
- }
- return false;
- }
-
- int segments = 0;
- bool first = true;
- for (int i = 0; i < pname.length(); i++) {
- char32_t c = pname[i];
- if (first && c == '.') {
- if (r_error) {
- *r_error = TTR("Package segments must be of non-zero length.");
- }
- return false;
- }
- if (c == '.') {
- segments++;
- first = true;
- continue;
- }
- if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')) {
- if (r_error) {
- *r_error = vformat(TTR("The character '%s' is not allowed in Android application package names."), String::chr(c));
- }
- return false;
- }
- if (first && (c >= '0' && c <= '9')) {
- if (r_error) {
- *r_error = TTR("A digit cannot be the first character in a package segment.");
- }
- return false;
- }
- if (first && c == '_') {
- if (r_error) {
- *r_error = vformat(TTR("The character '%s' cannot be the first character in a package segment."), String::chr(c));
- }
- return false;
- }
- first = false;
- }
-
- if (segments == 0) {
- if (r_error) {
- *r_error = TTR("The package must have at least one '.' separator.");
- }
- return false;
- }
-
- if (first) {
- if (r_error) {
- *r_error = TTR("Package segments must be of non-zero length.");
- }
- return false;
- }
-
- return true;
- }
-
- static bool _should_compress_asset(const String &p_path, const Vector<uint8_t> &p_data) {
- /*
- * By not compressing files with little or not benefit in doing so,
- * a performance gain is expected attime. Moreover, if the APK is
- * zip-aligned, assets stored as they are can be efficiently read by
- * Android by memory-mapping them.
- */
-
- // -- Unconditional uncompress to mimic AAPT plus some other
-
- static const char *unconditional_compress_ext[] = {
- // From https://github.com/android/platform_frameworks_base/blob/master/tools/aapt/Package.cpp
- // These formats are already compressed, or don't compress well:
- ".jpg", ".jpeg", ".png", ".gif",
- ".wav", ".mp2", ".mp3", ".ogg", ".aac",
- ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet",
- ".rtttl", ".imy", ".xmf", ".mp4", ".m4a",
- ".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2",
- ".amr", ".awb", ".wma", ".wmv",
- // Godot-specific:
- ".webp", // Same reasoning as .png
- ".cfb", // Don't let small config files slow-down startup
- ".scn", // Binary scenes are usually already compressed
- ".stex", // Streamable textures are usually already compressed
- // Trailer for easier processing
- nullptr
- };
-
- for (const char **ext = unconditional_compress_ext; *ext; ++ext) {
- if (p_path.to_lower().ends_with(String(*ext))) {
- return false;
- }
- }
-
- // -- Compressed resource?
-
- if (p_data.size() >= 4 && p_data[0] == 'R' && p_data[1] == 'S' && p_data[2] == 'C' && p_data[3] == 'C') {
- // Already compressed
- return false;
- }
-
- // --- TODO: Decide on texture resources according to their image compression setting
-
- return true;
- }
-
- static zip_fileinfo get_zip_fileinfo() {
- OS::Time time = OS::get_singleton()->get_time();
- OS::Date date = OS::get_singleton()->get_date();
-
- zip_fileinfo zipfi;
- zipfi.tmz_date.tm_hour = time.hour;
- zipfi.tmz_date.tm_mday = date.day;
- zipfi.tmz_date.tm_min = time.minute;
- zipfi.tmz_date.tm_mon = date.month - 1; // tm_mon is zero indexed
- zipfi.tmz_date.tm_sec = time.second;
- zipfi.tmz_date.tm_year = date.year;
- zipfi.dosDate = 0;
- zipfi.external_fa = 0;
- zipfi.internal_fa = 0;
-
- return zipfi;
- }
-
- static Vector<String> get_abis() {
- Vector<String> abis;
- abis.push_back("armeabi-v7a");
- abis.push_back("arm64-v8a");
- abis.push_back("x86");
- abis.push_back("x86_64");
- return abis;
- }
-
- /// List the gdap files in the directory specified by the p_path parameter.
- static Vector<String> list_gdap_files(const String &p_path) {
- Vector<String> dir_files;
- DirAccessRef da = DirAccess::open(p_path);
- if (da) {
- da->list_dir_begin();
- while (true) {
- String file = da->get_next();
- if (file == "") {
- break;
- }
-
- if (da->current_is_dir() || da->current_is_hidden()) {
- continue;
- }
-
- if (file.ends_with(PluginConfigAndroid::PLUGIN_CONFIG_EXT)) {
- dir_files.push_back(file);
- }
- }
- da->list_dir_end();
- }
-
- return dir_files;
- }
-
- static Vector<PluginConfigAndroid> get_plugins() {
- Vector<PluginConfigAndroid> loaded_plugins;
-
- String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/plugins");
-
- // Add the prebuilt plugins
- loaded_plugins.append_array(get_prebuilt_plugins(plugins_dir));
-
- if (DirAccess::exists(plugins_dir)) {
- Vector<String> plugins_filenames = list_gdap_files(plugins_dir);
-
- if (!plugins_filenames.is_empty()) {
- Ref<ConfigFile> config_file = memnew(ConfigFile);
- for (int i = 0; i < plugins_filenames.size(); i++) {
- PluginConfigAndroid config = load_plugin_config(config_file, plugins_dir.plus_file(plugins_filenames[i]));
- if (config.valid_config) {
- loaded_plugins.push_back(config);
- } else {
- print_error("Invalid plugin config file " + plugins_filenames[i]);
- }
- }
- }
- }
-
- return loaded_plugins;
- }
-
- static Vector<PluginConfigAndroid> get_enabled_plugins(const Ref<EditorExportPreset> &p_presets) {
- Vector<PluginConfigAndroid> enabled_plugins;
- Vector<PluginConfigAndroid> all_plugins = get_plugins();
- for (int i = 0; i < all_plugins.size(); i++) {
- PluginConfigAndroid plugin = all_plugins[i];
- bool enabled = p_presets->get("plugins/" + plugin.name);
- if (enabled) {
- enabled_plugins.push_back(plugin);
- }
- }
-
- return enabled_plugins;
- }
-
- static Error store_in_apk(APKExportData *ed, const String &p_path, const Vector<uint8_t> &p_data, int compression_method = Z_DEFLATED) {
- zip_fileinfo zipfi = get_zip_fileinfo();
- zipOpenNewFileInZip(ed->apk,
- p_path.utf8().get_data(),
- &zipfi,
- nullptr,
- 0,
- nullptr,
- 0,
- nullptr,
- compression_method,
- Z_DEFAULT_COMPRESSION);
-
- zipWriteInFileInZip(ed->apk, p_data.ptr(), p_data.size());
- zipCloseFileInZip(ed->apk);
-
- return OK;
- }
-
- static Error save_apk_so(void *p_userdata, const SharedObject &p_so) {
- if (!p_so.path.get_file().begins_with("lib")) {
- String err = "Android .so file names must start with \"lib\", but got: " + p_so.path;
- ERR_PRINT(err);
- return FAILED;
- }
- APKExportData *ed = (APKExportData *)p_userdata;
- Vector<String> abis = get_abis();
- bool exported = false;
- for (int i = 0; i < p_so.tags.size(); ++i) {
- // shared objects can be fat (compatible with multiple ABIs)
- int abi_index = abis.find(p_so.tags[i]);
- if (abi_index != -1) {
- exported = true;
- String abi = abis[abi_index];
- String dst_path = String("lib").plus_file(abi).plus_file(p_so.path.get_file());
- Vector<uint8_t> array = FileAccess::get_file_as_array(p_so.path);
- Error store_err = store_in_apk(ed, dst_path, array);
- ERR_FAIL_COND_V_MSG(store_err, store_err, "Cannot store in apk file '" + dst_path + "'.");
- }
- }
- if (!exported) {
- String abis_string = String(" ").join(abis);
- String err = "Cannot determine ABI for library \"" + p_so.path + "\". One of the supported ABIs must be used as a tag: " + abis_string;
- ERR_PRINT(err);
- return FAILED;
- }
- return OK;
- }
-
- static Error save_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
- APKExportData *ed = (APKExportData *)p_userdata;
- String dst_path = p_path.replace_first("res://", "assets/");
-
- store_in_apk(ed, dst_path, p_data, _should_compress_asset(p_path, p_data) ? Z_DEFLATED : 0);
- return OK;
- }
-
- static Error ignore_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
- return OK;
- }
-
- static Error copy_gradle_so(void *p_userdata, const SharedObject &p_so) {
- ERR_FAIL_COND_V_MSG(!p_so.path.get_file().begins_with("lib"), FAILED,
- "Android .so file names must start with \"lib\", but got: " + p_so.path);
- Vector<String> abis = get_abis();
- CustomExportData *export_data = (CustomExportData *)p_userdata;
- bool exported = false;
- for (int i = 0; i < p_so.tags.size(); ++i) {
- int abi_index = abis.find(p_so.tags[i]);
- if (abi_index != -1) {
- exported = true;
- String base = "res://android/build/libs";
- String type = export_data->debug ? "debug" : "release";
- String abi = abis[abi_index];
- String filename = p_so.path.get_file();
- String dst_path = base.plus_file(type).plus_file(abi).plus_file(filename);
- Vector<uint8_t> data = FileAccess::get_file_as_array(p_so.path);
- print_verbose("Copying .so file from " + p_so.path + " to " + dst_path);
- Error err = store_file_at_path(dst_path, data);
- ERR_FAIL_COND_V_MSG(err, err, "Failed to copy .so file from " + p_so.path + " to " + dst_path);
- export_data->libs.push_back(dst_path);
- }
- }
- ERR_FAIL_COND_V_MSG(!exported, FAILED,
- "Cannot determine ABI for library \"" + p_so.path + "\". One of the supported ABIs must be used as a tag: " + String(" ").join(abis));
- return OK;
- }
-
- void _get_permissions(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, Vector<String> &r_permissions) {
- const char **aperms = android_perms;
- while (*aperms) {
- bool enabled = p_preset->get("permissions/" + String(*aperms).to_lower());
- if (enabled) {
- r_permissions.push_back("android.permission." + String(*aperms));
- }
- aperms++;
- }
- PackedStringArray user_perms = p_preset->get("permissions/custom_permissions");
- for (int i = 0; i < user_perms.size(); i++) {
- String user_perm = user_perms[i].strip_edges();
- if (!user_perm.is_empty()) {
- r_permissions.push_back(user_perm);
- }
- }
- if (p_give_internet) {
- if (r_permissions.find("android.permission.INTERNET") == -1) {
- r_permissions.push_back("android.permission.INTERNET");
- }
- }
-
- int xr_mode_index = p_preset->get("xr_features/xr_mode");
- if (xr_mode_index == 1 /* XRMode.OVR */) {
- int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
- if (hand_tracking_index > 0) {
- if (r_permissions.find("com.oculus.permission.HAND_TRACKING") == -1) {
- r_permissions.push_back("com.oculus.permission.HAND_TRACKING");
- }
- }
- }
- }
-
- void _write_tmp_manifest(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, bool p_debug) {
- print_verbose("Building temporary manifest..");
- String manifest_text =
- "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
- "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
- " xmlns:tools=\"http://schemas.android.com/tools\">\n";
-
- manifest_text += _get_screen_sizes_tag(p_preset);
- manifest_text += _get_gles_tag();
-
- Vector<String> perms;
- _get_permissions(p_preset, p_give_internet, perms);
- for (int i = 0; i < perms.size(); i++) {
- manifest_text += vformat(" <uses-permission android:name=\"%s\" />\n", perms.get(i));
- }
-
- manifest_text += _get_xr_features_tag(p_preset);
- manifest_text += _get_instrumentation_tag(p_preset);
- manifest_text += _get_application_tag(p_preset);
- manifest_text += "</manifest>\n";
- String manifest_path = vformat("res://android/build/src/%s/AndroidManifest.xml", (p_debug ? "debug" : "release"));
-
- print_verbose("Storing manifest into " + manifest_path + ": " + "\n" + manifest_text);
- store_string_at_path(manifest_path, manifest_text);
- }
-
- void _fix_manifest(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_manifest, bool p_give_internet) {
- // Leaving the unused types commented because looking these constants up
- // again later would be annoying
- // const int CHUNK_AXML_FILE = 0x00080003;
- // const int CHUNK_RESOURCEIDS = 0x00080180;
- const int CHUNK_STRINGS = 0x001C0001;
- // const int CHUNK_XML_END_NAMESPACE = 0x00100101;
- const int CHUNK_XML_END_TAG = 0x00100103;
- // const int CHUNK_XML_START_NAMESPACE = 0x00100100;
- const int CHUNK_XML_START_TAG = 0x00100102;
- // const int CHUNK_XML_TEXT = 0x00100104;
- const int UTF8_FLAG = 0x00000100;
-
- Vector<String> string_table;
-
- uint32_t ofs = 8;
-
- uint32_t string_count = 0;
- //uint32_t styles_count = 0;
- uint32_t string_flags = 0;
- uint32_t string_data_offset = 0;
-
- //uint32_t styles_offset = 0;
- uint32_t string_table_begins = 0;
- uint32_t string_table_ends = 0;
- Vector<uint8_t> stable_extra;
-
- String version_name = p_preset->get("version/name");
- int version_code = p_preset->get("version/code");
- String package_name = p_preset->get("package/unique_name");
-
- const int screen_orientation =
- _get_android_orientation_value(DisplayServer::ScreenOrientation(int(GLOBAL_GET("display/window/handheld/orientation"))));
-
- bool screen_support_small = p_preset->get("screen/support_small");
- bool screen_support_normal = p_preset->get("screen/support_normal");
- bool screen_support_large = p_preset->get("screen/support_large");
- bool screen_support_xlarge = p_preset->get("screen/support_xlarge");
-
- int xr_mode_index = p_preset->get("xr_features/xr_mode");
-
- bool backup_allowed = p_preset->get("user_data_backup/allow");
- bool classify_as_game = p_preset->get("package/classify_as_game");
-
- Vector<String> perms;
- // Write permissions into the perms variable.
- _get_permissions(p_preset, p_give_internet, perms);
-
- while (ofs < (uint32_t)p_manifest.size()) {
- uint32_t chunk = decode_uint32(&p_manifest[ofs]);
- uint32_t size = decode_uint32(&p_manifest[ofs + 4]);
-
- switch (chunk) {
- case CHUNK_STRINGS: {
- int iofs = ofs + 8;
-
- string_count = decode_uint32(&p_manifest[iofs]);
- //styles_count = decode_uint32(&p_manifest[iofs + 4]);
- string_flags = decode_uint32(&p_manifest[iofs + 8]);
- string_data_offset = decode_uint32(&p_manifest[iofs + 12]);
- //styles_offset = decode_uint32(&p_manifest[iofs + 16]);
- /*
- printf("string count: %i\n",string_count);
- printf("flags: %i\n",string_flags);
- printf("sdata ofs: %i\n",string_data_offset);
- printf("styles ofs: %i\n",styles_offset);
- */
- uint32_t st_offset = iofs + 20;
- string_table.resize(string_count);
- uint32_t string_end = 0;
-
- string_table_begins = st_offset;
-
- for (uint32_t i = 0; i < string_count; i++) {
- uint32_t string_at = decode_uint32(&p_manifest[st_offset + i * 4]);
- string_at += st_offset + string_count * 4;
-
- ERR_FAIL_COND_MSG(string_flags & UTF8_FLAG, "Unimplemented, can't read UTF-8 string table.");
-
- if (string_flags & UTF8_FLAG) {
- } else {
- uint32_t len = decode_uint16(&p_manifest[string_at]);
- Vector<char32_t> ucstring;
- ucstring.resize(len + 1);
- for (uint32_t j = 0; j < len; j++) {
- uint16_t c = decode_uint16(&p_manifest[string_at + 2 + 2 * j]);
- ucstring.write[j] = c;
- }
- string_end = MAX(string_at + 2 + 2 * len, string_end);
- ucstring.write[len] = 0;
- string_table.write[i] = ucstring.ptr();
- }
- }
-
- for (uint32_t i = string_end; i < (ofs + size); i++) {
- stable_extra.push_back(p_manifest[i]);
- }
-
- string_table_ends = ofs + size;
-
- } break;
- case CHUNK_XML_START_TAG: {
- int iofs = ofs + 8;
- uint32_t name = decode_uint32(&p_manifest[iofs + 12]);
-
- String tname = string_table[name];
- uint32_t attrcount = decode_uint32(&p_manifest[iofs + 20]);
- iofs += 28;
-
- for (uint32_t i = 0; i < attrcount; i++) {
- uint32_t attr_nspace = decode_uint32(&p_manifest[iofs]);
- uint32_t attr_name = decode_uint32(&p_manifest[iofs + 4]);
- uint32_t attr_value = decode_uint32(&p_manifest[iofs + 8]);
- uint32_t attr_resid = decode_uint32(&p_manifest[iofs + 16]);
-
- const String value = (attr_value != 0xFFFFFFFF) ? string_table[attr_value] : "Res #" + itos(attr_resid);
- String attrname = string_table[attr_name];
- const String nspace = (attr_nspace != 0xFFFFFFFF) ? string_table[attr_nspace] : "";
-
- //replace project information
- if (tname == "manifest" && attrname == "package") {
- string_table.write[attr_value] = get_package_name(package_name);
- }
-
- if (tname == "manifest" && attrname == "versionCode") {
- encode_uint32(version_code, &p_manifest.write[iofs + 16]);
- }
-
- if (tname == "manifest" && attrname == "versionName") {
- if (attr_value == 0xFFFFFFFF) {
- WARN_PRINT("Version name in a resource, should be plain text");
- } else {
- string_table.write[attr_value] = version_name;
- }
- }
-
- if (tname == "application" && attrname == "allowBackup") {
- encode_uint32(backup_allowed, &p_manifest.write[iofs + 16]);
- }
-
- if (tname == "application" && attrname == "isGame") {
- encode_uint32(classify_as_game, &p_manifest.write[iofs + 16]);
- }
-
- if (tname == "instrumentation" && attrname == "targetPackage") {
- string_table.write[attr_value] = get_package_name(package_name);
- }
-
- if (tname == "activity" && attrname == "screenOrientation") {
- encode_uint32(screen_orientation, &p_manifest.write[iofs + 16]);
- }
-
- if (tname == "supports-screens") {
- if (attrname == "smallScreens") {
- encode_uint32(screen_support_small ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]);
-
- } else if (attrname == "normalScreens") {
- encode_uint32(screen_support_normal ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]);
-
- } else if (attrname == "largeScreens") {
- encode_uint32(screen_support_large ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]);
-
- } else if (attrname == "xlargeScreens") {
- encode_uint32(screen_support_xlarge ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]);
- }
- }
-
- iofs += 20;
- }
-
- } break;
- case CHUNK_XML_END_TAG: {
- int iofs = ofs + 8;
- uint32_t name = decode_uint32(&p_manifest[iofs + 12]);
- String tname = string_table[name];
-
- if (tname == "uses-feature") {
- Vector<String> feature_names;
- Vector<bool> feature_required_list;
- Vector<int> feature_versions;
-
- if (xr_mode_index == 1 /* XRMode.OVR */) {
- // Check for hand tracking
- int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
- if (hand_tracking_index > 0) {
- feature_names.push_back("oculus.software.handtracking");
- feature_required_list.push_back(hand_tracking_index == 2);
- feature_versions.push_back(-1); // no version attribute should be added.
- }
- }
-
- if (feature_names.size() > 0) {
- ofs += 24; // skip over end tag
-
- // save manifest ending so we can restore it
- Vector<uint8_t> manifest_end;
- uint32_t manifest_cur_size = p_manifest.size();
-
- manifest_end.resize(p_manifest.size() - ofs);
- memcpy(manifest_end.ptrw(), &p_manifest[ofs], manifest_end.size());
-
- int32_t attr_name_string = string_table.find("name");
- ERR_FAIL_COND_MSG(attr_name_string == -1, "Template does not have 'name' attribute.");
-
- int32_t ns_android_string = string_table.find("http://schemas.android.com/apk/res/android");
- if (ns_android_string == -1) {
- string_table.push_back("http://schemas.android.com/apk/res/android");
- ns_android_string = string_table.size() - 1;
- }
-
- int32_t attr_uses_feature_string = string_table.find("uses-feature");
- if (attr_uses_feature_string == -1) {
- string_table.push_back("uses-feature");
- attr_uses_feature_string = string_table.size() - 1;
- }
-
- int32_t attr_required_string = string_table.find("required");
- if (attr_required_string == -1) {
- string_table.push_back("required");
- attr_required_string = string_table.size() - 1;
- }
-
- for (int i = 0; i < feature_names.size(); i++) {
- String feature_name = feature_names[i];
- bool feature_required = feature_required_list[i];
- int feature_version = feature_versions[i];
- bool has_version_attribute = feature_version != -1;
-
- print_line("Adding feature " + feature_name);
-
- int32_t feature_string = string_table.find(feature_name);
- if (feature_string == -1) {
- string_table.push_back(feature_name);
- feature_string = string_table.size() - 1;
- }
-
- String required_value_string = feature_required ? "true" : "false";
- int32_t required_value = string_table.find(required_value_string);
- if (required_value == -1) {
- string_table.push_back(required_value_string);
- required_value = string_table.size() - 1;
- }
-
- int32_t attr_version_string = -1;
- int32_t version_value = -1;
- int tag_size;
- int attr_count;
- if (has_version_attribute) {
- attr_version_string = string_table.find("version");
- if (attr_version_string == -1) {
- string_table.push_back("version");
- attr_version_string = string_table.size() - 1;
- }
-
- version_value = string_table.find(itos(feature_version));
- if (version_value == -1) {
- string_table.push_back(itos(feature_version));
- version_value = string_table.size() - 1;
- }
-
- tag_size = 96; // node and three attrs + end node
- attr_count = 3;
- } else {
- tag_size = 76; // node and two attrs + end node
- attr_count = 2;
- }
- manifest_cur_size += tag_size + 24;
- p_manifest.resize(manifest_cur_size);
-
- // start tag
- encode_uint16(0x102, &p_manifest.write[ofs]); // type
- encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize
- encode_uint32(tag_size, &p_manifest.write[ofs + 4]); // size
- encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno
- encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment
- encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns
- encode_uint32(attr_uses_feature_string, &p_manifest.write[ofs + 20]); // name
- encode_uint16(20, &p_manifest.write[ofs + 24]); // attr_start
- encode_uint16(20, &p_manifest.write[ofs + 26]); // attr_size
- encode_uint16(attr_count, &p_manifest.write[ofs + 28]); // num_attrs
- encode_uint16(0, &p_manifest.write[ofs + 30]); // id_index
- encode_uint16(0, &p_manifest.write[ofs + 32]); // class_index
- encode_uint16(0, &p_manifest.write[ofs + 34]); // style_index
-
- // android:name attribute
- encode_uint32(ns_android_string, &p_manifest.write[ofs + 36]); // ns
- encode_uint32(attr_name_string, &p_manifest.write[ofs + 40]); // 'name'
- encode_uint32(feature_string, &p_manifest.write[ofs + 44]); // raw_value
- encode_uint16(8, &p_manifest.write[ofs + 48]); // typedvalue_size
- p_manifest.write[ofs + 50] = 0; // typedvalue_always0
- p_manifest.write[ofs + 51] = 0x03; // typedvalue_type (string)
- encode_uint32(feature_string, &p_manifest.write[ofs + 52]); // typedvalue reference
-
- // android:required attribute
- encode_uint32(ns_android_string, &p_manifest.write[ofs + 56]); // ns
- encode_uint32(attr_required_string, &p_manifest.write[ofs + 60]); // 'name'
- encode_uint32(required_value, &p_manifest.write[ofs + 64]); // raw_value
- encode_uint16(8, &p_manifest.write[ofs + 68]); // typedvalue_size
- p_manifest.write[ofs + 70] = 0; // typedvalue_always0
- p_manifest.write[ofs + 71] = 0x03; // typedvalue_type (string)
- encode_uint32(required_value, &p_manifest.write[ofs + 72]); // typedvalue reference
-
- ofs += 76;
-
- if (has_version_attribute) {
- // android:version attribute
- encode_uint32(ns_android_string, &p_manifest.write[ofs]); // ns
- encode_uint32(attr_version_string, &p_manifest.write[ofs + 4]); // 'name'
- encode_uint32(version_value, &p_manifest.write[ofs + 8]); // raw_value
- encode_uint16(8, &p_manifest.write[ofs + 12]); // typedvalue_size
- p_manifest.write[ofs + 14] = 0; // typedvalue_always0
- p_manifest.write[ofs + 15] = 0x03; // typedvalue_type (string)
- encode_uint32(version_value, &p_manifest.write[ofs + 16]); // typedvalue reference
-
- ofs += 20;
- }
-
- // end tag
- encode_uint16(0x103, &p_manifest.write[ofs]); // type
- encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize
- encode_uint32(24, &p_manifest.write[ofs + 4]); // size
- encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno
- encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment
- encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns
- encode_uint32(attr_uses_feature_string, &p_manifest.write[ofs + 20]); // name
-
- ofs += 24;
- }
- memcpy(&p_manifest.write[ofs], manifest_end.ptr(), manifest_end.size());
- ofs -= 24; // go back over back end
- }
- }
- if (tname == "manifest") {
- // save manifest ending so we can restore it
- Vector<uint8_t> manifest_end;
- uint32_t manifest_cur_size = p_manifest.size();
-
- manifest_end.resize(p_manifest.size() - ofs);
- memcpy(manifest_end.ptrw(), &p_manifest[ofs], manifest_end.size());
-
- int32_t attr_name_string = string_table.find("name");
- ERR_FAIL_COND_MSG(attr_name_string == -1, "Template does not have 'name' attribute.");
-
- int32_t ns_android_string = string_table.find("android");
- ERR_FAIL_COND_MSG(ns_android_string == -1, "Template does not have 'android' namespace.");
-
- int32_t attr_uses_permission_string = string_table.find("uses-permission");
- if (attr_uses_permission_string == -1) {
- string_table.push_back("uses-permission");
- attr_uses_permission_string = string_table.size() - 1;
- }
-
- for (int i = 0; i < perms.size(); ++i) {
- print_line("Adding permission " + perms[i]);
-
- manifest_cur_size += 56 + 24; // node + end node
- p_manifest.resize(manifest_cur_size);
-
- // Add permission to the string pool
- int32_t perm_string = string_table.find(perms[i]);
- if (perm_string == -1) {
- string_table.push_back(perms[i]);
- perm_string = string_table.size() - 1;
- }
-
- // start tag
- encode_uint16(0x102, &p_manifest.write[ofs]); // type
- encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize
- encode_uint32(56, &p_manifest.write[ofs + 4]); // size
- encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno
- encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment
- encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns
- encode_uint32(attr_uses_permission_string, &p_manifest.write[ofs + 20]); // name
- encode_uint16(20, &p_manifest.write[ofs + 24]); // attr_start
- encode_uint16(20, &p_manifest.write[ofs + 26]); // attr_size
- encode_uint16(1, &p_manifest.write[ofs + 28]); // num_attrs
- encode_uint16(0, &p_manifest.write[ofs + 30]); // id_index
- encode_uint16(0, &p_manifest.write[ofs + 32]); // class_index
- encode_uint16(0, &p_manifest.write[ofs + 34]); // style_index
-
- // attribute
- encode_uint32(ns_android_string, &p_manifest.write[ofs + 36]); // ns
- encode_uint32(attr_name_string, &p_manifest.write[ofs + 40]); // 'name'
- encode_uint32(perm_string, &p_manifest.write[ofs + 44]); // raw_value
- encode_uint16(8, &p_manifest.write[ofs + 48]); // typedvalue_size
- p_manifest.write[ofs + 50] = 0; // typedvalue_always0
- p_manifest.write[ofs + 51] = 0x03; // typedvalue_type (string)
- encode_uint32(perm_string, &p_manifest.write[ofs + 52]); // typedvalue reference
-
- ofs += 56;
-
- // end tag
- encode_uint16(0x103, &p_manifest.write[ofs]); // type
- encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize
- encode_uint32(24, &p_manifest.write[ofs + 4]); // size
- encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno
- encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment
- encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns
- encode_uint32(attr_uses_permission_string, &p_manifest.write[ofs + 20]); // name
-
- ofs += 24;
- }
-
- // copy footer back in
- memcpy(&p_manifest.write[ofs], manifest_end.ptr(), manifest_end.size());
- }
- } break;
- }
-
- ofs += size;
- }
-
- //create new andriodmanifest binary
-
- Vector<uint8_t> ret;
- ret.resize(string_table_begins + string_table.size() * 4);
-
- for (uint32_t i = 0; i < string_table_begins; i++) {
- ret.write[i] = p_manifest[i];
- }
-
- ofs = 0;
- for (int i = 0; i < string_table.size(); i++) {
- encode_uint32(ofs, &ret.write[string_table_begins + i * 4]);
- ofs += string_table[i].length() * 2 + 2 + 2;
- }
-
- ret.resize(ret.size() + ofs);
- string_data_offset = ret.size() - ofs;
- uint8_t *chars = &ret.write[string_data_offset];
- for (int i = 0; i < string_table.size(); i++) {
- String s = string_table[i];
- encode_uint16(s.length(), chars);
- chars += 2;
- for (int j = 0; j < s.length(); j++) {
- encode_uint16(s[j], chars);
- chars += 2;
- }
- encode_uint16(0, chars);
- chars += 2;
- }
-
- for (int i = 0; i < stable_extra.size(); i++) {
- ret.push_back(stable_extra[i]);
- }
-
- //pad
- while (ret.size() % 4) {
- ret.push_back(0);
- }
-
- uint32_t new_stable_end = ret.size();
-
- uint32_t extra = (p_manifest.size() - string_table_ends);
- ret.resize(new_stable_end + extra);
- for (uint32_t i = 0; i < extra; i++) {
- ret.write[new_stable_end + i] = p_manifest[string_table_ends + i];
- }
-
- while (ret.size() % 4) {
- ret.push_back(0);
- }
- encode_uint32(ret.size(), &ret.write[4]); //update new file size
-
- encode_uint32(new_stable_end - 8, &ret.write[12]); //update new string table size
- encode_uint32(string_table.size(), &ret.write[16]); //update new number of strings
- encode_uint32(string_data_offset - 8, &ret.write[28]); //update new string data offset
-
- p_manifest = ret;
- }
-
- static String _parse_string(const uint8_t *p_bytes, bool p_utf8) {
- uint32_t offset = 0;
- uint32_t len = 0;
-
- if (p_utf8) {
- uint8_t byte = p_bytes[offset];
- if (byte & 0x80) {
- offset += 2;
- } else {
- offset += 1;
- }
- byte = p_bytes[offset];
- offset++;
- if (byte & 0x80) {
- len = byte & 0x7F;
- len = (len << 8) + p_bytes[offset];
- offset++;
- } else {
- len = byte;
- }
- } else {
- len = decode_uint16(&p_bytes[offset]);
- offset += 2;
- if (len & 0x8000) {
- len &= 0x7FFF;
- len = (len << 16) + decode_uint16(&p_bytes[offset]);
- offset += 2;
- }
- }
-
- if (p_utf8) {
- Vector<uint8_t> str8;
- str8.resize(len + 1);
- for (uint32_t i = 0; i < len; i++) {
- str8.write[i] = p_bytes[offset + i];
- }
- str8.write[len] = 0;
- String str;
- str.parse_utf8((const char *)str8.ptr());
- return str;
- } else {
- String str;
- for (uint32_t i = 0; i < len; i++) {
- char32_t c = decode_uint16(&p_bytes[offset + i * 2]);
- if (c == 0) {
- break;
- }
- str += String::chr(c);
- }
- return str;
- }
- }
-
- void _fix_resources(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &r_manifest) {
- const int UTF8_FLAG = 0x00000100;
-
- uint32_t string_block_len = decode_uint32(&r_manifest[16]);
- uint32_t string_count = decode_uint32(&r_manifest[20]);
- uint32_t string_flags = decode_uint32(&r_manifest[28]);
- const uint32_t string_table_begins = 40;
-
- Vector<String> string_table;
-
- String package_name = p_preset->get("package/name");
-
- for (uint32_t i = 0; i < string_count; i++) {
- uint32_t offset = decode_uint32(&r_manifest[string_table_begins + i * 4]);
- offset += string_table_begins + string_count * 4;
-
- String str = _parse_string(&r_manifest[offset], string_flags & UTF8_FLAG);
-
- if (str.begins_with("godot-project-name")) {
- if (str == "godot-project-name") {
- //project name
- str = get_project_name(package_name);
-
- } else {
- String lang = str.substr(str.rfind("-") + 1, str.length()).replace("-", "_");
- String prop = "application/config/name_" + lang;
- if (ProjectSettings::get_singleton()->has_setting(prop)) {
- str = ProjectSettings::get_singleton()->get(prop);
- } else {
- str = get_project_name(package_name);
- }
- }
- }
-
- string_table.push_back(str);
- }
-
- //write a new string table, but use 16 bits
- Vector<uint8_t> ret;
- ret.resize(string_table_begins + string_table.size() * 4);
-
- for (uint32_t i = 0; i < string_table_begins; i++) {
- ret.write[i] = r_manifest[i];
- }
-
- int ofs = 0;
- for (int i = 0; i < string_table.size(); i++) {
- encode_uint32(ofs, &ret.write[string_table_begins + i * 4]);
- ofs += string_table[i].length() * 2 + 2 + 2;
- }
-
- ret.resize(ret.size() + ofs);
- uint8_t *chars = &ret.write[ret.size() - ofs];
- for (int i = 0; i < string_table.size(); i++) {
- String s = string_table[i];
- encode_uint16(s.length(), chars);
- chars += 2;
- for (int j = 0; j < s.length(); j++) {
- encode_uint16(s[j], chars);
- chars += 2;
- }
- encode_uint16(0, chars);
- chars += 2;
- }
-
- //pad
- while (ret.size() % 4) {
- ret.push_back(0);
- }
-
- //change flags to not use utf8
- encode_uint32(string_flags & ~0x100, &ret.write[28]);
- //change length
- encode_uint32(ret.size() - 12, &ret.write[16]);
- //append the rest...
- int rest_from = 12 + string_block_len;
- int rest_to = ret.size();
- int rest_len = (r_manifest.size() - rest_from);
- ret.resize(ret.size() + (r_manifest.size() - rest_from));
- for (int i = 0; i < rest_len; i++) {
- ret.write[rest_to + i] = r_manifest[rest_from + i];
- }
- //finally update the size
- encode_uint32(ret.size(), &ret.write[4]);
-
- r_manifest = ret;
- //printf("end\n");
- }
-
- void _load_image_data(const Ref<Image> &p_splash_image, Vector<uint8_t> &p_data) {
- Vector<uint8_t> png_buffer;
- Error err = PNGDriverCommon::image_to_png(p_splash_image, png_buffer);
- if (err == OK) {
- p_data.resize(png_buffer.size());
- memcpy(p_data.ptrw(), png_buffer.ptr(), p_data.size());
- } else {
- String err_str = String("Failed to convert splash image to png.");
- WARN_PRINT(err_str.utf8().get_data());
- }
- }
-
- void _process_launcher_icons(const String &p_file_name, const Ref<Image> &p_source_image, int dimension, Vector<uint8_t> &p_data) {
- Ref<Image> working_image = p_source_image;
-
- if (p_source_image->get_width() != dimension || p_source_image->get_height() != dimension) {
- working_image = p_source_image->duplicate();
- working_image->resize(dimension, dimension, Image::Interpolation::INTERPOLATE_LANCZOS);
- }
-
- Vector<uint8_t> png_buffer;
- Error err = PNGDriverCommon::image_to_png(working_image, png_buffer);
- if (err == OK) {
- p_data.resize(png_buffer.size());
- memcpy(p_data.ptrw(), png_buffer.ptr(), p_data.size());
- } else {
- String err_str = String("Failed to convert resized icon (") + p_file_name + ") to png.";
- WARN_PRINT(err_str.utf8().get_data());
- }
- }
-
- String load_splash_refs(Ref<Image> &splash_image, Ref<Image> &splash_bg_color_image) {
- bool scale_splash = ProjectSettings::get_singleton()->get("application/boot_splash/fullsize");
- bool apply_filter = ProjectSettings::get_singleton()->get("application/boot_splash/use_filter");
- String project_splash_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
-
- if (!project_splash_path.is_empty()) {
- splash_image.instantiate();
- print_verbose("Loading splash image: " + project_splash_path);
- const Error err = ImageLoader::load_image(project_splash_path, splash_image);
- if (err) {
- if (OS::get_singleton()->is_stdout_verbose()) {
- print_error("- unable to load splash image from " + project_splash_path + " (" + itos(err) + ")");
- }
- splash_image.unref();
- }
- }
-
- if (splash_image.is_null()) {
- // Use the default
- print_verbose("Using default splash image.");
- splash_image = Ref<Image>(memnew(Image(boot_splash_png)));
- }
-
- if (scale_splash) {
- Size2 screen_size = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
- int width, height;
- if (screen_size.width > screen_size.height) {
- // scale horizontally
- height = screen_size.height;
- width = splash_image->get_width() * screen_size.height / splash_image->get_height();
- } else {
- // scale vertically
- width = screen_size.width;
- height = splash_image->get_height() * screen_size.width / splash_image->get_width();
- }
- splash_image->resize(width, height);
- }
-
- // Setup the splash bg color
- bool bg_color_valid;
- Color bg_color = ProjectSettings::get_singleton()->get("application/boot_splash/bg_color", &bg_color_valid);
- if (!bg_color_valid) {
- bg_color = boot_splash_bg_color;
- }
-
- print_verbose("Creating splash background color image.");
- splash_bg_color_image.instantiate();
- splash_bg_color_image->create(splash_image->get_width(), splash_image->get_height(), false, splash_image->get_format());
- splash_bg_color_image->fill(bg_color);
-
- String processed_splash_config_xml = vformat(SPLASH_CONFIG_XML_CONTENT, bool_to_string(apply_filter));
- return processed_splash_config_xml;
- }
-
- void load_icon_refs(const Ref<EditorExportPreset> &p_preset, Ref<Image> &icon, Ref<Image> &foreground, Ref<Image> &background) {
- String project_icon_path = ProjectSettings::get_singleton()->get("application/config/icon");
-
- icon.instantiate();
- foreground.instantiate();
- background.instantiate();
-
- // Regular icon: user selection -> project icon -> default.
- String path = static_cast<String>(p_preset->get(launcher_icon_option)).strip_edges();
- print_verbose("Loading regular icon from " + path);
- if (path.is_empty() || ImageLoader::load_image(path, icon) != OK) {
- print_verbose("- falling back to project icon: " + project_icon_path);
- ImageLoader::load_image(project_icon_path, icon);
- }
-
- // Adaptive foreground: user selection -> regular icon (user selection -> project icon -> default).
- path = static_cast<String>(p_preset->get(launcher_adaptive_icon_foreground_option)).strip_edges();
- print_verbose("Loading adaptive foreground icon from " + path);
- if (path.is_empty() || ImageLoader::load_image(path, foreground) != OK) {
- print_verbose("- falling back to using the regular icon");
- foreground = icon;
- }
-
- // Adaptive background: user selection -> default.
- path = static_cast<String>(p_preset->get(launcher_adaptive_icon_background_option)).strip_edges();
- if (!path.is_empty()) {
- print_verbose("Loading adaptive background icon from " + path);
- ImageLoader::load_image(path, background);
- }
- }
-
- void store_image(const LauncherIcon launcher_icon, const Vector<uint8_t> &data) {
- store_image(launcher_icon.export_path, data);
- }
-
- void store_image(const String &export_path, const Vector<uint8_t> &data) {
- String img_path = export_path.insert(0, "res://android/build/");
- store_file_at_path(img_path, data);
- }
-
- void _copy_icons_to_gradle_project(const Ref<EditorExportPreset> &p_preset,
- const String &processed_splash_config_xml,
- const Ref<Image> &splash_image,
- const Ref<Image> &splash_bg_color_image,
- const Ref<Image> &main_image,
- const Ref<Image> &foreground,
- const Ref<Image> &background) {
- // Store the splash configuration
- if (!processed_splash_config_xml.is_empty()) {
- print_verbose("Storing processed splash configuration: " + String("\n") + processed_splash_config_xml);
- store_string_at_path(SPLASH_CONFIG_PATH, processed_splash_config_xml);
- }
-
- // Store the splash image
- if (splash_image.is_valid() && !splash_image->is_empty()) {
- print_verbose("Storing splash image in " + String(SPLASH_IMAGE_EXPORT_PATH));
- Vector<uint8_t> data;
- _load_image_data(splash_image, data);
- store_image(SPLASH_IMAGE_EXPORT_PATH, data);
- }
-
- // Store the splash bg color image
- if (splash_bg_color_image.is_valid() && !splash_bg_color_image->is_empty()) {
- print_verbose("Storing splash background image in " + String(SPLASH_BG_COLOR_PATH));
- Vector<uint8_t> data;
- _load_image_data(splash_bg_color_image, data);
- store_image(SPLASH_BG_COLOR_PATH, data);
- }
-
- // Prepare images to be resized for the icons. If some image ends up being uninitialized,
- // the default image from the export template will be used.
-
- for (int i = 0; i < icon_densities_count; ++i) {
- if (main_image.is_valid() && !main_image->is_empty()) {
- print_verbose("Processing launcher icon for dimension " + itos(launcher_icons[i].dimensions) + " into " + launcher_icons[i].export_path);
- Vector<uint8_t> data;
- _process_launcher_icons(launcher_icons[i].export_path, main_image, launcher_icons[i].dimensions, data);
- store_image(launcher_icons[i], data);
- }
-
- if (foreground.is_valid() && !foreground->is_empty()) {
- print_verbose("Processing launcher adaptive icon foreground for dimension " + itos(launcher_adaptive_icon_foregrounds[i].dimensions) + " into " + launcher_adaptive_icon_foregrounds[i].export_path);
- Vector<uint8_t> data;
- _process_launcher_icons(launcher_adaptive_icon_foregrounds[i].export_path, foreground,
- launcher_adaptive_icon_foregrounds[i].dimensions, data);
- store_image(launcher_adaptive_icon_foregrounds[i], data);
- }
-
- if (background.is_valid() && !background->is_empty()) {
- print_verbose("Processing launcher adaptive icon background for dimension " + itos(launcher_adaptive_icon_backgrounds[i].dimensions) + " into " + launcher_adaptive_icon_backgrounds[i].export_path);
- Vector<uint8_t> data;
- _process_launcher_icons(launcher_adaptive_icon_backgrounds[i].export_path, background,
- launcher_adaptive_icon_backgrounds[i].dimensions, data);
- store_image(launcher_adaptive_icon_backgrounds[i], data);
- }
- }
- }
-
- static Vector<String> get_enabled_abis(const Ref<EditorExportPreset> &p_preset) {
- Vector<String> abis = get_abis();
- Vector<String> enabled_abis;
- for (int i = 0; i < abis.size(); ++i) {
- bool is_enabled = p_preset->get("architectures/" + abis[i]);
- if (is_enabled) {
- enabled_abis.push_back(abis[i]);
- }
- }
- return enabled_abis;
- }
-
-public:
- typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
-
-public:
- virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) override {
- String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
- if (driver == "GLES2") {
- r_features->push_back("etc");
- }
- // FIXME: Review what texture formats are used for Vulkan.
- if (driver == "Vulkan") {
- r_features->push_back("etc2");
- }
-
- Vector<String> abis = get_enabled_abis(p_preset);
- for (int i = 0; i < abis.size(); ++i) {
- r_features->push_back(abis[i]);
- }
- }
-
- virtual void get_export_options(List<ExportOption> *r_options) override {
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "custom_template/use_custom_build"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "custom_template/export_format", PROPERTY_HINT_ENUM, "Export APK,Export AAB"), EXPORT_FORMAT_APK));
-
- Vector<PluginConfigAndroid> plugins_configs = get_plugins();
- for (int i = 0; i < plugins_configs.size(); i++) {
- print_verbose("Found Android plugin " + plugins_configs[i].name);
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "plugins/" + plugins_configs[i].name), false));
- }
- plugins_changed.clear();
-
- Vector<String> abis = get_abis();
- for (int i = 0; i < abis.size(); ++i) {
- String abi = abis[i];
- bool is_default = (abi == "armeabi-v7a" || abi == "arm64-v8a");
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architectures/" + abi), is_default));
- }
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_user"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_password"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_user"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_password"), ""));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "one_click_deploy/clear_previous_install"), false));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0"));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "ext.domain.name"), "org.godotengine.$genname"));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name [default if blank]"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/signed"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/classify_as_game"), true));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_icon_option, PROPERTY_HINT_FILE, "*.png"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_adaptive_icon_foreground_option, PROPERTY_HINT_FILE, "*.png"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_adaptive_icon_background_option, PROPERTY_HINT_FILE, "*.png"), ""));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/32_bits_framebuffer"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/opengl_debug"), false));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/xr_mode", PROPERTY_HINT_ENUM, "Regular,Oculus Mobile VR"), 0));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/hand_tracking", PROPERTY_HINT_ENUM, "None,Optional,Required"), 0));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/immersive_mode"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_small"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_normal"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_large"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_xlarge"), true));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "user_data_backup/allow"), false));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), ""));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "apk_expansion/enable"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "apk_expansion/SALT"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "apk_expansion/public_key", PROPERTY_HINT_MULTILINE_TEXT), ""));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "permissions/custom_permissions"), PackedStringArray()));
-
- const char **perms = android_perms;
- while (*perms) {
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "permissions/" + String(*perms).to_lower()), false));
- perms++;
- }
- }
-
- virtual String get_name() const override {
- return "Android";
- }
-
- virtual String get_os_name() const override {
- return "Android";
- }
-
- virtual Ref<Texture2D> get_logo() const override {
- return logo;
- }
-
- virtual bool should_update_export_options() override {
- bool export_options_changed = plugins_changed.is_set();
- if (export_options_changed) {
- // don't clear unless we're reporting true, to avoid race
- plugins_changed.clear();
- }
- return export_options_changed;
- }
-
- virtual bool poll_export() override {
- bool dc = devices_changed.is_set();
- if (dc) {
- // don't clear unless we're reporting true, to avoid race
- devices_changed.clear();
- }
- return dc;
- }
-
- virtual int get_options_count() const override {
- MutexLock lock(device_lock);
- return devices.size();
- }
-
- virtual String get_options_tooltip() const override {
- return TTR("Select device from the list");
- }
-
- virtual String get_option_label(int p_index) const override {
- ERR_FAIL_INDEX_V(p_index, devices.size(), "");
- MutexLock lock(device_lock);
- return devices[p_index].name;
- }
-
- virtual String get_option_tooltip(int p_index) const override {
- ERR_FAIL_INDEX_V(p_index, devices.size(), "");
- MutexLock lock(device_lock);
- String s = devices[p_index].description;
- if (devices.size() == 1) {
- // Tooltip will be:
- // Name
- // Description
- s = devices[p_index].name + "\n\n" + s;
- }
- return s;
- }
-
- virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) override {
- ERR_FAIL_INDEX_V(p_device, devices.size(), ERR_INVALID_PARAMETER);
-
- String can_export_error;
- bool can_export_missing_templates;
- if (!can_export(p_preset, can_export_error, can_export_missing_templates)) {
- EditorNode::add_io_error(can_export_error);
- return ERR_UNCONFIGURED;
- }
-
- MutexLock lock(device_lock);
-
- EditorProgress ep("run", vformat(TTR("Running on %s"), devices[p_device].name), 3);
-
- String adb = get_adb_path();
-
- // Export_temp APK.
- if (ep.step(TTR("Exporting APK..."), 0)) {
- return ERR_SKIP;
- }
-
- const bool use_remote = (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) || (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT);
- const bool use_reverse = devices[p_device].api_level >= 21;
-
- if (use_reverse) {
- p_debug_flags |= DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST;
- }
-
- String tmp_export_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpexport." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
-
-#define CLEANUP_AND_RETURN(m_err) \
- { \
- DirAccess::remove_file_or_error(tmp_export_path); \
- return m_err; \
- }
-
- // Export to temporary APK before sending to device.
- Error err = export_project_helper(p_preset, true, tmp_export_path, EXPORT_FORMAT_APK, true, p_debug_flags);
-
- if (err != OK) {
- CLEANUP_AND_RETURN(err);
- }
-
- List<String> args;
- int rv;
- String output;
-
- bool remove_prev = p_preset->get("one_click_deploy/clear_previous_install");
- String version_name = p_preset->get("version/name");
- String package_name = p_preset->get("package/unique_name");
-
- if (remove_prev) {
- if (ep.step(TTR("Uninstalling..."), 1)) {
- CLEANUP_AND_RETURN(ERR_SKIP);
- }
-
- print_line("Uninstalling previous version: " + devices[p_device].name);
-
- args.push_back("-s");
- args.push_back(devices[p_device].id);
- args.push_back("uninstall");
- args.push_back(get_package_name(package_name));
-
- output.clear();
- err = OS::get_singleton()->execute(adb, args, &output, &rv, true);
- print_verbose(output);
- }
-
- print_line("Installing to device (please wait...): " + devices[p_device].name);
- if (ep.step(TTR("Installing to device, please wait..."), 2)) {
- CLEANUP_AND_RETURN(ERR_SKIP);
- }
-
- args.clear();
- args.push_back("-s");
- args.push_back(devices[p_device].id);
- args.push_back("install");
- args.push_back("-r");
- args.push_back(tmp_export_path);
-
- output.clear();
- err = OS::get_singleton()->execute(adb, args, &output, &rv, true);
- print_verbose(output);
- if (err || rv != 0) {
- EditorNode::add_io_error(vformat(TTR("Could not install to device: %s"), output));
- CLEANUP_AND_RETURN(ERR_CANT_CREATE);
- }
-
- if (use_remote) {
- if (use_reverse) {
- static const char *const msg = "--- Device API >= 21; debugging over USB ---";
- EditorNode::get_singleton()->get_log()->add_message(msg, EditorLog::MSG_TYPE_EDITOR);
- print_line(String(msg).to_upper());
-
- args.clear();
- args.push_back("-s");
- args.push_back(devices[p_device].id);
- args.push_back("reverse");
- args.push_back("--remove-all");
- output.clear();
- OS::get_singleton()->execute(adb, args, &output, &rv, true);
- print_verbose(output);
-
- if (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) {
- int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port");
- args.clear();
- args.push_back("-s");
- args.push_back(devices[p_device].id);
- args.push_back("reverse");
- args.push_back("tcp:" + itos(dbg_port));
- args.push_back("tcp:" + itos(dbg_port));
-
- output.clear();
- OS::get_singleton()->execute(adb, args, &output, &rv, true);
- print_verbose(output);
- print_line("Reverse result: " + itos(rv));
- }
-
- if (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT) {
- int fs_port = EditorSettings::get_singleton()->get("filesystem/file_server/port");
-
- args.clear();
- args.push_back("-s");
- args.push_back(devices[p_device].id);
- args.push_back("reverse");
- args.push_back("tcp:" + itos(fs_port));
- args.push_back("tcp:" + itos(fs_port));
-
- output.clear();
- err = OS::get_singleton()->execute(adb, args, &output, &rv, true);
- print_verbose(output);
- print_line("Reverse result2: " + itos(rv));
- }
- } else {
- static const char *const msg = "--- Device API < 21; debugging over Wi-Fi ---";
- EditorNode::get_singleton()->get_log()->add_message(msg, EditorLog::MSG_TYPE_EDITOR);
- print_line(String(msg).to_upper());
- }
- }
-
- if (ep.step(TTR("Running on device..."), 3)) {
- CLEANUP_AND_RETURN(ERR_SKIP);
- }
- args.clear();
- args.push_back("-s");
- args.push_back(devices[p_device].id);
- args.push_back("shell");
- args.push_back("am");
- args.push_back("start");
- if ((bool)EditorSettings::get_singleton()->get("export/android/force_system_user") && devices[p_device].api_level >= 17) { // Multi-user introduced in Android 17
- args.push_back("--user");
- args.push_back("0");
- }
- args.push_back("-a");
- args.push_back("android.intent.action.MAIN");
- args.push_back("-n");
- args.push_back(get_package_name(package_name) + "/com.godot.game.GodotApp");
-
- output.clear();
- err = OS::get_singleton()->execute(adb, args, &output, &rv, true);
- print_verbose(output);
- if (err || rv != 0) {
- EditorNode::add_io_error(TTR("Could not execute on device."));
- CLEANUP_AND_RETURN(ERR_CANT_CREATE);
- }
-
- CLEANUP_AND_RETURN(OK);
-#undef CLEANUP_AND_RETURN
- }
-
- virtual Ref<Texture2D> get_run_icon() const override {
- return run_icon;
- }
-
- static String get_adb_path() {
- String exe_ext = "";
- if (OS::get_singleton()->get_name() == "Windows") {
- exe_ext = ".exe";
- }
- String sdk_path = EditorSettings::get_singleton()->get("export/android/android_sdk_path");
- return sdk_path.plus_file("platform-tools/adb" + exe_ext);
- }
-
- static String get_apksigner_path() {
- String exe_ext = "";
- if (OS::get_singleton()->get_name() == "Windows") {
- exe_ext = ".bat";
- }
- String apksigner_command_name = "apksigner" + exe_ext;
- String sdk_path = EditorSettings::get_singleton()->get("export/android/android_sdk_path");
- String apksigner_path = "";
-
- Error errn;
- String build_tools_dir = sdk_path.plus_file("build-tools");
- DirAccessRef da = DirAccess::open(build_tools_dir, &errn);
- if (errn != OK) {
- print_error("Unable to open Android 'build-tools' directory.");
- return apksigner_path;
- }
-
- // There are additional versions directories we need to go through.
- da->list_dir_begin();
- String sub_dir = da->get_next();
- while (!sub_dir.is_empty()) {
- if (!sub_dir.begins_with(".") && da->current_is_dir()) {
- // Check if the tool is here.
- String tool_path = build_tools_dir.plus_file(sub_dir).plus_file(apksigner_command_name);
- if (FileAccess::exists(tool_path)) {
- apksigner_path = tool_path;
- break;
- }
- }
- sub_dir = da->get_next();
- }
- da->list_dir_end();
-
- if (apksigner_path.is_empty()) {
- EditorNode::get_singleton()->show_warning(TTR("Unable to find the 'apksigner' tool."));
- }
-
- return apksigner_path;
- }
-
- virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override {
- String err;
- bool valid = false;
-
- // Look for export templates (first official, and if defined custom templates).
-
- if (!bool(p_preset->get("custom_template/use_custom_build"))) {
- String template_err;
- bool dvalid = false;
- bool rvalid = false;
- bool has_export_templates = false;
-
- if (p_preset->get("custom_template/debug") != "") {
- dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
- if (!dvalid) {
- template_err += TTR("Custom debug template not found.") + "\n";
- }
- } else {
- has_export_templates |= exists_export_template("android_debug.apk", &template_err);
- }
-
- if (p_preset->get("custom_template/release") != "") {
- rvalid = FileAccess::exists(p_preset->get("custom_template/release"));
- if (!rvalid) {
- template_err += TTR("Custom release template not found.") + "\n";
- }
- } else {
- has_export_templates |= exists_export_template("android_release.apk", &template_err);
- }
-
- r_missing_templates = !has_export_templates;
- valid = dvalid || rvalid || has_export_templates;
- if (!valid) {
- err += template_err;
- }
- } else {
- bool installed_android_build_template = FileAccess::exists("res://android/build/build.gradle");
- if (!installed_android_build_template) {
- r_missing_templates = !exists_export_template("android_source.zip", &err);
- err += TTR("Android build template not installed in the project. Install it from the Project menu.") + "\n";
- } else {
- r_missing_templates = false;
- }
-
- valid = installed_android_build_template && !r_missing_templates;
- }
-
- // Validate the rest of the configuration.
-
- String dk = p_preset->get("keystore/debug");
- String dk_user = p_preset->get("keystore/debug_user");
- String dk_password = p_preset->get("keystore/debug_password");
-
- if ((dk.is_empty() || dk_user.is_empty() || dk_password.is_empty()) && (!dk.is_empty() || !dk_user.is_empty() || !dk_password.is_empty())) {
- valid = false;
- err += TTR("Either Debug Keystore, Debug User AND Debug Password settings must be configured OR none of them.") + "\n";
- }
-
- if (!FileAccess::exists(dk)) {
- dk = EditorSettings::get_singleton()->get("export/android/debug_keystore");
- if (!FileAccess::exists(dk)) {
- valid = false;
- err += TTR("Debug keystore not configured in the Editor Settings nor in the preset.") + "\n";
- }
- }
-
- String rk = p_preset->get("keystore/release");
- String rk_user = p_preset->get("keystore/release_user");
- String rk_password = p_preset->get("keystore/release_password");
-
- if ((rk.is_empty() || rk_user.is_empty() || rk_password.is_empty()) && (!rk.is_empty() || !rk_user.is_empty() || !rk_password.is_empty())) {
- valid = false;
- err += TTR("Either Release Keystore, Release User AND Release Password settings must be configured OR none of them.") + "\n";
- }
-
- if (!rk.is_empty() && !FileAccess::exists(rk)) {
- valid = false;
- err += TTR("Release keystore incorrectly configured in the export preset.") + "\n";
- }
-
- String sdk_path = EditorSettings::get_singleton()->get("export/android/android_sdk_path");
- if (sdk_path == "") {
- err += TTR("A valid Android SDK path is required in Editor Settings.") + "\n";
- valid = false;
- } else {
- Error errn;
- // Check for the platform-tools directory.
- DirAccessRef da = DirAccess::open(sdk_path.plus_file("platform-tools"), &errn);
- if (errn != OK) {
- err += TTR("Invalid Android SDK path in Editor Settings.");
- err += TTR("Missing 'platform-tools' directory!");
- err += "\n";
- valid = false;
- }
-
- // Validate that adb is available
- String adb_path = get_adb_path();
- if (!FileAccess::exists(adb_path)) {
- err += TTR("Unable to find Android SDK platform-tools' adb command.");
- err += TTR("Please check in the Android SDK directory specified in Editor Settings.");
- err += "\n";
- valid = false;
- }
-
- // Check for the build-tools directory.
- DirAccessRef build_tools_da = DirAccess::open(sdk_path.plus_file("build-tools"), &errn);
- if (errn != OK) {
- err += TTR("Invalid Android SDK path in Editor Settings.");
- err += TTR("Missing 'build-tools' directory!");
- err += "\n";
- valid = false;
- }
-
- // Validate that apksigner is available
- String apksigner_path = get_apksigner_path();
- if (!FileAccess::exists(apksigner_path)) {
- err += TTR("Unable to find Android SDK build-tools' apksigner command.");
- err += TTR("Please check in the Android SDK directory specified in Editor Settings.");
- err += "\n";
- valid = false;
- }
- }
-
- bool apk_expansion = p_preset->get("apk_expansion/enable");
-
- if (apk_expansion) {
- String apk_expansion_pkey = p_preset->get("apk_expansion/public_key");
-
- if (apk_expansion_pkey == "") {
- valid = false;
-
- err += TTR("Invalid public key for APK expansion.") + "\n";
- }
- }
-
- String pn = p_preset->get("package/unique_name");
- String pn_err;
-
- if (!is_package_name_valid(get_package_name(pn), &pn_err)) {
- valid = false;
- err += TTR("Invalid package name:") + " " + pn_err + "\n";
- }
-
- String etc_error = test_etc2();
- if (etc_error != String()) {
- valid = false;
- err += etc_error;
- }
-
- // Ensure that `Use Custom Build` is enabled if a plugin is selected.
- String enabled_plugins_names = get_plugins_names(get_enabled_plugins(p_preset));
- bool custom_build_enabled = p_preset->get("custom_template/use_custom_build");
- if (!enabled_plugins_names.is_empty() && !custom_build_enabled) {
- valid = false;
- err += TTR("\"Use Custom Build\" must be enabled to use the plugins.");
- err += "\n";
- }
-
- // Validate the Xr features are properly populated
- int xr_mode_index = p_preset->get("xr_features/xr_mode");
- int hand_tracking = p_preset->get("xr_features/hand_tracking");
- if (xr_mode_index != /* XRMode.OVR*/ 1) {
- if (hand_tracking > 0) {
- valid = false;
- err += TTR("\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\".");
- err += "\n";
- }
- }
-
- if (int(p_preset->get("custom_template/export_format")) == EXPORT_FORMAT_AAB &&
- !bool(p_preset->get("custom_template/use_custom_build"))) {
- valid = false;
- err += TTR("\"Export AAB\" is only valid when \"Use Custom Build\" is enabled.");
- err += "\n";
- }
-
- r_error = err;
- return valid;
- }
-
- virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override {
- List<String> list;
- list.push_back("apk");
- list.push_back("aab");
- return list;
- }
-
- inline bool is_clean_build_required(Vector<PluginConfigAndroid> enabled_plugins) {
- String plugin_names = get_plugins_names(enabled_plugins);
- bool first_build = last_custom_build_time == 0;
- bool have_plugins_changed = false;
-
- if (!first_build) {
- have_plugins_changed = plugin_names != last_plugin_names;
- if (!have_plugins_changed) {
- for (int i = 0; i < enabled_plugins.size(); i++) {
- if (enabled_plugins.get(i).last_updated > last_custom_build_time) {
- have_plugins_changed = true;
- break;
- }
- }
- }
- }
-
- last_custom_build_time = OS::get_singleton()->get_unix_time();
- last_plugin_names = plugin_names;
-
- return have_plugins_changed || first_build;
- }
-
- String get_apk_expansion_fullpath(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
- int version_code = p_preset->get("version/code");
- String package_name = p_preset->get("package/unique_name");
- String apk_file_name = "main." + itos(version_code) + "." + get_package_name(package_name) + ".obb";
- String fullpath = p_path.get_base_dir().plus_file(apk_file_name);
- return fullpath;
- }
-
- Error save_apk_expansion_file(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
- String fullpath = get_apk_expansion_fullpath(p_preset, p_path);
- Error err = save_pack(p_preset, fullpath);
- return err;
- }
-
- void get_command_line_flags(const Ref<EditorExportPreset> &p_preset, const String &p_path, int p_flags, Vector<uint8_t> &r_command_line_flags) {
- String cmdline = p_preset->get("command_line/extra_args");
- Vector<String> command_line_strings = cmdline.strip_edges().split(" ");
- for (int i = 0; i < command_line_strings.size(); i++) {
- if (command_line_strings[i].strip_edges().length() == 0) {
- command_line_strings.remove(i);
- i--;
- }
- }
-
- gen_export_flags(command_line_strings, p_flags);
-
- bool apk_expansion = p_preset->get("apk_expansion/enable");
- if (apk_expansion) {
- String fullpath = get_apk_expansion_fullpath(p_preset, p_path);
- String apk_expansion_public_key = p_preset->get("apk_expansion/public_key");
-
- command_line_strings.push_back("--use_apk_expansion");
- command_line_strings.push_back("--apk_expansion_md5");
- command_line_strings.push_back(FileAccess::get_md5(fullpath));
- command_line_strings.push_back("--apk_expansion_key");
- command_line_strings.push_back(apk_expansion_public_key.strip_edges());
- }
-
- int xr_mode_index = p_preset->get("xr_features/xr_mode");
- if (xr_mode_index == 1) {
- command_line_strings.push_back("--xr_mode_ovr");
- } else { // XRMode.REGULAR is the default.
- command_line_strings.push_back("--xr_mode_regular");
- }
-
- bool use_32_bit_framebuffer = p_preset->get("graphics/32_bits_framebuffer");
- if (use_32_bit_framebuffer) {
- command_line_strings.push_back("--use_depth_32");
- }
-
- bool immersive = p_preset->get("screen/immersive_mode");
- if (immersive) {
- command_line_strings.push_back("--use_immersive");
- }
-
- bool debug_opengl = p_preset->get("graphics/opengl_debug");
- if (debug_opengl) {
- command_line_strings.push_back("--debug_opengl");
- }
-
- if (command_line_strings.size()) {
- r_command_line_flags.resize(4);
- encode_uint32(command_line_strings.size(), &r_command_line_flags.write[0]);
- for (int i = 0; i < command_line_strings.size(); i++) {
- print_line(itos(i) + " param: " + command_line_strings[i]);
- CharString command_line_argument = command_line_strings[i].utf8();
- int base = r_command_line_flags.size();
- int length = command_line_argument.length();
- if (length == 0) {
- continue;
- }
- r_command_line_flags.resize(base + 4 + length);
- encode_uint32(length, &r_command_line_flags.write[base]);
- memcpy(&r_command_line_flags.write[base + 4], command_line_argument.ptr(), length);
- }
- }
- }
-
- Error sign_apk(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &export_path, EditorProgress &ep) {
- int export_format = int(p_preset->get("custom_template/export_format"));
- String export_label = export_format == EXPORT_FORMAT_AAB ? "AAB" : "APK";
- String release_keystore = p_preset->get("keystore/release");
- String release_username = p_preset->get("keystore/release_user");
- String release_password = p_preset->get("keystore/release_password");
-
- String apksigner = get_apksigner_path();
- print_verbose("Starting signing of the " + export_label + " binary using " + apksigner);
- if (!FileAccess::exists(apksigner)) {
- EditorNode::add_io_error(vformat(TTR("'apksigner' could not be found.\nPlease check the command is available in the Android SDK build-tools directory.\nThe resulting %s is unsigned."), export_label));
- return OK;
- }
-
- String keystore;
- String password;
- String user;
- if (p_debug) {
- keystore = p_preset->get("keystore/debug");
- password = p_preset->get("keystore/debug_password");
- user = p_preset->get("keystore/debug_user");
-
- if (keystore.is_empty()) {
- keystore = EditorSettings::get_singleton()->get("export/android/debug_keystore");
- password = EditorSettings::get_singleton()->get("export/android/debug_keystore_pass");
- user = EditorSettings::get_singleton()->get("export/android/debug_keystore_user");
- }
-
- if (ep.step(vformat(TTR("Signing debug %s..."), export_label), 104)) {
- return ERR_SKIP;
- }
-
- } else {
- keystore = release_keystore;
- password = release_password;
- user = release_username;
-
- if (ep.step(vformat(TTR("Signing release %s..."), export_label), 104)) {
- return ERR_SKIP;
- }
- }
-
- if (!FileAccess::exists(keystore)) {
- EditorNode::add_io_error(TTR("Could not find keystore, unable to export."));
- return ERR_FILE_CANT_OPEN;
- }
-
- String output;
- List<String> args;
- args.push_back("sign");
- args.push_back("--verbose");
- args.push_back("--ks");
- args.push_back(keystore);
- args.push_back("--ks-pass");
- args.push_back("pass:" + password);
- args.push_back("--ks-key-alias");
- args.push_back(user);
- args.push_back(export_path);
- if (p_debug) {
- // We only print verbose logs for debug builds to avoid leaking release keystore credentials.
- print_verbose("Signing debug binary using: " + String("\n") + apksigner + " " + join_list(args, String(" ")));
- }
- int retval;
- output.clear();
- OS::get_singleton()->execute(apksigner, args, &output, &retval, true);
- print_verbose(output);
- if (retval) {
- EditorNode::add_io_error(vformat(TTR("'apksigner' returned with error #%d"), retval));
- return ERR_CANT_CREATE;
- }
-
- if (ep.step(vformat(TTR("Verifying %s..."), export_label), 105)) {
- return ERR_SKIP;
- }
-
- args.clear();
- args.push_back("verify");
- args.push_back("--verbose");
- args.push_back(export_path);
- if (p_debug) {
- print_verbose("Verifying signed build using: " + String("\n") + apksigner + " " + join_list(args, String(" ")));
- }
-
- output.clear();
- OS::get_singleton()->execute(apksigner, args, &output, &retval, true);
- print_verbose(output);
- if (retval) {
- EditorNode::add_io_error(vformat(TTR("'apksigner' verification of %s failed."), export_label));
- return ERR_CANT_CREATE;
- }
-
- print_verbose("Successfully completed signing build.");
- return OK;
- }
-
- void _clear_assets_directory() {
- DirAccessRef da_res = DirAccess::create(DirAccess::ACCESS_RESOURCES);
- if (da_res->dir_exists("res://android/build/assets")) {
- print_verbose("Clearing assets directory..");
- DirAccessRef da_assets = DirAccess::open("res://android/build/assets");
- da_assets->erase_contents_recursive();
- da_res->remove("res://android/build/assets");
- }
- }
-
- void _remove_copied_libs() {
- print_verbose("Removing previously installed libraries...");
- Error error;
- String libs_json = FileAccess::get_file_as_string(GDNATIVE_LIBS_PATH, &error);
- if (error || libs_json.is_empty()) {
- print_verbose("No previously installed libraries found");
- return;
- }
-
- JSON json;
- error = json.parse(libs_json);
- ERR_FAIL_COND_MSG(error, "Error parsing \"" + libs_json + "\" on line " + itos(json.get_error_line()) + ": " + json.get_error_message());
-
- Vector<String> libs = json.get_data();
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
- for (int i = 0; i < libs.size(); i++) {
- print_verbose("Removing previously installed library " + libs[i]);
- da->remove(libs[i]);
- }
- da->remove(GDNATIVE_LIBS_PATH);
- }
-
- String join_list(List<String> parts, const String &separator) const {
- String ret;
- for (int i = 0; i < parts.size(); ++i) {
- if (i > 0) {
- ret += separator;
- }
- ret += parts[i];
- }
- return ret;
- }
-
- virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override {
- int export_format = int(p_preset->get("custom_template/export_format"));
- bool should_sign = p_preset->get("package/signed");
- return export_project_helper(p_preset, p_debug, p_path, export_format, should_sign, p_flags);
- }
-
- Error export_project_helper(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int export_format, bool should_sign, int p_flags) {
- ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
-
- String src_apk;
- Error err;
-
- EditorProgress ep("export", TTR("Exporting for Android"), 105, true);
-
- bool use_custom_build = bool(p_preset->get("custom_template/use_custom_build"));
- bool p_give_internet = p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG);
- bool apk_expansion = p_preset->get("apk_expansion/enable");
- Vector<String> enabled_abis = get_enabled_abis(p_preset);
-
- print_verbose("Exporting for Android...");
- print_verbose("- debug build: " + bool_to_string(p_debug));
- print_verbose("- export path: " + p_path);
- print_verbose("- export format: " + itos(export_format));
- print_verbose("- sign build: " + bool_to_string(should_sign));
- print_verbose("- custom build enabled: " + bool_to_string(use_custom_build));
- print_verbose("- apk expansion enabled: " + bool_to_string(apk_expansion));
- print_verbose("- enabled abis: " + String(",").join(enabled_abis));
- print_verbose("- export filter: " + itos(p_preset->get_export_filter()));
- print_verbose("- include filter: " + p_preset->get_include_filter());
- print_verbose("- exclude filter: " + p_preset->get_exclude_filter());
-
- Ref<Image> splash_image;
- Ref<Image> splash_bg_color_image;
- String processed_splash_config_xml = load_splash_refs(splash_image, splash_bg_color_image);
-
- Ref<Image> main_image;
- Ref<Image> foreground;
- Ref<Image> background;
-
- load_icon_refs(p_preset, main_image, foreground, background);
-
- Vector<uint8_t> command_line_flags;
- // Write command line flags into the command_line_flags variable.
- get_command_line_flags(p_preset, p_path, p_flags, command_line_flags);
-
- if (export_format == EXPORT_FORMAT_AAB) {
- if (!p_path.ends_with(".aab")) {
- EditorNode::get_singleton()->show_warning(TTR("Invalid filename! Android App Bundle requires the *.aab extension."));
- return ERR_UNCONFIGURED;
- }
- if (apk_expansion) {
- EditorNode::get_singleton()->show_warning(TTR("APK Expansion not compatible with Android App Bundle."));
- return ERR_UNCONFIGURED;
- }
- }
- if (export_format == EXPORT_FORMAT_APK && !p_path.ends_with(".apk")) {
- EditorNode::get_singleton()->show_warning(
- TTR("Invalid filename! Android APK requires the *.apk extension."));
- return ERR_UNCONFIGURED;
- }
- if (export_format > EXPORT_FORMAT_AAB || export_format < EXPORT_FORMAT_APK) {
- EditorNode::add_io_error(TTR("Unsupported export format!\n"));
- return ERR_UNCONFIGURED; //TODO: is this the right error?
- }
-
- if (use_custom_build) {
- print_verbose("Starting custom build..");
- //test that installed build version is alright
- {
- print_verbose("Checking build version..");
- FileAccessRef f = FileAccess::open("res://android/.build_version", FileAccess::READ);
- if (!f) {
- EditorNode::get_singleton()->show_warning(TTR("Trying to build from a custom built template, but no version info for it exists. Please reinstall from the 'Project' menu."));
- return ERR_UNCONFIGURED;
- }
- String version = f->get_line().strip_edges();
- print_verbose("- build version: " + version);
- f->close();
- if (version != VERSION_FULL_CONFIG) {
- EditorNode::get_singleton()->show_warning(vformat(TTR("Android build version mismatch:\n Template installed: %s\n Godot Version: %s\nPlease reinstall Android build template from 'Project' menu."), version, VERSION_FULL_CONFIG));
- return ERR_UNCONFIGURED;
- }
- }
- String sdk_path = EDITOR_GET("export/android/android_sdk_path");
- ERR_FAIL_COND_V_MSG(sdk_path.is_empty(), ERR_UNCONFIGURED, "Android SDK path must be configured in Editor Settings at 'export/android/android_sdk_path'.");
- print_verbose("Android sdk path: " + sdk_path);
-
- // TODO: should we use "package/name" or "application/config/name"?
- String project_name = get_project_name(p_preset->get("package/name"));
- err = _create_project_name_strings_files(p_preset, project_name); //project name localization.
- if (err != OK) {
- EditorNode::add_io_error(TTR("Unable to overwrite res://android/build/res/*.xml files with project name"));
- }
- // Copies the project icon files into the appropriate Gradle project directory.
- _copy_icons_to_gradle_project(p_preset, processed_splash_config_xml, splash_image, splash_bg_color_image, main_image, foreground, background);
- // Write an AndroidManifest.xml file into the Gradle project directory.
- _write_tmp_manifest(p_preset, p_give_internet, p_debug);
-
- //stores all the project files inside the Gradle project directory. Also includes all ABIs
- _clear_assets_directory();
- _remove_copied_libs();
- if (!apk_expansion) {
- print_verbose("Exporting project files..");
- CustomExportData user_data;
- user_data.debug = p_debug;
- err = export_project_files(p_preset, rename_and_store_file_in_gradle_project, &user_data, copy_gradle_so);
- if (err != OK) {
- EditorNode::add_io_error(TTR("Could not export project files to gradle project\n"));
- return err;
- }
- if (user_data.libs.size() > 0) {
- FileAccessRef fa = FileAccess::open(GDNATIVE_LIBS_PATH, FileAccess::WRITE);
- JSON json;
- fa->store_string(json.stringify(user_data.libs, "\t"));
- fa->close();
- }
- } else {
- print_verbose("Saving apk expansion file..");
- err = save_apk_expansion_file(p_preset, p_path);
- if (err != OK) {
- EditorNode::add_io_error(TTR("Could not write expansion package file!"));
- return err;
- }
- }
- print_verbose("Storing command line flags..");
- store_file_at_path("res://android/build/assets/_cl_", command_line_flags);
-
- print_verbose("Updating ANDROID_HOME environment to " + sdk_path);
- OS::get_singleton()->set_environment("ANDROID_HOME", sdk_path); //set and overwrite if required
- String build_command;
-
-#ifdef WINDOWS_ENABLED
- build_command = "gradlew.bat";
-#else
- build_command = "gradlew";
-#endif
-
- String build_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/build");
- build_command = build_path.plus_file(build_command);
-
- String package_name = get_package_name(p_preset->get("package/unique_name"));
- String version_code = itos(p_preset->get("version/code"));
- String version_name = p_preset->get("version/name");
- String enabled_abi_string = String("|").join(enabled_abis);
- String sign_flag = should_sign ? "true" : "false";
- String zipalign_flag = "true";
-
- Vector<PluginConfigAndroid> enabled_plugins = get_enabled_plugins(p_preset);
- String local_plugins_binaries = get_plugins_binaries(PluginConfigAndroid::BINARY_TYPE_LOCAL, enabled_plugins);
- String remote_plugins_binaries = get_plugins_binaries(PluginConfigAndroid::BINARY_TYPE_REMOTE, enabled_plugins);
- String custom_maven_repos = get_plugins_custom_maven_repos(enabled_plugins);
- bool clean_build_required = is_clean_build_required(enabled_plugins);
-
- List<String> cmdline;
- if (clean_build_required) {
- cmdline.push_back("clean");
- }
-
- String build_type = p_debug ? "Debug" : "Release";
- if (export_format == EXPORT_FORMAT_AAB) {
- String bundle_build_command = vformat("bundle%s", build_type);
- cmdline.push_back(bundle_build_command);
- } else if (export_format == EXPORT_FORMAT_APK) {
- String apk_build_command = vformat("assemble%s", build_type);
- cmdline.push_back(apk_build_command);
- }
-
- cmdline.push_back("-p"); // argument to specify the start directory.
- cmdline.push_back(build_path); // start directory.
- cmdline.push_back("-Pexport_package_name=" + package_name); // argument to specify the package name.
- cmdline.push_back("-Pexport_version_code=" + version_code); // argument to specify the version code.
- cmdline.push_back("-Pexport_version_name=" + version_name); // argument to specify the version name.
- cmdline.push_back("-Pexport_enabled_abis=" + enabled_abi_string); // argument to specify enabled ABIs.
- cmdline.push_back("-Pplugins_local_binaries=" + local_plugins_binaries); // argument to specify the list of plugins local dependencies.
- cmdline.push_back("-Pplugins_remote_binaries=" + remote_plugins_binaries); // argument to specify the list of plugins remote dependencies.
- cmdline.push_back("-Pplugins_maven_repos=" + custom_maven_repos); // argument to specify the list of custom maven repos for the plugins dependencies.
- cmdline.push_back("-Pperform_zipalign=" + zipalign_flag); // argument to specify whether the build should be zipaligned.
- cmdline.push_back("-Pperform_signing=" + sign_flag); // argument to specify whether the build should be signed.
- cmdline.push_back("-Pgodot_editor_version=" + String(VERSION_FULL_CONFIG));
-
- // NOTE: The release keystore is not included in the verbose logging
- // to avoid accidentally leaking sensitive information when sharing verbose logs for troubleshooting.
- // Any non-sensitive additions to the command line arguments must be done above this section.
- // Sensitive additions must be done below the logging statement.
- print_verbose("Build Android project using gradle command: " + String("\n") + build_command + " " + join_list(cmdline, String(" ")));
-
- if (should_sign) {
- if (p_debug) {
- String debug_keystore = p_preset->get("keystore/debug");
- String debug_password = p_preset->get("keystore/debug_password");
- String debug_user = p_preset->get("keystore/debug_user");
-
- if (debug_keystore.is_empty()) {
- debug_keystore = EditorSettings::get_singleton()->get("export/android/debug_keystore");
- debug_password = EditorSettings::get_singleton()->get("export/android/debug_keystore_pass");
- debug_user = EditorSettings::get_singleton()->get("export/android/debug_keystore_user");
- }
-
- cmdline.push_back("-Pdebug_keystore_file=" + debug_keystore); // argument to specify the debug keystore file.
- cmdline.push_back("-Pdebug_keystore_alias=" + debug_user); // argument to specify the debug keystore alias.
- cmdline.push_back("-Pdebug_keystore_password=" + debug_password); // argument to specify the debug keystore password.
- } else {
- // Pass the release keystore info as well
- String release_keystore = p_preset->get("keystore/release");
- String release_username = p_preset->get("keystore/release_user");
- String release_password = p_preset->get("keystore/release_password");
- if (!FileAccess::exists(release_keystore)) {
- EditorNode::add_io_error(TTR("Could not find keystore, unable to export."));
- return ERR_FILE_CANT_OPEN;
- }
-
- cmdline.push_back("-Prelease_keystore_file=" + release_keystore); // argument to specify the release keystore file.
- cmdline.push_back("-Prelease_keystore_alias=" + release_username); // argument to specify the release keystore alias.
- cmdline.push_back("-Prelease_keystore_password=" + release_password); // argument to specify the release keystore password.
- }
- }
-
- int result = EditorNode::get_singleton()->execute_and_show_output(TTR("Building Android Project (gradle)"), build_command, cmdline);
- if (result != 0) {
- EditorNode::get_singleton()->show_warning(TTR("Building of Android project failed, check output for the error.\nAlternatively visit docs.godotengine.org for Android build documentation."));
- return ERR_CANT_CREATE;
- }
-
- List<String> copy_args;
- String copy_command;
- if (export_format == EXPORT_FORMAT_AAB) {
- copy_command = vformat("copyAndRename%sAab", build_type);
- } else if (export_format == EXPORT_FORMAT_APK) {
- copy_command = vformat("copyAndRename%sApk", build_type);
- }
-
- copy_args.push_back(copy_command);
-
- copy_args.push_back("-p"); // argument to specify the start directory.
- copy_args.push_back(build_path); // start directory.
-
- String export_filename = p_path.get_file();
- String export_path = p_path.get_base_dir();
- if (export_path.is_rel_path()) {
- export_path = OS::get_singleton()->get_resource_dir().plus_file(export_path);
- }
- export_path = ProjectSettings::get_singleton()->globalize_path(export_path).simplify_path();
-
- copy_args.push_back("-Pexport_path=file:" + export_path);
- copy_args.push_back("-Pexport_filename=" + export_filename);
-
- print_verbose("Copying Android binary using gradle command: " + String("\n") + build_command + " " + join_list(copy_args, String(" ")));
- int copy_result = EditorNode::get_singleton()->execute_and_show_output(TTR("Moving output"), build_command, copy_args);
- if (copy_result != 0) {
- EditorNode::get_singleton()->show_warning(TTR("Unable to copy and rename export file, check gradle project directory for outputs."));
- return ERR_CANT_CREATE;
- }
-
- print_verbose("Successfully completed Android custom build.");
- return OK;
- }
- // This is the start of the Legacy build system
- print_verbose("Starting legacy build system..");
- if (p_debug) {
- src_apk = p_preset->get("custom_template/debug");
- } else {
- src_apk = p_preset->get("custom_template/release");
- }
- src_apk = src_apk.strip_edges();
- if (src_apk == "") {
- if (p_debug) {
- src_apk = find_export_template("android_debug.apk");
- } else {
- src_apk = find_export_template("android_release.apk");
- }
- if (src_apk == "") {
- EditorNode::add_io_error(vformat(TTR("Package not found: %s"), src_apk));
- return ERR_FILE_NOT_FOUND;
- }
- }
-
- if (!DirAccess::exists(p_path.get_base_dir())) {
- return ERR_FILE_BAD_PATH;
- }
-
- FileAccess *src_f = nullptr;
- zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
-
- if (ep.step(TTR("Creating APK..."), 0)) {
- return ERR_SKIP;
- }
-
- unzFile pkg = unzOpen2(src_apk.utf8().get_data(), &io);
- if (!pkg) {
- EditorNode::add_io_error(vformat(TTR("Could not find template APK to export:\n%s"), src_apk));
- return ERR_FILE_NOT_FOUND;
- }
-
- int ret = unzGoToFirstFile(pkg);
-
- zlib_filefunc_def io2 = io;
- FileAccess *dst_f = nullptr;
- io2.opaque = &dst_f;
-
- String tmp_unaligned_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpexport-unaligned." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
-
-#define CLEANUP_AND_RETURN(m_err) \
- { \
- DirAccess::remove_file_or_error(tmp_unaligned_path); \
- return m_err; \
- }
-
- zipFile unaligned_apk = zipOpen2(tmp_unaligned_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io2);
-
- String cmdline = p_preset->get("command_line/extra_args");
-
- String version_name = p_preset->get("version/name");
- String package_name = p_preset->get("package/unique_name");
-
- String apk_expansion_pkey = p_preset->get("apk_expansion/public_key");
-
- Vector<String> invalid_abis(enabled_abis);
- while (ret == UNZ_OK) {
- //get filename
- unz_file_info info;
- char fname[16384];
- ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
-
- bool skip = false;
-
- String file = fname;
-
- Vector<uint8_t> data;
- data.resize(info.uncompressed_size);
-
- //read
- unzOpenCurrentFile(pkg);
- unzReadCurrentFile(pkg, data.ptrw(), data.size());
- unzCloseCurrentFile(pkg);
-
- //write
- if (file == "AndroidManifest.xml") {
- _fix_manifest(p_preset, data, p_give_internet);
- }
- if (file == "resources.arsc") {
- _fix_resources(p_preset, data);
- }
-
- // Process the splash image
- if ((file == SPLASH_IMAGE_EXPORT_PATH || file == LEGACY_BUILD_SPLASH_IMAGE_EXPORT_PATH) && splash_image.is_valid() && !splash_image->is_empty()) {
- _load_image_data(splash_image, data);
- }
-
- // Process the splash bg color image
- if ((file == SPLASH_BG_COLOR_PATH || file == LEGACY_BUILD_SPLASH_BG_COLOR_PATH) && splash_bg_color_image.is_valid() && !splash_bg_color_image->is_empty()) {
- _load_image_data(splash_bg_color_image, data);
- }
-
- for (int i = 0; i < icon_densities_count; ++i) {
- if (main_image.is_valid() && !main_image->is_empty()) {
- if (file == launcher_icons[i].export_path) {
- _process_launcher_icons(file, main_image, launcher_icons[i].dimensions, data);
- }
- }
- if (foreground.is_valid() && !foreground->is_empty()) {
- if (file == launcher_adaptive_icon_foregrounds[i].export_path) {
- _process_launcher_icons(file, foreground, launcher_adaptive_icon_foregrounds[i].dimensions, data);
- }
- }
- if (background.is_valid() && !background->is_empty()) {
- if (file == launcher_adaptive_icon_backgrounds[i].export_path) {
- _process_launcher_icons(file, background, launcher_adaptive_icon_backgrounds[i].dimensions, data);
- }
- }
- }
-
- if (file.ends_with(".so")) {
- bool enabled = false;
- for (int i = 0; i < enabled_abis.size(); ++i) {
- if (file.begins_with("lib/" + enabled_abis[i] + "/")) {
- invalid_abis.erase(enabled_abis[i]);
- enabled = true;
- break;
- }
- }
- if (!enabled) {
- skip = true;
- }
- }
-
- if (file.begins_with("META-INF") && should_sign) {
- skip = true;
- }
-
- if (!skip) {
- print_line("ADDING: " + file);
-
- // Respect decision on compression made by AAPT for the export template
- const bool uncompressed = info.compression_method == 0;
-
- zip_fileinfo zipfi = get_zip_fileinfo();
-
- zipOpenNewFileInZip(unaligned_apk,
- file.utf8().get_data(),
- &zipfi,
- nullptr,
- 0,
- nullptr,
- 0,
- nullptr,
- uncompressed ? 0 : Z_DEFLATED,
- Z_DEFAULT_COMPRESSION);
-
- zipWriteInFileInZip(unaligned_apk, data.ptr(), data.size());
- zipCloseFileInZip(unaligned_apk);
- }
-
- ret = unzGoToNextFile(pkg);
- }
-
- if (!invalid_abis.is_empty()) {
- String unsupported_arch = String(", ").join(invalid_abis);
- EditorNode::add_io_error(vformat(TTR("Missing libraries in the export template for the selected architectures: %s.\nPlease build a template with all required libraries, or uncheck the missing architectures in the export preset."), unsupported_arch));
- CLEANUP_AND_RETURN(ERR_FILE_NOT_FOUND);
- }
-
- if (ep.step(TTR("Adding files..."), 1)) {
- CLEANUP_AND_RETURN(ERR_SKIP);
- }
- err = OK;
-
- if (p_flags & DEBUG_FLAG_DUMB_CLIENT) {
- APKExportData ed;
- ed.ep = &ep;
- ed.apk = unaligned_apk;
- err = export_project_files(p_preset, ignore_apk_file, &ed, save_apk_so);
- } else {
- if (apk_expansion) {
- err = save_apk_expansion_file(p_preset, p_path);
- if (err != OK) {
- EditorNode::add_io_error(TTR("Could not write expansion package file!"));
- return err;
- }
- } else {
- APKExportData ed;
- ed.ep = &ep;
- ed.apk = unaligned_apk;
- err = export_project_files(p_preset, save_apk_file, &ed, save_apk_so);
- }
- }
-
- if (err != OK) {
- unzClose(pkg);
- EditorNode::add_io_error(TTR("Could not export project files"));
- CLEANUP_AND_RETURN(ERR_SKIP);
- }
-
- zip_fileinfo zipfi = get_zip_fileinfo();
- zipOpenNewFileInZip(unaligned_apk,
- "assets/_cl_",
- &zipfi,
- nullptr,
- 0,
- nullptr,
- 0,
- nullptr,
- 0, // No compress (little size gain and potentially slower startup)
- Z_DEFAULT_COMPRESSION);
- zipWriteInFileInZip(unaligned_apk, command_line_flags.ptr(), command_line_flags.size());
- zipCloseFileInZip(unaligned_apk);
- zipClose(unaligned_apk, nullptr);
- unzClose(pkg);
-
- if (err != OK) {
- CLEANUP_AND_RETURN(err);
- }
-
- // Let's zip-align (must be done before signing)
-
- static const int ZIP_ALIGNMENT = 4;
-
- // If we're not signing the apk, then the next step should be the last.
- const int next_step = should_sign ? 103 : 105;
- if (ep.step(TTR("Aligning APK..."), next_step)) {
- CLEANUP_AND_RETURN(ERR_SKIP);
- }
-
- unzFile tmp_unaligned = unzOpen2(tmp_unaligned_path.utf8().get_data(), &io);
- if (!tmp_unaligned) {
- EditorNode::add_io_error(TTR("Could not unzip temporary unaligned APK."));
- CLEANUP_AND_RETURN(ERR_FILE_NOT_FOUND);
- }
-
- ret = unzGoToFirstFile(tmp_unaligned);
-
- io2 = io;
- dst_f = nullptr;
- io2.opaque = &dst_f;
- zipFile final_apk = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io2);
-
- // Take files from the unaligned APK and write them out to the aligned one
- // in raw mode, i.e. not uncompressing and recompressing, aligning them as needed,
- // following what is done in https://github.com/android/platform_build/blob/master/tools/zipalign/ZipAlign.cpp
- int bias = 0;
- while (ret == UNZ_OK) {
- unz_file_info info;
- memset(&info, 0, sizeof(info));
-
- char fname[16384];
- char extra[16384];
- ret = unzGetCurrentFileInfo(tmp_unaligned, &info, fname, 16384, extra, 16384 - ZIP_ALIGNMENT, nullptr, 0);
-
- String file = fname;
-
- Vector<uint8_t> data;
- data.resize(info.compressed_size);
-
- // read
- int method, level;
- unzOpenCurrentFile2(tmp_unaligned, &method, &level, 1); // raw read
- long file_offset = unzGetCurrentFileZStreamPos64(tmp_unaligned);
- unzReadCurrentFile(tmp_unaligned, data.ptrw(), data.size());
- unzCloseCurrentFile(tmp_unaligned);
-
- // align
- int padding = 0;
- if (!info.compression_method) {
- // Uncompressed file => Align
- long new_offset = file_offset + bias;
- padding = (ZIP_ALIGNMENT - (new_offset % ZIP_ALIGNMENT)) % ZIP_ALIGNMENT;
- }
-
- memset(extra + info.size_file_extra, 0, padding);
-
- zip_fileinfo fileinfo = get_zip_fileinfo();
- zipOpenNewFileInZip2(final_apk,
- file.utf8().get_data(),
- &fileinfo,
- extra,
- info.size_file_extra + padding,
- nullptr,
- 0,
- nullptr,
- method,
- level,
- 1); // raw write
- zipWriteInFileInZip(final_apk, data.ptr(), data.size());
- zipCloseFileInZipRaw(final_apk, info.uncompressed_size, info.crc);
-
- bias += padding;
-
- ret = unzGoToNextFile(tmp_unaligned);
- }
-
- zipClose(final_apk, nullptr);
- unzClose(tmp_unaligned);
-
- if (should_sign) {
- // Signing must be done last as any additional modifications to the
- // file will invalidate the signature.
- err = sign_apk(p_preset, p_debug, p_path, ep);
- if (err != OK) {
- CLEANUP_AND_RETURN(err);
- }
- }
-
- CLEANUP_AND_RETURN(OK);
- }
-
- virtual void get_platform_features(List<String> *r_features) override {
- r_features->push_back("mobile");
- r_features->push_back("Android");
- }
-
- virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) override {
- }
-
- EditorExportPlatformAndroid() {
- Ref<Image> img = memnew(Image(_android_logo));
- logo.instantiate();
- logo->create_from_image(img);
-
- img = Ref<Image>(memnew(Image(_android_run_icon)));
- run_icon.instantiate();
- run_icon->create_from_image(img);
-
- devices_changed.set();
- plugins_changed.set();
- check_for_changes_thread.start(_check_for_changes_poll_thread, this);
- }
-
- ~EditorExportPlatformAndroid() {
- quit_request.set();
- check_for_changes_thread.wait_to_finish();
- }
-};
+#include "export_plugin.h"
void register_android_exporter() {
String exe_ext;
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
new file mode 100644
index 0000000000..6c2e481856
--- /dev/null
+++ b/platform/android/export/export_plugin.cpp
@@ -0,0 +1,2945 @@
+/*************************************************************************/
+/* export_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "export_plugin.h"
+
+static const char *android_perms[] = {
+ "ACCESS_CHECKIN_PROPERTIES",
+ "ACCESS_COARSE_LOCATION",
+ "ACCESS_FINE_LOCATION",
+ "ACCESS_LOCATION_EXTRA_COMMANDS",
+ "ACCESS_MOCK_LOCATION",
+ "ACCESS_NETWORK_STATE",
+ "ACCESS_SURFACE_FLINGER",
+ "ACCESS_WIFI_STATE",
+ "ACCOUNT_MANAGER",
+ "ADD_VOICEMAIL",
+ "AUTHENTICATE_ACCOUNTS",
+ "BATTERY_STATS",
+ "BIND_ACCESSIBILITY_SERVICE",
+ "BIND_APPWIDGET",
+ "BIND_DEVICE_ADMIN",
+ "BIND_INPUT_METHOD",
+ "BIND_NFC_SERVICE",
+ "BIND_NOTIFICATION_LISTENER_SERVICE",
+ "BIND_PRINT_SERVICE",
+ "BIND_REMOTEVIEWS",
+ "BIND_TEXT_SERVICE",
+ "BIND_VPN_SERVICE",
+ "BIND_WALLPAPER",
+ "BLUETOOTH",
+ "BLUETOOTH_ADMIN",
+ "BLUETOOTH_PRIVILEGED",
+ "BRICK",
+ "BROADCAST_PACKAGE_REMOVED",
+ "BROADCAST_SMS",
+ "BROADCAST_STICKY",
+ "BROADCAST_WAP_PUSH",
+ "CALL_PHONE",
+ "CALL_PRIVILEGED",
+ "CAMERA",
+ "CAPTURE_AUDIO_OUTPUT",
+ "CAPTURE_SECURE_VIDEO_OUTPUT",
+ "CAPTURE_VIDEO_OUTPUT",
+ "CHANGE_COMPONENT_ENABLED_STATE",
+ "CHANGE_CONFIGURATION",
+ "CHANGE_NETWORK_STATE",
+ "CHANGE_WIFI_MULTICAST_STATE",
+ "CHANGE_WIFI_STATE",
+ "CLEAR_APP_CACHE",
+ "CLEAR_APP_USER_DATA",
+ "CONTROL_LOCATION_UPDATES",
+ "DELETE_CACHE_FILES",
+ "DELETE_PACKAGES",
+ "DEVICE_POWER",
+ "DIAGNOSTIC",
+ "DISABLE_KEYGUARD",
+ "DUMP",
+ "EXPAND_STATUS_BAR",
+ "FACTORY_TEST",
+ "FLASHLIGHT",
+ "FORCE_BACK",
+ "GET_ACCOUNTS",
+ "GET_PACKAGE_SIZE",
+ "GET_TASKS",
+ "GET_TOP_ACTIVITY_INFO",
+ "GLOBAL_SEARCH",
+ "HARDWARE_TEST",
+ "INJECT_EVENTS",
+ "INSTALL_LOCATION_PROVIDER",
+ "INSTALL_PACKAGES",
+ "INSTALL_SHORTCUT",
+ "INTERNAL_SYSTEM_WINDOW",
+ "INTERNET",
+ "KILL_BACKGROUND_PROCESSES",
+ "LOCATION_HARDWARE",
+ "MANAGE_ACCOUNTS",
+ "MANAGE_APP_TOKENS",
+ "MANAGE_DOCUMENTS",
+ "MASTER_CLEAR",
+ "MEDIA_CONTENT_CONTROL",
+ "MODIFY_AUDIO_SETTINGS",
+ "MODIFY_PHONE_STATE",
+ "MOUNT_FORMAT_FILESYSTEMS",
+ "MOUNT_UNMOUNT_FILESYSTEMS",
+ "NFC",
+ "PERSISTENT_ACTIVITY",
+ "PROCESS_OUTGOING_CALLS",
+ "READ_CALENDAR",
+ "READ_CALL_LOG",
+ "READ_CONTACTS",
+ "READ_EXTERNAL_STORAGE",
+ "READ_FRAME_BUFFER",
+ "READ_HISTORY_BOOKMARKS",
+ "READ_INPUT_STATE",
+ "READ_LOGS",
+ "READ_PHONE_STATE",
+ "READ_PROFILE",
+ "READ_SMS",
+ "READ_SOCIAL_STREAM",
+ "READ_SYNC_SETTINGS",
+ "READ_SYNC_STATS",
+ "READ_USER_DICTIONARY",
+ "REBOOT",
+ "RECEIVE_BOOT_COMPLETED",
+ "RECEIVE_MMS",
+ "RECEIVE_SMS",
+ "RECEIVE_WAP_PUSH",
+ "RECORD_AUDIO",
+ "REORDER_TASKS",
+ "RESTART_PACKAGES",
+ "SEND_RESPOND_VIA_MESSAGE",
+ "SEND_SMS",
+ "SET_ACTIVITY_WATCHER",
+ "SET_ALARM",
+ "SET_ALWAYS_FINISH",
+ "SET_ANIMATION_SCALE",
+ "SET_DEBUG_APP",
+ "SET_ORIENTATION",
+ "SET_POINTER_SPEED",
+ "SET_PREFERRED_APPLICATIONS",
+ "SET_PROCESS_LIMIT",
+ "SET_TIME",
+ "SET_TIME_ZONE",
+ "SET_WALLPAPER",
+ "SET_WALLPAPER_HINTS",
+ "SIGNAL_PERSISTENT_PROCESSES",
+ "STATUS_BAR",
+ "SUBSCRIBED_FEEDS_READ",
+ "SUBSCRIBED_FEEDS_WRITE",
+ "SYSTEM_ALERT_WINDOW",
+ "TRANSMIT_IR",
+ "UNINSTALL_SHORTCUT",
+ "UPDATE_DEVICE_STATS",
+ "USE_CREDENTIALS",
+ "USE_SIP",
+ "VIBRATE",
+ "WAKE_LOCK",
+ "WRITE_APN_SETTINGS",
+ "WRITE_CALENDAR",
+ "WRITE_CALL_LOG",
+ "WRITE_CONTACTS",
+ "WRITE_EXTERNAL_STORAGE",
+ "WRITE_GSERVICES",
+ "WRITE_HISTORY_BOOKMARKS",
+ "WRITE_PROFILE",
+ "WRITE_SECURE_SETTINGS",
+ "WRITE_SETTINGS",
+ "WRITE_SMS",
+ "WRITE_SOCIAL_STREAM",
+ "WRITE_SYNC_SETTINGS",
+ "WRITE_USER_DICTIONARY",
+ nullptr
+};
+
+static const char *SPLASH_IMAGE_EXPORT_PATH = "res/drawable-nodpi/splash.png";
+static const char *LEGACY_BUILD_SPLASH_IMAGE_EXPORT_PATH = "res/drawable-nodpi-v4/splash.png";
+static const char *SPLASH_BG_COLOR_PATH = "res/drawable-nodpi/splash_bg_color.png";
+static const char *LEGACY_BUILD_SPLASH_BG_COLOR_PATH = "res/drawable-nodpi-v4/splash_bg_color.png";
+static const char *SPLASH_CONFIG_PATH = "res://android/build/res/drawable/splash_drawable.xml";
+static const char *GDNATIVE_LIBS_PATH = "res://android/build/libs/gdnativelibs.json";
+
+static const int icon_densities_count = 6;
+static const char *launcher_icon_option = "launcher_icons/main_192x192";
+static const char *launcher_adaptive_icon_foreground_option = "launcher_icons/adaptive_foreground_432x432";
+static const char *launcher_adaptive_icon_background_option = "launcher_icons/adaptive_background_432x432";
+
+static const LauncherIcon launcher_icons[icon_densities_count] = {
+ { "res/mipmap-xxxhdpi-v4/icon.png", 192 },
+ { "res/mipmap-xxhdpi-v4/icon.png", 144 },
+ { "res/mipmap-xhdpi-v4/icon.png", 96 },
+ { "res/mipmap-hdpi-v4/icon.png", 72 },
+ { "res/mipmap-mdpi-v4/icon.png", 48 },
+ { "res/mipmap/icon.png", 192 }
+};
+
+static const LauncherIcon launcher_adaptive_icon_foregrounds[icon_densities_count] = {
+ { "res/mipmap-xxxhdpi-v4/icon_foreground.png", 432 },
+ { "res/mipmap-xxhdpi-v4/icon_foreground.png", 324 },
+ { "res/mipmap-xhdpi-v4/icon_foreground.png", 216 },
+ { "res/mipmap-hdpi-v4/icon_foreground.png", 162 },
+ { "res/mipmap-mdpi-v4/icon_foreground.png", 108 },
+ { "res/mipmap/icon_foreground.png", 432 }
+};
+
+static const LauncherIcon launcher_adaptive_icon_backgrounds[icon_densities_count] = {
+ { "res/mipmap-xxxhdpi-v4/icon_background.png", 432 },
+ { "res/mipmap-xxhdpi-v4/icon_background.png", 324 },
+ { "res/mipmap-xhdpi-v4/icon_background.png", 216 },
+ { "res/mipmap-hdpi-v4/icon_background.png", 162 },
+ { "res/mipmap-mdpi-v4/icon_background.png", 108 },
+ { "res/mipmap/icon_background.png", 432 }
+};
+
+static const int EXPORT_FORMAT_APK = 0;
+static const int EXPORT_FORMAT_AAB = 1;
+
+void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) {
+ EditorExportPlatformAndroid *ea = (EditorExportPlatformAndroid *)ud;
+
+ while (!ea->quit_request.is_set()) {
+ // Check for plugins updates
+ {
+ // Nothing to do if we already know the plugins have changed.
+ if (!ea->plugins_changed.is_set()) {
+ Vector<PluginConfigAndroid> loaded_plugins = get_plugins();
+
+ MutexLock lock(ea->plugins_lock);
+
+ if (ea->plugins.size() != loaded_plugins.size()) {
+ ea->plugins_changed.set();
+ } else {
+ for (int i = 0; i < ea->plugins.size(); i++) {
+ if (ea->plugins[i].name != loaded_plugins[i].name) {
+ ea->plugins_changed.set();
+ break;
+ }
+ }
+ }
+
+ if (ea->plugins_changed.is_set()) {
+ ea->plugins = loaded_plugins;
+ }
+ }
+ }
+
+ // Check for devices updates
+ String adb = get_adb_path();
+ if (FileAccess::exists(adb)) {
+ String devices;
+ List<String> args;
+ args.push_back("devices");
+ int ec;
+ OS::get_singleton()->execute(adb, args, &devices, &ec);
+
+ Vector<String> ds = devices.split("\n");
+ Vector<String> ldevices;
+ for (int i = 1; i < ds.size(); i++) {
+ String d = ds[i];
+ int dpos = d.find("device");
+ if (dpos == -1) {
+ continue;
+ }
+ d = d.substr(0, dpos).strip_edges();
+ ldevices.push_back(d);
+ }
+
+ MutexLock lock(ea->device_lock);
+
+ bool different = false;
+
+ if (ea->devices.size() != ldevices.size()) {
+ different = true;
+ } else {
+ for (int i = 0; i < ea->devices.size(); i++) {
+ if (ea->devices[i].id != ldevices[i]) {
+ different = true;
+ break;
+ }
+ }
+ }
+
+ if (different) {
+ Vector<Device> ndevices;
+
+ for (int i = 0; i < ldevices.size(); i++) {
+ Device d;
+ d.id = ldevices[i];
+ for (int j = 0; j < ea->devices.size(); j++) {
+ if (ea->devices[j].id == ldevices[i]) {
+ d.description = ea->devices[j].description;
+ d.name = ea->devices[j].name;
+ d.api_level = ea->devices[j].api_level;
+ }
+ }
+
+ if (d.description == "") {
+ //in the oven, request!
+ args.clear();
+ args.push_back("-s");
+ args.push_back(d.id);
+ args.push_back("shell");
+ args.push_back("getprop");
+ int ec2;
+ String dp;
+
+ OS::get_singleton()->execute(adb, args, &dp, &ec2);
+
+ Vector<String> props = dp.split("\n");
+ String vendor;
+ String device;
+ d.description = "Device ID: " + d.id + "\n";
+ d.api_level = 0;
+ for (int j = 0; j < props.size(); j++) {
+ // got information by `shell cat /system/build.prop` before and its format is "property=value"
+ // it's now changed to use `shell getporp` because of permission issue with Android 8.0 and above
+ // its format is "[property]: [value]" so changed it as like build.prop
+ String p = props[j];
+ p = p.replace("]: ", "=");
+ p = p.replace("[", "");
+ p = p.replace("]", "");
+
+ if (p.begins_with("ro.product.model=")) {
+ device = p.get_slice("=", 1).strip_edges();
+ } else if (p.begins_with("ro.product.brand=")) {
+ vendor = p.get_slice("=", 1).strip_edges().capitalize();
+ } else if (p.begins_with("ro.build.display.id=")) {
+ d.description += "Build: " + p.get_slice("=", 1).strip_edges() + "\n";
+ } else if (p.begins_with("ro.build.version.release=")) {
+ d.description += "Release: " + p.get_slice("=", 1).strip_edges() + "\n";
+ } else if (p.begins_with("ro.build.version.sdk=")) {
+ d.api_level = p.get_slice("=", 1).to_int();
+ } else if (p.begins_with("ro.product.cpu.abi=")) {
+ d.description += "CPU: " + p.get_slice("=", 1).strip_edges() + "\n";
+ } else if (p.begins_with("ro.product.manufacturer=")) {
+ d.description += "Manufacturer: " + p.get_slice("=", 1).strip_edges() + "\n";
+ } else if (p.begins_with("ro.board.platform=")) {
+ d.description += "Chipset: " + p.get_slice("=", 1).strip_edges() + "\n";
+ } else if (p.begins_with("ro.opengles.version=")) {
+ uint32_t opengl = p.get_slice("=", 1).to_int();
+ d.description += "OpenGL: " + itos(opengl >> 16) + "." + itos((opengl >> 8) & 0xFF) + "." + itos((opengl)&0xFF) + "\n";
+ }
+ }
+
+ d.name = vendor + " " + device;
+ if (device == String()) {
+ continue;
+ }
+ }
+
+ ndevices.push_back(d);
+ }
+
+ ea->devices = ndevices;
+ ea->devices_changed.set();
+ }
+ }
+
+ uint64_t sleep = 200;
+ uint64_t wait = 3000000;
+ uint64_t time = OS::get_singleton()->get_ticks_usec();
+ while (OS::get_singleton()->get_ticks_usec() - time < wait) {
+ OS::get_singleton()->delay_usec(1000 * sleep);
+ if (ea->quit_request.is_set()) {
+ break;
+ }
+ }
+ }
+
+ if (EditorSettings::get_singleton()->get("export/android/shutdown_adb_on_exit")) {
+ String adb = get_adb_path();
+ if (!FileAccess::exists(adb)) {
+ return; //adb not configured
+ }
+
+ List<String> args;
+ args.push_back("kill-server");
+ OS::get_singleton()->execute(adb, args);
+ };
+}
+
+String EditorExportPlatformAndroid::get_project_name(const String &p_name) const {
+ String aname;
+ if (p_name != "") {
+ aname = p_name;
+ } else {
+ aname = ProjectSettings::get_singleton()->get("application/config/name");
+ }
+
+ if (aname == "") {
+ aname = VERSION_NAME;
+ }
+
+ return aname;
+}
+
+String EditorExportPlatformAndroid::get_package_name(const String &p_package) const {
+ String pname = p_package;
+ String basename = ProjectSettings::get_singleton()->get("application/config/name");
+ basename = basename.to_lower();
+
+ String name;
+ bool first = true;
+ for (int i = 0; i < basename.length(); i++) {
+ char32_t c = basename[i];
+ if (c >= '0' && c <= '9' && first) {
+ continue;
+ }
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) {
+ name += String::chr(c);
+ first = false;
+ }
+ }
+ if (name == "") {
+ name = "noname";
+ }
+
+ pname = pname.replace("$genname", name);
+
+ return pname;
+}
+
+bool EditorExportPlatformAndroid::is_package_name_valid(const String &p_package, String *r_error) const {
+ String pname = p_package;
+
+ if (pname.length() == 0) {
+ if (r_error) {
+ *r_error = TTR("Package name is missing.");
+ }
+ return false;
+ }
+
+ int segments = 0;
+ bool first = true;
+ for (int i = 0; i < pname.length(); i++) {
+ char32_t c = pname[i];
+ if (first && c == '.') {
+ if (r_error) {
+ *r_error = TTR("Package segments must be of non-zero length.");
+ }
+ return false;
+ }
+ if (c == '.') {
+ segments++;
+ first = true;
+ continue;
+ }
+ if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')) {
+ if (r_error) {
+ *r_error = vformat(TTR("The character '%s' is not allowed in Android application package names."), String::chr(c));
+ }
+ return false;
+ }
+ if (first && (c >= '0' && c <= '9')) {
+ if (r_error) {
+ *r_error = TTR("A digit cannot be the first character in a package segment.");
+ }
+ return false;
+ }
+ if (first && c == '_') {
+ if (r_error) {
+ *r_error = vformat(TTR("The character '%s' cannot be the first character in a package segment."), String::chr(c));
+ }
+ return false;
+ }
+ first = false;
+ }
+
+ if (segments == 0) {
+ if (r_error) {
+ *r_error = TTR("The package must have at least one '.' separator.");
+ }
+ return false;
+ }
+
+ if (first) {
+ if (r_error) {
+ *r_error = TTR("Package segments must be of non-zero length.");
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool EditorExportPlatformAndroid::_should_compress_asset(const String &p_path, const Vector<uint8_t> &p_data) {
+ /*
+ * By not compressing files with little or not benefit in doing so,
+ * a performance gain is expected attime. Moreover, if the APK is
+ * zip-aligned, assets stored as they are can be efficiently read by
+ * Android by memory-mapping them.
+ */
+
+ // -- Unconditional uncompress to mimic AAPT plus some other
+
+ static const char *unconditional_compress_ext[] = {
+ // From https://github.com/android/platform_frameworks_base/blob/master/tools/aapt/Package.cpp
+ // These formats are already compressed, or don't compress well:
+ ".jpg", ".jpeg", ".png", ".gif",
+ ".wav", ".mp2", ".mp3", ".ogg", ".aac",
+ ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet",
+ ".rtttl", ".imy", ".xmf", ".mp4", ".m4a",
+ ".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2",
+ ".amr", ".awb", ".wma", ".wmv",
+ // Godot-specific:
+ ".webp", // Same reasoning as .png
+ ".cfb", // Don't let small config files slow-down startup
+ ".scn", // Binary scenes are usually already compressed
+ ".stex", // Streamable textures are usually already compressed
+ // Trailer for easier processing
+ nullptr
+ };
+
+ for (const char **ext = unconditional_compress_ext; *ext; ++ext) {
+ if (p_path.to_lower().ends_with(String(*ext))) {
+ return false;
+ }
+ }
+
+ // -- Compressed resource?
+
+ if (p_data.size() >= 4 && p_data[0] == 'R' && p_data[1] == 'S' && p_data[2] == 'C' && p_data[3] == 'C') {
+ // Already compressed
+ return false;
+ }
+
+ // --- TODO: Decide on texture resources according to their image compression setting
+
+ return true;
+}
+
+zip_fileinfo EditorExportPlatformAndroid::get_zip_fileinfo() {
+ OS::Time time = OS::get_singleton()->get_time();
+ OS::Date date = OS::get_singleton()->get_date();
+
+ zip_fileinfo zipfi;
+ zipfi.tmz_date.tm_hour = time.hour;
+ zipfi.tmz_date.tm_mday = date.day;
+ zipfi.tmz_date.tm_min = time.minute;
+ zipfi.tmz_date.tm_mon = date.month - 1; // tm_mon is zero indexed
+ zipfi.tmz_date.tm_sec = time.second;
+ zipfi.tmz_date.tm_year = date.year;
+ zipfi.dosDate = 0;
+ zipfi.external_fa = 0;
+ zipfi.internal_fa = 0;
+
+ return zipfi;
+}
+
+Vector<String> EditorExportPlatformAndroid::get_abis() {
+ Vector<String> abis;
+ abis.push_back("armeabi-v7a");
+ abis.push_back("arm64-v8a");
+ abis.push_back("x86");
+ abis.push_back("x86_64");
+ return abis;
+}
+
+/// List the gdap files in the directory specified by the p_path parameter.
+Vector<String> EditorExportPlatformAndroid::list_gdap_files(const String &p_path) {
+ Vector<String> dir_files;
+ DirAccessRef da = DirAccess::open(p_path);
+ if (da) {
+ da->list_dir_begin();
+ while (true) {
+ String file = da->get_next();
+ if (file == "") {
+ break;
+ }
+
+ if (da->current_is_dir() || da->current_is_hidden()) {
+ continue;
+ }
+
+ if (file.ends_with(PluginConfigAndroid::PLUGIN_CONFIG_EXT)) {
+ dir_files.push_back(file);
+ }
+ }
+ da->list_dir_end();
+ }
+
+ return dir_files;
+}
+
+Vector<PluginConfigAndroid> EditorExportPlatformAndroid::get_plugins() {
+ Vector<PluginConfigAndroid> loaded_plugins;
+
+ String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/plugins");
+
+ // Add the prebuilt plugins
+ loaded_plugins.append_array(PluginConfigAndroid::get_prebuilt_plugins(plugins_dir));
+
+ if (DirAccess::exists(plugins_dir)) {
+ Vector<String> plugins_filenames = list_gdap_files(plugins_dir);
+
+ if (!plugins_filenames.is_empty()) {
+ Ref<ConfigFile> config_file = memnew(ConfigFile);
+ for (int i = 0; i < plugins_filenames.size(); i++) {
+ PluginConfigAndroid config = PluginConfigAndroid::load_plugin_config(config_file, plugins_dir.plus_file(plugins_filenames[i]));
+ if (config.valid_config) {
+ loaded_plugins.push_back(config);
+ } else {
+ print_error("Invalid plugin config file " + plugins_filenames[i]);
+ }
+ }
+ }
+ }
+
+ return loaded_plugins;
+}
+
+Vector<PluginConfigAndroid> EditorExportPlatformAndroid::get_enabled_plugins(const Ref<EditorExportPreset> &p_presets) {
+ Vector<PluginConfigAndroid> enabled_plugins;
+ Vector<PluginConfigAndroid> all_plugins = get_plugins();
+ for (int i = 0; i < all_plugins.size(); i++) {
+ PluginConfigAndroid plugin = all_plugins[i];
+ bool enabled = p_presets->get("plugins/" + plugin.name);
+ if (enabled) {
+ enabled_plugins.push_back(plugin);
+ }
+ }
+
+ return enabled_plugins;
+}
+
+Error EditorExportPlatformAndroid::store_in_apk(APKExportData *ed, const String &p_path, const Vector<uint8_t> &p_data, int compression_method) {
+ zip_fileinfo zipfi = get_zip_fileinfo();
+ zipOpenNewFileInZip(ed->apk,
+ p_path.utf8().get_data(),
+ &zipfi,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ nullptr,
+ compression_method,
+ Z_DEFAULT_COMPRESSION);
+
+ zipWriteInFileInZip(ed->apk, p_data.ptr(), p_data.size());
+ zipCloseFileInZip(ed->apk);
+
+ return OK;
+}
+
+Error EditorExportPlatformAndroid::save_apk_so(void *p_userdata, const SharedObject &p_so) {
+ if (!p_so.path.get_file().begins_with("lib")) {
+ String err = "Android .so file names must start with \"lib\", but got: " + p_so.path;
+ ERR_PRINT(err);
+ return FAILED;
+ }
+ APKExportData *ed = (APKExportData *)p_userdata;
+ Vector<String> abis = get_abis();
+ bool exported = false;
+ for (int i = 0; i < p_so.tags.size(); ++i) {
+ // shared objects can be fat (compatible with multiple ABIs)
+ int abi_index = abis.find(p_so.tags[i]);
+ if (abi_index != -1) {
+ exported = true;
+ String abi = abis[abi_index];
+ String dst_path = String("lib").plus_file(abi).plus_file(p_so.path.get_file());
+ Vector<uint8_t> array = FileAccess::get_file_as_array(p_so.path);
+ Error store_err = store_in_apk(ed, dst_path, array);
+ ERR_FAIL_COND_V_MSG(store_err, store_err, "Cannot store in apk file '" + dst_path + "'.");
+ }
+ }
+ if (!exported) {
+ String abis_string = String(" ").join(abis);
+ String err = "Cannot determine ABI for library \"" + p_so.path + "\". One of the supported ABIs must be used as a tag: " + abis_string;
+ ERR_PRINT(err);
+ return FAILED;
+ }
+ return OK;
+}
+
+Error EditorExportPlatformAndroid::save_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
+ APKExportData *ed = (APKExportData *)p_userdata;
+ String dst_path = p_path.replace_first("res://", "assets/");
+
+ store_in_apk(ed, dst_path, p_data, _should_compress_asset(p_path, p_data) ? Z_DEFLATED : 0);
+ return OK;
+}
+
+Error EditorExportPlatformAndroid::ignore_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
+ return OK;
+}
+
+Error EditorExportPlatformAndroid::copy_gradle_so(void *p_userdata, const SharedObject &p_so) {
+ ERR_FAIL_COND_V_MSG(!p_so.path.get_file().begins_with("lib"), FAILED,
+ "Android .so file names must start with \"lib\", but got: " + p_so.path);
+ Vector<String> abis = get_abis();
+ CustomExportData *export_data = (CustomExportData *)p_userdata;
+ bool exported = false;
+ for (int i = 0; i < p_so.tags.size(); ++i) {
+ int abi_index = abis.find(p_so.tags[i]);
+ if (abi_index != -1) {
+ exported = true;
+ String base = "res://android/build/libs";
+ String type = export_data->debug ? "debug" : "release";
+ String abi = abis[abi_index];
+ String filename = p_so.path.get_file();
+ String dst_path = base.plus_file(type).plus_file(abi).plus_file(filename);
+ Vector<uint8_t> data = FileAccess::get_file_as_array(p_so.path);
+ print_verbose("Copying .so file from " + p_so.path + " to " + dst_path);
+ Error err = store_file_at_path(dst_path, data);
+ ERR_FAIL_COND_V_MSG(err, err, "Failed to copy .so file from " + p_so.path + " to " + dst_path);
+ export_data->libs.push_back(dst_path);
+ }
+ }
+ ERR_FAIL_COND_V_MSG(!exported, FAILED,
+ "Cannot determine ABI for library \"" + p_so.path + "\". One of the supported ABIs must be used as a tag: " + String(" ").join(abis));
+ return OK;
+}
+
+void EditorExportPlatformAndroid::_get_permissions(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, Vector<String> &r_permissions) {
+ const char **aperms = android_perms;
+ while (*aperms) {
+ bool enabled = p_preset->get("permissions/" + String(*aperms).to_lower());
+ if (enabled) {
+ r_permissions.push_back("android.permission." + String(*aperms));
+ }
+ aperms++;
+ }
+ PackedStringArray user_perms = p_preset->get("permissions/custom_permissions");
+ for (int i = 0; i < user_perms.size(); i++) {
+ String user_perm = user_perms[i].strip_edges();
+ if (!user_perm.is_empty()) {
+ r_permissions.push_back(user_perm);
+ }
+ }
+ if (p_give_internet) {
+ if (r_permissions.find("android.permission.INTERNET") == -1) {
+ r_permissions.push_back("android.permission.INTERNET");
+ }
+ }
+
+ int xr_mode_index = p_preset->get("xr_features/xr_mode");
+ if (xr_mode_index == 1 /* XRMode.OVR */) {
+ int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
+ if (hand_tracking_index > 0) {
+ if (r_permissions.find("com.oculus.permission.HAND_TRACKING") == -1) {
+ r_permissions.push_back("com.oculus.permission.HAND_TRACKING");
+ }
+ }
+ }
+}
+
+void EditorExportPlatformAndroid::_write_tmp_manifest(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, bool p_debug) {
+ print_verbose("Building temporary manifest..");
+ String manifest_text =
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " xmlns:tools=\"http://schemas.android.com/tools\">\n";
+
+ manifest_text += _get_screen_sizes_tag(p_preset);
+ manifest_text += _get_gles_tag();
+
+ Vector<String> perms;
+ _get_permissions(p_preset, p_give_internet, perms);
+ for (int i = 0; i < perms.size(); i++) {
+ manifest_text += vformat(" <uses-permission android:name=\"%s\" />\n", perms.get(i));
+ }
+
+ manifest_text += _get_xr_features_tag(p_preset);
+ manifest_text += _get_instrumentation_tag(p_preset);
+ manifest_text += _get_application_tag(p_preset);
+ manifest_text += "</manifest>\n";
+ String manifest_path = vformat("res://android/build/src/%s/AndroidManifest.xml", (p_debug ? "debug" : "release"));
+
+ print_verbose("Storing manifest into " + manifest_path + ": " + "\n" + manifest_text);
+ store_string_at_path(manifest_path, manifest_text);
+}
+
+void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_manifest, bool p_give_internet) {
+ // Leaving the unused types commented because looking these constants up
+ // again later would be annoying
+ // const int CHUNK_AXML_FILE = 0x00080003;
+ // const int CHUNK_RESOURCEIDS = 0x00080180;
+ const int CHUNK_STRINGS = 0x001C0001;
+ // const int CHUNK_XML_END_NAMESPACE = 0x00100101;
+ const int CHUNK_XML_END_TAG = 0x00100103;
+ // const int CHUNK_XML_START_NAMESPACE = 0x00100100;
+ const int CHUNK_XML_START_TAG = 0x00100102;
+ // const int CHUNK_XML_TEXT = 0x00100104;
+ const int UTF8_FLAG = 0x00000100;
+
+ Vector<String> string_table;
+
+ uint32_t ofs = 8;
+
+ uint32_t string_count = 0;
+ //uint32_t styles_count = 0;
+ uint32_t string_flags = 0;
+ uint32_t string_data_offset = 0;
+
+ //uint32_t styles_offset = 0;
+ uint32_t string_table_begins = 0;
+ uint32_t string_table_ends = 0;
+ Vector<uint8_t> stable_extra;
+
+ String version_name = p_preset->get("version/name");
+ int version_code = p_preset->get("version/code");
+ String package_name = p_preset->get("package/unique_name");
+
+ const int screen_orientation =
+ _get_android_orientation_value(DisplayServer::ScreenOrientation(int(GLOBAL_GET("display/window/handheld/orientation"))));
+
+ bool screen_support_small = p_preset->get("screen/support_small");
+ bool screen_support_normal = p_preset->get("screen/support_normal");
+ bool screen_support_large = p_preset->get("screen/support_large");
+ bool screen_support_xlarge = p_preset->get("screen/support_xlarge");
+
+ int xr_mode_index = p_preset->get("xr_features/xr_mode");
+
+ bool backup_allowed = p_preset->get("user_data_backup/allow");
+ bool classify_as_game = p_preset->get("package/classify_as_game");
+
+ Vector<String> perms;
+ // Write permissions into the perms variable.
+ _get_permissions(p_preset, p_give_internet, perms);
+
+ while (ofs < (uint32_t)p_manifest.size()) {
+ uint32_t chunk = decode_uint32(&p_manifest[ofs]);
+ uint32_t size = decode_uint32(&p_manifest[ofs + 4]);
+
+ switch (chunk) {
+ case CHUNK_STRINGS: {
+ int iofs = ofs + 8;
+
+ string_count = decode_uint32(&p_manifest[iofs]);
+ //styles_count = decode_uint32(&p_manifest[iofs + 4]);
+ string_flags = decode_uint32(&p_manifest[iofs + 8]);
+ string_data_offset = decode_uint32(&p_manifest[iofs + 12]);
+ //styles_offset = decode_uint32(&p_manifest[iofs + 16]);
+ /*
+ printf("string count: %i\n",string_count);
+ printf("flags: %i\n",string_flags);
+ printf("sdata ofs: %i\n",string_data_offset);
+ printf("styles ofs: %i\n",styles_offset);
+ */
+ uint32_t st_offset = iofs + 20;
+ string_table.resize(string_count);
+ uint32_t string_end = 0;
+
+ string_table_begins = st_offset;
+
+ for (uint32_t i = 0; i < string_count; i++) {
+ uint32_t string_at = decode_uint32(&p_manifest[st_offset + i * 4]);
+ string_at += st_offset + string_count * 4;
+
+ ERR_FAIL_COND_MSG(string_flags & UTF8_FLAG, "Unimplemented, can't read UTF-8 string table.");
+
+ if (string_flags & UTF8_FLAG) {
+ } else {
+ uint32_t len = decode_uint16(&p_manifest[string_at]);
+ Vector<char32_t> ucstring;
+ ucstring.resize(len + 1);
+ for (uint32_t j = 0; j < len; j++) {
+ uint16_t c = decode_uint16(&p_manifest[string_at + 2 + 2 * j]);
+ ucstring.write[j] = c;
+ }
+ string_end = MAX(string_at + 2 + 2 * len, string_end);
+ ucstring.write[len] = 0;
+ string_table.write[i] = ucstring.ptr();
+ }
+ }
+
+ for (uint32_t i = string_end; i < (ofs + size); i++) {
+ stable_extra.push_back(p_manifest[i]);
+ }
+
+ string_table_ends = ofs + size;
+
+ } break;
+ case CHUNK_XML_START_TAG: {
+ int iofs = ofs + 8;
+ uint32_t name = decode_uint32(&p_manifest[iofs + 12]);
+
+ String tname = string_table[name];
+ uint32_t attrcount = decode_uint32(&p_manifest[iofs + 20]);
+ iofs += 28;
+
+ for (uint32_t i = 0; i < attrcount; i++) {
+ uint32_t attr_nspace = decode_uint32(&p_manifest[iofs]);
+ uint32_t attr_name = decode_uint32(&p_manifest[iofs + 4]);
+ uint32_t attr_value = decode_uint32(&p_manifest[iofs + 8]);
+ uint32_t attr_resid = decode_uint32(&p_manifest[iofs + 16]);
+
+ const String value = (attr_value != 0xFFFFFFFF) ? string_table[attr_value] : "Res #" + itos(attr_resid);
+ String attrname = string_table[attr_name];
+ const String nspace = (attr_nspace != 0xFFFFFFFF) ? string_table[attr_nspace] : "";
+
+ //replace project information
+ if (tname == "manifest" && attrname == "package") {
+ string_table.write[attr_value] = get_package_name(package_name);
+ }
+
+ if (tname == "manifest" && attrname == "versionCode") {
+ encode_uint32(version_code, &p_manifest.write[iofs + 16]);
+ }
+
+ if (tname == "manifest" && attrname == "versionName") {
+ if (attr_value == 0xFFFFFFFF) {
+ WARN_PRINT("Version name in a resource, should be plain text");
+ } else {
+ string_table.write[attr_value] = version_name;
+ }
+ }
+
+ if (tname == "application" && attrname == "allowBackup") {
+ encode_uint32(backup_allowed, &p_manifest.write[iofs + 16]);
+ }
+
+ if (tname == "application" && attrname == "isGame") {
+ encode_uint32(classify_as_game, &p_manifest.write[iofs + 16]);
+ }
+
+ if (tname == "instrumentation" && attrname == "targetPackage") {
+ string_table.write[attr_value] = get_package_name(package_name);
+ }
+
+ if (tname == "activity" && attrname == "screenOrientation") {
+ encode_uint32(screen_orientation, &p_manifest.write[iofs + 16]);
+ }
+
+ if (tname == "supports-screens") {
+ if (attrname == "smallScreens") {
+ encode_uint32(screen_support_small ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]);
+
+ } else if (attrname == "normalScreens") {
+ encode_uint32(screen_support_normal ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]);
+
+ } else if (attrname == "largeScreens") {
+ encode_uint32(screen_support_large ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]);
+
+ } else if (attrname == "xlargeScreens") {
+ encode_uint32(screen_support_xlarge ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]);
+ }
+ }
+
+ iofs += 20;
+ }
+
+ } break;
+ case CHUNK_XML_END_TAG: {
+ int iofs = ofs + 8;
+ uint32_t name = decode_uint32(&p_manifest[iofs + 12]);
+ String tname = string_table[name];
+
+ if (tname == "uses-feature") {
+ Vector<String> feature_names;
+ Vector<bool> feature_required_list;
+ Vector<int> feature_versions;
+
+ if (xr_mode_index == 1 /* XRMode.OVR */) {
+ // Check for hand tracking
+ int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
+ if (hand_tracking_index > 0) {
+ feature_names.push_back("oculus.software.handtracking");
+ feature_required_list.push_back(hand_tracking_index == 2);
+ feature_versions.push_back(-1); // no version attribute should be added.
+ }
+ }
+
+ if (feature_names.size() > 0) {
+ ofs += 24; // skip over end tag
+
+ // save manifest ending so we can restore it
+ Vector<uint8_t> manifest_end;
+ uint32_t manifest_cur_size = p_manifest.size();
+
+ manifest_end.resize(p_manifest.size() - ofs);
+ memcpy(manifest_end.ptrw(), &p_manifest[ofs], manifest_end.size());
+
+ int32_t attr_name_string = string_table.find("name");
+ ERR_FAIL_COND_MSG(attr_name_string == -1, "Template does not have 'name' attribute.");
+
+ int32_t ns_android_string = string_table.find("http://schemas.android.com/apk/res/android");
+ if (ns_android_string == -1) {
+ string_table.push_back("http://schemas.android.com/apk/res/android");
+ ns_android_string = string_table.size() - 1;
+ }
+
+ int32_t attr_uses_feature_string = string_table.find("uses-feature");
+ if (attr_uses_feature_string == -1) {
+ string_table.push_back("uses-feature");
+ attr_uses_feature_string = string_table.size() - 1;
+ }
+
+ int32_t attr_required_string = string_table.find("required");
+ if (attr_required_string == -1) {
+ string_table.push_back("required");
+ attr_required_string = string_table.size() - 1;
+ }
+
+ for (int i = 0; i < feature_names.size(); i++) {
+ String feature_name = feature_names[i];
+ bool feature_required = feature_required_list[i];
+ int feature_version = feature_versions[i];
+ bool has_version_attribute = feature_version != -1;
+
+ print_line("Adding feature " + feature_name);
+
+ int32_t feature_string = string_table.find(feature_name);
+ if (feature_string == -1) {
+ string_table.push_back(feature_name);
+ feature_string = string_table.size() - 1;
+ }
+
+ String required_value_string = feature_required ? "true" : "false";
+ int32_t required_value = string_table.find(required_value_string);
+ if (required_value == -1) {
+ string_table.push_back(required_value_string);
+ required_value = string_table.size() - 1;
+ }
+
+ int32_t attr_version_string = -1;
+ int32_t version_value = -1;
+ int tag_size;
+ int attr_count;
+ if (has_version_attribute) {
+ attr_version_string = string_table.find("version");
+ if (attr_version_string == -1) {
+ string_table.push_back("version");
+ attr_version_string = string_table.size() - 1;
+ }
+
+ version_value = string_table.find(itos(feature_version));
+ if (version_value == -1) {
+ string_table.push_back(itos(feature_version));
+ version_value = string_table.size() - 1;
+ }
+
+ tag_size = 96; // node and three attrs + end node
+ attr_count = 3;
+ } else {
+ tag_size = 76; // node and two attrs + end node
+ attr_count = 2;
+ }
+ manifest_cur_size += tag_size + 24;
+ p_manifest.resize(manifest_cur_size);
+
+ // start tag
+ encode_uint16(0x102, &p_manifest.write[ofs]); // type
+ encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize
+ encode_uint32(tag_size, &p_manifest.write[ofs + 4]); // size
+ encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno
+ encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment
+ encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns
+ encode_uint32(attr_uses_feature_string, &p_manifest.write[ofs + 20]); // name
+ encode_uint16(20, &p_manifest.write[ofs + 24]); // attr_start
+ encode_uint16(20, &p_manifest.write[ofs + 26]); // attr_size
+ encode_uint16(attr_count, &p_manifest.write[ofs + 28]); // num_attrs
+ encode_uint16(0, &p_manifest.write[ofs + 30]); // id_index
+ encode_uint16(0, &p_manifest.write[ofs + 32]); // class_index
+ encode_uint16(0, &p_manifest.write[ofs + 34]); // style_index
+
+ // android:name attribute
+ encode_uint32(ns_android_string, &p_manifest.write[ofs + 36]); // ns
+ encode_uint32(attr_name_string, &p_manifest.write[ofs + 40]); // 'name'
+ encode_uint32(feature_string, &p_manifest.write[ofs + 44]); // raw_value
+ encode_uint16(8, &p_manifest.write[ofs + 48]); // typedvalue_size
+ p_manifest.write[ofs + 50] = 0; // typedvalue_always0
+ p_manifest.write[ofs + 51] = 0x03; // typedvalue_type (string)
+ encode_uint32(feature_string, &p_manifest.write[ofs + 52]); // typedvalue reference
+
+ // android:required attribute
+ encode_uint32(ns_android_string, &p_manifest.write[ofs + 56]); // ns
+ encode_uint32(attr_required_string, &p_manifest.write[ofs + 60]); // 'name'
+ encode_uint32(required_value, &p_manifest.write[ofs + 64]); // raw_value
+ encode_uint16(8, &p_manifest.write[ofs + 68]); // typedvalue_size
+ p_manifest.write[ofs + 70] = 0; // typedvalue_always0
+ p_manifest.write[ofs + 71] = 0x03; // typedvalue_type (string)
+ encode_uint32(required_value, &p_manifest.write[ofs + 72]); // typedvalue reference
+
+ ofs += 76;
+
+ if (has_version_attribute) {
+ // android:version attribute
+ encode_uint32(ns_android_string, &p_manifest.write[ofs]); // ns
+ encode_uint32(attr_version_string, &p_manifest.write[ofs + 4]); // 'name'
+ encode_uint32(version_value, &p_manifest.write[ofs + 8]); // raw_value
+ encode_uint16(8, &p_manifest.write[ofs + 12]); // typedvalue_size
+ p_manifest.write[ofs + 14] = 0; // typedvalue_always0
+ p_manifest.write[ofs + 15] = 0x03; // typedvalue_type (string)
+ encode_uint32(version_value, &p_manifest.write[ofs + 16]); // typedvalue reference
+
+ ofs += 20;
+ }
+
+ // end tag
+ encode_uint16(0x103, &p_manifest.write[ofs]); // type
+ encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize
+ encode_uint32(24, &p_manifest.write[ofs + 4]); // size
+ encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno
+ encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment
+ encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns
+ encode_uint32(attr_uses_feature_string, &p_manifest.write[ofs + 20]); // name
+
+ ofs += 24;
+ }
+ memcpy(&p_manifest.write[ofs], manifest_end.ptr(), manifest_end.size());
+ ofs -= 24; // go back over back end
+ }
+ }
+ if (tname == "manifest") {
+ // save manifest ending so we can restore it
+ Vector<uint8_t> manifest_end;
+ uint32_t manifest_cur_size = p_manifest.size();
+
+ manifest_end.resize(p_manifest.size() - ofs);
+ memcpy(manifest_end.ptrw(), &p_manifest[ofs], manifest_end.size());
+
+ int32_t attr_name_string = string_table.find("name");
+ ERR_FAIL_COND_MSG(attr_name_string == -1, "Template does not have 'name' attribute.");
+
+ int32_t ns_android_string = string_table.find("android");
+ ERR_FAIL_COND_MSG(ns_android_string == -1, "Template does not have 'android' namespace.");
+
+ int32_t attr_uses_permission_string = string_table.find("uses-permission");
+ if (attr_uses_permission_string == -1) {
+ string_table.push_back("uses-permission");
+ attr_uses_permission_string = string_table.size() - 1;
+ }
+
+ for (int i = 0; i < perms.size(); ++i) {
+ print_line("Adding permission " + perms[i]);
+
+ manifest_cur_size += 56 + 24; // node + end node
+ p_manifest.resize(manifest_cur_size);
+
+ // Add permission to the string pool
+ int32_t perm_string = string_table.find(perms[i]);
+ if (perm_string == -1) {
+ string_table.push_back(perms[i]);
+ perm_string = string_table.size() - 1;
+ }
+
+ // start tag
+ encode_uint16(0x102, &p_manifest.write[ofs]); // type
+ encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize
+ encode_uint32(56, &p_manifest.write[ofs + 4]); // size
+ encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno
+ encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment
+ encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns
+ encode_uint32(attr_uses_permission_string, &p_manifest.write[ofs + 20]); // name
+ encode_uint16(20, &p_manifest.write[ofs + 24]); // attr_start
+ encode_uint16(20, &p_manifest.write[ofs + 26]); // attr_size
+ encode_uint16(1, &p_manifest.write[ofs + 28]); // num_attrs
+ encode_uint16(0, &p_manifest.write[ofs + 30]); // id_index
+ encode_uint16(0, &p_manifest.write[ofs + 32]); // class_index
+ encode_uint16(0, &p_manifest.write[ofs + 34]); // style_index
+
+ // attribute
+ encode_uint32(ns_android_string, &p_manifest.write[ofs + 36]); // ns
+ encode_uint32(attr_name_string, &p_manifest.write[ofs + 40]); // 'name'
+ encode_uint32(perm_string, &p_manifest.write[ofs + 44]); // raw_value
+ encode_uint16(8, &p_manifest.write[ofs + 48]); // typedvalue_size
+ p_manifest.write[ofs + 50] = 0; // typedvalue_always0
+ p_manifest.write[ofs + 51] = 0x03; // typedvalue_type (string)
+ encode_uint32(perm_string, &p_manifest.write[ofs + 52]); // typedvalue reference
+
+ ofs += 56;
+
+ // end tag
+ encode_uint16(0x103, &p_manifest.write[ofs]); // type
+ encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize
+ encode_uint32(24, &p_manifest.write[ofs + 4]); // size
+ encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno
+ encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment
+ encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns
+ encode_uint32(attr_uses_permission_string, &p_manifest.write[ofs + 20]); // name
+
+ ofs += 24;
+ }
+
+ // copy footer back in
+ memcpy(&p_manifest.write[ofs], manifest_end.ptr(), manifest_end.size());
+ }
+ } break;
+ }
+
+ ofs += size;
+ }
+
+ //create new andriodmanifest binary
+
+ Vector<uint8_t> ret;
+ ret.resize(string_table_begins + string_table.size() * 4);
+
+ for (uint32_t i = 0; i < string_table_begins; i++) {
+ ret.write[i] = p_manifest[i];
+ }
+
+ ofs = 0;
+ for (int i = 0; i < string_table.size(); i++) {
+ encode_uint32(ofs, &ret.write[string_table_begins + i * 4]);
+ ofs += string_table[i].length() * 2 + 2 + 2;
+ }
+
+ ret.resize(ret.size() + ofs);
+ string_data_offset = ret.size() - ofs;
+ uint8_t *chars = &ret.write[string_data_offset];
+ for (int i = 0; i < string_table.size(); i++) {
+ String s = string_table[i];
+ encode_uint16(s.length(), chars);
+ chars += 2;
+ for (int j = 0; j < s.length(); j++) {
+ encode_uint16(s[j], chars);
+ chars += 2;
+ }
+ encode_uint16(0, chars);
+ chars += 2;
+ }
+
+ for (int i = 0; i < stable_extra.size(); i++) {
+ ret.push_back(stable_extra[i]);
+ }
+
+ //pad
+ while (ret.size() % 4) {
+ ret.push_back(0);
+ }
+
+ uint32_t new_stable_end = ret.size();
+
+ uint32_t extra = (p_manifest.size() - string_table_ends);
+ ret.resize(new_stable_end + extra);
+ for (uint32_t i = 0; i < extra; i++) {
+ ret.write[new_stable_end + i] = p_manifest[string_table_ends + i];
+ }
+
+ while (ret.size() % 4) {
+ ret.push_back(0);
+ }
+ encode_uint32(ret.size(), &ret.write[4]); //update new file size
+
+ encode_uint32(new_stable_end - 8, &ret.write[12]); //update new string table size
+ encode_uint32(string_table.size(), &ret.write[16]); //update new number of strings
+ encode_uint32(string_data_offset - 8, &ret.write[28]); //update new string data offset
+
+ p_manifest = ret;
+}
+
+String EditorExportPlatformAndroid::_parse_string(const uint8_t *p_bytes, bool p_utf8) {
+ uint32_t offset = 0;
+ uint32_t len = 0;
+
+ if (p_utf8) {
+ uint8_t byte = p_bytes[offset];
+ if (byte & 0x80) {
+ offset += 2;
+ } else {
+ offset += 1;
+ }
+ byte = p_bytes[offset];
+ offset++;
+ if (byte & 0x80) {
+ len = byte & 0x7F;
+ len = (len << 8) + p_bytes[offset];
+ offset++;
+ } else {
+ len = byte;
+ }
+ } else {
+ len = decode_uint16(&p_bytes[offset]);
+ offset += 2;
+ if (len & 0x8000) {
+ len &= 0x7FFF;
+ len = (len << 16) + decode_uint16(&p_bytes[offset]);
+ offset += 2;
+ }
+ }
+
+ if (p_utf8) {
+ Vector<uint8_t> str8;
+ str8.resize(len + 1);
+ for (uint32_t i = 0; i < len; i++) {
+ str8.write[i] = p_bytes[offset + i];
+ }
+ str8.write[len] = 0;
+ String str;
+ str.parse_utf8((const char *)str8.ptr());
+ return str;
+ } else {
+ String str;
+ for (uint32_t i = 0; i < len; i++) {
+ char32_t c = decode_uint16(&p_bytes[offset + i * 2]);
+ if (c == 0) {
+ break;
+ }
+ str += String::chr(c);
+ }
+ return str;
+ }
+}
+
+void EditorExportPlatformAndroid::_fix_resources(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &r_manifest) {
+ const int UTF8_FLAG = 0x00000100;
+
+ uint32_t string_block_len = decode_uint32(&r_manifest[16]);
+ uint32_t string_count = decode_uint32(&r_manifest[20]);
+ uint32_t string_flags = decode_uint32(&r_manifest[28]);
+ const uint32_t string_table_begins = 40;
+
+ Vector<String> string_table;
+
+ String package_name = p_preset->get("package/name");
+
+ for (uint32_t i = 0; i < string_count; i++) {
+ uint32_t offset = decode_uint32(&r_manifest[string_table_begins + i * 4]);
+ offset += string_table_begins + string_count * 4;
+
+ String str = _parse_string(&r_manifest[offset], string_flags & UTF8_FLAG);
+
+ if (str.begins_with("godot-project-name")) {
+ if (str == "godot-project-name") {
+ //project name
+ str = get_project_name(package_name);
+
+ } else {
+ String lang = str.substr(str.rfind("-") + 1, str.length()).replace("-", "_");
+ String prop = "application/config/name_" + lang;
+ if (ProjectSettings::get_singleton()->has_setting(prop)) {
+ str = ProjectSettings::get_singleton()->get(prop);
+ } else {
+ str = get_project_name(package_name);
+ }
+ }
+ }
+
+ string_table.push_back(str);
+ }
+
+ //write a new string table, but use 16 bits
+ Vector<uint8_t> ret;
+ ret.resize(string_table_begins + string_table.size() * 4);
+
+ for (uint32_t i = 0; i < string_table_begins; i++) {
+ ret.write[i] = r_manifest[i];
+ }
+
+ int ofs = 0;
+ for (int i = 0; i < string_table.size(); i++) {
+ encode_uint32(ofs, &ret.write[string_table_begins + i * 4]);
+ ofs += string_table[i].length() * 2 + 2 + 2;
+ }
+
+ ret.resize(ret.size() + ofs);
+ uint8_t *chars = &ret.write[ret.size() - ofs];
+ for (int i = 0; i < string_table.size(); i++) {
+ String s = string_table[i];
+ encode_uint16(s.length(), chars);
+ chars += 2;
+ for (int j = 0; j < s.length(); j++) {
+ encode_uint16(s[j], chars);
+ chars += 2;
+ }
+ encode_uint16(0, chars);
+ chars += 2;
+ }
+
+ //pad
+ while (ret.size() % 4) {
+ ret.push_back(0);
+ }
+
+ //change flags to not use utf8
+ encode_uint32(string_flags & ~0x100, &ret.write[28]);
+ //change length
+ encode_uint32(ret.size() - 12, &ret.write[16]);
+ //append the rest...
+ int rest_from = 12 + string_block_len;
+ int rest_to = ret.size();
+ int rest_len = (r_manifest.size() - rest_from);
+ ret.resize(ret.size() + (r_manifest.size() - rest_from));
+ for (int i = 0; i < rest_len; i++) {
+ ret.write[rest_to + i] = r_manifest[rest_from + i];
+ }
+ //finally update the size
+ encode_uint32(ret.size(), &ret.write[4]);
+
+ r_manifest = ret;
+ //printf("end\n");
+}
+
+void EditorExportPlatformAndroid::_load_image_data(const Ref<Image> &p_splash_image, Vector<uint8_t> &p_data) {
+ Vector<uint8_t> png_buffer;
+ Error err = PNGDriverCommon::image_to_png(p_splash_image, png_buffer);
+ if (err == OK) {
+ p_data.resize(png_buffer.size());
+ memcpy(p_data.ptrw(), png_buffer.ptr(), p_data.size());
+ } else {
+ String err_str = String("Failed to convert splash image to png.");
+ WARN_PRINT(err_str.utf8().get_data());
+ }
+}
+
+void EditorExportPlatformAndroid::_process_launcher_icons(const String &p_file_name, const Ref<Image> &p_source_image, int dimension, Vector<uint8_t> &p_data) {
+ Ref<Image> working_image = p_source_image;
+
+ if (p_source_image->get_width() != dimension || p_source_image->get_height() != dimension) {
+ working_image = p_source_image->duplicate();
+ working_image->resize(dimension, dimension, Image::Interpolation::INTERPOLATE_LANCZOS);
+ }
+
+ Vector<uint8_t> png_buffer;
+ Error err = PNGDriverCommon::image_to_png(working_image, png_buffer);
+ if (err == OK) {
+ p_data.resize(png_buffer.size());
+ memcpy(p_data.ptrw(), png_buffer.ptr(), p_data.size());
+ } else {
+ String err_str = String("Failed to convert resized icon (") + p_file_name + ") to png.";
+ WARN_PRINT(err_str.utf8().get_data());
+ }
+}
+
+String EditorExportPlatformAndroid::load_splash_refs(Ref<Image> &splash_image, Ref<Image> &splash_bg_color_image) {
+ bool scale_splash = ProjectSettings::get_singleton()->get("application/boot_splash/fullsize");
+ bool apply_filter = ProjectSettings::get_singleton()->get("application/boot_splash/use_filter");
+ String project_splash_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
+
+ if (!project_splash_path.is_empty()) {
+ splash_image.instantiate();
+ print_verbose("Loading splash image: " + project_splash_path);
+ const Error err = ImageLoader::load_image(project_splash_path, splash_image);
+ if (err) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ print_error("- unable to load splash image from " + project_splash_path + " (" + itos(err) + ")");
+ }
+ splash_image.unref();
+ }
+ }
+
+ if (splash_image.is_null()) {
+ // Use the default
+ print_verbose("Using default splash image.");
+ splash_image = Ref<Image>(memnew(Image(boot_splash_png)));
+ }
+
+ if (scale_splash) {
+ Size2 screen_size = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
+ int width, height;
+ if (screen_size.width > screen_size.height) {
+ // scale horizontally
+ height = screen_size.height;
+ width = splash_image->get_width() * screen_size.height / splash_image->get_height();
+ } else {
+ // scale vertically
+ width = screen_size.width;
+ height = splash_image->get_height() * screen_size.width / splash_image->get_width();
+ }
+ splash_image->resize(width, height);
+ }
+
+ // Setup the splash bg color
+ bool bg_color_valid;
+ Color bg_color = ProjectSettings::get_singleton()->get("application/boot_splash/bg_color", &bg_color_valid);
+ if (!bg_color_valid) {
+ bg_color = boot_splash_bg_color;
+ }
+
+ print_verbose("Creating splash background color image.");
+ splash_bg_color_image.instantiate();
+ splash_bg_color_image->create(splash_image->get_width(), splash_image->get_height(), false, splash_image->get_format());
+ splash_bg_color_image->fill(bg_color);
+
+ String processed_splash_config_xml = vformat(SPLASH_CONFIG_XML_CONTENT, bool_to_string(apply_filter));
+ return processed_splash_config_xml;
+}
+
+void EditorExportPlatformAndroid::load_icon_refs(const Ref<EditorExportPreset> &p_preset, Ref<Image> &icon, Ref<Image> &foreground, Ref<Image> &background) {
+ String project_icon_path = ProjectSettings::get_singleton()->get("application/config/icon");
+
+ icon.instantiate();
+ foreground.instantiate();
+ background.instantiate();
+
+ // Regular icon: user selection -> project icon -> default.
+ String path = static_cast<String>(p_preset->get(launcher_icon_option)).strip_edges();
+ print_verbose("Loading regular icon from " + path);
+ if (path.is_empty() || ImageLoader::load_image(path, icon) != OK) {
+ print_verbose("- falling back to project icon: " + project_icon_path);
+ ImageLoader::load_image(project_icon_path, icon);
+ }
+
+ // Adaptive foreground: user selection -> regular icon (user selection -> project icon -> default).
+ path = static_cast<String>(p_preset->get(launcher_adaptive_icon_foreground_option)).strip_edges();
+ print_verbose("Loading adaptive foreground icon from " + path);
+ if (path.is_empty() || ImageLoader::load_image(path, foreground) != OK) {
+ print_verbose("- falling back to using the regular icon");
+ foreground = icon;
+ }
+
+ // Adaptive background: user selection -> default.
+ path = static_cast<String>(p_preset->get(launcher_adaptive_icon_background_option)).strip_edges();
+ if (!path.is_empty()) {
+ print_verbose("Loading adaptive background icon from " + path);
+ ImageLoader::load_image(path, background);
+ }
+}
+
+void EditorExportPlatformAndroid::store_image(const LauncherIcon launcher_icon, const Vector<uint8_t> &data) {
+ store_image(launcher_icon.export_path, data);
+}
+
+void EditorExportPlatformAndroid::store_image(const String &export_path, const Vector<uint8_t> &data) {
+ String img_path = export_path.insert(0, "res://android/build/");
+ store_file_at_path(img_path, data);
+}
+
+void EditorExportPlatformAndroid::_copy_icons_to_gradle_project(const Ref<EditorExportPreset> &p_preset,
+ const String &processed_splash_config_xml,
+ const Ref<Image> &splash_image,
+ const Ref<Image> &splash_bg_color_image,
+ const Ref<Image> &main_image,
+ const Ref<Image> &foreground,
+ const Ref<Image> &background) {
+ // Store the splash configuration
+ if (!processed_splash_config_xml.is_empty()) {
+ print_verbose("Storing processed splash configuration: " + String("\n") + processed_splash_config_xml);
+ store_string_at_path(SPLASH_CONFIG_PATH, processed_splash_config_xml);
+ }
+
+ // Store the splash image
+ if (splash_image.is_valid() && !splash_image->is_empty()) {
+ print_verbose("Storing splash image in " + String(SPLASH_IMAGE_EXPORT_PATH));
+ Vector<uint8_t> data;
+ _load_image_data(splash_image, data);
+ store_image(SPLASH_IMAGE_EXPORT_PATH, data);
+ }
+
+ // Store the splash bg color image
+ if (splash_bg_color_image.is_valid() && !splash_bg_color_image->is_empty()) {
+ print_verbose("Storing splash background image in " + String(SPLASH_BG_COLOR_PATH));
+ Vector<uint8_t> data;
+ _load_image_data(splash_bg_color_image, data);
+ store_image(SPLASH_BG_COLOR_PATH, data);
+ }
+
+ // Prepare images to be resized for the icons. If some image ends up being uninitialized,
+ // the default image from the export template will be used.
+
+ for (int i = 0; i < icon_densities_count; ++i) {
+ if (main_image.is_valid() && !main_image->is_empty()) {
+ print_verbose("Processing launcher icon for dimension " + itos(launcher_icons[i].dimensions) + " into " + launcher_icons[i].export_path);
+ Vector<uint8_t> data;
+ _process_launcher_icons(launcher_icons[i].export_path, main_image, launcher_icons[i].dimensions, data);
+ store_image(launcher_icons[i], data);
+ }
+
+ if (foreground.is_valid() && !foreground->is_empty()) {
+ print_verbose("Processing launcher adaptive icon foreground for dimension " + itos(launcher_adaptive_icon_foregrounds[i].dimensions) + " into " + launcher_adaptive_icon_foregrounds[i].export_path);
+ Vector<uint8_t> data;
+ _process_launcher_icons(launcher_adaptive_icon_foregrounds[i].export_path, foreground,
+ launcher_adaptive_icon_foregrounds[i].dimensions, data);
+ store_image(launcher_adaptive_icon_foregrounds[i], data);
+ }
+
+ if (background.is_valid() && !background->is_empty()) {
+ print_verbose("Processing launcher adaptive icon background for dimension " + itos(launcher_adaptive_icon_backgrounds[i].dimensions) + " into " + launcher_adaptive_icon_backgrounds[i].export_path);
+ Vector<uint8_t> data;
+ _process_launcher_icons(launcher_adaptive_icon_backgrounds[i].export_path, background,
+ launcher_adaptive_icon_backgrounds[i].dimensions, data);
+ store_image(launcher_adaptive_icon_backgrounds[i], data);
+ }
+ }
+}
+
+Vector<String> EditorExportPlatformAndroid::get_enabled_abis(const Ref<EditorExportPreset> &p_preset) {
+ Vector<String> abis = get_abis();
+ Vector<String> enabled_abis;
+ for (int i = 0; i < abis.size(); ++i) {
+ bool is_enabled = p_preset->get("architectures/" + abis[i]);
+ if (is_enabled) {
+ enabled_abis.push_back(abis[i]);
+ }
+ }
+ return enabled_abis;
+}
+
+void EditorExportPlatformAndroid::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
+ String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
+ if (driver == "GLES2") {
+ r_features->push_back("etc");
+ }
+ // FIXME: Review what texture formats are used for Vulkan.
+ if (driver == "Vulkan") {
+ r_features->push_back("etc2");
+ }
+
+ Vector<String> abis = get_enabled_abis(p_preset);
+ for (int i = 0; i < abis.size(); ++i) {
+ r_features->push_back(abis[i]);
+ }
+}
+
+void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_options) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "custom_template/use_custom_build"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "custom_template/export_format", PROPERTY_HINT_ENUM, "Export APK,Export AAB"), EXPORT_FORMAT_APK));
+
+ Vector<PluginConfigAndroid> plugins_configs = get_plugins();
+ for (int i = 0; i < plugins_configs.size(); i++) {
+ print_verbose("Found Android plugin " + plugins_configs[i].name);
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "plugins/" + plugins_configs[i].name), false));
+ }
+ plugins_changed.clear();
+
+ Vector<String> abis = get_abis();
+ for (int i = 0; i < abis.size(); ++i) {
+ String abi = abis[i];
+ bool is_default = (abi == "armeabi-v7a" || abi == "arm64-v8a");
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architectures/" + abi), is_default));
+ }
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_user"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_password"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_user"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_password"), ""));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "one_click_deploy/clear_previous_install"), false));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "ext.domain.name"), "org.godotengine.$genname"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name [default if blank]"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/signed"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/classify_as_game"), true));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_icon_option, PROPERTY_HINT_FILE, "*.png"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_adaptive_icon_foreground_option, PROPERTY_HINT_FILE, "*.png"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_adaptive_icon_background_option, PROPERTY_HINT_FILE, "*.png"), ""));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/32_bits_framebuffer"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/opengl_debug"), false));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/xr_mode", PROPERTY_HINT_ENUM, "Regular,Oculus Mobile VR"), 0));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/hand_tracking", PROPERTY_HINT_ENUM, "None,Optional,Required"), 0));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/immersive_mode"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_small"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_normal"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_large"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_xlarge"), true));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "user_data_backup/allow"), false));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), ""));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "apk_expansion/enable"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "apk_expansion/SALT"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "apk_expansion/public_key", PROPERTY_HINT_MULTILINE_TEXT), ""));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "permissions/custom_permissions"), PackedStringArray()));
+
+ const char **perms = android_perms;
+ while (*perms) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "permissions/" + String(*perms).to_lower()), false));
+ perms++;
+ }
+}
+
+String EditorExportPlatformAndroid::get_name() const {
+ return "Android";
+}
+
+String EditorExportPlatformAndroid::get_os_name() const {
+ return "Android";
+}
+
+Ref<Texture2D> EditorExportPlatformAndroid::get_logo() const {
+ return logo;
+}
+
+bool EditorExportPlatformAndroid::should_update_export_options() {
+ bool export_options_changed = plugins_changed.is_set();
+ if (export_options_changed) {
+ // don't clear unless we're reporting true, to avoid race
+ plugins_changed.clear();
+ }
+ return export_options_changed;
+}
+
+bool EditorExportPlatformAndroid::poll_export() {
+ bool dc = devices_changed.is_set();
+ if (dc) {
+ // don't clear unless we're reporting true, to avoid race
+ devices_changed.clear();
+ }
+ return dc;
+}
+
+int EditorExportPlatformAndroid::get_options_count() const {
+ MutexLock lock(device_lock);
+ return devices.size();
+}
+
+String EditorExportPlatformAndroid::get_options_tooltip() const {
+ return TTR("Select device from the list");
+}
+
+String EditorExportPlatformAndroid::get_option_label(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, devices.size(), "");
+ MutexLock lock(device_lock);
+ return devices[p_index].name;
+}
+
+String EditorExportPlatformAndroid::get_option_tooltip(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, devices.size(), "");
+ MutexLock lock(device_lock);
+ String s = devices[p_index].description;
+ if (devices.size() == 1) {
+ // Tooltip will be:
+ // Name
+ // Description
+ s = devices[p_index].name + "\n\n" + s;
+ }
+ return s;
+}
+
+Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) {
+ ERR_FAIL_INDEX_V(p_device, devices.size(), ERR_INVALID_PARAMETER);
+
+ String can_export_error;
+ bool can_export_missing_templates;
+ if (!can_export(p_preset, can_export_error, can_export_missing_templates)) {
+ EditorNode::add_io_error(can_export_error);
+ return ERR_UNCONFIGURED;
+ }
+
+ MutexLock lock(device_lock);
+
+ EditorProgress ep("run", vformat(TTR("Running on %s"), devices[p_device].name), 3);
+
+ String adb = get_adb_path();
+
+ // Export_temp APK.
+ if (ep.step(TTR("Exporting APK..."), 0)) {
+ return ERR_SKIP;
+ }
+
+ const bool use_remote = (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) || (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT);
+ const bool use_reverse = devices[p_device].api_level >= 21;
+
+ if (use_reverse) {
+ p_debug_flags |= DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST;
+ }
+
+ String tmp_export_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpexport." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
+
+#define CLEANUP_AND_RETURN(m_err) \
+ { \
+ DirAccess::remove_file_or_error(tmp_export_path); \
+ return m_err; \
+ }
+
+ // Export to temporary APK before sending to device.
+ Error err = export_project_helper(p_preset, true, tmp_export_path, EXPORT_FORMAT_APK, true, p_debug_flags);
+
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ List<String> args;
+ int rv;
+ String output;
+
+ bool remove_prev = p_preset->get("one_click_deploy/clear_previous_install");
+ String version_name = p_preset->get("version/name");
+ String package_name = p_preset->get("package/unique_name");
+
+ if (remove_prev) {
+ if (ep.step(TTR("Uninstalling..."), 1)) {
+ CLEANUP_AND_RETURN(ERR_SKIP);
+ }
+
+ print_line("Uninstalling previous version: " + devices[p_device].name);
+
+ args.push_back("-s");
+ args.push_back(devices[p_device].id);
+ args.push_back("uninstall");
+ args.push_back(get_package_name(package_name));
+
+ output.clear();
+ err = OS::get_singleton()->execute(adb, args, &output, &rv, true);
+ print_verbose(output);
+ }
+
+ print_line("Installing to device (please wait...): " + devices[p_device].name);
+ if (ep.step(TTR("Installing to device, please wait..."), 2)) {
+ CLEANUP_AND_RETURN(ERR_SKIP);
+ }
+
+ args.clear();
+ args.push_back("-s");
+ args.push_back(devices[p_device].id);
+ args.push_back("install");
+ args.push_back("-r");
+ args.push_back(tmp_export_path);
+
+ output.clear();
+ err = OS::get_singleton()->execute(adb, args, &output, &rv, true);
+ print_verbose(output);
+ if (err || rv != 0) {
+ EditorNode::add_io_error(vformat(TTR("Could not install to device: %s"), output));
+ CLEANUP_AND_RETURN(ERR_CANT_CREATE);
+ }
+
+ if (use_remote) {
+ if (use_reverse) {
+ static const char *const msg = "--- Device API >= 21; debugging over USB ---";
+ EditorNode::get_singleton()->get_log()->add_message(msg, EditorLog::MSG_TYPE_EDITOR);
+ print_line(String(msg).to_upper());
+
+ args.clear();
+ args.push_back("-s");
+ args.push_back(devices[p_device].id);
+ args.push_back("reverse");
+ args.push_back("--remove-all");
+ output.clear();
+ OS::get_singleton()->execute(adb, args, &output, &rv, true);
+ print_verbose(output);
+
+ if (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) {
+ int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port");
+ args.clear();
+ args.push_back("-s");
+ args.push_back(devices[p_device].id);
+ args.push_back("reverse");
+ args.push_back("tcp:" + itos(dbg_port));
+ args.push_back("tcp:" + itos(dbg_port));
+
+ output.clear();
+ OS::get_singleton()->execute(adb, args, &output, &rv, true);
+ print_verbose(output);
+ print_line("Reverse result: " + itos(rv));
+ }
+
+ if (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT) {
+ int fs_port = EditorSettings::get_singleton()->get("filesystem/file_server/port");
+
+ args.clear();
+ args.push_back("-s");
+ args.push_back(devices[p_device].id);
+ args.push_back("reverse");
+ args.push_back("tcp:" + itos(fs_port));
+ args.push_back("tcp:" + itos(fs_port));
+
+ output.clear();
+ err = OS::get_singleton()->execute(adb, args, &output, &rv, true);
+ print_verbose(output);
+ print_line("Reverse result2: " + itos(rv));
+ }
+ } else {
+ static const char *const msg = "--- Device API < 21; debugging over Wi-Fi ---";
+ EditorNode::get_singleton()->get_log()->add_message(msg, EditorLog::MSG_TYPE_EDITOR);
+ print_line(String(msg).to_upper());
+ }
+ }
+
+ if (ep.step(TTR("Running on device..."), 3)) {
+ CLEANUP_AND_RETURN(ERR_SKIP);
+ }
+ args.clear();
+ args.push_back("-s");
+ args.push_back(devices[p_device].id);
+ args.push_back("shell");
+ args.push_back("am");
+ args.push_back("start");
+ if ((bool)EditorSettings::get_singleton()->get("export/android/force_system_user") && devices[p_device].api_level >= 17) { // Multi-user introduced in Android 17
+ args.push_back("--user");
+ args.push_back("0");
+ }
+ args.push_back("-a");
+ args.push_back("android.intent.action.MAIN");
+ args.push_back("-n");
+ args.push_back(get_package_name(package_name) + "/com.godot.game.GodotApp");
+
+ output.clear();
+ err = OS::get_singleton()->execute(adb, args, &output, &rv, true);
+ print_verbose(output);
+ if (err || rv != 0) {
+ EditorNode::add_io_error(TTR("Could not execute on device."));
+ CLEANUP_AND_RETURN(ERR_CANT_CREATE);
+ }
+
+ CLEANUP_AND_RETURN(OK);
+#undef CLEANUP_AND_RETURN
+}
+
+Ref<Texture2D> EditorExportPlatformAndroid::get_run_icon() const {
+ return run_icon;
+}
+
+String EditorExportPlatformAndroid::get_adb_path() {
+ String exe_ext = "";
+ if (OS::get_singleton()->get_name() == "Windows") {
+ exe_ext = ".exe";
+ }
+ String sdk_path = EditorSettings::get_singleton()->get("export/android/android_sdk_path");
+ return sdk_path.plus_file("platform-tools/adb" + exe_ext);
+}
+
+String EditorExportPlatformAndroid::get_apksigner_path() {
+ String exe_ext = "";
+ if (OS::get_singleton()->get_name() == "Windows") {
+ exe_ext = ".bat";
+ }
+ String apksigner_command_name = "apksigner" + exe_ext;
+ String sdk_path = EditorSettings::get_singleton()->get("export/android/android_sdk_path");
+ String apksigner_path = "";
+
+ Error errn;
+ String build_tools_dir = sdk_path.plus_file("build-tools");
+ DirAccessRef da = DirAccess::open(build_tools_dir, &errn);
+ if (errn != OK) {
+ print_error("Unable to open Android 'build-tools' directory.");
+ return apksigner_path;
+ }
+
+ // There are additional versions directories we need to go through.
+ da->list_dir_begin();
+ String sub_dir = da->get_next();
+ while (!sub_dir.is_empty()) {
+ if (!sub_dir.begins_with(".") && da->current_is_dir()) {
+ // Check if the tool is here.
+ String tool_path = build_tools_dir.plus_file(sub_dir).plus_file(apksigner_command_name);
+ if (FileAccess::exists(tool_path)) {
+ apksigner_path = tool_path;
+ break;
+ }
+ }
+ sub_dir = da->get_next();
+ }
+ da->list_dir_end();
+
+ if (apksigner_path.is_empty()) {
+ EditorNode::get_singleton()->show_warning(TTR("Unable to find the 'apksigner' tool."));
+ }
+
+ return apksigner_path;
+}
+
+bool EditorExportPlatformAndroid::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+ String err;
+ bool valid = false;
+
+ // Look for export templates (first official, and if defined custom templates).
+
+ if (!bool(p_preset->get("custom_template/use_custom_build"))) {
+ String template_err;
+ bool dvalid = false;
+ bool rvalid = false;
+ bool has_export_templates = false;
+
+ if (p_preset->get("custom_template/debug") != "") {
+ dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
+ if (!dvalid) {
+ template_err += TTR("Custom debug template not found.") + "\n";
+ }
+ } else {
+ has_export_templates |= exists_export_template("android_debug.apk", &template_err);
+ }
+
+ if (p_preset->get("custom_template/release") != "") {
+ rvalid = FileAccess::exists(p_preset->get("custom_template/release"));
+ if (!rvalid) {
+ template_err += TTR("Custom release template not found.") + "\n";
+ }
+ } else {
+ has_export_templates |= exists_export_template("android_release.apk", &template_err);
+ }
+
+ r_missing_templates = !has_export_templates;
+ valid = dvalid || rvalid || has_export_templates;
+ if (!valid) {
+ err += template_err;
+ }
+ } else {
+ bool installed_android_build_template = FileAccess::exists("res://android/build/build.gradle");
+ if (!installed_android_build_template) {
+ r_missing_templates = !exists_export_template("android_source.zip", &err);
+ err += TTR("Android build template not installed in the project. Install it from the Project menu.") + "\n";
+ } else {
+ r_missing_templates = false;
+ }
+
+ valid = installed_android_build_template && !r_missing_templates;
+ }
+
+ // Validate the rest of the configuration.
+
+ String dk = p_preset->get("keystore/debug");
+ String dk_user = p_preset->get("keystore/debug_user");
+ String dk_password = p_preset->get("keystore/debug_password");
+
+ if ((dk.is_empty() || dk_user.is_empty() || dk_password.is_empty()) && (!dk.is_empty() || !dk_user.is_empty() || !dk_password.is_empty())) {
+ valid = false;
+ err += TTR("Either Debug Keystore, Debug User AND Debug Password settings must be configured OR none of them.") + "\n";
+ }
+
+ if (!FileAccess::exists(dk)) {
+ dk = EditorSettings::get_singleton()->get("export/android/debug_keystore");
+ if (!FileAccess::exists(dk)) {
+ valid = false;
+ err += TTR("Debug keystore not configured in the Editor Settings nor in the preset.") + "\n";
+ }
+ }
+
+ String rk = p_preset->get("keystore/release");
+ String rk_user = p_preset->get("keystore/release_user");
+ String rk_password = p_preset->get("keystore/release_password");
+
+ if ((rk.is_empty() || rk_user.is_empty() || rk_password.is_empty()) && (!rk.is_empty() || !rk_user.is_empty() || !rk_password.is_empty())) {
+ valid = false;
+ err += TTR("Either Release Keystore, Release User AND Release Password settings must be configured OR none of them.") + "\n";
+ }
+
+ if (!rk.is_empty() && !FileAccess::exists(rk)) {
+ valid = false;
+ err += TTR("Release keystore incorrectly configured in the export preset.") + "\n";
+ }
+
+ String sdk_path = EditorSettings::get_singleton()->get("export/android/android_sdk_path");
+ if (sdk_path == "") {
+ err += TTR("A valid Android SDK path is required in Editor Settings.") + "\n";
+ valid = false;
+ } else {
+ Error errn;
+ // Check for the platform-tools directory.
+ DirAccessRef da = DirAccess::open(sdk_path.plus_file("platform-tools"), &errn);
+ if (errn != OK) {
+ err += TTR("Invalid Android SDK path in Editor Settings.");
+ err += TTR("Missing 'platform-tools' directory!");
+ err += "\n";
+ valid = false;
+ }
+
+ // Validate that adb is available
+ String adb_path = get_adb_path();
+ if (!FileAccess::exists(adb_path)) {
+ err += TTR("Unable to find Android SDK platform-tools' adb command.");
+ err += TTR("Please check in the Android SDK directory specified in Editor Settings.");
+ err += "\n";
+ valid = false;
+ }
+
+ // Check for the build-tools directory.
+ DirAccessRef build_tools_da = DirAccess::open(sdk_path.plus_file("build-tools"), &errn);
+ if (errn != OK) {
+ err += TTR("Invalid Android SDK path in Editor Settings.");
+ err += TTR("Missing 'build-tools' directory!");
+ err += "\n";
+ valid = false;
+ }
+
+ // Validate that apksigner is available
+ String apksigner_path = get_apksigner_path();
+ if (!FileAccess::exists(apksigner_path)) {
+ err += TTR("Unable to find Android SDK build-tools' apksigner command.");
+ err += TTR("Please check in the Android SDK directory specified in Editor Settings.");
+ err += "\n";
+ valid = false;
+ }
+ }
+
+ bool apk_expansion = p_preset->get("apk_expansion/enable");
+
+ if (apk_expansion) {
+ String apk_expansion_pkey = p_preset->get("apk_expansion/public_key");
+
+ if (apk_expansion_pkey == "") {
+ valid = false;
+
+ err += TTR("Invalid public key for APK expansion.") + "\n";
+ }
+ }
+
+ String pn = p_preset->get("package/unique_name");
+ String pn_err;
+
+ if (!is_package_name_valid(get_package_name(pn), &pn_err)) {
+ valid = false;
+ err += TTR("Invalid package name:") + " " + pn_err + "\n";
+ }
+
+ String etc_error = test_etc2();
+ if (etc_error != String()) {
+ valid = false;
+ err += etc_error;
+ }
+
+ // Ensure that `Use Custom Build` is enabled if a plugin is selected.
+ String enabled_plugins_names = PluginConfigAndroid::get_plugins_names(get_enabled_plugins(p_preset));
+ bool custom_build_enabled = p_preset->get("custom_template/use_custom_build");
+ if (!enabled_plugins_names.is_empty() && !custom_build_enabled) {
+ valid = false;
+ err += TTR("\"Use Custom Build\" must be enabled to use the plugins.");
+ err += "\n";
+ }
+
+ // Validate the Xr features are properly populated
+ int xr_mode_index = p_preset->get("xr_features/xr_mode");
+ int hand_tracking = p_preset->get("xr_features/hand_tracking");
+ if (xr_mode_index != /* XRMode.OVR*/ 1) {
+ if (hand_tracking > 0) {
+ valid = false;
+ err += TTR("\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\".");
+ err += "\n";
+ }
+ }
+
+ if (int(p_preset->get("custom_template/export_format")) == EXPORT_FORMAT_AAB &&
+ !bool(p_preset->get("custom_template/use_custom_build"))) {
+ valid = false;
+ err += TTR("\"Export AAB\" is only valid when \"Use Custom Build\" is enabled.");
+ err += "\n";
+ }
+
+ r_error = err;
+ return valid;
+}
+
+List<String> EditorExportPlatformAndroid::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
+ List<String> list;
+ list.push_back("apk");
+ list.push_back("aab");
+ return list;
+}
+
+String EditorExportPlatformAndroid::get_apk_expansion_fullpath(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
+ int version_code = p_preset->get("version/code");
+ String package_name = p_preset->get("package/unique_name");
+ String apk_file_name = "main." + itos(version_code) + "." + get_package_name(package_name) + ".obb";
+ String fullpath = p_path.get_base_dir().plus_file(apk_file_name);
+ return fullpath;
+}
+
+Error EditorExportPlatformAndroid::save_apk_expansion_file(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
+ String fullpath = get_apk_expansion_fullpath(p_preset, p_path);
+ Error err = save_pack(p_preset, fullpath);
+ return err;
+}
+
+void EditorExportPlatformAndroid::get_command_line_flags(const Ref<EditorExportPreset> &p_preset, const String &p_path, int p_flags, Vector<uint8_t> &r_command_line_flags) {
+ String cmdline = p_preset->get("command_line/extra_args");
+ Vector<String> command_line_strings = cmdline.strip_edges().split(" ");
+ for (int i = 0; i < command_line_strings.size(); i++) {
+ if (command_line_strings[i].strip_edges().length() == 0) {
+ command_line_strings.remove(i);
+ i--;
+ }
+ }
+
+ gen_export_flags(command_line_strings, p_flags);
+
+ bool apk_expansion = p_preset->get("apk_expansion/enable");
+ if (apk_expansion) {
+ String fullpath = get_apk_expansion_fullpath(p_preset, p_path);
+ String apk_expansion_public_key = p_preset->get("apk_expansion/public_key");
+
+ command_line_strings.push_back("--use_apk_expansion");
+ command_line_strings.push_back("--apk_expansion_md5");
+ command_line_strings.push_back(FileAccess::get_md5(fullpath));
+ command_line_strings.push_back("--apk_expansion_key");
+ command_line_strings.push_back(apk_expansion_public_key.strip_edges());
+ }
+
+ int xr_mode_index = p_preset->get("xr_features/xr_mode");
+ if (xr_mode_index == 1) {
+ command_line_strings.push_back("--xr_mode_ovr");
+ } else { // XRMode.REGULAR is the default.
+ command_line_strings.push_back("--xr_mode_regular");
+ }
+
+ bool use_32_bit_framebuffer = p_preset->get("graphics/32_bits_framebuffer");
+ if (use_32_bit_framebuffer) {
+ command_line_strings.push_back("--use_depth_32");
+ }
+
+ bool immersive = p_preset->get("screen/immersive_mode");
+ if (immersive) {
+ command_line_strings.push_back("--use_immersive");
+ }
+
+ bool debug_opengl = p_preset->get("graphics/opengl_debug");
+ if (debug_opengl) {
+ command_line_strings.push_back("--debug_opengl");
+ }
+
+ if (command_line_strings.size()) {
+ r_command_line_flags.resize(4);
+ encode_uint32(command_line_strings.size(), &r_command_line_flags.write[0]);
+ for (int i = 0; i < command_line_strings.size(); i++) {
+ print_line(itos(i) + " param: " + command_line_strings[i]);
+ CharString command_line_argument = command_line_strings[i].utf8();
+ int base = r_command_line_flags.size();
+ int length = command_line_argument.length();
+ if (length == 0) {
+ continue;
+ }
+ r_command_line_flags.resize(base + 4 + length);
+ encode_uint32(length, &r_command_line_flags.write[base]);
+ memcpy(&r_command_line_flags.write[base + 4], command_line_argument.ptr(), length);
+ }
+ }
+}
+
+Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &export_path, EditorProgress &ep) {
+ int export_format = int(p_preset->get("custom_template/export_format"));
+ String export_label = export_format == EXPORT_FORMAT_AAB ? "AAB" : "APK";
+ String release_keystore = p_preset->get("keystore/release");
+ String release_username = p_preset->get("keystore/release_user");
+ String release_password = p_preset->get("keystore/release_password");
+
+ String apksigner = get_apksigner_path();
+ print_verbose("Starting signing of the " + export_label + " binary using " + apksigner);
+ if (!FileAccess::exists(apksigner)) {
+ EditorNode::add_io_error(vformat(TTR("'apksigner' could not be found.\nPlease check the command is available in the Android SDK build-tools directory.\nThe resulting %s is unsigned."), export_label));
+ return OK;
+ }
+
+ String keystore;
+ String password;
+ String user;
+ if (p_debug) {
+ keystore = p_preset->get("keystore/debug");
+ password = p_preset->get("keystore/debug_password");
+ user = p_preset->get("keystore/debug_user");
+
+ if (keystore.is_empty()) {
+ keystore = EditorSettings::get_singleton()->get("export/android/debug_keystore");
+ password = EditorSettings::get_singleton()->get("export/android/debug_keystore_pass");
+ user = EditorSettings::get_singleton()->get("export/android/debug_keystore_user");
+ }
+
+ if (ep.step(vformat(TTR("Signing debug %s..."), export_label), 104)) {
+ return ERR_SKIP;
+ }
+
+ } else {
+ keystore = release_keystore;
+ password = release_password;
+ user = release_username;
+
+ if (ep.step(vformat(TTR("Signing release %s..."), export_label), 104)) {
+ return ERR_SKIP;
+ }
+ }
+
+ if (!FileAccess::exists(keystore)) {
+ EditorNode::add_io_error(TTR("Could not find keystore, unable to export."));
+ return ERR_FILE_CANT_OPEN;
+ }
+
+ String output;
+ List<String> args;
+ args.push_back("sign");
+ args.push_back("--verbose");
+ args.push_back("--ks");
+ args.push_back(keystore);
+ args.push_back("--ks-pass");
+ args.push_back("pass:" + password);
+ args.push_back("--ks-key-alias");
+ args.push_back(user);
+ args.push_back(export_path);
+ if (p_debug) {
+ // We only print verbose logs for debug builds to avoid leaking release keystore credentials.
+ print_verbose("Signing debug binary using: " + String("\n") + apksigner + " " + join_list(args, String(" ")));
+ }
+ int retval;
+ output.clear();
+ OS::get_singleton()->execute(apksigner, args, &output, &retval, true);
+ print_verbose(output);
+ if (retval) {
+ EditorNode::add_io_error(vformat(TTR("'apksigner' returned with error #%d"), retval));
+ return ERR_CANT_CREATE;
+ }
+
+ if (ep.step(vformat(TTR("Verifying %s..."), export_label), 105)) {
+ return ERR_SKIP;
+ }
+
+ args.clear();
+ args.push_back("verify");
+ args.push_back("--verbose");
+ args.push_back(export_path);
+ if (p_debug) {
+ print_verbose("Verifying signed build using: " + String("\n") + apksigner + " " + join_list(args, String(" ")));
+ }
+
+ output.clear();
+ OS::get_singleton()->execute(apksigner, args, &output, &retval, true);
+ print_verbose(output);
+ if (retval) {
+ EditorNode::add_io_error(vformat(TTR("'apksigner' verification of %s failed."), export_label));
+ return ERR_CANT_CREATE;
+ }
+
+ print_verbose("Successfully completed signing build.");
+ return OK;
+}
+
+void EditorExportPlatformAndroid::_clear_assets_directory() {
+ DirAccessRef da_res = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ if (da_res->dir_exists("res://android/build/assets")) {
+ print_verbose("Clearing assets directory..");
+ DirAccessRef da_assets = DirAccess::open("res://android/build/assets");
+ da_assets->erase_contents_recursive();
+ da_res->remove("res://android/build/assets");
+ }
+}
+
+void EditorExportPlatformAndroid::_remove_copied_libs() {
+ print_verbose("Removing previously installed libraries...");
+ Error error;
+ String libs_json = FileAccess::get_file_as_string(GDNATIVE_LIBS_PATH, &error);
+ if (error || libs_json.is_empty()) {
+ print_verbose("No previously installed libraries found");
+ return;
+ }
+
+ JSON json;
+ error = json.parse(libs_json);
+ ERR_FAIL_COND_MSG(error, "Error parsing \"" + libs_json + "\" on line " + itos(json.get_error_line()) + ": " + json.get_error_message());
+
+ Vector<String> libs = json.get_data();
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ for (int i = 0; i < libs.size(); i++) {
+ print_verbose("Removing previously installed library " + libs[i]);
+ da->remove(libs[i]);
+ }
+ da->remove(GDNATIVE_LIBS_PATH);
+}
+
+String EditorExportPlatformAndroid::join_list(List<String> parts, const String &separator) const {
+ String ret;
+ for (int i = 0; i < parts.size(); ++i) {
+ if (i > 0) {
+ ret += separator;
+ }
+ ret += parts[i];
+ }
+ return ret;
+}
+
+Error EditorExportPlatformAndroid::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
+ int export_format = int(p_preset->get("custom_template/export_format"));
+ bool should_sign = p_preset->get("package/signed");
+ return export_project_helper(p_preset, p_debug, p_path, export_format, should_sign, p_flags);
+}
+
+Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int export_format, bool should_sign, int p_flags) {
+ ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
+
+ String src_apk;
+ Error err;
+
+ EditorProgress ep("export", TTR("Exporting for Android"), 105, true);
+
+ bool use_custom_build = bool(p_preset->get("custom_template/use_custom_build"));
+ bool p_give_internet = p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG);
+ bool apk_expansion = p_preset->get("apk_expansion/enable");
+ Vector<String> enabled_abis = get_enabled_abis(p_preset);
+
+ print_verbose("Exporting for Android...");
+ print_verbose("- debug build: " + bool_to_string(p_debug));
+ print_verbose("- export path: " + p_path);
+ print_verbose("- export format: " + itos(export_format));
+ print_verbose("- sign build: " + bool_to_string(should_sign));
+ print_verbose("- custom build enabled: " + bool_to_string(use_custom_build));
+ print_verbose("- apk expansion enabled: " + bool_to_string(apk_expansion));
+ print_verbose("- enabled abis: " + String(",").join(enabled_abis));
+ print_verbose("- export filter: " + itos(p_preset->get_export_filter()));
+ print_verbose("- include filter: " + p_preset->get_include_filter());
+ print_verbose("- exclude filter: " + p_preset->get_exclude_filter());
+
+ Ref<Image> splash_image;
+ Ref<Image> splash_bg_color_image;
+ String processed_splash_config_xml = load_splash_refs(splash_image, splash_bg_color_image);
+
+ Ref<Image> main_image;
+ Ref<Image> foreground;
+ Ref<Image> background;
+
+ load_icon_refs(p_preset, main_image, foreground, background);
+
+ Vector<uint8_t> command_line_flags;
+ // Write command line flags into the command_line_flags variable.
+ get_command_line_flags(p_preset, p_path, p_flags, command_line_flags);
+
+ if (export_format == EXPORT_FORMAT_AAB) {
+ if (!p_path.ends_with(".aab")) {
+ EditorNode::get_singleton()->show_warning(TTR("Invalid filename! Android App Bundle requires the *.aab extension."));
+ return ERR_UNCONFIGURED;
+ }
+ if (apk_expansion) {
+ EditorNode::get_singleton()->show_warning(TTR("APK Expansion not compatible with Android App Bundle."));
+ return ERR_UNCONFIGURED;
+ }
+ }
+ if (export_format == EXPORT_FORMAT_APK && !p_path.ends_with(".apk")) {
+ EditorNode::get_singleton()->show_warning(
+ TTR("Invalid filename! Android APK requires the *.apk extension."));
+ return ERR_UNCONFIGURED;
+ }
+ if (export_format > EXPORT_FORMAT_AAB || export_format < EXPORT_FORMAT_APK) {
+ EditorNode::add_io_error(TTR("Unsupported export format!\n"));
+ return ERR_UNCONFIGURED; //TODO: is this the right error?
+ }
+
+ if (use_custom_build) {
+ print_verbose("Starting custom build..");
+ //test that installed build version is alright
+ {
+ print_verbose("Checking build version..");
+ FileAccessRef f = FileAccess::open("res://android/.build_version", FileAccess::READ);
+ if (!f) {
+ EditorNode::get_singleton()->show_warning(TTR("Trying to build from a custom built template, but no version info for it exists. Please reinstall from the 'Project' menu."));
+ return ERR_UNCONFIGURED;
+ }
+ String version = f->get_line().strip_edges();
+ print_verbose("- build version: " + version);
+ f->close();
+ if (version != VERSION_FULL_CONFIG) {
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Android build version mismatch:\n Template installed: %s\n Godot Version: %s\nPlease reinstall Android build template from 'Project' menu."), version, VERSION_FULL_CONFIG));
+ return ERR_UNCONFIGURED;
+ }
+ }
+ String sdk_path = EDITOR_GET("export/android/android_sdk_path");
+ ERR_FAIL_COND_V_MSG(sdk_path.is_empty(), ERR_UNCONFIGURED, "Android SDK path must be configured in Editor Settings at 'export/android/android_sdk_path'.");
+ print_verbose("Android sdk path: " + sdk_path);
+
+ // TODO: should we use "package/name" or "application/config/name"?
+ String project_name = get_project_name(p_preset->get("package/name"));
+ err = _create_project_name_strings_files(p_preset, project_name); //project name localization.
+ if (err != OK) {
+ EditorNode::add_io_error(TTR("Unable to overwrite res://android/build/res/*.xml files with project name"));
+ }
+ // Copies the project icon files into the appropriate Gradle project directory.
+ _copy_icons_to_gradle_project(p_preset, processed_splash_config_xml, splash_image, splash_bg_color_image, main_image, foreground, background);
+ // Write an AndroidManifest.xml file into the Gradle project directory.
+ _write_tmp_manifest(p_preset, p_give_internet, p_debug);
+
+ //stores all the project files inside the Gradle project directory. Also includes all ABIs
+ _clear_assets_directory();
+ _remove_copied_libs();
+ if (!apk_expansion) {
+ print_verbose("Exporting project files..");
+ CustomExportData user_data;
+ user_data.debug = p_debug;
+ err = export_project_files(p_preset, rename_and_store_file_in_gradle_project, &user_data, copy_gradle_so);
+ if (err != OK) {
+ EditorNode::add_io_error(TTR("Could not export project files to gradle project\n"));
+ return err;
+ }
+ if (user_data.libs.size() > 0) {
+ FileAccessRef fa = FileAccess::open(GDNATIVE_LIBS_PATH, FileAccess::WRITE);
+ JSON json;
+ fa->store_string(json.stringify(user_data.libs, "\t"));
+ fa->close();
+ }
+ } else {
+ print_verbose("Saving apk expansion file..");
+ err = save_apk_expansion_file(p_preset, p_path);
+ if (err != OK) {
+ EditorNode::add_io_error(TTR("Could not write expansion package file!"));
+ return err;
+ }
+ }
+ print_verbose("Storing command line flags..");
+ store_file_at_path("res://android/build/assets/_cl_", command_line_flags);
+
+ print_verbose("Updating ANDROID_HOME environment to " + sdk_path);
+ OS::get_singleton()->set_environment("ANDROID_HOME", sdk_path); //set and overwrite if required
+ String build_command;
+
+#ifdef WINDOWS_ENABLED
+ build_command = "gradlew.bat";
+#else
+ build_command = "gradlew";
+#endif
+
+ String build_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/build");
+ build_command = build_path.plus_file(build_command);
+
+ String package_name = get_package_name(p_preset->get("package/unique_name"));
+ String version_code = itos(p_preset->get("version/code"));
+ String version_name = p_preset->get("version/name");
+ String enabled_abi_string = String("|").join(enabled_abis);
+ String sign_flag = should_sign ? "true" : "false";
+ String zipalign_flag = "true";
+
+ Vector<PluginConfigAndroid> enabled_plugins = get_enabled_plugins(p_preset);
+ String local_plugins_binaries = PluginConfigAndroid::get_plugins_binaries(PluginConfigAndroid::BINARY_TYPE_LOCAL, enabled_plugins);
+ String remote_plugins_binaries = PluginConfigAndroid::get_plugins_binaries(PluginConfigAndroid::BINARY_TYPE_REMOTE, enabled_plugins);
+ String custom_maven_repos = PluginConfigAndroid::get_plugins_custom_maven_repos(enabled_plugins);
+ bool clean_build_required = is_clean_build_required(enabled_plugins);
+
+ List<String> cmdline;
+ if (clean_build_required) {
+ cmdline.push_back("clean");
+ }
+
+ String build_type = p_debug ? "Debug" : "Release";
+ if (export_format == EXPORT_FORMAT_AAB) {
+ String bundle_build_command = vformat("bundle%s", build_type);
+ cmdline.push_back(bundle_build_command);
+ } else if (export_format == EXPORT_FORMAT_APK) {
+ String apk_build_command = vformat("assemble%s", build_type);
+ cmdline.push_back(apk_build_command);
+ }
+
+ cmdline.push_back("-p"); // argument to specify the start directory.
+ cmdline.push_back(build_path); // start directory.
+ cmdline.push_back("-Pexport_package_name=" + package_name); // argument to specify the package name.
+ cmdline.push_back("-Pexport_version_code=" + version_code); // argument to specify the version code.
+ cmdline.push_back("-Pexport_version_name=" + version_name); // argument to specify the version name.
+ cmdline.push_back("-Pexport_enabled_abis=" + enabled_abi_string); // argument to specify enabled ABIs.
+ cmdline.push_back("-Pplugins_local_binaries=" + local_plugins_binaries); // argument to specify the list of plugins local dependencies.
+ cmdline.push_back("-Pplugins_remote_binaries=" + remote_plugins_binaries); // argument to specify the list of plugins remote dependencies.
+ cmdline.push_back("-Pplugins_maven_repos=" + custom_maven_repos); // argument to specify the list of custom maven repos for the plugins dependencies.
+ cmdline.push_back("-Pperform_zipalign=" + zipalign_flag); // argument to specify whether the build should be zipaligned.
+ cmdline.push_back("-Pperform_signing=" + sign_flag); // argument to specify whether the build should be signed.
+ cmdline.push_back("-Pgodot_editor_version=" + String(VERSION_FULL_CONFIG));
+
+ // NOTE: The release keystore is not included in the verbose logging
+ // to avoid accidentally leaking sensitive information when sharing verbose logs for troubleshooting.
+ // Any non-sensitive additions to the command line arguments must be done above this section.
+ // Sensitive additions must be done below the logging statement.
+ print_verbose("Build Android project using gradle command: " + String("\n") + build_command + " " + join_list(cmdline, String(" ")));
+
+ if (should_sign) {
+ if (p_debug) {
+ String debug_keystore = p_preset->get("keystore/debug");
+ String debug_password = p_preset->get("keystore/debug_password");
+ String debug_user = p_preset->get("keystore/debug_user");
+
+ if (debug_keystore.is_empty()) {
+ debug_keystore = EditorSettings::get_singleton()->get("export/android/debug_keystore");
+ debug_password = EditorSettings::get_singleton()->get("export/android/debug_keystore_pass");
+ debug_user = EditorSettings::get_singleton()->get("export/android/debug_keystore_user");
+ }
+
+ cmdline.push_back("-Pdebug_keystore_file=" + debug_keystore); // argument to specify the debug keystore file.
+ cmdline.push_back("-Pdebug_keystore_alias=" + debug_user); // argument to specify the debug keystore alias.
+ cmdline.push_back("-Pdebug_keystore_password=" + debug_password); // argument to specify the debug keystore password.
+ } else {
+ // Pass the release keystore info as well
+ String release_keystore = p_preset->get("keystore/release");
+ String release_username = p_preset->get("keystore/release_user");
+ String release_password = p_preset->get("keystore/release_password");
+ if (!FileAccess::exists(release_keystore)) {
+ EditorNode::add_io_error(TTR("Could not find keystore, unable to export."));
+ return ERR_FILE_CANT_OPEN;
+ }
+
+ cmdline.push_back("-Prelease_keystore_file=" + release_keystore); // argument to specify the release keystore file.
+ cmdline.push_back("-Prelease_keystore_alias=" + release_username); // argument to specify the release keystore alias.
+ cmdline.push_back("-Prelease_keystore_password=" + release_password); // argument to specify the release keystore password.
+ }
+ }
+
+ int result = EditorNode::get_singleton()->execute_and_show_output(TTR("Building Android Project (gradle)"), build_command, cmdline);
+ if (result != 0) {
+ EditorNode::get_singleton()->show_warning(TTR("Building of Android project failed, check output for the error.\nAlternatively visit docs.godotengine.org for Android build documentation."));
+ return ERR_CANT_CREATE;
+ }
+
+ List<String> copy_args;
+ String copy_command;
+ if (export_format == EXPORT_FORMAT_AAB) {
+ copy_command = vformat("copyAndRename%sAab", build_type);
+ } else if (export_format == EXPORT_FORMAT_APK) {
+ copy_command = vformat("copyAndRename%sApk", build_type);
+ }
+
+ copy_args.push_back(copy_command);
+
+ copy_args.push_back("-p"); // argument to specify the start directory.
+ copy_args.push_back(build_path); // start directory.
+
+ String export_filename = p_path.get_file();
+ String export_path = p_path.get_base_dir();
+ if (export_path.is_rel_path()) {
+ export_path = OS::get_singleton()->get_resource_dir().plus_file(export_path);
+ }
+ export_path = ProjectSettings::get_singleton()->globalize_path(export_path).simplify_path();
+
+ copy_args.push_back("-Pexport_path=file:" + export_path);
+ copy_args.push_back("-Pexport_filename=" + export_filename);
+
+ print_verbose("Copying Android binary using gradle command: " + String("\n") + build_command + " " + join_list(copy_args, String(" ")));
+ int copy_result = EditorNode::get_singleton()->execute_and_show_output(TTR("Moving output"), build_command, copy_args);
+ if (copy_result != 0) {
+ EditorNode::get_singleton()->show_warning(TTR("Unable to copy and rename export file, check gradle project directory for outputs."));
+ return ERR_CANT_CREATE;
+ }
+
+ print_verbose("Successfully completed Android custom build.");
+ return OK;
+ }
+ // This is the start of the Legacy build system
+ print_verbose("Starting legacy build system..");
+ if (p_debug) {
+ src_apk = p_preset->get("custom_template/debug");
+ } else {
+ src_apk = p_preset->get("custom_template/release");
+ }
+ src_apk = src_apk.strip_edges();
+ if (src_apk == "") {
+ if (p_debug) {
+ src_apk = find_export_template("android_debug.apk");
+ } else {
+ src_apk = find_export_template("android_release.apk");
+ }
+ if (src_apk == "") {
+ EditorNode::add_io_error(vformat(TTR("Package not found: %s"), src_apk));
+ return ERR_FILE_NOT_FOUND;
+ }
+ }
+
+ if (!DirAccess::exists(p_path.get_base_dir())) {
+ return ERR_FILE_BAD_PATH;
+ }
+
+ FileAccess *src_f = nullptr;
+ zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
+
+ if (ep.step(TTR("Creating APK..."), 0)) {
+ return ERR_SKIP;
+ }
+
+ unzFile pkg = unzOpen2(src_apk.utf8().get_data(), &io);
+ if (!pkg) {
+ EditorNode::add_io_error(vformat(TTR("Could not find template APK to export:\n%s"), src_apk));
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ int ret = unzGoToFirstFile(pkg);
+
+ zlib_filefunc_def io2 = io;
+ FileAccess *dst_f = nullptr;
+ io2.opaque = &dst_f;
+
+ String tmp_unaligned_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpexport-unaligned." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
+
+#define CLEANUP_AND_RETURN(m_err) \
+ { \
+ DirAccess::remove_file_or_error(tmp_unaligned_path); \
+ return m_err; \
+ }
+
+ zipFile unaligned_apk = zipOpen2(tmp_unaligned_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io2);
+
+ String cmdline = p_preset->get("command_line/extra_args");
+
+ String version_name = p_preset->get("version/name");
+ String package_name = p_preset->get("package/unique_name");
+
+ String apk_expansion_pkey = p_preset->get("apk_expansion/public_key");
+
+ Vector<String> invalid_abis(enabled_abis);
+ while (ret == UNZ_OK) {
+ //get filename
+ unz_file_info info;
+ char fname[16384];
+ ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
+
+ bool skip = false;
+
+ String file = fname;
+
+ Vector<uint8_t> data;
+ data.resize(info.uncompressed_size);
+
+ //read
+ unzOpenCurrentFile(pkg);
+ unzReadCurrentFile(pkg, data.ptrw(), data.size());
+ unzCloseCurrentFile(pkg);
+
+ //write
+ if (file == "AndroidManifest.xml") {
+ _fix_manifest(p_preset, data, p_give_internet);
+ }
+ if (file == "resources.arsc") {
+ _fix_resources(p_preset, data);
+ }
+
+ // Process the splash image
+ if ((file == SPLASH_IMAGE_EXPORT_PATH || file == LEGACY_BUILD_SPLASH_IMAGE_EXPORT_PATH) && splash_image.is_valid() && !splash_image->is_empty()) {
+ _load_image_data(splash_image, data);
+ }
+
+ // Process the splash bg color image
+ if ((file == SPLASH_BG_COLOR_PATH || file == LEGACY_BUILD_SPLASH_BG_COLOR_PATH) && splash_bg_color_image.is_valid() && !splash_bg_color_image->is_empty()) {
+ _load_image_data(splash_bg_color_image, data);
+ }
+
+ for (int i = 0; i < icon_densities_count; ++i) {
+ if (main_image.is_valid() && !main_image->is_empty()) {
+ if (file == launcher_icons[i].export_path) {
+ _process_launcher_icons(file, main_image, launcher_icons[i].dimensions, data);
+ }
+ }
+ if (foreground.is_valid() && !foreground->is_empty()) {
+ if (file == launcher_adaptive_icon_foregrounds[i].export_path) {
+ _process_launcher_icons(file, foreground, launcher_adaptive_icon_foregrounds[i].dimensions, data);
+ }
+ }
+ if (background.is_valid() && !background->is_empty()) {
+ if (file == launcher_adaptive_icon_backgrounds[i].export_path) {
+ _process_launcher_icons(file, background, launcher_adaptive_icon_backgrounds[i].dimensions, data);
+ }
+ }
+ }
+
+ if (file.ends_with(".so")) {
+ bool enabled = false;
+ for (int i = 0; i < enabled_abis.size(); ++i) {
+ if (file.begins_with("lib/" + enabled_abis[i] + "/")) {
+ invalid_abis.erase(enabled_abis[i]);
+ enabled = true;
+ break;
+ }
+ }
+ if (!enabled) {
+ skip = true;
+ }
+ }
+
+ if (file.begins_with("META-INF") && should_sign) {
+ skip = true;
+ }
+
+ if (!skip) {
+ print_line("ADDING: " + file);
+
+ // Respect decision on compression made by AAPT for the export template
+ const bool uncompressed = info.compression_method == 0;
+
+ zip_fileinfo zipfi = get_zip_fileinfo();
+
+ zipOpenNewFileInZip(unaligned_apk,
+ file.utf8().get_data(),
+ &zipfi,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ nullptr,
+ uncompressed ? 0 : Z_DEFLATED,
+ Z_DEFAULT_COMPRESSION);
+
+ zipWriteInFileInZip(unaligned_apk, data.ptr(), data.size());
+ zipCloseFileInZip(unaligned_apk);
+ }
+
+ ret = unzGoToNextFile(pkg);
+ }
+
+ if (!invalid_abis.is_empty()) {
+ String unsupported_arch = String(", ").join(invalid_abis);
+ EditorNode::add_io_error(vformat(TTR("Missing libraries in the export template for the selected architectures: %s.\nPlease build a template with all required libraries, or uncheck the missing architectures in the export preset."), unsupported_arch));
+ CLEANUP_AND_RETURN(ERR_FILE_NOT_FOUND);
+ }
+
+ if (ep.step(TTR("Adding files..."), 1)) {
+ CLEANUP_AND_RETURN(ERR_SKIP);
+ }
+ err = OK;
+
+ if (p_flags & DEBUG_FLAG_DUMB_CLIENT) {
+ APKExportData ed;
+ ed.ep = &ep;
+ ed.apk = unaligned_apk;
+ err = export_project_files(p_preset, ignore_apk_file, &ed, save_apk_so);
+ } else {
+ if (apk_expansion) {
+ err = save_apk_expansion_file(p_preset, p_path);
+ if (err != OK) {
+ EditorNode::add_io_error(TTR("Could not write expansion package file!"));
+ return err;
+ }
+ } else {
+ APKExportData ed;
+ ed.ep = &ep;
+ ed.apk = unaligned_apk;
+ err = export_project_files(p_preset, save_apk_file, &ed, save_apk_so);
+ }
+ }
+
+ if (err != OK) {
+ unzClose(pkg);
+ EditorNode::add_io_error(TTR("Could not export project files"));
+ CLEANUP_AND_RETURN(ERR_SKIP);
+ }
+
+ zip_fileinfo zipfi = get_zip_fileinfo();
+ zipOpenNewFileInZip(unaligned_apk,
+ "assets/_cl_",
+ &zipfi,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ nullptr,
+ 0, // No compress (little size gain and potentially slower startup)
+ Z_DEFAULT_COMPRESSION);
+ zipWriteInFileInZip(unaligned_apk, command_line_flags.ptr(), command_line_flags.size());
+ zipCloseFileInZip(unaligned_apk);
+ zipClose(unaligned_apk, nullptr);
+ unzClose(pkg);
+
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ // Let's zip-align (must be done before signing)
+
+ static const int ZIP_ALIGNMENT = 4;
+
+ // If we're not signing the apk, then the next step should be the last.
+ const int next_step = should_sign ? 103 : 105;
+ if (ep.step(TTR("Aligning APK..."), next_step)) {
+ CLEANUP_AND_RETURN(ERR_SKIP);
+ }
+
+ unzFile tmp_unaligned = unzOpen2(tmp_unaligned_path.utf8().get_data(), &io);
+ if (!tmp_unaligned) {
+ EditorNode::add_io_error(TTR("Could not unzip temporary unaligned APK."));
+ CLEANUP_AND_RETURN(ERR_FILE_NOT_FOUND);
+ }
+
+ ret = unzGoToFirstFile(tmp_unaligned);
+
+ io2 = io;
+ dst_f = nullptr;
+ io2.opaque = &dst_f;
+ zipFile final_apk = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io2);
+
+ // Take files from the unaligned APK and write them out to the aligned one
+ // in raw mode, i.e. not uncompressing and recompressing, aligning them as needed,
+ // following what is done in https://github.com/android/platform_build/blob/master/tools/zipalign/ZipAlign.cpp
+ int bias = 0;
+ while (ret == UNZ_OK) {
+ unz_file_info info;
+ memset(&info, 0, sizeof(info));
+
+ char fname[16384];
+ char extra[16384];
+ ret = unzGetCurrentFileInfo(tmp_unaligned, &info, fname, 16384, extra, 16384 - ZIP_ALIGNMENT, nullptr, 0);
+
+ String file = fname;
+
+ Vector<uint8_t> data;
+ data.resize(info.compressed_size);
+
+ // read
+ int method, level;
+ unzOpenCurrentFile2(tmp_unaligned, &method, &level, 1); // raw read
+ long file_offset = unzGetCurrentFileZStreamPos64(tmp_unaligned);
+ unzReadCurrentFile(tmp_unaligned, data.ptrw(), data.size());
+ unzCloseCurrentFile(tmp_unaligned);
+
+ // align
+ int padding = 0;
+ if (!info.compression_method) {
+ // Uncompressed file => Align
+ long new_offset = file_offset + bias;
+ padding = (ZIP_ALIGNMENT - (new_offset % ZIP_ALIGNMENT)) % ZIP_ALIGNMENT;
+ }
+
+ memset(extra + info.size_file_extra, 0, padding);
+
+ zip_fileinfo fileinfo = get_zip_fileinfo();
+ zipOpenNewFileInZip2(final_apk,
+ file.utf8().get_data(),
+ &fileinfo,
+ extra,
+ info.size_file_extra + padding,
+ nullptr,
+ 0,
+ nullptr,
+ method,
+ level,
+ 1); // raw write
+ zipWriteInFileInZip(final_apk, data.ptr(), data.size());
+ zipCloseFileInZipRaw(final_apk, info.uncompressed_size, info.crc);
+
+ bias += padding;
+
+ ret = unzGoToNextFile(tmp_unaligned);
+ }
+
+ zipClose(final_apk, nullptr);
+ unzClose(tmp_unaligned);
+
+ if (should_sign) {
+ // Signing must be done last as any additional modifications to the
+ // file will invalidate the signature.
+ err = sign_apk(p_preset, p_debug, p_path, ep);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+ }
+
+ CLEANUP_AND_RETURN(OK);
+}
+
+void EditorExportPlatformAndroid::get_platform_features(List<String> *r_features) {
+ r_features->push_back("mobile");
+ r_features->push_back("Android");
+}
+
+void EditorExportPlatformAndroid::resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) {
+}
+
+EditorExportPlatformAndroid::EditorExportPlatformAndroid() {
+ Ref<Image> img = memnew(Image(_android_logo));
+ logo.instantiate();
+ logo->create_from_image(img);
+
+ img = Ref<Image>(memnew(Image(_android_run_icon)));
+ run_icon.instantiate();
+ run_icon->create_from_image(img);
+
+ devices_changed.set();
+ plugins_changed.set();
+ check_for_changes_thread.start(_check_for_changes_poll_thread, this);
+}
+
+EditorExportPlatformAndroid::~EditorExportPlatformAndroid() {
+ quit_request.set();
+ check_for_changes_thread.wait_to_finish();
+}
diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h
new file mode 100644
index 0000000000..909428c2fe
--- /dev/null
+++ b/platform/android/export/export_plugin.h
@@ -0,0 +1,255 @@
+/*************************************************************************/
+/* export_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "core/config/project_settings.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
+#include "core/io/image_loader.h"
+#include "core/io/json.h"
+#include "core/io/marshalls.h"
+#include "core/io/zip_io.h"
+#include "core/os/os.h"
+#include "core/templates/safe_refcount.h"
+#include "core/version.h"
+#include "drivers/png/png_driver_common.h"
+#include "editor/editor_export.h"
+#include "editor/editor_log.h"
+#include "editor/editor_node.h"
+#include "editor/editor_settings.h"
+#include "main/splash.gen.h"
+#include "platform/android/logo.gen.h"
+#include "platform/android/run_icon.gen.h"
+
+#include "godot_plugin_config.h"
+#include "gradle_export_util.h"
+
+#include <string.h>
+
+const String SPLASH_CONFIG_XML_CONTENT = R"SPLASH(<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/splash_bg_color" />
+ <item>
+ <bitmap
+ android:gravity="center"
+ android:filter="%s"
+ android:src="@drawable/splash" />
+ </item>
+</layer-list>
+)SPLASH";
+
+struct LauncherIcon {
+ const char *export_path;
+ int dimensions = 0;
+};
+
+class EditorExportPlatformAndroid : public EditorExportPlatform {
+ GDCLASS(EditorExportPlatformAndroid, EditorExportPlatform);
+
+ Ref<ImageTexture> logo;
+ Ref<ImageTexture> run_icon;
+
+ struct Device {
+ String id;
+ String name;
+ String description;
+ int api_level = 0;
+ };
+
+ struct APKExportData {
+ zipFile apk;
+ EditorProgress *ep = nullptr;
+ };
+
+ struct CustomExportData {
+ bool debug;
+ Vector<String> libs;
+ };
+
+ Vector<PluginConfigAndroid> plugins;
+ String last_plugin_names;
+ uint64_t last_custom_build_time = 0;
+ SafeFlag plugins_changed;
+ Mutex plugins_lock;
+ Vector<Device> devices;
+ SafeFlag devices_changed;
+ Mutex device_lock;
+ Thread check_for_changes_thread;
+ SafeFlag quit_request;
+
+ static void _check_for_changes_poll_thread(void *ud);
+
+ String get_project_name(const String &p_name) const;
+
+ String get_package_name(const String &p_package) const;
+
+ bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const;
+
+ static bool _should_compress_asset(const String &p_path, const Vector<uint8_t> &p_data);
+
+ static zip_fileinfo get_zip_fileinfo();
+
+ static Vector<String> get_abis();
+
+ /// List the gdap files in the directory specified by the p_path parameter.
+ static Vector<String> list_gdap_files(const String &p_path);
+
+ static Vector<PluginConfigAndroid> get_plugins();
+
+ static Vector<PluginConfigAndroid> get_enabled_plugins(const Ref<EditorExportPreset> &p_presets);
+
+ static Error store_in_apk(APKExportData *ed, const String &p_path, const Vector<uint8_t> &p_data, int compression_method = Z_DEFLATED);
+
+ static Error save_apk_so(void *p_userdata, const SharedObject &p_so);
+
+ static Error save_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
+
+ static Error ignore_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
+
+ static Error copy_gradle_so(void *p_userdata, const SharedObject &p_so);
+
+ void _get_permissions(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, Vector<String> &r_permissions);
+
+ void _write_tmp_manifest(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, bool p_debug);
+
+ void _fix_manifest(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_manifest, bool p_give_internet);
+
+ static String _parse_string(const uint8_t *p_bytes, bool p_utf8);
+
+ void _fix_resources(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &r_manifest);
+
+ void _load_image_data(const Ref<Image> &p_splash_image, Vector<uint8_t> &p_data);
+
+ void _process_launcher_icons(const String &p_file_name, const Ref<Image> &p_source_image, int dimension, Vector<uint8_t> &p_data);
+
+ String load_splash_refs(Ref<Image> &splash_image, Ref<Image> &splash_bg_color_image);
+
+ void load_icon_refs(const Ref<EditorExportPreset> &p_preset, Ref<Image> &icon, Ref<Image> &foreground, Ref<Image> &background);
+
+ void store_image(const LauncherIcon launcher_icon, const Vector<uint8_t> &data);
+
+ void store_image(const String &export_path, const Vector<uint8_t> &data);
+
+ void _copy_icons_to_gradle_project(const Ref<EditorExportPreset> &p_preset,
+ const String &processed_splash_config_xml,
+ const Ref<Image> &splash_image,
+ const Ref<Image> &splash_bg_color_image,
+ const Ref<Image> &main_image,
+ const Ref<Image> &foreground,
+ const Ref<Image> &background);
+
+ static Vector<String> get_enabled_abis(const Ref<EditorExportPreset> &p_preset);
+
+public:
+ typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
+
+public:
+ virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) override;
+
+ virtual void get_export_options(List<ExportOption> *r_options) override;
+
+ virtual String get_name() const override;
+
+ virtual String get_os_name() const override;
+
+ virtual Ref<Texture2D> get_logo() const override;
+
+ virtual bool should_update_export_options() override;
+
+ virtual bool poll_export() override;
+
+ virtual int get_options_count() const override;
+
+ virtual String get_options_tooltip() const override;
+
+ virtual String get_option_label(int p_index) const override;
+
+ virtual String get_option_tooltip(int p_index) const override;
+
+ virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) override;
+
+ virtual Ref<Texture2D> get_run_icon() const override;
+
+ static String get_adb_path();
+
+ static String get_apksigner_path();
+
+ virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+
+ virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
+
+ inline bool is_clean_build_required(Vector<PluginConfigAndroid> enabled_plugins) {
+ String plugin_names = PluginConfigAndroid::get_plugins_names(enabled_plugins);
+ bool first_build = last_custom_build_time == 0;
+ bool have_plugins_changed = false;
+
+ if (!first_build) {
+ have_plugins_changed = plugin_names != last_plugin_names;
+ if (!have_plugins_changed) {
+ for (int i = 0; i < enabled_plugins.size(); i++) {
+ if (enabled_plugins.get(i).last_updated > last_custom_build_time) {
+ have_plugins_changed = true;
+ break;
+ }
+ }
+ }
+ }
+
+ last_custom_build_time = OS::get_singleton()->get_unix_time();
+ last_plugin_names = plugin_names;
+
+ return have_plugins_changed || first_build;
+ }
+
+ String get_apk_expansion_fullpath(const Ref<EditorExportPreset> &p_preset, const String &p_path);
+
+ Error save_apk_expansion_file(const Ref<EditorExportPreset> &p_preset, const String &p_path);
+
+ void get_command_line_flags(const Ref<EditorExportPreset> &p_preset, const String &p_path, int p_flags, Vector<uint8_t> &r_command_line_flags);
+
+ Error sign_apk(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &export_path, EditorProgress &ep);
+
+ void _clear_assets_directory();
+
+ void _remove_copied_libs();
+
+ String join_list(List<String> parts, const String &separator) const;
+
+ virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
+
+ Error export_project_helper(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int export_format, bool should_sign, int p_flags);
+
+ virtual void get_platform_features(List<String> *r_features) override;
+
+ virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) override;
+
+ EditorExportPlatformAndroid();
+
+ ~EditorExportPlatformAndroid();
+};
diff --git a/platform/android/plugin/godot_plugin_config.h b/platform/android/export/godot_plugin_config.cpp
index 6b708548ae..ba7b8ce6c7 100644
--- a/platform/android/plugin/godot_plugin_config.h
+++ b/platform/android/export/godot_plugin_config.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* godot_plugin_config.h */
+/* godot_plugin_config.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,78 +28,23 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef GODOT_PLUGIN_CONFIG_H
-#define GODOT_PLUGIN_CONFIG_H
-
-#include "core/error/error_list.h"
-#include "core/io/config_file.h"
-#include "core/string/ustring.h"
-
-/*
- The `config` section and fields are required and defined as follow:
-- **name**: name of the plugin.
-- **binary_type**: can be either `local` or `remote`. The type affects the **binary** field.
-- **binary**:
- - if **binary_type** is `local`, then this should be the filename of the plugin `aar` file in the `res://android/plugins` directory (e.g: `MyPlugin.aar`).
- - if **binary_type** is `remote`, then this should be a declaration for a remote gradle binary (e.g: "org.godot.example:my-plugin:0.0.0").
-
-The `dependencies` section and fields are optional and defined as follow:
-- **local**: contains a list of local `.aar` binary files the plugin depends on. The local binary dependencies must also be located in the `res://android/plugins` directory.
-- **remote**: contains a list of remote binary gradle dependencies for the plugin.
-- **custom_maven_repos**: contains a list of urls specifying custom maven repos required for the plugin's dependencies.
-
- See https://github.com/godotengine/godot/issues/38157#issuecomment-618773871
- */
-struct PluginConfigAndroid {
- inline static const char *PLUGIN_CONFIG_EXT = ".gdap";
-
- inline static const char *CONFIG_SECTION = "config";
- inline static const char *CONFIG_NAME_KEY = "name";
- inline static const char *CONFIG_BINARY_TYPE_KEY = "binary_type";
- inline static const char *CONFIG_BINARY_KEY = "binary";
-
- inline static const char *DEPENDENCIES_SECTION = "dependencies";
- inline static const char *DEPENDENCIES_LOCAL_KEY = "local";
- inline static const char *DEPENDENCIES_REMOTE_KEY = "remote";
- inline static const char *DEPENDENCIES_CUSTOM_MAVEN_REPOS_KEY = "custom_maven_repos";
-
- inline static const char *BINARY_TYPE_LOCAL = "local";
- inline static const char *BINARY_TYPE_REMOTE = "remote";
-
- inline static const char *PLUGIN_VALUE_SEPARATOR = "|";
-
- // Set to true when the config file is properly loaded.
- bool valid_config = false;
- // Unix timestamp of last change to this plugin.
- uint64_t last_updated = 0;
-
- // Required config section
- String name;
- String binary_type;
- String binary;
-
- // Optional dependencies section
- Vector<String> local_dependencies;
- Vector<String> remote_dependencies;
- Vector<String> custom_maven_repos;
-};
-
+#include "godot_plugin_config.h"
/*
* Set of prebuilt plugins.
* Currently unused, this is just for future reference:
*/
// static const PluginConfigAndroid MY_PREBUILT_PLUGIN = {
-// /*.valid_config =*/true,
-// /*.last_updated =*/0,
-// /*.name =*/"GodotPayment",
-// /*.binary_type =*/"local",
-// /*.binary =*/"res://android/build/libs/plugins/GodotPayment.release.aar",
-// /*.local_dependencies =*/{},
-// /*.remote_dependencies =*/String("com.android.billingclient:billing:2.2.1").split("|"),
-// /*.custom_maven_repos =*/{}
+// /*.valid_config =*/true,
+// /*.last_updated =*/0,
+// /*.name =*/"GodotPayment",
+// /*.binary_type =*/"local",
+// /*.binary =*/"res://android/build/libs/plugins/GodotPayment.release.aar",
+// /*.local_dependencies =*/{},
+// /*.remote_dependencies =*/String("com.android.billingclient:billing:2.2.1").split("|"),
+// /*.custom_maven_repos =*/{}
// };
-static inline String resolve_local_dependency_path(String plugin_config_dir, String dependency_path) {
+String PluginConfigAndroid::resolve_local_dependency_path(String plugin_config_dir, String dependency_path) {
String absolute_path;
if (!dependency_path.is_empty()) {
if (dependency_path.is_absolute_path()) {
@@ -112,7 +57,7 @@ static inline String resolve_local_dependency_path(String plugin_config_dir, Str
return absolute_path;
}
-static inline PluginConfigAndroid resolve_prebuilt_plugin(PluginConfigAndroid prebuilt_plugin, String plugin_config_dir) {
+PluginConfigAndroid PluginConfigAndroid::resolve_prebuilt_plugin(PluginConfigAndroid prebuilt_plugin, String plugin_config_dir) {
PluginConfigAndroid resolved = prebuilt_plugin;
resolved.binary = resolved.binary_type == PluginConfigAndroid::BINARY_TYPE_LOCAL ? resolve_local_dependency_path(plugin_config_dir, prebuilt_plugin.binary) : prebuilt_plugin.binary;
if (!prebuilt_plugin.local_dependencies.is_empty()) {
@@ -124,13 +69,13 @@ static inline PluginConfigAndroid resolve_prebuilt_plugin(PluginConfigAndroid pr
return resolved;
}
-static inline Vector<PluginConfigAndroid> get_prebuilt_plugins(String plugins_base_dir) {
+Vector<PluginConfigAndroid> PluginConfigAndroid::get_prebuilt_plugins(String plugins_base_dir) {
Vector<PluginConfigAndroid> prebuilt_plugins;
// prebuilt_plugins.push_back(resolve_prebuilt_plugin(MY_PREBUILT_PLUGIN, plugins_base_dir));
return prebuilt_plugins;
}
-static inline bool is_plugin_config_valid(PluginConfigAndroid plugin_config) {
+bool PluginConfigAndroid::is_plugin_config_valid(PluginConfigAndroid plugin_config) {
bool valid_name = !plugin_config.name.is_empty();
bool valid_binary_type = plugin_config.binary_type == PluginConfigAndroid::BINARY_TYPE_LOCAL ||
plugin_config.binary_type == PluginConfigAndroid::BINARY_TYPE_REMOTE;
@@ -155,7 +100,7 @@ static inline bool is_plugin_config_valid(PluginConfigAndroid plugin_config) {
return valid_name && valid_binary && valid_binary_type && valid_local_dependencies;
}
-static inline uint64_t get_plugin_modification_time(const PluginConfigAndroid &plugin_config, const String &config_path) {
+uint64_t PluginConfigAndroid::get_plugin_modification_time(const PluginConfigAndroid &plugin_config, const String &config_path) {
uint64_t last_updated = FileAccess::get_modified_time(config_path);
last_updated = MAX(last_updated, FileAccess::get_modified_time(plugin_config.binary));
@@ -167,7 +112,7 @@ static inline uint64_t get_plugin_modification_time(const PluginConfigAndroid &p
return last_updated;
}
-static inline PluginConfigAndroid load_plugin_config(Ref<ConfigFile> config_file, const String &path) {
+PluginConfigAndroid PluginConfigAndroid::load_plugin_config(Ref<ConfigFile> config_file, const String &path) {
PluginConfigAndroid plugin_config = {};
if (config_file.is_valid()) {
@@ -201,7 +146,7 @@ static inline PluginConfigAndroid load_plugin_config(Ref<ConfigFile> config_file
return plugin_config;
}
-static inline String get_plugins_binaries(String binary_type, Vector<PluginConfigAndroid> plugins_configs) {
+String PluginConfigAndroid::get_plugins_binaries(String binary_type, Vector<PluginConfigAndroid> plugins_configs) {
String plugins_binaries;
if (!plugins_configs.is_empty()) {
Vector<String> binaries;
@@ -230,7 +175,7 @@ static inline String get_plugins_binaries(String binary_type, Vector<PluginConfi
return plugins_binaries;
}
-static inline String get_plugins_custom_maven_repos(Vector<PluginConfigAndroid> plugins_configs) {
+String PluginConfigAndroid::get_plugins_custom_maven_repos(Vector<PluginConfigAndroid> plugins_configs) {
String custom_maven_repos;
if (!plugins_configs.is_empty()) {
Vector<String> repos_urls;
@@ -248,7 +193,7 @@ static inline String get_plugins_custom_maven_repos(Vector<PluginConfigAndroid>
return custom_maven_repos;
}
-static inline String get_plugins_names(Vector<PluginConfigAndroid> plugins_configs) {
+String PluginConfigAndroid::get_plugins_names(Vector<PluginConfigAndroid> plugins_configs) {
String plugins_names;
if (!plugins_configs.is_empty()) {
Vector<String> names;
@@ -265,5 +210,3 @@ static inline String get_plugins_names(Vector<PluginConfigAndroid> plugins_confi
return plugins_names;
}
-
-#endif // GODOT_PLUGIN_CONFIG_H
diff --git a/platform/android/export/godot_plugin_config.h b/platform/android/export/godot_plugin_config.h
new file mode 100644
index 0000000000..c016634371
--- /dev/null
+++ b/platform/android/export/godot_plugin_config.h
@@ -0,0 +1,106 @@
+/*************************************************************************/
+/* godot_plugin_config.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef ANDROID_GODOT_PLUGIN_CONFIG_H
+#define ANDROID_GODOT_PLUGIN_CONFIG_H
+
+#include "core/config/project_settings.h"
+#include "core/error/error_list.h"
+#include "core/io/config_file.h"
+#include "core/string/ustring.h"
+
+/*
+ The `config` section and fields are required and defined as follow:
+- **name**: name of the plugin.
+- **binary_type**: can be either `local` or `remote`. The type affects the **binary** field.
+- **binary**:
+ - if **binary_type** is `local`, then this should be the filename of the plugin `aar` file in the `res://android/plugins` directory (e.g: `MyPlugin.aar`).
+ - if **binary_type** is `remote`, then this should be a declaration for a remote gradle binary (e.g: "org.godot.example:my-plugin:0.0.0").
+
+The `dependencies` section and fields are optional and defined as follow:
+- **local**: contains a list of local `.aar` binary files the plugin depends on. The local binary dependencies must also be located in the `res://android/plugins` directory.
+- **remote**: contains a list of remote binary gradle dependencies for the plugin.
+- **custom_maven_repos**: contains a list of urls specifying custom maven repos required for the plugin's dependencies.
+
+ See https://github.com/godotengine/godot/issues/38157#issuecomment-618773871
+ */
+struct PluginConfigAndroid {
+ inline static const char *PLUGIN_CONFIG_EXT = ".gdap";
+
+ inline static const char *CONFIG_SECTION = "config";
+ inline static const char *CONFIG_NAME_KEY = "name";
+ inline static const char *CONFIG_BINARY_TYPE_KEY = "binary_type";
+ inline static const char *CONFIG_BINARY_KEY = "binary";
+
+ inline static const char *DEPENDENCIES_SECTION = "dependencies";
+ inline static const char *DEPENDENCIES_LOCAL_KEY = "local";
+ inline static const char *DEPENDENCIES_REMOTE_KEY = "remote";
+ inline static const char *DEPENDENCIES_CUSTOM_MAVEN_REPOS_KEY = "custom_maven_repos";
+
+ inline static const char *BINARY_TYPE_LOCAL = "local";
+ inline static const char *BINARY_TYPE_REMOTE = "remote";
+
+ inline static const char *PLUGIN_VALUE_SEPARATOR = "|";
+
+ // Set to true when the config file is properly loaded.
+ bool valid_config = false;
+ // Unix timestamp of last change to this plugin.
+ uint64_t last_updated = 0;
+
+ // Required config section
+ String name;
+ String binary_type;
+ String binary;
+
+ // Optional dependencies section
+ Vector<String> local_dependencies;
+ Vector<String> remote_dependencies;
+ Vector<String> custom_maven_repos;
+
+ static String resolve_local_dependency_path(String plugin_config_dir, String dependency_path);
+
+ static PluginConfigAndroid resolve_prebuilt_plugin(PluginConfigAndroid prebuilt_plugin, String plugin_config_dir);
+
+ static Vector<PluginConfigAndroid> get_prebuilt_plugins(String plugins_base_dir);
+
+ static bool is_plugin_config_valid(PluginConfigAndroid plugin_config);
+
+ static uint64_t get_plugin_modification_time(const PluginConfigAndroid &plugin_config, const String &config_path);
+
+ static PluginConfigAndroid load_plugin_config(Ref<ConfigFile> config_file, const String &path);
+
+ static String get_plugins_binaries(String binary_type, Vector<PluginConfigAndroid> plugins_configs);
+
+ static String get_plugins_custom_maven_repos(Vector<PluginConfigAndroid> plugins_configs);
+
+ static String get_plugins_names(Vector<PluginConfigAndroid> plugins_configs);
+};
+
+#endif // GODOT_PLUGIN_CONFIG_H
diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp
new file mode 100644
index 0000000000..354287d872
--- /dev/null
+++ b/platform/android/export/gradle_export_util.cpp
@@ -0,0 +1,252 @@
+/*************************************************************************/
+/* gradle_export_util.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gradle_export_util.h"
+
+int _get_android_orientation_value(DisplayServer::ScreenOrientation screen_orientation) {
+ switch (screen_orientation) {
+ case DisplayServer::SCREEN_PORTRAIT:
+ return 1;
+ case DisplayServer::SCREEN_REVERSE_LANDSCAPE:
+ return 8;
+ case DisplayServer::SCREEN_REVERSE_PORTRAIT:
+ return 9;
+ case DisplayServer::SCREEN_SENSOR_LANDSCAPE:
+ return 11;
+ case DisplayServer::SCREEN_SENSOR_PORTRAIT:
+ return 12;
+ case DisplayServer::SCREEN_SENSOR:
+ return 13;
+ case DisplayServer::SCREEN_LANDSCAPE:
+ default:
+ return 0;
+ }
+}
+
+String _get_android_orientation_label(DisplayServer::ScreenOrientation screen_orientation) {
+ switch (screen_orientation) {
+ case DisplayServer::SCREEN_PORTRAIT:
+ return "portrait";
+ case DisplayServer::SCREEN_REVERSE_LANDSCAPE:
+ return "reverseLandscape";
+ case DisplayServer::SCREEN_REVERSE_PORTRAIT:
+ return "reversePortrait";
+ case DisplayServer::SCREEN_SENSOR_LANDSCAPE:
+ return "userLandscape";
+ case DisplayServer::SCREEN_SENSOR_PORTRAIT:
+ return "userPortrait";
+ case DisplayServer::SCREEN_SENSOR:
+ return "fullUser";
+ case DisplayServer::SCREEN_LANDSCAPE:
+ default:
+ return "landscape";
+ }
+}
+
+// Utility method used to create a directory.
+Error create_directory(const String &p_dir) {
+ if (!DirAccess::exists(p_dir)) {
+ DirAccess *filesystem_da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ ERR_FAIL_COND_V_MSG(!filesystem_da, ERR_CANT_CREATE, "Cannot create directory '" + p_dir + "'.");
+ Error err = filesystem_da->make_dir_recursive(p_dir);
+ ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "Cannot create directory '" + p_dir + "'.");
+ memdelete(filesystem_da);
+ }
+ return OK;
+}
+
+// Writes p_data into a file at p_path, creating directories if necessary.
+// Note: this will overwrite the file at p_path if it already exists.
+Error store_file_at_path(const String &p_path, const Vector<uint8_t> &p_data) {
+ String dir = p_path.get_base_dir();
+ Error err = create_directory(dir);
+ if (err != OK) {
+ return err;
+ }
+ FileAccess *fa = FileAccess::open(p_path, FileAccess::WRITE);
+ ERR_FAIL_COND_V_MSG(!fa, ERR_CANT_CREATE, "Cannot create file '" + p_path + "'.");
+ fa->store_buffer(p_data.ptr(), p_data.size());
+ memdelete(fa);
+ return OK;
+}
+
+// Writes string p_data into a file at p_path, creating directories if necessary.
+// Note: this will overwrite the file at p_path if it already exists.
+Error store_string_at_path(const String &p_path, const String &p_data) {
+ String dir = p_path.get_base_dir();
+ Error err = create_directory(dir);
+ if (err != OK) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ print_error("Unable to write data into " + p_path);
+ }
+ return err;
+ }
+ FileAccess *fa = FileAccess::open(p_path, FileAccess::WRITE);
+ ERR_FAIL_COND_V_MSG(!fa, ERR_CANT_CREATE, "Cannot create file '" + p_path + "'.");
+ fa->store_string(p_data);
+ memdelete(fa);
+ return OK;
+}
+
+// Implementation of EditorExportSaveFunction.
+// This method will only be called as an input to export_project_files.
+// It is used by the export_project_files method to save all the asset files into the gradle project.
+// It's functionality mirrors that of the method save_apk_file.
+// This method will be called ONLY when custom build is enabled.
+Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
+ String dst_path = p_path.replace_first("res://", "res://android/build/assets/");
+ print_verbose("Saving project files from " + p_path + " into " + dst_path);
+ Error err = store_file_at_path(dst_path, p_data);
+ return err;
+}
+
+// Creates strings.xml files inside the gradle project for different locales.
+Error _create_project_name_strings_files(const Ref<EditorExportPreset> &p_preset, const String &project_name) {
+ print_verbose("Creating strings resources for supported locales for project " + project_name);
+ // Stores the string into the default values directory.
+ String processed_default_xml_string = vformat(godot_project_name_xml_string, project_name.xml_escape(true));
+ store_string_at_path("res://android/build/res/values/godot_project_name_string.xml", processed_default_xml_string);
+
+ // Searches the Gradle project res/ directory to find all supported locales
+ DirAccessRef da = DirAccess::open("res://android/build/res");
+ if (!da) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ print_error("Unable to open Android resources directory.");
+ }
+ return ERR_CANT_OPEN;
+ }
+ da->list_dir_begin();
+ while (true) {
+ String file = da->get_next();
+ if (file == "") {
+ break;
+ }
+ if (!file.begins_with("values-")) {
+ // NOTE: This assumes all directories that start with "values-" are for localization.
+ continue;
+ }
+ String locale = file.replace("values-", "").replace("-r", "_");
+ String property_name = "application/config/name_" + locale;
+ String locale_directory = "res://android/build/res/" + file + "/godot_project_name_string.xml";
+ if (ProjectSettings::get_singleton()->has_setting(property_name)) {
+ String locale_project_name = ProjectSettings::get_singleton()->get(property_name);
+ String processed_xml_string = vformat(godot_project_name_xml_string, locale_project_name.xml_escape(true));
+ print_verbose("Storing project name for locale " + locale + " under " + locale_directory);
+ store_string_at_path(locale_directory, processed_xml_string);
+ } else {
+ // TODO: Once the legacy build system is deprecated we don't need to have xml files for this else branch
+ store_string_at_path(locale_directory, processed_default_xml_string);
+ }
+ }
+ da->list_dir_end();
+ return OK;
+}
+
+String bool_to_string(bool v) {
+ return v ? "true" : "false";
+}
+
+String _get_gles_tag() {
+ bool min_gles3 = ProjectSettings::get_singleton()->get("rendering/driver/driver_name") == "GLES3" &&
+ !ProjectSettings::get_singleton()->get("rendering/driver/fallback_to_gles2");
+ return min_gles3 ? " <uses-feature android:glEsVersion=\"0x00030000\" android:required=\"true\" />\n" : "";
+}
+
+String _get_screen_sizes_tag(const Ref<EditorExportPreset> &p_preset) {
+ String manifest_screen_sizes = " <supports-screens \n tools:node=\"replace\"";
+ String sizes[] = { "small", "normal", "large", "xlarge" };
+ size_t num_sizes = sizeof(sizes) / sizeof(sizes[0]);
+ for (size_t i = 0; i < num_sizes; i++) {
+ String feature_name = vformat("screen/support_%s", sizes[i]);
+ String feature_support = bool_to_string(p_preset->get(feature_name));
+ String xml_entry = vformat("\n android:%sScreens=\"%s\"", sizes[i], feature_support);
+ manifest_screen_sizes += xml_entry;
+ }
+ manifest_screen_sizes += " />\n";
+ return manifest_screen_sizes;
+}
+
+String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset) {
+ String manifest_xr_features;
+ bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1;
+ if (uses_xr) {
+ int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
+ if (hand_tracking_index == 1) {
+ manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"oculus.software.handtracking\" android:required=\"false\" />\n";
+ } else if (hand_tracking_index == 2) {
+ manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"oculus.software.handtracking\" android:required=\"true\" />\n";
+ }
+ }
+ return manifest_xr_features;
+}
+
+String _get_instrumentation_tag(const Ref<EditorExportPreset> &p_preset) {
+ String package_name = p_preset->get("package/unique_name");
+ String manifest_instrumentation_text = vformat(
+ " <instrumentation\n"
+ " tools:node=\"replace\"\n"
+ " android:name=\".GodotInstrumentation\"\n"
+ " android:icon=\"@mipmap/icon\"\n"
+ " android:label=\"@string/godot_project_name_string\"\n"
+ " android:targetPackage=\"%s\" />\n",
+ package_name);
+ return manifest_instrumentation_text;
+}
+
+String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) {
+ bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1;
+ String orientation = _get_android_orientation_label(DisplayServer::ScreenOrientation(int(GLOBAL_GET("display/window/handheld/orientation"))));
+ String manifest_activity_text = vformat(
+ " <activity android:name=\"com.godot.game.GodotApp\" "
+ "tools:replace=\"android:screenOrientation\" "
+ "android:screenOrientation=\"%s\">\n",
+ orientation);
+ if (!uses_xr) {
+ manifest_activity_text += " <meta-data tools:node=\"remove\" android:name=\"com.oculus.vr.focusaware\" />\n";
+ }
+ manifest_activity_text += " </activity>\n";
+ return manifest_activity_text;
+}
+
+String _get_application_tag(const Ref<EditorExportPreset> &p_preset) {
+ String manifest_application_text = vformat(
+ " <application android:label=\"@string/godot_project_name_string\"\n"
+ " android:allowBackup=\"%s\"\n"
+ " android:icon=\"@mipmap/icon\"\n"
+ " android:isGame=\"%s\"\n"
+ " tools:replace=\"android:allowBackup,android:isGame\"\n"
+ " tools:ignore=\"GoogleAppIndexingWarning\">\n\n",
+ bool_to_string(p_preset->get("user_data_backup/allow")),
+ bool_to_string(p_preset->get("package/classify_as_game")));
+
+ manifest_application_text += _get_activity_tag(p_preset);
+ manifest_application_text += " </application>\n";
+ return manifest_application_text;
+}
diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h
index 52a7e4c5cf..44e9a1727d 100644
--- a/platform/android/export/gradle_export_util.h
+++ b/platform/android/export/gradle_export_util.h
@@ -44,225 +44,43 @@ const String godot_project_name_xml_string = R"(<?xml version="1.0" encoding="ut
</resources>
)";
-int _get_android_orientation_value(DisplayServer::ScreenOrientation screen_orientation) {
- switch (screen_orientation) {
- case DisplayServer::SCREEN_PORTRAIT:
- return 1;
- case DisplayServer::SCREEN_REVERSE_LANDSCAPE:
- return 8;
- case DisplayServer::SCREEN_REVERSE_PORTRAIT:
- return 9;
- case DisplayServer::SCREEN_SENSOR_LANDSCAPE:
- return 11;
- case DisplayServer::SCREEN_SENSOR_PORTRAIT:
- return 12;
- case DisplayServer::SCREEN_SENSOR:
- return 13;
- case DisplayServer::SCREEN_LANDSCAPE:
- default:
- return 0;
- }
-}
+int _get_android_orientation_value(DisplayServer::ScreenOrientation screen_orientation);
-String _get_android_orientation_label(DisplayServer::ScreenOrientation screen_orientation) {
- switch (screen_orientation) {
- case DisplayServer::SCREEN_PORTRAIT:
- return "portrait";
- case DisplayServer::SCREEN_REVERSE_LANDSCAPE:
- return "reverseLandscape";
- case DisplayServer::SCREEN_REVERSE_PORTRAIT:
- return "reversePortrait";
- case DisplayServer::SCREEN_SENSOR_LANDSCAPE:
- return "userLandscape";
- case DisplayServer::SCREEN_SENSOR_PORTRAIT:
- return "userPortrait";
- case DisplayServer::SCREEN_SENSOR:
- return "fullUser";
- case DisplayServer::SCREEN_LANDSCAPE:
- default:
- return "landscape";
- }
-}
+String _get_android_orientation_label(DisplayServer::ScreenOrientation screen_orientation);
// Utility method used to create a directory.
-Error create_directory(const String &p_dir) {
- if (!DirAccess::exists(p_dir)) {
- DirAccess *filesystem_da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
- ERR_FAIL_COND_V_MSG(!filesystem_da, ERR_CANT_CREATE, "Cannot create directory '" + p_dir + "'.");
- Error err = filesystem_da->make_dir_recursive(p_dir);
- ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "Cannot create directory '" + p_dir + "'.");
- memdelete(filesystem_da);
- }
- return OK;
-}
+Error create_directory(const String &p_dir);
// Writes p_data into a file at p_path, creating directories if necessary.
// Note: this will overwrite the file at p_path if it already exists.
-Error store_file_at_path(const String &p_path, const Vector<uint8_t> &p_data) {
- String dir = p_path.get_base_dir();
- Error err = create_directory(dir);
- if (err != OK) {
- return err;
- }
- FileAccess *fa = FileAccess::open(p_path, FileAccess::WRITE);
- ERR_FAIL_COND_V_MSG(!fa, ERR_CANT_CREATE, "Cannot create file '" + p_path + "'.");
- fa->store_buffer(p_data.ptr(), p_data.size());
- memdelete(fa);
- return OK;
-}
+Error store_file_at_path(const String &p_path, const Vector<uint8_t> &p_data);
// Writes string p_data into a file at p_path, creating directories if necessary.
// Note: this will overwrite the file at p_path if it already exists.
-Error store_string_at_path(const String &p_path, const String &p_data) {
- String dir = p_path.get_base_dir();
- Error err = create_directory(dir);
- if (err != OK) {
- if (OS::get_singleton()->is_stdout_verbose()) {
- print_error("Unable to write data into " + p_path);
- }
- return err;
- }
- FileAccess *fa = FileAccess::open(p_path, FileAccess::WRITE);
- ERR_FAIL_COND_V_MSG(!fa, ERR_CANT_CREATE, "Cannot create file '" + p_path + "'.");
- fa->store_string(p_data);
- memdelete(fa);
- return OK;
-}
+Error store_string_at_path(const String &p_path, const String &p_data);
// Implementation of EditorExportSaveFunction.
// This method will only be called as an input to export_project_files.
// It is used by the export_project_files method to save all the asset files into the gradle project.
// It's functionality mirrors that of the method save_apk_file.
// This method will be called ONLY when custom build is enabled.
-Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
- String dst_path = p_path.replace_first("res://", "res://android/build/assets/");
- print_verbose("Saving project files from " + p_path + " into " + dst_path);
- Error err = store_file_at_path(dst_path, p_data);
- return err;
-}
+Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
// Creates strings.xml files inside the gradle project for different locales.
-Error _create_project_name_strings_files(const Ref<EditorExportPreset> &p_preset, const String &project_name) {
- print_verbose("Creating strings resources for supported locales for project " + project_name);
- // Stores the string into the default values directory.
- String processed_default_xml_string = vformat(godot_project_name_xml_string, project_name.xml_escape(true));
- store_string_at_path("res://android/build/res/values/godot_project_name_string.xml", processed_default_xml_string);
+Error _create_project_name_strings_files(const Ref<EditorExportPreset> &p_preset, const String &project_name);
- // Searches the Gradle project res/ directory to find all supported locales
- DirAccessRef da = DirAccess::open("res://android/build/res");
- if (!da) {
- if (OS::get_singleton()->is_stdout_verbose()) {
- print_error("Unable to open Android resources directory.");
- }
- return ERR_CANT_OPEN;
- }
- da->list_dir_begin();
- while (true) {
- String file = da->get_next();
- if (file == "") {
- break;
- }
- if (!file.begins_with("values-")) {
- // NOTE: This assumes all directories that start with "values-" are for localization.
- continue;
- }
- String locale = file.replace("values-", "").replace("-r", "_");
- String property_name = "application/config/name_" + locale;
- String locale_directory = "res://android/build/res/" + file + "/godot_project_name_string.xml";
- if (ProjectSettings::get_singleton()->has_setting(property_name)) {
- String locale_project_name = ProjectSettings::get_singleton()->get(property_name);
- String processed_xml_string = vformat(godot_project_name_xml_string, locale_project_name.xml_escape(true));
- print_verbose("Storing project name for locale " + locale + " under " + locale_directory);
- store_string_at_path(locale_directory, processed_xml_string);
- } else {
- // TODO: Once the legacy build system is deprecated we don't need to have xml files for this else branch
- store_string_at_path(locale_directory, processed_default_xml_string);
- }
- }
- da->list_dir_end();
- return OK;
-}
+String bool_to_string(bool v);
-String bool_to_string(bool v) {
- return v ? "true" : "false";
-}
+String _get_gles_tag();
-String _get_gles_tag() {
- bool min_gles3 = ProjectSettings::get_singleton()->get("rendering/driver/driver_name") == "GLES3" &&
- !ProjectSettings::get_singleton()->get("rendering/driver/fallback_to_gles2");
- return min_gles3 ? " <uses-feature android:glEsVersion=\"0x00030000\" android:required=\"true\" />\n" : "";
-}
+String _get_screen_sizes_tag(const Ref<EditorExportPreset> &p_preset);
-String _get_screen_sizes_tag(const Ref<EditorExportPreset> &p_preset) {
- String manifest_screen_sizes = " <supports-screens \n tools:node=\"replace\"";
- String sizes[] = { "small", "normal", "large", "xlarge" };
- size_t num_sizes = sizeof(sizes) / sizeof(sizes[0]);
- for (size_t i = 0; i < num_sizes; i++) {
- String feature_name = vformat("screen/support_%s", sizes[i]);
- String feature_support = bool_to_string(p_preset->get(feature_name));
- String xml_entry = vformat("\n android:%sScreens=\"%s\"", sizes[i], feature_support);
- manifest_screen_sizes += xml_entry;
- }
- manifest_screen_sizes += " />\n";
- return manifest_screen_sizes;
-}
+String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset);
-String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset) {
- String manifest_xr_features;
- bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1;
- if (uses_xr) {
- int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
- if (hand_tracking_index == 1) {
- manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"oculus.software.handtracking\" android:required=\"false\" />\n";
- } else if (hand_tracking_index == 2) {
- manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"oculus.software.handtracking\" android:required=\"true\" />\n";
- }
- }
- return manifest_xr_features;
-}
+String _get_instrumentation_tag(const Ref<EditorExportPreset> &p_preset);
-String _get_instrumentation_tag(const Ref<EditorExportPreset> &p_preset) {
- String package_name = p_preset->get("package/unique_name");
- String manifest_instrumentation_text = vformat(
- " <instrumentation\n"
- " tools:node=\"replace\"\n"
- " android:name=\".GodotInstrumentation\"\n"
- " android:icon=\"@mipmap/icon\"\n"
- " android:label=\"@string/godot_project_name_string\"\n"
- " android:targetPackage=\"%s\" />\n",
- package_name);
- return manifest_instrumentation_text;
-}
+String _get_activity_tag(const Ref<EditorExportPreset> &p_preset);
-String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) {
- bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1;
- String orientation = _get_android_orientation_label(DisplayServer::ScreenOrientation(int(GLOBAL_GET("display/window/handheld/orientation"))));
- String manifest_activity_text = vformat(
- " <activity android:name=\"com.godot.game.GodotApp\" "
- "tools:replace=\"android:screenOrientation\" "
- "android:screenOrientation=\"%s\">\n",
- orientation);
- if (!uses_xr) {
- manifest_activity_text += " <meta-data tools:node=\"remove\" android:name=\"com.oculus.vr.focusaware\" />\n";
- }
- manifest_activity_text += " </activity>\n";
- return manifest_activity_text;
-}
-
-String _get_application_tag(const Ref<EditorExportPreset> &p_preset) {
- String manifest_application_text = vformat(
- " <application android:label=\"@string/godot_project_name_string\"\n"
- " android:allowBackup=\"%s\"\n"
- " android:icon=\"@mipmap/icon\"\n"
- " android:isGame=\"%s\"\n"
- " tools:replace=\"android:allowBackup,android:isGame\"\n"
- " tools:ignore=\"GoogleAppIndexingWarning\">\n\n",
- bool_to_string(p_preset->get("user_data_backup/allow")),
- bool_to_string(p_preset->get("package/classify_as_game")));
-
- manifest_application_text += _get_activity_tag(p_preset);
- manifest_application_text += " </application>\n";
- return manifest_application_text;
-}
+String _get_application_tag(const Ref<EditorExportPreset> &p_preset);
#endif //GODOT_GRADLE_EXPORT_UTIL_H
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
index 8ffa4a9249..01eb1f1ec8 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
@@ -842,6 +842,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
}
private void forceQuit() {
+ getActivity().finish();
System.exit(0);
}
diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp
index f21a14e84b..208626ae36 100644
--- a/platform/iphone/export/export.cpp
+++ b/platform/iphone/export/export.cpp
@@ -30,2027 +30,7 @@
#include "export.h"
-#include "core/config/project_settings.h"
-#include "core/io/file_access.h"
-#include "core/io/image_loader.h"
-#include "core/io/marshalls.h"
-#include "core/io/resource_saver.h"
-#include "core/io/zip_io.h"
-#include "core/os/os.h"
-#include "core/templates/safe_refcount.h"
-#include "core/version.h"
-#include "editor/editor_export.h"
-#include "editor/editor_node.h"
-#include "editor/editor_settings.h"
-#include "main/splash.gen.h"
-#include "platform/iphone/logo.gen.h"
-#include "platform/iphone/plugin/godot_plugin_config.h"
-#include "string.h"
-
-#include <sys/stat.h>
-
-class EditorExportPlatformIOS : public EditorExportPlatform {
- GDCLASS(EditorExportPlatformIOS, EditorExportPlatform);
-
- int version_code;
-
- Ref<ImageTexture> logo;
-
- // Plugins
- SafeFlag plugins_changed;
- Thread check_for_changes_thread;
- SafeFlag quit_request;
- Mutex plugins_lock;
- Vector<PluginConfigIOS> plugins;
-
- typedef Error (*FileHandler)(String p_file, void *p_userdata);
- static Error _walk_dir_recursive(DirAccess *p_da, FileHandler p_handler, void *p_userdata);
- static Error _codesign(String p_file, void *p_userdata);
- void _blend_and_rotate(Ref<Image> &p_dst, Ref<Image> &p_src, bool p_rot);
-
- struct IOSConfigData {
- String pkg_name;
- String binary_name;
- String plist_content;
- String architectures;
- String linker_flags;
- String cpp_code;
- String modules_buildfile;
- String modules_fileref;
- String modules_buildphase;
- String modules_buildgrp;
- Vector<String> capabilities;
- };
- struct ExportArchitecture {
- String name;
- bool is_default = false;
-
- ExportArchitecture() {}
-
- ExportArchitecture(String p_name, bool p_is_default) {
- name = p_name;
- is_default = p_is_default;
- }
- };
-
- struct IOSExportAsset {
- String exported_path;
- bool is_framework = false; // framework is anything linked to the binary, otherwise it's a resource
- bool should_embed = false;
- };
-
- String _get_additional_plist_content();
- String _get_linker_flags();
- String _get_cpp_code();
- void _fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const IOSConfigData &p_config, bool p_debug);
- Error _export_loading_screen_images(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir);
- Error _export_loading_screen_file(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir);
- Error _export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir);
-
- Vector<ExportArchitecture> _get_supported_architectures();
- Vector<String> _get_preset_architectures(const Ref<EditorExportPreset> &p_preset);
-
- void _add_assets_to_project(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets);
- Error _export_additional_assets(const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets);
- Error _copy_asset(const String &p_out_dir, const String &p_asset, const String *p_custom_file_name, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets);
- Error _export_additional_assets(const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets);
- Error _export_ios_plugins(const Ref<EditorExportPreset> &p_preset, IOSConfigData &p_config_data, const String &dest_dir, Vector<IOSExportAsset> &r_exported_assets, bool p_debug);
-
- bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const {
- String pname = p_package;
-
- if (pname.length() == 0) {
- if (r_error) {
- *r_error = TTR("Identifier is missing.");
- }
- return false;
- }
-
- for (int i = 0; i < pname.length(); i++) {
- char32_t c = pname[i];
- if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '.')) {
- if (r_error) {
- *r_error = vformat(TTR("The character '%s' is not allowed in Identifier."), String::chr(c));
- }
- return false;
- }
- }
-
- return true;
- }
-
- static void _check_for_changes_poll_thread(void *ud) {
- EditorExportPlatformIOS *ea = (EditorExportPlatformIOS *)ud;
-
- while (!ea->quit_request.is_set()) {
- // Nothing to do if we already know the plugins have changed.
- if (!ea->plugins_changed.is_set()) {
- MutexLock lock(ea->plugins_lock);
-
- Vector<PluginConfigIOS> loaded_plugins = get_plugins();
-
- if (ea->plugins.size() != loaded_plugins.size()) {
- ea->plugins_changed.set();
- } else {
- for (int i = 0; i < ea->plugins.size(); i++) {
- if (ea->plugins[i].name != loaded_plugins[i].name || ea->plugins[i].last_updated != loaded_plugins[i].last_updated) {
- ea->plugins_changed.set();
- break;
- }
- }
- }
- }
-
- uint64_t wait = 3000000;
- uint64_t time = OS::get_singleton()->get_ticks_usec();
- while (OS::get_singleton()->get_ticks_usec() - time < wait) {
- OS::get_singleton()->delay_usec(300000);
-
- if (ea->quit_request.is_set()) {
- break;
- }
- }
- }
- }
-
-protected:
- virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) override;
- virtual void get_export_options(List<ExportOption> *r_options) override;
-
-public:
- virtual String get_name() const override { return "iOS"; }
- virtual String get_os_name() const override { return "iOS"; }
- virtual Ref<Texture2D> get_logo() const override { return logo; }
-
- virtual bool should_update_export_options() override {
- bool export_options_changed = plugins_changed.is_set();
- if (export_options_changed) {
- // don't clear unless we're reporting true, to avoid race
- plugins_changed.clear();
- }
- return export_options_changed;
- }
-
- virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override {
- List<String> list;
- list.push_back("ipa");
- return list;
- }
- virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
-
- virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
-
- virtual void get_platform_features(List<String> *r_features) override {
- r_features->push_back("mobile");
- r_features->push_back("iOS");
- }
-
- virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) override {
- }
-
- EditorExportPlatformIOS();
- ~EditorExportPlatformIOS();
-
- /// List the gdip files in the directory specified by the p_path parameter.
- static Vector<String> list_plugin_config_files(const String &p_path, bool p_check_directories) {
- Vector<String> dir_files;
- DirAccessRef da = DirAccess::open(p_path);
- if (da) {
- da->list_dir_begin();
- while (true) {
- String file = da->get_next();
- if (file.is_empty()) {
- break;
- }
-
- if (file == "." || file == "..") {
- continue;
- }
-
- if (da->current_is_hidden()) {
- continue;
- }
-
- if (da->current_is_dir()) {
- if (p_check_directories) {
- Vector<String> directory_files = list_plugin_config_files(p_path.plus_file(file), false);
- for (int i = 0; i < directory_files.size(); ++i) {
- dir_files.push_back(file.plus_file(directory_files[i]));
- }
- }
-
- continue;
- }
-
- if (file.ends_with(PluginConfigIOS::PLUGIN_CONFIG_EXT)) {
- dir_files.push_back(file);
- }
- }
- da->list_dir_end();
- }
-
- return dir_files;
- }
-
- static Vector<PluginConfigIOS> get_plugins() {
- Vector<PluginConfigIOS> loaded_plugins;
-
- String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().plus_file("ios/plugins");
-
- if (DirAccess::exists(plugins_dir)) {
- Vector<String> plugins_filenames = list_plugin_config_files(plugins_dir, true);
-
- if (!plugins_filenames.is_empty()) {
- Ref<ConfigFile> config_file = memnew(ConfigFile);
- for (int i = 0; i < plugins_filenames.size(); i++) {
- PluginConfigIOS config = load_plugin_config(config_file, plugins_dir.plus_file(plugins_filenames[i]));
- if (config.valid_config) {
- loaded_plugins.push_back(config);
- } else {
- print_error("Invalid plugin config file " + plugins_filenames[i]);
- }
- }
- }
- }
-
- return loaded_plugins;
- }
-
- static Vector<PluginConfigIOS> get_enabled_plugins(const Ref<EditorExportPreset> &p_presets) {
- Vector<PluginConfigIOS> enabled_plugins;
- Vector<PluginConfigIOS> all_plugins = get_plugins();
- for (int i = 0; i < all_plugins.size(); i++) {
- PluginConfigIOS plugin = all_plugins[i];
- bool enabled = p_presets->get("plugins/" + plugin.name);
- if (enabled) {
- enabled_plugins.push_back(plugin);
- }
- }
-
- return enabled_plugins;
- }
-};
-
-void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
- String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
- r_features->push_back("pvrtc");
- if (driver == "Vulkan") {
- // FIXME: Review if this is correct.
- r_features->push_back("etc2");
- }
-
- Vector<String> architectures = _get_preset_architectures(p_preset);
- for (int i = 0; i < architectures.size(); ++i) {
- r_features->push_back(architectures[i]);
- }
-}
-
-Vector<EditorExportPlatformIOS::ExportArchitecture> EditorExportPlatformIOS::_get_supported_architectures() {
- Vector<ExportArchitecture> archs;
- archs.push_back(ExportArchitecture("armv7", false)); // Disabled by default, not included in official templates.
- archs.push_back(ExportArchitecture("arm64", true));
- return archs;
-}
-
-struct LoadingScreenInfo {
- const char *preset_key;
- const char *export_name;
- int width = 0;
- int height = 0;
- bool rotate = false;
-};
-
-static const LoadingScreenInfo loading_screen_infos[] = {
- { "landscape_launch_screens/iphone_2436x1125", "Default-Landscape-X.png", 2436, 1125, false },
- { "landscape_launch_screens/iphone_2208x1242", "Default-Landscape-736h@3x.png", 2208, 1242, false },
- { "landscape_launch_screens/ipad_1024x768", "Default-Landscape.png", 1024, 768, false },
- { "landscape_launch_screens/ipad_2048x1536", "Default-Landscape@2x.png", 2048, 1536, false },
-
- { "portrait_launch_screens/iphone_640x960", "Default-480h@2x.png", 640, 960, true },
- { "portrait_launch_screens/iphone_640x1136", "Default-568h@2x.png", 640, 1136, true },
- { "portrait_launch_screens/iphone_750x1334", "Default-667h@2x.png", 750, 1334, true },
- { "portrait_launch_screens/iphone_1125x2436", "Default-Portrait-X.png", 1125, 2436, true },
- { "portrait_launch_screens/ipad_768x1024", "Default-Portrait.png", 768, 1024, true },
- { "portrait_launch_screens/ipad_1536x2048", "Default-Portrait@2x.png", 1536, 2048, true },
- { "portrait_launch_screens/iphone_1242x2208", "Default-Portrait-736h@3x.png", 1242, 2208, true }
-};
-
-void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) {
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
-
- Vector<ExportArchitecture> architectures = _get_supported_architectures();
- for (int i = 0; i < architectures.size(); ++i) {
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architectures/" + architectures[i].name), architectures[i].is_default));
- }
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_store_team_id"), ""));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/provisioning_profile_uuid_debug"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/code_sign_identity_debug", PROPERTY_HINT_PLACEHOLDER_TEXT, "iPhone Developer"), "iPhone Developer"));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/export_method_debug", PROPERTY_HINT_ENUM, "App Store,Development,Ad-Hoc,Enterprise"), 1));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/provisioning_profile_uuid_release"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/code_sign_identity_release", PROPERTY_HINT_PLACEHOLDER_TEXT, "iPhone Distribution"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/export_method_release", PROPERTY_HINT_ENUM, "App Store,Development,Ad-Hoc,Enterprise"), 0));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/targeted_device_family", PROPERTY_HINT_ENUM, "iPhone,iPad,iPhone & iPad"), 2));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/info"), "Made with Godot Engine"));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0"));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0"));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
-
- Vector<PluginConfigIOS> found_plugins = get_plugins();
- for (int i = 0; i < found_plugins.size(); i++) {
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "plugins/" + found_plugins[i].name), false));
- }
-
- Set<String> plist_keys;
-
- for (int i = 0; i < found_plugins.size(); i++) {
- // Editable plugin plist values
- PluginConfigIOS plugin = found_plugins[i];
- const String *K = nullptr;
-
- while ((K = plugin.plist.next(K))) {
- String key = *K;
- PluginConfigIOS::PlistItem item = plugin.plist[key];
- switch (item.type) {
- case PluginConfigIOS::PlistItemType::STRING_INPUT: {
- String preset_name = "plugins_plist/" + key;
- if (!plist_keys.has(preset_name)) {
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, preset_name), item.value));
- plist_keys.insert(preset_name);
- }
- } break;
- default:
- continue;
- }
- }
- }
-
- plugins_changed.clear();
- plugins = found_plugins;
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/access_wifi"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/push_notifications"), false));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "user_data/accessible_from_files_app"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "user_data/accessible_from_itunes_sharing"), false));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/camera_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the camera"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photolibrary_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need access to the photo library"), ""));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "icons/generate_missing"), false));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "required_icons/iphone_120x120", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPhone/iPod Touch with retina display
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "required_icons/ipad_76x76", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "required_icons/app_store_1024x1024", PROPERTY_HINT_FILE, "*.png"), "")); // App Store
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/iphone_180x180", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPhone with retina HD display
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/ipad_152x152", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad with retina display
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/ipad_167x167", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad Pro
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/spotlight_40x40", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/spotlight_80x80", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight on devices with retina display
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_launch_screen_storyboard"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "storyboard/image_scale_mode", PROPERTY_HINT_ENUM, "Same as Logo,Center,Scale to Fit,Scale to Fill,Scale"), 0));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@2x", PROPERTY_HINT_FILE, "*.png"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@3x", PROPERTY_HINT_FILE, "*.png"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_custom_bg_color"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "storyboard/custom_bg_color"), Color()));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "launch_screens/generate_missing"), false));
-
- for (uint64_t i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) {
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, loading_screen_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png"), ""));
- }
-}
-
-void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const IOSConfigData &p_config, bool p_debug) {
- static const String export_method_string[] = {
- "app-store",
- "development",
- "ad-hoc",
- "enterprise"
- };
- static const String storyboard_image_scale_mode[] = {
- "center",
- "scaleAspectFit",
- "scaleAspectFill",
- "scaleToFill"
- };
- String str;
- String strnew;
- str.parse_utf8((const char *)pfile.ptr(), pfile.size());
- Vector<String> lines = str.split("\n");
- for (int i = 0; i < lines.size(); i++) {
- if (lines[i].find("$binary") != -1) {
- strnew += lines[i].replace("$binary", p_config.binary_name) + "\n";
- } else if (lines[i].find("$modules_buildfile") != -1) {
- strnew += lines[i].replace("$modules_buildfile", p_config.modules_buildfile) + "\n";
- } else if (lines[i].find("$modules_fileref") != -1) {
- strnew += lines[i].replace("$modules_fileref", p_config.modules_fileref) + "\n";
- } else if (lines[i].find("$modules_buildphase") != -1) {
- strnew += lines[i].replace("$modules_buildphase", p_config.modules_buildphase) + "\n";
- } else if (lines[i].find("$modules_buildgrp") != -1) {
- strnew += lines[i].replace("$modules_buildgrp", p_config.modules_buildgrp) + "\n";
- } else if (lines[i].find("$name") != -1) {
- strnew += lines[i].replace("$name", p_config.pkg_name) + "\n";
- } else if (lines[i].find("$info") != -1) {
- strnew += lines[i].replace("$info", p_preset->get("application/info")) + "\n";
- } else if (lines[i].find("$bundle_identifier") != -1) {
- strnew += lines[i].replace("$bundle_identifier", p_preset->get("application/bundle_identifier")) + "\n";
- } else if (lines[i].find("$short_version") != -1) {
- strnew += lines[i].replace("$short_version", p_preset->get("application/short_version")) + "\n";
- } else if (lines[i].find("$version") != -1) {
- strnew += lines[i].replace("$version", p_preset->get("application/version")) + "\n";
- } else if (lines[i].find("$signature") != -1) {
- strnew += lines[i].replace("$signature", p_preset->get("application/signature")) + "\n";
- } else if (lines[i].find("$copyright") != -1) {
- strnew += lines[i].replace("$copyright", p_preset->get("application/copyright")) + "\n";
- } else if (lines[i].find("$team_id") != -1) {
- strnew += lines[i].replace("$team_id", p_preset->get("application/app_store_team_id")) + "\n";
- } else if (lines[i].find("$default_build_config") != -1) {
- strnew += lines[i].replace("$default_build_config", p_debug ? "Debug" : "Release") + "\n";
- } else if (lines[i].find("$export_method") != -1) {
- int export_method = p_preset->get(p_debug ? "application/export_method_debug" : "application/export_method_release");
- strnew += lines[i].replace("$export_method", export_method_string[export_method]) + "\n";
- } else if (lines[i].find("$provisioning_profile_uuid_release") != -1) {
- strnew += lines[i].replace("$provisioning_profile_uuid_release", p_preset->get("application/provisioning_profile_uuid_release")) + "\n";
- } else if (lines[i].find("$provisioning_profile_uuid_debug") != -1) {
- strnew += lines[i].replace("$provisioning_profile_uuid_debug", p_preset->get("application/provisioning_profile_uuid_debug")) + "\n";
- } else if (lines[i].find("$provisioning_profile_uuid") != -1) {
- String uuid = p_debug ? p_preset->get("application/provisioning_profile_uuid_debug") : p_preset->get("application/provisioning_profile_uuid_release");
- strnew += lines[i].replace("$provisioning_profile_uuid", uuid) + "\n";
- } else if (lines[i].find("$code_sign_identity_debug") != -1) {
- strnew += lines[i].replace("$code_sign_identity_debug", p_preset->get("application/code_sign_identity_debug")) + "\n";
- } else if (lines[i].find("$code_sign_identity_release") != -1) {
- strnew += lines[i].replace("$code_sign_identity_release", p_preset->get("application/code_sign_identity_release")) + "\n";
- } else if (lines[i].find("$additional_plist_content") != -1) {
- strnew += lines[i].replace("$additional_plist_content", p_config.plist_content) + "\n";
- } else if (lines[i].find("$godot_archs") != -1) {
- strnew += lines[i].replace("$godot_archs", p_config.architectures) + "\n";
- } else if (lines[i].find("$linker_flags") != -1) {
- strnew += lines[i].replace("$linker_flags", p_config.linker_flags) + "\n";
- } else if (lines[i].find("$targeted_device_family") != -1) {
- String xcode_value;
- switch ((int)p_preset->get("application/targeted_device_family")) {
- case 0: // iPhone
- xcode_value = "1";
- break;
- case 1: // iPad
- xcode_value = "2";
- break;
- case 2: // iPhone & iPad
- xcode_value = "1,2";
- break;
- }
- strnew += lines[i].replace("$targeted_device_family", xcode_value) + "\n";
- } else if (lines[i].find("$cpp_code") != -1) {
- strnew += lines[i].replace("$cpp_code", p_config.cpp_code) + "\n";
- } else if (lines[i].find("$docs_in_place") != -1) {
- strnew += lines[i].replace("$docs_in_place", ((bool)p_preset->get("user_data/accessible_from_files_app")) ? "<true/>" : "<false/>") + "\n";
- } else if (lines[i].find("$docs_sharing") != -1) {
- strnew += lines[i].replace("$docs_sharing", ((bool)p_preset->get("user_data/accessible_from_itunes_sharing")) ? "<true/>" : "<false/>") + "\n";
- } else if (lines[i].find("$entitlements_push_notifications") != -1) {
- bool is_on = p_preset->get("capabilities/push_notifications");
- strnew += lines[i].replace("$entitlements_push_notifications", is_on ? "<key>aps-environment</key><string>development</string>" : "") + "\n";
- } else if (lines[i].find("$required_device_capabilities") != -1) {
- String capabilities;
-
- // I've removed armv7 as we can run on 64bit only devices
- // Note that capabilities listed here are requirements for the app to be installed.
- // They don't enable anything.
- Vector<String> capabilities_list = p_config.capabilities;
-
- if ((bool)p_preset->get("capabilities/access_wifi") && !capabilities_list.has("wifi")) {
- capabilities_list.push_back("wifi");
- }
-
- for (int idx = 0; idx < capabilities_list.size(); idx++) {
- capabilities += "<string>" + capabilities_list[idx] + "</string>\n";
- }
-
- strnew += lines[i].replace("$required_device_capabilities", capabilities);
- } else if (lines[i].find("$interface_orientations") != -1) {
- String orientations;
- const DisplayServer::ScreenOrientation screen_orientation =
- DisplayServer::ScreenOrientation(int(GLOBAL_GET("display/window/handheld/orientation")));
-
- switch (screen_orientation) {
- case DisplayServer::SCREEN_LANDSCAPE:
- orientations += "<string>UIInterfaceOrientationLandscapeLeft</string>\n";
- break;
- case DisplayServer::SCREEN_PORTRAIT:
- orientations += "<string>UIInterfaceOrientationPortrait</string>\n";
- break;
- case DisplayServer::SCREEN_REVERSE_LANDSCAPE:
- orientations += "<string>UIInterfaceOrientationLandscapeRight</string>\n";
- break;
- case DisplayServer::SCREEN_REVERSE_PORTRAIT:
- orientations += "<string>UIInterfaceOrientationPortraitUpsideDown</string>\n";
- break;
- case DisplayServer::SCREEN_SENSOR_LANDSCAPE:
- // Allow both landscape orientations depending on sensor direction.
- orientations += "<string>UIInterfaceOrientationLandscapeLeft</string>\n";
- orientations += "<string>UIInterfaceOrientationLandscapeRight</string>\n";
- break;
- case DisplayServer::SCREEN_SENSOR_PORTRAIT:
- // Allow both portrait orientations depending on sensor direction.
- orientations += "<string>UIInterfaceOrientationPortrait</string>\n";
- orientations += "<string>UIInterfaceOrientationPortraitUpsideDown</string>\n";
- break;
- case DisplayServer::SCREEN_SENSOR:
- // Allow all screen orientations depending on sensor direction.
- orientations += "<string>UIInterfaceOrientationLandscapeLeft</string>\n";
- orientations += "<string>UIInterfaceOrientationLandscapeRight</string>\n";
- orientations += "<string>UIInterfaceOrientationPortrait</string>\n";
- orientations += "<string>UIInterfaceOrientationPortraitUpsideDown</string>\n";
- break;
- }
-
- strnew += lines[i].replace("$interface_orientations", orientations);
- } else if (lines[i].find("$camera_usage_description") != -1) {
- String description = p_preset->get("privacy/camera_usage_description");
- strnew += lines[i].replace("$camera_usage_description", description) + "\n";
- } else if (lines[i].find("$microphone_usage_description") != -1) {
- String description = p_preset->get("privacy/microphone_usage_description");
- strnew += lines[i].replace("$microphone_usage_description", description) + "\n";
- } else if (lines[i].find("$photolibrary_usage_description") != -1) {
- String description = p_preset->get("privacy/photolibrary_usage_description");
- strnew += lines[i].replace("$photolibrary_usage_description", description) + "\n";
- } else if (lines[i].find("$plist_launch_screen_name") != -1) {
- bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
- String value = is_on ? "<key>UILaunchStoryboardName</key>\n<string>Launch Screen</string>" : "";
- strnew += lines[i].replace("$plist_launch_screen_name", value) + "\n";
- } else if (lines[i].find("$pbx_launch_screen_file_reference") != -1) {
- bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
- String value = is_on ? "90DD2D9D24B36E8000717FE1 = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = \"Launch Screen.storyboard\"; sourceTree = \"<group>\"; };" : "";
- strnew += lines[i].replace("$pbx_launch_screen_file_reference", value) + "\n";
- } else if (lines[i].find("$pbx_launch_screen_copy_files") != -1) {
- bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
- String value = is_on ? "90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */," : "";
- strnew += lines[i].replace("$pbx_launch_screen_copy_files", value) + "\n";
- } else if (lines[i].find("$pbx_launch_screen_build_phase") != -1) {
- bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
- String value = is_on ? "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */," : "";
- strnew += lines[i].replace("$pbx_launch_screen_build_phase", value) + "\n";
- } else if (lines[i].find("$pbx_launch_screen_build_reference") != -1) {
- bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
- String value = is_on ? "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */; };" : "";
- strnew += lines[i].replace("$pbx_launch_screen_build_reference", value) + "\n";
- } else if (lines[i].find("$pbx_launch_image_usage_setting") != -1) {
- bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
- String value = is_on ? "" : "ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;";
- strnew += lines[i].replace("$pbx_launch_image_usage_setting", value) + "\n";
- } else if (lines[i].find("$launch_screen_image_mode") != -1) {
- int image_scale_mode = p_preset->get("storyboard/image_scale_mode");
- String value;
-
- switch (image_scale_mode) {
- case 0: {
- String logo_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
- bool is_on = ProjectSettings::get_singleton()->get("application/boot_splash/fullsize");
- // If custom logo is not specified, Godot does not scale default one, so we should do the same.
- value = (is_on && logo_path.length() > 0) ? "scaleAspectFit" : "center";
- } break;
- default: {
- value = storyboard_image_scale_mode[image_scale_mode - 1];
- }
- }
-
- strnew += lines[i].replace("$launch_screen_image_mode", value) + "\n";
- } else if (lines[i].find("$launch_screen_background_color") != -1) {
- bool use_custom = p_preset->get("storyboard/use_custom_bg_color");
- Color color = use_custom ? p_preset->get("storyboard/custom_bg_color") : ProjectSettings::get_singleton()->get("application/boot_splash/bg_color");
- const String value_format = "red=\"$red\" green=\"$green\" blue=\"$blue\" alpha=\"$alpha\"";
-
- Dictionary value_dictionary;
- value_dictionary["red"] = color.r;
- value_dictionary["green"] = color.g;
- value_dictionary["blue"] = color.b;
- value_dictionary["alpha"] = color.a;
- String value = value_format.format(value_dictionary, "$_");
-
- strnew += lines[i].replace("$launch_screen_background_color", value) + "\n";
- } else {
- strnew += lines[i] + "\n";
- }
- }
-
- // !BAS! I'm assuming the 9 in the original code was a typo. I've added -1 or else it seems to also be adding our terminating zero...
- // should apply the same fix in our OSX export.
- CharString cs = strnew.utf8();
- pfile.resize(cs.size() - 1);
- for (int i = 0; i < cs.size() - 1; i++) {
- pfile.write[i] = cs[i];
- }
-}
-
-String EditorExportPlatformIOS::_get_additional_plist_content() {
- Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
- String result;
- for (int i = 0; i < export_plugins.size(); ++i) {
- result += export_plugins[i]->get_ios_plist_content();
- }
- return result;
-}
-
-String EditorExportPlatformIOS::_get_linker_flags() {
- Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
- String result;
- for (int i = 0; i < export_plugins.size(); ++i) {
- String flags = export_plugins[i]->get_ios_linker_flags();
- if (flags.length() == 0) {
- continue;
- }
- if (result.length() > 0) {
- result += ' ';
- }
- result += flags;
- }
- // the flags will be enclosed in quotes, so need to escape them
- return result.replace("\"", "\\\"");
-}
-
-String EditorExportPlatformIOS::_get_cpp_code() {
- Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
- String result;
- for (int i = 0; i < export_plugins.size(); ++i) {
- result += export_plugins[i]->get_ios_cpp_code();
- }
- return result;
-}
-
-void EditorExportPlatformIOS::_blend_and_rotate(Ref<Image> &p_dst, Ref<Image> &p_src, bool p_rot) {
- ERR_FAIL_COND(p_dst.is_null());
- ERR_FAIL_COND(p_src.is_null());
-
- int sw = p_rot ? p_src->get_height() : p_src->get_width();
- int sh = p_rot ? p_src->get_width() : p_src->get_height();
-
- int x_pos = (p_dst->get_width() - sw) / 2;
- int y_pos = (p_dst->get_height() - sh) / 2;
-
- int xs = (x_pos >= 0) ? 0 : -x_pos;
- int ys = (y_pos >= 0) ? 0 : -y_pos;
-
- if (sw + x_pos > p_dst->get_width()) {
- sw = p_dst->get_width() - x_pos;
- }
- if (sh + y_pos > p_dst->get_height()) {
- sh = p_dst->get_height() - y_pos;
- }
-
- for (int y = ys; y < sh; y++) {
- for (int x = xs; x < sw; x++) {
- Color sc = p_rot ? p_src->get_pixel(p_src->get_width() - y - 1, x) : p_src->get_pixel(x, y);
- Color dc = p_dst->get_pixel(x_pos + x, y_pos + y);
- dc.r = (double)(sc.a * sc.r + dc.a * (1.0 - sc.a) * dc.r);
- dc.g = (double)(sc.a * sc.g + dc.a * (1.0 - sc.a) * dc.g);
- dc.b = (double)(sc.a * sc.b + dc.a * (1.0 - sc.a) * dc.b);
- dc.a = (double)(sc.a + dc.a * (1.0 - sc.a));
- p_dst->set_pixel(x_pos + x, y_pos + y, dc);
- }
- }
-}
-
-struct IconInfo {
- const char *preset_key;
- const char *idiom;
- const char *export_name;
- const char *actual_size_side;
- const char *scale;
- const char *unscaled_size;
- bool is_required = false;
-};
-
-static const IconInfo icon_infos[] = {
- { "required_icons/iphone_120x120", "iphone", "Icon-120.png", "120", "2x", "60x60", true },
- { "required_icons/iphone_120x120", "iphone", "Icon-120.png", "120", "3x", "40x40", true },
-
- { "required_icons/ipad_76x76", "ipad", "Icon-76.png", "76", "1x", "76x76", true },
- { "required_icons/app_store_1024x1024", "ios-marketing", "Icon-1024.png", "1024", "1x", "1024x1024", true },
-
- { "optional_icons/iphone_180x180", "iphone", "Icon-180.png", "180", "3x", "60x60", false },
-
- { "optional_icons/ipad_152x152", "ipad", "Icon-152.png", "152", "2x", "76x76", false },
-
- { "optional_icons/ipad_167x167", "ipad", "Icon-167.png", "167", "2x", "83.5x83.5", false },
-
- { "optional_icons/spotlight_40x40", "ipad", "Icon-40.png", "40", "1x", "40x40", false },
-
- { "optional_icons/spotlight_80x80", "iphone", "Icon-80.png", "80", "2x", "40x40", false },
- { "optional_icons/spotlight_80x80", "ipad", "Icon-80.png", "80", "2x", "40x40", false }
-};
-
-Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir) {
- String json_description = "{\"images\":[";
- String sizes;
-
- DirAccess *da = DirAccess::open(p_iconset_dir);
- ERR_FAIL_COND_V_MSG(!da, ERR_CANT_OPEN, "Cannot open directory '" + p_iconset_dir + "'.");
-
- for (uint64_t i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) {
- IconInfo info = icon_infos[i];
- int side_size = String(info.actual_size_side).to_int();
- String icon_path = p_preset->get(info.preset_key);
- if (icon_path.length() == 0) {
- if ((bool)p_preset->get("icons/generate_missing")) {
- // Resize main app icon
- icon_path = ProjectSettings::get_singleton()->get("application/config/icon");
- Ref<Image> img = memnew(Image);
- Error err = ImageLoader::load_image(icon_path, img);
- if (err != OK) {
- ERR_PRINT("Invalid icon (" + String(info.preset_key) + "): '" + icon_path + "'.");
- return ERR_UNCONFIGURED;
- }
- img->resize(side_size, side_size);
- err = img->save_png(p_iconset_dir + info.export_name);
- if (err) {
- String err_str = String("Failed to export icon(" + String(info.preset_key) + "): '" + icon_path + "'.");
- ERR_PRINT(err_str.utf8().get_data());
- return err;
- }
- } else {
- if (info.is_required) {
- String err_str = String("Required icon (") + info.preset_key + ") is not specified in the preset.";
- ERR_PRINT(err_str);
- return ERR_UNCONFIGURED;
- } else {
- String err_str = String("Icon (") + info.preset_key + ") is not specified in the preset.";
- WARN_PRINT(err_str);
- }
- continue;
- }
- } else {
- // Load custom icon
- Ref<Image> img = memnew(Image);
- Error err = ImageLoader::load_image(icon_path, img);
- if (err != OK) {
- ERR_PRINT("Invalid icon (" + String(info.preset_key) + "): '" + icon_path + "'.");
- return ERR_UNCONFIGURED;
- }
- if (img->get_width() != side_size || img->get_height() != side_size) {
- ERR_PRINT("Invalid icon size (" + String(info.preset_key) + "): '" + icon_path + "'.");
- return ERR_UNCONFIGURED;
- }
-
- err = da->copy(icon_path, p_iconset_dir + info.export_name);
- if (err) {
- memdelete(da);
- String err_str = String("Failed to export icon(" + String(info.preset_key) + "): '" + icon_path + "'.");
- ERR_PRINT(err_str.utf8().get_data());
- return err;
- }
- }
- sizes += String(info.actual_size_side) + "\n";
- if (i > 0) {
- json_description += ",";
- }
- json_description += String("{");
- json_description += String("\"idiom\":") + "\"" + info.idiom + "\",";
- json_description += String("\"size\":") + "\"" + info.unscaled_size + "\",";
- json_description += String("\"scale\":") + "\"" + info.scale + "\",";
- json_description += String("\"filename\":") + "\"" + info.export_name + "\"";
- json_description += String("}");
- }
- json_description += "]}";
- memdelete(da);
-
- FileAccess *json_file = FileAccess::open(p_iconset_dir + "Contents.json", FileAccess::WRITE);
- ERR_FAIL_COND_V(!json_file, ERR_CANT_CREATE);
- CharString json_utf8 = json_description.utf8();
- json_file->store_buffer((const uint8_t *)json_utf8.get_data(), json_utf8.length());
- memdelete(json_file);
-
- FileAccess *sizes_file = FileAccess::open(p_iconset_dir + "sizes", FileAccess::WRITE);
- ERR_FAIL_COND_V(!sizes_file, ERR_CANT_CREATE);
- CharString sizes_utf8 = sizes.utf8();
- sizes_file->store_buffer((const uint8_t *)sizes_utf8.get_data(), sizes_utf8.length());
- memdelete(sizes_file);
-
- return OK;
-}
-
-Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir) {
- const String custom_launch_image_2x = p_preset->get("storyboard/custom_image@2x");
- const String custom_launch_image_3x = p_preset->get("storyboard/custom_image@3x");
-
- if (custom_launch_image_2x.length() > 0 && custom_launch_image_3x.length() > 0) {
- Ref<Image> image;
- String image_path = p_dest_dir.plus_file("splash@2x.png");
- image.instantiate();
- Error err = image->load(custom_launch_image_2x);
-
- if (err) {
- image.unref();
- return err;
- }
-
- if (image->save_png(image_path) != OK) {
- return ERR_FILE_CANT_WRITE;
- }
-
- image.unref();
- image_path = p_dest_dir.plus_file("splash@3x.png");
- image.instantiate();
- err = image->load(custom_launch_image_3x);
-
- if (err) {
- image.unref();
- return err;
- }
-
- if (image->save_png(image_path) != OK) {
- return ERR_FILE_CANT_WRITE;
- }
- } else {
- Ref<Image> splash;
-
- const String splash_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
-
- if (!splash_path.is_empty()) {
- splash.instantiate();
- const Error err = splash->load(splash_path);
- if (err) {
- splash.unref();
- }
- }
-
- if (splash.is_null()) {
- splash = Ref<Image>(memnew(Image(boot_splash_png)));
- }
-
- // Using same image for both @2x and @3x
- // because Godot's own boot logo uses single image for all resolutions.
- // Also not using @1x image, because devices using this image variant
- // are not supported by iOS 9, which is minimal target.
- const String splash_png_path_2x = p_dest_dir.plus_file("splash@2x.png");
- const String splash_png_path_3x = p_dest_dir.plus_file("splash@3x.png");
-
- if (splash->save_png(splash_png_path_2x) != OK) {
- return ERR_FILE_CANT_WRITE;
- }
-
- if (splash->save_png(splash_png_path_3x) != OK) {
- return ERR_FILE_CANT_WRITE;
- }
- }
-
- return OK;
-}
-
-Error EditorExportPlatformIOS::_export_loading_screen_images(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir) {
- DirAccess *da = DirAccess::open(p_dest_dir);
- ERR_FAIL_COND_V_MSG(!da, ERR_CANT_OPEN, "Cannot open directory '" + p_dest_dir + "'.");
-
- for (uint64_t i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) {
- LoadingScreenInfo info = loading_screen_infos[i];
- String loading_screen_file = p_preset->get(info.preset_key);
- if (loading_screen_file.size() > 0) {
- // Load custom loading screens
- Ref<Image> img = memnew(Image);
- Error err = ImageLoader::load_image(loading_screen_file, img);
- if (err != OK) {
- ERR_PRINT("Invalid loading screen (" + String(info.preset_key) + "): '" + loading_screen_file + "'.");
- return ERR_UNCONFIGURED;
- }
- if (img->get_width() != info.width || img->get_height() != info.height) {
- ERR_PRINT("Invalid loading screen size (" + String(info.preset_key) + "): '" + loading_screen_file + "'.");
- return ERR_UNCONFIGURED;
- }
- err = da->copy(loading_screen_file, p_dest_dir + info.export_name);
- if (err) {
- memdelete(da);
- String err_str = String("Failed to export loading screen (") + info.preset_key + ") from path '" + loading_screen_file + "'.";
- ERR_PRINT(err_str.utf8().get_data());
- return err;
- }
- } else if ((bool)p_preset->get("launch_screens/generate_missing")) {
- // Generate loading screen from the splash screen
- Color boot_bg_color = ProjectSettings::get_singleton()->get("application/boot_splash/bg_color");
- String boot_logo_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
- bool boot_logo_scale = ProjectSettings::get_singleton()->get("application/boot_splash/fullsize");
-
- Ref<Image> img = memnew(Image);
- img->create(info.width, info.height, false, Image::FORMAT_RGBA8);
- img->fill(boot_bg_color);
-
- Ref<Image> img_bs;
-
- if (boot_logo_path.length() > 0) {
- img_bs = Ref<Image>(memnew(Image));
- ImageLoader::load_image(boot_logo_path, img_bs);
- }
- if (!img_bs.is_valid()) {
- img_bs = Ref<Image>(memnew(Image(boot_splash_png)));
- }
- if (img_bs.is_valid()) {
- float aspect_ratio = (float)img_bs->get_width() / (float)img_bs->get_height();
- if (info.rotate) {
- if (boot_logo_scale) {
- if (info.width * aspect_ratio <= info.height) {
- img_bs->resize(info.width * aspect_ratio, info.width);
- } else {
- img_bs->resize(info.height, info.height / aspect_ratio);
- }
- }
- } else {
- if (boot_logo_scale) {
- if (info.height * aspect_ratio <= info.width) {
- img_bs->resize(info.height * aspect_ratio, info.height);
- } else {
- img_bs->resize(info.width, info.width / aspect_ratio);
- }
- }
- }
- _blend_and_rotate(img, img_bs, info.rotate);
- }
- Error err = img->save_png(p_dest_dir + info.export_name);
- if (err) {
- String err_str = String("Failed to export loading screen (") + info.preset_key + ") from splash screen.";
- WARN_PRINT(err_str.utf8().get_data());
- }
- } else {
- String err_str = String("No loading screen (") + info.preset_key + ") specified.";
- WARN_PRINT(err_str.utf8().get_data());
- }
- }
- memdelete(da);
-
- return OK;
-}
-
-Error EditorExportPlatformIOS::_walk_dir_recursive(DirAccess *p_da, FileHandler p_handler, void *p_userdata) {
- Vector<String> dirs;
- String path;
- String current_dir = p_da->get_current_dir();
- p_da->list_dir_begin();
- while ((path = p_da->get_next()).length() != 0) {
- if (p_da->current_is_dir()) {
- if (path != "." && path != "..") {
- dirs.push_back(path);
- }
- } else {
- Error err = p_handler(current_dir.plus_file(path), p_userdata);
- if (err) {
- p_da->list_dir_end();
- return err;
- }
- }
- }
- p_da->list_dir_end();
-
- for (int i = 0; i < dirs.size(); ++i) {
- String dir = dirs[i];
- p_da->change_dir(dir);
- Error err = _walk_dir_recursive(p_da, p_handler, p_userdata);
- p_da->change_dir("..");
- if (err) {
- return err;
- }
- }
-
- return OK;
-}
-
-struct CodesignData {
- const Ref<EditorExportPreset> &preset;
- bool debug = false;
-
- CodesignData(const Ref<EditorExportPreset> &p_preset, bool p_debug) :
- preset(p_preset),
- debug(p_debug) {
- }
-};
-
-Error EditorExportPlatformIOS::_codesign(String p_file, void *p_userdata) {
- if (p_file.ends_with(".dylib")) {
- CodesignData *data = (CodesignData *)p_userdata;
- print_line(String("Signing ") + p_file);
- List<String> codesign_args;
- codesign_args.push_back("-f");
- codesign_args.push_back("-s");
- codesign_args.push_back(data->preset->get(data->debug ? "application/code_sign_identity_debug" : "application/code_sign_identity_release"));
- codesign_args.push_back(p_file);
- return OS::get_singleton()->execute("codesign", codesign_args);
- }
- return OK;
-}
-
-struct PbxId {
-private:
- static char _hex_char(uint8_t four_bits) {
- if (four_bits < 10) {
- return ('0' + four_bits);
- }
- return 'A' + (four_bits - 10);
- }
-
- static String _hex_pad(uint32_t num) {
- Vector<char> ret;
- ret.resize(sizeof(num) * 2);
- for (uint64_t i = 0; i < sizeof(num) * 2; ++i) {
- uint8_t four_bits = (num >> (sizeof(num) * 8 - (i + 1) * 4)) & 0xF;
- ret.write[i] = _hex_char(four_bits);
- }
- return String::utf8(ret.ptr(), ret.size());
- }
-
-public:
- uint32_t high_bits;
- uint32_t mid_bits;
- uint32_t low_bits;
-
- String str() const {
- return _hex_pad(high_bits) + _hex_pad(mid_bits) + _hex_pad(low_bits);
- }
-
- PbxId &operator++() {
- low_bits++;
- if (!low_bits) {
- mid_bits++;
- if (!mid_bits) {
- high_bits++;
- }
- }
-
- return *this;
- }
-};
-
-struct ExportLibsData {
- Vector<String> lib_paths;
- String dest_dir;
-};
-
-void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets) {
- // that is just a random number, we just need Godot IDs not to clash with
- // existing IDs in the project.
- PbxId current_id = { 0x58938401, 0, 0 };
- String pbx_files;
- String pbx_frameworks_build;
- String pbx_frameworks_refs;
- String pbx_resources_build;
- String pbx_resources_refs;
- String pbx_embeded_frameworks;
-
- const String file_info_format = String("$build_id = {isa = PBXBuildFile; fileRef = $ref_id; };\n") +
- "$ref_id = {isa = PBXFileReference; lastKnownFileType = $file_type; name = \"$name\"; path = \"$file_path\"; sourceTree = \"<group>\"; };\n";
-
- for (int i = 0; i < p_additional_assets.size(); ++i) {
- String additional_asset_info_format = file_info_format;
-
- String build_id = (++current_id).str();
- String ref_id = (++current_id).str();
- String framework_id = "";
-
- const IOSExportAsset &asset = p_additional_assets[i];
-
- String type;
- if (asset.exported_path.ends_with(".framework")) {
- if (asset.should_embed) {
- additional_asset_info_format += "$framework_id = {isa = PBXBuildFile; fileRef = $ref_id; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n";
- framework_id = (++current_id).str();
- pbx_embeded_frameworks += framework_id + ",\n";
- }
-
- type = "wrapper.framework";
- } else if (asset.exported_path.ends_with(".xcframework")) {
- if (asset.should_embed) {
- additional_asset_info_format += "$framework_id = {isa = PBXBuildFile; fileRef = $ref_id; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n";
- framework_id = (++current_id).str();
- pbx_embeded_frameworks += framework_id + ",\n";
- }
-
- type = "wrapper.xcframework";
- } else if (asset.exported_path.ends_with(".dylib")) {
- type = "compiled.mach-o.dylib";
- } else if (asset.exported_path.ends_with(".a")) {
- type = "archive.ar";
- } else {
- type = "file";
- }
-
- String &pbx_build = asset.is_framework ? pbx_frameworks_build : pbx_resources_build;
- String &pbx_refs = asset.is_framework ? pbx_frameworks_refs : pbx_resources_refs;
-
- if (pbx_build.length() > 0) {
- pbx_build += ",\n";
- pbx_refs += ",\n";
- }
- pbx_build += build_id;
- pbx_refs += ref_id;
-
- Dictionary format_dict;
- format_dict["build_id"] = build_id;
- format_dict["ref_id"] = ref_id;
- format_dict["name"] = asset.exported_path.get_file();
- format_dict["file_path"] = asset.exported_path;
- format_dict["file_type"] = type;
- if (framework_id.length() > 0) {
- format_dict["framework_id"] = framework_id;
- }
- pbx_files += additional_asset_info_format.format(format_dict, "$_");
- }
-
- // Note, frameworks like gamekit are always included in our project.pbxprof file
- // even if turned off in capabilities.
-
- String str = String::utf8((const char *)p_project_data.ptr(), p_project_data.size());
- str = str.replace("$additional_pbx_files", pbx_files);
- str = str.replace("$additional_pbx_frameworks_build", pbx_frameworks_build);
- str = str.replace("$additional_pbx_frameworks_refs", pbx_frameworks_refs);
- str = str.replace("$additional_pbx_resources_build", pbx_resources_build);
- str = str.replace("$additional_pbx_resources_refs", pbx_resources_refs);
- str = str.replace("$pbx_embeded_frameworks", pbx_embeded_frameworks);
-
- CharString cs = str.utf8();
- p_project_data.resize(cs.size() - 1);
- for (int i = 0; i < cs.size() - 1; i++) {
- p_project_data.write[i] = cs[i];
- }
-}
-
-Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String &p_asset, const String *p_custom_file_name, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets) {
- DirAccess *filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND_V_MSG(!filesystem_da, ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_out_dir + "'.");
-
- String binary_name = p_out_dir.get_file().get_basename();
-
- DirAccess *da = DirAccess::create_for_path(p_asset);
- if (!da) {
- memdelete(filesystem_da);
- ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't create directory: " + p_asset + ".");
- }
- bool file_exists = da->file_exists(p_asset);
- bool dir_exists = da->dir_exists(p_asset);
- if (!file_exists && !dir_exists) {
- memdelete(da);
- memdelete(filesystem_da);
- return ERR_FILE_NOT_FOUND;
- }
-
- String base_dir = p_asset.get_base_dir().replace("res://", "");
- String destination_dir;
- String destination;
- String asset_path;
-
- bool create_framework = false;
-
- if (p_is_framework && p_asset.ends_with(".dylib")) {
- // For iOS we need to turn .dylib into .framework
- // to be able to send application to AppStore
- asset_path = String("dylibs").plus_file(base_dir);
-
- String file_name;
-
- if (!p_custom_file_name) {
- file_name = p_asset.get_basename().get_file();
- } else {
- file_name = *p_custom_file_name;
- }
-
- String framework_name = file_name + ".framework";
-
- asset_path = asset_path.plus_file(framework_name);
- destination_dir = p_out_dir.plus_file(asset_path);
- destination = destination_dir.plus_file(file_name);
- create_framework = true;
- } else if (p_is_framework && (p_asset.ends_with(".framework") || p_asset.ends_with(".xcframework"))) {
- asset_path = String("dylibs").plus_file(base_dir);
-
- String file_name;
-
- if (!p_custom_file_name) {
- file_name = p_asset.get_file();
- } else {
- file_name = *p_custom_file_name;
- }
-
- asset_path = asset_path.plus_file(file_name);
- destination_dir = p_out_dir.plus_file(asset_path);
- destination = destination_dir;
- } else {
- asset_path = base_dir;
-
- String file_name;
-
- if (!p_custom_file_name) {
- file_name = p_asset.get_file();
- } else {
- file_name = *p_custom_file_name;
- }
-
- destination_dir = p_out_dir.plus_file(asset_path);
- asset_path = asset_path.plus_file(file_name);
- destination = p_out_dir.plus_file(asset_path);
- }
-
- if (!filesystem_da->dir_exists(destination_dir)) {
- Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir);
- if (make_dir_err) {
- memdelete(da);
- memdelete(filesystem_da);
- return make_dir_err;
- }
- }
-
- Error err = dir_exists ? da->copy_dir(p_asset, destination) : da->copy(p_asset, destination);
- memdelete(da);
- if (err) {
- memdelete(filesystem_da);
- return err;
- }
- IOSExportAsset exported_asset = { binary_name.plus_file(asset_path), p_is_framework, p_should_embed };
- r_exported_assets.push_back(exported_asset);
-
- if (create_framework) {
- String file_name;
-
- if (!p_custom_file_name) {
- file_name = p_asset.get_basename().get_file();
- } else {
- file_name = *p_custom_file_name;
- }
-
- String framework_name = file_name + ".framework";
-
- // Performing `install_name_tool -id @rpath/{name}.framework/{name} ./{name}` on dylib
- {
- List<String> install_name_args;
- install_name_args.push_back("-id");
- install_name_args.push_back(String("@rpath").plus_file(framework_name).plus_file(file_name));
- install_name_args.push_back(destination);
-
- OS::get_singleton()->execute("install_name_tool", install_name_args);
- }
-
- // Creating Info.plist
- {
- String info_plist_format = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
- "<plist version=\"1.0\">\n"
- "<dict>\n"
- "<key>CFBundleShortVersionString</key>\n"
- "<string>1.0</string>\n"
- "<key>CFBundleIdentifier</key>\n"
- "<string>com.gdnative.framework.$name</string>\n"
- "<key>CFBundleName</key>\n"
- "<string>$name</string>\n"
- "<key>CFBundleExecutable</key>\n"
- "<string>$name</string>\n"
- "<key>DTPlatformName</key>\n"
- "<string>iphoneos</string>\n"
- "<key>CFBundleInfoDictionaryVersion</key>\n"
- "<string>6.0</string>\n"
- "<key>CFBundleVersion</key>\n"
- "<string>1</string>\n"
- "<key>CFBundlePackageType</key>\n"
- "<string>FMWK</string>\n"
- "<key>MinimumOSVersion</key>\n"
- "<string>10.0</string>\n"
- "</dict>\n"
- "</plist>";
-
- String info_plist = info_plist_format.replace("$name", file_name);
-
- FileAccess *f = FileAccess::open(destination_dir.plus_file("Info.plist"), FileAccess::WRITE);
- if (f) {
- f->store_string(info_plist);
- f->close();
- memdelete(f);
- }
- }
- }
-
- memdelete(filesystem_da);
-
- return OK;
-}
-
-Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets) {
- for (int f_idx = 0; f_idx < p_assets.size(); ++f_idx) {
- String asset = p_assets[f_idx];
- if (!asset.begins_with("res://")) {
- // either SDK-builtin or already a part of the export template
- IOSExportAsset exported_asset = { asset, p_is_framework, p_should_embed };
- r_exported_assets.push_back(exported_asset);
- } else {
- Error err = _copy_asset(p_out_dir, asset, nullptr, p_is_framework, p_should_embed, r_exported_assets);
- ERR_FAIL_COND_V(err, err);
- }
- }
-
- return OK;
-}
-
-Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets) {
- Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
- for (int i = 0; i < export_plugins.size(); i++) {
- Vector<String> linked_frameworks = export_plugins[i]->get_ios_frameworks();
- Error err = _export_additional_assets(p_out_dir, linked_frameworks, true, false, r_exported_assets);
- ERR_FAIL_COND_V(err, err);
-
- Vector<String> embedded_frameworks = export_plugins[i]->get_ios_embedded_frameworks();
- err = _export_additional_assets(p_out_dir, embedded_frameworks, true, true, r_exported_assets);
- ERR_FAIL_COND_V(err, err);
-
- Vector<String> project_static_libs = export_plugins[i]->get_ios_project_static_libs();
- for (int j = 0; j < project_static_libs.size(); j++) {
- project_static_libs.write[j] = project_static_libs[j].get_file(); // Only the file name as it's copied to the project
- }
- err = _export_additional_assets(p_out_dir, project_static_libs, true, true, r_exported_assets);
- ERR_FAIL_COND_V(err, err);
-
- Vector<String> ios_bundle_files = export_plugins[i]->get_ios_bundle_files();
- err = _export_additional_assets(p_out_dir, ios_bundle_files, false, false, r_exported_assets);
- ERR_FAIL_COND_V(err, err);
- }
-
- Vector<String> library_paths;
- for (int i = 0; i < p_libraries.size(); ++i) {
- library_paths.push_back(p_libraries[i].path);
- }
- Error err = _export_additional_assets(p_out_dir, library_paths, true, true, r_exported_assets);
- ERR_FAIL_COND_V(err, err);
-
- return OK;
-}
-
-Vector<String> EditorExportPlatformIOS::_get_preset_architectures(const Ref<EditorExportPreset> &p_preset) {
- Vector<ExportArchitecture> all_archs = _get_supported_architectures();
- Vector<String> enabled_archs;
- for (int i = 0; i < all_archs.size(); ++i) {
- bool is_enabled = p_preset->get("architectures/" + all_archs[i].name);
- if (is_enabled) {
- enabled_archs.push_back(all_archs[i].name);
- }
- }
- return enabled_archs;
-}
-
-Error EditorExportPlatformIOS::_export_ios_plugins(const Ref<EditorExportPreset> &p_preset, IOSConfigData &p_config_data, const String &dest_dir, Vector<IOSExportAsset> &r_exported_assets, bool p_debug) {
- String plugin_definition_cpp_code;
- String plugin_initialization_cpp_code;
- String plugin_deinitialization_cpp_code;
-
- Vector<String> plugin_linked_dependencies;
- Vector<String> plugin_embedded_dependencies;
- Vector<String> plugin_files;
-
- Vector<PluginConfigIOS> enabled_plugins = get_enabled_plugins(p_preset);
-
- Vector<String> added_linked_dependenciy_names;
- Vector<String> added_embedded_dependenciy_names;
- HashMap<String, String> plist_values;
-
- Set<String> plugin_linker_flags;
-
- Error err;
-
- for (int i = 0; i < enabled_plugins.size(); i++) {
- PluginConfigIOS plugin = enabled_plugins[i];
-
- // Export plugin binary.
- String plugin_main_binary = get_plugin_main_binary(plugin, p_debug);
- String plugin_binary_result_file = plugin.binary.get_file();
- // We shouldn't embed .xcframework that contains static libraries.
- // Static libraries are not embedded anyway.
- err = _copy_asset(dest_dir, plugin_main_binary, &plugin_binary_result_file, true, false, r_exported_assets);
-
- ERR_FAIL_COND_V(err, err);
-
- // Adding dependencies.
- // Use separate container for names to check for duplicates.
- for (int j = 0; j < plugin.linked_dependencies.size(); j++) {
- String dependency = plugin.linked_dependencies[j];
- String name = dependency.get_file();
-
- if (added_linked_dependenciy_names.has(name)) {
- continue;
- }
-
- added_linked_dependenciy_names.push_back(name);
- plugin_linked_dependencies.push_back(dependency);
- }
-
- for (int j = 0; j < plugin.system_dependencies.size(); j++) {
- String dependency = plugin.system_dependencies[j];
- String name = dependency.get_file();
-
- if (added_linked_dependenciy_names.has(name)) {
- continue;
- }
-
- added_linked_dependenciy_names.push_back(name);
- plugin_linked_dependencies.push_back(dependency);
- }
-
- for (int j = 0; j < plugin.embedded_dependencies.size(); j++) {
- String dependency = plugin.embedded_dependencies[j];
- String name = dependency.get_file();
-
- if (added_embedded_dependenciy_names.has(name)) {
- continue;
- }
-
- added_embedded_dependenciy_names.push_back(name);
- plugin_embedded_dependencies.push_back(dependency);
- }
-
- plugin_files.append_array(plugin.files_to_copy);
-
- // Capabilities
- // Also checking for duplicates.
- for (int j = 0; j < plugin.capabilities.size(); j++) {
- String capability = plugin.capabilities[j];
-
- if (p_config_data.capabilities.has(capability)) {
- continue;
- }
-
- p_config_data.capabilities.push_back(capability);
- }
-
- // Linker flags
- // Checking duplicates
- for (int j = 0; j < plugin.linker_flags.size(); j++) {
- String linker_flag = plugin.linker_flags[j];
- plugin_linker_flags.insert(linker_flag);
- }
-
- // Plist
- // Using hash map container to remove duplicates
- const String *K = nullptr;
-
- while ((K = plugin.plist.next(K))) {
- String key = *K;
- PluginConfigIOS::PlistItem item = plugin.plist[key];
-
- String value;
-
- switch (item.type) {
- case PluginConfigIOS::PlistItemType::STRING_INPUT: {
- String preset_name = "plugins_plist/" + key;
- String input_value = p_preset->get(preset_name);
- value = "<string>" + input_value + "</string>";
- } break;
- default:
- value = item.value;
- break;
- }
-
- if (key.is_empty() || value.is_empty()) {
- continue;
- }
-
- String plist_key = "<key>" + key + "</key>";
-
- plist_values[plist_key] = value;
- }
-
- // CPP Code
- String definition_comment = "// Plugin: " + plugin.name + "\n";
- String initialization_method = plugin.initialization_method + "();\n";
- String deinitialization_method = plugin.deinitialization_method + "();\n";
-
- plugin_definition_cpp_code += definition_comment +
- "extern void " + initialization_method +
- "extern void " + deinitialization_method + "\n";
-
- plugin_initialization_cpp_code += "\t" + initialization_method;
- plugin_deinitialization_cpp_code += "\t" + deinitialization_method;
- }
-
- // Updating `Info.plist`
- {
- const String *K = nullptr;
- while ((K = plist_values.next(K))) {
- String key = *K;
- String value = plist_values[key];
-
- if (key.is_empty() || value.is_empty()) {
- continue;
- }
-
- p_config_data.plist_content += key + value + "\n";
- }
- }
-
- // Export files
- {
- // Export linked plugin dependency
- err = _export_additional_assets(dest_dir, plugin_linked_dependencies, true, false, r_exported_assets);
- ERR_FAIL_COND_V(err, err);
-
- // Export embedded plugin dependency
- err = _export_additional_assets(dest_dir, plugin_embedded_dependencies, true, true, r_exported_assets);
- ERR_FAIL_COND_V(err, err);
-
- // Export plugin files
- err = _export_additional_assets(dest_dir, plugin_files, false, false, r_exported_assets);
- ERR_FAIL_COND_V(err, err);
- }
-
- // Update CPP
- {
- Dictionary plugin_format;
- plugin_format["definition"] = plugin_definition_cpp_code;
- plugin_format["initialization"] = plugin_initialization_cpp_code;
- plugin_format["deinitialization"] = plugin_deinitialization_cpp_code;
-
- String plugin_cpp_code = "\n// Godot Plugins\n"
- "void godot_ios_plugins_initialize();\n"
- "void godot_ios_plugins_deinitialize();\n"
- "// Exported Plugins\n\n"
- "$definition"
- "// Use Plugins\n"
- "void godot_ios_plugins_initialize() {\n"
- "$initialization"
- "}\n\n"
- "void godot_ios_plugins_deinitialize() {\n"
- "$deinitialization"
- "}\n";
-
- p_config_data.cpp_code += plugin_cpp_code.format(plugin_format, "$_");
- }
-
- // Update Linker Flag Values
- {
- String result_linker_flags = " ";
- for (Set<String>::Element *E = plugin_linker_flags.front(); E; E = E->next()) {
- const String &flag = E->get();
-
- if (flag.length() == 0) {
- continue;
- }
-
- if (result_linker_flags.length() > 0) {
- result_linker_flags += ' ';
- }
-
- result_linker_flags += flag;
- }
- result_linker_flags = result_linker_flags.replace("\"", "\\\"");
- p_config_data.linker_flags += result_linker_flags;
- }
-
- return OK;
-}
-
-Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
- ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
-
- String src_pkg_name;
- String dest_dir = p_path.get_base_dir() + "/";
- String binary_name = p_path.get_file().get_basename();
-
- EditorProgress ep("export", "Exporting for iOS", 5, true);
-
- String team_id = p_preset->get("application/app_store_team_id");
- ERR_FAIL_COND_V_MSG(team_id.length() == 0, ERR_CANT_OPEN, "App Store Team ID not specified - cannot configure the project.");
-
- if (p_debug) {
- src_pkg_name = p_preset->get("custom_template/debug");
- } else {
- src_pkg_name = p_preset->get("custom_template/release");
- }
-
- if (src_pkg_name == "") {
- String err;
- src_pkg_name = find_export_template("iphone.zip", &err);
- if (src_pkg_name == "") {
- EditorNode::add_io_error(err);
- return ERR_FILE_NOT_FOUND;
- }
- }
-
- if (!DirAccess::exists(dest_dir)) {
- return ERR_FILE_BAD_PATH;
- }
-
- DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- if (da) {
- String current_dir = da->get_current_dir();
-
- // remove leftovers from last export so they don't interfere
- // in case some files are no longer needed
- if (da->change_dir(dest_dir + binary_name + ".xcodeproj") == OK) {
- da->erase_contents_recursive();
- }
- if (da->change_dir(dest_dir + binary_name) == OK) {
- da->erase_contents_recursive();
- }
-
- da->change_dir(current_dir);
-
- if (!da->dir_exists(dest_dir + binary_name)) {
- Error err = da->make_dir(dest_dir + binary_name);
- if (err) {
- memdelete(da);
- return err;
- }
- }
- memdelete(da);
- }
-
- if (ep.step("Making .pck", 0)) {
- return ERR_SKIP;
- }
- String pack_path = dest_dir + binary_name + ".pck";
- Vector<SharedObject> libraries;
- Error err = save_pack(p_preset, pack_path, &libraries);
- if (err) {
- return err;
- }
-
- if (ep.step("Extracting and configuring Xcode project", 1)) {
- return ERR_SKIP;
- }
-
- String library_to_use = "libgodot.iphone." + String(p_debug ? "debug" : "release") + ".xcframework";
-
- print_line("Static framework: " + library_to_use);
- String pkg_name;
- if (p_preset->get("application/name") != "") {
- pkg_name = p_preset->get("application/name"); // app_name
- } else if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") {
- pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
- } else {
- pkg_name = "Unnamed";
- }
-
- bool found_library = false;
- int total_size = 0;
-
- const String project_file = "godot_ios.xcodeproj/project.pbxproj";
- Set<String> files_to_parse;
- files_to_parse.insert("godot_ios/godot_ios-Info.plist");
- files_to_parse.insert(project_file);
- files_to_parse.insert("godot_ios/export_options.plist");
- files_to_parse.insert("godot_ios/dummy.cpp");
- files_to_parse.insert("godot_ios.xcodeproj/project.xcworkspace/contents.xcworkspacedata");
- files_to_parse.insert("godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme");
- files_to_parse.insert("godot_ios/godot_ios.entitlements");
- files_to_parse.insert("godot_ios/Launch Screen.storyboard");
-
- IOSConfigData config_data = {
- pkg_name,
- binary_name,
- _get_additional_plist_content(),
- String(" ").join(_get_preset_architectures(p_preset)),
- _get_linker_flags(),
- _get_cpp_code(),
- "",
- "",
- "",
- "",
- Vector<String>()
- };
-
- Vector<IOSExportAsset> assets;
-
- DirAccess *tmp_app_path = DirAccess::create_for_path(dest_dir);
- ERR_FAIL_COND_V(!tmp_app_path, ERR_CANT_CREATE);
-
- print_line("Unzipping...");
- FileAccess *src_f = nullptr;
- zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
- unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io);
- if (!src_pkg_zip) {
- EditorNode::add_io_error("Could not open export template (not a zip file?):\n" + src_pkg_name);
- return ERR_CANT_OPEN;
- }
-
- err = _export_ios_plugins(p_preset, config_data, dest_dir + binary_name, assets, p_debug);
- ERR_FAIL_COND_V(err, err);
-
- //export rest of the files
- int ret = unzGoToFirstFile(src_pkg_zip);
- Vector<uint8_t> project_file_data;
- while (ret == UNZ_OK) {
-#if defined(OSX_ENABLED) || defined(X11_ENABLED)
- bool is_execute = false;
-#endif
-
- //get filename
- unz_file_info info;
- char fname[16384];
- ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, nullptr, 0, nullptr, 0);
-
- String file = fname;
-
- print_line("READ: " + file);
- Vector<uint8_t> data;
- data.resize(info.uncompressed_size);
-
- //read
- unzOpenCurrentFile(src_pkg_zip);
- unzReadCurrentFile(src_pkg_zip, data.ptrw(), data.size());
- unzCloseCurrentFile(src_pkg_zip);
-
- //write
-
- file = file.replace_first("iphone/", "");
-
- if (files_to_parse.has(file)) {
- _fix_config_file(p_preset, data, config_data, p_debug);
- } else if (file.begins_with("libgodot.iphone")) {
- if (!file.begins_with(library_to_use) || file.ends_with(String("/empty"))) {
- ret = unzGoToNextFile(src_pkg_zip);
- continue; //ignore!
- }
- found_library = true;
-#if defined(OSX_ENABLED) || defined(X11_ENABLED)
- is_execute = true;
-#endif
- file = file.replace(library_to_use, binary_name + ".xcframework");
- }
-
- if (file == project_file) {
- project_file_data = data;
- }
-
- ///@TODO need to parse logo files
-
- if (data.size() > 0) {
- file = file.replace("godot_ios", binary_name);
-
- print_line("ADDING: " + file + " size: " + itos(data.size()));
- total_size += data.size();
-
- /* write it into our folder structure */
- file = dest_dir + file;
-
- /* make sure this folder exists */
- String dir_name = file.get_base_dir();
- if (!tmp_app_path->dir_exists(dir_name)) {
- print_line("Creating " + dir_name);
- Error dir_err = tmp_app_path->make_dir_recursive(dir_name);
- if (dir_err) {
- ERR_PRINT("Can't create '" + dir_name + "'.");
- unzClose(src_pkg_zip);
- memdelete(tmp_app_path);
- return ERR_CANT_CREATE;
- }
- }
-
- /* write the file */
- FileAccess *f = FileAccess::open(file, FileAccess::WRITE);
- if (!f) {
- ERR_PRINT("Can't write '" + file + "'.");
- unzClose(src_pkg_zip);
- memdelete(tmp_app_path);
- return ERR_CANT_CREATE;
- };
- f->store_buffer(data.ptr(), data.size());
- f->close();
- memdelete(f);
-
-#if defined(OSX_ENABLED) || defined(X11_ENABLED)
- if (is_execute) {
- // we need execute rights on this file
- chmod(file.utf8().get_data(), 0755);
- }
-#endif
- }
-
- ret = unzGoToNextFile(src_pkg_zip);
- }
-
- /* we're done with our source zip */
- unzClose(src_pkg_zip);
-
- if (!found_library) {
- ERR_PRINT("Requested template library '" + library_to_use + "' not found. It might be missing from your template archive.");
- memdelete(tmp_app_path);
- return ERR_FILE_NOT_FOUND;
- }
-
- // Copy project static libs to the project
- Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
- for (int i = 0; i < export_plugins.size(); i++) {
- Vector<String> project_static_libs = export_plugins[i]->get_ios_project_static_libs();
- for (int j = 0; j < project_static_libs.size(); j++) {
- const String &static_lib_path = project_static_libs[j];
- String dest_lib_file_path = dest_dir + static_lib_path.get_file();
- Error lib_copy_err = tmp_app_path->copy(static_lib_path, dest_lib_file_path);
- if (lib_copy_err != OK) {
- ERR_PRINT("Can't copy '" + static_lib_path + "'.");
- memdelete(tmp_app_path);
- return lib_copy_err;
- }
- }
- }
-
- String iconset_dir = dest_dir + binary_name + "/Images.xcassets/AppIcon.appiconset/";
- err = OK;
- if (!tmp_app_path->dir_exists(iconset_dir)) {
- err = tmp_app_path->make_dir_recursive(iconset_dir);
- }
- memdelete(tmp_app_path);
- if (err) {
- return err;
- }
-
- err = _export_icons(p_preset, iconset_dir);
- if (err) {
- return err;
- }
-
- bool use_storyboard = p_preset->get("storyboard/use_launch_screen_storyboard");
-
- String launch_image_path = dest_dir + binary_name + "/Images.xcassets/LaunchImage.launchimage/";
- String splash_image_path = dest_dir + binary_name + "/Images.xcassets/SplashImage.imageset/";
-
- DirAccess *launch_screen_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
-
- if (!launch_screen_da) {
- return ERR_CANT_CREATE;
- }
-
- if (use_storyboard) {
- print_line("Using Launch Storyboard");
-
- if (launch_screen_da->change_dir(launch_image_path) == OK) {
- launch_screen_da->erase_contents_recursive();
- launch_screen_da->remove(launch_image_path);
- }
-
- err = _export_loading_screen_file(p_preset, splash_image_path);
- } else {
- print_line("Using Launch Images");
-
- const String launch_screen_path = dest_dir + binary_name + "/Launch Screen.storyboard";
-
- launch_screen_da->remove(launch_screen_path);
-
- if (launch_screen_da->change_dir(splash_image_path) == OK) {
- launch_screen_da->erase_contents_recursive();
- launch_screen_da->remove(splash_image_path);
- }
-
- err = _export_loading_screen_images(p_preset, launch_image_path);
- }
-
- memdelete(launch_screen_da);
-
- if (err) {
- return err;
- }
-
- print_line("Exporting additional assets");
- _export_additional_assets(dest_dir + binary_name, libraries, assets);
- _add_assets_to_project(p_preset, project_file_data, assets);
- String project_file_name = dest_dir + binary_name + ".xcodeproj/project.pbxproj";
- FileAccess *f = FileAccess::open(project_file_name, FileAccess::WRITE);
- if (!f) {
- ERR_PRINT("Can't write '" + project_file_name + "'.");
- return ERR_CANT_CREATE;
- };
- f->store_buffer(project_file_data.ptr(), project_file_data.size());
- f->close();
- memdelete(f);
-
-#ifdef OSX_ENABLED
- if (ep.step("Code-signing dylibs", 2)) {
- return ERR_SKIP;
- }
- DirAccess *dylibs_dir = DirAccess::open(dest_dir + binary_name + "/dylibs");
- ERR_FAIL_COND_V(!dylibs_dir, ERR_CANT_OPEN);
- CodesignData codesign_data(p_preset, p_debug);
- err = _walk_dir_recursive(dylibs_dir, _codesign, &codesign_data);
- memdelete(dylibs_dir);
- ERR_FAIL_COND_V(err, err);
-
- if (ep.step("Making .xcarchive", 3)) {
- return ERR_SKIP;
- }
- String archive_path = p_path.get_basename() + ".xcarchive";
- List<String> archive_args;
- archive_args.push_back("-project");
- archive_args.push_back(dest_dir + binary_name + ".xcodeproj");
- archive_args.push_back("-scheme");
- archive_args.push_back(binary_name);
- archive_args.push_back("-sdk");
- archive_args.push_back("iphoneos");
- archive_args.push_back("-configuration");
- archive_args.push_back(p_debug ? "Debug" : "Release");
- archive_args.push_back("-destination");
- archive_args.push_back("generic/platform=iOS");
- archive_args.push_back("archive");
- archive_args.push_back("-archivePath");
- archive_args.push_back(archive_path);
- err = OS::get_singleton()->execute("xcodebuild", archive_args);
- ERR_FAIL_COND_V(err, err);
-
- if (ep.step("Making .ipa", 4)) {
- return ERR_SKIP;
- }
- List<String> export_args;
- export_args.push_back("-exportArchive");
- export_args.push_back("-archivePath");
- export_args.push_back(archive_path);
- export_args.push_back("-exportOptionsPlist");
- export_args.push_back(dest_dir + binary_name + "/export_options.plist");
- export_args.push_back("-allowProvisioningUpdates");
- export_args.push_back("-exportPath");
- export_args.push_back(dest_dir);
- err = OS::get_singleton()->execute("xcodebuild", export_args);
- ERR_FAIL_COND_V(err, err);
-#else
- print_line(".ipa can only be built on macOS. Leaving Xcode project without building the package.");
-#endif
-
- return OK;
-}
-
-bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
- String err;
- bool valid = false;
-
- // Look for export templates (first official, and if defined custom templates).
-
- bool dvalid = exists_export_template("iphone.zip", &err);
- bool rvalid = dvalid; // Both in the same ZIP.
-
- if (p_preset->get("custom_template/debug") != "") {
- dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
- if (!dvalid) {
- err += TTR("Custom debug template not found.") + "\n";
- }
- }
- if (p_preset->get("custom_template/release") != "") {
- rvalid = FileAccess::exists(p_preset->get("custom_template/release"));
- if (!rvalid) {
- err += TTR("Custom release template not found.") + "\n";
- }
- }
-
- valid = dvalid || rvalid;
- r_missing_templates = !valid;
-
- // Validate the rest of the configuration.
-
- String team_id = p_preset->get("application/app_store_team_id");
- if (team_id.length() == 0) {
- err += TTR("App Store Team ID not specified - cannot configure the project.") + "\n";
- valid = false;
- }
-
- String identifier = p_preset->get("application/bundle_identifier");
- String pn_err;
- if (!is_package_name_valid(identifier, &pn_err)) {
- err += TTR("Invalid Identifier:") + " " + pn_err + "\n";
- valid = false;
- }
-
- for (uint64_t i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) {
- IconInfo info = icon_infos[i];
- String icon_path = p_preset->get(info.preset_key);
- if (icon_path.length() == 0) {
- if (info.is_required) {
- err += TTR("Required icon is not specified in the preset.") + "\n";
- valid = false;
- }
- break;
- }
- }
-
- String etc_error = test_etc2_or_pvrtc();
- if (etc_error != String()) {
- valid = false;
- err += etc_error;
- }
-
- if (!err.is_empty()) {
- r_error = err;
- }
-
- return valid;
-}
-
-EditorExportPlatformIOS::EditorExportPlatformIOS() {
- Ref<Image> img = memnew(Image(_iphone_logo));
- logo.instantiate();
- logo->create_from_image(img);
-
- plugins_changed.set();
-
- check_for_changes_thread.start(_check_for_changes_poll_thread, this);
-}
-
-EditorExportPlatformIOS::~EditorExportPlatformIOS() {
- quit_request.set();
- check_for_changes_thread.wait_to_finish();
-}
+#include "export_plugin.h"
void register_iphone_exporter() {
Ref<EditorExportPlatformIOS> platform;
diff --git a/platform/iphone/export/export_plugin.cpp b/platform/iphone/export/export_plugin.cpp
new file mode 100644
index 0000000000..69a8203e9f
--- /dev/null
+++ b/platform/iphone/export/export_plugin.cpp
@@ -0,0 +1,1792 @@
+/*************************************************************************/
+/* export_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "export_plugin.h"
+
+void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
+ String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
+ r_features->push_back("pvrtc");
+ if (driver == "Vulkan") {
+ // FIXME: Review if this is correct.
+ r_features->push_back("etc2");
+ }
+
+ Vector<String> architectures = _get_preset_architectures(p_preset);
+ for (int i = 0; i < architectures.size(); ++i) {
+ r_features->push_back(architectures[i]);
+ }
+}
+
+Vector<EditorExportPlatformIOS::ExportArchitecture> EditorExportPlatformIOS::_get_supported_architectures() {
+ Vector<ExportArchitecture> archs;
+ archs.push_back(ExportArchitecture("armv7", false)); // Disabled by default, not included in official templates.
+ archs.push_back(ExportArchitecture("arm64", true));
+ return archs;
+}
+
+struct LoadingScreenInfo {
+ const char *preset_key;
+ const char *export_name;
+ int width = 0;
+ int height = 0;
+ bool rotate = false;
+};
+
+static const LoadingScreenInfo loading_screen_infos[] = {
+ { "landscape_launch_screens/iphone_2436x1125", "Default-Landscape-X.png", 2436, 1125, false },
+ { "landscape_launch_screens/iphone_2208x1242", "Default-Landscape-736h@3x.png", 2208, 1242, false },
+ { "landscape_launch_screens/ipad_1024x768", "Default-Landscape.png", 1024, 768, false },
+ { "landscape_launch_screens/ipad_2048x1536", "Default-Landscape@2x.png", 2048, 1536, false },
+
+ { "portrait_launch_screens/iphone_640x960", "Default-480h@2x.png", 640, 960, true },
+ { "portrait_launch_screens/iphone_640x1136", "Default-568h@2x.png", 640, 1136, true },
+ { "portrait_launch_screens/iphone_750x1334", "Default-667h@2x.png", 750, 1334, true },
+ { "portrait_launch_screens/iphone_1125x2436", "Default-Portrait-X.png", 1125, 2436, true },
+ { "portrait_launch_screens/ipad_768x1024", "Default-Portrait.png", 768, 1024, true },
+ { "portrait_launch_screens/ipad_1536x2048", "Default-Portrait@2x.png", 1536, 2048, true },
+ { "portrait_launch_screens/iphone_1242x2208", "Default-Portrait-736h@3x.png", 1242, 2208, true }
+};
+
+void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
+
+ Vector<ExportArchitecture> architectures = _get_supported_architectures();
+ for (int i = 0; i < architectures.size(); ++i) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architectures/" + architectures[i].name), architectures[i].is_default));
+ }
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_store_team_id"), ""));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/provisioning_profile_uuid_debug"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/code_sign_identity_debug", PROPERTY_HINT_PLACEHOLDER_TEXT, "iPhone Developer"), "iPhone Developer"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/export_method_debug", PROPERTY_HINT_ENUM, "App Store,Development,Ad-Hoc,Enterprise"), 1));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/provisioning_profile_uuid_release"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/code_sign_identity_release", PROPERTY_HINT_PLACEHOLDER_TEXT, "iPhone Distribution"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/export_method_release", PROPERTY_HINT_ENUM, "App Store,Development,Ad-Hoc,Enterprise"), 0));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/targeted_device_family", PROPERTY_HINT_ENUM, "iPhone,iPad,iPhone & iPad"), 2));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/info"), "Made with Godot Engine"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
+
+ Vector<PluginConfigIOS> found_plugins = get_plugins();
+ for (int i = 0; i < found_plugins.size(); i++) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "plugins/" + found_plugins[i].name), false));
+ }
+
+ Set<String> plist_keys;
+
+ for (int i = 0; i < found_plugins.size(); i++) {
+ // Editable plugin plist values
+ PluginConfigIOS plugin = found_plugins[i];
+ const String *K = nullptr;
+
+ while ((K = plugin.plist.next(K))) {
+ String key = *K;
+ PluginConfigIOS::PlistItem item = plugin.plist[key];
+ switch (item.type) {
+ case PluginConfigIOS::PlistItemType::STRING_INPUT: {
+ String preset_name = "plugins_plist/" + key;
+ if (!plist_keys.has(preset_name)) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, preset_name), item.value));
+ plist_keys.insert(preset_name);
+ }
+ } break;
+ default:
+ continue;
+ }
+ }
+ }
+
+ plugins_changed.clear();
+ plugins = found_plugins;
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/access_wifi"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/push_notifications"), false));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "user_data/accessible_from_files_app"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "user_data/accessible_from_itunes_sharing"), false));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/camera_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the camera"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photolibrary_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need access to the photo library"), ""));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "icons/generate_missing"), false));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "required_icons/iphone_120x120", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPhone/iPod Touch with retina display
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "required_icons/ipad_76x76", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "required_icons/app_store_1024x1024", PROPERTY_HINT_FILE, "*.png"), "")); // App Store
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/iphone_180x180", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPhone with retina HD display
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/ipad_152x152", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad with retina display
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/ipad_167x167", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad Pro
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/spotlight_40x40", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/spotlight_80x80", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight on devices with retina display
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_launch_screen_storyboard"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "storyboard/image_scale_mode", PROPERTY_HINT_ENUM, "Same as Logo,Center,Scale to Fit,Scale to Fill,Scale"), 0));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@2x", PROPERTY_HINT_FILE, "*.png"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@3x", PROPERTY_HINT_FILE, "*.png"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_custom_bg_color"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "storyboard/custom_bg_color"), Color()));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "launch_screens/generate_missing"), false));
+
+ for (uint64_t i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, loading_screen_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png"), ""));
+ }
+}
+
+void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const IOSConfigData &p_config, bool p_debug) {
+ static const String export_method_string[] = {
+ "app-store",
+ "development",
+ "ad-hoc",
+ "enterprise"
+ };
+ static const String storyboard_image_scale_mode[] = {
+ "center",
+ "scaleAspectFit",
+ "scaleAspectFill",
+ "scaleToFill"
+ };
+ String str;
+ String strnew;
+ str.parse_utf8((const char *)pfile.ptr(), pfile.size());
+ Vector<String> lines = str.split("\n");
+ for (int i = 0; i < lines.size(); i++) {
+ if (lines[i].find("$binary") != -1) {
+ strnew += lines[i].replace("$binary", p_config.binary_name) + "\n";
+ } else if (lines[i].find("$modules_buildfile") != -1) {
+ strnew += lines[i].replace("$modules_buildfile", p_config.modules_buildfile) + "\n";
+ } else if (lines[i].find("$modules_fileref") != -1) {
+ strnew += lines[i].replace("$modules_fileref", p_config.modules_fileref) + "\n";
+ } else if (lines[i].find("$modules_buildphase") != -1) {
+ strnew += lines[i].replace("$modules_buildphase", p_config.modules_buildphase) + "\n";
+ } else if (lines[i].find("$modules_buildgrp") != -1) {
+ strnew += lines[i].replace("$modules_buildgrp", p_config.modules_buildgrp) + "\n";
+ } else if (lines[i].find("$name") != -1) {
+ strnew += lines[i].replace("$name", p_config.pkg_name) + "\n";
+ } else if (lines[i].find("$info") != -1) {
+ strnew += lines[i].replace("$info", p_preset->get("application/info")) + "\n";
+ } else if (lines[i].find("$bundle_identifier") != -1) {
+ strnew += lines[i].replace("$bundle_identifier", p_preset->get("application/bundle_identifier")) + "\n";
+ } else if (lines[i].find("$short_version") != -1) {
+ strnew += lines[i].replace("$short_version", p_preset->get("application/short_version")) + "\n";
+ } else if (lines[i].find("$version") != -1) {
+ strnew += lines[i].replace("$version", p_preset->get("application/version")) + "\n";
+ } else if (lines[i].find("$signature") != -1) {
+ strnew += lines[i].replace("$signature", p_preset->get("application/signature")) + "\n";
+ } else if (lines[i].find("$copyright") != -1) {
+ strnew += lines[i].replace("$copyright", p_preset->get("application/copyright")) + "\n";
+ } else if (lines[i].find("$team_id") != -1) {
+ strnew += lines[i].replace("$team_id", p_preset->get("application/app_store_team_id")) + "\n";
+ } else if (lines[i].find("$default_build_config") != -1) {
+ strnew += lines[i].replace("$default_build_config", p_debug ? "Debug" : "Release") + "\n";
+ } else if (lines[i].find("$export_method") != -1) {
+ int export_method = p_preset->get(p_debug ? "application/export_method_debug" : "application/export_method_release");
+ strnew += lines[i].replace("$export_method", export_method_string[export_method]) + "\n";
+ } else if (lines[i].find("$provisioning_profile_uuid_release") != -1) {
+ strnew += lines[i].replace("$provisioning_profile_uuid_release", p_preset->get("application/provisioning_profile_uuid_release")) + "\n";
+ } else if (lines[i].find("$provisioning_profile_uuid_debug") != -1) {
+ strnew += lines[i].replace("$provisioning_profile_uuid_debug", p_preset->get("application/provisioning_profile_uuid_debug")) + "\n";
+ } else if (lines[i].find("$provisioning_profile_uuid") != -1) {
+ String uuid = p_debug ? p_preset->get("application/provisioning_profile_uuid_debug") : p_preset->get("application/provisioning_profile_uuid_release");
+ strnew += lines[i].replace("$provisioning_profile_uuid", uuid) + "\n";
+ } else if (lines[i].find("$code_sign_identity_debug") != -1) {
+ strnew += lines[i].replace("$code_sign_identity_debug", p_preset->get("application/code_sign_identity_debug")) + "\n";
+ } else if (lines[i].find("$code_sign_identity_release") != -1) {
+ strnew += lines[i].replace("$code_sign_identity_release", p_preset->get("application/code_sign_identity_release")) + "\n";
+ } else if (lines[i].find("$additional_plist_content") != -1) {
+ strnew += lines[i].replace("$additional_plist_content", p_config.plist_content) + "\n";
+ } else if (lines[i].find("$godot_archs") != -1) {
+ strnew += lines[i].replace("$godot_archs", p_config.architectures) + "\n";
+ } else if (lines[i].find("$linker_flags") != -1) {
+ strnew += lines[i].replace("$linker_flags", p_config.linker_flags) + "\n";
+ } else if (lines[i].find("$targeted_device_family") != -1) {
+ String xcode_value;
+ switch ((int)p_preset->get("application/targeted_device_family")) {
+ case 0: // iPhone
+ xcode_value = "1";
+ break;
+ case 1: // iPad
+ xcode_value = "2";
+ break;
+ case 2: // iPhone & iPad
+ xcode_value = "1,2";
+ break;
+ }
+ strnew += lines[i].replace("$targeted_device_family", xcode_value) + "\n";
+ } else if (lines[i].find("$cpp_code") != -1) {
+ strnew += lines[i].replace("$cpp_code", p_config.cpp_code) + "\n";
+ } else if (lines[i].find("$docs_in_place") != -1) {
+ strnew += lines[i].replace("$docs_in_place", ((bool)p_preset->get("user_data/accessible_from_files_app")) ? "<true/>" : "<false/>") + "\n";
+ } else if (lines[i].find("$docs_sharing") != -1) {
+ strnew += lines[i].replace("$docs_sharing", ((bool)p_preset->get("user_data/accessible_from_itunes_sharing")) ? "<true/>" : "<false/>") + "\n";
+ } else if (lines[i].find("$entitlements_push_notifications") != -1) {
+ bool is_on = p_preset->get("capabilities/push_notifications");
+ strnew += lines[i].replace("$entitlements_push_notifications", is_on ? "<key>aps-environment</key><string>development</string>" : "") + "\n";
+ } else if (lines[i].find("$required_device_capabilities") != -1) {
+ String capabilities;
+
+ // I've removed armv7 as we can run on 64bit only devices
+ // Note that capabilities listed here are requirements for the app to be installed.
+ // They don't enable anything.
+ Vector<String> capabilities_list = p_config.capabilities;
+
+ if ((bool)p_preset->get("capabilities/access_wifi") && !capabilities_list.has("wifi")) {
+ capabilities_list.push_back("wifi");
+ }
+
+ for (int idx = 0; idx < capabilities_list.size(); idx++) {
+ capabilities += "<string>" + capabilities_list[idx] + "</string>\n";
+ }
+
+ strnew += lines[i].replace("$required_device_capabilities", capabilities);
+ } else if (lines[i].find("$interface_orientations") != -1) {
+ String orientations;
+ const DisplayServer::ScreenOrientation screen_orientation =
+ DisplayServer::ScreenOrientation(int(GLOBAL_GET("display/window/handheld/orientation")));
+
+ switch (screen_orientation) {
+ case DisplayServer::SCREEN_LANDSCAPE:
+ orientations += "<string>UIInterfaceOrientationLandscapeLeft</string>\n";
+ break;
+ case DisplayServer::SCREEN_PORTRAIT:
+ orientations += "<string>UIInterfaceOrientationPortrait</string>\n";
+ break;
+ case DisplayServer::SCREEN_REVERSE_LANDSCAPE:
+ orientations += "<string>UIInterfaceOrientationLandscapeRight</string>\n";
+ break;
+ case DisplayServer::SCREEN_REVERSE_PORTRAIT:
+ orientations += "<string>UIInterfaceOrientationPortraitUpsideDown</string>\n";
+ break;
+ case DisplayServer::SCREEN_SENSOR_LANDSCAPE:
+ // Allow both landscape orientations depending on sensor direction.
+ orientations += "<string>UIInterfaceOrientationLandscapeLeft</string>\n";
+ orientations += "<string>UIInterfaceOrientationLandscapeRight</string>\n";
+ break;
+ case DisplayServer::SCREEN_SENSOR_PORTRAIT:
+ // Allow both portrait orientations depending on sensor direction.
+ orientations += "<string>UIInterfaceOrientationPortrait</string>\n";
+ orientations += "<string>UIInterfaceOrientationPortraitUpsideDown</string>\n";
+ break;
+ case DisplayServer::SCREEN_SENSOR:
+ // Allow all screen orientations depending on sensor direction.
+ orientations += "<string>UIInterfaceOrientationLandscapeLeft</string>\n";
+ orientations += "<string>UIInterfaceOrientationLandscapeRight</string>\n";
+ orientations += "<string>UIInterfaceOrientationPortrait</string>\n";
+ orientations += "<string>UIInterfaceOrientationPortraitUpsideDown</string>\n";
+ break;
+ }
+
+ strnew += lines[i].replace("$interface_orientations", orientations);
+ } else if (lines[i].find("$camera_usage_description") != -1) {
+ String description = p_preset->get("privacy/camera_usage_description");
+ strnew += lines[i].replace("$camera_usage_description", description) + "\n";
+ } else if (lines[i].find("$microphone_usage_description") != -1) {
+ String description = p_preset->get("privacy/microphone_usage_description");
+ strnew += lines[i].replace("$microphone_usage_description", description) + "\n";
+ } else if (lines[i].find("$photolibrary_usage_description") != -1) {
+ String description = p_preset->get("privacy/photolibrary_usage_description");
+ strnew += lines[i].replace("$photolibrary_usage_description", description) + "\n";
+ } else if (lines[i].find("$plist_launch_screen_name") != -1) {
+ bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
+ String value = is_on ? "<key>UILaunchStoryboardName</key>\n<string>Launch Screen</string>" : "";
+ strnew += lines[i].replace("$plist_launch_screen_name", value) + "\n";
+ } else if (lines[i].find("$pbx_launch_screen_file_reference") != -1) {
+ bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
+ String value = is_on ? "90DD2D9D24B36E8000717FE1 = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = \"Launch Screen.storyboard\"; sourceTree = \"<group>\"; };" : "";
+ strnew += lines[i].replace("$pbx_launch_screen_file_reference", value) + "\n";
+ } else if (lines[i].find("$pbx_launch_screen_copy_files") != -1) {
+ bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
+ String value = is_on ? "90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */," : "";
+ strnew += lines[i].replace("$pbx_launch_screen_copy_files", value) + "\n";
+ } else if (lines[i].find("$pbx_launch_screen_build_phase") != -1) {
+ bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
+ String value = is_on ? "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */," : "";
+ strnew += lines[i].replace("$pbx_launch_screen_build_phase", value) + "\n";
+ } else if (lines[i].find("$pbx_launch_screen_build_reference") != -1) {
+ bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
+ String value = is_on ? "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */; };" : "";
+ strnew += lines[i].replace("$pbx_launch_screen_build_reference", value) + "\n";
+ } else if (lines[i].find("$pbx_launch_image_usage_setting") != -1) {
+ bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
+ String value = is_on ? "" : "ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;";
+ strnew += lines[i].replace("$pbx_launch_image_usage_setting", value) + "\n";
+ } else if (lines[i].find("$launch_screen_image_mode") != -1) {
+ int image_scale_mode = p_preset->get("storyboard/image_scale_mode");
+ String value;
+
+ switch (image_scale_mode) {
+ case 0: {
+ String logo_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
+ bool is_on = ProjectSettings::get_singleton()->get("application/boot_splash/fullsize");
+ // If custom logo is not specified, Godot does not scale default one, so we should do the same.
+ value = (is_on && logo_path.length() > 0) ? "scaleAspectFit" : "center";
+ } break;
+ default: {
+ value = storyboard_image_scale_mode[image_scale_mode - 1];
+ }
+ }
+
+ strnew += lines[i].replace("$launch_screen_image_mode", value) + "\n";
+ } else if (lines[i].find("$launch_screen_background_color") != -1) {
+ bool use_custom = p_preset->get("storyboard/use_custom_bg_color");
+ Color color = use_custom ? p_preset->get("storyboard/custom_bg_color") : ProjectSettings::get_singleton()->get("application/boot_splash/bg_color");
+ const String value_format = "red=\"$red\" green=\"$green\" blue=\"$blue\" alpha=\"$alpha\"";
+
+ Dictionary value_dictionary;
+ value_dictionary["red"] = color.r;
+ value_dictionary["green"] = color.g;
+ value_dictionary["blue"] = color.b;
+ value_dictionary["alpha"] = color.a;
+ String value = value_format.format(value_dictionary, "$_");
+
+ strnew += lines[i].replace("$launch_screen_background_color", value) + "\n";
+ } else {
+ strnew += lines[i] + "\n";
+ }
+ }
+
+ // !BAS! I'm assuming the 9 in the original code was a typo. I've added -1 or else it seems to also be adding our terminating zero...
+ // should apply the same fix in our OSX export.
+ CharString cs = strnew.utf8();
+ pfile.resize(cs.size() - 1);
+ for (int i = 0; i < cs.size() - 1; i++) {
+ pfile.write[i] = cs[i];
+ }
+}
+
+String EditorExportPlatformIOS::_get_additional_plist_content() {
+ Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ String result;
+ for (int i = 0; i < export_plugins.size(); ++i) {
+ result += export_plugins[i]->get_ios_plist_content();
+ }
+ return result;
+}
+
+String EditorExportPlatformIOS::_get_linker_flags() {
+ Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ String result;
+ for (int i = 0; i < export_plugins.size(); ++i) {
+ String flags = export_plugins[i]->get_ios_linker_flags();
+ if (flags.length() == 0) {
+ continue;
+ }
+ if (result.length() > 0) {
+ result += ' ';
+ }
+ result += flags;
+ }
+ // the flags will be enclosed in quotes, so need to escape them
+ return result.replace("\"", "\\\"");
+}
+
+String EditorExportPlatformIOS::_get_cpp_code() {
+ Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ String result;
+ for (int i = 0; i < export_plugins.size(); ++i) {
+ result += export_plugins[i]->get_ios_cpp_code();
+ }
+ return result;
+}
+
+void EditorExportPlatformIOS::_blend_and_rotate(Ref<Image> &p_dst, Ref<Image> &p_src, bool p_rot) {
+ ERR_FAIL_COND(p_dst.is_null());
+ ERR_FAIL_COND(p_src.is_null());
+
+ int sw = p_rot ? p_src->get_height() : p_src->get_width();
+ int sh = p_rot ? p_src->get_width() : p_src->get_height();
+
+ int x_pos = (p_dst->get_width() - sw) / 2;
+ int y_pos = (p_dst->get_height() - sh) / 2;
+
+ int xs = (x_pos >= 0) ? 0 : -x_pos;
+ int ys = (y_pos >= 0) ? 0 : -y_pos;
+
+ if (sw + x_pos > p_dst->get_width()) {
+ sw = p_dst->get_width() - x_pos;
+ }
+ if (sh + y_pos > p_dst->get_height()) {
+ sh = p_dst->get_height() - y_pos;
+ }
+
+ for (int y = ys; y < sh; y++) {
+ for (int x = xs; x < sw; x++) {
+ Color sc = p_rot ? p_src->get_pixel(p_src->get_width() - y - 1, x) : p_src->get_pixel(x, y);
+ Color dc = p_dst->get_pixel(x_pos + x, y_pos + y);
+ dc.r = (double)(sc.a * sc.r + dc.a * (1.0 - sc.a) * dc.r);
+ dc.g = (double)(sc.a * sc.g + dc.a * (1.0 - sc.a) * dc.g);
+ dc.b = (double)(sc.a * sc.b + dc.a * (1.0 - sc.a) * dc.b);
+ dc.a = (double)(sc.a + dc.a * (1.0 - sc.a));
+ p_dst->set_pixel(x_pos + x, y_pos + y, dc);
+ }
+ }
+}
+
+struct IconInfo {
+ const char *preset_key;
+ const char *idiom;
+ const char *export_name;
+ const char *actual_size_side;
+ const char *scale;
+ const char *unscaled_size;
+ bool is_required = false;
+};
+
+static const IconInfo icon_infos[] = {
+ { "required_icons/iphone_120x120", "iphone", "Icon-120.png", "120", "2x", "60x60", true },
+ { "required_icons/iphone_120x120", "iphone", "Icon-120.png", "120", "3x", "40x40", true },
+
+ { "required_icons/ipad_76x76", "ipad", "Icon-76.png", "76", "1x", "76x76", true },
+ { "required_icons/app_store_1024x1024", "ios-marketing", "Icon-1024.png", "1024", "1x", "1024x1024", true },
+
+ { "optional_icons/iphone_180x180", "iphone", "Icon-180.png", "180", "3x", "60x60", false },
+
+ { "optional_icons/ipad_152x152", "ipad", "Icon-152.png", "152", "2x", "76x76", false },
+
+ { "optional_icons/ipad_167x167", "ipad", "Icon-167.png", "167", "2x", "83.5x83.5", false },
+
+ { "optional_icons/spotlight_40x40", "ipad", "Icon-40.png", "40", "1x", "40x40", false },
+
+ { "optional_icons/spotlight_80x80", "iphone", "Icon-80.png", "80", "2x", "40x40", false },
+ { "optional_icons/spotlight_80x80", "ipad", "Icon-80.png", "80", "2x", "40x40", false }
+};
+
+Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir) {
+ String json_description = "{\"images\":[";
+ String sizes;
+
+ DirAccess *da = DirAccess::open(p_iconset_dir);
+ ERR_FAIL_COND_V_MSG(!da, ERR_CANT_OPEN, "Cannot open directory '" + p_iconset_dir + "'.");
+
+ for (uint64_t i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) {
+ IconInfo info = icon_infos[i];
+ int side_size = String(info.actual_size_side).to_int();
+ String icon_path = p_preset->get(info.preset_key);
+ if (icon_path.length() == 0) {
+ if ((bool)p_preset->get("icons/generate_missing")) {
+ // Resize main app icon
+ icon_path = ProjectSettings::get_singleton()->get("application/config/icon");
+ Ref<Image> img = memnew(Image);
+ Error err = ImageLoader::load_image(icon_path, img);
+ if (err != OK) {
+ ERR_PRINT("Invalid icon (" + String(info.preset_key) + "): '" + icon_path + "'.");
+ return ERR_UNCONFIGURED;
+ }
+ img->resize(side_size, side_size);
+ err = img->save_png(p_iconset_dir + info.export_name);
+ if (err) {
+ String err_str = String("Failed to export icon(" + String(info.preset_key) + "): '" + icon_path + "'.");
+ ERR_PRINT(err_str.utf8().get_data());
+ return err;
+ }
+ } else {
+ if (info.is_required) {
+ String err_str = String("Required icon (") + info.preset_key + ") is not specified in the preset.";
+ ERR_PRINT(err_str);
+ return ERR_UNCONFIGURED;
+ } else {
+ String err_str = String("Icon (") + info.preset_key + ") is not specified in the preset.";
+ WARN_PRINT(err_str);
+ }
+ continue;
+ }
+ } else {
+ // Load custom icon
+ Ref<Image> img = memnew(Image);
+ Error err = ImageLoader::load_image(icon_path, img);
+ if (err != OK) {
+ ERR_PRINT("Invalid icon (" + String(info.preset_key) + "): '" + icon_path + "'.");
+ return ERR_UNCONFIGURED;
+ }
+ if (img->get_width() != side_size || img->get_height() != side_size) {
+ ERR_PRINT("Invalid icon size (" + String(info.preset_key) + "): '" + icon_path + "'.");
+ return ERR_UNCONFIGURED;
+ }
+
+ err = da->copy(icon_path, p_iconset_dir + info.export_name);
+ if (err) {
+ memdelete(da);
+ String err_str = String("Failed to export icon(" + String(info.preset_key) + "): '" + icon_path + "'.");
+ ERR_PRINT(err_str.utf8().get_data());
+ return err;
+ }
+ }
+ sizes += String(info.actual_size_side) + "\n";
+ if (i > 0) {
+ json_description += ",";
+ }
+ json_description += String("{");
+ json_description += String("\"idiom\":") + "\"" + info.idiom + "\",";
+ json_description += String("\"size\":") + "\"" + info.unscaled_size + "\",";
+ json_description += String("\"scale\":") + "\"" + info.scale + "\",";
+ json_description += String("\"filename\":") + "\"" + info.export_name + "\"";
+ json_description += String("}");
+ }
+ json_description += "]}";
+ memdelete(da);
+
+ FileAccess *json_file = FileAccess::open(p_iconset_dir + "Contents.json", FileAccess::WRITE);
+ ERR_FAIL_COND_V(!json_file, ERR_CANT_CREATE);
+ CharString json_utf8 = json_description.utf8();
+ json_file->store_buffer((const uint8_t *)json_utf8.get_data(), json_utf8.length());
+ memdelete(json_file);
+
+ FileAccess *sizes_file = FileAccess::open(p_iconset_dir + "sizes", FileAccess::WRITE);
+ ERR_FAIL_COND_V(!sizes_file, ERR_CANT_CREATE);
+ CharString sizes_utf8 = sizes.utf8();
+ sizes_file->store_buffer((const uint8_t *)sizes_utf8.get_data(), sizes_utf8.length());
+ memdelete(sizes_file);
+
+ return OK;
+}
+
+Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir) {
+ const String custom_launch_image_2x = p_preset->get("storyboard/custom_image@2x");
+ const String custom_launch_image_3x = p_preset->get("storyboard/custom_image@3x");
+
+ if (custom_launch_image_2x.length() > 0 && custom_launch_image_3x.length() > 0) {
+ Ref<Image> image;
+ String image_path = p_dest_dir.plus_file("splash@2x.png");
+ image.instantiate();
+ Error err = image->load(custom_launch_image_2x);
+
+ if (err) {
+ image.unref();
+ return err;
+ }
+
+ if (image->save_png(image_path) != OK) {
+ return ERR_FILE_CANT_WRITE;
+ }
+
+ image.unref();
+ image_path = p_dest_dir.plus_file("splash@3x.png");
+ image.instantiate();
+ err = image->load(custom_launch_image_3x);
+
+ if (err) {
+ image.unref();
+ return err;
+ }
+
+ if (image->save_png(image_path) != OK) {
+ return ERR_FILE_CANT_WRITE;
+ }
+ } else {
+ Ref<Image> splash;
+
+ const String splash_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
+
+ if (!splash_path.is_empty()) {
+ splash.instantiate();
+ const Error err = splash->load(splash_path);
+ if (err) {
+ splash.unref();
+ }
+ }
+
+ if (splash.is_null()) {
+ splash = Ref<Image>(memnew(Image(boot_splash_png)));
+ }
+
+ // Using same image for both @2x and @3x
+ // because Godot's own boot logo uses single image for all resolutions.
+ // Also not using @1x image, because devices using this image variant
+ // are not supported by iOS 9, which is minimal target.
+ const String splash_png_path_2x = p_dest_dir.plus_file("splash@2x.png");
+ const String splash_png_path_3x = p_dest_dir.plus_file("splash@3x.png");
+
+ if (splash->save_png(splash_png_path_2x) != OK) {
+ return ERR_FILE_CANT_WRITE;
+ }
+
+ if (splash->save_png(splash_png_path_3x) != OK) {
+ return ERR_FILE_CANT_WRITE;
+ }
+ }
+
+ return OK;
+}
+
+Error EditorExportPlatformIOS::_export_loading_screen_images(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir) {
+ DirAccess *da = DirAccess::open(p_dest_dir);
+ ERR_FAIL_COND_V_MSG(!da, ERR_CANT_OPEN, "Cannot open directory '" + p_dest_dir + "'.");
+
+ for (uint64_t i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) {
+ LoadingScreenInfo info = loading_screen_infos[i];
+ String loading_screen_file = p_preset->get(info.preset_key);
+ if (loading_screen_file.size() > 0) {
+ // Load custom loading screens
+ Ref<Image> img = memnew(Image);
+ Error err = ImageLoader::load_image(loading_screen_file, img);
+ if (err != OK) {
+ ERR_PRINT("Invalid loading screen (" + String(info.preset_key) + "): '" + loading_screen_file + "'.");
+ return ERR_UNCONFIGURED;
+ }
+ if (img->get_width() != info.width || img->get_height() != info.height) {
+ ERR_PRINT("Invalid loading screen size (" + String(info.preset_key) + "): '" + loading_screen_file + "'.");
+ return ERR_UNCONFIGURED;
+ }
+ err = da->copy(loading_screen_file, p_dest_dir + info.export_name);
+ if (err) {
+ memdelete(da);
+ String err_str = String("Failed to export loading screen (") + info.preset_key + ") from path '" + loading_screen_file + "'.";
+ ERR_PRINT(err_str.utf8().get_data());
+ return err;
+ }
+ } else if ((bool)p_preset->get("launch_screens/generate_missing")) {
+ // Generate loading screen from the splash screen
+ Color boot_bg_color = ProjectSettings::get_singleton()->get("application/boot_splash/bg_color");
+ String boot_logo_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
+ bool boot_logo_scale = ProjectSettings::get_singleton()->get("application/boot_splash/fullsize");
+
+ Ref<Image> img = memnew(Image);
+ img->create(info.width, info.height, false, Image::FORMAT_RGBA8);
+ img->fill(boot_bg_color);
+
+ Ref<Image> img_bs;
+
+ if (boot_logo_path.length() > 0) {
+ img_bs = Ref<Image>(memnew(Image));
+ ImageLoader::load_image(boot_logo_path, img_bs);
+ }
+ if (!img_bs.is_valid()) {
+ img_bs = Ref<Image>(memnew(Image(boot_splash_png)));
+ }
+ if (img_bs.is_valid()) {
+ float aspect_ratio = (float)img_bs->get_width() / (float)img_bs->get_height();
+ if (info.rotate) {
+ if (boot_logo_scale) {
+ if (info.width * aspect_ratio <= info.height) {
+ img_bs->resize(info.width * aspect_ratio, info.width);
+ } else {
+ img_bs->resize(info.height, info.height / aspect_ratio);
+ }
+ }
+ } else {
+ if (boot_logo_scale) {
+ if (info.height * aspect_ratio <= info.width) {
+ img_bs->resize(info.height * aspect_ratio, info.height);
+ } else {
+ img_bs->resize(info.width, info.width / aspect_ratio);
+ }
+ }
+ }
+ _blend_and_rotate(img, img_bs, info.rotate);
+ }
+ Error err = img->save_png(p_dest_dir + info.export_name);
+ if (err) {
+ String err_str = String("Failed to export loading screen (") + info.preset_key + ") from splash screen.";
+ WARN_PRINT(err_str.utf8().get_data());
+ }
+ } else {
+ String err_str = String("No loading screen (") + info.preset_key + ") specified.";
+ WARN_PRINT(err_str.utf8().get_data());
+ }
+ }
+ memdelete(da);
+
+ return OK;
+}
+
+Error EditorExportPlatformIOS::_walk_dir_recursive(DirAccess *p_da, FileHandler p_handler, void *p_userdata) {
+ Vector<String> dirs;
+ String path;
+ String current_dir = p_da->get_current_dir();
+ p_da->list_dir_begin();
+ while ((path = p_da->get_next()).length() != 0) {
+ if (p_da->current_is_dir()) {
+ if (path != "." && path != "..") {
+ dirs.push_back(path);
+ }
+ } else {
+ Error err = p_handler(current_dir.plus_file(path), p_userdata);
+ if (err) {
+ p_da->list_dir_end();
+ return err;
+ }
+ }
+ }
+ p_da->list_dir_end();
+
+ for (int i = 0; i < dirs.size(); ++i) {
+ String dir = dirs[i];
+ p_da->change_dir(dir);
+ Error err = _walk_dir_recursive(p_da, p_handler, p_userdata);
+ p_da->change_dir("..");
+ if (err) {
+ return err;
+ }
+ }
+
+ return OK;
+}
+
+struct CodesignData {
+ const Ref<EditorExportPreset> &preset;
+ bool debug = false;
+
+ CodesignData(const Ref<EditorExportPreset> &p_preset, bool p_debug) :
+ preset(p_preset),
+ debug(p_debug) {
+ }
+};
+
+Error EditorExportPlatformIOS::_codesign(String p_file, void *p_userdata) {
+ if (p_file.ends_with(".dylib")) {
+ CodesignData *data = (CodesignData *)p_userdata;
+ print_line(String("Signing ") + p_file);
+ List<String> codesign_args;
+ codesign_args.push_back("-f");
+ codesign_args.push_back("-s");
+ codesign_args.push_back(data->preset->get(data->debug ? "application/code_sign_identity_debug" : "application/code_sign_identity_release"));
+ codesign_args.push_back(p_file);
+ return OS::get_singleton()->execute("codesign", codesign_args);
+ }
+ return OK;
+}
+
+struct PbxId {
+private:
+ static char _hex_char(uint8_t four_bits) {
+ if (four_bits < 10) {
+ return ('0' + four_bits);
+ }
+ return 'A' + (four_bits - 10);
+ }
+
+ static String _hex_pad(uint32_t num) {
+ Vector<char> ret;
+ ret.resize(sizeof(num) * 2);
+ for (uint64_t i = 0; i < sizeof(num) * 2; ++i) {
+ uint8_t four_bits = (num >> (sizeof(num) * 8 - (i + 1) * 4)) & 0xF;
+ ret.write[i] = _hex_char(four_bits);
+ }
+ return String::utf8(ret.ptr(), ret.size());
+ }
+
+public:
+ uint32_t high_bits;
+ uint32_t mid_bits;
+ uint32_t low_bits;
+
+ String str() const {
+ return _hex_pad(high_bits) + _hex_pad(mid_bits) + _hex_pad(low_bits);
+ }
+
+ PbxId &operator++() {
+ low_bits++;
+ if (!low_bits) {
+ mid_bits++;
+ if (!mid_bits) {
+ high_bits++;
+ }
+ }
+
+ return *this;
+ }
+};
+
+struct ExportLibsData {
+ Vector<String> lib_paths;
+ String dest_dir;
+};
+
+void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets) {
+ // that is just a random number, we just need Godot IDs not to clash with
+ // existing IDs in the project.
+ PbxId current_id = { 0x58938401, 0, 0 };
+ String pbx_files;
+ String pbx_frameworks_build;
+ String pbx_frameworks_refs;
+ String pbx_resources_build;
+ String pbx_resources_refs;
+ String pbx_embeded_frameworks;
+
+ const String file_info_format = String("$build_id = {isa = PBXBuildFile; fileRef = $ref_id; };\n") +
+ "$ref_id = {isa = PBXFileReference; lastKnownFileType = $file_type; name = \"$name\"; path = \"$file_path\"; sourceTree = \"<group>\"; };\n";
+
+ for (int i = 0; i < p_additional_assets.size(); ++i) {
+ String additional_asset_info_format = file_info_format;
+
+ String build_id = (++current_id).str();
+ String ref_id = (++current_id).str();
+ String framework_id = "";
+
+ const IOSExportAsset &asset = p_additional_assets[i];
+
+ String type;
+ if (asset.exported_path.ends_with(".framework")) {
+ if (asset.should_embed) {
+ additional_asset_info_format += "$framework_id = {isa = PBXBuildFile; fileRef = $ref_id; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n";
+ framework_id = (++current_id).str();
+ pbx_embeded_frameworks += framework_id + ",\n";
+ }
+
+ type = "wrapper.framework";
+ } else if (asset.exported_path.ends_with(".xcframework")) {
+ if (asset.should_embed) {
+ additional_asset_info_format += "$framework_id = {isa = PBXBuildFile; fileRef = $ref_id; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n";
+ framework_id = (++current_id).str();
+ pbx_embeded_frameworks += framework_id + ",\n";
+ }
+
+ type = "wrapper.xcframework";
+ } else if (asset.exported_path.ends_with(".dylib")) {
+ type = "compiled.mach-o.dylib";
+ } else if (asset.exported_path.ends_with(".a")) {
+ type = "archive.ar";
+ } else {
+ type = "file";
+ }
+
+ String &pbx_build = asset.is_framework ? pbx_frameworks_build : pbx_resources_build;
+ String &pbx_refs = asset.is_framework ? pbx_frameworks_refs : pbx_resources_refs;
+
+ if (pbx_build.length() > 0) {
+ pbx_build += ",\n";
+ pbx_refs += ",\n";
+ }
+ pbx_build += build_id;
+ pbx_refs += ref_id;
+
+ Dictionary format_dict;
+ format_dict["build_id"] = build_id;
+ format_dict["ref_id"] = ref_id;
+ format_dict["name"] = asset.exported_path.get_file();
+ format_dict["file_path"] = asset.exported_path;
+ format_dict["file_type"] = type;
+ if (framework_id.length() > 0) {
+ format_dict["framework_id"] = framework_id;
+ }
+ pbx_files += additional_asset_info_format.format(format_dict, "$_");
+ }
+
+ // Note, frameworks like gamekit are always included in our project.pbxprof file
+ // even if turned off in capabilities.
+
+ String str = String::utf8((const char *)p_project_data.ptr(), p_project_data.size());
+ str = str.replace("$additional_pbx_files", pbx_files);
+ str = str.replace("$additional_pbx_frameworks_build", pbx_frameworks_build);
+ str = str.replace("$additional_pbx_frameworks_refs", pbx_frameworks_refs);
+ str = str.replace("$additional_pbx_resources_build", pbx_resources_build);
+ str = str.replace("$additional_pbx_resources_refs", pbx_resources_refs);
+ str = str.replace("$pbx_embeded_frameworks", pbx_embeded_frameworks);
+
+ CharString cs = str.utf8();
+ p_project_data.resize(cs.size() - 1);
+ for (int i = 0; i < cs.size() - 1; i++) {
+ p_project_data.write[i] = cs[i];
+ }
+}
+
+Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String &p_asset, const String *p_custom_file_name, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets) {
+ DirAccess *filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V_MSG(!filesystem_da, ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_out_dir + "'.");
+
+ String binary_name = p_out_dir.get_file().get_basename();
+
+ DirAccess *da = DirAccess::create_for_path(p_asset);
+ if (!da) {
+ memdelete(filesystem_da);
+ ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't create directory: " + p_asset + ".");
+ }
+ bool file_exists = da->file_exists(p_asset);
+ bool dir_exists = da->dir_exists(p_asset);
+ if (!file_exists && !dir_exists) {
+ memdelete(da);
+ memdelete(filesystem_da);
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ String base_dir = p_asset.get_base_dir().replace("res://", "");
+ String destination_dir;
+ String destination;
+ String asset_path;
+
+ bool create_framework = false;
+
+ if (p_is_framework && p_asset.ends_with(".dylib")) {
+ // For iOS we need to turn .dylib into .framework
+ // to be able to send application to AppStore
+ asset_path = String("dylibs").plus_file(base_dir);
+
+ String file_name;
+
+ if (!p_custom_file_name) {
+ file_name = p_asset.get_basename().get_file();
+ } else {
+ file_name = *p_custom_file_name;
+ }
+
+ String framework_name = file_name + ".framework";
+
+ asset_path = asset_path.plus_file(framework_name);
+ destination_dir = p_out_dir.plus_file(asset_path);
+ destination = destination_dir.plus_file(file_name);
+ create_framework = true;
+ } else if (p_is_framework && (p_asset.ends_with(".framework") || p_asset.ends_with(".xcframework"))) {
+ asset_path = String("dylibs").plus_file(base_dir);
+
+ String file_name;
+
+ if (!p_custom_file_name) {
+ file_name = p_asset.get_file();
+ } else {
+ file_name = *p_custom_file_name;
+ }
+
+ asset_path = asset_path.plus_file(file_name);
+ destination_dir = p_out_dir.plus_file(asset_path);
+ destination = destination_dir;
+ } else {
+ asset_path = base_dir;
+
+ String file_name;
+
+ if (!p_custom_file_name) {
+ file_name = p_asset.get_file();
+ } else {
+ file_name = *p_custom_file_name;
+ }
+
+ destination_dir = p_out_dir.plus_file(asset_path);
+ asset_path = asset_path.plus_file(file_name);
+ destination = p_out_dir.plus_file(asset_path);
+ }
+
+ if (!filesystem_da->dir_exists(destination_dir)) {
+ Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir);
+ if (make_dir_err) {
+ memdelete(da);
+ memdelete(filesystem_da);
+ return make_dir_err;
+ }
+ }
+
+ Error err = dir_exists ? da->copy_dir(p_asset, destination) : da->copy(p_asset, destination);
+ memdelete(da);
+ if (err) {
+ memdelete(filesystem_da);
+ return err;
+ }
+ IOSExportAsset exported_asset = { binary_name.plus_file(asset_path), p_is_framework, p_should_embed };
+ r_exported_assets.push_back(exported_asset);
+
+ if (create_framework) {
+ String file_name;
+
+ if (!p_custom_file_name) {
+ file_name = p_asset.get_basename().get_file();
+ } else {
+ file_name = *p_custom_file_name;
+ }
+
+ String framework_name = file_name + ".framework";
+
+ // Performing `install_name_tool -id @rpath/{name}.framework/{name} ./{name}` on dylib
+ {
+ List<String> install_name_args;
+ install_name_args.push_back("-id");
+ install_name_args.push_back(String("@rpath").plus_file(framework_name).plus_file(file_name));
+ install_name_args.push_back(destination);
+
+ OS::get_singleton()->execute("install_name_tool", install_name_args);
+ }
+
+ // Creating Info.plist
+ {
+ String info_plist_format = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
+ "<plist version=\"1.0\">\n"
+ "<dict>\n"
+ "<key>CFBundleShortVersionString</key>\n"
+ "<string>1.0</string>\n"
+ "<key>CFBundleIdentifier</key>\n"
+ "<string>com.gdnative.framework.$name</string>\n"
+ "<key>CFBundleName</key>\n"
+ "<string>$name</string>\n"
+ "<key>CFBundleExecutable</key>\n"
+ "<string>$name</string>\n"
+ "<key>DTPlatformName</key>\n"
+ "<string>iphoneos</string>\n"
+ "<key>CFBundleInfoDictionaryVersion</key>\n"
+ "<string>6.0</string>\n"
+ "<key>CFBundleVersion</key>\n"
+ "<string>1</string>\n"
+ "<key>CFBundlePackageType</key>\n"
+ "<string>FMWK</string>\n"
+ "<key>MinimumOSVersion</key>\n"
+ "<string>10.0</string>\n"
+ "</dict>\n"
+ "</plist>";
+
+ String info_plist = info_plist_format.replace("$name", file_name);
+
+ FileAccess *f = FileAccess::open(destination_dir.plus_file("Info.plist"), FileAccess::WRITE);
+ if (f) {
+ f->store_string(info_plist);
+ f->close();
+ memdelete(f);
+ }
+ }
+ }
+
+ memdelete(filesystem_da);
+
+ return OK;
+}
+
+Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets) {
+ for (int f_idx = 0; f_idx < p_assets.size(); ++f_idx) {
+ String asset = p_assets[f_idx];
+ if (!asset.begins_with("res://")) {
+ // either SDK-builtin or already a part of the export template
+ IOSExportAsset exported_asset = { asset, p_is_framework, p_should_embed };
+ r_exported_assets.push_back(exported_asset);
+ } else {
+ Error err = _copy_asset(p_out_dir, asset, nullptr, p_is_framework, p_should_embed, r_exported_assets);
+ ERR_FAIL_COND_V(err, err);
+ }
+ }
+
+ return OK;
+}
+
+Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets) {
+ Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ for (int i = 0; i < export_plugins.size(); i++) {
+ Vector<String> linked_frameworks = export_plugins[i]->get_ios_frameworks();
+ Error err = _export_additional_assets(p_out_dir, linked_frameworks, true, false, r_exported_assets);
+ ERR_FAIL_COND_V(err, err);
+
+ Vector<String> embedded_frameworks = export_plugins[i]->get_ios_embedded_frameworks();
+ err = _export_additional_assets(p_out_dir, embedded_frameworks, true, true, r_exported_assets);
+ ERR_FAIL_COND_V(err, err);
+
+ Vector<String> project_static_libs = export_plugins[i]->get_ios_project_static_libs();
+ for (int j = 0; j < project_static_libs.size(); j++) {
+ project_static_libs.write[j] = project_static_libs[j].get_file(); // Only the file name as it's copied to the project
+ }
+ err = _export_additional_assets(p_out_dir, project_static_libs, true, true, r_exported_assets);
+ ERR_FAIL_COND_V(err, err);
+
+ Vector<String> ios_bundle_files = export_plugins[i]->get_ios_bundle_files();
+ err = _export_additional_assets(p_out_dir, ios_bundle_files, false, false, r_exported_assets);
+ ERR_FAIL_COND_V(err, err);
+ }
+
+ Vector<String> library_paths;
+ for (int i = 0; i < p_libraries.size(); ++i) {
+ library_paths.push_back(p_libraries[i].path);
+ }
+ Error err = _export_additional_assets(p_out_dir, library_paths, true, true, r_exported_assets);
+ ERR_FAIL_COND_V(err, err);
+
+ return OK;
+}
+
+Vector<String> EditorExportPlatformIOS::_get_preset_architectures(const Ref<EditorExportPreset> &p_preset) {
+ Vector<ExportArchitecture> all_archs = _get_supported_architectures();
+ Vector<String> enabled_archs;
+ for (int i = 0; i < all_archs.size(); ++i) {
+ bool is_enabled = p_preset->get("architectures/" + all_archs[i].name);
+ if (is_enabled) {
+ enabled_archs.push_back(all_archs[i].name);
+ }
+ }
+ return enabled_archs;
+}
+
+Error EditorExportPlatformIOS::_export_ios_plugins(const Ref<EditorExportPreset> &p_preset, IOSConfigData &p_config_data, const String &dest_dir, Vector<IOSExportAsset> &r_exported_assets, bool p_debug) {
+ String plugin_definition_cpp_code;
+ String plugin_initialization_cpp_code;
+ String plugin_deinitialization_cpp_code;
+
+ Vector<String> plugin_linked_dependencies;
+ Vector<String> plugin_embedded_dependencies;
+ Vector<String> plugin_files;
+
+ Vector<PluginConfigIOS> enabled_plugins = get_enabled_plugins(p_preset);
+
+ Vector<String> added_linked_dependenciy_names;
+ Vector<String> added_embedded_dependenciy_names;
+ HashMap<String, String> plist_values;
+
+ Set<String> plugin_linker_flags;
+
+ Error err;
+
+ for (int i = 0; i < enabled_plugins.size(); i++) {
+ PluginConfigIOS plugin = enabled_plugins[i];
+
+ // Export plugin binary.
+ String plugin_main_binary = PluginConfigIOS::get_plugin_main_binary(plugin, p_debug);
+ String plugin_binary_result_file = plugin.binary.get_file();
+ // We shouldn't embed .xcframework that contains static libraries.
+ // Static libraries are not embedded anyway.
+ err = _copy_asset(dest_dir, plugin_main_binary, &plugin_binary_result_file, true, false, r_exported_assets);
+
+ ERR_FAIL_COND_V(err, err);
+
+ // Adding dependencies.
+ // Use separate container for names to check for duplicates.
+ for (int j = 0; j < plugin.linked_dependencies.size(); j++) {
+ String dependency = plugin.linked_dependencies[j];
+ String name = dependency.get_file();
+
+ if (added_linked_dependenciy_names.has(name)) {
+ continue;
+ }
+
+ added_linked_dependenciy_names.push_back(name);
+ plugin_linked_dependencies.push_back(dependency);
+ }
+
+ for (int j = 0; j < plugin.system_dependencies.size(); j++) {
+ String dependency = plugin.system_dependencies[j];
+ String name = dependency.get_file();
+
+ if (added_linked_dependenciy_names.has(name)) {
+ continue;
+ }
+
+ added_linked_dependenciy_names.push_back(name);
+ plugin_linked_dependencies.push_back(dependency);
+ }
+
+ for (int j = 0; j < plugin.embedded_dependencies.size(); j++) {
+ String dependency = plugin.embedded_dependencies[j];
+ String name = dependency.get_file();
+
+ if (added_embedded_dependenciy_names.has(name)) {
+ continue;
+ }
+
+ added_embedded_dependenciy_names.push_back(name);
+ plugin_embedded_dependencies.push_back(dependency);
+ }
+
+ plugin_files.append_array(plugin.files_to_copy);
+
+ // Capabilities
+ // Also checking for duplicates.
+ for (int j = 0; j < plugin.capabilities.size(); j++) {
+ String capability = plugin.capabilities[j];
+
+ if (p_config_data.capabilities.has(capability)) {
+ continue;
+ }
+
+ p_config_data.capabilities.push_back(capability);
+ }
+
+ // Linker flags
+ // Checking duplicates
+ for (int j = 0; j < plugin.linker_flags.size(); j++) {
+ String linker_flag = plugin.linker_flags[j];
+ plugin_linker_flags.insert(linker_flag);
+ }
+
+ // Plist
+ // Using hash map container to remove duplicates
+ const String *K = nullptr;
+
+ while ((K = plugin.plist.next(K))) {
+ String key = *K;
+ PluginConfigIOS::PlistItem item = plugin.plist[key];
+
+ String value;
+
+ switch (item.type) {
+ case PluginConfigIOS::PlistItemType::STRING_INPUT: {
+ String preset_name = "plugins_plist/" + key;
+ String input_value = p_preset->get(preset_name);
+ value = "<string>" + input_value + "</string>";
+ } break;
+ default:
+ value = item.value;
+ break;
+ }
+
+ if (key.is_empty() || value.is_empty()) {
+ continue;
+ }
+
+ String plist_key = "<key>" + key + "</key>";
+
+ plist_values[plist_key] = value;
+ }
+
+ // CPP Code
+ String definition_comment = "// Plugin: " + plugin.name + "\n";
+ String initialization_method = plugin.initialization_method + "();\n";
+ String deinitialization_method = plugin.deinitialization_method + "();\n";
+
+ plugin_definition_cpp_code += definition_comment +
+ "extern void " + initialization_method +
+ "extern void " + deinitialization_method + "\n";
+
+ plugin_initialization_cpp_code += "\t" + initialization_method;
+ plugin_deinitialization_cpp_code += "\t" + deinitialization_method;
+ }
+
+ // Updating `Info.plist`
+ {
+ const String *K = nullptr;
+ while ((K = plist_values.next(K))) {
+ String key = *K;
+ String value = plist_values[key];
+
+ if (key.is_empty() || value.is_empty()) {
+ continue;
+ }
+
+ p_config_data.plist_content += key + value + "\n";
+ }
+ }
+
+ // Export files
+ {
+ // Export linked plugin dependency
+ err = _export_additional_assets(dest_dir, plugin_linked_dependencies, true, false, r_exported_assets);
+ ERR_FAIL_COND_V(err, err);
+
+ // Export embedded plugin dependency
+ err = _export_additional_assets(dest_dir, plugin_embedded_dependencies, true, true, r_exported_assets);
+ ERR_FAIL_COND_V(err, err);
+
+ // Export plugin files
+ err = _export_additional_assets(dest_dir, plugin_files, false, false, r_exported_assets);
+ ERR_FAIL_COND_V(err, err);
+ }
+
+ // Update CPP
+ {
+ Dictionary plugin_format;
+ plugin_format["definition"] = plugin_definition_cpp_code;
+ plugin_format["initialization"] = plugin_initialization_cpp_code;
+ plugin_format["deinitialization"] = plugin_deinitialization_cpp_code;
+
+ String plugin_cpp_code = "\n// Godot Plugins\n"
+ "void godot_ios_plugins_initialize();\n"
+ "void godot_ios_plugins_deinitialize();\n"
+ "// Exported Plugins\n\n"
+ "$definition"
+ "// Use Plugins\n"
+ "void godot_ios_plugins_initialize() {\n"
+ "$initialization"
+ "}\n\n"
+ "void godot_ios_plugins_deinitialize() {\n"
+ "$deinitialization"
+ "}\n";
+
+ p_config_data.cpp_code += plugin_cpp_code.format(plugin_format, "$_");
+ }
+
+ // Update Linker Flag Values
+ {
+ String result_linker_flags = " ";
+ for (Set<String>::Element *E = plugin_linker_flags.front(); E; E = E->next()) {
+ const String &flag = E->get();
+
+ if (flag.length() == 0) {
+ continue;
+ }
+
+ if (result_linker_flags.length() > 0) {
+ result_linker_flags += ' ';
+ }
+
+ result_linker_flags += flag;
+ }
+ result_linker_flags = result_linker_flags.replace("\"", "\\\"");
+ p_config_data.linker_flags += result_linker_flags;
+ }
+
+ return OK;
+}
+
+Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
+ ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
+
+ String src_pkg_name;
+ String dest_dir = p_path.get_base_dir() + "/";
+ String binary_name = p_path.get_file().get_basename();
+
+ EditorProgress ep("export", "Exporting for iOS", 5, true);
+
+ String team_id = p_preset->get("application/app_store_team_id");
+ ERR_FAIL_COND_V_MSG(team_id.length() == 0, ERR_CANT_OPEN, "App Store Team ID not specified - cannot configure the project.");
+
+ if (p_debug) {
+ src_pkg_name = p_preset->get("custom_template/debug");
+ } else {
+ src_pkg_name = p_preset->get("custom_template/release");
+ }
+
+ if (src_pkg_name == "") {
+ String err;
+ src_pkg_name = find_export_template("iphone.zip", &err);
+ if (src_pkg_name == "") {
+ EditorNode::add_io_error(err);
+ return ERR_FILE_NOT_FOUND;
+ }
+ }
+
+ if (!DirAccess::exists(dest_dir)) {
+ return ERR_FILE_BAD_PATH;
+ }
+
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ if (da) {
+ String current_dir = da->get_current_dir();
+
+ // remove leftovers from last export so they don't interfere
+ // in case some files are no longer needed
+ if (da->change_dir(dest_dir + binary_name + ".xcodeproj") == OK) {
+ da->erase_contents_recursive();
+ }
+ if (da->change_dir(dest_dir + binary_name) == OK) {
+ da->erase_contents_recursive();
+ }
+
+ da->change_dir(current_dir);
+
+ if (!da->dir_exists(dest_dir + binary_name)) {
+ Error err = da->make_dir(dest_dir + binary_name);
+ if (err) {
+ memdelete(da);
+ return err;
+ }
+ }
+ memdelete(da);
+ }
+
+ if (ep.step("Making .pck", 0)) {
+ return ERR_SKIP;
+ }
+ String pack_path = dest_dir + binary_name + ".pck";
+ Vector<SharedObject> libraries;
+ Error err = save_pack(p_preset, pack_path, &libraries);
+ if (err) {
+ return err;
+ }
+
+ if (ep.step("Extracting and configuring Xcode project", 1)) {
+ return ERR_SKIP;
+ }
+
+ String library_to_use = "libgodot.iphone." + String(p_debug ? "debug" : "release") + ".xcframework";
+
+ print_line("Static framework: " + library_to_use);
+ String pkg_name;
+ if (p_preset->get("application/name") != "") {
+ pkg_name = p_preset->get("application/name"); // app_name
+ } else if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") {
+ pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
+ } else {
+ pkg_name = "Unnamed";
+ }
+
+ bool found_library = false;
+ int total_size = 0;
+
+ const String project_file = "godot_ios.xcodeproj/project.pbxproj";
+ Set<String> files_to_parse;
+ files_to_parse.insert("godot_ios/godot_ios-Info.plist");
+ files_to_parse.insert(project_file);
+ files_to_parse.insert("godot_ios/export_options.plist");
+ files_to_parse.insert("godot_ios/dummy.cpp");
+ files_to_parse.insert("godot_ios.xcodeproj/project.xcworkspace/contents.xcworkspacedata");
+ files_to_parse.insert("godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme");
+ files_to_parse.insert("godot_ios/godot_ios.entitlements");
+ files_to_parse.insert("godot_ios/Launch Screen.storyboard");
+
+ IOSConfigData config_data = {
+ pkg_name,
+ binary_name,
+ _get_additional_plist_content(),
+ String(" ").join(_get_preset_architectures(p_preset)),
+ _get_linker_flags(),
+ _get_cpp_code(),
+ "",
+ "",
+ "",
+ "",
+ Vector<String>()
+ };
+
+ Vector<IOSExportAsset> assets;
+
+ DirAccess *tmp_app_path = DirAccess::create_for_path(dest_dir);
+ ERR_FAIL_COND_V(!tmp_app_path, ERR_CANT_CREATE);
+
+ print_line("Unzipping...");
+ FileAccess *src_f = nullptr;
+ zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
+ unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io);
+ if (!src_pkg_zip) {
+ EditorNode::add_io_error("Could not open export template (not a zip file?):\n" + src_pkg_name);
+ return ERR_CANT_OPEN;
+ }
+
+ err = _export_ios_plugins(p_preset, config_data, dest_dir + binary_name, assets, p_debug);
+ ERR_FAIL_COND_V(err, err);
+
+ //export rest of the files
+ int ret = unzGoToFirstFile(src_pkg_zip);
+ Vector<uint8_t> project_file_data;
+ while (ret == UNZ_OK) {
+#if defined(OSX_ENABLED) || defined(X11_ENABLED)
+ bool is_execute = false;
+#endif
+
+ //get filename
+ unz_file_info info;
+ char fname[16384];
+ ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, nullptr, 0, nullptr, 0);
+
+ String file = fname;
+
+ print_line("READ: " + file);
+ Vector<uint8_t> data;
+ data.resize(info.uncompressed_size);
+
+ //read
+ unzOpenCurrentFile(src_pkg_zip);
+ unzReadCurrentFile(src_pkg_zip, data.ptrw(), data.size());
+ unzCloseCurrentFile(src_pkg_zip);
+
+ //write
+
+ file = file.replace_first("iphone/", "");
+
+ if (files_to_parse.has(file)) {
+ _fix_config_file(p_preset, data, config_data, p_debug);
+ } else if (file.begins_with("libgodot.iphone")) {
+ if (!file.begins_with(library_to_use) || file.ends_with(String("/empty"))) {
+ ret = unzGoToNextFile(src_pkg_zip);
+ continue; //ignore!
+ }
+ found_library = true;
+#if defined(OSX_ENABLED) || defined(X11_ENABLED)
+ is_execute = true;
+#endif
+ file = file.replace(library_to_use, binary_name + ".xcframework");
+ }
+
+ if (file == project_file) {
+ project_file_data = data;
+ }
+
+ ///@TODO need to parse logo files
+
+ if (data.size() > 0) {
+ file = file.replace("godot_ios", binary_name);
+
+ print_line("ADDING: " + file + " size: " + itos(data.size()));
+ total_size += data.size();
+
+ /* write it into our folder structure */
+ file = dest_dir + file;
+
+ /* make sure this folder exists */
+ String dir_name = file.get_base_dir();
+ if (!tmp_app_path->dir_exists(dir_name)) {
+ print_line("Creating " + dir_name);
+ Error dir_err = tmp_app_path->make_dir_recursive(dir_name);
+ if (dir_err) {
+ ERR_PRINT("Can't create '" + dir_name + "'.");
+ unzClose(src_pkg_zip);
+ memdelete(tmp_app_path);
+ return ERR_CANT_CREATE;
+ }
+ }
+
+ /* write the file */
+ FileAccess *f = FileAccess::open(file, FileAccess::WRITE);
+ if (!f) {
+ ERR_PRINT("Can't write '" + file + "'.");
+ unzClose(src_pkg_zip);
+ memdelete(tmp_app_path);
+ return ERR_CANT_CREATE;
+ };
+ f->store_buffer(data.ptr(), data.size());
+ f->close();
+ memdelete(f);
+
+#if defined(OSX_ENABLED) || defined(X11_ENABLED)
+ if (is_execute) {
+ // we need execute rights on this file
+ chmod(file.utf8().get_data(), 0755);
+ }
+#endif
+ }
+
+ ret = unzGoToNextFile(src_pkg_zip);
+ }
+
+ /* we're done with our source zip */
+ unzClose(src_pkg_zip);
+
+ if (!found_library) {
+ ERR_PRINT("Requested template library '" + library_to_use + "' not found. It might be missing from your template archive.");
+ memdelete(tmp_app_path);
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ // Copy project static libs to the project
+ Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ for (int i = 0; i < export_plugins.size(); i++) {
+ Vector<String> project_static_libs = export_plugins[i]->get_ios_project_static_libs();
+ for (int j = 0; j < project_static_libs.size(); j++) {
+ const String &static_lib_path = project_static_libs[j];
+ String dest_lib_file_path = dest_dir + static_lib_path.get_file();
+ Error lib_copy_err = tmp_app_path->copy(static_lib_path, dest_lib_file_path);
+ if (lib_copy_err != OK) {
+ ERR_PRINT("Can't copy '" + static_lib_path + "'.");
+ memdelete(tmp_app_path);
+ return lib_copy_err;
+ }
+ }
+ }
+
+ String iconset_dir = dest_dir + binary_name + "/Images.xcassets/AppIcon.appiconset/";
+ err = OK;
+ if (!tmp_app_path->dir_exists(iconset_dir)) {
+ err = tmp_app_path->make_dir_recursive(iconset_dir);
+ }
+ memdelete(tmp_app_path);
+ if (err) {
+ return err;
+ }
+
+ err = _export_icons(p_preset, iconset_dir);
+ if (err) {
+ return err;
+ }
+
+ bool use_storyboard = p_preset->get("storyboard/use_launch_screen_storyboard");
+
+ String launch_image_path = dest_dir + binary_name + "/Images.xcassets/LaunchImage.launchimage/";
+ String splash_image_path = dest_dir + binary_name + "/Images.xcassets/SplashImage.imageset/";
+
+ DirAccess *launch_screen_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+
+ if (!launch_screen_da) {
+ return ERR_CANT_CREATE;
+ }
+
+ if (use_storyboard) {
+ print_line("Using Launch Storyboard");
+
+ if (launch_screen_da->change_dir(launch_image_path) == OK) {
+ launch_screen_da->erase_contents_recursive();
+ launch_screen_da->remove(launch_image_path);
+ }
+
+ err = _export_loading_screen_file(p_preset, splash_image_path);
+ } else {
+ print_line("Using Launch Images");
+
+ const String launch_screen_path = dest_dir + binary_name + "/Launch Screen.storyboard";
+
+ launch_screen_da->remove(launch_screen_path);
+
+ if (launch_screen_da->change_dir(splash_image_path) == OK) {
+ launch_screen_da->erase_contents_recursive();
+ launch_screen_da->remove(splash_image_path);
+ }
+
+ err = _export_loading_screen_images(p_preset, launch_image_path);
+ }
+
+ memdelete(launch_screen_da);
+
+ if (err) {
+ return err;
+ }
+
+ print_line("Exporting additional assets");
+ _export_additional_assets(dest_dir + binary_name, libraries, assets);
+ _add_assets_to_project(p_preset, project_file_data, assets);
+ String project_file_name = dest_dir + binary_name + ".xcodeproj/project.pbxproj";
+ FileAccess *f = FileAccess::open(project_file_name, FileAccess::WRITE);
+ if (!f) {
+ ERR_PRINT("Can't write '" + project_file_name + "'.");
+ return ERR_CANT_CREATE;
+ };
+ f->store_buffer(project_file_data.ptr(), project_file_data.size());
+ f->close();
+ memdelete(f);
+
+#ifdef OSX_ENABLED
+ if (ep.step("Code-signing dylibs", 2)) {
+ return ERR_SKIP;
+ }
+ DirAccess *dylibs_dir = DirAccess::open(dest_dir + binary_name + "/dylibs");
+ ERR_FAIL_COND_V(!dylibs_dir, ERR_CANT_OPEN);
+ CodesignData codesign_data(p_preset, p_debug);
+ err = _walk_dir_recursive(dylibs_dir, _codesign, &codesign_data);
+ memdelete(dylibs_dir);
+ ERR_FAIL_COND_V(err, err);
+
+ if (ep.step("Making .xcarchive", 3)) {
+ return ERR_SKIP;
+ }
+ String archive_path = p_path.get_basename() + ".xcarchive";
+ List<String> archive_args;
+ archive_args.push_back("-project");
+ archive_args.push_back(dest_dir + binary_name + ".xcodeproj");
+ archive_args.push_back("-scheme");
+ archive_args.push_back(binary_name);
+ archive_args.push_back("-sdk");
+ archive_args.push_back("iphoneos");
+ archive_args.push_back("-configuration");
+ archive_args.push_back(p_debug ? "Debug" : "Release");
+ archive_args.push_back("-destination");
+ archive_args.push_back("generic/platform=iOS");
+ archive_args.push_back("archive");
+ archive_args.push_back("-archivePath");
+ archive_args.push_back(archive_path);
+ err = OS::get_singleton()->execute("xcodebuild", archive_args);
+ ERR_FAIL_COND_V(err, err);
+
+ if (ep.step("Making .ipa", 4)) {
+ return ERR_SKIP;
+ }
+ List<String> export_args;
+ export_args.push_back("-exportArchive");
+ export_args.push_back("-archivePath");
+ export_args.push_back(archive_path);
+ export_args.push_back("-exportOptionsPlist");
+ export_args.push_back(dest_dir + binary_name + "/export_options.plist");
+ export_args.push_back("-allowProvisioningUpdates");
+ export_args.push_back("-exportPath");
+ export_args.push_back(dest_dir);
+ err = OS::get_singleton()->execute("xcodebuild", export_args);
+ ERR_FAIL_COND_V(err, err);
+#else
+ print_line(".ipa can only be built on macOS. Leaving Xcode project without building the package.");
+#endif
+
+ return OK;
+}
+
+bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+ String err;
+ bool valid = false;
+
+ // Look for export templates (first official, and if defined custom templates).
+
+ bool dvalid = exists_export_template("iphone.zip", &err);
+ bool rvalid = dvalid; // Both in the same ZIP.
+
+ if (p_preset->get("custom_template/debug") != "") {
+ dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
+ if (!dvalid) {
+ err += TTR("Custom debug template not found.") + "\n";
+ }
+ }
+ if (p_preset->get("custom_template/release") != "") {
+ rvalid = FileAccess::exists(p_preset->get("custom_template/release"));
+ if (!rvalid) {
+ err += TTR("Custom release template not found.") + "\n";
+ }
+ }
+
+ valid = dvalid || rvalid;
+ r_missing_templates = !valid;
+
+ // Validate the rest of the configuration.
+
+ String team_id = p_preset->get("application/app_store_team_id");
+ if (team_id.length() == 0) {
+ err += TTR("App Store Team ID not specified - cannot configure the project.") + "\n";
+ valid = false;
+ }
+
+ String identifier = p_preset->get("application/bundle_identifier");
+ String pn_err;
+ if (!is_package_name_valid(identifier, &pn_err)) {
+ err += TTR("Invalid Identifier:") + " " + pn_err + "\n";
+ valid = false;
+ }
+
+ for (uint64_t i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) {
+ IconInfo info = icon_infos[i];
+ String icon_path = p_preset->get(info.preset_key);
+ if (icon_path.length() == 0) {
+ if (info.is_required) {
+ err += TTR("Required icon is not specified in the preset.") + "\n";
+ valid = false;
+ }
+ break;
+ }
+ }
+
+ String etc_error = test_etc2_or_pvrtc();
+ if (etc_error != String()) {
+ valid = false;
+ err += etc_error;
+ }
+
+ if (!err.is_empty()) {
+ r_error = err;
+ }
+
+ return valid;
+}
+
+EditorExportPlatformIOS::EditorExportPlatformIOS() {
+ Ref<Image> img = memnew(Image(_iphone_logo));
+ logo.instantiate();
+ logo->create_from_image(img);
+
+ plugins_changed.set();
+
+ check_for_changes_thread.start(_check_for_changes_poll_thread, this);
+}
+
+EditorExportPlatformIOS::~EditorExportPlatformIOS() {
+ quit_request.set();
+ check_for_changes_thread.wait_to_finish();
+}
diff --git a/platform/iphone/export/export_plugin.h b/platform/iphone/export/export_plugin.h
new file mode 100644
index 0000000000..8d3af6e057
--- /dev/null
+++ b/platform/iphone/export/export_plugin.h
@@ -0,0 +1,296 @@
+/*************************************************************************/
+/* export_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef IPHONE_EXPORT_PLUGIN_H
+#define IPHONE_EXPORT_PLUGIN_H
+
+#include "core/config/project_settings.h"
+#include "core/io/file_access.h"
+#include "core/io/image_loader.h"
+#include "core/io/marshalls.h"
+#include "core/io/resource_saver.h"
+#include "core/io/zip_io.h"
+#include "core/os/os.h"
+#include "core/templates/safe_refcount.h"
+#include "core/version.h"
+#include "editor/editor_export.h"
+#include "editor/editor_node.h"
+#include "editor/editor_settings.h"
+#include "main/splash.gen.h"
+#include "platform/iphone/logo.gen.h"
+#include "string.h"
+
+#include "godot_plugin_config.h"
+
+#include <sys/stat.h>
+
+class EditorExportPlatformIOS : public EditorExportPlatform {
+ GDCLASS(EditorExportPlatformIOS, EditorExportPlatform);
+
+ int version_code;
+
+ Ref<ImageTexture> logo;
+
+ // Plugins
+ SafeFlag plugins_changed;
+ Thread check_for_changes_thread;
+ SafeFlag quit_request;
+ Mutex plugins_lock;
+ Vector<PluginConfigIOS> plugins;
+
+ typedef Error (*FileHandler)(String p_file, void *p_userdata);
+ static Error _walk_dir_recursive(DirAccess *p_da, FileHandler p_handler, void *p_userdata);
+ static Error _codesign(String p_file, void *p_userdata);
+ void _blend_and_rotate(Ref<Image> &p_dst, Ref<Image> &p_src, bool p_rot);
+
+ struct IOSConfigData {
+ String pkg_name;
+ String binary_name;
+ String plist_content;
+ String architectures;
+ String linker_flags;
+ String cpp_code;
+ String modules_buildfile;
+ String modules_fileref;
+ String modules_buildphase;
+ String modules_buildgrp;
+ Vector<String> capabilities;
+ };
+ struct ExportArchitecture {
+ String name;
+ bool is_default = false;
+
+ ExportArchitecture() {}
+
+ ExportArchitecture(String p_name, bool p_is_default) {
+ name = p_name;
+ is_default = p_is_default;
+ }
+ };
+
+ struct IOSExportAsset {
+ String exported_path;
+ bool is_framework = false; // framework is anything linked to the binary, otherwise it's a resource
+ bool should_embed = false;
+ };
+
+ String _get_additional_plist_content();
+ String _get_linker_flags();
+ String _get_cpp_code();
+ void _fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const IOSConfigData &p_config, bool p_debug);
+ Error _export_loading_screen_images(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir);
+ Error _export_loading_screen_file(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir);
+ Error _export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir);
+
+ Vector<ExportArchitecture> _get_supported_architectures();
+ Vector<String> _get_preset_architectures(const Ref<EditorExportPreset> &p_preset);
+
+ void _add_assets_to_project(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets);
+ Error _export_additional_assets(const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets);
+ Error _copy_asset(const String &p_out_dir, const String &p_asset, const String *p_custom_file_name, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets);
+ Error _export_additional_assets(const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets);
+ Error _export_ios_plugins(const Ref<EditorExportPreset> &p_preset, IOSConfigData &p_config_data, const String &dest_dir, Vector<IOSExportAsset> &r_exported_assets, bool p_debug);
+
+ bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const {
+ String pname = p_package;
+
+ if (pname.length() == 0) {
+ if (r_error) {
+ *r_error = TTR("Identifier is missing.");
+ }
+ return false;
+ }
+
+ for (int i = 0; i < pname.length(); i++) {
+ char32_t c = pname[i];
+ if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '.')) {
+ if (r_error) {
+ *r_error = vformat(TTR("The character '%s' is not allowed in Identifier."), String::chr(c));
+ }
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ static void _check_for_changes_poll_thread(void *ud) {
+ EditorExportPlatformIOS *ea = (EditorExportPlatformIOS *)ud;
+
+ while (!ea->quit_request.is_set()) {
+ // Nothing to do if we already know the plugins have changed.
+ if (!ea->plugins_changed.is_set()) {
+ MutexLock lock(ea->plugins_lock);
+
+ Vector<PluginConfigIOS> loaded_plugins = get_plugins();
+
+ if (ea->plugins.size() != loaded_plugins.size()) {
+ ea->plugins_changed.set();
+ } else {
+ for (int i = 0; i < ea->plugins.size(); i++) {
+ if (ea->plugins[i].name != loaded_plugins[i].name || ea->plugins[i].last_updated != loaded_plugins[i].last_updated) {
+ ea->plugins_changed.set();
+ break;
+ }
+ }
+ }
+ }
+
+ uint64_t wait = 3000000;
+ uint64_t time = OS::get_singleton()->get_ticks_usec();
+ while (OS::get_singleton()->get_ticks_usec() - time < wait) {
+ OS::get_singleton()->delay_usec(300000);
+
+ if (ea->quit_request.is_set()) {
+ break;
+ }
+ }
+ }
+ }
+
+protected:
+ virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) override;
+ virtual void get_export_options(List<ExportOption> *r_options) override;
+
+public:
+ virtual String get_name() const override { return "iOS"; }
+ virtual String get_os_name() const override { return "iOS"; }
+ virtual Ref<Texture2D> get_logo() const override { return logo; }
+
+ virtual bool should_update_export_options() override {
+ bool export_options_changed = plugins_changed.is_set();
+ if (export_options_changed) {
+ // don't clear unless we're reporting true, to avoid race
+ plugins_changed.clear();
+ }
+ return export_options_changed;
+ }
+
+ virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override {
+ List<String> list;
+ list.push_back("ipa");
+ return list;
+ }
+ virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
+
+ virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+
+ virtual void get_platform_features(List<String> *r_features) override {
+ r_features->push_back("mobile");
+ r_features->push_back("iOS");
+ }
+
+ virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) override {
+ }
+
+ EditorExportPlatformIOS();
+ ~EditorExportPlatformIOS();
+
+ /// List the gdip files in the directory specified by the p_path parameter.
+ static Vector<String> list_plugin_config_files(const String &p_path, bool p_check_directories) {
+ Vector<String> dir_files;
+ DirAccessRef da = DirAccess::open(p_path);
+ if (da) {
+ da->list_dir_begin();
+ while (true) {
+ String file = da->get_next();
+ if (file.is_empty()) {
+ break;
+ }
+
+ if (file == "." || file == "..") {
+ continue;
+ }
+
+ if (da->current_is_hidden()) {
+ continue;
+ }
+
+ if (da->current_is_dir()) {
+ if (p_check_directories) {
+ Vector<String> directory_files = list_plugin_config_files(p_path.plus_file(file), false);
+ for (int i = 0; i < directory_files.size(); ++i) {
+ dir_files.push_back(file.plus_file(directory_files[i]));
+ }
+ }
+
+ continue;
+ }
+
+ if (file.ends_with(PluginConfigIOS::PLUGIN_CONFIG_EXT)) {
+ dir_files.push_back(file);
+ }
+ }
+ da->list_dir_end();
+ }
+
+ return dir_files;
+ }
+
+ static Vector<PluginConfigIOS> get_plugins() {
+ Vector<PluginConfigIOS> loaded_plugins;
+
+ String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().plus_file("ios/plugins");
+
+ if (DirAccess::exists(plugins_dir)) {
+ Vector<String> plugins_filenames = list_plugin_config_files(plugins_dir, true);
+
+ if (!plugins_filenames.is_empty()) {
+ Ref<ConfigFile> config_file = memnew(ConfigFile);
+ for (int i = 0; i < plugins_filenames.size(); i++) {
+ PluginConfigIOS config = PluginConfigIOS::load_plugin_config(config_file, plugins_dir.plus_file(plugins_filenames[i]));
+ if (config.valid_config) {
+ loaded_plugins.push_back(config);
+ } else {
+ print_error("Invalid plugin config file " + plugins_filenames[i]);
+ }
+ }
+ }
+ }
+
+ return loaded_plugins;
+ }
+
+ static Vector<PluginConfigIOS> get_enabled_plugins(const Ref<EditorExportPreset> &p_presets) {
+ Vector<PluginConfigIOS> enabled_plugins;
+ Vector<PluginConfigIOS> all_plugins = get_plugins();
+ for (int i = 0; i < all_plugins.size(); i++) {
+ PluginConfigIOS plugin = all_plugins[i];
+ bool enabled = p_presets->get("plugins/" + plugin.name);
+ if (enabled) {
+ enabled_plugins.push_back(plugin);
+ }
+ }
+
+ return enabled_plugins;
+ }
+};
+
+#endif
diff --git a/platform/iphone/plugin/godot_plugin_config.h b/platform/iphone/export/godot_plugin_config.cpp
index f9c5d7e51f..9d0324f41a 100644
--- a/platform/iphone/plugin/godot_plugin_config.h
+++ b/platform/iphone/export/godot_plugin_config.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* godot_plugin_config.h */
+/* godot_plugin_config.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,92 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef GODOT_PLUGIN_CONFIG_H
-#define GODOT_PLUGIN_CONFIG_H
-
-#include "core/error/error_list.h"
-#include "core/io/config_file.h"
-#include "core/string/ustring.h"
-
-/*
- The `config` section and fields are required and defined as follow:
-- **name**: name of the plugin
-- **binary**: path to static `.a` library
-
-The `dependencies` and fields are optional.
-- **linked**: dependencies that should only be linked.
-- **embedded**: dependencies that should be linked and embedded into application.
-- **system**: system dependencies that should be linked.
-- **capabilities**: capabilities that would be used for `UIRequiredDeviceCapabilities` options in Info.plist file.
-- **files**: files that would be copied into application
-
-The `plist` section are optional.
-- **key**: key and value that would be added in Info.plist file.
- */
-
-struct PluginConfigIOS {
- inline static const char *PLUGIN_CONFIG_EXT = ".gdip";
-
- inline static const char *CONFIG_SECTION = "config";
- inline static const char *CONFIG_NAME_KEY = "name";
- inline static const char *CONFIG_BINARY_KEY = "binary";
- inline static const char *CONFIG_INITIALIZE_KEY = "initialization";
- inline static const char *CONFIG_DEINITIALIZE_KEY = "deinitialization";
-
- inline static const char *DEPENDENCIES_SECTION = "dependencies";
- inline static const char *DEPENDENCIES_LINKED_KEY = "linked";
- inline static const char *DEPENDENCIES_EMBEDDED_KEY = "embedded";
- inline static const char *DEPENDENCIES_SYSTEM_KEY = "system";
- inline static const char *DEPENDENCIES_CAPABILITIES_KEY = "capabilities";
- inline static const char *DEPENDENCIES_FILES_KEY = "files";
- inline static const char *DEPENDENCIES_LINKER_FLAGS = "linker_flags";
-
- inline static const char *PLIST_SECTION = "plist";
-
- enum PlistItemType {
- UNKNOWN,
- STRING,
- INTEGER,
- BOOLEAN,
- RAW,
- STRING_INPUT,
- };
-
- struct PlistItem {
- PlistItemType type;
- String value;
- };
-
- // Set to true when the config file is properly loaded.
- bool valid_config = false;
- bool supports_targets = false;
- // Unix timestamp of last change to this plugin.
- uint64_t last_updated = 0;
-
- // Required config section
- String name;
- String binary;
- String initialization_method;
- String deinitialization_method;
-
- // Optional dependencies section
- Vector<String> linked_dependencies;
- Vector<String> embedded_dependencies;
- Vector<String> system_dependencies;
-
- Vector<String> files_to_copy;
- Vector<String> capabilities;
-
- Vector<String> linker_flags;
-
- // Optional plist section
- // String value is default value.
- // Currently supports `string`, `boolean`, `integer`, `raw`, `string_input` types
- // <name>:<type> = <value>
- HashMap<String, PlistItem> plist;
-};
-
-static inline String resolve_local_dependency_path(String plugin_config_dir, String dependency_path) {
+#include "godot_plugin_config.h"
+
+#include "core/config/project_settings.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
+
+String PluginConfigIOS::resolve_local_dependency_path(String plugin_config_dir, String dependency_path) {
String absolute_path;
if (dependency_path.is_empty()) {
@@ -130,7 +51,7 @@ static inline String resolve_local_dependency_path(String plugin_config_dir, Str
return absolute_path.replace(res_path, "res://");
}
-static inline String resolve_system_dependency_path(String dependency_path) {
+String PluginConfigIOS::resolve_system_dependency_path(String dependency_path) {
String absolute_path;
if (dependency_path.is_empty()) {
@@ -146,7 +67,7 @@ static inline String resolve_system_dependency_path(String dependency_path) {
return system_path.plus_file(dependency_path);
}
-static inline Vector<String> resolve_local_dependencies(String plugin_config_dir, Vector<String> p_paths) {
+Vector<String> PluginConfigIOS::resolve_local_dependencies(String plugin_config_dir, Vector<String> p_paths) {
Vector<String> paths;
for (int i = 0; i < p_paths.size(); i++) {
@@ -162,7 +83,7 @@ static inline Vector<String> resolve_local_dependencies(String plugin_config_dir
return paths;
}
-static inline Vector<String> resolve_system_dependencies(Vector<String> p_paths) {
+Vector<String> PluginConfigIOS::resolve_system_dependencies(Vector<String> p_paths) {
Vector<String> paths;
for (int i = 0; i < p_paths.size(); i++) {
@@ -178,7 +99,7 @@ static inline Vector<String> resolve_system_dependencies(Vector<String> p_paths)
return paths;
}
-static inline bool validate_plugin(PluginConfigIOS &plugin_config) {
+bool PluginConfigIOS::validate_plugin(PluginConfigIOS &plugin_config) {
bool valid_name = !plugin_config.name.is_empty();
bool valid_binary_name = !plugin_config.binary.is_empty();
bool valid_initialize = !plugin_config.initialization_method.is_empty();
@@ -213,7 +134,7 @@ static inline bool validate_plugin(PluginConfigIOS &plugin_config) {
return plugin_config.valid_config;
}
-static inline String get_plugin_main_binary(PluginConfigIOS &plugin_config, bool p_debug) {
+String PluginConfigIOS::get_plugin_main_binary(PluginConfigIOS &plugin_config, bool p_debug) {
if (!plugin_config.supports_targets) {
return plugin_config.binary;
}
@@ -226,7 +147,7 @@ static inline String get_plugin_main_binary(PluginConfigIOS &plugin_config, bool
return plugin_binary_dir.plus_file(plugin_file);
}
-static inline uint64_t get_plugin_modification_time(const PluginConfigIOS &plugin_config, const String &config_path) {
+uint64_t PluginConfigIOS::get_plugin_modification_time(const PluginConfigIOS &plugin_config, const String &config_path) {
uint64_t last_updated = FileAccess::get_modified_time(config_path);
if (!plugin_config.supports_targets) {
@@ -245,7 +166,7 @@ static inline uint64_t get_plugin_modification_time(const PluginConfigIOS &plugi
return last_updated;
}
-static inline PluginConfigIOS load_plugin_config(Ref<ConfigFile> config_file, const String &path) {
+PluginConfigIOS PluginConfigIOS::load_plugin_config(Ref<ConfigFile> config_file, const String &path) {
PluginConfigIOS plugin_config = {};
if (!config_file.is_valid()) {
@@ -362,5 +283,3 @@ static inline PluginConfigIOS load_plugin_config(Ref<ConfigFile> config_file, co
return plugin_config;
}
-
-#endif // GODOT_PLUGIN_CONFIG_H
diff --git a/platform/iphone/export/godot_plugin_config.h b/platform/iphone/export/godot_plugin_config.h
new file mode 100644
index 0000000000..1add281627
--- /dev/null
+++ b/platform/iphone/export/godot_plugin_config.h
@@ -0,0 +1,132 @@
+/*************************************************************************/
+/* godot_plugin_config.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef IPHONE_GODOT_PLUGIN_CONFIG_H
+#define IPHONE_GODOT_PLUGIN_CONFIG_H
+
+#include "core/error/error_list.h"
+#include "core/io/config_file.h"
+#include "core/string/ustring.h"
+
+/*
+ The `config` section and fields are required and defined as follow:
+- **name**: name of the plugin
+- **binary**: path to static `.a` library
+
+The `dependencies` and fields are optional.
+- **linked**: dependencies that should only be linked.
+- **embedded**: dependencies that should be linked and embedded into application.
+- **system**: system dependencies that should be linked.
+- **capabilities**: capabilities that would be used for `UIRequiredDeviceCapabilities` options in Info.plist file.
+- **files**: files that would be copied into application
+
+The `plist` section are optional.
+- **key**: key and value that would be added in Info.plist file.
+ */
+
+struct PluginConfigIOS {
+ inline static const char *PLUGIN_CONFIG_EXT = ".gdip";
+
+ inline static const char *CONFIG_SECTION = "config";
+ inline static const char *CONFIG_NAME_KEY = "name";
+ inline static const char *CONFIG_BINARY_KEY = "binary";
+ inline static const char *CONFIG_INITIALIZE_KEY = "initialization";
+ inline static const char *CONFIG_DEINITIALIZE_KEY = "deinitialization";
+
+ inline static const char *DEPENDENCIES_SECTION = "dependencies";
+ inline static const char *DEPENDENCIES_LINKED_KEY = "linked";
+ inline static const char *DEPENDENCIES_EMBEDDED_KEY = "embedded";
+ inline static const char *DEPENDENCIES_SYSTEM_KEY = "system";
+ inline static const char *DEPENDENCIES_CAPABILITIES_KEY = "capabilities";
+ inline static const char *DEPENDENCIES_FILES_KEY = "files";
+ inline static const char *DEPENDENCIES_LINKER_FLAGS = "linker_flags";
+
+ inline static const char *PLIST_SECTION = "plist";
+
+ enum PlistItemType {
+ UNKNOWN,
+ STRING,
+ INTEGER,
+ BOOLEAN,
+ RAW,
+ STRING_INPUT,
+ };
+
+ struct PlistItem {
+ PlistItemType type;
+ String value;
+ };
+
+ // Set to true when the config file is properly loaded.
+ bool valid_config = false;
+ bool supports_targets = false;
+ // Unix timestamp of last change to this plugin.
+ uint64_t last_updated = 0;
+
+ // Required config section
+ String name;
+ String binary;
+ String initialization_method;
+ String deinitialization_method;
+
+ // Optional dependencies section
+ Vector<String> linked_dependencies;
+ Vector<String> embedded_dependencies;
+ Vector<String> system_dependencies;
+
+ Vector<String> files_to_copy;
+ Vector<String> capabilities;
+
+ Vector<String> linker_flags;
+
+ // Optional plist section
+ // String value is default value.
+ // Currently supports `string`, `boolean`, `integer`, `raw`, `string_input` types
+ // <name>:<type> = <value>
+ HashMap<String, PlistItem> plist;
+
+ static String resolve_local_dependency_path(String plugin_config_dir, String dependency_path);
+
+ static String resolve_system_dependency_path(String dependency_path);
+
+ static Vector<String> resolve_local_dependencies(String plugin_config_dir, Vector<String> p_paths);
+
+ static Vector<String> resolve_system_dependencies(Vector<String> p_paths);
+
+ static bool validate_plugin(PluginConfigIOS &plugin_config);
+
+ static String get_plugin_main_binary(PluginConfigIOS &plugin_config, bool p_debug);
+
+ static uint64_t get_plugin_modification_time(const PluginConfigIOS &plugin_config, const String &config_path);
+
+ static PluginConfigIOS load_plugin_config(Ref<ConfigFile> config_file, const String &path);
+};
+
+#endif // GODOT_PLUGIN_CONFIG_H
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index bf4244eda4..889b0bbd02 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -28,971 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "core/io/image_loader.h"
-#include "core/io/stream_peer_ssl.h"
-#include "core/io/tcp_server.h"
-#include "core/io/zip_io.h"
-#include "editor/editor_export.h"
-#include "editor/editor_node.h"
-#include "main/splash.gen.h"
-#include "platform/javascript/logo.gen.h"
-#include "platform/javascript/run_icon.gen.h"
+#include "export.h"
-class EditorHTTPServer : public RefCounted {
-private:
- Ref<TCPServer> server;
- Map<String, String> mimes;
- Ref<StreamPeerTCP> tcp;
- Ref<StreamPeerSSL> ssl;
- Ref<StreamPeer> peer;
- Ref<CryptoKey> key;
- Ref<X509Certificate> cert;
- bool use_ssl = false;
- uint64_t time = 0;
- uint8_t req_buf[4096];
- int req_pos = 0;
-
- void _clear_client() {
- peer = Ref<StreamPeer>();
- ssl = Ref<StreamPeerSSL>();
- tcp = Ref<StreamPeerTCP>();
- memset(req_buf, 0, sizeof(req_buf));
- time = 0;
- req_pos = 0;
- }
-
- void _set_internal_certs(Ref<Crypto> p_crypto) {
- const String cache_path = EditorPaths::get_singleton()->get_cache_dir();
- const String key_path = cache_path.plus_file("html5_server.key");
- const String crt_path = cache_path.plus_file("html5_server.crt");
- bool regen = !FileAccess::exists(key_path) || !FileAccess::exists(crt_path);
- if (!regen) {
- key = Ref<CryptoKey>(CryptoKey::create());
- cert = Ref<X509Certificate>(X509Certificate::create());
- if (key->load(key_path) != OK || cert->load(crt_path) != OK) {
- regen = true;
- }
- }
- if (regen) {
- key = p_crypto->generate_rsa(2048);
- key->save(key_path);
- cert = p_crypto->generate_self_signed_certificate(key, "CN=godot-debug.local,O=A Game Dev,C=XXA", "20140101000000", "20340101000000");
- cert->save(crt_path);
- }
- }
-
-public:
- EditorHTTPServer() {
- mimes["html"] = "text/html";
- mimes["js"] = "application/javascript";
- mimes["json"] = "application/json";
- mimes["pck"] = "application/octet-stream";
- mimes["png"] = "image/png";
- mimes["svg"] = "image/svg";
- mimes["wasm"] = "application/wasm";
- server.instantiate();
- stop();
- }
-
- void stop() {
- server->stop();
- _clear_client();
- }
-
- Error listen(int p_port, IPAddress p_address, bool p_use_ssl, String p_ssl_key, String p_ssl_cert) {
- use_ssl = p_use_ssl;
- if (use_ssl) {
- Ref<Crypto> crypto = Crypto::create();
- if (crypto.is_null()) {
- return ERR_UNAVAILABLE;
- }
- if (!p_ssl_key.is_empty() && !p_ssl_cert.is_empty()) {
- key = Ref<CryptoKey>(CryptoKey::create());
- Error err = key->load(p_ssl_key);
- ERR_FAIL_COND_V(err != OK, err);
- cert = Ref<X509Certificate>(X509Certificate::create());
- err = cert->load(p_ssl_cert);
- ERR_FAIL_COND_V(err != OK, err);
- } else {
- _set_internal_certs(crypto);
- }
- }
- return server->listen(p_port, p_address);
- }
-
- bool is_listening() const {
- return server->is_listening();
- }
-
- void _send_response() {
- Vector<String> psa = String((char *)req_buf).split("\r\n");
- int len = psa.size();
- ERR_FAIL_COND_MSG(len < 4, "Not enough response headers, got: " + itos(len) + ", expected >= 4.");
-
- Vector<String> req = psa[0].split(" ", false);
- ERR_FAIL_COND_MSG(req.size() < 2, "Invalid protocol or status code.");
-
- // Wrong protocol
- ERR_FAIL_COND_MSG(req[0] != "GET" || req[2] != "HTTP/1.1", "Invalid method or HTTP version.");
-
- const int query_index = req[1].find_char('?');
- const String path = (query_index == -1) ? req[1] : req[1].substr(0, query_index);
-
- const String req_file = path.get_file();
- const String req_ext = path.get_extension();
- const String cache_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("web");
- const String filepath = cache_path.plus_file(req_file);
-
- if (!mimes.has(req_ext) || !FileAccess::exists(filepath)) {
- String s = "HTTP/1.1 404 Not Found\r\n";
- s += "Connection: Close\r\n";
- s += "\r\n";
- CharString cs = s.utf8();
- peer->put_data((const uint8_t *)cs.get_data(), cs.size() - 1);
- return;
- }
- const String ctype = mimes[req_ext];
-
- FileAccess *f = FileAccess::open(filepath, FileAccess::READ);
- ERR_FAIL_COND(!f);
- String s = "HTTP/1.1 200 OK\r\n";
- s += "Connection: Close\r\n";
- s += "Content-Type: " + ctype + "\r\n";
- s += "Access-Control-Allow-Origin: *\r\n";
- s += "Cross-Origin-Opener-Policy: same-origin\r\n";
- s += "Cross-Origin-Embedder-Policy: require-corp\r\n";
- s += "Cache-Control: no-store, max-age=0\r\n";
- s += "\r\n";
- CharString cs = s.utf8();
- Error err = peer->put_data((const uint8_t *)cs.get_data(), cs.size() - 1);
- if (err != OK) {
- memdelete(f);
- ERR_FAIL();
- }
-
- while (true) {
- uint8_t bytes[4096];
- uint64_t read = f->get_buffer(bytes, 4096);
- if (read == 0) {
- break;
- }
- err = peer->put_data(bytes, read);
- if (err != OK) {
- memdelete(f);
- ERR_FAIL();
- }
- }
- memdelete(f);
- }
-
- void poll() {
- if (!server->is_listening()) {
- return;
- }
- if (tcp.is_null()) {
- if (!server->is_connection_available()) {
- return;
- }
- tcp = server->take_connection();
- peer = tcp;
- time = OS::get_singleton()->get_ticks_usec();
- }
- if (OS::get_singleton()->get_ticks_usec() - time > 1000000) {
- _clear_client();
- return;
- }
- if (tcp->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
- return;
- }
-
- if (use_ssl) {
- if (ssl.is_null()) {
- ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create());
- peer = ssl;
- ssl->set_blocking_handshake_enabled(false);
- if (ssl->accept_stream(tcp, key, cert) != OK) {
- _clear_client();
- return;
- }
- }
- ssl->poll();
- if (ssl->get_status() == StreamPeerSSL::STATUS_HANDSHAKING) {
- // Still handshaking, keep waiting.
- return;
- }
- if (ssl->get_status() != StreamPeerSSL::STATUS_CONNECTED) {
- _clear_client();
- return;
- }
- }
-
- while (true) {
- char *r = (char *)req_buf;
- int l = req_pos - 1;
- if (l > 3 && r[l] == '\n' && r[l - 1] == '\r' && r[l - 2] == '\n' && r[l - 3] == '\r') {
- _send_response();
- _clear_client();
- return;
- }
-
- int read = 0;
- ERR_FAIL_COND(req_pos >= 4096);
- Error err = peer->get_partial_data(&req_buf[req_pos], 1, read);
- if (err != OK) {
- // Got an error
- _clear_client();
- return;
- } else if (read != 1) {
- // Busy, wait next poll
- return;
- }
- req_pos += read;
- }
- }
-};
-
-class EditorExportPlatformJavaScript : public EditorExportPlatform {
- GDCLASS(EditorExportPlatformJavaScript, EditorExportPlatform);
-
- Ref<ImageTexture> logo;
- Ref<ImageTexture> run_icon;
- Ref<ImageTexture> stop_icon;
- int menu_options = 0;
-
- Ref<EditorHTTPServer> server;
- bool server_quit = false;
- Mutex server_lock;
- Thread server_thread;
-
- enum ExportMode {
- EXPORT_MODE_NORMAL = 0,
- EXPORT_MODE_THREADS = 1,
- EXPORT_MODE_GDNATIVE = 2,
- };
-
- String _get_template_name(ExportMode p_mode, bool p_debug) const {
- String name = "webassembly";
- switch (p_mode) {
- case EXPORT_MODE_THREADS:
- name += "_threads";
- break;
- case EXPORT_MODE_GDNATIVE:
- name += "_gdnative";
- break;
- default:
- break;
- }
- if (p_debug) {
- name += "_debug.zip";
- } else {
- name += "_release.zip";
- }
- return name;
- }
-
- Ref<Image> _get_project_icon() const {
- Ref<Image> icon;
- icon.instantiate();
- const String icon_path = String(GLOBAL_GET("application/config/icon")).strip_edges();
- if (icon_path.is_empty() || ImageLoader::load_image(icon_path, icon) != OK) {
- return EditorNode::get_singleton()->get_editor_theme()->get_icon("DefaultProjectIcon", "EditorIcons")->get_image();
- }
- return icon;
- }
-
- Ref<Image> _get_project_splash() const {
- Ref<Image> splash;
- splash.instantiate();
- const String splash_path = String(GLOBAL_GET("application/boot_splash/image")).strip_edges();
- if (splash_path.is_empty() || ImageLoader::load_image(splash_path, splash) != OK) {
- return Ref<Image>(memnew(Image(boot_splash_png)));
- }
- return splash;
- }
-
- Error _extract_template(const String &p_template, const String &p_dir, const String &p_name, bool pwa);
- void _replace_strings(Map<String, String> p_replaces, Vector<uint8_t> &r_template);
- void _fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects, const Dictionary &p_file_sizes);
- Error _add_manifest_icon(const String &p_path, const String &p_icon, int p_size, Array &r_arr);
- Error _build_pwa(const Ref<EditorExportPreset> &p_preset, const String p_path, const Vector<SharedObject> &p_shared_objects);
- Error _write_or_error(const uint8_t *p_content, int p_len, String p_path);
-
- static void _server_thread_poll(void *data);
-
-public:
- virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) override;
-
- virtual void get_export_options(List<ExportOption> *r_options) override;
-
- virtual String get_name() const override;
- virtual String get_os_name() const override;
- virtual Ref<Texture2D> get_logo() const override;
-
- virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
- virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
- virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
-
- virtual bool poll_export() override;
- virtual int get_options_count() const override;
- virtual String get_option_label(int p_index) const override { return p_index ? TTR("Stop HTTP Server") : TTR("Run in Browser"); }
- virtual String get_option_tooltip(int p_index) const override { return p_index ? TTR("Stop HTTP Server") : TTR("Run exported HTML in the system's default browser."); }
- virtual Ref<ImageTexture> get_option_icon(int p_index) const override;
- virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_option, int p_debug_flags) override;
- virtual Ref<Texture2D> get_run_icon() const override;
-
- virtual void get_platform_features(List<String> *r_features) override {
- r_features->push_back("web");
- r_features->push_back(get_os_name());
- }
-
- virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) override {
- }
-
- String get_debug_protocol() const override { return "ws://"; }
-
- EditorExportPlatformJavaScript();
- ~EditorExportPlatformJavaScript();
-};
-
-Error EditorExportPlatformJavaScript::_extract_template(const String &p_template, const String &p_dir, const String &p_name, bool pwa) {
- FileAccess *src_f = nullptr;
- zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
- unzFile pkg = unzOpen2(p_template.utf8().get_data(), &io);
-
- if (!pkg) {
- EditorNode::get_singleton()->show_warning(TTR("Could not open template for export:") + "\n" + p_template);
- return ERR_FILE_NOT_FOUND;
- }
-
- if (unzGoToFirstFile(pkg) != UNZ_OK) {
- EditorNode::get_singleton()->show_warning(TTR("Invalid export template:") + "\n" + p_template);
- unzClose(pkg);
- return ERR_FILE_CORRUPT;
- }
-
- do {
- //get filename
- unz_file_info info;
- char fname[16384];
- unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
-
- String file = fname;
-
- // Skip service worker and offline page if not exporting pwa.
- if (!pwa && (file == "godot.service.worker.js" || file == "godot.offline.html")) {
- continue;
- }
- Vector<uint8_t> data;
- data.resize(info.uncompressed_size);
-
- //read
- unzOpenCurrentFile(pkg);
- unzReadCurrentFile(pkg, data.ptrw(), data.size());
- unzCloseCurrentFile(pkg);
-
- //write
- String dst = p_dir.plus_file(file.replace("godot", p_name));
- FileAccess *f = FileAccess::open(dst, FileAccess::WRITE);
- if (!f) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + dst);
- unzClose(pkg);
- return ERR_FILE_CANT_WRITE;
- }
- f->store_buffer(data.ptr(), data.size());
- memdelete(f);
-
- } while (unzGoToNextFile(pkg) == UNZ_OK);
- unzClose(pkg);
- return OK;
-}
-
-Error EditorExportPlatformJavaScript::_write_or_error(const uint8_t *p_content, int p_size, String p_path) {
- FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE);
- if (!f) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + p_path);
- return ERR_FILE_CANT_WRITE;
- }
- f->store_buffer(p_content, p_size);
- memdelete(f);
- return OK;
-}
-
-void EditorExportPlatformJavaScript::_replace_strings(Map<String, String> p_replaces, Vector<uint8_t> &r_template) {
- String str_template = String::utf8(reinterpret_cast<const char *>(r_template.ptr()), r_template.size());
- String out;
- Vector<String> lines = str_template.split("\n");
- for (int i = 0; i < lines.size(); i++) {
- String current_line = lines[i];
- for (Map<String, String>::Element *E = p_replaces.front(); E; E = E->next()) {
- current_line = current_line.replace(E->key(), E->get());
- }
- out += current_line + "\n";
- }
- CharString cs = out.utf8();
- r_template.resize(cs.length());
- for (int i = 0; i < cs.length(); i++) {
- r_template.write[i] = cs[i];
- }
-}
-
-void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects, const Dictionary &p_file_sizes) {
- // Engine.js config
- Dictionary config;
- Array libs;
- for (int i = 0; i < p_shared_objects.size(); i++) {
- libs.push_back(p_shared_objects[i].path.get_file());
- }
- Vector<String> flags;
- gen_export_flags(flags, p_flags & (~DEBUG_FLAG_DUMB_CLIENT));
- Array args;
- for (int i = 0; i < flags.size(); i++) {
- args.push_back(flags[i]);
- }
- config["canvasResizePolicy"] = p_preset->get("html/canvas_resize_policy");
- config["experimentalVK"] = p_preset->get("html/experimental_virtual_keyboard");
- config["focusCanvas"] = p_preset->get("html/focus_canvas_on_start");
- config["gdnativeLibs"] = libs;
- config["executable"] = p_name;
- config["args"] = args;
- config["fileSizes"] = p_file_sizes;
-
- String head_include;
- if (p_preset->get("html/export_icon")) {
- head_include += "<link id='-gd-engine-icon' rel='icon' type='image/png' href='" + p_name + ".icon.png' />\n";
- head_include += "<link rel='apple-touch-icon' href='" + p_name + ".apple-touch-icon.png'/>\n";
- }
- if (p_preset->get("progressive_web_app/enabled")) {
- head_include += "<link rel='manifest' href='" + p_name + ".manifest.json'>\n";
- head_include += "<script type='application/javascript'>window.addEventListener('load', () => {if ('serviceWorker' in navigator) {navigator.serviceWorker.register('" +
- p_name + ".service.worker.js');}});</script>\n";
- }
-
- // Replaces HTML string
- const String str_config = Variant(config).to_json_string();
- const String custom_head_include = p_preset->get("html/head_include");
- Map<String, String> replaces;
- replaces["$GODOT_URL"] = p_name + ".js";
- replaces["$GODOT_PROJECT_NAME"] = ProjectSettings::get_singleton()->get_setting("application/config/name");
- replaces["$GODOT_HEAD_INCLUDE"] = head_include + custom_head_include;
- replaces["$GODOT_CONFIG"] = str_config;
- _replace_strings(replaces, p_html);
-}
-
-Error EditorExportPlatformJavaScript::_add_manifest_icon(const String &p_path, const String &p_icon, int p_size, Array &r_arr) {
- const String name = p_path.get_file().get_basename();
- const String icon_name = vformat("%s.%dx%d.png", name, p_size, p_size);
- const String icon_dest = p_path.get_base_dir().plus_file(icon_name);
-
- Ref<Image> icon;
- if (!p_icon.is_empty()) {
- icon.instantiate();
- const Error err = ImageLoader::load_image(p_icon, icon);
- if (err != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Could not read file:") + "\n" + p_icon);
- return err;
- }
- if (icon->get_width() != p_size || icon->get_height() != p_size) {
- icon->resize(p_size, p_size);
- }
- } else {
- icon = _get_project_icon();
- icon->resize(p_size, p_size);
- }
- const Error err = icon->save_png(icon_dest);
- if (err != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + icon_dest);
- return err;
- }
- Dictionary icon_dict;
- icon_dict["sizes"] = vformat("%dx%d", p_size, p_size);
- icon_dict["type"] = "image/png";
- icon_dict["src"] = icon_name;
- r_arr.push_back(icon_dict);
- return err;
-}
-
-Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &p_preset, const String p_path, const Vector<SharedObject> &p_shared_objects) {
- // Service worker
- const String dir = p_path.get_base_dir();
- const String name = p_path.get_file().get_basename();
- const ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
- Map<String, String> replaces;
- replaces["@GODOT_VERSION@"] = "1";
- replaces["@GODOT_NAME@"] = name;
- replaces["@GODOT_OFFLINE_PAGE@"] = name + ".offline.html";
- Array files;
- replaces["@GODOT_OPT_CACHE@"] = Variant(files).to_json_string();
- files.push_back(name + ".html");
- files.push_back(name + ".js");
- files.push_back(name + ".wasm");
- files.push_back(name + ".pck");
- files.push_back(name + ".offline.html");
- if (p_preset->get("html/export_icon")) {
- files.push_back(name + ".icon.png");
- files.push_back(name + ".apple-touch-icon.png");
- }
- if (mode == EXPORT_MODE_THREADS) {
- files.push_back(name + ".worker.js");
- files.push_back(name + ".audio.worklet.js");
- } else if (mode == EXPORT_MODE_GDNATIVE) {
- files.push_back(name + ".side.wasm");
- for (int i = 0; i < p_shared_objects.size(); i++) {
- files.push_back(p_shared_objects[i].path.get_file());
- }
- }
- replaces["@GODOT_CACHE@"] = Variant(files).to_json_string();
-
- const String sw_path = dir.plus_file(name + ".service.worker.js");
- Vector<uint8_t> sw;
- {
- FileAccess *f = FileAccess::open(sw_path, FileAccess::READ);
- if (!f) {
- EditorNode::get_singleton()->show_warning(TTR("Could not read file:") + "\n" + sw_path);
- return ERR_FILE_CANT_READ;
- }
- sw.resize(f->get_length());
- f->get_buffer(sw.ptrw(), sw.size());
- memdelete(f);
- f = nullptr;
- }
- _replace_strings(replaces, sw);
- Error err = _write_or_error(sw.ptr(), sw.size(), dir.plus_file(name + ".service.worker.js"));
- if (err != OK) {
- return err;
- }
-
- // Custom offline page
- const String offline_page = p_preset->get("progressive_web_app/offline_page");
- if (!offline_page.is_empty()) {
- DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- const String offline_dest = dir.plus_file(name + ".offline.html");
- err = da->copy(ProjectSettings::get_singleton()->globalize_path(offline_page), offline_dest);
- if (err != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Could not read file:") + "\n" + offline_dest);
- return err;
- }
- }
-
- // Manifest
- const char *modes[4] = { "fullscreen", "standalone", "minimal-ui", "browser" };
- const char *orientations[3] = { "any", "landscape", "portrait" };
- const int display = CLAMP(int(p_preset->get("progressive_web_app/display")), 0, 4);
- const int orientation = CLAMP(int(p_preset->get("progressive_web_app/orientation")), 0, 3);
-
- Dictionary manifest;
- String proj_name = ProjectSettings::get_singleton()->get_setting("application/config/name");
- if (proj_name.is_empty()) {
- proj_name = "Godot Game";
- }
- manifest["name"] = proj_name;
- manifest["start_url"] = "./" + name + ".html";
- manifest["display"] = String::utf8(modes[display]);
- manifest["orientation"] = String::utf8(orientations[orientation]);
- manifest["background_color"] = "#" + p_preset->get("progressive_web_app/background_color").operator Color().to_html(false);
-
- Array icons_arr;
- const String icon144_path = p_preset->get("progressive_web_app/icon_144x144");
- err = _add_manifest_icon(p_path, icon144_path, 144, icons_arr);
- if (err != OK) {
- return err;
- }
- const String icon180_path = p_preset->get("progressive_web_app/icon_180x180");
- err = _add_manifest_icon(p_path, icon180_path, 180, icons_arr);
- if (err != OK) {
- return err;
- }
- const String icon512_path = p_preset->get("progressive_web_app/icon_512x512");
- err = _add_manifest_icon(p_path, icon512_path, 512, icons_arr);
- if (err != OK) {
- return err;
- }
- manifest["icons"] = icons_arr;
-
- CharString cs = Variant(manifest).to_json_string().utf8();
- err = _write_or_error((const uint8_t *)cs.get_data(), cs.length(), dir.plus_file(name + ".manifest.json"));
- if (err != OK) {
- return err;
- }
-
- return OK;
-}
-
-void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
- if (p_preset->get("vram_texture_compression/for_desktop")) {
- r_features->push_back("s3tc");
- }
-
- if (p_preset->get("vram_texture_compression/for_mobile")) {
- String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
- if (driver == "GLES2") {
- r_features->push_back("etc");
- } else if (driver == "Vulkan") {
- // FIXME: Review if this is correct.
- r_features->push_back("etc2");
- }
- }
- ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
- if (mode == EXPORT_MODE_THREADS) {
- r_features->push_back("threads");
- } else if (mode == EXPORT_MODE_GDNATIVE) {
- r_features->push_back("wasm32");
- }
-}
-
-void EditorExportPlatformJavaScript::get_export_options(List<ExportOption> *r_options) {
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "variant/export_type", PROPERTY_HINT_ENUM, "Regular,Threads,GDNative"), 0)); // Export type.
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_desktop"), true)); // S3TC
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_mobile"), false)); // ETC or ETC2, depending on renderer
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "html/export_icon"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/custom_html_shell", PROPERTY_HINT_FILE, "*.html"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/head_include", PROPERTY_HINT_MULTILINE_TEXT), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "html/canvas_resize_policy", PROPERTY_HINT_ENUM, "None,Project,Adaptive"), 2));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "html/focus_canvas_on_start"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "html/experimental_virtual_keyboard"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "progressive_web_app/enabled"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/offline_page", PROPERTY_HINT_FILE, "*.html"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "progressive_web_app/display", PROPERTY_HINT_ENUM, "Fullscreen,Standalone,Minimal UI,Browser"), 1));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "progressive_web_app/orientation", PROPERTY_HINT_ENUM, "Any,Landscape,Portrait"), 0));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/icon_144x144", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg,*.svgz"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/icon_180x180", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg,*.svgz"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/icon_512x512", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg,*.svgz"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "progressive_web_app/background_color", PROPERTY_HINT_COLOR_NO_ALPHA), Color()));
-}
-
-String EditorExportPlatformJavaScript::get_name() const {
- return "HTML5";
-}
-
-String EditorExportPlatformJavaScript::get_os_name() const {
- return "HTML5";
-}
-
-Ref<Texture2D> EditorExportPlatformJavaScript::get_logo() const {
- return logo;
-}
-
-bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
- String err;
- bool valid = false;
- ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
-
- // Look for export templates (first official, and if defined custom templates).
- bool dvalid = exists_export_template(_get_template_name(mode, true), &err);
- bool rvalid = exists_export_template(_get_template_name(mode, false), &err);
-
- if (p_preset->get("custom_template/debug") != "") {
- dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
- if (!dvalid) {
- err += TTR("Custom debug template not found.") + "\n";
- }
- }
- if (p_preset->get("custom_template/release") != "") {
- rvalid = FileAccess::exists(p_preset->get("custom_template/release"));
- if (!rvalid) {
- err += TTR("Custom release template not found.") + "\n";
- }
- }
-
- valid = dvalid || rvalid;
- r_missing_templates = !valid;
-
- // Validate the rest of the configuration.
-
- if (p_preset->get("vram_texture_compression/for_mobile")) {
- String etc_error = test_etc2();
- if (etc_error != String()) {
- valid = false;
- err += etc_error;
- }
- }
-
- if (!err.is_empty()) {
- r_error = err;
- }
-
- return valid;
-}
-
-List<String> EditorExportPlatformJavaScript::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
- List<String> list;
- list.push_back("html");
- return list;
-}
-
-Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
- ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
-
- const String custom_debug = p_preset->get("custom_template/debug");
- const String custom_release = p_preset->get("custom_template/release");
- const String custom_html = p_preset->get("html/custom_html_shell");
- const bool export_icon = p_preset->get("html/export_icon");
- const bool pwa = p_preset->get("progressive_web_app/enabled");
-
- const String base_dir = p_path.get_base_dir();
- const String base_path = p_path.get_basename();
- const String base_name = p_path.get_file().get_basename();
-
- // Find the correct template
- String template_path = p_debug ? custom_debug : custom_release;
- template_path = template_path.strip_edges();
- if (template_path == String()) {
- ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
- template_path = find_export_template(_get_template_name(mode, p_debug));
- }
-
- if (!DirAccess::exists(base_dir)) {
- return ERR_FILE_BAD_PATH;
- }
-
- if (template_path != String() && !FileAccess::exists(template_path)) {
- EditorNode::get_singleton()->show_warning(TTR("Template file not found:") + "\n" + template_path);
- return ERR_FILE_NOT_FOUND;
- }
-
- // Export pck and shared objects
- Vector<SharedObject> shared_objects;
- String pck_path = base_path + ".pck";
- Error error = save_pack(p_preset, pck_path, &shared_objects);
- if (error != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + pck_path);
- return error;
- }
- DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- for (int i = 0; i < shared_objects.size(); i++) {
- String dst = base_dir.plus_file(shared_objects[i].path.get_file());
- error = da->copy(shared_objects[i].path, dst);
- if (error != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + shared_objects[i].path.get_file());
- memdelete(da);
- return error;
- }
- }
- memdelete(da);
- da = nullptr;
-
- // Extract templates.
- error = _extract_template(template_path, base_dir, base_name, pwa);
- if (error) {
- return error;
- }
-
- // Parse generated file sizes (pck and wasm, to help show a meaningful loading bar).
- Dictionary file_sizes;
- FileAccess *f = nullptr;
- f = FileAccess::open(pck_path, FileAccess::READ);
- if (f) {
- file_sizes[pck_path.get_file()] = (uint64_t)f->get_length();
- memdelete(f);
- f = nullptr;
- }
- f = FileAccess::open(base_path + ".wasm", FileAccess::READ);
- if (f) {
- file_sizes[base_name + ".wasm"] = (uint64_t)f->get_length();
- memdelete(f);
- f = nullptr;
- }
-
- // Read the HTML shell file (custom or from template).
- const String html_path = custom_html.is_empty() ? base_path + ".html" : custom_html;
- Vector<uint8_t> html;
- f = FileAccess::open(html_path, FileAccess::READ);
- if (!f) {
- EditorNode::get_singleton()->show_warning(TTR("Could not read HTML shell:") + "\n" + html_path);
- return ERR_FILE_CANT_READ;
- }
- html.resize(f->get_length());
- f->get_buffer(html.ptrw(), html.size());
- memdelete(f);
- f = nullptr;
-
- // Generate HTML file with replaced strings.
- _fix_html(html, p_preset, base_name, p_debug, p_flags, shared_objects, file_sizes);
- Error err = _write_or_error(html.ptr(), html.size(), p_path);
- if (err != OK) {
- return err;
- }
- html.resize(0);
-
- // Export splash (why?)
- Ref<Image> splash = _get_project_splash();
- const String splash_png_path = base_path + ".png";
- if (splash->save_png(splash_png_path) != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + splash_png_path);
- return ERR_FILE_CANT_WRITE;
- }
-
- // Save a favicon that can be accessed without waiting for the project to finish loading.
- // This way, the favicon can be displayed immediately when loading the page.
- if (export_icon) {
- Ref<Image> favicon = _get_project_icon();
- const String favicon_png_path = base_path + ".icon.png";
- if (favicon->save_png(favicon_png_path) != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + favicon_png_path);
- return ERR_FILE_CANT_WRITE;
- }
- favicon->resize(180, 180);
- const String apple_icon_png_path = base_path + ".apple-touch-icon.png";
- if (favicon->save_png(apple_icon_png_path) != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + apple_icon_png_path);
- return ERR_FILE_CANT_WRITE;
- }
- }
-
- // Generate the PWA worker and manifest
- if (pwa) {
- err = _build_pwa(p_preset, p_path, shared_objects);
- if (err != OK) {
- return err;
- }
- }
-
- return OK;
-}
-
-bool EditorExportPlatformJavaScript::poll_export() {
- Ref<EditorExportPreset> preset;
-
- for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
- Ref<EditorExportPreset> ep = EditorExport::get_singleton()->get_export_preset(i);
- if (ep->is_runnable() && ep->get_platform() == this) {
- preset = ep;
- break;
- }
- }
-
- int prev = menu_options;
- menu_options = preset.is_valid();
- if (server->is_listening()) {
- if (menu_options == 0) {
- MutexLock lock(server_lock);
- server->stop();
- } else {
- menu_options += 1;
- }
- }
- return menu_options != prev;
-}
-
-Ref<ImageTexture> EditorExportPlatformJavaScript::get_option_icon(int p_index) const {
- return p_index == 1 ? stop_icon : EditorExportPlatform::get_option_icon(p_index);
-}
-
-int EditorExportPlatformJavaScript::get_options_count() const {
- return menu_options;
-}
-
-Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_preset, int p_option, int p_debug_flags) {
- if (p_option == 1) {
- MutexLock lock(server_lock);
- server->stop();
- return OK;
- }
-
- const String dest = EditorPaths::get_singleton()->get_cache_dir().plus_file("web");
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- if (!da->dir_exists(dest)) {
- Error err = da->make_dir_recursive(dest);
- if (err != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Could not create HTTP server directory:") + "\n" + dest);
- return err;
- }
- }
- const String basepath = dest.plus_file("tmp_js_export");
- Error err = export_project(p_preset, true, basepath + ".html", p_debug_flags);
- if (err != OK) {
- // Export generates several files, clean them up on failure.
- DirAccess::remove_file_or_error(basepath + ".html");
- DirAccess::remove_file_or_error(basepath + ".offline.html");
- DirAccess::remove_file_or_error(basepath + ".js");
- DirAccess::remove_file_or_error(basepath + ".worker.js");
- DirAccess::remove_file_or_error(basepath + ".audio.worklet.js");
- DirAccess::remove_file_or_error(basepath + ".service.worker.js");
- DirAccess::remove_file_or_error(basepath + ".pck");
- DirAccess::remove_file_or_error(basepath + ".png");
- DirAccess::remove_file_or_error(basepath + ".side.wasm");
- DirAccess::remove_file_or_error(basepath + ".wasm");
- DirAccess::remove_file_or_error(basepath + ".icon.png");
- DirAccess::remove_file_or_error(basepath + ".apple-touch-icon.png");
- return err;
- }
-
- const uint16_t bind_port = EDITOR_GET("export/web/http_port");
- // Resolve host if needed.
- const String bind_host = EDITOR_GET("export/web/http_host");
- IPAddress bind_ip;
- if (bind_host.is_valid_ip_address()) {
- bind_ip = bind_host;
- } else {
- bind_ip = IP::get_singleton()->resolve_hostname(bind_host);
- }
- ERR_FAIL_COND_V_MSG(!bind_ip.is_valid(), ERR_INVALID_PARAMETER, "Invalid editor setting 'export/web/http_host': '" + bind_host + "'. Try using '127.0.0.1'.");
-
- const bool use_ssl = EDITOR_GET("export/web/use_ssl");
- const String ssl_key = EDITOR_GET("export/web/ssl_key");
- const String ssl_cert = EDITOR_GET("export/web/ssl_certificate");
-
- // Restart server.
- {
- MutexLock lock(server_lock);
-
- server->stop();
- err = server->listen(bind_port, bind_ip, use_ssl, ssl_key, ssl_cert);
- }
- if (err != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Error starting HTTP server:") + "\n" + itos(err));
- return err;
- }
-
- OS::get_singleton()->shell_open(String((use_ssl ? "https://" : "http://") + bind_host + ":" + itos(bind_port) + "/tmp_js_export.html"));
- // FIXME: Find out how to clean up export files after running the successfully
- // exported game. Might not be trivial.
- return OK;
-}
-
-Ref<Texture2D> EditorExportPlatformJavaScript::get_run_icon() const {
- return run_icon;
-}
-
-void EditorExportPlatformJavaScript::_server_thread_poll(void *data) {
- EditorExportPlatformJavaScript *ej = (EditorExportPlatformJavaScript *)data;
- while (!ej->server_quit) {
- OS::get_singleton()->delay_usec(1000);
- {
- MutexLock lock(ej->server_lock);
- ej->server->poll();
- }
- }
-}
-
-EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() {
- server.instantiate();
- server_thread.start(_server_thread_poll, this);
-
- Ref<Image> img = memnew(Image(_javascript_logo));
- logo.instantiate();
- logo->create_from_image(img);
-
- img = Ref<Image>(memnew(Image(_javascript_run_icon)));
- run_icon.instantiate();
- run_icon->create_from_image(img);
-
- Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
- if (theme.is_valid()) {
- stop_icon = theme->get_icon("Stop", "EditorIcons");
- } else {
- stop_icon.instantiate();
- }
-}
-
-EditorExportPlatformJavaScript::~EditorExportPlatformJavaScript() {
- server->stop();
- server_quit = true;
- server_thread.wait_to_finish();
-}
+#include "export_plugin.h"
void register_javascript_exporter() {
EDITOR_DEF("export/web/http_host", "localhost");
diff --git a/platform/javascript/export/export.h b/platform/javascript/export/export.h
index e641339f55..8e8161b547 100644
--- a/platform/javascript/export/export.h
+++ b/platform/javascript/export/export.h
@@ -28,4 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef JAVASCRIPT_EXPORT_H
+#define JAVASCRIPT_EXPORT_H
+
void register_javascript_exporter();
+
+#endif
diff --git a/platform/javascript/export/export_plugin.cpp b/platform/javascript/export/export_plugin.cpp
new file mode 100644
index 0000000000..5d285a6e60
--- /dev/null
+++ b/platform/javascript/export/export_plugin.cpp
@@ -0,0 +1,671 @@
+/*************************************************************************/
+/* export_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "export_plugin.h"
+
+Error EditorExportPlatformJavaScript::_extract_template(const String &p_template, const String &p_dir, const String &p_name, bool pwa) {
+ FileAccess *src_f = nullptr;
+ zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
+ unzFile pkg = unzOpen2(p_template.utf8().get_data(), &io);
+
+ if (!pkg) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not open template for export:") + "\n" + p_template);
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ if (unzGoToFirstFile(pkg) != UNZ_OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Invalid export template:") + "\n" + p_template);
+ unzClose(pkg);
+ return ERR_FILE_CORRUPT;
+ }
+
+ do {
+ //get filename
+ unz_file_info info;
+ char fname[16384];
+ unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
+
+ String file = fname;
+
+ // Skip service worker and offline page if not exporting pwa.
+ if (!pwa && (file == "godot.service.worker.js" || file == "godot.offline.html")) {
+ continue;
+ }
+ Vector<uint8_t> data;
+ data.resize(info.uncompressed_size);
+
+ //read
+ unzOpenCurrentFile(pkg);
+ unzReadCurrentFile(pkg, data.ptrw(), data.size());
+ unzCloseCurrentFile(pkg);
+
+ //write
+ String dst = p_dir.plus_file(file.replace("godot", p_name));
+ FileAccess *f = FileAccess::open(dst, FileAccess::WRITE);
+ if (!f) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + dst);
+ unzClose(pkg);
+ return ERR_FILE_CANT_WRITE;
+ }
+ f->store_buffer(data.ptr(), data.size());
+ memdelete(f);
+
+ } while (unzGoToNextFile(pkg) == UNZ_OK);
+ unzClose(pkg);
+ return OK;
+}
+
+Error EditorExportPlatformJavaScript::_write_or_error(const uint8_t *p_content, int p_size, String p_path) {
+ FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE);
+ if (!f) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + p_path);
+ return ERR_FILE_CANT_WRITE;
+ }
+ f->store_buffer(p_content, p_size);
+ memdelete(f);
+ return OK;
+}
+
+void EditorExportPlatformJavaScript::_replace_strings(Map<String, String> p_replaces, Vector<uint8_t> &r_template) {
+ String str_template = String::utf8(reinterpret_cast<const char *>(r_template.ptr()), r_template.size());
+ String out;
+ Vector<String> lines = str_template.split("\n");
+ for (int i = 0; i < lines.size(); i++) {
+ String current_line = lines[i];
+ for (Map<String, String>::Element *E = p_replaces.front(); E; E = E->next()) {
+ current_line = current_line.replace(E->key(), E->get());
+ }
+ out += current_line + "\n";
+ }
+ CharString cs = out.utf8();
+ r_template.resize(cs.length());
+ for (int i = 0; i < cs.length(); i++) {
+ r_template.write[i] = cs[i];
+ }
+}
+
+void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects, const Dictionary &p_file_sizes) {
+ // Engine.js config
+ Dictionary config;
+ Array libs;
+ for (int i = 0; i < p_shared_objects.size(); i++) {
+ libs.push_back(p_shared_objects[i].path.get_file());
+ }
+ Vector<String> flags;
+ gen_export_flags(flags, p_flags & (~DEBUG_FLAG_DUMB_CLIENT));
+ Array args;
+ for (int i = 0; i < flags.size(); i++) {
+ args.push_back(flags[i]);
+ }
+ config["canvasResizePolicy"] = p_preset->get("html/canvas_resize_policy");
+ config["experimentalVK"] = p_preset->get("html/experimental_virtual_keyboard");
+ config["focusCanvas"] = p_preset->get("html/focus_canvas_on_start");
+ config["gdnativeLibs"] = libs;
+ config["executable"] = p_name;
+ config["args"] = args;
+ config["fileSizes"] = p_file_sizes;
+
+ String head_include;
+ if (p_preset->get("html/export_icon")) {
+ head_include += "<link id='-gd-engine-icon' rel='icon' type='image/png' href='" + p_name + ".icon.png' />\n";
+ head_include += "<link rel='apple-touch-icon' href='" + p_name + ".apple-touch-icon.png'/>\n";
+ }
+ if (p_preset->get("progressive_web_app/enabled")) {
+ head_include += "<link rel='manifest' href='" + p_name + ".manifest.json'>\n";
+ head_include += "<script type='application/javascript'>window.addEventListener('load', () => {if ('serviceWorker' in navigator) {navigator.serviceWorker.register('" +
+ p_name + ".service.worker.js');}});</script>\n";
+ }
+
+ // Replaces HTML string
+ const String str_config = Variant(config).to_json_string();
+ const String custom_head_include = p_preset->get("html/head_include");
+ Map<String, String> replaces;
+ replaces["$GODOT_URL"] = p_name + ".js";
+ replaces["$GODOT_PROJECT_NAME"] = ProjectSettings::get_singleton()->get_setting("application/config/name");
+ replaces["$GODOT_HEAD_INCLUDE"] = head_include + custom_head_include;
+ replaces["$GODOT_CONFIG"] = str_config;
+ _replace_strings(replaces, p_html);
+}
+
+Error EditorExportPlatformJavaScript::_add_manifest_icon(const String &p_path, const String &p_icon, int p_size, Array &r_arr) {
+ const String name = p_path.get_file().get_basename();
+ const String icon_name = vformat("%s.%dx%d.png", name, p_size, p_size);
+ const String icon_dest = p_path.get_base_dir().plus_file(icon_name);
+
+ Ref<Image> icon;
+ if (!p_icon.is_empty()) {
+ icon.instantiate();
+ const Error err = ImageLoader::load_image(p_icon, icon);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not read file:") + "\n" + p_icon);
+ return err;
+ }
+ if (icon->get_width() != p_size || icon->get_height() != p_size) {
+ icon->resize(p_size, p_size);
+ }
+ } else {
+ icon = _get_project_icon();
+ icon->resize(p_size, p_size);
+ }
+ const Error err = icon->save_png(icon_dest);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + icon_dest);
+ return err;
+ }
+ Dictionary icon_dict;
+ icon_dict["sizes"] = vformat("%dx%d", p_size, p_size);
+ icon_dict["type"] = "image/png";
+ icon_dict["src"] = icon_name;
+ r_arr.push_back(icon_dict);
+ return err;
+}
+
+Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &p_preset, const String p_path, const Vector<SharedObject> &p_shared_objects) {
+ // Service worker
+ const String dir = p_path.get_base_dir();
+ const String name = p_path.get_file().get_basename();
+ const ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
+ Map<String, String> replaces;
+ replaces["@GODOT_VERSION@"] = "1";
+ replaces["@GODOT_NAME@"] = name;
+ replaces["@GODOT_OFFLINE_PAGE@"] = name + ".offline.html";
+ Array files;
+ replaces["@GODOT_OPT_CACHE@"] = Variant(files).to_json_string();
+ files.push_back(name + ".html");
+ files.push_back(name + ".js");
+ files.push_back(name + ".wasm");
+ files.push_back(name + ".pck");
+ files.push_back(name + ".offline.html");
+ if (p_preset->get("html/export_icon")) {
+ files.push_back(name + ".icon.png");
+ files.push_back(name + ".apple-touch-icon.png");
+ }
+ if (mode == EXPORT_MODE_THREADS) {
+ files.push_back(name + ".worker.js");
+ files.push_back(name + ".audio.worklet.js");
+ } else if (mode == EXPORT_MODE_GDNATIVE) {
+ files.push_back(name + ".side.wasm");
+ for (int i = 0; i < p_shared_objects.size(); i++) {
+ files.push_back(p_shared_objects[i].path.get_file());
+ }
+ }
+ replaces["@GODOT_CACHE@"] = Variant(files).to_json_string();
+
+ const String sw_path = dir.plus_file(name + ".service.worker.js");
+ Vector<uint8_t> sw;
+ {
+ FileAccess *f = FileAccess::open(sw_path, FileAccess::READ);
+ if (!f) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not read file:") + "\n" + sw_path);
+ return ERR_FILE_CANT_READ;
+ }
+ sw.resize(f->get_length());
+ f->get_buffer(sw.ptrw(), sw.size());
+ memdelete(f);
+ f = nullptr;
+ }
+ _replace_strings(replaces, sw);
+ Error err = _write_or_error(sw.ptr(), sw.size(), dir.plus_file(name + ".service.worker.js"));
+ if (err != OK) {
+ return err;
+ }
+
+ // Custom offline page
+ const String offline_page = p_preset->get("progressive_web_app/offline_page");
+ if (!offline_page.is_empty()) {
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ const String offline_dest = dir.plus_file(name + ".offline.html");
+ err = da->copy(ProjectSettings::get_singleton()->globalize_path(offline_page), offline_dest);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not read file:") + "\n" + offline_dest);
+ return err;
+ }
+ }
+
+ // Manifest
+ const char *modes[4] = { "fullscreen", "standalone", "minimal-ui", "browser" };
+ const char *orientations[3] = { "any", "landscape", "portrait" };
+ const int display = CLAMP(int(p_preset->get("progressive_web_app/display")), 0, 4);
+ const int orientation = CLAMP(int(p_preset->get("progressive_web_app/orientation")), 0, 3);
+
+ Dictionary manifest;
+ String proj_name = ProjectSettings::get_singleton()->get_setting("application/config/name");
+ if (proj_name.is_empty()) {
+ proj_name = "Godot Game";
+ }
+ manifest["name"] = proj_name;
+ manifest["start_url"] = "./" + name + ".html";
+ manifest["display"] = String::utf8(modes[display]);
+ manifest["orientation"] = String::utf8(orientations[orientation]);
+ manifest["background_color"] = "#" + p_preset->get("progressive_web_app/background_color").operator Color().to_html(false);
+
+ Array icons_arr;
+ const String icon144_path = p_preset->get("progressive_web_app/icon_144x144");
+ err = _add_manifest_icon(p_path, icon144_path, 144, icons_arr);
+ if (err != OK) {
+ return err;
+ }
+ const String icon180_path = p_preset->get("progressive_web_app/icon_180x180");
+ err = _add_manifest_icon(p_path, icon180_path, 180, icons_arr);
+ if (err != OK) {
+ return err;
+ }
+ const String icon512_path = p_preset->get("progressive_web_app/icon_512x512");
+ err = _add_manifest_icon(p_path, icon512_path, 512, icons_arr);
+ if (err != OK) {
+ return err;
+ }
+ manifest["icons"] = icons_arr;
+
+ CharString cs = Variant(manifest).to_json_string().utf8();
+ err = _write_or_error((const uint8_t *)cs.get_data(), cs.length(), dir.plus_file(name + ".manifest.json"));
+ if (err != OK) {
+ return err;
+ }
+
+ return OK;
+}
+
+void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
+ if (p_preset->get("vram_texture_compression/for_desktop")) {
+ r_features->push_back("s3tc");
+ }
+
+ if (p_preset->get("vram_texture_compression/for_mobile")) {
+ String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
+ if (driver == "GLES2") {
+ r_features->push_back("etc");
+ } else if (driver == "Vulkan") {
+ // FIXME: Review if this is correct.
+ r_features->push_back("etc2");
+ }
+ }
+ ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
+ if (mode == EXPORT_MODE_THREADS) {
+ r_features->push_back("threads");
+ } else if (mode == EXPORT_MODE_GDNATIVE) {
+ r_features->push_back("wasm32");
+ }
+}
+
+void EditorExportPlatformJavaScript::get_export_options(List<ExportOption> *r_options) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "variant/export_type", PROPERTY_HINT_ENUM, "Regular,Threads,GDNative"), 0)); // Export type.
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_desktop"), true)); // S3TC
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_mobile"), false)); // ETC or ETC2, depending on renderer
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "html/export_icon"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/custom_html_shell", PROPERTY_HINT_FILE, "*.html"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/head_include", PROPERTY_HINT_MULTILINE_TEXT), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "html/canvas_resize_policy", PROPERTY_HINT_ENUM, "None,Project,Adaptive"), 2));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "html/focus_canvas_on_start"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "html/experimental_virtual_keyboard"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "progressive_web_app/enabled"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/offline_page", PROPERTY_HINT_FILE, "*.html"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "progressive_web_app/display", PROPERTY_HINT_ENUM, "Fullscreen,Standalone,Minimal UI,Browser"), 1));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "progressive_web_app/orientation", PROPERTY_HINT_ENUM, "Any,Landscape,Portrait"), 0));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/icon_144x144", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg,*.svgz"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/icon_180x180", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg,*.svgz"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/icon_512x512", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg,*.svgz"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "progressive_web_app/background_color", PROPERTY_HINT_COLOR_NO_ALPHA), Color()));
+}
+
+String EditorExportPlatformJavaScript::get_name() const {
+ return "HTML5";
+}
+
+String EditorExportPlatformJavaScript::get_os_name() const {
+ return "HTML5";
+}
+
+Ref<Texture2D> EditorExportPlatformJavaScript::get_logo() const {
+ return logo;
+}
+
+bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+ String err;
+ bool valid = false;
+ ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
+
+ // Look for export templates (first official, and if defined custom templates).
+ bool dvalid = exists_export_template(_get_template_name(mode, true), &err);
+ bool rvalid = exists_export_template(_get_template_name(mode, false), &err);
+
+ if (p_preset->get("custom_template/debug") != "") {
+ dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
+ if (!dvalid) {
+ err += TTR("Custom debug template not found.") + "\n";
+ }
+ }
+ if (p_preset->get("custom_template/release") != "") {
+ rvalid = FileAccess::exists(p_preset->get("custom_template/release"));
+ if (!rvalid) {
+ err += TTR("Custom release template not found.") + "\n";
+ }
+ }
+
+ valid = dvalid || rvalid;
+ r_missing_templates = !valid;
+
+ // Validate the rest of the configuration.
+
+ if (p_preset->get("vram_texture_compression/for_mobile")) {
+ String etc_error = test_etc2();
+ if (etc_error != String()) {
+ valid = false;
+ err += etc_error;
+ }
+ }
+
+ if (!err.is_empty()) {
+ r_error = err;
+ }
+
+ return valid;
+}
+
+List<String> EditorExportPlatformJavaScript::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
+ List<String> list;
+ list.push_back("html");
+ return list;
+}
+
+Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
+ ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
+
+ const String custom_debug = p_preset->get("custom_template/debug");
+ const String custom_release = p_preset->get("custom_template/release");
+ const String custom_html = p_preset->get("html/custom_html_shell");
+ const bool export_icon = p_preset->get("html/export_icon");
+ const bool pwa = p_preset->get("progressive_web_app/enabled");
+
+ const String base_dir = p_path.get_base_dir();
+ const String base_path = p_path.get_basename();
+ const String base_name = p_path.get_file().get_basename();
+
+ // Find the correct template
+ String template_path = p_debug ? custom_debug : custom_release;
+ template_path = template_path.strip_edges();
+ if (template_path == String()) {
+ ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
+ template_path = find_export_template(_get_template_name(mode, p_debug));
+ }
+
+ if (!DirAccess::exists(base_dir)) {
+ return ERR_FILE_BAD_PATH;
+ }
+
+ if (template_path != String() && !FileAccess::exists(template_path)) {
+ EditorNode::get_singleton()->show_warning(TTR("Template file not found:") + "\n" + template_path);
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ // Export pck and shared objects
+ Vector<SharedObject> shared_objects;
+ String pck_path = base_path + ".pck";
+ Error error = save_pack(p_preset, pck_path, &shared_objects);
+ if (error != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + pck_path);
+ return error;
+ }
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ for (int i = 0; i < shared_objects.size(); i++) {
+ String dst = base_dir.plus_file(shared_objects[i].path.get_file());
+ error = da->copy(shared_objects[i].path, dst);
+ if (error != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + shared_objects[i].path.get_file());
+ memdelete(da);
+ return error;
+ }
+ }
+ memdelete(da);
+ da = nullptr;
+
+ // Extract templates.
+ error = _extract_template(template_path, base_dir, base_name, pwa);
+ if (error) {
+ return error;
+ }
+
+ // Parse generated file sizes (pck and wasm, to help show a meaningful loading bar).
+ Dictionary file_sizes;
+ FileAccess *f = nullptr;
+ f = FileAccess::open(pck_path, FileAccess::READ);
+ if (f) {
+ file_sizes[pck_path.get_file()] = (uint64_t)f->get_length();
+ memdelete(f);
+ f = nullptr;
+ }
+ f = FileAccess::open(base_path + ".wasm", FileAccess::READ);
+ if (f) {
+ file_sizes[base_name + ".wasm"] = (uint64_t)f->get_length();
+ memdelete(f);
+ f = nullptr;
+ }
+
+ // Read the HTML shell file (custom or from template).
+ const String html_path = custom_html.is_empty() ? base_path + ".html" : custom_html;
+ Vector<uint8_t> html;
+ f = FileAccess::open(html_path, FileAccess::READ);
+ if (!f) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not read HTML shell:") + "\n" + html_path);
+ return ERR_FILE_CANT_READ;
+ }
+ html.resize(f->get_length());
+ f->get_buffer(html.ptrw(), html.size());
+ memdelete(f);
+ f = nullptr;
+
+ // Generate HTML file with replaced strings.
+ _fix_html(html, p_preset, base_name, p_debug, p_flags, shared_objects, file_sizes);
+ Error err = _write_or_error(html.ptr(), html.size(), p_path);
+ if (err != OK) {
+ return err;
+ }
+ html.resize(0);
+
+ // Export splash (why?)
+ Ref<Image> splash = _get_project_splash();
+ const String splash_png_path = base_path + ".png";
+ if (splash->save_png(splash_png_path) != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + splash_png_path);
+ return ERR_FILE_CANT_WRITE;
+ }
+
+ // Save a favicon that can be accessed without waiting for the project to finish loading.
+ // This way, the favicon can be displayed immediately when loading the page.
+ if (export_icon) {
+ Ref<Image> favicon = _get_project_icon();
+ const String favicon_png_path = base_path + ".icon.png";
+ if (favicon->save_png(favicon_png_path) != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + favicon_png_path);
+ return ERR_FILE_CANT_WRITE;
+ }
+ favicon->resize(180, 180);
+ const String apple_icon_png_path = base_path + ".apple-touch-icon.png";
+ if (favicon->save_png(apple_icon_png_path) != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + apple_icon_png_path);
+ return ERR_FILE_CANT_WRITE;
+ }
+ }
+
+ // Generate the PWA worker and manifest
+ if (pwa) {
+ err = _build_pwa(p_preset, p_path, shared_objects);
+ if (err != OK) {
+ return err;
+ }
+ }
+
+ return OK;
+}
+
+bool EditorExportPlatformJavaScript::poll_export() {
+ Ref<EditorExportPreset> preset;
+
+ for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
+ Ref<EditorExportPreset> ep = EditorExport::get_singleton()->get_export_preset(i);
+ if (ep->is_runnable() && ep->get_platform() == this) {
+ preset = ep;
+ break;
+ }
+ }
+
+ int prev = menu_options;
+ menu_options = preset.is_valid();
+ if (server->is_listening()) {
+ if (menu_options == 0) {
+ MutexLock lock(server_lock);
+ server->stop();
+ } else {
+ menu_options += 1;
+ }
+ }
+ return menu_options != prev;
+}
+
+Ref<ImageTexture> EditorExportPlatformJavaScript::get_option_icon(int p_index) const {
+ return p_index == 1 ? stop_icon : EditorExportPlatform::get_option_icon(p_index);
+}
+
+int EditorExportPlatformJavaScript::get_options_count() const {
+ return menu_options;
+}
+
+Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_preset, int p_option, int p_debug_flags) {
+ if (p_option == 1) {
+ MutexLock lock(server_lock);
+ server->stop();
+ return OK;
+ }
+
+ const String dest = EditorPaths::get_singleton()->get_cache_dir().plus_file("web");
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ if (!da->dir_exists(dest)) {
+ Error err = da->make_dir_recursive(dest);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not create HTTP server directory:") + "\n" + dest);
+ return err;
+ }
+ }
+ const String basepath = dest.plus_file("tmp_js_export");
+ Error err = export_project(p_preset, true, basepath + ".html", p_debug_flags);
+ if (err != OK) {
+ // Export generates several files, clean them up on failure.
+ DirAccess::remove_file_or_error(basepath + ".html");
+ DirAccess::remove_file_or_error(basepath + ".offline.html");
+ DirAccess::remove_file_or_error(basepath + ".js");
+ DirAccess::remove_file_or_error(basepath + ".worker.js");
+ DirAccess::remove_file_or_error(basepath + ".audio.worklet.js");
+ DirAccess::remove_file_or_error(basepath + ".service.worker.js");
+ DirAccess::remove_file_or_error(basepath + ".pck");
+ DirAccess::remove_file_or_error(basepath + ".png");
+ DirAccess::remove_file_or_error(basepath + ".side.wasm");
+ DirAccess::remove_file_or_error(basepath + ".wasm");
+ DirAccess::remove_file_or_error(basepath + ".icon.png");
+ DirAccess::remove_file_or_error(basepath + ".apple-touch-icon.png");
+ return err;
+ }
+
+ const uint16_t bind_port = EDITOR_GET("export/web/http_port");
+ // Resolve host if needed.
+ const String bind_host = EDITOR_GET("export/web/http_host");
+ IPAddress bind_ip;
+ if (bind_host.is_valid_ip_address()) {
+ bind_ip = bind_host;
+ } else {
+ bind_ip = IP::get_singleton()->resolve_hostname(bind_host);
+ }
+ ERR_FAIL_COND_V_MSG(!bind_ip.is_valid(), ERR_INVALID_PARAMETER, "Invalid editor setting 'export/web/http_host': '" + bind_host + "'. Try using '127.0.0.1'.");
+
+ const bool use_ssl = EDITOR_GET("export/web/use_ssl");
+ const String ssl_key = EDITOR_GET("export/web/ssl_key");
+ const String ssl_cert = EDITOR_GET("export/web/ssl_certificate");
+
+ // Restart server.
+ {
+ MutexLock lock(server_lock);
+
+ server->stop();
+ err = server->listen(bind_port, bind_ip, use_ssl, ssl_key, ssl_cert);
+ }
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Error starting HTTP server:") + "\n" + itos(err));
+ return err;
+ }
+
+ OS::get_singleton()->shell_open(String((use_ssl ? "https://" : "http://") + bind_host + ":" + itos(bind_port) + "/tmp_js_export.html"));
+ // FIXME: Find out how to clean up export files after running the successfully
+ // exported game. Might not be trivial.
+ return OK;
+}
+
+Ref<Texture2D> EditorExportPlatformJavaScript::get_run_icon() const {
+ return run_icon;
+}
+
+void EditorExportPlatformJavaScript::_server_thread_poll(void *data) {
+ EditorExportPlatformJavaScript *ej = (EditorExportPlatformJavaScript *)data;
+ while (!ej->server_quit) {
+ OS::get_singleton()->delay_usec(1000);
+ {
+ MutexLock lock(ej->server_lock);
+ ej->server->poll();
+ }
+ }
+}
+
+EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() {
+ server.instantiate();
+ server_thread.start(_server_thread_poll, this);
+
+ Ref<Image> img = memnew(Image(_javascript_logo));
+ logo.instantiate();
+ logo->create_from_image(img);
+
+ img = Ref<Image>(memnew(Image(_javascript_run_icon)));
+ run_icon.instantiate();
+ run_icon->create_from_image(img);
+
+ Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
+ if (theme.is_valid()) {
+ stop_icon = theme->get_icon("Stop", "EditorIcons");
+ } else {
+ stop_icon.instantiate();
+ }
+}
+
+EditorExportPlatformJavaScript::~EditorExportPlatformJavaScript() {
+ server->stop();
+ server_quit = true;
+ server_thread.wait_to_finish();
+}
diff --git a/platform/javascript/export/export_plugin.h b/platform/javascript/export/export_plugin.h
new file mode 100644
index 0000000000..736edfe3a8
--- /dev/null
+++ b/platform/javascript/export/export_plugin.h
@@ -0,0 +1,149 @@
+/*************************************************************************/
+/* export_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef JAVASCRIPT_EXPORT_PLUGIN_H
+#define JAVASCRIPT_EXPORT_PLUGIN_H
+
+#include "core/io/image_loader.h"
+#include "core/io/stream_peer_ssl.h"
+#include "core/io/tcp_server.h"
+#include "core/io/zip_io.h"
+#include "editor/editor_export.h"
+#include "editor/editor_node.h"
+#include "main/splash.gen.h"
+#include "platform/javascript/logo.gen.h"
+#include "platform/javascript/run_icon.gen.h"
+
+#include "export_server.h"
+
+class EditorExportPlatformJavaScript : public EditorExportPlatform {
+ GDCLASS(EditorExportPlatformJavaScript, EditorExportPlatform);
+
+ Ref<ImageTexture> logo;
+ Ref<ImageTexture> run_icon;
+ Ref<ImageTexture> stop_icon;
+ int menu_options = 0;
+
+ Ref<EditorHTTPServer> server;
+ bool server_quit = false;
+ Mutex server_lock;
+ Thread server_thread;
+
+ enum ExportMode {
+ EXPORT_MODE_NORMAL = 0,
+ EXPORT_MODE_THREADS = 1,
+ EXPORT_MODE_GDNATIVE = 2,
+ };
+
+ String _get_template_name(ExportMode p_mode, bool p_debug) const {
+ String name = "webassembly";
+ switch (p_mode) {
+ case EXPORT_MODE_THREADS:
+ name += "_threads";
+ break;
+ case EXPORT_MODE_GDNATIVE:
+ name += "_gdnative";
+ break;
+ default:
+ break;
+ }
+ if (p_debug) {
+ name += "_debug.zip";
+ } else {
+ name += "_release.zip";
+ }
+ return name;
+ }
+
+ Ref<Image> _get_project_icon() const {
+ Ref<Image> icon;
+ icon.instantiate();
+ const String icon_path = String(GLOBAL_GET("application/config/icon")).strip_edges();
+ if (icon_path.is_empty() || ImageLoader::load_image(icon_path, icon) != OK) {
+ return EditorNode::get_singleton()->get_editor_theme()->get_icon("DefaultProjectIcon", "EditorIcons")->get_image();
+ }
+ return icon;
+ }
+
+ Ref<Image> _get_project_splash() const {
+ Ref<Image> splash;
+ splash.instantiate();
+ const String splash_path = String(GLOBAL_GET("application/boot_splash/image")).strip_edges();
+ if (splash_path.is_empty() || ImageLoader::load_image(splash_path, splash) != OK) {
+ return Ref<Image>(memnew(Image(boot_splash_png)));
+ }
+ return splash;
+ }
+
+ Error _extract_template(const String &p_template, const String &p_dir, const String &p_name, bool pwa);
+ void _replace_strings(Map<String, String> p_replaces, Vector<uint8_t> &r_template);
+ void _fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects, const Dictionary &p_file_sizes);
+ Error _add_manifest_icon(const String &p_path, const String &p_icon, int p_size, Array &r_arr);
+ Error _build_pwa(const Ref<EditorExportPreset> &p_preset, const String p_path, const Vector<SharedObject> &p_shared_objects);
+ Error _write_or_error(const uint8_t *p_content, int p_len, String p_path);
+
+ static void _server_thread_poll(void *data);
+
+public:
+ virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) override;
+
+ virtual void get_export_options(List<ExportOption> *r_options) override;
+
+ virtual String get_name() const override;
+ virtual String get_os_name() const override;
+ virtual Ref<Texture2D> get_logo() const override;
+
+ virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
+ virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
+
+ virtual bool poll_export() override;
+ virtual int get_options_count() const override;
+ virtual String get_option_label(int p_index) const override { return p_index ? TTR("Stop HTTP Server") : TTR("Run in Browser"); }
+ virtual String get_option_tooltip(int p_index) const override { return p_index ? TTR("Stop HTTP Server") : TTR("Run exported HTML in the system's default browser."); }
+ virtual Ref<ImageTexture> get_option_icon(int p_index) const override;
+ virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_option, int p_debug_flags) override;
+ virtual Ref<Texture2D> get_run_icon() const override;
+
+ virtual void get_platform_features(List<String> *r_features) override {
+ r_features->push_back("web");
+ r_features->push_back(get_os_name());
+ }
+
+ virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) override {
+ }
+
+ String get_debug_protocol() const override { return "ws://"; }
+
+ EditorExportPlatformJavaScript();
+ ~EditorExportPlatformJavaScript();
+};
+
+#endif
diff --git a/platform/javascript/export/export_server.h b/platform/javascript/export/export_server.h
new file mode 100644
index 0000000000..87cbdcab47
--- /dev/null
+++ b/platform/javascript/export/export_server.h
@@ -0,0 +1,254 @@
+/*************************************************************************/
+/* export_server.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef JAVASCRIPT_EXPORT_SERVER_H
+#define JAVASCRIPT_EXPORT_SERVER_H
+
+#include "core/io/image_loader.h"
+#include "core/io/stream_peer_ssl.h"
+#include "core/io/tcp_server.h"
+#include "core/io/zip_io.h"
+#include "editor/editor_export.h"
+#include "editor/editor_node.h"
+
+class EditorHTTPServer : public RefCounted {
+private:
+ Ref<TCPServer> server;
+ Map<String, String> mimes;
+ Ref<StreamPeerTCP> tcp;
+ Ref<StreamPeerSSL> ssl;
+ Ref<StreamPeer> peer;
+ Ref<CryptoKey> key;
+ Ref<X509Certificate> cert;
+ bool use_ssl = false;
+ uint64_t time = 0;
+ uint8_t req_buf[4096];
+ int req_pos = 0;
+
+ void _clear_client() {
+ peer = Ref<StreamPeer>();
+ ssl = Ref<StreamPeerSSL>();
+ tcp = Ref<StreamPeerTCP>();
+ memset(req_buf, 0, sizeof(req_buf));
+ time = 0;
+ req_pos = 0;
+ }
+
+ void _set_internal_certs(Ref<Crypto> p_crypto) {
+ const String cache_path = EditorPaths::get_singleton()->get_cache_dir();
+ const String key_path = cache_path.plus_file("html5_server.key");
+ const String crt_path = cache_path.plus_file("html5_server.crt");
+ bool regen = !FileAccess::exists(key_path) || !FileAccess::exists(crt_path);
+ if (!regen) {
+ key = Ref<CryptoKey>(CryptoKey::create());
+ cert = Ref<X509Certificate>(X509Certificate::create());
+ if (key->load(key_path) != OK || cert->load(crt_path) != OK) {
+ regen = true;
+ }
+ }
+ if (regen) {
+ key = p_crypto->generate_rsa(2048);
+ key->save(key_path);
+ cert = p_crypto->generate_self_signed_certificate(key, "CN=godot-debug.local,O=A Game Dev,C=XXA", "20140101000000", "20340101000000");
+ cert->save(crt_path);
+ }
+ }
+
+public:
+ EditorHTTPServer() {
+ mimes["html"] = "text/html";
+ mimes["js"] = "application/javascript";
+ mimes["json"] = "application/json";
+ mimes["pck"] = "application/octet-stream";
+ mimes["png"] = "image/png";
+ mimes["svg"] = "image/svg";
+ mimes["wasm"] = "application/wasm";
+ server.instantiate();
+ stop();
+ }
+
+ void stop() {
+ server->stop();
+ _clear_client();
+ }
+
+ Error listen(int p_port, IPAddress p_address, bool p_use_ssl, String p_ssl_key, String p_ssl_cert) {
+ use_ssl = p_use_ssl;
+ if (use_ssl) {
+ Ref<Crypto> crypto = Crypto::create();
+ if (crypto.is_null()) {
+ return ERR_UNAVAILABLE;
+ }
+ if (!p_ssl_key.is_empty() && !p_ssl_cert.is_empty()) {
+ key = Ref<CryptoKey>(CryptoKey::create());
+ Error err = key->load(p_ssl_key);
+ ERR_FAIL_COND_V(err != OK, err);
+ cert = Ref<X509Certificate>(X509Certificate::create());
+ err = cert->load(p_ssl_cert);
+ ERR_FAIL_COND_V(err != OK, err);
+ } else {
+ _set_internal_certs(crypto);
+ }
+ }
+ return server->listen(p_port, p_address);
+ }
+
+ bool is_listening() const {
+ return server->is_listening();
+ }
+
+ void _send_response() {
+ Vector<String> psa = String((char *)req_buf).split("\r\n");
+ int len = psa.size();
+ ERR_FAIL_COND_MSG(len < 4, "Not enough response headers, got: " + itos(len) + ", expected >= 4.");
+
+ Vector<String> req = psa[0].split(" ", false);
+ ERR_FAIL_COND_MSG(req.size() < 2, "Invalid protocol or status code.");
+
+ // Wrong protocol
+ ERR_FAIL_COND_MSG(req[0] != "GET" || req[2] != "HTTP/1.1", "Invalid method or HTTP version.");
+
+ const int query_index = req[1].find_char('?');
+ const String path = (query_index == -1) ? req[1] : req[1].substr(0, query_index);
+
+ const String req_file = path.get_file();
+ const String req_ext = path.get_extension();
+ const String cache_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("web");
+ const String filepath = cache_path.plus_file(req_file);
+
+ if (!mimes.has(req_ext) || !FileAccess::exists(filepath)) {
+ String s = "HTTP/1.1 404 Not Found\r\n";
+ s += "Connection: Close\r\n";
+ s += "\r\n";
+ CharString cs = s.utf8();
+ peer->put_data((const uint8_t *)cs.get_data(), cs.size() - 1);
+ return;
+ }
+ const String ctype = mimes[req_ext];
+
+ FileAccess *f = FileAccess::open(filepath, FileAccess::READ);
+ ERR_FAIL_COND(!f);
+ String s = "HTTP/1.1 200 OK\r\n";
+ s += "Connection: Close\r\n";
+ s += "Content-Type: " + ctype + "\r\n";
+ s += "Access-Control-Allow-Origin: *\r\n";
+ s += "Cross-Origin-Opener-Policy: same-origin\r\n";
+ s += "Cross-Origin-Embedder-Policy: require-corp\r\n";
+ s += "Cache-Control: no-store, max-age=0\r\n";
+ s += "\r\n";
+ CharString cs = s.utf8();
+ Error err = peer->put_data((const uint8_t *)cs.get_data(), cs.size() - 1);
+ if (err != OK) {
+ memdelete(f);
+ ERR_FAIL();
+ }
+
+ while (true) {
+ uint8_t bytes[4096];
+ uint64_t read = f->get_buffer(bytes, 4096);
+ if (read == 0) {
+ break;
+ }
+ err = peer->put_data(bytes, read);
+ if (err != OK) {
+ memdelete(f);
+ ERR_FAIL();
+ }
+ }
+ memdelete(f);
+ }
+
+ void poll() {
+ if (!server->is_listening()) {
+ return;
+ }
+ if (tcp.is_null()) {
+ if (!server->is_connection_available()) {
+ return;
+ }
+ tcp = server->take_connection();
+ peer = tcp;
+ time = OS::get_singleton()->get_ticks_usec();
+ }
+ if (OS::get_singleton()->get_ticks_usec() - time > 1000000) {
+ _clear_client();
+ return;
+ }
+ if (tcp->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
+ return;
+ }
+
+ if (use_ssl) {
+ if (ssl.is_null()) {
+ ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create());
+ peer = ssl;
+ ssl->set_blocking_handshake_enabled(false);
+ if (ssl->accept_stream(tcp, key, cert) != OK) {
+ _clear_client();
+ return;
+ }
+ }
+ ssl->poll();
+ if (ssl->get_status() == StreamPeerSSL::STATUS_HANDSHAKING) {
+ // Still handshaking, keep waiting.
+ return;
+ }
+ if (ssl->get_status() != StreamPeerSSL::STATUS_CONNECTED) {
+ _clear_client();
+ return;
+ }
+ }
+
+ while (true) {
+ char *r = (char *)req_buf;
+ int l = req_pos - 1;
+ if (l > 3 && r[l] == '\n' && r[l - 1] == '\r' && r[l - 2] == '\n' && r[l - 3] == '\r') {
+ _send_response();
+ _clear_client();
+ return;
+ }
+
+ int read = 0;
+ ERR_FAIL_COND(req_pos >= 4096);
+ Error err = peer->get_partial_data(&req_buf[req_pos], 1, read);
+ if (err != OK) {
+ // Got an error
+ _clear_client();
+ return;
+ } else if (read != 1) {
+ // Busy, wait next poll
+ return;
+ }
+ req_pos += read;
+ }
+ }
+};
+
+#endif
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index 131c4b821e..1164d76580 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -30,1153 +30,7 @@
#include "export.h"
-#include "core/config/project_settings.h"
-#include "core/io/dir_access.h"
-#include "core/io/file_access.h"
-#include "core/io/marshalls.h"
-#include "core/io/resource_saver.h"
-#include "core/io/zip_io.h"
-#include "core/os/os.h"
-#include "core/version.h"
-#include "editor/editor_export.h"
-#include "editor/editor_node.h"
-#include "editor/editor_settings.h"
-#include "platform/osx/logo.gen.h"
-
-#include <sys/stat.h>
-
-class EditorExportPlatformOSX : public EditorExportPlatform {
- GDCLASS(EditorExportPlatformOSX, EditorExportPlatform);
-
- int version_code = 0;
-
- Ref<ImageTexture> logo;
-
- void _fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary);
- void _make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data);
-
- Error _notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path);
- Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path);
- Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name);
- void _zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name);
-
-#ifdef OSX_ENABLED
- bool use_codesign() const { return true; }
- bool use_dmg() const { return true; }
-#else
- bool use_codesign() const { return false; }
- bool use_dmg() const { return false; }
-#endif
- bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const {
- String pname = p_package;
-
- if (pname.length() == 0) {
- if (r_error) {
- *r_error = TTR("Identifier is missing.");
- }
- return false;
- }
-
- for (int i = 0; i < pname.length(); i++) {
- char32_t c = pname[i];
- if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '.')) {
- if (r_error) {
- *r_error = vformat(TTR("The character '%s' is not allowed in Identifier."), String::chr(c));
- }
- return false;
- }
- }
-
- return true;
- }
-
-protected:
- virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) override;
- virtual void get_export_options(List<ExportOption> *r_options) override;
-
-public:
- virtual String get_name() const override { return "macOS"; }
- virtual String get_os_name() const override { return "macOS"; }
- virtual Ref<Texture2D> get_logo() const override { return logo; }
-
- virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override {
- List<String> list;
- if (use_dmg()) {
- list.push_back("dmg");
- }
- list.push_back("zip");
- return list;
- }
- virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
-
- virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
-
- virtual void get_platform_features(List<String> *r_features) override {
- r_features->push_back("pc");
- r_features->push_back("s3tc");
- r_features->push_back("macOS");
- }
-
- virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) override {
- }
-
- EditorExportPlatformOSX();
- ~EditorExportPlatformOSX();
-};
-
-void EditorExportPlatformOSX::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
- if (p_preset->get("texture_format/s3tc")) {
- r_features->push_back("s3tc");
- }
- if (p_preset->get("texture_format/etc")) {
- r_features->push_back("etc");
- }
- if (p_preset->get("texture_format/etc2")) {
- r_features->push_back("etc2");
- }
-
- r_features->push_back("64");
-}
-
-void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) {
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/info"), "Made with Godot Engine"));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.png,*.icns"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_category", PROPERTY_HINT_ENUM, "Business,Developer-tools,Education,Entertainment,Finance,Games,Action-games,Adventure-games,Arcade-games,Board-games,Card-games,Casino-games,Dice-games,Educational-games,Family-games,Kids-games,Music-games,Puzzle-games,Racing-games,Role-playing-games,Simulation-games,Sports-games,Strategy-games,Trivia-games,Word-games,Graphics-design,Healthcare-fitness,Lifestyle,Medical,Music,News,Photography,Productivity,Reference,Social-networking,Sports,Travel,Utilities,Video,Weather"), "Games"));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0"));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0"));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/camera_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the camera"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), ""));
-
-#ifdef OSX_ENABLED
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_PLACEHOLDER_TEXT, "Type: Name (ID)"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/hardened_runtime"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/replace_existing_signature"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements/custom_file", PROPERTY_HINT_GLOBAL_FILE, "*.plist"), ""));
-
- if (!Engine::get_singleton()->has_singleton("GodotSharp")) {
- // These entitlements are required to run managed code, and are always enabled in Mono builds.
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_jit_code_execution"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_unsigned_executable_memory"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_dyld_environment_variables"), false));
- }
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/disable_library_validation"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/audio_input"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/camera"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/location"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/address_book"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/calendars"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/photos_library"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/apple_events"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/debugging"), false));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/enabled"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/network_server"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/network_client"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/device_usb"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/device_bluetooth"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_downloads", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_pictures", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_music", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_movies", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "notarization/enable"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Apple ID email"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_password", PROPERTY_HINT_PLACEHOLDER_TEXT, "Enable two-factor authentication and provide app-specific password"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_team_id", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide team ID if your Apple ID belongs to multiple teams"), ""));
-#endif
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), false));
-}
-
-void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source, Vector<uint8_t> &p_dest) {
- int src_len = p_size * p_size;
-
- Vector<uint8_t> result;
- result.resize(src_len * 1.25); //temp vector for rle encoded data, make it 25% larger for worst case scenario
- int res_size = 0;
-
- uint8_t buf[128];
- int buf_size = 0;
-
- int i = 0;
- while (i < src_len) {
- uint8_t cur = p_source.ptr()[i * 4 + p_ch];
-
- if (i < src_len - 2) {
- if ((p_source.ptr()[(i + 1) * 4 + p_ch] == cur) && (p_source.ptr()[(i + 2) * 4 + p_ch] == cur)) {
- if (buf_size > 0) {
- result.write[res_size++] = (uint8_t)(buf_size - 1);
- memcpy(&result.write[res_size], &buf, buf_size);
- res_size += buf_size;
- buf_size = 0;
- }
-
- uint8_t lim = i + 130 >= src_len ? src_len - i - 1 : 130;
- bool hit_lim = true;
-
- for (int j = 3; j <= lim; j++) {
- if (p_source.ptr()[(i + j) * 4 + p_ch] != cur) {
- hit_lim = false;
- i = i + j - 1;
- result.write[res_size++] = (uint8_t)(j - 3 + 0x80);
- result.write[res_size++] = cur;
- break;
- }
- }
- if (hit_lim) {
- result.write[res_size++] = (uint8_t)(lim - 3 + 0x80);
- result.write[res_size++] = cur;
- i = i + lim;
- }
- } else {
- buf[buf_size++] = cur;
- if (buf_size == 128) {
- result.write[res_size++] = (uint8_t)(buf_size - 1);
- memcpy(&result.write[res_size], &buf, buf_size);
- res_size += buf_size;
- buf_size = 0;
- }
- }
- } else {
- buf[buf_size++] = cur;
- result.write[res_size++] = (uint8_t)(buf_size - 1);
- memcpy(&result.write[res_size], &buf, buf_size);
- res_size += buf_size;
- buf_size = 0;
- }
-
- i++;
- }
-
- int ofs = p_dest.size();
- p_dest.resize(p_dest.size() + res_size);
- memcpy(&p_dest.write[ofs], result.ptr(), res_size);
-}
-
-void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) {
- Ref<ImageTexture> it = memnew(ImageTexture);
-
- Vector<uint8_t> data;
-
- data.resize(8);
- data.write[0] = 'i';
- data.write[1] = 'c';
- data.write[2] = 'n';
- data.write[3] = 's';
-
- struct MacOSIconInfo {
- const char *name;
- const char *mask_name;
- bool is_png;
- int size;
- };
-
- static const MacOSIconInfo icon_infos[] = {
- { "ic10", "", true, 1024 }, //1024x1024 32-bit PNG and 512x512@2x 32-bit "retina" PNG
- { "ic09", "", true, 512 }, //512×512 32-bit PNG
- { "ic14", "", true, 512 }, //256x256@2x 32-bit "retina" PNG
- { "ic08", "", true, 256 }, //256×256 32-bit PNG
- { "ic13", "", true, 256 }, //128x128@2x 32-bit "retina" PNG
- { "ic07", "", true, 128 }, //128x128 32-bit PNG
- { "ic12", "", true, 64 }, //32x32@2x 32-bit "retina" PNG
- { "ic11", "", true, 32 }, //16x16@2x 32-bit "retina" PNG
- { "il32", "l8mk", false, 32 }, //32x32 24-bit RLE + 8-bit uncompressed mask
- { "is32", "s8mk", false, 16 } //16x16 24-bit RLE + 8-bit uncompressed mask
- };
-
- for (uint64_t i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) {
- Ref<Image> copy = p_icon; // does this make sense? doesn't this just increase the reference count instead of making a copy? Do we even need a copy?
- copy->convert(Image::FORMAT_RGBA8);
- copy->resize(icon_infos[i].size, icon_infos[i].size);
-
- if (icon_infos[i].is_png) {
- // Encode PNG icon.
- it->create_from_image(copy);
- String path = EditorPaths::get_singleton()->get_cache_dir().plus_file("icon.png");
- ResourceSaver::save(path, it);
-
- FileAccess *f = FileAccess::open(path, FileAccess::READ);
- if (!f) {
- // Clean up generated file.
- DirAccess::remove_file_or_error(path);
- ERR_FAIL();
- }
-
- int ofs = data.size();
- uint64_t len = f->get_length();
- data.resize(data.size() + len + 8);
- f->get_buffer(&data.write[ofs + 8], len);
- memdelete(f);
- len += 8;
- len = BSWAP32(len);
- memcpy(&data.write[ofs], icon_infos[i].name, 4);
- encode_uint32(len, &data.write[ofs + 4]);
-
- // Clean up generated file.
- DirAccess::remove_file_or_error(path);
-
- } else {
- Vector<uint8_t> src_data = copy->get_data();
-
- //encode 24bit RGB RLE icon
- {
- int ofs = data.size();
- data.resize(data.size() + 8);
-
- _rgba8_to_packbits_encode(0, icon_infos[i].size, src_data, data); // encode R
- _rgba8_to_packbits_encode(1, icon_infos[i].size, src_data, data); // encode G
- _rgba8_to_packbits_encode(2, icon_infos[i].size, src_data, data); // encode B
-
- int len = data.size() - ofs;
- len = BSWAP32(len);
- memcpy(&data.write[ofs], icon_infos[i].name, 4);
- encode_uint32(len, &data.write[ofs + 4]);
- }
-
- //encode 8bit mask uncompressed icon
- {
- int ofs = data.size();
- int len = copy->get_width() * copy->get_height();
- data.resize(data.size() + len + 8);
-
- for (int j = 0; j < len; j++) {
- data.write[ofs + 8 + j] = src_data.ptr()[j * 4 + 3];
- }
- len += 8;
- len = BSWAP32(len);
- memcpy(&data.write[ofs], icon_infos[i].mask_name, 4);
- encode_uint32(len, &data.write[ofs + 4]);
- }
- }
- }
-
- uint32_t total_len = data.size();
- total_len = BSWAP32(total_len);
- encode_uint32(total_len, &data.write[4]);
-
- p_data = data;
-}
-
-void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary) {
- String str;
- String strnew;
- str.parse_utf8((const char *)plist.ptr(), plist.size());
- Vector<String> lines = str.split("\n");
- for (int i = 0; i < lines.size(); i++) {
- if (lines[i].find("$binary") != -1) {
- strnew += lines[i].replace("$binary", p_binary) + "\n";
- } else if (lines[i].find("$name") != -1) {
- strnew += lines[i].replace("$name", p_binary) + "\n";
- } else if (lines[i].find("$info") != -1) {
- strnew += lines[i].replace("$info", p_preset->get("application/info")) + "\n";
- } else if (lines[i].find("$bundle_identifier") != -1) {
- strnew += lines[i].replace("$bundle_identifier", p_preset->get("application/bundle_identifier")) + "\n";
- } else if (lines[i].find("$short_version") != -1) {
- strnew += lines[i].replace("$short_version", p_preset->get("application/short_version")) + "\n";
- } else if (lines[i].find("$version") != -1) {
- strnew += lines[i].replace("$version", p_preset->get("application/version")) + "\n";
- } else if (lines[i].find("$signature") != -1) {
- strnew += lines[i].replace("$signature", p_preset->get("application/signature")) + "\n";
- } else if (lines[i].find("$app_category") != -1) {
- String cat = p_preset->get("application/app_category");
- strnew += lines[i].replace("$app_category", cat.to_lower()) + "\n";
- } else if (lines[i].find("$copyright") != -1) {
- strnew += lines[i].replace("$copyright", p_preset->get("application/copyright")) + "\n";
- } else if (lines[i].find("$highres") != -1) {
- strnew += lines[i].replace("$highres", p_preset->get("display/high_res") ? "<true/>" : "<false/>") + "\n";
- } else if (lines[i].find("$camera_usage_description") != -1) {
- String description = p_preset->get("privacy/camera_usage_description");
- strnew += lines[i].replace("$camera_usage_description", description) + "\n";
- } else if (lines[i].find("$microphone_usage_description") != -1) {
- String description = p_preset->get("privacy/microphone_usage_description");
- strnew += lines[i].replace("$microphone_usage_description", description) + "\n";
- } else {
- strnew += lines[i] + "\n";
- }
- }
-
- CharString cs = strnew.utf8();
- plist.resize(cs.size() - 1);
- for (int i = 0; i < cs.size() - 1; i++) {
- plist.write[i] = cs[i];
- }
-}
-
-/**
- If we're running the OSX version of the Godot editor we'll:
- - export our application bundle to a temporary folder
- - attempt to code sign it
- - and then wrap it up in a DMG
-**/
-
-Error EditorExportPlatformOSX::_notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
-#ifdef OSX_ENABLED
- List<String> args;
-
- args.push_back("altool");
- args.push_back("--notarize-app");
-
- args.push_back("--primary-bundle-id");
- args.push_back(p_preset->get("application/bundle_identifier"));
-
- args.push_back("--username");
- args.push_back(p_preset->get("notarization/apple_id_name"));
-
- args.push_back("--password");
- args.push_back(p_preset->get("notarization/apple_id_password"));
-
- args.push_back("--type");
- args.push_back("osx");
-
- if (p_preset->get("notarization/apple_team_id")) {
- args.push_back("--asc-provider");
- args.push_back(p_preset->get("notarization/apple_team_id"));
- }
-
- args.push_back("--file");
- args.push_back(p_path);
-
- String str;
- Error err = OS::get_singleton()->execute("xcrun", args, &str, nullptr, true);
- ERR_FAIL_COND_V(err != OK, err);
-
- print_line("altool (" + p_path + "):\n" + str);
- if (str.find("RequestUUID") == -1) {
- EditorNode::add_io_error("altool: " + str);
- return FAILED;
- } else {
- print_line("Note: The notarization process generally takes less than an hour. When the process is completed, you'll receive an email.");
- print_line(" You can check progress manually by opening a Terminal and running the following command:");
- print_line(" \"xcrun altool --notarization-history 0 -u <your email> -p <app-specific pwd>\"");
- }
-
-#endif
-
- return OK;
-}
-
-Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path) {
-#ifdef OSX_ENABLED
- List<String> args;
-
- if (p_preset->get("codesign/timestamp")) {
- args.push_back("--timestamp");
- }
- if (p_preset->get("codesign/hardened_runtime")) {
- args.push_back("--options");
- args.push_back("runtime");
- }
-
- if (p_path.get_extension() != "dmg") {
- args.push_back("--entitlements");
- args.push_back(p_ent_path);
- }
-
- PackedStringArray user_args = p_preset->get("codesign/custom_options");
- for (int i = 0; i < user_args.size(); i++) {
- String user_arg = user_args[i].strip_edges();
- if (!user_arg.is_empty()) {
- args.push_back(user_arg);
- }
- }
-
- args.push_back("-s");
- if (p_preset->get("codesign/identity") == "") {
- args.push_back("-");
- } else {
- args.push_back(p_preset->get("codesign/identity"));
- }
-
- args.push_back("-v"); /* provide some more feedback */
-
- if (p_preset->get("codesign/replace_existing_signature")) {
- args.push_back("-f");
- }
-
- args.push_back(p_path);
-
- String str;
- Error err = OS::get_singleton()->execute("codesign", args, &str, nullptr, true);
- ERR_FAIL_COND_V(err != OK, err);
-
- print_line("codesign (" + p_path + "):\n" + str);
- if (str.find("no identity found") != -1) {
- EditorNode::add_io_error("codesign: no identity found");
- return FAILED;
- }
- if ((str.find("unrecognized blob type") != -1) || (str.find("cannot read entitlement data") != -1)) {
- EditorNode::add_io_error("codesign: invalid entitlements file");
- return FAILED;
- }
-#endif
-
- return OK;
-}
-
-Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name) {
- List<String> args;
-
- if (FileAccess::exists(p_dmg_path)) {
- OS::get_singleton()->move_to_trash(p_dmg_path);
- }
-
- args.push_back("create");
- args.push_back(p_dmg_path);
- args.push_back("-volname");
- args.push_back(p_pkg_name);
- args.push_back("-fs");
- args.push_back("HFS+");
- args.push_back("-srcfolder");
- args.push_back(p_app_path_name);
-
- String str;
- Error err = OS::get_singleton()->execute("hdiutil", args, &str, nullptr, true);
- ERR_FAIL_COND_V(err != OK, err);
-
- print_line("hdiutil returned: " + str);
- if (str.find("create failed") != -1) {
- if (str.find("File exists") != -1) {
- EditorNode::add_io_error("hdiutil: create failed - file exists");
- } else {
- EditorNode::add_io_error("hdiutil: create failed");
- }
- return FAILED;
- }
-
- return OK;
-}
-
-Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
- ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
-
- String src_pkg_name;
-
- EditorProgress ep("export", "Exporting for OSX", 3, true);
-
- if (p_debug) {
- src_pkg_name = p_preset->get("custom_template/debug");
- } else {
- src_pkg_name = p_preset->get("custom_template/release");
- }
-
- if (src_pkg_name == "") {
- String err;
- src_pkg_name = find_export_template("osx.zip", &err);
- if (src_pkg_name == "") {
- EditorNode::add_io_error(err);
- return ERR_FILE_NOT_FOUND;
- }
- }
-
- if (!DirAccess::exists(p_path.get_base_dir())) {
- return ERR_FILE_BAD_PATH;
- }
-
- FileAccess *src_f = nullptr;
- zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
-
- if (ep.step("Creating app", 0)) {
- return ERR_SKIP;
- }
-
- unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io);
- if (!src_pkg_zip) {
- EditorNode::add_io_error("Could not find template app to export:\n" + src_pkg_name);
- return ERR_FILE_NOT_FOUND;
- }
-
- int ret = unzGoToFirstFile(src_pkg_zip);
-
- String binary_to_use = "godot_osx_" + String(p_debug ? "debug" : "release") + ".64";
-
- String pkg_name;
- if (p_preset->get("application/name") != "") {
- pkg_name = p_preset->get("application/name"); // app_name
- } else if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") {
- pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
- } else {
- pkg_name = "Unnamed";
- }
-
- pkg_name = OS::get_singleton()->get_safe_dir_name(pkg_name);
-
- String export_format = use_dmg() && p_path.ends_with("dmg") ? "dmg" : "zip";
-
- // Create our application bundle.
- String tmp_app_dir_name = pkg_name + ".app";
- String tmp_app_path_name = EditorPaths::get_singleton()->get_cache_dir().plus_file(tmp_app_dir_name);
- print_line("Exporting to " + tmp_app_path_name);
-
- Error err = OK;
-
- DirAccessRef tmp_app_dir = DirAccess::create_for_path(tmp_app_path_name);
- if (!tmp_app_dir) {
- err = ERR_CANT_CREATE;
- }
-
- // Create our folder structure.
- if (err == OK) {
- print_line("Creating " + tmp_app_path_name + "/Contents/MacOS");
- err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/MacOS");
- }
-
- if (err == OK) {
- print_line("Creating " + tmp_app_path_name + "/Contents/Frameworks");
- err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Frameworks");
- }
-
- if (err == OK) {
- print_line("Creating " + tmp_app_path_name + "/Contents/Resources");
- err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Resources");
- }
-
- // Now process our template.
- bool found_binary = false;
- int total_size = 0;
- Vector<String> dylibs_found;
-
- while (ret == UNZ_OK && err == OK) {
- bool is_execute = false;
-
- // Get filename.
- unz_file_info info;
- char fname[16384];
- ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, nullptr, 0, nullptr, 0);
-
- String file = fname;
-
- Vector<uint8_t> data;
- data.resize(info.uncompressed_size);
-
- // Read.
- unzOpenCurrentFile(src_pkg_zip);
- unzReadCurrentFile(src_pkg_zip, data.ptrw(), data.size());
- unzCloseCurrentFile(src_pkg_zip);
-
- // Write.
- file = file.replace_first("osx_template.app/", "");
-
- if (file == "Contents/Info.plist") {
- _fix_plist(p_preset, data, pkg_name);
- }
-
- if (file.begins_with("Contents/MacOS/godot_")) {
- if (file != "Contents/MacOS/" + binary_to_use) {
- ret = unzGoToNextFile(src_pkg_zip);
- continue; // skip
- }
- found_binary = true;
- is_execute = true;
- file = "Contents/MacOS/" + pkg_name;
- }
-
- if (file == "Contents/Resources/icon.icns") {
- // See if there is an icon.
- String iconpath;
- if (p_preset->get("application/icon") != "") {
- iconpath = p_preset->get("application/icon");
- } else {
- iconpath = ProjectSettings::get_singleton()->get("application/config/icon");
- }
-
- if (iconpath != "") {
- if (iconpath.get_extension() == "icns") {
- FileAccess *icon = FileAccess::open(iconpath, FileAccess::READ);
- if (icon) {
- data.resize(icon->get_length());
- icon->get_buffer(&data.write[0], icon->get_length());
- icon->close();
- memdelete(icon);
- }
- } else {
- Ref<Image> icon;
- icon.instantiate();
- icon->load(iconpath);
- if (!icon->is_empty()) {
- _make_icon(icon, data);
- }
- }
- }
- }
-
- if (data.size() > 0) {
- if (file.find("/data.mono.osx.64.release_debug/") != -1) {
- if (!p_debug) {
- ret = unzGoToNextFile(src_pkg_zip);
- continue; // skip
- }
- file = file.replace("/data.mono.osx.64.release_debug/", "/GodotSharp/");
- }
- if (file.find("/data.mono.osx.64.release/") != -1) {
- if (p_debug) {
- ret = unzGoToNextFile(src_pkg_zip);
- continue; // skip
- }
- file = file.replace("/data.mono.osx.64.release/", "/GodotSharp/");
- }
-
- if (file.ends_with(".dylib")) {
- dylibs_found.push_back(file);
- }
-
- print_line("ADDING: " + file + " size: " + itos(data.size()));
- total_size += data.size();
-
- // Write it into our application bundle.
- file = tmp_app_path_name.plus_file(file);
- if (err == OK) {
- err = tmp_app_dir->make_dir_recursive(file.get_base_dir());
- }
- if (err == OK) {
- FileAccess *f = FileAccess::open(file, FileAccess::WRITE);
- if (f) {
- f->store_buffer(data.ptr(), data.size());
- f->close();
- if (is_execute) {
- // chmod with 0755 if the file is executable.
- FileAccess::set_unix_permissions(file, 0755);
- }
- memdelete(f);
- } else {
- err = ERR_CANT_CREATE;
- }
- }
- }
-
- ret = unzGoToNextFile(src_pkg_zip);
- }
-
- // We're done with our source zip.
- unzClose(src_pkg_zip);
-
- if (!found_binary) {
- ERR_PRINT("Requested template binary '" + binary_to_use + "' not found. It might be missing from your template archive.");
- err = ERR_FILE_NOT_FOUND;
- }
-
- if (err == OK) {
- if (ep.step("Making PKG", 1)) {
- return ERR_SKIP;
- }
-
- String pack_path = tmp_app_path_name + "/Contents/Resources/" + pkg_name + ".pck";
- Vector<SharedObject> shared_objects;
- err = save_pack(p_preset, pack_path, &shared_objects);
-
- // See if we can code sign our new package.
- bool sign_enabled = p_preset->get("codesign/enable");
-
- String ent_path = p_preset->get("codesign/entitlements/custom_file");
- if (sign_enabled && (ent_path == "")) {
- ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + ".entitlements");
-
- FileAccess *ent_f = FileAccess::open(ent_path, FileAccess::WRITE);
- if (ent_f) {
- ent_f->store_line("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
- ent_f->store_line("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
- ent_f->store_line("<plist version=\"1.0\">");
- ent_f->store_line("<dict>");
- if (Engine::get_singleton()->has_singleton("GodotSharp")) {
- // These entitlements are required to run managed code, and are always enabled in Mono builds.
- ent_f->store_line("<key>com.apple.security.cs.allow-jit</key>");
- ent_f->store_line("<true/>");
- ent_f->store_line("<key>com.apple.security.cs.allow-unsigned-executable-memory</key>");
- ent_f->store_line("<true/>");
- ent_f->store_line("<key>com.apple.security.cs.allow-dyld-environment-variables</key>");
- ent_f->store_line("<true/>");
- } else {
- if ((bool)p_preset->get("codesign/entitlements/allow_jit_code_execution")) {
- ent_f->store_line("<key>com.apple.security.cs.allow-jit</key>");
- ent_f->store_line("<true/>");
- }
- if ((bool)p_preset->get("codesign/entitlements/allow_unsigned_executable_memory")) {
- ent_f->store_line("<key>com.apple.security.cs.allow-unsigned-executable-memory</key>");
- ent_f->store_line("<true/>");
- }
- if ((bool)p_preset->get("codesign/entitlements/allow_dyld_environment_variables")) {
- ent_f->store_line("<key>com.apple.security.cs.allow-dyld-environment-variables</key>");
- ent_f->store_line("<true/>");
- }
- }
-
- if ((bool)p_preset->get("codesign/entitlements/disable_library_validation")) {
- ent_f->store_line("<key>com.apple.security.cs.disable-library-validation</key>");
- ent_f->store_line("<true/>");
- }
- if ((bool)p_preset->get("codesign/entitlements/audio_input")) {
- ent_f->store_line("<key>com.apple.security.device.audio-input</key>");
- ent_f->store_line("<true/>");
- }
- if ((bool)p_preset->get("codesign/entitlements/camera")) {
- ent_f->store_line("<key>com.apple.security.device.camera</key>");
- ent_f->store_line("<true/>");
- }
- if ((bool)p_preset->get("codesign/entitlements/location")) {
- ent_f->store_line("<key>com.apple.security.personal-information.location</key>");
- ent_f->store_line("<true/>");
- }
- if ((bool)p_preset->get("codesign/entitlements/address_book")) {
- ent_f->store_line("<key>com.apple.security.personal-information.addressbook</key>");
- ent_f->store_line("<true/>");
- }
- if ((bool)p_preset->get("codesign/entitlements/calendars")) {
- ent_f->store_line("<key>com.apple.security.personal-information.calendars</key>");
- ent_f->store_line("<true/>");
- }
- if ((bool)p_preset->get("codesign/entitlements/photos_library")) {
- ent_f->store_line("<key>com.apple.security.personal-information.photos-library</key>");
- ent_f->store_line("<true/>");
- }
- if ((bool)p_preset->get("codesign/entitlements/apple_events")) {
- ent_f->store_line("<key>com.apple.security.automation.apple-events</key>");
- ent_f->store_line("<true/>");
- }
- if ((bool)p_preset->get("codesign/entitlements/debugging")) {
- ent_f->store_line("<key>com.apple.security.get-task-allow</key>");
- ent_f->store_line("<true/>");
- }
-
- if ((bool)p_preset->get("codesign/entitlements/app_sandbox/enabled")) {
- ent_f->store_line("<key>com.apple.security.app-sandbox</key>");
- ent_f->store_line("<true/>");
-
- if ((bool)p_preset->get("codesign/entitlements/app_sandbox/network_server")) {
- ent_f->store_line("<key>com.apple.security.network.server</key>");
- ent_f->store_line("<true/>");
- }
- if ((bool)p_preset->get("codesign/entitlements/app_sandbox/network_client")) {
- ent_f->store_line("<key>com.apple.security.network.client</key>");
- ent_f->store_line("<true/>");
- }
- if ((bool)p_preset->get("codesign/entitlements/app_sandbox/device_usb")) {
- ent_f->store_line("<key>com.apple.security.device.usb</key>");
- ent_f->store_line("<true/>");
- }
- if ((bool)p_preset->get("codesign/entitlements/app_sandbox/device_bluetooth")) {
- ent_f->store_line("<key>com.apple.security.device.bluetooth</key>");
- ent_f->store_line("<true/>");
- }
- if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_downloads") == 1) {
- ent_f->store_line("<key>com.apple.security.files.downloads.read-only</key>");
- ent_f->store_line("<true/>");
- }
- if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_downloads") == 2) {
- ent_f->store_line("<key>com.apple.security.files.downloads.read-write</key>");
- ent_f->store_line("<true/>");
- }
- if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_pictures") == 1) {
- ent_f->store_line("<key>com.apple.security.files.pictures.read-only</key>");
- ent_f->store_line("<true/>");
- }
- if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_pictures") == 2) {
- ent_f->store_line("<key>com.apple.security.files.pictures.read-write</key>");
- ent_f->store_line("<true/>");
- }
- if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_music") == 1) {
- ent_f->store_line("<key>com.apple.security.files.music.read-only</key>");
- ent_f->store_line("<true/>");
- }
- if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_music") == 2) {
- ent_f->store_line("<key>com.apple.security.files.music.read-write</key>");
- ent_f->store_line("<true/>");
- }
- if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_movies") == 1) {
- ent_f->store_line("<key>com.apple.security.files.movies.read-only</key>");
- ent_f->store_line("<true/>");
- }
- if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_movies") == 2) {
- ent_f->store_line("<key>com.apple.security.files.movies.read-write</key>");
- ent_f->store_line("<true/>");
- }
- }
-
- ent_f->store_line("</dict>");
- ent_f->store_line("</plist>");
-
- ent_f->close();
- memdelete(ent_f);
- } else {
- err = ERR_CANT_CREATE;
- }
- }
-
- if (err == OK) {
- DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- for (int i = 0; i < shared_objects.size(); i++) {
- String src_path = ProjectSettings::get_singleton()->globalize_path(shared_objects[i].path);
- if (da->dir_exists(src_path)) {
-#ifndef UNIX_ENABLED
- WARN_PRINT("Relative symlinks are not supported, exported " + src_path.get_file() + " might be broken!");
-#endif
- print_verbose("export framework: " + src_path + " -> " + tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file());
- err = da->make_dir_recursive(tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file());
- if (err == OK) {
- err = da->copy_dir(src_path, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file(), -1, true);
- }
- } else {
- print_verbose("export dylib: " + src_path + " -> " + tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file());
- err = da->copy(src_path, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file());
- }
- if (err == OK && sign_enabled) {
- err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file(), ent_path);
- }
- }
- memdelete(da);
- }
-
- if (sign_enabled) {
- for (int i = 0; i < dylibs_found.size(); i++) {
- if (err == OK) {
- err = _code_sign(p_preset, tmp_app_path_name + "/" + dylibs_found[i], ent_path);
- }
- }
- }
-
- if (err == OK && sign_enabled) {
- if (ep.step("Code signing bundle", 2)) {
- return ERR_SKIP;
- }
- err = _code_sign(p_preset, tmp_app_path_name + "/Contents/MacOS/" + pkg_name, ent_path);
- }
-
- if (export_format == "dmg") {
- // Create a DMG.
- if (err == OK) {
- if (ep.step("Making DMG", 3)) {
- return ERR_SKIP;
- }
- err = _create_dmg(p_path, pkg_name, tmp_app_path_name);
- }
- // Sign DMG.
- if (err == OK && sign_enabled) {
- if (ep.step("Code signing DMG", 3)) {
- return ERR_SKIP;
- }
- err = _code_sign(p_preset, p_path, ent_path);
- }
- } else {
- // Create ZIP.
- if (err == OK) {
- if (ep.step("Making ZIP", 3)) {
- return ERR_SKIP;
- }
- if (FileAccess::exists(p_path)) {
- OS::get_singleton()->move_to_trash(p_path);
- }
-
- FileAccess *dst_f = nullptr;
- zlib_filefunc_def io_dst = zipio_create_io_from_file(&dst_f);
- zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io_dst);
-
- _zip_folder_recursive(zip, EditorPaths::get_singleton()->get_cache_dir(), pkg_name + ".app", pkg_name);
-
- zipClose(zip, nullptr);
- }
- }
-
- bool noto_enabled = p_preset->get("notarization/enable");
- if (err == OK && noto_enabled) {
- if (ep.step("Sending archive for notarization", 4)) {
- return ERR_SKIP;
- }
- err = _notarize(p_preset, p_path);
- }
-
- // Clean up temporary .app dir.
- tmp_app_dir->change_dir(tmp_app_path_name);
- tmp_app_dir->erase_contents_recursive();
- tmp_app_dir->change_dir("..");
- tmp_app_dir->remove(tmp_app_dir_name);
- }
-
- return err;
-}
-
-void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name) {
- String dir = p_root_path.plus_file(p_folder);
-
- DirAccess *da = DirAccess::open(dir);
- da->list_dir_begin();
- String f;
- while ((f = da->get_next()) != "") {
- if (f == "." || f == "..") {
- continue;
- }
- if (da->is_link(f)) {
- OS::Time time = OS::get_singleton()->get_time();
- OS::Date date = OS::get_singleton()->get_date();
-
- zip_fileinfo zipfi;
- zipfi.tmz_date.tm_hour = time.hour;
- zipfi.tmz_date.tm_mday = date.day;
- zipfi.tmz_date.tm_min = time.minute;
- zipfi.tmz_date.tm_mon = date.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, http://www.cplusplus.com/reference/ctime/tm/
- zipfi.tmz_date.tm_sec = time.second;
- zipfi.tmz_date.tm_year = date.year;
- zipfi.dosDate = 0;
- // 0120000: symbolic link type
- // 0000755: permissions rwxr-xr-x
- // 0000644: permissions rw-r--r--
- uint32_t _mode = 0120644;
- zipfi.external_fa = (_mode << 16L) | !(_mode & 0200);
- zipfi.internal_fa = 0;
-
- zipOpenNewFileInZip4(p_zip,
- p_folder.plus_file(f).utf8().get_data(),
- &zipfi,
- nullptr,
- 0,
- nullptr,
- 0,
- nullptr,
- Z_DEFLATED,
- Z_DEFAULT_COMPRESSION,
- 0,
- -MAX_WBITS,
- DEF_MEM_LEVEL,
- Z_DEFAULT_STRATEGY,
- nullptr,
- 0,
- 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions
- 0);
-
- String target = da->read_link(f);
- zipWriteInFileInZip(p_zip, target.utf8().get_data(), target.utf8().size());
- zipCloseFileInZip(p_zip);
- } else if (da->current_is_dir()) {
- _zip_folder_recursive(p_zip, p_root_path, p_folder.plus_file(f), p_pkg_name);
- } else {
- bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name));
-
- OS::Time time = OS::get_singleton()->get_time();
- OS::Date date = OS::get_singleton()->get_date();
-
- zip_fileinfo zipfi;
- zipfi.tmz_date.tm_hour = time.hour;
- zipfi.tmz_date.tm_mday = date.day;
- zipfi.tmz_date.tm_min = time.minute;
- zipfi.tmz_date.tm_mon = date.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, http://www.cplusplus.com/reference/ctime/tm/
- zipfi.tmz_date.tm_sec = time.second;
- zipfi.tmz_date.tm_year = date.year;
- zipfi.dosDate = 0;
- // 0100000: regular file type
- // 0000755: permissions rwxr-xr-x
- // 0000644: permissions rw-r--r--
- uint32_t _mode = (is_executable ? 0100755 : 0100644);
- zipfi.external_fa = (_mode << 16L) | !(_mode & 0200);
- zipfi.internal_fa = 0;
-
- zipOpenNewFileInZip4(p_zip,
- p_folder.plus_file(f).utf8().get_data(),
- &zipfi,
- nullptr,
- 0,
- nullptr,
- 0,
- nullptr,
- Z_DEFLATED,
- Z_DEFAULT_COMPRESSION,
- 0,
- -MAX_WBITS,
- DEF_MEM_LEVEL,
- Z_DEFAULT_STRATEGY,
- nullptr,
- 0,
- 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions
- 0);
-
- Vector<uint8_t> array = FileAccess::get_file_as_array(dir.plus_file(f));
- zipWriteInFileInZip(p_zip, array.ptr(), array.size());
- zipCloseFileInZip(p_zip);
- }
- }
- da->list_dir_end();
- memdelete(da);
-}
-
-bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
- String err;
- bool valid = false;
-
- // Look for export templates (first official, and if defined custom templates).
-
- bool dvalid = exists_export_template("osx.zip", &err);
- bool rvalid = dvalid; // Both in the same ZIP.
-
- if (p_preset->get("custom_template/debug") != "") {
- dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
- if (!dvalid) {
- err += TTR("Custom debug template not found.") + "\n";
- }
- }
- if (p_preset->get("custom_template/release") != "") {
- rvalid = FileAccess::exists(p_preset->get("custom_template/release"));
- if (!rvalid) {
- err += TTR("Custom release template not found.") + "\n";
- }
- }
-
- valid = dvalid || rvalid;
- r_missing_templates = !valid;
-
- String identifier = p_preset->get("application/bundle_identifier");
- String pn_err;
- if (!is_package_name_valid(identifier, &pn_err)) {
- err += TTR("Invalid bundle identifier:") + " " + pn_err + "\n";
- valid = false;
- }
-
- bool sign_enabled = p_preset->get("codesign/enable");
- bool noto_enabled = p_preset->get("notarization/enable");
- if (noto_enabled) {
- if (!sign_enabled) {
- err += TTR("Notarization: code signing required.") + "\n";
- valid = false;
- }
- bool hr_enabled = p_preset->get("codesign/hardened_runtime");
- if (!hr_enabled) {
- err += TTR("Notarization: hardened runtime required.") + "\n";
- valid = false;
- }
- if (p_preset->get("notarization/apple_id_name") == "") {
- err += TTR("Notarization: Apple ID name not specified.") + "\n";
- valid = false;
- }
- if (p_preset->get("notarization/apple_id_password") == "") {
- err += TTR("Notarization: Apple ID password not specified.") + "\n";
- valid = false;
- }
- }
-
- if (!err.is_empty()) {
- r_error = err;
- }
- return valid;
-}
-
-EditorExportPlatformOSX::EditorExportPlatformOSX() {
- Ref<Image> img = memnew(Image(_osx_logo));
- logo.instantiate();
- logo->create_from_image(img);
-}
-
-EditorExportPlatformOSX::~EditorExportPlatformOSX() {
-}
+#include "export_plugin.h"
void register_osx_exporter() {
Ref<EditorExportPlatformOSX> platform;
diff --git a/platform/osx/export/export_plugin.cpp b/platform/osx/export/export_plugin.cpp
new file mode 100644
index 0000000000..53ae1ea6fe
--- /dev/null
+++ b/platform/osx/export/export_plugin.cpp
@@ -0,0 +1,1085 @@
+/*************************************************************************/
+/* export_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "export_plugin.h"
+
+void EditorExportPlatformOSX::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
+ if (p_preset->get("texture_format/s3tc")) {
+ r_features->push_back("s3tc");
+ }
+ if (p_preset->get("texture_format/etc")) {
+ r_features->push_back("etc");
+ }
+ if (p_preset->get("texture_format/etc2")) {
+ r_features->push_back("etc2");
+ }
+
+ r_features->push_back("64");
+}
+
+void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/info"), "Made with Godot Engine"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.png,*.icns"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_category", PROPERTY_HINT_ENUM, "Business,Developer-tools,Education,Entertainment,Finance,Games,Action-games,Adventure-games,Arcade-games,Board-games,Card-games,Casino-games,Dice-games,Educational-games,Family-games,Kids-games,Music-games,Puzzle-games,Racing-games,Role-playing-games,Simulation-games,Sports-games,Strategy-games,Trivia-games,Word-games,Graphics-design,Healthcare-fitness,Lifestyle,Medical,Music,News,Photography,Productivity,Reference,Social-networking,Sports,Travel,Utilities,Video,Weather"), "Games"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/camera_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the camera"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), ""));
+
+#ifdef OSX_ENABLED
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_PLACEHOLDER_TEXT, "Type: Name (ID)"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/hardened_runtime"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/replace_existing_signature"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements/custom_file", PROPERTY_HINT_GLOBAL_FILE, "*.plist"), ""));
+
+ if (!Engine::get_singleton()->has_singleton("GodotSharp")) {
+ // These entitlements are required to run managed code, and are always enabled in Mono builds.
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_jit_code_execution"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_unsigned_executable_memory"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_dyld_environment_variables"), false));
+ }
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/disable_library_validation"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/audio_input"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/camera"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/location"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/address_book"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/calendars"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/photos_library"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/apple_events"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/debugging"), false));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/enabled"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/network_server"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/network_client"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/device_usb"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/device_bluetooth"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_downloads", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_pictures", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_music", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_movies", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "notarization/enable"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Apple ID email"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_password", PROPERTY_HINT_PLACEHOLDER_TEXT, "Enable two-factor authentication and provide app-specific password"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_team_id", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide team ID if your Apple ID belongs to multiple teams"), ""));
+#endif
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), false));
+}
+
+void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source, Vector<uint8_t> &p_dest) {
+ int src_len = p_size * p_size;
+
+ Vector<uint8_t> result;
+ result.resize(src_len * 1.25); //temp vector for rle encoded data, make it 25% larger for worst case scenario
+ int res_size = 0;
+
+ uint8_t buf[128];
+ int buf_size = 0;
+
+ int i = 0;
+ while (i < src_len) {
+ uint8_t cur = p_source.ptr()[i * 4 + p_ch];
+
+ if (i < src_len - 2) {
+ if ((p_source.ptr()[(i + 1) * 4 + p_ch] == cur) && (p_source.ptr()[(i + 2) * 4 + p_ch] == cur)) {
+ if (buf_size > 0) {
+ result.write[res_size++] = (uint8_t)(buf_size - 1);
+ memcpy(&result.write[res_size], &buf, buf_size);
+ res_size += buf_size;
+ buf_size = 0;
+ }
+
+ uint8_t lim = i + 130 >= src_len ? src_len - i - 1 : 130;
+ bool hit_lim = true;
+
+ for (int j = 3; j <= lim; j++) {
+ if (p_source.ptr()[(i + j) * 4 + p_ch] != cur) {
+ hit_lim = false;
+ i = i + j - 1;
+ result.write[res_size++] = (uint8_t)(j - 3 + 0x80);
+ result.write[res_size++] = cur;
+ break;
+ }
+ }
+ if (hit_lim) {
+ result.write[res_size++] = (uint8_t)(lim - 3 + 0x80);
+ result.write[res_size++] = cur;
+ i = i + lim;
+ }
+ } else {
+ buf[buf_size++] = cur;
+ if (buf_size == 128) {
+ result.write[res_size++] = (uint8_t)(buf_size - 1);
+ memcpy(&result.write[res_size], &buf, buf_size);
+ res_size += buf_size;
+ buf_size = 0;
+ }
+ }
+ } else {
+ buf[buf_size++] = cur;
+ result.write[res_size++] = (uint8_t)(buf_size - 1);
+ memcpy(&result.write[res_size], &buf, buf_size);
+ res_size += buf_size;
+ buf_size = 0;
+ }
+
+ i++;
+ }
+
+ int ofs = p_dest.size();
+ p_dest.resize(p_dest.size() + res_size);
+ memcpy(&p_dest.write[ofs], result.ptr(), res_size);
+}
+
+void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) {
+ Ref<ImageTexture> it = memnew(ImageTexture);
+
+ Vector<uint8_t> data;
+
+ data.resize(8);
+ data.write[0] = 'i';
+ data.write[1] = 'c';
+ data.write[2] = 'n';
+ data.write[3] = 's';
+
+ struct MacOSIconInfo {
+ const char *name;
+ const char *mask_name;
+ bool is_png;
+ int size;
+ };
+
+ static const MacOSIconInfo icon_infos[] = {
+ { "ic10", "", true, 1024 }, //1024x1024 32-bit PNG and 512x512@2x 32-bit "retina" PNG
+ { "ic09", "", true, 512 }, //512×512 32-bit PNG
+ { "ic14", "", true, 512 }, //256x256@2x 32-bit "retina" PNG
+ { "ic08", "", true, 256 }, //256×256 32-bit PNG
+ { "ic13", "", true, 256 }, //128x128@2x 32-bit "retina" PNG
+ { "ic07", "", true, 128 }, //128x128 32-bit PNG
+ { "ic12", "", true, 64 }, //32x32@2x 32-bit "retina" PNG
+ { "ic11", "", true, 32 }, //16x16@2x 32-bit "retina" PNG
+ { "il32", "l8mk", false, 32 }, //32x32 24-bit RLE + 8-bit uncompressed mask
+ { "is32", "s8mk", false, 16 } //16x16 24-bit RLE + 8-bit uncompressed mask
+ };
+
+ for (uint64_t i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) {
+ Ref<Image> copy = p_icon; // does this make sense? doesn't this just increase the reference count instead of making a copy? Do we even need a copy?
+ copy->convert(Image::FORMAT_RGBA8);
+ copy->resize(icon_infos[i].size, icon_infos[i].size);
+
+ if (icon_infos[i].is_png) {
+ // Encode PNG icon.
+ it->create_from_image(copy);
+ String path = EditorPaths::get_singleton()->get_cache_dir().plus_file("icon.png");
+ ResourceSaver::save(path, it);
+
+ FileAccess *f = FileAccess::open(path, FileAccess::READ);
+ if (!f) {
+ // Clean up generated file.
+ DirAccess::remove_file_or_error(path);
+ ERR_FAIL();
+ }
+
+ int ofs = data.size();
+ uint64_t len = f->get_length();
+ data.resize(data.size() + len + 8);
+ f->get_buffer(&data.write[ofs + 8], len);
+ memdelete(f);
+ len += 8;
+ len = BSWAP32(len);
+ memcpy(&data.write[ofs], icon_infos[i].name, 4);
+ encode_uint32(len, &data.write[ofs + 4]);
+
+ // Clean up generated file.
+ DirAccess::remove_file_or_error(path);
+
+ } else {
+ Vector<uint8_t> src_data = copy->get_data();
+
+ //encode 24bit RGB RLE icon
+ {
+ int ofs = data.size();
+ data.resize(data.size() + 8);
+
+ _rgba8_to_packbits_encode(0, icon_infos[i].size, src_data, data); // encode R
+ _rgba8_to_packbits_encode(1, icon_infos[i].size, src_data, data); // encode G
+ _rgba8_to_packbits_encode(2, icon_infos[i].size, src_data, data); // encode B
+
+ int len = data.size() - ofs;
+ len = BSWAP32(len);
+ memcpy(&data.write[ofs], icon_infos[i].name, 4);
+ encode_uint32(len, &data.write[ofs + 4]);
+ }
+
+ //encode 8bit mask uncompressed icon
+ {
+ int ofs = data.size();
+ int len = copy->get_width() * copy->get_height();
+ data.resize(data.size() + len + 8);
+
+ for (int j = 0; j < len; j++) {
+ data.write[ofs + 8 + j] = src_data.ptr()[j * 4 + 3];
+ }
+ len += 8;
+ len = BSWAP32(len);
+ memcpy(&data.write[ofs], icon_infos[i].mask_name, 4);
+ encode_uint32(len, &data.write[ofs + 4]);
+ }
+ }
+ }
+
+ uint32_t total_len = data.size();
+ total_len = BSWAP32(total_len);
+ encode_uint32(total_len, &data.write[4]);
+
+ p_data = data;
+}
+
+void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary) {
+ String str;
+ String strnew;
+ str.parse_utf8((const char *)plist.ptr(), plist.size());
+ Vector<String> lines = str.split("\n");
+ for (int i = 0; i < lines.size(); i++) {
+ if (lines[i].find("$binary") != -1) {
+ strnew += lines[i].replace("$binary", p_binary) + "\n";
+ } else if (lines[i].find("$name") != -1) {
+ strnew += lines[i].replace("$name", p_binary) + "\n";
+ } else if (lines[i].find("$info") != -1) {
+ strnew += lines[i].replace("$info", p_preset->get("application/info")) + "\n";
+ } else if (lines[i].find("$bundle_identifier") != -1) {
+ strnew += lines[i].replace("$bundle_identifier", p_preset->get("application/bundle_identifier")) + "\n";
+ } else if (lines[i].find("$short_version") != -1) {
+ strnew += lines[i].replace("$short_version", p_preset->get("application/short_version")) + "\n";
+ } else if (lines[i].find("$version") != -1) {
+ strnew += lines[i].replace("$version", p_preset->get("application/version")) + "\n";
+ } else if (lines[i].find("$signature") != -1) {
+ strnew += lines[i].replace("$signature", p_preset->get("application/signature")) + "\n";
+ } else if (lines[i].find("$app_category") != -1) {
+ String cat = p_preset->get("application/app_category");
+ strnew += lines[i].replace("$app_category", cat.to_lower()) + "\n";
+ } else if (lines[i].find("$copyright") != -1) {
+ strnew += lines[i].replace("$copyright", p_preset->get("application/copyright")) + "\n";
+ } else if (lines[i].find("$highres") != -1) {
+ strnew += lines[i].replace("$highres", p_preset->get("display/high_res") ? "<true/>" : "<false/>") + "\n";
+ } else if (lines[i].find("$camera_usage_description") != -1) {
+ String description = p_preset->get("privacy/camera_usage_description");
+ strnew += lines[i].replace("$camera_usage_description", description) + "\n";
+ } else if (lines[i].find("$microphone_usage_description") != -1) {
+ String description = p_preset->get("privacy/microphone_usage_description");
+ strnew += lines[i].replace("$microphone_usage_description", description) + "\n";
+ } else {
+ strnew += lines[i] + "\n";
+ }
+ }
+
+ CharString cs = strnew.utf8();
+ plist.resize(cs.size() - 1);
+ for (int i = 0; i < cs.size() - 1; i++) {
+ plist.write[i] = cs[i];
+ }
+}
+
+/**
+ If we're running the OSX version of the Godot editor we'll:
+ - export our application bundle to a temporary folder
+ - attempt to code sign it
+ - and then wrap it up in a DMG
+**/
+
+Error EditorExportPlatformOSX::_notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
+#ifdef OSX_ENABLED
+ List<String> args;
+
+ args.push_back("altool");
+ args.push_back("--notarize-app");
+
+ args.push_back("--primary-bundle-id");
+ args.push_back(p_preset->get("application/bundle_identifier"));
+
+ args.push_back("--username");
+ args.push_back(p_preset->get("notarization/apple_id_name"));
+
+ args.push_back("--password");
+ args.push_back(p_preset->get("notarization/apple_id_password"));
+
+ args.push_back("--type");
+ args.push_back("osx");
+
+ if (p_preset->get("notarization/apple_team_id")) {
+ args.push_back("--asc-provider");
+ args.push_back(p_preset->get("notarization/apple_team_id"));
+ }
+
+ args.push_back("--file");
+ args.push_back(p_path);
+
+ String str;
+ Error err = OS::get_singleton()->execute("xcrun", args, &str, nullptr, true);
+ ERR_FAIL_COND_V(err != OK, err);
+
+ print_line("altool (" + p_path + "):\n" + str);
+ if (str.find("RequestUUID") == -1) {
+ EditorNode::add_io_error("altool: " + str);
+ return FAILED;
+ } else {
+ print_line("Note: The notarization process generally takes less than an hour. When the process is completed, you'll receive an email.");
+ print_line(" You can check progress manually by opening a Terminal and running the following command:");
+ print_line(" \"xcrun altool --notarization-history 0 -u <your email> -p <app-specific pwd>\"");
+ }
+
+#endif
+
+ return OK;
+}
+
+Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path) {
+#ifdef OSX_ENABLED
+ List<String> args;
+
+ if (p_preset->get("codesign/timestamp")) {
+ args.push_back("--timestamp");
+ }
+ if (p_preset->get("codesign/hardened_runtime")) {
+ args.push_back("--options");
+ args.push_back("runtime");
+ }
+
+ if (p_path.get_extension() != "dmg") {
+ args.push_back("--entitlements");
+ args.push_back(p_ent_path);
+ }
+
+ PackedStringArray user_args = p_preset->get("codesign/custom_options");
+ for (int i = 0; i < user_args.size(); i++) {
+ String user_arg = user_args[i].strip_edges();
+ if (!user_arg.is_empty()) {
+ args.push_back(user_arg);
+ }
+ }
+
+ args.push_back("-s");
+ if (p_preset->get("codesign/identity") == "") {
+ args.push_back("-");
+ } else {
+ args.push_back(p_preset->get("codesign/identity"));
+ }
+
+ args.push_back("-v"); /* provide some more feedback */
+
+ if (p_preset->get("codesign/replace_existing_signature")) {
+ args.push_back("-f");
+ }
+
+ args.push_back(p_path);
+
+ String str;
+ Error err = OS::get_singleton()->execute("codesign", args, &str, nullptr, true);
+ ERR_FAIL_COND_V(err != OK, err);
+
+ print_line("codesign (" + p_path + "):\n" + str);
+ if (str.find("no identity found") != -1) {
+ EditorNode::add_io_error("codesign: no identity found");
+ return FAILED;
+ }
+ if ((str.find("unrecognized blob type") != -1) || (str.find("cannot read entitlement data") != -1)) {
+ EditorNode::add_io_error("codesign: invalid entitlements file");
+ return FAILED;
+ }
+#endif
+
+ return OK;
+}
+
+Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name) {
+ List<String> args;
+
+ if (FileAccess::exists(p_dmg_path)) {
+ OS::get_singleton()->move_to_trash(p_dmg_path);
+ }
+
+ args.push_back("create");
+ args.push_back(p_dmg_path);
+ args.push_back("-volname");
+ args.push_back(p_pkg_name);
+ args.push_back("-fs");
+ args.push_back("HFS+");
+ args.push_back("-srcfolder");
+ args.push_back(p_app_path_name);
+
+ String str;
+ Error err = OS::get_singleton()->execute("hdiutil", args, &str, nullptr, true);
+ ERR_FAIL_COND_V(err != OK, err);
+
+ print_line("hdiutil returned: " + str);
+ if (str.find("create failed") != -1) {
+ if (str.find("File exists") != -1) {
+ EditorNode::add_io_error("hdiutil: create failed - file exists");
+ } else {
+ EditorNode::add_io_error("hdiutil: create failed");
+ }
+ return FAILED;
+ }
+
+ return OK;
+}
+
+Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
+ ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
+
+ String src_pkg_name;
+
+ EditorProgress ep("export", "Exporting for OSX", 3, true);
+
+ if (p_debug) {
+ src_pkg_name = p_preset->get("custom_template/debug");
+ } else {
+ src_pkg_name = p_preset->get("custom_template/release");
+ }
+
+ if (src_pkg_name == "") {
+ String err;
+ src_pkg_name = find_export_template("osx.zip", &err);
+ if (src_pkg_name == "") {
+ EditorNode::add_io_error(err);
+ return ERR_FILE_NOT_FOUND;
+ }
+ }
+
+ if (!DirAccess::exists(p_path.get_base_dir())) {
+ return ERR_FILE_BAD_PATH;
+ }
+
+ FileAccess *src_f = nullptr;
+ zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
+
+ if (ep.step("Creating app", 0)) {
+ return ERR_SKIP;
+ }
+
+ unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io);
+ if (!src_pkg_zip) {
+ EditorNode::add_io_error("Could not find template app to export:\n" + src_pkg_name);
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ int ret = unzGoToFirstFile(src_pkg_zip);
+
+ String binary_to_use = "godot_osx_" + String(p_debug ? "debug" : "release") + ".64";
+
+ String pkg_name;
+ if (p_preset->get("application/name") != "") {
+ pkg_name = p_preset->get("application/name"); // app_name
+ } else if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") {
+ pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
+ } else {
+ pkg_name = "Unnamed";
+ }
+
+ pkg_name = OS::get_singleton()->get_safe_dir_name(pkg_name);
+
+ String export_format = use_dmg() && p_path.ends_with("dmg") ? "dmg" : "zip";
+
+ // Create our application bundle.
+ String tmp_app_dir_name = pkg_name + ".app";
+ String tmp_app_path_name = EditorPaths::get_singleton()->get_cache_dir().plus_file(tmp_app_dir_name);
+ print_line("Exporting to " + tmp_app_path_name);
+
+ Error err = OK;
+
+ DirAccessRef tmp_app_dir = DirAccess::create_for_path(tmp_app_path_name);
+ if (!tmp_app_dir) {
+ err = ERR_CANT_CREATE;
+ }
+
+ // Create our folder structure.
+ if (err == OK) {
+ print_line("Creating " + tmp_app_path_name + "/Contents/MacOS");
+ err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/MacOS");
+ }
+
+ if (err == OK) {
+ print_line("Creating " + tmp_app_path_name + "/Contents/Frameworks");
+ err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Frameworks");
+ }
+
+ if (err == OK) {
+ print_line("Creating " + tmp_app_path_name + "/Contents/Resources");
+ err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Resources");
+ }
+
+ // Now process our template.
+ bool found_binary = false;
+ int total_size = 0;
+ Vector<String> dylibs_found;
+
+ while (ret == UNZ_OK && err == OK) {
+ bool is_execute = false;
+
+ // Get filename.
+ unz_file_info info;
+ char fname[16384];
+ ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, nullptr, 0, nullptr, 0);
+
+ String file = fname;
+
+ Vector<uint8_t> data;
+ data.resize(info.uncompressed_size);
+
+ // Read.
+ unzOpenCurrentFile(src_pkg_zip);
+ unzReadCurrentFile(src_pkg_zip, data.ptrw(), data.size());
+ unzCloseCurrentFile(src_pkg_zip);
+
+ // Write.
+ file = file.replace_first("osx_template.app/", "");
+
+ if (file == "Contents/Info.plist") {
+ _fix_plist(p_preset, data, pkg_name);
+ }
+
+ if (file.begins_with("Contents/MacOS/godot_")) {
+ if (file != "Contents/MacOS/" + binary_to_use) {
+ ret = unzGoToNextFile(src_pkg_zip);
+ continue; // skip
+ }
+ found_binary = true;
+ is_execute = true;
+ file = "Contents/MacOS/" + pkg_name;
+ }
+
+ if (file == "Contents/Resources/icon.icns") {
+ // See if there is an icon.
+ String iconpath;
+ if (p_preset->get("application/icon") != "") {
+ iconpath = p_preset->get("application/icon");
+ } else {
+ iconpath = ProjectSettings::get_singleton()->get("application/config/icon");
+ }
+
+ if (iconpath != "") {
+ if (iconpath.get_extension() == "icns") {
+ FileAccess *icon = FileAccess::open(iconpath, FileAccess::READ);
+ if (icon) {
+ data.resize(icon->get_length());
+ icon->get_buffer(&data.write[0], icon->get_length());
+ icon->close();
+ memdelete(icon);
+ }
+ } else {
+ Ref<Image> icon;
+ icon.instantiate();
+ icon->load(iconpath);
+ if (!icon->is_empty()) {
+ _make_icon(icon, data);
+ }
+ }
+ }
+ }
+
+ if (data.size() > 0) {
+ if (file.find("/data.mono.osx.64.release_debug/") != -1) {
+ if (!p_debug) {
+ ret = unzGoToNextFile(src_pkg_zip);
+ continue; // skip
+ }
+ file = file.replace("/data.mono.osx.64.release_debug/", "/GodotSharp/");
+ }
+ if (file.find("/data.mono.osx.64.release/") != -1) {
+ if (p_debug) {
+ ret = unzGoToNextFile(src_pkg_zip);
+ continue; // skip
+ }
+ file = file.replace("/data.mono.osx.64.release/", "/GodotSharp/");
+ }
+
+ if (file.ends_with(".dylib")) {
+ dylibs_found.push_back(file);
+ }
+
+ print_line("ADDING: " + file + " size: " + itos(data.size()));
+ total_size += data.size();
+
+ // Write it into our application bundle.
+ file = tmp_app_path_name.plus_file(file);
+ if (err == OK) {
+ err = tmp_app_dir->make_dir_recursive(file.get_base_dir());
+ }
+ if (err == OK) {
+ FileAccess *f = FileAccess::open(file, FileAccess::WRITE);
+ if (f) {
+ f->store_buffer(data.ptr(), data.size());
+ f->close();
+ if (is_execute) {
+ // chmod with 0755 if the file is executable.
+ FileAccess::set_unix_permissions(file, 0755);
+ }
+ memdelete(f);
+ } else {
+ err = ERR_CANT_CREATE;
+ }
+ }
+ }
+
+ ret = unzGoToNextFile(src_pkg_zip);
+ }
+
+ // We're done with our source zip.
+ unzClose(src_pkg_zip);
+
+ if (!found_binary) {
+ ERR_PRINT("Requested template binary '" + binary_to_use + "' not found. It might be missing from your template archive.");
+ err = ERR_FILE_NOT_FOUND;
+ }
+
+ if (err == OK) {
+ if (ep.step("Making PKG", 1)) {
+ return ERR_SKIP;
+ }
+
+ String pack_path = tmp_app_path_name + "/Contents/Resources/" + pkg_name + ".pck";
+ Vector<SharedObject> shared_objects;
+ err = save_pack(p_preset, pack_path, &shared_objects);
+
+ // See if we can code sign our new package.
+ bool sign_enabled = p_preset->get("codesign/enable");
+
+ String ent_path = p_preset->get("codesign/entitlements/custom_file");
+ if (sign_enabled && (ent_path == "")) {
+ ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + ".entitlements");
+
+ FileAccess *ent_f = FileAccess::open(ent_path, FileAccess::WRITE);
+ if (ent_f) {
+ ent_f->store_line("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ ent_f->store_line("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
+ ent_f->store_line("<plist version=\"1.0\">");
+ ent_f->store_line("<dict>");
+ if (Engine::get_singleton()->has_singleton("GodotSharp")) {
+ // These entitlements are required to run managed code, and are always enabled in Mono builds.
+ ent_f->store_line("<key>com.apple.security.cs.allow-jit</key>");
+ ent_f->store_line("<true/>");
+ ent_f->store_line("<key>com.apple.security.cs.allow-unsigned-executable-memory</key>");
+ ent_f->store_line("<true/>");
+ ent_f->store_line("<key>com.apple.security.cs.allow-dyld-environment-variables</key>");
+ ent_f->store_line("<true/>");
+ } else {
+ if ((bool)p_preset->get("codesign/entitlements/allow_jit_code_execution")) {
+ ent_f->store_line("<key>com.apple.security.cs.allow-jit</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/allow_unsigned_executable_memory")) {
+ ent_f->store_line("<key>com.apple.security.cs.allow-unsigned-executable-memory</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/allow_dyld_environment_variables")) {
+ ent_f->store_line("<key>com.apple.security.cs.allow-dyld-environment-variables</key>");
+ ent_f->store_line("<true/>");
+ }
+ }
+
+ if ((bool)p_preset->get("codesign/entitlements/disable_library_validation")) {
+ ent_f->store_line("<key>com.apple.security.cs.disable-library-validation</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/audio_input")) {
+ ent_f->store_line("<key>com.apple.security.device.audio-input</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/camera")) {
+ ent_f->store_line("<key>com.apple.security.device.camera</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/location")) {
+ ent_f->store_line("<key>com.apple.security.personal-information.location</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/address_book")) {
+ ent_f->store_line("<key>com.apple.security.personal-information.addressbook</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/calendars")) {
+ ent_f->store_line("<key>com.apple.security.personal-information.calendars</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/photos_library")) {
+ ent_f->store_line("<key>com.apple.security.personal-information.photos-library</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/apple_events")) {
+ ent_f->store_line("<key>com.apple.security.automation.apple-events</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/debugging")) {
+ ent_f->store_line("<key>com.apple.security.get-task-allow</key>");
+ ent_f->store_line("<true/>");
+ }
+
+ if ((bool)p_preset->get("codesign/entitlements/app_sandbox/enabled")) {
+ ent_f->store_line("<key>com.apple.security.app-sandbox</key>");
+ ent_f->store_line("<true/>");
+
+ if ((bool)p_preset->get("codesign/entitlements/app_sandbox/network_server")) {
+ ent_f->store_line("<key>com.apple.security.network.server</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/app_sandbox/network_client")) {
+ ent_f->store_line("<key>com.apple.security.network.client</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/app_sandbox/device_usb")) {
+ ent_f->store_line("<key>com.apple.security.device.usb</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/app_sandbox/device_bluetooth")) {
+ ent_f->store_line("<key>com.apple.security.device.bluetooth</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_downloads") == 1) {
+ ent_f->store_line("<key>com.apple.security.files.downloads.read-only</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_downloads") == 2) {
+ ent_f->store_line("<key>com.apple.security.files.downloads.read-write</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_pictures") == 1) {
+ ent_f->store_line("<key>com.apple.security.files.pictures.read-only</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_pictures") == 2) {
+ ent_f->store_line("<key>com.apple.security.files.pictures.read-write</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_music") == 1) {
+ ent_f->store_line("<key>com.apple.security.files.music.read-only</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_music") == 2) {
+ ent_f->store_line("<key>com.apple.security.files.music.read-write</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_movies") == 1) {
+ ent_f->store_line("<key>com.apple.security.files.movies.read-only</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_movies") == 2) {
+ ent_f->store_line("<key>com.apple.security.files.movies.read-write</key>");
+ ent_f->store_line("<true/>");
+ }
+ }
+
+ ent_f->store_line("</dict>");
+ ent_f->store_line("</plist>");
+
+ ent_f->close();
+ memdelete(ent_f);
+ } else {
+ err = ERR_CANT_CREATE;
+ }
+ }
+
+ if (err == OK) {
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ for (int i = 0; i < shared_objects.size(); i++) {
+ String src_path = ProjectSettings::get_singleton()->globalize_path(shared_objects[i].path);
+ if (da->dir_exists(src_path)) {
+#ifndef UNIX_ENABLED
+ WARN_PRINT("Relative symlinks are not supported, exported " + src_path.get_file() + " might be broken!");
+#endif
+ print_verbose("export framework: " + src_path + " -> " + tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file());
+ err = da->make_dir_recursive(tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file());
+ if (err == OK) {
+ err = da->copy_dir(src_path, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file(), -1, true);
+ }
+ } else {
+ print_verbose("export dylib: " + src_path + " -> " + tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file());
+ err = da->copy(src_path, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file());
+ }
+ if (err == OK && sign_enabled) {
+ err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file(), ent_path);
+ }
+ }
+ memdelete(da);
+ }
+
+ if (sign_enabled) {
+ for (int i = 0; i < dylibs_found.size(); i++) {
+ if (err == OK) {
+ err = _code_sign(p_preset, tmp_app_path_name + "/" + dylibs_found[i], ent_path);
+ }
+ }
+ }
+
+ if (err == OK && sign_enabled) {
+ if (ep.step("Code signing bundle", 2)) {
+ return ERR_SKIP;
+ }
+ err = _code_sign(p_preset, tmp_app_path_name + "/Contents/MacOS/" + pkg_name, ent_path);
+ }
+
+ if (export_format == "dmg") {
+ // Create a DMG.
+ if (err == OK) {
+ if (ep.step("Making DMG", 3)) {
+ return ERR_SKIP;
+ }
+ err = _create_dmg(p_path, pkg_name, tmp_app_path_name);
+ }
+ // Sign DMG.
+ if (err == OK && sign_enabled) {
+ if (ep.step("Code signing DMG", 3)) {
+ return ERR_SKIP;
+ }
+ err = _code_sign(p_preset, p_path, ent_path);
+ }
+ } else {
+ // Create ZIP.
+ if (err == OK) {
+ if (ep.step("Making ZIP", 3)) {
+ return ERR_SKIP;
+ }
+ if (FileAccess::exists(p_path)) {
+ OS::get_singleton()->move_to_trash(p_path);
+ }
+
+ FileAccess *dst_f = nullptr;
+ zlib_filefunc_def io_dst = zipio_create_io_from_file(&dst_f);
+ zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io_dst);
+
+ _zip_folder_recursive(zip, EditorPaths::get_singleton()->get_cache_dir(), pkg_name + ".app", pkg_name);
+
+ zipClose(zip, nullptr);
+ }
+ }
+
+ bool noto_enabled = p_preset->get("notarization/enable");
+ if (err == OK && noto_enabled) {
+ if (ep.step("Sending archive for notarization", 4)) {
+ return ERR_SKIP;
+ }
+ err = _notarize(p_preset, p_path);
+ }
+
+ // Clean up temporary .app dir.
+ tmp_app_dir->change_dir(tmp_app_path_name);
+ tmp_app_dir->erase_contents_recursive();
+ tmp_app_dir->change_dir("..");
+ tmp_app_dir->remove(tmp_app_dir_name);
+ }
+
+ return err;
+}
+
+void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name) {
+ String dir = p_root_path.plus_file(p_folder);
+
+ DirAccess *da = DirAccess::open(dir);
+ da->list_dir_begin();
+ String f;
+ while ((f = da->get_next()) != "") {
+ if (f == "." || f == "..") {
+ continue;
+ }
+ if (da->is_link(f)) {
+ OS::Time time = OS::get_singleton()->get_time();
+ OS::Date date = OS::get_singleton()->get_date();
+
+ zip_fileinfo zipfi;
+ zipfi.tmz_date.tm_hour = time.hour;
+ zipfi.tmz_date.tm_mday = date.day;
+ zipfi.tmz_date.tm_min = time.minute;
+ zipfi.tmz_date.tm_mon = date.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, http://www.cplusplus.com/reference/ctime/tm/
+ zipfi.tmz_date.tm_sec = time.second;
+ zipfi.tmz_date.tm_year = date.year;
+ zipfi.dosDate = 0;
+ // 0120000: symbolic link type
+ // 0000755: permissions rwxr-xr-x
+ // 0000644: permissions rw-r--r--
+ uint32_t _mode = 0120644;
+ zipfi.external_fa = (_mode << 16L) | !(_mode & 0200);
+ zipfi.internal_fa = 0;
+
+ zipOpenNewFileInZip4(p_zip,
+ p_folder.plus_file(f).utf8().get_data(),
+ &zipfi,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ nullptr,
+ Z_DEFLATED,
+ Z_DEFAULT_COMPRESSION,
+ 0,
+ -MAX_WBITS,
+ DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY,
+ nullptr,
+ 0,
+ 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions
+ 0);
+
+ String target = da->read_link(f);
+ zipWriteInFileInZip(p_zip, target.utf8().get_data(), target.utf8().size());
+ zipCloseFileInZip(p_zip);
+ } else if (da->current_is_dir()) {
+ _zip_folder_recursive(p_zip, p_root_path, p_folder.plus_file(f), p_pkg_name);
+ } else {
+ bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name));
+
+ OS::Time time = OS::get_singleton()->get_time();
+ OS::Date date = OS::get_singleton()->get_date();
+
+ zip_fileinfo zipfi;
+ zipfi.tmz_date.tm_hour = time.hour;
+ zipfi.tmz_date.tm_mday = date.day;
+ zipfi.tmz_date.tm_min = time.minute;
+ zipfi.tmz_date.tm_mon = date.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, http://www.cplusplus.com/reference/ctime/tm/
+ zipfi.tmz_date.tm_sec = time.second;
+ zipfi.tmz_date.tm_year = date.year;
+ zipfi.dosDate = 0;
+ // 0100000: regular file type
+ // 0000755: permissions rwxr-xr-x
+ // 0000644: permissions rw-r--r--
+ uint32_t _mode = (is_executable ? 0100755 : 0100644);
+ zipfi.external_fa = (_mode << 16L) | !(_mode & 0200);
+ zipfi.internal_fa = 0;
+
+ zipOpenNewFileInZip4(p_zip,
+ p_folder.plus_file(f).utf8().get_data(),
+ &zipfi,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ nullptr,
+ Z_DEFLATED,
+ Z_DEFAULT_COMPRESSION,
+ 0,
+ -MAX_WBITS,
+ DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY,
+ nullptr,
+ 0,
+ 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions
+ 0);
+
+ Vector<uint8_t> array = FileAccess::get_file_as_array(dir.plus_file(f));
+ zipWriteInFileInZip(p_zip, array.ptr(), array.size());
+ zipCloseFileInZip(p_zip);
+ }
+ }
+ da->list_dir_end();
+ memdelete(da);
+}
+
+bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+ String err;
+ bool valid = false;
+
+ // Look for export templates (first official, and if defined custom templates).
+
+ bool dvalid = exists_export_template("osx.zip", &err);
+ bool rvalid = dvalid; // Both in the same ZIP.
+
+ if (p_preset->get("custom_template/debug") != "") {
+ dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
+ if (!dvalid) {
+ err += TTR("Custom debug template not found.") + "\n";
+ }
+ }
+ if (p_preset->get("custom_template/release") != "") {
+ rvalid = FileAccess::exists(p_preset->get("custom_template/release"));
+ if (!rvalid) {
+ err += TTR("Custom release template not found.") + "\n";
+ }
+ }
+
+ valid = dvalid || rvalid;
+ r_missing_templates = !valid;
+
+ String identifier = p_preset->get("application/bundle_identifier");
+ String pn_err;
+ if (!is_package_name_valid(identifier, &pn_err)) {
+ err += TTR("Invalid bundle identifier:") + " " + pn_err + "\n";
+ valid = false;
+ }
+
+ bool sign_enabled = p_preset->get("codesign/enable");
+ bool noto_enabled = p_preset->get("notarization/enable");
+ if (noto_enabled) {
+ if (!sign_enabled) {
+ err += TTR("Notarization: code signing required.") + "\n";
+ valid = false;
+ }
+ bool hr_enabled = p_preset->get("codesign/hardened_runtime");
+ if (!hr_enabled) {
+ err += TTR("Notarization: hardened runtime required.") + "\n";
+ valid = false;
+ }
+ if (p_preset->get("notarization/apple_id_name") == "") {
+ err += TTR("Notarization: Apple ID name not specified.") + "\n";
+ valid = false;
+ }
+ if (p_preset->get("notarization/apple_id_password") == "") {
+ err += TTR("Notarization: Apple ID password not specified.") + "\n";
+ valid = false;
+ }
+ }
+
+ if (!err.is_empty()) {
+ r_error = err;
+ }
+ return valid;
+}
+
+EditorExportPlatformOSX::EditorExportPlatformOSX() {
+ Ref<Image> img = memnew(Image(_osx_logo));
+ logo.instantiate();
+ logo->create_from_image(img);
+}
+
+EditorExportPlatformOSX::~EditorExportPlatformOSX() {
+}
diff --git a/platform/osx/export/export_plugin.h b/platform/osx/export/export_plugin.h
new file mode 100644
index 0000000000..cd85ce2aad
--- /dev/null
+++ b/platform/osx/export/export_plugin.h
@@ -0,0 +1,128 @@
+/*************************************************************************/
+/* export_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef OSX_EXPORT_PLUGIN_H
+#define OSX_EXPORT_PLUGIN_H
+
+#include "core/config/project_settings.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
+#include "core/io/marshalls.h"
+#include "core/io/resource_saver.h"
+#include "core/io/zip_io.h"
+#include "core/os/os.h"
+#include "core/version.h"
+#include "editor/editor_export.h"
+#include "editor/editor_node.h"
+#include "editor/editor_settings.h"
+#include "platform/osx/logo.gen.h"
+
+#include <sys/stat.h>
+
+class EditorExportPlatformOSX : public EditorExportPlatform {
+ GDCLASS(EditorExportPlatformOSX, EditorExportPlatform);
+
+ int version_code = 0;
+
+ Ref<ImageTexture> logo;
+
+ void _fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary);
+ void _make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data);
+
+ Error _notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path);
+ Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path);
+ Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name);
+ void _zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name);
+
+#ifdef OSX_ENABLED
+ bool use_codesign() const { return true; }
+ bool use_dmg() const { return true; }
+#else
+ bool use_codesign() const { return false; }
+ bool use_dmg() const { return false; }
+#endif
+ bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const {
+ String pname = p_package;
+
+ if (pname.length() == 0) {
+ if (r_error) {
+ *r_error = TTR("Identifier is missing.");
+ }
+ return false;
+ }
+
+ for (int i = 0; i < pname.length(); i++) {
+ char32_t c = pname[i];
+ if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '.')) {
+ if (r_error) {
+ *r_error = vformat(TTR("The character '%s' is not allowed in Identifier."), String::chr(c));
+ }
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+protected:
+ virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) override;
+ virtual void get_export_options(List<ExportOption> *r_options) override;
+
+public:
+ virtual String get_name() const override { return "macOS"; }
+ virtual String get_os_name() const override { return "macOS"; }
+ virtual Ref<Texture2D> get_logo() const override { return logo; }
+
+ virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override {
+ List<String> list;
+ if (use_dmg()) {
+ list.push_back("dmg");
+ }
+ list.push_back("zip");
+ return list;
+ }
+ virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
+
+ virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+
+ virtual void get_platform_features(List<String> *r_features) override {
+ r_features->push_back("pc");
+ r_features->push_back("s3tc");
+ r_features->push_back("macOS");
+ }
+
+ virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) override {
+ }
+
+ EditorExportPlatformOSX();
+ ~EditorExportPlatformOSX();
+};
+
+#endif
diff --git a/platform/uwp/export/app_packager.cpp b/platform/uwp/export/app_packager.cpp
new file mode 100644
index 0000000000..39a2693f75
--- /dev/null
+++ b/platform/uwp/export/app_packager.cpp
@@ -0,0 +1,474 @@
+/*************************************************************************/
+/* app_packager.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "app_packager.h"
+
+String AppxPackager::hash_block(const uint8_t *p_block_data, size_t p_block_len) {
+ unsigned char hash[32];
+ char base64[45];
+
+ CryptoCore::sha256(p_block_data, p_block_len, hash);
+ size_t len = 0;
+ CryptoCore::b64_encode((unsigned char *)base64, 45, &len, (unsigned char *)hash, 32);
+ base64[44] = '\0';
+
+ return String(base64);
+}
+
+void AppxPackager::make_block_map(const String &p_path) {
+ FileAccess *tmp_file = FileAccess::open(p_path, FileAccess::WRITE);
+
+ tmp_file->store_string("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
+ tmp_file->store_string("<BlockMap xmlns=\"http://schemas.microsoft.com/appx/2010/blockmap\" HashMethod=\"http://www.w3.org/2001/04/xmlenc#sha256\">");
+
+ for (int i = 0; i < file_metadata.size(); i++) {
+ FileMeta file = file_metadata[i];
+
+ tmp_file->store_string(
+ "<File Name=\"" + file.name.replace("/", "\\") + "\" Size=\"" + itos(file.uncompressed_size) + "\" LfhSize=\"" + itos(file.lfh_size) + "\">");
+
+ for (int j = 0; j < file.hashes.size(); j++) {
+ tmp_file->store_string("<Block Hash=\"" + file.hashes[j].base64_hash + "\" ");
+ if (file.compressed) {
+ tmp_file->store_string("Size=\"" + itos(file.hashes[j].compressed_size) + "\" ");
+ }
+ tmp_file->store_string("/>");
+ }
+
+ tmp_file->store_string("</File>");
+ }
+
+ tmp_file->store_string("</BlockMap>");
+
+ tmp_file->close();
+ memdelete(tmp_file);
+}
+
+String AppxPackager::content_type(String p_extension) {
+ if (p_extension == "png") {
+ return "image/png";
+ } else if (p_extension == "jpg") {
+ return "image/jpg";
+ } else if (p_extension == "xml") {
+ return "application/xml";
+ } else if (p_extension == "exe" || p_extension == "dll") {
+ return "application/x-msdownload";
+ } else {
+ return "application/octet-stream";
+ }
+}
+
+void AppxPackager::make_content_types(const String &p_path) {
+ FileAccess *tmp_file = FileAccess::open(p_path, FileAccess::WRITE);
+
+ tmp_file->store_string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ tmp_file->store_string("<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">");
+
+ Map<String, String> types;
+
+ for (int i = 0; i < file_metadata.size(); i++) {
+ String ext = file_metadata[i].name.get_extension().to_lower();
+
+ if (types.has(ext)) {
+ continue;
+ }
+
+ types[ext] = content_type(ext);
+
+ tmp_file->store_string("<Default Extension=\"" + ext + "\" ContentType=\"" + types[ext] + "\" />");
+ }
+
+ // Appx signature file
+ tmp_file->store_string("<Default Extension=\"p7x\" ContentType=\"application/octet-stream\" />");
+
+ // Override for package files
+ tmp_file->store_string("<Override PartName=\"/AppxManifest.xml\" ContentType=\"application/vnd.ms-appx.manifest+xml\" />");
+ tmp_file->store_string("<Override PartName=\"/AppxBlockMap.xml\" ContentType=\"application/vnd.ms-appx.blockmap+xml\" />");
+ tmp_file->store_string("<Override PartName=\"/AppxSignature.p7x\" ContentType=\"application/vnd.ms-appx.signature\" />");
+ tmp_file->store_string("<Override PartName=\"/AppxMetadata/CodeIntegrity.cat\" ContentType=\"application/vnd.ms-pkiseccat\" />");
+
+ tmp_file->store_string("</Types>");
+
+ tmp_file->close();
+ memdelete(tmp_file);
+}
+
+Vector<uint8_t> AppxPackager::make_file_header(FileMeta p_file_meta) {
+ Vector<uint8_t> buf;
+ buf.resize(BASE_FILE_HEADER_SIZE + p_file_meta.name.length());
+
+ int offs = 0;
+ // Write magic
+ offs += buf_put_int32(FILE_HEADER_MAGIC, &buf.write[offs]);
+
+ // Version
+ offs += buf_put_int16(ZIP_VERSION, &buf.write[offs]);
+
+ // Special flag
+ offs += buf_put_int16(GENERAL_PURPOSE, &buf.write[offs]);
+
+ // Compression
+ offs += buf_put_int16(p_file_meta.compressed ? Z_DEFLATED : 0, &buf.write[offs]);
+
+ // File date and time
+ offs += buf_put_int32(0, &buf.write[offs]);
+
+ // CRC-32
+ offs += buf_put_int32(p_file_meta.file_crc32, &buf.write[offs]);
+
+ // Compressed size
+ offs += buf_put_int32(p_file_meta.compressed_size, &buf.write[offs]);
+
+ // Uncompressed size
+ offs += buf_put_int32(p_file_meta.uncompressed_size, &buf.write[offs]);
+
+ // File name length
+ offs += buf_put_int16(p_file_meta.name.length(), &buf.write[offs]);
+
+ // Extra data length
+ offs += buf_put_int16(0, &buf.write[offs]);
+
+ // File name
+ offs += buf_put_string(p_file_meta.name, &buf.write[offs]);
+
+ // Done!
+ return buf;
+}
+
+void AppxPackager::store_central_dir_header(const FileMeta &p_file, bool p_do_hash) {
+ Vector<uint8_t> &buf = central_dir_data;
+ int offs = buf.size();
+ buf.resize(buf.size() + BASE_CENTRAL_DIR_SIZE + p_file.name.length());
+
+ // Write magic
+ offs += buf_put_int32(CENTRAL_DIR_MAGIC, &buf.write[offs]);
+
+ // ZIP versions
+ offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf.write[offs]);
+ offs += buf_put_int16(ZIP_VERSION, &buf.write[offs]);
+
+ // General purpose flag
+ offs += buf_put_int16(GENERAL_PURPOSE, &buf.write[offs]);
+
+ // Compression
+ offs += buf_put_int16(p_file.compressed ? Z_DEFLATED : 0, &buf.write[offs]);
+
+ // Modification date/time
+ offs += buf_put_int32(0, &buf.write[offs]);
+
+ // Crc-32
+ offs += buf_put_int32(p_file.file_crc32, &buf.write[offs]);
+
+ // File sizes
+ offs += buf_put_int32(p_file.compressed_size, &buf.write[offs]);
+ offs += buf_put_int32(p_file.uncompressed_size, &buf.write[offs]);
+
+ // File name length
+ offs += buf_put_int16(p_file.name.length(), &buf.write[offs]);
+
+ // Extra field length
+ offs += buf_put_int16(0, &buf.write[offs]);
+
+ // Comment length
+ offs += buf_put_int16(0, &buf.write[offs]);
+
+ // Disk number start, internal/external file attributes
+ for (int i = 0; i < 8; i++) {
+ buf.write[offs++] = 0;
+ }
+
+ // Relative offset
+ offs += buf_put_int32(p_file.zip_offset, &buf.write[offs]);
+
+ // File name
+ offs += buf_put_string(p_file.name, &buf.write[offs]);
+
+ // Done!
+}
+
+Vector<uint8_t> AppxPackager::make_end_of_central_record() {
+ Vector<uint8_t> buf;
+ buf.resize(ZIP64_END_OF_CENTRAL_DIR_SIZE + 12 + END_OF_CENTRAL_DIR_SIZE); // Size plus magic
+
+ int offs = 0;
+
+ // Write magic
+ offs += buf_put_int32(ZIP64_END_OF_CENTRAL_DIR_MAGIC, &buf.write[offs]);
+
+ // Size of this record
+ offs += buf_put_int64(ZIP64_END_OF_CENTRAL_DIR_SIZE, &buf.write[offs]);
+
+ // Version (yes, twice)
+ offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf.write[offs]);
+ offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf.write[offs]);
+
+ // Disk number
+ for (int i = 0; i < 8; i++) {
+ buf.write[offs++] = 0;
+ }
+
+ // Number of entries (total and per disk)
+ offs += buf_put_int64(file_metadata.size(), &buf.write[offs]);
+ offs += buf_put_int64(file_metadata.size(), &buf.write[offs]);
+
+ // Size of central dir
+ offs += buf_put_int64(central_dir_data.size(), &buf.write[offs]);
+
+ // Central dir offset
+ offs += buf_put_int64(central_dir_offset, &buf.write[offs]);
+
+ ////// ZIP64 locator
+
+ // Write magic for zip64 central dir locator
+ offs += buf_put_int32(ZIP64_END_DIR_LOCATOR_MAGIC, &buf.write[offs]);
+
+ // Disk number
+ for (int i = 0; i < 4; i++) {
+ buf.write[offs++] = 0;
+ }
+
+ // Relative offset
+ offs += buf_put_int64(end_of_central_dir_offset, &buf.write[offs]);
+
+ // Number of disks
+ offs += buf_put_int32(1, &buf.write[offs]);
+
+ /////// End of zip directory
+
+ // Write magic for end central dir
+ offs += buf_put_int32(END_OF_CENTRAL_DIR_MAGIC, &buf.write[offs]);
+
+ // Dummy stuff for Zip64
+ for (int i = 0; i < 4; i++) {
+ buf.write[offs++] = 0x0;
+ }
+ for (int i = 0; i < 12; i++) {
+ buf.write[offs++] = 0xFF;
+ }
+
+ // Size of comments
+ for (int i = 0; i < 2; i++) {
+ buf.write[offs++] = 0;
+ }
+
+ // Done!
+ return buf;
+}
+
+void AppxPackager::init(FileAccess *p_fa) {
+ package = p_fa;
+ central_dir_offset = 0;
+ end_of_central_dir_offset = 0;
+}
+
+Error AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t p_len, int p_file_no, int p_total_files, bool p_compress) {
+ if (p_file_no >= 1 && p_total_files >= 1) {
+ if (EditorNode::progress_task_step(progress_task, "File: " + p_file_name, (p_file_no * 100) / p_total_files)) {
+ return ERR_SKIP;
+ }
+ }
+
+ FileMeta meta;
+ meta.name = p_file_name;
+ meta.uncompressed_size = p_len;
+ meta.compressed_size = p_len;
+ meta.compressed = p_compress;
+ meta.zip_offset = package->get_position();
+
+ Vector<uint8_t> file_buffer;
+
+ // Data for compression
+ z_stream strm;
+ FileAccess *strm_f = nullptr;
+ Vector<uint8_t> strm_in;
+ strm_in.resize(BLOCK_SIZE);
+ Vector<uint8_t> strm_out;
+
+ if (p_compress) {
+ strm.zalloc = zipio_alloc;
+ strm.zfree = zipio_free;
+ strm.opaque = &strm_f;
+
+ strm_out.resize(BLOCK_SIZE + 8);
+
+ deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
+ }
+
+ int step = 0;
+
+ while (p_len - step > 0) {
+ size_t block_size = (p_len - step) > BLOCK_SIZE ? (size_t)BLOCK_SIZE : (p_len - step);
+
+ for (uint64_t i = 0; i < block_size; i++) {
+ strm_in.write[i] = p_buffer[step + i];
+ }
+
+ BlockHash bh;
+ bh.base64_hash = hash_block(strm_in.ptr(), block_size);
+
+ if (p_compress) {
+ strm.avail_in = block_size;
+ strm.avail_out = strm_out.size();
+ strm.next_in = (uint8_t *)strm_in.ptr();
+ strm.next_out = strm_out.ptrw();
+
+ int total_out_before = strm.total_out;
+
+ int err = deflate(&strm, Z_FULL_FLUSH);
+ ERR_FAIL_COND_V(err < 0, ERR_BUG); // Negative means bug
+
+ bh.compressed_size = strm.total_out - total_out_before;
+
+ //package->store_buffer(strm_out.ptr(), strm.total_out - total_out_before);
+ int start = file_buffer.size();
+ file_buffer.resize(file_buffer.size() + bh.compressed_size);
+ for (uint64_t i = 0; i < bh.compressed_size; i++) {
+ file_buffer.write[start + i] = strm_out[i];
+ }
+ } else {
+ bh.compressed_size = block_size;
+ //package->store_buffer(strm_in.ptr(), block_size);
+ int start = file_buffer.size();
+ file_buffer.resize(file_buffer.size() + block_size);
+ for (uint64_t i = 0; i < bh.compressed_size; i++) {
+ file_buffer.write[start + i] = strm_in[i];
+ }
+ }
+
+ meta.hashes.push_back(bh);
+
+ step += block_size;
+ }
+
+ if (p_compress) {
+ strm.avail_in = 0;
+ strm.avail_out = strm_out.size();
+ strm.next_in = (uint8_t *)strm_in.ptr();
+ strm.next_out = strm_out.ptrw();
+
+ int total_out_before = strm.total_out;
+
+ deflate(&strm, Z_FINISH);
+
+ //package->store_buffer(strm_out.ptr(), strm.total_out - total_out_before);
+ int start = file_buffer.size();
+ file_buffer.resize(file_buffer.size() + (strm.total_out - total_out_before));
+ for (uint64_t i = 0; i < (strm.total_out - total_out_before); i++) {
+ file_buffer.write[start + i] = strm_out[i];
+ }
+
+ deflateEnd(&strm);
+ meta.compressed_size = strm.total_out;
+
+ } else {
+ meta.compressed_size = p_len;
+ }
+
+ // Calculate file CRC-32
+ uLong crc = crc32(0L, Z_NULL, 0);
+ crc = crc32(crc, p_buffer, p_len);
+ meta.file_crc32 = crc;
+
+ // Create file header
+ Vector<uint8_t> file_header = make_file_header(meta);
+ meta.lfh_size = file_header.size();
+
+ // Store the header and file;
+ package->store_buffer(file_header.ptr(), file_header.size());
+ package->store_buffer(file_buffer.ptr(), file_buffer.size());
+
+ file_metadata.push_back(meta);
+
+ return OK;
+}
+
+void AppxPackager::finish() {
+ // Create and add block map file
+ EditorNode::progress_task_step("export", "Creating block map...", 4);
+
+ const String &tmp_blockmap_file_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpblockmap.xml");
+ make_block_map(tmp_blockmap_file_path);
+
+ FileAccess *blockmap_file = FileAccess::open(tmp_blockmap_file_path, FileAccess::READ);
+ Vector<uint8_t> blockmap_buffer;
+ blockmap_buffer.resize(blockmap_file->get_length());
+
+ blockmap_file->get_buffer(blockmap_buffer.ptrw(), blockmap_buffer.size());
+
+ add_file("AppxBlockMap.xml", blockmap_buffer.ptr(), blockmap_buffer.size(), -1, -1, true);
+
+ blockmap_file->close();
+ memdelete(blockmap_file);
+
+ // Add content types
+
+ EditorNode::progress_task_step("export", "Setting content types...", 5);
+
+ const String &tmp_content_types_file_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpcontenttypes.xml");
+ make_content_types(tmp_content_types_file_path);
+
+ FileAccess *types_file = FileAccess::open(tmp_content_types_file_path, FileAccess::READ);
+ Vector<uint8_t> types_buffer;
+ types_buffer.resize(types_file->get_length());
+
+ types_file->get_buffer(types_buffer.ptrw(), types_buffer.size());
+
+ add_file("[Content_Types].xml", types_buffer.ptr(), types_buffer.size(), -1, -1, true);
+
+ types_file->close();
+ memdelete(types_file);
+
+ // Cleanup generated files.
+ DirAccess::remove_file_or_error(tmp_blockmap_file_path);
+ DirAccess::remove_file_or_error(tmp_content_types_file_path);
+
+ // Pre-process central directory before signing
+ for (int i = 0; i < file_metadata.size(); i++) {
+ store_central_dir_header(file_metadata[i]);
+ }
+
+ // Write central directory
+ EditorNode::progress_task_step("export", "Finishing package...", 6);
+ central_dir_offset = package->get_position();
+ package->store_buffer(central_dir_data.ptr(), central_dir_data.size());
+
+ // End record
+ end_of_central_dir_offset = package->get_position();
+ Vector<uint8_t> end_record = make_end_of_central_record();
+ package->store_buffer(end_record.ptr(), end_record.size());
+
+ package->close();
+ memdelete(package);
+ package = nullptr;
+}
+
+AppxPackager::AppxPackager() {}
+
+AppxPackager::~AppxPackager() {}
diff --git a/platform/uwp/export/app_packager.h b/platform/uwp/export/app_packager.h
new file mode 100644
index 0000000000..0eb1a78df1
--- /dev/null
+++ b/platform/uwp/export/app_packager.h
@@ -0,0 +1,150 @@
+/*************************************************************************/
+/* app_packager.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef UWP_APP_PACKAGER_H
+#define UWP_APP_PACKAGER_H
+
+#include "core/config/project_settings.h"
+#include "core/core_bind.h"
+#include "core/crypto/crypto_core.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
+#include "core/io/marshalls.h"
+#include "core/io/zip_io.h"
+#include "core/object/class_db.h"
+#include "core/version.h"
+#include "editor/editor_export.h"
+#include "editor/editor_node.h"
+
+#include "thirdparty/minizip/unzip.h"
+#include "thirdparty/minizip/zip.h"
+
+#include <zlib.h>
+
+class AppxPackager {
+ enum {
+ FILE_HEADER_MAGIC = 0x04034b50,
+ DATA_DESCRIPTOR_MAGIC = 0x08074b50,
+ CENTRAL_DIR_MAGIC = 0x02014b50,
+ END_OF_CENTRAL_DIR_MAGIC = 0x06054b50,
+ ZIP64_END_OF_CENTRAL_DIR_MAGIC = 0x06064b50,
+ ZIP64_END_DIR_LOCATOR_MAGIC = 0x07064b50,
+ P7X_SIGNATURE = 0x58434b50,
+ ZIP64_HEADER_ID = 0x0001,
+ ZIP_VERSION = 20,
+ ZIP_ARCHIVE_VERSION = 45,
+ GENERAL_PURPOSE = 0x00,
+ BASE_FILE_HEADER_SIZE = 30,
+ DATA_DESCRIPTOR_SIZE = 24,
+ BASE_CENTRAL_DIR_SIZE = 46,
+ EXTRA_FIELD_LENGTH = 28,
+ ZIP64_HEADER_SIZE = 24,
+ ZIP64_END_OF_CENTRAL_DIR_SIZE = (56 - 12),
+ END_OF_CENTRAL_DIR_SIZE = 42,
+ BLOCK_SIZE = 65536,
+ };
+
+ struct BlockHash {
+ String base64_hash;
+ size_t compressed_size = 0;
+ };
+
+ struct FileMeta {
+ String name;
+ int lfh_size = 0;
+ bool compressed = false;
+ size_t compressed_size = 0;
+ size_t uncompressed_size = 0;
+ Vector<BlockHash> hashes;
+ uLong file_crc32 = 0;
+ ZPOS64_T zip_offset = 0;
+ };
+
+ String progress_task;
+ FileAccess *package = nullptr;
+
+ Set<String> mime_types;
+
+ Vector<FileMeta> file_metadata;
+
+ ZPOS64_T central_dir_offset;
+ ZPOS64_T end_of_central_dir_offset;
+ Vector<uint8_t> central_dir_data;
+
+ String hash_block(const uint8_t *p_block_data, size_t p_block_len);
+
+ void make_block_map(const String &p_path);
+ void make_content_types(const String &p_path);
+
+ _FORCE_INLINE_ unsigned int buf_put_int16(uint16_t p_val, uint8_t *p_buf) {
+ for (int i = 0; i < 2; i++) {
+ *p_buf++ = (p_val >> (i * 8)) & 0xFF;
+ }
+ return 2;
+ }
+
+ _FORCE_INLINE_ unsigned int buf_put_int32(uint32_t p_val, uint8_t *p_buf) {
+ for (int i = 0; i < 4; i++) {
+ *p_buf++ = (p_val >> (i * 8)) & 0xFF;
+ }
+ return 4;
+ }
+
+ _FORCE_INLINE_ unsigned int buf_put_int64(uint64_t p_val, uint8_t *p_buf) {
+ for (int i = 0; i < 8; i++) {
+ *p_buf++ = (p_val >> (i * 8)) & 0xFF;
+ }
+ return 8;
+ }
+
+ _FORCE_INLINE_ unsigned int buf_put_string(String p_val, uint8_t *p_buf) {
+ for (int i = 0; i < p_val.length(); i++) {
+ *p_buf++ = p_val.utf8().get(i);
+ }
+ return p_val.length();
+ }
+
+ Vector<uint8_t> make_file_header(FileMeta p_file_meta);
+ void store_central_dir_header(const FileMeta &p_file, bool p_do_hash = true);
+ Vector<uint8_t> make_end_of_central_record();
+
+ String content_type(String p_extension);
+
+public:
+ void set_progress_task(String p_task) { progress_task = p_task; }
+ void init(FileAccess *p_fa);
+ Error add_file(String p_file_name, const uint8_t *p_buffer, size_t p_len, int p_file_no, int p_total_files, bool p_compress = false);
+ void finish();
+
+ AppxPackager();
+ ~AppxPackager();
+};
+
+#endif
diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp
index 98925fd7fa..f5c3db33bb 100644
--- a/platform/uwp/export/export.cpp
+++ b/platform/uwp/export/export.cpp
@@ -30,1408 +30,7 @@
#include "export.h"
-#include "core/config/project_settings.h"
-#include "core/crypto/crypto_core.h"
-#include "core/io/dir_access.h"
-#include "core/io/file_access.h"
-#include "core/io/marshalls.h"
-#include "core/io/zip_io.h"
-#include "core/object/class_db.h"
-#include "core/version.h"
-#include "editor/editor_export.h"
-#include "editor/editor_node.h"
-#include "platform/uwp/logo.gen.h"
-
-#include "thirdparty/minizip/unzip.h"
-#include "thirdparty/minizip/zip.h"
-
-#include <zlib.h>
-
-// Capabilities
-static const char *uwp_capabilities[] = {
- "allJoyn",
- "codeGeneration",
- "internetClient",
- "internetClientServer",
- "privateNetworkClientServer",
- nullptr
-};
-static const char *uwp_uap_capabilities[] = {
- "appointments",
- "blockedChatMessages",
- "chat",
- "contacts",
- "enterpriseAuthentication",
- "musicLibrary",
- "objects3D",
- "picturesLibrary",
- "phoneCall",
- "removableStorage",
- "sharedUserCertificates",
- "userAccountInformation",
- "videosLibrary",
- "voipCall",
- nullptr
-};
-static const char *uwp_device_capabilities[] = {
- "bluetooth",
- "location",
- "microphone",
- "proximity",
- "webcam",
- nullptr
-};
-
-class AppxPackager {
- enum {
- FILE_HEADER_MAGIC = 0x04034b50,
- DATA_DESCRIPTOR_MAGIC = 0x08074b50,
- CENTRAL_DIR_MAGIC = 0x02014b50,
- END_OF_CENTRAL_DIR_MAGIC = 0x06054b50,
- ZIP64_END_OF_CENTRAL_DIR_MAGIC = 0x06064b50,
- ZIP64_END_DIR_LOCATOR_MAGIC = 0x07064b50,
- P7X_SIGNATURE = 0x58434b50,
- ZIP64_HEADER_ID = 0x0001,
- ZIP_VERSION = 20,
- ZIP_ARCHIVE_VERSION = 45,
- GENERAL_PURPOSE = 0x00,
- BASE_FILE_HEADER_SIZE = 30,
- DATA_DESCRIPTOR_SIZE = 24,
- BASE_CENTRAL_DIR_SIZE = 46,
- EXTRA_FIELD_LENGTH = 28,
- ZIP64_HEADER_SIZE = 24,
- ZIP64_END_OF_CENTRAL_DIR_SIZE = (56 - 12),
- END_OF_CENTRAL_DIR_SIZE = 42,
- BLOCK_SIZE = 65536,
- };
-
- struct BlockHash {
- String base64_hash;
- size_t compressed_size = 0;
- };
-
- struct FileMeta {
- String name;
- int lfh_size = 0;
- bool compressed = false;
- size_t compressed_size = 0;
- size_t uncompressed_size = 0;
- Vector<BlockHash> hashes;
- uLong file_crc32 = 0;
- ZPOS64_T zip_offset = 0;
- };
-
- String progress_task;
- FileAccess *package = nullptr;
-
- Set<String> mime_types;
-
- Vector<FileMeta> file_metadata;
-
- ZPOS64_T central_dir_offset;
- ZPOS64_T end_of_central_dir_offset;
- Vector<uint8_t> central_dir_data;
-
- String hash_block(const uint8_t *p_block_data, size_t p_block_len);
-
- void make_block_map(const String &p_path);
- void make_content_types(const String &p_path);
-
- _FORCE_INLINE_ unsigned int buf_put_int16(uint16_t p_val, uint8_t *p_buf) {
- for (int i = 0; i < 2; i++) {
- *p_buf++ = (p_val >> (i * 8)) & 0xFF;
- }
- return 2;
- }
-
- _FORCE_INLINE_ unsigned int buf_put_int32(uint32_t p_val, uint8_t *p_buf) {
- for (int i = 0; i < 4; i++) {
- *p_buf++ = (p_val >> (i * 8)) & 0xFF;
- }
- return 4;
- }
-
- _FORCE_INLINE_ unsigned int buf_put_int64(uint64_t p_val, uint8_t *p_buf) {
- for (int i = 0; i < 8; i++) {
- *p_buf++ = (p_val >> (i * 8)) & 0xFF;
- }
- return 8;
- }
-
- _FORCE_INLINE_ unsigned int buf_put_string(String p_val, uint8_t *p_buf) {
- for (int i = 0; i < p_val.length(); i++) {
- *p_buf++ = p_val.utf8().get(i);
- }
- return p_val.length();
- }
-
- Vector<uint8_t> make_file_header(FileMeta p_file_meta);
- void store_central_dir_header(const FileMeta &p_file, bool p_do_hash = true);
- Vector<uint8_t> make_end_of_central_record();
-
- String content_type(String p_extension);
-
-public:
- void set_progress_task(String p_task) { progress_task = p_task; }
- void init(FileAccess *p_fa);
- Error add_file(String p_file_name, const uint8_t *p_buffer, size_t p_len, int p_file_no, int p_total_files, bool p_compress = false);
- void finish();
-
- AppxPackager();
- ~AppxPackager();
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-String AppxPackager::hash_block(const uint8_t *p_block_data, size_t p_block_len) {
- unsigned char hash[32];
- char base64[45];
-
- CryptoCore::sha256(p_block_data, p_block_len, hash);
- size_t len = 0;
- CryptoCore::b64_encode((unsigned char *)base64, 45, &len, (unsigned char *)hash, 32);
- base64[44] = '\0';
-
- return String(base64);
-}
-
-void AppxPackager::make_block_map(const String &p_path) {
- FileAccess *tmp_file = FileAccess::open(p_path, FileAccess::WRITE);
-
- tmp_file->store_string("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
- tmp_file->store_string("<BlockMap xmlns=\"http://schemas.microsoft.com/appx/2010/blockmap\" HashMethod=\"http://www.w3.org/2001/04/xmlenc#sha256\">");
-
- for (int i = 0; i < file_metadata.size(); i++) {
- FileMeta file = file_metadata[i];
-
- tmp_file->store_string(
- "<File Name=\"" + file.name.replace("/", "\\") + "\" Size=\"" + itos(file.uncompressed_size) + "\" LfhSize=\"" + itos(file.lfh_size) + "\">");
-
- for (int j = 0; j < file.hashes.size(); j++) {
- tmp_file->store_string("<Block Hash=\"" + file.hashes[j].base64_hash + "\" ");
- if (file.compressed) {
- tmp_file->store_string("Size=\"" + itos(file.hashes[j].compressed_size) + "\" ");
- }
- tmp_file->store_string("/>");
- }
-
- tmp_file->store_string("</File>");
- }
-
- tmp_file->store_string("</BlockMap>");
-
- tmp_file->close();
- memdelete(tmp_file);
-}
-
-String AppxPackager::content_type(String p_extension) {
- if (p_extension == "png") {
- return "image/png";
- } else if (p_extension == "jpg") {
- return "image/jpg";
- } else if (p_extension == "xml") {
- return "application/xml";
- } else if (p_extension == "exe" || p_extension == "dll") {
- return "application/x-msdownload";
- } else {
- return "application/octet-stream";
- }
-}
-
-void AppxPackager::make_content_types(const String &p_path) {
- FileAccess *tmp_file = FileAccess::open(p_path, FileAccess::WRITE);
-
- tmp_file->store_string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
- tmp_file->store_string("<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">");
-
- Map<String, String> types;
-
- for (int i = 0; i < file_metadata.size(); i++) {
- String ext = file_metadata[i].name.get_extension().to_lower();
-
- if (types.has(ext)) {
- continue;
- }
-
- types[ext] = content_type(ext);
-
- tmp_file->store_string("<Default Extension=\"" + ext + "\" ContentType=\"" + types[ext] + "\" />");
- }
-
- // Appx signature file
- tmp_file->store_string("<Default Extension=\"p7x\" ContentType=\"application/octet-stream\" />");
-
- // Override for package files
- tmp_file->store_string("<Override PartName=\"/AppxManifest.xml\" ContentType=\"application/vnd.ms-appx.manifest+xml\" />");
- tmp_file->store_string("<Override PartName=\"/AppxBlockMap.xml\" ContentType=\"application/vnd.ms-appx.blockmap+xml\" />");
- tmp_file->store_string("<Override PartName=\"/AppxSignature.p7x\" ContentType=\"application/vnd.ms-appx.signature\" />");
- tmp_file->store_string("<Override PartName=\"/AppxMetadata/CodeIntegrity.cat\" ContentType=\"application/vnd.ms-pkiseccat\" />");
-
- tmp_file->store_string("</Types>");
-
- tmp_file->close();
- memdelete(tmp_file);
-}
-
-Vector<uint8_t> AppxPackager::make_file_header(FileMeta p_file_meta) {
- Vector<uint8_t> buf;
- buf.resize(BASE_FILE_HEADER_SIZE + p_file_meta.name.length());
-
- int offs = 0;
- // Write magic
- offs += buf_put_int32(FILE_HEADER_MAGIC, &buf.write[offs]);
-
- // Version
- offs += buf_put_int16(ZIP_VERSION, &buf.write[offs]);
-
- // Special flag
- offs += buf_put_int16(GENERAL_PURPOSE, &buf.write[offs]);
-
- // Compression
- offs += buf_put_int16(p_file_meta.compressed ? Z_DEFLATED : 0, &buf.write[offs]);
-
- // File date and time
- offs += buf_put_int32(0, &buf.write[offs]);
-
- // CRC-32
- offs += buf_put_int32(p_file_meta.file_crc32, &buf.write[offs]);
-
- // Compressed size
- offs += buf_put_int32(p_file_meta.compressed_size, &buf.write[offs]);
-
- // Uncompressed size
- offs += buf_put_int32(p_file_meta.uncompressed_size, &buf.write[offs]);
-
- // File name length
- offs += buf_put_int16(p_file_meta.name.length(), &buf.write[offs]);
-
- // Extra data length
- offs += buf_put_int16(0, &buf.write[offs]);
-
- // File name
- offs += buf_put_string(p_file_meta.name, &buf.write[offs]);
-
- // Done!
- return buf;
-}
-
-void AppxPackager::store_central_dir_header(const FileMeta &p_file, bool p_do_hash) {
- Vector<uint8_t> &buf = central_dir_data;
- int offs = buf.size();
- buf.resize(buf.size() + BASE_CENTRAL_DIR_SIZE + p_file.name.length());
-
- // Write magic
- offs += buf_put_int32(CENTRAL_DIR_MAGIC, &buf.write[offs]);
-
- // ZIP versions
- offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf.write[offs]);
- offs += buf_put_int16(ZIP_VERSION, &buf.write[offs]);
-
- // General purpose flag
- offs += buf_put_int16(GENERAL_PURPOSE, &buf.write[offs]);
-
- // Compression
- offs += buf_put_int16(p_file.compressed ? Z_DEFLATED : 0, &buf.write[offs]);
-
- // Modification date/time
- offs += buf_put_int32(0, &buf.write[offs]);
-
- // Crc-32
- offs += buf_put_int32(p_file.file_crc32, &buf.write[offs]);
-
- // File sizes
- offs += buf_put_int32(p_file.compressed_size, &buf.write[offs]);
- offs += buf_put_int32(p_file.uncompressed_size, &buf.write[offs]);
-
- // File name length
- offs += buf_put_int16(p_file.name.length(), &buf.write[offs]);
-
- // Extra field length
- offs += buf_put_int16(0, &buf.write[offs]);
-
- // Comment length
- offs += buf_put_int16(0, &buf.write[offs]);
-
- // Disk number start, internal/external file attributes
- for (int i = 0; i < 8; i++) {
- buf.write[offs++] = 0;
- }
-
- // Relative offset
- offs += buf_put_int32(p_file.zip_offset, &buf.write[offs]);
-
- // File name
- offs += buf_put_string(p_file.name, &buf.write[offs]);
-
- // Done!
-}
-
-Vector<uint8_t> AppxPackager::make_end_of_central_record() {
- Vector<uint8_t> buf;
- buf.resize(ZIP64_END_OF_CENTRAL_DIR_SIZE + 12 + END_OF_CENTRAL_DIR_SIZE); // Size plus magic
-
- int offs = 0;
-
- // Write magic
- offs += buf_put_int32(ZIP64_END_OF_CENTRAL_DIR_MAGIC, &buf.write[offs]);
-
- // Size of this record
- offs += buf_put_int64(ZIP64_END_OF_CENTRAL_DIR_SIZE, &buf.write[offs]);
-
- // Version (yes, twice)
- offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf.write[offs]);
- offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf.write[offs]);
-
- // Disk number
- for (int i = 0; i < 8; i++) {
- buf.write[offs++] = 0;
- }
-
- // Number of entries (total and per disk)
- offs += buf_put_int64(file_metadata.size(), &buf.write[offs]);
- offs += buf_put_int64(file_metadata.size(), &buf.write[offs]);
-
- // Size of central dir
- offs += buf_put_int64(central_dir_data.size(), &buf.write[offs]);
-
- // Central dir offset
- offs += buf_put_int64(central_dir_offset, &buf.write[offs]);
-
- ////// ZIP64 locator
-
- // Write magic for zip64 central dir locator
- offs += buf_put_int32(ZIP64_END_DIR_LOCATOR_MAGIC, &buf.write[offs]);
-
- // Disk number
- for (int i = 0; i < 4; i++) {
- buf.write[offs++] = 0;
- }
-
- // Relative offset
- offs += buf_put_int64(end_of_central_dir_offset, &buf.write[offs]);
-
- // Number of disks
- offs += buf_put_int32(1, &buf.write[offs]);
-
- /////// End of zip directory
-
- // Write magic for end central dir
- offs += buf_put_int32(END_OF_CENTRAL_DIR_MAGIC, &buf.write[offs]);
-
- // Dummy stuff for Zip64
- for (int i = 0; i < 4; i++) {
- buf.write[offs++] = 0x0;
- }
- for (int i = 0; i < 12; i++) {
- buf.write[offs++] = 0xFF;
- }
-
- // Size of comments
- for (int i = 0; i < 2; i++) {
- buf.write[offs++] = 0;
- }
-
- // Done!
- return buf;
-}
-
-void AppxPackager::init(FileAccess *p_fa) {
- package = p_fa;
- central_dir_offset = 0;
- end_of_central_dir_offset = 0;
-}
-
-Error AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t p_len, int p_file_no, int p_total_files, bool p_compress) {
- if (p_file_no >= 1 && p_total_files >= 1) {
- if (EditorNode::progress_task_step(progress_task, "File: " + p_file_name, (p_file_no * 100) / p_total_files)) {
- return ERR_SKIP;
- }
- }
-
- FileMeta meta;
- meta.name = p_file_name;
- meta.uncompressed_size = p_len;
- meta.compressed_size = p_len;
- meta.compressed = p_compress;
- meta.zip_offset = package->get_position();
-
- Vector<uint8_t> file_buffer;
-
- // Data for compression
- z_stream strm;
- FileAccess *strm_f = nullptr;
- Vector<uint8_t> strm_in;
- strm_in.resize(BLOCK_SIZE);
- Vector<uint8_t> strm_out;
-
- if (p_compress) {
- strm.zalloc = zipio_alloc;
- strm.zfree = zipio_free;
- strm.opaque = &strm_f;
-
- strm_out.resize(BLOCK_SIZE + 8);
-
- deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
- }
-
- int step = 0;
-
- while (p_len - step > 0) {
- size_t block_size = (p_len - step) > BLOCK_SIZE ? (size_t)BLOCK_SIZE : (p_len - step);
-
- for (uint64_t i = 0; i < block_size; i++) {
- strm_in.write[i] = p_buffer[step + i];
- }
-
- BlockHash bh;
- bh.base64_hash = hash_block(strm_in.ptr(), block_size);
-
- if (p_compress) {
- strm.avail_in = block_size;
- strm.avail_out = strm_out.size();
- strm.next_in = (uint8_t *)strm_in.ptr();
- strm.next_out = strm_out.ptrw();
-
- int total_out_before = strm.total_out;
-
- int err = deflate(&strm, Z_FULL_FLUSH);
- ERR_FAIL_COND_V(err < 0, ERR_BUG); // Negative means bug
-
- bh.compressed_size = strm.total_out - total_out_before;
-
- //package->store_buffer(strm_out.ptr(), strm.total_out - total_out_before);
- int start = file_buffer.size();
- file_buffer.resize(file_buffer.size() + bh.compressed_size);
- for (uint64_t i = 0; i < bh.compressed_size; i++) {
- file_buffer.write[start + i] = strm_out[i];
- }
- } else {
- bh.compressed_size = block_size;
- //package->store_buffer(strm_in.ptr(), block_size);
- int start = file_buffer.size();
- file_buffer.resize(file_buffer.size() + block_size);
- for (uint64_t i = 0; i < bh.compressed_size; i++) {
- file_buffer.write[start + i] = strm_in[i];
- }
- }
-
- meta.hashes.push_back(bh);
-
- step += block_size;
- }
-
- if (p_compress) {
- strm.avail_in = 0;
- strm.avail_out = strm_out.size();
- strm.next_in = (uint8_t *)strm_in.ptr();
- strm.next_out = strm_out.ptrw();
-
- int total_out_before = strm.total_out;
-
- deflate(&strm, Z_FINISH);
-
- //package->store_buffer(strm_out.ptr(), strm.total_out - total_out_before);
- int start = file_buffer.size();
- file_buffer.resize(file_buffer.size() + (strm.total_out - total_out_before));
- for (uint64_t i = 0; i < (strm.total_out - total_out_before); i++) {
- file_buffer.write[start + i] = strm_out[i];
- }
-
- deflateEnd(&strm);
- meta.compressed_size = strm.total_out;
-
- } else {
- meta.compressed_size = p_len;
- }
-
- // Calculate file CRC-32
- uLong crc = crc32(0L, Z_NULL, 0);
- crc = crc32(crc, p_buffer, p_len);
- meta.file_crc32 = crc;
-
- // Create file header
- Vector<uint8_t> file_header = make_file_header(meta);
- meta.lfh_size = file_header.size();
-
- // Store the header and file;
- package->store_buffer(file_header.ptr(), file_header.size());
- package->store_buffer(file_buffer.ptr(), file_buffer.size());
-
- file_metadata.push_back(meta);
-
- return OK;
-}
-
-void AppxPackager::finish() {
- // Create and add block map file
- EditorNode::progress_task_step("export", "Creating block map...", 4);
-
- const String &tmp_blockmap_file_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpblockmap.xml");
- make_block_map(tmp_blockmap_file_path);
-
- FileAccess *blockmap_file = FileAccess::open(tmp_blockmap_file_path, FileAccess::READ);
- Vector<uint8_t> blockmap_buffer;
- blockmap_buffer.resize(blockmap_file->get_length());
-
- blockmap_file->get_buffer(blockmap_buffer.ptrw(), blockmap_buffer.size());
-
- add_file("AppxBlockMap.xml", blockmap_buffer.ptr(), blockmap_buffer.size(), -1, -1, true);
-
- blockmap_file->close();
- memdelete(blockmap_file);
-
- // Add content types
-
- EditorNode::progress_task_step("export", "Setting content types...", 5);
-
- const String &tmp_content_types_file_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpcontenttypes.xml");
- make_content_types(tmp_content_types_file_path);
-
- FileAccess *types_file = FileAccess::open(tmp_content_types_file_path, FileAccess::READ);
- Vector<uint8_t> types_buffer;
- types_buffer.resize(types_file->get_length());
-
- types_file->get_buffer(types_buffer.ptrw(), types_buffer.size());
-
- add_file("[Content_Types].xml", types_buffer.ptr(), types_buffer.size(), -1, -1, true);
-
- types_file->close();
- memdelete(types_file);
-
- // Cleanup generated files.
- DirAccess::remove_file_or_error(tmp_blockmap_file_path);
- DirAccess::remove_file_or_error(tmp_content_types_file_path);
-
- // Pre-process central directory before signing
- for (int i = 0; i < file_metadata.size(); i++) {
- store_central_dir_header(file_metadata[i]);
- }
-
- // Write central directory
- EditorNode::progress_task_step("export", "Finishing package...", 6);
- central_dir_offset = package->get_position();
- package->store_buffer(central_dir_data.ptr(), central_dir_data.size());
-
- // End record
- end_of_central_dir_offset = package->get_position();
- Vector<uint8_t> end_record = make_end_of_central_record();
- package->store_buffer(end_record.ptr(), end_record.size());
-
- package->close();
- memdelete(package);
- package = nullptr;
-}
-
-AppxPackager::AppxPackager() {}
-
-AppxPackager::~AppxPackager() {}
-
-////////////////////////////////////////////////////////////////////
-
-class EditorExportPlatformUWP : public EditorExportPlatform {
- GDCLASS(EditorExportPlatformUWP, EditorExportPlatform);
-
- Ref<ImageTexture> logo;
-
- enum Platform {
- ARM,
- X86,
- X64
- };
-
- bool _valid_resource_name(const String &p_name) const {
- if (p_name.is_empty()) {
- return false;
- }
- if (p_name.ends_with(".")) {
- return false;
- }
-
- static const char *invalid_names[] = {
- "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7",
- "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
- nullptr
- };
-
- const char **t = invalid_names;
- while (*t) {
- if (p_name == *t) {
- return false;
- }
- t++;
- }
-
- return true;
- }
-
- bool _valid_guid(const String &p_guid) const {
- Vector<String> parts = p_guid.split("-");
-
- if (parts.size() != 5) {
- return false;
- }
- if (parts[0].length() != 8) {
- return false;
- }
- for (int i = 1; i < 4; i++) {
- if (parts[i].length() != 4) {
- return false;
- }
- }
- if (parts[4].length() != 12) {
- return false;
- }
-
- return true;
- }
-
- bool _valid_bgcolor(const String &p_color) const {
- if (p_color.is_empty()) {
- return true;
- }
- if (p_color.begins_with("#") && p_color.is_valid_html_color()) {
- return true;
- }
-
- // Colors from https://msdn.microsoft.com/en-us/library/windows/apps/dn934817.aspx
- static const char *valid_colors[] = {
- "aliceBlue", "antiqueWhite", "aqua", "aquamarine", "azure", "beige",
- "bisque", "black", "blanchedAlmond", "blue", "blueViolet", "brown",
- "burlyWood", "cadetBlue", "chartreuse", "chocolate", "coral", "cornflowerBlue",
- "cornsilk", "crimson", "cyan", "darkBlue", "darkCyan", "darkGoldenrod",
- "darkGray", "darkGreen", "darkKhaki", "darkMagenta", "darkOliveGreen", "darkOrange",
- "darkOrchid", "darkRed", "darkSalmon", "darkSeaGreen", "darkSlateBlue", "darkSlateGray",
- "darkTurquoise", "darkViolet", "deepPink", "deepSkyBlue", "dimGray", "dodgerBlue",
- "firebrick", "floralWhite", "forestGreen", "fuchsia", "gainsboro", "ghostWhite",
- "gold", "goldenrod", "gray", "green", "greenYellow", "honeydew",
- "hotPink", "indianRed", "indigo", "ivory", "khaki", "lavender",
- "lavenderBlush", "lawnGreen", "lemonChiffon", "lightBlue", "lightCoral", "lightCyan",
- "lightGoldenrodYellow", "lightGreen", "lightGray", "lightPink", "lightSalmon", "lightSeaGreen",
- "lightSkyBlue", "lightSlateGray", "lightSteelBlue", "lightYellow", "lime", "limeGreen",
- "linen", "magenta", "maroon", "mediumAquamarine", "mediumBlue", "mediumOrchid",
- "mediumPurple", "mediumSeaGreen", "mediumSlateBlue", "mediumSpringGreen", "mediumTurquoise", "mediumVioletRed",
- "midnightBlue", "mintCream", "mistyRose", "moccasin", "navajoWhite", "navy",
- "oldLace", "olive", "oliveDrab", "orange", "orangeRed", "orchid",
- "paleGoldenrod", "paleGreen", "paleTurquoise", "paleVioletRed", "papayaWhip", "peachPuff",
- "peru", "pink", "plum", "powderBlue", "purple", "red",
- "rosyBrown", "royalBlue", "saddleBrown", "salmon", "sandyBrown", "seaGreen",
- "seaShell", "sienna", "silver", "skyBlue", "slateBlue", "slateGray",
- "snow", "springGreen", "steelBlue", "tan", "teal", "thistle",
- "tomato", "transparent", "turquoise", "violet", "wheat", "white",
- "whiteSmoke", "yellow", "yellowGreen",
- nullptr
- };
-
- const char **color = valid_colors;
-
- while (*color) {
- if (p_color == *color) {
- return true;
- }
- color++;
- }
-
- return false;
- }
-
- bool _valid_image(const StreamTexture2D *p_image, int p_width, int p_height) const {
- if (!p_image) {
- return false;
- }
-
- // TODO: Add resource creation or image rescaling to enable other scales:
- // 1.25, 1.5, 2.0
- return p_width == p_image->get_width() && p_height == p_image->get_height();
- }
-
- Vector<uint8_t> _fix_manifest(const Ref<EditorExportPreset> &p_preset, const Vector<uint8_t> &p_template, bool p_give_internet) const {
- String result = String::utf8((const char *)p_template.ptr(), p_template.size());
-
- result = result.replace("$godot_version$", VERSION_FULL_NAME);
-
- result = result.replace("$identity_name$", p_preset->get("package/unique_name"));
- result = result.replace("$publisher$", p_preset->get("package/publisher"));
-
- result = result.replace("$product_guid$", p_preset->get("identity/product_guid"));
- result = result.replace("$publisher_guid$", p_preset->get("identity/publisher_guid"));
-
- String version = itos(p_preset->get("version/major")) + "." + itos(p_preset->get("version/minor")) + "." + itos(p_preset->get("version/build")) + "." + itos(p_preset->get("version/revision"));
- result = result.replace("$version_string$", version);
-
- Platform arch = (Platform)(int)p_preset->get("architecture/target");
- String architecture = arch == ARM ? "arm" : (arch == X86 ? "x86" : "x64");
- result = result.replace("$architecture$", architecture);
-
- result = result.replace("$display_name$", String(p_preset->get("package/display_name")).is_empty() ? (String)ProjectSettings::get_singleton()->get("application/config/name") : String(p_preset->get("package/display_name")));
-
- result = result.replace("$publisher_display_name$", p_preset->get("package/publisher_display_name"));
- result = result.replace("$app_description$", p_preset->get("package/description"));
- result = result.replace("$bg_color$", p_preset->get("images/background_color"));
- result = result.replace("$short_name$", p_preset->get("package/short_name"));
-
- String name_on_tiles = "";
- if ((bool)p_preset->get("tiles/show_name_on_square150x150")) {
- name_on_tiles += " <uap:ShowOn Tile=\"square150x150Logo\" />\n";
- }
- if ((bool)p_preset->get("tiles/show_name_on_wide310x150")) {
- name_on_tiles += " <uap:ShowOn Tile=\"wide310x150Logo\" />\n";
- }
- if ((bool)p_preset->get("tiles/show_name_on_square310x310")) {
- name_on_tiles += " <uap:ShowOn Tile=\"square310x310Logo\" />\n";
- }
-
- String show_name_on_tiles = "";
- if (!name_on_tiles.is_empty()) {
- show_name_on_tiles = "<uap:ShowNameOnTiles>\n" + name_on_tiles + " </uap:ShowNameOnTiles>";
- }
-
- result = result.replace("$name_on_tiles$", name_on_tiles);
-
- String rotations = "";
- if ((bool)p_preset->get("orientation/landscape")) {
- rotations += " <uap:Rotation Preference=\"landscape\" />\n";
- }
- if ((bool)p_preset->get("orientation/portrait")) {
- rotations += " <uap:Rotation Preference=\"portrait\" />\n";
- }
- if ((bool)p_preset->get("orientation/landscape_flipped")) {
- rotations += " <uap:Rotation Preference=\"landscapeFlipped\" />\n";
- }
- if ((bool)p_preset->get("orientation/portrait_flipped")) {
- rotations += " <uap:Rotation Preference=\"portraitFlipped\" />\n";
- }
-
- String rotation_preference = "";
- if (!rotations.is_empty()) {
- rotation_preference = "<uap:InitialRotationPreference>\n" + rotations + " </uap:InitialRotationPreference>";
- }
-
- result = result.replace("$rotation_preference$", rotation_preference);
-
- String capabilities_elements = "";
- const char **basic = uwp_capabilities;
- while (*basic) {
- if ((bool)p_preset->get("capabilities/" + String(*basic))) {
- capabilities_elements += " <Capability Name=\"" + String(*basic) + "\" />\n";
- }
- basic++;
- }
- const char **uap = uwp_uap_capabilities;
- while (*uap) {
- if ((bool)p_preset->get("capabilities/" + String(*uap))) {
- capabilities_elements += " <uap:Capability Name=\"" + String(*uap) + "\" />\n";
- }
- uap++;
- }
- const char **device = uwp_device_capabilities;
- while (*device) {
- if ((bool)p_preset->get("capabilities/" + String(*device))) {
- capabilities_elements += " <DeviceCapability Name=\"" + String(*device) + "\" />\n";
- }
- device++;
- }
-
- if (!((bool)p_preset->get("capabilities/internetClient")) && p_give_internet) {
- capabilities_elements += " <Capability Name=\"internetClient\" />\n";
- }
-
- String capabilities_string = "<Capabilities />";
- if (!capabilities_elements.is_empty()) {
- capabilities_string = "<Capabilities>\n" + capabilities_elements + " </Capabilities>";
- }
-
- result = result.replace("$capabilities_place$", capabilities_string);
-
- Vector<uint8_t> r_ret;
- r_ret.resize(result.length());
-
- for (int i = 0; i < result.length(); i++) {
- r_ret.write[i] = result.utf8().get(i);
- }
-
- return r_ret;
- }
-
- Vector<uint8_t> _get_image_data(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
- Vector<uint8_t> data;
- StreamTexture2D *texture = nullptr;
-
- if (p_path.find("StoreLogo") != -1) {
- texture = p_preset->get("images/store_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/store_logo")));
- } else if (p_path.find("Square44x44Logo") != -1) {
- texture = p_preset->get("images/square44x44_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square44x44_logo")));
- } else if (p_path.find("Square71x71Logo") != -1) {
- texture = p_preset->get("images/square71x71_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square71x71_logo")));
- } else if (p_path.find("Square150x150Logo") != -1) {
- texture = p_preset->get("images/square150x150_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square150x150_logo")));
- } else if (p_path.find("Square310x310Logo") != -1) {
- texture = p_preset->get("images/square310x310_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square310x310_logo")));
- } else if (p_path.find("Wide310x150Logo") != -1) {
- texture = p_preset->get("images/wide310x150_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/wide310x150_logo")));
- } else if (p_path.find("SplashScreen") != -1) {
- texture = p_preset->get("images/splash_screen").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/splash_screen")));
- } else {
- ERR_PRINT("Unable to load logo");
- }
-
- if (!texture) {
- return data;
- }
-
- String tmp_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("uwp_tmp_logo.png");
-
- Error err = texture->get_image()->save_png(tmp_path);
-
- if (err != OK) {
- String err_string = "Couldn't save temp logo file.";
-
- EditorNode::add_io_error(err_string);
- ERR_FAIL_V_MSG(data, err_string);
- }
-
- FileAccess *f = FileAccess::open(tmp_path, FileAccess::READ, &err);
-
- if (err != OK) {
- String err_string = "Couldn't open temp logo file.";
- // Cleanup generated file.
- DirAccess::remove_file_or_error(tmp_path);
- EditorNode::add_io_error(err_string);
- ERR_FAIL_V_MSG(data, err_string);
- }
-
- data.resize(f->get_length());
- f->get_buffer(data.ptrw(), data.size());
-
- f->close();
- memdelete(f);
- DirAccess::remove_file_or_error(tmp_path);
-
- return data;
- }
-
- static bool _should_compress_asset(const String &p_path, const Vector<uint8_t> &p_data) {
- /* TODO: This was copied verbatim from Android export. It should be
- * refactored to the parent class and also be used for .zip export.
- */
-
- /*
- * By not compressing files with little or not benefit in doing so,
- * a performance gain is expected at runtime. Moreover, if the APK is
- * zip-aligned, assets stored as they are can be efficiently read by
- * Android by memory-mapping them.
- */
-
- // -- Unconditional uncompress to mimic AAPT plus some other
-
- static const char *unconditional_compress_ext[] = {
- // From https://github.com/android/platform_frameworks_base/blob/master/tools/aapt/Package.cpp
- // These formats are already compressed, or don't compress well:
- ".jpg", ".jpeg", ".png", ".gif",
- ".wav", ".mp2", ".mp3", ".ogg", ".aac",
- ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet",
- ".rtttl", ".imy", ".xmf", ".mp4", ".m4a",
- ".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2",
- ".amr", ".awb", ".wma", ".wmv",
- // Godot-specific:
- ".webp", // Same reasoning as .png
- ".cfb", // Don't let small config files slow-down startup
- ".scn", // Binary scenes are usually already compressed
- ".stex", // Streamable textures are usually already compressed
- // Trailer for easier processing
- nullptr
- };
-
- for (const char **ext = unconditional_compress_ext; *ext; ++ext) {
- if (p_path.to_lower().ends_with(String(*ext))) {
- return false;
- }
- }
-
- // -- Compressed resource?
-
- if (p_data.size() >= 4 && p_data[0] == 'R' && p_data[1] == 'S' && p_data[2] == 'C' && p_data[3] == 'C') {
- // Already compressed
- return false;
- }
-
- // --- TODO: Decide on texture resources according to their image compression setting
-
- return true;
- }
-
- static Error save_appx_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
- AppxPackager *packager = (AppxPackager *)p_userdata;
- String dst_path = p_path.replace_first("res://", "game/");
-
- return packager->add_file(dst_path, p_data.ptr(), p_data.size(), p_file, p_total, _should_compress_asset(p_path, p_data));
- }
-
-public:
- virtual String get_name() const override {
- return "UWP";
- }
- virtual String get_os_name() const override {
- return "UWP";
- }
-
- virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override {
- List<String> list;
- list.push_back("appx");
- return list;
- }
-
- virtual Ref<Texture2D> get_logo() const override {
- return logo;
- }
-
- virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) override {
- r_features->push_back("s3tc");
- r_features->push_back("etc");
- switch ((int)p_preset->get("architecture/target")) {
- case EditorExportPlatformUWP::ARM: {
- r_features->push_back("arm");
- } break;
- case EditorExportPlatformUWP::X86: {
- r_features->push_back("32");
- } break;
- case EditorExportPlatformUWP::X64: {
- r_features->push_back("64");
- } break;
- }
- }
-
- virtual void get_export_options(List<ExportOption> *r_options) override {
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "architecture/target", PROPERTY_HINT_ENUM, "arm,x86,x64"), 1));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), ""));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/display_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/short_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game.Name"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/description"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/publisher", PROPERTY_HINT_PLACEHOLDER_TEXT, "CN=CompanyName"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/publisher_display_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Company Name"), ""));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "identity/product_guid", PROPERTY_HINT_PLACEHOLDER_TEXT, "00000000-0000-0000-0000-000000000000"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "identity/publisher_guid", PROPERTY_HINT_PLACEHOLDER_TEXT, "00000000-0000-0000-0000-000000000000"), ""));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "signing/certificate", PROPERTY_HINT_GLOBAL_FILE, "*.pfx"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "signing/password"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "signing/algorithm", PROPERTY_HINT_ENUM, "MD5,SHA1,SHA256"), 2));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/major"), 1));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/minor"), 0));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/build"), 0));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/revision"), 0));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/landscape"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/portrait"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/landscape_flipped"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/portrait_flipped"), true));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "images/background_color"), "transparent"));
- r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/store_logo", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture2D"), Variant()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/square44x44_logo", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture2D"), Variant()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/square71x71_logo", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture2D"), Variant()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/square150x150_logo", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture2D"), Variant()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/square310x310_logo", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture2D"), Variant()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/wide310x150_logo", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture2D"), Variant()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/splash_screen", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture2D"), Variant()));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "tiles/show_name_on_square150x150"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "tiles/show_name_on_wide310x150"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "tiles/show_name_on_square310x310"), false));
-
- // Capabilities
- const char **basic = uwp_capabilities;
- while (*basic) {
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/" + String(*basic)), false));
- basic++;
- }
-
- const char **uap = uwp_uap_capabilities;
- while (*uap) {
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/" + String(*uap)), false));
- uap++;
- }
-
- const char **device = uwp_device_capabilities;
- while (*device) {
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/" + String(*device)), false));
- device++;
- }
- }
-
- virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override {
- String err;
- bool valid = false;
-
- // Look for export templates (first official, and if defined custom templates).
-
- Platform arch = (Platform)(int)(p_preset->get("architecture/target"));
- String platform_infix;
- switch (arch) {
- case EditorExportPlatformUWP::ARM: {
- platform_infix = "arm";
- } break;
- case EditorExportPlatformUWP::X86: {
- platform_infix = "x86";
- } break;
- case EditorExportPlatformUWP::X64: {
- platform_infix = "x64";
- } break;
- }
-
- bool dvalid = exists_export_template("uwp_" + platform_infix + "_debug.zip", &err);
- bool rvalid = exists_export_template("uwp_" + platform_infix + "_release.zip", &err);
-
- if (p_preset->get("custom_template/debug") != "") {
- dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
- if (!dvalid) {
- err += TTR("Custom debug template not found.") + "\n";
- }
- }
- if (p_preset->get("custom_template/release") != "") {
- rvalid = FileAccess::exists(p_preset->get("custom_template/release"));
- if (!rvalid) {
- err += TTR("Custom release template not found.") + "\n";
- }
- }
-
- valid = dvalid || rvalid;
- r_missing_templates = !valid;
-
- // Validate the rest of the configuration.
-
- if (!_valid_resource_name(p_preset->get("package/short_name"))) {
- valid = false;
- err += TTR("Invalid package short name.") + "\n";
- }
-
- if (!_valid_resource_name(p_preset->get("package/unique_name"))) {
- valid = false;
- err += TTR("Invalid package unique name.") + "\n";
- }
-
- if (!_valid_resource_name(p_preset->get("package/publisher_display_name"))) {
- valid = false;
- err += TTR("Invalid package publisher display name.") + "\n";
- }
-
- if (!_valid_guid(p_preset->get("identity/product_guid"))) {
- valid = false;
- err += TTR("Invalid product GUID.") + "\n";
- }
-
- if (!_valid_guid(p_preset->get("identity/publisher_guid"))) {
- valid = false;
- err += TTR("Invalid publisher GUID.") + "\n";
- }
-
- if (!_valid_bgcolor(p_preset->get("images/background_color"))) {
- valid = false;
- err += TTR("Invalid background color.") + "\n";
- }
-
- if (!p_preset->get("images/store_logo").is_zero() && !_valid_image((Object::cast_to<StreamTexture2D>((Object *)p_preset->get("images/store_logo"))), 50, 50)) {
- valid = false;
- err += TTR("Invalid Store Logo image dimensions (should be 50x50).") + "\n";
- }
-
- if (!p_preset->get("images/square44x44_logo").is_zero() && !_valid_image((Object::cast_to<StreamTexture2D>((Object *)p_preset->get("images/square44x44_logo"))), 44, 44)) {
- valid = false;
- err += TTR("Invalid square 44x44 logo image dimensions (should be 44x44).") + "\n";
- }
-
- if (!p_preset->get("images/square71x71_logo").is_zero() && !_valid_image((Object::cast_to<StreamTexture2D>((Object *)p_preset->get("images/square71x71_logo"))), 71, 71)) {
- valid = false;
- err += TTR("Invalid square 71x71 logo image dimensions (should be 71x71).") + "\n";
- }
-
- if (!p_preset->get("images/square150x150_logo").is_zero() && !_valid_image((Object::cast_to<StreamTexture2D>((Object *)p_preset->get("images/square150x150_logo"))), 150, 150)) {
- valid = false;
- err += TTR("Invalid square 150x150 logo image dimensions (should be 150x150).") + "\n";
- }
-
- if (!p_preset->get("images/square310x310_logo").is_zero() && !_valid_image((Object::cast_to<StreamTexture2D>((Object *)p_preset->get("images/square310x310_logo"))), 310, 310)) {
- valid = false;
- err += TTR("Invalid square 310x310 logo image dimensions (should be 310x310).") + "\n";
- }
-
- if (!p_preset->get("images/wide310x150_logo").is_zero() && !_valid_image((Object::cast_to<StreamTexture2D>((Object *)p_preset->get("images/wide310x150_logo"))), 310, 150)) {
- valid = false;
- err += TTR("Invalid wide 310x150 logo image dimensions (should be 310x150).") + "\n";
- }
-
- if (!p_preset->get("images/splash_screen").is_zero() && !_valid_image((Object::cast_to<StreamTexture2D>((Object *)p_preset->get("images/splash_screen"))), 620, 300)) {
- valid = false;
- err += TTR("Invalid splash screen image dimensions (should be 620x300).") + "\n";
- }
-
- r_error = err;
- return valid;
- }
-
- virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override {
- ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
-
- String src_appx;
-
- EditorProgress ep("export", "Exporting for UWP", 7, true);
-
- if (p_debug) {
- src_appx = p_preset->get("custom_template/debug");
- } else {
- src_appx = p_preset->get("custom_template/release");
- }
-
- src_appx = src_appx.strip_edges();
-
- Platform arch = (Platform)(int)p_preset->get("architecture/target");
-
- if (src_appx == "") {
- String err, infix;
- switch (arch) {
- case ARM: {
- infix = "_arm_";
- } break;
- case X86: {
- infix = "_x86_";
- } break;
- case X64: {
- infix = "_x64_";
- } break;
- }
- if (p_debug) {
- src_appx = find_export_template("uwp" + infix + "debug.zip", &err);
- } else {
- src_appx = find_export_template("uwp" + infix + "release.zip", &err);
- }
- if (src_appx == "") {
- EditorNode::add_io_error(err);
- return ERR_FILE_NOT_FOUND;
- }
- }
-
- if (!DirAccess::exists(p_path.get_base_dir())) {
- return ERR_FILE_BAD_PATH;
- }
-
- Error err = OK;
-
- FileAccess *fa_pack = FileAccess::open(p_path, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V_MSG(err != OK, ERR_CANT_CREATE, "Cannot create file '" + p_path + "'.");
-
- AppxPackager packager;
- packager.init(fa_pack);
-
- FileAccess *src_f = nullptr;
- zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
-
- if (ep.step("Creating package...", 0)) {
- return ERR_SKIP;
- }
-
- unzFile pkg = unzOpen2(src_appx.utf8().get_data(), &io);
-
- if (!pkg) {
- EditorNode::add_io_error("Could not find template appx to export:\n" + src_appx);
- return ERR_FILE_NOT_FOUND;
- }
-
- int ret = unzGoToFirstFile(pkg);
-
- if (ep.step("Copying template files...", 1)) {
- return ERR_SKIP;
- }
-
- EditorNode::progress_add_task("template_files", "Template files", 100);
- packager.set_progress_task("template_files");
-
- int template_files_amount = 9;
- int template_file_no = 1;
-
- while (ret == UNZ_OK) {
- // get file name
- unz_file_info info;
- char fname[16834];
- ret = unzGetCurrentFileInfo(pkg, &info, fname, 16834, nullptr, 0, nullptr, 0);
-
- String path = fname;
-
- if (path.ends_with("/")) {
- // Ignore directories
- ret = unzGoToNextFile(pkg);
- continue;
- }
-
- Vector<uint8_t> data;
- bool do_read = true;
-
- if (path.begins_with("Assets/")) {
- path = path.replace(".scale-100", "");
-
- data = _get_image_data(p_preset, path);
- if (data.size() > 0) {
- do_read = false;
- }
- }
-
- //read
- if (do_read) {
- data.resize(info.uncompressed_size);
- unzOpenCurrentFile(pkg);
- unzReadCurrentFile(pkg, data.ptrw(), data.size());
- unzCloseCurrentFile(pkg);
- }
-
- if (path == "AppxManifest.xml") {
- data = _fix_manifest(p_preset, data, p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG));
- }
-
- print_line("ADDING: " + path);
-
- err = packager.add_file(path, data.ptr(), data.size(), template_file_no++, template_files_amount, _should_compress_asset(path, data));
- if (err != OK) {
- return err;
- }
-
- ret = unzGoToNextFile(pkg);
- }
-
- EditorNode::progress_end_task("template_files");
-
- if (ep.step("Creating command line...", 2)) {
- return ERR_SKIP;
- }
-
- Vector<String> cl = ((String)p_preset->get("command_line/extra_args")).strip_edges().split(" ");
- for (int i = 0; i < cl.size(); i++) {
- if (cl[i].strip_edges().length() == 0) {
- cl.remove(i);
- i--;
- }
- }
-
- if (!(p_flags & DEBUG_FLAG_DUMB_CLIENT)) {
- cl.push_back("--path");
- cl.push_back("game");
- }
-
- gen_export_flags(cl, p_flags);
-
- // Command line file
- Vector<uint8_t> clf;
-
- // Argc
- clf.resize(4);
- encode_uint32(cl.size(), clf.ptrw());
-
- for (int i = 0; i < cl.size(); i++) {
- CharString txt = cl[i].utf8();
- int base = clf.size();
- clf.resize(base + 4 + txt.length());
- encode_uint32(txt.length(), &clf.write[base]);
- memcpy(&clf.write[base + 4], txt.ptr(), txt.length());
- print_line(itos(i) + " param: " + cl[i]);
- }
-
- err = packager.add_file("__cl__.cl", clf.ptr(), clf.size(), -1, -1, false);
- if (err != OK) {
- return err;
- }
-
- if (ep.step("Adding project files...", 3)) {
- return ERR_SKIP;
- }
-
- EditorNode::progress_add_task("project_files", "Project Files", 100);
- packager.set_progress_task("project_files");
-
- err = export_project_files(p_preset, save_appx_file, &packager);
-
- EditorNode::progress_end_task("project_files");
-
- if (ep.step("Closing package...", 7)) {
- return ERR_SKIP;
- }
-
- unzClose(pkg);
-
- packager.finish();
-
-#ifdef WINDOWS_ENABLED
- // Sign with signtool
- String signtool_path = EditorSettings::get_singleton()->get("export/uwp/signtool");
- if (signtool_path == String()) {
- return OK;
- }
-
- if (!FileAccess::exists(signtool_path)) {
- ERR_PRINT("Could not find signtool executable at " + signtool_path + ", aborting.");
- return ERR_FILE_NOT_FOUND;
- }
-
- static String algs[] = { "MD5", "SHA1", "SHA256" };
-
- String cert_path = EditorSettings::get_singleton()->get("export/uwp/debug_certificate");
- String cert_pass = EditorSettings::get_singleton()->get("export/uwp/debug_password");
- int cert_alg = EditorSettings::get_singleton()->get("export/uwp/debug_algorithm");
-
- if (!p_debug) {
- cert_path = p_preset->get("signing/certificate");
- cert_pass = p_preset->get("signing/password");
- cert_alg = p_preset->get("signing/algorithm");
- }
-
- if (cert_path == String()) {
- return OK; // Certificate missing, don't try to sign
- }
-
- if (!FileAccess::exists(cert_path)) {
- ERR_PRINT("Could not find certificate file at " + cert_path + ", aborting.");
- return ERR_FILE_NOT_FOUND;
- }
-
- if (cert_alg < 0 || cert_alg > 2) {
- ERR_PRINT("Invalid certificate algorithm " + itos(cert_alg) + ", aborting.");
- return ERR_INVALID_DATA;
- }
-
- List<String> args;
- args.push_back("sign");
- args.push_back("/fd");
- args.push_back(algs[cert_alg]);
- args.push_back("/a");
- args.push_back("/f");
- args.push_back(cert_path);
- args.push_back("/p");
- args.push_back(cert_pass);
- args.push_back(p_path);
-
- OS::get_singleton()->execute(signtool_path, args);
-#endif // WINDOWS_ENABLED
-
- return OK;
- }
-
- virtual void get_platform_features(List<String> *r_features) override {
- r_features->push_back("pc");
- r_features->push_back("UWP");
- }
-
- virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) override {
- }
-
- EditorExportPlatformUWP() {
- Ref<Image> img = memnew(Image(_uwp_logo));
- logo.instantiate();
- logo->create_from_image(img);
- }
-};
+#include "export_plugin.h"
void register_uwp_exporter() {
#ifdef WINDOWS_ENABLED
diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp
new file mode 100644
index 0000000000..5bd00b1549
--- /dev/null
+++ b/platform/uwp/export/export_plugin.cpp
@@ -0,0 +1,498 @@
+/*************************************************************************/
+/* export_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "export_plugin.h"
+
+#include "platform/uwp/logo.gen.h"
+
+String EditorExportPlatformUWP::get_name() const {
+ return "UWP";
+}
+String EditorExportPlatformUWP::get_os_name() const {
+ return "UWP";
+}
+
+List<String> EditorExportPlatformUWP::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
+ List<String> list;
+ list.push_back("appx");
+ return list;
+}
+
+Ref<Texture2D> EditorExportPlatformUWP::get_logo() const {
+ return logo;
+}
+
+void EditorExportPlatformUWP::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
+ r_features->push_back("s3tc");
+ r_features->push_back("etc");
+ switch ((int)p_preset->get("architecture/target")) {
+ case EditorExportPlatformUWP::ARM: {
+ r_features->push_back("arm");
+ } break;
+ case EditorExportPlatformUWP::X86: {
+ r_features->push_back("32");
+ } break;
+ case EditorExportPlatformUWP::X64: {
+ r_features->push_back("64");
+ } break;
+ }
+}
+
+void EditorExportPlatformUWP::get_export_options(List<ExportOption> *r_options) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "architecture/target", PROPERTY_HINT_ENUM, "arm,x86,x64"), 1));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), ""));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/display_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/short_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game.Name"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/description"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/publisher", PROPERTY_HINT_PLACEHOLDER_TEXT, "CN=CompanyName"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/publisher_display_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Company Name"), ""));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "identity/product_guid", PROPERTY_HINT_PLACEHOLDER_TEXT, "00000000-0000-0000-0000-000000000000"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "identity/publisher_guid", PROPERTY_HINT_PLACEHOLDER_TEXT, "00000000-0000-0000-0000-000000000000"), ""));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "signing/certificate", PROPERTY_HINT_GLOBAL_FILE, "*.pfx"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "signing/password"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "signing/algorithm", PROPERTY_HINT_ENUM, "MD5,SHA1,SHA256"), 2));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/major"), 1));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/minor"), 0));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/build"), 0));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/revision"), 0));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/landscape"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/portrait"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/landscape_flipped"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/portrait_flipped"), true));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "images/background_color"), "transparent"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/store_logo", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture2D"), Variant()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/square44x44_logo", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture2D"), Variant()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/square71x71_logo", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture2D"), Variant()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/square150x150_logo", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture2D"), Variant()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/square310x310_logo", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture2D"), Variant()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/wide310x150_logo", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture2D"), Variant()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/splash_screen", PROPERTY_HINT_RESOURCE_TYPE, "StreamTexture2D"), Variant()));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "tiles/show_name_on_square150x150"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "tiles/show_name_on_wide310x150"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "tiles/show_name_on_square310x310"), false));
+
+ // Capabilities
+ const char **basic = uwp_capabilities;
+ while (*basic) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/" + String(*basic)), false));
+ basic++;
+ }
+
+ const char **uap = uwp_uap_capabilities;
+ while (*uap) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/" + String(*uap)), false));
+ uap++;
+ }
+
+ const char **device = uwp_device_capabilities;
+ while (*device) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/" + String(*device)), false));
+ device++;
+ }
+}
+
+bool EditorExportPlatformUWP::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+ String err;
+ bool valid = false;
+
+ // Look for export templates (first official, and if defined custom templates).
+
+ Platform arch = (Platform)(int)(p_preset->get("architecture/target"));
+ String platform_infix;
+ switch (arch) {
+ case EditorExportPlatformUWP::ARM: {
+ platform_infix = "arm";
+ } break;
+ case EditorExportPlatformUWP::X86: {
+ platform_infix = "x86";
+ } break;
+ case EditorExportPlatformUWP::X64: {
+ platform_infix = "x64";
+ } break;
+ }
+
+ bool dvalid = exists_export_template("uwp_" + platform_infix + "_debug.zip", &err);
+ bool rvalid = exists_export_template("uwp_" + platform_infix + "_release.zip", &err);
+
+ if (p_preset->get("custom_template/debug") != "") {
+ dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
+ if (!dvalid) {
+ err += TTR("Custom debug template not found.") + "\n";
+ }
+ }
+ if (p_preset->get("custom_template/release") != "") {
+ rvalid = FileAccess::exists(p_preset->get("custom_template/release"));
+ if (!rvalid) {
+ err += TTR("Custom release template not found.") + "\n";
+ }
+ }
+
+ valid = dvalid || rvalid;
+ r_missing_templates = !valid;
+
+ // Validate the rest of the configuration.
+
+ if (!_valid_resource_name(p_preset->get("package/short_name"))) {
+ valid = false;
+ err += TTR("Invalid package short name.") + "\n";
+ }
+
+ if (!_valid_resource_name(p_preset->get("package/unique_name"))) {
+ valid = false;
+ err += TTR("Invalid package unique name.") + "\n";
+ }
+
+ if (!_valid_resource_name(p_preset->get("package/publisher_display_name"))) {
+ valid = false;
+ err += TTR("Invalid package publisher display name.") + "\n";
+ }
+
+ if (!_valid_guid(p_preset->get("identity/product_guid"))) {
+ valid = false;
+ err += TTR("Invalid product GUID.") + "\n";
+ }
+
+ if (!_valid_guid(p_preset->get("identity/publisher_guid"))) {
+ valid = false;
+ err += TTR("Invalid publisher GUID.") + "\n";
+ }
+
+ if (!_valid_bgcolor(p_preset->get("images/background_color"))) {
+ valid = false;
+ err += TTR("Invalid background color.") + "\n";
+ }
+
+ if (!p_preset->get("images/store_logo").is_zero() && !_valid_image((Object::cast_to<StreamTexture2D>((Object *)p_preset->get("images/store_logo"))), 50, 50)) {
+ valid = false;
+ err += TTR("Invalid Store Logo image dimensions (should be 50x50).") + "\n";
+ }
+
+ if (!p_preset->get("images/square44x44_logo").is_zero() && !_valid_image((Object::cast_to<StreamTexture2D>((Object *)p_preset->get("images/square44x44_logo"))), 44, 44)) {
+ valid = false;
+ err += TTR("Invalid square 44x44 logo image dimensions (should be 44x44).") + "\n";
+ }
+
+ if (!p_preset->get("images/square71x71_logo").is_zero() && !_valid_image((Object::cast_to<StreamTexture2D>((Object *)p_preset->get("images/square71x71_logo"))), 71, 71)) {
+ valid = false;
+ err += TTR("Invalid square 71x71 logo image dimensions (should be 71x71).") + "\n";
+ }
+
+ if (!p_preset->get("images/square150x150_logo").is_zero() && !_valid_image((Object::cast_to<StreamTexture2D>((Object *)p_preset->get("images/square150x150_logo"))), 150, 150)) {
+ valid = false;
+ err += TTR("Invalid square 150x150 logo image dimensions (should be 150x150).") + "\n";
+ }
+
+ if (!p_preset->get("images/square310x310_logo").is_zero() && !_valid_image((Object::cast_to<StreamTexture2D>((Object *)p_preset->get("images/square310x310_logo"))), 310, 310)) {
+ valid = false;
+ err += TTR("Invalid square 310x310 logo image dimensions (should be 310x310).") + "\n";
+ }
+
+ if (!p_preset->get("images/wide310x150_logo").is_zero() && !_valid_image((Object::cast_to<StreamTexture2D>((Object *)p_preset->get("images/wide310x150_logo"))), 310, 150)) {
+ valid = false;
+ err += TTR("Invalid wide 310x150 logo image dimensions (should be 310x150).") + "\n";
+ }
+
+ if (!p_preset->get("images/splash_screen").is_zero() && !_valid_image((Object::cast_to<StreamTexture2D>((Object *)p_preset->get("images/splash_screen"))), 620, 300)) {
+ valid = false;
+ err += TTR("Invalid splash screen image dimensions (should be 620x300).") + "\n";
+ }
+
+ r_error = err;
+ return valid;
+}
+
+Error EditorExportPlatformUWP::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
+ ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
+
+ String src_appx;
+
+ EditorProgress ep("export", "Exporting for UWP", 7, true);
+
+ if (p_debug) {
+ src_appx = p_preset->get("custom_template/debug");
+ } else {
+ src_appx = p_preset->get("custom_template/release");
+ }
+
+ src_appx = src_appx.strip_edges();
+
+ Platform arch = (Platform)(int)p_preset->get("architecture/target");
+
+ if (src_appx == "") {
+ String err, infix;
+ switch (arch) {
+ case ARM: {
+ infix = "_arm_";
+ } break;
+ case X86: {
+ infix = "_x86_";
+ } break;
+ case X64: {
+ infix = "_x64_";
+ } break;
+ }
+ if (p_debug) {
+ src_appx = find_export_template("uwp" + infix + "debug.zip", &err);
+ } else {
+ src_appx = find_export_template("uwp" + infix + "release.zip", &err);
+ }
+ if (src_appx == "") {
+ EditorNode::add_io_error(err);
+ return ERR_FILE_NOT_FOUND;
+ }
+ }
+
+ if (!DirAccess::exists(p_path.get_base_dir())) {
+ return ERR_FILE_BAD_PATH;
+ }
+
+ Error err = OK;
+
+ FileAccess *fa_pack = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V_MSG(err != OK, ERR_CANT_CREATE, "Cannot create file '" + p_path + "'.");
+
+ AppxPackager packager;
+ packager.init(fa_pack);
+
+ FileAccess *src_f = nullptr;
+ zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
+
+ if (ep.step("Creating package...", 0)) {
+ return ERR_SKIP;
+ }
+
+ unzFile pkg = unzOpen2(src_appx.utf8().get_data(), &io);
+
+ if (!pkg) {
+ EditorNode::add_io_error("Could not find template appx to export:\n" + src_appx);
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ int ret = unzGoToFirstFile(pkg);
+
+ if (ep.step("Copying template files...", 1)) {
+ return ERR_SKIP;
+ }
+
+ EditorNode::progress_add_task("template_files", "Template files", 100);
+ packager.set_progress_task("template_files");
+
+ int template_files_amount = 9;
+ int template_file_no = 1;
+
+ while (ret == UNZ_OK) {
+ // get file name
+ unz_file_info info;
+ char fname[16834];
+ ret = unzGetCurrentFileInfo(pkg, &info, fname, 16834, nullptr, 0, nullptr, 0);
+
+ String path = fname;
+
+ if (path.ends_with("/")) {
+ // Ignore directories
+ ret = unzGoToNextFile(pkg);
+ continue;
+ }
+
+ Vector<uint8_t> data;
+ bool do_read = true;
+
+ if (path.begins_with("Assets/")) {
+ path = path.replace(".scale-100", "");
+
+ data = _get_image_data(p_preset, path);
+ if (data.size() > 0) {
+ do_read = false;
+ }
+ }
+
+ //read
+ if (do_read) {
+ data.resize(info.uncompressed_size);
+ unzOpenCurrentFile(pkg);
+ unzReadCurrentFile(pkg, data.ptrw(), data.size());
+ unzCloseCurrentFile(pkg);
+ }
+
+ if (path == "AppxManifest.xml") {
+ data = _fix_manifest(p_preset, data, p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG));
+ }
+
+ print_line("ADDING: " + path);
+
+ err = packager.add_file(path, data.ptr(), data.size(), template_file_no++, template_files_amount, _should_compress_asset(path, data));
+ if (err != OK) {
+ return err;
+ }
+
+ ret = unzGoToNextFile(pkg);
+ }
+
+ EditorNode::progress_end_task("template_files");
+
+ if (ep.step("Creating command line...", 2)) {
+ return ERR_SKIP;
+ }
+
+ Vector<String> cl = ((String)p_preset->get("command_line/extra_args")).strip_edges().split(" ");
+ for (int i = 0; i < cl.size(); i++) {
+ if (cl[i].strip_edges().length() == 0) {
+ cl.remove(i);
+ i--;
+ }
+ }
+
+ if (!(p_flags & DEBUG_FLAG_DUMB_CLIENT)) {
+ cl.push_back("--path");
+ cl.push_back("game");
+ }
+
+ gen_export_flags(cl, p_flags);
+
+ // Command line file
+ Vector<uint8_t> clf;
+
+ // Argc
+ clf.resize(4);
+ encode_uint32(cl.size(), clf.ptrw());
+
+ for (int i = 0; i < cl.size(); i++) {
+ CharString txt = cl[i].utf8();
+ int base = clf.size();
+ clf.resize(base + 4 + txt.length());
+ encode_uint32(txt.length(), &clf.write[base]);
+ memcpy(&clf.write[base + 4], txt.ptr(), txt.length());
+ print_line(itos(i) + " param: " + cl[i]);
+ }
+
+ err = packager.add_file("__cl__.cl", clf.ptr(), clf.size(), -1, -1, false);
+ if (err != OK) {
+ return err;
+ }
+
+ if (ep.step("Adding project files...", 3)) {
+ return ERR_SKIP;
+ }
+
+ EditorNode::progress_add_task("project_files", "Project Files", 100);
+ packager.set_progress_task("project_files");
+
+ err = export_project_files(p_preset, save_appx_file, &packager);
+
+ EditorNode::progress_end_task("project_files");
+
+ if (ep.step("Closing package...", 7)) {
+ return ERR_SKIP;
+ }
+
+ unzClose(pkg);
+
+ packager.finish();
+
+#ifdef WINDOWS_ENABLED
+ // Sign with signtool
+ String signtool_path = EditorSettings::get_singleton()->get("export/uwp/signtool");
+ if (signtool_path == String()) {
+ return OK;
+ }
+
+ if (!FileAccess::exists(signtool_path)) {
+ ERR_PRINT("Could not find signtool executable at " + signtool_path + ", aborting.");
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ static String algs[] = { "MD5", "SHA1", "SHA256" };
+
+ String cert_path = EditorSettings::get_singleton()->get("export/uwp/debug_certificate");
+ String cert_pass = EditorSettings::get_singleton()->get("export/uwp/debug_password");
+ int cert_alg = EditorSettings::get_singleton()->get("export/uwp/debug_algorithm");
+
+ if (!p_debug) {
+ cert_path = p_preset->get("signing/certificate");
+ cert_pass = p_preset->get("signing/password");
+ cert_alg = p_preset->get("signing/algorithm");
+ }
+
+ if (cert_path == String()) {
+ return OK; // Certificate missing, don't try to sign
+ }
+
+ if (!FileAccess::exists(cert_path)) {
+ ERR_PRINT("Could not find certificate file at " + cert_path + ", aborting.");
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ if (cert_alg < 0 || cert_alg > 2) {
+ ERR_PRINT("Invalid certificate algorithm " + itos(cert_alg) + ", aborting.");
+ return ERR_INVALID_DATA;
+ }
+
+ List<String> args;
+ args.push_back("sign");
+ args.push_back("/fd");
+ args.push_back(algs[cert_alg]);
+ args.push_back("/a");
+ args.push_back("/f");
+ args.push_back(cert_path);
+ args.push_back("/p");
+ args.push_back(cert_pass);
+ args.push_back(p_path);
+
+ OS::get_singleton()->execute(signtool_path, args);
+#endif // WINDOWS_ENABLED
+
+ return OK;
+}
+
+void EditorExportPlatformUWP::get_platform_features(List<String> *r_features) {
+ r_features->push_back("pc");
+ r_features->push_back("UWP");
+}
+
+void EditorExportPlatformUWP::resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) {
+}
+
+EditorExportPlatformUWP::EditorExportPlatformUWP() {
+ Ref<Image> img = memnew(Image(_uwp_logo));
+ logo.instantiate();
+ logo->create_from_image(img);
+}
diff --git a/platform/uwp/export/export_plugin.h b/platform/uwp/export/export_plugin.h
new file mode 100644
index 0000000000..f295789254
--- /dev/null
+++ b/platform/uwp/export/export_plugin.h
@@ -0,0 +1,448 @@
+/*************************************************************************/
+/* export_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef UWP_EXPORT_PLUGIN_H
+#define UWP_EXPORT_PLUGIN_H
+
+#include "core/config/project_settings.h"
+#include "core/crypto/crypto_core.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
+#include "core/io/marshalls.h"
+#include "core/io/zip_io.h"
+#include "core/object/class_db.h"
+#include "core/version.h"
+#include "editor/editor_export.h"
+#include "editor/editor_node.h"
+
+#include "thirdparty/minizip/unzip.h"
+#include "thirdparty/minizip/zip.h"
+
+#include "app_packager.h"
+
+#include <zlib.h>
+
+// Capabilities
+static const char *uwp_capabilities[] = {
+ "allJoyn",
+ "codeGeneration",
+ "internetClient",
+ "internetClientServer",
+ "privateNetworkClientServer",
+ nullptr
+};
+static const char *uwp_uap_capabilities[] = {
+ "appointments",
+ "blockedChatMessages",
+ "chat",
+ "contacts",
+ "enterpriseAuthentication",
+ "musicLibrary",
+ "objects3D",
+ "picturesLibrary",
+ "phoneCall",
+ "removableStorage",
+ "sharedUserCertificates",
+ "userAccountInformation",
+ "videosLibrary",
+ "voipCall",
+ nullptr
+};
+static const char *uwp_device_capabilities[] = {
+ "bluetooth",
+ "location",
+ "microphone",
+ "proximity",
+ "webcam",
+ nullptr
+};
+
+class EditorExportPlatformUWP : public EditorExportPlatform {
+ GDCLASS(EditorExportPlatformUWP, EditorExportPlatform);
+
+ Ref<ImageTexture> logo;
+
+ enum Platform {
+ ARM,
+ X86,
+ X64
+ };
+
+ bool _valid_resource_name(const String &p_name) const {
+ if (p_name.is_empty()) {
+ return false;
+ }
+ if (p_name.ends_with(".")) {
+ return false;
+ }
+
+ static const char *invalid_names[] = {
+ "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7",
+ "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
+ nullptr
+ };
+
+ const char **t = invalid_names;
+ while (*t) {
+ if (p_name == *t) {
+ return false;
+ }
+ t++;
+ }
+
+ return true;
+ }
+
+ bool _valid_guid(const String &p_guid) const {
+ Vector<String> parts = p_guid.split("-");
+
+ if (parts.size() != 5) {
+ return false;
+ }
+ if (parts[0].length() != 8) {
+ return false;
+ }
+ for (int i = 1; i < 4; i++) {
+ if (parts[i].length() != 4) {
+ return false;
+ }
+ }
+ if (parts[4].length() != 12) {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool _valid_bgcolor(const String &p_color) const {
+ if (p_color.is_empty()) {
+ return true;
+ }
+ if (p_color.begins_with("#") && p_color.is_valid_html_color()) {
+ return true;
+ }
+
+ // Colors from https://msdn.microsoft.com/en-us/library/windows/apps/dn934817.aspx
+ static const char *valid_colors[] = {
+ "aliceBlue", "antiqueWhite", "aqua", "aquamarine", "azure", "beige",
+ "bisque", "black", "blanchedAlmond", "blue", "blueViolet", "brown",
+ "burlyWood", "cadetBlue", "chartreuse", "chocolate", "coral", "cornflowerBlue",
+ "cornsilk", "crimson", "cyan", "darkBlue", "darkCyan", "darkGoldenrod",
+ "darkGray", "darkGreen", "darkKhaki", "darkMagenta", "darkOliveGreen", "darkOrange",
+ "darkOrchid", "darkRed", "darkSalmon", "darkSeaGreen", "darkSlateBlue", "darkSlateGray",
+ "darkTurquoise", "darkViolet", "deepPink", "deepSkyBlue", "dimGray", "dodgerBlue",
+ "firebrick", "floralWhite", "forestGreen", "fuchsia", "gainsboro", "ghostWhite",
+ "gold", "goldenrod", "gray", "green", "greenYellow", "honeydew",
+ "hotPink", "indianRed", "indigo", "ivory", "khaki", "lavender",
+ "lavenderBlush", "lawnGreen", "lemonChiffon", "lightBlue", "lightCoral", "lightCyan",
+ "lightGoldenrodYellow", "lightGreen", "lightGray", "lightPink", "lightSalmon", "lightSeaGreen",
+ "lightSkyBlue", "lightSlateGray", "lightSteelBlue", "lightYellow", "lime", "limeGreen",
+ "linen", "magenta", "maroon", "mediumAquamarine", "mediumBlue", "mediumOrchid",
+ "mediumPurple", "mediumSeaGreen", "mediumSlateBlue", "mediumSpringGreen", "mediumTurquoise", "mediumVioletRed",
+ "midnightBlue", "mintCream", "mistyRose", "moccasin", "navajoWhite", "navy",
+ "oldLace", "olive", "oliveDrab", "orange", "orangeRed", "orchid",
+ "paleGoldenrod", "paleGreen", "paleTurquoise", "paleVioletRed", "papayaWhip", "peachPuff",
+ "peru", "pink", "plum", "powderBlue", "purple", "red",
+ "rosyBrown", "royalBlue", "saddleBrown", "salmon", "sandyBrown", "seaGreen",
+ "seaShell", "sienna", "silver", "skyBlue", "slateBlue", "slateGray",
+ "snow", "springGreen", "steelBlue", "tan", "teal", "thistle",
+ "tomato", "transparent", "turquoise", "violet", "wheat", "white",
+ "whiteSmoke", "yellow", "yellowGreen",
+ nullptr
+ };
+
+ const char **color = valid_colors;
+
+ while (*color) {
+ if (p_color == *color) {
+ return true;
+ }
+ color++;
+ }
+
+ return false;
+ }
+
+ bool _valid_image(const StreamTexture2D *p_image, int p_width, int p_height) const {
+ if (!p_image) {
+ return false;
+ }
+
+ // TODO: Add resource creation or image rescaling to enable other scales:
+ // 1.25, 1.5, 2.0
+ return p_width == p_image->get_width() && p_height == p_image->get_height();
+ }
+
+ Vector<uint8_t> _fix_manifest(const Ref<EditorExportPreset> &p_preset, const Vector<uint8_t> &p_template, bool p_give_internet) const {
+ String result = String::utf8((const char *)p_template.ptr(), p_template.size());
+
+ result = result.replace("$godot_version$", VERSION_FULL_NAME);
+
+ result = result.replace("$identity_name$", p_preset->get("package/unique_name"));
+ result = result.replace("$publisher$", p_preset->get("package/publisher"));
+
+ result = result.replace("$product_guid$", p_preset->get("identity/product_guid"));
+ result = result.replace("$publisher_guid$", p_preset->get("identity/publisher_guid"));
+
+ String version = itos(p_preset->get("version/major")) + "." + itos(p_preset->get("version/minor")) + "." + itos(p_preset->get("version/build")) + "." + itos(p_preset->get("version/revision"));
+ result = result.replace("$version_string$", version);
+
+ Platform arch = (Platform)(int)p_preset->get("architecture/target");
+ String architecture = arch == ARM ? "arm" : (arch == X86 ? "x86" : "x64");
+ result = result.replace("$architecture$", architecture);
+
+ result = result.replace("$display_name$", String(p_preset->get("package/display_name")).is_empty() ? (String)ProjectSettings::get_singleton()->get("application/config/name") : String(p_preset->get("package/display_name")));
+
+ result = result.replace("$publisher_display_name$", p_preset->get("package/publisher_display_name"));
+ result = result.replace("$app_description$", p_preset->get("package/description"));
+ result = result.replace("$bg_color$", p_preset->get("images/background_color"));
+ result = result.replace("$short_name$", p_preset->get("package/short_name"));
+
+ String name_on_tiles = "";
+ if ((bool)p_preset->get("tiles/show_name_on_square150x150")) {
+ name_on_tiles += " <uap:ShowOn Tile=\"square150x150Logo\" />\n";
+ }
+ if ((bool)p_preset->get("tiles/show_name_on_wide310x150")) {
+ name_on_tiles += " <uap:ShowOn Tile=\"wide310x150Logo\" />\n";
+ }
+ if ((bool)p_preset->get("tiles/show_name_on_square310x310")) {
+ name_on_tiles += " <uap:ShowOn Tile=\"square310x310Logo\" />\n";
+ }
+
+ String show_name_on_tiles = "";
+ if (!name_on_tiles.is_empty()) {
+ show_name_on_tiles = "<uap:ShowNameOnTiles>\n" + name_on_tiles + " </uap:ShowNameOnTiles>";
+ }
+
+ result = result.replace("$name_on_tiles$", name_on_tiles);
+
+ String rotations = "";
+ if ((bool)p_preset->get("orientation/landscape")) {
+ rotations += " <uap:Rotation Preference=\"landscape\" />\n";
+ }
+ if ((bool)p_preset->get("orientation/portrait")) {
+ rotations += " <uap:Rotation Preference=\"portrait\" />\n";
+ }
+ if ((bool)p_preset->get("orientation/landscape_flipped")) {
+ rotations += " <uap:Rotation Preference=\"landscapeFlipped\" />\n";
+ }
+ if ((bool)p_preset->get("orientation/portrait_flipped")) {
+ rotations += " <uap:Rotation Preference=\"portraitFlipped\" />\n";
+ }
+
+ String rotation_preference = "";
+ if (!rotations.is_empty()) {
+ rotation_preference = "<uap:InitialRotationPreference>\n" + rotations + " </uap:InitialRotationPreference>";
+ }
+
+ result = result.replace("$rotation_preference$", rotation_preference);
+
+ String capabilities_elements = "";
+ const char **basic = uwp_capabilities;
+ while (*basic) {
+ if ((bool)p_preset->get("capabilities/" + String(*basic))) {
+ capabilities_elements += " <Capability Name=\"" + String(*basic) + "\" />\n";
+ }
+ basic++;
+ }
+ const char **uap = uwp_uap_capabilities;
+ while (*uap) {
+ if ((bool)p_preset->get("capabilities/" + String(*uap))) {
+ capabilities_elements += " <uap:Capability Name=\"" + String(*uap) + "\" />\n";
+ }
+ uap++;
+ }
+ const char **device = uwp_device_capabilities;
+ while (*device) {
+ if ((bool)p_preset->get("capabilities/" + String(*device))) {
+ capabilities_elements += " <DeviceCapability Name=\"" + String(*device) + "\" />\n";
+ }
+ device++;
+ }
+
+ if (!((bool)p_preset->get("capabilities/internetClient")) && p_give_internet) {
+ capabilities_elements += " <Capability Name=\"internetClient\" />\n";
+ }
+
+ String capabilities_string = "<Capabilities />";
+ if (!capabilities_elements.is_empty()) {
+ capabilities_string = "<Capabilities>\n" + capabilities_elements + " </Capabilities>";
+ }
+
+ result = result.replace("$capabilities_place$", capabilities_string);
+
+ Vector<uint8_t> r_ret;
+ r_ret.resize(result.length());
+
+ for (int i = 0; i < result.length(); i++) {
+ r_ret.write[i] = result.utf8().get(i);
+ }
+
+ return r_ret;
+ }
+
+ Vector<uint8_t> _get_image_data(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
+ Vector<uint8_t> data;
+ StreamTexture2D *texture = nullptr;
+
+ if (p_path.find("StoreLogo") != -1) {
+ texture = p_preset->get("images/store_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/store_logo")));
+ } else if (p_path.find("Square44x44Logo") != -1) {
+ texture = p_preset->get("images/square44x44_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square44x44_logo")));
+ } else if (p_path.find("Square71x71Logo") != -1) {
+ texture = p_preset->get("images/square71x71_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square71x71_logo")));
+ } else if (p_path.find("Square150x150Logo") != -1) {
+ texture = p_preset->get("images/square150x150_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square150x150_logo")));
+ } else if (p_path.find("Square310x310Logo") != -1) {
+ texture = p_preset->get("images/square310x310_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square310x310_logo")));
+ } else if (p_path.find("Wide310x150Logo") != -1) {
+ texture = p_preset->get("images/wide310x150_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/wide310x150_logo")));
+ } else if (p_path.find("SplashScreen") != -1) {
+ texture = p_preset->get("images/splash_screen").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/splash_screen")));
+ } else {
+ ERR_PRINT("Unable to load logo");
+ }
+
+ if (!texture) {
+ return data;
+ }
+
+ String tmp_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("uwp_tmp_logo.png");
+
+ Error err = texture->get_image()->save_png(tmp_path);
+
+ if (err != OK) {
+ String err_string = "Couldn't save temp logo file.";
+
+ EditorNode::add_io_error(err_string);
+ ERR_FAIL_V_MSG(data, err_string);
+ }
+
+ FileAccess *f = FileAccess::open(tmp_path, FileAccess::READ, &err);
+
+ if (err != OK) {
+ String err_string = "Couldn't open temp logo file.";
+ // Cleanup generated file.
+ DirAccess::remove_file_or_error(tmp_path);
+ EditorNode::add_io_error(err_string);
+ ERR_FAIL_V_MSG(data, err_string);
+ }
+
+ data.resize(f->get_length());
+ f->get_buffer(data.ptrw(), data.size());
+
+ f->close();
+ memdelete(f);
+ DirAccess::remove_file_or_error(tmp_path);
+
+ return data;
+ }
+
+ static bool _should_compress_asset(const String &p_path, const Vector<uint8_t> &p_data) {
+ /* TODO: This was copied verbatim from Android export. It should be
+ * refactored to the parent class and also be used for .zip export.
+ */
+
+ /*
+ * By not compressing files with little or not benefit in doing so,
+ * a performance gain is expected at runtime. Moreover, if the APK is
+ * zip-aligned, assets stored as they are can be efficiently read by
+ * Android by memory-mapping them.
+ */
+
+ // -- Unconditional uncompress to mimic AAPT plus some other
+
+ static const char *unconditional_compress_ext[] = {
+ // From https://github.com/android/platform_frameworks_base/blob/master/tools/aapt/Package.cpp
+ // These formats are already compressed, or don't compress well:
+ ".jpg", ".jpeg", ".png", ".gif",
+ ".wav", ".mp2", ".mp3", ".ogg", ".aac",
+ ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet",
+ ".rtttl", ".imy", ".xmf", ".mp4", ".m4a",
+ ".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2",
+ ".amr", ".awb", ".wma", ".wmv",
+ // Godot-specific:
+ ".webp", // Same reasoning as .png
+ ".cfb", // Don't let small config files slow-down startup
+ ".scn", // Binary scenes are usually already compressed
+ ".stex", // Streamable textures are usually already compressed
+ // Trailer for easier processing
+ nullptr
+ };
+
+ for (const char **ext = unconditional_compress_ext; *ext; ++ext) {
+ if (p_path.to_lower().ends_with(String(*ext))) {
+ return false;
+ }
+ }
+
+ // -- Compressed resource?
+
+ if (p_data.size() >= 4 && p_data[0] == 'R' && p_data[1] == 'S' && p_data[2] == 'C' && p_data[3] == 'C') {
+ // Already compressed
+ return false;
+ }
+
+ // --- TODO: Decide on texture resources according to their image compression setting
+
+ return true;
+ }
+
+ static Error save_appx_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
+ AppxPackager *packager = (AppxPackager *)p_userdata;
+ String dst_path = p_path.replace_first("res://", "game/");
+
+ return packager->add_file(dst_path, p_data.ptr(), p_data.size(), p_file, p_total, _should_compress_asset(p_path, p_data));
+ }
+
+public:
+ virtual String get_name() const override;
+ virtual String get_os_name() const override;
+
+ virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
+
+ virtual Ref<Texture2D> get_logo() const override;
+
+ virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) override;
+
+ virtual void get_export_options(List<ExportOption> *r_options) override;
+
+ virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+
+ virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
+
+ virtual void get_platform_features(List<String> *r_features) override;
+
+ virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) override;
+
+ EditorExportPlatformUWP();
+};
+
+#endif
diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp
index 10f953f2ec..4ff42f3f62 100644
--- a/platform/windows/export/export.cpp
+++ b/platform/windows/export/export.cpp
@@ -28,316 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "core/io/file_access.h"
-#include "core/os/os.h"
-#include "editor/editor_export.h"
-#include "editor/editor_node.h"
-#include "editor/editor_settings.h"
-#include "platform/windows/logo.gen.h"
+#include "export.h"
-static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size);
-
-class EditorExportPlatformWindows : public EditorExportPlatformPC {
- void _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path);
- Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path);
-
-public:
- virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
- virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path);
- virtual void get_export_options(List<ExportOption> *r_options);
-};
-
-Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) {
- if (p_preset->get("codesign/enable")) {
- return _code_sign(p_preset, p_path);
- } else {
- return OK;
- }
-}
-
-Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
- Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, p_path, p_flags);
-
- if (err != OK) {
- return err;
- }
-
- _rcedit_add_data(p_preset, p_path);
-
- if (p_preset->get("codesign/enable") && err == OK) {
- err = _code_sign(p_preset, p_path);
- }
-
- return err;
-}
-
-void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_options) {
- EditorExportPlatformPC::get_export_options(r_options);
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false));
-#ifdef WINDOWS_ENABLED
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/identity_type", PROPERTY_HINT_ENUM, "Select automatically,Use PKCS12 file (specify *.PFX/*.P12 file),Use certificate store (specify SHA1 hash)"), 0));
-#endif
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/password"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/timestamp_server_url"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/digest_algorithm", PROPERTY_HINT_ENUM, "SHA1,SHA256"), 1));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/description"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
-
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/company_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Company Name"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_description"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/trademarks"), ""));
-}
-
-void EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
- String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit");
-
- if (rcedit_path == String()) {
- return;
- }
-
- if (!FileAccess::exists(rcedit_path)) {
- ERR_PRINT("Could not find rcedit executable at " + rcedit_path + ", no icon or app information data will be included.");
- return;
- }
-
-#ifndef WINDOWS_ENABLED
- // On non-Windows we need WINE to run rcedit
- String wine_path = EditorSettings::get_singleton()->get("export/windows/wine");
-
- if (wine_path != String() && !FileAccess::exists(wine_path)) {
- ERR_PRINT("Could not find wine executable at " + wine_path + ", no icon or app information data will be included.");
- return;
- }
-
- if (wine_path == String()) {
- wine_path = "wine"; // try to run wine from PATH
- }
-#endif
-
- String icon_path = ProjectSettings::get_singleton()->globalize_path(p_preset->get("application/icon"));
- String file_verion = p_preset->get("application/file_version");
- String product_version = p_preset->get("application/product_version");
- String company_name = p_preset->get("application/company_name");
- String product_name = p_preset->get("application/product_name");
- String file_description = p_preset->get("application/file_description");
- String copyright = p_preset->get("application/copyright");
- String trademarks = p_preset->get("application/trademarks");
- String comments = p_preset->get("application/comments");
-
- List<String> args;
- args.push_back(p_path);
- if (icon_path != String()) {
- args.push_back("--set-icon");
- args.push_back(icon_path);
- }
- if (file_verion != String()) {
- args.push_back("--set-file-version");
- args.push_back(file_verion);
- }
- if (product_version != String()) {
- args.push_back("--set-product-version");
- args.push_back(product_version);
- }
- if (company_name != String()) {
- args.push_back("--set-version-string");
- args.push_back("CompanyName");
- args.push_back(company_name);
- }
- if (product_name != String()) {
- args.push_back("--set-version-string");
- args.push_back("ProductName");
- args.push_back(product_name);
- }
- if (file_description != String()) {
- args.push_back("--set-version-string");
- args.push_back("FileDescription");
- args.push_back(file_description);
- }
- if (copyright != String()) {
- args.push_back("--set-version-string");
- args.push_back("LegalCopyright");
- args.push_back(copyright);
- }
- if (trademarks != String()) {
- args.push_back("--set-version-string");
- args.push_back("LegalTrademarks");
- args.push_back(trademarks);
- }
-
-#ifdef WINDOWS_ENABLED
- OS::get_singleton()->execute(rcedit_path, args);
-#else
- // On non-Windows we need WINE to run rcedit
- args.push_front(rcedit_path);
- OS::get_singleton()->execute(wine_path, args);
-#endif
-}
-
-Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
- List<String> args;
-
-#ifdef WINDOWS_ENABLED
- String signtool_path = EditorSettings::get_singleton()->get("export/windows/signtool");
- if (signtool_path != String() && !FileAccess::exists(signtool_path)) {
- ERR_PRINT("Could not find signtool executable at " + signtool_path + ", aborting.");
- return ERR_FILE_NOT_FOUND;
- }
- if (signtool_path == String()) {
- signtool_path = "signtool"; // try to run signtool from PATH
- }
-#else
- String signtool_path = EditorSettings::get_singleton()->get("export/windows/osslsigncode");
- if (signtool_path != String() && !FileAccess::exists(signtool_path)) {
- ERR_PRINT("Could not find osslsigncode executable at " + signtool_path + ", aborting.");
- return ERR_FILE_NOT_FOUND;
- }
- if (signtool_path == String()) {
- signtool_path = "osslsigncode"; // try to run signtool from PATH
- }
-#endif
-
- args.push_back("sign");
-
- //identity
-#ifdef WINDOWS_ENABLED
- int id_type = p_preset->get("codesign/identity_type");
- if (id_type == 0) { //auto select
- args.push_back("/a");
- } else if (id_type == 1) { //pkcs12
- if (p_preset->get("codesign/identity") != "") {
- args.push_back("/f");
- args.push_back(p_preset->get("codesign/identity"));
- } else {
- EditorNode::add_io_error("codesign: no identity found");
- return FAILED;
- }
- } else if (id_type == 2) { //Windows certificate store
- if (p_preset->get("codesign/identity") != "") {
- args.push_back("/sha1");
- args.push_back(p_preset->get("codesign/identity"));
- } else {
- EditorNode::add_io_error("codesign: no identity found");
- return FAILED;
- }
- } else {
- EditorNode::add_io_error("codesign: invalid identity type");
- return FAILED;
- }
-#else
- if (p_preset->get("codesign/identity") != "") {
- args.push_back("-pkcs12");
- args.push_back(p_preset->get("codesign/identity"));
- } else {
- EditorNode::add_io_error("codesign: no identity found");
- return FAILED;
- }
-#endif
-
- //password
- if (p_preset->get("codesign/password") != "") {
-#ifdef WINDOWS_ENABLED
- args.push_back("/p");
-#else
- args.push_back("-pass");
-#endif
- args.push_back(p_preset->get("codesign/password"));
- }
-
- //timestamp
- if (p_preset->get("codesign/timestamp")) {
- if (p_preset->get("codesign/timestamp_server") != "") {
-#ifdef WINDOWS_ENABLED
- args.push_back("/tr");
- args.push_back(p_preset->get("codesign/timestamp_server_url"));
- args.push_back("/td");
- if ((int)p_preset->get("codesign/digest_algorithm") == 0) {
- args.push_back("sha1");
- } else {
- args.push_back("sha256");
- }
-#else
- args.push_back("-ts");
- args.push_back(p_preset->get("codesign/timestamp_server_url"));
-#endif
- } else {
- EditorNode::add_io_error("codesign: invalid timestamp server");
- return FAILED;
- }
- }
-
- //digest
-#ifdef WINDOWS_ENABLED
- args.push_back("/fd");
-#else
- args.push_back("-h");
-#endif
- if ((int)p_preset->get("codesign/digest_algorithm") == 0) {
- args.push_back("sha1");
- } else {
- args.push_back("sha256");
- }
-
- //description
- if (p_preset->get("codesign/description") != "") {
-#ifdef WINDOWS_ENABLED
- args.push_back("/d");
-#else
- args.push_back("-n");
-#endif
- args.push_back(p_preset->get("codesign/description"));
- }
-
- //user options
- PackedStringArray user_args = p_preset->get("codesign/custom_options");
- for (int i = 0; i < user_args.size(); i++) {
- String user_arg = user_args[i].strip_edges();
- if (!user_arg.is_empty()) {
- args.push_back(user_arg);
- }
- }
-
-#ifndef WINDOWS_ENABLED
- args.push_back("-in");
-#endif
- args.push_back(p_path);
-#ifndef WINDOWS_ENABLED
- args.push_back("-out");
- args.push_back(p_path + "_signed");
-#endif
-
- String str;
- Error err = OS::get_singleton()->execute(signtool_path, args, &str, nullptr, true);
- ERR_FAIL_COND_V(err != OK, err);
-
- print_line("codesign (" + p_path + "): " + str);
-#ifndef WINDOWS_ENABLED
- if (str.find("SignTool Error") != -1) {
-#else
- if (str.find("Failed") != -1) {
-#endif
- return FAILED;
- }
+#include "export_plugin.h"
-#ifndef WINDOWS_ENABLED
- DirAccessRef tmp_dir = DirAccess::create_for_path(p_path.get_base_dir());
-
- err = tmp_dir->remove(p_path);
- ERR_FAIL_COND_V(err != OK, err);
-
- err = tmp_dir->rename(p_path + "_signed", p_path);
- ERR_FAIL_COND_V(err != OK, err);
-#endif
-
- return OK;
-}
+static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size);
void register_windows_exporter() {
EDITOR_DEF("export/windows/rcedit", "");
diff --git a/platform/windows/export/export.h b/platform/windows/export/export.h
index 6a7131c73f..110e1439e2 100644
--- a/platform/windows/export/export.h
+++ b/platform/windows/export/export.h
@@ -28,4 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef WINDOWS_EXPORT_H
+#define WINDOWS_EXPORT_H
+
void register_windows_exporter();
+
+#endif
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
new file mode 100644
index 0000000000..165e86c066
--- /dev/null
+++ b/platform/windows/export/export_plugin.cpp
@@ -0,0 +1,323 @@
+/*************************************************************************/
+/* export_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "export_plugin.h"
+
+Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) {
+ if (p_preset->get("codesign/enable")) {
+ return _code_sign(p_preset, p_path);
+ } else {
+ return OK;
+ }
+}
+
+Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
+ Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, p_path, p_flags);
+
+ if (err != OK) {
+ return err;
+ }
+
+ _rcedit_add_data(p_preset, p_path);
+
+ if (p_preset->get("codesign/enable") && err == OK) {
+ err = _code_sign(p_preset, p_path);
+ }
+
+ return err;
+}
+
+void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_options) {
+ EditorExportPlatformPC::get_export_options(r_options);
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false));
+#ifdef WINDOWS_ENABLED
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/identity_type", PROPERTY_HINT_ENUM, "Select automatically,Use PKCS12 file (specify *.PFX/*.P12 file),Use certificate store (specify SHA1 hash)"), 0));
+#endif
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/password"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/timestamp_server_url"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/digest_algorithm", PROPERTY_HINT_ENUM, "SHA1,SHA256"), 1));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/description"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/company_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Company Name"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_description"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/trademarks"), ""));
+}
+
+void EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
+ String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit");
+
+ if (rcedit_path == String()) {
+ return;
+ }
+
+ if (!FileAccess::exists(rcedit_path)) {
+ ERR_PRINT("Could not find rcedit executable at " + rcedit_path + ", no icon or app information data will be included.");
+ return;
+ }
+
+#ifndef WINDOWS_ENABLED
+ // On non-Windows we need WINE to run rcedit
+ String wine_path = EditorSettings::get_singleton()->get("export/windows/wine");
+
+ if (wine_path != String() && !FileAccess::exists(wine_path)) {
+ ERR_PRINT("Could not find wine executable at " + wine_path + ", no icon or app information data will be included.");
+ return;
+ }
+
+ if (wine_path == String()) {
+ wine_path = "wine"; // try to run wine from PATH
+ }
+#endif
+
+ String icon_path = ProjectSettings::get_singleton()->globalize_path(p_preset->get("application/icon"));
+ String file_verion = p_preset->get("application/file_version");
+ String product_version = p_preset->get("application/product_version");
+ String company_name = p_preset->get("application/company_name");
+ String product_name = p_preset->get("application/product_name");
+ String file_description = p_preset->get("application/file_description");
+ String copyright = p_preset->get("application/copyright");
+ String trademarks = p_preset->get("application/trademarks");
+ String comments = p_preset->get("application/comments");
+
+ List<String> args;
+ args.push_back(p_path);
+ if (icon_path != String()) {
+ args.push_back("--set-icon");
+ args.push_back(icon_path);
+ }
+ if (file_verion != String()) {
+ args.push_back("--set-file-version");
+ args.push_back(file_verion);
+ }
+ if (product_version != String()) {
+ args.push_back("--set-product-version");
+ args.push_back(product_version);
+ }
+ if (company_name != String()) {
+ args.push_back("--set-version-string");
+ args.push_back("CompanyName");
+ args.push_back(company_name);
+ }
+ if (product_name != String()) {
+ args.push_back("--set-version-string");
+ args.push_back("ProductName");
+ args.push_back(product_name);
+ }
+ if (file_description != String()) {
+ args.push_back("--set-version-string");
+ args.push_back("FileDescription");
+ args.push_back(file_description);
+ }
+ if (copyright != String()) {
+ args.push_back("--set-version-string");
+ args.push_back("LegalCopyright");
+ args.push_back(copyright);
+ }
+ if (trademarks != String()) {
+ args.push_back("--set-version-string");
+ args.push_back("LegalTrademarks");
+ args.push_back(trademarks);
+ }
+
+#ifdef WINDOWS_ENABLED
+ OS::get_singleton()->execute(rcedit_path, args);
+#else
+ // On non-Windows we need WINE to run rcedit
+ args.push_front(rcedit_path);
+ OS::get_singleton()->execute(wine_path, args);
+#endif
+}
+
+Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
+ List<String> args;
+
+#ifdef WINDOWS_ENABLED
+ String signtool_path = EditorSettings::get_singleton()->get("export/windows/signtool");
+ if (signtool_path != String() && !FileAccess::exists(signtool_path)) {
+ ERR_PRINT("Could not find signtool executable at " + signtool_path + ", aborting.");
+ return ERR_FILE_NOT_FOUND;
+ }
+ if (signtool_path == String()) {
+ signtool_path = "signtool"; // try to run signtool from PATH
+ }
+#else
+ String signtool_path = EditorSettings::get_singleton()->get("export/windows/osslsigncode");
+ if (signtool_path != String() && !FileAccess::exists(signtool_path)) {
+ ERR_PRINT("Could not find osslsigncode executable at " + signtool_path + ", aborting.");
+ return ERR_FILE_NOT_FOUND;
+ }
+ if (signtool_path == String()) {
+ signtool_path = "osslsigncode"; // try to run signtool from PATH
+ }
+#endif
+
+ args.push_back("sign");
+
+ //identity
+#ifdef WINDOWS_ENABLED
+ int id_type = p_preset->get("codesign/identity_type");
+ if (id_type == 0) { //auto select
+ args.push_back("/a");
+ } else if (id_type == 1) { //pkcs12
+ if (p_preset->get("codesign/identity") != "") {
+ args.push_back("/f");
+ args.push_back(p_preset->get("codesign/identity"));
+ } else {
+ EditorNode::add_io_error("codesign: no identity found");
+ return FAILED;
+ }
+ } else if (id_type == 2) { //Windows certificate store
+ if (p_preset->get("codesign/identity") != "") {
+ args.push_back("/sha1");
+ args.push_back(p_preset->get("codesign/identity"));
+ } else {
+ EditorNode::add_io_error("codesign: no identity found");
+ return FAILED;
+ }
+ } else {
+ EditorNode::add_io_error("codesign: invalid identity type");
+ return FAILED;
+ }
+#else
+ if (p_preset->get("codesign/identity") != "") {
+ args.push_back("-pkcs12");
+ args.push_back(p_preset->get("codesign/identity"));
+ } else {
+ EditorNode::add_io_error("codesign: no identity found");
+ return FAILED;
+ }
+#endif
+
+ //password
+ if (p_preset->get("codesign/password") != "") {
+#ifdef WINDOWS_ENABLED
+ args.push_back("/p");
+#else
+ args.push_back("-pass");
+#endif
+ args.push_back(p_preset->get("codesign/password"));
+ }
+
+ //timestamp
+ if (p_preset->get("codesign/timestamp")) {
+ if (p_preset->get("codesign/timestamp_server") != "") {
+#ifdef WINDOWS_ENABLED
+ args.push_back("/tr");
+ args.push_back(p_preset->get("codesign/timestamp_server_url"));
+ args.push_back("/td");
+ if ((int)p_preset->get("codesign/digest_algorithm") == 0) {
+ args.push_back("sha1");
+ } else {
+ args.push_back("sha256");
+ }
+#else
+ args.push_back("-ts");
+ args.push_back(p_preset->get("codesign/timestamp_server_url"));
+#endif
+ } else {
+ EditorNode::add_io_error("codesign: invalid timestamp server");
+ return FAILED;
+ }
+ }
+
+ //digest
+#ifdef WINDOWS_ENABLED
+ args.push_back("/fd");
+#else
+ args.push_back("-h");
+#endif
+ if ((int)p_preset->get("codesign/digest_algorithm") == 0) {
+ args.push_back("sha1");
+ } else {
+ args.push_back("sha256");
+ }
+
+ //description
+ if (p_preset->get("codesign/description") != "") {
+#ifdef WINDOWS_ENABLED
+ args.push_back("/d");
+#else
+ args.push_back("-n");
+#endif
+ args.push_back(p_preset->get("codesign/description"));
+ }
+
+ //user options
+ PackedStringArray user_args = p_preset->get("codesign/custom_options");
+ for (int i = 0; i < user_args.size(); i++) {
+ String user_arg = user_args[i].strip_edges();
+ if (!user_arg.is_empty()) {
+ args.push_back(user_arg);
+ }
+ }
+
+#ifndef WINDOWS_ENABLED
+ args.push_back("-in");
+#endif
+ args.push_back(p_path);
+#ifndef WINDOWS_ENABLED
+ args.push_back("-out");
+ args.push_back(p_path + "_signed");
+#endif
+
+ String str;
+ Error err = OS::get_singleton()->execute(signtool_path, args, &str, nullptr, true);
+ ERR_FAIL_COND_V(err != OK, err);
+
+ print_line("codesign (" + p_path + "): " + str);
+#ifndef WINDOWS_ENABLED
+ if (str.find("SignTool Error") != -1) {
+#else
+ if (str.find("Failed") != -1) {
+#endif
+ return FAILED;
+ }
+
+#ifndef WINDOWS_ENABLED
+ DirAccessRef tmp_dir = DirAccess::create_for_path(p_path.get_base_dir());
+
+ err = tmp_dir->remove(p_path);
+ ERR_FAIL_COND_V(err != OK, err);
+
+ err = tmp_dir->rename(p_path + "_signed", p_path);
+ ERR_FAIL_COND_V(err != OK, err);
+#endif
+
+ return OK;
+}
diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h
new file mode 100644
index 0000000000..11d3826410
--- /dev/null
+++ b/platform/windows/export/export_plugin.h
@@ -0,0 +1,51 @@
+/*************************************************************************/
+/* export_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef WINDOWS_EXPORT_PLUGIN_H
+#define WINDOWS_EXPORT_PLUGIN_H
+
+#include "core/io/file_access.h"
+#include "core/os/os.h"
+#include "editor/editor_export.h"
+#include "editor/editor_node.h"
+#include "editor/editor_settings.h"
+#include "platform/windows/logo.gen.h"
+
+class EditorExportPlatformWindows : public EditorExportPlatformPC {
+ void _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path);
+ Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path);
+
+public:
+ virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
+ virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path);
+ virtual void get_export_options(List<ExportOption> *r_options);
+};
+
+#endif
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index 3ba3a4eec5..60f29ca163 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -147,36 +147,40 @@ uint32_t CollisionObject2D::get_collision_mask() const {
return collision_mask;
}
-void CollisionObject2D::set_collision_layer_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
+void CollisionObject2D::set_collision_layer_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
uint32_t collision_layer = get_collision_layer();
if (p_value) {
- collision_layer |= 1 << p_bit;
+ collision_layer |= 1 << (p_layer_number - 1);
} else {
- collision_layer &= ~(1 << p_bit);
+ collision_layer &= ~(1 << (p_layer_number - 1));
}
set_collision_layer(collision_layer);
}
-bool CollisionObject2D::get_collision_layer_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
- return get_collision_layer() & (1 << p_bit);
+bool CollisionObject2D::get_collision_layer_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_layer() & (1 << (p_layer_number - 1));
}
-void CollisionObject2D::set_collision_mask_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
+void CollisionObject2D::set_collision_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
- mask |= 1 << p_bit;
+ mask |= 1 << (p_layer_number - 1);
} else {
- mask &= ~(1 << p_bit);
+ mask &= ~(1 << (p_layer_number - 1));
}
set_collision_mask(mask);
}
-bool CollisionObject2D::get_collision_mask_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
- return get_collision_mask() & (1 << p_bit);
+bool CollisionObject2D::get_collision_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_mask() & (1 << (p_layer_number - 1));
}
void CollisionObject2D::set_disable_mode(DisableMode p_mode) {
@@ -565,10 +569,10 @@ void CollisionObject2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_collision_layer"), &CollisionObject2D::get_collision_layer);
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &CollisionObject2D::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &CollisionObject2D::get_collision_mask);
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &CollisionObject2D::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CollisionObject2D::get_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &CollisionObject2D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CollisionObject2D::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &CollisionObject2D::set_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &CollisionObject2D::get_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &CollisionObject2D::set_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &CollisionObject2D::get_collision_mask_value);
ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &CollisionObject2D::set_disable_mode);
ClassDB::bind_method(D_METHOD("get_disable_mode"), &CollisionObject2D::get_disable_mode);
ClassDB::bind_method(D_METHOD("set_pickable", "enabled"), &CollisionObject2D::set_pickable);
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index eca53eecfc..11e11d1382 100644
--- a/scene/2d/collision_object_2d.h
+++ b/scene/2d/collision_object_2d.h
@@ -107,11 +107,11 @@ public:
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
- void set_collision_layer_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
+ void set_collision_layer_value(int p_layer_number, bool p_value);
+ bool get_collision_layer_value(int p_layer_number) const;
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
+ void set_collision_mask_value(int p_layer_number, bool p_value);
+ bool get_collision_mask_value(int p_layer_number) const;
void set_disable_mode(DisableMode p_mode);
DisableMode get_disable_mode() const;
diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp
index c478f03356..a8a2639ccf 100644
--- a/scene/2d/line_builder.cpp
+++ b/scene/2d/line_builder.cpp
@@ -62,14 +62,6 @@ static SegmentIntersectionResult segment_intersection(
return SEGMENT_PARALLEL;
}
-// TODO I'm pretty sure there is an even faster way to swap things
-template <typename T>
-static inline void swap(T &a, T &b) {
- T tmp = a;
- a = b;
- b = tmp;
-}
-
static float calculate_total_distance(const Vector<Vector2> &points) {
float d = 0.f;
for (int i = 1; i < points.size(); ++i) {
diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp
index 602a0f2115..546536f546 100644
--- a/scene/2d/ray_cast_2d.cpp
+++ b/scene/2d/ray_cast_2d.cpp
@@ -54,20 +54,22 @@ uint32_t RayCast2D::get_collision_mask() const {
return collision_mask;
}
-void RayCast2D::set_collision_mask_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
+void RayCast2D::set_collision_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
- mask |= 1 << p_bit;
+ mask |= 1 << (p_layer_number - 1);
} else {
- mask &= ~(1 << p_bit);
+ mask &= ~(1 << (p_layer_number - 1));
}
set_collision_mask(mask);
}
-bool RayCast2D::get_collision_mask_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
- return get_collision_mask() & (1 << p_bit);
+bool RayCast2D::get_collision_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_mask() & (1 << (p_layer_number - 1));
}
bool RayCast2D::is_colliding() const {
@@ -323,8 +325,8 @@ void RayCast2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &RayCast2D::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &RayCast2D::get_collision_mask);
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &RayCast2D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &RayCast2D::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &RayCast2D::set_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &RayCast2D::get_collision_mask_value);
ClassDB::bind_method(D_METHOD("set_exclude_parent_body", "mask"), &RayCast2D::set_exclude_parent_body);
ClassDB::bind_method(D_METHOD("get_exclude_parent_body"), &RayCast2D::get_exclude_parent_body);
diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h
index 984c6bda49..65b6e7899b 100644
--- a/scene/2d/ray_cast_2d.h
+++ b/scene/2d/ray_cast_2d.h
@@ -74,8 +74,8 @@ public:
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
+ void set_collision_mask_value(int p_layer_number, bool p_value);
+ bool get_collision_mask_value(int p_layer_number) const;
void set_exclude_parent_body(bool p_exclude_parent_body);
bool get_exclude_parent_body() const;
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index e504277a55..9dc1df202c 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -499,8 +499,8 @@ void Camera3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_position_in_frustum", "world_point"), &Camera3D::is_position_in_frustum);
ClassDB::bind_method(D_METHOD("get_camera_rid"), &Camera3D::get_camera);
- ClassDB::bind_method(D_METHOD("set_cull_mask_bit", "layer", "enable"), &Camera3D::set_cull_mask_bit);
- ClassDB::bind_method(D_METHOD("get_cull_mask_bit", "layer"), &Camera3D::get_cull_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_cull_mask_value", "layer_number", "value"), &Camera3D::set_cull_mask_value);
+ ClassDB::bind_method(D_METHOD("get_cull_mask_value", "layer_number"), &Camera3D::get_cull_mask_value);
//ClassDB::bind_method(D_METHOD("_camera_make_current"),&Camera::_camera_make_current );
@@ -592,18 +592,22 @@ uint32_t Camera3D::get_cull_mask() const {
return layers;
}
-void Camera3D::set_cull_mask_bit(int p_layer, bool p_enable) {
- ERR_FAIL_INDEX(p_layer, 32);
- if (p_enable) {
- set_cull_mask(layers | (1 << p_layer));
+void Camera3D::set_cull_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Render layer number must be between 1 and 20 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 20, "Render layer number must be between 1 and 20 inclusive.");
+ uint32_t mask = get_cull_mask();
+ if (p_value) {
+ mask |= 1 << (p_layer_number - 1);
} else {
- set_cull_mask(layers & (~(1 << p_layer)));
+ mask &= ~(1 << (p_layer_number - 1));
}
+ set_cull_mask(mask);
}
-bool Camera3D::get_cull_mask_bit(int p_layer) const {
- ERR_FAIL_INDEX_V(p_layer, 32, false);
- return (layers & (1 << p_layer));
+bool Camera3D::get_cull_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Render layer number must be between 1 and 20 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 20, false, "Render layer number must be between 1 and 20 inclusive.");
+ return layers & (1 << (p_layer_number - 1));
}
Vector<Plane> Camera3D::get_frustum() const {
@@ -767,20 +771,22 @@ uint32_t ClippedCamera3D::get_collision_mask() const {
return collision_mask;
}
-void ClippedCamera3D::set_collision_mask_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
+void ClippedCamera3D::set_collision_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
- mask |= 1 << p_bit;
+ mask |= 1 << (p_layer_number - 1);
} else {
- mask &= ~(1 << p_bit);
+ mask &= ~(1 << (p_layer_number - 1));
}
set_collision_mask(mask);
}
-bool ClippedCamera3D::get_collision_mask_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
- return get_collision_mask() & (1 << p_bit);
+bool ClippedCamera3D::get_collision_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_mask() & (1 << (p_layer_number - 1));
}
void ClippedCamera3D::add_exception_rid(const RID &p_rid) {
@@ -843,8 +849,8 @@ void ClippedCamera3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &ClippedCamera3D::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &ClippedCamera3D::get_collision_mask);
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &ClippedCamera3D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &ClippedCamera3D::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &ClippedCamera3D::set_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &ClippedCamera3D::get_collision_mask_value);
ClassDB::bind_method(D_METHOD("add_exception_rid", "rid"), &ClippedCamera3D::add_exception_rid);
ClassDB::bind_method(D_METHOD("add_exception", "node"), &ClippedCamera3D::add_exception);
diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h
index 61e3f51d0b..b7bf5566e7 100644
--- a/scene/3d/camera_3d.h
+++ b/scene/3d/camera_3d.h
@@ -147,8 +147,8 @@ public:
void set_cull_mask(uint32_t p_layers);
uint32_t get_cull_mask() const;
- void set_cull_mask_bit(int p_layer, bool p_enable);
- bool get_cull_mask_bit(int p_layer) const;
+ void set_cull_mask_value(int p_layer_number, bool p_enable);
+ bool get_cull_mask_value(int p_layer_number) const;
virtual Vector<Plane> get_frustum() const;
bool is_position_in_frustum(const Vector3 &p_position) const;
@@ -224,8 +224,8 @@ public:
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
+ void set_collision_mask_value(int p_layer_number, bool p_value);
+ bool get_collision_mask_value(int p_layer_number) const;
void add_exception_rid(const RID &p_rid);
void add_exception(const Object *p_object);
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index dd1f25da68..75bb2995d3 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -146,36 +146,40 @@ uint32_t CollisionObject3D::get_collision_mask() const {
return collision_mask;
}
-void CollisionObject3D::set_collision_layer_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
+void CollisionObject3D::set_collision_layer_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
uint32_t collision_layer = get_collision_layer();
if (p_value) {
- collision_layer |= 1 << p_bit;
+ collision_layer |= 1 << (p_layer_number - 1);
} else {
- collision_layer &= ~(1 << p_bit);
+ collision_layer &= ~(1 << (p_layer_number - 1));
}
set_collision_layer(collision_layer);
}
-bool CollisionObject3D::get_collision_layer_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
- return get_collision_layer() & (1 << p_bit);
+bool CollisionObject3D::get_collision_layer_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_layer() & (1 << (p_layer_number - 1));
}
-void CollisionObject3D::set_collision_mask_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
+void CollisionObject3D::set_collision_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
- mask |= 1 << p_bit;
+ mask |= 1 << (p_layer_number - 1);
} else {
- mask &= ~(1 << p_bit);
+ mask &= ~(1 << (p_layer_number - 1));
}
set_collision_mask(mask);
}
-bool CollisionObject3D::get_collision_mask_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
- return get_collision_mask() & (1 << p_bit);
+bool CollisionObject3D::get_collision_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_mask() & (1 << (p_layer_number - 1));
}
void CollisionObject3D::set_disable_mode(DisableMode p_mode) {
@@ -423,10 +427,10 @@ void CollisionObject3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_collision_layer"), &CollisionObject3D::get_collision_layer);
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &CollisionObject3D::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &CollisionObject3D::get_collision_mask);
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &CollisionObject3D::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CollisionObject3D::get_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &CollisionObject3D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CollisionObject3D::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &CollisionObject3D::set_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &CollisionObject3D::get_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &CollisionObject3D::set_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &CollisionObject3D::get_collision_mask_value);
ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &CollisionObject3D::set_disable_mode);
ClassDB::bind_method(D_METHOD("get_disable_mode"), &CollisionObject3D::get_disable_mode);
ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &CollisionObject3D::set_ray_pickable);
diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h
index 7c30a5cd98..2e74d84465 100644
--- a/scene/3d/collision_object_3d.h
+++ b/scene/3d/collision_object_3d.h
@@ -119,11 +119,11 @@ public:
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
- void set_collision_layer_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
+ void set_collision_layer_value(int p_layer_number, bool p_value);
+ bool get_collision_layer_value(int p_layer_number) const;
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
+ void set_collision_mask_value(int p_layer_number, bool p_value);
+ bool get_collision_mask_value(int p_layer_number) const;
void set_disable_mode(DisableMode p_mode);
DisableMode get_disable_mode() const;
diff --git a/scene/3d/occluder_instance_3d.cpp b/scene/3d/occluder_instance_3d.cpp
index 3d1a27911b..f3e174c01b 100644
--- a/scene/3d/occluder_instance_3d.cpp
+++ b/scene/3d/occluder_instance_3d.cpp
@@ -195,18 +195,22 @@ uint32_t OccluderInstance3D::get_bake_mask() const {
return bake_mask;
}
-void OccluderInstance3D::set_bake_mask_bit(int p_layer, bool p_enable) {
- ERR_FAIL_INDEX(p_layer, 32);
- if (p_enable) {
- set_bake_mask(bake_mask | (1 << p_layer));
+void OccluderInstance3D::set_bake_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Render layer number must be between 1 and 20 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 20, "Render layer number must be between 1 and 20 inclusive.");
+ uint32_t mask = get_bake_mask();
+ if (p_value) {
+ mask |= 1 << (p_layer_number - 1);
} else {
- set_bake_mask(bake_mask & (~(1 << p_layer)));
+ mask &= ~(1 << (p_layer_number - 1));
}
+ set_bake_mask(mask);
}
-bool OccluderInstance3D::get_bake_mask_bit(int p_layer) const {
- ERR_FAIL_INDEX_V(p_layer, 32, false);
- return (bake_mask & (1 << p_layer));
+bool OccluderInstance3D::get_bake_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Render layer number must be between 1 and 20 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 20, false, "Render layer number must be between 1 and 20 inclusive.");
+ return bake_mask & (1 << (p_layer_number - 1));
}
bool OccluderInstance3D::_bake_material_check(Ref<Material> p_material) {
@@ -345,8 +349,8 @@ TypedArray<String> OccluderInstance3D::get_configuration_warnings() const {
void OccluderInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bake_mask", "mask"), &OccluderInstance3D::set_bake_mask);
ClassDB::bind_method(D_METHOD("get_bake_mask"), &OccluderInstance3D::get_bake_mask);
- ClassDB::bind_method(D_METHOD("set_bake_mask_bit", "layer", "enabled"), &OccluderInstance3D::set_bake_mask_bit);
- ClassDB::bind_method(D_METHOD("get_bake_mask_bit", "layer"), &OccluderInstance3D::get_bake_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_bake_mask_value", "layer_number", "value"), &OccluderInstance3D::set_bake_mask_value);
+ ClassDB::bind_method(D_METHOD("get_bake_mask_value", "layer_number"), &OccluderInstance3D::get_bake_mask_value);
ClassDB::bind_method(D_METHOD("set_occluder", "occluder"), &OccluderInstance3D::set_occluder);
ClassDB::bind_method(D_METHOD("get_occluder"), &OccluderInstance3D::get_occluder);
diff --git a/scene/3d/occluder_instance_3d.h b/scene/3d/occluder_instance_3d.h
index d382cd090e..173614b80c 100644
--- a/scene/3d/occluder_instance_3d.h
+++ b/scene/3d/occluder_instance_3d.h
@@ -99,8 +99,9 @@ public:
void set_bake_mask(uint32_t p_mask);
uint32_t get_bake_mask() const;
- void set_bake_mask_bit(int p_layer, bool p_enable);
- bool get_bake_mask_bit(int p_layer) const;
+ void set_bake_mask_value(int p_layer_number, bool p_enable);
+ bool get_bake_mask_value(int p_layer_number) const;
+
BakeError bake(Node *p_from_node, String p_occluder_path = "");
OccluderInstance3D();
diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp
index 7356ce478b..e757d6d3f4 100644
--- a/scene/3d/ray_cast_3d.cpp
+++ b/scene/3d/ray_cast_3d.cpp
@@ -60,20 +60,22 @@ uint32_t RayCast3D::get_collision_mask() const {
return collision_mask;
}
-void RayCast3D::set_collision_mask_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
+void RayCast3D::set_collision_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
- mask |= 1 << p_bit;
+ mask |= 1 << (p_layer_number - 1);
} else {
- mask &= ~(1 << p_bit);
+ mask &= ~(1 << (p_layer_number - 1));
}
set_collision_mask(mask);
}
-bool RayCast3D::get_collision_mask_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
- return get_collision_mask() & (1 << p_bit);
+bool RayCast3D::get_collision_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_mask() & (1 << (p_layer_number - 1));
}
bool RayCast3D::is_colliding() const {
@@ -303,8 +305,8 @@ void RayCast3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &RayCast3D::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &RayCast3D::get_collision_mask);
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &RayCast3D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &RayCast3D::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &RayCast3D::set_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &RayCast3D::get_collision_mask_value);
ClassDB::bind_method(D_METHOD("set_exclude_parent_body", "mask"), &RayCast3D::set_exclude_parent_body);
ClassDB::bind_method(D_METHOD("get_exclude_parent_body"), &RayCast3D::get_exclude_parent_body);
diff --git a/scene/3d/ray_cast_3d.h b/scene/3d/ray_cast_3d.h
index 968cede9f2..3828bfb4c4 100644
--- a/scene/3d/ray_cast_3d.h
+++ b/scene/3d/ray_cast_3d.h
@@ -86,8 +86,8 @@ public:
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
+ void set_collision_mask_value(int p_layer_number, bool p_value);
+ bool get_collision_mask_value(int p_layer_number) const;
void set_exclude_parent_body(bool p_exclude_parent_body);
bool get_exclude_parent_body() const;
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index a7ff0842d2..3dbeac5e97 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -327,11 +327,11 @@ void SoftBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &SoftBody3D::set_collision_layer);
ClassDB::bind_method(D_METHOD("get_collision_layer"), &SoftBody3D::get_collision_layer);
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &SoftBody3D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &SoftBody3D::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &SoftBody3D::set_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &SoftBody3D::get_collision_mask_value);
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &SoftBody3D::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &SoftBody3D::get_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &SoftBody3D::set_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &SoftBody3D::get_collision_layer_value);
ClassDB::bind_method(D_METHOD("set_parent_collision_ignore", "parent_collision_ignore"), &SoftBody3D::set_parent_collision_ignore);
ClassDB::bind_method(D_METHOD("get_parent_collision_ignore"), &SoftBody3D::get_parent_collision_ignore);
@@ -515,36 +515,40 @@ uint32_t SoftBody3D::get_collision_layer() const {
return collision_layer;
}
-void SoftBody3D::set_collision_mask_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
- uint32_t mask = get_collision_mask();
+void SoftBody3D::set_collision_layer_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
+ uint32_t collision_layer = get_collision_layer();
if (p_value) {
- mask |= 1 << p_bit;
+ collision_layer |= 1 << (p_layer_number - 1);
} else {
- mask &= ~(1 << p_bit);
+ collision_layer &= ~(1 << (p_layer_number - 1));
}
- set_collision_mask(mask);
+ set_collision_layer(collision_layer);
}
-bool SoftBody3D::get_collision_mask_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
- return get_collision_mask() & (1 << p_bit);
+bool SoftBody3D::get_collision_layer_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_layer() & (1 << (p_layer_number - 1));
}
-void SoftBody3D::set_collision_layer_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
- uint32_t layer = get_collision_layer();
+void SoftBody3D::set_collision_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
+ uint32_t mask = get_collision_mask();
if (p_value) {
- layer |= 1 << p_bit;
+ mask |= 1 << (p_layer_number - 1);
} else {
- layer &= ~(1 << p_bit);
+ mask &= ~(1 << (p_layer_number - 1));
}
- set_collision_layer(layer);
+ set_collision_mask(mask);
}
-bool SoftBody3D::get_collision_layer_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
- return get_collision_layer() & (1 << p_bit);
+bool SoftBody3D::get_collision_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_mask() & (1 << (p_layer_number - 1));
}
void SoftBody3D::set_disable_mode(DisableMode p_mode) {
diff --git a/scene/3d/soft_body_3d.h b/scene/3d/soft_body_3d.h
index 81aa0c10c6..46b185a32c 100644
--- a/scene/3d/soft_body_3d.h
+++ b/scene/3d/soft_body_3d.h
@@ -138,11 +138,11 @@ public:
void set_collision_layer(uint32_t p_layer);
uint32_t get_collision_layer() const;
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
+ void set_collision_layer_value(int p_layer_number, bool p_value);
+ bool get_collision_layer_value(int p_layer_number) const;
- void set_collision_layer_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
+ void set_collision_mask_value(int p_layer_number, bool p_value);
+ bool get_collision_mask_value(int p_layer_number) const;
void set_disable_mode(DisableMode p_mode);
DisableMode get_disable_mode() const;
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index c155819159..b437379b2a 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -93,18 +93,22 @@ uint32_t VisualInstance3D::get_layer_mask() const {
return layers;
}
-void VisualInstance3D::set_layer_mask_bit(int p_layer, bool p_enable) {
- ERR_FAIL_INDEX(p_layer, 32);
- if (p_enable) {
- set_layer_mask(layers | (1 << p_layer));
+void VisualInstance3D::set_layer_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Render layer number must be between 1 and 20 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 20, "Render layer number must be between 1 and 20 inclusive.");
+ uint32_t mask = get_layer_mask();
+ if (p_value) {
+ mask |= 1 << (p_layer_number - 1);
} else {
- set_layer_mask(layers & (~(1 << p_layer)));
+ mask &= ~(1 << (p_layer_number - 1));
}
+ set_layer_mask(mask);
}
-bool VisualInstance3D::get_layer_mask_bit(int p_layer) const {
- ERR_FAIL_INDEX_V(p_layer, 32, false);
- return (layers & (1 << p_layer));
+bool VisualInstance3D::get_layer_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Render layer number must be between 1 and 20 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 20, false, "Render layer number must be between 1 and 20 inclusive.");
+ return layers & (1 << (p_layer_number - 1));
}
void VisualInstance3D::_bind_methods() {
@@ -114,8 +118,8 @@ void VisualInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_instance"), &VisualInstance3D::get_instance);
ClassDB::bind_method(D_METHOD("set_layer_mask", "mask"), &VisualInstance3D::set_layer_mask);
ClassDB::bind_method(D_METHOD("get_layer_mask"), &VisualInstance3D::get_layer_mask);
- ClassDB::bind_method(D_METHOD("set_layer_mask_bit", "layer", "enabled"), &VisualInstance3D::set_layer_mask_bit);
- ClassDB::bind_method(D_METHOD("get_layer_mask_bit", "layer"), &VisualInstance3D::get_layer_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_layer_mask_value", "layer_number", "value"), &VisualInstance3D::set_layer_mask_value);
+ ClassDB::bind_method(D_METHOD("get_layer_mask_value", "layer_number"), &VisualInstance3D::get_layer_mask_value);
ClassDB::bind_method(D_METHOD("get_transformed_aabb"), &VisualInstance3D::get_transformed_aabb);
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index 97aac149a1..aa64195c2b 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -72,8 +72,8 @@ public:
void set_layer_mask(uint32_t p_mask);
uint32_t get_layer_mask() const;
- void set_layer_mask_bit(int p_layer, bool p_enable);
- bool get_layer_mask_bit(int p_layer) const;
+ void set_layer_mask_value(int p_layer_number, bool p_enable);
+ bool get_layer_mask_value(int p_layer_number) const;
VisualInstance3D();
~VisualInstance3D();
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 5ff92c6ff6..04a533bedb 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -994,15 +994,15 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
for (int i = 0; i < 20; i++) {
- GLOBAL_DEF_BASIC(vformat("layer_names/2d_render/layer_%d", i), "");
- GLOBAL_DEF_BASIC(vformat("layer_names/3d_render/layer_%d", i), "");
+ GLOBAL_DEF_BASIC(vformat("layer_names/2d_render/layer_%d", i + 1), "");
+ GLOBAL_DEF_BASIC(vformat("layer_names/3d_render/layer_%d", i + 1), "");
}
for (int i = 0; i < 32; i++) {
- GLOBAL_DEF_BASIC(vformat("layer_names/2d_physics/layer_%d", i), "");
- GLOBAL_DEF_BASIC(vformat("layer_names/2d_navigation/layer_%d", i), "");
- GLOBAL_DEF_BASIC(vformat("layer_names/3d_physics/layer_%d", i), "");
- GLOBAL_DEF_BASIC(vformat("layer_names/3d_navigation/layer_%d", i), "");
+ GLOBAL_DEF_BASIC(vformat("layer_names/2d_physics/layer_%d", i + 1), "");
+ GLOBAL_DEF_BASIC(vformat("layer_names/2d_navigation/layer_%d", i + 1), "");
+ GLOBAL_DEF_BASIC(vformat("layer_names/3d_physics/layer_%d", i + 1), "");
+ GLOBAL_DEF_BASIC(vformat("layer_names/3d_navigation/layer_%d", i + 1), "");
}
bool default_theme_hidpi = GLOBAL_DEF("gui/theme/use_hidpi", false);
diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp
index 3c3c643367..00cee9269b 100644
--- a/scene/resources/navigation_mesh.cpp
+++ b/scene/resources/navigation_mesh.cpp
@@ -91,20 +91,22 @@ uint32_t NavigationMesh::get_collision_mask() const {
return collision_mask;
}
-void NavigationMesh::set_collision_mask_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
+void NavigationMesh::set_collision_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
- mask |= 1 << p_bit;
+ mask |= 1 << (p_layer_number - 1);
} else {
- mask &= ~(1 << p_bit);
+ mask &= ~(1 << (p_layer_number - 1));
}
set_collision_mask(mask);
}
-bool NavigationMesh::get_collision_mask_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
- return get_collision_mask() & (1 << p_bit);
+bool NavigationMesh::get_collision_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_mask() & (1 << (p_layer_number - 1));
}
void NavigationMesh::set_source_geometry_mode(SourceGeometryMode p_geometry_mode) {
@@ -403,8 +405,8 @@ void NavigationMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &NavigationMesh::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &NavigationMesh::get_collision_mask);
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &NavigationMesh::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &NavigationMesh::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &NavigationMesh::set_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &NavigationMesh::get_collision_mask_value);
ClassDB::bind_method(D_METHOD("set_source_geometry_mode", "mask"), &NavigationMesh::set_source_geometry_mode);
ClassDB::bind_method(D_METHOD("get_source_geometry_mode"), &NavigationMesh::get_source_geometry_mode);
diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h
index 99b2b6ff58..1cdf7a07ed 100644
--- a/scene/resources/navigation_mesh.h
+++ b/scene/resources/navigation_mesh.h
@@ -118,8 +118,8 @@ public:
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
+ void set_collision_mask_value(int p_layer_number, bool p_value);
+ bool get_collision_mask_value(int p_layer_number) const;
void set_source_geometry_mode(SourceGeometryMode p_geometry_mode);
SourceGeometryMode get_source_geometry_mode() const;
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index a6815da6f4..75dd7448e7 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -3081,10 +3081,84 @@ String VisualShaderNodeUniform::get_warning(Shader::Mode p_mode, VisualShader::T
List<String> keyword_list;
ShaderLanguage::get_keyword_list(&keyword_list);
if (keyword_list.find(uniform_name)) {
- return TTR("Uniform name cannot be equal to a shader keyword. Choose another name.");
+ return TTR("Shader keywords cannot be used as uniform names.\nChoose another name.");
}
if (!is_qualifier_supported(qualifier)) {
- return "This uniform type does not support that qualifier.";
+ String qualifier_str;
+ switch (qualifier) {
+ case QUAL_NONE:
+ break;
+ case QUAL_GLOBAL:
+ qualifier_str = "global";
+ break;
+ case QUAL_INSTANCE:
+ qualifier_str = "instance";
+ break;
+ }
+ return vformat(TTR("This uniform type does not support the '%s' qualifier."), qualifier_str);
+ } else if (qualifier == Qualifier::QUAL_GLOBAL) {
+ RS::GlobalVariableType gvt = RS::get_singleton()->global_variable_get_type(uniform_name);
+ if (gvt == RS::GLOBAL_VAR_TYPE_MAX) {
+ return vformat(TTR("Global uniform '%s' does not exist.\nCreate it in the Project Settings."), uniform_name);
+ }
+ bool incompatible_type = false;
+ switch (gvt) {
+ case RS::GLOBAL_VAR_TYPE_FLOAT: {
+ if (!Object::cast_to<VisualShaderNodeFloatUniform>(this)) {
+ incompatible_type = true;
+ }
+ } break;
+ case RS::GLOBAL_VAR_TYPE_INT: {
+ if (!Object::cast_to<VisualShaderNodeIntUniform>(this)) {
+ incompatible_type = true;
+ }
+ } break;
+ case RS::GLOBAL_VAR_TYPE_BOOL: {
+ if (!Object::cast_to<VisualShaderNodeBooleanUniform>(this)) {
+ incompatible_type = true;
+ }
+ } break;
+ case RS::GLOBAL_VAR_TYPE_COLOR: {
+ if (!Object::cast_to<VisualShaderNodeColorUniform>(this)) {
+ incompatible_type = true;
+ }
+ } break;
+ case RS::GLOBAL_VAR_TYPE_VEC3: {
+ if (!Object::cast_to<VisualShaderNodeVec3Uniform>(this)) {
+ incompatible_type = true;
+ }
+ } break;
+ case RS::GLOBAL_VAR_TYPE_TRANSFORM: {
+ if (!Object::cast_to<VisualShaderNodeTransformUniform>(this)) {
+ incompatible_type = true;
+ }
+ } break;
+ case RS::GLOBAL_VAR_TYPE_SAMPLER2D: {
+ if (!Object::cast_to<VisualShaderNodeTextureUniform>(this)) {
+ incompatible_type = true;
+ }
+ } break;
+ case RS::GLOBAL_VAR_TYPE_SAMPLER3D: {
+ if (!Object::cast_to<VisualShaderNodeTexture3DUniform>(this)) {
+ incompatible_type = true;
+ }
+ } break;
+ case RS::GLOBAL_VAR_TYPE_SAMPLER2DARRAY: {
+ if (!Object::cast_to<VisualShaderNodeTexture2DArrayUniform>(this)) {
+ incompatible_type = true;
+ }
+ } break;
+ case RS::GLOBAL_VAR_TYPE_SAMPLERCUBE: {
+ if (!Object::cast_to<VisualShaderNodeCubemapUniform>(this)) {
+ incompatible_type = true;
+ }
+ } break;
+ default:
+ break;
+ }
+ if (incompatible_type) {
+ return vformat(TTR("Global uniform '%s' has an incompatible type for this kind of node.\nChange it in the Project Settings."), uniform_name);
+ }
}
return String();
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 6fd6fd8f3b..afe0bdfd5c 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -4575,7 +4575,10 @@ bool VisualShaderNodeTransformUniform::is_use_prop_slots() const {
}
bool VisualShaderNodeTransformUniform::is_qualifier_supported(Qualifier p_qual) const {
- return true; // all qualifiers are supported
+ if (p_qual == Qualifier::QUAL_INSTANCE) {
+ return false;
+ }
+ return true;
}
bool VisualShaderNodeTransformUniform::is_convertible_to_constant() const {
diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp
index 3efa16fe0a..c2dedde0be 100644
--- a/servers/physics_server_2d.cpp
+++ b/servers/physics_server_2d.cpp
@@ -234,8 +234,8 @@ void PhysicsShapeQueryParameters2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_margin", "margin"), &PhysicsShapeQueryParameters2D::set_margin);
ClassDB::bind_method(D_METHOD("get_margin"), &PhysicsShapeQueryParameters2D::get_margin);
- ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &PhysicsShapeQueryParameters2D::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_layer"), &PhysicsShapeQueryParameters2D::get_collision_mask);
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &PhysicsShapeQueryParameters2D::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &PhysicsShapeQueryParameters2D::get_collision_mask);
ClassDB::bind_method(D_METHOD("set_exclude", "exclude"), &PhysicsShapeQueryParameters2D::set_exclude);
ClassDB::bind_method(D_METHOD("get_exclude"), &PhysicsShapeQueryParameters2D::get_exclude);
@@ -246,7 +246,7 @@ void PhysicsShapeQueryParameters2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &PhysicsShapeQueryParameters2D::set_collide_with_areas);
ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &PhysicsShapeQueryParameters2D::is_collide_with_areas_enabled);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_NONE, itos(Variant::RID) + ":"), "set_exclude", "get_exclude");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_margin", "get_margin");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion"), "set_motion", "get_motion");
@@ -411,9 +411,9 @@ PhysicsDirectSpaceState2D::PhysicsDirectSpaceState2D() {
}
void PhysicsDirectSpaceState2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("intersect_point", "point", "max_results", "exclude", "collision_layer", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_point, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("intersect_point_on_canvas", "point", "canvas_instance_id", "max_results", "exclude", "collision_layer", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_point_on_canvas, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("intersect_ray", "from", "to", "exclude", "collision_layer", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_ray, DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("intersect_point", "point", "max_results", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_point, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("intersect_point_on_canvas", "point", "canvas_instance_id", "max_results", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_point_on_canvas, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("intersect_ray", "from", "to", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_ray, DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
ClassDB::bind_method(D_METHOD("intersect_shape", "shape", "max_results"), &PhysicsDirectSpaceState2D::_intersect_shape, DEFVAL(32));
ClassDB::bind_method(D_METHOD("cast_motion", "shape"), &PhysicsDirectSpaceState2D::_cast_motion);
ClassDB::bind_method(D_METHOD("collide_shape", "shape", "max_results"), &PhysicsDirectSpaceState2D::_collide_shape, DEFVAL(32));
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
index 4feaf08808..475f6c475d 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
@@ -9129,7 +9129,7 @@ RendererStorageRD::RendererStorageRD() {
} break;
case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: {
sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
- sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
} else {
@@ -9148,7 +9148,7 @@ RendererStorageRD::RendererStorageRD() {
} break;
case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC: {
sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
- sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
} else {