Compare commits

...

133 Commits

Author SHA1 Message Date
Andreia Gaita
bdde9ec5a4
Merge 84db024f6f into 9e6098432a 2024-11-21 10:20:54 +00:00
Andreia Gaita
84db024f6f Use scons to calculate all the sources needed for vsproj generation.
Scons knows every file - sources, headers, etc - that the binary depends on,
and trying to figure that out manually is just too prone to error.
2024-11-21 11:11:35 +01:00
Rémi Verschelde
9e6098432a
Merge pull request #99469 from akien-mga/revert-97370
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
🔗 GHA / 🪲 Godot CPP (push) Has been cancelled
Revert "ResourceLoader: Report error if resource type unrecognized"
2024-11-20 17:03:26 +01:00
Rémi Verschelde
cfef79415b
Merge pull request #99449 from Sauermann/fix-revert-device-id-clash
Revert "Fix `InputEvent` device id clash" and add a compatibility function
2024-11-20 17:03:23 +01:00
Rémi Verschelde
7c1f42506a
Merge pull request #99448 from clayjohn/RD-sky-flip
Unify y-flip behavior for sky in RD backends
2024-11-20 17:03:19 +01:00
Rémi Verschelde
70963cf515
Merge pull request #99413 from Alex2782/fix_transfer_bit
Fix: Error output is not require, `VK_QUEUE_TRANSFER_BIT` is optional.
2024-11-20 17:03:16 +01:00
Rémi Verschelde
b11bb1aa97
Merge pull request #99319 from TokageItLab/fix-fps-inspector
Fix key is deselected by changing key time in KeyEdit in FPS mode
2024-11-20 17:03:12 +01:00
Rémi Verschelde
285954659d
Merge pull request #96721 from aXu-AP/tooltip-distance
Fix tooltip appearing in old place, on movement
2024-11-20 17:03:08 +01:00
Rémi Verschelde
23fc8e22a3
Merge pull request #95303 from EIREXE/inverted_composer
Fix `Projection::invert` for orthographic projection
2024-11-20 17:03:03 +01:00
Rémi Verschelde
219b14b905
Revert "ResourceLoader: Report error if resource type unrecognized"
This reverts commit fe21913ee8.
2024-11-20 16:50:30 +01:00
Markus Sauermann
bc5e2f9b96 Revert "Fix InputEvent device id clash" and add a compatibility function
This reverts commit 916d480686.

Revert "Fix InputEvent crash when opening project"
This reverts commit abb9c0f171.

Introduce a compatibility function for projects affected by the
device id clash reversal

Since the reverted PR introduced changes in the project.godot
file, it seems prudent to introduce a compatibility function for
such affected projects.
2024-11-20 09:18:55 +01:00
clayjohn
02efdb28dc Unify y-flip behavior for sky in RD backends 2024-11-19 16:59:04 -08:00
Thaddeus Crews
a0cd8f187a
Merge pull request #99391 from Giganzo/export-debug
Some checks are pending
🔗 GHA / 📊 Static checks (push) Waiting to run
🔗 GHA / 🤖 Android (push) Blocked by required conditions
🔗 GHA / 🍏 iOS (push) Blocked by required conditions
🔗 GHA / 🐧 Linux (push) Blocked by required conditions
🔗 GHA / 🍎 macOS (push) Blocked by required conditions
🔗 GHA / 🏁 Windows (push) Blocked by required conditions
🔗 GHA / 🌐 Web (push) Blocked by required conditions
🔗 GHA / 🪲 Godot CPP (push) Blocked by required conditions
Add persistent states for export with debug, as patch on editor restarts
2024-11-19 15:20:28 -06:00
Thaddeus Crews
650e96b768
Merge pull request #99353 from syntaxerror247/some_uid_issues
Fix Android boot splash and gradle build issue
2024-11-19 15:20:23 -06:00
Thaddeus Crews
3a4feeda89
Merge pull request #99289 from shahriarlabib000/hideExp
Hide unused `exp_edit` from SpinBox's inspector
2024-11-19 15:20:21 -06:00
Thaddeus Crews
32b4f40cc8
Merge pull request #99131 from MarcusAahl/my-testing-branch
Add basic tests for Fontfile
2024-11-19 15:20:17 -06:00
Thaddeus Crews
d6ec81af77
Merge pull request #99354 from Nodragem/fix-hidden-gizmo-at-startup
GridMap: Fix hidden gizmo at start-up
2024-11-19 15:20:15 -06:00
Thaddeus Crews
918faec239
Merge pull request #98297 from Calinou/editor-tweak-lightmapgi-no-meshes-to-bake-error-dialog
Improve "No meshes to bake" LightmapGI error dialog in the editor
2024-11-19 15:20:12 -06:00
Thaddeus Crews
1680edb2cd
Merge pull request #99231 from fire/sort-blendshapes-by-id
Sort blend shapes in the inspector by ID instead of alphabetically
2024-11-19 15:20:11 -06:00
Thaddeus Crews
e4dbba94d9
Merge pull request #99324 from TokageItLab/fix-fpe-spinner
Fix spinner in AnimationTrackEdit in FPS mode
2024-11-19 15:20:10 -06:00
Thaddeus Crews
97b3dd4cfe
Merge pull request #99403 from dsnopek/gdextension-fix-varargs-with-no-args
GDExtension: Fix method binds not saying if they are varargs
2024-11-19 15:20:09 -06:00
Thaddeus Crews
3e77646645
Merge pull request #99419 from ntlblpm/patch-1
Fix typo in FileAccess docs
2024-11-19 15:20:08 -06:00
Thaddeus Crews
ec7fd4f6f1
Merge pull request #97894 from paulloz/dotnet/export-tool-button
Implement `[ExportToolButton]`
2024-11-19 15:20:07 -06:00
Thaddeus Crews
63a408f320
Merge pull request #99363 from passivestar/fix-marker-drawing
Fix issues with animation markers drawing
2024-11-19 15:20:04 -06:00
Thaddeus Crews
480f616bbe
Merge pull request #99426 from DarioSamo/rd-graph-partial-coverage-fix
Improve dependency detection in render graph for draw lists with partial coverage.
2024-11-19 15:20:03 -06:00
Thaddeus Crews
dd0c24bcd3
Merge pull request #99137 from KoBeWi/uideal_scenario
Handle scene UIDs in MultiplayerSpawner
2024-11-19 15:20:00 -06:00
passivestar
c4a78d09e5 Fix issues with animation markers drawing 2024-11-19 19:45:36 +04:00
Dario
288717d7eb Improve dependency detection in render graph for draw lists with partial coverage. 2024-11-19 11:23:11 -03:00
marcus åhl
c636c86f65 Basic Fontfile tests 2024-11-19 11:56:26 +01:00
ntlblpm
086d1ea2ac
Update FileAccess.xml 2024-11-19 03:45:03 -05:00
Alexander Hartmann
8e170248b3 Fix: Error output is not require, VK_QUEUE_TRANSFER_BIT is optional. 2024-11-19 03:01:07 +01:00
Paul Joannon
4f52c2bb1f
Implement [ExportToolButton] 2024-11-18 20:19:47 +01:00
David Snopek
2599df3b8a GDExtension: Fix method binds not saying if they are varargs 2024-11-18 13:19:22 -06:00
Anish Mishra
728927425f Fix Android boot splash and gradle build issue 2024-11-18 21:12:22 +05:30
Thaddeus Crews
fd4c29a189
Merge pull request #98683 from clayjohn/wireframe
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
🔗 GHA / 🪲 Godot CPP (push) Has been cancelled
Ensure shadow material and mesh are not used with wireframe mode
2024-11-18 09:23:54 -06:00
Thaddeus Crews
cf541f0997
Merge pull request #97656 from kitbdev/doc-textedit-improve
Improve TextEdit and CodeEdit documentation
2024-11-18 09:23:53 -06:00
Thaddeus Crews
91bd80de51
Merge pull request #98160 from Rindbee/change-the-parent-node-of-EditorHelpBitTooltip
Add `EditorHelpBitTooltip` as a child of `p_target` to avoid jitter
2024-11-18 09:23:52 -06:00
Thaddeus Crews
3ded11d0bc
Merge pull request #85359 from miv391/faster-exit-from-cull_canvas_item
Faster exit from `_cull_canvas_item` if alpha is zero
2024-11-18 09:23:51 -06:00
Thaddeus Crews
449d90b64e
Merge pull request #99178 from mrsaturnsan/windows_sleep_precision
Make `delay_usec` more precise on Windows to fix framepacing
2024-11-18 09:23:50 -06:00
Thaddeus Crews
8d530bc95a
Merge pull request #99176 from tracefree/obstacle_transform
Fix obstacle avoidance and 3D editor ignoring transform
2024-11-18 09:23:48 -06:00
Thaddeus Crews
7ac9d7fec9
Merge pull request #99304 from emanvidmaker/Update-gamecontrollerdb.txt-2024
Sync controller mappings DB with SDL2 community repo [Nov 2024]
2024-11-18 09:23:47 -06:00
Thaddeus Crews
0a50cef751
Merge pull request #98788 from Bonkahe/master
Add `multimesh_get_buffer_rd_rid` method to `RenderingServer`.
2024-11-18 09:23:46 -06:00
Thaddeus Crews
7a5b1ed736
Merge pull request #99299 from Bonkahe/ResolveParticlesSetViewAxisThreadIssue
Move `_scene_particles_set_view_axis` to new static function to allow call to be done on render thread, preventing multi threaded error on compute shader execution.
2024-11-18 09:23:45 -06:00
Thaddeus Crews
0dda6a974c
Merge pull request #99286 from KoBeWi/uid_in_a_path_factory
Support uid:// in more places
2024-11-18 09:23:44 -06:00
Thaddeus Crews
1dcb686325
Merge pull request #99026 from Faless/net/split_ip
[Net] Split Unix/Windows IP implementation
2024-11-18 09:23:43 -06:00
Thaddeus Crews
8811b39968
Merge pull request #97992 from Nikitf777/android-sdk-path
Add default value of editor property `export/android/android_sdk_path` for Windows, Linux, and macOS
2024-11-18 09:23:42 -06:00
Thaddeus Crews
895d433f50
Merge pull request #99389 from KoBeWi/globalization_ensues
Fix global paths in EditorPropertyPath
2024-11-18 09:23:41 -06:00
Thaddeus Crews
cc48a22b29
Merge pull request #99388 from bruvzg/disable_nahimic
Disable Nahimic code injection.
2024-11-18 09:23:40 -06:00
Thaddeus Crews
a46abc4f15
Merge pull request #99386 from dustdfg/scons_ninja_file_regression
SCons: Pass `ninja_file` variable in tool instead of default name
2024-11-18 09:23:39 -06:00
Thaddeus Crews
8e324c4589
Merge pull request #86195 from GreenCrowDev/curve3d_close
Add `closed` property to `Curve3D`
2024-11-18 09:23:38 -06:00
Thaddeus Crews
80e73b0dca
Merge pull request #98483 from timothyqiu/pack-dir-exists
`DirAccessPack`: Fix `file_exists` and `dir_exists` in exported projects
2024-11-18 09:23:37 -06:00
Thaddeus Crews
1c1e833a43
Merge pull request #99376 from clayjohn/basisu-defer-init
Defer initializing BasisU encoder until it is needed
2024-11-18 09:23:35 -06:00
Thaddeus Crews
778f26e69e
Merge pull request #99372 from tdaven/fix-inconsistent-wayland-clipboard
Wayland: Only set selection when there is not already a source.
2024-11-18 09:23:34 -06:00
Thaddeus Crews
2dbf195af5
Merge pull request #98983 from nikitalita/patch-2
Prevent stack-use-after-scope in rendering_device_driver_metal.mm
2024-11-18 09:23:33 -06:00
Thaddeus Crews
fa29dde142
Merge pull request #99367 from BlueCube3310/mobile-probe-capture
Fix updating lightmap captures on Mobile
2024-11-18 09:23:32 -06:00
Thaddeus Crews
3d6e712177
Merge pull request #93714 from Calinou/normal-map-invert-y-preserve-alpha-channel
Preserve existing alpha channel when using Normal Map Invert Y import option
2024-11-18 09:23:31 -06:00
Thaddeus Crews
1889d2a264
Merge pull request #99206 from a-johnston/fix_double_diagnostic
Remove duplicate read/write-only property warning from ScriptPropertiesGenerator
2024-11-18 09:23:30 -06:00
Thaddeus Crews
6330db475f
Merge pull request #87558 from clayjohn/GLES3-canvas-spec
Reduce shader permutations in the compatibility backend
2024-11-18 09:23:29 -06:00
Thaddeus Crews
d72112ba0a
Merge pull request #98816 from arkology/to-infinity-and-beyond
Improve `TextureProgressBar.set_radial_initial_angle()` by removing loops
2024-11-18 09:23:28 -06:00
Thaddeus Crews
973f16aef1
Merge pull request #99328 from AThousandShips/use_find_char
Use `(r)find_char` instead of `(r)find` for single characters
2024-11-18 09:23:27 -06:00
Álex Román
02b2efc668 Fix Projection::invert on orthogonal projections and others.
Fixes #68878, specially when using orthographic projection.

Also adds some tests.
2024-11-18 16:13:04 +01:00
kobewi
7fa39c0dbe Fix global paths in EditorPropertyPath 2024-11-18 12:25:48 +01:00
Yevhen Babiichuk (DustDFG)
1250681a4f SCons: pass ninja_file variable in tool instead of default name
Noticed that when I run with `ninja_file` it wasn't created even
though in terminal I saw that the file will be generated

Signed-off-by: Yevhen Babiichuk (DustDFG) <dfgdust@gmail.com>
2024-11-18 13:25:47 +02:00
bruvzg
8bb3e5360e Disable Nahimic code injection. 2024-11-18 13:00:55 +02:00
Trevor Davenport
0d9a705e25 Wayland: Only set selection when there is not already a source.
Co-authored-by: Riteo Siuga <riteo@posteo.net>
2024-11-17 16:00:24 -07:00
clayjohn
985dc61386 Defer initializing BasisU encoder until it is needed.
This saves a lot of time on startup
2024-11-17 14:03:20 -08:00
Giganzo
8a8fd299f8 Add persistent states for export with debug, as patch on editor restarts 2024-11-17 21:15:48 +01:00
Nikita
c6f4228706 Add default value of editor propetry "export/android/android_sdk_path" for Windows, Linux, and macOS 2024-11-17 22:25:39 +03:00
BlueCube3310
bb3d0045b0 Fix updating lightmap captures on Mobile 2024-11-17 19:29:21 +01:00
Nodragem
f5871c18bf fix hidden gizmo at start-up 2024-11-17 13:03:19 +00:00
A Thousand Ships
68f638cf02
Use (r)find_char instead of (r)find for single characters 2024-11-17 10:02:18 +01:00
clayjohn
90b4b48b5a Ensure shadow material and mesh are not used with wireframe mode
And in the Compatibility renderer actually use the wireframe render mode
2024-11-16 22:25:00 -08:00
kobewi
3b6705a641 Support uid:// in more places 2024-11-16 21:43:18 +01:00
David House
7e3d480087 Created static method and moved _particles_set_view_axis over to it to allow calling on render thread. 2024-11-16 13:26:26 -06:00
Silc Lizard (Tokage) Renew
e283fdfb59 Fix spinner in AnimationTrackEdit in FPS mode 2024-11-17 01:54:06 +09:00
mrsaturnsan
df3367f334 Make delay_usec more precise
Comment fix
2024-11-16 09:15:46 -06:00
Silc Lizard (Tokage) Renew
602c5edbc4 Fix key is deselected by chaning key time in KeyEdit in FPS mode 2024-11-16 23:48:10 +09:00
matricola787
790efbb783 Implement closed path for Curve3d 2024-11-16 12:59:08 +01:00
Rémi Verschelde
5efd124ca1
Merge pull request #99300 from akien-mga/revert-pr98895
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
🔗 GHA / 🪲 Godot CPP (push) Has been cancelled
Revert "Warn on unknown command line arguments"
2024-11-16 12:35:45 +01:00
Mika Viskari
39423d99fa Faster exit from _cull_canvas_item if alpha is zero 2024-11-16 13:27:45 +02:00
Rie
31a3b418f7 Fix obstacle avoidance and 3D editor ignoring transform 2024-11-16 11:30:48 +01:00
clayjohn
c810ea4c1b Reduce shader permutations in the compatibility backend 2024-11-15 23:13:33 -08:00
Emanuel Acosta Gonzalez (emanvidmaker)
f2d58f5d76
Sync controller mappings DB with SDL2 community repo [Nov 2024]
Synced with cfc2bffe0a
2024-11-15 21:56:25 -04:00
Rémi Verschelde
4d4407ce5a
Revert "Warn on unknown command line arguments"
This reverts commit 8379cc85aa.

This caused some regressions, as this approach doesn't properly handle all
possible arguments.
2024-11-15 21:48:51 +01:00
Rémi Verschelde
6c05ec3d67
Merge pull request #99291 from akien-mga/scons-cache-fixup
Some checks are pending
🔗 GHA / 📊 Static checks (push) Waiting to run
🔗 GHA / 🤖 Android (push) Blocked by required conditions
🔗 GHA / 🍏 iOS (push) Blocked by required conditions
🔗 GHA / 🐧 Linux (push) Blocked by required conditions
🔗 GHA / 🍎 macOS (push) Blocked by required conditions
🔗 GHA / 🏁 Windows (push) Blocked by required conditions
🔗 GHA / 🌐 Web (push) Blocked by required conditions
🔗 GHA / 🪲 Godot CPP (push) Blocked by required conditions
SCons: Fix up build after cache logic changes
2024-11-15 18:26:05 +01:00
Rémi Verschelde
c9acbf5a79
SCons: Fix up build after cache logic changes 2024-11-15 18:18:12 +01:00
shahriarlabib000
177bba12b0 hide unused exp_edit from SpinBox inspector 2024-11-15 22:57:43 +06:00
Thaddeus Crews
68fe5817aa
Merge pull request #99261 from stuartcarnie/issue/99029
Metal: Ensure position invariance is captured from SPIRV-Cross
2024-11-15 10:42:48 -06:00
Thaddeus Crews
e4608dd6c2
Merge pull request #98138 from CrayolaEater/better-explanation-mp-sync
Better explanation for replication interval and delta interval (MultiplayerSynchronizer)
2024-11-15 10:42:47 -06:00
Thaddeus Crews
773c8e9a93
Merge pull request #99253 from KoBeWi/tldr
Simplify some UID conversions
2024-11-15 10:42:46 -06:00
Thaddeus Crews
e9ce3932b3
Merge pull request #98099 from dalexeev/pot-gen-add-comment-support
POT Generator: Add support for `TRANSLATORS:` and `NO_TRANSLATE` comments
2024-11-15 10:42:45 -06:00
Thaddeus Crews
a52e28436e
Merge pull request #99148 from TopherBriggs/keyframe_crash_fix
Fix crash when inserting keyframes with empty properties array
2024-11-15 10:42:43 -06:00
Thaddeus Crews
6c9337de36
Merge pull request #99217 from dustdfg/refactor_compiler_min_detection
Buildsystem: Refactor compiler detection code
2024-11-15 10:42:42 -06:00
Thaddeus Crews
d9b458d4b0
Merge pull request #99280 from bruvzg/win32_build_fix
Fix 32-bit Windows build.
2024-11-15 10:42:41 -06:00
Thaddeus Crews
1d5c589e71
Merge pull request #99212 from CW-Jesse/patch-1
Describe edge cases for `DisplayServer.get_screen_from_rect()`
2024-11-15 10:42:40 -06:00
Thaddeus Crews
03863f117f
Merge pull request #99276 from kiroxas/fixBrokenNavigationObstacle2D
Fix broken Navigation Obstacle regression
2024-11-15 10:42:39 -06:00
Thaddeus Crews
46d83fd149
Merge pull request #99277 from HolonProduction/why-remove-this-in-the-first-place
Add back `AnimationPlayer.get_argument_options`
2024-11-15 10:42:38 -06:00
Thaddeus Crews
f5431fe3f0
Merge pull request #98220 from bruvzg/dict_ed_fix
[Editor] Fix dictionary editor removing wrong keys and not updating key labels.
2024-11-15 10:42:37 -06:00
Thaddeus Crews
d4a62ace48
Merge pull request #98154 from Repiteo/scons/cache-options
SCons: Improve cache purging logic
2024-11-15 10:42:36 -06:00
Thaddeus Crews
313fe08e19
Merge pull request #99177 from Chaosus/vs_swap_connections
Add swap connection option to visual shader graph
2024-11-15 10:42:35 -06:00
Thaddeus Crews
89f97021de
Merge pull request #99272 from Chaosus/vs_bug
Fix error emitting when reset a visual shader preview parameter
2024-11-15 10:42:34 -06:00
Thaddeus Crews
af3fb0a2b8
Merge pull request #86085 from TheSofox/text-undo-cleanup
Cleanup in undo in `TextEdit` and `LineEdit`
2024-11-15 10:42:33 -06:00
Thaddeus Crews
934549e2a0
Merge pull request #99266 from bruvzg/fd_proc_filters
Use processed filter list for native dialogs.
2024-11-15 10:42:30 -06:00
Thaddeus Crews
0e4a4e3c4d
SCons: Improve cache purging logic
• Implement caching via SCons arguments, rather than environment variables
2024-11-15 08:29:58 -06:00
Pāvels Nadtočajevs
287b7543a0 Fix 32-bit Windows build. 2024-11-15 15:49:08 +02:00
Kiro
3a946aaa73 fixed navigation obstacle carving broken during 07b7f76 2024-11-15 13:47:47 +01:00
HolonProduction
a389eb4608 Add back AnimationPlayer.get_argument_options 2024-11-15 13:06:59 +01:00
Yevhen Babiichuk (DustDFG)
d55ed0cb15 Buildsystem: Refactor compiler detection code
* Delete old check for gcc 8 as we support 9 or higher
* Flatten branches for clang and apple clang
* Renamed is_vanilla_clang to is_apple_clang to be more clear

Signed-off-by: Yevhen Babiichuk (DustDFG) <dfgdust@gmail.com>
2024-11-15 12:59:46 +02:00
Pāvels Nadtočajevs
f5fad7592f Use processed filter list for native dialogs. 2024-11-15 12:08:33 +02:00
Chaosus
ce833a3885 Add swap connection option to visual shader graph 2024-11-15 13:02:09 +03:00
Christopher Briggs
d1ba152197
Fix crash when inserting keyframes with empty properties array 2024-11-15 11:01:34 +01:00
Chaosus
5a856a6896 Fix error emitting when reset a visual shader preview parameter 2024-11-15 12:39:07 +03:00
Stuart Carnie
9c2ca820f2
Metal: Ensure position invariance is captured from SPIRV-Cross
Closes #99029
2024-11-15 14:06:32 +11:00
Bogdan Inculet
f72b841390 Better explanation for the replication interval and delta interval in the MultiplayerSynchronizer node 2024-11-15 02:46:10 +02:00
Jesse
121097db0a
[DisplayServer] [docs] Improve readability of get_screen_from_rect()
Co-authored-by: Micky <66727710+Mickeon@users.noreply.github.com>
2024-11-14 16:28:51 -08:00
kobewi
88b3090745 Handle scene UIDs in MultiplayerSpawner 2024-11-14 23:41:58 +01:00
kobewi
5be53c36c0 Simplify some UID conversions 2024-11-14 23:22:59 +01:00
kit
d467b3acb5 Improve TextEdit and CodeEdit documentation 2024-11-14 17:09:00 -05:00
David House
6e9d31f602 Implemented multimesh_get_buffer_rd_rid function into RenderingServer.
Fixed style error.

