summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/bind/core_bind.cpp18
-rw-r--r--core/bind/core_bind.h5
-rw-r--r--core/error_macros.cpp3
-rw-r--r--core/io/file_access_buffered_fa.h5
-rw-r--r--core/io/file_access_compressed.cpp7
-rw-r--r--core/io/file_access_compressed.h1
-rw-r--r--core/io/file_access_encrypted.cpp6
-rw-r--r--core/io/file_access_encrypted.h1
-rw-r--r--core/io/file_access_memory.cpp4
-rw-r--r--core/io/file_access_memory.h1
-rw-r--r--core/io/file_access_network.cpp4
-rw-r--r--core/io/file_access_network.h1
-rw-r--r--core/io/file_access_pack.cpp5
-rw-r--r--core/io/file_access_pack.h1
-rw-r--r--core/io/file_access_zip.cpp5
-rw-r--r--core/io/file_access_zip.h1
-rw-r--r--core/io/http_client.cpp2
-rw-r--r--core/io/logger.cpp255
-rw-r--r--core/io/logger.h107
-rw-r--r--core/io/resource_import.cpp2
-rw-r--r--core/io/resource_loader.cpp2
-rw-r--r--core/os/file_access.cpp2
-rw-r--r--core/os/file_access.h1
-rw-r--r--core/os/os.cpp49
-rw-r--r--core/os/os.h28
-rw-r--r--core/project_settings.cpp18
-rw-r--r--core/project_settings.h5
-rw-r--r--core/translation.cpp2
28 files changed, 500 insertions, 41 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp
index f47d540351..b47e611a51 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -453,6 +453,11 @@ int _OS::get_power_percent_left() {
return OS::get_singleton()->get_power_percent_left();
}
+bool _OS::has_feature(const String &p_feature) const {
+
+ return OS::get_singleton()->has_feature(p_feature);
+}
+
/*
enum Weekday {
DAY_SUNDAY,
@@ -755,6 +760,11 @@ bool _OS::can_draw() const {
return OS::get_singleton()->can_draw();
}
+bool _OS::is_userfs_persistent() const {
+
+ return OS::get_singleton()->is_userfs_persistent();
+}
+
int _OS::get_processor_count() const {
return OS::get_singleton()->get_processor_count();
@@ -858,6 +868,10 @@ void _OS::hide_virtual_keyboard() {
OS::get_singleton()->hide_virtual_keyboard();
}
+int _OS::get_virtual_keyboard_height() {
+ return OS::get_singleton()->get_virtual_keyboard_height();
+}
+
void _OS::print_all_resources(const String &p_to_file) {
OS::get_singleton()->print_all_resources(p_to_file);
@@ -1051,6 +1065,7 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_model_name"), &_OS::get_model_name);
ClassDB::bind_method(D_METHOD("can_draw"), &_OS::can_draw);
+ ClassDB::bind_method(D_METHOD("is_userfs_persistent"), &_OS::is_userfs_persistent);
ClassDB::bind_method(D_METHOD("is_stdout_verbose"), &_OS::is_stdout_verbose);
ClassDB::bind_method(D_METHOD("can_use_threads"), &_OS::can_use_threads);
@@ -1064,6 +1079,7 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_virtual_keyboard"), &_OS::has_virtual_keyboard);
ClassDB::bind_method(D_METHOD("show_virtual_keyboard", "existing_text"), &_OS::show_virtual_keyboard, DEFVAL(""));
ClassDB::bind_method(D_METHOD("hide_virtual_keyboard"), &_OS::hide_virtual_keyboard);
+ ClassDB::bind_method(D_METHOD("get_virtual_keyboard_height"), &_OS::get_virtual_keyboard_height);
ClassDB::bind_method(D_METHOD("print_resources_in_use", "short"), &_OS::print_resources_in_use, DEFVAL(false));
ClassDB::bind_method(D_METHOD("print_all_resources", "tofile"), &_OS::print_all_resources, DEFVAL(""));
@@ -1099,6 +1115,8 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_vsync", "enable"), &_OS::set_use_vsync);
ClassDB::bind_method(D_METHOD("is_vsync_enabled"), &_OS::is_vsync_enabled);
+ ClassDB::bind_method(D_METHOD("has_feature", "tag_name"), &_OS::has_feature);
+
ClassDB::bind_method(D_METHOD("get_power_state"), &_OS::get_power_state);
ClassDB::bind_method(D_METHOD("get_power_seconds_left"), &_OS::get_power_seconds_left);
ClassDB::bind_method(D_METHOD("get_power_percent_left"), &_OS::get_power_percent_left);
diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h
index f12ab9f000..7f8c734e36 100644
--- a/core/bind/core_bind.h
+++ b/core/bind/core_bind.h
@@ -204,6 +204,7 @@ public:
bool has_virtual_keyboard() const;
void show_virtual_keyboard(const String &p_existing_text = "");
void hide_virtual_keyboard();
+ int get_virtual_keyboard_height();
void print_resources_in_use(bool p_short = false);
void print_all_resources(const String &p_to_file);
@@ -266,6 +267,8 @@ public:
bool can_draw() const;
+ bool is_userfs_persistent() const;
+
bool is_stdout_verbose() const;
int get_processor_count() const;
@@ -315,6 +318,8 @@ public:
int get_power_seconds_left();
int get_power_percent_left();
+ bool has_feature(const String &p_feature) const;
+
static _OS *get_singleton() { return singleton; }
_OS();
diff --git a/core/error_macros.cpp b/core/error_macros.cpp
index 5919d38375..170a22e8dd 100644
--- a/core/error_macros.cpp
+++ b/core/error_macros.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "error_macros.h"
+#include "io/logger.h"
#include "os/os.h"
bool _err_error_exists = false;
@@ -79,7 +80,7 @@ void remove_error_handler(ErrorHandlerList *p_handler) {
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, ErrorHandlerType p_type) {
- OS::get_singleton()->print_error(p_function, p_file, p_line, p_error, _err_error_exists ? OS::get_singleton()->get_last_error() : "", (OS::ErrorType)p_type);
+ OS::get_singleton()->print_error(p_function, p_file, p_line, p_error, _err_error_exists ? OS::get_singleton()->get_last_error() : "", (Logger::ErrorType)p_type);
_global_lock();
ErrorHandlerList *l = error_handler_list;
diff --git a/core/io/file_access_buffered_fa.h b/core/io/file_access_buffered_fa.h
index 9e41834561..309fc16d09 100644
--- a/core/io/file_access_buffered_fa.h
+++ b/core/io/file_access_buffered_fa.h
@@ -76,6 +76,11 @@ protected:
};
public:
+ void flush() {
+
+ f.flush();
+ };
+
void store_8(uint8_t p_dest) {
f.store_8(p_dest);
diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
index 4750945854..514e3c65f0 100644
--- a/core/io/file_access_compressed.cpp
+++ b/core/io/file_access_compressed.cpp
@@ -338,6 +338,13 @@ Error FileAccessCompressed::get_error() const {
return read_eof ? ERR_FILE_EOF : OK;
}
+void FileAccessCompressed::flush() {
+ ERR_FAIL_COND(!f);
+ ERR_FAIL_COND(!writing);
+
+ // compressed files keep data in memory till close()
+}
+
void FileAccessCompressed::store_8(uint8_t p_dest) {
ERR_FAIL_COND(!f);
diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h
index 1a57e2d4ee..1d99e5bfd4 100644
--- a/core/io/file_access_compressed.h
+++ b/core/io/file_access_compressed.h
@@ -84,6 +84,7 @@ public:
virtual Error get_error() const; ///< get last error
+ virtual void flush();
virtual void store_8(uint8_t p_dest); ///< store a byte
virtual bool file_exists(const String &p_name); ///< return true if a file exists
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index 461c5bafe2..c93e12f7da 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -268,6 +268,12 @@ void FileAccessEncrypted::store_buffer(const uint8_t *p_src, int p_length) {
}
}
+void FileAccessEncrypted::flush() {
+ ERR_FAIL_COND(!writing);
+
+ // encrypted files keep data in memory till close()
+}
+
void FileAccessEncrypted::store_8(uint8_t p_dest) {
ERR_FAIL_COND(!writing);
diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h
index 82f60ac654..d83fed3e0e 100644
--- a/core/io/file_access_encrypted.h
+++ b/core/io/file_access_encrypted.h
@@ -71,6 +71,7 @@ public:
virtual Error get_error() const; ///< get last error
+ virtual void flush();
virtual void store_8(uint8_t p_dest); ///< store a byte
virtual void store_buffer(const uint8_t *p_src, int p_length); ///< store an array of bytes
diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp
index b948394385..0a5815fca8 100644
--- a/core/io/file_access_memory.cpp
+++ b/core/io/file_access_memory.cpp
@@ -170,6 +170,10 @@ Error FileAccessMemory::get_error() const {
return pos >= length ? ERR_FILE_EOF : OK;
}
+void FileAccessMemory::flush() {
+ ERR_FAIL_COND(!data);
+}
+
void FileAccessMemory::store_8(uint8_t p_byte) {
ERR_FAIL_COND(!data);
diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h
index b7b8430089..23392719b4 100644
--- a/core/io/file_access_memory.h
+++ b/core/io/file_access_memory.h
@@ -62,6 +62,7 @@ public:
virtual Error get_error() const; ///< get last error
+ virtual void flush();
virtual void store_8(uint8_t p_byte); ///< store a byte
virtual void store_buffer(const uint8_t *p_src, int p_length); ///< store an array of bytes
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 8c624226a1..a224abd9e7 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -456,6 +456,10 @@ Error FileAccessNetwork::get_error() const {
return pos == total_size ? ERR_FILE_EOF : OK;
}
+void FileAccessNetwork::flush() {
+ ERR_FAIL();
+}
+
void FileAccessNetwork::store_8(uint8_t p_dest) {
ERR_FAIL();
diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h
index abbe378b60..20614476d0 100644
--- a/core/io/file_access_network.h
+++ b/core/io/file_access_network.h
@@ -155,6 +155,7 @@ public:
virtual Error get_error() const; ///< get last error
+ virtual void flush();
virtual void store_8(uint8_t p_dest); ///< store a byte
virtual bool file_exists(const String &p_path); ///< return true if a file exists
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index ff4c28ec39..a7eb8ce6a9 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -293,6 +293,11 @@ Error FileAccessPack::get_error() const {
return OK;
}
+void FileAccessPack::flush() {
+
+ ERR_FAIL();
+}
+
void FileAccessPack::store_8(uint8_t p_dest) {
ERR_FAIL();
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index 3deb0d2bd3..12187a353a 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -161,6 +161,7 @@ public:
virtual Error get_error() const;
+ virtual void flush();
virtual void store_8(uint8_t p_dest);
virtual void store_buffer(const uint8_t *p_src, int p_length);
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
index 73b23ac702..ec809011a9 100644
--- a/core/io/file_access_zip.cpp
+++ b/core/io/file_access_zip.cpp
@@ -353,6 +353,11 @@ Error FileAccessZip::get_error() const {
return OK;
};
+void FileAccessZip::flush() {
+
+ ERR_FAIL();
+}
+
void FileAccessZip::store_8(uint8_t p_dest) {
ERR_FAIL();
diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h
index a40e1a753d..0977b241ee 100644
--- a/core/io/file_access_zip.h
+++ b/core/io/file_access_zip.h
@@ -108,6 +108,7 @@ public:
virtual Error get_error() const; ///< get last error
+ virtual void flush();
virtual void store_8(uint8_t p_dest); ///< store a byte
virtual bool file_exists(const String &p_name); ///< return true if a file exists
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp
index dd56db9bf9..b8c0a2b616 100644
--- a/core/io/http_client.cpp
+++ b/core/io/http_client.cpp
@@ -297,7 +297,7 @@ Error HTTPClient::poll() {
case StreamPeerTCP::STATUS_CONNECTED: {
if (ssl) {
Ref<StreamPeerSSL> ssl = StreamPeerSSL::create();
- Error err = ssl->connect_to_stream(tcp_connection, true, ssl_verify_host ? conn_host : String());
+ Error err = ssl->connect_to_stream(tcp_connection, ssl_verify_host, ssl_verify_host ? conn_host : String());
if (err != OK) {
close();
status = STATUS_SSL_HANDSHAKE_ERROR;
diff --git a/core/io/logger.cpp b/core/io/logger.cpp
new file mode 100644
index 0000000000..b94007d316
--- /dev/null
+++ b/core/io/logger.cpp
@@ -0,0 +1,255 @@
+/*************************************************************************/
+/* logger.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "logger.h"
+#include "os/dir_access.h"
+#include "os/os.h"
+#include "print_string.h"
+
+bool Logger::should_log(bool p_err) {
+ return (!p_err || _print_error_enabled) && (p_err || _print_line_enabled);
+}
+
+void Logger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) {
+ if (!should_log(true)) {
+ return;
+ }
+
+ const char *err_type = "**ERROR**";
+ switch (p_type) {
+ case ERR_ERROR: err_type = "**ERROR**"; break;
+ case ERR_WARNING: err_type = "**WARNING**"; break;
+ case ERR_SCRIPT: err_type = "**SCRIPT ERROR**"; break;
+ case ERR_SHADER: err_type = "**SHADER ERROR**"; break;
+ default: ERR_PRINT("Unknown error type"); break;
+ }
+
+ const char *err_details;
+ if (p_rationale && *p_rationale)
+ err_details = p_rationale;
+ else
+ err_details = p_code;
+
+ logf_error("%s: %s\n", err_type, err_details);
+ logf_error(" At: %s:%i:%s() - %s\n", p_file, p_line, p_function, p_code);
+}
+
+void Logger::logf(const char *p_format, ...) {
+ if (!should_log(false)) {
+ return;
+ }
+
+ va_list argp;
+ va_start(argp, p_format);
+
+ logv(p_format, argp, false);
+
+ va_end(argp);
+}
+
+void Logger::logf_error(const char *p_format, ...) {
+ if (!should_log(true)) {
+ return;
+ }
+
+ va_list argp;
+ va_start(argp, p_format);
+
+ logv(p_format, argp, true);
+
+ va_end(argp);
+}
+
+Logger::~Logger() {}
+
+void RotatedFileLogger::close_file() {
+ if (file) {
+ memdelete(file);
+ file = NULL;
+ }
+}
+
+void RotatedFileLogger::clear_old_backups() {
+ int max_backups = max_files - 1; // -1 for the current file
+
+ String basename = base_path.get_basename();
+ String extension = "." + base_path.get_extension();
+
+ DirAccess *da = DirAccess::open(base_path.get_base_dir());
+ if (!da) {
+ return;
+ }
+
+ da->list_dir_begin();
+ String f = da->get_next();
+ Set<String> backups;
+ while (f != String()) {
+ if (!da->current_is_dir() && f.begins_with(basename) && f.ends_with(extension) && f != base_path) {
+ backups.insert(f);
+ }
+ f = da->get_next();
+ }
+ da->list_dir_end();
+
+ if (backups.size() > max_backups) {
+ // since backups are appended with timestamp and Set iterates them in sorted order,
+ // first backups are the oldest
+ int to_delete = backups.size() - max_backups;
+ for (Set<String>::Element *E = backups.front(); E && to_delete > 0; E = E->next(), --to_delete) {
+ da->remove(E->get());
+ }
+ }
+
+ memdelete(da);
+}
+
+void RotatedFileLogger::rotate_file() {
+ close_file();
+
+ if (FileAccess::exists(base_path)) {
+ if (max_files > 1) {
+ char timestamp[21];
+ OS::Date date = OS::get_singleton()->get_date();
+ OS::Time time = OS::get_singleton()->get_time();
+ sprintf(timestamp, "-%04d-%02d-%02d-%02d-%02d-%02d", date.year, date.month, date.day + 1, time.hour, time.min, time.sec);
+
+ String backup_name = base_path.get_basename() + timestamp + "." + base_path.get_extension();
+
+ DirAccess *da = DirAccess::open(base_path.get_base_dir());
+ if (da) {
+ da->copy(base_path, backup_name);
+ memdelete(da);
+ }
+ clear_old_backups();
+ }
+ } else {
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_USERDATA);
+ if (da) {
+ da->make_dir_recursive(base_path.get_base_dir());
+ memdelete(da);
+ }
+ }
+
+ file = FileAccess::open(base_path, FileAccess::WRITE);
+}
+
+RotatedFileLogger::RotatedFileLogger(const String &p_base_path, int p_max_files) {
+ file = NULL;
+ base_path = p_base_path.simplify_path();
+ max_files = p_max_files > 0 ? p_max_files : 1;
+
+ rotate_file();
+}
+
+void RotatedFileLogger::logv(const char *p_format, va_list p_list, bool p_err) {
+ if (!should_log(p_err)) {
+ return;
+ }
+
+ if (file) {
+ const int static_buf_size = 512;
+ char static_buf[static_buf_size];
+ char *buf = static_buf;
+ va_list list_copy;
+ va_copy(list_copy, p_list);
+ int len = vsnprintf(buf, static_buf_size, p_format, p_list);
+ if (len >= static_buf_size) {
+ buf = (char *)Memory::alloc_static(len + 1);
+ vsnprintf(buf, len + 1, p_format, list_copy);
+ }
+ va_end(list_copy);
+ file->store_buffer((uint8_t *)buf, len);
+ if (len >= static_buf_size) {
+ Memory::free_static(buf);
+ }
+#ifdef DEBUG_ENABLED
+ const bool need_flush = true;
+#else
+ bool need_flush = p_err;
+#endif
+ if (need_flush) {
+ file->flush();
+ }
+ }
+}
+
+RotatedFileLogger::~RotatedFileLogger() {
+ close_file();
+}
+
+void StdLogger::logv(const char *p_format, va_list p_list, bool p_err) {
+ if (!should_log(p_err)) {
+ return;
+ }
+
+ if (p_err) {
+ vfprintf(stderr, p_format, p_list);
+ } else {
+ vprintf(p_format, p_list);
+#ifdef DEBUG_ENABLED
+ fflush(stdout);
+#endif
+ }
+}
+
+StdLogger::~StdLogger() {}
+
+CompositeLogger::CompositeLogger(Vector<Logger *> p_loggers) {
+ loggers = p_loggers;
+}
+
+void CompositeLogger::logv(const char *p_format, va_list p_list, bool p_err) {
+ if (!should_log(p_err)) {
+ return;
+ }
+
+ for (int i = 0; i < loggers.size(); ++i) {
+ va_list list_copy;
+ va_copy(list_copy, p_list);
+ loggers[i]->logv(p_format, list_copy, p_err);
+ va_end(list_copy);
+ }
+}
+
+void CompositeLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) {
+ if (!should_log(true)) {
+ return;
+ }
+
+ for (int i = 0; i < loggers.size(); ++i) {
+ loggers[i]->log_error(p_function, p_file, p_line, p_code, p_rationale, p_type);
+ }
+}
+
+CompositeLogger::~CompositeLogger() {
+ for (int i = 0; i < loggers.size(); ++i) {
+ memdelete(loggers[i]);
+ }
+}
diff --git a/core/io/logger.h b/core/io/logger.h
new file mode 100644
index 0000000000..cf0cc7699f
--- /dev/null
+++ b/core/io/logger.h
@@ -0,0 +1,107 @@
+/*************************************************************************/
+/* logger.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef LOGGER_H
+#define LOGGER_H
+
+#include "os/file_access.h"
+#include "ustring.h"
+#include "vector.h"
+#include <stdarg.h>
+
+class Logger {
+protected:
+ bool should_log(bool p_err);
+
+public:
+ enum ErrorType {
+ ERR_ERROR,
+ ERR_WARNING,
+ ERR_SCRIPT,
+ ERR_SHADER
+ };
+
+ virtual void logv(const char *p_format, va_list p_list, bool p_err) = 0;
+ virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR);
+
+ void logf(const char *p_format, ...);
+ void logf_error(const char *p_format, ...);
+
+ virtual ~Logger();
+};
+
+/**
+ * Writes messages to stdout/stderr.
+ */
+class StdLogger : public Logger {
+
+public:
+ virtual void logv(const char *p_format, va_list p_list, bool p_err);
+ virtual ~StdLogger();
+};
+
+/**
+ * Writes messages to the specified file. If the file already exists, creates a copy (backup)
+ * of it with timestamp appended to the file name. Maximum number of backups is configurable.
+ * When maximum is reached, the oldest backups are erased. With the maximum being equal to 1,
+ * it acts as a simple file logger.
+ */
+class RotatedFileLogger : public Logger {
+ String base_path;
+ int max_files;
+
+ FileAccess *file;
+
+ void rotate_file_without_closing();
+ void close_file();
+ void clear_old_backups();
+ void rotate_file();
+
+public:
+ RotatedFileLogger(const String &p_base_path, int p_max_files = 10);
+
+ virtual void logv(const char *p_format, va_list p_list, bool p_err);
+
+ virtual ~RotatedFileLogger();
+};
+
+class CompositeLogger : public Logger {
+ Vector<Logger *> loggers;
+
+public:
+ CompositeLogger(Vector<Logger *> p_loggers);
+
+ virtual void logv(const char *p_format, va_list p_list, bool p_err);
+ virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR);
+
+ virtual ~CompositeLogger();
+};
+
+#endif \ No newline at end of file
diff --git a/core/io/resource_import.cpp b/core/io/resource_import.cpp
index bc7ea47762..401d704222 100644
--- a/core/io/resource_import.cpp
+++ b/core/io/resource_import.cpp
@@ -77,7 +77,7 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy
if (assign != String()) {
if (!path_found && assign.begins_with("path.") && r_path_and_type.path == String()) {
String feature = assign.get_slicec('.', 1);
- if (OS::get_singleton()->check_feature_support(feature)) {
+ if (OS::get_singleton()->has_feature(feature)) {
r_path_and_type.path = value;
path_found = true; //first match must have priority
}
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index 89cb4a22c2..ed0d491679 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -492,7 +492,7 @@ void ResourceLoader::reload_translation_remaps() {
void ResourceLoader::load_translation_remaps() {
- if (!ProjectSettings::get_singleton()->has("locale/translation_remaps"))
+ if (!ProjectSettings::get_singleton()->has_setting("locale/translation_remaps"))
return;
Dictionary remaps = ProjectSettings::get_singleton()->get("locale/translation_remaps");
diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp
index b969b58bfb..fcb3b58fed 100644
--- a/core/os/file_access.cpp
+++ b/core/os/file_access.cpp
@@ -55,7 +55,7 @@ FileAccess *FileAccess::create(AccessType p_access) {
bool FileAccess::exists(const String &p_name) {
- if (PackedData::get_singleton()->has_path(p_name))
+ if (PackedData::get_singleton() && PackedData::get_singleton()->has_path(p_name))
return true;
FileAccess *f = open(p_name, READ);
diff --git a/core/os/file_access.h b/core/os/file_access.h
index 34e7549fa3..455dd1ea99 100644
--- a/core/os/file_access.h
+++ b/core/os/file_access.h
@@ -119,6 +119,7 @@ public:
virtual Error get_error() const = 0; ///< get last error
+ virtual void flush() = 0;
virtual void store_8(uint8_t p_dest) = 0; ///< store a byte
virtual void store_16(uint16_t p_dest); ///< store 16 bits uint
virtual void store_32(uint32_t p_dest); ///< store 32 bits uint
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 437ce01a5e..eb5d5be33d 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -62,20 +62,20 @@ void OS::debug_break(){
// something
};
-void OS::print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) {
-
- const char *err_type = "**ERROR**";
- switch (p_type) {
- case ERR_ERROR: err_type = "**ERROR**"; break;
- case ERR_WARNING: err_type = "**WARNING**"; break;
- case ERR_SCRIPT: err_type = "**SCRIPT ERROR**"; break;
- case ERR_SHADER: err_type = "**SHADER ERROR**"; break;
- default: ERR_PRINT("Unknown error type"); break;
+void OS::_set_logger(Logger *p_logger) {
+ if (_logger) {
+ memdelete(_logger);
}
+ _logger = p_logger;
+}
+
+void OS::initialize_logger() {
+ _set_logger(memnew(StdLogger));
+}
+
+void OS::print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, Logger::ErrorType p_type) {
- if (p_rationale && *p_rationale)
- print("%s: %s\n ", err_type, p_rationale);
- print("%s: At: %s:%i:%s() - %s\n", err_type, p_file, p_line, p_function, p_code);
+ _logger->log_error(p_function, p_file, p_line, p_code, p_rationale, p_type);
}
void OS::print(const char *p_format, ...) {
@@ -83,17 +83,16 @@ void OS::print(const char *p_format, ...) {
va_list argp;
va_start(argp, p_format);
- vprint(p_format, argp);
+ _logger->logv(p_format, argp, false);
va_end(argp);
};
void OS::printerr(const char *p_format, ...) {
-
va_list argp;
va_start(argp, p_format);
- vprint(p_format, argp, true);
+ _logger->logv(p_format, argp, true);
va_end(argp);
};
@@ -194,6 +193,10 @@ void OS::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_scr
void OS::hide_virtual_keyboard() {
}
+int OS::get_virtual_keyboard_height() const {
+ return 0;
+}
+
void OS::print_all_resources(String p_to_file) {
ERR_FAIL_COND(p_to_file != "" && _OSPRF);
@@ -495,7 +498,7 @@ int OS::get_power_percent_left() {
return -1;
}
-bool OS::check_feature_support(const String &p_feature) {
+bool OS::has_feature(const String &p_feature) {
if (p_feature == get_name())
return true;
@@ -507,6 +510,13 @@ bool OS::check_feature_support(const String &p_feature) {
return true;
#endif
+ if (sizeof(void *) == 8 && p_feature == "64") {
+ return true;
+ }
+ if (sizeof(void *) == 4 && p_feature == "32") {
+ return true;
+ }
+
if (_check_internal_feature_support(p_feature))
return true;
@@ -531,11 +541,14 @@ OS::OS() {
_render_thread_mode = RENDER_THREAD_SAFE;
- _allow_hidpi = true;
+ _allow_hidpi = false;
_stack_bottom = (void *)(&stack_bottom);
+
+ _logger = NULL;
+ _set_logger(memnew(StdLogger));
}
OS::~OS() {
-
+ memdelete(_logger);
singleton = NULL;
}
diff --git a/core/os/os.h b/core/os/os.h
index 3806217f55..6fcfd71332 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -32,6 +32,7 @@
#include "engine.h"
#include "image.h"
+#include "io/logger.h"
#include "list.h"
#include "os/main_loop.h"
#include "ustring.h"
@@ -61,6 +62,11 @@ class OS {
void *_stack_bottom;
+ Logger *_logger;
+
+protected:
+ void _set_logger(Logger *p_logger);
+
public:
typedef void (*ImeCallback)(void *p_inp, String p_text, Point2 p_selection);
@@ -108,6 +114,7 @@ protected:
virtual int get_audio_driver_count() const = 0;
virtual const char *get_audio_driver_name(int p_driver) const = 0;
+ virtual void initialize_logger();
virtual void initialize_core() = 0;
virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) = 0;
@@ -127,18 +134,10 @@ public:
static OS *get_singleton();
- enum ErrorType {
- ERR_ERROR,
- ERR_WARNING,
- ERR_SCRIPT,
- ERR_SHADER
- };
+ void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, Logger::ErrorType p_type = Logger::ERR_ERROR);
+ void print(const char *p_format, ...);
+ void printerr(const char *p_format, ...);
- virtual void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR);
-
- virtual void print(const char *p_format, ...);
- virtual void printerr(const char *p_format, ...);
- virtual void vprint(const char *p_format, va_list p_list, bool p_stderr = false) = 0;
virtual void alert(const String &p_alert, const String &p_title = "ALERT!") = 0;
virtual String get_stdin_string(bool p_block = true) = 0;
@@ -284,6 +283,8 @@ public:
virtual bool can_draw() const = 0;
+ virtual bool is_userfs_persistent() const { return true; }
+
bool is_stdout_verbose() const;
virtual void disable_crash_handler() {}
@@ -314,6 +315,9 @@ public:
virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2());
virtual void hide_virtual_keyboard();
+ // returns height of the currently shown virtual keyboard (0 if keyboard is hidden)
+ virtual int get_virtual_keyboard_height() const;
+
virtual void set_cursor_shape(CursorShape p_shape) = 0;
virtual bool get_swap_ok_cancel() { return false; }
@@ -426,7 +430,7 @@ public:
virtual int get_power_seconds_left();
virtual int get_power_percent_left();
- bool check_feature_support(const String &p_feature);
+ bool has_feature(const String &p_feature);
/**
* Returns the stack bottom of the main thread of the application.
diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index 14ebe87dc5..ff2be87b07 100644
--- a/core/project_settings.cpp
+++ b/core/project_settings.cpp
@@ -152,7 +152,7 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
bool override_valid = false;
for (int i = 1; i < s.size(); i++) {
String feature = s[i].strip_edges();
- if (OS::get_singleton()->check_feature_support(feature) || custom_features.has(feature)) {
+ if (OS::get_singleton()->has_feature(feature) || custom_features.has(feature)) {
override_valid = true;
break;
}
@@ -420,7 +420,7 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack) {
return OK;
}
-bool ProjectSettings::has(String p_var) const {
+bool ProjectSettings::has_setting(String p_var) const {
_THREAD_SAFE_METHOD_
@@ -800,7 +800,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default) {
Variant ret;
- if (ProjectSettings::get_singleton()->has(p_var)) {
+ if (ProjectSettings::get_singleton()->has_setting(p_var)) {
ret = ProjectSettings::get_singleton()->get(p_var);
} else {
ProjectSettings::get_singleton()->set(p_var, p_default);
@@ -907,9 +907,19 @@ Variant ProjectSettings::property_get_revert(const String &p_name) {
return props[p_name].initial;
}
+void ProjectSettings::set_setting(const String &p_setting, const Variant &p_value) {
+ set(p_setting, p_value);
+}
+
+Variant ProjectSettings::get_setting(const String &p_setting) const {
+ return get(p_setting);
+}
+
void ProjectSettings::_bind_methods() {
- ClassDB::bind_method(D_METHOD("has", "name"), &ProjectSettings::has);
+ ClassDB::bind_method(D_METHOD("has_setting", "name"), &ProjectSettings::has_setting);
+ ClassDB::bind_method(D_METHOD("set_setting", "name", "value"), &ProjectSettings::set_setting);
+ ClassDB::bind_method(D_METHOD("get_setting", "name"), &ProjectSettings::get_setting);
ClassDB::bind_method(D_METHOD("set_order", "name", "position"), &ProjectSettings::set_order);
ClassDB::bind_method(D_METHOD("get_order", "name"), &ProjectSettings::get_order);
ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value"), &ProjectSettings::set_initial_value);
diff --git a/core/project_settings.h b/core/project_settings.h
index 718ab2a011..ea6034dc84 100644
--- a/core/project_settings.h
+++ b/core/project_settings.h
@@ -119,7 +119,10 @@ protected:
static void _bind_methods();
public:
- bool has(String p_var) const;
+ void set_setting(const String &p_setting, const Variant &p_value);
+ Variant get_setting(const String &p_setting) const;
+
+ bool has_setting(String p_var) const;
String localize_path(const String &p_path) const;
String globalize_path(const String &p_path) const;
diff --git a/core/translation.cpp b/core/translation.cpp
index f1f9c72b85..27e3b202d0 100644
--- a/core/translation.cpp
+++ b/core/translation.cpp
@@ -1052,7 +1052,7 @@ TranslationServer *TranslationServer::singleton = NULL;
bool TranslationServer::_load_translations(const String &p_from) {
- if (ProjectSettings::get_singleton()->has(p_from)) {
+ if (ProjectSettings::get_singleton()->has_setting(p_from)) {
PoolVector<String> translations = ProjectSettings::get_singleton()->get(p_from);
int tcount = translations.size();