From f6baa951fc0bd18d12c54fc1259713504e239e33 Mon Sep 17 00:00:00 2001 From: sasha80 Date: Tue, 25 Jul 2023 08:46:38 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/godot-logger/.gitattributes | 7 + addons/godot-logger/.gitignore | 3 + addons/godot-logger/LICENSE.md | 21 ++ addons/godot-logger/README.md | 60 +++++ addons/godot-logger/icons/logger.svg | 3 + addons/godot-logger/plugin.cfg | 7 + addons/godot-logger/plugin.gd | 49 +++++ addons/godot-logger/scripts/logger.gd | 218 +++++++++++++++++++ addons/godot-logger/scripts/logger_output.gd | 76 +++++++ project.godot | 2 +- scenes/pribor_spt_r.tscn | 6 +- 11 files changed, 446 insertions(+), 6 deletions(-) create mode 100644 addons/godot-logger/.gitattributes create mode 100644 addons/godot-logger/.gitignore create mode 100644 addons/godot-logger/LICENSE.md create mode 100644 addons/godot-logger/README.md create mode 100644 addons/godot-logger/icons/logger.svg create mode 100644 addons/godot-logger/plugin.cfg create mode 100644 addons/godot-logger/plugin.gd create mode 100644 addons/godot-logger/scripts/logger.gd create mode 100644 addons/godot-logger/scripts/logger_output.gd diff --git a/addons/godot-logger/.gitattributes b/addons/godot-logger/.gitattributes new file mode 100644 index 0000000..85718c8 --- /dev/null +++ b/addons/godot-logger/.gitattributes @@ -0,0 +1,7 @@ +# Normalize EOL for all files that Git considers text files. +* text=auto eol=lf + +/.gitattributes export-ignore +/.gitignore export-ignore +/README.md export-ignore +/LICENSE.md export-ignore diff --git a/addons/godot-logger/.gitignore b/addons/godot-logger/.gitignore new file mode 100644 index 0000000..6a0dfb7 --- /dev/null +++ b/addons/godot-logger/.gitignore @@ -0,0 +1,3 @@ +# Godot auto generated files +*.import +/.idea/ diff --git a/addons/godot-logger/LICENSE.md b/addons/godot-logger/LICENSE.md new file mode 100644 index 0000000..0d306ec --- /dev/null +++ b/addons/godot-logger/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2020-2023 Mansur Isaev and contributors + +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. diff --git a/addons/godot-logger/README.md b/addons/godot-logger/README.md new file mode 100644 index 0000000..0d6f598 --- /dev/null +++ b/addons/godot-logger/README.md @@ -0,0 +1,60 @@ +# Godot-Log + +Simple in-game logger for Godot 4.0. + +![](https://user-images.githubusercontent.com/8208165/144706770-e4fda4c0-249b-4851-b7a8-8d0bc3d278bc.png) + +# Features +- Installed as plugin. +- Singleton Log. +- Write to log file. +- Disable log levels. +- Custom log levels. + +# Installation: +1. Clone or download this repository to `addons` folder. +2. Enable `Godot Log` in Plugins. +3. Add `LogOutput` node to the scene. +4. Profit. + +# Usage: +## Calling default levels: +```gdscript +Log.info(text) +Log.debug(text) +Log.warning(text) +Log.error(text) +Log.fatal(text) +``` + +## Create a custom log level: +```gdscript +# main.gd +const CUSTOM = Log.MAX << 1 # Bitwise left shift the MAX value for a custom level. + +func _ready() -> void: + Log.add_level(CUSTOM, "Level Name") +``` + +## Calling the custom level: +```gdscript +Log.message(CUSTOM, "Something happened") +``` + +## Disable log level: +```gdscript +Log.set_level(Log.INFO, false) # Disable built-in level. +Log.set_level(CUSTOM, false) # Disable custom level. +``` + +## Enable log level: +```gdscript +Log.set_level(Log.DEBUG, true) # Enable built-in level. +Log.set_level(CUSTOM, true) # Enable custom level. +``` + +# License +Copyright (c) 2020-2023 Mansur Isaev and contributors + +Unless otherwise specified, files in this repository are licensed under the +MIT license. See [LICENSE.md](LICENSE.md) for more information. diff --git a/addons/godot-logger/icons/logger.svg b/addons/godot-logger/icons/logger.svg new file mode 100644 index 0000000..91184a5 --- /dev/null +++ b/addons/godot-logger/icons/logger.svg @@ -0,0 +1,3 @@ + + + diff --git a/addons/godot-logger/plugin.cfg b/addons/godot-logger/plugin.cfg new file mode 100644 index 0000000..26b4134 --- /dev/null +++ b/addons/godot-logger/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Godot Log" +description="Simple in-game Logger" +author="Mansur Isaev" +version="0.7" +script="plugin.gd" diff --git a/addons/godot-logger/plugin.gd b/addons/godot-logger/plugin.gd new file mode 100644 index 0000000..0062df0 --- /dev/null +++ b/addons/godot-logger/plugin.gd @@ -0,0 +1,49 @@ +# Copyright (c) 2020-2023 Mansur Isaev and contributors - MIT License +# See `LICENSE.md` included in the source distribution for details. + +@tool +extends EditorPlugin + + +const AUTOLOAD_NAME = "Log" +const AUTOLOAD_PATH = "res://addons/godot-logger/scripts/logger.gd" + +const LOGGER_OUTPUT = "LoggerOutput" +const LOGGER_OUTPUT_SCRIPT = "res://addons/godot-logger/scripts/logger_output.gd" +const LOGGER_OUTPUT_ICON = "res://addons/godot-logger/icons/logger.svg" + + +func _def_settings(name: String, default: Variant) -> void: + if not ProjectSettings.has_setting(name): + ProjectSettings.set_setting(name, default) + + ProjectSettings.set_initial_value(name, default) + + +func _enter_tree() -> void: + _def_settings("plugins/logger/log_enabled", true) + _def_settings("plugins/logger/default_output", false) + + _def_settings("plugins/logger/level", 31) # The magic number is - INFO | DEBUG | WARNING | ERROR | FATAL + ProjectSettings.add_property_info( + { + "name": "plugins/logger/level", + "type": TYPE_INT, + "hint": PROPERTY_HINT_FLAGS, + "hint_string": "Info,Debug,Warning,Error,Fatal", + } + ) + + _def_settings("plugins/logger/file/file_path", "user://uarep-ctl.log") + _def_settings("plugins/logger/file/log_file_write", true) + + _def_settings("plugins/logger/default_output_format", "[{hour}:{minute}:{second}][{level}]{text}") + _def_settings("plugins/logger/file_format", "[{hour}:{minute}:{second}][{level}]{text}") + + add_autoload_singleton(AUTOLOAD_NAME, AUTOLOAD_PATH) + add_custom_type(LOGGER_OUTPUT, "RichTextLabel", load(LOGGER_OUTPUT_SCRIPT), load(LOGGER_OUTPUT_ICON)) + + +func _exit_tree() -> void: + remove_custom_type(LOGGER_OUTPUT) + remove_autoload_singleton(AUTOLOAD_NAME) diff --git a/addons/godot-logger/scripts/logger.gd b/addons/godot-logger/scripts/logger.gd new file mode 100644 index 0000000..a8ae6f9 --- /dev/null +++ b/addons/godot-logger/scripts/logger.gd @@ -0,0 +1,218 @@ +# Copyright (c) 2020-2023 Mansur Isaev and contributors - MIT License +# See `LICENSE.md` included in the source distribution for details. + +## Logger class. +class_name Logger +extends Node + +## Emitted when the logger create a message. +signal logged(message: Dictionary) + + +enum { + INFO = 1, ## Info level. + DEBUG = 1<<1, ## Warning level. + WARNING = 1<<2, ## Debug level. + ERROR = 1<<3, ## Error level. + FATAL = 1<<4, ## Fatal level. + MAX = FATAL, ## Bitwise left shift for custom levels. +} + + +var _level : int + +var _log_enabled : bool +var _default_output_enabled : bool +var _file_write_enabled : bool + +var _file : FileAccess +var _file_path : String + +var _format_default_output : String +var _format_file : String + +var _names = { + INFO: "INFO", + DEBUG: "DEBUG", + WARNING: "WARNING", + ERROR: "ERROR", + FATAL: "FATAL" +} + +# Can be overridden to define custom default values. +func _enter_tree() -> void: + set_log_enabled(ProjectSettings.get_setting("plugins/logger/log_enabled", true)) + set_default_output_enabled(ProjectSettings.get_setting("plugins/logger/default_output", false)) + + _level = ProjectSettings.get_setting("plugins/logger/level", INFO | DEBUG | WARNING | ERROR | FATAL) + + set_file_path(ProjectSettings.get_setting("plugins/logger/file/file_path", "user://uarep-ctl.log")) + set_file_write_enabled(ProjectSettings.get_setting("plugins/logger/file/log_file_write", true)) + + _format_default_output = ProjectSettings.get_setting("plugins/logger/default_output_format", "[{hour}:{minute}:{second}][{level}]{text}") + _format_file = ProjectSettings.get_setting("plugins/logger/file_format", "[{hour}:{minute}:{second}][{level}]{text}") + + +func _exit_tree() -> void: + _close_file() + +## Return [param true] if logger has level. +func has_level(level: int) -> bool: + return _names.has(level) + +## Set the level enabled. +func set_level(level: int, enabled: bool) -> void: + assert(has_level(level), "Invalid level.") + if not has_level(level): + return + + if enabled: + _level |= level + else: + _level &= ~level + +## Add a custom log level. The level value must be unique and be greater than [member MAX]. +## To call the custom level use [method message] method. +func add_level(level: int, nm: String) -> void: + assert(not has_level(level), "Has level.") + assert(level > MAX and not level % 2, "Invalid level.") + assert(name, "Invalid name.") + + if not has_level(level) and level > MAX and not level % MAX and not name.is_empty(): + _names[level] = name + set_level(level, true) + +## Return the level name. +func get_level_name(level: int) -> String: + return _names[level] + +## Set Log enabled. Disable ALL messages. +func set_log_enabled(enabled: bool) -> void: + _log_enabled = enabled + +## Return [param true] if Log enabled. +func is_log_enabled() -> bool: + return _log_enabled + +## Set default output enabled. +func set_default_output_enabled(enabled: bool) -> void: + _default_output_enabled = enabled + +## Returns [param true] if default output is enabled. +func is_default_output_enabled() -> bool: + return _default_output_enabled + +## Set file write enabled. +func set_file_write_enabled(enabled: bool) -> void: + if _file_write_enabled == enabled: + return + + _file_write_enabled = enabled + + if enabled: + _open_file() + else: + _close_file() + +## Returns [param true] if write to a file is enabled. +func is_file_write_enabled() -> bool: + return _file_write_enabled + +## Set the path to the log file. +func set_file_path(path: String) -> void: + assert(path.is_absolute_path(), "Invalid path.") + if not path.is_absolute_path() or _file_path == path: + return + + _file_path = path + + if is_file_write_enabled(): + _open_file() + +## Return path to log file. +func get_file_path() -> String: + return _file_path + +## Create an info message. +func info(text: String) -> void: + message(INFO, text) + +## Create a debug message. Debug build only. +func debug(text: String) -> void: + if OS.is_debug_build(): + message(DEBUG, text) + +## Create a warning message. +func warning(text: String) -> void: + message(WARNING, text) + +## Create an error message. +func error(text: String) -> void: + message(ERROR, text) + +## Create a fatal error message. +func fatal(text: String) -> void: + message(FATAL, text) + +## Format string for log file. +func format_file(msg: Dictionary) -> String: + return _format_file.format( + { + "hour": "%02d" % msg["hour"], + "minute":"%02d" % msg["minute"], + "second":"%02d" % msg["second"], + "level": _names[msg["level"]], + "text": msg["text"], + } + ) + +## Format string for editor output. +func format_stdout(msg: Dictionary) -> String: + return _format_default_output.format( + { + "hour": "%02d" % msg["hour"], + "minute":"%02d" % msg["minute"], + "second":"%02d" % msg["second"], + "level": _names[msg["level"]], + "text": msg["text"], + } + ) + +## Create a message with a custom level. +func message(level: int, text: String) -> void: + assert(has_level(level), "Has not level.") + assert(text, "Invalid message text.") + + if _log_enabled and _level & level: + var msg : Dictionary = Time.get_time_dict_from_system() + msg["level"] = level + msg["level_name"] = _names[level] + msg["text"] = text + + logged.emit(msg) + + if _file_write_enabled: + _file.store_line(format_file(msg)) + + if _default_output_enabled: + print(format_stdout(msg)) + + +func _open_file() -> void: + if is_instance_valid(_file) and _file.is_open(): + _file.close() + + _file = FileAccess.open(get_file_path(), FileAccess.WRITE) + + var err := FileAccess.get_open_error() + if err: + return print_debug(error_string(err)) + + err = _file.get_error() + if err: + return print_debug(error_string(err)) + + +func _close_file() -> void: + if is_instance_valid(_file) and _file.is_open(): + _file = null diff --git a/addons/godot-logger/scripts/logger_output.gd b/addons/godot-logger/scripts/logger_output.gd new file mode 100644 index 0000000..4b0b9d3 --- /dev/null +++ b/addons/godot-logger/scripts/logger_output.gd @@ -0,0 +1,76 @@ +# Copyright (c) 2020-2023 Mansur Isaev and contributors - MIT License +# See `LICENSE.md` included in the source distribution for details. + +@tool +## LoggerOutput class. +class_name LoggerOutput +extends RichTextLabel + +## Emited when handle [signal Logger.logged] signal. +signal handled() + + +@export var format_text : String = "[{hour}:{minute}:{second}][{level}]{text}" +@export var colors : Dictionary = { + Logger.INFO: Color.WHITE, + Logger.DEBUG: Color.GRAY, + Logger.WARNING: Color.YELLOW, + Logger.ERROR: Color.RED, + Logger.FATAL: Color.RED, +} + + +var _logger : Logger + + +func _enter_tree() -> void: + var logger := get_node_or_null("/root/Log") as Logger + if is_instance_valid(logger): + set_logger(logger) + + +func _exit_tree() -> void: + if is_instance_valid(_logger) and _logger.logged.is_connected(handle_message): + _logger.logged.disconnect(handle_message) + +## Return the level color or [member Color.WHITE]. +func get_color(level: int) -> Color: + return colors.get(level, Color.WHITE) + +## Set the logger. +func set_logger(logger: Logger) -> void: + assert(is_instance_valid(logger), "Invalid Logger.") + if not is_instance_valid(logger) or is_same(_logger, logger): + return + + if is_instance_valid(_logger) and _logger.logged.is_connected(handle_message): + _logger.logged.disconnect(handle_message) + + if not logger.logged.is_connected(handle_message): + logger.logged.connect(handle_message) + + _logger = logger + +## Return the logger. +func get_logger() -> Logger: + return _logger + +## Return formatted string from message. +func format(message: Dictionary) -> String: + return format_text.format( + { + "hour": "%02d" % message["hour"], + "minute": "%02d" % message["minute"], + "second": "%02d" % message["second"], + "level": message["level_name"], + "text": message["text"], + } + ) + +## Handle the message. +func handle_message(message: Dictionary) -> void: + push_color(get_color(message["level"])) + append_text(format(message) + "\n") + pop() + + handled.emit() diff --git a/project.godot b/project.godot index c8cd0cf..a393a4c 100644 --- a/project.godot +++ b/project.godot @@ -60,7 +60,7 @@ version_control/autoload_on_startup=true [editor_plugins] -enabled=PackedStringArray("res://addons/godot-logger/plugin.cfg") +enabled=PackedStringArray() [gui] diff --git a/scenes/pribor_spt_r.tscn b/scenes/pribor_spt_r.tscn index 62c0337..6834bbe 100644 --- a/scenes/pribor_spt_r.tscn +++ b/scenes/pribor_spt_r.tscn @@ -1,10 +1,6 @@ -[gd_scene format=2] +[gd_scene format=3 uid="uid://bv0dyyaodxcvc"] [node name="pribor_UF" type="Node2D"] [node name="test_label" type="Label" parent="."] -margin_left = 12.0 -margin_top = 8.0 -margin_right = 154.0 -margin_bottom = 22.0 text = "Здесь будет схема прибора СПТ Правый"