Updated dummy mesh_storage to move from cpp to h the return of a blank Rid on _multimesh_get_buffer_rd_rid.
2024-11-14 15:52:08 -06:00
arkology
d692b7bdde Improve set_radial_initial_angle by removing loops
Replace two while loops with fposmodp.
Document radial_initial_angle wrapping.
Add testcases for set_radial_initial_angle()
2024-11-14 20:20:20 +03:00
K. S. Ernest (iFire) Lee
b0e04c1e7a Sort blend shapes in the inspector by ID instead of alphabetically
Blend shapes (morph targets, shape keys) should be sorted by the physical order of the blend shapes, and that index should be converted to a name string.
2024-11-14 05:54:32 -08:00
Jesse
4ba533d0b5
[DisplayServer] [docs] Describe edge cases for get_screen_from_rect()
Describes output when multiple screens intersect with rectangle or rectangle has no area.
2024-11-13 22:02:42 -08:00
Adam Johnston
186f35fc9b remove duplicate read/write only property warning from ScriptPropertiesGenerator 2024-11-13 14:23:53 -08:00
Fabio Alessandrelli
168a2a1466 [Net] Split Unix/Windows IP implementation 2024-11-12 17:33:47 +01:00
nikitalita
78895c709c
Prevent stack-use-after-scope in rendering_device_driver_metal.mm 2024-11-09 00:07:33 -06:00
aXu-AP
be349fa6d3 Fix tooltip appearing in old place, on movement
Fixes tooltip appearing in editor on old position of mouse.
Fixes tooltip appearing even if mouse is in steady motion (now accepts max 5 px movement).
2024-11-05 16:51:23 +02:00
Hugo Locurcio
78fc90e81e
Improve "No meshes to bake" LightmapGI error dialog in the editor
The error dialog now gives advice on the steps to follow to enable
lightmapping support on imported scenes and primitive meshes.
2024-11-01 02:21:33 +01:00
Haoyu Qiu
1b4f6f6bfa DirAccessPack: Fix file_exists and dir_exists in exported projects 2024-10-24 14:26:36 +08:00
bruvzg
cbc8468e3e
[Editor] Fix dictionary editor removing wrong keys and not updating key labels. 2024-10-16 10:35:39 +03:00
风青山
bc30bb4fc0
Add EditorHelpBitTooltip as a child of p_target to avoid jitter
Previously the tooltip popup was added as a child of the `p_target`'s
viewport (usually the root window), which caused the root window to
recalculate the window size, that could cause jitter issues on i3wm
if the actual width of the root window was less than `1024`.
2024-10-14 11:17:08 +08:00
Danil Alexeev
cab80cb97d
POT Generator: Add support for TRANSLATORS: and NO_TRANSLATE comments 2024-10-13 11:40:11 +03:00
Hugo Locurcio
49b4c20f3a
Preserve existing alpha channel when using Normal Map Invert Y import option
While normal maps with RGTC compression cannot contain an alpha channel,
it is possible for Godot to read non-RGTC normal maps that can contain
an alpha channel that custom shaders can read.

The visual output for opaque images (including RGTC normal maps)
is unaffected by this change.
2024-06-28 21:48:36 +02:00
Sofox
a1a5c87f9e Cleanup in undo in TextEdit and LineEdit 2023-12-12 17:51:53 +00:00
216 changed files with 2979 additions and 1420 deletions

View File

@ -18,12 +18,12 @@ inputs:
required: false
scons-cache:
description: The SCons cache path.
default: ${{ github.workspace }}/.scons-cache/
default: ${{ github.workspace }}/.scons_cache/
scons-cache-limit:
description: The SCons cache size limit.
# actions/cache has 10 GiB limit, and GitHub runners have a 14 GiB disk.
# Limit to 7 GiB to avoid having the extracted cache fill the disk.
default: 7168
default: 7
runs:
using: composite
@ -32,10 +32,8 @@ runs:
shell: sh
env:
SCONSFLAGS: ${{ inputs.sconsflags }}
SCONS_CACHE: ${{ inputs.scons-cache }}
SCONS_CACHE_LIMIT: ${{ inputs.scons-cache-limit }}
run: |
echo "Building with flags:" platform=${{ inputs.platform }} target=${{ inputs.target }} tests=${{ inputs.tests }} ${{ env.SCONSFLAGS }}
echo "Building with flags:" platform=${{ inputs.platform }} target=${{ inputs.target }} tests=${{ inputs.tests }} ${{ env.SCONSFLAGS }} "cache_path=${{ inputs.scons-cache }}" cache_limit=${{ inputs.scons-cache-limit }}
if [ "${{ inputs.target }}" != "editor" ]; then
# Ensure we don't include editor code in export template builds.
@ -49,5 +47,5 @@ runs:
export BUILD_NAME="gh"
fi
scons platform=${{ inputs.platform }} target=${{ inputs.target }} tests=${{ inputs.tests }} ${{ env.SCONSFLAGS }}
scons platform=${{ inputs.platform }} target=${{ inputs.target }} tests=${{ inputs.tests }} ${{ env.SCONSFLAGS }} "cache_path=${{ inputs.scons-cache }}" cache_limit=${{ inputs.scons-cache-limit }}
ls -l bin/

View File

@ -6,7 +6,7 @@ inputs:
default: ${{ github.job }}
scons-cache:
description: The SCons cache path.
default: ${{ github.workspace }}/.scons-cache/
default: ${{ github.workspace }}/.scons_cache/
runs:
using: composite
@ -29,7 +29,6 @@ runs:
# 4. A partial match for the same base branch only (not ideal, matches any PR with the same base branch).
restore-keys: |
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }}
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-refs/heads/${{ env.GODOT_BASE_BRANCH }}
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}

View File

@ -6,7 +6,7 @@ inputs:
default: ${{ github.job }}
scons-cache:
description: The SCons cache path.
default: ${{ github.workspace }}/.scons-cache/
default: ${{ github.workspace }}/.scons_cache/
runs:
using: composite

View File

@ -52,9 +52,6 @@ jobs:
# continue-on-error: true
- name: Build godot-cpp test extension
env: # Keep synced with godot-build.
SCONS_CACHE: ${{ github.workspace }}/.scons-cache/
SCONS_CACHE_LIMIT: 7168
run: scons --directory=./godot-cpp/test target=template_debug dev_build=yes verbose=yes
# - name: Save Godot build cache

10
.gitignore vendored
View File

@ -36,8 +36,8 @@ compile_commands.json
platform/windows/godot_res.res
# Ninja build files
build.ninja
.ninja
*.ninja
.ninja/
run_ninja_env.bat
# Generated by Godot binary
@ -77,6 +77,9 @@ venv
__pycache__/
*.pyc
# Python modules
.*_cache/
# Documentation
doc/_build/
@ -164,9 +167,6 @@ gmon.out
# Kdevelop
*.kdev4
# Mypy
.mypy_cache
# Qt Creator
*.config
*.creator

View File

@ -271,6 +271,8 @@ opts.Add(BoolVariable("scu_build", "Use single compilation unit build", False))
opts.Add("scu_limit", "Max includes per SCU file when using scu_build (determines RAM use)", "0")
opts.Add(BoolVariable("engine_update_check", "Enable engine update checks in the Project Manager", True))
opts.Add(BoolVariable("steamapi", "Enable minimal SteamAPI integration for usage time tracking (editor only)", False))
opts.Add("cache_path", "Path to a directory where SCons cache files will be stored. No value disables the cache.", "")
opts.Add("cache_limit", "Max size (in GiB) for the SCons cache. 0 means no limit.", "0")
# Thirdparty libraries
opts.Add(BoolVariable("builtin_brotli", "Use the built-in Brotli library", True))
@ -321,6 +323,9 @@ opts.Add("rcflags", "Custom flags for Windows resource compiler")
# in following code (especially platform and custom_modules).
opts.Update(env)
# Setup caching logic early to catch everything.
methods.prepare_cache(env)
# Copy custom environment variables if set.
if env["import_env_vars"]:
for env_var in str(env["import_env_vars"]).split(","):
@ -354,7 +359,9 @@ if env["platform"] == "":
if env["platform"] in compatibility_platform_aliases:
alias = env["platform"]
platform = compatibility_platform_aliases[alias]
print_warning(f'Platform "{alias}" has been renamed to "{platform}" in Godot 4. Building for platform "{platform}".')
print_warning(
f'Platform "{alias}" has been renamed to "{platform}" in Godot 4. Building for platform "{platform}".'
)
env["platform"] = platform
# Alias for convenience.
@ -656,40 +663,32 @@ elif methods.using_gcc(env):
"to switch to posix threads."
)
Exit(255)
if env["debug_paths_relative"] and cc_version_major < 8:
print_warning("GCC < 8 doesn't support -ffile-prefix-map, disabling `debug_paths_relative` option.")
env["debug_paths_relative"] = False
elif methods.using_clang(env):
# Apple LLVM versions differ from upstream LLVM version \o/, compare
# in https://en.wikipedia.org/wiki/Xcode#Toolchain_versions
if env["platform"] == "macos" or env["platform"] == "ios":
vanilla = methods.is_vanilla_clang(env)
if vanilla and cc_version_major < 6:
print_error(
"Detected Clang version older than 6, which does not fully support "
"C++17. Supported versions are Clang 6 and later."
)
Exit(255)
elif not vanilla and cc_version_major < 10:
if methods.is_apple_clang(env):
if cc_version_major < 10:
print_error(
"Detected Apple Clang version older than 10, which does not fully "
"support C++17. Supported versions are Apple Clang 10 and later."
)
Exit(255)
if env["debug_paths_relative"] and not vanilla and cc_version_major < 12:
elif env["debug_paths_relative"] and cc_version_major < 12:
print_warning(
"Apple Clang < 12 doesn't support -ffile-prefix-map, disabling `debug_paths_relative` option."
)
env["debug_paths_relative"] = False
elif cc_version_major < 6:
else:
if cc_version_major < 6:
print_error(
"Detected Clang version older than 6, which does not fully support "
"C++17. Supported versions are Clang 6 and later."
)
Exit(255)
if env["debug_paths_relative"] and cc_version_major < 10:
elif env["debug_paths_relative"] and cc_version_major < 10:
print_warning("Clang < 10 doesn't support -ffile-prefix-map, disabling `debug_paths_relative` option.")
env["debug_paths_relative"] = False
elif env.msvc:
# Ensure latest minor builds of Visual Studio 2017/2019.
# https://github.com/godotengine/godot/pull/94995#issuecomment-2336464574
@ -753,7 +752,7 @@ else:
project_path = Dir("#").abspath
env.Append(CCFLAGS=[f"-ffile-prefix-map={project_path}=."])
else:
if methods.using_clang(env) and not methods.is_vanilla_clang(env):
if methods.is_apple_clang(env):
# Apple Clang, its linker doesn't like -s.
env.Append(LINKFLAGS=["-Wl,-S", "-Wl,-x", "-Wl,-dead_strip"])
else:
@ -1039,11 +1038,6 @@ GLSL_BUILDERS = {
}
env.Append(BUILDERS=GLSL_BUILDERS)
scons_cache_path = os.environ.get("SCONS_CACHE")
if scons_cache_path is not None:
CacheDir(scons_cache_path)
print("Scons cache enabled... (path: '" + scons_cache_path + "')")
if env["compiledb"]:
env.Tool("compilation_db")
env.Alias("compiledb", env.CompilationDatabase())
@ -1056,7 +1050,7 @@ if env["ninja"]:
SetOption("experimental", "ninja")
env["NINJA_FILE_NAME"] = env["ninja_file"]
env["NINJA_DISABLE_AUTO_RUN"] = not env["ninja_auto_run"]
env.Tool("ninja", "build.ninja")
env.Tool("ninja", env["ninja_file"])
# Threads
if env["threads"]:
@ -1118,7 +1112,7 @@ atexit.register(print_elapsed_time)
def purge_flaky_files():
paths_to_keep = ["build.ninja"]
paths_to_keep = [env["ninja_file"]]
for build_failure in GetBuildFailures():
path = build_failure.node.path
if os.path.isfile(path) and path not in paths_to_keep:
@ -1126,5 +1120,3 @@ def purge_flaky_files():
atexit.register(purge_flaky_files)
methods.clean_cache(env)

View File

