Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/config/engine.cpp
20844 views
1
/**************************************************************************/
2
/* engine.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 "engine.h"
32
33
#include "core/authors.gen.h"
34
#include "core/config/project_settings.h"
35
#include "core/donors.gen.h"
36
#include "core/license.gen.h"
37
#include "core/variant/typed_array.h"
38
#include "core/version.h"
39
#include "servers/rendering/rendering_device.h"
40
41
void Engine::_update_time_scale() {
42
_time_scale = _user_time_scale * _game_time_scale;
43
user_ips = MAX(1, ips * _user_time_scale);
44
max_user_physics_steps_per_frame = MAX(max_physics_steps_per_frame, max_physics_steps_per_frame * _user_time_scale);
45
}
46
47
void Engine::set_physics_ticks_per_second(int p_ips) {
48
ERR_FAIL_COND_MSG(p_ips <= 0, "Engine iterations per second must be greater than 0.");
49
ips = p_ips;
50
_update_time_scale();
51
}
52
53
int Engine::get_physics_ticks_per_second() const {
54
return ips;
55
}
56
57
int Engine::get_user_physics_ticks_per_second() const {
58
return user_ips;
59
}
60
61
void Engine::set_max_physics_steps_per_frame(int p_max_physics_steps) {
62
ERR_FAIL_COND_MSG(p_max_physics_steps <= 0, "Maximum number of physics steps per frame must be greater than 0.");
63
max_physics_steps_per_frame = p_max_physics_steps;
64
_update_time_scale();
65
}
66
67
int Engine::get_max_physics_steps_per_frame() const {
68
return max_physics_steps_per_frame;
69
}
70
71
int Engine::get_user_max_physics_steps_per_frame() const {
72
return max_user_physics_steps_per_frame;
73
}
74
75
void Engine::set_physics_jitter_fix(double p_threshold) {
76
if (p_threshold < 0) {
77
p_threshold = 0;
78
}
79
physics_jitter_fix = p_threshold;
80
}
81
82
double Engine::get_physics_jitter_fix() const {
83
return physics_jitter_fix;
84
}
85
86
void Engine::set_max_fps(int p_fps) {
87
_max_fps = p_fps > 0 ? p_fps : 0;
88
89
RenderingDevice *rd = RenderingDevice::get_singleton();
90
if (rd) {
91
rd->_set_max_fps(_max_fps);
92
}
93
}
94
95
int Engine::get_max_fps() const {
96
return _max_fps;
97
}
98
99
void Engine::set_audio_output_latency(int p_msec) {
100
_audio_output_latency = p_msec > 1 ? p_msec : 1;
101
}
102
103
int Engine::get_audio_output_latency() const {
104
return _audio_output_latency;
105
}
106
107
void Engine::increment_frames_drawn() {
108
if (frame_server_synced) {
109
server_syncs++;
110
} else {
111
server_syncs = 0;
112
}
113
frame_server_synced = false;
114
115
frames_drawn++;
116
}
117
118
uint64_t Engine::get_frames_drawn() {
119
return frames_drawn;
120
}
121
122
void Engine::set_frame_delay(uint32_t p_msec) {
123
_frame_delay = p_msec;
124
}
125
126
uint32_t Engine::get_frame_delay() const {
127
return _frame_delay;
128
}
129
130
void Engine::set_time_scale(double p_scale) {
131
_game_time_scale = p_scale;
132
_update_time_scale();
133
}
134
135
double Engine::get_time_scale() const {
136
return freeze_time_scale ? 0.0 : _game_time_scale;
137
}
138
139
void Engine::set_user_time_scale(double p_scale) {
140
_user_time_scale = p_scale;
141
_update_time_scale();
142
}
143
144
double Engine::get_effective_time_scale() const {
145
return freeze_time_scale ? 0.0 : _time_scale;
146
}
147
148
double Engine::get_unfrozen_time_scale() const {
149
return _time_scale;
150
}
151
152
Dictionary Engine::get_version_info() const {
153
Dictionary dict;
154
dict["major"] = GODOT_VERSION_MAJOR;
155
dict["minor"] = GODOT_VERSION_MINOR;
156
dict["patch"] = GODOT_VERSION_PATCH;
157
dict["hex"] = GODOT_VERSION_HEX;
158
dict["status"] = GODOT_VERSION_STATUS;
159
dict["build"] = GODOT_VERSION_BUILD;
160
161
String hash = String(GODOT_VERSION_HASH);
162
dict["hash"] = hash.is_empty() ? String("unknown") : hash;
163
164
dict["timestamp"] = GODOT_VERSION_TIMESTAMP;
165
166
String stringver = String(dict["major"]) + "." + String(dict["minor"]);
167
if ((int)dict["patch"] != 0) {
168
stringver += "." + String(dict["patch"]);
169
}
170
stringver += "-" + String(dict["status"]) + " (" + String(dict["build"]) + ")";
171
dict["string"] = stringver;
172
173
return dict;
174
}
175
176
static Array array_from_info(const char *const *info_list) {
177
Array arr;
178
for (int i = 0; info_list[i] != nullptr; i++) {
179
arr.push_back(String::utf8(info_list[i]));
180
}
181
return arr;
182
}
183
184
static Array array_from_info_count(const char *const *info_list, int info_count) {
185
Array arr;
186
for (int i = 0; i < info_count; i++) {
187
arr.push_back(String::utf8(info_list[i]));
188
}
189
return arr;
190
}
191
192
Dictionary Engine::get_author_info() const {
193
Dictionary dict;
194
195
dict["lead_developers"] = array_from_info(AUTHORS_LEAD_DEVELOPERS);
196
dict["project_managers"] = array_from_info(AUTHORS_PROJECT_MANAGERS);
197
dict["founders"] = array_from_info(AUTHORS_FOUNDERS);
198
dict["developers"] = array_from_info(AUTHORS_DEVELOPERS);
199
200
return dict;
201
}
202
203
TypedArray<Dictionary> Engine::get_copyright_info() const {
204
TypedArray<Dictionary> components;
205
for (int component_index = 0; component_index < COPYRIGHT_INFO_COUNT; component_index++) {
206
const ComponentCopyright &cp_info = COPYRIGHT_INFO[component_index];
207
Dictionary component_dict;
208
component_dict["name"] = String::utf8(cp_info.name);
209
Array parts;
210
for (int i = 0; i < cp_info.part_count; i++) {
211
const ComponentCopyrightPart &cp_part = cp_info.parts[i];
212
Dictionary part_dict;
213
part_dict["files"] = array_from_info_count(cp_part.files, cp_part.file_count);
214
part_dict["copyright"] = array_from_info_count(cp_part.copyright_statements, cp_part.copyright_count);
215
part_dict["license"] = String::utf8(cp_part.license);
216
parts.push_back(part_dict);
217
}
218
component_dict["parts"] = parts;
219
220
components.push_back(component_dict);
221
}
222
return components;
223
}
224
225
Dictionary Engine::get_donor_info() const {
226
Dictionary donors;
227
donors["patrons"] = array_from_info(DONORS_PATRONS);
228
donors["platinum_sponsors"] = array_from_info(DONORS_SPONSORS_PLATINUM);
229
donors["gold_sponsors"] = array_from_info(DONORS_SPONSORS_GOLD);
230
donors["silver_sponsors"] = array_from_info(DONORS_SPONSORS_SILVER);
231
donors["diamond_members"] = array_from_info(DONORS_MEMBERS_DIAMOND);
232
donors["titanium_members"] = array_from_info(DONORS_MEMBERS_TITANIUM);
233
donors["platinum_members"] = array_from_info(DONORS_MEMBERS_PLATINUM);
234
donors["gold_members"] = array_from_info(DONORS_MEMBERS_GOLD);
235
return donors;
236
}
237
238
Dictionary Engine::get_license_info() const {
239
Dictionary licenses;
240
for (int i = 0; i < LICENSE_COUNT; i++) {
241
licenses[LICENSE_NAMES[i]] = LICENSE_BODIES[i];
242
}
243
return licenses;
244
}
245
246
String Engine::get_license_text() const {
247
return String(GODOT_LICENSE_TEXT);
248
}
249
250
String Engine::get_architecture_name() const {
251
#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(_M_X64)
252
return "x86_64";
253
#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
254
return "x86_32";
255
#elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
256
return "arm64";
257
#elif defined(__arm__) || defined(_M_ARM)
258
return "arm32";
259
#elif defined(__riscv)
260
return "rv64";
261
#elif defined(__powerpc64__)
262
return "ppc64";
263
#elif defined(__loongarch64)
264
return "loongarch64";
265
#elif defined(__wasm64__)
266
return "wasm64";
267
#elif defined(__wasm32__)
268
return "wasm32";
269
#endif
270
}
271
272
bool Engine::is_abort_on_gpu_errors_enabled() const {
273
return abort_on_gpu_errors;
274
}
275
276
int32_t Engine::get_gpu_index() const {
277
return gpu_idx;
278
}
279
280
bool Engine::is_validation_layers_enabled() const {
281
return use_validation_layers;
282
}
283
284
bool Engine::is_generate_spirv_debug_info_enabled() const {
285
return generate_spirv_debug_info;
286
}
287
288
bool Engine::is_extra_gpu_memory_tracking_enabled() const {
289
return extra_gpu_memory_tracking;
290
}
291
292
#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
293
bool Engine::is_accurate_breadcrumbs_enabled() const {
294
return accurate_breadcrumbs;
295
}
296
#endif
297
298
void Engine::set_print_to_stdout(bool p_enabled) {
299
CoreGlobals::print_line_enabled = p_enabled;
300
}
301
302
bool Engine::is_printing_to_stdout() const {
303
return CoreGlobals::print_line_enabled;
304
}
305
306
void Engine::set_print_error_messages(bool p_enabled) {
307
CoreGlobals::print_error_enabled = p_enabled;
308
}
309
310
bool Engine::is_printing_error_messages() const {
311
return CoreGlobals::print_error_enabled;
312
}
313
314
void Engine::print_header(const String &p_string) const {
315
if (_print_header) {
316
print_line(p_string);
317
}
318
}
319
320
void Engine::print_header_rich(const String &p_string) const {
321
if (_print_header) {
322
print_line_rich(p_string);
323
}
324
}
325
326
void Engine::add_singleton(const Singleton &p_singleton) {
327
ERR_FAIL_COND_MSG(singleton_ptrs.has(p_singleton.name), vformat("Can't register singleton '%s' because it already exists.", p_singleton.name));
328
singletons.push_back(p_singleton);
329
singleton_ptrs[p_singleton.name] = p_singleton.ptr;
330
}
331
332
Object *Engine::get_singleton_object(const StringName &p_name) const {
333
HashMap<StringName, Object *>::ConstIterator E = singleton_ptrs.find(p_name);
334
ERR_FAIL_COND_V_MSG(!E, nullptr, vformat("Failed to retrieve non-existent singleton '%s'.", p_name));
335
336
#ifdef TOOLS_ENABLED
337
if (!is_editor_hint() && is_singleton_editor_only(p_name)) {
338
ERR_FAIL_V_MSG(nullptr, vformat("Can't retrieve singleton '%s' outside of editor.", p_name));
339
}
340
#endif
341
342
return E->value;
343
}
344
345
bool Engine::is_singleton_user_created(const StringName &p_name) const {
346
ERR_FAIL_COND_V(!singleton_ptrs.has(p_name), false);
347
348
for (const Singleton &E : singletons) {
349
if (E.name == p_name && E.user_created) {
350
return true;
351
}
352
}
353
354
return false;
355
}
356
357
bool Engine::is_singleton_editor_only(const StringName &p_name) const {
358
ERR_FAIL_COND_V(!singleton_ptrs.has(p_name), false);
359
360
for (const Singleton &E : singletons) {
361
if (E.name == p_name && E.editor_only) {
362
return true;
363
}
364
}
365
366
return false;
367
}
368
369
void Engine::remove_singleton(const StringName &p_name) {
370
ERR_FAIL_COND(!singleton_ptrs.has(p_name));
371
372
for (List<Singleton>::Element *E = singletons.front(); E; E = E->next()) {
373
if (E->get().name == p_name) {
374
singletons.erase(E);
375
singleton_ptrs.erase(p_name);
376
return;
377
}
378
}
379
}
380
381
bool Engine::has_singleton(const StringName &p_name) const {
382
return singleton_ptrs.has(p_name);
383
}
384
385
void Engine::get_singletons(List<Singleton> *p_singletons) {
386
for (const Singleton &E : singletons) {
387
#ifdef TOOLS_ENABLED
388
if (!is_editor_hint() && E.editor_only) {
389
continue;
390
}
391
#endif
392
393
p_singletons->push_back(E);
394
}
395
}
396
397
String Engine::get_write_movie_path() const {
398
return write_movie_path;
399
}
400
401
void Engine::set_write_movie_path(const String &p_path) {
402
write_movie_path = p_path;
403
}
404
405
void Engine::set_shader_cache_path(const String &p_path) {
406
shader_cache_path = p_path;
407
}
408
String Engine::get_shader_cache_path() const {
409
return shader_cache_path;
410
}
411
412
Engine *Engine::get_singleton() {
413
return singleton;
414
}
415
416
bool Engine::notify_frame_server_synced() {
417
frame_server_synced = true;
418
return server_syncs > SERVER_SYNC_FRAME_COUNT_WARNING;
419
}
420
421
void Engine::set_freeze_time_scale(bool p_frozen) {
422
freeze_time_scale = p_frozen;
423
}
424
425
void Engine::set_embedded_in_editor(bool p_enabled) {
426
embedded_in_editor = p_enabled;
427
}
428
429
bool Engine::is_embedded_in_editor() const {
430
return embedded_in_editor;
431
}
432
433
Engine::Engine() {
434
singleton = this;
435
}
436
437
Engine::~Engine() {
438
if (singleton == this) {
439
singleton = nullptr;
440
}
441
}
442
443
Engine::Singleton::Singleton(const StringName &p_name, Object *p_ptr, const StringName &p_class_name) :
444
name(p_name),
445
ptr(p_ptr),
446
class_name(p_class_name) {
447
#ifdef DEBUG_ENABLED
448
RefCounted *rc = Object::cast_to<RefCounted>(p_ptr);
449
if (rc && !rc->is_referenced()) {
450
WARN_PRINT("You must use Ref<> to ensure the lifetime of a RefCounted object intended to be used as a singleton.");
451
}
452
#endif
453
}
454
455