Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/editor/run/editor_run.cpp
9902 views
1
/**************************************************************************/
2
/* editor_run.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "editor_run.h"
32
33
#include "core/config/project_settings.h"
34
#include "editor/debugger/editor_debugger_node.h"
35
#include "editor/editor_node.h"
36
#include "editor/run/run_instances_dialog.h"
37
#include "editor/settings/editor_settings.h"
38
#include "main/main.h"
39
#include "servers/display_server.h"
40
41
EditorRun::Status EditorRun::get_status() const {
42
return status;
43
}
44
45
String EditorRun::get_running_scene() const {
46
return running_scene;
47
}
48
49
Error EditorRun::run(const String &p_scene, const String &p_write_movie, const Vector<String> &p_run_args) {
50
List<String> args;
51
52
for (const String &a : Main::get_forwardable_cli_arguments(Main::CLI_SCOPE_PROJECT)) {
53
args.push_back(a);
54
}
55
56
String resource_path = ProjectSettings::get_singleton()->get_resource_path();
57
if (!resource_path.is_empty()) {
58
args.push_back("--path");
59
args.push_back(resource_path.replace(" ", "%20"));
60
}
61
62
const String debug_uri = EditorDebuggerNode::get_singleton()->get_server_uri();
63
if (debug_uri.size()) {
64
args.push_back("--remote-debug");
65
args.push_back(debug_uri);
66
}
67
68
args.push_back("--editor-pid");
69
args.push_back(itos(OS::get_singleton()->get_process_id()));
70
71
bool debug_collisions = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_collisions", false);
72
bool debug_paths = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_paths", false);
73
bool debug_navigation = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_navigation", false);
74
bool debug_avoidance = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_avoidance", false);
75
bool debug_canvas_redraw = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_canvas_redraw", false);
76
bool debug_mute_audio = EditorDebuggerNode::get_singleton()->get_debug_mute_audio();
77
78
if (debug_collisions) {
79
args.push_back("--debug-collisions");
80
}
81
82
if (debug_paths) {
83
args.push_back("--debug-paths");
84
}
85
86
if (debug_navigation) {
87
args.push_back("--debug-navigation");
88
}
89
90
if (debug_avoidance) {
91
args.push_back("--debug-avoidance");
92
}
93
94
if (debug_canvas_redraw) {
95
args.push_back("--debug-canvas-item-redraw");
96
}
97
98
if (debug_mute_audio) {
99
args.push_back("--debug-mute-audio");
100
}
101
102
if (p_write_movie != "") {
103
args.push_back("--write-movie");
104
args.push_back(p_write_movie);
105
args.push_back("--fixed-fps");
106
args.push_back(itos(GLOBAL_GET("editor/movie_writer/fps")));
107
if (bool(GLOBAL_GET("editor/movie_writer/disable_vsync"))) {
108
args.push_back("--disable-vsync");
109
}
110
}
111
112
WindowPlacement window_placement = get_window_placement();
113
if (window_placement.position != Point2i(INT_MAX, INT_MAX)) {
114
args.push_back("--position");
115
args.push_back(itos(window_placement.position.x) + "," + itos(window_placement.position.y));
116
}
117
118
if (window_placement.force_maximized) {
119
args.push_back("--maximized");
120
} else if (window_placement.force_fullscreen) {
121
args.push_back("--fullscreen");
122
}
123
124
List<String> breakpoints;
125
EditorNode::get_editor_data().get_editor_breakpoints(&breakpoints);
126
127
if (!breakpoints.is_empty()) {
128
args.push_back("--breakpoints");
129
String bpoints;
130
for (const List<String>::Element *E = breakpoints.front(); E; E = E->next()) {
131
bpoints += E->get().replace(" ", "%20");
132
if (E->next()) {
133
bpoints += ",";
134
}
135
}
136
137
args.push_back(bpoints);
138
}
139
140
if (EditorDebuggerNode::get_singleton()->is_skip_breakpoints()) {
141
args.push_back("--skip-breakpoints");
142
}
143
144
if (EditorDebuggerNode::get_singleton()->is_ignore_error_breaks()) {
145
args.push_back("--ignore-error-breaks");
146
}
147
148
if (!p_scene.is_empty()) {
149
args.push_back("--scene");
150
args.push_back(p_scene);
151
}
152
153
if (!p_run_args.is_empty()) {
154
for (const String &run_arg : p_run_args) {
155
args.push_back(run_arg);
156
}
157
}
158
159
String exec = OS::get_singleton()->get_executable_path();
160
int instance_count = RunInstancesDialog::get_singleton()->get_instance_count();
161
for (int i = 0; i < instance_count; i++) {
162
List<String> instance_args(args);
163
RunInstancesDialog::get_singleton()->get_argument_list_for_instance(i, instance_args);
164
RunInstancesDialog::get_singleton()->apply_custom_features(i);
165
if (instance_starting_callback) {
166
instance_starting_callback(i, instance_args);
167
}
168
169
if (OS::get_singleton()->is_stdout_verbose()) {
170
print_line(vformat("Running: %s", exec));
171
for (const String &E : instance_args) {
172
print_line(" %s", E);
173
}
174
}
175
176
OS::ProcessID pid = 0;
177
Error err = OS::get_singleton()->create_instance(instance_args, &pid);
178
ERR_FAIL_COND_V(err, err);
179
if (pid != 0) {
180
pids.push_back(pid);
181
}
182
}
183
184
status = STATUS_PLAY;
185
if (!p_scene.is_empty()) {
186
running_scene = p_scene;
187
}
188
189
return OK;
190
}
191
192
bool EditorRun::request_screenshot(const Callable &p_callback) {
193
if (instance_rq_screenshot_callback) {
194
return instance_rq_screenshot_callback(p_callback);
195
} else {
196
return false;
197
}
198
}
199
200
bool EditorRun::has_child_process(OS::ProcessID p_pid) const {
201
for (const OS::ProcessID &E : pids) {
202
if (E == p_pid) {
203
return true;
204
}
205
}
206
return false;
207
}
208
209
void EditorRun::stop_child_process(OS::ProcessID p_pid) {
210
if (has_child_process(p_pid)) {
211
OS::get_singleton()->kill(p_pid);
212
pids.erase(p_pid);
213
}
214
}
215
216
void EditorRun::stop() {
217
if (status != STATUS_STOP && pids.size() > 0) {
218
for (const OS::ProcessID &E : pids) {
219
OS::get_singleton()->kill(E);
220
}
221
pids.clear();
222
}
223
224
status = STATUS_STOP;
225
running_scene = "";
226
}
227
228
OS::ProcessID EditorRun::get_current_process() const {
229
if (pids.front() == nullptr) {
230
return 0;
231
}
232
return pids.front()->get();
233
}
234
235
EditorRun::WindowPlacement EditorRun::get_window_placement() {
236
WindowPlacement placement = WindowPlacement();
237
placement.screen = EDITOR_GET("run/window_placement/screen");
238
if (placement.screen == -5) {
239
// Same as editor
240
placement.screen = DisplayServer::get_singleton()->window_get_current_screen();
241
} else if (placement.screen == -4) {
242
// Previous monitor (wrap to the other end if needed)
243
placement.screen = Math::wrapi(
244
DisplayServer::get_singleton()->window_get_current_screen() - 1,
245
0,
246
DisplayServer::get_singleton()->get_screen_count());
247
} else if (placement.screen == -3) {
248
// Next monitor (wrap to the other end if needed)
249
placement.screen = Math::wrapi(
250
DisplayServer::get_singleton()->window_get_current_screen() + 1,
251
0,
252
DisplayServer::get_singleton()->get_screen_count());
253
} else if (placement.screen == -2) {
254
// Primary screen
255
placement.screen = DisplayServer::get_singleton()->get_primary_screen();
256
}
257
258
placement.size.x = GLOBAL_GET("display/window/size/viewport_width");
259
placement.size.y = GLOBAL_GET("display/window/size/viewport_height");
260
261
Size2 desired_size;
262
desired_size.x = GLOBAL_GET("display/window/size/window_width_override");
263
desired_size.y = GLOBAL_GET("display/window/size/window_height_override");
264
if (desired_size.x > 0 && desired_size.y > 0) {
265
placement.size = desired_size;
266
}
267
268
Rect2 screen_rect = DisplayServer::get_singleton()->screen_get_usable_rect(placement.screen);
269
270
int window_placement = EDITOR_GET("run/window_placement/rect");
271
if (screen_rect != Rect2()) {
272
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_HIDPI)) {
273
bool hidpi_proj = GLOBAL_GET("display/window/dpi/allow_hidpi");
274
int display_scale = 1;
275
276
if (OS::get_singleton()->is_hidpi_allowed()) {
277
if (hidpi_proj) {
278
display_scale = 1; // Both editor and project runs in hiDPI mode, do not scale.
279
} else {
280
display_scale = DisplayServer::get_singleton()->screen_get_max_scale(); // Editor is in hiDPI mode, project is not, scale down.
281
}
282
} else {
283
if (hidpi_proj) {
284
display_scale = (1.f / DisplayServer::get_singleton()->screen_get_max_scale()); // Editor is not in hiDPI mode, project is, scale up.
285
} else {
286
display_scale = 1; // Both editor and project runs in lowDPI mode, do not scale.
287
}
288
}
289
screen_rect.position /= display_scale;
290
screen_rect.size /= display_scale;
291
}
292
293
switch (window_placement) {
294
case 0: { // top left
295
placement.position = screen_rect.position;
296
} break;
297
case 1: { // centered
298
placement.position = (screen_rect.position) + ((screen_rect.size - placement.size) / 2).floor();
299
} break;
300
case 2: { // custom pos
301
Vector2 pos = EDITOR_GET("run/window_placement/rect_custom_position");
302
pos += screen_rect.position;
303
placement.position = pos;
304
} break;
305
case 3: { // force maximized
306
placement.force_maximized = true;
307
placement.position = (screen_rect.position) + ((screen_rect.size - placement.size) / 2).floor();
308
} break;
309
case 4: { // force fullscreen
310
placement.force_fullscreen = true;
311
placement.position = (screen_rect.position) + ((screen_rect.size - placement.size) / 2).floor();
312
} break;
313
}
314
} else {
315
// Unable to get screen info, skip setting position.
316
switch (window_placement) {
317
case 3: { // force maximized
318
placement.force_maximized = true;
319
} break;
320
case 4: { // force fullscreen
321
placement.force_fullscreen = true;
322
} break;
323
}
324
}
325
326
return placement;
327
}
328
329
EditorRun::EditorRun() {
330
status = STATUS_STOP;
331
running_scene = "";
332
}
333
334