@ -194,7 +194,7 @@ String ProjectSettings::localize_path(const String &p_path) const {
return cwd.replace_first(res_path, "res://");
} else {
int sep = path.rfind("/");
int sep = path.rfind_char('/');
if (sep == -1) {
return "res://" + path;
}
@ -262,6 +262,12 @@ String ProjectSettings::globalize_path(const String &p_path) const {
return p_path.replace("res:/", resource_path);
}
return p_path.replace("res://", "");
} else if (p_path.begins_with("uid://")) {
const String path = ResourceUID::uid_to_path(p_path);
if (!resource_path.is_empty()) {
return path.replace("res:/", resource_path);
}
return path.replace("res://", "");
} else if (p_path.begins_with("user://")) {
String data_dir = OS::get_singleton()->get_user_data_dir();
if (!data_dir.is_empty()) {
@ -300,7 +306,7 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
}
{ // Feature overrides.
int dot = p_name.operator String().find(".");
int dot = p_name.operator String().find_char('.');
if (dot != -1) {
Vector<String> s = p_name.operator String().split(".");
@ -435,7 +441,7 @@ void ProjectSettings::_get_property_list(List<PropertyInfo> *p_list) const {
for (const _VCSort &E : vclist) {
String prop_info_name = E.name;
int dot = prop_info_name.find(".");
int dot = prop_info_name.find_char('.');
if (dot != -1 && !custom_prop_info.has(prop_info_name)) {
prop_info_name = prop_info_name.substr(0, dot);
}
@ -508,16 +514,19 @@ void ProjectSettings::_convert_to_last_version(int p_from_version) {
}
}
}
if (p_from_version <= 5) {
// Converts the device in events from -1 (emulated events) to -3 (all events).
if (p_from_version == 5) {
// Converts the device in events from -3 to -1.
// -3 was introduced in GH-97707 as a way to prevent a clash in device IDs, but as reported in GH-99243, this leads to problems.
// -3 was used during dev-releases, so this conversion helps to revert such affected projects.
// This conversion doesn't affect any other projects, since -3 is not used otherwise.
for (KeyValue<StringName, ProjectSettings::VariantContainer> &E : props) {
if (String(E.key).begins_with("input/")) {
Dictionary action = E.value.variant;
Array events = action["events"];
for (int i = 0; i < events.size(); i++) {
Ref<InputEvent> ev = events[i];
if (ev.is_valid() && ev->get_device() == -1) { // -1 was the previous value (GH-97707).
ev->set_device(InputEvent::DEVICE_ID_ALL_DEVICES);
if (ev.is_valid() && ev->get_device() == -3) {
ev->set_device(-1);
}
}
}
@ -1092,7 +1101,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
String category = E.name;
String name = E.name;
int div = category.find("/");
int div = category.find_char('/');
if (div < 0) {
category = "";

View File

@ -163,7 +163,7 @@ void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, co
for (int i = 0; i < p_breakpoints.size(); i++) {
const String &bp = p_breakpoints[i];
int sp = bp.rfind(":");
int sp = bp.rfind_char(':');
ERR_CONTINUE_MSG(sp == -1, vformat("Invalid breakpoint: '%s', expected file:line format.", bp));
singleton_script_debugger->insert_breakpoint(bp.substr(sp + 1, bp.length()).to_int(), bp.substr(0, sp));

View File

@ -171,7 +171,7 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
} else {
String key_value = line.get_slicec(' ', 1);
int value_pos = key_value.find("=");
int value_pos = key_value.find_char('=');
if (value_pos < 0) {
print_line("Error: Invalid set format. Use: set key=value");
@ -344,7 +344,7 @@ Pair<String, int> LocalDebugger::to_breakpoint(const String &p_line) {
String breakpoint_part = p_line.get_slicec(' ', 1);
Pair<String, int> breakpoint;
int last_colon = breakpoint_part.rfind(":");
int last_colon = breakpoint_part.rfind_char(':');
if (last_colon < 0) {
print_line("Error: Invalid breakpoint format. Expected [source:line]");
return breakpoint;

View File

@ -338,7 +338,7 @@ void RemoteDebugger::_send_stack_vars(List<String> &p_names, List<Variant> &p_va
}
Error RemoteDebugger::_try_capture(const String &p_msg, const Array &p_data, bool &r_captured) {
const int idx = p_msg.find(":");
const int idx = p_msg.find_char(':');
r_captured = false;
if (idx < 0) { // No prefix, unknown message.
return OK;
@ -610,7 +610,7 @@ void RemoteDebugger::poll_events(bool p_is_idle) {
ERR_CONTINUE(arr[1].get_type() != Variant::ARRAY);
const String cmd = arr[0];
const int idx = cmd.find(":");
const int idx = cmd.find_char(':');
bool parsed = false;
if (idx < 0) { // Not prefix, use scripts capture.
capture_parse("core", cmd, arr[1], parsed);

View File

@ -224,7 +224,7 @@ RemoteDebuggerPeer *RemoteDebuggerPeerTCP::create(const String &p_uri) {
uint16_t debug_port = 6007;
if (debug_host.contains(":")) {
int sep_pos = debug_host.rfind(":");
int sep_pos = debug_host.rfind_char(':');
debug_port = debug_host.substr(sep_pos + 1).to_int();
debug_host = debug_host.substr(0, sep_pos);
}

View File

@ -154,7 +154,7 @@ public:
}
virtual bool is_vararg() const override {
return false;
return vararg;
}
#ifdef TOOLS_ENABLED

File diff suppressed because it is too large Load Diff

View File

@ -236,7 +236,7 @@ void Input::get_argument_options(const StringName &p_function, int p_idx, List<S
continue;
}
String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
String name = pi.name.substr(pi.name.find_char('/') + 1, pi.name.length());
r_options->push_back(name.quote());
}
}

View File

@ -35,6 +35,9 @@
#include "core/os/keyboard.h"
#include "core/os/os.h"
const int InputEvent::DEVICE_ID_EMULATION = -1;
const int InputEvent::DEVICE_ID_INTERNAL = -2;
void InputEvent::set_device(int p_device) {
device = p_device;
emit_changed();

View File

@ -62,9 +62,8 @@ protected:
static void _bind_methods();
public:
inline static constexpr int DEVICE_ID_EMULATION = -1;
inline static constexpr int DEVICE_ID_INTERNAL = -2;
inline static constexpr int DEVICE_ID_ALL_DEVICES = -3; // Signify that a given Action can be triggered by any device.
static const int DEVICE_ID_EMULATION;
static const int DEVICE_ID_INTERNAL;
void set_device(int p_device);
int get_device() const;

View File

@ -39,6 +39,8 @@
InputMap *InputMap::singleton = nullptr;
int InputMap::ALL_DEVICES = -1;
void InputMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_action", "action"), &InputMap::has_action);
ClassDB::bind_method(D_METHOD("get_actions"), &InputMap::_get_actions);
@ -104,7 +106,7 @@ void InputMap::get_argument_options(const StringName &p_function, int p_idx, Lis
continue;
}
String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
String name = pi.name.substr(pi.name.find_char('/') + 1, pi.name.length());
r_options->push_back(name.quote());
}
}
@ -161,7 +163,7 @@ List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Re
int i = 0;
for (List<Ref<InputEvent>>::Element *E = p_action.inputs.front(); E; E = E->next()) {
int device = E->get()->get_device();
if (device == InputEvent::DEVICE_ID_ALL_DEVICES || device == p_event->get_device()) {
if (device == ALL_DEVICES || device == p_event->get_device()) {
if (E->get()->action_match(p_event, p_exact_match, p_action.deadzone, r_pressed, r_strength, r_raw_strength)) {
if (r_event_index) {
*r_event_index = i;
@ -302,7 +304,7 @@ void InputMap::load_from_project_settings() {
continue;
}
String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
String name = pi.name.substr(pi.name.find_char('/') + 1, pi.name.length());
Dictionary action = GLOBAL_GET(pi.name);
float deadzone = action.has("deadzone") ? (float)action["deadzone"] : DEFAULT_DEADZONE;

View File

@ -43,6 +43,11 @@ class InputMap : public Object {
GDCLASS(InputMap, Object);
public:
/**
* A special value used to signify that a given Action can be triggered by any device
*/
static int ALL_DEVICES;
struct Action {
int id;
float deadzone;

View File

@ -155,9 +155,9 @@ Error DirAccess::make_dir_recursive(const String &p_dir) {
} else if (full_dir.begins_with("user://")) {
base = "user://";
} else if (full_dir.is_network_share_path()) {
int pos = full_dir.find("/", 2);
int pos = full_dir.find_char('/', 2);
ERR_FAIL_COND_V(pos < 0, ERR_INVALID_PARAMETER);
pos = full_dir.find("/", pos + 1);
pos = full_dir.find_char('/', pos + 1);
ERR_FAIL_COND_V(pos < 0, ERR_INVALID_PARAMETER);
base = full_dir.substr(0, pos + 1);
} else if (full_dir.begins_with("/")) {

View File

@ -71,7 +71,7 @@ void FileAccess::_set_access_type(AccessType p_access) {
Ref<FileAccess> FileAccess::create_for_path(const String &p_path) {
Ref<FileAccess> ret;
if (p_path.begins_with("res://")) {
if (p_path.begins_with("res://") || p_path.begins_with("uid://")) {
ret = create(ACCESS_RESOURCES);
} else if (p_path.begins_with("user://")) {
ret = create(ACCESS_USERDATA);
@ -183,13 +183,17 @@ FileAccess::AccessType FileAccess::get_access_type() const {
}
String FileAccess::fix_path(const String &p_path) const {
//helper used by file accesses that use a single filesystem
// Helper used by file accesses that use a single filesystem.
String r_path = p_path.replace("\\", "/");
switch (_access_type) {
case ACCESS_RESOURCES: {
if (ProjectSettings::get_singleton()) {
if (r_path.begins_with("uid://")) {
r_path = ResourceUID::uid_to_path(r_path);
}
if (r_path.begins_with("res://")) {
String resource_path = ProjectSettings::get_singleton()->get_resource_path();
if (!resource_path.is_empty()) {

View File

@ -590,8 +590,6 @@ String DirAccessPack::get_current_dir(bool p_include_drive) const {
}
bool DirAccessPack::file_exists(String p_file) {
p_file = fix_path(p_file);
PackedData::PackedDir *pd = _find_dir(p_file.get_base_dir());
if (!pd) {
return false;
@ -600,8 +598,6 @@ bool DirAccessPack::file_exists(String p_file) {
}
bool DirAccessPack::dir_exists(String p_dir) {
p_dir = fix_path(p_dir);
return _find_dir(p_dir) != nullptr;
}

View File

@ -101,7 +101,7 @@ Error HTTPClient::verify_headers(const Vector<String> &p_headers) {
for (int i = 0; i < p_headers.size(); i++) {
String sanitized = p_headers[i].strip_edges();
ERR_FAIL_COND_V_MSG(sanitized.is_empty(), ERR_INVALID_PARAMETER, vformat("Invalid HTTP header at index %d: empty.", i));
ERR_FAIL_COND_V_MSG(sanitized.find(":") < 1, ERR_INVALID_PARAMETER,
ERR_FAIL_COND_V_MSG(sanitized.find_char(':') < 1, ERR_INVALID_PARAMETER,
vformat("Invalid HTTP header at index %d: String must contain header-value pair, delimited by ':', but was: '%s'.", i, p_headers[i]));
}
@ -113,7 +113,7 @@ Dictionary HTTPClient::_get_response_headers_as_dictionary() {
get_response_headers(&rh);
Dictionary ret;
for (const String &s : rh) {
int sp = s.find(":");
int sp = s.find_char(':');
if (sp == -1) {
continue;
}

View File

@ -508,11 +508,11 @@ Error HTTPClientTCP::poll() {
continue;
}
if (s.begins_with("content-length:")) {
body_size = s.substr(s.find(":") + 1, s.length()).strip_edges().to_int();
body_size = s.substr(s.find_char(':') + 1, s.length()).strip_edges().to_int();
body_left = body_size;
} else if (s.begins_with("transfer-encoding:")) {
String encoding = header.substr(header.find(":") + 1, header.length()).strip_edges();
String encoding = header.substr(header.find_char(':') + 1, header.length()).strip_edges();
if (encoding == "chunked") {
chunked = true;
}

View File

@ -2617,7 +2617,7 @@ Error Image::load(const String &p_path) {
WARN_PRINT(vformat("Loaded resource as image file, this will not work on export: '%s'. Instead, import the image file as an Image resource and load it normally as a resource.", path));
}
#endif
return ImageLoader::load_image(ResourceUID::ensure_path(p_path), this);
return ImageLoader::load_image(path, this);
}
Ref<Image> Image::load_from_file(const String &p_path) {

View File

@ -82,15 +82,16 @@ void ImageFormatLoaderExtension::_bind_methods() {
Error ImageLoader::load_image(const String &p_file, Ref<Image> p_image, Ref<FileAccess> p_custom, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
ERR_FAIL_COND_V_MSG(p_image.is_null(), ERR_INVALID_PARAMETER, "Can't load an image: invalid Image object.");
const String file = ResourceUID::ensure_path(p_file);
Ref<FileAccess> f = p_custom;
if (f.is_null()) {
Error err;
f = FileAccess::open(p_file, FileAccess::READ, &err);
ERR_FAIL_COND_V_MSG(f.is_null(), err, vformat("Error opening file '%s'.", p_file));
f = FileAccess::open(file, FileAccess::READ, &err);
ERR_FAIL_COND_V_MSG(f.is_null(), err, vformat("Error opening file '%s'.", file));
}
String extension = p_file.get_extension();
String extension = file.get_extension();
for (int i = 0; i < loader.size(); i++) {
if (!loader[i]->recognize(extension)) {
@ -98,7 +99,7 @@ Error ImageLoader::load_image(const String &p_file, Ref<Image> p_image, Ref<File
}
Error err = loader.write[i]->load_image(p_image, f, p_flags, p_scale);
if (err != OK) {
ERR_PRINT(vformat("Error loading image: '%s'.", p_file));
ERR_PRINT(vformat("Error loading image: '%s'.", file));
}
if (err != ERR_FILE_UNRECOGNIZED) {

View File

@ -661,12 +661,12 @@ bool PList::load_string(const String &p_string, String &r_err_out) {
List<Ref<PListNode>> stack;
String key;
while (pos >= 0) {
int open_token_s = p_string.find("<", pos);
int open_token_s = p_string.find_char('<', pos);
if (open_token_s == -1) {
r_err_out = "Unexpected end of data. No tags found.";
return false;
}
int open_token_e = p_string.find(">", open_token_s);
int open_token_e = p_string.find_char('>', open_token_s);
pos = open_token_e;
String token = p_string.substr(open_token_s + 1, open_token_e - open_token_s - 1);
@ -676,7 +676,7 @@ bool PList::load_string(const String &p_string, String &r_err_out) {
}
String value;
if (token[0] == '?' || token[0] == '!') { // Skip <?xml ... ?> and <!DOCTYPE ... >
int end_token_e = p_string.find(">", open_token_s);
int end_token_e = p_string.find_char('>', open_token_s);
pos = end_token_e;
continue;
}
@ -769,7 +769,7 @@ bool PList::load_string(const String &p_string, String &r_err_out) {
r_err_out = vformat("Mismatched <%s> tag.", token);
return false;
}
int end_token_e = p_string.find(">", end_token_s);
int end_token_e = p_string.find_char('>', end_token_s);
pos = end_token_e;
String end_token = p_string.substr(end_token_s + 2, end_token_e - end_token_s - 2);
if (end_token != token) {

View File

@ -295,13 +295,13 @@ Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_origin
load_paths_stack.push_back(original_path);
// Try all loaders and pick the first match for the type hint
bool loader_found = false;
bool found = false;
Ref<Resource> res;
for (int i = 0; i < loader_count; i++) {
if (!loader[i]->recognize_path(p_path, p_type_hint)) {
continue;
}
loader_found = true;
found = true;
res = loader[i]->load(p_path, original_path, r_error, p_use_sub_threads, r_progress, p_cache_mode);
if (!res.is_null()) {
break;
@ -316,24 +316,15 @@ Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_origin
return res;
}
if (!loader_found) {
if (r_error) {
*r_error = ERR_FILE_UNRECOGNIZED;
}
ERR_FAIL_V_MSG(Ref<Resource>(), vformat("No loader found for resource: %s (expected type: %s)", p_path, p_type_hint));
}
ERR_FAIL_COND_V_MSG(found, Ref<Resource>(),
vformat("Failed loading resource: %s. Make sure resources have been imported by opening the project in the editor at least once.", p_path));
#ifdef TOOLS_ENABLED
Ref<FileAccess> file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES);
if (!file_check->file_exists(p_path)) {
if (r_error) {
*r_error = ERR_FILE_NOT_FOUND;
}
ERR_FAIL_V_MSG(Ref<Resource>(), vformat("Resource file not found: %s (expected type: %s)", p_path, p_type_hint));
}
ERR_FAIL_COND_V_MSG(!file_check->file_exists(p_path), Ref<Resource>(), vformat("Resource file not found: %s (expected type: %s)", p_path, p_type_hint));
#endif
ERR_FAIL_V_MSG(Ref<Resource>(), vformat("Failed loading resource: %s. Make sure resources have been imported by opening the project in the editor at least once.", p_path));
ERR_FAIL_V_MSG(Ref<Resource>(), vformat("No loader found for resource: %s (expected type: %s)", p_path, p_type_hint));
}
// This implementation must allow re-entrancy for a task that started awaiting in a deeper stack frame.
@ -1206,7 +1197,7 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem
int best_score = 0;
for (int i = 0; i < res_remaps.size(); i++) {
int split = res_remaps[i].rfind(":");
int split = res_remaps[i].rfind_char(':');
if (split == -1) {
continue;
}
@ -1498,11 +1489,11 @@ Vector<String> ResourceLoader::list_directory(const String &p_directory) {
}
} else {
if (d.ends_with(".import") || d.ends_with(".remap") || d.ends_with(".uid")) {
d = d.substr(0, d.rfind("."));
d = d.substr(0, d.rfind_char('.'));
}
if (d.ends_with(".gdc")) {
d = d.substr(0, d.rfind("."));
d = d.substr(0, d.rfind_char('.'));
d += ".gd";
}

View File

@ -108,7 +108,7 @@ Ref<Resource> TranslationLoaderPO::load_translation(Ref<FileAccess> f, Error *r_
// Record plural rule.
int p_start = config.find("Plural-Forms");
if (p_start != -1) {
int p_end = config.find("\n", p_start);
int p_end = config.find_char('\n', p_start);
translation->set_plural_rule(config.substr(p_start, p_end - p_start));
}
} else {
@ -224,7 +224,7 @@ Ref<Resource> TranslationLoaderPO::load_translation(Ref<FileAccess> f, Error *r_
// Record plural rule.
int p_start = config.find("Plural-Forms");
if (p_start != -1) {
int p_end = config.find("\n", p_start);
int p_end = config.find_char('\n', p_start);
translation->set_plural_rule(config.substr(p_start, p_end - p_start));
plural_forms = translation->get_plural_forms();
}
@ -324,7 +324,7 @@ Ref<Resource> TranslationLoaderPO::load_translation(Ref<FileAccess> f, Error *r_
Vector<String> configs = config.split("\n");
for (int i = 0; i < configs.size(); i++) {
String c = configs[i].strip_edges();
int p = c.find(":");
int p = c.find_char(':');
if (p == -1) {
continue;
}

View File

@ -596,101 +596,229 @@ Projection Projection::inverse() const {
}
void Projection::invert() {
int i, j, k;
int pvt_i[4], pvt_j[4]; /* Locations of pivot matrix */
real_t pvt_val; /* Value of current pivot element */
real_t hold; /* Temporary storage */
real_t determinant = 1.0f;
for (k = 0; k < 4; k++) {
/** Locate k'th pivot element **/
pvt_val = columns[k][k]; /** Initialize for search **/
pvt_i[k] = k;
pvt_j[k] = k;
for (i = k; i < 4; i++) {
for (j = k; j < 4; j++) {
if (Math::abs(columns[i][j]) > Math::abs(pvt_val)) {
pvt_i[k] = i;
pvt_j[k] = j;
pvt_val = columns[i][j];
// Adapted from Mesa's `src/util/u_math.c` `util_invert_mat4x4`.
// MIT licensed. Copyright 2008 VMware, Inc. Authored by Jacques Leroy.
Projection temp;
real_t *out = (real_t *)temp.columns;
real_t *m = (real_t *)columns;
real_t wtmp[4][8];
real_t m0, m1, m2, m3, s;
real_t *r0, *r1, *r2, *r3;
#define MAT(m, r, c) (m)[(c) * 4 + (r)]
r0 = wtmp[0];
r1 = wtmp[1];
r2 = wtmp[2];
r3 = wtmp[3];
r0[0] = MAT(m, 0, 0);
r0[1] = MAT(m, 0, 1);
r0[2] = MAT(m, 0, 2);
r0[3] = MAT(m, 0, 3);
r0[4] = 1.0;
r0[5] = 0.0;
r0[6] = 0.0;
r0[7] = 0.0;
r1[0] = MAT(m, 1, 0);
r1[1] = MAT(m, 1, 1);
r1[2] = MAT(m, 1, 2);
r1[3] = MAT(m, 1, 3);
r1[5] = 1.0;
r1[4] = 0.0;
r1[6] = 0.0;
r1[7] = 0.0;
r2[0] = MAT(m, 2, 0);
r2[1] = MAT(m, 2, 1);
r2[2] = MAT(m, 2, 2);
r2[3] = MAT(m, 2, 3);
r2[6] = 1.0;
r2[4] = 0.0;
r2[5] = 0.0;
r2[7] = 0.0;
r3[0] = MAT(m, 3, 0);
r3[1] = MAT(m, 3, 1);
r3[2] = MAT(m, 3, 2);
r3[3] = MAT(m, 3, 3);
r3[7] = 1.0;
r3[4] = 0.0;
r3[5] = 0.0;
r3[6] = 0.0;
/* choose pivot - or die */
if (Math::abs(r3[0]) > Math::abs(r2[0])) {
SWAP(r3, r2);
}
if (Math::abs(r2[0]) > Math::abs(r1[0])) {
SWAP(r2, r1);
}
if (Math::abs(r1[0]) > Math::abs(r0[0])) {
SWAP(r1, r0);
}
ERR_FAIL_COND(0.0 == r0[0]);
/* eliminate first variable */
m1 = r1[0] / r0[0];
m2 = r2[0] / r0[0];
m3 = r3[0] / r0[0];
s = r0[1];
r1[1] -= m1 * s;
r2[1] -= m2 * s;
r3[1] -= m3 * s;
s = r0[2];
r1[2] -= m1 * s;
r2[2] -= m2 * s;
r3[2] -= m3 * s;
s = r0[3];
r1[3] -= m1 * s;
r2[3] -= m2 * s;
r3[3] -= m3 * s;
s = r0[4];
if (s != 0.0) {
r1[4] -= m1 * s;
r2[4] -= m2 * s;
r3[4] -= m3 * s;
}
s = r0[5];
if (s != 0.0) {
r1[5] -= m1 * s;
r2[5] -= m2 * s;
r3[5] -= m3 * s;
}
s = r0[6];
if (s != 0.0) {
r1[6] -= m1 * s;
r2[6] -= m2 * s;
r3[6] -= m3 * s;
}
s = r0[7];
if (s != 0.0) {
r1[7] -= m1 * s;
r2[7] -= m2 * s;
r3[7] -= m3 * s;
}
/** Product of pivots, gives determinant when finished **/
determinant *= pvt_val;
if (Math::is_zero_approx(determinant)) {
return; /** Matrix is singular (zero determinant). **/
/* choose pivot - or die */
if (Math::abs(r3[1]) > Math::abs(r2[1])) {
SWAP(r3, r2);
}
if (Math::abs(r2[1]) > Math::abs(r1[1])) {
SWAP(r2, r1);
}
ERR_FAIL_COND(0.0 == r1[1]);
/* eliminate second variable */
m2 = r2[1] / r1[1];
m3 = r3[1] / r1[1];
r2[2] -= m2 * r1[2];
r3[2] -= m3 * r1[2];
r2[3] -= m2 * r1[3];
r3[3] -= m3 * r1[3];
s = r1[4];
if (0.0 != s) {
r2[4] -= m2 * s;
r3[4] -= m3 * s;
}
s = r1[5];
if (0.0 != s) {
r2[5] -= m2 * s;
r3[5] -= m3 * s;
}
s = r1[6];
if (0.0 != s) {
r2[6] -= m2 * s;
r3[6] -= m3 * s;
}
s = r1[7];
if (0.0 != s) {
r2[7] -= m2 * s;
r3[7] -= m3 * s;
}
/** "Interchange" rows (with sign change stuff) **/
i = pvt_i[k];
if (i != k) { /** If rows are different **/
for (j = 0; j < 4; j++) {
hold = -columns[k][j];
columns[k][j] = columns[i][j];
columns[i][j] = hold;
}
/* choose pivot - or die */
if (Math::abs(r3[2]) > Math::abs(r2[2])) {
SWAP(r3, r2);
}
ERR_FAIL_COND(0.0 == r2[2]);
/** "Interchange" columns **/
j = pvt_j[k];
if (j != k) { /** If columns are different **/
for (i = 0; i < 4; i++) {
hold = -columns[i][k];
columns[i][k] = columns[i][j];
columns[i][j] = hold;
}
}
/* eliminate third variable */
m3 = r3[2] / r2[2];
r3[3] -= m3 * r2[3];
r3[4] -= m3 * r2[4];
r3[5] -= m3 * r2[5];
r3[6] -= m3 * r2[6];
r3[7] -= m3 * r2[7];
/** Divide column by minus pivot value **/
for (i = 0; i < 4; i++) {
if (i != k) {
columns[i][k] /= (-pvt_val);
}
}
/* last check */
ERR_FAIL_COND(0.0 == r3[3]);
/** Reduce the matrix **/
for (i = 0; i < 4; i++) {
hold = columns[i][k];
for (j = 0; j < 4; j++) {
if (i != k && j != k) {
columns[i][j] += hold * columns[k][j];
}
}
}
s = 1.0 / r3[3]; /* now back substitute row 3 */
r3[4] *= s;
r3[5] *= s;
r3[6] *= s;
r3[7] *= s;
/** Divide row by pivot **/
for (j = 0; j < 4; j++) {
if (j != k) {
columns[k][j] /= pvt_val;
}
}
m2 = r2[3]; /* now back substitute row 2 */
s = 1.0 / r2[2];
r2[4] = s * (r2[4] - r3[4] * m2);
r2[5] = s * (r2[5] - r3[5] * m2);
r2[6] = s * (r2[6] - r3[6] * m2);
r2[7] = s * (r2[7] - r3[7] * m2);
m1 = r1[3];
r1[4] -= r3[4] * m1;
r1[5] -= r3[5] * m1;
r1[6] -= r3[6] * m1;
r1[7] -= r3[7] * m1;
m0 = r0[3];
r0[4] -= r3[4] * m0;
r0[5] -= r3[5] * m0;
r0[6] -= r3[6] * m0;
r0[7] -= r3[7] * m0;
/** Replace pivot by reciprocal (at last we can touch it). **/
columns[k][k] = 1.0 / pvt_val;
}
m1 = r1[2]; /* now back substitute row 1 */
s = 1.0 / r1[1];
r1[4] = s * (r1[4] - r2[4] * m1);
r1[5] = s * (r1[5] - r2[5] * m1),
r1[6] = s * (r1[6] - r2[6] * m1);
r1[7] = s * (r1[7] - r2[7] * m1);
m0 = r0[2];
r0[4] -= r2[4] * m0;
r0[5] -= r2[5] * m0;
r0[6] -= r2[6] * m0;
r0[7] -= r2[7] * m0;
/* That was most of the work, one final pass of row/column interchange */
/* to finish */
for (k = 4 - 2; k >= 0; k--) { /* Don't need to work with 1 by 1 corner*/
i = pvt_j[k]; /* Rows to swap correspond to pivot COLUMN */
if (i != k) { /* If rows are different */
for (j = 0; j < 4; j++) {
hold = columns[k][j];
columns[k][j] = -columns[i][j];
columns[i][j] = hold;
}
}
m0 = r0[1]; /* now back substitute row 0 */
s = 1.0 / r0[0];
r0[4] = s * (r0[4] - r1[4] * m0);
r0[5] = s * (r0[5] - r1[5] * m0),
r0[6] = s * (r0[6] - r1[6] * m0);
r0[7] = s * (r0[7] - r1[7] * m0);
j = pvt_i[k]; /* Columns to swap correspond to pivot ROW */
if (j != k) { /* If columns are different */
for (i = 0; i < 4; i++) {
hold = columns[i][k];
columns[i][k] = -columns[i][j];
columns[i][j] = hold;
}
}
}
MAT(out, 0, 0) = r0[4];
MAT(out, 0, 1) = r0[5];
MAT(out, 0, 2) = r0[6];
MAT(out, 0, 3) = r0[7];
MAT(out, 1, 0) = r1[4];
MAT(out, 1, 1) = r1[5];
MAT(out, 1, 2) = r1[6];
MAT(out, 1, 3) = r1[7];
MAT(out, 2, 0) = r2[4];
MAT(out, 2, 1) = r2[5];
MAT(out, 2, 2) = r2[6];
MAT(out, 2, 3) = r2[7];
MAT(out, 3, 0) = r3[4];
MAT(out, 3, 1) = r3[5];
MAT(out, 3, 2) = r3[6];
MAT(out, 3, 3) = r3[7];
#undef MAT
*this = temp;
}
void Projection::flip_y() {

View File

@ -407,7 +407,7 @@ NodePath::NodePath(const String &p_path) {
bool absolute = (path[0] == '/');
bool last_is_slash = true;
int slices = 0;
int subpath_pos = path.find(":");
int subpath_pos = path.find_char(':');
if (subpath_pos != -1) {
int from = subpath_pos + 1;

View File

@ -227,11 +227,11 @@ void TranslationPO::set_plural_rule(const String &p_plural_rule) {
// Set plural_forms and plural_rule.
// p_plural_rule passed in has the form "Plural-Forms: nplurals=2; plural=(n >= 2);".
int first_semi_col = p_plural_rule.find(";");
plural_forms = p_plural_rule.substr(p_plural_rule.find("=") + 1, first_semi_col - (p_plural_rule.find("=") + 1)).to_int();
int first_semi_col = p_plural_rule.find_char(';');
plural_forms = p_plural_rule.substr(p_plural_rule.find_char('=') + 1, first_semi_col - (p_plural_rule.find_char('=') + 1)).to_int();
int expression_start = p_plural_rule.find("=", first_semi_col) + 1;
int second_semi_col = p_plural_rule.rfind(";");
int expression_start = p_plural_rule.find_char('=', first_semi_col) + 1;
int second_semi_col = p_plural_rule.rfind_char(';');
plural_rule = p_plural_rule.substr(expression_start, second_semi_col - expression_start).strip_edges();
// Setup the cache to make evaluating plural rule faster later on.

View File

@ -246,27 +246,27 @@ Error String::parse_url(String &r_scheme, String &r_host, int &r_port, String &r
base = base.substr(pos + 3, base.length() - pos - 3);
}
}
pos = base.find("#");
pos = base.find_char('#');
// Fragment
if (pos != -1) {
r_fragment = base.substr(pos + 1);
base = base.substr(0, pos);
}
pos = base.find("/");
pos = base.find_char('/');
// Path
if (pos != -1) {
r_path = base.substr(pos, base.length() - pos);
base = base.substr(0, pos);
}
// Host
pos = base.find("@");
pos = base.find_char('@');
if (pos != -1) {
// Strip credentials
base = base.substr(pos + 1, base.length() - pos - 1);
}
if (base.begins_with("[")) {
// Literal IPv6
pos = base.rfind("]");
pos = base.rfind_char(']');
if (pos == -1) {
return ERR_INVALID_PARAMETER;
}
@ -277,7 +277,7 @@ Error String::parse_url(String &r_scheme, String &r_host, int &r_port, String &r
if (base.get_slice_count(":") > 2) {
return ERR_INVALID_PARAMETER;
}
pos = base.rfind(":");
pos = base.rfind_char(':');
if (pos == -1) {
r_host = base;
base = "";
@ -2641,7 +2641,7 @@ int64_t String::to_int() const {
return 0;
}
int to = (find(".") >= 0) ? find(".") : length();
int to = (find_char('.') >= 0) ? find_char('.') : length();
int64_t integer = 0;
int64_t sign = 1;
@ -4580,7 +4580,7 @@ String String::simplify_path() const {
if (p == -1) {
p = s.find(":\\");
}
if (p != -1 && p < s.find("/")) {
if (p != -1 && p < s.find_char('/')) {
drive = s.substr(0, p + 2);
s = s.substr(p + 2);
}
@ -5025,7 +5025,7 @@ String String::xml_unescape() const {
String String::pad_decimals(int p_digits) const {
String s = *this;
int c = s.find(".");
int c = s.find_char('.');
if (c == -1) {
if (p_digits <= 0) {
@ -5049,7 +5049,7 @@ String String::pad_decimals(int p_digits) const {
String String::pad_zeros(int p_digits) const {
String s = *this;
int end = s.find(".");
int end = s.find_char('.');
if (end == -1) {
end = s.length();
@ -5316,7 +5316,7 @@ String String::validate_filename() const {
}
bool String::is_valid_ip_address() const {
if (find(":") >= 0) {
if (find_char(':') >= 0) {
Vector<String> ip = split(":");
for (int i = 0; i < ip.size(); i++) {
const String &n = ip[i];
@ -5386,13 +5386,13 @@ String String::get_base_dir() const {
// Windows UNC network share path.
if (end == 0) {
if (is_network_share_path()) {
basepos = find("/", 2);
basepos = find_char('/', 2);
if (basepos == -1) {
basepos = find("\\", 2);
basepos = find_char('\\', 2);
}
int servpos = find("/", basepos + 1);
int servpos = find_char('/', basepos + 1);
if (servpos == -1) {
servpos = find("\\", basepos + 1);
servpos = find_char('\\', basepos + 1);
}
if (servpos != -1) {
end = servpos + 1;
@ -5416,7 +5416,7 @@ String String::get_base_dir() const {
rs = *this;
}
int sep = MAX(rs.rfind("/"), rs.rfind("\\"));
int sep = MAX(rs.rfind_char('/'), rs.rfind_char('\\'));
if (sep == -1) {
return base;
}
@ -5425,7 +5425,7 @@ String String::get_base_dir() const {
}
String String::get_file() const {
int sep = MAX(rfind("/"), rfind("\\"));
int sep = MAX(rfind_char('/'), rfind_char('\\'));
if (sep == -1) {
return *this;
}
@ -5434,8 +5434,8 @@ String String::get_file() const {
}
String String::get_extension() const {
int pos = rfind(".");
if (pos < 0 || pos < MAX(rfind("/"), rfind("\\"))) {
int pos = rfind_char('.');
if (pos < 0 || pos < MAX(rfind_char('/'), rfind_char('\\'))) {
return "";
}
@ -5533,8 +5533,8 @@ String String::validate_node_name() const {
}
String String::get_basename() const {
int pos = rfind(".");
if (pos < 0 || pos < MAX(rfind("/"), rfind("\\"))) {
int pos = rfind_char('.');
if (pos < 0 || pos < MAX(rfind_char('/'), rfind_char('\\'))) {
return *this;
}

View File

@ -80,7 +80,7 @@
<return type="bool" />
<param index="0" name="line" type="int" />
<description>
Returns if the given line is foldable, that is, it has indented lines right below it or a comment / string block.
Returns [code]true[/code] if the given line is foldable. A line is foldable if it is the start of a valid code region (see [method get_code_region_start_tag]), if it is the start of a comment or string block, or if the next non-empty line is more indented (see [method TextEdit.get_indent_level]).
</description>
</method>
<method name="cancel_code_completion">
@ -153,7 +153,7 @@
<method name="do_indent">
<return type="void" />
<description>
Perform an indent as if the user activated the "ui_text_indent" action.
If there is no selection, indentation is inserted at the caret. Otherwise, the selected lines are indented like [method indent_lines]. Equivalent to the [member ProjectSettings.input/ui_text_indent] action. The indentation characters used depend on [member indent_use_spaces] and [member indent_size].
</description>
</method>
<method name="duplicate_lines">
@ -276,7 +276,7 @@
<method name="get_folded_lines" qualifiers="const">
<return type="int[]" />
<description>
Returns all lines that are current folded.
Returns all lines that are currently folded.
</description>
</method>
<method name="get_text_for_code_completion" qualifiers="const">
@ -330,7 +330,7 @@
<method name="indent_lines">
<return type="void" />
<description>
Indents selected lines, or in the case of no selection the caret line by one.
Indents all lines that are selected or have a caret on them. Uses spaces or a tab depending on [member indent_use_spaces]. See [method unindent_lines].
</description>
</method>
<method name="is_in_comment" qualifiers="const">
@ -353,42 +353,42 @@
<return type="bool" />
<param index="0" name="line" type="int" />
<description>
Returns whether the line at the specified index is bookmarked or not.
Returns [code]true[/code] if the given line is bookmarked. See [method set_line_as_bookmarked].
</description>
</method>
<method name="is_line_breakpointed" qualifiers="const">
<return type="bool" />
<param index="0" name="line" type="int" />
<description>
Returns whether the line at the specified index is breakpointed or not.
Returns [code]true[/code] if the given line is breakpointed. See [method set_line_as_breakpoint].
</description>
</method>
<method name="is_line_code_region_end" qualifiers="const">
<return type="bool" />
<param index="0" name="line" type="int" />
<description>
Returns whether the line at the specified index is a code region end.
Returns [code]true[/code] if the given line is a code region end. See [method set_code_region_tags].
</description>
</method>
<method name="is_line_code_region_start" qualifiers="const">
<return type="bool" />
<param index="0" name="line" type="int" />
<description>
Returns whether the line at the specified index is a code region start.
Returns [code]true[/code] if the given line is a code region start. See [method set_code_region_tags].
</description>
</method>
<method name="is_line_executing" qualifiers="const">
<return type="bool" />
<param index="0" name="line" type="int" />
<description>
Returns whether the line at the specified index is marked as executing or not.
Returns [code]true[/code] if the given line is marked as executing. See [method set_line_as_executing].
</description>
</method>
<method name="is_line_folded" qualifiers="const">
<return type="bool" />
<param index="0" name="line" type="int" />
<description>
Returns whether the line at the specified index is folded or not.
Returns [code]true[/code] if the given line is folded. See [method fold_line].
</description>
</method>
<method name="move_lines_down">
@ -442,7 +442,7 @@
<return type="void" />
<param index="0" name="draw_below" type="bool" />
<description>
Sets if the code hint should draw below the text.
If [code]true[/code], the code hint will draw below the main caret. If [code]false[/code], the code hint will draw above the main caret. See [method set_code_hint].
</description>
</method>
<method name="set_code_region_tags">
@ -458,7 +458,7 @@
<param index="0" name="line" type="int" />
<param index="1" name="bookmarked" type="bool" />
<description>
Sets the line as bookmarked.
Sets the given line as bookmarked. If [code]true[/code] and [member gutters_draw_bookmarks] is [code]true[/code], draws the [theme_item bookmark] icon in the gutter for this line. See [method get_bookmarked_lines] and [method is_line_bookmarked].
</description>
</method>
<method name="set_line_as_breakpoint">
@ -466,7 +466,7 @@
<param index="0" name="line" type="int" />
<param index="1" name="breakpointed" type="bool" />
<description>
Sets the line as breakpointed.
Sets the given line as a breakpoint. If [code]true[/code] and [member gutters_draw_breakpoints_gutter] is [code]true[/code], draws the [theme_item breakpoint] icon in the gutter for this line. See [method get_breakpointed_lines] and [method is_line_breakpointed].
</description>
</method>
<method name="set_line_as_executing">
@ -474,7 +474,7 @@
<param index="0" name="line" type="int" />
<param index="1" name="executing" type="bool" />
<description>
Sets the line as executing.
Sets the given line as executing. If [code]true[/code] and [member gutters_draw_executing_lines] is [code]true[/code], draws the [theme_item executing_line] icon in the gutter for this line. See [method get_executing_lines] and [method is_line_executing].
</description>
</method>
<method name="set_symbol_lookup_word_as_valid">
@ -500,20 +500,20 @@
<method name="unfold_all_lines">
<return type="void" />
<description>
Unfolds all lines, folded or not.
Unfolds all lines that are folded.
</description>
</method>
<method name="unfold_line">
<return type="void" />
<param index="0" name="line" type="int" />
<description>
Unfolds all lines that were previously folded.
Unfolds the given line if it is folded or if it is hidden under a folded line.
</description>
</method>
<method name="unindent_lines">
<return type="void" />
<description>
Unindents selected lines, or in the case of no selection the caret line by one. Same as performing "ui_text_unindent" action.
Unindents all lines that are selected or have a caret on them. Uses spaces or a tab depending on [member indent_use_spaces]. Equivalent to the [member ProjectSettings.input/ui_text_dedent] action. See [method indent_lines].
</description>
</method>
<method name="update_code_completion_options">
@ -527,16 +527,16 @@
</methods>
<members>
<member name="auto_brace_completion_enabled" type="bool" setter="set_auto_brace_completion_enabled" getter="is_auto_brace_completion_enabled" default="false">
Sets whether brace pairs should be autocompleted.
If [code]true[/code], uses [member auto_brace_completion_pairs] to automatically insert the closing brace when the opening brace is inserted by typing or autocompletion. Also automatically removes the closing brace when using backspace on the opening brace.
</member>
<member name="auto_brace_completion_highlight_matching" type="bool" setter="set_highlight_matching_braces_enabled" getter="is_highlight_matching_braces_enabled" default="false">
Highlight mismatching brace pairs.
If [code]true[/code], highlights brace pairs when the caret is on either one, using [member auto_brace_completion_pairs]. If matching, the pairs will be underlined. If a brace is unmatched, it is colored with [theme_item brace_mismatch_color].
</member>
<member name="auto_brace_completion_pairs" type="Dictionary" setter="set_auto_brace_completion_pairs" getter="get_auto_brace_completion_pairs" default="{ &quot;\&quot;&quot;: &quot;\&quot;&quot;, &quot;&apos;&quot;: &quot;&apos;&quot;, &quot;(&quot;: &quot;)&quot;, &quot;[&quot;: &quot;]&quot;, &quot;{&quot;: &quot;}&quot; }">
Sets the brace pairs to be autocompleted.
Sets the brace pairs to be autocompleted. For each entry in the dictionary, the key is the opening brace and the value is the closing brace that matches it. A brace is a [String] made of symbols. See [member auto_brace_completion_enabled] and [member auto_brace_completion_highlight_matching].
</member>
<member name="code_completion_enabled" type="bool" setter="set_code_completion_enabled" getter="is_code_completion_enabled" default="false">
Sets whether code completion is allowed.
If [code]true[/code], the [member ProjectSettings.input/ui_text_completion_query] action requests code completion. To handle it, see [method _request_code_completion] or [signal code_completion_requested].
</member>
<member name="code_completion_prefixes" type="String[]" setter="set_code_completion_prefixes" getter="get_code_completion_prefixes" default="[]">
Sets prefixes that will trigger code completion.
@ -548,28 +548,28 @@
Sets the string delimiters. All existing string delimiters will be removed.
</member>
<member name="gutters_draw_bookmarks" type="bool" setter="set_draw_bookmarks_gutter" getter="is_drawing_bookmarks_gutter" default="false">
Sets if bookmarked should be drawn in the gutter. This gutter is shared with breakpoints and executing lines.
If [code]true[/code], bookmarks are drawn in the gutter. This gutter is shared with breakpoints and executing lines. See [method set_line_as_bookmarked].
</member>
<member name="gutters_draw_breakpoints_gutter" type="bool" setter="set_draw_breakpoints_gutter" getter="is_drawing_breakpoints_gutter" default="false">
Sets if breakpoints should be drawn in the gutter. This gutter is shared with bookmarks and executing lines.
If [code]true[/code], breakpoints are drawn in the gutter. This gutter is shared with bookmarks and executing lines. Clicking the gutter will toggle the breakpoint for the line, see [method set_line_as_breakpoint].
</member>
<member name="gutters_draw_executing_lines" type="bool" setter="set_draw_executing_lines_gutter" getter="is_drawing_executing_lines_gutter" default="false">
Sets if executing lines should be marked in the gutter. This gutter is shared with breakpoints and bookmarks lines.
If [code]true[/code], executing lines are marked in the gutter. This gutter is shared with breakpoints and bookmarks. See [method set_line_as_executing].
</member>
<member name="gutters_draw_fold_gutter" type="bool" setter="set_draw_fold_gutter" getter="is_drawing_fold_gutter" default="false">
Sets if foldable lines icons should be drawn in the gutter.
If [code]true[/code], the fold gutter is drawn. In this gutter, the [theme_item can_fold_code_region] icon is drawn for each foldable line (see [method can_fold_line]) and the [theme_item folded_code_region] icon is drawn for each folded line (see [method is_line_folded]). These icons can be clicked to toggle the fold state, see [method toggle_foldable_line]. [member line_folding] must be [code]true[/code] to show icons.
</member>
<member name="gutters_draw_line_numbers" type="bool" setter="set_draw_line_numbers" getter="is_draw_line_numbers_enabled" default="false">
Sets if line numbers should be drawn in the gutter.
If [code]true[/code], the line number gutter is drawn. Line numbers start at [code]1[/code] and are incremented for each line of text. Clicking and dragging in the line number gutter will select entire lines of text.
</member>
<member name="gutters_zero_pad_line_numbers" type="bool" setter="set_line_numbers_zero_padded" getter="is_line_numbers_zero_padded" default="false">
Sets if line numbers drawn in the gutter are zero padded.
If [code]true[/code], line numbers drawn in the gutter are zero padded based on the total line count. Requires [member gutters_draw_line_numbers] to be set to [code]true[/code].
</member>
<member name="indent_automatic" type="bool" setter="set_auto_indent_enabled" getter="is_auto_indent_enabled" default="false">
Sets whether automatic indent are enabled, this will add an extra indent if a prefix or brace is found.
If [code]true[/code], an extra indent is automatically inserted when a new line is added and a prefix in [member indent_automatic_prefixes] is found. If a brace pair opening key is found, the matching closing brace will be moved to another new line (see [member auto_brace_completion_pairs]).
</member>
<member name="indent_automatic_prefixes" type="String[]" setter="set_auto_indent_prefixes" getter="get_auto_indent_prefixes" default="[&quot;:&quot;, &quot;{&quot;, &quot;[&quot;, &quot;(&quot;]">
Prefixes to trigger an automatic indent.
Prefixes to trigger an automatic indent. Used when [member indent_automatic] is set to [code]true[/code].
</member>
<member name="indent_size" type="int" setter="set_indent_size" getter="get_indent_size" default="4">
Size of the tabulation indent (one [kbd]Tab[/kbd] press) in characters. If [member indent_use_spaces] is enabled the number of spaces to use.
@ -579,7 +579,7 @@
</member>
<member name="layout_direction" type="int" setter="set_layout_direction" getter="get_layout_direction" overrides="Control" enum="Control.LayoutDirection" default="2" />
<member name="line_folding" type="bool" setter="set_line_folding_enabled" getter="is_line_folding_enabled" default="false">
Sets whether line folding is allowed.
If [code]true[/code], lines can be folded. Otherwise, line folding methods like [method fold_line] will not work and [method can_fold_line] will always return [code]false[/code]. See [member gutters_draw_fold_gutter].
</member>
<member name="line_length_guidelines" type="int[]" setter="set_line_length_guidelines" getter="get_line_length_guidelines" default="[]">
Draws vertical lines at the provided columns. The first entry is considered a main hard guideline and is draw more prominently.
@ -598,7 +598,7 @@
</signal>
<signal name="code_completion_requested">
<description>
Emitted when the user requests code completion.
Emitted when the user requests code completion. This signal will not be sent if [method _request_code_completion] is overridden or [member code_completion_enabled] is [code]false[/code].
</description>
</signal>
<signal name="symbol_lookup">

View File

@ -204,6 +204,9 @@
<member name="bake_interval" type="float" setter="set_bake_interval" getter="get_bake_interval" default="0.2">
The distance in meters between two adjacent cached points. Changing it forces the cache to be recomputed the next time the [method get_baked_points] or [method get_baked_length] function is called. The smaller the distance, the more points in the cache and the more memory it will consume, so use with care.
</member>
<member name="closed" type="bool" setter="set_closed" getter="is_closed" default="false">
If [code]true[/code], and the curve has more than 2 control points, the last point and the first one will be connected in a loop.
</member>
<member name="point_count" type="int" setter="set_point_count" getter="get_point_count" default="0">
The number of points describing the curve.
</member>

View File

@ -237,7 +237,7 @@
<return type="int" />
<param index="0" name="rect" type="Rect2" />
<description>
Returns index of the screen which contains specified rectangle.
Returns the index of the screen that overlaps the most with the given rectangle. Returns [code]-1[/code] if the rectangle doesn't overlap with any screen or has no area.
</description>
</method>
<method name="get_swap_cancel_ok">

View File

@ -1275,7 +1275,7 @@
If [code]true[/code], adds [url=$DOCS_URL/tutorials/scripting/gdscript/static_typing.html]GDScript static typing[/url] hints such as [code]-&gt; void[/code] and [code]: int[/code] when using code autocompletion or when creating onready variables by drag and dropping nodes into the script editor while pressing the [kbd]Ctrl[/kbd] key. If [code]true[/code], newly created scripts will also automatically have type hints added to their method parameters and return types.
</member>
<member name="text_editor/completion/auto_brace_complete" type="bool" setter="" getter="">
If [code]true[/code], automatically completes braces when making use of code completion.
If [code]true[/code], automatically inserts the matching closing brace when the opening brace is inserted by typing or autocompletion. Also automatically removes the closing brace when pressing [kbd]Backspace[/kbd] on the opening brace. This includes brackets ([code]()[/code], [code][][/code], [code]{}[/code]), string quotation marks ([code]''[/code], [code]""[/code]), and comments ([code]/**/[/code]) if the language supports it.
</member>
<member name="text_editor/completion/code_complete_delay" type="float" setter="" getter="">
The delay in seconds after which autocompletion suggestions should be displayed when the user stops typing.

View File

@ -40,6 +40,11 @@
Emitted when the spinner/slider is ungrabbed.
</description>
</signal>
<signal name="updown_pressed">
<description>
Emitted when the updown button is pressed.
</description>
</signal>
<signal name="value_focus_entered">
<description>
Emitted when the value form gains focus.

View File

@ -99,6 +99,14 @@
<tutorials>
</tutorials>
<methods>
<method name="_get_comments" qualifiers="virtual">
<return type="void" />
<param index="0" name="msgids_comment" type="String[]" />
<param index="1" name="msgids_context_plural_comment" type="String[]" />
<description>
If overridden, called after [method _parse_file] to get comments for the parsed entries. This method should fill the arrays with the same number of elements and in the same order as [method _parse_file].
</description>
</method>
<method name="_get_recognized_extensions" qualifiers="virtual const">
<return type="PackedStringArray" />
<description>

View File

@ -4,7 +4,7 @@
Provides methods for file reading and writing operations.
</brief_description>
<description>
This class can be used to permanently store data in the user device's file system and to read from it. This is useful for store game save data or player configuration files.
This class can be used to permanently store data in the user device's file system and to read from it. This is useful for storing game save data or player configuration files.
Here's a sample on how to write and read from a file:
[codeblocks]
[gdscript]

View File

@ -2545,6 +2545,13 @@
[b]Note:[/b] If the buffer is in the engine's internal cache, it will have to be fetched from GPU memory and possibly decompressed. This means [method multimesh_get_buffer] is potentially a slow operation and should be avoided whenever possible.
</description>
</method>
<method name="multimesh_get_buffer_rd_rid" qualifiers="const">
<return type="RID" />
<param index="0" name="multimesh" type="RID" />
<description>
Returns the [RenderingDevice] [RID] handle of the [MultiMesh], which can be used as any other buffer on the Rendering Device.
</description>
</method>
<method name="multimesh_get_custom_aabb" qualifiers="const">
<return type="AABB" />
<param index="0" name="multimesh" type="RID" />
@ -3314,7 +3321,8 @@
<return type="void" />
<param index="0" name="generate" type="bool" />
<description>
This method is currently unimplemented and does nothing if called with [param generate] set to [code]true[/code].
If [param generate] is [code]true[/code], generates debug wireframes for all meshes that are loaded when using the Compatibility renderer. By default, the engine does not generate debug wireframes at runtime, since they slow down loading of assets and take up VRAM.
[b]Note:[/b] You must call this method before loading any meshes when using the Compatibility renderer, otherwise wireframes will not be used.
</description>
</method>
<method name="set_default_clear_color">
@ -5047,6 +5055,7 @@
</constant>
<constant name="VIEWPORT_DEBUG_DRAW_WIREFRAME" value="4" enum="ViewportDebugDraw">
Debug draw draws objects in wireframe.
[b]Note:[/b] [method set_debug_generate_wireframes] must be called before loading any meshes for wireframes to be visible when using the Compatibility renderer.
</constant>
<constant name="VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER" value="5" enum="ViewportDebugDraw">
Normal buffer is drawn instead of regular scene so you can see the per-pixel normals that will be used by post-processing effects.

View File

@ -265,7 +265,7 @@
<return type="int" />
<param index="0" name="line" type="int" />
<description>
Returns the first column containing a non-whitespace character.
Returns the first column containing a non-whitespace character on the given line. If there is only whitespace, returns the number of characters.
</description>
</method>
<method name="get_first_visible_line" qualifiers="const">
@ -311,7 +311,7 @@
<return type="int" />
<param index="0" name="line" type="int" />
<description>
Returns the number of spaces and [code]tab * tab_size[/code] before the first char.
Returns the indent level of the given line. This is the number of spaces and tabs at the beginning of the line, with the tabs taking the tab size into account (see [method get_tab_size]).
</description>
</method>
<method name="get_last_full_visible_line" qualifiers="const">
@ -343,7 +343,7 @@
<return type="Color" />
<param index="0" name="line" type="int" />
<description>
Returns the current background color of the line. [code]Color(0, 0, 0, 0)[/code] is returned if no color is set.
Returns the custom background color of the given line. If no color is set, returns [code]Color(0, 0, 0, 0)[/code].
</description>
</method>
<method name="get_line_column_at_pos" qualifiers="const">
@ -428,7 +428,7 @@
<param index="0" name="line" type="int" />
<param index="1" name="column" type="int" />
<description>
Returns the wrap index of the given line column.
Returns the wrap index of the given column on the given line. This ranges from [code]0[/code] to [method get_line_wrap_count].
</description>
</method>
<method name="get_line_wrapped_text" qualifiers="const">
@ -655,7 +655,7 @@
<method name="get_total_visible_line_count" qualifiers="const">
<return type="int" />
<description>
Returns the number of lines that may be drawn.
Returns the total number of lines in the text. This includes wrapped lines and excludes folded lines. If [member wrap_mode] is set to [constant LINE_WRAPPING_NONE] and no lines are folded (see [method CodeEdit.is_line_folded]) then this is equivalent to [method get_line_count]. See [method get_visible_line_count_in_range] for a limited range of lines.
</description>
</method>
<method name="get_v_scroll_bar" qualifiers="const">
@ -673,7 +673,7 @@
<method name="get_visible_line_count" qualifiers="const">
<return type="int" />
<description>
Returns the number of visible lines, including wrapped text.
Returns the number of lines that can visually fit, rounded down, based on this control's height.
</description>
</method>
<method name="get_visible_line_count_in_range" qualifiers="const">
@ -681,7 +681,7 @@
<param index="0" name="from_line" type="int" />
<param index="1" name="to_line" type="int" />
<description>
Returns the total number of visible + wrapped lines between the two lines.
Returns the total number of lines between [param from_line] and [param to_line] (inclusive) in the text. This includes wrapped lines and excludes folded lines. If the range covers all lines it is equivalent to [method get_total_visible_line_count].
</description>
</method>
<method name="get_word_at_pos" qualifiers="const">
@ -777,21 +777,21 @@
<return type="bool" />
<param index="0" name="gutter" type="int" />
<description>
Returns whether the gutter is clickable.
Returns [code]true[/code] if the gutter at the given index is clickable. See [method set_gutter_clickable].
</description>
</method>
<method name="is_gutter_drawn" qualifiers="const">
<return type="bool" />
<param index="0" name="gutter" type="int" />
<description>
Returns whether the gutter is currently drawn.
Returns [code]true[/code] if the gutter at the given index is currently drawn. See [method set_gutter_draw].
</description>
</method>
<method name="is_gutter_overwritable" qualifiers="const">
<return type="bool" />
<param index="0" name="gutter" type="int" />
<description>
Returns whether the gutter is overwritable.
Returns [code]true[/code] if the gutter at the given index is overwritable. See [method set_gutter_overwritable].
</description>
</method>
<method name="is_in_mulitcaret_edit" qualifiers="const">
@ -805,7 +805,7 @@
<param index="0" name="line" type="int" />
<param index="1" name="gutter" type="int" />
<description>
Returns whether the gutter on the given line is clickable.
Returns [code]true[/code] if the gutter at the given index on the given line is clickable. See [method set_line_gutter_clickable].
</description>
</method>
<method name="is_line_wrapped" qualifiers="const">
@ -818,7 +818,7 @@
<method name="is_menu_visible" qualifiers="const">
<return type="bool" />
<description>
Returns whether the menu is visible. Use this instead of [code]get_menu().visible[/code] to improve performance (so the creation of the menu is avoided).
Returns [code]true[/code] if the menu is visible. Use this instead of [code]get_menu().visible[/code] to improve performance (so the creation of the menu is avoided). See [method get_menu].
</description>
</method>
<method name="is_mouse_over_selection" qualifiers="const">
@ -826,13 +826,13 @@
<param index="0" name="edges" type="bool" />
<param index="1" name="caret_index" type="int" default="-1" />
<description>
Returns whether the mouse is over selection. If [param edges] is [code]true[/code], the edges are considered part of the selection.
Returns [code]true[/code] if the mouse is over a selection. If [param edges] is [code]true[/code], the edges are considered part of the selection.
</description>
</method>
<method name="is_overtype_mode_enabled" qualifiers="const">
<return type="bool" />
<description>
Returns whether the user is in overtype mode.
Returns [code]true[/code] if overtype mode is enabled. See [method set_overtype_mode_enabled].
</description>
</method>
<method name="menu_option">
@ -847,7 +847,7 @@
<param index="0" name="from_line" type="int" />
<param index="1" name="to_line" type="int" />
<description>
Merge the gutters from [param from_line] into [param to_line]. Only overwritable gutters will be copied.
Merge the gutters from [param from_line] into [param to_line]. Only overwritable gutters will be copied. See [method set_gutter_overwritable].
</description>
</method>
<method name="merge_overlapping_carets">
@ -898,7 +898,7 @@
<return type="void" />
<param index="0" name="gutter" type="int" />
<description>
Removes the gutter from this [TextEdit].
Removes the gutter at the given index.
</description>
</method>
<method name="remove_line_at">
@ -1013,7 +1013,7 @@
<param index="0" name="gutter" type="int" />
<param index="1" name="clickable" type="bool" />
<description>
Sets the gutter as clickable. This will change the mouse cursor to a pointing hand when hovering over the gutter.
If [code]true[/code], the mouse cursor will change to a pointing hand ([constant Control.CURSOR_POINTING_HAND]) when hovering over the gutter at the given index. See [method is_gutter_clickable] and [method set_line_gutter_clickable].
</description>
</method>
<method name="set_gutter_custom_draw">
@ -1021,7 +1021,7 @@
<param index="0" name="column" type="int" />
<param index="1" name="draw_callback" type="Callable" />
<description>
Set a custom draw method for the gutter. The callback method must take the following args: [code]line: int, gutter: int, Area: Rect2[/code]. This only works when the gutter type is [constant GUTTER_TYPE_CUSTOM] (see [method set_gutter_type]).
Set a custom draw callback for the gutter at the given index. [param draw_callback] must take the following arguments: A line index [int], a gutter index [int], and an area [Rect2]. This callback only works when the gutter type is [constant GUTTER_TYPE_CUSTOM] (see [method set_gutter_type]).
</description>
</method>
<method name="set_gutter_draw">
@ -1029,7 +1029,7 @@
<param index="0" name="gutter" type="int" />
<param index="1" name="draw" type="bool" />
<description>
Sets whether the gutter should be drawn.
If [code]true[/code], the gutter at the given index is drawn. The gutter type ([method set_gutter_type]) determines how it is drawn. See [method is_gutter_drawn].
</description>
</method>
<method name="set_gutter_name">
@ -1037,7 +1037,7 @@
<param index="0" name="gutter" type="int" />
<param index="1" name="name" type="String" />
<description>
Sets the name of the gutter.
Sets the name of the gutter at the given index.
</description>
</method>
<method name="set_gutter_overwritable">
@ -1045,7 +1045,7 @@
<param index="0" name="gutter" type="int" />
<param index="1" name="overwritable" type="bool" />
<description>
Sets the gutter to overwritable. See [method merge_gutters].
If [code]true[/code], the line data of the gutter at the given index can be overridden when using [method merge_gutters]. See [method is_gutter_overwritable].
</description>
</method>
<method name="set_gutter_type">
@ -1053,7 +1053,7 @@
<param index="0" name="gutter" type="int" />
<param index="1" name="type" type="int" enum="TextEdit.GutterType" />
<description>
Sets the type of gutter. Gutters can contain icons, text, or custom visuals. See [enum TextEdit.GutterType] for options.
Sets the type of gutter at the given index. Gutters can contain icons, text, or custom visuals. See [enum TextEdit.GutterType] for options.
</description>
</method>
<method name="set_gutter_width">
@ -1061,7 +1061,7 @@
<param index="0" name="gutter" type="int" />
<param index="1" name="width" type="int" />
<description>
Set the width of the gutter.
Set the width of the gutter at the given index.
</description>
</method>
<method name="set_line">
@ -1102,7 +1102,7 @@
<param index="0" name="line" type="int" />
<param index="1" name="color" type="Color" />
<description>
Sets the current background color of the line. Set to [code]Color(0, 0, 0, 0)[/code] for no color.
Sets the custom background color of the given line. If transparent, this color is applied on top of the default background color (See [theme_item background_color]). If set to [code]Color(0, 0, 0, 0)[/code], no additional color is applied.
</description>
</method>
<method name="set_line_gutter_clickable">
@ -1111,7 +1111,7 @@
<param index="1" name="gutter" type="int" />
<param index="2" name="clickable" type="bool" />
<description>
If [param clickable] is [code]true[/code], makes the [param gutter] on [param line] clickable. See [signal gutter_clicked].
If [param clickable] is [code]true[/code], makes the [param gutter] on the given [param line] clickable. This is like [method set_gutter_clickable], but for a single line. If [method is_gutter_clickable] is [code]true[/code], this will not have any effect. See [method is_line_gutter_clickable] and [signal gutter_clicked].
</description>
</method>
<method name="set_line_gutter_icon">
@ -1154,7 +1154,7 @@
<return type="void" />
<param index="0" name="enabled" type="bool" />
<description>
If [code]true[/code], sets the user into overtype mode. When the user types in this mode, it will override existing text.
If [code]true[/code], enables overtype mode. In this mode, typing overrides existing text instead of inserting text. The [member ProjectSettings.input/ui_text_toggle_insert_mode] action toggles overtype mode. See [method is_overtype_mode_enabled].
</description>
</method>
<method name="set_search_flags">
@ -1269,7 +1269,7 @@
If [code]false[/code], the context menu ignores mouse location.
</member>
<member name="caret_multiple" type="bool" setter="set_multiple_carets_enabled" getter="is_multiple_carets_enabled" default="true">
Sets if multiple carets are allowed.
If [code]true[/code], multiple carets are allowed. Left-clicking with [kbd]Alt[/kbd] adds a new caret. See [method add_caret] and [method get_caret_count].
</member>
<member name="caret_type" type="int" setter="set_caret_type" getter="get_caret_type" enum="TextEdit.CaretType" default="0">
Set the type of caret to draw.

View File

@ -42,6 +42,7 @@
</member>
<member name="radial_initial_angle" type="float" setter="set_radial_initial_angle" getter="get_radial_initial_angle" default="0.0">
Starting angle for the fill of [member texture_progress] if [member fill_mode] is [constant FILL_CLOCKWISE], [constant FILL_COUNTER_CLOCKWISE], or [constant FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE]. When the node's [code]value[/code] is equal to its [code]min_value[/code], the texture doesn't show up at all. When the [code]value[/code] increases, the texture fills and tends towards [member radial_fill_degrees].
[b]Note:[/b] [member radial_initial_angle] is wrapped between [code]0[/code] and [code]360[/code] degrees (inclusive).
</member>
<member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" enum="Control.SizeFlags" is_bitfield="true" default="1" />
<member name="step" type="float" setter="set_step" getter="get_step" overrides="Range" default="1.0" />

View File

@ -555,6 +555,7 @@
</constant>
<constant name="DEBUG_DRAW_WIREFRAME" value="4" enum="DebugDraw">
Objects are displayed as wireframe models.
[b]Note:[/b] [method RenderingServer.set_debug_generate_wireframes] must be called before loading any meshes for wireframes to be visible when using the Compatibility renderer.
</constant>
<constant name="DEBUG_DRAW_NORMAL_BUFFER" value="5" enum="DebugDraw">
Objects are displayed without lighting information and their textures replaced by normal mapping.

View File

@ -80,7 +80,7 @@ Error AudioDriverALSA::init_output_device() {
status = snd_pcm_open(&pcm_handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
} else {
String device = output_device_name;
int pos = device.find(";");
int pos = device.find_char(';');
if (pos != -1) {
device = device.substr(0, pos);
}

View File

@ -687,6 +687,8 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
state.current_tex = RID();
const uint64_t base_specialization = GLES3::Config::get_singleton()->float_texture_supported ? 0 : CanvasShaderGLES3::USE_RGBA_SHADOWS;
for (uint32_t i = 0; i <= state.current_batch_index; i++) {
// Skipping when there is no instances.
if (state.canvas_instance_batches[i].instance_count == 0) {
@ -705,10 +707,9 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
}
GLES3::CanvasMaterialData *material_data = state.canvas_instance_batches[i].material_data;
CanvasShaderGLES3::ShaderVariant variant = state.canvas_instance_batches[i].shader_variant;
uint64_t specialization = 0;
specialization |= uint64_t(state.canvas_instance_batches[i].lights_disabled);
specialization |= uint64_t(!GLES3::Config::get_singleton()->float_texture_supported) << 1;
CanvasShaderGLES3::ShaderVariant variant = CanvasShaderGLES3::MODE_DEFAULT;
uint64_t specialization = state.canvas_instance_batches[i].specialization;
specialization |= base_specialization;
RID shader_version = data.canvas_shader_default_version;
if (material_data) {
@ -810,6 +811,7 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_render_target, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, GLES3::CanvasShaderData::BlendMode p_blend_mode, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used, const Point2 &p_repeat_offset) {
RenderingServer::CanvasItemTextureFilter texture_filter = p_item->texture_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? state.default_filter : p_item->texture_filter;
const uint64_t specialization_command_mask = ~(CanvasShaderGLES3::USE_NINEPATCH | CanvasShaderGLES3::USE_PRIMITIVE | CanvasShaderGLES3::USE_ATTRIBUTES | CanvasShaderGLES3::USE_INSTANCING);
if (texture_filter != state.canvas_instance_batches[state.current_batch_index].filter) {
_new_batch(r_batch_broken);
@ -868,9 +870,9 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
bool lights_disabled = light_count == 0 && !state.using_directional_lights;
if (lights_disabled != state.canvas_instance_batches[state.current_batch_index].lights_disabled) {
if (lights_disabled != bool(state.canvas_instance_batches[state.current_batch_index].specialization & CanvasShaderGLES3::DISABLE_LIGHTING)) {
_new_batch(r_batch_broken);
state.canvas_instance_batches[state.current_batch_index].lights_disabled = lights_disabled;
state.canvas_instance_batches[state.current_batch_index].specialization ^= CanvasShaderGLES3::DISABLE_LIGHTING;
}
const Item::Command *c = p_item->commands;
@ -936,7 +938,7 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
state.canvas_instance_batches[state.current_batch_index].tex = rect->texture;
state.canvas_instance_batches[state.current_batch_index].command_type = Item::Command::TYPE_RECT;
state.canvas_instance_batches[state.current_batch_index].command = c;
state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_QUAD;
state.canvas_instance_batches[state.current_batch_index].specialization &= specialization_command_mask;
}
_prepare_canvas_texture(rect->texture, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
@ -1026,7 +1028,8 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
state.canvas_instance_batches[state.current_batch_index].tex = np->texture;
state.canvas_instance_batches[state.current_batch_index].command_type = Item::Command::TYPE_NINEPATCH;
state.canvas_instance_batches[state.current_batch_index].command = c;
state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_NINEPATCH;
state.canvas_instance_batches[state.current_batch_index].specialization &= specialization_command_mask;
state.canvas_instance_batches[state.current_batch_index].specialization |= CanvasShaderGLES3::USE_NINEPATCH;
}
_prepare_canvas_texture(np->texture, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
@ -1092,7 +1095,8 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
state.canvas_instance_batches[state.current_batch_index].tex = polygon->texture;
state.canvas_instance_batches[state.current_batch_index].command_type = Item::Command::TYPE_POLYGON;
state.canvas_instance_batches[state.current_batch_index].command = c;
state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_ATTRIBUTES;
state.canvas_instance_batches[state.current_batch_index].specialization &= specialization_command_mask;
state.canvas_instance_batches[state.current_batch_index].specialization |= CanvasShaderGLES3::USE_ATTRIBUTES;
_prepare_canvas_texture(polygon->texture, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
@ -1119,7 +1123,8 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
state.canvas_instance_batches[state.current_batch_index].primitive_points = primitive->point_count;
state.canvas_instance_batches[state.current_batch_index].command_type = Item::Command::TYPE_PRIMITIVE;
state.canvas_instance_batches[state.current_batch_index].command = c;
state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_PRIMITIVE;
state.canvas_instance_batches[state.current_batch_index].specialization &= specialization_command_mask;
state.canvas_instance_batches[state.current_batch_index].specialization |= CanvasShaderGLES3::USE_PRIMITIVE;
}
_prepare_canvas_texture(state.canvas_instance_batches[state.current_batch_index].tex, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
@ -1164,7 +1169,8 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
_new_batch(r_batch_broken);
Color modulate(1, 1, 1, 1);
state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_ATTRIBUTES;
state.canvas_instance_batches[state.current_batch_index].specialization &= specialization_command_mask;
state.canvas_instance_batches[state.current_batch_index].specialization |= CanvasShaderGLES3::USE_ATTRIBUTES;
if (c->type == Item::Command::TYPE_MESH) {
const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c);
state.canvas_instance_batches[state.current_batch_index].tex = m->texture;
@ -1174,7 +1180,7 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
} else if (c->type == Item::Command::TYPE_MULTIMESH) {
const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(c);
state.canvas_instance_batches[state.current_batch_index].tex = mm->texture;
state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_INSTANCED;
state.canvas_instance_batches[state.current_batch_index].specialization |= CanvasShaderGLES3::USE_INSTANCING;
if (GLES3::MeshStorage::get_singleton()->multimesh_uses_colors(mm->multimesh)) {
state.instance_data_array[r_index].flags |= FLAGS_INSTANCING_HAS_COLORS;
@ -1189,7 +1195,7 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(c);
RID particles = pt->particles;
state.canvas_instance_batches[state.current_batch_index].tex = pt->texture;
state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_INSTANCED;
state.canvas_instance_batches[state.current_batch_index].specialization |= CanvasShaderGLES3::USE_INSTANCING;
state.instance_data_array[r_index].flags |= FLAGS_INSTANCING_HAS_COLORS;
state.instance_data_array[r_index].flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA;

View File

@ -273,14 +273,12 @@ public:
RID material;
GLES3::CanvasMaterialData *material_data = nullptr;
CanvasShaderGLES3::ShaderVariant shader_variant = CanvasShaderGLES3::MODE_QUAD;
uint64_t vertex_input_mask = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_COLOR | RS::ARRAY_FORMAT_TEX_UV;
uint64_t specialization = 0;
const Item::Command *command = nullptr;
Item::Command::Type command_type = Item::Command::TYPE_ANIMATION_SLICE; // Can default to any type that doesn't form a batch.
uint32_t primitive_points = 0;
bool lights_disabled = false;
};
// DataBuffer contains our per-frame data. I.e. the resources that are updated each frame.

View File

@ -238,7 +238,7 @@ void RasterizerSceneGLES3::_geometry_instance_add_surface_with_material(Geometry
GLES3::SceneMaterialData *material_shadow = nullptr;
void *surface_shadow = nullptr;
if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip && !p_material->shader_data->uses_world_coordinates) {
if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip && !p_material->shader_data->uses_world_coordinates && !p_material->shader_data->wireframe) {
flags |= GeometryInstanceSurface::FLAG_USES_SHARED_SHADOW_MATERIAL;
material_shadow = static_cast<GLES3::SceneMaterialData *>(GLES3::MaterialStorage::get_singleton()->material_get_data(scene_globals.default_material, RS::SHADER_SPATIAL));
@ -3157,7 +3157,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
}
bool use_wireframe = false;
if (p_params->force_wireframe) {
if (p_params->force_wireframe || shader->wireframe) {
GLuint wireframe_index_array_gl = mesh_storage->mesh_surface_get_index_buffer_wireframe(mesh_surface);
if (wireframe_index_array_gl) {
index_array_gl = wireframe_index_array_gl;

View File

@ -1,17 +1,16 @@
/* clang-format off */
#[modes]
mode_quad =
mode_ninepatch = #define USE_NINEPATCH
mode_primitive = #define USE_PRIMITIVE
mode_attributes = #define USE_ATTRIBUTES
mode_instanced = #define USE_ATTRIBUTES \n#define USE_INSTANCING
mode_default =
#[specializations]
DISABLE_LIGHTING = true
USE_RGBA_SHADOWS = false
SINGLE_INSTANCE = false
USE_NINEPATCH = false
USE_PRIMITIVE = false
USE_ATTRIBUTES = false
USE_INSTANCING = false
#[vertex]

View File

@ -2,17 +2,15 @@
#[modes]
mode_background =
mode_half_res = #define USE_HALF_RES_PASS
mode_quarter_res = #define USE_QUARTER_RES_PASS
mode_cubemap = #define USE_CUBEMAP_PASS
mode_cubemap_half_res = #define USE_CUBEMAP_PASS \n#define USE_HALF_RES_PASS
mode_cubemap_quarter_res = #define USE_CUBEMAP_PASS \n#define USE_QUARTER_RES_PASS
#[specializations]
USE_MULTIVIEW = false
USE_INVERTED_Y = true
APPLY_TONEMAPPING = true
USE_QUARTER_RES_PASS = false
USE_HALF_RES_PASS = false
#[vertex]

View File

@ -1974,6 +1974,10 @@ void MeshStorage::_multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_
}
}
RID MeshStorage::_multimesh_get_buffer_rd_rid(RID p_multimesh) const {
ERR_FAIL_V_MSG(RID(), "GLES3 does not contain a Rid for the multimesh buffer.");
}
Vector<float> MeshStorage::_multimesh_get_buffer(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, Vector<float>());

View File

@ -517,6 +517,7 @@ public:
virtual Color _multimesh_instance_get_color(RID p_multimesh, int p_index) const override;
virtual Color _multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override;
virtual void _multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override;
virtual RID _multimesh_get_buffer_rd_rid(RID p_multimesh) const override;
virtual Vector<float> _multimesh_get_buffer(RID p_multimesh) const override;
virtual void _multimesh_set_visible_instances(RID p_multimesh, int p_visible) override;

View File

@ -1032,7 +1032,7 @@ void RenderingDeviceDriverMetal::framebuffer_free(FramebufferID p_framebuffer) {
#pragma mark - Shader
const uint32_t SHADER_BINARY_VERSION = 2;
const uint32_t SHADER_BINARY_VERSION = 3;
// region Serialization
@ -1336,23 +1336,32 @@ struct ComputeSize {
struct ShaderStageData {
RD::ShaderStage stage = RD::ShaderStage::SHADER_STAGE_MAX;
uint32_t is_position_invariant = UINT32_MAX;
uint32_t supports_fast_math = UINT32_MAX;
CharString entry_point_name;
CharString source;
size_t serialize_size() const {
int comp_size = Compression::get_max_compressed_buffer_size(source.length(), Compression::MODE_ZSTD);
return sizeof(uint32_t) // Stage.
+ sizeof(uint32_t) /* entry_point_name.utf8().length */ + entry_point_name.length() + sizeof(uint32_t) /* uncompressed size */ + sizeof(uint32_t) /* compressed size */ + comp_size;
+ sizeof(uint32_t) // is_position_invariant
+ sizeof(uint32_t) // supports_fast_math
+ sizeof(uint32_t) /* entry_point_name.utf8().length */
+ entry_point_name.length() + sizeof(uint32_t) /* uncompressed size */ + sizeof(uint32_t) /* compressed size */ + comp_size;
}
void serialize(BufWriter &p_writer) const {
p_writer.write((uint32_t)stage);
p_writer.write(is_position_invariant);
p_writer.write(supports_fast_math);
p_writer.write(entry_point_name);
p_writer.write_compressed(source);
}
void deserialize(BufReader &p_reader) {
p_reader.read((uint32_t &)stage);
p_reader.read(is_position_invariant);
p_reader.read(supports_fast_math);
p_reader.read(entry_point_name);
p_reader.read_compressed(source);
}
@ -2011,7 +2020,8 @@ Vector<uint8_t> RenderingDeviceDriverMetal::shader_compile_binary_from_spirv(Vec
ERR_FAIL_COND_V_MSG(compiler.get_entry_points_and_stages().size() != 1, Result(), "Expected a single entry point and stage.");
EntryPoint &entry_point_stage = compiler.get_entry_points_and_stages().front();
SmallVector<EntryPoint> entry_pts_stages = compiler.get_entry_points_and_stages();
EntryPoint &entry_point_stage = entry_pts_stages.front();
SPIREntryPoint &entry_point = compiler.get_entry_point(entry_point_stage.name, entry_point_stage.execution_model);
// Process specialization constants.
@ -2293,6 +2303,8 @@ Vector<uint8_t> RenderingDeviceDriverMetal::shader_compile_binary_from_spirv(Vec
ShaderStageData stage_data;
stage_data.stage = v.shader_stage;
stage_data.is_position_invariant = compiler.is_position_invariant();
stage_data.supports_fast_math = !entry_point.flags.get(spv::ExecutionModeSignedZeroInfNanPreserve);
stage_data.entry_point_name = entry_point.name.c_str();
stage_data.source = source.c_str();
bin_data.stages.push_back(stage_data);
@ -2365,7 +2377,8 @@ RDD::ShaderID RenderingDeviceDriverMetal::shader_create_from_bytecode(const Vect
ShaderCacheEntry *cd = memnew(ShaderCacheEntry(*this, key));
cd->name = binary_data.shader_name;
cd->stage = shader_data.stage;
options.preserveInvariance = shader_data.is_position_invariant;
options.fastMathEnabled = YES;
MDLibrary *library = [MDLibrary newLibraryWithCacheEntry:cd
device:device
source:source

View File

@ -28,23 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#if defined(UNIX_ENABLED)
#include "ip_unix.h"
#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED)
#ifdef WINDOWS_ENABLED
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <stdio.h>
#else // UNIX
#include <netdb.h>
#ifdef ANDROID_ENABLED
@ -67,8 +54,6 @@
#include <net/if.h> // Order is important on OpenBSD, leave as last.
#endif // UNIX
#include <string.h>
static IPAddress _sockaddr2ip(struct sockaddr *p_addr) {
@ -108,7 +93,7 @@ void IPUnix::_resolve_hostname(List<IPAddress> &r_addresses, const String &p_hos
}
if (result == nullptr || result->ai_addr == nullptr) {
print_verbose("Invalid response from getaddrinfo");
print_verbose("Invalid response from getaddrinfo.");
if (result) {
freeaddrinfo(result);
}
@ -132,56 +117,6 @@ void IPUnix::_resolve_hostname(List<IPAddress> &r_addresses, const String &p_hos
freeaddrinfo(result);
}
#if defined(WINDOWS_ENABLED)
void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const {
ULONG buf_size = 1024;
IP_ADAPTER_ADDRESSES *addrs;
while (true) {
addrs = (IP_ADAPTER_ADDRESSES *)memalloc(buf_size);
int err = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME,
nullptr, addrs, &buf_size);
if (err == NO_ERROR) {
break;
}
memfree(addrs);
if (err == ERROR_BUFFER_OVERFLOW) {
continue; // will go back and alloc the right size
}
ERR_FAIL_MSG("Call to GetAdaptersAddresses failed with error " + itos(err) + ".");
}
IP_ADAPTER_ADDRESSES *adapter = addrs;
while (adapter != nullptr) {
Interface_Info info;
info.name = adapter->AdapterName;
info.name_friendly = adapter->FriendlyName;
info.index = String::num_uint64(adapter->IfIndex);
IP_ADAPTER_UNICAST_ADDRESS *address = adapter->FirstUnicastAddress;
while (address != nullptr) {
int family = address->Address.lpSockaddr->sa_family;
if (family != AF_INET && family != AF_INET6) {
continue;
}
info.ip_addresses.push_front(_sockaddr2ip(address->Address.lpSockaddr));
address = address->Next;
}
adapter = adapter->Next;
// Only add interface if it has at least one IP
if (info.ip_addresses.size() > 0) {
r_interfaces->insert(info.name, info);
}
}
memfree(addrs);
}
#else // UNIX
void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const {
struct ifaddrs *ifAddrStruct = nullptr;
struct ifaddrs *ifa = nullptr;
@ -219,8 +154,6 @@ void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces)
}
}
#endif // UNIX
void IPUnix::make_default() {
_create = _create_unix;
}
@ -232,4 +165,4 @@ IP *IPUnix::_create_unix() {
IPUnix::IPUnix() {
}
#endif // UNIX_ENABLED || WINDOWS_ENABLED
#endif // UNIX_ENABLED

View File

@ -31,9 +31,9 @@
#ifndef IP_UNIX_H
#define IP_UNIX_H
#include "core/io/ip.h"
#if defined(UNIX_ENABLED)
#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED)
#include "core/io/ip.h"
class IPUnix : public IP {
GDCLASS(IPUnix, IP);
@ -49,6 +49,6 @@ public:
IPUnix();
};
#endif
#endif // UNIX_ENABLED
#endif // IP_UNIX_H

View File

@ -860,7 +860,7 @@ String OS_Unix::get_locale() const {
}
String locale = get_environment("LANG");
int tp = locale.find(".");
int tp = locale.find_char('.');
if (tp != -1) {
locale = locale.substr(0, tp);
}

View File

@ -2392,7 +2392,9 @@ RDD::CommandQueueFamilyID RenderingDeviceDriverVulkan::command_queue_family_get(
}
}
ERR_FAIL_COND_V_MSG(picked_family_index >= queue_family_properties.size(), CommandQueueFamilyID(), "A queue family with the requested bits could not be found.");
if (picked_family_index >= queue_family_properties.size()) {
return CommandQueueFamilyID();
}
// Since 0 is a valid index and we use 0 as the error case, we make the index start from 1 instead.
return CommandQueueFamilyID(picked_family_index + 1);

View File

@ -230,7 +230,7 @@ String DirAccessWindows::get_current_dir(bool p_include_drive) const {
return cdir;
} else {
if (_get_root_string().is_empty()) {
int pos = cdir.find(":");
int pos = cdir.find_char(':');
if (pos != -1) {
return cdir.substr(pos + 1);
}
@ -344,7 +344,7 @@ String DirAccessWindows::get_filesystem_type() const {
return "Network Share";
}
int unit_end = path.find(":");
int unit_end = path.find_char(':');
ERR_FAIL_COND_V(unit_end == -1, String());
String unit = path.substr(0, unit_end + 1) + "\\";

View File

@ -64,7 +64,7 @@ bool FileAccessWindows::is_path_invalid(const String &p_path) {
// Check for invalid operating system file.
String fname = p_path.get_file().to_lower();
int dot = fname.find(".");
int dot = fname.find_char('.');
if (dot != -1) {
fname = fname.substr(0, dot);
}

View File

@ -0,0 +1,164 @@
/**************************************************************************/
/* ip_windows.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#if defined(WINDOWS_ENABLED)
#include "ip_windows.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <string.h>
static IPAddress _sockaddr2ip(struct sockaddr *p_addr) {
IPAddress ip;
if (p_addr->sa_family == AF_INET) {
struct sockaddr_in *addr = (struct sockaddr_in *)p_addr;
ip.set_ipv4((uint8_t *)&(addr->sin_addr));
} else if (p_addr->sa_family == AF_INET6) {
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr;
ip.set_ipv6(addr6->sin6_addr.s6_addr);
}
return ip;
}
void IPWindows::_resolve_hostname(List<IPAddress> &r_addresses, const String &p_hostname, Type p_type) const {
struct addrinfo hints;
struct addrinfo *result = nullptr;
memset(&hints, 0, sizeof(struct addrinfo));
if (p_type == TYPE_IPV4) {
hints.ai_family = AF_INET;
} else if (p_type == TYPE_IPV6) {
hints.ai_family = AF_INET6;
hints.ai_flags = 0;
} else {
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_ADDRCONFIG;
}
hints.ai_flags &= ~AI_NUMERICHOST;
int s = getaddrinfo(p_hostname.utf8().get_data(), nullptr, &hints, &result);
if (s != 0) {
print_verbose("getaddrinfo failed! Cannot resolve hostname.");
return;
}
if (result == nullptr || result->ai_addr == nullptr) {
print_verbose("Invalid response from getaddrinfo.");
if (result) {
freeaddrinfo(result);
}
return;
}
struct addrinfo *next = result;
do {
if (next->ai_addr == nullptr) {
next = next->ai_next;
continue;
}
IPAddress ip = _sockaddr2ip(next->ai_addr);
if (ip.is_valid() && !r_addresses.find(ip)) {
r_addresses.push_back(ip);
}
next = next->ai_next;
} while (next);
freeaddrinfo(result);
}
void IPWindows::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const {
ULONG buf_size = 1024;
IP_ADAPTER_ADDRESSES *addrs;
while (true) {
addrs = (IP_ADAPTER_ADDRESSES *)memalloc(buf_size);
int err = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME,
nullptr, addrs, &buf_size);
if (err == NO_ERROR) {
break;
}
memfree(addrs);
if (err == ERROR_BUFFER_OVERFLOW) {
continue; // Will go back and alloc the right size.
}
ERR_FAIL_MSG("Call to GetAdaptersAddresses failed with error " + itos(err) + ".");
}
IP_ADAPTER_ADDRESSES *adapter = addrs;
while (adapter != nullptr) {
Interface_Info info;
info.name = adapter->AdapterName;
info.name_friendly = adapter->FriendlyName;
info.index = String::num_uint64(adapter->IfIndex);
IP_ADAPTER_UNICAST_ADDRESS *address = adapter->FirstUnicastAddress;
while (address != nullptr) {
int family = address->Address.lpSockaddr->sa_family;
if (family != AF_INET && family != AF_INET6) {
continue;
}
info.ip_addresses.push_front(_sockaddr2ip(address->Address.lpSockaddr));
address = address->Next;
}
adapter = adapter->Next;
// Only add interface if it has at least one IP.
if (info.ip_addresses.size() > 0) {
r_interfaces->insert(info.name, info);
}
}
memfree(addrs);
}
void IPWindows::make_default() {
_create = _create_unix;
}
IP *IPWindows::_create_unix() {
return memnew(IPWindows);
}
IPWindows::IPWindows() {
}
#endif // WINDOWS_ENABLED

View File

@ -0,0 +1,54 @@
/**************************************************************************/
/* ip_windows.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 IP_WINDOWS_H
#define IP_WINDOWS_H
#if defined(WINDOWS_ENABLED)
#include "core/io/ip.h"
class IPWindows : public IP {
GDCLASS(IPWindows, IP);
virtual void _resolve_hostname(List<IPAddress> &r_addresses, const String &p_hostname, Type p_type = TYPE_ANY) const override;
static IP *_create_unix();
public:
virtual void get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const override;
static void make_default();
IPWindows();
};
#endif // WINDOWS_ENABLED
#endif // IP_WINDOWS_H

View File

@ -275,7 +275,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
}
String base_path = animation->track_get_path(i);
int end = base_path.find(":");
int end = base_path.find_char(':');
if (end != -1) {
base_path = base_path.substr(0, end + 1);
}

View File

@ -2191,7 +2191,7 @@ void AnimationTrackEdit::_notification(int p_what) {
offset = offset * scale + limit;
Color marker_color = animation->get_marker_color(marker);
marker_color.a = 0.2;
draw_line(Point2(offset, 0), Point2(offset, get_size().height), marker_color);
draw_line(Point2(offset, 0), Point2(offset, get_size().height), marker_color, Math::round(EDSCALE));
}
}
}
@ -3647,7 +3647,7 @@ void AnimationTrackEditGroup::_notification(int p_what) {
offset = offset * scale + limit;
Color marker_color = editor->get_current_animation()->get_marker_color(marker);
marker_color.a = 0.2;
draw_line(Point2(offset, 0), Point2(offset, get_size().height), marker_color);
draw_line(Point2(offset, 0), Point2(offset, get_size().height), marker_color, Math::round(EDSCALE));
}
}
}
@ -4340,7 +4340,7 @@ void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_p
if (track_path == np) {
actual_value = value; // All good.
} else {
int sep = track_path.rfind(":");
int sep = track_path.rfind_char(':');
if (sep != -1) {
String base_path = track_path.substr(0, sep);
if (base_path == np) {
@ -6495,7 +6495,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
path = NodePath(node->get_path().get_names(), path.get_subnames(), true); // Store full path instead for copying.
} else {
text = path;
int sep = text.find(":");
int sep = text.find_char(':');
if (sep != -1) {
text = text.substr(sep + 1, text.length());
}
@ -7364,7 +7364,6 @@ void AnimationTrackEditor::_update_snap_unit() {
}
if (timeline->is_using_fps()) {
_clear_selection(true); // Needs to recreate a spinbox of the KeyEdit.
snap_unit = 1.0 / step->get_value();
} else {
if (fps_compat->is_pressed()) {
@ -7983,6 +7982,11 @@ AnimationTrackEditor::~AnimationTrackEditor() {
// AnimationTrackKeyEditEditorPlugin.
void AnimationTrackKeyEditEditor::_time_edit_spun() {
_time_edit_entered();
_time_edit_exited();
}
void AnimationTrackKeyEditEditor::_time_edit_entered() {
int key = animation->track_find_key(track, key_ofs, Animation::FIND_MODE_APPROX);
if (key == -1) {
@ -8010,7 +8014,7 @@ void AnimationTrackKeyEditEditor::_time_edit_exited() {
int existing = animation->track_find_key(track, new_time, Animation::FIND_MODE_APPROX);
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Change Keyframe Time"), UndoRedo::MERGE_ENDS);
undo_redo->create_action(TTR("Animation Change Keyframe Time"));
if (existing != -1) {
undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", track, animation->track_get_key_time(track, existing));
@ -8057,6 +8061,7 @@ AnimationTrackKeyEditEditor::AnimationTrackKeyEditEditor(Ref<Animation> p_animat
spinner->set_min(0);
spinner->set_allow_greater(true);
spinner->set_allow_lesser(true);
add_child(spinner);
if (use_fps) {
spinner->set_step(FPS_DECIMAL);
@ -8065,14 +8070,13 @@ AnimationTrackKeyEditEditor::AnimationTrackKeyEditEditor(Ref<Animation> p_animat
fps = 1.0 / fps;
}
spinner->set_value(key_ofs * fps);
spinner->connect("updown_pressed", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_spun), CONNECT_DEFERRED);
} else {
spinner->set_step(SECOND_DECIMAL);
spinner->set_value(key_ofs);
spinner->set_max(animation->get_length());
}
add_child(spinner);
spinner->connect("grabbed", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_entered), CONNECT_DEFERRED);
spinner->connect("ungrabbed", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_exited), CONNECT_DEFERRED);
spinner->connect("value_focus_entered", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_entered), CONNECT_DEFERRED);
@ -8307,9 +8311,6 @@ void AnimationMarkerEdit::_notification(int p_what) {
Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));
Color color = get_theme_color(SceneStringName(font_color), SNAME("Label"));
int hsep = get_theme_constant(SNAME("h_separation"), SNAME("ItemList"));
Color linecolor = color;
linecolor.a = 0.2;
// SECTION PREVIEW //
@ -8368,31 +8369,21 @@ void AnimationMarkerEdit::_notification(int p_what) {
draw_key(name, scale, int(offset), is_selected, limit, limit_end);
const int font_size = 16;
const int font_size = 12 * EDSCALE;
Size2 string_size = font->get_string_size(name, HORIZONTAL_ALIGNMENT_LEFT, -1.0, font_size);
if (int(offset) <= limit_end && int(offset) >= limit && should_show_all_marker_names) {
float bottom = get_size().height + string_size.y - font->get_descent(font_size);
float extrusion = MAX(0, offset + string_size.x - limit_end); // How much the string would extrude outside limit_end if unadjusted.
Color marker_color = animation->get_marker_color(name);
draw_string(font, Point2(offset - extrusion, bottom), name, HORIZONTAL_ALIGNMENT_LEFT, -1.0, font_size, marker_color);
draw_string_outline(font, Point2(offset - extrusion, bottom), name, HORIZONTAL_ALIGNMENT_LEFT, -1.0, font_size, 1, color);
float margin = 4 * EDSCALE;
Point2 pos = Point2(offset - extrusion + margin, bottom + margin);
draw_string(font, pos, name, HORIZONTAL_ALIGNMENT_LEFT, -1.0, font_size, marker_color);
draw_string_outline(font, pos, name, HORIZONTAL_ALIGNMENT_LEFT, -1.0, font_size, 1, color);
}
}
}
draw_fg(limit, get_size().width - timeline->get_buttons_width());
// BUTTONS //
{
int ofs = get_size().width - timeline->get_buttons_width();
draw_line(Point2(ofs, 0), Point2(ofs, get_size().height), linecolor, Math::round(EDSCALE));
ofs += hsep;
}
draw_line(Vector2(0, get_size().height), get_size(), linecolor, Math::round(EDSCALE));
} break;
case NOTIFICATION_MOUSE_ENTER:
@ -9193,9 +9184,6 @@ void AnimationMultiMarkerKeyEdit::_get_property_list(List<PropertyInfo> *p_list)
// AnimationMarkerKeyEditEditorPlugin
void AnimationMarkerKeyEditEditor::_time_edit_entered() {
}
void AnimationMarkerKeyEditEditor::_time_edit_exited() {
real_t new_time = spinner->get_value();
@ -9214,7 +9202,7 @@ void AnimationMarkerKeyEditEditor::_time_edit_exited() {
}
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Change Marker Time"), UndoRedo::MERGE_ENDS);
undo_redo->create_action(TTR("Animation Change Marker Time"));
Color color = animation->get_marker_color(marker_name);
undo_redo->add_do_method(animation.ptr(), "add_marker", marker_name, new_time);
@ -9255,6 +9243,7 @@ AnimationMarkerKeyEditEditor::AnimationMarkerKeyEditEditor(Ref<Animation> p_anim
spinner->set_min(0);
spinner->set_allow_greater(true);
spinner->set_allow_lesser(true);
add_child(spinner);
float time = animation->get_marker_time(marker_name);
@ -9265,17 +9254,14 @@ AnimationMarkerKeyEditEditor::AnimationMarkerKeyEditEditor(Ref<Animation> p_anim
fps = 1.0 / fps;
}
spinner->set_value(time * fps);
spinner->connect("updown_pressed", callable_mp(this, &AnimationMarkerKeyEditEditor::_time_edit_exited), CONNECT_DEFERRED);
} else {
spinner->set_step(SECOND_DECIMAL);
spinner->set_value(time);
spinner->set_max(animation->get_length());
}
add_child(spinner);
spinner->connect("grabbed", callable_mp(this, &AnimationMarkerKeyEditEditor::_time_edit_entered), CONNECT_DEFERRED);
spinner->connect("ungrabbed", callable_mp(this, &AnimationMarkerKeyEditEditor::_time_edit_exited), CONNECT_DEFERRED);
spinner->connect("value_focus_entered", callable_mp(this, &AnimationMarkerKeyEditEditor::_time_edit_entered), CONNECT_DEFERRED);
spinner->connect("value_focus_exited", callable_mp(this, &AnimationMarkerKeyEditEditor::_time_edit_exited), CONNECT_DEFERRED);
}

View File

@ -977,6 +977,7 @@ class AnimationTrackKeyEditEditor : public EditorProperty {
Variant value;
} key_data_cache;
void _time_edit_spun();
void _time_edit_entered();
void _time_edit_exited();
@ -996,7 +997,6 @@ class AnimationMarkerKeyEditEditor : public EditorProperty {
EditorSpinSlider *spinner = nullptr;
void _time_edit_entered();
void _time_edit_exited();
public:

View File

@ -524,7 +524,7 @@ void ConnectDialog::set_dst_node(Node *p_node) {
StringName ConnectDialog::get_dst_method_name() const {
String txt = dst_method->get_text();
if (txt.contains("(")) {
txt = txt.left(txt.find("(")).strip_edges();
txt = txt.left(txt.find_char('(')).strip_edges();
}
return txt;
}

View File

@ -160,13 +160,13 @@ bool CreateDialog::_should_hide_type(const StringName &p_type) const {
String script_path = ScriptServer::get_global_class_path(p_type);
if (script_path.begins_with("res://addons/")) {
int i = script_path.find("/", 13); // 13 is length of "res://addons/".
int i = script_path.find_char('/', 13); // 13 is length of "res://addons/".
while (i > -1) {
const String plugin_path = script_path.substr(0, i).path_join("plugin.cfg");
if (FileAccess::exists(plugin_path)) {
return !EditorNode::get_singleton()->is_addon_plugin_enabled(plugin_path);
}
i = script_path.find("/", i + 1);
i = script_path.find_char('/', i + 1);
}
}
}

View File

@ -147,7 +147,7 @@ Dictionary DebugAdapterParser::req_initialize(const Dictionary &p_params) const
for (List<String>::Element *E = breakpoints.front(); E; E = E->next()) {
String breakpoint = E->get();
String path = breakpoint.left(breakpoint.find(":", 6)); // Skip initial part of path, aka "res://"
String path = breakpoint.left(breakpoint.find_char(':', 6)); // Skip initial part of path, aka "res://"
int line = breakpoint.substr(path.size()).to_int();
DebugAdapterProtocol::get_singleton()->on_debug_breakpoint_toggled(path, line, true);

View File

@ -160,9 +160,9 @@ void EditorDebuggerNode::_text_editor_stack_goto(const ScriptEditorDebugger *p_d
} else {
// If the script is built-in, it can be opened only if the scene is loaded in memory.
int i = file.find("::");
int j = file.rfind("(", i);
int j = file.rfind_char('(', i);
if (j > -1) { // If the script is named, the string is "name (file)", so we need to extract the path.
file = file.substr(j + 1, file.find(")", i) - j - 1);
file = file.substr(j + 1, file.find_char(')', i) - j - 1);
}
Ref<PackedScene> ps = ResourceLoader::load(file.get_slice("::", 0));
stack_script = ResourceLoader::load(file);
@ -183,9 +183,9 @@ void EditorDebuggerNode::_text_editor_stack_clear(const ScriptEditorDebugger *p_
} else {
// If the script is built-in, it can be opened only if the scene is loaded in memory.
int i = file.find("::");
int j = file.rfind("(", i);
int j = file.rfind_char('(', i);
if (j > -1) { // If the script is named, the string is "name (file)", so we need to extract the path.
file = file.substr(j + 1, file.find(")", i) - j - 1);
file = file.substr(j + 1, file.find_char(')', i) - j - 1);
}
Ref<PackedScene> ps = ResourceLoader::load(file.get_slice("::", 0));
stack_script = ResourceLoader::load(file);

View File

@ -382,7 +382,7 @@ void EditorDebuggerTree::_item_menu_id_pressed(int p_option) {
text = ".";
} else {
text = text.replace("/root/", "");
int slash = text.find("/");
int slash = text.find_char('/');
if (slash < 0) {
text = ".";
} else {

View File

@ -471,7 +471,7 @@ void DependencyRemoveDialog::_find_localization_remaps_of_removed_files(Vector<R
for (int j = 0; j < remap_keys.size(); j++) {
PackedStringArray remapped_files = remaps[remap_keys[j]];
for (int k = 0; k < remapped_files.size(); k++) {
int splitter_pos = remapped_files[k].rfind(":");
int splitter_pos = remapped_files[k].rfind_char(':');
String res_path = remapped_files[k].substr(0, splitter_pos);
if (res_path == path) {
String locale_name = remapped_files[k].substr(splitter_pos + 1);

View File

@ -142,7 +142,7 @@ void DirectoryCreateDialog::config(const String &p_base_dir, const Callable &p_a
validation_panel->update();
if (p_mode == MODE_FILE) {
int extension_pos = p_default_name.rfind(".");
int extension_pos = p_default_name.rfind_char('.');
if (extension_pos > -1) {
dir_path->select(0, extension_pos);
return;

View File

@ -130,14 +130,14 @@ void EditorAssetInstaller::open_asset(const String &p_path, bool p_autoskip_topl
// Create intermediate directories if they aren't reported by unzip.
// We are only interested in subfolders, so skip the root slash.
int separator = source_name.find("/", 1);
int separator = source_name.find_char('/', 1);
while (separator != -1) {
String dir_name = source_name.substr(0, separator + 1);
if (!dir_name.is_empty() && !asset_files.has(dir_name)) {
asset_files.insert(dir_name);
}
separator = source_name.find("/", separator + 1);
separator = source_name.find_char('/', separator + 1);
}
if (!source_name.is_empty() && !asset_files.has(source_name)) {
@ -214,7 +214,7 @@ void EditorAssetInstaller::_rebuild_source_tree() {
TreeItem *parent_item;
int separator = path.rfind("/");
int separator = path.rfind_char('/');
if (separator == -1) {
parent_item = root;
} else {
@ -313,7 +313,7 @@ void EditorAssetInstaller::_rebuild_destination_tree() {
TreeItem *parent_item;
int separator = path.rfind("/");
int separator = path.rfind_char('/');
if (separator == -1) {
parent_item = root;
} else {

View File

@ -249,7 +249,7 @@ void EditorFolding::_do_object_unfolds(Object *p_object, HashSet<Ref<Resource>>
}
}
} else { //path
int last = E.name.rfind("/");
int last = E.name.rfind_char('/');
if (last != -1) {
bool can_revert = EditorPropertyRevert::can_property_revert(p_object, E.name);
if (can_revert) {

View File

@ -148,7 +148,7 @@ static String _contextualize_class_specifier(const String &p_class_specifier, co
// Here equal length + begins_with from above implies p_class_specifier == p_edited_class :)
if (p_class_specifier.length() == p_edited_class.length()) {
int rfind = p_class_specifier.rfind(".");
int rfind = p_class_specifier.rfind_char('.');
if (rfind == -1) { // Single identifier
return p_class_specifier;
}
@ -234,7 +234,7 @@ void EditorHelp::_class_desc_select(const String &p_select) {
enum_class_name = "@GlobalScope";
enum_name = link;
} else {
const int dot_pos = link.rfind(".");
const int dot_pos = link.rfind_char('.');
if (dot_pos >= 0) {
enum_class_name = link.left(dot_pos);
enum_name = link.substr(dot_pos + 1);
@ -3252,7 +3252,7 @@ EditorHelpBit::HelpData EditorHelpBit::_get_property_help_data(const StringName
enum_class_name = "@GlobalScope";
enum_name = property.enumeration;
} else {
const int dot_pos = property.enumeration.rfind(".");
const int dot_pos = property.enumeration.rfind_char('.');
if (dot_pos >= 0) {
enum_class_name = property.enumeration.left(dot_pos);
enum_name = property.enumeration.substr(dot_pos + 1);
@ -3619,7 +3619,7 @@ void EditorHelpBit::_meta_clicked(const String &p_select) {
enum_class_name = "@GlobalScope";
enum_name = link;
} else {
const int dot_pos = link.rfind(".");
const int dot_pos = link.rfind_char('.');
if (dot_pos >= 0) {
enum_class_name = link.left(dot_pos);
enum_name = link.substr(dot_pos + 1);
@ -3868,7 +3868,7 @@ void EditorHelpBitTooltip::show_tooltip(EditorHelpBit *p_help_bit, Control *p_ta
EditorHelpBitTooltip *tooltip = memnew(EditorHelpBitTooltip(p_target));
p_help_bit->connect("request_hide", callable_mp(tooltip, &EditorHelpBitTooltip::_safe_queue_free));
tooltip->add_child(p_help_bit);
p_target->get_viewport()->add_child(tooltip);
p_target->add_child(tooltip);
p_help_bit->update_content_height();
tooltip->popup_under_cursor();
}

View File

@ -2724,7 +2724,7 @@ void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, EditorIn
for (const EditorInspectorPlugin::AddedEditor &F : ped->added_editors) {
EditorProperty *ep = Object::cast_to<EditorProperty>(F.property_editor);
if (ep && current_favorites.has(F.properties[0])) {
if (ep && !F.properties.is_empty() && current_favorites.has(F.properties[0])) {
ep->favorited = true;
favorites_vbox->add_child(F.property_editor);
} else {
@ -3131,7 +3131,7 @@ void EditorInspector::update_tree() {
if (!array_prefix.is_empty()) {
path = path.trim_prefix(array_prefix);
int char_index = path.find("/");
int char_index = path.find_char('/');
if (char_index >= 0) {
path = path.right(-char_index - 1);
} else {
@ -3171,10 +3171,10 @@ void EditorInspector::update_tree() {
}
// Get the property label's string.
String name_override = (path.contains("/")) ? path.substr(path.rfind("/") + 1) : path;
String name_override = (path.contains("/")) ? path.substr(path.rfind_char('/') + 1) : path;
String feature_tag;
{
const int dot = name_override.find(".");
const int dot = name_override.find_char('.');
if (dot != -1) {
feature_tag = name_override.substr(dot);
name_override = name_override.substr(0, dot);
@ -3189,7 +3189,7 @@ void EditorInspector::update_tree() {
const String property_label_string = EditorPropertyNameProcessor::get_singleton()->process_name(name_override, name_style, p.name, doc_name) + feature_tag;
// Remove the property from the path.
int idx = path.rfind("/");
int idx = path.rfind_char('/');
if (idx > -1) {
path = path.left(idx);
} else {
@ -3320,7 +3320,7 @@ void EditorInspector::update_tree() {
array_element_prefix = class_name_components[0];
editor_inspector_array = memnew(EditorInspectorArray(all_read_only));
String array_label = path.contains("/") ? path.substr(path.rfind("/") + 1) : path;
String array_label = path.contains("/") ? path.substr(path.rfind_char('/') + 1) : path;
array_label = EditorPropertyNameProcessor::get_singleton()->process_name(property_label_string, property_name_style, p.name, doc_name);
int page = per_array_page.has(array_element_prefix) ? per_array_page[array_element_prefix] : 0;
editor_inspector_array->setup_with_move_element_function(object, array_label, array_element_prefix, page, c, use_folding);

View File

@ -253,8 +253,8 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto
// append that to yield "folder/foo.tscn".
if (difference > 0) {
String parent = full_path.substr(0, difference);
int slash_idx = parent.rfind("/");
slash_idx = parent.rfind("/", slash_idx - 1);
int slash_idx = parent.rfind_char('/');
slash_idx = parent.rfind_char('/', slash_idx - 1);
parent = (slash_idx >= 0 && parent.length() > 1) ? parent.substr(slash_idx + 1) : parent;
r_filenames.write[set_idx] = parent + r_filenames[set_idx];
}

View File

@ -463,11 +463,13 @@ void EditorPropertyPath::_set_read_only(bool p_read_only) {
void EditorPropertyPath::_path_selected(const String &p_path) {
String full_path = p_path;
ResourceUID::ID id = ResourceLoader::get_resource_uid(full_path);
if (!global) {
const ResourceUID::ID id = ResourceLoader::get_resource_uid(full_path);
if (id != ResourceUID::INVALID_ID) {
full_path = ResourceUID::get_singleton()->id_to_text(id);
}
}
emit_changed(get_edited_property(), full_path);
update_property();
@ -476,7 +478,7 @@ void EditorPropertyPath::_path_selected(const String &p_path) {
String EditorPropertyPath::_get_path_text() {
String full_path = get_edited_property_value();
if (full_path.begins_with("uid://")) {
full_path = ResourceUID::get_singleton()->get_id_path(ResourceUID::get_singleton()->text_to_id(full_path));
full_path = ResourceUID::uid_to_path(full_path);
}
return full_path;

View File

@ -740,10 +740,10 @@ void EditorPropertyArray::setup(Variant::Type p_array_type, const String &p_hint
// The format of p_hint_string is:
// subType/subTypeHint:nextSubtype ... etc.
if (!p_hint_string.is_empty()) {
int hint_subtype_separator = p_hint_string.find(":");
int hint_subtype_separator = p_hint_string.find_char(':');
if (hint_subtype_separator >= 0) {
String subtype_string = p_hint_string.substr(0, hint_subtype_separator);
int slash_pos = subtype_string.find("/");
int slash_pos = subtype_string.find_char('/');
if (slash_pos >= 0) {
subtype_hint = PropertyHint(subtype_string.substr(slash_pos + 1, subtype_string.size() - slash_pos - 1).to_int());
subtype_string = subtype_string.substr(0, slash_pos);
@ -1006,10 +1006,10 @@ void EditorPropertyDictionary::setup(PropertyHint p_hint, const String &p_hint_s
PackedStringArray types = p_hint_string.split(";");
if (types.size() > 0 && !types[0].is_empty()) {
String key = types[0];
int hint_key_subtype_separator = key.find(":");
int hint_key_subtype_separator = key.find_char(':');
if (hint_key_subtype_separator >= 0) {
String key_subtype_string = key.substr(0, hint_key_subtype_separator);
int slash_pos = key_subtype_string.find("/");
int slash_pos = key_subtype_string.find_char('/');
if (slash_pos >= 0) {
key_subtype_hint = PropertyHint(key_subtype_string.substr(slash_pos + 1, key_subtype_string.size() - slash_pos - 1).to_int());
key_subtype_string = key_subtype_string.substr(0, slash_pos);
@ -1025,10 +1025,10 @@ void EditorPropertyDictionary::setup(PropertyHint p_hint, const String &p_hint_s
}
if (types.size() > 1 && !types[1].is_empty()) {
String value = types[1];
int hint_value_subtype_separator = value.find(":");
int hint_value_subtype_separator = value.find_char(':');
if (hint_value_subtype_separator >= 0) {
String value_subtype_string = value.substr(0, hint_value_subtype_separator);
int slash_pos = value_subtype_string.find("/");
int slash_pos = value_subtype_string.find_char('/');
if (slash_pos >= 0) {
value_subtype_hint = PropertyHint(value_subtype_string.substr(slash_pos + 1, value_subtype_string.size() - slash_pos - 1).to_int());
value_subtype_string = value_subtype_string.substr(0, slash_pos);
@ -1173,6 +1173,11 @@ void EditorPropertyDictionary::update_property() {
new_prop->set_h_size_flags(SIZE_EXPAND_FILL);
new_prop->set_read_only(is_read_only());
slot.set_prop(new_prop);
} else if (slot.index != EditorPropertyDictionaryObject::NEW_KEY_INDEX && slot.index != EditorPropertyDictionaryObject::NEW_VALUE_INDEX) {
Variant key = dict.get_key_at_index(slot.index);
String cs = key.get_construct_string();
slot.prop->set_label(cs);
slot.prop->set_tooltip_text(cs);
}
// We need to grab the focus of the property that is being changed, even if the type didn't actually changed.
@ -1200,7 +1205,8 @@ void EditorPropertyDictionary::update_property() {
void EditorPropertyDictionary::_remove_pressed(int p_slot_index) {
Dictionary dict = object->get_dict().duplicate();
dict.erase(dict.get_key_at_index(p_slot_index));
int index = slots[p_slot_index].index;
dict.erase(dict.get_key_at_index(index));
emit_changed(get_edited_property(), dict);
}

View File

@ -96,7 +96,7 @@ class SectionedInspectorFilter : public Object {
List<PropertyInfo> pinfo;
edited->get_property_list(&pinfo);
for (PropertyInfo &pi : pinfo) {
int sp = pi.name.find("/");
int sp = pi.name.find_char('/');
if (pi.name == "resource_path" || pi.name == "resource_name" || pi.name == "resource_local_to_scene" || pi.name.begins_with("script/") || pi.name.begins_with("_global_script")) { //skip resource stuff
continue;
@ -255,7 +255,7 @@ void SectionedInspector::update_category_list() {
continue;
}
int sp = pi.name.find("/");
int sp = pi.name.find_char('/');
if (sp == -1) {
pi.name = "global/" + pi.name;
}

View File

@ -31,7 +31,6 @@
#include "editor_translation_parser.h"
#include "core/error/error_macros.h"
#include "core/io/file_access.h"
#include "core/object/script_language.h"
#include "core/templates/hash_set.h"
@ -65,6 +64,21 @@ Error EditorTranslationParserPlugin::parse_file(const String &p_path, Vector<Str
}
}
void EditorTranslationParserPlugin::get_comments(Vector<String> *r_ids_comment, Vector<String> *r_ids_ctx_plural_comment) {
TypedArray<String> ids_comment;
TypedArray<String> ids_ctx_plural_comment;
if (GDVIRTUAL_CALL(_get_comments, ids_comment, ids_ctx_plural_comment)) {
for (int i = 0; i < ids_comment.size(); i++) {
r_ids_comment->append(ids_comment[i]);
}
for (int i = 0; i < ids_ctx_plural_comment.size(); i++) {
r_ids_ctx_plural_comment->append(ids_ctx_plural_comment[i]);
}
}
}
void EditorTranslationParserPlugin::get_recognized_extensions(List<String> *r_extensions) const {
Vector<String> extensions;
if (GDVIRTUAL_CALL(_get_recognized_extensions, extensions)) {
@ -78,6 +92,7 @@ void EditorTranslationParserPlugin::get_recognized_extensions(List<String> *r_ex
void EditorTranslationParserPlugin::_bind_methods() {
GDVIRTUAL_BIND(_parse_file, "path", "msgids", "msgids_context_plural");
GDVIRTUAL_BIND(_get_comments, "msgids_comment", "msgids_context_plural_comment");
GDVIRTUAL_BIND(_get_recognized_extensions);
}

View File

@ -43,10 +43,12 @@ protected:
static void _bind_methods();
GDVIRTUAL3(_parse_file, String, TypedArray<String>, TypedArray<Array>)
GDVIRTUAL2(_get_comments, TypedArray<String>, TypedArray<String>)
GDVIRTUAL0RC(Vector<String>, _get_recognized_extensions)
public:
virtual Error parse_file(const String &p_path, Vector<String> *r_ids, Vector<Vector<String>> *r_ids_ctx_plural);
virtual void get_comments(Vector<String> *r_ids_comment, Vector<String> *r_ids_ctx_plural_comment);
virtual void get_recognized_extensions(List<String> *r_extensions) const;
};

View File

@ -240,8 +240,8 @@ EngineUpdateLabel::VersionType EngineUpdateLabel::_get_version_type(const String
}
String EngineUpdateLabel::_extract_sub_string(const String &p_line) const {
int j = p_line.find("\"") + 1;
return p_line.substr(j, p_line.find("\"", j) - j);
int j = p_line.find_char('"') + 1;
return p_line.substr(j, p_line.find_char('"', j) - j);
}
void EngineUpdateLabel::_notification(int p_what) {

View File

@ -121,7 +121,7 @@ String EventListenerLineEdit::get_event_text(const Ref<InputEvent> &p_event, boo
}
String EventListenerLineEdit::get_device_string(int p_device) {
if (p_device == InputEvent::DEVICE_ID_ALL_DEVICES) {
if (p_device == InputMap::ALL_DEVICES) {
return TTR("All Devices");
}
return TTR("Device") + " " + itos(p_device);

View File

@ -1206,6 +1206,9 @@ void ProjectExportDialog::_export_pck_zip_selected(const String &p_path) {
bool export_debug = fd_option.get(TTR("Export With Debug"), true);
bool export_as_patch = fd_option.get(TTR("Export As Patch"), true);
EditorSettings::get_singleton()->set_project_metadata("export_options", "export_debug", export_debug);
EditorSettings::get_singleton()->set_project_metadata("export_options", "export_as_patch", export_as_patch);
if (p_path.ends_with(".zip")) {
if (export_as_patch) {
platform->export_zip_patch(current, export_debug, p_path);
@ -1305,6 +1308,8 @@ void ProjectExportDialog::_export_project_to_path(const String &p_path) {
Dictionary fd_option = export_project->get_selected_options();
bool export_debug = fd_option.get(TTR("Export With Debug"), true);
EditorSettings::get_singleton()->set_project_metadata("export_options", "export_debug", export_debug);
Error err = platform->export_project(current, export_debug, current->get_export_path(), 0);
result_dialog_log->clear();
if (err != ERR_SKIP) {
@ -1774,9 +1779,9 @@ ProjectExportDialog::ProjectExportDialog() {
export_project->connect("file_selected", callable_mp(this, &ProjectExportDialog::_export_project_to_path));
export_project->get_line_edit()->connect(SceneStringName(text_changed), callable_mp(this, &ProjectExportDialog::_validate_export_path));
export_project->add_option(TTR("Export With Debug"), Vector<String>(), true);
export_pck_zip->add_option(TTR("Export With Debug"), Vector<String>(), true);
export_pck_zip->add_option(TTR("Export As Patch"), Vector<String>(), true);
export_project->add_option(TTR("Export With Debug"), Vector<String>(), EditorSettings::get_singleton()->get_project_metadata("export_options", "export_debug", true));
export_pck_zip->add_option(TTR("Export With Debug"), Vector<String>(), EditorSettings::get_singleton()->get_project_metadata("export_options", "export_debug", true));
export_pck_zip->add_option(TTR("Export As Patch"), Vector<String>(), EditorSettings::get_singleton()->get_project_metadata("export_options", "export_as_patch", true));
set_hide_on_ok(false);

View File

@ -137,7 +137,7 @@ bool FileSystemList::edit_selected() {
String name = get_item_text(s);
line_editor->set_text(name);
line_editor->select(0, name.rfind("."));
line_editor->select(0, name.rfind_char('.'));
popup_edit_commited = false; // Start edit popup processing.
popup_editor->popup();
@ -2432,7 +2432,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
if (to_rename.is_file) {
String name = to_rename.path.get_file();
tree->set_editor_selection(0, name.rfind("."));
tree->set_editor_selection(0, name.rfind_char('.'));
} else {
String name = to_rename.path.left(-1).get_file(); // Removes the "/" suffix for folders.
tree->set_editor_selection(0, name.length());
@ -3658,10 +3658,10 @@ void FileSystemDock::_file_list_gui_input(Ref<InputEvent> p_event) {
tree_item->select(0);
} else {
// Find parent folder.
fpath = fpath.substr(0, fpath.rfind("/") + 1);
fpath = fpath.substr(0, fpath.rfind_char('/') + 1);
if (fpath.size() > String("res://").size()) {
fpath = fpath.left(fpath.size() - 2); // Remove last '/'.
const int slash_idx = fpath.rfind("/");
const int slash_idx = fpath.rfind_char('/');
fpath = fpath.substr(slash_idx + 1, fpath.size() - slash_idx - 1);
}

View File

@ -65,7 +65,7 @@ void EditorFileDialog::_native_popup() {
} else if (access == ACCESS_USERDATA) {
root = OS::get_singleton()->get_user_data_dir();
}
DisplayServer::get_singleton()->file_dialog_with_options_show(get_translated_title(), ProjectSettings::get_singleton()->globalize_path(dir->get_text()), root, file->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), filters, _get_options(), callable_mp(this, &EditorFileDialog::_native_dialog_cb));
DisplayServer::get_singleton()->file_dialog_with_options_show(get_translated_title(), ProjectSettings::get_singleton()->globalize_path(dir->get_text()), root, file->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), processed_filters, _get_options(), callable_mp(this, &EditorFileDialog::_native_dialog_cb));
}
void EditorFileDialog::popup(const Rect2i &p_rect) {
@ -156,7 +156,7 @@ void EditorFileDialog::popup_file_dialog() {
}
void EditorFileDialog::_focus_file_text() {
int lp = file->get_text().rfind(".");
int lp = file->get_text().rfind_char('.');
if (lp != -1) {
file->select(0, lp);
file->grab_focus();
@ -1148,37 +1148,54 @@ void EditorFileDialog::_filter_selected(int) {
void EditorFileDialog::update_filters() {
filter->clear();
processed_filters.clear();
if (filters.size() > 1) {
String all_filters;
String all_filters_full;
const int max_filters = 5;
for (int i = 0; i < MIN(max_filters, filters.size()); i++) {
String flt = filters[i].get_slice(";", 0).strip_edges();
String flt = filters[i].get_slicec(';', 0).strip_edges();
if (i > 0) {
all_filters += ", ";
}
all_filters += flt;
}
for (int i = 0; i < filters.size(); i++) {
String flt = filters[i].get_slicec(';', 0).strip_edges();
if (i > 0) {
all_filters_full += ",";
}
all_filters_full += flt;
}
if (max_filters < filters.size()) {
all_filters += ", ...";
}
filter->add_item(TTR("All Recognized") + " (" + all_filters + ")");
String f = TTR("All Recognized") + " (" + all_filters + ")";
filter->add_item(f);
processed_filters.push_back(all_filters_full + ";" + f);
}
for (int i = 0; i < filters.size(); i++) {
String flt = filters[i].get_slice(";", 0).strip_edges();
String flt = filters[i].get_slicec(';', 0).strip_edges();
String desc = filters[i].get_slice(";", 1).strip_edges();
if (desc.length()) {
filter->add_item(desc + " (" + flt + ")");
String f = desc + " (" + flt + ")";
filter->add_item(f);
processed_filters.push_back(flt + ";" + f);
} else {
filter->add_item("(" + flt + ")");
String f = "(" + flt + ")";
filter->add_item(f);
processed_filters.push_back(flt + ";" + f);
}
}
filter->add_item(TTR("All Files (*)"));
String f = TTR("All Files (*)");
filter->add_item(f);
processed_filters.push_back("*.*;" + f);
}
void EditorFileDialog::clear_filters() {
@ -1246,7 +1263,7 @@ void EditorFileDialog::set_current_path(const String &p_path) {
if (!p_path.size()) {
return;
}
int pos = MAX(p_path.rfind("/"), p_path.rfind("\\"));
int pos = MAX(p_path.rfind_char('/'), p_path.rfind_char('\\'));
if (pos == -1) {
set_current_file(p_path);
} else {

View File

@ -145,6 +145,7 @@ private:
void _push_history();
Vector<String> filters;
Vector<String> processed_filters;
bool previews_enabled = true;
bool preview_waiting = false;

View File

@ -67,6 +67,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
} else {
set_value(get_value() - get_step());
}
emit_signal("updown_pressed");
return;
}
_grab_start();
@ -696,6 +697,7 @@ void EditorSpinSlider::_bind_methods() {
ADD_SIGNAL(MethodInfo("grabbed"));
ADD_SIGNAL(MethodInfo("ungrabbed"));
ADD_SIGNAL(MethodInfo("updown_pressed"));
ADD_SIGNAL(MethodInfo("value_focus_entered"));
ADD_SIGNAL(MethodInfo("value_focus_exited"));

View File

@ -199,7 +199,7 @@ Error ResourceImporterImageFont::import(ResourceUID::ID p_source_id, const Strin
case STEP_OFF_Y_BEGIN: {
// Read advance and offset.
if (range[c] == ' ') {
int next = range.find(" ", c + 1);
int next = range.find_char(' ', c + 1);
if (next < c) {
next = range.length();
}

View File

@ -590,7 +590,7 @@ Error ResourceImporterTexture::import(ResourceUID::ID p_source_id, const String
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
const Color color = target_image->get_pixel(i, j);
target_image->set_pixel(i, j, Color(color.r, 1 - color.g, color.b));
target_image->set_pixel(i, j, Color(color.r, 1 - color.g, color.b, color.a));
}
}
}

View File

@ -551,18 +551,18 @@ void InputEventConfigurationDialog::_input_list_item_selected() {
}
void InputEventConfigurationDialog::_device_selection_changed(int p_option_button_index) {
// Option index 0 corresponds to "All Devices" (value of -3).
// Otherwise subtract 1 as option index 1 corresponds to device 0, etc...
event->set_device(p_option_button_index == 0 ? InputEvent::DEVICE_ID_ALL_DEVICES : p_option_button_index - 1);
// Subtract 1 as option index 0 corresponds to "All Devices" (value of -1)
// and option index 1 corresponds to device 0, etc...
event->set_device(p_option_button_index - 1);
event_as_text->set_text(EventListenerLineEdit::get_event_text(event, true));
}
void InputEventConfigurationDialog::_set_current_device(int p_device) {
device_id_option->select(p_device == InputEvent::DEVICE_ID_ALL_DEVICES ? 0 : p_device + 1);
device_id_option->select(p_device + 1);
}
int InputEventConfigurationDialog::_get_current_device() const {
return device_id_option->get_selected() == 0 ? InputEvent::DEVICE_ID_ALL_DEVICES : device_id_option->get_selected() - 1;
return device_id_option->get_selected() - 1;
}
void InputEventConfigurationDialog::_notification(int p_what) {
@ -705,12 +705,11 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() {
device_id_option = memnew(OptionButton);
device_id_option->set_h_size_flags(Control::SIZE_EXPAND_FILL);
device_id_option->add_item(EventListenerLineEdit::get_device_string(InputEvent::DEVICE_ID_ALL_DEVICES));
for (int i = 0; i < 8; i++) {
for (int i = -1; i < 8; i++) {
device_id_option->add_item(EventListenerLineEdit::get_device_string(i));
}
device_id_option->connect(SceneStringName(item_selected), callable_mp(this, &InputEventConfigurationDialog::_device_selection_changed));
_set_current_device(InputEvent::DEVICE_ID_ALL_DEVICES);
_set_current_device(InputMap::ALL_DEVICES);
device_container->add_child(device_id_option);
device_container->hide();

View File

@ -441,7 +441,7 @@ void LocalizationEditor::_filesystem_files_moved(const String &p_old_file, const
bool remapped_files_updated = false;
for (int j = 0; j < remapped_files.size(); j++) {
int splitter_pos = remapped_files[j].rfind(":");
int splitter_pos = remapped_files[j].rfind_char(':');
String res_path = remapped_files[j].substr(0, splitter_pos);
if (res_path == p_old_file) {
@ -482,7 +482,7 @@ void LocalizationEditor::_filesystem_file_removed(const String &p_file) {
for (int i = 0; i < remap_keys.size() && !remaps_changed; i++) {
PackedStringArray remapped_files = remaps[remap_keys[i]];
for (int j = 0; j < remapped_files.size() && !remaps_changed; j++) {
int splitter_pos = remapped_files[j].rfind(":");
int splitter_pos = remapped_files[j].rfind_char(':');
String res_path = remapped_files[j].substr(0, splitter_pos);
remaps_changed = p_file == res_path;
if (remaps_changed) {
@ -567,7 +567,7 @@ void LocalizationEditor::update_translations() {
PackedStringArray selected = remaps[keys[i]];
for (int j = 0; j < selected.size(); j++) {
const String &s2 = selected[j];
int qp = s2.rfind(":");
int qp = s2.rfind_char(':');
String path = s2.substr(0, qp);
String locale = s2.substr(qp + 1, s2.length());

View File

@ -907,7 +907,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons
for (int i = 0; i < headers.size(); i++) {
if (headers[i].findn("ETag:") == 0) { // Save etag
String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().path_join("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
String new_etag = headers[i].substr(headers[i].find(":") + 1, headers[i].length()).strip_edges();
String new_etag = headers[i].substr(headers[i].find_char(':') + 1, headers[i].length()).strip_edges();
Ref<FileAccess> file = FileAccess::open(cache_filename_base + ".etag", FileAccess::WRITE);
if (file.is_valid()) {
file->store_line(new_etag);

View File

@ -93,10 +93,14 @@ void LightmapGIEditorPlugin::_bake_select_file(const String &p_file) {
file_dialog->popup_file_dialog();
} break;
case LightmapGI::BAKE_ERROR_NO_MESHES: {
EditorNode::get_singleton()->show_warning(TTR("No meshes to bake. Make sure they contain an UV2 channel and that the 'Bake Light' flag is on."));
EditorNode::get_singleton()->show_warning(
TTR("No meshes with lightmapping support to bake. Make sure they contain UV2 data and their Global Illumination property is set to Static.") +
String::utf8("\n\n") + TTR("To import a scene with lightmapping support, set Meshes > Light Baking to Static Lightmaps in the Import dock.") +
String::utf8("\n") + TTR("To enable lightmapping support on a primitive mesh, edit the PrimitiveMesh resource in the inspector and check Add UV2.") +
String::utf8("\n") + TTR("To enable lightmapping support on a CSG mesh, select the root CSG node and choose CSG > Bake Mesh Instance at the top of the 3D editor viewport.\nSelect the generated MeshInstance3D node and choose Mesh > Unwrap UV2 for Lightmap/AO at the top of the 3D editor viewport."));
} break;
case LightmapGI::BAKE_ERROR_CANT_CREATE_IMAGE: {
EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images, make sure path is writable."));
EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images. Make sure the lightmap destination path is writable."));
} break;
case LightmapGI::BAKE_ERROR_NO_SCENE_ROOT: {
EditorNode::get_singleton()->show_warning(TTR("No editor scene root found."));
@ -108,7 +112,7 @@ void LightmapGIEditorPlugin::_bake_select_file(const String &p_file) {
EditorNode::get_singleton()->show_warning(TTR("Maximum texture size is too small for the lightmap images.\nWhile this can be fixed by increasing the maximum texture size, it is recommended you split the scene into more objects instead."));
} break;
case LightmapGI::BAKE_ERROR_LIGHTMAP_TOO_SMALL: {
EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images. Make sure all meshes selected to bake have `lightmap_size_hint` value set high enough, and `texel_scale` value of LightmapGI is not too low."));
EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images. Make sure all meshes to bake have the Lightmap Size Hint property set high enough, and the LightmapGI's Texel Scale value is not too low."));
} break;
case LightmapGI::BAKE_ERROR_ATLAS_TOO_SMALL: {
EditorNode::get_singleton()->show_warning(TTR("Failed fitting a lightmap image into an atlas. This should never happen and should be reported."));

View File

@ -69,8 +69,10 @@ void NavigationObstacle3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
float height = obstacle->get_height();
Basis gbi = obstacle->get_global_basis().inverse();
const Basis safe_basis = Basis(Vector3(0.0, 1.0, 0.0), obstacle->get_global_rotation().y, obstacle->get_global_basis().get_scale().abs().maxf(0.001));
const Basis gbi = obstacle->get_global_basis().inverse();
const Basis safe_global_basis = gbi * safe_basis;
const int vertex_count = vertices.size();
Vector<Vector3> lines_mesh_vertices;
@ -83,21 +85,22 @@ void NavigationObstacle3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Vector3 point = vertices[i];
Vector3 next_point = vertices[(i + 1) % vertex_count];
Vector3 direction = next_point.direction_to(point);
Vector3 direction = safe_basis.xform(next_point.direction_to(point));
Vector3 arrow_dir = direction.cross(Vector3(0.0, 1.0, 0.0));
Vector3 edge_middle = point + ((next_point - point) * 0.5);
lines_mesh_vertices_ptrw[vertex_index++] = gbi.xform(edge_middle);
lines_mesh_vertices_ptrw[vertex_index++] = gbi.xform(edge_middle + (arrow_dir * 0.5));
// Ensure vector stays perpendicular even when scaled non-uniformly.
lines_mesh_vertices_ptrw[vertex_index++] = safe_global_basis.xform(edge_middle);
lines_mesh_vertices_ptrw[vertex_index++] = safe_global_basis.xform(edge_middle) + gbi.xform(arrow_dir) * 0.5;
lines_mesh_vertices_ptrw[vertex_index++] = gbi.xform(point);
lines_mesh_vertices_ptrw[vertex_index++] = gbi.xform(next_point);
lines_mesh_vertices_ptrw[vertex_index++] = safe_global_basis.xform(point);
lines_mesh_vertices_ptrw[vertex_index++] = safe_global_basis.xform(next_point);
lines_mesh_vertices_ptrw[vertex_index++] = gbi.xform(Vector3(point.x, height, point.z));
lines_mesh_vertices_ptrw[vertex_index++] = gbi.xform(Vector3(next_point.x, height, next_point.z));
lines_mesh_vertices_ptrw[vertex_index++] = safe_global_basis.xform(Vector3(point.x, height, point.z));
lines_mesh_vertices_ptrw[vertex_index++] = safe_global_basis.xform(Vector3(next_point.x, height, next_point.z));
lines_mesh_vertices_ptrw[vertex_index++] = gbi.xform(point);
lines_mesh_vertices_ptrw[vertex_index++] = gbi.xform(Vector3(point.x, height, point.z));
lines_mesh_vertices_ptrw[vertex_index++] = safe_global_basis.xform(point);
lines_mesh_vertices_ptrw[vertex_index++] = safe_global_basis.xform(Vector3(point.x, height, point.z));
}
Vector<Vector2> polygon_2d_vertices;
@ -138,7 +141,8 @@ int NavigationObstacle3DGizmoPlugin::subgizmos_intersect_ray(const EditorNode3DG
NavigationObstacle3D *obstacle_node = Object::cast_to<NavigationObstacle3D>(p_gizmo->get_node_3d());
ERR_FAIL_NULL_V(obstacle_node, -1);
Transform3D gt = Transform3D(Basis(), obstacle_node->get_global_position());
const Vector3 safe_scale = obstacle_node->get_global_basis().get_scale().abs().maxf(0.001);
const Transform3D gt = Transform3D(Basis().scaled(safe_scale).rotated(Vector3(0.0, 1.0, 0.0), obstacle_node->get_global_rotation().y), obstacle_node->get_global_position());
const Vector<Vector3> &vertices = obstacle_node->get_vertices();
for (int idx = 0; idx < vertices.size(); ++idx) {
@ -160,7 +164,8 @@ Vector<int> NavigationObstacle3DGizmoPlugin::subgizmos_intersect_frustum(const E
NavigationObstacle3D *obstacle_node = Object::cast_to<NavigationObstacle3D>(p_gizmo->get_node_3d());
ERR_FAIL_NULL_V(obstacle_node, contained_points);
Transform3D gt = Transform3D(Basis(), obstacle_node->get_global_position());
const Vector3 safe_scale = obstacle_node->get_global_basis().get_scale().abs().maxf(0.001);
const Transform3D gt = Transform3D(Basis().scaled(safe_scale).rotated(Vector3(0.0, 1.0, 0.0), obstacle_node->get_global_rotation().y), obstacle_node->get_global_position());
const Vector<Vector3> &vertices = obstacle_node->get_vertices();
for (int idx = 0; idx < vertices.size(); ++idx) {
@ -188,9 +193,8 @@ Transform3D NavigationObstacle3DGizmoPlugin::get_subgizmo_transform(const Editor
const Vector<Vector3> &vertices = obstacle_node->get_vertices();
ERR_FAIL_INDEX_V(p_id, vertices.size(), Transform3D());
Basis gbi = obstacle_node->get_global_basis().inverse();
Transform3D subgizmo_transform = Transform3D(Basis(), gbi.xform(vertices[p_id]));
const Basis safe_basis_inverse = Basis(Vector3(0.0, 1.0, 0.0), obstacle_node->get_global_rotation().y, obstacle_node->get_global_basis().get_scale().abs().maxf(0.001)).inverse();
Transform3D subgizmo_transform = Transform3D(Basis(), safe_basis_inverse.xform(vertices[p_id]));
return subgizmo_transform;
}
@ -198,14 +202,13 @@ void NavigationObstacle3DGizmoPlugin::set_subgizmo_transform(const EditorNode3DG
NavigationObstacle3D *obstacle_node = Object::cast_to<NavigationObstacle3D>(p_gizmo->get_node_3d());
ERR_FAIL_NULL(obstacle_node);
Basis gb = obstacle_node->get_global_basis();
const Basis safe_basis = Basis(Vector3(0.0, 1.0, 0.0), obstacle_node->get_global_rotation().y, obstacle_node->get_global_basis().get_scale().abs().maxf(0.001));
Vector3 new_vertex_pos = p_transform.origin;
Vector<Vector3> vertices = obstacle_node->get_vertices();
ERR_FAIL_INDEX(p_id, vertices.size());
Vector3 vertex = gb.xform(new_vertex_pos);
Vector3 vertex = safe_basis.xform(new_vertex_pos);
vertex.y = 0.0;
vertices.write[p_id] = vertex;
@ -216,14 +219,14 @@ void NavigationObstacle3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *
NavigationObstacle3D *obstacle_node = Object::cast_to<NavigationObstacle3D>(p_gizmo->get_node_3d());
ERR_FAIL_NULL(obstacle_node);
Basis gb = obstacle_node->get_global_basis();
const Basis safe_basis = Basis(Vector3(0.0, 1.0, 0.0), obstacle_node->get_global_rotation().y, obstacle_node->get_global_basis().get_scale().abs().maxf(0.001));
Vector<Vector3> vertices = obstacle_node->get_vertices();
Vector<Vector3> restore_vertices = vertices;
for (int i = 0; i < p_ids.size(); ++i) {
const int idx = p_ids[i];
Vector3 vertex = gb.xform(p_restore[i].origin);
Vector3 vertex = safe_basis.xform(p_restore[i].origin);
vertex.y = 0.0;
restore_vertices.write[idx] = vertex;
}
@ -446,7 +449,8 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditorPlugin::forward_3d_gui_inp
Vector3 ray_from = p_camera->project_ray_origin(mouse_position);
Vector3 ray_dir = p_camera->project_ray_normal(mouse_position);
Transform3D gt = Transform3D(Basis(), obstacle_node->get_global_position());
const Vector3 safe_scale = obstacle_node->get_global_basis().get_scale().abs().maxf(0.001);
const Transform3D gt = Transform3D(Basis().scaled(safe_scale).rotated(Vector3(0.0, 1.0, 0.0), obstacle_node->get_global_rotation().y), obstacle_node->get_global_position());
Transform3D gi = gt.affine_inverse();
Plane projection_plane(Vector3(0.0, 1.0, 0.0), gt.origin);
@ -666,7 +670,8 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditorPlugin::forward_3d_gui_inp
Vector3 ray_from = p_camera->project_ray_origin(mouse_position);
Vector3 ray_dir = p_camera->project_ray_normal(mouse_position);
Transform3D gt = Transform3D(Basis(), obstacle_node->get_global_position());
const Vector3 safe_scale = obstacle_node->get_global_basis().get_scale().abs().maxf(0.001);
const Transform3D gt = Transform3D(Basis().scaled(safe_scale).rotated(Vector3(0.0, 1.0, 0.0), obstacle_node->get_global_rotation().y), obstacle_node->get_global_position());
Transform3D gi = gt.affine_inverse();
Plane projection_plane(Vector3(0.0, 1.0, 0.0), gt.origin);
@ -762,7 +767,9 @@ void NavigationObstacle3DEditorPlugin::redraw() {
rs->mesh_add_surface_from_arrays(point_lines_mesh_rid, RS::PRIMITIVE_LINES, point_lines_mesh_array);
rs->instance_set_surface_override_material(point_lines_instance_rid, 0, line_material->get_rid());
rs->instance_set_transform(point_lines_instance_rid, Transform3D(Basis(), obstacle_node->get_global_position()));
const Vector3 safe_scale = obstacle_node->get_global_basis().get_scale().abs().maxf(0.001);
const Transform3D gt = Transform3D(Basis().scaled(safe_scale).rotated(Vector3(0.0, 1.0, 0.0), obstacle_node->get_global_rotation().y), obstacle_node->get_global_position());
rs->instance_set_transform(point_lines_instance_rid, gt);
Array point_handle_mesh_array;
point_handle_mesh_array.resize(Mesh::ARRAY_MAX);
@ -787,7 +794,7 @@ void NavigationObstacle3DEditorPlugin::redraw() {
rs->mesh_add_surface_from_arrays(point_handle_mesh_rid, RS::PRIMITIVE_POINTS, point_handle_mesh_array);
rs->instance_set_surface_override_material(point_handles_instance_rid, 0, handle_material->get_rid());
rs->instance_set_transform(point_handles_instance_rid, Transform3D(Basis(), obstacle_node->get_global_position()));
rs->instance_set_transform(point_handles_instance_rid, gt);
}
NavigationObstacle3DEditorPlugin *NavigationObstacle3DEditorPlugin::singleton = nullptr;

View File

@ -277,8 +277,15 @@ void Path3DGizmo::redraw() {
Ref<StandardMaterial3D> path_tilt_material = gizmo_plugin->get_material("path_tilt_material", this);
Ref<StandardMaterial3D> path_tilt_muted_material = gizmo_plugin->get_material("path_tilt_muted_material", this);
Ref<StandardMaterial3D> handles_material = gizmo_plugin->get_material("handles");
Ref<StandardMaterial3D> first_pt_handle_material = gizmo_plugin->get_material("first_pt_handle");
Ref<StandardMaterial3D> last_pt_handle_material = gizmo_plugin->get_material("last_pt_handle");
Ref<StandardMaterial3D> closed_pt_handle_material = gizmo_plugin->get_material("closed_pt_handle");
Ref<StandardMaterial3D> sec_handles_material = gizmo_plugin->get_material("sec_handles");
first_pt_handle_material->set_albedo(Color(0.2, 1.0, 0.0));
last_pt_handle_material->set_albedo(Color(1.0, 0.2, 0.0));
closed_pt_handle_material->set_albedo(Color(1.0, 0.8, 0.0));
Ref<Curve3D> c = path->get_curve();
if (c.is_null()) {
return;
@ -369,7 +376,7 @@ void Path3DGizmo::redraw() {
info.point_idx = idx;
// Collect in-handles except for the first point.
if (idx > 0 && Path3DEditorPlugin::singleton->curve_edit_curve->is_pressed()) {
if (idx > (c->is_closed() ? -1 : 0) && Path3DEditorPlugin::singleton->curve_edit_curve->is_pressed()) {
const Vector3 in = c->get_point_in(idx);
info.type = HandleType::HANDLE_TYPE_IN;
@ -383,7 +390,7 @@ void Path3DGizmo::redraw() {
}
// Collect out-handles except for the last point.
if (idx < c->get_point_count() - 1 && Path3DEditorPlugin::singleton->curve_edit_curve->is_pressed()) {
if (idx < (c->is_closed() ? c->get_point_count() : c->get_point_count() - 1) && Path3DEditorPlugin::singleton->curve_edit_curve->is_pressed()) {
const Vector3 out = c->get_point_out(idx);
info.type = HandleType::HANDLE_TYPE_OUT;
@ -441,7 +448,42 @@ void Path3DGizmo::redraw() {
}
if (!Path3DEditorPlugin::singleton->curve_edit->is_pressed() && primary_handle_points.size()) {
add_handles(primary_handle_points, handles_material);
// Need to define indices separately.
// Point count.
const int pc = primary_handle_points.size();
Vector<int> idx;
idx.resize(pc);
int *idx_ptr = idx.ptrw();
for (int j = 0; j < pc; j++) {
idx_ptr[j] = j;
}
// Initialize arrays for first point.
PackedVector3Array first_pt_handle_point;
Vector<int> first_pt_id;
first_pt_handle_point.append(primary_handle_points[0]);
first_pt_id.append(idx[0]);
// Initialize arrays and add handle for last point if needed.
if (pc > 1) {
PackedVector3Array last_pt_handle_point;
Vector<int> last_pt_id;
last_pt_handle_point.append(primary_handle_points[pc - 1]);
last_pt_id.append(idx[pc - 1]);
primary_handle_points.remove_at(pc - 1);
idx.remove_at(pc - 1);
add_handles(last_pt_handle_point, c->is_closed() ? handles_material : last_pt_handle_material, last_pt_id);
}
// Add handle for first point.
primary_handle_points.remove_at(0);
idx.remove_at(0);
add_handles(first_pt_handle_point, c->is_closed() ? closed_pt_handle_material : first_pt_handle_material, first_pt_id);
// Add handles for remaining intermediate points.
if (!primary_handle_points.is_empty()) {
add_handles(primary_handle_points, handles_material, idx);
}
}
if (secondary_handle_points.size()) {
add_handles(secondary_handle_points, sec_handles_material, collected_secondary_handle_ids, false, true);
@ -469,7 +511,7 @@ Path3DGizmo::Path3DGizmo(Path3D *p_path, float p_disk_size) {
Path3DEditorPlugin::singleton->curve_edit_curve->connect(SceneStringName(pressed), callable_mp(this, &Path3DGizmo::redraw));
Path3DEditorPlugin::singleton->curve_create->connect(SceneStringName(pressed), callable_mp(this, &Path3DGizmo::redraw));
Path3DEditorPlugin::singleton->curve_del->connect(SceneStringName(pressed), callable_mp(this, &Path3DGizmo::redraw));
Path3DEditorPlugin::singleton->curve_close->connect(SceneStringName(pressed), callable_mp(this, &Path3DGizmo::redraw));
Path3DEditorPlugin::singleton->curve_closed->connect(SceneStringName(pressed), callable_mp(this, &Path3DGizmo::redraw));
}
EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
@ -696,7 +738,7 @@ void Path3DEditorPlugin::_mode_changed(int p_mode) {
Node3DEditor::get_singleton()->clear_subgizmo_selection();
}
void Path3DEditorPlugin::_close_curve() {
void Path3DEditorPlugin::_toggle_closed_curve() {
Ref<Curve3D> c = path->get_curve();
if (c.is_null()) {
return;
@ -704,13 +746,10 @@ void Path3DEditorPlugin::_close_curve() {
if (c->get_point_count() < 2) {
return;
}
if (c->get_point_position(0) == c->get_point_position(c->get_point_count() - 1)) {
return;
}
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Close Curve"));
ur->add_do_method(c.ptr(), "add_point", c->get_point_position(0), c->get_point_in(0), c->get_point_out(0), -1);
ur->add_undo_method(c.ptr(), "remove_point", c->get_point_count());
ur->create_action(TTR("Toggle Open/Closed Curve"));
ur->add_do_method(c.ptr(), "set_closed", !c.ptr()->is_closed());
ur->add_undo_method(c.ptr(), "set_closed", c.ptr()->is_closed());
ur->commit_action();
}
@ -771,6 +810,7 @@ void Path3DEditorPlugin::_clear_curve_points() {
return;
}
Ref<Curve3D> curve = path->get_curve();
curve->set_closed(false);
curve->clear_points();
}
@ -795,7 +835,7 @@ void Path3DEditorPlugin::_update_theme() {
curve_edit_tilt->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveTilt")));
curve_create->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveCreate")));
curve_del->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveDelete")));
curve_close->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveClose")));
curve_closed->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveClose")));
curve_clear_points->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("Clear")));
create_curve_button->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("Curve3D")));
}
@ -872,12 +912,12 @@ Path3DEditorPlugin::Path3DEditorPlugin() {
toolbar->add_child(curve_del);
curve_del->connect(SceneStringName(pressed), callable_mp(this, &Path3DEditorPlugin::_mode_changed).bind(MODE_DELETE));
curve_close = memnew(Button);
curve_close->set_theme_type_variation("FlatButton");
curve_close->set_focus_mode(Control::FOCUS_NONE);
curve_close->set_tooltip_text(TTR("Close Curve"));
toolbar->add_child(curve_close);
curve_close->connect(SceneStringName(pressed), callable_mp(this, &Path3DEditorPlugin::_close_curve));
curve_closed = memnew(Button);
curve_closed->set_theme_type_variation("FlatButton");
curve_closed->set_focus_mode(Control::FOCUS_NONE);
curve_closed->set_tooltip_text(TTR("Close Curve"));
toolbar->add_child(curve_closed);
curve_closed->connect(SceneStringName(pressed), callable_mp(this, &Path3DEditorPlugin::_toggle_closed_curve));
curve_clear_points = memnew(Button);
curve_clear_points->set_theme_type_variation("FlatButton");
@ -943,6 +983,14 @@ void Path3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Ref<Curve3D> curve = path->get_curve();
Ref<StandardMaterial3D> handle_material = get_material("handles", p_gizmo);
Ref<StandardMaterial3D> first_pt_handle_material = get_material("first_pt_handle", p_gizmo);
Ref<StandardMaterial3D> last_pt_handle_material = get_material("last_pt_handle", p_gizmo);
Ref<StandardMaterial3D> closed_pt_handle_material = get_material("closed_pt_handle", p_gizmo);
first_pt_handle_material->set_albedo(Color(0.2, 1.0, 0.0));
last_pt_handle_material->set_albedo(Color(1.0, 0.2, 0.0));
closed_pt_handle_material->set_albedo(Color(1.0, 0.8, 0.0));
PackedVector3Array handles;
if (Path3DEditorPlugin::singleton->curve_edit->is_pressed()) {
@ -955,9 +1003,39 @@ void Path3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
if (handles.size()) {
// Point count.
const int pc = handles.size();
// Initialize arrays for first point.
PackedVector3Array first_pt;
first_pt.append(handles[0]);
// Initialize arrays and add handle for last point if needed.
if (pc > 1) {
PackedVector3Array last_pt;
last_pt.append(handles[handles.size() - 1]);
handles.remove_at(handles.size() - 1);
if (curve->is_closed()) {
p_gizmo->add_vertices(last_pt, handle_material, Mesh::PRIMITIVE_POINTS);
} else {
p_gizmo->add_vertices(last_pt, last_pt_handle_material, Mesh::PRIMITIVE_POINTS);
}
}
// Add handle for first point.
handles.remove_at(0);
if (curve->is_closed()) {
p_gizmo->add_vertices(first_pt, closed_pt_handle_material, Mesh::PRIMITIVE_POINTS);
} else {
p_gizmo->add_vertices(first_pt, first_pt_handle_material, Mesh::PRIMITIVE_POINTS);
}
// Add handles for remaining intermediate points.
if (!handles.is_empty()) {
p_gizmo->add_vertices(handles, handle_material, Mesh::PRIMITIVE_POINTS);
}
}
}
int Path3DGizmoPlugin::subgizmos_intersect_ray(const EditorNode3DGizmo *p_gizmo, Camera3D *p_camera, const Vector2 &p_point) const {
Path3D *path = Object::cast_to<Path3D>(p_gizmo->get_node_3d());
@ -1072,5 +1150,8 @@ Path3DGizmoPlugin::Path3DGizmoPlugin(float p_disk_size) {
create_material("path_tilt_material", path_tilt_color);
create_material("path_tilt_muted_material", path_tilt_color * 0.7);
create_handle_material("handles", false, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("EditorPathSmoothHandle"), EditorStringName(EditorIcons)));
create_handle_material("first_pt_handle", false, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("EditorPathSmoothHandle"), EditorStringName(EditorIcons)));
create_handle_material("last_pt_handle", false, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("EditorPathSmoothHandle"), EditorStringName(EditorIcons)));
create_handle_material("closed_pt_handle", false, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("EditorPathSmoothHandle"), EditorStringName(EditorIcons)));
create_handle_material("sec_handles", false, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("EditorCurveHandle"), EditorStringName(EditorIcons)));
}

View File

@ -120,7 +120,7 @@ class Path3DEditorPlugin : public EditorPlugin {
Button *curve_edit_curve = nullptr;
Button *curve_edit_tilt = nullptr;
Button *curve_del = nullptr;
Button *curve_close = nullptr;
Button *curve_closed = nullptr;
Button *curve_clear_points = nullptr;
MenuButton *handle_menu = nullptr;
@ -144,7 +144,7 @@ class Path3DEditorPlugin : public EditorPlugin {
void _update_toolbar();
void _mode_changed(int p_mode);
void _close_curve();
void _toggle_closed_curve();
void _handle_option_pressed(int p_option);
bool handle_clicked = false;
bool mirror_handle_angle = true;

View File

@ -282,7 +282,7 @@ void ScriptTextEditor::_warning_clicked(const Variant &p_line) {
CodeEdit *text_editor = code_editor->get_text_editor();
String prev_line = line > 0 ? text_editor->get_line(line - 1) : "";
if (prev_line.contains("@warning_ignore")) {
const int closing_bracket_idx = prev_line.find(")");
const int closing_bracket_idx = prev_line.find_char(')');
const String text_to_insert = ", " + code.quote(quote_style);
text_editor->insert_text(text_to_insert, line - 1, closing_bracket_idx);
} else {
@ -951,7 +951,7 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
} else if (p_symbol.is_resource_file() || p_symbol.begins_with("uid://")) {
String symbol = p_symbol;
if (symbol.begins_with("uid://")) {
symbol = ResourceUID::get_singleton()->get_id_path(ResourceUID::get_singleton()->text_to_id(symbol));
symbol = ResourceUID::uid_to_path(symbol);
}
List<String> scene_extensions;
@ -1205,7 +1205,7 @@ void ScriptTextEditor::_update_connected_methods() {
// Account for inner classes by stripping the class names from the method,
// starting from the right since our inner class might be inside of another inner class.
int pos = raw_name.rfind(".");
int pos = raw_name.rfind_char('.');
if (pos != -1) {
name = raw_name.substr(pos + 1);
}

View File

@ -4125,6 +4125,7 @@ void VisualShaderEditor::_connection_request(const String &p_from, int p_from_in
int from = p_from.to_int();
int to = p_to.to_int();
bool swap = last_to_node != -1 && Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL);
if (!visual_shader->can_connect_nodes(type, from, p_from_index, to, p_to_index)) {
return;
@ -4142,6 +4143,14 @@ void VisualShaderEditor::_connection_request(const String &p_from, int p_from_in
undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
if (swap) {
undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, last_to_node, last_to_port);
undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, last_to_node, last_to_port);
undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, last_to_node, last_to_port);
undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, last_to_node, last_to_port);
}
break;
}
}
@ -4155,6 +4164,9 @@ void VisualShaderEditor::_connection_request(const String &p_from, int p_from_in
undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, to);
undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, to);
undo_redo->commit_action();
last_to_node = -1;
last_to_port = -1;
}
void VisualShaderEditor::_disconnection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) {
@ -4165,6 +4177,11 @@ void VisualShaderEditor::_disconnection_request(const String &p_from, int p_from
int from = p_from.to_int();
int to = p_to.to_int();
last_to_node = to;
last_to_port = p_to_index;
info_label->show();
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Nodes Disconnected"));
undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);
@ -4176,6 +4193,10 @@ void VisualShaderEditor::_disconnection_request(const String &p_from, int p_from
undo_redo->commit_action();
}
void VisualShaderEditor::_connection_drag_ended() {
info_label->hide();
}
void VisualShaderEditor::_connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position) {
from_node = p_from.to_int();
from_slot = p_from_slot;
@ -5080,8 +5101,11 @@ void VisualShaderEditor::_param_property_changed(const String &p_property, const
void VisualShaderEditor::_update_current_param() {
if (current_prop != nullptr) {
String name = current_prop->get_meta("id");
if (visual_shader->_has_preview_shader_parameter(name)) {
preview_material->set("shader_parameter/" + name, visual_shader->_get_preview_shader_parameter(name));
} else {
preview_material->set("shader_parameter/" + name, Variant());
}
current_prop->update_property();
current_prop->update_editor_property_status();
current_prop->update_cache();
@ -6367,6 +6391,7 @@ VisualShaderEditor::VisualShaderEditor() {
graph->connect(SceneStringName(gui_input), callable_mp(this, &VisualShaderEditor::_graph_gui_input));
graph->connect("connection_to_empty", callable_mp(this, &VisualShaderEditor::_connection_to_empty));
graph->connect("connection_from_empty", callable_mp(this, &VisualShaderEditor::_connection_from_empty));
graph->connect("connection_drag_ended", callable_mp(this, &VisualShaderEditor::_connection_drag_ended));
graph->connect(SceneStringName(visibility_changed), callable_mp(this, &VisualShaderEditor::_visibility_changed));
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR_INT);
@ -6427,6 +6452,13 @@ VisualShaderEditor::VisualShaderEditor() {
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShaderNode::PORT_TYPE_TRANSFORM);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SAMPLER, VisualShaderNode::PORT_TYPE_SAMPLER);
info_label = memnew(Label);
info_label->set_text(vformat(TTR("Hold %s Key To Swap Connections"), keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL)));
info_label->set_anchors_and_offsets_preset(Control::PRESET_BOTTOM_WIDE, PRESET_MODE_MINSIZE, 20);
info_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
info_label->hide();
graph->get_top_layer()->add_child(info_label);
PanelContainer *toolbar_panel = static_cast<PanelContainer *>(graph->get_menu_hbox()->get_parent());
toolbar_panel->set_anchors_and_offsets_preset(Control::PRESET_TOP_WIDE, PRESET_MODE_MINSIZE, 10);
toolbar_panel->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);

View File

@ -221,6 +221,10 @@ class VisualShaderEditor : public ShaderEditor {
Button *code_preview_button = nullptr;
Button *shader_preview_button = nullptr;
int last_to_node = -1;
int last_to_port = -1;
Label *info_label = nullptr;
OptionButton *edit_type = nullptr;
OptionButton *edit_type_standard = nullptr;
OptionButton *edit_type_particles = nullptr;
@ -502,6 +506,7 @@ class VisualShaderEditor : public ShaderEditor {
void _unlink_node_from_parent_frame(int p_node_id);
void _connection_drag_ended();
void _connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position);
void _connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position);
bool _check_node_drop_on_connection(const Vector2 &p_position, Ref<GraphEdit::Connection> *r_closest_connection, int *r_node_id = nullptr, int *r_to_port = nullptr);

View File

@ -69,11 +69,16 @@ void POTGenerator::generate_pot(const String &p_file) {
for (int i = 0; i < files.size(); i++) {
Vector<String> msgids;
Vector<Vector<String>> msgids_context_plural;
Vector<String> msgids_comment;
Vector<String> msgids_context_plural_comment;
const String &file_path = files[i];
String file_extension = file_path.get_extension();
if (EditorTranslationParser::get_singleton()->can_parse(file_extension)) {
EditorTranslationParser::get_singleton()->get_parser(file_extension)->parse_file(file_path, &msgids, &msgids_context_plural);
EditorTranslationParser::get_singleton()->get_parser(file_extension)->get_comments(&msgids_comment, &msgids_context_plural_comment);
} else {
ERR_PRINT("Unrecognized file extension " + file_extension + " in generate_pot()");
return;
@ -81,16 +86,18 @@ void POTGenerator::generate_pot(const String &p_file) {
for (int j = 0; j < msgids_context_plural.size(); j++) {
const Vector<String> &entry = msgids_context_plural[j];
_add_new_msgid(entry[0], entry[1], entry[2], file_path);
const String &comment = (j < msgids_context_plural_comment.size()) ? msgids_context_plural_comment[j] : String();
_add_new_msgid(entry[0], entry[1], entry[2], file_path, comment);
}
for (int j = 0; j < msgids.size(); j++) {
_add_new_msgid(msgids[j], "", "", file_path);
const String &comment = (j < msgids_comment.size()) ? msgids_comment[j] : String();
_add_new_msgid(msgids[j], "", "", file_path, comment);
}
}
if (GLOBAL_GET("internationalization/locale/translation_add_builtin_strings_to_pot")) {
for (const Vector<String> &extractable_msgids : get_extractable_message_list()) {
_add_new_msgid(extractable_msgids[0], extractable_msgids[1], extractable_msgids[2], "");
_add_new_msgid(extractable_msgids[0], extractable_msgids[1], extractable_msgids[2], "", "");
}
}
@ -136,16 +143,26 @@ void POTGenerator::_write_to_pot(const String &p_file) {
String context = v_msgid_data[i].ctx;
String plural = v_msgid_data[i].plural;
const HashSet<String> &locations = v_msgid_data[i].locations;
const HashSet<String> &comments = v_msgid_data[i].comments;
// Put the blank line at the start, to avoid a double at the end when closing the file.
file->store_line("");
// Write comments.
bool is_first_comment = true;
for (const String &E : comments) {
if (is_first_comment) {
file->store_line("#. TRANSLATORS: " + E.replace("\n", "\n#. "));
} else {
file->store_line("#. " + E.replace("\n", "\n#. "));
}
is_first_comment = false;
}
// Write file locations.
for (const String &E : locations) {
if (!E.is_empty()) {
file->store_line("#: " + E.trim_prefix("res://").replace("\n", "\\n"));
}
}
// Write context.
if (!context.is_empty()) {
@ -199,7 +216,7 @@ void POTGenerator::_write_msgid(Ref<FileAccess> r_file, const String &p_id, bool
}
}
void POTGenerator::_add_new_msgid(const String &p_msgid, const String &p_context, const String &p_plural, const String &p_location) {
void POTGenerator::_add_new_msgid(const String &p_msgid, const String &p_context, const String &p_plural, const String &p_location, const String &p_comment) {
// Insert new location if msgid under same context exists already.
if (all_translation_strings.has(p_msgid)) {
Vector<MsgidData> &v_mdata = all_translation_strings[p_msgid];
@ -208,18 +225,27 @@ void POTGenerator::_add_new_msgid(const String &p_msgid, const String &p_context
if (!v_mdata[i].plural.is_empty() && !p_plural.is_empty() && v_mdata[i].plural != p_plural) {
WARN_PRINT("Redefinition of plural message (msgid_plural), under the same message (msgid) and context (msgctxt)");
}
if (!p_location.is_empty()) {
v_mdata.write[i].locations.insert(p_location);
}
if (!p_comment.is_empty()) {
v_mdata.write[i].comments.insert(p_comment);
}
return;
}
}
}
// Add a new entry of msgid, context, plural and location - context and plural might be empty if the inserted msgid doesn't associated
// context or plurals.
// Add a new entry.
MsgidData mdata;
mdata.ctx = p_context;
mdata.plural = p_plural;
if (!p_location.is_empty()) {
mdata.locations.insert(p_location);
}
if (!p_comment.is_empty()) {
mdata.comments.insert(p_comment);
}
all_translation_strings[p_msgid].push_back(mdata);
}

Some files were not shown because too many files have changed in this diff Show More