diff --git a/Constants.gd b/Constants.gd index 8362662..bc17c45 100644 --- a/Constants.gd +++ b/Constants.gd @@ -14,15 +14,6 @@ var WGS84_AB = WGS84_A_M * WGS84_B_M var g = 9.80665 -func calc_time_diff(timestamp_1, timestamp_2): - if timestamp_2 < 3600 and timestamp_1 > 82800: - return (timestamp_2 + 86400) - timestamp_1 - return timestamp_2 - timestamp_1 - -func is_timestamp_newer(old_timestamp: float, new_timestamp: float) -> bool: - if old_timestamp > 82800. and new_timestamp < 3600: # earlier than 23 hours - return true - return old_timestamp < new_timestamp func calc_wgs84_altitude(latitude_rad: float): var theta_rad = abs(latitude_rad) diff --git a/Main.tscn b/Main.tscn index 20af8f4..a213d37 100644 --- a/Main.tscn +++ b/Main.tscn @@ -11,6 +11,7 @@ [ext_resource type="PackedScene" uid="uid://crpqmmpxfe2yi" path="res://views/3d/View3D.tscn" id="10_wkp8b"] [ext_resource type="PackedScene" uid="uid://cf2vkjpwwdog7" path="res://vehicle/vehicle.tscn" id="11_5vvyt"] [ext_resource type="PackedScene" uid="uid://blijvkgrhoas" path="res://settings/SettingsMenu.tscn" id="11_20pc6"] +[ext_resource type="Script" uid="uid://cb0e5702tjrqc" path="res://data_recorder_node.gd" id="12_5vvyt"] [node name="Main" type="Node" unique_id=247156581] @@ -51,5 +52,9 @@ text = "Settings" [node name="SettingsMenu" parent="Settings" unique_id=1877869509 instance=ExtResource("11_20pc6")] +[node name="DataRecorderNode" type="Node" parent="." unique_id=504334504] +script = ExtResource("12_5vvyt") +metadata/_custom_type_script = "uid://cb0e5702tjrqc" + [connection signal="pressed" from="Settings/OpenSettings" to="ViewController" method="_on_open_settings_pressed"] [connection signal="pressed" from="Settings/OpenSettings" to="Settings" method="_on_settings_opened"] diff --git a/addons/loggie-console/assets/NinePatchWindow-InnerRecess.png b/addons/loggie-console/assets/NinePatchWindow-InnerRecess.png deleted file mode 100644 index 95b07ec..0000000 Binary files a/addons/loggie-console/assets/NinePatchWindow-InnerRecess.png and /dev/null differ diff --git a/addons/loggie-console/assets/NinePatchWindow-InnerRecess.png.import b/addons/loggie-console/assets/NinePatchWindow-InnerRecess.png.import deleted file mode 100644 index 9ea3f65..0000000 --- a/addons/loggie-console/assets/NinePatchWindow-InnerRecess.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ivppb5cqrsak" -path="res://.godot/imported/NinePatchWindow-InnerRecess.png-07bd09e8d845ac941af5cf12e9f19c54.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/loggie-console/assets/NinePatchWindow-InnerRecess.png" -dest_files=["res://.godot/imported/NinePatchWindow-InnerRecess.png-07bd09e8d845ac941af5cf12e9f19c54.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/loggie-console/assets/NinePatchWindowInner.png b/addons/loggie-console/assets/NinePatchWindowInner.png deleted file mode 100644 index 7fd9ac9..0000000 Binary files a/addons/loggie-console/assets/NinePatchWindowInner.png and /dev/null differ diff --git a/addons/loggie-console/assets/NinePatchWindowInner.png.import b/addons/loggie-console/assets/NinePatchWindowInner.png.import deleted file mode 100644 index 5f99860..0000000 --- a/addons/loggie-console/assets/NinePatchWindowInner.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://d1w4w4yi6p3w3" -path="res://.godot/imported/NinePatchWindowInner.png-47f4d96fc18c0a2a90855797a8cd0e05.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/loggie-console/assets/NinePatchWindowInner.png" -dest_files=["res://.godot/imported/NinePatchWindowInner.png-47f4d96fc18c0a2a90855797a8cd0e05.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/loggie-console/assets/NinePatchWindowOuter.png b/addons/loggie-console/assets/NinePatchWindowOuter.png deleted file mode 100644 index 366a7e1..0000000 Binary files a/addons/loggie-console/assets/NinePatchWindowOuter.png and /dev/null differ diff --git a/addons/loggie-console/assets/NinePatchWindowOuter.png.import b/addons/loggie-console/assets/NinePatchWindowOuter.png.import deleted file mode 100644 index 5feb3b6..0000000 --- a/addons/loggie-console/assets/NinePatchWindowOuter.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cs676riq457do" -path="res://.godot/imported/NinePatchWindowOuter.png-bca6314f960490a8a5e8b837d843d94e.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/loggie-console/assets/NinePatchWindowOuter.png" -dest_files=["res://.godot/imported/NinePatchWindowOuter.png-bca6314f960490a8a5e8b837d843d94e.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/loggie-console/assets/close.png b/addons/loggie-console/assets/close.png deleted file mode 100644 index c2880ad..0000000 Binary files a/addons/loggie-console/assets/close.png and /dev/null differ diff --git a/addons/loggie-console/assets/close.png.import b/addons/loggie-console/assets/close.png.import deleted file mode 100644 index b413e19..0000000 --- a/addons/loggie-console/assets/close.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bhps6csrl6lef" -path="res://.godot/imported/close.png-9f5b597652eecfc041a6acfb8a79a5f3.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/loggie-console/assets/close.png" -dest_files=["res://.godot/imported/close.png-9f5b597652eecfc041a6acfb8a79a5f3.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/loggie-console/assets/icon.png.import b/addons/loggie-console/assets/icon.png.import deleted file mode 100644 index 181b910..0000000 --- a/addons/loggie-console/assets/icon.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ckoblpvpivjma" -path="res://.godot/imported/icon.png-b025e725a72f01c7e881efaf61058c1e.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/loggie-console/assets/icon.png" -dest_files=["res://.godot/imported/icon.png-b025e725a72f01c7e881efaf61058c1e.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/loggie-console/assets/inner_panel.tres b/addons/loggie-console/assets/inner_panel.tres deleted file mode 100644 index e97c8a8..0000000 --- a/addons/loggie-console/assets/inner_panel.tres +++ /dev/null @@ -1,17 +0,0 @@ -[gd_resource type="StyleBoxTexture" load_steps=2 format=3 uid="uid://b7k8yo7jfhpue"] - -[ext_resource type="Texture2D" uid="uid://d1w4w4yi6p3w3" path="res://addons/loggie-console/assets/NinePatchWindowInner.png" id="1_vngi6"] - -[resource] -content_margin_left = 4.0 -content_margin_top = 4.0 -content_margin_right = 4.0 -content_margin_bottom = 4.0 -texture = ExtResource("1_vngi6") -texture_margin_left = 2.0 -texture_margin_top = 2.0 -texture_margin_right = 2.0 -texture_margin_bottom = 2.0 -axis_stretch_horizontal = 1 -axis_stretch_vertical = 1 -region_rect = Rect2(0, 0, 36, 36) diff --git a/addons/loggie-console/assets/inner_panel_recess.tres b/addons/loggie-console/assets/inner_panel_recess.tres deleted file mode 100644 index f627bd4..0000000 --- a/addons/loggie-console/assets/inner_panel_recess.tres +++ /dev/null @@ -1,16 +0,0 @@ -[gd_resource type="StyleBoxTexture" load_steps=2 format=3 uid="uid://dolgdjpxlvt8f"] - -[ext_resource type="Texture2D" uid="uid://ivppb5cqrsak" path="res://addons/loggie-console/assets/NinePatchWindow-InnerRecess.png" id="1_lfme6"] - -[resource] -content_margin_left = 4.0 -content_margin_right = 4.0 -content_margin_bottom = 4.0 -texture = ExtResource("1_lfme6") -texture_margin_left = 2.0 -texture_margin_top = 2.0 -texture_margin_right = 2.0 -texture_margin_bottom = 2.0 -axis_stretch_horizontal = 1 -axis_stretch_vertical = 1 -region_rect = Rect2(0, 0, 36, 36) diff --git a/addons/loggie-console/assets/minimize.png b/addons/loggie-console/assets/minimize.png deleted file mode 100644 index 48511b2..0000000 Binary files a/addons/loggie-console/assets/minimize.png and /dev/null differ diff --git a/addons/loggie-console/assets/minimize.png.import b/addons/loggie-console/assets/minimize.png.import deleted file mode 100644 index 0795883..0000000 --- a/addons/loggie-console/assets/minimize.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://2ie83nlho48h" -path="res://.godot/imported/minimize.png-3f9dff399b51d5e6e7a64266986b96cf.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/loggie-console/assets/minimize.png" -dest_files=["res://.godot/imported/minimize.png-3f9dff399b51d5e6e7a64266986b96cf.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/loggie-console/assets/outer_panel.tres b/addons/loggie-console/assets/outer_panel.tres deleted file mode 100644 index b22bfc7..0000000 --- a/addons/loggie-console/assets/outer_panel.tres +++ /dev/null @@ -1,13 +0,0 @@ -[gd_resource type="StyleBoxTexture" load_steps=2 format=3 uid="uid://bpkqcbx15ejak"] - -[ext_resource type="Texture2D" uid="uid://cs676riq457do" path="res://sprites/ui/NinePatchWindowBrown.png" id="1_4h7p8"] - -[resource] -texture = ExtResource("1_4h7p8") -texture_margin_left = 2.0 -texture_margin_top = 2.0 -texture_margin_right = 2.0 -texture_margin_bottom = 2.0 -axis_stretch_horizontal = 1 -axis_stretch_vertical = 1 -region_rect = Rect2(0, 0, 36, 36) diff --git a/addons/loggie-console/assets/outer_window_panel.tres b/addons/loggie-console/assets/outer_window_panel.tres deleted file mode 100644 index b4a44e0..0000000 --- a/addons/loggie-console/assets/outer_window_panel.tres +++ /dev/null @@ -1,21 +0,0 @@ -[gd_resource type="StyleBoxTexture" load_steps=2 format=3 uid="uid://cfafk3ybc15uo"] - -[ext_resource type="Texture2D" uid="uid://cs676riq457do" path="res://sprites/ui/NinePatchWindowBrown.png" id="1_8qfda"] - -[resource] -content_margin_left = 2.0 -content_margin_top = 2.0 -content_margin_right = 2.0 -content_margin_bottom = 2.0 -texture = ExtResource("1_8qfda") -texture_margin_left = 2.0 -texture_margin_top = 2.0 -texture_margin_right = 2.0 -texture_margin_bottom = 2.0 -expand_margin_left = 4.0 -expand_margin_top = 24.0 -expand_margin_right = 4.0 -expand_margin_bottom = 4.0 -axis_stretch_horizontal = 1 -axis_stretch_vertical = 1 -region_rect = Rect2(0, 0, 36, 36) diff --git a/addons/loggie-console/plugin.cfg b/addons/loggie-console/plugin.cfg deleted file mode 100644 index c2b0d7e..0000000 --- a/addons/loggie-console/plugin.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[plugin] - -name="Loggie Console" -description="Interactive debug console built upon the Loggie logging framework" -author="Smitner Studio" -version="1.0" -script="plugin.gd" diff --git a/addons/loggie-console/plugin.gd b/addons/loggie-console/plugin.gd deleted file mode 100644 index c53fa35..0000000 --- a/addons/loggie-console/plugin.gd +++ /dev/null @@ -1,16 +0,0 @@ -@tool -class_name LoggieConsoleEditorPlugin extends EditorPlugin - -const AUTOLOAD_NAME = &"LoggieConsoleAutoload" - -func _enter_tree(): - add_autoload_singleton(AUTOLOAD_NAME, "res://addons/loggie-console/scenes/console.tscn") - -func _exit_tree(): - remove_autoload_singleton(AUTOLOAD_NAME) - -func _enable_plugin() -> void: - print("%s enabled" % AUTOLOAD_NAME) - -func _disable_plugin() -> void: - print("%s disabled" % AUTOLOAD_NAME) diff --git a/addons/loggie-console/plugin.gd.uid b/addons/loggie-console/plugin.gd.uid deleted file mode 100644 index f6345bb..0000000 --- a/addons/loggie-console/plugin.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b8ul8pbaeqx2l diff --git a/addons/loggie-console/resources/loggie_console_filter_state.gd b/addons/loggie-console/resources/loggie_console_filter_state.gd deleted file mode 100644 index d841e03..0000000 --- a/addons/loggie-console/resources/loggie_console_filter_state.gd +++ /dev/null @@ -1,55 +0,0 @@ -@tool -class_name LoggieConsoleFilterState extends Resource - -## Persistent filter state resource for LoggieConsole -## -## Stores filtering criteria (domains, log levels, search terms) in a format compatible -## with Godot's Resource system while maintaining compatibility with LogBuffer.FilterState. -## This enables console filter settings to persist between application sessions. - - -## List of domain names that are currently enabled for display -@export var enabled_domains: Array[String] = [] - -## Minimum log level to display (stored as int for persistence compatibility) -@export var min_log_level: int = LoggieEnums.LogLevel.DEBUG - -## Text search filter - only messages containing this text will be shown -@export var text_search: String = "" - -## Whether to show only messages that include stack traces -@export var show_stack_only: bool = false - -## Converts this persistent resource to runtime FilterState object -## Returns: A new LogBuffer.FilterState instance with matching filter criteria -func to_filter_state() -> LogBuffer.FilterState: - var filter_state: LogBuffer.FilterState = LogBuffer.FilterState.new() - filter_state.enabled_domains = enabled_domains.duplicate() - filter_state.min_log_level = min_log_level as LoggieEnums.LogLevel - filter_state.text_search = text_search - filter_state.show_stack_only = show_stack_only - return filter_state - -## Populates this resource from runtime FilterState object -## Param filter_state: The LogBuffer.FilterState to copy data from -func from_filter_state(filter_state: LogBuffer.FilterState) -> void: - enabled_domains = filter_state.enabled_domains.duplicate() - min_log_level = filter_state.min_log_level as int - text_search = filter_state.text_search - show_stack_only = filter_state.show_stack_only - -## Validates and sanitizes all data after loading from disk -## Ensures all fields have valid values even if the saved file was corrupted -func validate() -> void: - # Ensure domain array exists - if enabled_domains == null: - enabled_domains = [] - - # Validate log level is within valid enum range - if min_log_level < 0 or min_log_level >= LoggieEnums.LogLevel.size(): - min_log_level = LoggieEnums.LogLevel.DEBUG - Loggie.msg("Invalid log level, reset to DEBUG").domain(LoggieConsoleConstants.DOMAIN).warn() - - # Ensure search text is never null - if text_search == null: - text_search = "" diff --git a/addons/loggie-console/resources/loggie_console_filter_state.gd.uid b/addons/loggie-console/resources/loggie_console_filter_state.gd.uid deleted file mode 100644 index c9f5fde..0000000 --- a/addons/loggie-console/resources/loggie_console_filter_state.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b6iuus8kvu3y3 diff --git a/addons/loggie-console/resources/loggie_console_settings.gd b/addons/loggie-console/resources/loggie_console_settings.gd deleted file mode 100644 index de9148b..0000000 --- a/addons/loggie-console/resources/loggie_console_settings.gd +++ /dev/null @@ -1,294 +0,0 @@ -@tool -class_name LoggieConsoleSettings extends Resource - -## Complete persistent settings for LoggieConsole -## -## This resource stores all console state including window properties, filter settings, -## component states, and discovered domains. It automatically saves when the console -## exits and loads on startup to restore the user's previous console configuration. - -const LoggieConsoleFilterState = preload("res://addons/loggie-console/resources/loggie_console_filter_state.gd") - -# Configuration constants -const MIN_WINDOW_WIDTH: int = 400 -const MIN_WINDOW_HEIGHT: int = 300 -const DEFAULT_WINDOW_WIDTH: int = 800 -const DEFAULT_WINDOW_HEIGHT: int = 400 -const SCREEN_MARGIN_PIXELS: int = 100 # 50px on each side -const WINDOW_EDGE_MARGIN: int = 20 -const WINDOW_MIN_MARGIN: int = 10 - - -## Filter state for log message display (domains, levels, search terms) -@export var filter_state: LoggieConsoleFilterState - -## Currently enabled domain names for filtering -@export var enabled_domains: Array[String] = [] - -## All domain names discovered during runtime (persisted for next session) -@export var all_known_domains: Array[String] = [] - -## Console window screen position (-1, -1 means use default centering) -@export var window_position: Vector2i = Vector2i(-1, -1) - -## Console window size in pixels -@export var window_size: Vector2i = Vector2i(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT) - -## Whether console is currently minimized -@export var is_minimized: bool = false - -## Whether console window is visible -@export var is_visible: bool = true - -## Display/screen index where console was last positioned (-1 means primary display) -@export var display_index: int = -1 - -## Whether subwindows were embedded when settings were last saved -@export var was_embedded_subwindows: bool = false - -## Current log level filter (stored as int for persistence) -@export var log_level: int = LoggieEnums.LogLevel.DEBUG - -## Whether to auto-scroll to newest messages -@export var scroll_follow_enabled: bool = true - -## Current text search filter term -@export var search_text: String = "" - -## Whether to show only messages with stack traces -@export var stack_filter_enabled: bool = false - -## Maximum number of messages to keep in buffer before cleanup -@export var max_messages: int = 5000 - -## Text size multiplier for console fonts (0.5 to 2.0, default 1.0) -@export var text_size_multiplier: float = 1.0 - -## Restore button alignment position (0=TOP_LEFT, 1=TOP_RIGHT, 2=BOTTOM_LEFT, 3=BOTTOM_RIGHT) -@export var restore_button_alignment: int = 1 # Default to TOP_RIGHT - -## Settings file format version for future migration compatibility -@export var version: int = 1 - -## Unix timestamp when settings were last saved -@export var last_saved: float = 0.0 - -## Initializes default settings values -## -## Creates the filter state resource if it doesn't exist. This ensures that -## all required sub-resources are properly initialized even when creating -## settings from scratch. -func _init() -> void: - if not filter_state: - filter_state = LoggieConsoleFilterState.new() - -## Validates and sanitizes all data after loading from disk -## Ensures all fields have valid values even if the saved file was corrupted -func validate() -> void: - # Ensure filter state exists and is valid - if not filter_state: - filter_state = LoggieConsoleFilterState.new() - filter_state.validate() - - # Ensure domain arrays exist - if enabled_domains == null: - enabled_domains = [] - if all_known_domains == null: - all_known_domains = [] - - # Validate log level is within enum range - if log_level < 0 or log_level >= LoggieEnums.LogLevel.size(): - log_level = LoggieEnums.LogLevel.DEBUG - Loggie.msg("Invalid log level, reset to DEBUG").domain(LoggieConsoleConstants.DOMAIN).warn() - - # Enforce minimum and maximum window size for usability - _validate_window_size() - - # Ensure search text is never null - if search_text == null: - search_text = "" - - # Validate text size multiplier is within reasonable bounds - if text_size_multiplier < 0.5 or text_size_multiplier > 2.0: - text_size_multiplier = 1.0 - Loggie.msg("Invalid text size multiplier, reset to 1.0").domain(LoggieConsoleConstants.DOMAIN).warn() - - # Validate restore button alignment is within enum range (0-3) - if restore_button_alignment < 0 or restore_button_alignment > 3: - restore_button_alignment = 1 # Default to TOP_RIGHT - Loggie.msg("Invalid restore button alignment, reset to TOP_RIGHT").domain(LoggieConsoleConstants.DOMAIN).warn() - - # Update save timestamp - last_saved = Time.get_unix_time_from_system() - -## Validates and ensures window size fits within available screen space -## -## Enforces minimum size for usability (400x300) and maximum size based on -## screen dimensions. Checks all connected displays to find the largest -## available space and clamps the window size accordingly. -func _validate_window_size() -> void: - # Get the largest available screen to determine maximum constraints - var max_screen_size: Vector2i = Vector2i.ZERO - var screens: int = DisplayServer.get_screen_count() - - for i: int in screens: - var screen_rect: Rect2i = DisplayServer.screen_get_usable_rect(i) - max_screen_size.x = maxi(max_screen_size.x, screen_rect.size.x) - max_screen_size.y = maxi(max_screen_size.y, screen_rect.size.y) - - # Fallback if no screens detected - if max_screen_size == Vector2i.ZERO: - max_screen_size = Vector2i(1920, 1080) - - # Enforce minimum window size for usability - window_size.x = maxi(window_size.x, MIN_WINDOW_WIDTH) - window_size.y = maxi(window_size.y, MIN_WINDOW_HEIGHT) - - # Enforce maximum window size to fit on screen (with margins) - var max_width: int = max_screen_size.x - SCREEN_MARGIN_PIXELS - var max_height: int = max_screen_size.y - SCREEN_MARGIN_PIXELS - - if window_size.x > max_width: - window_size.x = max_width - Loggie.msg("Window width too large, clamped to %d" % max_width).domain(LoggieConsoleConstants.DOMAIN).warn() - - if window_size.y > max_height: - window_size.y = max_height - Loggie.msg("Window height too large, clamped to %d" % max_height).domain(LoggieConsoleConstants.DOMAIN).warn() - -## Detects if embed_subwindows setting has changed since last save -## Returns: true if setting has changed and window positioning needs reset -func _has_embed_setting_changed() -> bool: - var current_embedded = ProjectSettings.get_setting("display/window/subwindows/embed_subwindows", true) - return current_embedded != was_embedded_subwindows - -## Updates the stored embed_subwindows setting to current project setting -## -## This should be called whenever settings are saved to track the current -## embed_subwindows state for future change detection. -func update_embed_setting() -> void: - was_embedded_subwindows = ProjectSettings.get_setting("display/window/subwindows/embed_subwindows", true) - -## Validates and corrects window position for current display setup -## Returns: A valid window position that will be visible on screen -func validate_window_position() -> Vector2i: - # Check if embed_subwindows setting has changed - var embed_changed = _has_embed_setting_changed() - var current_embedded = ProjectSettings.get_setting("display/window/subwindows/embed_subwindows", true) - - # If embed setting changed and window was previously invisible, reset position - if embed_changed and not is_visible: - Loggie.msg("embed_subwindows changed from %s to %s, resetting window position" % [was_embedded_subwindows, current_embedded]).domain(LoggieConsoleConstants.DOMAIN).warn() - update_embed_setting() - # Reset to default centering - var target_display = _get_target_display() - var target_rect: Rect2i = DisplayServer.screen_get_usable_rect(target_display) - window_position = Vector2i(-1, -1) # Mark for centering - display_index = target_display - return _center_window_on_screen(target_rect) - - # Update embed setting for future comparisons - update_embed_setting() - - # Use default centering if position is not set - if window_position == Vector2i(-1, -1): - var target_display = _get_target_display() - var target_rect: Rect2i = DisplayServer.screen_get_usable_rect(target_display) - return _center_window_on_screen(target_rect) - - # If we have a specific display preference, validate against it first - if display_index >= 0 and display_index < DisplayServer.get_screen_count(): - var preferred_rect: Rect2i = DisplayServer.screen_get_usable_rect(display_index) - var validated_pos = _clamp_window_to_screen(window_position, preferred_rect) - if validated_pos != window_position: - Loggie.msg("Window position adjusted to fit display %d" % display_index).domain(LoggieConsoleConstants.DOMAIN).warn() - return validated_pos - - # Check if window can fit properly on any connected display - var screens: int = DisplayServer.get_screen_count() - var best_display: int = -1 - var best_pos: Vector2i = window_position - - for i: int in screens: - var screen_rect: Rect2i = DisplayServer.screen_get_usable_rect(i) - var window_rect: Rect2i = Rect2i(window_position, window_size) - - # Check if window intersects with this screen - if screen_rect.intersects(window_rect): - best_display = i - best_pos = _clamp_window_to_screen(window_position, screen_rect) - # If the window fits perfectly on this screen, use it - if best_pos == window_position: - display_index = i - return window_position - break - - # If we found a suitable display, use the clamped position - if best_display >= 0: - display_index = best_display - if best_pos != window_position: - Loggie.msg("Window position clamped to fit display %d" % best_display).domain(LoggieConsoleConstants.DOMAIN).warn() - return best_pos - - # Window is completely off-screen, center it on target display - var target_display = _get_target_display() - var target_rect: Rect2i = DisplayServer.screen_get_usable_rect(target_display) - display_index = target_display - Loggie.msg("Window position off-screen, centering on display %d" % target_display).domain(LoggieConsoleConstants.DOMAIN).warn() - return _center_window_on_screen(target_rect) - -## Centers the window on the given screen rectangle with margins -## -## Calculates a centered position that keeps the window fully visible with -## appropriate margins from screen edges. -## @param screen_rect: The target screen's usable rectangle -## @return: Position that centers the window with 20px margins -func _center_window_on_screen(screen_rect: Rect2i) -> Vector2i: - var margin_vector: Vector2i = Vector2i(WINDOW_EDGE_MARGIN, WINDOW_EDGE_MARGIN) - var available_size: Vector2i = screen_rect.size - margin_vector * 2 - var centered_offset: Vector2i = (available_size - window_size) / 2 - return screen_rect.position + margin_vector + centered_offset - -## Clamps window position to ensure it fits entirely within screen bounds -## -## Adjusts the position to keep the entire window visible on the screen, -## respecting minimum margins from edges. -## @param pos: The desired window position -## @param screen_rect: The target screen's rectangle -## @return: Adjusted position that keeps the entire window visible -func _clamp_window_to_screen(pos: Vector2i, screen_rect: Rect2i) -> Vector2i: - var margin: Vector2i = Vector2i(WINDOW_MIN_MARGIN, WINDOW_MIN_MARGIN) - var usable_rect: Rect2i = Rect2i( - screen_rect.position + margin, - screen_rect.size - margin * 2 - ) - - # Ensure window fits within usable area - var max_pos: Vector2i = usable_rect.position + usable_rect.size - window_size - - var clamped_pos: Vector2i = Vector2i( - clampi(pos.x, usable_rect.position.x, max_pos.x), - clampi(pos.y, usable_rect.position.y, max_pos.y) - ) - - return clamped_pos - -## Gets the target display index for window positioning -## Returns: Valid display index (0 if saved display no longer exists) -func _get_target_display() -> int: - # Use saved display if it still exists - if display_index >= 0 and display_index < DisplayServer.get_screen_count(): - return display_index - - # Fall back to primary display (index 0) - return 0 - -## Gets the log level as a proper enum value -## Returns: The current log level as LoggieEnums.LogLevel -func get_log_level() -> LoggieEnums.LogLevel: - return log_level as LoggieEnums.LogLevel - -## Sets the log level from an enum value -## @param level: The new log level to store -func set_log_level(level: LoggieEnums.LogLevel) -> void: - log_level = level as int diff --git a/addons/loggie-console/resources/loggie_console_settings.gd.uid b/addons/loggie-console/resources/loggie_console_settings.gd.uid deleted file mode 100644 index c594ea5..0000000 --- a/addons/loggie-console/resources/loggie_console_settings.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://w2lnu7heu47v diff --git a/addons/loggie-console/scenes/console.gd b/addons/loggie-console/scenes/console.gd deleted file mode 100644 index 7bd27cc..0000000 --- a/addons/loggie-console/scenes/console.gd +++ /dev/null @@ -1,563 +0,0 @@ -## Enhanced LoggieConsole with persistence, minimize/restore, and multi-display support -## -## This console window provides an advanced debugging interface for the Loggie logging system. -## Features include: -## - Persistent window positioning and settings across sessions -## - Multi-display awareness for non-embedded subwindows -## - Domain-based filtering with dynamic discovery -## - Minimize/restore functionality with floating restore button -## - Complete component-based architecture for extensibility -## -## The console automatically saves all settings when closed or minimized, and restores -## the exact previous state on next startup, including window position, size, filters, -## and discovered domains. -class_name LoggieConsole extends Window - -# Constants -const LoggieConsoleChannel = preload("res://addons/loggie-console/scripts/loggie_console_channel.gd") -const ConsoleSettingsManager = preload("res://addons/loggie-console/scripts/managers/console_settings_manager.gd") -const LoggieConsoleSettings = preload("res://addons/loggie-console/resources/loggie_console_settings.gd") -const RestoreButtonScene := preload("res://addons/loggie-console/scenes/restore_button.tscn") -const DomainColorManager = preload("res://addons/loggie-console/scripts/domain_color_manager.gd") - - -# UI Constants -const WINDOW_MARGIN_PIXELS: int = 5 - -# Display detection constants -const DEFAULT_DOMAIN_OFFSET: int = 1 # +1 for default domain in total domain count - - -# Exported component references - automatically assigned from scene -@export var buffer: LogBuffer ## Log message display and filtering component -@export var output_level: LogLevelFilter ## Log level selection component -@export var domain_filter: PanelDomainSelector ## Domain multi-selection component -@export var controls: ConsoleControls ## Control buttons and settings component -@export var status_display: StatusDisplay ## Status and statistics display component - -# Settings UI references -var _settings_button: Button ## Settings button in controls -var _settings_panel: LoggieConsoleSettingsPanel ## Settings panel component - - -# Minimize/restore system state -var _restore_button_component: RestoreButton ## Restore button component instance -var _is_minimized: bool = false ## Current minimized state - -# Custom Loggie channel for receiving log messages -var _console_channel: LoggieConsoleChannel ## Direct channel integration with Loggie - -# Component coordination -var _filter_state: LogBuffer.FilterState ## Shared filter state between components - -# Persistence system -var _settings_manager: ConsoleSettingsManager ## Handles save/load operations -var _current_settings: LoggieConsoleSettings ## Current settings instance - -# Domain color management -var _domain_color_manager: DomainColorManager ## Centralized color management for all components - -## Initializes the console window and all its components -## -## This is the main initialization sequence that: -## 1. Loads persistent settings from disk -## 2. Applies window positioning and visibility settings -## 3. Initializes all components with loaded state -## 4. Sets up the custom Loggie channel for message reception -## 5. Connects all necessary signals for runtime operation -## -## The order is critical - settings must be loaded and applied before -## components are initialized to prevent unwanted signal emissions during startup. -func _ready() -> void: - # Initialize persistence system FIRST - _settings_manager = ConsoleSettingsManager.new() - _current_settings = _settings_manager.load_settings() - - _restore_button_component = RestoreButtonScene.instantiate() - _restore_button_component.restore_requested.connect(_on_restore_requested) - - # Apply window settings before component initialization - _apply_window_settings() - - # Connect window signals for persistence - close_requested.connect(_on_close_requested) - - # Initialize components with loaded settings - _initialize_components() - - # Setup save triggers after initialization - _setup_save_triggers() - - # Setup custom channel - _setup_console_channel() - - # Apply loaded filters after components are ready - _apply_loaded_settings() - -## Called by our custom LoggieConsoleChannel with complete message data -## -## This is the main message reception callback that receives log messages directly -## from the Loggie system through our custom channel. Unlike signal-based approaches, -## this provides complete type information including LogLevel and MsgType enums. -## -## @param msg: The original LoggieMsg with all metadata -## @param preprocessed_content: Fully formatted message text from Loggie -## @param msg_type: Message type enum (ERROR, WARNING, DEBUG, STANDARD) -## @param log_level: Log level enum (ERROR, WARN, NOTICE, INFO, DEBUG) -func receive_log_message(msg: LoggieMsg, preprocessed_content: String, msg_type: LoggieEnums.MsgType, log_level: LoggieEnums.LogLevel) -> void: - # Check if we need to add a new domain to our list - if not msg.domain_name.is_empty(): - domain_filter.add_domain(msg.domain_name) - - # Add message to buffer (buffer handles filtering internally) - buffer.add_message(msg, preprocessed_content, msg_type, log_level) - -## Sets up the custom Loggie channel for direct message reception -## -## Creates and registers a LoggieConsoleChannel that provides the console with -## direct access to log messages including complete type information. The channel -## is automatically added to the default channels list so it receives all messages -## by default, without requiring explicit channel targeting in log calls. -func _setup_console_channel() -> void: - # Create and register our custom channel - _console_channel = LoggieConsoleChannel.new() - _console_channel.set_console_window(self) - Loggie.add_channel(_console_channel) - - # Automatically add our channel to the default channels so console receives all messages - var current_defaults: Array = Loggie.settings.default_channels - if not current_defaults.has("loggie_console"): - var new_defaults: Array = current_defaults.duplicate() - new_defaults.append("loggie_console") - Loggie.settings.default_channels = new_defaults - -func _setup_domain_filter() -> void: - # Get all domains dynamically from Loggie - var initial_domains: Array[String] = [""] # Always include default domain - - # Get all registered domains from Loggie - for domain_name: String in Loggie.domains.keys(): - if not initial_domains.has(domain_name): - initial_domains.append(domain_name) - - # Add LoggieConsole internal domain (will appear unselected by default) - if not initial_domains.has(LoggieConsoleConstants.DOMAIN): - var all_domains: Array[String] = initial_domains.duplicate() - all_domains.append(LoggieConsoleConstants.DOMAIN) - - # Initialize the domain selector with all domains (including console domain) - domain_filter.set_domains_with_console_unselected(all_domains, initial_domains, [LoggieConsoleConstants.DOMAIN]) - else: - # Console domain already exists, use standard initialization - domain_filter.set_domains(initial_domains) - domain_filter.domains_changed.connect(_on_domains_changed) - - # Apply initial filter state to buffer (only enabled domains, not internal ones) - _filter_state.enabled_domains = initial_domains - buffer.set_filters(_filter_state) - -func _on_domains_changed(enabled_domains: Array[String]) -> void: - # Update filter state and apply to buffer - _filter_state.enabled_domains = enabled_domains - buffer.set_filters(_filter_state) - - - - -## New component event handlers - -func _on_log_level_changed(new_level: LoggieEnums.LogLevel) -> void: - # Update filter state and apply to buffer - _filter_state.min_log_level = new_level - buffer.set_filters(_filter_state) - -func _on_clear_requested() -> void: - # Clear the buffer - buffer.clear_all() - -func _on_scroll_follow_changed(enabled: bool) -> void: - # Update buffer scroll following - buffer.scroll_following = enabled - -func _on_text_search_changed(search_text: String) -> void: - # Update filter state and apply to buffer - _filter_state.text_search = search_text - buffer.set_filters(_filter_state) - -func _on_stack_filter_changed(enabled: bool) -> void: - # Update filter state and apply to buffer - _filter_state.show_stack_only = enabled - buffer.set_filters(_filter_state) - -func _on_buffer_filter_changed(visible_count: int, total_count: int) -> void: - # Update status display with current counts - var enabled_domains: Array[String] = domain_filter.get_enabled_domains() - var total_domains: int = enabled_domains.size() - if total_domains == 0: - total_domains = Loggie.domains.keys().size() + DEFAULT_DOMAIN_OFFSET - - status_display.update_status(total_count, visible_count, enabled_domains, total_domains) - - -## Minimize/Restore System - - -## Minimizes the console window and shows a floating restore button -## -## This hides the console window and creates a small floating "LOG" button in the -## top-right corner of the main viewport. The button allows restoring the console -## to its previous position and size. All settings are saved before minimizing -## to ensure state persistence. -func minimize_console() -> void: - if _is_minimized: - Loggie.msg("Already minimized, ignoring request").domain(LoggieConsoleConstants.DOMAIN).warn() - return - - # Save current settings including window state before minimizing - _capture_current_state() - _settings_manager.save_settings(_current_settings) - - _is_minimized = true - hide() # Hide the console window - _show_restore_button() - -## Creates and shows the restore button component -## -## Instantiates the RestoreButton scene and displays it in the root viewport. -## Connects the restore_requested signal to handle button clicks and restore the console. -func _show_restore_button() -> void: - _restore_button_component.show_restore_button(get_tree().root) - Loggie.msg("RestoreButton show_restore_button() called").domain(LoggieConsoleConstants.DOMAIN).debug() - -## Handles restore button click events from the RestoreButton component -## -## Called when the RestoreButton component emits its restore_requested signal. -## Triggers the console restoration process. -func _on_restore_requested() -> void: - restore_console() - -## Restores the console window from minimized state -## -## This shows the console window at its previously saved position and size, -## removes the floating restore button, and updates the minimized state. -## The window is restored exactly as it was when minimized. -func restore_console() -> void: - if not _is_minimized: - Loggie.msg("Not minimized, ignoring restore request").domain(LoggieConsoleConstants.DOMAIN).warn() - return - - # Restore to saved position and size from settings - position = _current_settings.window_position - size = _current_settings.window_size - - _is_minimized = false - show() # Show the console window - _hide_restore_button() - -## Hides and cleans up the restore button component -## -## Removes the RestoreButton component from the scene tree and frees its resources. -## Ensures proper cleanup when the console is restored from minimized state. -func _hide_restore_button() -> void: - if _restore_button_component and is_instance_valid(_restore_button_component): - _restore_button_component.hide_restore_button() - Loggie.msg("Restore button component cleaned up").domain(LoggieConsoleConstants.DOMAIN).debug() - -## Applies saved window properties to the console window -## Validates position to ensure window remains visible on current display setup -func _apply_window_settings() -> void: - # Check if we're using embedded subwindows - var subwindows_embedded: bool = ProjectSettings.get_setting("display/window/subwindows/embed_subwindows", true) - - var validated_pos: Vector2i - if subwindows_embedded and _is_outside_viewport(): - validated_pos = _center_window() - else: - # Use existing validation for separate windows or valid embedded positions - validated_pos = _current_settings.validate_window_position() - - position = validated_pos - - # Apply saved window dimensions - size = _current_settings.window_size - - # Apply visibility state - visible = _current_settings.is_visible - - # Apply minimized state (defer restore button creation) - _is_minimized = _current_settings.is_minimized - if _is_minimized: - hide() - # Defer restore button creation until scene tree is ready - _show_restore_button.call_deferred() - -## Checks if console window is outside the main viewport (for embedded subwindows) -func _is_outside_viewport() -> bool: - var viewport_size: Vector2i = Vector2i(get_tree().root.get_visible_rect().size) - var window_rect: Rect2i = Rect2i(_current_settings.window_position, _current_settings.window_size) - var viewport_rect: Rect2i = Rect2i(Vector2i.ZERO, viewport_size) - - # Return true if window is not completely within viewport or has invalid position - return _current_settings.window_position == Vector2i(-1, -1) or not viewport_rect.encloses(window_rect) - -## Centers the console window in the main viewport -func _center_window() -> Vector2i: - var viewport_size: Vector2i = Vector2i(get_tree().root.get_visible_rect().size) - const MARGIN = 50 - var centered_pos: Vector2i = (viewport_size - _current_settings.window_size) / 2 - return Vector2i(maxi(MARGIN, centered_pos.x), maxi(MARGIN, centered_pos.y)) - -## Initializes all console components with loaded settings before connecting signals -## This prevents unwanted signal emissions during the initialization process -func _initialize_components() -> void: - # Initialize base filter state - _filter_state = LogBuffer.FilterState.new() - - # Create domain color manager - _domain_color_manager = DomainColorManager.new() - - # Pass color manager to components that need it - buffer.set_color_manager(_domain_color_manager) - domain_filter.set_color_manager(_domain_color_manager) - - # Load persistent settings into each component - buffer.load_settings_from_resource(_current_settings) - domain_filter.load_settings_from_resource(_current_settings) - controls.load_settings_from_resource(_current_settings) - output_level.load_settings_from_resource(_current_settings) - - # Connect component signals for runtime interaction - output_level.level_changed.connect(_on_log_level_changed) - controls.clear_requested.connect(_on_clear_requested) - controls.scroll_follow_changed.connect(_on_scroll_follow_changed) - controls.text_search_changed.connect(_on_text_search_changed) - controls.stack_filter_changed.connect(_on_stack_filter_changed) - - # Configure buffer with loaded scroll following setting - buffer.filter_changed.connect(_on_buffer_filter_changed) - buffer.scroll_following = controls.is_scroll_follow_enabled() - - # Set up remaining console systems - _setup_domain_filter() - - # Initialize settings UI - _setup_settings_ui() - status_display.reset() - -## Finalizes the loading process by applying loaded filter settings -## Called after component initialization to ensure filters work with existing messages -func _apply_loaded_settings() -> void: - # Apply the loaded filter state to any existing messages - buffer.apply_loaded_filters() - - # Sync domain filter state to ensure consistency - domain_filter.domains_changed.emit(domain_filter.get_enabled_domains()) - - # Apply text size setting to theme - _apply_text_size_to_theme(_current_settings.text_size_multiplier) - - # Apply restore button alignment - _apply_restore_button_alignment(_current_settings.restore_button_alignment) - -## Placeholder for save triggers (not used in exit-tree persistence model) -func _setup_save_triggers() -> void: - pass # Settings saved only on exit tree - -## Captures current state from window and all components into the settings resource -## This is called before each save operation to ensure all current state is preserved -func _capture_current_state() -> void: - # Capture window properties - _current_settings.window_position = position - _current_settings.window_size = size - _current_settings.is_visible = visible - _current_settings.is_minimized = _is_minimized - - # Capture current display index (important when embed_subwindows=false) - _current_settings.display_index = _get_current_display_index() - - # Capture current embed_subwindows setting for change detection - _current_settings.update_embed_setting() - - # Let each component save its own state - buffer.save_settings_to_resource(_current_settings) - domain_filter.save_settings_to_resource(_current_settings) - controls.save_settings_to_resource(_current_settings) - output_level.save_settings_to_resource(_current_settings) - -## Manually saves current console settings to disk -## Useful for forcing a save before potentially destructive operations -func save_settings() -> void: - _capture_current_state() - _settings_manager.save_settings(_current_settings) - -## Handles window close requests by saving settings first, then minimizing -## This ensures settings are preserved even if the console is closed unexpectedly -func _on_close_requested() -> void: - # Preserve settings before minimizing - _capture_current_state() - _settings_manager.save_settings(_current_settings) - - # Continue with normal minimize behavior - minimize_console() - -## Automatically saves settings when console exits the scene tree -## This is the primary save mechanism ensuring settings persist between sessions -func _exit_tree() -> void: - if _settings_manager and _current_settings: - _capture_current_state() - _settings_manager.save_settings(_current_settings) - -## Handles system-level window destruction notifications -## Provides additional safety net for settings preservation -func _notification(what: int) -> void: - if what == NOTIFICATION_WM_CLOSE_REQUEST: - if _settings_manager and _current_settings: - _capture_current_state() - _settings_manager.save_settings(_current_settings) - -## Determines which display the console window is currently on -## Returns: Display index (0-based) where the window center is located -func _get_current_display_index() -> int: - # Calculate window center point - var window_center: Vector2i = position + size / 2 - - # Check which display contains the window center - var screens: int = DisplayServer.get_screen_count() - for i: int in screens: - var screen_rect: Rect2i = DisplayServer.screen_get_usable_rect(i) - if screen_rect.has_point(window_center): - return i - - # Fallback: find display with most window overlap - var max_overlap: int = 0 - var best_display: int = 0 - var window_rect: Rect2i = Rect2i(position, size) - - for i: int in screens: - var screen_rect: Rect2i = DisplayServer.screen_get_usable_rect(i) - var intersection: Rect2i = screen_rect.intersection(window_rect) - var overlap_area: int = intersection.size.x * intersection.size.y - if overlap_area > max_overlap: - max_overlap = overlap_area - best_display = i - - return best_display - -## Sets up the settings UI components and connects their signals -## -## Initializes the settings button and panel component, loads current settings, -## and connects the component's signals for handling settings changes. -func _setup_settings_ui() -> void: - # Get UI component references - _settings_button = get_node("PanelContainer/VBoxContainer/Controls/Settings") - _settings_panel = get_node("SettingsPanel") - - # Connect signals - _settings_button.pressed.connect(_on_settings_button_pressed) - _settings_panel.settings_applied.connect(_on_settings_applied) - _settings_panel.settings_reset.connect(_on_settings_reset) - - # Load current settings into the panel - _settings_panel.set_text_size_multiplier(_current_settings.text_size_multiplier) - _settings_panel.set_restore_button_alignment(_current_settings.restore_button_alignment) - -## Called when the Settings button is pressed -## -## Shows the settings panel dialog with current values loaded. -func _on_settings_button_pressed() -> void: - _settings_panel.show_settings() - -## Called when settings are applied via the settings panel -## -## Saves the new settings and applies them dynamically. -## @param text_size_multiplier: The new text size multiplier value -## @param restore_button_alignment: The new restore button alignment -func _on_settings_applied(text_size_multiplier: float, restore_button_alignment: RestoreButton.Alignment) -> void: - # Update settings - _current_settings.text_size_multiplier = text_size_multiplier - _current_settings.restore_button_alignment = restore_button_alignment as int - _settings_manager.save_settings(_current_settings) - - # Apply text size change to theme - _apply_text_size_to_theme(text_size_multiplier) - - # Apply restore button alignment - _apply_restore_button_alignment(restore_button_alignment as int) - - Loggie.msg("Settings updated: text size %.1fx, alignment %s" % [text_size_multiplier, _get_alignment_name(restore_button_alignment)]).domain(LoggieConsoleConstants.DOMAIN).info() - -## Called when the settings are reset to defaults -## -## Logs the reset action for user feedback. -func _on_settings_reset() -> void: - Loggie.msg("Settings reset to defaults").domain(LoggieConsoleConstants.DOMAIN).info() - -## Dynamically applies text size multiplier to the current theme -## -## Modifies font sizes in the theme resource at runtime to immediately -## reflect the new text size setting without requiring a restart. -## @param multiplier: Text size multiplier (0.5 to 2.0) -func _apply_text_size_to_theme(multiplier: float) -> void: - var console_theme: Theme = get_theme() - if not console_theme: - Loggie.msg("No theme found, cannot apply text size").domain(LoggieConsoleConstants.DOMAIN).error() - return - - # Define base font sizes (from theme_compact.tres) - var base_font_sizes: Dictionary = { - "Button/font_size": 11, - "CheckBox/font_size": 11, - "LineEdit/font_size": 12, - "MenuButton/font_size": 11, - "OptionButton/font_size": 11, - "PopupMenu/font_size": 11, - "RichTextLabel/bold_font_size": 10, - "RichTextLabel/bold_italics_font_size": 10, - "RichTextLabel/italics_font_size": 10, - "RichTextLabel/mono_font_size": 9, - "RichTextLabel/normal_font_size": 10, - "Window/title_font_size": 16 - } - - # Apply multiplier to each font size - for font_path: String in base_font_sizes: - var parts: PackedStringArray = font_path.split("/") - var control_type: String = parts[0] - var property: String = parts[1] - var base_size: int = base_font_sizes[font_path] - var new_size: int = int(base_size * multiplier) - - console_theme.set_font_size(property, control_type, new_size) - - # Theme changes are applied automatically - -## Applies the restore button alignment setting -## -## Updates the restore button position based on the alignment preference. -## @param alignment: Alignment enum value (0=TOP_LEFT, 1=TOP_RIGHT, 2=BOTTOM_LEFT, 3=BOTTOM_RIGHT) -func _apply_restore_button_alignment(alignment: int) -> void: - if not _restore_button_component: - return - - # Set position based on alignment using the RestoreButton's enum - var restore_alignment: RestoreButton.Alignment = alignment as RestoreButton.Alignment - _restore_button_component.set_alignment(restore_alignment) - -## Gets a human-readable name for the alignment enum -## -## @param alignment: The alignment enum value -## @return: String name of the alignment -func _get_alignment_name(alignment: RestoreButton.Alignment) -> String: - match alignment: - RestoreButton.Alignment.TOP_LEFT: - return "Top Left" - RestoreButton.Alignment.TOP_RIGHT: - return "Top Right" - RestoreButton.Alignment.BOTTOM_LEFT: - return "Bottom Left" - RestoreButton.Alignment.BOTTOM_RIGHT: - return "Bottom Right" - _: - return "Unknown" - - diff --git a/addons/loggie-console/scenes/console.gd.uid b/addons/loggie-console/scenes/console.gd.uid deleted file mode 100644 index 76842e9..0000000 --- a/addons/loggie-console/scenes/console.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://64r2in67soep diff --git a/addons/loggie-console/scenes/console.tscn b/addons/loggie-console/scenes/console.tscn deleted file mode 100644 index 9ae2b12..0000000 --- a/addons/loggie-console/scenes/console.tscn +++ /dev/null @@ -1,164 +0,0 @@ -[gd_scene format=3 uid="uid://d0sxs0is80byx"] - -[ext_resource type="Script" uid="uid://64r2in67soep" path="res://addons/loggie-console/scenes/console.gd" id="1_yp485"] -[ext_resource type="PackedScene" uid="uid://dgok5l3frx53m" path="res://addons/loggie-console/scenes/panel_domain_selector.tscn" id="2_domain"] -[ext_resource type="StyleBox" uid="uid://b7k8yo7jfhpue" path="res://addons/loggie-console/assets/inner_panel.tres" id="3_fxnpl"] -[ext_resource type="Script" uid="uid://wah8efffydnu" path="res://addons/loggie-console/scripts/components/log_buffer.gd" id="3_logbuffer"] -[ext_resource type="Theme" uid="uid://c1lnnysnspc6v" path="res://addons/loggie-console/theme_compact.tres" id="4_2cgp1"] -[ext_resource type="Script" uid="uid://d3l2tmf5gym1d" path="res://addons/loggie-console/scripts/components/log_level_filter.gd" id="4_loglevel"] -[ext_resource type="Script" uid="uid://c4f6c3gs8venj" path="res://addons/loggie-console/scripts/components/console_controls.gd" id="5_controls"] -[ext_resource type="Script" uid="uid://whrim6lbiako" path="res://addons/loggie-console/scripts/components/status_display.gd" id="6_status"] -[ext_resource type="Texture2D" uid="uid://ivppb5cqrsak" path="res://addons/loggie-console/assets/NinePatchWindow-InnerRecess.png" id="7_56hvo"] -[ext_resource type="PackedScene" uid="uid://bw8k3yap2n4qv" path="res://addons/loggie-console/scenes/settings_panel.tscn" id="7_settings_panel"] - -[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_20rq3"] -content_margin_left = 4.0 -content_margin_right = 4.0 -content_margin_bottom = 4.0 -texture = ExtResource("7_56hvo") -texture_margin_left = 2.0 -texture_margin_top = 2.0 -texture_margin_right = 2.0 -texture_margin_bottom = 2.0 -axis_stretch_horizontal = 1 -axis_stretch_vertical = 1 -region_rect = Rect2(0, 0, 36, 36) -modulate_color = Color(0.60933, 0.60933, 0.60933, 1) - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_njst7"] - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ibivl"] - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_0yrjc"] - -[node name="LoggieConsoleWindow" type="Window" unique_id=1024795111 node_paths=PackedStringArray("buffer", "output_level", "domain_filter", "controls", "status_display")] -oversampling_override = 1.0 -title = "Loggie Console" -initial_position = 1 -size = Vector2i(889, 905) -wrap_controls = true -sharp_corners = true -min_size = Vector2i(600, 300) -keep_title_visible = true -theme = ExtResource("4_2cgp1") -script = ExtResource("1_yp485") -buffer = NodePath("PanelContainer/VBoxContainer/PanelContainer/Buffer") -output_level = NodePath("PanelContainer/VBoxContainer/Controls/OutputLevel") -domain_filter = NodePath("PanelContainer/VBoxContainer/Controls/DomainFilter") -controls = NodePath("PanelContainer/VBoxContainer/Controls") -status_display = NodePath("PanelContainer/VBoxContainer/StatusContainer/HBoxContainer/StatusLabel") - -[node name="PanelContainer" type="PanelContainer" parent="." unique_id=1949067581] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -theme_override_styles/panel = ExtResource("3_fxnpl") - -[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer" unique_id=1611268808] -layout_mode = 2 - -[node name="Controls" type="HBoxContainer" parent="PanelContainer/VBoxContainer" unique_id=251197975 node_paths=PackedStringArray("clear_button", "scroll_follow_checkbox", "search_input", "stack_filter_checkbox")] -layout_mode = 2 -script = ExtResource("5_controls") -clear_button = NodePath("Clear") -scroll_follow_checkbox = NodePath("ScrollFollow") -search_input = NodePath("../StatusContainer/HBoxContainer/SearchInput") -stack_filter_checkbox = NodePath("StackFilter") - -[node name="OutputLevel" type="OptionButton" parent="PanelContainer/VBoxContainer/Controls" unique_id=751332603] -custom_minimum_size = Vector2(60, 20) -layout_mode = 2 -size_flags_horizontal = 0 -tooltip_text = "Filter by log level" -selected = 3 -item_count = 5 -popup/item_0/text = "ERROR" -popup/item_0/id = 0 -popup/item_1/text = "WARN" -popup/item_1/id = 1 -popup/item_2/text = "NOTICE" -popup/item_2/id = 2 -popup/item_3/text = "INFO" -popup/item_3/id = 3 -popup/item_4/text = "DEBUG" -popup/item_4/id = 4 -script = ExtResource("4_loglevel") - -[node name="ScrollFollow" type="CheckBox" parent="PanelContainer/VBoxContainer/Controls" unique_id=569696074] -custom_minimum_size = Vector2(50, 20) -layout_mode = 2 -size_flags_horizontal = 0 -tooltip_text = "Auto-scroll to newest messages" -button_pressed = true -text = "Follow" - -[node name="StackFilter" type="CheckBox" parent="PanelContainer/VBoxContainer/Controls" unique_id=719019705] -custom_minimum_size = Vector2(80, 20) -layout_mode = 2 -size_flags_horizontal = 0 -tooltip_text = "Show only messages with stack traces" -text = "Stack Only" - -[node name="Clear" type="Button" parent="PanelContainer/VBoxContainer/Controls" unique_id=1133245115] -custom_minimum_size = Vector2(45, 20) -layout_mode = 2 -size_flags_horizontal = 0 -tooltip_text = "Clear console buffer" -text = "Clear" - -[node name="Settings" type="Button" parent="PanelContainer/VBoxContainer/Controls" unique_id=671578664] -custom_minimum_size = Vector2(60, 20) -layout_mode = 2 -size_flags_horizontal = 0 -tooltip_text = "Console settings" -text = "Settings" - -[node name="DomainFilter" parent="PanelContainer/VBoxContainer/Controls" unique_id=582666238 instance=ExtResource("2_domain")] -custom_minimum_size = Vector2(300, 20) -layout_mode = 2 -size_flags_horizontal = 10 - -[node name="PanelContainer" type="PanelContainer" parent="PanelContainer/VBoxContainer" unique_id=2068430600] -layout_mode = 2 -size_flags_vertical = 3 -theme_override_styles/panel = SubResource("StyleBoxTexture_20rq3") - -[node name="Buffer" type="RichTextLabel" parent="PanelContainer/VBoxContainer/PanelContainer" unique_id=1261116881] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -focus_mode = 2 -theme_override_styles/normal = SubResource("StyleBoxEmpty_njst7") -theme_override_styles/focus = SubResource("StyleBoxEmpty_ibivl") -bbcode_enabled = true -scroll_following = true -context_menu_enabled = true -selection_enabled = true -script = ExtResource("3_logbuffer") - -[node name="StatusContainer" type="PanelContainer" parent="PanelContainer/VBoxContainer" unique_id=592277225] -layout_mode = 2 -theme_override_styles/panel = SubResource("StyleBoxEmpty_0yrjc") - -[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/VBoxContainer/StatusContainer" unique_id=958031751] -layout_mode = 2 - -[node name="SearchInput" type="LineEdit" parent="PanelContainer/VBoxContainer/StatusContainer/HBoxContainer" unique_id=526298685] -custom_minimum_size = Vector2(200, 20) -layout_mode = 2 -size_flags_horizontal = 2 -placeholder_text = "Filter messages..." -clear_button_enabled = true - -[node name="StatusLabel" type="Label" parent="PanelContainer/VBoxContainer/StatusContainer/HBoxContainer" unique_id=848734114] -layout_mode = 2 -size_flags_horizontal = 8 -theme_override_font_sizes/font_size = 12 -text = "Ready" -horizontal_alignment = 2 -vertical_alignment = 1 -script = ExtResource("6_status") - -[node name="SettingsPanel" parent="." unique_id=1146821245 instance=ExtResource("7_settings_panel")] diff --git a/addons/loggie-console/scenes/domain_item.tscn b/addons/loggie-console/scenes/domain_item.tscn deleted file mode 100644 index 8c9f9e7..0000000 --- a/addons/loggie-console/scenes/domain_item.tscn +++ /dev/null @@ -1,55 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://cjy8b6h1xrq2x"] - -[ext_resource type="Script" uid="uid://dgkxvw0v5n6hq" path="res://addons/loggie-console/scripts/components/domain_item.gd" id="1_domain_item"] -[ext_resource type="Theme" uid="uid://c1lnnysnspc6v" path="res://addons/loggie-console/theme_compact.tres" id="2_theme"] - -[node name="DomainItem" type="Control" node_paths=PackedStringArray("select_checkbox", "only_button", "color_indicator")] -custom_minimum_size = Vector2(280, 32) -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -theme = ExtResource("2_theme") -script = ExtResource("1_domain_item") -select_checkbox = NodePath("HBoxContainer/SelectCheckBox") -only_button = NodePath("OnlyButton") -color_indicator = NodePath("HBoxContainer/ColorIndicator") - -[node name="HBoxContainer" type="HBoxContainer" parent="."] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="ColorIndicator" type="ColorRect" parent="HBoxContainer"] -custom_minimum_size = Vector2(12, 12) -layout_mode = 2 - -[node name="SelectCheckBox" type="CheckBox" parent="HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -tooltip_text = "Select/deselect this domain" -theme_override_constants/h_separation = 20 -text_overrun_behavior = 3 - -[node name="OnlyButton" type="Button" parent="."] -modulate = Color(1, 1, 1, 0) -custom_minimum_size = Vector2(45, 24) -layout_mode = 1 -anchors_preset = 6 -anchor_left = 1.0 -anchor_top = 0.5 -anchor_right = 1.0 -anchor_bottom = 0.5 -offset_left = -45.0 -offset_top = -12.0 -offset_bottom = 12.0 -grow_horizontal = 0 -grow_vertical = 2 -tooltip_text = "Select only this domain" -mouse_filter = 2 -text = "Only" diff --git a/addons/loggie-console/scenes/panel_domain_selector.tscn b/addons/loggie-console/scenes/panel_domain_selector.tscn deleted file mode 100644 index 55239a8..0000000 --- a/addons/loggie-console/scenes/panel_domain_selector.tscn +++ /dev/null @@ -1,86 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://dgok5l3frx53m"] - -[ext_resource type="Script" uid="uid://bfmpjs4x3fhte" path="res://addons/loggie-console/scripts/components/panel_domain_selector.gd" id="1_panel_selector"] -[ext_resource type="Theme" uid="uid://c1lnnysnspc6v" path="res://addons/loggie-console/theme_compact.tres" id="2_theme"] -[ext_resource type="StyleBox" uid="uid://b7k8yo7jfhpue" path="res://addons/loggie-console/assets/inner_panel.tres" id="3_panel_style"] - -[node name="PanelDomainSelector" type="Control" node_paths=PackedStringArray("trigger_button", "domain_panel", "select_all_button", "select_none_button", "scroll_container", "domain_list")] -custom_minimum_size = Vector2(100, 20) -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -theme = ExtResource("2_theme") -script = ExtResource("1_panel_selector") -trigger_button = NodePath("TriggerButton") -domain_panel = NodePath("DomainPanel") -select_all_button = NodePath("DomainPanel/PanelContainer/VBoxContainer/SelectionControls/SelectAllButton") -select_none_button = NodePath("DomainPanel/PanelContainer/VBoxContainer/SelectionControls/SelectNoneButton") -scroll_container = NodePath("DomainPanel/PanelContainer/VBoxContainer/ScrollContainer") -domain_list = NodePath("DomainPanel/PanelContainer/VBoxContainer/ScrollContainer/DomainList") - -[node name="TriggerButton" type="Button" parent="."] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -tooltip_text = "All domains selected (1)" -text = "Domains: All" -text_overrun_behavior = 3 - -[node name="DomainPanel" type="PopupPanel" parent="."] -initial_position = 1 -size = Vector2i(300, 160) -visible = true -min_size = Vector2i(300, 150) - -[node name="PanelContainer" type="PanelContainer" parent="DomainPanel"] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 2.0 -offset_top = 2.0 -offset_right = -2.0 -offset_bottom = -2.0 -grow_horizontal = 2 -grow_vertical = 2 -theme_override_styles/panel = ExtResource("3_panel_style") - -[node name="VBoxContainer" type="VBoxContainer" parent="DomainPanel/PanelContainer"] -layout_mode = 2 - -[node name="SelectionControls" type="HBoxContainer" parent="DomainPanel/PanelContainer/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 0 -alignment = 2 - -[node name="SelectAllButton" type="Button" parent="DomainPanel/PanelContainer/VBoxContainer/SelectionControls"] -custom_minimum_size = Vector2(60, 20) -layout_mode = 2 -size_flags_horizontal = 0 -tooltip_text = "Select all domains" -text = "Select All" - -[node name="SelectNoneButton" type="Button" parent="DomainPanel/PanelContainer/VBoxContainer/SelectionControls"] -custom_minimum_size = Vector2(60, 20) -layout_mode = 2 -size_flags_horizontal = 0 -tooltip_text = "Deselect all domains" -text = "None" - -[node name="HSeparator" type="HSeparator" parent="DomainPanel/PanelContainer/VBoxContainer"] -layout_mode = 2 - -[node name="ScrollContainer" type="ScrollContainer" parent="DomainPanel/PanelContainer/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="DomainList" type="VBoxContainer" parent="DomainPanel/PanelContainer/VBoxContainer/ScrollContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - diff --git a/addons/loggie-console/scenes/restore_button.tscn b/addons/loggie-console/scenes/restore_button.tscn deleted file mode 100644 index 168ce3b..0000000 --- a/addons/loggie-console/scenes/restore_button.tscn +++ /dev/null @@ -1,29 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://cb5mkvrnm3hxn"] - -[ext_resource type="Script" uid="uid://dmyd1gquxy42u" path="res://addons/loggie-console/scripts/components/restore_button.gd" id="1_2h8k5"] -[ext_resource type="Theme" uid="uid://c1lnnysnspc6v" path="res://addons/loggie-console/theme_compact.tres" id="1_o01pp"] - -[node name="LoggieConsoleOverlay" type="CanvasLayer" node_paths=PackedStringArray("restore_button")] -layer = 2147483647 -script = ExtResource("1_2h8k5") -restore_button = NodePath("MarginContainer/Button") - -[node name="MarginContainer" type="MarginContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -mouse_filter = 2 -theme_override_constants/margin_left = 5 -theme_override_constants/margin_top = 5 -theme_override_constants/margin_right = 5 -theme_override_constants/margin_bottom = 5 - -[node name="Button" type="Button" parent="MarginContainer"] -layout_mode = 2 -size_flags_horizontal = 8 -size_flags_vertical = 0 -tooltip_text = "Show Loggie Console" -theme = ExtResource("1_o01pp") -text = " Loggie Console " diff --git a/addons/loggie-console/scenes/settings_panel.tscn b/addons/loggie-console/scenes/settings_panel.tscn deleted file mode 100644 index b817dc0..0000000 --- a/addons/loggie-console/scenes/settings_panel.tscn +++ /dev/null @@ -1,90 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://bw8k3yap2n4qv"] - -[ext_resource type="Theme" uid="uid://c1lnnysnspc6v" path="res://addons/loggie-console/theme_compact.tres" id="1_08jdj"] -[ext_resource type="Script" uid="uid://giuyu6vhhgam" path="res://addons/loggie-console/scripts/components/settings_panel.gd" id="1_settings_panel"] -[ext_resource type="StyleBox" uid="uid://b7k8yo7jfhpue" path="res://addons/loggie-console/assets/inner_panel.tres" id="2_08jdj"] - -[node name="SettingsPanel" type="AcceptDialog" node_paths=PackedStringArray("_text_size_slider", "_text_size_value_label", "_reset_button", "_alignment_option")] -title = "Console Settings" -initial_position = 1 -size = Vector2i(320, 210) -transient = false -sharp_corners = true -theme = ExtResource("1_08jdj") -theme_override_styles/panel = ExtResource("2_08jdj") -ok_button_text = " Apply Changes " -script = ExtResource("1_settings_panel") -_text_size_slider = NodePath("VBoxContainer/TextSizeContainer/TextSizeSlider") -_text_size_value_label = NodePath("VBoxContainer/TextSizeContainer/TextSizeValueLabel") -_reset_button = NodePath("VBoxContainer/ResetContainer/ResetButton") -_alignment_option = NodePath("VBoxContainer/AlignmentContainer/AlignmentOption") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -38.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="TextSizeContainer" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 - -[node name="TextSizeLabel" type="Label" parent="VBoxContainer/TextSizeContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -text = "Text Size:" -vertical_alignment = 1 - -[node name="TextSizeSlider" type="HSlider" parent="VBoxContainer/TextSizeContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -min_value = 0.5 -max_value = 2.0 -step = 0.1 -value = 1.0 -tick_count = 16 -ticks_on_borders = true - -[node name="TextSizeValueLabel" type="Label" parent="VBoxContainer/TextSizeContainer"] -custom_minimum_size = Vector2(40, 0) -layout_mode = 2 -size_flags_horizontal = 0 -text = "1.0x" -horizontal_alignment = 2 -vertical_alignment = 1 - -[node name="AlignmentContainer" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 - -[node name="AlignmentLabel" type="Label" parent="VBoxContainer/AlignmentContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -text = "Restore Button:" -vertical_alignment = 1 - -[node name="AlignmentOption" type="OptionButton" parent="VBoxContainer/AlignmentContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -selected = 1 -item_count = 4 -popup/item_0/text = "Top Left" -popup/item_0/id = 0 -popup/item_1/text = "Top Right" -popup/item_1/id = 1 -popup/item_2/text = "Bottom Left" -popup/item_2/id = 2 -popup/item_3/text = "Bottom Right" -popup/item_3/id = 3 - -[node name="ResetContainer" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 -alignment = 1 - -[node name="ResetButton" type="Button" parent="VBoxContainer/ResetContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -text = "Reset to Default" diff --git a/addons/loggie-console/scripts/components/console_controls.gd b/addons/loggie-console/scripts/components/console_controls.gd deleted file mode 100644 index 27aee6c..0000000 --- a/addons/loggie-console/scripts/components/console_controls.gd +++ /dev/null @@ -1,104 +0,0 @@ -class_name ConsoleControls extends HBoxContainer - -## Console controls toolbar component -## Manages clear button, scroll follow, and other control elements - -const LoggieConsoleSettings = preload("res://addons/loggie-console/resources/loggie_console_settings.gd") - -# Signals -signal clear_requested() -signal scroll_follow_changed(enabled: bool) -signal text_search_changed(search_text: String) -signal stack_filter_changed(enabled: bool) - -# Exported references to child controls -@export var clear_button: Button -@export var scroll_follow_checkbox: CheckBox -@export var search_input: LineEdit -@export var stack_filter_checkbox: CheckBox - -func _ready() -> void: - _setup_controls() - -## Initialize the controls with default states -func initialize() -> void: - if scroll_follow_checkbox: - scroll_follow_checkbox.button_pressed = true - _on_scroll_follow_toggled(true) - -## Get current scroll follow state -func is_scroll_follow_enabled() -> bool: - return scroll_follow_checkbox.button_pressed if scroll_follow_checkbox else false - -## Set scroll follow state programmatically -func set_scroll_follow(enabled: bool) -> void: - if scroll_follow_checkbox: - scroll_follow_checkbox.button_pressed = enabled - -## Get current text search -func get_search_text() -> String: - return search_input.text if search_input else "" - -## Set search text programmatically -func set_search_text(text: String) -> void: - if search_input: - search_input.text = text - -## Get current stack filter state -func is_stack_filter_enabled() -> bool: - return stack_filter_checkbox.button_pressed if stack_filter_checkbox else false - -## Set stack filter state programmatically -func set_stack_filter(enabled: bool) -> void: - if stack_filter_checkbox: - stack_filter_checkbox.button_pressed = enabled - -## Private methods - -func _setup_controls() -> void: - # Connect clear button if available - if clear_button: - clear_button.pressed.connect(_on_clear_pressed) - clear_button.tooltip_text = "Clear console buffer" - - # Connect scroll follow checkbox if available - if scroll_follow_checkbox: - scroll_follow_checkbox.toggled.connect(_on_scroll_follow_toggled) - scroll_follow_checkbox.tooltip_text = "Auto-scroll to newest messages" - - # Connect search input if available - if search_input: - search_input.text_changed.connect(_on_search_text_changed) - search_input.placeholder_text = "Filter messages..." - - # Connect stack filter checkbox if available - if stack_filter_checkbox: - stack_filter_checkbox.toggled.connect(_on_stack_filter_toggled) - stack_filter_checkbox.tooltip_text = "Show only messages with stack traces" - -func _on_clear_pressed() -> void: - clear_requested.emit() - -func _on_scroll_follow_toggled(enabled: bool) -> void: - scroll_follow_changed.emit(enabled) - -func _on_search_text_changed(new_text: String) -> void: - text_search_changed.emit(new_text) - -func _on_stack_filter_toggled(enabled: bool) -> void: - stack_filter_changed.emit(enabled) - -## Saves current toolbar control states to persistent settings -## Param settings: The settings resource to populate with current control states -func save_settings_to_resource(settings: LoggieConsoleSettings) -> void: - settings.scroll_follow_enabled = is_scroll_follow_enabled() - settings.search_text = get_search_text() - settings.stack_filter_enabled = is_stack_filter_enabled() - -## Loads toolbar control states from persistent settings and applies them -## Updates all UI controls to reflect the loaded state without emitting signals -## Param settings: The settings resource containing saved control states -func load_settings_from_resource(settings: LoggieConsoleSettings) -> void: - set_scroll_follow(settings.scroll_follow_enabled) - set_search_text(settings.search_text) - set_stack_filter(settings.stack_filter_enabled) diff --git a/addons/loggie-console/scripts/components/console_controls.gd.uid b/addons/loggie-console/scripts/components/console_controls.gd.uid deleted file mode 100644 index c088a09..0000000 --- a/addons/loggie-console/scripts/components/console_controls.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c4f6c3gs8venj diff --git a/addons/loggie-console/scripts/components/domain_item.gd b/addons/loggie-console/scripts/components/domain_item.gd deleted file mode 100644 index b0b92e6..0000000 --- a/addons/loggie-console/scripts/components/domain_item.gd +++ /dev/null @@ -1,166 +0,0 @@ -class_name DomainItem extends Control - -## Custom control for individual domain rows in PanelDomainSelector -## Provides checkbox selection, domain label, and hover-revealed "Only" button - -const DomainColorManager = preload("res://addons/loggie-console/scripts/domain_color_manager.gd") - -# Signals -signal selection_changed(domain_name: String, is_selected: bool) -signal only_button_pressed(domain_name: String) - -# UI Components - exported for scene tree assignment -@export var select_checkbox: CheckBox -@export var only_button: Button -@export var color_indicator: ColorRect - -# Domain state -var _domain_name: String = "" -var _is_hovered: bool = false -var _color_manager: DomainColorManager - -# UI Layout constants -const ITEM_MIN_WIDTH: int = 280 -const ITEM_MIN_HEIGHT: int = 32 - -# Visibility constants for only button hover effect -const ONLY_BUTTON_ALPHA_HIDDEN: float = 0.0 -const ONLY_BUTTON_ALPHA_VISIBLE: float = 1.0 - -## Initializes the domain item control with UI connections and hover behavior -## -## Sets up consistent sizing, signal connections for checkbox and button interactions, -## and configures mouse hover detection for the "Only" button visibility toggle. -## The only button starts hidden and becomes visible on hover with smooth alpha transition. -## Requires select_checkbox and only_button to be properly assigned via @export. -func _ready() -> void: - if not select_checkbox: - return - - # Set minimum size for consistent layout - custom_minimum_size = Vector2(ITEM_MIN_WIDTH, ITEM_MIN_HEIGHT) - - # Connect signals - select_checkbox.toggled.connect(_on_checkbox_toggled) - only_button.pressed.connect(_on_only_button_pressed) - - # Setup hover detection on checkbox (which now contains the text) - select_checkbox.mouse_entered.connect(_on_mouse_entered) - select_checkbox.mouse_exited.connect(_on_mouse_exited) - - # Also setup hover detection on the main control for complete coverage - mouse_entered.connect(_on_mouse_entered) - mouse_exited.connect(_on_mouse_exited) - - - # Initialize only button as hidden - only_button.modulate.a = ONLY_BUTTON_ALPHA_HIDDEN - only_button.mouse_filter = Control.MOUSE_FILTER_IGNORE - -## Set the domain color manager instance -func set_color_manager(color_manager: DomainColorManager) -> void: - _color_manager = color_manager - -## Configures the domain item with a specific domain name and selection state -## -## Sets up the checkbox display text (shows "(default)" for empty domain names), -## configures tooltips for both checkbox and only button, and applies the initial -## selection state. This method should be called after the item is added to the scene tree. -## -## @param domain_name: The domain name to display and track -## @param is_selected: Whether the domain should start as selected -func setup_domain(domain_name: String, is_selected: bool = false) -> void: - _domain_name = domain_name - - if select_checkbox: - var display_name = domain_name if not domain_name.is_empty() else "(default)" - - # Update color indicator instead of modulating checkbox - if _color_manager and color_indicator: - var domain_color = _color_manager.get_domain_color(domain_name) - color_indicator.color = domain_color - - select_checkbox.text = display_name - select_checkbox.tooltip_text = "Select/deselect domain: " + domain_name - select_checkbox.button_pressed = is_selected - - if only_button: - only_button.text = "Only" - only_button.tooltip_text = "Select only this domain: " + domain_name - -## Get the domain name for this item -func get_domain_name() -> String: - return _domain_name - -## Updates the checkbox selection state without emitting signals -## -## Useful for programmatically setting the selection state during bulk operations -## like "Select All" or when loading from saved settings. Uses set_pressed_no_signal -## to avoid triggering selection_changed signals during these operations. -## -## @param is_selected: The new selection state for the checkbox -func set_selected(is_selected: bool) -> void: - if select_checkbox: - select_checkbox.set_pressed_no_signal(is_selected) - -## Get current selection state -func is_selected() -> bool: - return select_checkbox.button_pressed if select_checkbox else false - -## Private methods - -func _on_checkbox_toggled(pressed: bool) -> void: - selection_changed.emit(_domain_name, pressed) - -func _on_only_button_pressed() -> void: - only_button_pressed.emit(_domain_name) - - -func _on_mouse_entered() -> void: - _is_hovered = true - _set_only_button_visibility(true) - -func _on_mouse_exited() -> void: - _is_hovered = false - _set_only_button_visibility(false) - -## Controls the visibility and interaction of the "Only" button based on hover state -## -## Instantly toggles the button's alpha transparency and mouse filter to create -## a hover-reveal effect. When hidden, the button becomes completely transparent -## and ignores mouse input. When visible, it becomes fully opaque and interactive. -## -## @param show: Whether to show (true) or hide (false) the only button -func _set_only_button_visibility(show: bool) -> void: - if not only_button: - return - - # Set visibility instantly - no animation - var target_alpha = ONLY_BUTTON_ALPHA_VISIBLE if show else ONLY_BUTTON_ALPHA_HIDDEN - var target_mouse_filter = Control.MOUSE_FILTER_PASS if show else Control.MOUSE_FILTER_IGNORE - - only_button.modulate.a = target_alpha - only_button.mouse_filter = target_mouse_filter - -func _gui_input(event: InputEvent) -> void: - # Handle keyboard navigation - if event is InputEventKey and event.pressed: - match event.keycode: - KEY_SPACE, KEY_ENTER: - if select_checkbox: - select_checkbox.button_pressed = not select_checkbox.button_pressed - _on_checkbox_toggled(select_checkbox.button_pressed) - accept_event() - KEY_O: - if event.ctrl_pressed: # Ctrl+O for "Only" - _on_only_button_pressed() - accept_event() - -func _notification(what: int) -> void: - match what: - NOTIFICATION_FOCUS_ENTER: - # Add visual focus indication if needed - pass - NOTIFICATION_FOCUS_EXIT: - # Remove visual focus indication if needed - pass diff --git a/addons/loggie-console/scripts/components/domain_item.gd.uid b/addons/loggie-console/scripts/components/domain_item.gd.uid deleted file mode 100644 index b2931e5..0000000 --- a/addons/loggie-console/scripts/components/domain_item.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dgkxvw0v5n6hq \ No newline at end of file diff --git a/addons/loggie-console/scripts/components/domain_selector.gd b/addons/loggie-console/scripts/components/domain_selector.gd deleted file mode 100644 index 64d76c0..0000000 --- a/addons/loggie-console/scripts/components/domain_selector.gd +++ /dev/null @@ -1,256 +0,0 @@ -class_name DomainSelector extends MenuButton - -## Standalone domain selector component for filtering log messages by domain -## Provides clean interface with proper signal-based communication - -const LoggieConsoleSettings = preload("res://addons/loggie-console/resources/loggie_console_settings.gd") -const DomainColorManager = preload("res://addons/loggie-console/scripts/domain_color_manager.gd") - -# Signals -signal domains_changed(enabled_domains: Array[String]) - -# Properties -var _enabled_domains: Array[String] = [] -var _all_domains: Array[String] = [] -var _domain_popup: PopupMenu -var _color_manager: DomainColorManager - -# Constants -const ALL_ITEM_ID = 0 -const SEPARATOR_ID = 1 -const DOMAIN_ID_OFFSET = 2 - - -func _ready() -> void: - _domain_popup = get_popup() - _domain_popup.id_pressed.connect(_on_domain_selected) - _initialize_empty_state() - -## Set the domain color manager instance -func set_color_manager(color_manager: DomainColorManager) -> void: - _color_manager = color_manager - -## Initialize the selector with available domains -func set_domains(domains: Array[String]) -> void: - _all_domains = domains.duplicate() - _enabled_domains = domains.duplicate() - _rebuild_popup() - _update_button_text() - domains_changed.emit(_enabled_domains) - -## Initialize the selector with all domains, but only enable selected ones -## Console domains appear normally but are unselected by default -func set_domains_with_console_unselected(all_domains: Array[String], enabled_domains: Array[String], console_domains: Array[String]) -> void: - _all_domains = all_domains.duplicate() - _enabled_domains = enabled_domains.duplicate() - _rebuild_popup_with_console_unselected(console_domains) - _update_button_text() - domains_changed.emit(_enabled_domains) - -## Add a new domain to the selector (for dynamic discovery) -func add_domain(domain_name: String) -> void: - if domain_name.is_empty() or _all_domains.has(domain_name): - return - - _all_domains.append(domain_name) - _enabled_domains.append(domain_name) - - # Add new item to popup with color icon - var display_name = _get_domain_display_name(domain_name) - var color_icon = _create_domain_color_icon(domain_name) - var item_id = _get_domain_item_id(_all_domains.size() - 1) - - _domain_popup.add_check_item(display_name, item_id) - _domain_popup.set_item_icon(item_id, color_icon) - _domain_popup.set_item_checked(item_id, true) - - _update_all_checkbox() - _update_button_text() - domains_changed.emit(_enabled_domains) - -## Get currently enabled domains -func get_enabled_domains() -> Array[String]: - return _enabled_domains.duplicate() - -## Check if a domain is enabled -func is_domain_enabled(domain_name: String) -> bool: - return _enabled_domains.has(domain_name) - -## Private methods - -## Create colored icon for domain display in popup -func _create_domain_color_icon(domain_name: String, size: int = 12) -> ImageTexture: - var color: Color = Color.WHITE # Default color - if _color_manager: - color = _color_manager.get_domain_color(domain_name) - - # Create a small colored square image - var image = Image.create(size, size, false, Image.FORMAT_RGBA8) - image.fill(color) - - # Convert to texture - var texture: ImageTexture = ImageTexture.create_from_image(image) - return texture - -## Get display name for domain (without color formatting) -func _get_domain_display_name(domain_name: String) -> String: - return domain_name if not domain_name.is_empty() else "(default)" - -func _initialize_empty_state() -> void: - _domain_popup.clear() - _domain_popup.add_item("No domains available") - _domain_popup.set_item_disabled(0, true) - text = "Domains: None" - -func _rebuild_popup() -> void: - _domain_popup.clear() - - # Add "All" toggle - _domain_popup.add_check_item("All", ALL_ITEM_ID) - _domain_popup.set_item_checked(ALL_ITEM_ID, _enabled_domains.size() == _all_domains.size()) - - # Add separator - _domain_popup.add_separator() - - # Add individual domain items with color icons - for i in range(_all_domains.size()): - var domain_name = _all_domains[i] - var display_name = _get_domain_display_name(domain_name) - var color_icon = _create_domain_color_icon(domain_name) - var item_id = _get_domain_item_id(i) - - _domain_popup.add_check_item(display_name, item_id) - _domain_popup.set_item_icon(item_id, color_icon) - _domain_popup.set_item_checked(item_id, _enabled_domains.has(domain_name)) - -## Builds popup with console domain unselected by default (no separator) -func _rebuild_popup_with_console_unselected(console_domains: Array[String]) -> void: - _domain_popup.clear() - - # Add "All" toggle (only for non-console domains) - _domain_popup.add_check_item("All", ALL_ITEM_ID) - var non_console_domains = [] - for domain in _all_domains: - if not console_domains.has(domain): - non_console_domains.append(domain) - _domain_popup.set_item_checked(ALL_ITEM_ID, _enabled_domains.size() == non_console_domains.size()) - - # Add separator - _domain_popup.add_separator() - - # Add all domain items in order with color icons - for i in range(_all_domains.size()): - var domain_name = _all_domains[i] - var display_name: String - - # Use friendly name for console domain - if console_domains.has(domain_name): - display_name = "LoggieConsole" # Simplified name for console domain - else: - display_name = domain_name if not domain_name.is_empty() else "(default)" - - # Create color icon for the domain - var color_icon = _create_domain_color_icon(domain_name) - - var item_id = _get_domain_item_id(i) - _domain_popup.add_check_item(display_name, item_id) - _domain_popup.set_item_icon(item_id, color_icon) - _domain_popup.set_item_checked(item_id, _enabled_domains.has(domain_name)) - -func _on_domain_selected(id: int) -> void: - if id == ALL_ITEM_ID: - _toggle_all_domains() - else: - _toggle_individual_domain(id) - - _update_all_checkbox() - _update_button_text() - domains_changed.emit(_enabled_domains) - -func _toggle_all_domains() -> void: - var current_all_state = _domain_popup.is_item_checked(ALL_ITEM_ID) - var new_all_state = not current_all_state - - # Update all checkbox - _domain_popup.set_item_checked(ALL_ITEM_ID, new_all_state) - - # Update all domain checkboxes and enabled list - _enabled_domains.clear() - for i in range(_all_domains.size()): - var item_id = _get_domain_item_id(i) - _domain_popup.set_item_checked(item_id, new_all_state) - if new_all_state: - _enabled_domains.append(_all_domains[i]) - -func _toggle_individual_domain(id: int) -> void: - var domain_index = _get_domain_index_from_id(id) - if domain_index < 0 or domain_index >= _all_domains.size(): - Loggie.msg("Invalid domain index %d for ID %d" % [domain_index, id]).domain(LoggieConsoleConstants.DOMAIN).warn() - return - - var domain_name = _all_domains[domain_index] - var current_state = _domain_popup.is_item_checked(id) - var new_state = not current_state - - # Update checkbox - _domain_popup.set_item_checked(id, new_state) - - # Update enabled domains list - if new_state and not _enabled_domains.has(domain_name): - _enabled_domains.append(domain_name) - elif not new_state and _enabled_domains.has(domain_name): - _enabled_domains.erase(domain_name) - -func _update_all_checkbox() -> void: - var all_enabled = _enabled_domains.size() == _all_domains.size() - _domain_popup.set_item_checked(ALL_ITEM_ID, all_enabled) - -func _update_button_text() -> void: - var enabled_count = _enabled_domains.size() - var total_count = _all_domains.size() - - if total_count == 0: - text = "Domains: None" - elif enabled_count == total_count: - text = "Domains: All" - elif enabled_count == 0: - text = "Domains: None" - elif enabled_count == 1: - var domain_name = _enabled_domains[0] - var display_name = _get_domain_display_name(domain_name) - text = "Domains: " + display_name - else: - text = "Domains: %d selected" % enabled_count - -func _get_domain_item_id(domain_index: int) -> int: - return DOMAIN_ID_OFFSET + domain_index - -func _get_domain_index_from_id(item_id: int) -> int: - return item_id - DOMAIN_ID_OFFSET - -## Saves current domain selection state to persistent settings -## Param settings: The settings resource to populate with current domain state -func save_settings_to_resource(settings: LoggieConsoleSettings) -> void: - settings.enabled_domains = _enabled_domains.duplicate() - settings.all_known_domains = _all_domains.duplicate() - -## Loads domain selection state from persistent settings and rebuilds UI -## Automatically validates that enabled domains still exist in the known domains list -## Param settings: The settings resource containing saved domain state -func load_settings_from_resource(settings: LoggieConsoleSettings) -> void: - _all_domains = settings.all_known_domains.duplicate() - _enabled_domains = settings.enabled_domains.duplicate() - - # Remove any enabled domains that no longer exist in all_domains - var valid_enabled_domains: Array[String] = [] - for domain in _enabled_domains: - if _all_domains.has(domain): - valid_enabled_domains.append(domain) - _enabled_domains = valid_enabled_domains - - # Rebuild UI to reflect loaded state - if _all_domains.size() > 0: - _rebuild_popup() - _update_button_text() - else: - _initialize_empty_state() diff --git a/addons/loggie-console/scripts/components/domain_selector.gd.uid b/addons/loggie-console/scripts/components/domain_selector.gd.uid deleted file mode 100644 index 679268a..0000000 --- a/addons/loggie-console/scripts/components/domain_selector.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bq6xlpjg4qoca diff --git a/addons/loggie-console/scripts/components/log_buffer.gd b/addons/loggie-console/scripts/components/log_buffer.gd deleted file mode 100644 index 80fc2dc..0000000 --- a/addons/loggie-console/scripts/components/log_buffer.gd +++ /dev/null @@ -1,209 +0,0 @@ -class_name LogBuffer extends RichTextLabel - -## Enhanced message buffer with retroactive filtering capabilities -## Stores all messages and applies filters dynamically without losing data - -const LoggieConsoleSettings = preload("res://addons/loggie-console/resources/loggie_console_settings.gd") -const DomainColorManager = preload("res://addons/loggie-console/scripts/domain_color_manager.gd") - -# Signals -signal filter_changed(visible_count: int, total_count: int) - -# Internal message storage -var _all_messages: Array[LogMessage] = [] -var _filtered_messages: Array[LogMessage] = [] -var _current_filters: FilterState - -# Domain color manager reference -var _color_manager: DomainColorManager - -# Memory management constants -const DEFAULT_MAX_MESSAGES: int = 5000 -const CLEANUP_PERCENTAGE: float = 0.2 # Remove 20% of messages when limit reached - -# Memory management -@export var max_messages: int = DEFAULT_MAX_MESSAGES - -## Internal LogMessage class for storing complete message data -class LogMessage: - var msg: LoggieMsg - var preprocessed_content: String - var msg_type: LoggieEnums.MsgType - var log_level: LoggieEnums.LogLevel - var timestamp: float - var enhanced_content: String - - func _init(p_msg: LoggieMsg, p_content: String, p_type: LoggieEnums.MsgType, p_level: LoggieEnums.LogLevel) -> void: - msg = p_msg - preprocessed_content = p_content - msg_type = p_type - log_level = p_level - timestamp = Time.get_unix_time_from_system() - -## Filter state for retroactive filtering -class FilterState: - var enabled_domains: Array[String] = [] - var min_log_level: LoggieEnums.LogLevel = LoggieEnums.LogLevel.DEBUG - var text_search: String = "" - var show_stack_only: bool = false - - func _init() -> void: - # Initialize to show ERROR and above by default (lower numbers = higher priority) - min_log_level = LoggieEnums.LogLevel.DEBUG - -func _ready() -> void: - _current_filters = FilterState.new() - bbcode_enabled = true - -## Set the domain color manager instance -func set_color_manager(color_manager: DomainColorManager) -> void: - _color_manager = color_manager - -## Add a new log message to the buffer -func add_message(msg: LoggieMsg, content: String, msg_type: LoggieEnums.MsgType, log_level: LoggieEnums.LogLevel) -> void: - # Create and store the message - var log_msg: LogMessage = LogMessage.new(msg, content, msg_type, log_level) - log_msg.enhanced_content = _enhance_with_metadata(log_msg) - - _all_messages.append(log_msg) - - # Manage memory if needed - _manage_memory() - - # Apply current filters and rebuild display - _reapply_filters() - -## Set new filter state and reapply filters -func set_filters(filter_state: FilterState) -> void: - _current_filters = filter_state - _reapply_filters() - -## Set text search filter -func set_text_search(search: String) -> void: - if _current_filters.text_search == search: - return - - _current_filters.text_search = search - _reapply_filters() - -## Clear all messages -func clear_all() -> void: - _all_messages.clear() - _filtered_messages.clear() - text = "" - clear() - - # Emit updated counts - filter_changed.emit(0, 0) - -## Get current message counts -func get_message_counts() -> Dictionary: - return { - "total": _all_messages.size(), - "filtered": _filtered_messages.size() - } - -## Saves current buffer state to persistent settings resource -## Param settings: The settings resource to populate with current state -func save_settings_to_resource(settings: LoggieConsoleSettings) -> void: - settings.filter_state.from_filter_state(_current_filters) - settings.max_messages = max_messages - -## Loads buffer state from persistent settings resource -## Note: Does not immediately apply filters to avoid triggering reapply before messages exist -## Param settings: The settings resource containing saved state -func load_settings_from_resource(settings: LoggieConsoleSettings) -> void: - if settings.filter_state: - _current_filters = settings.filter_state.to_filter_state() - max_messages = settings.max_messages - -## Applies previously loaded filter state to existing messages -## Call this after load_settings_from_resource() and message loading is complete -func apply_loaded_filters() -> void: - _reapply_filters() - - -## Private methods - -func _reapply_filters() -> void: - _filtered_messages.clear() - - for msg in _all_messages: - if msg != null and _message_passes_filters(msg, _current_filters): - _filtered_messages.append(msg) - - _rebuild_display() - - # Emit filter change signal - filter_changed.emit(_filtered_messages.size(), _all_messages.size()) - -func _message_passes_filters(msg: LogMessage, filters: FilterState) -> bool: - # Domain check - if no domains are enabled, show no messages - if filters.enabled_domains.size() == 0: - return false - - # If domains are enabled, check if this message's domain is in the enabled list - if not filters.enabled_domains.has(msg.msg.domain_name): - return false - - # Level check - show messages at or above the minimum level (lower numbers = higher priority) - if msg.log_level > filters.min_log_level: - return false - - # Text search - if not filters.text_search.is_empty(): - var search_lower: String = filters.text_search.to_lower() - if not msg.preprocessed_content.to_lower().contains(search_lower): - return false - - # Stack filter - if filters.show_stack_only and not msg.msg.appends_stack: - return false - - return true - -func _rebuild_display() -> void: - # Clear current display - text = "" - clear() - - # Add all filtered messages - for msg in _filtered_messages: - text += msg.enhanced_content + "\n" - -func _enhance_with_metadata(msg: LogMessage) -> String: - var metadata_parts: Array[String] = [] - - metadata_parts.append("[color=%s]%s [/color]" % [Color.DIM_GRAY.to_html(false), Time.get_time_string_from_unix_time(int(msg.timestamp))]) - - if msg.msg.domain_name and not msg.msg.domain_name.is_empty(): - var domain_color_html: String = _color_manager.get_domain_color_html(msg.msg.domain_name) - metadata_parts.append("[color=%s]%s[/color]" % [domain_color_html, msg.msg.domain_name]) - - if msg.msg.domain_name and not msg.msg.domain_name.is_empty(): - metadata_parts.append("[color=%s][%s] [/color]" % [_get_color_for_log_level(msg.log_level).to_html(false), LoggieEnums.LogLevel.keys()[msg.log_level]]) - - return "%s %s" % [" ".join(metadata_parts), msg.msg.content[0]] - -func _get_color_for_log_level(level: LoggieEnums.LogLevel) -> Color: - match level: - LoggieEnums.LogLevel.ERROR: - return Color.RED - LoggieEnums.LogLevel.WARN: - return Color.ORANGE - LoggieEnums.LogLevel.NOTICE: - return Color.GREEN - LoggieEnums.LogLevel.INFO: - return Color.WHITE - LoggieEnums.LogLevel.DEBUG, _: - return Color.AQUA - -## Manages memory by removing oldest messages when buffer limit exceeded -## Uses CLEANUP_PERCENTAGE constant to determine how many messages to remove -func _manage_memory() -> void: - if _all_messages.size() > max_messages: - # Remove oldest messages based on cleanup percentage - var remove_count: int = int(max_messages * CLEANUP_PERCENTAGE) - _all_messages = _all_messages.slice(remove_count) - # Note: This will cause filtered_messages indices to be invalid, - # but _reapply_filters() will be called which rebuilds it diff --git a/addons/loggie-console/scripts/components/log_buffer.gd.uid b/addons/loggie-console/scripts/components/log_buffer.gd.uid deleted file mode 100644 index b7b792d..0000000 --- a/addons/loggie-console/scripts/components/log_buffer.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://wah8efffydnu diff --git a/addons/loggie-console/scripts/components/log_level_filter.gd b/addons/loggie-console/scripts/components/log_level_filter.gd deleted file mode 100644 index 62a9cb7..0000000 --- a/addons/loggie-console/scripts/components/log_level_filter.gd +++ /dev/null @@ -1,62 +0,0 @@ -class_name LogLevelFilter extends OptionButton - -## Standalone log level filter component -## Manages log level selection and syncs with Loggie settings - -const LoggieConsoleSettings = preload("res://addons/loggie-console/resources/loggie_console_settings.gd") - -# Signals -signal level_changed(new_level: LoggieEnums.LogLevel) - -func _ready() -> void: - _setup_level_options() - item_selected.connect(_on_level_selected) - tooltip_text = "Filter by log level" - -## Initialize with current Loggie settings -func initialize() -> void: - selected = Loggie.settings.log_level - level_changed.emit(Loggie.settings.log_level) - -## Get currently selected log level -func get_current_level() -> LoggieEnums.LogLevel: - if selected >= 0 and selected < get_item_count(): - return get_item_id(selected) as LoggieEnums.LogLevel - return LoggieEnums.LogLevel.DEBUG - -## Set log level programmatically -func set_log_level(level: LoggieEnums.LogLevel) -> void: - for i in range(get_item_count()): - if get_item_id(i) == level: - selected = i - break - -## Private methods - -func _setup_level_options() -> void: - clear() - - # Add all log levels as options - for value in LoggieEnums.LogLevel.values(): - var label: String = LoggieEnums.LogLevel.keys()[value] - add_item(label, value) - -func _on_level_selected(index: int) -> void: - var new_level = get_item_id(index) as LoggieEnums.LogLevel - - # Update Loggie settings - Loggie.settings.log_level = new_level - - # Emit change signal - level_changed.emit(new_level) - -## Saves current log level selection to persistent settings -## Param settings: The settings resource to populate with current log level -func save_settings_to_resource(settings: LoggieConsoleSettings) -> void: - settings.set_log_level(get_current_level()) - -## Loads log level selection from persistent settings and applies it -## Updates the UI control to reflect the loaded level without emitting change signals -## Param settings: The settings resource containing saved log level -func load_settings_from_resource(settings: LoggieConsoleSettings) -> void: - set_log_level(settings.get_log_level()) diff --git a/addons/loggie-console/scripts/components/log_level_filter.gd.uid b/addons/loggie-console/scripts/components/log_level_filter.gd.uid deleted file mode 100644 index 85b2fbb..0000000 --- a/addons/loggie-console/scripts/components/log_level_filter.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d3l2tmf5gym1d diff --git a/addons/loggie-console/scripts/components/panel_domain_selector.gd b/addons/loggie-console/scripts/components/panel_domain_selector.gd deleted file mode 100644 index b87e621..0000000 --- a/addons/loggie-console/scripts/components/panel_domain_selector.gd +++ /dev/null @@ -1,381 +0,0 @@ -class_name PanelDomainSelector extends Control - -## Panel-based domain selector component for filtering log messages by domain -## Provides enhanced UI with vertical list, hover "Only" buttons, and Apply/Cancel workflow -## Drop-in replacement for MenuButton-based DomainSelector with identical API - -const LoggieConsoleSettings = preload("res://addons/loggie-console/resources/loggie_console_settings.gd") -const LoggieConsoleConstants = preload("res://addons/loggie-console/scripts/loggie_console_constants.gd") -const DomainItemScene = preload("res://addons/loggie-console/scenes/domain_item.tscn") -const DomainColorManager = preload("res://addons/loggie-console/scripts/domain_color_manager.gd") - -# Signals - maintains API compatibility with existing DomainSelector -signal domains_changed(enabled_domains: Array[String]) - -# UI Components - exported for scene tree assignment -@export var trigger_button: Button -@export var domain_panel: PopupPanel -@export var select_all_button: Button -@export var select_none_button: Button -@export var scroll_container: ScrollContainer -@export var domain_list: VBoxContainer - -# Domain management -var _all_domains: Array[String] = [] -var _enabled_domains: Array[String] = [] - -# Domain item tracking -var _domain_items: Array[DomainItem] = [] - -# Panel state tracking -var _panel_is_open: bool = false - -# Color management -var _color_manager: DomainColorManager - -# Panel sizing constants -const PANEL_WIDTH: int = 300 -const PANEL_MAX_HEIGHT: int = 400 -const PANEL_MIN_HEIGHT: int = 150 - -# Panel positioning constants -const PANEL_VERTICAL_GAP: int = 2 -const PANEL_HORIZONTAL_MARGIN: int = 10 - -# Domain item layout constants -const DOMAIN_ITEM_HEIGHT: int = 32 -const PANEL_HEADER_HEIGHT: int = 40 -const PANEL_SELECTION_CONTROLS_HEIGHT: int = 28 -const PANEL_FOOTER_HEIGHT: int = 40 -const PANEL_PADDING: int = 20 - - -## Initializes the panel domain selector component -## -## Sets up UI connections, panel sizing, and attempts to load domains from Loggie. -## If no domains are found, initializes an empty state. All UI components must be -## properly assigned via @export variables in the scene for initialization to succeed. -func _ready() -> void: - if not trigger_button: - _initialize_empty_state() - return - - domain_panel.hide() - - # Connect UI signals - trigger_button.pressed.connect(_on_trigger_button_pressed) - select_all_button.pressed.connect(_on_select_all_button_pressed) - select_none_button.pressed.connect(_on_select_none_button_pressed) - - # Connect popup signals to track state - domain_panel.popup_hide.connect(_on_panel_hidden) - domain_panel.about_to_popup.connect(_on_panel_about_to_show) - - # Set initial panel size - domain_panel.size = Vector2(PANEL_WIDTH, PANEL_MIN_HEIGHT) - - # Try to initialize with real Loggie domains first - _initialize_domains_from_loggie() - - # If no domains found, show empty state - if _all_domains.is_empty(): - _initialize_empty_state() - -## Set the domain color manager instance -func set_color_manager(color_manager: DomainColorManager) -> void: - _color_manager = color_manager - -## Initialize the selector with available domains -func set_domains(domains: Array[String]) -> void: - _all_domains = domains.duplicate() - _enabled_domains = domains.duplicate() - _rebuild_domain_list() - _update_trigger_button_text() - domains_changed.emit(_enabled_domains) - -## Initialize the selector with all domains, but only enable selected ones -## Console domains appear normally but are unselected by default -func set_domains_with_console_unselected(all_domains: Array[String], enabled_domains: Array[String], _console_domains: Array[String]) -> void: - _all_domains = all_domains.duplicate() - _enabled_domains = enabled_domains.duplicate() - _rebuild_domain_list() - _update_trigger_button_text() - domains_changed.emit(_enabled_domains) - -## Add a new domain to the selector (for dynamic discovery) -func add_domain(domain_name: String) -> void: - if domain_name.is_empty() or _all_domains.has(domain_name): - return - - _all_domains.append(domain_name) - _enabled_domains.append(domain_name) - - _add_domain_item(domain_name, true) - _update_trigger_button_text() - _update_panel_size() - domains_changed.emit(_enabled_domains) - -## Get currently enabled domains -func get_enabled_domains() -> Array[String]: - return _enabled_domains.duplicate() - -## Check if a domain is enabled -func is_domain_enabled(domain_name: String) -> bool: - return _enabled_domains.has(domain_name) - -## Saves current domain selection state to persistent settings -func save_settings_to_resource(settings: LoggieConsoleSettings) -> void: - settings.enabled_domains = _enabled_domains.duplicate() - settings.all_known_domains = _all_domains.duplicate() - -## Loads domain selection state from persistent settings and rebuilds UI -func load_settings_from_resource(settings: LoggieConsoleSettings) -> void: - _all_domains = settings.all_known_domains.duplicate() - _enabled_domains = settings.enabled_domains.duplicate() - - # Remove any enabled domains that no longer exist in all_domains - var valid_enabled_domains: Array[String] = [] - for domain in _enabled_domains: - if _all_domains.has(domain): - valid_enabled_domains.append(domain) - _enabled_domains = valid_enabled_domains - - # Rebuild UI to reflect loaded state - if _all_domains.size() > 0: - _rebuild_domain_list() - _update_trigger_button_text() - else: - _initialize_empty_state() - -## Private methods - -func _initialize_empty_state() -> void: - if trigger_button: - trigger_button.text = "Domains: None" - trigger_button.tooltip_text = "No domains available" - -func _initialize_domains_from_loggie() -> void: - # Query Loggie for registered domains - if not Loggie: - return - - var loggie_domains: Array[String] = [] - - # Get domains from Loggie's registered domains - for domain_name: String in Loggie.domains.keys(): - if not domain_name.is_empty(): - loggie_domains.append(domain_name) - - # If we found domains, initialize with them - if loggie_domains.size() > 0: - set_domains(loggie_domains) - Loggie.msg("Initialized domain selector with %d domains from Loggie" % loggie_domains.size()).domain(LoggieConsoleConstants.DOMAIN).info() - else: - _initialize_empty_state() - -## Refresh domains from Loggie (useful for dynamic discovery) -func refresh_domains_from_loggie() -> void: - if not Loggie: - return - - var _current_domains: Array[String] = _all_domains.duplicate() - var loggie_domains: Array[String] = [] - - # Get current domains from Loggie - for domain_name: String in Loggie.domains.keys(): - if not domain_name.is_empty(): - loggie_domains.append(domain_name) - - # Add any new domains we discovered - var new_domains_added: bool = false - for domain_name in loggie_domains: - if not _all_domains.has(domain_name): - add_domain(domain_name) - new_domains_added = true - - if new_domains_added: - Loggie.msg("Discovered new domains from Loggie").domain(LoggieConsoleConstants.DOMAIN).info() - -func _on_trigger_button_pressed() -> void: - if _all_domains.is_empty(): - return - - # Only open panel if not already open (button disabled when open) - if not _panel_is_open: - # Position and show panel - domain_panel.popup() - _position_panel() - - -func _on_select_all_button_pressed() -> void: - # Select all domains instantly - _enabled_domains = _all_domains.duplicate() - _update_domain_items_state() - _update_trigger_button_text() - domains_changed.emit(_enabled_domains) - -func _on_select_none_button_pressed() -> void: - # Deselect all domains instantly - _enabled_domains.clear() - _update_domain_items_state() - _update_trigger_button_text() - domains_changed.emit(_enabled_domains) - -## Intelligently positions the domain selection panel relative to the trigger button -## -## Calculates optimal panel placement considering viewport boundaries and trigger button -## position. Prefers positioning below and left-aligned to the trigger button, but will -## adjust to above or right-aligned if necessary to keep the panel fully visible. -## Ensures minimum margins from viewport edges for accessibility. -func _position_panel() -> void: - if not trigger_button: - return - - # Get trigger button global position and size - var button_global_pos: Vector2 = trigger_button.global_position - - var button_size: Vector2 = trigger_button.size - await get_tree().process_frame - var panel_size: Vector2 = domain_panel.size - - # Get viewport rect for boundary checking - var viewport: Viewport = get_viewport() - var viewport_rect: Rect2 = viewport.get_visible_rect() - - # Position directly below button, aligned to left edge - var panel_pos: Vector2i = Vector2i( - button_global_pos.x, - button_global_pos.y + button_size.y + PANEL_VERTICAL_GAP - ) - - # Check if panel would go off-screen horizontally - if panel_pos.x + panel_size.x > viewport_rect.size.x: - # Align to right edge of button instead - panel_pos.x = button_global_pos.x + button_size.x - panel_size.x - # Ensure still within bounds - panel_pos.x = max(PANEL_HORIZONTAL_MARGIN, panel_pos.x) - - # Check if panel would go off-screen vertically - if panel_pos.y + panel_size.y > viewport_rect.size.y: - # Position above button instead - panel_pos.y = button_global_pos.y - panel_size.y - PANEL_VERTICAL_GAP - - # Final boundary check - panel_pos.x = max(PANEL_HORIZONTAL_MARGIN, min(panel_pos.x, viewport_rect.size.x - panel_size.x - PANEL_HORIZONTAL_MARGIN)) - panel_pos.y = max(PANEL_HORIZONTAL_MARGIN, min(panel_pos.y, viewport_rect.size.y - panel_size.y - PANEL_HORIZONTAL_MARGIN)) - - domain_panel.position = get_window().position + panel_pos - -func _rebuild_domain_list() -> void: - # Clear existing domain items - _clear_domain_items() - - # Create new domain items - for domain_name in _all_domains: - var is_enabled: bool = _enabled_domains.has(domain_name) - _add_domain_item(domain_name, is_enabled) - - _update_panel_size() - -func _clear_domain_items() -> void: - for item in _domain_items: - if is_instance_valid(item): - item.queue_free() - _domain_items.clear() - - # Clear any remaining children - for child in domain_list.get_children(): - child.queue_free() - -func _add_domain_item(domain_name: String, is_enabled: bool) -> void: - var item: DomainItem = DomainItemScene.instantiate() - - # Add to scene first - domain_list.add_child(item) - _domain_items.append(item) - - # Set color manager if available - if _color_manager: - item.set_color_manager(_color_manager) - - # Setup domain after adding to scene tree (ensures _ready is called first) - item.setup_domain(domain_name, is_enabled) - - # Connect signals - item.selection_changed.connect(_on_domain_item_selection_changed) - item.only_button_pressed.connect(_on_domain_item_only_pressed) - -## Dynamically adjusts panel size based on the number of domain items -## -## Calculates the optimal panel height by summing all component heights (header, -## selection controls, domain items, footer, and padding). Clamps the result between -## minimum and maximum height constraints to ensure usability and prevent overflow. -func _update_panel_size() -> void: - if not domain_panel or _domain_items.is_empty(): - return - - # Calculate required height based on content - var required_height: int = PANEL_HEADER_HEIGHT + PANEL_SELECTION_CONTROLS_HEIGHT + (_domain_items.size() * DOMAIN_ITEM_HEIGHT) + PANEL_FOOTER_HEIGHT + PANEL_PADDING - var final_height: int = clamp(required_height, PANEL_MIN_HEIGHT, PANEL_MAX_HEIGHT) - - domain_panel.size = Vector2(PANEL_WIDTH, final_height) - -func _update_trigger_button_text() -> void: - if not trigger_button: - return - - var enabled_count: int = _enabled_domains.size() - var total_count: int = _all_domains.size() - - if total_count == 0: - trigger_button.text = "Domains: None" - trigger_button.tooltip_text = "No domains available" - elif enabled_count == total_count: - trigger_button.text = "Domains: All" - trigger_button.tooltip_text = "All domains selected (%d)" % total_count - elif enabled_count == 0: - trigger_button.text = "Domains: None" - trigger_button.tooltip_text = "No domains selected" - elif enabled_count == 1: - var domain_name: String = _enabled_domains[0] - var display_name: String = domain_name if not domain_name.is_empty() else "(default)" - trigger_button.text = "Domains: " + display_name - trigger_button.tooltip_text = "Selected: " + display_name - else: - trigger_button.text = "Domains: %d selected" % enabled_count - trigger_button.tooltip_text = "%d of %d domains selected" % [enabled_count, total_count] - -func _update_domain_items_state() -> void: - for item in _domain_items: - if is_instance_valid(item): - var domain_name: String = item.get_domain_name() - var is_enabled: bool = _enabled_domains.has(domain_name) - item.set_selected(is_enabled) - -func _on_domain_item_selection_changed(domain_name: String, is_selected: bool) -> void: - if is_selected and not _enabled_domains.has(domain_name): - _enabled_domains.append(domain_name) - elif not is_selected and _enabled_domains.has(domain_name): - _enabled_domains.erase(domain_name) - - # Update UI and emit change immediately - _update_trigger_button_text() - domains_changed.emit(_enabled_domains) - -func _on_domain_item_only_pressed(domain_name: String) -> void: - # Clear all selections and select only this domain instantly - _enabled_domains.clear() - _enabled_domains.append(domain_name) - _update_domain_items_state() - _update_trigger_button_text() - domains_changed.emit(_enabled_domains) - -func _on_panel_about_to_show() -> void: - _panel_is_open = true - if trigger_button: - trigger_button.disabled = true - -func _on_panel_hidden() -> void: - _panel_is_open = false - if trigger_button: - trigger_button.disabled = false diff --git a/addons/loggie-console/scripts/components/panel_domain_selector.gd.uid b/addons/loggie-console/scripts/components/panel_domain_selector.gd.uid deleted file mode 100644 index 9e8b0cc..0000000 --- a/addons/loggie-console/scripts/components/panel_domain_selector.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bfmpjs4x3fhte \ No newline at end of file diff --git a/addons/loggie-console/scripts/components/restore_button.gd b/addons/loggie-console/scripts/components/restore_button.gd deleted file mode 100644 index 5574b4b..0000000 --- a/addons/loggie-console/scripts/components/restore_button.gd +++ /dev/null @@ -1,123 +0,0 @@ -class_name RestoreButton extends CanvasLayer - -## Floating restore button component for minimized LoggieConsole -## -## Self-contained overlay button that appears when the console is minimized. -## Handles its own positioning, styling, and lifecycle management with proper -## cleanup when the console is restored. Designed to be added to the root viewport -## for maximum visibility across all scenes. - -const LoggieConsoleConstants = preload("res://addons/loggie-console/scripts/loggie_console_constants.gd") - -# Alignment constants -enum Alignment { - TOP_LEFT = 0, - TOP_RIGHT = 1, - BOTTOM_LEFT = 2, - BOTTOM_RIGHT = 3 -} - -# Signals -signal restore_requested() ## Emitted when user clicks the restore button -@export var restore_button: Button - -## Initializes the restore button component and sets up styling -## -## Configures the canvas layer for maximum rendering priority, sets up the -## container to fill the viewport, and applies professional styling to the -## restore button. All UI components must be properly assigned via @export. -func _ready() -> void: - Loggie.msg("RestoreButton _ready() called").domain(LoggieConsoleConstants.DOMAIN).debug() - - # Connect button signal - restore_button.pressed.connect(_on_restore_button_pressed) - - Loggie.msg("RestoreButton initialization complete").domain(LoggieConsoleConstants.DOMAIN).debug() - -## Shows the restore button by adding it to the provided scene tree root -## -## This method expects to be called from a parent that has access to the scene tree. -## The parent should pass the root viewport so this component can add itself properly. -## -## @param root_viewport: The root viewport where the button should be added -func show_restore_button(root_viewport: Window = null) -> void: - Loggie.msg("RestoreButton show_restore_button() method called").domain(LoggieConsoleConstants.DOMAIN).debug() - - if not root_viewport: - Loggie.msg("No root viewport available for restore button").domain(LoggieConsoleConstants.DOMAIN).error() - return - - root_viewport.add_child(self) - Loggie.msg("Restore button added to root viewport: %s" % root_viewport.name).domain(LoggieConsoleConstants.DOMAIN).debug() - await get_tree().process_frame - # Ensure visibility - visible = true - Loggie.msg("Restore button visibility set to true").domain(LoggieConsoleConstants.DOMAIN).debug() - - # Force positioning update and debug info - await get_tree().process_frame - -## Hides and removes the restore button from the scene tree -## -## Safely removes the button from its parent and hides it. Handles cleanup -## and ensures proper resource management when the console is restored. -func hide_restore_button() -> void: - Loggie.msg("Hiding restore button").domain(LoggieConsoleConstants.DOMAIN).debug() - - visible = false - - # Remove from parent if attached - if get_parent(): - get_parent().remove_child(self) - Loggie.msg("Restore button removed from parent").domain(LoggieConsoleConstants.DOMAIN).debug() - -## Sets the alignment position of the restore button -## -## Updates the button's position flags to align it to the specified corner of the screen. -## @param alignment: The alignment enum value (TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT) -func set_alignment(alignment: Alignment) -> void: - if not restore_button: - Loggie.msg("RestoreButton not found, cannot set alignment").domain(LoggieConsoleConstants.DOMAIN).warn() - return - - match alignment: - Alignment.TOP_LEFT: - restore_button.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN # 0 = left align - restore_button.size_flags_vertical = Control.SIZE_SHRINK_BEGIN # 0 = top align - Alignment.TOP_RIGHT: - restore_button.size_flags_horizontal = Control.SIZE_SHRINK_END # 8 = right align - restore_button.size_flags_vertical = Control.SIZE_SHRINK_BEGIN # 0 = top align - Alignment.BOTTOM_LEFT: - restore_button.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN # 0 = left align - restore_button.size_flags_vertical = Control.SIZE_SHRINK_END # 8 = bottom align - Alignment.BOTTOM_RIGHT: - restore_button.size_flags_horizontal = Control.SIZE_SHRINK_END # 8 = right align - restore_button.size_flags_vertical = Control.SIZE_SHRINK_END # 8 = bottom align - - Loggie.msg("Restore button alignment set to: %s" % _get_alignment_name(alignment)).domain(LoggieConsoleConstants.DOMAIN).debug() - -## Gets a human-readable name for the alignment enum -## -## @param alignment: The alignment enum value -## @return: String name of the alignment -func _get_alignment_name(alignment: Alignment) -> String: - match alignment: - Alignment.TOP_LEFT: - return "Top Left" - Alignment.TOP_RIGHT: - return "Top Right" - Alignment.BOTTOM_LEFT: - return "Bottom Left" - Alignment.BOTTOM_RIGHT: - return "Bottom Right" - _: - return "Unknown" - -## Handles restore button click events -## -## Emits the restore_requested signal when the button is pressed, allowing -## the parent console to handle the actual restore logic while keeping -## this component focused solely on UI concerns. -func _on_restore_button_pressed() -> void: - Loggie.msg("Restore button pressed").domain(LoggieConsoleConstants.DOMAIN).debug() - restore_requested.emit() diff --git a/addons/loggie-console/scripts/components/restore_button.gd.uid b/addons/loggie-console/scripts/components/restore_button.gd.uid deleted file mode 100644 index ed782fd..0000000 --- a/addons/loggie-console/scripts/components/restore_button.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dmyd1gquxy42u diff --git a/addons/loggie-console/scripts/components/settings_panel.gd b/addons/loggie-console/scripts/components/settings_panel.gd deleted file mode 100644 index 0e68368..0000000 --- a/addons/loggie-console/scripts/components/settings_panel.gd +++ /dev/null @@ -1,125 +0,0 @@ -class_name LoggieConsoleSettingsPanel extends AcceptDialog - -## Standalone settings panel component for LoggieConsole -## -## This component provides a clean, reusable interface for adjusting console settings -## such as text size multiplier. It emits signals when settings are changed and provides -## methods to get/set current values. -## -## Signals: -## - settings_applied(text_size_multiplier: float): Emitted when Apply is clicked -## - settings_reset(): Emitted when Reset to Default is clicked -## -## Public Methods: -## - set_text_size_multiplier(value: float): Sets the current text size value -## - get_text_size_multiplier() -> float: Gets the current text size value -## - reset_to_defaults(): Resets all settings to default values - -## Emitted when the user clicks Apply with current settings -signal settings_applied(text_size_multiplier: float, restore_button_alignment: RestoreButton.Alignment) - -## Emitted when the user clicks Reset to Default -signal settings_reset() - -# UI component references - assigned via editor -@export var _text_size_slider: HSlider -@export var _text_size_value_label: Label -@export var _reset_button: Button -@export var _alignment_option: OptionButton ## Optional - may be null in simplified versions - -# Constants -const DEFAULT_TEXT_SIZE_MULTIPLIER: float = 1.0 -const MIN_TEXT_SIZE_MULTIPLIER: float = 0.5 -const MAX_TEXT_SIZE_MULTIPLIER: float = 2.0 -const DEFAULT_RESTORE_BUTTON_ALIGNMENT: RestoreButton.Alignment = RestoreButton.Alignment.TOP_RIGHT - -## Initializes the settings panel and connects internal signals -func _ready() -> void: - # Connect internal UI signals - _text_size_slider.value_changed.connect(_on_text_size_slider_changed) - _reset_button.pressed.connect(_on_reset_button_pressed) - confirmed.connect(_on_apply_pressed) - - # Initialize display - _update_text_size_label(_text_size_slider.value) - -## Sets the text size multiplier value -## -## Updates the slider position and display label to reflect the new value. -## The value is automatically clamped to the valid range (0.5 to 2.0). -## -## @param value: The text size multiplier (will be clamped to valid range) -func set_text_size_multiplier(value: float) -> void: - var clamped_value: float = clampf(value, MIN_TEXT_SIZE_MULTIPLIER, MAX_TEXT_SIZE_MULTIPLIER) - _text_size_slider.value = clamped_value - _update_text_size_label(clamped_value) - -## Gets the current text size multiplier value -## -## @return: The current text size multiplier value from the slider -func get_text_size_multiplier() -> float: - return _text_size_slider.value - -## Sets the restore button alignment -## -## Updates the alignment option button to reflect the new value. -## If the alignment option doesn't exist, the setting is ignored. -## @param alignment: The restore button alignment enum value -func set_restore_button_alignment(alignment: RestoreButton.Alignment) -> void: - if _alignment_option: - _alignment_option.selected = alignment as int - -## Gets the current restore button alignment -## -## @return: The current restore button alignment as an enum value, or default if option doesn't exist -func get_restore_button_alignment() -> RestoreButton.Alignment: - if _alignment_option: - return _alignment_option.selected as RestoreButton.Alignment - else: - return DEFAULT_RESTORE_BUTTON_ALIGNMENT - -## Resets all settings to their default values -## -## This method resets both text size multiplier and alignment to defaults and emits the settings_reset signal. -func reset_to_defaults() -> void: - set_text_size_multiplier(DEFAULT_TEXT_SIZE_MULTIPLIER) - set_restore_button_alignment(DEFAULT_RESTORE_BUTTON_ALIGNMENT) - settings_reset.emit() - -## Shows the settings panel centered on screen -## -## Convenience method that wraps popup_centered() for easier API usage. -func show_settings() -> void: - popup_centered() - -## Called when the text size slider value changes -## -## Updates the value display label to show the current multiplier. -## @param value: The new slider value -func _on_text_size_slider_changed(value: float) -> void: - _update_text_size_label(value) - -## Called when the Reset to Default button is pressed -## -## Resets settings to defaults and emits the settings_reset signal. -func _on_reset_button_pressed() -> void: - reset_to_defaults() - -## Called when the Apply button is pressed -## -## Emits the settings_applied signal with the current settings values. -func _on_apply_pressed() -> void: - settings_applied.emit(get_text_size_multiplier(), get_restore_button_alignment()) - -## Updates the text size value label to show the current multiplier -## -## @param value: The text size multiplier to display -func _update_text_size_label(value: float) -> void: - _text_size_value_label.text = "%.1fx" % value - -## Validates that a text size multiplier value is within acceptable bounds -## -## @param value: The value to validate -## @return: True if the value is valid, false otherwise -func is_valid_text_size_multiplier(value: float) -> bool: - return value >= MIN_TEXT_SIZE_MULTIPLIER and value <= MAX_TEXT_SIZE_MULTIPLIER diff --git a/addons/loggie-console/scripts/components/settings_panel.gd.uid b/addons/loggie-console/scripts/components/settings_panel.gd.uid deleted file mode 100644 index e5f3561..0000000 --- a/addons/loggie-console/scripts/components/settings_panel.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://giuyu6vhhgam diff --git a/addons/loggie-console/scripts/components/status_display.gd b/addons/loggie-console/scripts/components/status_display.gd deleted file mode 100644 index c6dc66e..0000000 --- a/addons/loggie-console/scripts/components/status_display.gd +++ /dev/null @@ -1,55 +0,0 @@ -class_name StatusDisplay extends Label - -## Standalone status display component for console information -## Shows message counts, filter status, and real-time feedback - -func _ready() -> void: - text = "Ready" - horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT - -## Update status with message and domain information -func update_status(total_messages: int, filtered_messages: int, enabled_domains: Array[String], total_domains: int) -> void: - var status_text = "" - - if total_messages == 0: - status_text = "Ready" - else: - # Message count display - if filtered_messages == total_messages: - status_text = "%d msgs" % total_messages - else: - status_text = "%d/%d msgs" % [filtered_messages, total_messages] - - # Domain filter info - if total_domains > 0 and enabled_domains.size() < total_domains: - status_text += " | %d/%d domains" % [enabled_domains.size(), total_domains] - - text = status_text - -## Update status when only message counts change (simpler version) -func update_message_counts(total_messages: int, filtered_messages: int) -> void: - if total_messages == 0: - text = "Ready" - elif filtered_messages == total_messages: - text = "%d msgs" % total_messages - else: - text = "%d/%d msgs" % [filtered_messages, total_messages] - -## Show search status when text filtering is active -## @param search_term: Current search filter text -## @param results_count: Number of messages matching the search -## @param total_count: Total number of messages in buffer -func update_search_status(search_term: String, results_count: int, total_count: int) -> void: - if search_term.is_empty(): - update_message_counts(total_count, results_count) - else: - text = "Search: \"%s\" - %d/%d msgs" % [search_term, results_count, total_count] - -## Show loading/processing status with operation name -## @param operation: Name of the operation being performed -func show_processing_status(operation: String) -> void: - text = "%s..." % operation - -## Reset to ready state -func reset() -> void: - text = "Ready" diff --git a/addons/loggie-console/scripts/components/status_display.gd.uid b/addons/loggie-console/scripts/components/status_display.gd.uid deleted file mode 100644 index c986b31..0000000 --- a/addons/loggie-console/scripts/components/status_display.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://whrim6lbiako diff --git a/addons/loggie-console/scripts/domain_color_manager.gd b/addons/loggie-console/scripts/domain_color_manager.gd deleted file mode 100644 index 2f5b866..0000000 --- a/addons/loggie-console/scripts/domain_color_manager.gd +++ /dev/null @@ -1,167 +0,0 @@ -class_name DomainColorManager extends RefCounted - -## Centralized domain color management for LoggieConsole -## Provides consistent color mapping across all console components - -## Domain color mapping information -class DomainColorInfo: - var domain_name: String - var color: Color - var palette_index: int - var cycle_count: int - var is_variation: bool - - func _init(p_domain_name: String, p_color: Color, p_palette_index: int, p_cycle_count: int) -> void: - domain_name = p_domain_name - color = p_color - palette_index = p_palette_index - cycle_count = p_cycle_count - is_variation = p_cycle_count > 0 - -## Color usage statistics and diagnostic information -class ColorUsageInfo: - var total_domains: int - var palette_size: int - var current_cycle: int - var next_color_index: int - var remaining_in_current_cycle: int - var has_color_variations: bool - - func _init(p_total_domains: int, p_palette_size: int, p_current_cycle: int, p_next_color_index: int, p_remaining_in_current_cycle: int, p_has_color_variations: bool) -> void: - total_domains = p_total_domains - palette_size = p_palette_size - current_cycle = p_current_cycle - next_color_index = p_next_color_index - remaining_in_current_cycle = p_remaining_in_current_cycle - has_color_variations = p_has_color_variations - -# Domain color mapping storage -var _domain_colors: Dictionary = {} # String -> DomainColorInfo -var _color_index: int = 0 - -# Predefined color palette for domains -const DOMAIN_COLOR_PALETTE: Array[Color] = [ - Color("#FF6B6B"), # Red - Color("#4ECDC4"), # Teal - Color("#45B7D1"), # Blue - Color("#96CEB4"), # Green - Color("#FECA57"), # Yellow - Color("#FF9FF3"), # Pink - Color("#54A0FF"), # Light Blue - Color("#5F27CD"), # Purple - Color("#00D2D3"), # Cyan - Color("#FF9F43"), # Orange - Color("#10AC84"), # Mint - Color("#EE5A24"), # Dark Orange - Color("#0984E3"), # Royal Blue - Color("#6C5CE7"), # Violet - Color("#A29BFE"), # Light Purple - Color("#FD79A8"), # Rose - Color("#FDCB6E"), # Light Yellow - Color("#6C5CE7"), # Indigo - Color("#00B894"), # Emerald - Color("#E84393") # Magenta -] - - -## Get or assign a color for a domain -func get_domain_color(domain: String) -> Color: - if domain.is_empty(): - return Color.WHITE - - if not _domain_colors.has(domain): - # Assign a new color from the palette with potential variations - var palette_index: int = _color_index % DOMAIN_COLOR_PALETTE.size() - var cycle_count: int = _color_index / DOMAIN_COLOR_PALETTE.size() - - var base_color: Color = DOMAIN_COLOR_PALETTE[palette_index] - var color: Color = _get_color_variation(base_color, cycle_count) - - var new_color_info: DomainColorInfo = DomainColorInfo.new(domain, color, palette_index, cycle_count) - _domain_colors[domain] = new_color_info - _color_index += 1 - - var existing_color_info: DomainColorInfo = _domain_colors[domain] as DomainColorInfo - return existing_color_info.color - -## Get HTML color string for domain (for BBCode) -func get_domain_color_html(domain: String) -> String: - return get_domain_color(domain).to_html(false) - -## Check if domain has assigned color -func has_domain_color(domain: String) -> bool: - return _domain_colors.has(domain) - -## Get domain color information for a specific domain -func get_domain_color_info(domain: String) -> DomainColorInfo: - if not _domain_colors.has(domain): - # Trigger color assignment by calling get_domain_color - get_domain_color(domain) - - return _domain_colors[domain] as DomainColorInfo - -## Get all registered domains with their color information -func get_all_domain_color_infos() -> Array[DomainColorInfo]: - var infos: Array[DomainColorInfo] = [] - for domain_color_info: DomainColorInfo in _domain_colors.values(): - infos.append(domain_color_info) - return infos - -## Get diagnostic information about color usage and cycles -func get_color_usage_info() -> ColorUsageInfo: - var current_cycle: int = _color_index / DOMAIN_COLOR_PALETTE.size() - var remaining_in_cycle: int = DOMAIN_COLOR_PALETTE.size() - (_color_index % DOMAIN_COLOR_PALETTE.size()) - - return ColorUsageInfo.new( - _domain_colors.size(), - DOMAIN_COLOR_PALETTE.size(), - current_cycle, - _color_index % DOMAIN_COLOR_PALETTE.size(), - remaining_in_cycle, - current_cycle > 0 - ) - -## Clear all color assignments (for testing/reset) -func clear_all_colors() -> void: - _domain_colors.clear() - _color_index = 0 - -## Get the color palette for reference -func get_color_palette() -> Array[Color]: - return DOMAIN_COLOR_PALETTE - -## Create color variations for domains beyond the initial palette -## Uses brightness and saturation adjustments to create distinguishable variations -func _get_color_variation(base_color: Color, cycle_count: int) -> Color: - if cycle_count == 0: - # First cycle - use original colors - return base_color - - # Get HSV components directly from Color - var hue: float = base_color.h - var saturation: float = base_color.s - var value: float = base_color.v - - match cycle_count: - 1: - # Second cycle - Increase brightness - value = minf(value * 1.3, 1.0) - 2: - # Third cycle - Decrease saturation (more pastel) - saturation = maxf(saturation * 0.6, 0.3) - 3: - # Fourth cycle - Decrease brightness - value = maxf(value * 0.7, 0.4) - 4: - # Fifth cycle - High saturation, medium brightness - saturation = minf(saturation * 1.2, 1.0) - value = maxf(minf(value * 0.85, 1.0), 0.5) - _: - # Beyond fifth cycle - Use mathematical variations - var brightness_mod: float = 1.0 + (cycle_count % 3) * 0.25 - 0.25 # -0.25, 0, +0.25 - var saturation_mod: float = 1.0 + ((cycle_count + 1) % 3) * 0.2 - 0.2 # -0.2, 0, +0.2 - - value = maxf(minf(value * brightness_mod, 1.0), 0.3) - saturation = maxf(minf(saturation * saturation_mod, 1.0), 0.2) - - return Color.from_hsv(hue, saturation, value) diff --git a/addons/loggie-console/scripts/domain_color_manager.gd.uid b/addons/loggie-console/scripts/domain_color_manager.gd.uid deleted file mode 100644 index 76aefc2..0000000 --- a/addons/loggie-console/scripts/domain_color_manager.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://x0ut5e0gpyu1 diff --git a/addons/loggie-console/scripts/loggie_console_channel.gd b/addons/loggie-console/scripts/loggie_console_channel.gd deleted file mode 100644 index 165ed6f..0000000 --- a/addons/loggie-console/scripts/loggie_console_channel.gd +++ /dev/null @@ -1,66 +0,0 @@ -class_name LoggieConsoleChannel extends LoggieMsgChannel - -## Custom Loggie channel that feeds messages directly to the LoggieConsole -## This channel captures all message metadata (level, type, domain, channels, stack info) -## without requiring string parsing - - -# Reference to the console window that will display messages -var _console_window: LoggieConsole - -func _init() -> void: - ID = "loggie_console" - # Enable all preprocessing steps to get complete information - preprocess_flags = ( - LoggieEnums.PreprocessStep.APPEND_TIMESTAMPS | - LoggieEnums.PreprocessStep.APPEND_DOMAIN_NAME | - LoggieEnums.PreprocessStep.APPEND_CLASS_NAME - ) - -## Sets the console window that will receive messages from this channel -## @param window: The console window instance, must not be null -func set_console_window(window: LoggieConsole) -> void: - if window == null: - Loggie.msg("Cannot set null console window").domain(LoggieConsoleConstants.DOMAIN).error() - return - _console_window = window - -## Override send method to pass complete message data to console -## @param msg: The Loggie message object containing all metadata -## @param msg_type: The message type enum from Loggie -func send(msg: LoggieMsg, msg_type: LoggieEnums.MsgType) -> void: - if _console_window == null: - Loggie.msg("No console window set, message dropped").domain(LoggieConsoleConstants.DOMAIN).warn() - return - - if msg == null: - Loggie.msg("Received null message").domain(LoggieConsoleConstants.DOMAIN).error() - return - - # Get the preprocessed text (already formatted by Loggie) - var preprocessed_text = msg.last_preprocess_result - - # Determine log level from the message content patterns or message type - var log_level = _determine_log_level(msg, msg_type, preprocessed_text) - - # Send complete message data to console - _console_window.receive_log_message(msg, preprocessed_text, msg_type, log_level) - -## Determine the log level based on message type and content -func _determine_log_level(_msg: LoggieMsg, msg_type: LoggieEnums.MsgType, content: String) -> LoggieEnums.LogLevel: - # Use message type to infer log level - match msg_type: - LoggieEnums.MsgType.ERROR: - return LoggieEnums.LogLevel.ERROR - LoggieEnums.MsgType.WARN: - return LoggieEnums.LogLevel.WARN - LoggieEnums.MsgType.DEBUG: - return LoggieEnums.LogLevel.DEBUG - LoggieEnums.MsgType.INFO: - # For standard messages, check content patterns to determine level - if content.contains("[NOTICE]"): - return LoggieEnums.LogLevel.NOTICE - else: - return LoggieEnums.LogLevel.INFO - _: - return LoggieEnums.LogLevel.INFO diff --git a/addons/loggie-console/scripts/loggie_console_channel.gd.uid b/addons/loggie-console/scripts/loggie_console_channel.gd.uid deleted file mode 100644 index d561040..0000000 --- a/addons/loggie-console/scripts/loggie_console_channel.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bcehgenffbmr3 diff --git a/addons/loggie-console/scripts/loggie_console_constants.gd b/addons/loggie-console/scripts/loggie_console_constants.gd deleted file mode 100644 index cea8304..0000000 --- a/addons/loggie-console/scripts/loggie_console_constants.gd +++ /dev/null @@ -1,9 +0,0 @@ -class_name LoggieConsoleConstants extends RefCounted - -## Centralized constants for the LoggieConsole addon -## -## Contains all shared constants used across LoggieConsole components to ensure -## consistency and avoid duplication. Use StringName for efficient string operations. - -## Domain for all LoggieConsole logging messages -const DOMAIN: StringName = &"LOGGIE_CONSOLE" diff --git a/addons/loggie-console/scripts/loggie_console_constants.gd.uid b/addons/loggie-console/scripts/loggie_console_constants.gd.uid deleted file mode 100644 index 683a374..0000000 --- a/addons/loggie-console/scripts/loggie_console_constants.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://7iexr4yxwqfg diff --git a/addons/loggie-console/scripts/managers/console_settings_manager.gd b/addons/loggie-console/scripts/managers/console_settings_manager.gd deleted file mode 100644 index 95f758e..0000000 --- a/addons/loggie-console/scripts/managers/console_settings_manager.gd +++ /dev/null @@ -1,96 +0,0 @@ -class_name ConsoleSettingsManager extends RefCounted - -## Manages persistent storage of LoggieConsole settings -## -## Provides robust save/load functionality with automatic backup creation and -## comprehensive error handling. Settings are saved immediately when requested -## (no debouncing) and loaded with fallback to backup file or defaults. - -const LoggieConsoleSettings = preload("res://addons/loggie-console/resources/loggie_console_settings.gd") - -# File paths and configuration -const SETTINGS_PATH = "user://loggie_console_settings.tres" -const BACKUP_PATH = "user://loggie_console_settings_backup.tres" -const SETTINGS_RESOURCE_TYPE = "LoggieConsoleSettings" - -## Loads console settings with comprehensive error handling and fallback chain -## -## Load order: primary file → backup file → create defaults -## All loaded settings are validated and sanitized before returning. -## Returns: A valid LoggieConsoleSettings instance (never null) -func load_settings() -> LoggieConsoleSettings: - var settings: LoggieConsoleSettings = null - - # Attempt to load primary settings file - settings = _try_load_file(SETTINGS_PATH, "main settings") - - # Fall back to backup file if primary failed - if settings == null: - settings = _try_load_file(BACKUP_PATH, "backup settings") - - # Create default settings if both files failed - if settings == null: - Loggie.msg("Creating default console settings").domain(LoggieConsoleConstants.DOMAIN).info() - settings = LoggieConsoleSettings.new() - - # Always validate to ensure data integrity - settings.validate() - - Loggie.msg("Console settings loaded successfully").domain(LoggieConsoleConstants.DOMAIN).debug() - return settings - -## Saves console settings to disk immediately with backup creation -## -## Creates a backup of the existing file before saving, then validates -## the settings and writes them using Godot's ResourceSaver. -## Param settings: The settings to save (must not be null) -## Returns: true if save succeeded, false if it failed -func save_settings(settings: LoggieConsoleSettings) -> bool: - return _save_with_backup(settings) - -## Attempts to load a settings file with error handling -## Param path: File path to load from -## Param description: Human-readable description for logging -## Returns: Loaded settings or null if loading failed -func _try_load_file(path: String, description: String) -> LoggieConsoleSettings: - if not FileAccess.file_exists(path): - Loggie.msg("Settings file not found: %s" % path).domain(LoggieConsoleConstants.DOMAIN).debug() - return null - - var resource: Resource = ResourceLoader.load(path, SETTINGS_RESOURCE_TYPE) - if resource == null: - Loggie.msg("Failed to load %s from: %s" % [description, path]).domain(LoggieConsoleConstants.DOMAIN).warn() - return null - - if not resource is LoggieConsoleSettings: - Loggie.msg("Invalid resource type in %s: %s" % [description, path]).domain(LoggieConsoleConstants.DOMAIN).error() - return null - - Loggie.msg("Loaded %s from: %s" % [description, path]).domain(LoggieConsoleConstants.DOMAIN).debug() - return resource as LoggieConsoleSettings - -## Saves settings with automatic backup creation -## Param settings: The settings to save -## Returns: true if save succeeded, false otherwise -func _save_with_backup(settings: LoggieConsoleSettings) -> bool: - if not settings: - Loggie.msg("Cannot save null settings").domain(LoggieConsoleConstants.DOMAIN).error() - return false - - # Validate settings before saving - settings.validate() - - # Create backup of existing file before overwriting - if FileAccess.file_exists(SETTINGS_PATH): - var dir: DirAccess = DirAccess.open("user://") - if dir: - dir.copy(SETTINGS_PATH, BACKUP_PATH) - - # Save the validated settings - var error: Error = ResourceSaver.save(settings, SETTINGS_PATH) - if error != OK: - Loggie.msg("Failed to save console settings: %s" % error_string(error)).domain(LoggieConsoleConstants.DOMAIN).error() - return false - - Loggie.msg("Console settings saved successfully").domain(LoggieConsoleConstants.DOMAIN).debug() - return true diff --git a/addons/loggie-console/scripts/managers/console_settings_manager.gd.uid b/addons/loggie-console/scripts/managers/console_settings_manager.gd.uid deleted file mode 100644 index 32b2998..0000000 --- a/addons/loggie-console/scripts/managers/console_settings_manager.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bntgmwyauc4h6 diff --git a/addons/loggie-console/theme_compact.tres b/addons/loggie-console/theme_compact.tres deleted file mode 100644 index 4d529ea..0000000 --- a/addons/loggie-console/theme_compact.tres +++ /dev/null @@ -1,141 +0,0 @@ -[gd_resource type="Theme" format=3 uid="uid://c1lnnysnspc6v"] - -[ext_resource type="StyleBox" uid="uid://dolgdjpxlvt8f" path="res://addons/loggie-console/assets/inner_panel_recess.tres" id="1_nubd1"] -[ext_resource type="Texture2D" uid="uid://bhps6csrl6lef" path="res://addons/loggie-console/assets/close.png" id="1_rapoa"] -[ext_resource type="StyleBox" uid="uid://bpkqcbx15ejak" path="res://addons/loggie-console/assets/outer_panel.tres" id="2_rapoa"] -[ext_resource type="StyleBox" uid="uid://cfafk3ybc15uo" path="res://addons/loggie-console/assets/outer_window_panel.tres" id="3_f200k"] -[ext_resource type="StyleBox" uid="uid://b7k8yo7jfhpue" path="res://addons/loggie-console/assets/inner_panel.tres" id="3_p21dw"] - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_button_normal"] -content_margin_left = 3.0 -content_margin_top = 1.0 -content_margin_right = 3.0 -content_margin_bottom = 1.0 -bg_color = Color(0.25, 0.25, 0.25, 1) -border_width_left = 1 -border_width_top = 1 -border_width_right = 1 -border_width_bottom = 1 -border_color = Color(0.4, 0.4, 0.4, 1) - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_checkbox_normal"] -bg_color = Color(0.15, 0.15, 0.15, 1) -border_width_left = 1 -border_width_top = 1 -border_width_right = 1 -border_width_bottom = 1 -border_color = Color(0.4, 0.4, 0.4, 1) - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_panel"] -bg_color = Color(0.15, 0.15, 0.15, 0.95) -border_width_left = 1 -border_width_top = 1 -border_width_right = 1 -border_width_bottom = 1 -border_color = Color(0.3, 0.3, 0.3, 1) - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_richtextlabel"] -content_margin_left = 1.0 -content_margin_top = 1.0 -content_margin_right = 1.0 -content_margin_bottom = 1.0 -bg_color = Color(0.1, 0.1, 0.1, 1) -border_width_left = 1 -border_width_top = 1 -border_width_right = 1 -border_width_bottom = 1 -border_color = Color(0.3, 0.3, 0.3, 1) - -[sub_resource type="SystemFont" id="SystemFont_f200k"] -font_names = PackedStringArray("Monospace") -font_weight = 800 -generate_mipmaps = true -multichannel_signed_distance_field = true - -[resource] -Button/colors/font_color = Color(0.9, 0.9, 0.9, 1) -Button/colors/font_disabled_color = Color(0.5, 0.5, 0.5, 1) -Button/colors/font_hover_color = Color(1, 1, 1, 1) -Button/colors/font_pressed_color = Color(0.8, 0.8, 0.8, 1) -Button/font_sizes/font_size = 11 -Button/styles/disabled = SubResource("StyleBoxFlat_button_normal") -Button/styles/hover = ExtResource("2_rapoa") -Button/styles/normal = ExtResource("2_rapoa") -Button/styles/pressed = ExtResource("1_nubd1") -CheckBox/colors/font_color = Color(0.9, 0.9, 0.9, 1) -CheckBox/colors/font_disabled_color = Color(0.5, 0.5, 0.5, 1) -CheckBox/colors/font_hover_color = Color(1, 1, 1, 1) -CheckBox/colors/font_pressed_color = Color(0.8, 0.8, 0.8, 1) -CheckBox/font_sizes/font_size = 11 -CheckBox/styles/disabled = SubResource("StyleBoxFlat_checkbox_normal") -CheckBox/styles/hover_pressed = ExtResource("2_rapoa") -CheckBox/styles/normal = ExtResource("2_rapoa") -CheckBox/styles/pressed = ExtResource("2_rapoa") -HBoxContainer/constants/separation = 2 -LineEdit/colors/caret_color = Color(1, 1, 1, 1) -LineEdit/colors/clear_button_color = Color(0, 0, 0, 1) -LineEdit/colors/clear_button_color_pressed = Color(0, 0, 0, 1) -LineEdit/colors/font_color = Color(1, 1, 1, 1) -LineEdit/colors/font_outline_color = Color(0, 0, 0, 1) -LineEdit/colors/font_placeholder_color = Color(0.447904, 0.509153, 0.407339, 1) -LineEdit/colors/font_selected_color = Color(0.792157, 0.901961, 0.85098, 1) -LineEdit/colors/font_uneditable_color = Color(0, 0, 0, 1) -LineEdit/colors/selection_color = Color(0.188235, 0.219608, 0.262745, 1) -LineEdit/constants/caret_width = 0 -LineEdit/constants/minimum_character_width = 0 -LineEdit/constants/outline_size = 0 -LineEdit/font_sizes/font_size = 12 -LineEdit/fonts/font = null -LineEdit/icons/clear = null -LineEdit/styles/focus = ExtResource("1_nubd1") -LineEdit/styles/normal = ExtResource("1_nubd1") -LineEdit/styles/read_only = ExtResource("3_p21dw") -MarginContainer/constants/margin_bottom = 1 -MarginContainer/constants/margin_left = 1 -MarginContainer/constants/margin_right = 1 -MarginContainer/constants/margin_top = 1 -MenuButton/colors/font_color = Color(0.9, 0.9, 0.9, 1) -MenuButton/colors/font_disabled_color = Color(0.5, 0.5, 0.5, 1) -MenuButton/colors/font_hover_color = Color(1, 1, 1, 1) -MenuButton/colors/font_pressed_color = Color(0.8, 0.8, 0.8, 1) -MenuButton/font_sizes/font_size = 11 -MenuButton/styles/hover = ExtResource("1_nubd1") -MenuButton/styles/normal = ExtResource("2_rapoa") -MenuButton/styles/pressed = ExtResource("2_rapoa") -OptionButton/colors/font_color = Color(0.9, 0.9, 0.9, 1) -OptionButton/colors/font_disabled_color = Color(0.5, 0.5, 0.5, 1) -OptionButton/colors/font_hover_color = Color(1, 1, 1, 1) -OptionButton/colors/font_pressed_color = Color(0.8, 0.8, 0.8, 1) -OptionButton/font_sizes/font_size = 11 -OptionButton/styles/disabled = ExtResource("3_f200k") -OptionButton/styles/hover = ExtResource("1_nubd1") -OptionButton/styles/normal = ExtResource("1_nubd1") -OptionButton/styles/pressed = ExtResource("1_nubd1") -Panel/styles/panel = SubResource("StyleBoxFlat_panel") -PopupMenu/colors/font_color = Color(0.9, 0.9, 0.9, 1) -PopupMenu/colors/font_hover_color = Color(1, 1, 1, 1) -PopupMenu/colors/font_separator_color = Color(0.5, 0.5, 0.5, 1) -PopupMenu/font_sizes/font_size = 11 -PopupMenu/styles/hover = ExtResource("1_nubd1") -PopupMenu/styles/normal = ExtResource("1_nubd1") -PopupMenu/styles/panel = ExtResource("2_rapoa") -PopupPanel/styles/panel = ExtResource("2_rapoa") -RichTextLabel/colors/default_color = Color(0.9, 0.9, 0.9, 1) -RichTextLabel/colors/selection_color = Color(0.4, 0.6, 0.8, 0.4) -RichTextLabel/font_sizes/bold_font_size = 10 -RichTextLabel/font_sizes/bold_italics_font_size = 10 -RichTextLabel/font_sizes/italics_font_size = 10 -RichTextLabel/font_sizes/mono_font_size = 9 -RichTextLabel/font_sizes/normal_font_size = 10 -RichTextLabel/styles/normal = SubResource("StyleBoxFlat_richtextlabel") -VBoxContainer/constants/separation = 2 -Window/colors/title_color = Color(0.175119, 0.187776, 0.176406, 1) -Window/constants/close_h_offset = 18 -Window/constants/close_v_offset = 20 -Window/constants/title_height = 22 -Window/font_sizes/title_font_size = 16 -Window/fonts/title_font = SubResource("SystemFont_f200k") -Window/icons/close = ExtResource("1_rapoa") -Window/icons/close_pressed = ExtResource("1_rapoa") -Window/styles/embedded_border = ExtResource("3_f200k") -Window/styles/embedded_unfocused_border = ExtResource("3_f200k") diff --git a/addons/loggie/assets/icon.png b/addons/loggie/assets/icon.png deleted file mode 100644 index 59c10f9..0000000 Binary files a/addons/loggie/assets/icon.png and /dev/null differ diff --git a/addons/loggie/assets/icon.png.import b/addons/loggie/assets/icon.png.import deleted file mode 100644 index 9cad268..0000000 --- a/addons/loggie/assets/icon.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://2fr6et0qni2y" -path="res://.godot/imported/icon.png-57313fc4d67f18c33a83a3388ad36531.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/loggie/assets/icon.png" -dest_files=["res://.godot/imported/icon.png-57313fc4d67f18c33a83a3388ad36531.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/loggie/assets/logo.png b/addons/loggie/assets/logo.png deleted file mode 100644 index c7d6cde..0000000 Binary files a/addons/loggie/assets/logo.png and /dev/null differ diff --git a/addons/loggie/assets/logo.png.import b/addons/loggie/assets/logo.png.import deleted file mode 100644 index 2f29861..0000000 --- a/addons/loggie/assets/logo.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://duuj0ibyreygv" -path="res://.godot/imported/logo.png-2771abf7e361d7f10d5859133bc43562.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/loggie/assets/logo.png" -dest_files=["res://.godot/imported/logo.png-2771abf7e361d7f10d5859133bc43562.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/loggie/assets/theme/checkbox/checkbox_checked.png b/addons/loggie/assets/theme/checkbox/checkbox_checked.png deleted file mode 100644 index 89bee08..0000000 Binary files a/addons/loggie/assets/theme/checkbox/checkbox_checked.png and /dev/null differ diff --git a/addons/loggie/assets/theme/checkbox/checkbox_checked.png.import b/addons/loggie/assets/theme/checkbox/checkbox_checked.png.import deleted file mode 100644 index f95406c..0000000 --- a/addons/loggie/assets/theme/checkbox/checkbox_checked.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bfnp2a0sbhi2x" -path="res://.godot/imported/checkbox_checked.png-a77d9d083c4ebd2bf01389a1bba7091b.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/loggie/assets/theme/checkbox/checkbox_checked.png" -dest_files=["res://.godot/imported/checkbox_checked.png-a77d9d083c4ebd2bf01389a1bba7091b.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/loggie/assets/theme/checkbox/checkbox_checked_disabled.png b/addons/loggie/assets/theme/checkbox/checkbox_checked_disabled.png deleted file mode 100644 index 29664d9..0000000 Binary files a/addons/loggie/assets/theme/checkbox/checkbox_checked_disabled.png and /dev/null differ diff --git a/addons/loggie/assets/theme/checkbox/checkbox_checked_disabled.png.import b/addons/loggie/assets/theme/checkbox/checkbox_checked_disabled.png.import deleted file mode 100644 index 23489cd..0000000 --- a/addons/loggie/assets/theme/checkbox/checkbox_checked_disabled.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dqf5cye21gyw8" -path="res://.godot/imported/checkbox_checked_disabled.png-0752d58bb0616edc7e127ccd992cc02f.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/loggie/assets/theme/checkbox/checkbox_checked_disabled.png" -dest_files=["res://.godot/imported/checkbox_checked_disabled.png-0752d58bb0616edc7e127ccd992cc02f.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/loggie/assets/theme/checkbox/checkbox_unchecked.png b/addons/loggie/assets/theme/checkbox/checkbox_unchecked.png deleted file mode 100644 index 9b96ba7..0000000 Binary files a/addons/loggie/assets/theme/checkbox/checkbox_unchecked.png and /dev/null differ diff --git a/addons/loggie/assets/theme/checkbox/checkbox_unchecked.png.import b/addons/loggie/assets/theme/checkbox/checkbox_unchecked.png.import deleted file mode 100644 index fd56a24..0000000 --- a/addons/loggie/assets/theme/checkbox/checkbox_unchecked.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bib1lwikra5kr" -path="res://.godot/imported/checkbox_unchecked.png-4c82347fbe6c6b60f40739ece2ad0dba.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/loggie/assets/theme/checkbox/checkbox_unchecked.png" -dest_files=["res://.godot/imported/checkbox_unchecked.png-4c82347fbe6c6b60f40739ece2ad0dba.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/loggie/assets/theme/checkbox/checkbox_unchecked_disabled.png b/addons/loggie/assets/theme/checkbox/checkbox_unchecked_disabled.png deleted file mode 100644 index 7cb80bb..0000000 Binary files a/addons/loggie/assets/theme/checkbox/checkbox_unchecked_disabled.png and /dev/null differ diff --git a/addons/loggie/assets/theme/checkbox/checkbox_unchecked_disabled.png.import b/addons/loggie/assets/theme/checkbox/checkbox_unchecked_disabled.png.import deleted file mode 100644 index 7dce3c8..0000000 --- a/addons/loggie/assets/theme/checkbox/checkbox_unchecked_disabled.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cloe7vx2ej0nf" -path="res://.godot/imported/checkbox_unchecked_disabled.png-aa159b17a13862a51b7ba58c26a64745.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/loggie/assets/theme/checkbox/checkbox_unchecked_disabled.png" -dest_files=["res://.godot/imported/checkbox_unchecked_disabled.png-aa159b17a13862a51b7ba58c26a64745.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/loggie/assets/theme/fonts/PatrickHandSC-Regular.LICENSE.txt b/addons/loggie/assets/theme/fonts/PatrickHandSC-Regular.LICENSE.txt deleted file mode 100644 index 4d859a3..0000000 --- a/addons/loggie/assets/theme/fonts/PatrickHandSC-Regular.LICENSE.txt +++ /dev/null @@ -1,45 +0,0 @@ -Font: Patrick Hand SC - -Source: https://fonts.google.com/specimen/Patrick+Hand+SC/license - -Designed by Patrick Wagesreiter -License -Copyright (c) 2010-2012 Patrick Wagesreiter (mail@patrickwagesreiter.at) - -This Font Software is licensed under the SIL Open Font License, Version 1.1 . This license is copied below, and is also available with a FAQ at: https://openfontlicense.org - -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 - -PREAMBLE - -The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others. - -The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives. - -DEFINITIONS - -"Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the copyright statement(s). -"Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment. - -"Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS - -Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions: - - Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself. - Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. - No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users. - The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission. - The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software. - -TERMINATION - -This license becomes null and void if any of the above conditions are not met. -DISCLAIMER - -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. \ No newline at end of file diff --git a/addons/loggie/assets/theme/fonts/PatrickHandSC-Regular.ttf b/addons/loggie/assets/theme/fonts/PatrickHandSC-Regular.ttf deleted file mode 100644 index 49dfe40..0000000 Binary files a/addons/loggie/assets/theme/fonts/PatrickHandSC-Regular.ttf and /dev/null differ diff --git a/addons/loggie/assets/theme/fonts/PatrickHandSC-Regular.ttf.import b/addons/loggie/assets/theme/fonts/PatrickHandSC-Regular.ttf.import deleted file mode 100644 index 9e898ef..0000000 --- a/addons/loggie/assets/theme/fonts/PatrickHandSC-Regular.ttf.import +++ /dev/null @@ -1,36 +0,0 @@ -[remap] - -importer="font_data_dynamic" -type="FontFile" -uid="uid://btuvtbhws7p8s" -path="res://.godot/imported/PatrickHandSC-Regular.ttf-a768b75713759378d46297f0740f6da5.fontdata" - -[deps] - -source_file="res://addons/loggie/assets/theme/fonts/PatrickHandSC-Regular.ttf" -dest_files=["res://.godot/imported/PatrickHandSC-Regular.ttf-a768b75713759378d46297f0740f6da5.fontdata"] - -[params] - -Rendering=null -antialiasing=1 -generate_mipmaps=false -disable_embedded_bitmaps=true -multichannel_signed_distance_field=false -msdf_pixel_range=8 -msdf_size=48 -allow_system_fallback=true -force_autohinter=false -modulate_color_glyphs=false -hinting=1 -subpixel_positioning=1 -keep_rounding_remainders=true -oversampling=0.0 -Fallbacks=null -fallbacks=[] -Compress=null -compress=true -preload=[] -language_support={} -script_support={} -opentype_features={} diff --git a/addons/loggie/assets/theme/fonts/coffee_soda.LICENSE.txt b/addons/loggie/assets/theme/fonts/coffee_soda.LICENSE.txt deleted file mode 100644 index 82a7f91..0000000 --- a/addons/loggie/assets/theme/fonts/coffee_soda.LICENSE.txt +++ /dev/null @@ -1,30 +0,0 @@ -Font: Coffee Soda -Source: https://www.creativefabrica.com/product/coffee-soda/ref/53/ - ---------- AUTHOR'S NOTE --------- - -First of All, - -Thank you for download my product. -This product 100% free for personal use & commercial use - -File include : - -1. Coffee Soda.ttf -2. Coffee Soda.otf - -More Info : -khurasantype@gmail.com - -For Donation: -paypal.me/khurasantype - -My OnlineShop: -https://www.creativefabrica.com/ref/53/ - -My Portofolio: -https://www.behance.net/khurasan - -My web: -www.khurasanstudio.com -www.mbkaos.com diff --git a/addons/loggie/assets/theme/fonts/coffee_soda.ttf b/addons/loggie/assets/theme/fonts/coffee_soda.ttf deleted file mode 100644 index 1d0f9f5..0000000 Binary files a/addons/loggie/assets/theme/fonts/coffee_soda.ttf and /dev/null differ diff --git a/addons/loggie/assets/theme/fonts/coffee_soda.ttf.import b/addons/loggie/assets/theme/fonts/coffee_soda.ttf.import deleted file mode 100644 index c03a977..0000000 --- a/addons/loggie/assets/theme/fonts/coffee_soda.ttf.import +++ /dev/null @@ -1,36 +0,0 @@ -[remap] - -importer="font_data_dynamic" -type="FontFile" -uid="uid://e3rpni7mpu0p" -path="res://.godot/imported/coffee_soda.ttf-1c45a1f5c42cb2ffa335471f7a4924a3.fontdata" - -[deps] - -source_file="res://addons/loggie/assets/theme/fonts/coffee_soda.ttf" -dest_files=["res://.godot/imported/coffee_soda.ttf-1c45a1f5c42cb2ffa335471f7a4924a3.fontdata"] - -[params] - -Rendering=null -antialiasing=1 -generate_mipmaps=false -disable_embedded_bitmaps=true -multichannel_signed_distance_field=false -msdf_pixel_range=8 -msdf_size=48 -allow_system_fallback=true -force_autohinter=false -modulate_color_glyphs=false -hinting=1 -subpixel_positioning=1 -keep_rounding_remainders=true -oversampling=0.0 -Fallbacks=null -fallbacks=[] -Compress=null -compress=true -preload=[] -language_support={} -script_support={} -opentype_features={} diff --git a/addons/loggie/assets/theme/loggie_border_box.tres b/addons/loggie/assets/theme/loggie_border_box.tres deleted file mode 100644 index d108787..0000000 --- a/addons/loggie/assets/theme/loggie_border_box.tres +++ /dev/null @@ -1,14 +0,0 @@ -[gd_resource type="StyleBoxFlat" format=3 uid="uid://ckw36egxdynxc"] - -[resource] -draw_center = false -border_width_left = 3 -border_width_top = 3 -border_width_right = 3 -border_width_bottom = 3 -border_color = Color(0.71, 0.52114, 0.1704, 0.772549) -border_blend = true -corner_radius_top_left = 10 -corner_radius_top_right = 10 -corner_radius_bottom_right = 10 -corner_radius_bottom_left = 10 diff --git a/addons/loggie/assets/theme/loggie_theme.tres b/addons/loggie/assets/theme/loggie_theme.tres deleted file mode 100644 index eb3767b..0000000 --- a/addons/loggie/assets/theme/loggie_theme.tres +++ /dev/null @@ -1,95 +0,0 @@ -[gd_resource type="Theme" load_steps=10 format=3 uid="uid://bntkg3oi4b314"] - -[ext_resource type="FontFile" uid="uid://btuvtbhws7p8s" path="res://addons/loggie/assets/theme/fonts/PatrickHandSC-Regular.ttf" id="1_ucfms"] -[ext_resource type="Texture2D" uid="uid://bfnp2a0sbhi2x" path="res://addons/loggie/assets/theme/checkbox/checkbox_checked.png" id="2_tqabx"] -[ext_resource type="Texture2D" uid="uid://dqf5cye21gyw8" path="res://addons/loggie/assets/theme/checkbox/checkbox_checked_disabled.png" id="3_plx1a"] -[ext_resource type="Texture2D" uid="uid://bib1lwikra5kr" path="res://addons/loggie/assets/theme/checkbox/checkbox_unchecked.png" id="4_yp55b"] -[ext_resource type="Texture2D" uid="uid://cloe7vx2ej0nf" path="res://addons/loggie/assets/theme/checkbox/checkbox_unchecked_disabled.png" id="5_0424s"] - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_gb03k"] -bg_color = Color(0.349691, 0.30101, 0.201282, 1) -border_width_left = 4 -border_width_top = 4 -border_width_right = 4 -border_width_bottom = 4 -border_color = Color(0.361244, 0.323458, 0.213348, 1) -corner_radius_top_left = 8 -corner_radius_top_right = 8 -corner_radius_bottom_right = 8 -corner_radius_bottom_left = 8 -expand_margin_left = 2.0 -expand_margin_top = 1.0 -expand_margin_right = 2.0 -expand_margin_bottom = 1.0 -anti_aliasing_size = 0.537 - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_73pt3"] -bg_color = Color(0.767332, 0.598222, 0.330864, 1) -border_width_left = 4 -border_width_top = 4 -border_width_right = 4 -border_width_bottom = 4 -border_color = Color(0.943861, 0.775452, 0.522251, 1) -corner_radius_top_left = 8 -corner_radius_top_right = 8 -corner_radius_bottom_right = 8 -corner_radius_bottom_left = 8 -expand_margin_left = 2.0 -expand_margin_top = 1.0 -expand_margin_right = 2.0 -expand_margin_bottom = 1.0 -anti_aliasing_size = 0.537 - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_xxk7l"] -bg_color = Color(0.661808, 0.507874, 0.261375, 1) -border_width_left = 4 -border_width_top = 4 -border_width_right = 4 -border_width_bottom = 4 -border_color = Color(0.83, 0.629555, 0.3071, 1) -corner_radius_top_left = 8 -corner_radius_top_right = 8 -corner_radius_bottom_right = 8 -corner_radius_bottom_left = 8 -expand_margin_left = 2.0 -expand_margin_top = 1.0 -expand_margin_right = 2.0 -expand_margin_bottom = 1.0 -anti_aliasing_size = 0.537 - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_i1fiu"] -bg_color = Color(0.6, 0.4574, 0.228, 1) -border_width_left = 4 -border_width_top = 4 -border_width_right = 4 -border_width_bottom = 4 -border_color = Color(0.83, 0.629555, 0.3071, 1) -corner_radius_top_left = 8 -corner_radius_top_right = 8 -corner_radius_bottom_right = 8 -corner_radius_bottom_left = 8 -expand_margin_left = 2.0 -expand_margin_top = 1.0 -expand_margin_right = 2.0 -expand_margin_bottom = 1.0 -anti_aliasing_size = 0.537 - -[resource] -Button/constants/outline_size = 6 -Button/font_sizes/font_size = 30 -Button/fonts/font = ExtResource("1_ucfms") -Button/styles/disabled = SubResource("StyleBoxFlat_gb03k") -Button/styles/focus = SubResource("StyleBoxFlat_73pt3") -Button/styles/hover = SubResource("StyleBoxFlat_xxk7l") -Button/styles/normal = SubResource("StyleBoxFlat_i1fiu") -CheckBox/icons/checked = ExtResource("2_tqabx") -CheckBox/icons/checked_disabled = ExtResource("3_plx1a") -CheckBox/icons/radio_checked = ExtResource("2_tqabx") -CheckBox/icons/radio_checked_disabled = ExtResource("3_plx1a") -CheckBox/icons/radio_unchecked = ExtResource("4_yp55b") -CheckBox/icons/radio_unchecked_disabled = ExtResource("5_0424s") -CheckBox/icons/unchecked = ExtResource("4_yp55b") -CheckBox/icons/unchecked_disabled = ExtResource("5_0424s") -Label/colors/font_color = Color(0.980392, 0.843137, 0.619608, 1) -Label/constants/outline_size = 3 -Label/font_sizes/font_size = 21 diff --git a/addons/loggie/assets/updater_bg.png b/addons/loggie/assets/updater_bg.png deleted file mode 100644 index 26d48d1..0000000 Binary files a/addons/loggie/assets/updater_bg.png and /dev/null differ diff --git a/addons/loggie/assets/updater_bg.png.import b/addons/loggie/assets/updater_bg.png.import deleted file mode 100644 index 81cb406..0000000 --- a/addons/loggie/assets/updater_bg.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cgh6hd3u8nlpj" -path="res://.godot/imported/updater_bg.png-c90bec38cc1681b029907f694c893180.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/loggie/assets/updater_bg.png" -dest_files=["res://.godot/imported/updater_bg.png-c90bec38cc1681b029907f694c893180.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=1 diff --git a/addons/loggie/channels/custom_channels/template.gd.example b/addons/loggie/channels/custom_channels/template.gd.example deleted file mode 100644 index 25bcc99..0000000 --- a/addons/loggie/channels/custom_channels/template.gd.example +++ /dev/null @@ -1,28 +0,0 @@ -extends LoggieMsgChannel - -func _init() -> void: - self.ID = "" - - # Example - Customize preprocess flags: - # self.preprocess_flags = LoggieEnums.PreprocessStep.APPEND_TIMESTAMPS | LoggieEnums.PreprocessStep.APPEND_DOMAIN_NAME | LoggieEnums.PreprocessStep.APPEND_CLASS_NAME - -func send(msg : LoggieMsg, msg_type : LoggieEnums.MsgType): - # Validate that the message is coming from a valid logger if you are going to be requiring access to a [Loggie] instance. - var loggie = msg.get_logger() # Access a [Loggie] instance directly from the message. - if loggie == null: - push_error("Attempt to send a message that's coming from an invalid logger.") - return - - # To access the most recently preprocessed version of the message - use: - # msg.last_preprocess_result - - # To access a string version of the message (no preprocessing) - use: - var msg_text = msg.string() - - # Optionally - # We can use `LoggieTools.convert_string_to_format_mode` to apply one of the Loggie format modes to it. - # Explore more functions in [LoggieTools] and [LoggieMsg]. - # var converted = LoggieTools.convert_string_to_format_mode(msg.last_preprocess_result, loggie.settings.msg_format_mode) - - # Do something with the message. - print(msg_text) diff --git a/addons/loggie/channels/discord.gd b/addons/loggie/channels/discord.gd deleted file mode 100644 index ead09ae..0000000 --- a/addons/loggie/channels/discord.gd +++ /dev/null @@ -1,75 +0,0 @@ -class_name DiscordLoggieMsgChannel extends LoggieMsgChannel - -const discord_msg_character_limit = 2000 # The max. amount of characters the content of the message can contain before discord refuses to post it. -var debug_domain = "_d_loggie_discord" -var debug_enabled = false - -func _init() -> void: - self.ID = "discord" - self.preprocess_flags = 0 # For this type of channel, this will be applied dynamically by Loggie after it loads LoggieSettings. - -func send(msg : LoggieMsg, msg_type : LoggieEnums.MsgType): - # Validate variables. - var loggie = msg.get_logger() - if loggie == null: - push_error("Attempt to send a message that's coming from an invalid logger.") - return - - # Wait until loggie is inside tree so that we can use add_child(http) on it without errors. - if !loggie.is_inside_tree(): - loggie.tree_entered.connect(func(): - send(msg, msg_type) - , CONNECT_ONE_SHOT) - return - - var webhook_url = loggie.settings.discord_webhook_url_live if loggie.is_in_production() else loggie.settings.discord_webhook_url_dev - if webhook_url == null or (webhook_url is String and webhook_url.is_empty()): - push_error("Attempt to send a message to the Discord channel with an invalid webhook_url.") - return - - var output_text = LoggieTools.convert_string_to_format_mode(msg.last_preprocess_result, LoggieEnums.MsgFormatMode.MARKDOWN) - - # Chunk the given string into chunks of maximum supported size by Discord, so we don't end up hitting the character limit - # which would prevent the message from getting posted. - var chunks = LoggieTools.chunk_string(output_text, discord_msg_character_limit) - if chunks.size() > 1: - loggie.debug("Chunking a long (", output_text.length(), "length ) message while sending to Discord into:", chunks.size(), "chunks.") - for chunk : String in chunks: - call_deferred("send_post_request", loggie, chunk, webhook_url) - -func send_post_request(logger : Variant, output_text : String, webhook_url : String): - # Enable debug messages if configured. - logger.set_domain_enabled(debug_domain, debug_enabled) - - # Create a new HTTPRequest POST request that will be sent to Discord and add it into the scenetree. - var http = HTTPRequest.new() - logger.add_child(http) - - # When the request is completed, destroy it. - http.request_completed.connect(func(result, response_code, headers, body): - var debug_msg = logger.msg("HTTP Request Completed:").color(Color.ORANGE).header().domain(debug_domain).channel("terminal") - debug_msg.nl().msg("Result:").color(Color.ORANGE).bold().space().msg(result).nl() - debug_msg.msg("Response Code:").color(Color.ORANGE).bold().space().msg(response_code).nl() - debug_msg.msg("Headers:").color(Color.ORANGE).bold().space().msg(headers).nl() - debug_msg.msg("Body:").color(Color.ORANGE).bold().space().msg(body) - debug_msg.debug() - - ## Inform the user about a received non-success response code. - if response_code < 200 or response_code > 299: - logger.msg("Discord responded with a non-success code: ").bold().msg(response_code, " - This is an indicator that something about the message you tried to send to Discord does not comply with their request body standards (e.g. content is too long, invalid format, etc.)").channel("terminal").warn() - - http.queue_free() - ) - - # Convert the [LoggieMsg]'s contents into markdown and post that to the target webhook url. - var json = JSON.stringify({"content": output_text}) - var header = ["Content-Type: application/json"] - - # Construct debug message. - if debug_enabled: - var debug_msg_post = logger.msg("Sending POST Request:").color(Color.CORNFLOWER_BLUE).header().channel("terminal").domain(debug_domain).nl() - debug_msg_post.msg("JSON stringified (length {size}):".format({"size": output_text.length()})).color(Color.LIGHT_SLATE_GRAY).bold().space().msg(json).color(Color.SLATE_GRAY) - debug_msg_post.debug() - - # Send the request. - http.request(webhook_url, header, HTTPClient.METHOD_POST, json) diff --git a/addons/loggie/channels/discord.gd.uid b/addons/loggie/channels/discord.gd.uid deleted file mode 100644 index 27dea4b..0000000 --- a/addons/loggie/channels/discord.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://byj005gxsloio diff --git a/addons/loggie/channels/slack.gd b/addons/loggie/channels/slack.gd deleted file mode 100644 index b380105..0000000 --- a/addons/loggie/channels/slack.gd +++ /dev/null @@ -1,65 +0,0 @@ -class_name SlackLoggieMsgChannel extends LoggieMsgChannel - -var debug_domain = "_d_loggie_slack" -var debug_enabled = false - -func _init() -> void: - self.ID = "slack" - self.preprocess_flags = 0 # For this type of channel, this will be applied dynamically by Loggie after it loads LoggieSettings. - -func send(msg : LoggieMsg, msg_type : LoggieEnums.MsgType): - # Validate variables. - var loggie = msg.get_logger() - if loggie == null: - push_error("Attempt to send a message that's coming from an invalid logger.") - return - - # Wait until loggie is inside tree so that we can use add_child(http) on it without errors. - if !loggie.is_inside_tree(): - loggie.tree_entered.connect(func(): - send(msg, msg_type) - , CONNECT_ONE_SHOT) - return - - var webhook = loggie.settings.slack_webhook_url_live if loggie.is_in_production() else loggie.settings.slack_webhook_url_dev - if webhook == null or (webhook is String and webhook.is_empty()): - push_error("Attempt to send a message to the Slack channel with an invalid webhook.") - return - - # Enable debug messages if configured. - loggie.set_domain_enabled(debug_domain, debug_enabled) - - # Create a new HTTPRequest POST request that will be sent to Slack and add it into the scenetree. - var http = HTTPRequest.new() - loggie.add_child(http) - - # When the request is completed, destroy it. - http.request_completed.connect(func(result, response_code, headers, body): - var debug_msg = loggie.msg("HTTP Request Completed:").color(Color.ORANGE).header().domain(debug_domain) - debug_msg.nl().msg("Result:").color(Color.ORANGE).bold().space().msg(result).nl() - debug_msg.msg("Response Code:").color(Color.ORANGE).bold().space().msg(response_code).nl() - debug_msg.msg("Headers:").color(Color.ORANGE).bold().space().msg(headers).nl() - debug_msg.msg("Body:").color(Color.ORANGE).bold().space().msg(body) - debug_msg.debug() - - ## Inform the user about a received non-success response code. - if response_code < 200 or response_code > 299: - loggie.msg("Slack responded with a non-success code: ").bold().msg(response_code, " - This is an indicator that something about the message you tried to send to Slack does not comply with their request body standards (e.g. content is too long, invalid format, etc.)").channel("terminal").warn() - - http.queue_free() - ) - - # Convert the [LoggieMsg]'s contents into markdown and post that to the target webhook url. - var md_text = LoggieTools.convert_string_to_format_mode(msg.last_preprocess_result, LoggieEnums.MsgFormatMode.PLAIN) - var json = JSON.stringify({"text": md_text}) - var header = ["Content-Type: application/json"] - - # Construct debug message. - if debug_enabled: - var debug_msg_post = loggie.msg("Sending POST Request:").color(Color.ORANGE).header().domain(debug_domain).nl() - debug_msg_post.msg("Preprocessed message:").color(Color.ORANGE).bold().space().msg(msg.last_preprocess_result).nl() - debug_msg_post.msg("JSON stringified:").color(Color.ORANGE).bold().space().msg(json) - debug_msg_post.debug() - - # Send the request. - http.request(webhook, header, HTTPClient.METHOD_POST, json) diff --git a/addons/loggie/channels/slack.gd.uid b/addons/loggie/channels/slack.gd.uid deleted file mode 100644 index 606adb9..0000000 --- a/addons/loggie/channels/slack.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dj1jdugf244ho diff --git a/addons/loggie/channels/terminal.gd b/addons/loggie/channels/terminal.gd deleted file mode 100644 index 572ba64..0000000 --- a/addons/loggie/channels/terminal.gd +++ /dev/null @@ -1,21 +0,0 @@ -class_name TerminalLoggieMsgChannel extends LoggieMsgChannel - -func _init() -> void: - self.ID = "terminal" - self.preprocess_flags = 0 # For this type of channel, this will be applied dynamically by Loggie after it loads LoggieSettings. - -func send(msg : LoggieMsg, msg_type : LoggieEnums.MsgType): - var loggie = msg.get_logger() - var text = LoggieTools.convert_string_to_format_mode(msg.last_preprocess_result, loggie.settings.msg_format_mode) - - match loggie.settings.msg_format_mode: - LoggieEnums.MsgFormatMode.ANSI, LoggieEnums.MsgFormatMode.BBCODE: - print_rich(text) - LoggieEnums.MsgFormatMode.PLAIN, _: - print(text) - - # Dump a non-preprocessed terminal-ready version of the message in additional ways if that has been configured. - if msg_type == LoggieEnums.MsgType.ERROR and loggie.settings.print_errors_to_console: - push_error(LoggieTools.convert_string_to_format_mode(msg.string(), LoggieEnums.MsgFormatMode.PLAIN)) - if msg_type == LoggieEnums.MsgType.WARN and loggie.settings.print_warnings_to_console: - push_warning(LoggieTools.convert_string_to_format_mode(msg.string(), LoggieEnums.MsgFormatMode.PLAIN)) diff --git a/addons/loggie/channels/terminal.gd.uid b/addons/loggie/channels/terminal.gd.uid deleted file mode 100644 index dcaecb0..0000000 --- a/addons/loggie/channels/terminal.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cd82p0vffosco diff --git a/addons/loggie/custom_settings.gd.example b/addons/loggie/custom_settings.gd.example deleted file mode 100644 index 35f066e..0000000 --- a/addons/loggie/custom_settings.gd.example +++ /dev/null @@ -1,52 +0,0 @@ -class_name CustomLoggieSettings extends LoggieSettings - -func load(): - # Omit settings from here to have them use their default value instead. - # Otherwise, directly set the value of the setting to your liking. - # Any variable in [LoggieSettings] except `project_settings` is a valid target to alter. - # You could also have them loaded here in some custom way, for example, from a .json or .ini file. - # See the documentation of the [LoggieSettings] class to see all available options and their descriptions. - # This template doesn't contain *all* the available options. - - # Example: Customize Loggie preferences. - self.update_check_mode = LoggieEnums.UpdateCheckType.CHECK_AND_SHOW_UPDATER_WINDOW - self.msg_format_mode = LoggieEnums.MsgFormatMode.BBCODE - self.log_level = LoggieEnums.LogLevel.INFO - self.show_loggie_specs = LoggieEnums.ShowLoggieSpecsMode.ESSENTIAL - self.show_system_specs = true - self.enforce_optimal_settings_in_release_build = true - - # Example: Customize logging settings. - self.print_errors_to_console = true - self.print_warnings_to_console = true - self.nameless_class_name_proxy = LoggieEnums.NamelessClassExtensionNameProxy.BASE_TYPE - self.timestamps_use_utc = true - - # Example: Customize formats. - self.format_info_msg = "{msg}" - self.format_notice_msg = "[b][color=cyan][NOTICE]:[/color][/b] {msg}" - self.format_warning_msg = "[b][color=orange][WARN]:[/color][/b] {msg}" - self.format_error_msg = "[b][color=red][ERROR]:[/color][/b] {msg}" - self.format_debug_msg = "[b][color=pink][DEBUG]:[/color][/b] {msg}" - - # Example: Customize boxes. - self.h_separator_symbol = "-" - self.box_characters_mode = LoggieEnums.BoxCharactersMode.COMPATIBLE - - self.box_symbols_compatible = { - "top_left" : "-", - "top_right" : "-", - "bottom_left" : "-", - "bottom_right" : "-", - "h_line" : "-", - "v_line" : ":", - } - - self.box_symbols_pretty = { - "top_left" : "┌", - "top_right" : "┐", - "bottom_left" : "└", - "bottom_right" : "┘", - "h_line" : "─", - "v_line" : "│", - } diff --git a/addons/loggie/loggie.gd b/addons/loggie/loggie.gd deleted file mode 100644 index 09da21a..0000000 --- a/addons/loggie/loggie.gd +++ /dev/null @@ -1,310 +0,0 @@ -@tool - -## Loggie is a basic logging utility for those who need common minor improvements and helpers around the basic [method print], [method print_rich] -## and other default Godot printing functions. Loggie creates instances of [LoggieMsg], which are a wrapper around a string that needs to manipulated, -## then uses them to properly format, arrange and present them in the console and .log files. Loggie uses the default Godot logging mechanism under the hood. -extends Node - -## The current version of Loggie. -## Needs to be updated manually when changing the version. -var version : LoggieVersion = LoggieVersion.new(3,0) - -## Emitted any time Loggie attempts to log a message. -## Useful for capturing the messages that pass through Loggie. -## [br][param msg] is the message Loggie attempted to log (before any preprocessing). -## [br][param msg_string] is a shortcut providing the string content of that message. -## [br][param result] describes the final result of the attempt to log that message. -signal log_attempted(msg : LoggieMsg, msg_string : String, result : LoggieEnums.LogAttemptResult) - -## A reference to the settings of this Loggie. Read more about [LoggieSettings]. -var settings : LoggieSettings - -## Holds a mapping between all registered domains (string keys) and bool values representing whether -## those domains are currently enabled. Enable domains with [method set_domain_enabled]. -## You can then place [LoggieMsg] messages into a domain by calling [method LoggieMsg.domain]. -## Messages belonging to a disabled domain will never be outputted. -var domains : Dictionary = {} - -## Holds a mapping between script paths and the names of the classes defined in those scripts. -var class_names : Dictionary = {} - -## Holds a mapping between channel IDs (string) and the -## [LoggieMsgChannel] objects those IDs are representing. -var available_channels = {} - -## Stores a reference to a [LoggieVersionManager] that will be used to manage the -## version of this instance. -var version_manager : LoggieVersionManager = LoggieVersionManager.new() - -## Stores a reference to each [LoggiePreset] that was created. -## The key is the ID (string) of the preset, and the value is the [LoggieMsg] that was saved as a preset. -var presets : Dictionary = {} - -func _init() -> void: - # Connect the version manager to this logger. - version_manager.connect_logger(self) - - # Load and initialize the settings. - var uses_original_settings_file = true - var default_settings_path = get_script().get_path().get_base_dir().path_join("loggie_settings.gd") - var custom_settings_path = get_script().get_path().get_base_dir().path_join("custom_settings.gd") - - if self.settings == null: - if custom_settings_path != null and custom_settings_path != "" and ResourceLoader.exists(custom_settings_path): - var loaded_successfully = load_settings_from_path(custom_settings_path) - if loaded_successfully: - uses_original_settings_file = false - - if uses_original_settings_file: - var _settings = ResourceLoader.load(default_settings_path) - if _settings != null: - self.settings = _settings.new() - self.settings.load() - else: - push_error("Loggie loaded neither a custom nor a default settings file. This will break the plugin. Make sure that a valid loggie_settings.gd is in the same directory where loggie.gd is.") - return - - # Enforce certain settings if configured to do so. - if self.settings.enforce_optimal_settings_in_release_build == true and is_in_production(): - apply_production_optimal_settings() - - # Set the default custom string converter. - self.settings.custom_string_converter = LoggieTools.convert_to_string - - # Install all the built-in channels. - var terminal_channel : TerminalLoggieMsgChannel = load("res://addons/loggie/channels/terminal.gd").new() - terminal_channel.preprocess_flags = self.settings.preprocess_flags_terminal_channel - add_channel(terminal_channel) - var discord_channel : DiscordLoggieMsgChannel = load("res://addons/loggie/channels/discord.gd").new() - discord_channel.preprocess_flags = self.settings.preprocess_flags_discord_channel - add_channel(discord_channel) - var slack_channel : SlackLoggieMsgChannel = load("res://addons/loggie/channels/slack.gd").new() - slack_channel.preprocess_flags = self.settings.preprocess_flags_slack_channel - add_channel(slack_channel) - - # Already cache the name of the singleton found at loggie's script path. - class_names[self.get_script().resource_path] = LoggieSettings.loggie_singleton_name - - # Prepopulate class data from ProjectSettings to avoid needing to read files. - if OS.has_feature("debug"): - for class_data: Dictionary in ProjectSettings.get_global_class_list(): - class_names[class_data.path] = class_data.class - - for autoload_setting: String in ProjectSettings.get_property_list().map(func(prop): return prop.name).filter(func(prop): return prop.begins_with("autoload/") and ProjectSettings.has_setting(prop)): - var autoload_class: String = autoload_setting.trim_prefix("autoload/") - var class_path: String = ProjectSettings.get_setting(autoload_setting) - class_path = class_path.trim_prefix("*") - if not class_names.has(class_path): - class_names[class_path] = autoload_class - - # And don't proceed further if we're in Editor mode, since we don't need to show loggie boot messages in that case. - if Engine.is_editor_hint(): - return - - # Print the Loggie boot messages. - if self.settings.show_loggie_specs != LoggieEnums.ShowLoggieSpecsMode.DISABLED: - msg("👀 Loggie {version}{isproxy} booted.".format({ - "version" : self.version_manager.version, - "isproxy" : " (proxy for {original})".format({"original": self.version_manager.version.proxy_for}) if self.version_manager.version.proxy_for != null else "" - })).color(Color.ORANGE).header().nl().info() - var loggie_specs_msg = LoggieSystemSpecsMsg.new().use_logger(self) - loggie_specs_msg.add(msg("|\t Using Custom Settings File: ").bold(), !uses_original_settings_file).nl().add("|\t ").hseparator(35).nl() - - match self.settings.show_loggie_specs: - LoggieEnums.ShowLoggieSpecsMode.ESSENTIAL: - loggie_specs_msg.embed_essential_logger_specs() - LoggieEnums.ShowLoggieSpecsMode.ADVANCED: - loggie_specs_msg.embed_advanced_logger_specs() - - loggie_specs_msg.preprocessed(false).info() - - if self.settings.show_system_specs: - var system_specs_msg = LoggieSystemSpecsMsg.new().use_logger(self) - system_specs_msg.embed_specs().preprocessed(false).info() - -## Attempts to instantiate and use a LoggieSettings object from the script at the given [param path]. -## Returns true if successful, otherwise false and prints an error. -func load_settings_from_path(path : String) -> bool: - var settings_resource = ResourceLoader.load(path) - var settings_instance - - if settings_resource != null: - settings_instance = settings_resource.new() - - if (settings_instance is LoggieSettings): - self.settings = settings_instance - self.settings.load() - return true - else: - push_error("Unable to instantiate a LoggieSettings object from the script at path {path}. Check that loggie.gd -> custom_settings_path is pointing to a valid .gd script that contains the class definition of a class that either extends LoggieSettings, or is LoggieSettings.".format({"path": path})) - return false - -## Checks if Loggie is running in production (release) mode of the game. -## While it is, every [LoggieMsg] will have plain output. -## Uses a sensible default check for most projects, but -## you can rewrite this function to your needs if necessary. -## TODO: Port this out of Loggie into LoggieSettings so users can override it easier. -func is_in_production() -> bool: - return OS.has_feature("release") - -## Returns a custom list of channels that messages from the given [param domain_name] will be sent to. -## This list can be set through the [method set_domain_enabled] method. -## If the list is empty, default channels will be used. -func get_domain_custom_target_channels(domain_name : String) -> Array: - if domains.has(domain_name): - return domains[domain_name].custom_target_channels - return [] - -## Sets whether the domain with the given name is enabled. -## If [param custom_target_channels] is provided, it will be used as the list of channels that messages from the given domain will be sent to. -## It can be provided as a string (if only one channel is used), or an array of strings (if multiple channels are used). -## Otherwise, the default channels will be used. -func set_domain_enabled(domain_name : String, enabled : bool, custom_target_channels : Variant = []) -> void: - var pruned_target_channels = [] - - if custom_target_channels is String: - custom_target_channels = [custom_target_channels] - - # Prune the array to ensure only string content is used. - if custom_target_channels is Array: - for entry in custom_target_channels: - if entry is String or entry is StringName: - pruned_target_channels.push_back(entry) - else: - push_error("Attempt to set a custom target channel for domain {domain_name} with an invalid value: {custom_target_channels}. The value must be a string or an array of strings. Default channels will be used instead.".format({ - "domain_name": domain_name, - "custom_target_channels": custom_target_channels - })) - - domains[domain_name] = {"enabled": enabled, "custom_target_channels": pruned_target_channels} - -## Checks whether the domain with the given name is enabled. -## The domain name "" (empty string) is the default one for all newly created messages, -## and is designed to always be enabled. -func is_domain_enabled(domain_name : String) -> bool: - if domain_name == "": - return true - - if domains.has(domain_name) and domains[domain_name].enabled == true: - return true - - return false - -## Returns an available channel with the given ID (if one exists), otherwise null. -func get_channel(channel_id : String) -> LoggieMsgChannel: - if available_channels.has(channel_id): - return available_channels[channel_id] - return null - -## Adds a new channel for sending messages to. -## Multiple channels with the same ID can not be added, so make sure your ID -## does not clash with one of the existing channels' IDs, which are: -## [param terminal], [param discord], [param slack]. -func add_channel(channel : LoggieMsgChannel): - if not available_channels.has(channel.ID): - available_channels[channel.ID] = channel - else: - push_error("Attempt to add a channel with ID {ID} failed, a channel with that ID already exists in Loggie.".format({ - "ID": channel.ID - })) - -## Gets a [LoggiePreset] message with the given ID, or creates one if it doesn't exist and returns it. -## The ID cannot be an empty string. -func preset(id : String) -> LoggiePreset: - if id.is_empty(): - push_error("Attempt to create or get a LoggiePreset with an empty ID - not allowed.") - return null - - if presets.has(id): - return presets[id] - else: - var newPreset : LoggiePreset = LoggiePreset.new() - newPreset.use_logger(self) - presets[id] = newPreset - return newPreset - -## Creates a new [LoggieMsg] out of the given [param msg] and extra arguments (by converting them to strings and concatenating them to the msg). -## You may continue to modify the [LoggieMsg] with additional functions from that class, then when you are ready to output it, use methods like: -## [method LoggieMsg.info], [method LoggieMsg.warn], etc. -func msg(message = "", arg1 = null, arg2 = null, arg3 = null, arg4 = null, arg5 = null) -> LoggieMsg: - var loggieMsg = LoggieMsg.new(message, arg1, arg2, arg3, arg4, arg5) - loggieMsg.use_logger(self) - return loggieMsg - -## A shortcut method that instantly creates a [LoggieMsg] with the given arguments and outputs it at the info level. -## Can be used when you have no intention of customizing a LoggieMsg in any way using helper methods. -## For customization, use [method msg] instead. -func info(message = "", arg1 = null, arg2 = null, arg3 = null, arg4 = null, arg5 = null) -> LoggieMsg: - return msg(message, arg1, arg2, arg3, arg4, arg5).info() - -## A shortcut method that instantly creates a [LoggieMsg] with the given arguments and outputs it at the warn level. -## Can be used when you have no intention of customizing a LoggieMsg in any way using helper methods. -## For customization, use [method msg] instead. -func warn(message = "", arg1 = null, arg2 = null, arg3 = null, arg4 = null, arg5 = null) -> LoggieMsg: - return msg(message, arg1, arg2, arg3, arg4, arg5).warn() - -## A shortcut method that instantly creates a [LoggieMsg] with the given arguments and outputs it at the error level. -## Can be used when you have no intention of customizing a LoggieMsg in any way using helper methods. -## For customization, use [method msg] instead. -func error(message = "", arg1 = null, arg2 = null, arg3 = null, arg4 = null, arg5 = null) -> LoggieMsg: - return msg(message, arg1, arg2, arg3, arg4, arg5).error() - -## A shortcut method that instantly creates a [LoggieMsg] with the given arguments and outputs it at the debug level. -## Can be used when you have no intention of customizing a LoggieMsg in any way using helper methods. -## For customization, use [method msg] instead. -func debug(message = "", arg1 = null, arg2 = null, arg3 = null, arg4 = null, arg5 = null) -> LoggieMsg: - return msg(message, arg1, arg2, arg3, arg4, arg5).debug() - -## A shortcut method that instantly creates a [LoggieMsg] with the given arguments and outputs it at the notice level. -## Can be used when you have no intention of customizing a LoggieMsg in any way using helper methods. -## For customization, use [method msg] instead. -func notice(message = "", arg1 = null, arg2 = null, arg3 = null, arg4 = null, arg5 = null) -> LoggieMsg: - return msg(message, arg1, arg2, arg3, arg4, arg5).notice() - -## Returns the path to the directory from which within this script is running. -func get_directory_path() -> String: - return get_script().resource_path.get_base_dir() - -## Returns a [LoggieMsg] that comes inserted with stylized content describing the stack trace obtained via [method get_stack]. -## This function only works in debug builds, and on the main thread, because it uses [method get_stack]. -## Read more about why in that function's documentation. -func stack() -> LoggieMsg: - if !OS.has_feature("debug"): - return msg() - - const FALLBACK_TXT_TO_FORMAT = "{index}: {fn_name}:{line} (in {source_path})" - var stack = get_stack() - var stack_msg = msg() - - var text_to_format = settings.format_stacktrace_entry if is_instance_valid(settings) else FALLBACK_TXT_TO_FORMAT - - stack.reverse() - - for index in stack.size(): - var file_name = stack[index].source.get_file().get_basename() - - if settings.skipped_filenames_in_stack_trace.has(file_name): - continue - - var entry_msg = LoggieMsg.new() - entry_msg.add(text_to_format.format({ - "index": index, - "source_path": stack[index].source, - "fn_name": stack[index].function, - "line": stack[index].line - })) - - if index == 0 or index < stack.size(): - entry_msg.prefix("\n ") - entry_msg.endseg() - - stack_msg.add(entry_msg) - - return stack_msg - -## Changes the values of certain members of [member settings] to values which are optimal for -## use in production builds. Used when [member LoggieSettings.enforce_optimal_settings_in_release_build] -## needs to be enforced. -func apply_production_optimal_settings(): - self.settings.msg_format_mode = LoggieEnums.MsgFormatMode.PLAIN - self.settings.box_characters_mode = LoggieEnums.BoxCharactersMode.COMPATIBLE diff --git a/addons/loggie/loggie.gd.uid b/addons/loggie/loggie.gd.uid deleted file mode 100644 index a77b9fa..0000000 --- a/addons/loggie/loggie.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bmh2auo806k0k diff --git a/addons/loggie/loggie_message.gd b/addons/loggie/loggie_message.gd deleted file mode 100644 index 4b67313..0000000 --- a/addons/loggie/loggie_message.gd +++ /dev/null @@ -1,566 +0,0 @@ -@tool - -## LoggieMsg represents a mutable object that holds an array of strings ([member content]) [i](referred to as 'content segments')[/i], and -## a bunch of helper methods that make it easy to manipulate these segments and chain together additions and changes to them. -## [br][br]For example: -## [codeblock] -### Prints: "Hello world!" at the INFO debug level. -##var msg = LoggieMsg.new("Hello world").color(Color.RED).suffix("!").info() -##[/codeblock] -## [br] You can also use [method Loggie.msg] to quickly construct a message. -## [br] Example of usage: -## [codeblock]Loggie.msg("Hello world").color(Color("#ffffff")).suffix("!").info()[/codeblock] -class_name LoggieMsg extends RefCounted - -## The full content of this message. By calling various helper methods in this class, this content is further altered. -## The content is an array of strings which represents segments of the message which are ultimately appended together -## to form the final message. You can start a new segment by calling [method msg] on this class. -## You can then output the whole message with methods like [method info], [method debug], etc. -var content : Array = [""] - -## The segment of [member content] that is currently being edited. -var current_segment_index : int = 0 - -## The (key string) domain this message belongs to. -## "" is the default domain which is always enabled. -## If this message attempts to be outputted, but belongs to a disabled domain, it will not be outputted. -## You can change which domains are enabled in Loggie at any time with [Loggie.set_domain_enabled]. -## This is useful for creating blocks of debugging output that you can simply turn off/on with a boolean when you actually need them. -var domain_name : String = "" - -## Stores a reference to the logger that generated this message, from which we need to read settings and other data. -## This variable should be set with [method use_logger] before an attempt is made to log this message out. -var _logger : Variant - -## Stores an array of IDs of all channels this message should be sent to when being outputted. -var used_channels : Array = ["terminal"] - -## Whether this message should be preprocessed and modified during [method output]. -var preprocess : bool = true - -## Usually, the [LoggieMsgChannel] this message gets outputted on sets the preprocessing steps this message should use. -## But sometimes we may want to use a specific set of preprocessing steps on this message, -## overriding the channel's set of rules. -## In that case, set this variable to the value of the [LoggieEnums.PreprocessStep] flags you want this message to use with -## [method preprocess]. -var custom_preprocess_flags : int = -1 - -## Stores the string which was obtained the last time the [method get_preprocessed] was called on this message. -## You need to call it at least once for this to have any results. -var last_preprocess_result : String = "" - -## Stores the integer value of a [enum LoggieEnums.LogLevel], matching the log level -## this message was most recently outputted at. If value is `-1`, the message was never -## outputted yet. -var last_outputted_at_log_level : int = -1 - -## Whether this message should append the stack trace during preprocessing. -var appends_stack : bool = false - -## Controls whether the [enum LoggieEnums.MsgType] of this message, during [method output], -## will be decided dynamically, based on the [enum LoggieEnums.LogLevel] the message is being output at. -## If disabled, the [member strict_type] will be used instead. -var dynamic_type : bool = true - -## The [LoggieEnums.MsgType] this message will be considered typed as, if [member dynamic_type] is set -## to [param false]. -var strict_type : LoggieEnums.MsgType = LoggieEnums.MsgType.INFO - -## The environment in which this message should be outputted based on the context the output is being requested from. -## (e.g. only in-engine (during tool scripts), or only ingame, or both). -var environment_mode : LoggieEnums.MsgEnvironment = LoggieEnums.MsgEnvironment.BOTH - -## If set to true, the [signal Loggie.log_attempted] signal will not be emitted when this message attempts to be outputted. -var dont_emit_log_attempted_signal : bool = false - -func _init(message = "", arg1 = null, arg2 = null, arg3 = null, arg4 = null, arg5 = null) -> void: - var args = [message, arg1, arg2, arg3, arg4, arg5] - self.content[0] = LoggieTools.concatenate_args(args) - self.set_meta("initial_args", args) - -## Returns a reference to the logger object that created this message. -func get_logger() -> Variant: - return self._logger - -## Sets this message to use the given [param logger] as the logger from which it will be reading -## settings. The given logger should be of class [Loggie] or an extension of it. -func use_logger(logger_to_use : Variant) -> LoggieMsg: - self._logger = logger_to_use - self.used_channels = self._logger.settings.default_channels - - # Now that a logger is connected, we can re-format the first segment - # using that Logger's converter function if it has a custom one defined. - if self.has_meta("initial_args"): - var initial_args = self.get_meta("initial_args") - if initial_args is Array: - var converter_fn = self._logger.settings.custom_string_converter if is_instance_valid(self._logger) and is_instance_valid(self._logger.settings) else null - if converter_fn != LoggieTools.convert_to_string: - self.content[0] = LoggieTools.concatenate_args(initial_args, converter_fn) - self.remove_meta("initial_args") # Clean up. - - return self - -## Sets the list of channels this message should be sent to when outputted. -## [param channels] should either be provided as a single channel ID (String), or -## as an array of channel IDs (Array of strings). -func channel(channels : Variant) -> LoggieMsg: - if typeof(channels) != TYPE_ARRAY and typeof(channels) != TYPE_PACKED_STRING_ARRAY: - channels = [str(channels)] - self.used_channels = channels - return self - -## Returns a processed version of the content of this message, which has modifications applied to -## it based on the requested [param type] and other settings defined by the provided preprocess [param flags]. -## Available preprocess flags are found in [enum LoggieEnums.PreprocessStep]. -func get_preprocessed(flags : int, _level : LoggieEnums.LogLevel, type : LoggieEnums.MsgType) -> String: - var loggie = get_logger() - var message = self.string() - - match type: - LoggieEnums.MsgType.ERROR: - message = loggie.settings.format_error_msg.format({"msg": message}) - LoggieEnums.MsgType.WARN: - message = loggie.settings.format_warning_msg.format({"msg": message}) - LoggieEnums.MsgType.NOTICE: - message = loggie.settings.format_notice_msg.format({"msg": message}) - LoggieEnums.MsgType.INFO: - message = loggie.settings.format_info_msg.format({"msg": message}) - LoggieEnums.MsgType.DEBUG: - message = loggie.settings.format_debug_msg.format({"msg": message}) - - if (flags & LoggieEnums.PreprocessStep.APPEND_DOMAIN_NAME != 0) and !self.domain_name.is_empty(): - message = _apply_format_domain(message) - - if (flags & LoggieEnums.PreprocessStep.APPEND_CLASS_NAME != 0) and OS.has_feature("debug"): - message = _apply_format_class_name(message) - - if (flags & LoggieEnums.PreprocessStep.APPEND_TIMESTAMPS != 0): - message = _apply_format_timestamp(message) - - if self.appends_stack or (loggie.settings.debug_msgs_print_stack_trace and type == LoggieEnums.MsgType.DEBUG): - message = _apply_format_stack(message) - - return message - -## Outputs the given string [param message] at the given output [param level] to the standard output using either [method print_rich] or [method print]. -## The domain from which the message is considered to be coming can be provided via [param target_domain]. -## The message type can be provided via [param msg_type], but it will be ignored if [member dynamic_type] is false, -## in which case, the [member strict_type] will be used. -## It also does a number of changes to the given [param msg] based on various Loggie settings. -## Designed to be called internally. You should consider using [method info], [method error], [method warn], [method notice], [method debug] instead. -func output(level : LoggieEnums.LogLevel, msg_type : LoggieEnums.MsgType = LoggieEnums.MsgType.INFO) -> void: - var loggie = get_logger() - var message = self.string() - var target_domain = self.domain_name - var target_channels = self.used_channels - - if loggie == null: - push_error("Attempt to log output with an invalid _logger. Make sure to call LoggieMsg.use_logger to set the appropriate logger before working with the message.") - return - - if loggie.settings == null: - push_error("Attempt to use a _logger with invalid settings to print: {msg}".format({"msg": message})) - return - - # We don't output the message if the settings dictate that messages of that level shouldn't be outputted. - if level > loggie.settings.log_level: - _emit_log_attempted_signal(LoggieEnums.LogAttemptResult.LOG_LEVEL_INSUFFICIENT) - return - - # We don't output the message if the domain from which it comes is not enabled. - if not loggie.is_domain_enabled(target_domain): - _emit_log_attempted_signal(LoggieEnums.LogAttemptResult.DOMAIN_DISABLED) - return - - # We don't output the message if the environment the output is being requested from is not compatible with - # the environment this message is configured to be outputted in. - match environment_mode: - LoggieEnums.MsgEnvironment.ENGINE: - if not Engine.is_editor_hint(): - _emit_log_attempted_signal(LoggieEnums.LogAttemptResult.WRONG_ENVIRONMENT) - return - LoggieEnums.MsgEnvironment.RUNTIME: - if Engine.is_editor_hint(): - _emit_log_attempted_signal(LoggieEnums.LogAttemptResult.WRONG_ENVIRONMENT) - return - - # Enforce the strict type of this message if it is configured not to allow dynamic type. - if !dynamic_type: - msg_type = strict_type - - # Send the message on all configured channels. - var custom_target_channels = loggie.get_domain_custom_target_channels(target_domain) - if custom_target_channels.size() > 0: - target_channels = custom_target_channels - - for channel_id : String in target_channels: - var channel : LoggieMsgChannel = loggie.get_channel(channel_id) - - if channel == null: - _emit_log_attempted_signal(LoggieEnums.LogAttemptResult.INVALID_CHANNEL) - continue - - # Preprocessing Stage: - # Apply full preprocessing only if explicitly enabled. - # Otherwise, simply concatenate together all the [member content]. - if self.preprocess: - var flags = self.custom_preprocess_flags if self.custom_preprocess_flags != -1 else channel.preprocess_flags - self.last_preprocess_result = get_preprocessed(flags, level, msg_type) - else: - self.last_preprocess_result = self.string() - - self.last_outputted_at_log_level = int(level) - channel.send(self, msg_type) - - # Emit signal deferred so if this is called from a thread, it doesn't cry about it. - _emit_log_attempted_signal(LoggieEnums.LogAttemptResult.SUCCESS, true) - -## Outputs this message from Loggie as an Error type message. -## The [Loggie.settings.log_level] must be equal to or higher to the ERROR level for this to work. -func error() -> LoggieMsg: - output(LoggieEnums.LogLevel.ERROR, LoggieEnums.MsgType.ERROR) - return self - -## Outputs this message from Loggie as an Warning type message. -## The [Loggie.settings.log_level] must be equal to or higher to the WARN level for this to work. -func warn() -> LoggieMsg: - output(LoggieEnums.LogLevel.WARN, LoggieEnums.MsgType.WARN) - return self - -## Outputs this message from Loggie as an Notice type message. -## The [Loggie.settings.log_level] must be equal to or higher to the NOTICE level for this to work. -func notice() -> LoggieMsg: - output(LoggieEnums.LogLevel.NOTICE, LoggieEnums.MsgType.NOTICE) - return self - -## Outputs this message from Loggie as an Info type message. -## The [Loggie.settings.log_level] must be equal to or higher to the INFO level for this to work. -func info() -> LoggieMsg: - output(LoggieEnums.LogLevel.INFO, LoggieEnums.MsgType.INFO) - return self - -## Outputs this message from Loggie as a Debug type message. -## The [Loggie.settings.log_level] must be equal to or higher to the DEBUG level for this to work. -func debug() -> LoggieMsg: - output(LoggieEnums.LogLevel.DEBUG, LoggieEnums.MsgType.DEBUG) - return self - -## Returns the string content of this message. -## If [param segment] is provided, it should be an integer indicating which segment of the message to return. -## If its value is -1, all segments are concatenated together and returned. -func string(segment : int = -1) -> String: - if segment == -1: - return "".join(self.content) - else: - if segment < self.content.size(): - return self.content[segment] - else: - push_error("Attempt to access a non-existent segment of a LoggieMsg. Make sure to use a valid segment index.") - return "" - -## Converts the current content of this message to an ANSI compatible form. -func to_ANSI() -> LoggieMsg: - var new_content : Array = [] - for segment in self.content: - new_content.append(LoggieTools.rich_to_ANSI(segment)) - self.content = new_content - return self - -## Strips all the BBCode in the current content of this message. -func strip_BBCode() -> LoggieMsg: - var new_content : Array = [] - for segment in self.content: - new_content.append(LoggieTools.remove_BBCode(segment)) - self.content = new_content - return self - -## Wraps the content of the current segment of this message in the given color. -## The [param color] can be provided as a [Color], a recognized Godot color name (String, e.g. "red"), or a color hex code (String, e.g. "#ff0000"). -func color(_color : Variant) -> LoggieMsg: - if _color is Color: - _color = _color.to_html() - - self.content[current_segment_index] = "[color={colorstr}]{msg}[/color]".format({ - "colorstr": _color, - "msg": self.content[current_segment_index] - }) - - return self - -## Stylizes the current segment of this message to be bold. -func bold() -> LoggieMsg: - self.content[current_segment_index] = "[b]{msg}[/b]".format({"msg": self.content[current_segment_index]}) - return self - -## Stylizes the current segment of this message to be italic. -func italic() -> LoggieMsg: - self.content[current_segment_index] = "[i]{msg}[/i]".format({"msg": self.content[current_segment_index]}) - return self - -## Makes the current segment of this message a hyperlink to the given [param url]. -## Optionally, you can provide a [param color], as the same type of parameter that [method color] uses, -## to colorize the link. This is a shortcut for additionally calling [method color] on the link. -## [br][br]If the link doesn't work when rendered inside of a [RichTextLabel], you may need to connect to the [signal RichTextLabel.meta_clicked] signal, -## and handle the opening of the link there. Read the docs of that signal for more info. -## [br][br][WARNING]: Appending URLs to messages is potentially dangerous. -## Please read this article for more info: https://docs.godotengine.org/en/latest/tutorials/ui/bbcode_in_richtextlabel.html#handling-user-input-safely -func link(url : String, _color : Variant = null) -> LoggieMsg: - self.content[current_segment_index] = "[url={url}]{msg}[/url]".format({"url": url, "msg": self.content[current_segment_index]}) - if _color: - self.color(_color) - return self - -## Stylizes the current segment of this message as a header. -func header() -> LoggieMsg: - var loggie = get_logger() - self.content[current_segment_index] = loggie.settings.format_header.format({"msg": self.content[current_segment_index]}) - return self - -## Sets whether this message should append the stack trace during preprocessing. -## If used in a different thread, it doesn't work, because it relies on [method get_stack] and -## that method doesn't work within threads. -func stack(enabled : bool = true) -> LoggieMsg: - self.appends_stack = enabled - return self - -## Constructs a decorative box with the given horizontal padding around the current segment -## of this message. Messages containing a box are not going to be preprocessed, so they are best -## used only as a special header or decoration. -func box(h_padding : int = 4) -> LoggieMsg: - var loggie = get_logger() - var stripped_content = LoggieTools.remove_BBCode(self.content[current_segment_index]).strip_edges(true, true) - var content_length = stripped_content.length() - var h_fill_length = content_length + (h_padding * 2) - var box_character_source = loggie.settings.box_symbols_compatible if loggie.settings.box_characters_mode == LoggieEnums.BoxCharactersMode.COMPATIBLE else loggie.settings.box_symbols_pretty - - var top_row_design = "{top_left_corner}{h_fill}{top_right_corner}".format({ - "top_left_corner" : box_character_source.top_left, - "h_fill" : box_character_source.h_line.repeat(h_fill_length), - "top_right_corner" : box_character_source.top_right - }) - - var middle_row_design = "{vert_line}{padding}{content}{space_fill}{padding}{vert_line}".format({ - "vert_line" : box_character_source.v_line, - "content" : self.content[current_segment_index], - "padding" : " ".repeat(h_padding), - "space_fill" : " ".repeat(h_fill_length - stripped_content.length() - h_padding*2) - }) - - var bottom_row_design = "{bottom_left_corner}{h_fill}{bottom_right_corner}".format({ - "bottom_left_corner" : box_character_source.bottom_left, - "h_fill" : box_character_source.h_line.repeat(h_fill_length), - "bottom_right_corner" : box_character_source.bottom_right - }) - - self.content[current_segment_index] = "{top_row}\n{middle_row}\n{bottom_row}\n".format({ - "top_row" : top_row_design, - "middle_row" : middle_row_design, - "bottom_row" : bottom_row_design - }) - - self.preprocessed(false) - return self - -## Appends additional content to this message at the end of the current content and its stylings. -## This does not create a new message segment, just appends to the current one. -func add(message : Variant = null, arg1 : Variant = null, arg2 : Variant = null, arg3 : Variant = null, arg4 : Variant = null, arg5 : Variant = null) -> LoggieMsg: - var converter_fn = self._logger.settings.custom_string_converter if is_instance_valid(self._logger) and is_instance_valid(self._logger.settings) else null - self.content[current_segment_index] = self.content[current_segment_index] + LoggieTools.concatenate_args([message, arg1, arg2, arg3, arg4, arg5], converter_fn) - return self - -## Adds a specified amount of newlines to the end of the current segment of this message. -func nl(amount : int = 1) -> LoggieMsg: - self.content[current_segment_index] += "\n".repeat(amount) - return self - -## Adds a specified amount of spaces to the end of the current segment of this message. -func space(amount : int = 1) -> LoggieMsg: - self.content[current_segment_index] += " ".repeat(amount) - return self - -## Adds a specified amount of tabs to the end of the current segment of this message. -func tab(amount : int = 1) -> LoggieMsg: - self.content[current_segment_index] += "\t".repeat(amount) - return self - -## Sets this message to belong to the domain with the given name. -## If it attempts to be outputted, but the domain is disabled, it won't be outputted. -func domain(_domain_name : String) -> LoggieMsg: - self.domain_name = _domain_name - return self - -## Prepends the given prefix string to the start of the message (first segment) with the provided separator. -func prefix(str_prefix : String, separator : String = "") -> LoggieMsg: - self.content[0] = "{prefix}{separator}{content}".format({ - "prefix" : str_prefix, - "separator" : separator, - "content" : self.content[0] - }) - return self - -## Appends the given suffix string to the end of the message (last segment) with the provided separator. -func suffix(str_suffix : String, separator : String = "") -> LoggieMsg: - self.content[self.content.size() - 1] = "{content}{separator}{suffix}".format({ - "suffix" : str_suffix, - "separator" : separator, - "content" : self.content[self.content.size() - 1] - }) - return self - -## Appends a horizontal separator with the given length to the current segment of this message. -## If [param alternative_symbol] is provided, it should be a String, and it will be used as the symbol for the separator instead of the default one. -func hseparator(size : int = 16, alternative_symbol : Variant = null) -> LoggieMsg: - var loggie = get_logger() - var symbol = loggie.settings.h_separator_symbol if alternative_symbol == null else str(alternative_symbol) - self.content[current_segment_index] = self.content[current_segment_index] + (symbol.repeat(size)) - return self - -## Ends the current segment of the message and starts a new one. -func endseg() -> LoggieMsg: - self.content.push_back("") - self.current_segment_index = self.content.size() - 1 - return self - -## Sets the environment in which this message should be outputted based on the context the output is being requested from. -## (e.g. only in-engine (during tool scripts), or only ingame, or both). -func env(mode : LoggieEnums.MsgEnvironment) -> LoggieMsg: - self.environment_mode = mode - return self - -## Creates a new segment in this message and sets its content to the given message. -## Acts as a shortcut for calling [method endseg] + [method add]. -func msg(message = "", arg1 = null, arg2 = null, arg3 = null, arg4 = null, arg5 = null) -> LoggieMsg: - self.endseg() - var converter_fn = self._logger.settings.custom_string_converter if is_instance_valid(self._logger) and is_instance_valid(self._logger.settings) else null - self.content[current_segment_index] = LoggieTools.concatenate_args([message, arg1, arg2, arg3, arg4, arg5], converter_fn) - return self - -## Sets whether this message should be preprocessed and potentially modified with prefixes and suffixes during [method output]. -## If turned off, while outputting this message, Loggie will skip the steps where it appends the messaage domain, class name, timestamp, etc. -## Whether preprocess is set to true doesn't affect the final conversion from RICH to ANSI or PLAIN, which always happens -## under some circumstances that are based on other settings. -func preprocessed(shouldPreprocess : bool) -> LoggieMsg: - self.preprocess = shouldPreprocess - return self - -## Sets this message's [LoggieEnums.MsgType] to be strictly the provided value, -## instead of dynamically decided by the log level at which it is being outputted. -## [br][param loggie_enums_msgtype_key_or_value] should either be provided as a direct value of the enum, -## (e.g. [enum LoggieEnum.MsgType.INFO]) or as a string matching one of the keys in that enum (e.g. -## `"info"` or `"INFO"`, case-insensitive). -func type(loggie_enums_msgtype_key_or_value : Variant) -> LoggieMsg: - var isValid = false - var _type : LoggieEnums.MsgType - - if loggie_enums_msgtype_key_or_value is LoggieEnums.MsgType: - _type = loggie_enums_msgtype_key_or_value - isValid = true - elif loggie_enums_msgtype_key_or_value is String: - var uppercase_key = loggie_enums_msgtype_key_or_value.to_upper() - if LoggieEnums.MsgType.keys().has(uppercase_key): - _type = LoggieEnums.MsgType[uppercase_key] - isValid = true - - if isValid: - dynamic_type = false - strict_type = _type - else: - push_error("Attempt to set LoggieMsg type to {value} - could not be converted to a proper [LoggieEnums.MsgType]. Either provide a [LoggieEnums.MsgType], or a string that matches a key in that enum (case-insensitive).".format({"value": str(loggie_enums_msgtype_key_or_value)})) - - return self - -## If [param enabled], the [signal Loggie.log_attempted] signal will not be emitted when this message attempts to be outputted. -func no_signal(enabled : bool = true) -> LoggieMsg: - dont_emit_log_attempted_signal = enabled - return self - -## Applies the [LoggiePreset] with the given [param id] to this message. -## [br]If [param apply_only_to_current_segment] is [param true], the styles from the preset will only be -## applied to the current content segment of this message. Otherwise, the entire content of this message -## will be collapsed into a single segment, and the styles will be applied to that. -func preset(id : String, apply_only_to_current_segment : bool = false) -> LoggieMsg: - var loggie = get_logger() - var preset_to_use : LoggiePreset = loggie.preset(id) - if preset_to_use: - preset_to_use.apply_to(self, apply_only_to_current_segment) - else: - push_error("Attempt to obtain LoggiePreset with ID {id} returned null. Something went terribly wrong, as this should usually be impossible.") - return self - -## Internal method. Emits the [signal Loggie.log_attempted] signal (unless that feature is disabled). -## Used during [method output]. If [param call_deferred] is true, the string of the message's content will -## be prepared immediately, but the emission of the signal will be deferred. -func _emit_log_attempted_signal(result : LoggieEnums.LogAttemptResult, call_deferred : bool = false) -> void: - if dont_emit_log_attempted_signal: - return - - var loggie = get_logger() - var string_content = self.string() - - if call_deferred: - loggie.call_deferred("emit_signal", "log_attempted", self, string_content, result) - else: - loggie.log_attempted.emit(self, string_content, result) - -## Adds this message's configured domain to the start of the given [param message] and returns the modifier version of it. -func _apply_format_domain(message : String) -> String: - var loggie = get_logger() - message = loggie.settings.format_domain_prefix.format({"domain" : self.domain_name, "msg" : message}) - return message - -## Adds a formatted class name to the given [param message] and returns the modified version of it. -func _apply_format_class_name(message : String) -> String: - var loggie = get_logger() - var stack_frame : Dictionary = LoggieTools.get_current_stack_frame_data() - var _class_name : String - - var scriptPath = stack_frame.source - if loggie.class_names.has(scriptPath): - _class_name = loggie.class_names[scriptPath] - else: - _class_name = LoggieTools.get_class_name_from_script(scriptPath, loggie.settings.nameless_class_name_proxy) - loggie.class_names[scriptPath] = _class_name - - if _class_name != "": - message = "[b]({class_name})[/b] {msg}".format({ - "class_name" : _class_name, - "msg" : message - }) - return message - -## Adds a formatted timestamp to the given [param message] and returns the modified version of it. -func _apply_format_timestamp(message : String) -> String: - var loggie = get_logger() - var format_dict : Dictionary = Time.get_datetime_dict_from_system(loggie.settings.timestamps_use_utc) - for field in ["month", "day", "hour", "minute", "second"]: - format_dict[field] = "%02d" % format_dict[field] - - # Add the millisecond - var unix_time: float = Time.get_unix_time_from_system() - var millisecond: int = int((unix_time - int(unix_time)) * 1000.0) - format_dict["millisecond"] = "%03d" % millisecond - - # Add the startup time to the format dictionary. - var elapsed_millisecond: int = Time.get_ticks_msec() - var startup_hour: int = elapsed_millisecond / 3_600_000 - var startup_minute: int = (elapsed_millisecond % 3_600_000) / 60_000 - var startup_second: int = (elapsed_millisecond % 60_000) / 1000 - var startup_millisecond: int = elapsed_millisecond % 1000 - format_dict["startup_hour"] = "%02d" % startup_hour - format_dict["startup_minute"] = "%02d" % startup_minute - format_dict["startup_second"] = "%02d" % startup_second - format_dict["startup_millisecond"] = "%03d" % startup_millisecond - - message = "{formatted_time} {msg}".format({ - "formatted_time" : loggie.settings.format_timestamp.format(format_dict), - "msg" : message - }) - - return message - -## Adds the stack trace to the given [param message] and returns the modified version of it. -func _apply_format_stack(message : String) -> String: - var loggie = get_logger() - var stack_msg = loggie.stack() - message = message + stack_msg.string() - return message diff --git a/addons/loggie/loggie_message.gd.uid b/addons/loggie/loggie_message.gd.uid deleted file mode 100644 index e1c7a5c..0000000 --- a/addons/loggie/loggie_message.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bd3hgca3nslui diff --git a/addons/loggie/loggie_message_channel.gd b/addons/loggie/loggie_message_channel.gd deleted file mode 100644 index 5a4d44e..0000000 --- a/addons/loggie/loggie_message_channel.gd +++ /dev/null @@ -1,24 +0,0 @@ -@tool - -## A class that describes a channel that can be used to output Loggie Messages. -class_name LoggieMsgChannel extends RefCounted - -## The ID of the channel. -var ID : String = "" - -## The preprocessing steps a [method LoggieMsg] that's about to be -## sent to this channel has to go through. See: [LoggieEnums.PreprocessStep] for -## the list of flags that can be used. -var preprocess_flags : int = 0 - -## Defines what happens when some [LoggieMsg] wants to be sent with this channel. -## [br]If you're implementing your own channel, override this function to define -## how your channel outputs the message. -## -## You can access the last known preprocessed version of the message -## in [LoggieMsg.last_preprocess_result]. -## -## If your channel requires extra data, the data can be embedded into a message -## with [method LoggieMsg.set_meta] and read here with [method LoggieMsg.get_meta]. -func send(msg : LoggieMsg, type : LoggieEnums.MsgType): - pass diff --git a/addons/loggie/loggie_message_channel.gd.uid b/addons/loggie/loggie_message_channel.gd.uid deleted file mode 100644 index acf9e4b..0000000 --- a/addons/loggie/loggie_message_channel.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bunns8okgi81c diff --git a/addons/loggie/loggie_preset.gd b/addons/loggie/loggie_preset.gd deleted file mode 100644 index b0d42aa..0000000 --- a/addons/loggie/loggie_preset.gd +++ /dev/null @@ -1,83 +0,0 @@ -## An extension of the [LoggieMsg] class, meant to clearly differentiate between a message -## that was created with the sole purpose of being used as a Preset. -## Future behaviors of the message may diverge from regular behaviors of LoggieMsg, hence -## being separated into a different class. -class_name LoggiePreset extends LoggieMsg - -## A placeholder that will be placed into the content of this preset as soon as it's initialized. -## This placeholder then gets wrapped with various styles as you call methods (e.g. [method bold], -## [method italic], etc.) on the preset. Later, only this string part of the content -## gets replaced by the actual content of a message this preset is being applied to, keeping the -## wrapped styles around it. -const content_placeholder = "{content}" - -func _init(message = "", arg1 = null, arg2 = null, arg3 = null, arg4 = null, arg5 = null) -> void: - self.content = [content_placeholder] - -## Applies the settings and styles from this preset onto the given [LoggieMsg], modifying that message -## (does not create a duplicate) and returning that same message after it has been modified. -## -## [br][br]If any styles are applied to this [LoggiePreset], the entire content of the given [LoggieMsg] will -## be collapsed into a single segment, then have this preset's styles wrapped around that segment. -## [b]This directly resizes the [member LoggieMsg.content] array on the modified message.[/b] -## -## [br][br]However, if [param only_to_current_segment] is true, only the [member LoggieMsg.content] of -## the message found at its [member LoggieMsg.current_segment_index] will be wrapped in this preset's styles and modified, -## hence no resizing of the [member LoggieMsg.content] array will occur. -## -## [br]Neither of the above described actions will occur if this preset's content was not modified by any styles in any way. -func apply_to(msg : LoggieMsg, only_to_current_segment : bool = false) -> LoggieMsg: - if msg is LoggiePreset: - push_error("Attempt to apply a [LoggiePreset] to another [LoggiePreset] - unsupported behavior.") - return - - # Apply the settings from this setting on the given message. - msg.domain_name = self.domain_name - msg.used_channels = self.used_channels.duplicate() - msg.preprocess = self.preprocess - msg.custom_preprocess_flags = self.custom_preprocess_flags - msg.appends_stack = self.appends_stack - msg.dynamic_type = self.dynamic_type - msg.strict_type = self.strict_type - msg.environment_mode = self.environment_mode - msg.dont_emit_log_attempted_signal = self.dont_emit_log_attempted_signal - - # If no modifications were done to this preset's content (no styles applied), - # we don't need to go further. - if self.content[0] == content_placeholder: - return msg - - # Otherwise, - # Based on the value of [param only_to_current_segment], either: - # 1. (if true): Replace the content of the [param msg] on its current segment to be that same content, but wrapped in the styles of this preset. - # 2. (if false): Smush the entire content of the [param msg] into a single segment, then wrap that segment in the styles of this preset. - var content_to_apply_preset_to : String - - if only_to_current_segment: - content_to_apply_preset_to = msg.string(msg.current_segment_index) - var new_segment_content = self.content[0].format({"content": content_to_apply_preset_to}) - msg.content[msg.current_segment_index] = new_segment_content - else: - content_to_apply_preset_to = msg.string() - var new_message_content = self.content[0].format({"content": content_to_apply_preset_to}) - msg.content = [new_message_content] - - return msg - -## Overrides the parent class method by the same name to disable its functionality. -## Presets cannot have additional segments added. -func endseg() -> LoggieMsg: - push_warning("Attempt to call LoggieMsg.endseg on a LoggiePreset. This is not allowed. Presets shouldn't have more than 1 string content segment.") - return self - -## Overrides the parent class method by the same name to disable its functionality. -## Presets cannot have their content modified. -func msg(message = "", arg1 = null, arg2 = null, arg3 = null, arg4 = null, arg5 = null) -> LoggieMsg: - push_warning("Attempt to call LoggieMsg.msg on a LoggiePreset. This is not allowed. Presets cannot have string content.") - return self - -## Overrides the parent class method by the same name to disable its functionality. -## Presets cannot be outputted, they are only meant to be applied to other [LoggieMsg]s. -func output(level : LoggieEnums.LogLevel, msg_type : LoggieEnums.MsgType = LoggieEnums.MsgType.INFO) -> void: - push_warning("Attempt to call LoggieMsg.output on a LoggiePreset. This is not allowed. Presets should only be applied to other [LoggieMsg] instances, not used directly.") - return diff --git a/addons/loggie/loggie_preset.gd.uid b/addons/loggie/loggie_preset.gd.uid deleted file mode 100644 index ad6f8a1..0000000 --- a/addons/loggie/loggie_preset.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b2oby5841g2bw diff --git a/addons/loggie/loggie_settings.gd b/addons/loggie/loggie_settings.gd deleted file mode 100644 index 48a1334..0000000 --- a/addons/loggie/loggie_settings.gd +++ /dev/null @@ -1,521 +0,0 @@ -@tool - -## Defines a set of variables through which all the relevant settings of Loggie can have their -## values set, read and documented. An instance of this class is found in [member Loggie.settings], and that's where Loggie -## ultimately reads from when it's asking for the value of a setting. For user convenience, settings are (by default) exported -## as custom Godot project settings and are loaded from there into these variables during [method load], however, -## you can extend or overwrite this class' [method load] method to define a different way of loading these settings if you prefer. -## [i](e.g. loading from a config.ini file, or a .json file, etc.)[/i].[br][br] -## -## Loggie calls [method load] on this class during its [method _ready] function. -class_name LoggieSettings extends Resource - -## The name that will be used for the singleton referring to Loggie. -## [br][br][i][b]Note:[/b] You may change this to something you're more used to, such as "log" or "logger".[/i] -## When doing so, make sure to either do it while the Plugin is enabled, then disable and re-enable the plugin, -## or that you manually clear out the previously created autoload (should be called "Loggie") in Project Settings -> Autoloads. -static var loggie_singleton_name = "Loggie" - -# ----------------------------------------------- # -#region Project Settings -# ----------------------------------------------- # -## The dictionary which is used to grab the defaults and other values associated with each setting -## relevant to Loggie, particularly important for the default way of loading [LoggieSettings] and -## setting up Godot Project Settings related to Loggie. -const project_settings = { - "update_check_mode" = { - "path": "loggie/general/check_for_updates", - "default_value" : LoggieEnums.UpdateCheckType.CHECK_AND_SHOW_UPDATER_WINDOW, - "type" : TYPE_INT, - "hint" : PROPERTY_HINT_ENUM, - "hint_string" : "Never:0,Only print notice if available:1,Print notice and auto-install:2,Yes and show updater window:3", - "doc" : "Sets which behavior Loggie should use when checking for updates.", - }, - "remove_settings_if_plugin_disabled" = { - "path": "loggie/general/remove_settings_if_plugin_disabled", - "default_value" : true, - "type" : TYPE_BOOL, - "hint" : PROPERTY_HINT_NONE, - "hint_string" : "", - "doc" : "Choose whether you want Loggie project settings to be wiped from ProjectSettings if the Loggie plugin is disabled.", - }, - "msg_format_mode" = { - "path": "loggie/general/msg_format_mode", - "default_value" : LoggieEnums.MsgFormatMode.BBCODE, - "type" : TYPE_INT, - "hint" : PROPERTY_HINT_ENUM, - "hint_string" : "Plain:0,ANSI:1,BBCode:2,Markdown:3", - "doc" : "Choose the format for which loggie should preprocess the output so that it displays correctly on the intended output medium.[br][br]Use BBCode for Godot console.[br]Use ANSI for Powershell, Bash, etc.[br]Use MARKDOWN for Discord.[br]Use PLAIN for log files.", - }, - "log_level" = { - "path": "loggie/general/log_level", - "default_value" : LoggieEnums.LogLevel.INFO, - "type" : TYPE_INT, - "hint" : PROPERTY_HINT_ENUM, - "hint_string" : "Error:0,Warn:1,Notice:2,Info:3,Debug:4", - "doc" : "Choose the level of messages which should be displayed. Loggie displays all messages that are outputted at the currently set level (or any lower level).", - }, - "show_system_specs" = { - "path": "loggie/general/show_system_specs", - "default_value" : true, - "type" : TYPE_BOOL, - "hint" : PROPERTY_HINT_NONE, - "hint_string" : "", - "doc" : "Should Loggie log the system and device specs of the user as soon as it is booted?", - }, - "show_loggie_specs" = { - "path": "loggie/general/show_loggie_specs", - "default_value" : LoggieEnums.ShowLoggieSpecsMode.ESSENTIAL, - "type" : TYPE_INT, - "hint" : PROPERTY_HINT_ENUM, - "hint_string" : "Disabled:0,Essential:1,Advanced:2", - "doc" : "Defines which way Loggie should print its own specs when it is booted.", - }, - "enforce_optimal_settings_in_release_build" = { - "path": "loggie/general/enforce_optimal_settings_in_release_build", - "default_value" : true, - "type" : TYPE_BOOL, - "hint" : PROPERTY_HINT_NONE, - "hint_string" : "", - "doc" : "Should Loggie enforce certain settings to automatically change to optimal values in production/release builds?", - }, - "default_channels" = { - "path": "loggie/general/default_channels", - "default_value" : ["terminal"], - "type" : TYPE_PACKED_STRING_ARRAY, - "hint" : PROPERTY_HINT_TYPE_STRING, - "hint_string" : "", - "doc" : "The channels messages outputted from Loggie will be sent to by default (if not modified with LoggieMsg.channel method).", - }, - "skipped_filenames_in_stack_trace" = { - "path": "loggie/general/skipped_filenames_in_stack_trace", - "default_value" : ["loggie", "loggie_message"], - "type" : TYPE_PACKED_STRING_ARRAY, - "hint" : PROPERTY_HINT_TYPE_STRING, - "hint_string" : "", - "doc" : "The file names, which, when appearing in a stack trace, should be omitted from the output.", - }, - "discord_webhook_url_live" = { - "path": "loggie/general/discord/live_webhook", - "default_value" : "", - "type" : TYPE_STRING, - "hint" : PROPERTY_HINT_MULTILINE_TEXT, - "hint_string" : "", - "doc" : "The endpoint URL for the Discord webhook used when Loggie is running in a production build.", - }, - "discord_webhook_url_dev" = { - "path": "loggie/general/discord/dev_webhook", - "default_value" : "", - "type" : TYPE_STRING, - "hint" : PROPERTY_HINT_MULTILINE_TEXT, - "hint_string" : "", - "doc" : "The endpoint URL for the Discord webhook used when Loggie is not running in a production build.", - }, - "slack_webhook_url_live" = { - "path": "loggie/general/slack/live_webhook", - "default_value" : "", - "type" : TYPE_STRING, - "hint" : PROPERTY_HINT_MULTILINE_TEXT, - "hint_string" : "", - "doc" : "The endpoint URL for the Slack webhook used when Loggie is running in a production build.", - }, - "slack_webhook_url_dev" = { - "path": "loggie/general/slack/dev_webhook", - "default_value" : "", - "type" : TYPE_STRING, - "hint" : PROPERTY_HINT_MULTILINE_TEXT, - "hint_string" : "", - "doc" : "The endpoint URL for the Slack webhook used when Loggie is not running in a production build.", - }, - "timestamps_use_utc" = { - "path": "loggie/preprocessing/timestamps_use_utc", - "default_value" : true, - "type" : TYPE_BOOL, - "hint" : PROPERTY_HINT_NONE, - "hint_string" : "", - "doc" : "If 'Output Timestamps' is true, should those timestamps use the UTC time. If not, local system time is used instead.", - }, - "output_errors_to_console" = { - "path": "loggie/preprocessing/terminal/output_errors_also_to_console", - "default_value" : true, - "type" : TYPE_BOOL, - "hint" : PROPERTY_HINT_NONE, - "hint_string" : "", - "doc" : "If true, errors printed by Loggie will also be visible through an additional print in the main output.", - }, - "output_warnings_to_console" = { - "path": "loggie/preprocessing/terminal/output_warnings_also_to_console", - "default_value" : true, - "type" : TYPE_BOOL, - "hint" : PROPERTY_HINT_NONE, - "hint_string" : "", - "doc" : "If true, warnings printed by Loggie will also be visible through an additional print in the main output.", - }, - "debug_msgs_print_stack_trace" = { - "path": "loggie/preprocessing/terminal/debug_msgs_print_stack_trace", - "default_value" : false, - "type" : TYPE_BOOL, - "hint" : PROPERTY_HINT_NONE, - "hint_string" : "", - "doc" : "If true, 'debug' level messages outputted by Loggie will also print the stack trace.", - }, - "nameless_class_name_proxy" = { - "path": "loggie/preprocessing/nameless_class_name_proxy", - "default_value" : LoggieEnums.NamelessClassExtensionNameProxy.BASE_TYPE, - "type" : TYPE_INT, - "hint" : PROPERTY_HINT_ENUM, - "hint_string" : "Nothing:0,ScriptName:1,BaseType:2", - "doc" : "If 'Derive and Display Class Names From Scripts' is enabled, and a script doesn't have a 'class_name', which text should we use as a substitute?", - }, - "preprocess_flags_terminal_channel" = { - "path": "loggie/preprocessing/terminal/preprocess_flags", - "default_value" : LoggieEnums.PreprocessStep.APPEND_TIMESTAMPS | LoggieEnums.PreprocessStep.APPEND_DOMAIN_NAME | LoggieEnums.PreprocessStep.APPEND_CLASS_NAME, - "type" : TYPE_INT, - "hint" : PROPERTY_HINT_FLAGS, - "hint_string" : "Append Timestamp:1,Append Domain Name:2,Append Class Name:4", - "doc" : "Defines the flags which LoggieMessages sent to the terminal channel will use during preprocessing.", - }, - "preprocess_flags_discord_channel" = { - "path": "loggie/preprocessing/discord/preprocess_flags", - "default_value" : LoggieEnums.PreprocessStep.APPEND_DOMAIN_NAME | LoggieEnums.PreprocessStep.APPEND_CLASS_NAME, - "type" : TYPE_INT, - "hint" : PROPERTY_HINT_FLAGS, - "hint_string" : "Append Timestamp:1,Append Domain Name:2,Append Class Name:4", - "doc" : "Defines the flags which LoggieMessages sent to the Discord channel will use during preprocessing.", - }, - "preprocess_flags_slack_channel" = { - "path": "loggie/preprocessing/slack/preprocess_flags", - "default_value" : LoggieEnums.PreprocessStep.APPEND_DOMAIN_NAME | LoggieEnums.PreprocessStep.APPEND_CLASS_NAME, - "type" : TYPE_INT, - "hint" : PROPERTY_HINT_FLAGS, - "hint_string" : "Append Timestamp:1,Append Domain Name:2,Append Class Name:4", - "doc" : "Defines the flags which LoggieMessages sent to the Slack channel will use during preprocessing.", - }, - "format_timestamp" = { - "path": "loggie/formats/timestamp", - "default_value" : "[{day}.{month}.{year} {hour}:{minute}:{second}]", - "type" : TYPE_STRING, - "hint" : PROPERTY_HINT_NONE, - "hint_string" : "", - "doc" : "The format used for timestamps which are prepended to the message when the appending of timestamps is enabled.", - }, - "format_stacktrace_entry" = { - "path": "loggie/formats/stacktrace_entry", - "default_value" : "{index}: [color=#ff7085]func[/color] [color=#53b1c3][b]{fn_name}[/b]:{line}[/color] [color=slate_gray][i](in {source_path})[/i][/color]", - "type" : TYPE_STRING, - "hint" : PROPERTY_HINT_NONE, - "hint_string" : "", - "doc" : "The format used for stack trace entries when trace logging is enabled.", - }, - "format_debug_msg" = { - "path": "loggie/formats/debug_message", - "default_value" : "[b][color=pink][DEBUG]:[/color][/b] {msg}", - "type" : TYPE_STRING, - "hint" : PROPERTY_HINT_NONE, - "hint_string" : "", - "doc" : "The format used for debug messages.", - }, - "format_info_msg" = { - "path": "loggie/formats/info_message", - "default_value" : "{msg}", - "type" : TYPE_STRING, - "hint" : PROPERTY_HINT_NONE, - "hint_string" : "", - "doc" : "The format used for info messages.", - }, - "format_notice_msg" = { - "path": "loggie/formats/notice_message", - "default_value" : "[b][color=cyan][NOTICE]:[/color][/b] {msg}", - "type" : TYPE_STRING, - "hint" : PROPERTY_HINT_NONE, - "hint_string" : "", - "doc" : "The format used for notice messages.", - }, - "format_warning_msg" = { - "path": "loggie/formats/warning_message", - "default_value" : "[b][color=orange][WARN]:[/color][/b] {msg}", - "type" : TYPE_STRING, - "hint" : PROPERTY_HINT_NONE, - "hint_string" : "", - "doc" : "The format used for warning messages.", - }, - "format_error_msg" = { - "path": "loggie/formats/error_message", - "default_value" : "[b][color=red][ERROR]:[/color][/b] {msg}", - "type" : TYPE_STRING, - "hint" : PROPERTY_HINT_NONE, - "hint_string" : "", - "doc" : "The format used for error messages.", - }, - "format_domain_prefix" = { - "path": "loggie/formats/domain_prefix", - "default_value" : "[b]({domain})[/b] {msg}", - "type" : TYPE_STRING, - "hint" : PROPERTY_HINT_NONE, - "hint_string" : "", - "doc" : "The format used for domain prefixes.", - }, - "format_header" = { - "path": "loggie/formats/header", - "default_value" : "[b][i]{msg}[/i][/b]", - "type" : TYPE_STRING, - "hint" : PROPERTY_HINT_NONE, - "hint_string" : "", - "doc" : "The format used for headers.", - }, - "h_separator_symbol" = { - "path": "loggie/formats/h_separator_symbol", - "default_value" : "-", - "type" : TYPE_STRING, - "hint" : PROPERTY_HINT_NONE, - "hint_string" : "", - "doc" : "The symbol used for the horizontal separator.", - }, - "box_characters_mode" = { - "path": "loggie/formats/box_characters_mode", - "default_value" : LoggieEnums.BoxCharactersMode.COMPATIBLE, - "type" : TYPE_INT, - "hint" : PROPERTY_HINT_ENUM, - "hint_string" : "Compatible:0,Pretty:1", - "doc" : "There are two sets of box characters defined in LoggieSettings - one set contains prettier characters that produce a nicer looking box, but may not render correctly in the context of various terminals. The other set contains characters that produce a less pretty box, but are compatible with being shown in most terminals.", - } -} - -#endregion -# ----------------------------------------------- # -#region Variables -# ----------------------------------------------- # - -## The current behavior Loggie uses to check for updates. -var update_check_mode : LoggieEnums.UpdateCheckType = LoggieEnums.UpdateCheckType.CHECK_AND_SHOW_UPDATER_WINDOW - -## The current Message Format Mode of Loggie. -## Message Format Mode determines whether BBCode, ANSI or some other type of -## formatting is used to convey text effects, such as bold, italic, colors, etc. -## [br][br]BBCode is compatible with the Godot console. -## [br]ANSI is compatible with consoles like Powershell and Windows CMD. -## [br]PLAIN is used to strip any effects and use plain text instead, which is good for saving raw logs into log files. -var msg_format_mode : LoggieEnums.MsgFormatMode = LoggieEnums.MsgFormatMode.BBCODE - -## The current log level of Loggie. -## It determines which types of messages are allowed to be logged. -## Set this using [method setLogLevel]. -var log_level : LoggieEnums.LogLevel = LoggieEnums.LogLevel.INFO - -## Whether or not Loggie should log the loggie specs on ready. -var show_loggie_specs : LoggieEnums.ShowLoggieSpecsMode = LoggieEnums.ShowLoggieSpecsMode.ESSENTIAL - -## Whether or not Loggie should log the system specs on ready. -var show_system_specs : bool = true - -## Whether to, in addition to logging errors with [method push_error], -## Loggie should also print the error as a message in the standard output. -var print_errors_to_console : bool = true - -## Whether to, in addition to logging errors with [method push_warning], -## Loggie should also print the error as a message in the standard output. -var print_warnings_to_console : bool = true - -## Defines which text will be used as a substitute for the 'class_name' of scripts that do not have a 'class_name'. -## Relevant only during the [member LoggieEnums.PreprocessStep.APPEND_CLASS_NAME] step of preprocessing. -var nameless_class_name_proxy : LoggieEnums.NamelessClassExtensionNameProxy - -## Whether the outputted timestamps use UTC or local machine time. -var timestamps_use_utc : bool = true - -## If true, when outputting Debug level messages, the stack trace will also be appended. -var debug_msgs_print_stack_trace : bool = false - -## Whether Loggie should enforce optimal values for certain settings when in a Release/Production build. -## [br]If true, Loggie will enforce: -## [br] * [member msg_format_mode] to [member LoggieEnums.MsgFormatMode.PLAIN] -## [br] * [member box_characters_mode] to [member LoggieEnums.BoxCharactersMode.COMPATIBLE] -var enforce_optimal_settings_in_release_build : bool = true - -## Endpoint URL for the Discord webhook (used in dev environment) -## [br][b]NEVER[/b] distribute your webhook in your project's repository, source code, or built game, where it can be accessed by other people. -## This is meant to be used only in controlled circumstances. -var discord_webhook_url_dev : String = "" - -## Endpoint URL for the Discord webhook (used in production/release environment) -## [br][b]NEVER[/b] distribute your webhook in your project's repository, source code, or built game, where it can be accessed by other people. -## This is meant to be used only in controlled circumstances. -var discord_webhook_url_live : String = "" - -## Endpoint URL for the Slack webhook (used in dev environment) -## [br][b]NEVER[/b] distribute your webhook in your project's repository, source code, or built game, where it can be accessed by other people. -## This is meant to be used only in controlled circumstances. -var slack_webhook_url_dev : String = "" - -## Endpoint URL for the Slack webhook (used in production/release environment) -## [br][b]NEVER[/b] distribute your webhook in your project's repository, source code, or built game, where it can be accessed by other people. -## This is meant to be used only in controlled circumstances. -var slack_webhook_url_live : String = "" - -## Defines the flags which LoggieMessages sent to the terminal channel will use during preprocessing. -var preprocess_flags_terminal_channel = LoggieEnums.PreprocessStep.APPEND_TIMESTAMPS | LoggieEnums.PreprocessStep.APPEND_DOMAIN_NAME | LoggieEnums.PreprocessStep.APPEND_CLASS_NAME - -## Defines the flags which LoggieMessages sent to the Discord channel output will use during preprocessing. -var preprocess_flags_discord_channel = LoggieEnums.PreprocessStep.APPEND_DOMAIN_NAME | LoggieEnums.PreprocessStep.APPEND_CLASS_NAME - -## Defines the flags which LoggieMessages sent to the Slack channel output will use during preprocessing. -var preprocess_flags_slack_channel = LoggieEnums.PreprocessStep.APPEND_DOMAIN_NAME | LoggieEnums.PreprocessStep.APPEND_CLASS_NAME - -## The list of channels a message outputted from Loggie should be sent to by default. -var default_channels : PackedStringArray = ["terminal"] - -## The list of file names, which, when appearing in a stack trace, should be omitted from the output.. -var skipped_filenames_in_stack_trace : PackedStringArray = ["loggie", "loggie_message"] - -#endregion -# ----------------------------------------------- # -#region Formats for prints -# ----------------------------------------------- # -# As per the `print_rich` documentation, supported colors are: black, red, green, yellow, blue, magenta, pink, purple, cyan, white, orange, gray. -# Any other color will be displayed in the Godot console or an ANSI based console, but the color tag (in case of BBCode) won't be properly stripped -# when written to the .log file, resulting in BBCode visible in .log files. - -## The format used to decorate a message as a header when using [method LoggieMsg.header].[br] -## The [param {msg}] is a variable that will be replaced with the contents of the message.[br] -var format_header = "[b][i]{msg}[/i][/b]" - -## The format used when appending a domain to a message.[br] -## The [param {msg}] is a variable that will be replaced with the contents of the message.[br] -## The [param {domain}] is a variable that will be replaced with the domain key.[br] -## You can customize this in your ProjectSettings, or custom_settings.gd (if using it).[br] -var format_domain_prefix = "[b]({domain})[/b] {msg}" - -## The format used when outputting error messages.[br] -## The [param {msg}] is a variable that will be replaced with the contents of the message.[br] -## You can customize this in your ProjectSettings, or custom_settings.gd (if using it).[br] -var format_error_msg = "[b][color=red][ERROR]:[/color][/b] {msg}" - -## The format used when outputting warning messages.[br] -## The [param {msg}] is a variable that will be replaced with the contents of the message.[br] -## You can customize this in your ProjectSettings, or custom_settings.gd (if using it).[br] -var format_warning_msg = "[b][color=orange][WARN]:[/color][/b] {msg}" - -## The format used when outputting notice messages.[br] -## The [param {msg}] is a variable that will be replaced with the contents of the message.[br] -## You can customize this in your ProjectSettings, or custom_settings.gd (if using it).[br] -var format_notice_msg = "[b][color=cyan][NOTICE]:[/color][/b] {msg}" - -## The format used when outputting info messages.[br] -## The [param {msg}] is a variable that will be replaced with the contents of the message.[br] -## You can customize this in your ProjectSettings, or custom_settings.gd (if using it).[br] -var format_info_msg = "{msg}" - -## The format used when outputting debug messages.[br] -## The [param {msg}] is a variable that will be replaced with the contents of the message.[br] -## You can customize this in your ProjectSettings, or custom_settings.gd (if using it).[br] -var format_debug_msg = "[b][color=pink][DEBUG]:[/color][/b] {msg}" - -## The format used for timestamps when they are prepended to the output.[br] -## The variables [param {day}], [param {month}], [param {year}], [param {hour}], [param {minute}], [param {second}], [param {weekday}], and [param {dst}] are supported. -## You can customize this in your ProjectSettings, or custom_settings.gd (if using it).[br] -var format_timestamp = "[{day}.{month}.{year} {hour}:{minute}:{second}]" - -## The format used for each entry in a stack trace that is obtained through [method Loggie.stack]. -## The variables [param {fn_name}], [param {index}], [param {source_path}], [param {line}] are supported. -## You can customize this in your ProjectSettings, or custom_settings.gd (if using it).[br] -var format_stacktrace_entry = "{index}: [color=#ff7085]func[/color] [color=#53b1c3][b]{fn_name}[/b]:{line}[/color] [color=slate_gray][i](in {source_path})[/i][/color]" - -## The symbol which will be used for the HSeparator. -var h_separator_symbol = "-" - -## The mode used for drawing boxes. -var box_characters_mode : LoggieEnums.BoxCharactersMode - -## The symbols which will be used to construct a box decoration that will properly -## display on any kind of terminal or text reader. -## For a prettier but potentially incompatible box, use [member box_symbols_pretty] instead. -var box_symbols_compatible = { - # ANSI and .log compatible box characters: - "top_left" : "-", - "top_right" : "-", - "bottom_left" : "-", - "bottom_right" : "-", - "h_line" : "-", - "v_line" : ":", -} - -## The symbols which will be used to construct pretty box decoration. -## These may not be compatible with some terminals or text readers. -## Use the [member box_symbols_compatible] instead as an alternative. -var box_symbols_pretty = { - "top_left" : "┌", - "top_right" : "┐", - "bottom_left" : "└", - "bottom_right" : "┘", - "h_line" : "─", - "v_line" : "│", -} - -#endregion -# ----------------------------------------------- # - -## A [Callable] function that takes 1 parameter [param something] (Variant), -## and returns a [String] which represents the given [param something] in text. -## By default, Loggie sets this to `LoggieTools.convert_to_string` when initialized. -## [br][br] -## You can, however, override that by changing this value to a valid replacement [Callable], -## after Loggie has initialized. -var custom_string_converter : Callable - -## Loads the initial (default) values for all of the LoggieSettings variables. -## (By default, loads them from ProjectSettings (if any modifications there exist), -## or looks in [LoggieEditorPlugin..project_settings] for default values). -## [br][br]Extend this class and override this function to write your own logic for -## how loggie should obtain these settings if you have a need for a different approach. -func load(): - update_check_mode = ProjectSettings.get_setting(project_settings.update_check_mode.path, project_settings.update_check_mode.default_value) - msg_format_mode = ProjectSettings.get_setting(project_settings.msg_format_mode.path, project_settings.msg_format_mode.default_value) - log_level = ProjectSettings.get_setting(project_settings.log_level.path, project_settings.log_level.default_value) - show_loggie_specs = ProjectSettings.get_setting(project_settings.show_loggie_specs.path, project_settings.show_loggie_specs.default_value) - show_system_specs = ProjectSettings.get_setting(project_settings.show_system_specs.path, project_settings.show_system_specs.default_value) - timestamps_use_utc = ProjectSettings.get_setting(project_settings.timestamps_use_utc.path, project_settings.timestamps_use_utc.default_value) - enforce_optimal_settings_in_release_build = ProjectSettings.get_setting(project_settings.enforce_optimal_settings_in_release_build.path, project_settings.enforce_optimal_settings_in_release_build.default_value) - default_channels = ProjectSettings.get_setting(project_settings.default_channels.path, project_settings.default_channels.default_value) - skipped_filenames_in_stack_trace = ProjectSettings.get_setting(project_settings.skipped_filenames_in_stack_trace.path, project_settings.skipped_filenames_in_stack_trace.default_value) - - print_errors_to_console = ProjectSettings.get_setting(project_settings.output_errors_to_console.path, project_settings.output_errors_to_console.default_value) - print_warnings_to_console = ProjectSettings.get_setting(project_settings.output_warnings_to_console.path, project_settings.output_warnings_to_console.default_value) - debug_msgs_print_stack_trace = ProjectSettings.get_setting(project_settings.debug_msgs_print_stack_trace.path, project_settings.debug_msgs_print_stack_trace.default_value) - - nameless_class_name_proxy = ProjectSettings.get_setting(project_settings.nameless_class_name_proxy.path, project_settings.nameless_class_name_proxy.default_value) - box_characters_mode = ProjectSettings.get_setting(project_settings.box_characters_mode.path, project_settings.box_characters_mode.default_value) - - format_timestamp = ProjectSettings.get_setting(project_settings.format_timestamp.path, project_settings.format_timestamp.default_value) - format_stacktrace_entry = ProjectSettings.get_setting(project_settings.format_stacktrace_entry.path, project_settings.format_stacktrace_entry.default_value) - format_info_msg = ProjectSettings.get_setting(project_settings.format_info_msg.path, project_settings.format_info_msg.default_value) - format_notice_msg = ProjectSettings.get_setting(project_settings.format_notice_msg.path, project_settings.format_notice_msg.default_value) - format_warning_msg = ProjectSettings.get_setting(project_settings.format_warning_msg.path, project_settings.format_warning_msg.default_value) - format_error_msg = ProjectSettings.get_setting(project_settings.format_error_msg.path, project_settings.format_error_msg.default_value) - format_debug_msg = ProjectSettings.get_setting(project_settings.format_debug_msg.path, project_settings.format_debug_msg.default_value) - h_separator_symbol = ProjectSettings.get_setting(project_settings.h_separator_symbol.path, project_settings.h_separator_symbol.default_value) - - discord_webhook_url_live = ProjectSettings.get_setting(project_settings.discord_webhook_url_live.path, project_settings.discord_webhook_url_live.default_value) - discord_webhook_url_dev = ProjectSettings.get_setting(project_settings.discord_webhook_url_dev.path, project_settings.discord_webhook_url_dev.default_value) - preprocess_flags_discord_channel = ProjectSettings.get_setting(project_settings.preprocess_flags_discord_channel.path, project_settings.preprocess_flags_discord_channel.default_value) - slack_webhook_url_live = ProjectSettings.get_setting(project_settings.slack_webhook_url_live.path, project_settings.slack_webhook_url_live.default_value) - slack_webhook_url_dev = ProjectSettings.get_setting(project_settings.slack_webhook_url_dev.path, project_settings.slack_webhook_url_dev.default_value) - preprocess_flags_slack_channel = ProjectSettings.get_setting(project_settings.preprocess_flags_slack_channel.path, project_settings.preprocess_flags_slack_channel.default_value) - preprocess_flags_terminal_channel = ProjectSettings.get_setting(project_settings.preprocess_flags_terminal_channel.path, project_settings.preprocess_flags_terminal_channel.default_value) - -## Returns a dictionary where the indices are names of relevant variables in the LoggieSettings class, -## and the values are their current values. -func to_dict() -> Dictionary: - var dict = {} - var included = [ - "preprocess_flags_discord_channel", "preprocess_flags_slack_channel", "preprocess_flags_terminal_channel", - "default_channels", "skipped_filenames_in_stack_trace", "msg_format_mode", "log_level", "show_loggie_specs", "show_system_specs", "enforce_optimal_settings_in_release_build", - "print_errors_to_console", "print_warnings_to_console", - "debug_msgs_print_stack_trace", "nameless_class_name_proxy", - "timestamps_use_utc", "format_header", "format_domain_prefix", "format_error_msg", - "format_warning_msg", "format_notice_msg", "format_info_msg", "format_debug_msg", "format_timestamp", - "h_separator_symbol", "box_characters_mode", "box_symbols_compatible", "box_symbols_pretty", - ] - - for var_name in included: - dict[var_name] = get(var_name) - return dict diff --git a/addons/loggie/loggie_settings.gd.uid b/addons/loggie/loggie_settings.gd.uid deleted file mode 100644 index 83257f7..0000000 --- a/addons/loggie/loggie_settings.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cs4ybo1axktlw diff --git a/addons/loggie/plugin.cfg b/addons/loggie/plugin.cfg deleted file mode 100644 index 36e9eea..0000000 --- a/addons/loggie/plugin.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[plugin] - -name="Loggie" -description="Simple functional stylish logger for your basic logging needs." -author="Shiva Shadowsong" -version="3.0" -script="plugin.gd" diff --git a/addons/loggie/plugin.gd b/addons/loggie/plugin.gd deleted file mode 100644 index b695b65..0000000 --- a/addons/loggie/plugin.gd +++ /dev/null @@ -1,50 +0,0 @@ -@tool -class_name LoggieEditorPlugin extends EditorPlugin - -func _enter_tree(): - add_loggie_project_settings() - Engine.set_meta("LoggieEditorPlugin", self) - if Engine.is_editor_hint(): - Engine.set_meta("LoggieEditorInterfaceBaseControl", EditorInterface.get_base_control()) - -func _enable_plugin() -> void: - add_autoload_singleton(LoggieSettings.loggie_singleton_name, "res://addons/loggie/loggie.gd") - add_loggie_project_settings() - -func _disable_plugin() -> void: - var wipe_setting_exists = ProjectSettings.has_setting(LoggieSettings.project_settings.remove_settings_if_plugin_disabled.path) - if (not wipe_setting_exists) or (wipe_setting_exists and ProjectSettings.get_setting(LoggieSettings.project_settings.remove_settings_if_plugin_disabled.path, true)): - push_warning("The Loggie plugin is being disabled, and all of its ProjectSettings are erased from Godot. If you wish to prevent this behavior, look for the 'Project Settings -> Loggie -> General -> Remove Settings if Plugin Disabled' option while the plugin is enabled.") - remove_loggie_project_setings() - else: - push_warning("The Loggie plugin is being disabled, but its ProjectSettings have been prevented from being removed from Godot. If you wish to allow that behavior, look for the 'Project Settings -> Loggie -> General -> Remove Settings if Plugin Disabled' option while the plugin is enabled.") - remove_autoload_singleton(LoggieSettings.loggie_singleton_name) - -## Adds new Loggie related ProjectSettings to Godot. -func add_loggie_project_settings(): - for setting in LoggieSettings.project_settings.values(): - add_project_setting(setting["path"], setting["default_value"], setting["type"], setting["hint"], setting["hint_string"], setting["doc"]) - -## Removes Loggie related ProjectSettings from Godot. -func remove_loggie_project_setings(): - for setting in LoggieSettings.project_settings.values(): - ProjectSettings.set_setting(setting["path"], null) - - var error: int = ProjectSettings.save() - if error != OK: - push_error("Loggie - Encountered error %d while saving project settings." % error) - -## Adds a new project setting to Godot. -## (WARNING): Unfortunately, as of Godot 4.3, it has been confirmed that it is not possible to set the -## popup tooltip text for a project setting. This should be implemented here as soon as that becomes possible. -func add_project_setting(setting_name: String, default_value : Variant, value_type: int, type_hint: int = PROPERTY_HINT_NONE, hint_string: String = "", documentation : String = ""): - if !ProjectSettings.has_setting(setting_name): - ProjectSettings.set_setting(setting_name, default_value) - - ProjectSettings.set_initial_value(setting_name, default_value) - ProjectSettings.add_property_info({ "name": setting_name, "type": value_type, "hint": type_hint, "hint_string": hint_string}) - ProjectSettings.set_as_basic(setting_name, true) - - var error: int = ProjectSettings.save() - if error: - push_error("Loggie - Encountered error %d while saving project settings." % error) diff --git a/addons/loggie/plugin.gd.uid b/addons/loggie/plugin.gd.uid deleted file mode 100644 index 8c5b93e..0000000 --- a/addons/loggie/plugin.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ct2hpdyg7gd81 diff --git a/addons/loggie/tools/loggie_enums.gd b/addons/loggie/tools/loggie_enums.gd deleted file mode 100644 index 375dc27..0000000 --- a/addons/loggie/tools/loggie_enums.gd +++ /dev/null @@ -1,88 +0,0 @@ -@tool -class_name LoggieEnums extends Node - -## Based on which log level is currently set to be used by the Loggie., attempting to log a message that's on -## a higher-than-configured log level will result in nothing happening. -enum LogLevel { - ERROR, ## Log level which includes only the logging of Error type messages. - WARN, ## Log level which includes the logging of Error and Warning type messages. - NOTICE, ## Log level which includes the logging of Error, Warning and Notice type messages. - INFO, ## Log level which includes the logging of Error, Warning, Notice and Info type messages. - DEBUG ## Log level which includes the logging of Error, Warning, Notice, Info and Debug type messages. -} - -## The classification of message types that can be used to distinguish two identical strings in nature -## of their origin. This is different from [enum LogLevel]. -enum MsgType { - ERROR, ## A message that is considered to be an error message. - WARN, ## A message that is considered to be a warning message. - NOTICE, ## A message that is considered to be a notice. - INFO, ## A message that is considered a standard text that is not special in any way. - DEBUG, ## A message that is considered to be a message used only during debugging. -} - -enum MsgFormatMode { - PLAIN, ## Prints will be plain text. - ANSI, ## Prints will be styled using the ANSI standard. Compatible with Powershell, Win CMD, etc. - BBCODE, ## Prints will be styled using the Godot BBCode rules. Compatible with the Godot console. - MARKDOWN, ## Prints will be styled using the Markdown standard. Compatible with most Markdown readers. -} - -## Classifies various steps that can happen during preprocessing. -enum PreprocessStep { - ## A timestamp will be added to the message. - APPEND_TIMESTAMPS = 1 << 0, - - ## The name of the domain from which the message is coming will be added to the message. - APPEND_DOMAIN_NAME = 1 << 1, - - ## Whether Loggie should use the scripts from which it is being called to - ## figure out a class name for the class that called a loggie function, - ## and append it to the outputted message. - ## This only works in debug builds because it uses [method @GDScript.get_stack]. - ## See that method's documentation to see why that can't be used in release builds. - APPEND_CLASS_NAME = 1 << 2, -} - -enum BoxCharactersMode { - COMPATIBLE, ## Boxes are drawn using characters that compatible with any kind of terminal or text reader. - PRETTY ## Boxes are drawn using special unicode characters that create a prettier looking box which may not display properly in some terminals or text readers. -} - -## Defines a list of possible approaches that can be taken to derive some kind of a class name proxy from a script that doesn't have a 'class_name' clause. -enum NamelessClassExtensionNameProxy { - NOTHING, ## If there is no class_name, nothing will be displayed. - SCRIPT_NAME, ## Use the name of the script whose class_name we tried to read. (e.g. "my_script.gd"). - BASE_TYPE, ## Use the name of the base type which the script extends (e.g. 'Node2D', 'Control', etc.) -} - -## Defines a list of possible behaviors for the 'show_loggie_specs' setting. -enum ShowLoggieSpecsMode { - DISABLED, ## Loggie specs won't be shown. - ESSENTIAL, ## Show only the essentials. - ADVANCED ## Show all loggie specs. -} - -## Defines a list of possible outcomes that can happen when attempting to log a message. -enum LogAttemptResult { - SUCCESS, ## Message will be logged successfully. - LOG_LEVEL_INSUFFICIENT, ## Message won't be logged because it was output at a log level higher than what Loggie is currently set to. - DOMAIN_DISABLED, ## Message won't be logged because it was outputted from a disabled domain. - INVALID_CHANNEL, ## Message won't be logged because the channel which was supposed to send it doesn't exist. - WRONG_ENVIRONMENT, ## Message won't be logged because the environment the output is being requested from is not compatible with the environment this message is configured to be outputted in. -} - -## Defines a list of possible ways to configure Loggie to check for updates. -enum UpdateCheckType { - DONT_CHECK, ## If the user doesn't want Loggie to check for updates at all. - CHECK_AND_SHOW_MSG, ## If the user wants Loggie to check for updates, and display info in a terminal message. - CHECK_DOWNLOAD_AND_SHOW_MSG, ## If the user wants Loggie to check for updates, download the update, and display info in a terminal message. - CHECK_AND_SHOW_UPDATER_WINDOW, ## If the user wants Loggie to check for updats, and display the updater window. -} - -## Defines a lists of possible environments in which a [LoggieMsg] can be outputted. -enum MsgEnvironment { - BOTH, ## The message will be outputted both in-engine (tool scripts) and when the project is running. - ENGINE, ## The message will be outputted only in-engine (tool scripts). - RUNTIME, ## The message will be outputted only when the project is running. -} diff --git a/addons/loggie/tools/loggie_enums.gd.uid b/addons/loggie/tools/loggie_enums.gd.uid deleted file mode 100644 index 4263530..0000000 --- a/addons/loggie/tools/loggie_enums.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dh3dmjky74fuo diff --git a/addons/loggie/tools/loggie_system_specs.gd b/addons/loggie/tools/loggie_system_specs.gd deleted file mode 100644 index b40eaac..0000000 --- a/addons/loggie/tools/loggie_system_specs.gd +++ /dev/null @@ -1,186 +0,0 @@ -@tool - -## LoggieSystemSpecs is a helper class that defines various functions on how to access data about the local machine and its specs -## and creates displayable strings out of them. -class_name LoggieSystemSpecsMsg extends LoggieMsg - -## Embeds various system specs into the content of this message. -func embed_specs() -> LoggieSystemSpecsMsg: - self.embed_system_specs() - self.embed_localization_specs() - self.embed_date_data().nl() - self.embed_hardware_specs().nl() - self.embed_video_specs().nl() - self.embed_display_specs().nl() - self.embed_audio_specs().nl() - self.embed_engine_specs().nl() - self.embed_input_specs() - return self - -## Embeds essential data about the logger into the content of this message. -func embed_essential_logger_specs() -> LoggieSystemSpecsMsg: - var loggie = get_logger() - self.add(loggie.msg("|\t Is in Production:").bold(), loggie.is_in_production()).nl() - self.add(loggie.msg("|\t Default Channel(s):").bold(),loggie.settings.default_channels).nl() - self.add(loggie.msg("|\t Msg Format Mode:").bold(), LoggieEnums.MsgFormatMode.keys()[loggie.settings.msg_format_mode]).nl() - self.add(loggie.msg("|\t Log Level:").bold(), LoggieEnums.LogLevel.keys()[loggie.settings.log_level]).nl() - return self - -## Embeds advanced data about the logger into the content of this message. -func embed_advanced_logger_specs() -> LoggieSystemSpecsMsg: - var loggie = get_logger() - - self.add(loggie.msg("|\t Is in Production:").bold(), loggie.is_in_production()).nl() - - var settings_dict = loggie.settings.to_dict() - for setting_var_name : String in settings_dict.keys(): - var setting_value = settings_dict[setting_var_name] - var content_to_print = setting_value - - match setting_var_name: - "msg_format_mode": - content_to_print = LoggieEnums.MsgFormatMode.keys()[setting_value] - "log_level": - content_to_print = LoggieEnums.LogLevel.keys()[setting_value] - "box_characters_mode": - content_to_print = LoggieEnums.BoxCharactersMode.keys()[setting_value] - - self.add(loggie.msg("|\t", setting_var_name.capitalize(), ":").bold(), content_to_print).nl() - - return self - -## Adds data about the user's software to the content of this message. -func embed_system_specs() -> LoggieSystemSpecsMsg: - var loggie = get_logger() - var header = loggie.msg("Operating System: ").color(Color.ORANGE).add(OS.get_name()).box(4) - self.add(header) - return self - -## Adds data about localization to the content of this message. -func embed_localization_specs() -> LoggieSystemSpecsMsg: - var loggie = get_logger() - var header = loggie.msg("Localization: ").color(Color.ORANGE).add(OS.get_locale()).box(7) - self.add(header) - return self - -## Adds data about the current date/time to the content of this message. -func embed_date_data() -> LoggieSystemSpecsMsg: - var loggie = get_logger() - var header = loggie.msg("Date").color(Color.ORANGE).box(15) - self.add(header) - self.add(loggie.msg("Date and time (local):").bold(), Time.get_datetime_string_from_system(false, true)).nl() - self.add(loggie.msg("Date and time (UTC):").bold(), Time.get_datetime_string_from_system(true, true)).nl() - self.add(loggie.msg("Date (local):").bold(), Time.get_date_string_from_system(false)).nl() - self.add(loggie.msg("Date (UTC):").bold(), Time.get_date_string_from_system(true)).nl() - self.add(loggie.msg("Time (local):").bold(), Time.get_time_string_from_system(false)).nl() - self.add(loggie.msg("Time (UTC):").bold(), Time.get_time_string_from_system(true)).nl() - self.add(loggie.msg("Timezone:").bold(), Time.get_time_zone_from_system()).nl() - self.add(loggie.msg("UNIX time:").bold(), Time.get_unix_time_from_system()).nl() - return self - -## Adds data about the user's hardware to the content of this message. -func embed_hardware_specs() -> LoggieSystemSpecsMsg: - var loggie = get_logger() - var header = loggie.msg("Hardware").color(Color.ORANGE).box(13) - self.add(header) - self.add(loggie.msg("Model name:").bold(), OS.get_model_name()).nl() - self.add(loggie.msg("Processor name:").bold(), OS.get_processor_name()).nl() - return self - -## Adds data about the video system to the content of this message. -func embed_video_specs() -> LoggieSystemSpecsMsg: - const adapter_type_to_string = ["Other (Unknown)", "Integrated", "Discrete", "Virtual", "CPU"] - var adapter_type_string = adapter_type_to_string[RenderingServer.get_video_adapter_type()] - var video_adapter_driver_info = OS.get_video_adapter_driver_info() - var loggie = get_logger() - - var header = loggie.msg("Video").color(Color.ORANGE).box(15) - self.add(header) - self.add(loggie.msg("Adapter name:").bold(), RenderingServer.get_video_adapter_name()).nl() - self.add(loggie.msg("Adapter vendor:").bold(), RenderingServer.get_video_adapter_vendor()).nl() - self.add(loggie.msg("Adapter type:").bold(), adapter_type_string).nl() - self.add(loggie.msg("Adapter graphics API version:").bold(), RenderingServer.get_video_adapter_api_version()).nl() - - if video_adapter_driver_info.size() > 0: - self.add(loggie.msg("Adapter driver name:").bold(), video_adapter_driver_info[0]).nl() - if video_adapter_driver_info.size() > 1: - self.add(loggie.msg("Adapter driver version:").bold(), video_adapter_driver_info[1]).nl() - - return self - -## Adds data about the display to the content of this message. -func embed_display_specs() -> LoggieSystemSpecsMsg: - const screen_orientation_to_string = [ - "Landscape", - "Portrait", - "Landscape (reverse)", - "Portrait (reverse)", - "Landscape (defined by sensor)", - "Portrait (defined by sensor)", - "Defined by sensor", - ] - var screen_orientation_string = screen_orientation_to_string[DisplayServer.screen_get_orientation()] - var loggie = get_logger() - - var header = loggie.msg("Display").color(Color.ORANGE).box(13) - self.add(header) - self.add(loggie.msg("Screen count:").bold(), DisplayServer.get_screen_count()).nl() - self.add(loggie.msg("DPI:").bold(), DisplayServer.screen_get_dpi()).nl() - self.add(loggie.msg("Scale factor:").bold(), DisplayServer.screen_get_scale()).nl() - self.add(loggie.msg("Maximum scale factor:").bold(), DisplayServer.screen_get_max_scale()).nl() - self.add(loggie.msg("Startup screen position:").bold(), DisplayServer.screen_get_position()).nl() - self.add(loggie.msg("Startup screen size:").bold(), DisplayServer.screen_get_size()).nl() - self.add(loggie.msg("Startup screen refresh rate:").bold(), ("%f Hz" % DisplayServer.screen_get_refresh_rate()) if DisplayServer.screen_get_refresh_rate() > 0.0 else "").nl() - self.add(loggie.msg("Usable (safe) area rectangle:").bold(), DisplayServer.get_display_safe_area()).nl() - self.add(loggie.msg("Screen orientation:").bold(), screen_orientation_string).nl() - return self - -## Adds data about the audio system to the content of this message. -func embed_audio_specs() -> LoggieSystemSpecsMsg: - var loggie = get_logger() - var header = loggie.msg("Audio").color(Color.ORANGE).box(14) - self.add(header) - self.add(loggie.msg("Mix rate:").bold(), "%d Hz" % AudioServer.get_mix_rate()).nl() - self.add(loggie.msg("Output latency:").bold(), "%f ms" % (AudioServer.get_output_latency() * 1000)).nl() - self.add(loggie.msg("Output device list:").bold(), ", ".join(AudioServer.get_output_device_list())).nl() - self.add(loggie.msg("Capture device list:").bold(), ", ".join(AudioServer.get_input_device_list())).nl() - return self - -## Adds data about the godot engine to the content of this message. -func embed_engine_specs() -> LoggieSystemSpecsMsg: - var loggie = get_logger() - var header = loggie.msg("Engine").color(Color.ORANGE).box(14) - self.add(header) - self.add(loggie.msg("Version:").bold(), Engine.get_version_info()["string"]).nl() - self.add(loggie.msg("Command-line arguments:").bold(), str(OS.get_cmdline_args())).nl() - self.add(loggie.msg("Is debug build:").bold(), OS.is_debug_build()).nl() - self.add(loggie.msg("Filesystem is persistent:").bold(), OS.is_userfs_persistent()).nl() - return self - -## Adds data about the input device to the content of this message. -func embed_input_specs() -> LoggieSystemSpecsMsg: - var has_virtual_keyboard = DisplayServer.has_feature(DisplayServer.FEATURE_VIRTUAL_KEYBOARD) - var loggie = get_logger() - - var header = loggie.msg("Input").color(Color.ORANGE).box(14) - self.add(header) - self.add(loggie.msg("Device has touch screen:").bold(), DisplayServer.is_touchscreen_available()).nl() - self.add(loggie.msg("Device has virtual keyboard:").bold(), has_virtual_keyboard).nl() - - if has_virtual_keyboard: - self.add(loggie.msg("Virtual keyboard height:").bold(), DisplayServer.virtual_keyboard_get_height()) - - return self - -## Prints out a bunch of useful data about a given script. -## Useful for debugging. -func embed_script_data(script : Script): - var loggie = get_logger() - self.add("Script Data for:", script.get_path()).color("pink") - self.add(":").nl() - self.add(loggie.msg("get_class(): ").color("slate_blue").bold()).add(script.get_class()).nl() - self.add(loggie.msg("get_global_name(): ").color("slate_blue").bold()).add(script.get_global_name()).nl() - self.add(loggie.msg("get_base_script(): ").color("slate_blue").bold()).add(script.get_base_script().resource_path if script.get_base_script() != null else "No base script.").nl() - self.add(loggie.msg("get_instance_base_type(): ").color("slate_blue").bold()).add(script.get_instance_base_type()).nl() - self.add(loggie.msg("get_script_property_list(): ").color("slate_blue").bold()).add(script.get_script_property_list()).nl() - return self diff --git a/addons/loggie/tools/loggie_system_specs.gd.uid b/addons/loggie/tools/loggie_system_specs.gd.uid deleted file mode 100644 index 919f66c..0000000 --- a/addons/loggie/tools/loggie_system_specs.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dnd34kic4p8bv diff --git a/addons/loggie/tools/loggie_tools.gd b/addons/loggie/tools/loggie_tools.gd deleted file mode 100644 index 2bc0764..0000000 --- a/addons/loggie/tools/loggie_tools.gd +++ /dev/null @@ -1,530 +0,0 @@ -@tool -class_name LoggieTools extends Node - -## Removes BBCode from the given text. -## If [param specific_tags] is an array, it removes only the tags found in that array. -## Otherwise, it removes the tags found in the default_tags array:[br] -## [param ["b", "i", "u", "s", "indent", "code", "url", "center", "right", "color", "bgcolor", "fgcolor"]] -static func remove_BBCode(text: String, specific_tags = null) -> String: - # The bbcode tags to remove. - var default_tags = ["b", "i", "u", "s", "indent", "code", "url", "center", "right", "color", "bgcolor", "fgcolor"] - var tags = specific_tags if specific_tags is Array else default_tags - - var regex = RegEx.new() - var tags_pattern = "|".join(tags) - regex.compile("\\[/?(" + tags_pattern + ")(=[^\\]]*)?\\]") - - var stripped_text = regex.sub(text, "", true) - return stripped_text - -## Concatenates all elements of the given [param args] array into one single string, in consecutive order. -## If [param custom_converter_fn] is provided, and is a [Callable], that function will be used to convert each element of the array into a string -## instead of using [method convert_to_string]. That function will receive 1 argument, which will be a 'Variant', and it has to return a 'String'. -static func concatenate_args(args : Array, custom_converter_fn : Variant = null) -> String: - if args.size() == 0: - return "" - - var converter_fn : Callable = LoggieTools.convert_to_string - if custom_converter_fn is Callable and custom_converter_fn.is_valid() and !custom_converter_fn.is_null(): - converter_fn = custom_converter_fn - - # Start with first element without modifying array - var final_msg : String = converter_fn.call(args[0]) - - # Start from index 1 since we already handled index 0 - for i in range(1, args.size()): - var arg = args[i] - var is_not_followed_by_a_null_arg = true if (i + 1 <= args.size() - 1) and (args[i + 1] != null) else false - if (arg != null) or (arg == null and is_not_followed_by_a_null_arg): - var converted_arg : String = converter_fn.call(arg) - final_msg += (" " + converted_arg) - - return final_msg - -## Converts a text with BBCode in it to markdown. -## A limited set of BBCode tags are supported for this conversion, because standard Markdown can't handle everything -## that BBCode can. For example, colors will be entirely stripped. -static func convert_BBCode_to_markdown(text: String) -> String: - # Purge the unsupported tags. - var unsupported_tags = ["indent", "url", "center", "right", "color", "bgcolor", "fgcolor"] - text = LoggieTools.remove_BBCode(text, unsupported_tags) - - # Space out all instances where "*" characters from multiple tags are strung together, - # since that would break them from rendering with the proper effect in markdown. - # This is only an issue with [b] and [i] tags because they both use the same "*" character - # in markdown to be represented. - text = text.replace("[/b][i]", "** *") - text = text.replace("[/b][/i]", "** *") - text = text.replace("[/i][b]", "* **") - text = text.replace("[/i][/b]", "* **") - text = text.replace("[/i][i]", "* *") - text = text.replace("[/i][/i]", "* *") - text = text.replace("[/b][b]", "** **") - text = text.replace("[/b][/b]", "** **") - - # Perform all supported conversion. - var supported_conversions = { - "[b]" : "**", "[/b]" : "**", - "[i]" : "*", "[/i]" : "*", - "[u]" : "__", "[/u]" : "__", - "[s]" : "~~", "[/s]" : "~~", - } - for bbcodetag in supported_conversions.keys(): - text = text.replace(bbcodetag, supported_conversions[bbcodetag]) - - return text - -## Converts [param something] into a string, with custom handling for -## certain native and custom classes. -static func convert_to_string(something : Variant) -> String: - var result : String - if something is Dictionary: - result = JSON.new().stringify(something, " ", false, true) - elif something is LoggieMsg: - result = something.string() - else: - result = str(something) - return result - -## Takes the given [param str] and returns a terminal-ready version of it by converting its content -## to the appropriate format required to display the string correctly in the provided [param mode] -## msg format mode. -## [b]The provided [param str] is expected to be either in Plain or BBCode format.[/b] -static func convert_string_to_format_mode(str : String, mode : LoggieEnums.MsgFormatMode) -> String: - match mode: - LoggieEnums.MsgFormatMode.ANSI: - # We put the message through the rich_to_ANSI converter which takes care of converting BBCode - # to appropriate ANSI. (Only if the MsgFormatMode is set to ANSI). - # Godot claims to be already preparing BBCode output for ANSI, but it only works with a small - # predefined set of colors, and I think it totally strips stuff like [b], [i], etc. - # It is possible to display those stylings in ANSI, but we have to do our own conversion here - # to support these features instead of having them stripped. - str = LoggieTools.rich_to_ANSI(str) - LoggieEnums.MsgFormatMode.BBCODE: - # No need to do anything for BBCODE mode, because we already expect all strings to - # start out with this format in mind. - pass - LoggieEnums.MsgFormatMode.MARKDOWN: - str = LoggieTools.convert_BBCode_to_markdown(str) - LoggieEnums.MsgFormatMode.PLAIN, _: - str = LoggieTools.remove_BBCode(str) - return str - -## Converts a given [Color] to an ANSI compatible representation of it in code. -static func color_to_ANSI(color: Color) -> String: - var r = int(color.r * 255) - var g = int(color.g * 255) - var b = int(color.b * 255) - return "\u001b[38;2;%d;%d;%dm" % [r, g, b] - -## Strips the BBCode from the given text, and converts all [b], [i] and [color] tags to appropriate ANSI representable codes, -## then returns the converted string. The result of this conversion becomes an ANSI compatible representation of the given [param text]. -static func rich_to_ANSI(text: String) -> String: - var regex_color = RegEx.new() - regex_color.compile("\\[color=(.*?)\\](.*?)\\[/color\\]") - - # Process color tags first. - while regex_color.search(text): - var match = regex_color.search(text) - var color_str = match.get_string(1).to_upper() - var color: Color - var color_code: String - var reset_code = "\u001b[0m" - - # Try to parse the color string - if LoggieTools.NamedColors.has(color_str): - color = LoggieTools.NamedColors[color_str] - else: - color = Color(color_str) - - if color: - color_code = color_to_ANSI(color) - else: - color_code = "" - reset_code = "" - - var replacement = color_code + match.get_string(2) + reset_code - text = text.replace(match.get_string(0), replacement) - - # Process bold and italic tags. - var bold_on = "\u001b[1m" - var bold_off = "\u001b[22m" - var italic_on = "\u001b[3m" - var italic_off = "\u001b[23m" - - text = text.replace("[b]", bold_on).replace("[/b]", bold_off) - text = text.replace("[i]", italic_on).replace("[/i]", italic_off) - - # Remove any other BBCode tags but retain the text between them. - var regex_bbcode = RegEx.new() - regex_bbcode.compile("\\[(b|/b|i|/i|color=[^\\]]+|/color)\\]") - text = regex_bbcode.sub(text, "", true) - - return text - -## Returns a dictionary of call stack data related to the stack the call to this function is a part of. -## This function only works in debug builds, and on the main thread, because it uses [method get_stack]. -## Read more about why in that function's documentation. -static func get_current_stack_frame_data() -> Dictionary: - var stack = get_stack() - if stack.size() > 0: - stack.reverse() - # Prune the frames starting from the first one that comes from loggie_message and onwards. - var pruned_stack = [] - for index in stack.size(): - var source : String = stack[index].source - var prune_breakpoint_files = ["loggie", "loggie_message"] - if prune_breakpoint_files.has(source.get_file().get_basename()): - break - pruned_stack.push_back(stack[index]) - - # The back-most remaining entry in the pruned stack is the first non-Loggie caller. - if pruned_stack.size() >= 1: - return pruned_stack.back() - - return { - "source" : "UnknownStackFrameSource", - "line" : 0, - "function" : "UnknownFunction" - } - -## Returns the `class_name` of a script. -## [br][param path_or_script] should be either an absolute path to the script -## (String, e.g. "res://my_script.gd"), or a [Script] object. -## [br][param proxy] defines which kind of text will be used as a replacement -## for the class name if the script has no 'class_name'. -static func get_class_name_from_script(path_or_script : Variant, proxy : LoggieEnums.NamelessClassExtensionNameProxy) -> String: - var script - var _class_name = "" - - if path_or_script is String or path_or_script is StringName: - if !ResourceLoader.exists(path_or_script, "Script"): - return _class_name - script = load(path_or_script) - elif path_or_script is Script: - script = path_or_script - - if not (script is Script): - push_error("Invalid 'path_or_script' param provided to get_class_name_from_script: {path}".format({"path" : path_or_script})) - else: - if not script.has_method("get_global_name"): - # User is using a pre-4.3 version of Godot that doesn't have Script.get_global_name. - # We must use a different method to achieve this then. - return extract_class_name_from_gd_script(path_or_script, proxy) - - # Try to get the class name directly. - _class_name = script.get_global_name() - - if _class_name != "": - return _class_name - - # If that's empty, the script is either a base class, or a class without a name. - # Check if this script has a base script, and if so, use that one as the target whose name to obtain. - # If it doesn't have it, use what the [param proxy] demands. - var base_script = script.get_base_script() - if base_script != null: - return get_class_name_from_script(base_script, proxy) - else: - match proxy: - LoggieEnums.NamelessClassExtensionNameProxy.BASE_TYPE: - _class_name = script.get_instance_base_type() - LoggieEnums.NamelessClassExtensionNameProxy.SCRIPT_NAME: - _class_name = script.get_script_property_list().front()["name"] - - return _class_name - -## Opens and reads a .gd script file to find out its 'class_name' or what it 'extends'. -## [param path_or_script] should be either an absolute path to the script -## (String, e.g. "res://my_script.gd"), or a [Script] object. -## [br][param proxy] defines which kind of text will be used as a replacement -## for the class name if the script has no 'class_name'. -## [br][br][b]Note:[/b] This is a compatibility method that will be used on older versions of Godot which -## don't support [method Script.get_global_name]. -static func extract_class_name_from_gd_script(path_or_script : Variant, proxy : LoggieEnums.NamelessClassExtensionNameProxy) -> String: - var path : String - - if path_or_script is String: - path = path_or_script - elif path_or_script is Script: - path = path_or_script.resource_path - else: - push_error("Invalid 'path_or_script' param provided to extract_class_name_from_gd_script: {path}".format({"path" : path_or_script})) - return "" - - var file = FileAccess.open(path, FileAccess.READ) - if not file: - return "File Open Error {filepath}".format({"filepath" : path}) - - var _class_name: String = "" - - for line_num in 40: # Loop only up to 40 lines - if file.eof_reached(): - break - - var line = file.get_line().strip_edges() - - if line.begins_with("class_name"): - _class_name = line.split(" ")[1] - break - - if _class_name == "": - var script = load(path) - if script is Script: - match proxy: - LoggieEnums.NamelessClassExtensionNameProxy.BASE_TYPE: - _class_name = script.get_instance_base_type() - LoggieEnums.NamelessClassExtensionNameProxy.SCRIPT_NAME: - _class_name = script.get_script_property_list().front()["name"] - - file.close() - return _class_name - -## Takes the given [param string] and returns an array made out of chunks of the given size. -## The string is chunked from start to end. -static func chunk_string(string : String, chunk_size : int) -> Array: - var message_chunks = [] - if string.length() >= chunk_size: - # Cut chunk_size pieces from the left side of the string and push them to message_chunks. - while string.length() >= chunk_size: - message_chunks.append(string.left(chunk_size)) - string = string.substr(chunk_size, -1) - - # Append the remaining slice as the final chunk. - if string.length() > 0: - message_chunks.append(string) - return message_chunks - else: - return [string] - -## Copies the directory at the given [param path_dir_to_copy] path and places the copy at the given [param path_dir_to_copy_into] path. -## Returns a dictionary with 2 keys: -##[codeblock] -##`errors` : Array[Error] # An array of all errors that occured during the process. ('Error.OK' is an exception and won't be included here) -##`messages` : Array[LoggieMsg] # An array of messages describing the process, including informational or error related content. -##[/codeblock] -static func copy_dir_absolute(path_dir_to_copy: String, path_dir_to_copy_into: String, overwrite_existing_files_with_same_name : bool = false) -> Dictionary: - const debug_enabled = false - var result = { - "errors" : [], - "messages" : [] - } - - # Ensure source directory is openable. - var source_dir = DirAccess.open(path_dir_to_copy) - if source_dir == null: - var open_error = DirAccess.get_open_error() - result.errors.push_back(open_error) - result.messages.push_back(LoggieMsg.new("Failed to open source directory: ", path_dir_to_copy, " with error: ", error_string(open_error))) - return result - - # Ensure target directory is openable. - var target_dir = DirAccess.open(path_dir_to_copy_into) - var target_dir_path_abs = ProjectSettings.globalize_path(path_dir_to_copy_into) - if target_dir == null: - var msg = LoggieMsg.new("📂 Target directory not found - creating it at:").msg(path_dir_to_copy_into).color(Color.CADET_BLUE) - result.messages.push_back(msg) - DirAccess.make_dir_recursive_absolute(path_dir_to_copy_into) - target_dir = DirAccess.open(path_dir_to_copy_into) - - # Copy all files from the current source directory into the target directory. - for file_name : String in source_dir.get_files(): - var file_path_abs = ProjectSettings.globalize_path(path_dir_to_copy.path_join(file_name)) - var target_file_path_abs = target_dir_path_abs.path_join(file_name) - var copying_msg = LoggieMsg.new("📝 Copying file...") - copying_msg.msg(file_path_abs).italic().color(Color.CORNFLOWER_BLUE).add(" -> ") - copying_msg.msg(target_file_path_abs).bold().color(Color.CORNFLOWER_BLUE) - - var is_overwrite_required = false - if FileAccess.file_exists(target_file_path_abs): - is_overwrite_required = true - if overwrite_existing_files_with_same_name: - copying_msg.nl().msg("\t[!] Target file already exists and will be overwritten.").bold().color(Color.DARK_KHAKI) - else: - copying_msg.nl().msg("\t🛑 File will not be copied as overwriting existing files is disabled.").bold().color(Color.SALMON) - - result.messages.push_back(copying_msg) - - if (not is_overwrite_required) or (is_overwrite_required and overwrite_existing_files_with_same_name): - var copy_error = DirAccess.copy_absolute(file_path_abs, target_file_path_abs) - if copy_error != OK: - result.errors.push_back(copy_error) - result.messages.push_back(LoggieMsg.new("Attempt to copy file failed with error: '", error_string(copy_error))) - - # Create all of source directory's subdirectories in the target directory and copy their contents. - for dir_name : String in source_dir.get_directories(): - var source_subdir_path = path_dir_to_copy.path_join(dir_name) - var source_subdir_path_abs = ProjectSettings.globalize_path(source_subdir_path) - var target_subdir_path = path_dir_to_copy_into.path_join(dir_name) - var dir_path_abs = ProjectSettings.globalize_path(target_subdir_path) - - result.messages.push_back(LoggieMsg.new("📂 Creating directory: ").msg("{dir}".format({"dir": dir_path_abs})).color(Color.CADET_BLUE)) - var make_dir_error = DirAccess.make_dir_recursive_absolute(dir_path_abs) - if make_dir_error != OK: - result.errors.push_back(make_dir_error) - var error_msg = LoggieMsg.new("Attempt to create directory at absolute path recursively failed with error: '", error_string(make_dir_error)) - result.messages.push_back(error_msg) - continue - - # Recursively copy the contents of the subdirectory - var subdir_copy_result = copy_dir_absolute(source_subdir_path_abs, target_subdir_path, overwrite_existing_files_with_same_name) - result.errors = result.errors + subdir_copy_result.errors - result.messages = result.messages + subdir_copy_result.messages - - if debug_enabled: - for msg : LoggieMsg in result.messages: - print_rich(msg.string()) - - return result - -## A dictionary of named colors matching the constants from [Color] used to help with rich text coloring. -## There may be a way to obtain these Color values without this dictionary if one can somehow check for the -## existence and value of a constant on the Color class (since they're already there), -## but I can't seem to find a way, so this will have to do for now. -static var NamedColors = { - "ALICE_BLUE": Color(0.941176, 0.972549, 1, 1), - "ANTIQUE_WHITE": Color(0.980392, 0.921569, 0.843137, 1), - "AQUA": Color(0, 1, 1, 1), - "AQUAMARINE": Color(0.498039, 1, 0.831373, 1), - "AZURE": Color(0.941176, 1, 1, 1), - "BEIGE": Color(0.960784, 0.960784, 0.862745, 1), - "BISQUE": Color(1, 0.894118, 0.768627, 1), - "BLACK": Color(0, 0, 0, 1), - "BLANCHED_ALMOND": Color(1, 0.921569, 0.803922, 1), - "BLUE": Color(0, 0, 1, 1), - "BLUE_VIOLET": Color(0.541176, 0.168627, 0.886275, 1), - "BROWN": Color(0.647059, 0.164706, 0.164706, 1), - "BURLYWOOD": Color(0.870588, 0.721569, 0.529412, 1), - "CADET_BLUE": Color(0.372549, 0.619608, 0.627451, 1), - "CHARTREUSE": Color(0.498039, 1, 0, 1), - "CHOCOLATE": Color(0.823529, 0.411765, 0.117647, 1), - "CORAL": Color(1, 0.498039, 0.313726, 1), - "CORNFLOWER_BLUE": Color(0.392157, 0.584314, 0.929412, 1), - "CORNSILK": Color(1, 0.972549, 0.862745, 1), - "CRIMSON": Color(0.862745, 0.0784314, 0.235294, 1), - "CYAN": Color(0, 1, 1, 1), - "DARK_BLUE": Color(0, 0, 0.545098, 1), - "DARK_CYAN": Color(0, 0.545098, 0.545098, 1), - "DARK_GOLDENROD": Color(0.721569, 0.52549, 0.0431373, 1), - "DARK_GRAY": Color(0.662745, 0.662745, 0.662745, 1), - "DARK_GREEN": Color(0, 0.392157, 0, 1), - "DARK_KHAKI": Color(0.741176, 0.717647, 0.419608, 1), - "DARK_MAGENTA": Color(0.545098, 0, 0.545098, 1), - "DARK_OLIVE_GREEN": Color(0.333333, 0.419608, 0.184314, 1), - "DARK_ORANGE": Color(1, 0.54902, 0, 1), - "DARK_ORCHID": Color(0.6, 0.196078, 0.8, 1), - "DARK_RED": Color(0.545098, 0, 0, 1), - "DARK_SALMON": Color(0.913725, 0.588235, 0.478431, 1), - "DARK_SEA_GREEN": Color(0.560784, 0.737255, 0.560784, 1), - "DARK_SLATE_BLUE": Color(0.282353, 0.239216, 0.545098, 1), - "DARK_SLATE_GRAY": Color(0.184314, 0.309804, 0.309804, 1), - "DARK_TURQUOISE": Color(0, 0.807843, 0.819608, 1), - "DARK_VIOLET": Color(0.580392, 0, 0.827451, 1), - "DEEP_PINK": Color(1, 0.0784314, 0.576471, 1), - "DEEP_SKY_BLUE": Color(0, 0.74902, 1, 1), - "DIM_GRAY": Color(0.411765, 0.411765, 0.411765, 1), - "DODGER_BLUE": Color(0.117647, 0.564706, 1, 1), - "FIREBRICK": Color(0.698039, 0.133333, 0.133333, 1), - "FLORAL_WHITE": Color(1, 0.980392, 0.941176, 1), - "FOREST_GREEN": Color(0.133333, 0.545098, 0.133333, 1), - "FUCHSIA": Color(1, 0, 1, 1), - "GAINSBORO": Color(0.862745, 0.862745, 0.862745, 1), - "GHOST_WHITE": Color(0.972549, 0.972549, 1, 1), - "GOLD": Color(1, 0.843137, 0, 1), - "GOLDENROD": Color(0.854902, 0.647059, 0.12549, 1), - "GRAY": Color(0.745098, 0.745098, 0.745098, 1), - "GREEN": Color(0, 1, 0, 1), - "GREEN_YELLOW": Color(0.678431, 1, 0.184314, 1), - "HONEYDEW": Color(0.941176, 1, 0.941176, 1), - "HOT_PINK": Color(1, 0.411765, 0.705882, 1), - "INDIAN_RED": Color(0.803922, 0.360784, 0.360784, 1), - "INDIGO": Color(0.294118, 0, 804, 1), - "IVORY": Color(1, 1, 0.941176, 1), - "KHAKI": Color(0.941176, 0.901961, 0.54902, 1), - "LAVENDER": Color(0.901961, 0.901961, 0.980392, 1), - "LAVENDER_BLUSH": Color(1, 0.941176, 0.960784, 1), - "LAWN_GREEN": Color(0.486275, 0.988235, 0, 1), - "LEMON_CHIFFON": Color(1, 0.980392, 0.803922, 1), - "LIGHT_BLUE": Color(0.678431, 0.847059, 0.901961, 1), - "LIGHT_CORAL": Color(0.941176, 0.501961, 0.501961, 1), - "LIGHT_CYAN": Color(0.878431, 1, 1, 1), - "LIGHT_GOLDENROD": Color(0.980392, 0.980392, 0.823529, 1), - "LIGHT_GRAY": Color(0.827451, 0.827451, 0.827451, 1), - "LIGHT_GREEN": Color(0.564706, 0.933333, 0.564706, 1), - "LIGHT_PINK": Color(1, 0.713726, 0.756863, 1), - "LIGHT_SALMON": Color(1, 0.627451, 0.478431, 1), - "LIGHT_SEA_GREEN": Color(0.12549, 0.698039, 0.666667, 1), - "LIGHT_SKY_BLUE": Color(0.529412, 0.807843, 0.980392, 1), - "LIGHT_SLATE_GRAY": Color(0.466667, 0.533333, 0.6, 1), - "LIGHT_STEEL_BLUE": Color(0.690196, 0.768627, 0.870588, 1), - "LIGHT_YELLOW": Color(1, 1, 0.878431, 1), - "LIME": Color(0, 1, 0, 1), - "LIME_GREEN": Color(0.196078, 0.803922, 0.196078, 1), - "LINEN": Color(0.980392, 0.941176, 0.901961, 1), - "MAGENTA": Color(1, 0, 1, 1), - "MAROON": Color(0.690196, 0.188235, 0.376471, 1), - "MEDIUM_AQUAMARINE": Color(0.4, 0.803922, 0.666667, 1), - "MEDIUM_BLUE": Color(0, 0, 0.803922, 1), - "MEDIUM_ORCHID": Color(0.729412, 0.333333, 0.827451, 1), - "MEDIUM_PURPLE": Color(0.576471, 0.439216, 0.858824, 1), - "MEDIUM_SEA_GREEN": Color(0.235294, 0.701961, 0.443137, 1), - "MEDIUM_SLATE_BLUE": Color(0.482353, 0.407843, 0.933333, 1), - "MEDIUM_SPRING_GREEN": Color(0, 0.980392, 0.603922, 1), - "MEDIUM_TURQUOISE": Color(0.282353, 0.819608, 0.8, 1), - "MEDIUM_VIOLET_RED": Color(0.780392, 0.0823529, 0.521569, 1), - "MIDNIGHT_BLUE": Color(0.0980392, 0.0980392, 0.439216, 1), - "MINT_CREAM": Color(0.960784, 1, 0.980392, 1), - "MISTY_ROSE": Color(1, 0.894118, 0.882353, 1), - "MOCCASIN": Color(1, 0.894118, 0.709804, 1), - "NAVAJO_WHITE": Color(1, 0.870588, 0.678431, 1), - "NAVY_BLUE": Color(0, 0, 0.501961, 1), - "OLD_LACE": Color(0.992157, 0.960784, 0.901961, 1), - "OLIVE": Color(0.501961, 0.501961, 0, 1), - "OLIVE_DRAB": Color(0.419608, 0.556863, 0.137255, 1), - "ORANGE": Color(1, 0.647059, 0, 1), - "ORANGE_RED": Color(1, 0.270588, 0, 1), - "ORCHID": Color(0.854902, 0.439216, 0.839216, 1), - "PALE_GOLDENROD": Color(0.933333, 0.909804, 0.666667, 1), - "PALE_GREEN": Color(0.596078, 0.984314, 0.596078, 1), - "PALE_TURQUOISE": Color(0.686275, 0.933333, 0.933333, 1), - "PALE_VIOLET_RED": Color(0.858824, 0.439216, 0.576471, 1), - "PAPAYA_WHIP": Color(1, 0.937255, 0.835294, 1), - "PEACH_PUFF": Color(1, 0.854902, 0.72549, 1), - "PERU": Color(0.803922, 0.521569, 0.247059, 1), - "PINK": Color(1, 0.752941, 0.796078, 1), - "PLUM": Color(0.866667, 0.627451, 0.866667, 1), - "POWDER_BLUE": Color(0.690196, 0.878431, 0.901961, 1), - "PURPLE": Color(0.627451, 0.12549, 0.941176, 1), - "REBECCA_PURPLE": Color(0.4, 0.2, 0.6, 1), - "RED": Color(1, 0, 0, 1), - "ROSY_BROWN": Color(0.737255, 0.560784, 0.560784, 1), - "ROYAL_BLUE": Color(0.254902, 0.411765, 0.882353, 1), - "SADDLE_BROWN": Color(0.545098, 0.270588, 0.0745098, 1), - "SALMON": Color(0.980392, 0.501961, 0.447059, 1), - "SANDY_BROWN": Color(0.956863, 0.643137, 0.376471, 1), - "SEA_GREEN": Color(0.180392, 0.545098, 0.341176, 1), - "SEASHELL": Color(1, 0.960784, 0.933333, 1), - "SIENNA": Color(0.627451, 0.321569, 0.176471, 1), - "SILVER": Color(0.752941, 0.752941, 0.752941, 1), - "SKY_BLUE": Color(0.529412, 0.807843, 0.921569, 1), - "SLATE_BLUE": Color(0.415686, 0.352941, 0.803922, 1), - "SLATE_GRAY": Color(0.439216, 0.501961, 0.564706, 1), - "SNOW": Color(1, 0.980392, 0.980392, 1), - "SPRING_GREEN": Color(0, 1, 0.498039, 1), - "STEEL_BLUE": Color(0.27451, 0.509804, 0.705882, 1), - "TAN": Color(0.823529, 0.705882, 0.54902, 1), - "TEAL": Color(0, 0.501961, 0.501961, 1), - "THISTLE": Color(0.847059, 0.74902, 0.847059, 1), - "TOMATO": Color(1, 0.388235, 0.278431, 1), - "TRANSPARENT": Color(1, 1, 1, 0), - "TURQUOISE": Color(0.25098, 0.878431, 0.815686, 1), - "VIOLET": Color(0.933333, 0.509804, 0.933333, 1), - "WEB_GRAY": Color(0.501961, 0.501961, 0.501961, 1), - "WEB_GREEN": Color(0, 0.501961, 0, 1), - "WEB_MAROON": Color(0.501961, 0, 0, 1), - "WEB_PURPLE": Color(0.501961, 0, 0.501961, 1), - "WHEAT": Color(0.960784, 0.870588, 0.701961, 1), - "WHITE": Color(1, 1, 1, 1), - "WHITE_SMOKE": Color(0.960784, 0.960784, 0.960784, 1), - "YELLOW": Color(1, 1, 0, 1), - "YELLOW_GREEN": Color(0.603922, 0.803922, 0.196078, 1) -} diff --git a/addons/loggie/tools/loggie_tools.gd.uid b/addons/loggie/tools/loggie_tools.gd.uid deleted file mode 100644 index 5261ecd..0000000 --- a/addons/loggie/tools/loggie_tools.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c857kew4i5tgp diff --git a/addons/loggie/version_management/loggie_update.gd b/addons/loggie/version_management/loggie_update.gd deleted file mode 100644 index e8cce0a..0000000 --- a/addons/loggie/version_management/loggie_update.gd +++ /dev/null @@ -1,335 +0,0 @@ -@tool -class_name LoggieUpdate extends Node - -## Emitted when this update fails. -signal failed() - -## Emitted when this update succeeds. -signal succeeded() - -## Emitted when this declares that it has made some progress. -signal progress(value : float) - -## Emitted when this declares that it wants a new status/substatus message to be used. -signal status_changed(status_msg : Variant, substatus_msg : Variant) - -## Emitted when this update is starting. -signal starting() - -## Emitted when the 'is_in_progress' status of this update changes. -signal is_in_progress_changed(new_value : bool) - -## The path to the directory that should have a temporary file created and filled with the patch zipball buffer. -const TEMP_FILES_DIR = "user://" - -## If this is set to a non-empty string, it will be used as the directory into which the new update will be -## installed. Used for testing/debugging. When set to empty string, Loggie will automatically figure out -## where it is being updated from and use that directory instead. -const ALT_LOGGIE_PLUGIN_CONTAINER_DIR = "" - -## The domain from which status report [LoggieMsg]s from this update will be logged from. -const REPORTS_DOMAIN : String = "loggie_update_status_reports" - -## Stores a reference to the logger that's requesting this update. -var _logger : Variant - -## The URL used to visit a page that contains the release notes for this update. -var release_notes_url = "" - -## Stores a reference to the previous version the connected [member _logger] is/was using. -var prev_version : LoggieVersion = null - -## Stores a reference to the new version the connected [member _logger] should be using after the update. -var new_version : LoggieVersion = null - -## Indicates whether this update is currently in progress. -var is_in_progress : bool = false - -## Whether the update should retain or purge the backup it makes of the previous version files once it is done -## installing and applying the new update. -var _clean_up_backup_files : bool = true - -func _init(_prev_version : LoggieVersion, _new_version : LoggieVersion) -> void: - self.prev_version = _prev_version - self.new_version = _new_version - -## Returns a reference to the logger that's requesting this update. -func get_logger() -> Variant: - return self._logger - -## Sets the URL used to visit a page that contains the release notes for this update. -func set_release_notes_url(url : String) -> void: - self.release_notes_url = url - -## Sets whether this window is currently performing the update. -func set_is_in_progress(value : bool) -> void: - self.is_in_progress = value - self.is_in_progress_changed.emit(value) - -## Tries to start the version update. Prevents the update from starting -## if something is not configured correctly and pushes a warning/error. -func try_start(): - if Engine.has_meta("LoggieUpdateSuccessful") and Engine.get_meta("LoggieUpdateSuccessful"): - # No plan to allow multiple updates to run during a single Engine session anyway so no need to start another one. - # Also, this helps with internal testing of the updater and prevents an updated plugin from auto-starting another update - # when dealing with proxy versions. - return - - if self._logger == null: - push_warning("Attempt to start Loggie update failed - member '_logger' on the LoggieUpdate object is null.") - return - - if self.is_in_progress: - push_warning("Attempt to start Loggie update failed - the update is already in progress.") - return - - if self.new_version == null or self.prev_version == null: - push_warning("Attempt to start Loggie update failed - the updater prompt has the 'new_version' or 'prev_version' variable at null value.") - return - elif !self.new_version.is_higher_than(self.prev_version): - push_warning("Attempt to start Loggie update failed - the 'new_version' is not higher than 'prev_version'.") - return - - if self.new_version.has_meta("github_data"): - var github_data = self.new_version.get_meta("github_data") - if !github_data.has("zipball_url"): - push_error("Attempt to start Loggie update failed - the meta key 'github_data' on the 'new_version' is a dictionary that does not contain the required 'zipball_url' key/value pair.") - return - else: - push_error("Attempt to start Loggie update failed - the meta key 'github_data' on the 'new_version' was not found.") - return - - _start() - -## Internal function. Starts the updating of the [param _logger] to the [param new_version]. -## Do not run without verification that configuration is correct. -## Use [method try_start] to call this safely. -func _start(): - var loggie = self.get_logger() - - loggie.msg("Loggie is updating from version {v_prev} to {v_new}.".format({ - "v_prev" : self.prev_version, - "v_new" : self.new_version - })).domain(REPORTS_DOMAIN).color(Color.ORANGE).box(12).info() - - set_is_in_progress(true) - starting.emit() - - # Make request to configured endpoint. - var update_data = self.new_version.get_meta("github_data") - var http_request = HTTPRequest.new() - loggie.add_child(http_request) - http_request.request_completed.connect(_on_download_request_completed) - http_request.request(update_data.zipball_url) - -## Internal callback function. -## Defines what happens when new update content is successfully downloaded from GitHub. -## Called automatically during [method _start] if everything is going according to plan. -func _on_download_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray) -> void: - var loggie = self.get_logger() - - if loggie == null: - _failure("The _logger used by the updater window is null.") - return - - if result != HTTPRequest.RESULT_SUCCESS: - _failure("Download request returned non-zero code: " + str(result)) - return - - #region || Prepare: Define variables and callbacks that will be used throughout. - # The path to the directory which is supposed to contain the plugin directory. - # This will usually be 'res://addons/', but could be anything else too. We'll read it dynamically - # from the connected logger to guarantee correctness. - var LOGGIE_PLUGIN_CONTAINER_DIR = ALT_LOGGIE_PLUGIN_CONTAINER_DIR if !ALT_LOGGIE_PLUGIN_CONTAINER_DIR.is_empty() else loggie.get_directory_path().get_base_dir() + "/" - - # The path to the `loggie` plugin directory. - var LOGGIE_PLUGIN_DIR = ProjectSettings.globalize_path(LOGGIE_PLUGIN_CONTAINER_DIR.path_join("loggie/")) - - # The full path filename of the temporary .zip archive that will be created to store the downloaded data. - var TEMP_ZIP_FILE_PATH = ProjectSettings.globalize_path(TEMP_FILES_DIR.path_join("_temp_loggie_{ver}.zip".format({"ver": str(new_version)}))) - - # The path to the directory where a temporary backup of current loggie plugin files will be copied to. - # (will be created if doesn't exist). - var TEMP_PREV_VER_FILES_DIR_PATH = ProjectSettings.globalize_path(TEMP_FILES_DIR.path_join("_temp_loggie_{ver}_backup".format({"ver": str(prev_version)}))) - - # A callable that can be reused within this function that cleans up the temporary and unused directories, - # once this function comes to a conclusion. - var clean_up : Callable = func(): - if FileAccess.file_exists(TEMP_ZIP_FILE_PATH): - OS.move_to_trash(TEMP_ZIP_FILE_PATH) - if DirAccess.dir_exists_absolute(TEMP_PREV_VER_FILES_DIR_PATH) and self._clean_up_backup_files: - OS.move_to_trash(TEMP_PREV_VER_FILES_DIR_PATH) - - # A callable that can be used to replace the currently existing Loggie plugin directory - # with whatever is currently (temporarily) stored as its backup. - var revert_to_backup = func(): - if FileAccess.file_exists(LOGGIE_PLUGIN_DIR): - OS.move_to_trash(LOGGIE_PLUGIN_DIR) - if DirAccess.dir_exists_absolute(TEMP_PREV_VER_FILES_DIR_PATH): - DirAccess.rename_absolute(TEMP_PREV_VER_FILES_DIR_PATH, LOGGIE_PLUGIN_DIR) - - #endregion - - #region || Step 1: Store the downloaded content into a temporary zip file. - send_progress_update(20, "Processing Files", "Storing patch locally...") - - var zip_file: FileAccess = FileAccess.open(TEMP_ZIP_FILE_PATH, FileAccess.WRITE) - if zip_file == null: - _failure("Failed to open temp. file for writing: {path}".format({"path": TEMP_ZIP_FILE_PATH})) - clean_up.call() - return - - zip_file.store_buffer(body) - zip_file.close() - #endregion - - #region || Step 2: Make a temporary backup of the currently used Loggie plugin directory. - send_progress_update(30, "Processing Files", "Backing up previous version files...") - - if !DirAccess.dir_exists_absolute(LOGGIE_PLUGIN_DIR): - _failure("The Loggie plugin directory ({path}) could not be found.".format({ - "path" : LOGGIE_PLUGIN_DIR - })) - clean_up.call() - return - - var copy_prev_ver_result = LoggieTools.copy_dir_absolute(LOGGIE_PLUGIN_DIR, TEMP_PREV_VER_FILES_DIR_PATH, true) - if copy_prev_ver_result.errors.size() > 0: - var copy_prev_var_result_errors_msg = LoggieMsg.new("Errors encountered:") - for error in copy_prev_ver_result.errors: - copy_prev_var_result_errors_msg.nl().add(error_string(error)) - _failure(copy_prev_var_result_errors_msg.string()) - clean_up.call() - return - #endregion - - #region || Step 3: Remove currently used Loggie plugin directory and create a new one in its place populated with new version files. - send_progress_update(50, "Processing Files", "Copying new version files...") - var zip_reader: ZIPReader = ZIPReader.new() - var zip_reader_open_error = zip_reader.open(TEMP_ZIP_FILE_PATH) - if zip_reader_open_error != OK: - _failure("Attempt to open temp. file(s) archive at {path} failed with error: {err_str}".format({ - "path": LOGGIE_PLUGIN_DIR, - "err_str" : error_string(zip_reader_open_error) - })) - clean_up.call() - return - - # Trash the previously existing loggie plugin dir entirely. - # A new one will be created in a moment. - OS.move_to_trash(LOGGIE_PLUGIN_DIR) - - # Get a list of all files and dirs in the zip. - var files : PackedStringArray = zip_reader.get_files() - - # This will always be the "addons" directory in the zip archive in which we expect - # to find the "loggie" directory containing the plugin. - var base_path_in_zip = files[1] - - # Remove the first 2 parts of the path that we won't be needing at all. - files.remove_at(0) - files.remove_at(0) - - # Create all needed files and directories. - for path in files: - var new_file_path: String = path.replace(base_path_in_zip, "") - if path.ends_with("/"): - DirAccess.make_dir_recursive_absolute(LOGGIE_PLUGIN_CONTAINER_DIR + new_file_path) - else: - var abs_path = LOGGIE_PLUGIN_CONTAINER_DIR + new_file_path - var file : FileAccess = FileAccess.open(abs_path, FileAccess.WRITE) - if file == null: - _failure("Error while storing buffer data into temporary files - write target directory or file {target} gave the error: {error}".format({ - "error" : error_string(FileAccess.get_open_error()), - "target" : abs_path - })) - revert_to_backup.call() - clean_up.call() - return - else: - var file_content = zip_reader.read_file(path) - file.store_buffer(file_content) - file.close() - - zip_reader.close() - #endregion - - #region || Step 4: Move the user's 'custom_settings.gd' to the new version directory if it existed in prev version. - send_progress_update(70, "Processing Files", "Reapplying custom settings...") - var CUSTOM_SETTINGS_IN_PREV_VER_PATH = TEMP_PREV_VER_FILES_DIR_PATH.path_join("custom_settings.gd") - if FileAccess.file_exists(CUSTOM_SETTINGS_IN_PREV_VER_PATH): - var CUSTOM_SETTINGS_IN_NEW_VER_PATH = ProjectSettings.globalize_path(LOGGIE_PLUGIN_DIR.path_join("custom_settings.gd")) - var custom_settings_copy_error = DirAccess.copy_absolute(CUSTOM_SETTINGS_IN_PREV_VER_PATH, CUSTOM_SETTINGS_IN_NEW_VER_PATH) - if custom_settings_copy_error != OK: - push_error("Attempt to copy the 'custom_settings.gd' file from {p1} to {p2} failed with error: {error}".format({ - "p1" : CUSTOM_SETTINGS_IN_PREV_VER_PATH, - "p2" : CUSTOM_SETTINGS_IN_NEW_VER_PATH, - "error" : error_string(custom_settings_copy_error) - })) - #endregion - - #region || Step 5: Move the user's 'channels/custom_channels' directory to the new version if it existed in prev version. - send_progress_update(80, "Processing Files", "Reapplying custom channels...") - var CUSTOM_CHANNELS_IN_PREV_VER_PATH = ProjectSettings.globalize_path(TEMP_PREV_VER_FILES_DIR_PATH.path_join("channels/custom_channels/")) - if DirAccess.dir_exists_absolute(CUSTOM_CHANNELS_IN_PREV_VER_PATH): - var CUSTOM_CHANNELS_IN_NEW_VER_PATH = ProjectSettings.globalize_path(LOGGIE_PLUGIN_DIR.path_join("channels/custom_channels/")) - var copy_prev_ver_custom_channels_result = LoggieTools.copy_dir_absolute(CUSTOM_CHANNELS_IN_PREV_VER_PATH, CUSTOM_CHANNELS_IN_NEW_VER_PATH, true) - if copy_prev_ver_custom_channels_result.errors.size() > 0: - var copy_prev_var_result_errors_msg = LoggieMsg.new("Errors encountered:") - for error in copy_prev_ver_result.errors: - copy_prev_var_result_errors_msg.nl().add(error_string(error)) - push_error("Attempt to copy the 'channels/custom_channels' directory from {p1} to {p2} failed with error: {error}".format({ - "p1" : CUSTOM_CHANNELS_IN_PREV_VER_PATH, - "p2" : CUSTOM_CHANNELS_IN_NEW_VER_PATH, - "error" : copy_prev_var_result_errors_msg.string() - })) - else: - print("The {path} directory doesn't exist.".format({"path": CUSTOM_CHANNELS_IN_PREV_VER_PATH})) - #endregion - - #region || Step 6: Clean up temporarily created files and close filewrite. - send_progress_update(90, "Processing Files", "Cleaning up...") - clean_up.call() - #endregion - - #region || Step 7: Declare successful. Wrap up. - send_progress_update(100, "Finishing up", "") - _success() - #endregion - -## Internal function used at the end of the updating process if it is successfully completed. -func _success(): - set_is_in_progress(false) - - var msg = "💬 You may see temporary errors in the console due to Loggie files being re-scanned and reloaded on the spot.\nIt should be safe to dismiss them, but for the best experience, reload the Godot editor (and the plugin, if something seems wrong).\n\n🚩 If you see a 'Files have been modified on disk' window pop up, choose 'Discard local changes and reload' to accept incoming changes." - status_changed.emit(null, msg) - succeeded.emit() - - print_rich(LoggieMsg.new("👀 Loggie updated to version {new_ver}!".format({"new_ver": self.new_version})).bold().color(Color.ORANGE).string()) - print_rich(LoggieMsg.new("\t📚 Release Notes: ").bold().msg("[url={url}]{url}[/url]".format({"url": release_notes_url})).color(Color.CORNFLOWER_BLUE).string()) - print_rich(LoggieMsg.new("\t💬 Support, Development & Feature Requests: ").bold().msg("[url=https://discord.gg/XPdxpMqmcs]https://discord.gg/XPdxpMqmcs[/url]").color(Color.CORNFLOWER_BLUE).string()) - - if Engine.is_editor_hint(): - var editor_plugin = Engine.get_meta("LoggieEditorPlugin") - editor_plugin.get_editor_interface().get_resource_filesystem().scan() - editor_plugin.get_editor_interface().call_deferred("set_plugin_enabled", "loggie", true) - editor_plugin.get_editor_interface().set_plugin_enabled("loggie", false) - Engine.set_meta("LoggieUpdateSuccessful", true) - print_rich("[b]Updater:[/b] ", msg) - -## Internal function used to interrupt an ongoing update and cause it to fail. -func _failure(status_msg : String): - var loggie = self.get_logger() - loggie.msg(status_msg).color(Color.SALMON).preprocessed(false).error() - loggie.msg("\t💬 If this issue persists, consider reporting: ").bold().msg("https://github.com/Shiva-Shadowsong/loggie/issues").color(Color.CORNFLOWER_BLUE).preprocessed(false).info() - set_is_in_progress(false) - failed.emit() - status_changed.emit(null, status_msg) - -## Informs the listeners of the [signal progress] / [signal status_changed] signals about a change in the progress of the update. -func send_progress_update(progress_amount : float, status_msg : String, substatus_msg : String): - var loggie = self.get_logger() - if !substatus_msg.is_empty(): - loggie.msg("•• ").msg(substatus_msg).domain(REPORTS_DOMAIN).preprocessed(false).info() - progress.emit(progress_amount) - status_changed.emit(status_msg, substatus_msg) diff --git a/addons/loggie/version_management/loggie_update.gd.uid b/addons/loggie/version_management/loggie_update.gd.uid deleted file mode 100644 index 18b5122..0000000 --- a/addons/loggie/version_management/loggie_update.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cx6w7o7nxwoob diff --git a/addons/loggie/version_management/loggie_version.gd b/addons/loggie/version_management/loggie_version.gd deleted file mode 100644 index 54de640..0000000 --- a/addons/loggie/version_management/loggie_version.gd +++ /dev/null @@ -1,39 +0,0 @@ -## A utility class that helps with storing data about a Loggie Version and converting and comparing version strings. -class_name LoggieVersion extends Resource - -var minor : int = -1 ## The minor component of the version. -var major : int = -1 ## The major component of the version. -var proxy_for : LoggieVersion = null ## The version that this version is a proxy for. (Internal use only) - -func _init(_major : int = -1, _minor : int = -1) -> void: - self.minor = _minor - self.major = _major - -func _to_string() -> String: - return str(self.major) + "." + str(self.minor) - -## Checks if this version is valid. -## (neither minor nor major component can be less than 0). -func is_valid() -> bool: - return (minor >= 0 and major >= 0) - -## Checks if the given [param version] if higher than this version. -func is_higher_than(version : LoggieVersion): - if self.major > version.major: - return true - if self.minor > version.minor: - return true - return false - -## Given a string that has 2 sets of digits separated by a ".", breaks that down -## into a version with a major and minor version component (ints). -static func from_string(version_string : String) -> LoggieVersion: - var version : LoggieVersion = LoggieVersion.new() - var regex = RegEx.new() - regex.compile("(\\d+)\\.(\\d+)") - - var result = regex.search(version_string) - if result: - version.major = result.get_string(1).to_int() - version.minor = result.get_string(2).to_int() - return version diff --git a/addons/loggie/version_management/loggie_version.gd.uid b/addons/loggie/version_management/loggie_version.gd.uid deleted file mode 100644 index b0edc52..0000000 --- a/addons/loggie/version_management/loggie_version.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dgetf62kxei2g diff --git a/addons/loggie/version_management/loggie_version_manager.gd b/addons/loggie/version_management/loggie_version_manager.gd deleted file mode 100644 index 0bc5979..0000000 --- a/addons/loggie/version_management/loggie_version_manager.gd +++ /dev/null @@ -1,225 +0,0 @@ -@tool -## A class that can be used to inquire about, generate, and operate on [LoggieVersion]s. -## It is also responsible for notifying about an available update, and starting it, if configured to do so. -class_name LoggieVersionManager extends RefCounted - -## Emitted when this version manager updates the known [member latest_version]. -signal latest_version_updated() - -## Emitted when this version manager has created a valid [LoggieUpdate] and is ready to use it. -signal update_ready() - -## The URL where loggie releases on GitHub can be found. -const REMOTE_RELEASES_URL = "https://api.github.com/repos/Shiva-Shadowsong/loggie/releases" - -## The domain from which [LoggieMsg]s from this version manager will be logged from. -const REPORTS_DOMAIN : String = "loggie_version_check_reports" - -## Stores the result of reading the Loggie version with [method get_current_Version]. -var version : LoggieVersion = null - -## Stores the result of reading the latest Loggie version with [method get_latest_version]. -var latest_version : LoggieVersion = null - -## Stores a reference to a ConfigFile which will be loaded from [member CONFIG_PATH] during [method find_and_store_current_version]. -var config : ConfigFile = ConfigFile.new() - -## Stores a reference to the logger that's using this version manager. -var _logger : Variant = null - -## Stores a reference to the [LoggieUpdate] that has been created to handle an available update. -var _update : LoggieUpdate = null - -## Internal debug variable. -## If not null, this version manager will treat the [LoggieVersion] provided under this variable to be the current [param version]. -## Useful for debugging this module when you want to simulate that the current version is something different than it actually is. -var _version_proxy : LoggieVersion = null - -## Initializes this version manager, connecting it to the logger that's using it and updating the version cache based on that logger, -## which will further prompt the emission of signals in this class, and so on. -func connect_logger(logger : Variant) -> void: - self.latest_version_updated.connect(on_latest_version_updated) - self._logger = logger - - # Set to true during development to enable debug prints related to version management. - self._logger.set_domain_enabled(self.REPORTS_DOMAIN, false) - - update_version_cache() - -## Returns a reference to the logger object that is using this version manager. -func get_logger() -> Variant: - return self._logger - -## Reads the current version of Loggie from plugin.cfg and stores it in [member version]. -func find_and_store_current_version(): - var detected_version = self._logger.version - if self._version_proxy != null: - self.version = self._version_proxy - self.version.proxy_for = detected_version - else: - self.version = detected_version - -## Reads the latest version of Loggie from a GitHub API response and stores it in [member latest_version]. -func find_and_store_latest_version(): - var loggie = self.get_logger() - var http_request = HTTPRequest.new() - loggie.add_child(http_request) - loggie.msg("Retrieving version(s) info from endpoint:", REMOTE_RELEASES_URL).domain(REPORTS_DOMAIN).debug() - http_request.request_completed.connect(_on_get_latest_version_request_completed, CONNECT_ONE_SHOT) - http_request.request(REMOTE_RELEASES_URL) - -## Defines what happens once this version manager emits the signal saying that an update is available. -func on_update_available_detected() -> void: - var loggie = self.get_logger() - if loggie.settings.update_check_mode == LoggieEnums.UpdateCheckType.DONT_CHECK: - return - - self._update = LoggieUpdate.new(self.version, self.latest_version) - self._update._logger = loggie - - var github_data = self.latest_version.get_meta("github_data") - var latest_release_notes_url = github_data.html_url - self._update.set_release_notes_url(latest_release_notes_url) - loggie.add_child(self._update) - update_ready.emit() - - # No plan to allow multiple updates to run during a single Engine session anyway so no need to start another one. - # Also, this helps with internal testing of the updater and prevents an updated plugin from auto-starting another update - # when dealing with proxy versions. - var hasUpdatedAlready = Engine.has_meta("LoggieUpdateSuccessful") and Engine.get_meta("LoggieUpdateSuccessful") - - match loggie.settings.update_check_mode: - LoggieEnums.UpdateCheckType.CHECK_AND_SHOW_UPDATER_WINDOW: - if hasUpdatedAlready: - loggie.info("Update already performed. ✔️") - return - create_and_show_updater_widget(self._update) - LoggieEnums.UpdateCheckType.CHECK_AND_SHOW_MSG: - loggie.msg("👀 Loggie update available!").color(Color.ORANGE).header().msg(" > Current version: {version}, Latest version: {latest}".format({ - "version" : self.version, - "latest" : self.latest_version - })).info() - LoggieEnums.UpdateCheckType.CHECK_DOWNLOAD_AND_SHOW_MSG: - if hasUpdatedAlready: - loggie.info("Update already performed. ✔️") - return - loggie.set_domain_enabled("loggie_update_status_reports", true) - self._update.try_start() - -## Defines what happens when the request to GitHub API which grabs all the Loggie releases is completed. -func _on_get_latest_version_request_completed(result : int, response_code : int, headers : PackedStringArray, body: PackedByteArray): - var loggie = self.get_logger() - loggie.msg("Response for request received:", response_code).domain(REPORTS_DOMAIN).debug() - - if result != HTTPRequest.RESULT_SUCCESS: - return - - var response = JSON.parse_string(body.get_string_from_utf8()) - - if typeof(response) != TYPE_ARRAY: - loggie.error("The response parsed from GitHub was not an array. Response received in an unsupported format.") - return - - var latest_version_data = response[0] # GitHub releases are in order of creation, so grab the first one from the response, that's the latest one. - self.latest_version = LoggieVersion.from_string(latest_version_data.tag_name) - self.latest_version.set_meta("github_data", latest_version_data) - - loggie.msg("Current version of Loggie:", self.version).msg(" (proxy for: {value})".format({"value": self.version.proxy_for})).domain(REPORTS_DOMAIN).debug() - loggie.msg("Latest version of Loggie:", self.latest_version).domain(REPORTS_DOMAIN).debug() - latest_version_updated.emit() - -## Executes every time this version manager updates the known latest_version. -func on_latest_version_updated() -> void: - var loggie = self.get_logger() - if loggie == null: - return - - # Check if update is available. - if loggie.settings.update_check_mode != LoggieEnums.UpdateCheckType.DONT_CHECK: - loggie.msg("👀 Loggie:").bold().color("orange").msg(" Checking for updates...").info() - if is_update_available(): - on_update_available_detected() - else: - loggie.msg("👀 Loggie:").bold().color("orange").msg(" Up to date. ✔️").color(Color.LIGHT_GREEN).info() - -## Displays the widget which informs the user of the available update and offers actions that they can take next. -func create_and_show_updater_widget(update : LoggieUpdate) -> Window: - const PATH_TO_WIDGET_SCENE = "addons/loggie/version_management/update_prompt_window.tscn" - var WIDGET_SCENE = load(PATH_TO_WIDGET_SCENE) - if !is_instance_valid(WIDGET_SCENE): - push_error("Loggie Update Prompt Window scene not found on expected path: {path}".format({"path": PATH_TO_WIDGET_SCENE})) - return - - var loggie = self.get_logger() - if loggie == null: - return - - var popup_parent = null - if Engine.is_editor_hint() and Engine.has_meta("LoggieEditorInterfaceBaseControl"): - popup_parent = Engine.get_meta("LoggieEditorInterfaceBaseControl") - else: - popup_parent = SceneTree.current_scene - - # Configure popup window. - var _popup = Window.new() - update.succeeded.connect(func(): - _popup.queue_free() - var success_dialog = AcceptDialog.new() - var msg = "💬 You may see temporary errors in the console due to Loggie files being re-scanned and reloaded on the spot.\nIt should be safe to dismiss them, but for the best experience, reload the Godot editor (and the plugin, if something seems wrong).\n\n🚩 If you see a 'Files have been modified on disk' window pop up, choose 'Discard local changes and reload' to accept incoming changes." - success_dialog.dialog_text = msg - success_dialog.title = "Loggie Updater" - if is_instance_valid(popup_parent): - popup_parent.add_child(success_dialog) - success_dialog.popup_centered() - ) - var on_close_requested = func(): - _popup.queue_free() - - _popup.close_requested.connect(on_close_requested, CONNECT_ONE_SHOT) - _popup.borderless = false - _popup.unresizable = true - _popup.transient = true - _popup.title = "Update Available" - - # Configure window widget and add it as a child of the popup window. - var widget : LoggieUpdatePrompt = WIDGET_SCENE.instantiate() - widget.connect_to_update(update) - widget.set_anchors_preset(Control.PRESET_FULL_RECT) - widget._logger = loggie - widget.close_requested.connect(on_close_requested, CONNECT_ONE_SHOT) - - if is_instance_valid(popup_parent): - popup_parent.add_child(_popup) - _popup.popup_centered(widget.host_window_size) - _popup.add_child(widget) - - return _popup - -## Updates the local variables which point to the current and latest version of Loggie. -func update_version_cache(): - # Read and cache the current version of Loggie from plugin.cfg. - find_and_store_current_version() - - # Read and cache the latest version of Loggie from GitHub. - # (Do it only if running in editor, no need for this if running in a game). - var logger = self.get_logger() - if logger is Node: - if !Engine.is_editor_hint(): - return - if logger.is_node_ready(): - find_and_store_latest_version() - else: - logger.ready.connect(func(): - find_and_store_latest_version() - , CONNECT_ONE_SHOT) - -## Checks if an update for Loggie is available. Run only after running [method update_version_cache]. -func is_update_available() -> bool: - var loggie = self.get_logger() - if !(self.version is LoggieVersion and self.version.is_valid()): - loggie.error("The current version of Loggie is not valid. Run `find_and_store_current_version` once to obtain this value first.") - return false - if !(self.latest_version is LoggieVersion and self.latest_version.is_valid()): - loggie.error("The latest version of Loggie is not valid. Run `find_and_store_latest_version` once to obtain this value first.") - return false - return self.latest_version.is_higher_than(self.version) diff --git a/addons/loggie/version_management/loggie_version_manager.gd.uid b/addons/loggie/version_management/loggie_version_manager.gd.uid deleted file mode 100644 index 36f8e28..0000000 --- a/addons/loggie/version_management/loggie_version_manager.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cqp1sp4ovt6pd diff --git a/addons/loggie/version_management/update_prompt_window.gd b/addons/loggie/version_management/update_prompt_window.gd deleted file mode 100644 index ce97d0a..0000000 --- a/addons/loggie/version_management/update_prompt_window.gd +++ /dev/null @@ -1,192 +0,0 @@ -@tool -## The Loggie Update Prompt is a control node that is meant to be created and added as a child of some other node, most commonly a [Window]. -## It connects to a [LoggieUpdate] via its [method connect_to_update] method, then displays data about that update depending on what kind of -## data that [LoggieUpdate] provides with its signals. -class_name LoggieUpdatePrompt extends Panel - -## Emitted when the user requests to close the update prompt. -signal close_requested() - -## The animation player that will be used to animate the appearance of this window. -@export var animator : AnimationPlayer - -## The size the window that's hosting this panel will be forced to assume when -## it's ready to pop this up on the screen. -@export var host_window_size : Vector2 = Vector2(1063, 672) - -## Stores a reference to the logger that's using this window. -var _logger : Variant - -## The update this window is visually representing. -var _update : LoggieUpdate - -## Stores a boolean which indicates whether the update is currently in progress. -var is_currently_updating : bool = false - -func _ready() -> void: - connect_control_effects() - %UpdateNowBtn.grab_focus() - refresh_remind_later_btn() - animator.play("RESET") - -## Connects this window to an instance of [LoggieUpdate] whose progress and properties this window is supposed to track. -func connect_to_update(p_update : LoggieUpdate) -> void: - self._update = p_update - _update.is_in_progress_changed.connect(is_update_in_progress_changed) - _update.starting.connect(on_update_starting) - _update.succeeded.connect(on_update_succeeded) - _update.failed.connect(on_update_failed) - _update.progress.connect(on_update_progress) - _update.status_changed.connect(on_update_status_changed) - -## Returns a reference to the logger object that is using this widget. -func get_logger() -> Variant: - return self._logger - -## Defines what happens when the update this window is representing updates its "is in progress" status. -func is_update_in_progress_changed(is_in_progress : bool) -> void: - self.is_currently_updating = is_in_progress - - # The first time we enter the UpdateMonitor view and start an update, - # the %Notice node and its children should no longer (ever) be interactive or processing, - # since there is no way to get back to that view anymore. - if is_in_progress and %Notice.process_mode != Node.PROCESS_MODE_DISABLED: - %Notice.process_mode = Node.PROCESS_MODE_DISABLED - for child in %NoticeButtons.get_children(): - if child is Button: - child.focus_mode = Button.FOCUS_NONE - -## Connects the effects and functionalities of various controls in this window. -func connect_control_effects(): - if !is_instance_valid(self._update): - return - - # Configure version(s) labels. - %LabelCurrentVersion.text = str(self._update.prev_version) - %LabelLatestVersion.text = str(self._update.new_version) - %LabelOldVersion.text = str(self._update.prev_version) - %LabelNewVersion.text = str(self._update.new_version) - - # Configure onhover/focused effects. - var buttons_with_on_focushover_effect = [%OptionExitBtn, %OptionRestartGodotBtn, %OptionRetryUpdateBtn, %ReleaseNotesBtn, %RemindLaterBtn, %UpdateNowBtn] - for button : Button in buttons_with_on_focushover_effect: - button.focus_entered.connect(_on_button_focus_entered.bind(button)) - button.focus_exited.connect(_on_button_focus_exited.bind(button)) - button.mouse_entered.connect(_on_button_focus_entered.bind(button)) - button.mouse_exited.connect(_on_button_focus_exited.bind(button)) - button.pivot_offset = button.size * 0.5 - - # Connect behavior which executes when "Update Now" is pressed. - %UpdateNowBtn.pressed.connect(func(): - self._update.try_start() - ) - - # Configure Release Notes button. - %ReleaseNotesBtn.visible = !self._update.release_notes_url.is_empty() - %ReleaseNotesBtn.tooltip_text = "Opens {url} in browser.".format({"url": self._update.release_notes_url}) - %ReleaseNotesBtn.pressed.connect(func(): - if !self._update.release_notes_url.is_empty(): - OS.shell_open(self._update.release_notes_url) - ) - - # Connect behavior which executes when the "Remind Me Later / Close" is pressed. - %RemindLaterBtn.pressed.connect(func(): close_requested.emit()) - %OptionExitBtn.pressed.connect(func(): close_requested.emit()) - - # Connect behavior which executes when the "Retry" button is pressed. - %OptionRetryUpdateBtn.pressed.connect(self._update.try_start) - - # Connect behavior which executes when the "Restart Godot" button is pressed. - %OptionRestartGodotBtn.pressed.connect(func(): - close_requested.emit() - if Engine.is_editor_hint(): - var editor_plugin = Engine.get_meta("LoggieEditorPlugin") - editor_plugin.get_editor_interface().restart_editor(true) - ) - - # The "Don't show again checkbox" updates project settings whenever it is toggled. - %DontShowAgainCheckbox.toggled.connect(func(toggled_on : bool): - var loggie = self.get_logger() - if Engine.is_editor_hint() and loggie != null: - if toggled_on: - loggie.settings.update_check_mode = LoggieEnums.UpdateCheckType.CHECK_AND_SHOW_MSG - ProjectSettings.set_setting(loggie.settings.project_settings.update_check_mode.path, LoggieEnums.UpdateCheckType.CHECK_AND_SHOW_MSG) - else: - loggie.settings.update_check_mode = LoggieEnums.UpdateCheckType.CHECK_AND_SHOW_UPDATER_WINDOW - ProjectSettings.set_setting(loggie.settings.project_settings.update_check_mode.path, LoggieEnums.UpdateCheckType.CHECK_AND_SHOW_UPDATER_WINDOW) - refresh_remind_later_btn() - ) - -## Updates the content of the "Remind Later Btn" to show text appropriate to the current state of the "Don't show again" checkbox. -func refresh_remind_later_btn(): - if %DontShowAgainCheckbox.button_pressed: - %RemindLaterBtn.text = "close" - else: - %RemindLaterBtn.text = "remind later" - -## Defines what happens when the [member _update] is detected to be starting. -func on_update_starting(): - if animator.current_animation != "show_update_overview": - animator.queue("show_update_overview") - %ProgressBar.value = 0 - %LabelMainStatus.text = "Downloading" - %LabelUpdateStatus.text = "Waiting for server response." - %OptionExitBtn.disabled = true - %OptionExitBtn.visible = false - %OptionRetryUpdateBtn.disabled = true - %OptionRetryUpdateBtn.visible = false - %OptionRestartGodotBtn.disabled = true - %OptionRestartGodotBtn.visible = false - -## Defines what happens when the [member _update] declares it has made progress. -func on_update_progress(value : float): - %ProgressBar.value = value - -## Defines what happens when the [member _update] declares it has succeeded. -func on_update_succeeded(): - %LabelMainStatus.text = "Updated" - %OptionExitBtn.disabled = false - %OptionExitBtn.visible = true - %OptionRestartGodotBtn.disabled = false - %OptionRestartGodotBtn.visible = true - if animator.is_playing(): - animator.stop() - animator.play("finish_success") - -## Defines what happens when the [member _update] declares it wants the status message to change. -func on_update_status_changed(status_msg : Variant, substatus_msg : Variant): - if status_msg is String: - %LabelMainStatus.text = status_msg - if substatus_msg is String: - %LabelUpdateStatus.text = substatus_msg - -## Defines what happens when the [member _update] declares it has failed. -func on_update_failed(): - %ProgressBar.value = 0 - %LabelMainStatus.text = "Failed" - %OptionExitBtn.disabled = false - %OptionExitBtn.visible = true - %OptionRetryUpdateBtn.disabled = false - %OptionRetryUpdateBtn.visible = true - %OptionRestartGodotBtn.disabled = true - %OptionRestartGodotBtn.visible = false - -func _on_button_focus_entered(button : Button): - if button.has_meta("scale_tween"): - var old_tween = button.get_meta("scale_tween") - old_tween.kill() - button.set_meta("scale_tween", null) - - var tween : Tween = button.create_tween() - tween.tween_property(button, "scale", Vector2(1.2, 1.2), 0.1) - button.set_meta("scale_tween", tween) - -func _on_button_focus_exited(button : Button): - if button.has_meta("scale_tween"): - var old_tween = button.get_meta("scale_tween") - old_tween.kill() - button.set_meta("scale_tween", null) - - var tween : Tween = button.create_tween() - tween.tween_property(button, "scale", Vector2(1.0, 1.0), 0.1).from_current() - button.set_meta("scale_tween", tween) diff --git a/addons/loggie/version_management/update_prompt_window.gd.uid b/addons/loggie/version_management/update_prompt_window.gd.uid deleted file mode 100644 index df14153..0000000 --- a/addons/loggie/version_management/update_prompt_window.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b48scbgtjloqx diff --git a/addons/loggie/version_management/update_prompt_window.tscn b/addons/loggie/version_management/update_prompt_window.tscn deleted file mode 100644 index 2997221..0000000 --- a/addons/loggie/version_management/update_prompt_window.tscn +++ /dev/null @@ -1,818 +0,0 @@ -[gd_scene load_steps=32 format=3 uid="uid://d2eq0khfi3s15"] - -[ext_resource type="Script" path="res://addons/loggie/version_management/update_prompt_window.gd" id="1_xb7je"] -[ext_resource type="Texture2D" uid="uid://cgh6hd3u8nlpj" path="res://addons/loggie/assets/updater_bg.png" id="2_lbawe"] -[ext_resource type="FontFile" uid="uid://e3rpni7mpu0p" path="res://addons/loggie/assets/theme/fonts/coffee_soda.ttf" id="3_a36jf"] -[ext_resource type="FontFile" uid="uid://btuvtbhws7p8s" path="res://addons/loggie/assets/theme/fonts/PatrickHandSC-Regular.ttf" id="4_lnh27"] -[ext_resource type="StyleBox" uid="uid://ckw36egxdynxc" path="res://addons/loggie/assets/theme/loggie_border_box.tres" id="5_avea8"] -[ext_resource type="Texture2D" uid="uid://bfnp2a0sbhi2x" path="res://addons/loggie/assets/theme/checkbox/checkbox_checked.png" id="6_yoxpw"] -[ext_resource type="Texture2D" uid="uid://bib1lwikra5kr" path="res://addons/loggie/assets/theme/checkbox/checkbox_unchecked.png" id="7_xu2hn"] -[ext_resource type="Texture2D" uid="uid://dqf5cye21gyw8" path="res://addons/loggie/assets/theme/checkbox/checkbox_checked_disabled.png" id="8_4h2cx"] -[ext_resource type="Texture2D" uid="uid://cloe7vx2ej0nf" path="res://addons/loggie/assets/theme/checkbox/checkbox_unchecked_disabled.png" id="9_51n7f"] -[ext_resource type="Texture2D" uid="uid://2fr6et0qni2y" path="res://addons/loggie/assets/icon.png" id="10_abt8m"] -[ext_resource type="Theme" uid="uid://bntkg3oi4b314" path="res://addons/loggie/assets/theme/loggie_theme.tres" id="11_5uxhl"] - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_3bh8r"] -draw_center = false -border_width_bottom = 4 -border_color = Color(0.86, 0.6794, 0.344, 1) - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_rjg43"] - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_bwgrr"] - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_qbrxo"] - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_3asxb"] - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_86pfv"] - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_rw12e"] - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_j1ttd"] - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_3sc8x"] - -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ndum7"] - -[sub_resource type="Gradient" id="Gradient_wnvcb"] -colors = PackedColorArray(0.0311948, 0.0139167, 0.0080977, 1, 0.125625, 0.1125, 0.15, 1) - -[sub_resource type="GradientTexture1D" id="GradientTexture1D_k1b6u"] -gradient = SubResource("Gradient_wnvcb") - -[sub_resource type="Gradient" id="Gradient_rkgx7"] -interpolation_mode = 2 -offsets = PackedFloat32Array(0, 0.270059, 1) -colors = PackedColorArray(0.584314, 0.337255, 0.145098, 1, 0.495303, 0.287021, 0.13981, 1, 0.188235, 0.113725, 0.121569, 1) - -[sub_resource type="GradientTexture2D" id="GradientTexture2D_p6ad4"] -gradient = SubResource("Gradient_rkgx7") -fill_from = Vector2(0.239316, 0) -fill_to = Vector2(0.303419, 0.876068) - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_y40yc"] -bg_color = Color(0.12, 0.0528, 0.09088, 0.556863) -border_width_left = 3 -border_width_top = 3 -border_width_right = 3 -border_width_bottom = 6 -border_color = Color(0.533576, 0.418125, 0.23421, 1) -border_blend = true -corner_radius_top_left = 11 -corner_radius_top_right = 11 -corner_radius_bottom_right = 11 -corner_radius_bottom_left = 11 - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_h3ybw"] -bg_color = Color(0.69, 0.49128, 0.2484, 0.486275) -border_width_right = 4 -border_color = Color(0.94, 0.6768, 0.282, 0.541176) -corner_radius_top_left = 18 -corner_radius_top_right = 18 -corner_radius_bottom_right = 18 -corner_radius_bottom_left = 18 - -[sub_resource type="Animation" id="Animation_almc7"] -length = 0.001 -tracks/0/type = "value" -tracks/0/imported = false -tracks/0/enabled = true -tracks/0/path = NodePath(".:position") -tracks/0/interp = 1 -tracks/0/loop_wrap = true -tracks/0/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [Vector2(0, -673)] -} -tracks/1/type = "value" -tracks/1/imported = false -tracks/1/enabled = true -tracks/1/path = NodePath(".:visible") -tracks/1/interp = 1 -tracks/1/loop_wrap = true -tracks/1/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 1, -"values": [false] -} -tracks/2/type = "value" -tracks/2/imported = false -tracks/2/enabled = true -tracks/2/path = NodePath("VBoxContainer/OptionButtons/OptionRetryUpdateBtn:disabled") -tracks/2/interp = 1 -tracks/2/loop_wrap = true -tracks/2/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 1, -"values": [true] -} -tracks/3/type = "value" -tracks/3/imported = false -tracks/3/enabled = true -tracks/3/path = NodePath("VBoxContainer/OptionButtons/OptionExitBtn:disabled") -tracks/3/interp = 1 -tracks/3/loop_wrap = true -tracks/3/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 1, -"values": [true] -} -tracks/4/type = "value" -tracks/4/imported = false -tracks/4/enabled = true -tracks/4/path = NodePath("VBoxContainer/OptionButtons/OptionRetryUpdateBtn:visible") -tracks/4/interp = 1 -tracks/4/loop_wrap = true -tracks/4/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 1, -"values": [false] -} -tracks/5/type = "value" -tracks/5/imported = false -tracks/5/enabled = true -tracks/5/path = NodePath("VBoxContainer/OptionButtons/OptionExitBtn:visible") -tracks/5/interp = 1 -tracks/5/loop_wrap = true -tracks/5/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 1, -"values": [false] -} -tracks/6/type = "value" -tracks/6/imported = false -tracks/6/enabled = true -tracks/6/path = NodePath("%LabelOldVersion:modulate") -tracks/6/interp = 1 -tracks/6/loop_wrap = true -tracks/6/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [Color(1, 1, 1, 1)] -} -tracks/7/type = "value" -tracks/7/imported = false -tracks/7/enabled = true -tracks/7/path = NodePath("%LabelNewVersion:modulate") -tracks/7/interp = 1 -tracks/7/loop_wrap = true -tracks/7/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [Color(1, 1, 1, 1)] -} -tracks/8/type = "value" -tracks/8/imported = false -tracks/8/enabled = true -tracks/8/path = NodePath("%ProgressBar:modulate") -tracks/8/interp = 1 -tracks/8/loop_wrap = true -tracks/8/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [Color(1, 1, 1, 1)] -} -tracks/9/type = "value" -tracks/9/imported = false -tracks/9/enabled = true -tracks/9/path = NodePath("VBoxContainer:position") -tracks/9/interp = 1 -tracks/9/loop_wrap = true -tracks/9/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [Vector2(0, 532)] -} -tracks/10/type = "value" -tracks/10/imported = false -tracks/10/enabled = true -tracks/10/path = NodePath("LoggieIcon:scale") -tracks/10/interp = 1 -tracks/10/loop_wrap = true -tracks/10/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [Vector2(1, 1)] -} - -[sub_resource type="Animation" id="Animation_dewq5"] -resource_name = "finish_success" -length = 0.5 -tracks/0/type = "value" -tracks/0/imported = false -tracks/0/enabled = true -tracks/0/path = NodePath(".:position") -tracks/0/interp = 1 -tracks/0/loop_wrap = true -tracks/0/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [Vector2(0, 0)] -} -tracks/1/type = "value" -tracks/1/imported = false -tracks/1/enabled = true -tracks/1/path = NodePath(".:visible") -tracks/1/interp = 1 -tracks/1/loop_wrap = true -tracks/1/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 1, -"values": [true] -} -tracks/2/type = "value" -tracks/2/imported = false -tracks/2/enabled = true -tracks/2/path = NodePath("%LabelOldVersion:modulate") -tracks/2/interp = 1 -tracks/2/loop_wrap = true -tracks/2/keys = { -"times": PackedFloat32Array(0, 0.2), -"transitions": PackedFloat32Array(1, 1), -"update": 0, -"values": [Color(1, 1, 1, 1), Color(1, 1, 1, 0)] -} -tracks/3/type = "value" -tracks/3/imported = false -tracks/3/enabled = true -tracks/3/path = NodePath("%LabelNewVersion:modulate") -tracks/3/interp = 1 -tracks/3/loop_wrap = true -tracks/3/keys = { -"times": PackedFloat32Array(0, 0.2), -"transitions": PackedFloat32Array(1, 1), -"update": 0, -"values": [Color(1, 1, 1, 1), Color(1, 1, 1, 0)] -} -tracks/4/type = "value" -tracks/4/imported = false -tracks/4/enabled = true -tracks/4/path = NodePath("%ProgressBar:modulate") -tracks/4/interp = 1 -tracks/4/loop_wrap = true -tracks/4/keys = { -"times": PackedFloat32Array(0, 0.2), -"transitions": PackedFloat32Array(1, 1), -"update": 0, -"values": [Color(1, 1, 1, 1), Color(1, 1, 1, 0)] -} -tracks/5/type = "value" -tracks/5/imported = false -tracks/5/enabled = true -tracks/5/path = NodePath("VBoxContainer:position") -tracks/5/interp = 1 -tracks/5/loop_wrap = true -tracks/5/keys = { -"times": PackedFloat32Array(0, 0.466667), -"transitions": PackedFloat32Array(1, 1), -"update": 0, -"values": [Vector2(0, 532), Vector2(1, 432)] -} -tracks/6/type = "value" -tracks/6/imported = false -tracks/6/enabled = true -tracks/6/path = NodePath("LoggieIcon:scale") -tracks/6/interp = 1 -tracks/6/loop_wrap = true -tracks/6/keys = { -"times": PackedFloat32Array(0, 0.166667, 0.2, 0.3, 0.366667, 0.433333), -"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1), -"update": 0, -"values": [Vector2(1, 1), Vector2(1, 1), Vector2(1.33, 1), Vector2(1.075, 1.575), Vector2(0.735, 1.465), Vector2(1, 1)] -} - -[sub_resource type="Animation" id="Animation_jm1cu"] -resource_name = "show_update_overview" -tracks/0/type = "value" -tracks/0/imported = false -tracks/0/enabled = true -tracks/0/path = NodePath(".:position") -tracks/0/interp = 1 -tracks/0/loop_wrap = true -tracks/0/keys = { -"times": PackedFloat32Array(0, 0.2, 0.266667, 0.333333), -"transitions": PackedFloat32Array(1, 1, 1, 1), -"update": 0, -"values": [Vector2(0, -673), Vector2(0, 0), Vector2(0, 16), Vector2(0, 0)] -} -tracks/1/type = "value" -tracks/1/imported = false -tracks/1/enabled = true -tracks/1/path = NodePath(".:visible") -tracks/1/interp = 1 -tracks/1/loop_wrap = true -tracks/1/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 1, -"values": [true] -} -tracks/2/type = "value" -tracks/2/imported = false -tracks/2/enabled = true -tracks/2/path = NodePath("%ProgressBar:modulate") -tracks/2/interp = 1 -tracks/2/loop_wrap = true -tracks/2/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [Color(1, 1, 1, 1)] -} -tracks/3/type = "value" -tracks/3/imported = false -tracks/3/enabled = true -tracks/3/path = NodePath("%LabelOldVersion:modulate") -tracks/3/interp = 1 -tracks/3/loop_wrap = true -tracks/3/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [Color(1, 1, 1, 1)] -} -tracks/4/type = "value" -tracks/4/imported = false -tracks/4/enabled = true -tracks/4/path = NodePath("%LabelNewVersion:modulate") -tracks/4/interp = 1 -tracks/4/loop_wrap = true -tracks/4/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [Color(1, 1, 1, 1)] -} -tracks/5/type = "value" -tracks/5/imported = false -tracks/5/enabled = true -tracks/5/path = NodePath("LoggieIcon:scale") -tracks/5/interp = 1 -tracks/5/loop_wrap = true -tracks/5/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [Vector2(1, 1)] -} -tracks/6/type = "value" -tracks/6/imported = false -tracks/6/enabled = true -tracks/6/path = NodePath("VBoxContainer:position") -tracks/6/interp = 1 -tracks/6/loop_wrap = true -tracks/6/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [Vector2(0, 532)] -} - -[sub_resource type="AnimationLibrary" id="AnimationLibrary_lwiu5"] -_data = { -"RESET": SubResource("Animation_almc7"), -"finish_success": SubResource("Animation_dewq5"), -"show_update_overview": SubResource("Animation_jm1cu") -} - -[node name="UpdatePromptWindow" type="Panel" node_paths=PackedStringArray("animator")] -anchors_preset = -1 -anchor_right = 0.923 -anchor_bottom = 1.037 -offset_right = -0.296021 -offset_bottom = 0.0239868 -grow_horizontal = 2 -grow_vertical = 2 -script = ExtResource("1_xb7je") -animator = NodePath("AnimationPlayer") - -[node name="Notice" type="Control" parent="."] -unique_name_in_owner = true -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="Background" type="TextureRect" parent="Notice"] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -texture = ExtResource("2_lbawe") -expand_mode = 1 - -[node name="LabelLatestVersion" type="Label" parent="Notice"] -unique_name_in_owner = true -layout_mode = 1 -anchors_preset = -1 -anchor_left = 0.148 -anchor_top = 0.549 -anchor_right = 0.352 -anchor_bottom = 0.735 -offset_left = 0.414978 -offset_top = 0.115936 -offset_right = -0.122009 -offset_bottom = 0.123932 -grow_horizontal = 2 -grow_vertical = 0 -theme_override_colors/font_color = Color(0.878431, 0.662745, 0.266667, 1) -theme_override_colors/font_shadow_color = Color(0, 0, 0, 1) -theme_override_colors/font_outline_color = Color(0, 0, 0, 1) -theme_override_constants/shadow_offset_x = 3 -theme_override_constants/shadow_offset_y = 3 -theme_override_constants/outline_size = 18 -theme_override_constants/shadow_outline_size = 3 -theme_override_fonts/font = ExtResource("3_a36jf") -theme_override_font_sizes/font_size = 133 -text = "X.Y" - -[node name="LabelCurrentVersion" type="Label" parent="Notice"] -unique_name_in_owner = true -layout_mode = 1 -anchors_preset = -1 -anchor_left = 0.76 -anchor_top = 0.454 -anchor_right = 0.869 -anchor_bottom = 0.571 -offset_left = 0.0449829 -offset_top = 0.18399 -offset_right = 57.004 -offset_bottom = -0.107056 -grow_horizontal = 0 -grow_vertical = 2 -theme_override_colors/font_color = Color(0.784314, 0.619608, 0.317647, 1) -theme_override_colors/font_shadow_color = Color(0, 0, 0, 1) -theme_override_colors/font_outline_color = Color(0, 0, 0, 1) -theme_override_constants/shadow_offset_x = 3 -theme_override_constants/shadow_offset_y = 3 -theme_override_constants/outline_size = 18 -theme_override_constants/shadow_outline_size = 3 -theme_override_fonts/font = ExtResource("3_a36jf") -theme_override_font_sizes/font_size = 73 -text = "X.Y" - -[node name="VBoxContainer" type="VBoxContainer" parent="Notice"] -layout_mode = 1 -anchors_preset = -1 -anchor_left = 0.229 -anchor_top = 0.789 -anchor_right = 0.771 -anchor_bottom = 0.926 -offset_left = 0.0729828 -offset_top = -0.208008 -offset_right = -0.0730591 -offset_bottom = 9.72797 -grow_horizontal = 2 -theme_override_constants/separation = -15 - -[node name="Label" type="Label" parent="Notice/VBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 4 -theme_override_colors/font_color = Color(0.872047, 0.774098, 0.671572, 1) -theme_override_constants/outline_size = 7 -theme_override_fonts/font = ExtResource("4_lnh27") -theme_override_font_sizes/font_size = 32 -text = "a new version of Loggie is available for download." -horizontal_alignment = 1 - -[node name="HBoxContainer" type="HBoxContainer" parent="Notice/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 4 -alignment = 1 - -[node name="NoticeButtons" type="HBoxContainer" parent="Notice/VBoxContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 6 -theme_override_constants/separation = 51 - -[node name="ReleaseNotesBtn" type="Button" parent="Notice/VBoxContainer/HBoxContainer/NoticeButtons"] -unique_name_in_owner = true -visible = false -layout_mode = 2 -mouse_default_cursor_shape = 2 -theme_override_colors/font_disabled_color = Color(0.53, 0.475145, 0.3869, 1) -theme_override_colors/font_hover_pressed_color = Color(0.996078, 0.94902, 0.882353, 1) -theme_override_colors/font_hover_color = Color(0.98, 0.67571, 0.1862, 1) -theme_override_colors/font_pressed_color = Color(0.994326, 0.950716, 0.88154, 1) -theme_override_colors/font_focus_color = Color(0.996078, 0.94902, 0.882353, 1) -theme_override_colors/font_color = Color(0.980932, 0.843799, 0.621104, 1) -theme_override_colors/font_outline_color = Color(0, 0, 0, 1) -theme_override_constants/outline_size = 8 -theme_override_fonts/font = ExtResource("4_lnh27") -theme_override_font_sizes/font_size = 43 -theme_override_styles/focus = SubResource("StyleBoxFlat_3bh8r") -theme_override_styles/disabled_mirrored = SubResource("StyleBoxEmpty_rjg43") -theme_override_styles/disabled = SubResource("StyleBoxEmpty_bwgrr") -theme_override_styles/hover_pressed_mirrored = SubResource("StyleBoxEmpty_qbrxo") -theme_override_styles/hover_pressed = SubResource("StyleBoxEmpty_3asxb") -theme_override_styles/hover_mirrored = SubResource("StyleBoxEmpty_86pfv") -theme_override_styles/hover = SubResource("StyleBoxFlat_3bh8r") -theme_override_styles/pressed_mirrored = SubResource("StyleBoxEmpty_rw12e") -theme_override_styles/pressed = SubResource("StyleBoxEmpty_j1ttd") -theme_override_styles/normal_mirrored = SubResource("StyleBoxEmpty_3sc8x") -theme_override_styles/normal = SubResource("StyleBoxEmpty_ndum7") -text = "release notes" - -[node name="UpdateNowBtn" type="Button" parent="Notice/VBoxContainer/HBoxContainer/NoticeButtons"] -unique_name_in_owner = true -layout_mode = 2 -mouse_default_cursor_shape = 2 -theme_override_colors/font_disabled_color = Color(0.53, 0.475145, 0.3869, 1) -theme_override_colors/font_hover_pressed_color = Color(0.996078, 0.94902, 0.882353, 1) -theme_override_colors/font_hover_color = Color(0.98, 0.67571, 0.1862, 1) -theme_override_colors/font_pressed_color = Color(0.994326, 0.950716, 0.88154, 1) -theme_override_colors/font_focus_color = Color(0.996078, 0.94902, 0.882353, 1) -theme_override_colors/font_color = Color(0.980932, 0.843799, 0.621104, 1) -theme_override_colors/font_outline_color = Color(0, 0, 0, 1) -theme_override_constants/outline_size = 8 -theme_override_fonts/font = ExtResource("4_lnh27") -theme_override_font_sizes/font_size = 43 -theme_override_styles/focus = SubResource("StyleBoxFlat_3bh8r") -theme_override_styles/disabled_mirrored = SubResource("StyleBoxEmpty_rjg43") -theme_override_styles/disabled = SubResource("StyleBoxEmpty_bwgrr") -theme_override_styles/hover_pressed_mirrored = SubResource("StyleBoxEmpty_qbrxo") -theme_override_styles/hover_pressed = SubResource("StyleBoxEmpty_3asxb") -theme_override_styles/hover_mirrored = SubResource("StyleBoxEmpty_86pfv") -theme_override_styles/hover = SubResource("StyleBoxFlat_3bh8r") -theme_override_styles/pressed_mirrored = SubResource("StyleBoxEmpty_rw12e") -theme_override_styles/pressed = SubResource("StyleBoxEmpty_j1ttd") -theme_override_styles/normal_mirrored = SubResource("StyleBoxEmpty_3sc8x") -theme_override_styles/normal = SubResource("StyleBoxEmpty_ndum7") -text = "update now" - -[node name="RemindLaterBtn" type="Button" parent="Notice/VBoxContainer/HBoxContainer/NoticeButtons"] -unique_name_in_owner = true -layout_mode = 2 -mouse_default_cursor_shape = 2 -theme_override_colors/font_disabled_color = Color(0.53, 0.475145, 0.3869, 1) -theme_override_colors/font_hover_pressed_color = Color(0.996078, 0.94902, 0.882353, 1) -theme_override_colors/font_hover_color = Color(0.98, 0.67571, 0.1862, 1) -theme_override_colors/font_pressed_color = Color(0.994326, 0.950716, 0.88154, 1) -theme_override_colors/font_focus_color = Color(0.996078, 0.94902, 0.882353, 1) -theme_override_colors/font_color = Color(0.98, 0.49, 0.5635, 1) -theme_override_colors/font_outline_color = Color(0, 0, 0, 1) -theme_override_constants/outline_size = 8 -theme_override_fonts/font = ExtResource("4_lnh27") -theme_override_font_sizes/font_size = 43 -theme_override_styles/focus = SubResource("StyleBoxFlat_3bh8r") -theme_override_styles/disabled_mirrored = SubResource("StyleBoxEmpty_rjg43") -theme_override_styles/disabled = SubResource("StyleBoxEmpty_bwgrr") -theme_override_styles/hover_pressed_mirrored = SubResource("StyleBoxEmpty_qbrxo") -theme_override_styles/hover_pressed = SubResource("StyleBoxEmpty_3asxb") -theme_override_styles/hover_mirrored = SubResource("StyleBoxEmpty_86pfv") -theme_override_styles/hover = SubResource("StyleBoxFlat_3bh8r") -theme_override_styles/pressed_mirrored = SubResource("StyleBoxEmpty_rw12e") -theme_override_styles/pressed = SubResource("StyleBoxEmpty_j1ttd") -theme_override_styles/normal_mirrored = SubResource("StyleBoxEmpty_3sc8x") -theme_override_styles/normal = SubResource("StyleBoxEmpty_ndum7") -text = "remind later" - -[node name="DontShowAgainCheckbox" type="CheckBox" parent="Notice"] -unique_name_in_owner = true -layout_mode = 1 -anchors_preset = 1 -anchor_left = 1.0 -anchor_right = 1.0 -offset_left = -289.0 -offset_top = 9.0 -offset_right = -20.0 -offset_bottom = 62.0 -grow_horizontal = 0 -mouse_default_cursor_shape = 2 -theme_override_colors/font_hover_color = Color(0.490196, 0.701961, 0.501961, 1) -theme_override_colors/font_focus_color = Color(0.92549, 0.92549, 0.756863, 1) -theme_override_colors/font_color = Color(0.980932, 0.843799, 0.621104, 1) -theme_override_constants/outline_size = 7 -theme_override_fonts/font = ExtResource("4_lnh27") -theme_override_font_sizes/font_size = 27 -theme_override_styles/focus = ExtResource("5_avea8") -theme_override_icons/checked = ExtResource("6_yoxpw") -theme_override_icons/unchecked = ExtResource("7_xu2hn") -theme_override_icons/radio_checked = ExtResource("6_yoxpw") -theme_override_icons/radio_unchecked = ExtResource("7_xu2hn") -theme_override_icons/checked_disabled = ExtResource("8_4h2cx") -theme_override_icons/unchecked_disabled = ExtResource("9_51n7f") -theme_override_icons/radio_checked_disabled = ExtResource("8_4h2cx") -theme_override_icons/radio_unchecked_disabled = ExtResource("9_51n7f") -text = "do not show this again" - -[node name="UpdateMonitor" type="Control" parent="."] -visible = false -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_top = -673.0 -offset_bottom = -673.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="BackgroundUnder" type="TextureRect" parent="UpdateMonitor"] -modulate = Color(1, 1, 1, 0.811765) -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -texture = SubResource("GradientTexture1D_k1b6u") - -[node name="BackgroundOver" type="TextureRect" parent="UpdateMonitor"] -modulate = Color(1, 1, 1, 0.752941) -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -texture = SubResource("GradientTexture2D_p6ad4") - -[node name="ProgressBar" type="ProgressBar" parent="UpdateMonitor"] -unique_name_in_owner = true -layout_mode = 1 -anchors_preset = 7 -anchor_left = 0.5 -anchor_top = 1.0 -anchor_right = 0.5 -anchor_bottom = 1.0 -offset_left = -448.5 -offset_top = -224.0 -offset_right = 449.5 -offset_bottom = -160.0 -grow_horizontal = 2 -grow_vertical = 0 -theme_override_constants/outline_size = 19 -theme_override_fonts/font = ExtResource("3_a36jf") -theme_override_font_sizes/font_size = 31 -theme_override_styles/background = SubResource("StyleBoxFlat_y40yc") -theme_override_styles/fill = SubResource("StyleBoxFlat_h3ybw") - -[node name="LabelMainStatus" type="Label" parent="UpdateMonitor"] -unique_name_in_owner = true -layout_mode = 1 -anchors_preset = 8 -anchor_left = 0.5 -anchor_top = 0.5 -anchor_right = 0.5 -anchor_bottom = 0.5 -offset_left = -201.0 -offset_top = -13.0 -offset_right = 201.0 -offset_bottom = 63.0 -grow_horizontal = 2 -grow_vertical = 2 -theme_override_colors/font_color = Color(0.878431, 0.662745, 0.266667, 1) -theme_override_colors/font_shadow_color = Color(0, 0, 0, 1) -theme_override_colors/font_outline_color = Color(0, 0, 0, 1) -theme_override_constants/outline_size = 14 -theme_override_fonts/font = ExtResource("3_a36jf") -theme_override_font_sizes/font_size = 81 -text = "status" -horizontal_alignment = 1 - -[node name="LabelOldVersion" type="Label" parent="UpdateMonitor"] -unique_name_in_owner = true -layout_mode = 1 -anchors_preset = 8 -anchor_left = 0.5 -anchor_top = 0.5 -anchor_right = 0.5 -anchor_bottom = 0.5 -offset_left = -426.5 -offset_top = 77.0 -offset_right = -24.5 -offset_bottom = 153.0 -grow_horizontal = 2 -grow_vertical = 2 -theme_override_colors/font_color = Color(0.878431, 0.662745, 0.266667, 1) -theme_override_colors/font_shadow_color = Color(0, 0, 0, 1) -theme_override_colors/font_outline_color = Color(0, 0, 0, 1) -theme_override_constants/outline_size = 14 -theme_override_fonts/font = ExtResource("3_a36jf") -theme_override_font_sizes/font_size = 25 -text = "v_old" - -[node name="LabelNewVersion" type="Label" parent="UpdateMonitor"] -unique_name_in_owner = true -layout_mode = 1 -anchors_preset = 8 -anchor_left = 0.5 -anchor_top = 0.5 -anchor_right = 0.5 -anchor_bottom = 0.5 -offset_left = 33.5 -offset_top = 76.0 -offset_right = 435.5 -offset_bottom = 152.0 -grow_horizontal = 2 -grow_vertical = 2 -theme_override_colors/font_color = Color(0.878431, 0.662745, 0.266667, 1) -theme_override_colors/font_shadow_color = Color(0, 0, 0, 1) -theme_override_colors/font_outline_color = Color(0, 0, 0, 1) -theme_override_constants/outline_size = 14 -theme_override_fonts/font = ExtResource("3_a36jf") -theme_override_font_sizes/font_size = 25 -text = "V_NEW" -horizontal_alignment = 2 - -[node name="LoggieIcon" type="TextureRect" parent="UpdateMonitor"] -layout_mode = 1 -anchors_preset = 8 -anchor_left = 0.5 -anchor_top = 0.5 -anchor_right = 0.5 -anchor_bottom = 0.5 -offset_left = -79.5 -offset_top = -213.0 -offset_right = 80.5 -offset_bottom = -53.0 -grow_horizontal = 2 -grow_vertical = 2 -pivot_offset = Vector2(80, 84) -texture = ExtResource("10_abt8m") - -[node name="VBoxContainer" type="VBoxContainer" parent="UpdateMonitor"] -layout_mode = 1 -anchors_preset = 12 -anchor_top = 1.0 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_top = -140.0 -offset_bottom = 77.0002 -grow_horizontal = 2 -grow_vertical = 0 -theme_override_constants/separation = 5 - -[node name="OptionButtons" type="HBoxContainer" parent="UpdateMonitor/VBoxContainer"] -layout_mode = 2 -theme_override_constants/separation = 24 -alignment = 1 - -[node name="OptionRetryUpdateBtn" type="Button" parent="UpdateMonitor/VBoxContainer/OptionButtons"] -unique_name_in_owner = true -visible = false -custom_minimum_size = Vector2(100, 0) -layout_mode = 2 -mouse_default_cursor_shape = 2 -theme = ExtResource("11_5uxhl") -disabled = true -text = "Retry" - -[node name="OptionRestartGodotBtn" type="Button" parent="UpdateMonitor/VBoxContainer/OptionButtons"] -unique_name_in_owner = true -visible = false -custom_minimum_size = Vector2(100, 0) -layout_mode = 2 -mouse_default_cursor_shape = 2 -theme = ExtResource("11_5uxhl") -disabled = true -text = "Reload Godot" - -[node name="OptionExitBtn" type="Button" parent="UpdateMonitor/VBoxContainer/OptionButtons"] -unique_name_in_owner = true -visible = false -custom_minimum_size = Vector2(100, 0) -layout_mode = 2 -mouse_default_cursor_shape = 2 -theme = ExtResource("11_5uxhl") -theme_override_colors/font_color = Color(0.980919, 0.500031, 0.570874, 1) -theme_override_colors/font_outline_color = Color(0.224555, 0.120107, 0.0255992, 1) -theme_override_constants/outline_size = 8 -disabled = true -text = "Exit" - -[node name="LabelUpdateStatus" type="Label" parent="UpdateMonitor/VBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -theme = ExtResource("11_5uxhl") -theme_override_font_sizes/font_size = 20 -text = "UPDATE_STATUS_DETAILED" -horizontal_alignment = 1 -autowrap_mode = 2 - -[node name="AnimationPlayer" type="AnimationPlayer" parent="."] -unique_name_in_owner = true -root_node = NodePath("../UpdateMonitor") -libraries = { -"": SubResource("AnimationLibrary_lwiu5") -} diff --git a/bisect.gd b/bisect.gd index 2113fd4..c10e949 100644 --- a/bisect.gd +++ b/bisect.gd @@ -42,3 +42,45 @@ func bisect(a: Array, x, lo: int = 0, hi=null): func insort(a: Array, x, lo: int = 0, hi=null): return insort_right(a, x, lo, hi) + +func reverse_insort_right(a: Array, x, lo: int = 0, hi=null): + lo = reverse_bisect_right(a, x, lo, hi) + a.insert(lo, x) + +func reverse_bisect_right(a: Array, x, lo: int = 0, hi=null): + if lo < 0: + return + if hi == null: + hi = a.size() + var mid: int = 0 + while lo < hi: + mid = (lo + hi) / 2 + if -x < -a[mid]: + hi = mid + else: + lo = mid + 1 + return lo + +func reverse_insort_left(a: Array, x, lo:int = 0, hi=null): + lo = reverse_bisect_left(a, x, lo, hi) + a.insert(lo, x) + +func reverse_bisect_left(a: Array, x, lo:int = 0, hi=null): + if lo < 0: + return + if hi == null: + hi = a.size() + var mid: int = 0 + while lo < hi: + mid = (lo + hi) / 2 + if -a[mid] < -x: + lo = mid + 1 + else: + hi = mid + return lo + +func reverse_bisect(a: Array, x, lo: int = 0, hi=null): + return reverse_bisect_right(a, x, lo, hi) + +func reverse_insort(a: Array, x, lo: int = 0, hi=null): + return reverse_insort_right(a, x, lo, hi) diff --git a/data_recorder_node.gd b/data_recorder_node.gd new file mode 100644 index 0000000..de89b76 --- /dev/null +++ b/data_recorder_node.gd @@ -0,0 +1,95 @@ +extends Node +class_name DataRecorderNode + +var MAX_SENSOR_DATA_SIZE = 524288000 + +var cached_data = [] + +var thread: Thread +var mutex: Mutex +var exit_thread = false + +var timer = 0 +var timer_target = 15 + +var target_dir = "user://sensor_data/" + +# Called when the node enters the scene tree for the first time. +func _ready() -> void: + DataSignals.raw_data_received.connect(_on_raw_data_received) + thread = Thread.new() + mutex = Mutex.new() + thread.start(_thread_func) + DirAccess.make_dir_absolute(target_dir) + +func _exit_tree() -> void: + mutex.lock() + exit_thread = true + mutex.unlock() + thread.wait_to_finish() + +func _process(delta: float) -> void: + mutex.lock() + timer += delta + mutex.unlock() + +func _on_raw_data_received(source_ip: String, data_type: String, timestamp_list: Array, data_dict: Dictionary): + cached_data.append([source_ip, data_type, timestamp_list, data_dict]) + +func _thread_func(): + while true: + mutex.lock() + var should_exit = exit_thread + mutex.unlock() + if should_exit: + break + mutex.lock() + var should_write_data = (timer >= timer_target) + mutex.unlock() + if not should_write_data: + continue + mutex.lock() + timer = 0 + var data_copy = null + if cached_data.size() > 0: + data_copy = cached_data.duplicate(true) + cached_data.clear() + mutex.unlock() + if data_copy != null: + _write_data(data_copy) + _delete_old_data() + +func _write_data(data_to_write: Array): + var current_file_path = target_dir + str(Time.get_unix_time_from_system()) + "_sensor_data.csv" + var file = FileAccess.open(current_file_path, FileAccess.WRITE) + for data in data_to_write: + var line = str(data[0]) + ',' + str(data[1]) + ',' + for time_data in data[2]: + line += str(time_data) + ',' + for value in data[3]: + line += str(value) + ',' + file.store_line(line) + file.close() + +func _delete_old_data(): + var files: Array = [] + var dir = DirAccess.open(target_dir) + dir.list_dir_begin() + while true: + var file_name = dir.get_next() + if file_name == "": + break + elif file_name.begins_with("."): + continue + files.append(file_name) + dir.list_dir_end() + files.sort() + var cutoff_idx = 0 + var file_size_sum = 0 + for idx in range(files.size(), 0, -1): + file_size_sum += FileAccess.get_size(target_dir + files[idx-1]) + if file_size_sum >= MAX_SENSOR_DATA_SIZE: + cutoff_idx = idx + for i in range(cutoff_idx): + DirAccess.remove_absolute(target_dir+files[i]) + diff --git a/data_recorder_node.gd.uid b/data_recorder_node.gd.uid new file mode 100644 index 0000000..3942677 --- /dev/null +++ b/data_recorder_node.gd.uid @@ -0,0 +1 @@ +uid://cb0e5702tjrqc diff --git a/helpers/TimeHelpers.gd b/helpers/TimeHelpers.gd new file mode 100644 index 0000000..3197339 --- /dev/null +++ b/helpers/TimeHelpers.gd @@ -0,0 +1,31 @@ +extends Node + +var latest_sensor_timestamp: float = 0 +var sys_time_at_sensor_time: float = 0 + +func on_time_data_received(timestamp_list: Array): + latest_sensor_timestamp = 3600.*timestamp_list[0] + 60.*timestamp_list[1] + timestamp_list[2] + timestamp_list[3] + sys_time_at_sensor_time = utc_timestamp_24h() + +func get_current_sensor_time(): + var sys_time = utc_timestamp_24h() + var sys_time_diff = calc_time_diff_24h(sys_time_at_sensor_time, sys_time) + var sensor_time = latest_sensor_timestamp + sys_time_diff + if sensor_time >= 86400: + return sensor_time - 86400 + return sensor_time + +func calc_time_diff_24h(timestamp_1, timestamp_2): + if timestamp_2 < 3600 and timestamp_1 > 82800: + return (timestamp_2 + 86400) - timestamp_1 + return timestamp_2 - timestamp_1 + +func is_timestamp_newer_24h(old_timestamp: float, new_timestamp: float) -> bool: + if old_timestamp > 82800. and new_timestamp < 3600: # earlier than 23 hours + return true + return old_timestamp < new_timestamp + +func utc_timestamp_24h(): + var time_dict = Time.get_time_dict_from_system(true) + var unix_time = Time.get_unix_time_from_system() + return time_dict["hour"] * 3600 + time_dict["minute"] * 60 + time_dict["second"] + (unix_time - int(unix_time)) diff --git a/helpers/TimeHelpers.gd.uid b/helpers/TimeHelpers.gd.uid new file mode 100644 index 0000000..4d83f72 --- /dev/null +++ b/helpers/TimeHelpers.gd.uid @@ -0,0 +1 @@ +uid://dqtc81pc74lcr diff --git a/networking/scripts/udp_broadcast.gd b/networking/scripts/udp_broadcast.gd index a7b9b00..3790cc1 100644 --- a/networking/scripts/udp_broadcast.gd +++ b/networking/scripts/udp_broadcast.gd @@ -5,30 +5,73 @@ extends Node var udp = PacketPeerUDP.new() var connected = false -var fast_broadcast_rate = 1.0 +var fast_broadcast_rate = 0.5 var slow_broadcast_rate = 10.0 var current_broadcast_rate = fast_broadcast_rate var last_broadcast = 0 var ip_address: String = "" +var thread: Thread +var mutex: Mutex +var signal_queue = [] +var exit_thread = false +var use_thread = true + func _ready(): _try_set_ip() udp.set_broadcast_enabled(true) udp.set_dest_address("192.168.0.255", 5000) SensorSignals.new_sensor_connected.connect(_on_sensor_connected) + + use_thread = OS.get_processor_count() > 1 + mutex = Mutex.new() + if use_thread: + thread = Thread.new() + print('Starting UDP Broadcast thread') + thread.start(_thread_function) + else: + print('UDP server running in single threaded mode') -func _process(delta): +func _process(delta: float) -> void: + mutex.lock() + last_broadcast += delta + mutex.unlock() + if not use_thread: + _process_broadcast() + +func _exit_tree() -> void: + if use_thread: + mutex.lock() + exit_thread = true + mutex.unlock() + thread.wait_to_finish() + +func _thread_function(): + print('UDP Broadcast thread started') + while true: + mutex.lock() + var should_exit = exit_thread + mutex.unlock() + if should_exit: + break + mutex.lock() + var do_broadcast = last_broadcast >= current_broadcast_rate + mutex.unlock() + if do_broadcast: + mutex.lock() + last_broadcast = 0 + mutex.unlock() + _process_broadcast() + +func _process_broadcast(): if ip_address.length() == 0: _try_set_ip() return - last_broadcast += delta - if last_broadcast >= current_broadcast_rate: # Try to contact server - last_broadcast = 0 - var broadcast_str = ip_address + "|%s" % Time.get_datetime_string_from_system(true) - print('Broadcasting to UDP: ', broadcast_str) - udp.put_packet(broadcast_str.to_utf8_buffer()) + var broadcast_str = ip_address + "|%s" % Time.get_datetime_string_from_system(true) + print('Broadcasting to UDP: ', broadcast_str) + udp.put_packet(broadcast_str.to_utf8_buffer()) func _try_set_ip(): for address in IP.get_local_addresses(): diff --git a/networking/scripts/udp_server.gd b/networking/scripts/udp_server.gd index 08617e5..960a2e3 100644 --- a/networking/scripts/udp_server.gd +++ b/networking/scripts/udp_server.gd @@ -12,6 +12,13 @@ var awaiting_sensors = {} var invalid_sensors = {} var valid_sensors = {} +var use_thread: bool = false +var thread: Thread +var mutex: Mutex +var exit_thread = true + +var signal_queue = [] + func _ready(): ServerSignals.sensor_approved.connect(_on_sensor_approved) ServerSignals.sensor_declined.connect(_on_sensor_declined) @@ -19,33 +26,75 @@ func _ready(): if not server.is_listening(): print('Unable to listen on port: ', port) print('Listening on port: ', port) + + mutex = Mutex.new() + if use_thread: + thread = Thread.new() + print('Starting UDP Server thread') + thread.start(_thread_function) + else: + print('UDP server running in single threaded mode') + +func _process(delta: float) -> void: + if not use_thread: + _process_connections() + while signal_queue.size() > 0: + mutex.lock() + var signal_data = signal_queue.pop_front() + mutex.unlock() + if signal_data[0] == "new_sensor_connected": + SensorSignals.new_sensor_connected.emit(signal_data[1], signal_data[2]) + elif signal_data[0] == "sensor_request_received": + ServerSignals.sensor_request_received.emit(signal_data[1], signal_data[2]) + elif signal_data[0] == "on_time_data_received": + TimeHelpers.on_time_data_received(signal_data[1]) + elif signal_data[0] == "raw_data_received": + DataSignals.raw_data_received.emit(signal_data[1], signal_data[2], signal_data[3], signal_data[4]) + +func _exit_tree() -> void: + if use_thread: + mutex.lock() + exit_thread = true + mutex.unlock() + thread.wait_to_finish() func _on_sensor_approved(sensor_ip: String): + mutex.lock() valid_sensors[sensor_ip] = awaiting_sensors[sensor_ip] if sensor_ip in awaiting_sensors: awaiting_sensors.erase(sensor_ip) - SensorSignals.new_sensor_connected.emit(sensor_ip, valid_sensors[sensor_ip]) + signal_queue.append(["new_sensor_connected", sensor_ip, valid_sensors[sensor_ip]]) + mutex.unlock() func _on_sensor_declined(sensor_ip: String): + mutex.lock() invalid_sensors[sensor_ip] = 0 if sensor_ip in awaiting_sensors: awaiting_sensors.erase(sensor_ip) + mutex.unlock() -func _process(delta): - _process_connections(delta) +func _thread_function(): + print('UDP Server thread started') + while true: + mutex.lock() + var should_exit = exit_thread + mutex.unlock() + if should_exit: + break + _process_connections() -func _process_connections(delta): +func _process_connections(): server.poll() if server.is_connection_available(): var peer = server.take_connection() var packet = peer.get_packet() if not _verify_checksum(packet): print('Received packet with incorrect checksum: %s' % peer.get_packet_ip()) - _handle_six_fps_message(peer, packet) else: - _handle_new_connection(delta, peer, packet) + + _handle_new_connection(peer, packet) -func _handle_new_connection(delta: float, peer: PacketPeerUDP, packet: PackedByteArray): +func _handle_new_connection(peer: PacketPeerUDP, packet: PackedByteArray): if packet.get(0) == 0xD4 and packet.get(1) == 0x53: """ | 2 bytes | 2 bytes | 2 bytes | variable length | 2 bytes | @@ -66,14 +115,9 @@ func _handle_new_connection(delta: float, peer: PacketPeerUDP, packet: PackedByt packet[packet.size()-1] = ck_b """ _handle_six_fps_message(peer, packet) - elif packet.get(0) == 0xb5 and packet.get(1) == 0x62: - _handle_racebox_message(delta, packet) else: print("Received: '%s' %s:%s" % [packet.get_string_from_utf8(), peer.get_packet_ip(), peer.get_packet_port()]) - for i in range(0, valid_sensors.size()): - pass # Do something with the connected peers. - func _calculate_checksum(packet) -> Array: var ck_a = 0 var ck_b = 0 @@ -92,7 +136,9 @@ func _handle_six_fps_message(peer: PacketPeerUDP, packet: PackedByteArray): return if peer_ip in awaiting_sensors: return + mutex.lock() var valid_sensor: bool = peer.get_packet_ip() in valid_sensors + mutex.unlock() var message_class = packet.get(2) var message_id = packet.get(3) if (not valid_sensor) and (message_class == 0x6e and message_id == 0x77): @@ -115,6 +161,8 @@ func _handle_six_fps_message(peer: PacketPeerUDP, packet: PackedByteArray): elif message_class == 0x2a and message_id == 0x39: #print('Mag packet received') _handle_magnetic_packet(peer_ip, packet) + elif message_class == 0x2a and message_id == 0x6f: + _handle_lidar_2d_packet(peer_ip, packet) elif message_class == 0x2a and message_id == 0xa7: _handle_public_key_packet(peer_ip, packet) elif message_class == 0x2a and message_id == 0x5e: # not in use @@ -133,55 +181,62 @@ func _handle_new_peer_request(peer_ip: String, packet: PackedByteArray): 9 | 1 byte | bool | peer provides euler orientation 10 | 1 byte | bool | peer provides quaternion orientation """ - awaiting_sensors[peer_ip] = [ - #packet.decode_u8(4), - packet.decode_u8(5), - packet.decode_u8(6), - packet.decode_u8(7), - packet.decode_u8(8), - #packet.decode_u8(9), - #packet.decode_u8(10), - ] - print('sensor request') - ServerSignals.sensor_request_received.emit(peer_ip, awaiting_sensors[peer_ip]) + mutex.lock() + if packet.get(4) == 0xf1: + awaiting_sensors[peer_ip] = "VEHICLE" + elif packet.get(4) == 0x23: + awaiting_sensors[peer_ip] = "LIDAR_2D" + signal_queue.append(["sensor_request_received", peer_ip, awaiting_sensors[peer_ip]]) + mutex.unlock() func _parse_timestamp_slice(packet: PackedByteArray): - var hour = packet.decode_u8(0) - var minute = packet.decode_u8(1) - var second = packet.decode_u8(2) - var nanosecond = packet.decode_u32(3) * pow(10,-9) + var hour = float(packet.decode_u8(0)) + var minute = float(packet.decode_u8(1)) + var second = float(packet.decode_u8(2)) + var nanosecond = float(packet.decode_u32(3)) * pow(10,-9) return [hour, minute, second, nanosecond] func _handle_heartbeat_packet(peer_ip: String, packet: PackedByteArray): #print('heartbeat') - var hour = packet.decode_u8(4) - var minute = packet.decode_u8(5) - var second = packet.decode_u8(6) + var timestamp_list = _parse_timestamp_slice(packet.slice(4, 11)) + mutex.lock() + signal_queue.append(["on_time_data_received", timestamp_list]) + mutex.unlock() #print(hour, ' ', minute, ' ', second) func _handle_time_packet(peer_ip: String, packet: PackedByteArray): #print('time') var timestamp_list = _parse_timestamp_slice(packet.slice(4, 11)) + mutex.lock() + signal_queue.append(["on_time_data_received", timestamp_list]) + mutex.unlock() #print(timestamp_list) func _handle_position_packet(peer_ip: String, packet: PackedByteArray): #print('gps') var timestamp_list = _parse_timestamp_slice(packet.slice(4, 11)) - var lat: float = (float(packet.decode_u64(11)) / 10.**9) - 90 - var lon: float = (float(packet.decode_u64(19)) / 10.**9) - 180 - var alt_neg = packet.decode_u8(27) - var alt_m: float = packet.decode_u32(28) / 1000.0 * (-1. ** alt_neg) - var geoid_neg = packet.decode_u8(32) - var goid_m: float = packet.decode_u16(33) / 100 * (-1. ** geoid_neg) - var speed_neg = packet.decode_u8(35) - var speed_kmh: float = packet.decode_u32(36) / 1000000.0 * (-1 ** speed_neg) - var pdop: float = packet.decode_u32(40) / 1000.0 - var hdop: float = packet.decode_u32(44) / 1000.0 - var vdop: float = packet.decode_u32(49) / 1000.0 - DataSignals.pnt_data_received.emit(peer_ip, timestamp_list, [lat, lon, alt_m, goid_m], speed_kmh, [pdop, hdop, vdop]) + mutex.lock() + signal_queue.append(["on_time_data_received", timestamp_list]) + mutex.unlock() + var data = [ + packet.decode_u64(11), + packet.decode_u64(19), + packet.decode_u32(28) * (-1. ** packet.decode_u8(27)), + packet.decode_u16(33)* (-1. ** packet.decode_u8(32)), + packet.decode_u32(36) * (-1 ** packet.decode_u8(35)), + packet.decode_u32(40), + packet.decode_u32(44), + packet.decode_u32(49) + ] + mutex.lock() + signal_queue.append(["raw_data_received", peer_ip, "GPS", timestamp_list, data]) + mutex.unlock() func _handle_gps_sats_packet(peer_ip: String, packet: PackedByteArray): var timestamp_list = _parse_timestamp_slice(packet.slice(4, 11)) + mutex.lock() + signal_queue.append(["on_time_data_received", timestamp_list]) + mutex.unlock() var ga = packet.decode_u8(11) var gb = packet.decode_u8(12) var gi = packet.decode_u8(13) @@ -194,59 +249,104 @@ func _handle_gps_sats_packet(peer_ip: String, packet: PackedByteArray): var el_offset = 4 var az_offset = 5 var sat_data = [] + var data = [ga, gb, gi, gl, gp, gq, gn] for i in range(num_entries): var start_offset = sats_offset + (i * 7) var sat_name = packet.slice(start_offset, start_offset + el_offset).get_string_from_ascii() var elevation = packet.decode_u8(start_offset+el_offset) var azimuth = packet.decode_u16(start_offset+az_offset) - sat_data.append([sat_name, elevation, azimuth]) - DataSignals.sat_data_received.emit(peer_ip, timestamp_list, [ga, gb, gi, gl, gp, gq, gn], sat_data) + data.append(sat_name) + data.append(elevation) + data.append(azimuth) + mutex.lock() + signal_queue.append(["raw_data_received", peer_ip, "SATS", timestamp_list, data]) + mutex.unlock() func _handle_accel_packet(peer_ip: String, packet: PackedByteArray): var timestamp_list = _parse_timestamp_slice(packet.slice(4, 11)) + mutex.lock() + signal_queue.append(["on_time_data_received", timestamp_list]) + mutex.unlock() var neg = packet.decode_u8(11) - var x = (packet.decode_s32(12) / 1000000.0) * (-1 ** neg) + var x = packet.decode_s32(12) * (-1 ** neg) neg = packet.decode_u8(16) - var y = (packet.decode_s32(17) / 1000000.0) * (-1 ** neg) + var y = packet.decode_s32(17) * (-1 ** neg) neg = packet.decode_u8(21) - var z = (packet.decode_s32(22) / 1000000.0) * (-1 ** neg) + var z = packet.decode_s32(22) * (-1 ** neg) neg = packet.decode_u8(26) - var lin_x = (packet.decode_s32(27) / 1000000.0) * (-1 ** neg) + var lin_x = packet.decode_s32(27) * (-1 ** neg) neg = packet.decode_u8(31) - var lin_y = (packet.decode_s32(32) / 1000000.0) * (-1 ** neg) + var lin_y = packet.decode_s32(32) * (-1 ** neg) neg = packet.decode_u8(36) - var lin_z = (packet.decode_s32(37) / 1000000.0) * (-1 ** neg) + var lin_z = packet.decode_s32(37) * (-1 ** neg) neg = packet.decode_u8(41) - var g_x = (packet.decode_s32(42) / 1000000.0) * (-1 ** neg) + var g_x = packet.decode_s32(42) * (-1 ** neg) neg = packet.decode_u8(46) - var g_y = (packet.decode_s32(47) / 1000000.0) * (-1 ** neg) + var g_y = packet.decode_s32(47) * (-1 ** neg) neg = packet.decode_u8(51) - var g_z = (packet.decode_s32(52) / 1000000.0) * (-1 ** neg) + var g_z = packet.decode_s32(52) * (-1 ** neg) - DataSignals.accelerometer_data_received.emit(peer_ip, timestamp_list, [x, y, z], [lin_x, lin_y, lin_z], [g_x, g_y, g_z]) + var data = [ + x, y, z, + lin_x, lin_y, lin_z, + g_x, g_y, g_z + ] + + mutex.lock() + signal_queue.append(["raw_data_received", peer_ip, "ACCEL", timestamp_list, data]) + mutex.unlock() func _handle_magnetic_packet(peer_ip: String, packet: PackedByteArray): var timestamp_list = _parse_timestamp_slice(packet.slice(4, 11)) + mutex.lock() + signal_queue.append(["on_time_data_received", timestamp_list]) + mutex.unlock() var neg = packet.decode_u8(11) var x = (packet.decode_u32(12) / 1000.0) * (-1 ** neg) neg = packet.decode_u8(16) var y = (packet.decode_u32(17) / 1000.0) * (-1 ** neg) neg = packet.decode_u8(21) var z = (packet.decode_u32(22) / 1000.0) * (-1 ** neg) - DataSignals.magnetometer_data_received.emit(peer_ip, timestamp_list, [x, y, z]) - + mutex.lock() + signal_queue.append(["magnetometer_data_received", peer_ip, timestamp_list, Vector3(x, y, z)]) + mutex.unlock() + +func _handle_lidar_2d_packet(peer_ip: String, packet: PackedByteArray): + var timestamp_list = _parse_timestamp_slice(packet.slice(4, 11)) + mutex.lock() + signal_queue.append(["on_time_data_received", timestamp_list]) + mutex.unlock() + var point_count = packet.decode_u8(11) + var point_data = [] + for idx in range(point_count): + var offset = idx * 7 + var angle: float = float(packet.decode_u32(12 + offset)) / 10000 + var distance: float = float(packet.decode_u16(12 + offset + 4)) / 1000 + var intensity: int = packet.decode_u8(12 + offset + 6) + point_data.append([angle, distance, intensity]) + signal_queue.append(["lidar_2d_data_received", peer_ip, timestamp_list, point_count, point_data]) + func _handle_public_key_packet(peer_ip: String, packet: PackedByteArray): var timestamp_list = _parse_timestamp_slice(packet.slice(4, 11)) + mutex.lock() + signal_queue.append(["on_time_data_received", timestamp_list]) + mutex.unlock() func _handle_euler_packet(peer_ip: String, packet: PackedByteArray): var timestamp_list = _parse_timestamp_slice(packet.slice(4, 11)) + mutex.lock() + signal_queue.append(["on_time_data_received", timestamp_list]) + mutex.unlock() func _handle_quaternion_packet(peer_ip: String, packet: PackedByteArray): var timestamp_list = _parse_timestamp_slice(packet.slice(4, 11)) + mutex.lock() + signal_queue.append(["on_time_data_received", timestamp_list]) + mutex.unlock() func _handle_racebox_message(delta, packet): diff --git a/project.godot b/project.godot index 56897aa..4cfb994 100644 --- a/project.godot +++ b/project.godot @@ -26,17 +26,17 @@ SensorSignals="*uid://b2pc7sfvudvig" SettingSignals="*uid://csng7b51505w0" DisplayData="*uid://xunxbytiofa2" Bisect="*uid://crwgaltrjx4ff" -Loggie="*uid://bmh2auo806k0k" -LoggieConsoleAutoload="*uid://d0sxs0is80byx" +TimeHelpers="*uid://dqtc81pc74lcr" + +[debug] + +file_logging/enable_file_logging=true [display] window/size/viewport_width=800 window/size/viewport_height=800 - -[editor_plugins] - -enabled=PackedStringArray("res://addons/loggie-console/plugin.cfg", "res://addons/loggie/plugin.cfg") +window/size/mode=4 [physics] @@ -45,3 +45,4 @@ enabled=PackedStringArray("res://addons/loggie-console/plugin.cfg", "res://addon [rendering] rendering_device/driver.windows="d3d12" +renderer/rendering_method="mobile" diff --git a/sensor_approval/SensorApproval.tscn b/sensor_approval/SensorApproval.tscn index 2b8b251..c7b641f 100644 --- a/sensor_approval/SensorApproval.tscn +++ b/sensor_approval/SensorApproval.tscn @@ -19,6 +19,7 @@ layout_mode = 2 [node name="Label" type="Label" parent="HBoxContainer" unique_id=1098572929] layout_mode = 2 +theme_override_font_sizes/font_size = 32 text = "127.0.0.1" [node name="Control" type="Control" parent="HBoxContainer" unique_id=1047175521] @@ -28,6 +29,7 @@ layout_mode = 2 [node name="Approve" type="Button" parent="HBoxContainer" unique_id=2039550355] layout_mode = 2 mouse_filter = 1 +theme_override_font_sizes/font_size = 32 text = "Approve" [node name="Control2" type="Control" parent="HBoxContainer" unique_id=225178386] @@ -37,6 +39,7 @@ layout_mode = 2 [node name="Decline" type="Button" parent="HBoxContainer" unique_id=1630362833] layout_mode = 2 mouse_filter = 1 +theme_override_font_sizes/font_size = 32 text = "Decline" [connection signal="pressed" from="HBoxContainer/Approve" to="." method="_on_approve_pressed"] diff --git a/sensor_approval/SensorApprovalController.gd b/sensor_approval/SensorApprovalController.gd index 4db07ea..5b60a82 100644 --- a/sensor_approval/SensorApprovalController.gd +++ b/sensor_approval/SensorApprovalController.gd @@ -32,9 +32,9 @@ func _on_settings_closed(): add_child(sensor_approval_nodes[val]) _update_container_position() -func _on_sensor_request_received(sensor_ip: String, data_provided: Array): +func _on_sensor_request_received(sensor_ip: String, sensor_class: String): sensor_approval_nodes[sensor_ip] = sensor_approval_scene.instantiate() - sensor_approval_nodes[sensor_ip].set_provided_data(sensor_ip, data_provided) + sensor_approval_nodes[sensor_ip].set_provided_data(sensor_ip, sensor_class) if not settings_open: add_child(sensor_approval_nodes[sensor_ip]) _update_container_position() diff --git a/sensor_approval/data_column.tscn b/sensor_approval/data_column.tscn index 27981ad..11a1f81 100644 --- a/sensor_approval/data_column.tscn +++ b/sensor_approval/data_column.tscn @@ -6,8 +6,10 @@ offset_bottom = 50.0 [node name="DataLabel" type="Label" parent="." unique_id=1663588703] layout_mode = 2 +theme_override_font_sizes/font_size = 16 horizontal_alignment = 1 [node name="DataValue" type="Label" parent="." unique_id=1789333906] layout_mode = 2 +theme_override_font_sizes/font_size = 16 horizontal_alignment = 1 diff --git a/sensor_approval/provided_data.gd b/sensor_approval/provided_data.gd index 1f1e7d1..730aff9 100644 --- a/sensor_approval/provided_data.gd +++ b/sensor_approval/provided_data.gd @@ -11,9 +11,10 @@ offset | size | type | description 9 | 1 byte | bool | peer provides euler orientation 10 | 1 byte | bool | peer provides quaternion orientation """ -var data_labels = ["Date Time", "PNT", "Accel", "Gyro", "Magnet", "Euler", "Quat"] +var data_labels = ["Date Time", "PNT", "Accel", "Gyro", "Magnet", "Euler", "Quat", "2D Lidar"] -var provided_data: Array = [0, 0, 0, 0, 0, 0, 0] +var sensor_class: String = '' +var provided_data: Array = [0, 0, 0, 0, 0, 0, 0, 0] var data_columns: Array @export var data_column_scene: PackedScene @@ -35,5 +36,9 @@ func _setup_data_columns(): func _process(delta: float) -> void: pass -func set_provided_data(incoming_provided_data): - provided_data = incoming_provided_data +func set_provided_data(incoming_sensor_class: String): + sensor_class = incoming_sensor_class.capitalize() + if incoming_sensor_class == "VEHICLE": + provided_data = [0, 1, 1, 1, 1, 0, 0, 0] + elif incoming_sensor_class == "LIDAR_2D": + provided_data = [0, 1, 1, 1, 0, 0, 0, 1] diff --git a/sensor_approval/sensor_approval.gd b/sensor_approval/sensor_approval.gd index df23497..841b59f 100644 --- a/sensor_approval/sensor_approval.gd +++ b/sensor_approval/sensor_approval.gd @@ -5,7 +5,7 @@ var ip_label: Label var data_instance: Node var sensor_ip: String = "127.0.0.1" -var data_labels = ["PNT", "Accel", "Gyro", "Magnet"] +var data_labels = ["PNT", "Accel", "Gyro", "Magnet", "2D Lidar"] var provided_data: Array = [0, 0, 0, 0] var data_columns: Array @@ -14,7 +14,7 @@ var data_columns: Array func _setup_data_columns(): - var container = get_node('HBoxContainer') + var container: HBoxContainer = get_node('HBoxContainer') for i in range(provided_data.size()): var spacer: Control = container.add_spacer(false) spacer.size = Vector2(2, 0) @@ -27,11 +27,14 @@ func _setup_data_columns(): column_instance.get_node('DataValue').text = "True" container.add_child(column_instance) -func set_provided_data(incoming_sensor_ip: String, incoming_provided_data: Array): +func set_provided_data(incoming_sensor_ip: String, sensor_class: String): sensor_ip = incoming_sensor_ip ip_label = get_node('HBoxContainer/Label') ip_label.text = sensor_ip - provided_data = incoming_provided_data + if sensor_class == "VEHICLE": + provided_data = [1, 1, 1, 1, 0] + elif sensor_class == "LIDAR_2D": + provided_data = [1, 1, 1, 0, 1] if data_columns.size() == 0: _setup_data_columns() else: diff --git a/sensors/accelerometer_sensor_node.gd b/sensors/accelerometer_sensor_node.gd deleted file mode 100644 index c6b9f46..0000000 --- a/sensors/accelerometer_sensor_node.gd +++ /dev/null @@ -1,30 +0,0 @@ -extends BaseSensorNode -class_name AccelSensorNode - - -var accel_vector: Vector3 = Vector3.ZERO -var linear_accel_vector: Vector3 = Vector3.ZERO -var g_accel_vector: Vector3 = Vector3.ZERO - -var DOWN = Vector2(0, -1.) - - -# Called when the node enters the scene tree for the first time. -func _ready() -> void: - super._ready() - DataSignals.accelerometer_data_received.connect(_on_data_received) - -func _on_data_received(source_ip: String, timestamp_list: Array, accel: Array, linear_accel: Array, g_accel: Array): - if source_ip != ip_address: - return - var msg_timestamp = timestamp_list[0] * 3600 + timestamp_list[1] * 60 + timestamp_list[2] + timestamp_list[3] - if not Constants.is_timestamp_newer(timestamp, msg_timestamp): - return - timestamp = msg_timestamp - Signals.linear_acceleration_updated.emit(ip_address, linear_accel) - var x_z = Vector2(g_accel[0], g_accel[2]).normalized() - var y_z = Vector2(g_accel[1], g_accel[2]).normalized() - var pitch = DOWN.angle_to(x_z) - var roll = y_z.angle_to(DOWN) - SensorSignals.pitch_updated.emit(ip_address, pitch) - SensorSignals.roll_updated.emit(ip_address, roll) diff --git a/sensors/accelerometer_sensor_node.gd.uid b/sensors/accelerometer_sensor_node.gd.uid deleted file mode 100644 index 7de80d4..0000000 --- a/sensors/accelerometer_sensor_node.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b8tbp8y3ic2hi diff --git a/sensors/base_sensor_node.gd b/sensors/base_sensor_node.gd index 9f44a98..72ba8d0 100644 --- a/sensors/base_sensor_node.gd +++ b/sensors/base_sensor_node.gd @@ -5,7 +5,15 @@ var max_measurement_size: float = 10 @export var ip_address: String var id: String = UUID.new().as_string() -var timestamp: float = 0. +var max_measurement_history_s: float = 10. +var latest_timestamp: float = 0. + +var sensor_class: String: + get: + return _get_sensor_class() func _ready() -> void: pass + +func _get_sensor_class(): + return null diff --git a/sensors/lidar_2d_sensor_node.gd b/sensors/lidar_2d_sensor_node.gd new file mode 100644 index 0000000..af4781e --- /dev/null +++ b/sensors/lidar_2d_sensor_node.gd @@ -0,0 +1,30 @@ +extends BaseSensorNode +class_name Lidar2DSensorNode + + +# Called when the node enters the scene tree for the first time. +func _ready() -> void: + super._ready() + DataSignals.lidar_2d_data_received.connect(_on_lidar_data_received) + DataSignals.gps_data_received.connect(_on_gps_data_received) + DataSignals.accelerometer_data_received.connect(_on_accel_data_received) + DataSignals.gyroscope_data_received.connect(_on_gyro_data_received) + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +func _process(delta: float) -> void: + pass + +func _get_sensor_class(): + return "LIDAR_2D" + +func _on_lidar_data_received(sensor_ip: String, timestamp_list: Array, lidar_point_count: int, lidar_data: Array):pass + +func _on_gps_data_received(source_ip: String, timestamp_list: Array, new_coordinates: Array, speed_kmh: float, dop: Array): + pass + +func _on_accel_data_received(source_ip: String, timestamp_list: Array, accel: Vector3, linear_accel: Vector3, g_accel: Vector3): + pass + +func _on_gyro_data_received(source_ip: String, timestamp_list: Array, gyro_data: Array): + pass diff --git a/sensors/lidar_2d_sensor_node.gd.uid b/sensors/lidar_2d_sensor_node.gd.uid new file mode 100644 index 0000000..b346419 --- /dev/null +++ b/sensors/lidar_2d_sensor_node.gd.uid @@ -0,0 +1 @@ +uid://c00jgww14wp8w diff --git a/sensors/magnetometer_sensor_node.gd b/sensors/magnetometer_sensor_node.gd deleted file mode 100644 index 193dac6..0000000 --- a/sensors/magnetometer_sensor_node.gd +++ /dev/null @@ -1,24 +0,0 @@ -extends BaseSensorNode -class_name MagnetSensorNode - - -var heading_rad: float = 0 - - -# Called when the node enters the scene tree for the first time. -func _ready() -> void: - super._ready() - DataSignals.magnetometer_data_received.connect(_on_data_received) - -func _on_data_received(source_ip: String, timestamp_list: Array, mag_vec: Array): - if source_ip != ip_address: - return - var msg_timestamp = timestamp_list[0] * 3600 + timestamp_list[1] * 60 + timestamp_list[2] + timestamp_list[3] - if not Constants.is_timestamp_newer(timestamp, msg_timestamp): - return - timestamp = msg_timestamp - var mag = Vector2(mag_vec[0], mag_vec[1]) - mag.normalized() - heading_rad = atan2(-mag[1], mag[0]) - Signals.sensor_mag_updated.emit(ip_address) - Signals.heading_updated.emit(ip_address, heading_rad) diff --git a/sensors/magnetometer_sensor_node.gd.uid b/sensors/magnetometer_sensor_node.gd.uid deleted file mode 100644 index 055f6b4..0000000 --- a/sensors/magnetometer_sensor_node.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://gwr7babnfojp diff --git a/sensors/pnt_sensor_node.gd b/sensors/pnt_sensor_node.gd deleted file mode 100644 index 8e6d77f..0000000 --- a/sensors/pnt_sensor_node.gd +++ /dev/null @@ -1,56 +0,0 @@ -extends BaseSensorNode -class_name PntSensorNode - - -var lat_rad: float = 0. -var lon_rad: float = 0. -var alt_km: float = 0. -var speed_kmh: float = 0. -var gps_position = Vector3(1., 1., 1.) -var speed_data: Array = [] -var lat_data: Array = [] -var lon_data: Array = [] -var alt_data: Array = [] -var position_data: Array = [] -var measurement_times: Array = [] - - -# Called when the node enters the scene tree for the first time. -func _ready() -> void: - super._ready() - DataSignals.pnt_data_received.connect(_on_data_received) - -func _on_data_received(source_ip: String, timestamp_list: Array, coordinates: Array, pnt_speed_kmh: float, dop: Array): - if source_ip != ip_address: - return - var msg_timestamp = timestamp_list[0] * 3600. + timestamp_list[1] * 60. + timestamp_list[2] + timestamp_list[3] - var insert_idx = Bisect.bisect(measurement_times, msg_timestamp) - measurement_times.insert(insert_idx, msg_timestamp) - - speed_kmh = pnt_speed_kmh - speed_data.insert(insert_idx, speed_data) - lat_rad = deg_to_rad(coordinates[0]) - lat_data.insert(insert_idx, lat_rad) - lon_rad = deg_to_rad(coordinates[1]) - lon_data.insert(insert_idx, lon_rad) - alt_km = (coordinates[2] + coordinates[3]) / 1000 - alt_data.insert(insert_idx, alt_km) - var radius_km = (coordinates[2] + coordinates[3] + Constants.EARTH_RADIUS_M) / 1000. - var pos_x = radius_km * sin(lon_rad) * cos(lat_rad) - var pos_z = radius_km * sin(lon_rad) * sin(lat_rad) - var pos_y = radius_km * cos(lon_rad) - gps_position = Vector3(pos_x, pos_y, pos_z) - position_data.insert(insert_idx, gps_position) - - Signals.sensor_pnt_updated.emit(ip_address, self) - Signals.altitude_updated.emit(ip_address, alt_km) - Signals.position_updated.emit(ip_address, gps_position) - SensorSignals.speed_updated.emit(ip_address, speed_kmh) - - while measurement_times.size() > max_measurement_size: - measurement_times.pop_back() - speed_data.pop_back() - lat_data.pop_back() - lon_data.pop_back() - alt_data.pop_back() - position_data.pop_back() diff --git a/sensors/pnt_sensor_node.gd.uid b/sensors/pnt_sensor_node.gd.uid deleted file mode 100644 index c9322ca..0000000 --- a/sensors/pnt_sensor_node.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ddxquur7spfsf diff --git a/sensors/satelites_sensor_node.gd b/sensors/satelites_sensor_node.gd index d9db9ab..beb79b7 100644 --- a/sensors/satelites_sensor_node.gd +++ b/sensors/satelites_sensor_node.gd @@ -11,9 +11,9 @@ func _on_data_received(source_ip: String, timestamp_list: Array, sat_counts: Arr if source_ip != ip_address: return var msg_timestamp = timestamp_list[0] * 3600 + timestamp_list[1] * 60 + timestamp_list[2] + timestamp_list[3] - if not Constants.is_timestamp_newer(timestamp, msg_timestamp): + if not Constants.is_timestamp_newer(latest_timestamp, msg_timestamp): return - timestamp = msg_timestamp + latest_timestamp = msg_timestamp var sat_ids = [] for sat_data in sat_positions: sat_ids.append(sat_data[0]) diff --git a/sensors/sensor_spawner.gd b/sensors/sensor_spawner.gd index 06d3230..e54911d 100644 --- a/sensors/sensor_spawner.gd +++ b/sensors/sensor_spawner.gd @@ -1,7 +1,6 @@ extends Node3D class_name SensorSpawner -@export var sensor_scene: PackedScene var vehicle: VehicleNode # Called when the node enters the scene tree for the first time. @@ -9,22 +8,14 @@ func _ready() -> void: vehicle = get_parent() SensorSignals.new_sensor_connected.connect(_on_new_sensor_connected) -func _on_new_sensor_connected(sensor_ip: String, provider_data: Array) -> void: - var sensor_suite = sensor_scene.instantiate() - sensor_suite.ip_address = sensor_ip - vehicle.sensor_suites[sensor_ip] = sensor_suite - if provider_data[0]: - sensor_suite.provides_pnt = true - sensor_suite.create_pnt() - sensor_suite.create_sats() - if provider_data[1]: - sensor_suite.provides_accel = true - sensor_suite.create_accel() - if provider_data[2]: - sensor_suite.provides_gyro = true - sensor_suite.create_gyro() - if provider_data[3]: - sensor_suite.provides_mag = true - sensor_suite.create_mag() - add_child(sensor_suite) - vehicle.add_sensor_node(sensor_suite) +func _on_new_sensor_connected(sensor_ip: String, sensor_type: String) -> void: + var sensor_node: BaseSensorNode + if sensor_type == "VEHICLE": + sensor_node = VehicleSensorNode.new() + elif sensor_type == "LIDAR_2D": + sensor_node = Lidar2DSensorNode.new() + else: + return + sensor_node.ip_address = sensor_ip + add_child(sensor_node) + vehicle.add_sensor_node(sensor_node) diff --git a/sensors/sensor_suite.tscn b/sensors/sensor_suite.tscn index 3e67edd..1c26887 100644 --- a/sensors/sensor_suite.tscn +++ b/sensors/sensor_suite.tscn @@ -1,7 +1,3 @@ [gd_scene format=3 uid="uid://trl3gugdy3hw"] -[ext_resource type="Script" uid="uid://xm4wqedyteei" path="res://sensors/sensor_suite_node.gd" id="1_1i1as"] - [node name="SensorSuite" type="Node3D" unique_id=1330923752] -script = ExtResource("1_1i1as") -metadata/_custom_type_script = "uid://xm4wqedyteei" diff --git a/sensors/sensor_suite_node.gd b/sensors/sensor_suite_node.gd deleted file mode 100644 index e961f9f..0000000 --- a/sensors/sensor_suite_node.gd +++ /dev/null @@ -1,54 +0,0 @@ -extends Node3D -class_name SensorSuiteNode - - -@export var ip_address: String -var provides_pnt: bool = false -var provides_accel: bool = false -var provides_gyro: bool = false -var provides_mag: bool = false - -var sensors = {} - -""" - sensor_suite.provides_pnt = true - sensor_suite.create_pnt() - sensor_suite.create_sats() - if provider_data[1]: - sensor_suite.provides_accel = true - sensor_suite.create_accel() - if provider_data[2]: - sensor_suite.provides_gyro = true - sensor_suite.create_gyro() - if provider_data[3]: - sensor_suite.provides_mag = true - sensor_suite.create_mag() -""" - -func create_pnt(): - var sensor = PntSensorNode.new() - sensor.ip_address = ip_address - sensors[sensor.id] = sensor - add_child(sensor) - -func create_sats(): - var sensor = SatelliteSensorNode.new() - sensor.ip_address = ip_address - sensors[sensor.id] = sensor - add_child(sensor) - -func create_accel(): - var sensor = AccelSensorNode.new() - sensor.ip_address = ip_address - sensors[sensor.id] = sensor - add_child(sensor) - -func create_gyro(): - return - -func create_mag(): - var sensor = MagnetSensorNode.new() - sensor.ip_address = ip_address - sensors[sensor.id] = sensor - add_child(sensor) - diff --git a/sensors/sensor_suite_node.gd.uid b/sensors/sensor_suite_node.gd.uid deleted file mode 100644 index 3d1a671..0000000 --- a/sensors/sensor_suite_node.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://xm4wqedyteei diff --git a/sensors/vehicle_sensor_node.gd b/sensors/vehicle_sensor_node.gd new file mode 100644 index 0000000..b6ccdd8 --- /dev/null +++ b/sensors/vehicle_sensor_node.gd @@ -0,0 +1,293 @@ +extends BaseSensorNode +class_name VehicleSensorNode + +""" +Vehicle sensor can provide the following data fields: + - GPS + - Contributing satellites + - Accelerometer + - Magnetometer + - Gyroscope +""" + + +var max_data_length: int = 10 +var gps_timestamps = [] +var coordinates = [] +var gps_positions = [] +var altitudes = [] +var alt_coefficients = [] +var altitude_m: + get: + return _get_current_altitude() +var speed_data = [] +var speed_coefficients = [] +var speed_kmh: + get: + return _get_current_speed() + +static var DOWN = Vector2(0, -1.) +var accel_timestamps = [] +var g_vecs = [] +var linear_vecs = [] +var pitch_data = [] +var pitch_rad: float +var roll_data = [] +var roll_rad: float +var lateral_g_data = [] +var x_coefficients = [] +var y_coefficients = [] +var lateral_accel: + get: + return _get_current_gs() + +var mag_timestamps = [] +var mag_vecs = [] +var heading_data = [] +var heading_rad: float + + +func _ready() -> void: + super._ready() + DataSignals.raw_data_received.connect(_on_raw_data_received) + #DataSignals.sat_data_received.connect(_on_sat_data_received) + DataSignals.accelerometer_data_received.connect(_on_accel_data_received) + #DataSignals.gyroscope_data_received.connect(_on_gyro_data_received) + +func _get_sensor_class(): + return "VEHICLE" + +func _on_raw_data_received(source_ip: String, sensor_type: String, timestamp_list: Array, data: Array): + if source_ip != ip_address: + return + if sensor_type == "GPS": + var parsed_coordinates = [ + (float(data[0]) / 10.**9) - 90, + (float(data[1]) / 10.**9) - 180, + (float(data[2]) / 1000.), + (float(data[3]) / 100.), + ] + var speed = float(data[4]) / 1000000. + var dop = [ + float(data[5]) / 1000., + float(data[6]) / 1000., + float(data[7]) / 1000., + ] + _on_gps_data_received(timestamp_list, parsed_coordinates, speed, dop) + if sensor_type == "ACCEL": + var accel = Vector3( + float(data[0]) / 1000000., + float(data[1]) / 1000000., + float(data[2]) / 1000000. + ) + var linear_accel = Vector3( + float(data[3]) / 1000000., + float(data[4]) / 1000000., + float(data[5]) / 1000000. + ) + var g_accel = Vector3( + float(data[6]) / 1000000., + float(data[7]) / 1000000., + float(data[8]) / 1000000. + ) + _on_accel_data_received(timestamp_list, accel, linear_accel, g_accel) + +func _on_gps_data_received(timestamp_list: Array, new_coordinates: Array, speed: float, dop: Array): + # coordinates = [lat rad, lon rad, alt m, geoid diff m] + # dop = [pdop, hdop, vdop] + var timestamp: float = 3600.*timestamp_list[0] + 60.*timestamp_list[1] + timestamp_list[2] + timestamp_list[3] + if gps_timestamps.size() > 0 and (timestamp - gps_timestamps[-1]) < -1: + gps_timestamps.clear() + coordinates.clear() + gps_positions.clear() + altitudes.clear() + speed_data.clear() + if gps_timestamps.size() == max_data_length and not TimeHelpers.is_timestamp_newer_24h(gps_timestamps[-1], timestamp): + return + var insert_idx = Bisect.reverse_bisect(gps_timestamps, timestamp) + var altitude = new_coordinates[2] + new_coordinates[3] + var radius_km = (new_coordinates[2] + new_coordinates[3] + Constants.EARTH_RADIUS_M) / 1000. + var pos_x = radius_km * sin(new_coordinates[1]) * cos(new_coordinates[0]) + var pos_z = radius_km * sin(new_coordinates[1]) * sin(new_coordinates[0]) + var pos_y = radius_km * cos(new_coordinates[1]) + gps_timestamps.insert(insert_idx, timestamp) + coordinates.insert(insert_idx, [new_coordinates[0], new_coordinates[1]]) + gps_positions.insert(insert_idx, Vector3(pos_x, pos_y, pos_z)) + altitudes.insert(insert_idx, altitude) + speed_data.insert(insert_idx, speed) + if gps_timestamps.size() > max_data_length: + gps_timestamps.pop_back() + coordinates.pop_back() + gps_positions.pop_back() + altitudes.pop_back() + speed_data.pop_back() + _update_alt_coefficients() + _update_speed_coefficients() + +func _on_sat_data_received(source_ip: String, timestamp: float): + if source_ip != ip_address: + return + +func _on_accel_data_received(timestamp_list: Array, accel: Vector3, linear_accel: Vector3, g_accel: Vector3): + var timestamp: float = 3600.*timestamp_list[0] + 60.*timestamp_list[1] + timestamp_list[2] + timestamp_list[3] + if accel_timestamps.size() > 0 and (timestamp - accel_timestamps[-1]) < -1: + accel_timestamps.clear() + linear_vecs.clear() + g_vecs.clear() + pitch_data.clear() + roll_data.clear() + lateral_g_data.clear() + if accel_timestamps.size() == max_data_length and not TimeHelpers.is_timestamp_newer_24h(accel_timestamps[-1], timestamp): + return + var insert_idx = Bisect.reverse_bisect(accel_timestamps, timestamp) + var x_z = Vector2(g_accel.x, g_accel.z).normalized() + var y_z = Vector2(g_accel.y, g_accel.z).normalized() + var pitch = DOWN.angle_to(x_z) + var roll = y_z.angle_to(DOWN) + accel_timestamps.insert(insert_idx, timestamp) + linear_vecs.insert(insert_idx, linear_accel) + g_vecs.insert(insert_idx, g_accel) + pitch_data.insert(insert_idx, pitch) + roll_data.insert(insert_idx, roll) + var lateral_g = Vector2(linear_accel.x, linear_accel.y) + lateral_g_data.insert(insert_idx, lateral_g.normalized()*lateral_g.length()) + if accel_timestamps.size() > max_data_length: + accel_timestamps.pop_back() + linear_vecs.pop_back() + g_vecs.pop_back() + pitch_data.pop_back() + roll_data.pop_back() + lateral_g_data.pop_back() + _update_avg_pitch() + _update_avg_roll() + _update_g_coefficients() + +func _on_mag_data_received(source_ip: String, timestamp_list: Array, mag_vec: Vector3): + if source_ip != ip_address: + return + var timestamp: float = 3600.*timestamp_list[0] + 60.*timestamp_list[1] + timestamp_list[2] + timestamp_list[3] + if mag_timestamps.size() > 0 and (timestamp - mag_timestamps[-1]) < -1: + mag_timestamps.clear() + mag_vecs.clear() + heading_data.clear() + if mag_timestamps.size() == max_data_length and not TimeHelpers.is_timestamp_newer_24h(mag_timestamps[-1], timestamp): + return + var insert_idx = Bisect.reverse_bisect(mag_timestamps, timestamp) + var mag_2d = Vector2(mag_vec.x, mag_vec.y) + mag_2d.normalized() + var new_heading_rad = atan2(-mag_2d.y, mag_2d.x) + if new_heading_rad < 0: + new_heading_rad += 2*PI + mag_timestamps.insert(insert_idx, timestamp) + mag_vecs.insert(insert_idx, mag_vec) + heading_data.insert(insert_idx, new_heading_rad) + if mag_timestamps.size() > max_data_length: + mag_timestamps.pop_back() + mag_vecs.pop_back() + heading_data.pop_back() + +func _on_gyro_data_received(source_ip: String, timestamp: float): + if source_ip != ip_address: + return + +func get_derrivative(dataset: Array) -> Array: + if dataset.size() < 2: + return [0, []] + var deltas = [] + var delta_sum = 0 + for i in range(dataset.size()-1): + deltas.append(dataset[i+1] - dataset[i]) + return [float(delta_sum) / deltas.size(), deltas] + +func get_array_avg(dataset: Array): + var data_sum = 0 + for i in dataset: + data_sum += i + return data_sum / dataset.size() + +func get_coefficients(dataset: Array, order: int): + if order == 0: + return [] + if dataset.size() <= order: + order = dataset.size() - 1 + var coefficients = [] + var tmp_dataset = dataset + var dx_result: Array + for i in range(order): + dx_result = get_derrivative(tmp_dataset) + coefficients.append(dx_result[0]) + tmp_dataset = dx_result[1] + return coefficients + +func _update_alt_coefficients(): + if gps_timestamps.size() < 2: + return + alt_coefficients = get_coefficients(altitudes, 2) + +func _get_current_altitude(): + if gps_timestamps.size() < 3: + return null + var current_timestamp = TimeHelpers.get_current_sensor_time() + var time_diff = max(0, TimeHelpers.calc_time_diff_24h(gps_timestamps[0], current_timestamp)) + var current_value = altitudes[0] + for idx in range(alt_coefficients.size()): + current_value += alt_coefficients[idx] * (time_diff ** idx+1) + return current_value + +func _update_speed_coefficients(): + if gps_timestamps.size() < 2: + return + speed_coefficients = get_coefficients(speed_data, 2) + +func _get_current_speed(): + if gps_timestamps.size() < 3: + return + var current_timestamp = TimeHelpers.get_current_sensor_time() + var time_diff = max(0, TimeHelpers.calc_time_diff_24h(gps_timestamps[-1], current_timestamp)) + var current_value = speed_data[0] + for idx in range(speed_coefficients.size()): + current_value += speed_coefficients[idx] * (time_diff ** idx+1) + return current_value + +func _update_g_coefficients(): + if accel_timestamps.size() < 2: + return + var x_dataset = [] + var y_dataset = [] + for i in lateral_g_data: + x_dataset.append(i.x) + y_dataset.append(i.y) + x_coefficients = get_coefficients(x_dataset, 3) + y_coefficients = get_coefficients(y_dataset, 3) + +func _get_current_gs(): + if accel_timestamps.size() < 3: + return + var current_timestamp = TimeHelpers.get_current_sensor_time() + var time_diff = max(0, TimeHelpers.calc_time_diff_24h(accel_timestamps[0], current_timestamp)) + var current_x = lateral_g_data[0].x + var current_y = lateral_g_data[0].y + for idx in range(speed_coefficients.size()): + current_x += x_coefficients[idx] * (time_diff ** idx+1) + current_y += y_coefficients[idx] * (time_diff ** idx+1) + return Vector2(current_x, current_y) + +func _update_avg_pitch(): + var pitch_sum = 0 + for i in range(accel_timestamps.size()): + pitch_sum += pitch_data[i] + pitch_rad = pitch_sum / pitch_data.size() + +func _update_avg_roll(): + var roll_sum = 0 + for i in range(accel_timestamps.size()): + roll_sum += roll_data[i] + roll_rad = roll_sum / roll_data.size() + +func _update_avg_heading(): + var heading_sum = 0 + for i in range(min(mag_timestamps.size(), 2)): + heading_sum += heading_data[i] + heading_rad = heading_sum / heading_data.size() + + diff --git a/sensors/vehicle_sensor_node.gd.uid b/sensors/vehicle_sensor_node.gd.uid new file mode 100644 index 0000000..01f5661 --- /dev/null +++ b/sensors/vehicle_sensor_node.gd.uid @@ -0,0 +1 @@ +uid://c30nkkqcp0orm diff --git a/settings/SettingsMenu.tscn b/settings/SettingsMenu.tscn index cbfcb88..8ee194c 100644 --- a/settings/SettingsMenu.tscn +++ b/settings/SettingsMenu.tscn @@ -20,13 +20,13 @@ layout_mode = 1 layout_mode = 1 [node name="Panel" type="Panel" parent="." unique_id=546432251] -custom_minimum_size = Vector2(250, 200) +custom_minimum_size = Vector2(250, 250) layout_mode = 0 offset_right = 168.0 offset_bottom = 142.0 [node name="VBoxContainer" type="VBoxContainer" parent="Panel" unique_id=1651822305] -custom_minimum_size = Vector2(200, 10) +custom_minimum_size = Vector2(200, 0) layout_mode = 0 offset_left = 25.0 offset_top = 28.0 @@ -51,6 +51,15 @@ text = "Widget Settings" custom_minimum_size = Vector2(0, 4) layout_mode = 2 +[node name="Debug" type="Button" parent="Panel/VBoxContainer" unique_id=739815847] +custom_minimum_size = Vector2(0, 40) +layout_mode = 2 +text = "Debug Mode" + +[node name="Control3" type="Control" parent="Panel/VBoxContainer" unique_id=1091785659] +custom_minimum_size = Vector2(0, 4) +layout_mode = 2 + [node name="Close" type="Button" parent="Panel/VBoxContainer" unique_id=1184969381] custom_minimum_size = Vector2(0, 40) layout_mode = 2 diff --git a/signals/data_signals.gd b/signals/data_signals.gd index 9eb3f56..69eb675 100644 --- a/signals/data_signals.gd +++ b/signals/data_signals.gd @@ -1,7 +1,11 @@ extends Node -signal pnt_data_received(source_ip: String, timestamp_list: Array, coordinates: Array, speed_kmh: float, dop: Array) -signal sat_data_received(source_ip: String, timestamp_list: Array, sat_count: Array, sat_position: Array) -signal accelerometer_data_received(source_ip: String, timestamp_list: Array, accel: Array, linear_accel: Array, g_accel: Array) -signal magnetometer_data_received(source_ip: String, timestamp_list: Array, mag_vec: Array) +signal raw_data_received(source_ip: String, data_type: String, timestamp_list: Array, data: Array) +signal time_data_received(source_ip: String, timestamp_list: Array) +signal gps_data_received(source_ip: String, timestamp_list: Array, coordinates: Array, speed_kmh: float, dop: Array) +signal sat_data_received(source_ip: String, timestamp: float, sat_count: Array, sat_position: Array) +signal accelerometer_data_received(source_ip: String, timestamp: float, accel: Vector3, linear_accel: Vector3, g_accel: Vector3) +signal magnetometer_data_received(source_ip: String, timestamp: float, mag_vec: Vector3) +signal gyroscope_data_received(source_ip: String, timestamp: float, data: Array) +signal lidar_2d_data_received(sensor_ip: String, timestamp_list: Array, lidar_point_count: int, lidar_data: Array) diff --git a/signals/server_signals.gd b/signals/server_signals.gd index 005a0b3..0c80917 100644 --- a/signals/server_signals.gd +++ b/signals/server_signals.gd @@ -1,5 +1,5 @@ extends Node -signal sensor_request_received(sensor_ip_address: String, data_provided: Array) +signal sensor_request_received(sensor_ip_address: String, sensor_class: String) signal sensor_approved(sensor_ip_adress: String) signal sensor_declined(sensor_ip_address: String) diff --git a/vehicle/scripts/vehicle_node.gd b/vehicle/scripts/vehicle_node.gd index 14fd699..d7a1712 100644 --- a/vehicle/scripts/vehicle_node.gd +++ b/vehicle/scripts/vehicle_node.gd @@ -13,35 +13,44 @@ var UUID = preload('res://addons/uuid/uuid.gd') var host_id: String = '' @export var host: bool = true -var axis_scene_template: PackedScene = preload("res://axis/Axis.tscn") -var sensor_suites = {} +var sensor_nodes = {} var sensor_classes = { - "PNT": [], - "ACCEL": [], - "GYRO": [], - "MAG": [] + "VEHICLE": [], + "LIDAR_2D": [], } -var datetime_sensors = {} -var gps_sensors = {} -var accelerometer_sensors = {} -var gyro_sensors = {} -var magnet_sensors = {} -var current_timestamp = 0. -var lat_rad: float = 0. -var long_rad: float = 0. -var alt_km: float = 0. +var timer: float = 0. +static var timer_1: float = 1. -var position_3d: Vector3 = Vector3.ZERO +var altitude_m: float: + get: + return _get_altitude_m() -var heading_rad: float = 0. +var speed_kmh: float: + get: + return _get_speed_kmh() + +var roll_rad: float: + get: + return _get_roll_rad() + +var pitch_rad: float: + get: + return _get_pitch_rad() + +var lateral_accel: Vector2: + get: + return _get_lateral_accel() + +var heading_rad: float: + get: + return _get_heading_rad() # Called when the node enters the scene tree for the first time. func _ready() -> void: if host: _load_id() - Signals.position_updated.connect(_on_pnt_position_updated) print('VehicleNode ready') #var axis_scene = axis_scene_template.instantiate() #axis_scene.axis_length = 2. @@ -50,14 +59,10 @@ func _ready() -> void: # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta: float) -> void: - var time_dict = Time.get_time_dict_from_system(true) - var unix_time = Time.get_unix_time_from_system() - current_timestamp = time_dict["hour"] * 3600 + time_dict["minute"] * 60 + time_dict["second"] + pass func _physics_process(delta: float) -> void: pass - #_update_position() - #_update_rotation() func _load_id(): var file_path = "user://host_id.idf" @@ -71,51 +76,87 @@ func _load_id(): func _generate_id(): return UUID.new().as_string() + +func _get_altitude_m(): + var alt_sum: float = 0 + var alt_count: int = 0 + for sensor_ip in sensor_classes["VEHICLE"]: + var sensor_alt = sensor_nodes[sensor_ip].altitude_m + if sensor_alt == null: + continue + alt_sum += sensor_alt + alt_count += 1 + if alt_count == 0: + return 0 + return alt_sum / alt_count -func _update_position(): - var time_offset = 0. - var sensor_data_array = [] - for sensor_id in gps_sensors: - var sensor = sensor_suites[sensor_id] - var sensor_time_offset = Constants.calc_time_diff(sensor.gps_timestamp, current_timestamp) - time_offset += sensor_time_offset - sensor_data_array.append([sensor_time_offset, sensor.gps_position]) - var avg_position = Vector3.ZERO - for sensor_data in sensor_data_array: - avg_position += (sensor_data[0]/time_offset) * sensor_data[1] - position = avg_position - #print(position) - #print(position.length()) - var camera: Camera3D = get_node("/root/Main/Node3D/Camera3D") - camera.position = position + position.normalized() * 1 - if camera.position != position: - camera.look_at(position, Vector3(0, 1, 0)) +func _get_speed_kmh(): + var speed_sum: float = 0 + var speed_count: int = 0 + for sensor_ip in sensor_classes["VEHICLE"]: + var sensor_speed = sensor_nodes[sensor_ip].speed_kmh + if sensor_speed == null: + continue + speed_sum += sensor_speed + speed_count += 1 + if speed_count == 0: + return 0 + return speed_sum / speed_count + +func _get_roll_rad(): + var roll_sum: float = 0 + var roll_count: int = 0 + for sensor_ip in sensor_classes["VEHICLE"]: + var sensor_roll = sensor_nodes[sensor_ip].roll_rad + if sensor_roll == null: + continue + roll_sum += sensor_roll + roll_count += 1 + if roll_count == 0: + return 0 + return roll_sum / roll_count + +func _get_pitch_rad(): + var pitch_sum: float = 0 + var pitch_count: int = 0 + for sensor_ip in sensor_classes["VEHICLE"]: + var sensor_pitch= sensor_nodes[sensor_ip].pitch_rad + if sensor_pitch == null: + continue + pitch_sum += sensor_pitch + pitch_count += 1 + if pitch_count == 0: + return 0 + return pitch_sum / pitch_count -func _update_rotation(): - if position.length() == 0: +func _get_lateral_accel(): + var gs_sum: Vector2 = Vector2.ZERO + var gs_count: int = 0 + for sensor_ip in sensor_classes["VEHICLE"]: + var sensor_gs = sensor_nodes[sensor_ip].lateral_accel + if sensor_gs == null: + continue + gs_sum += sensor_gs + gs_count += 1 + if gs_count == 0: + return Vector2.ZERO + return gs_sum / gs_count + +func _get_heading_rad(): + var heading_sum: float = 0 + var heading_count: int = 0 + for sensor_ip in sensor_classes["VEHICLE"]: + var sensor_heading = sensor_nodes[sensor_ip].heading_rad + if sensor_heading == null: + continue + heading_sum += sensor_heading + heading_count += 1 + if heading_count == 0: + return 0 + return heading_sum / heading_count + +func add_sensor_node(sensor_node: BaseSensorNode): + sensor_nodes[sensor_node.ip_address] = sensor_node + if sensor_node.sensor_class not in sensor_classes: return - var down_vec = -1 * position.normalized() - var up_axis = Vector3(0, 1, 0) - up_axis = (up_axis * quaternion).normalized() - var rot_axis = down_vec.cross(up_axis).normalized() - var rot_deg = up_axis.angle_to(down_vec) - var rot_quat = Quaternion(rot_axis, rot_deg).normalized() - quaternion = (quaternion * rot_quat).normalized() - -func _on_pnt_position_updated(sensor_ip: String, sensor_position_3d: Vector3): - if sensor_ip not in sensor_suites: - return - if sensor_ip not in sensor_classes["PNT"]: - return - position_3d = sensor_position_3d - -func add_sensor_node(sensor_node: SensorSuiteNode): - sensor_suites[sensor_node.ip_address] = sensor_node - if sensor_node.provides_pnt: - sensor_classes["PNT"].append(sensor_node.ip_address) - if sensor_node.provides_accel: - sensor_classes["ACCEL"].append(sensor_node.ip_address) - if sensor_node.provides_gyro: - sensor_classes["GYRO"].append(sensor_node.ip_address) - if sensor_node.provides_mag: - sensor_classes["MAG"].append(sensor_node.ip_address) + sensor_classes[sensor_node.sensor_class].append(sensor_node.ip_address) diff --git a/vehicle/vehicle.tscn b/vehicle/vehicle.tscn index c7d4796..7e10a14 100644 --- a/vehicle/vehicle.tscn +++ b/vehicle/vehicle.tscn @@ -2,7 +2,6 @@ [ext_resource type="Script" uid="uid://d264hr5vl2kqv" path="res://vehicle/scripts/vehicle_node.gd" id="1_2o63x"] [ext_resource type="Script" uid="uid://bflafrhk4eq4w" path="res://sensors/sensor_spawner.gd" id="2_2fi1b"] -[ext_resource type="PackedScene" uid="uid://trl3gugdy3hw" path="res://sensors/sensor_suite.tscn" id="3_1ktiy"] [node name="Vehicle" type="Node3D" unique_id=1694630995] script = ExtResource("1_2o63x") @@ -10,5 +9,4 @@ metadata/_custom_type_script = "uid://d264hr5vl2kqv" [node name="SensorSpawner" type="Node3D" parent="." unique_id=1875871474] script = ExtResource("2_2fi1b") -sensor_scene = ExtResource("3_1ktiy") metadata/_custom_type_script = "uid://bflafrhk4eq4w" diff --git a/views/2d/View2D.tscn b/views/2d/View2D.tscn index 898ff1d..07086b8 100644 --- a/views/2d/View2D.tscn +++ b/views/2d/View2D.tscn @@ -1,6 +1,5 @@ [gd_scene format=3 uid="uid://c2yga5koqwo72"] -[ext_resource type="PackedScene" uid="uid://bbdbyjievjpsq" path="res://widgets/compass/compass_widget_scene.tscn" id="1_fyqef"] [ext_resource type="Script" uid="uid://ba7ta7jjrjuhg" path="res://views/2d/view_2d.gd" id="1_n6fjn"] [ext_resource type="PackedScene" uid="uid://b71kuj4yole3j" path="res://widgets/satellites/satellite_widget.tscn" id="2_3b2b5"] [ext_resource type="PackedScene" uid="uid://m14p8xxs14rf" path="res://widgets/altitude/altitude_widget.tscn" id="3_g6l6n"] @@ -8,16 +7,12 @@ [ext_resource type="PackedScene" uid="uid://c61d1lcpgyld" path="res://widgets/rotation/roll_widget.tscn" id="6_s8d37"] [ext_resource type="PackedScene" uid="uid://bosjd085m7dnh" path="res://widgets/rotation/pitch_widget.tscn" id="7_5f0oj"] [ext_resource type="PackedScene" uid="uid://c71ads44rsa4u" path="res://widgets/speed/speed_widget.tscn" id="8_5f0oj"] -[ext_resource type="PackedScene" uid="uid://c1tptpc2xsvix" path="res://widgets/network/network_widget.tscn" id="9_r0eod"] [node name="View2D" type="Node" unique_id=1186202682] script = ExtResource("1_n6fjn") [node name="HUD" type="CanvasLayer" parent="." unique_id=1826106128] -[node name="Compass" parent="HUD" unique_id=2062816665 instance=ExtResource("1_fyqef")] -position = Vector2(114.99999, 538.00006) - [node name="TotalSatCount" parent="HUD" unique_id=931018379 instance=ExtResource("2_3b2b5")] visible = false scale = Vector2(0.05, 0.05) @@ -65,10 +60,10 @@ scale = Vector2(0.05, 0.05) sat_category = "QZSS" [node name="AltitudeWidget" parent="HUD" unique_id=1004159593 instance=ExtResource("3_g6l6n")] -position = Vector2(243, 494) +position = Vector2(233, 479) [node name="AccelerometerWidget" parent="HUD" unique_id=1057256615 instance=ExtResource("4_qui0h")] -position = Vector2(675, 400) +position = Vector2(673, 302) [node name="RollWidget" parent="HUD" unique_id=1446458625 instance=ExtResource("6_s8d37")] position = Vector2(407, 267) @@ -78,6 +73,3 @@ position = Vector2(400, 101) [node name="SpeedWidget" parent="HUD" unique_id=186354912 instance=ExtResource("8_5f0oj")] position = Vector2(314, 613) - -[node name="NetworkWidget" parent="HUD" unique_id=864131213 instance=ExtResource("9_r0eod")] -position = Vector2(97, 134) diff --git a/views/2d/test_lidar.gd b/views/2d/test_lidar.gd new file mode 100644 index 0000000..4e7d117 --- /dev/null +++ b/views/2d/test_lidar.gd @@ -0,0 +1,39 @@ +extends Node2D + +var line: Line2D + +var points_angle = [] +var points_distance = [] +var timer_static = 60 +var timer = 0. + +# Called when the node enters the scene tree for the first time. +func _ready() -> void: + line = get_node('Line2D') + DataSignals.lidar_2d_data_received.connect(_on_lidar_data_received) + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +func _process(delta: float) -> void: + timer += delta + if timer > timer_static: + timer = 0 + points_angle.clear() + points_distance.clear() + for i in line.points: + print(i - Vector2(400, 400)) + print() + _update_line() + +func _on_lidar_data_received(sensor_ip: String, timestamp_list: Array, lidar_point_count: int, lidar_data: Array): + for point in lidar_data: + var insert_idx = Bisect.bisect(points_angle, point[0]) + points_angle.insert(insert_idx, point[0]) + points_distance.insert(insert_idx, point[1]) + +func _update_line(): + line.clear_points() + for idx in range(points_angle.size()): + var x = 4*points_distance[idx] * cos(deg_to_rad(points_angle[idx])) + 400 + var y = 4*points_distance[idx] * sin(deg_to_rad(points_angle[idx])) + 400 + line.add_point(Vector2(x, y)) diff --git a/views/2d/test_lidar.gd.uid b/views/2d/test_lidar.gd.uid new file mode 100644 index 0000000..c2a85de --- /dev/null +++ b/views/2d/test_lidar.gd.uid @@ -0,0 +1 @@ +uid://cei6fgt3rsc2c diff --git a/views/2d/test_lidar.tscn b/views/2d/test_lidar.tscn new file mode 100644 index 0000000..fe0aa13 --- /dev/null +++ b/views/2d/test_lidar.tscn @@ -0,0 +1,13 @@ +[gd_scene format=3 uid="uid://ch0lyqkkxaem"] + +[ext_resource type="Script" uid="uid://cei6fgt3rsc2c" path="res://views/2d/test_lidar.gd" id="1_8h8gx"] + +[node name="TestLidar" type="Node2D" unique_id=948964638] +script = ExtResource("1_8h8gx") + +[node name="Camera2D" type="Camera2D" parent="." unique_id=60160156] +position = Vector2(400, 400) + +[node name="Line2D" type="Line2D" parent="." unique_id=1424623383] +closed = true +width = 1.0 diff --git a/views/ViewController.gd b/views/ViewController.gd index bcc7528..b414b71 100644 --- a/views/ViewController.gd +++ b/views/ViewController.gd @@ -25,8 +25,7 @@ func _ready() -> void: func add_widget(widget_type: String, widget_position: Vector2, widget_scale: float): pass -func _on_sensor_request_received(sensor_ip, sensor_data): - print('here') +func _on_sensor_request_received(sensor_ip, sensor_class): _on_open_settings_pressed() func _on_sensor_approced(sensor_ip): diff --git a/widgets/accelerometer/accelerometer_widget.tscn b/widgets/accelerometer/accelerometer_widget.tscn index 7b7426f..29f068d 100644 --- a/widgets/accelerometer/accelerometer_widget.tscn +++ b/widgets/accelerometer/accelerometer_widget.tscn @@ -7,6 +7,16 @@ script = ExtResource("1_hqf45") metadata/_custom_type_script = "uid://cr4oydwvmm28y" +[node name="Label" type="Label" parent="." unique_id=749031600] +custom_minimum_size = Vector2(200, 0) +offset_left = -100.0 +offset_top = 90.0 +offset_right = 100.0 +offset_bottom = 178.0 +theme_override_font_sizes/font_size = 64 +text = "10.0 g" +horizontal_alignment = 1 + [node name="Panel" type="Panel" parent="." unique_id=1154284634] visible = false offset_left = -103.0 @@ -32,17 +42,13 @@ default_color = Color(0, 1, 0, 1) begin_cap_mode = 2 end_cap_mode = 2 -[node name="Label" type="Label" parent="." unique_id=749031600] -offset_right = 40.0 -offset_bottom = 23.0 - [node name="MovableControl" type="Control" parent="." unique_id=345939378 node_paths=PackedStringArray("move_target")] layout_mode = 3 anchors_preset = 0 offset_left = -103.0 offset_top = -103.0 offset_right = 106.0 -offset_bottom = 106.0 +offset_bottom = 183.0 mouse_filter = 1 script = ExtResource("2_pog3i") move_target = NodePath("..") diff --git a/widgets/accelerometer/scripts/accelerometer_widget_node.gd b/widgets/accelerometer/scripts/accelerometer_widget_node.gd index fb488bd..db08195 100644 --- a/widgets/accelerometer/scripts/accelerometer_widget_node.gd +++ b/widgets/accelerometer/scripts/accelerometer_widget_node.gd @@ -11,7 +11,6 @@ var origin: Vector2 = Vector2(0., 0.) # Called when the node enters the scene tree for the first time. func _ready() -> void: super._ready() - Signals.linear_acceleration_updated.connect(_on_linear_acceleration_updated) label = get_node('Label') accel_vector = get_node("AccelVector") accel_vector.points = [origin, origin] @@ -20,13 +19,14 @@ func _ready() -> void: y_vector = get_node("YVector") y_vector.points = [origin, origin] -func _on_linear_acceleration_updated(sensor_ip: String, linear_acceleration: Array): - var accel_vec = Vector2(-linear_acceleration[1], linear_acceleration[0]) - var vec_norm: Vector2 = accel_vec.normalized() - var vec_length: float = accel_vec.length() - var accel_g = vec_length / Constants.g - var x_vec = Vector2(vec_norm.x*vec_length, 0) - accel_vector.points = [origin, accel_vec * 10] - x_vector.points = [origin, x_vec * 10] - y_vector.points = [x_vec * 10, accel_vec * 10] - label.text = str(round(accel_g*100)/100) + ' g' +func _update_data(): + if y_vector == null: + return + var lateral_gs = host_vehicle.lateral_accel + var accel_g = lateral_gs.length() / Constants.g + var end_point = Vector2(lateral_gs.y, -lateral_gs.x) + var forward = Vector2(0, -lateral_gs.x) + accel_vector.points = [origin, end_point * 4] + x_vector.points = [forward * 4, end_point * 4] + y_vector.points = [origin, forward * 4] + label.text = str(round(accel_g*10)/10) + ' g' diff --git a/widgets/altitude/altitude_widget.tscn b/widgets/altitude/altitude_widget.tscn index 00eb41a..5479681 100644 --- a/widgets/altitude/altitude_widget.tscn +++ b/widgets/altitude/altitude_widget.tscn @@ -8,22 +8,22 @@ script = ExtResource("1_hmdxp") metadata/_custom_type_script = "uid://b3rfje1auw6to" [node name="Panel" type="Panel" parent="." unique_id=1393400967] -offset_right = 306.0 -offset_bottom = 70.0 +offset_right = 300.0 +offset_bottom = 120.0 [node name="Label" type="Label" parent="." unique_id=1070194714] -offset_right = 306.0 -offset_bottom = 70.0 -theme_override_font_sizes/font_size = 32 -text = "Altitude: 99999 ft" +offset_right = 300.0 +offset_bottom = 120.0 +theme_override_font_sizes/font_size = 64 +text = "99999 ft" horizontal_alignment = 1 vertical_alignment = 1 [node name="MovableControl" type="Control" parent="." unique_id=1186292353 node_paths=PackedStringArray("move_target")] layout_mode = 3 anchors_preset = 0 -offset_right = 306.0 -offset_bottom = 70.0 +offset_right = 300.0 +offset_bottom = 120.0 mouse_filter = 1 script = ExtResource("2_34sps") move_target = NodePath("..") diff --git a/widgets/altitude/scripts/altitude_widget_node.gd b/widgets/altitude/scripts/altitude_widget_node.gd index b98ca1a..b1f222b 100644 --- a/widgets/altitude/scripts/altitude_widget_node.gd +++ b/widgets/altitude/scripts/altitude_widget_node.gd @@ -10,7 +10,8 @@ func _ready() -> void: super._ready() label_node = get_node("Label") label_node.text = "0 ft" - Signals.altitude_updated.connect(_on_altitude_updated) - -func _on_altitude_updated(sensor_ip: String, altitude_km: float): - label_node.text = 'Altitude: ' + str(int(round(altitude_km * Constants.M2FT * 1000))) + ' ft' + +func _update_data(): + if label_node == null: + return + label_node.text = str(int(round(host_vehicle.altitude_m * Constants.M2FT))) + ' ft' diff --git a/widgets/base_widget_node.gd b/widgets/base_widget_node.gd index 3bf54f6..1c16258 100644 --- a/widgets/base_widget_node.gd +++ b/widgets/base_widget_node.gd @@ -6,16 +6,27 @@ var used_sensors: Dictionary = {} var host_vehicle: VehicleNode +var timer: float = 0. +static var timer_1_60: float = 1/60 + # Called when the node enters the scene tree for the first time. func _ready() -> void: Signals.vehicle_added.connect(_on_vehicle_added) Signals.requested_host_vehicle.emit(self) func _process(delta: float): + timer += delta if host_vehicle != null: + if timer < timer_1_60: + return + timer = 0 + _update_data() return Signals.requested_host_vehicle.emit(self) +func _update_data(): + pass + func _on_vehicle_added(new_vehicle): host_vehicle = new_vehicle diff --git a/widgets/compass/compass_widget_scene.tscn b/widgets/compass/compass_widget_scene.tscn index ed619d9..2aabe03 100644 --- a/widgets/compass/compass_widget_scene.tscn +++ b/widgets/compass/compass_widget_scene.tscn @@ -14,14 +14,20 @@ scale = Vector2(0.1, 0.1) texture = ExtResource("2_qf1yp") [node name="Label" type="Label" parent="." unique_id=338110309] +anchors_preset = 7 +anchor_left = 0.5 +anchor_top = 1.0 +anchor_right = 0.5 +anchor_bottom = 1.0 offset_left = -50.0 -offset_top = -350.0 +offset_top = -300.0 offset_right = 50.0 -offset_bottom = -150.0 +grow_horizontal = 2 +grow_vertical = 0 +pivot_offset = Vector2(50, 300) theme_override_font_sizes/font_size = 80 text = "N" horizontal_alignment = 1 -vertical_alignment = 1 justification_flags = 161 [node name="MovableControl" type="Control" parent="." unique_id=124696843 node_paths=PackedStringArray("move_target")] diff --git a/widgets/compass/scripts/compass_widget_node.gd b/widgets/compass/scripts/compass_widget_node.gd index 940103a..05d9620 100644 --- a/widgets/compass/scripts/compass_widget_node.gd +++ b/widgets/compass/scripts/compass_widget_node.gd @@ -5,6 +5,7 @@ class_name CompassWidgetNode @export_range(0., 359., 0.1) var north_deg = 0. var north_rad: float var indicator: Sprite2D +var label: Label # Called when the node enters the scene tree for the first time. func _ready() -> void: @@ -12,10 +13,32 @@ func _ready() -> void: if north_deg == null: north_deg = 0. north_rad = deg_to_rad(north_deg) - Signals.heading_updated.connect(_on_heading_updated) indicator = get_node("CompassIndicator") + label = get_node("Label") -func _on_heading_updated(sensor_ip: String, heading_rad: float): - if not check_valid_sensor(sensor_ip, "MAG"): +func _update_data(): + if label == null: return - indicator.rotation = north_rad + heading_rad + #label.rotation = -host_vehicle.heading_rad + label.text = get_direction_label(host_vehicle.heading_rad) + +func get_direction_label(heading_rad): + var heading_deg = rad_to_deg(heading_rad) + if 0 <= heading_deg and heading_deg <= 22.5: + return 'N' + elif 22.5 < heading_deg and heading_deg <= 67.5: + return "NE" + elif 67.5 < heading_deg and heading_deg <= 112.5: + return "E" + elif 112.5 < heading_deg and heading_deg <= 157.5: + return "SE" + elif 157.5 < heading_deg and heading_deg <= 202.5: + return "S" + elif 202.5 < heading_deg and heading_deg <= 247.5: + return "SW" + elif 247.5 < heading_deg and heading_deg <= 292.5: + return "W" + elif 292.5 < heading_deg and heading_deg <= 337.5: + return "NW" + else: + return "N" diff --git a/widgets/lidar_2d/lidar_2d.tscn b/widgets/lidar_2d/lidar_2d.tscn new file mode 100644 index 0000000..9e31a4a --- /dev/null +++ b/widgets/lidar_2d/lidar_2d.tscn @@ -0,0 +1,3 @@ +[gd_scene format=3 uid="uid://dhxuhkb8inhqa"] + +[node name="Lidar2d" type="Node3D" unique_id=679038150] diff --git a/widgets/network/scripts/network_widget_node.gd b/widgets/network/scripts/network_widget_node.gd index ce66780..a22c29c 100644 --- a/widgets/network/scripts/network_widget_node.gd +++ b/widgets/network/scripts/network_widget_node.gd @@ -1,6 +1,10 @@ extends BaseWidgetNode class_name NetworkWidgetNode +var network_timer = 0. +static var timer_1 = 1. + +var label: Node # Called when the node enters the scene tree for the first time. func _ready() -> void: @@ -13,7 +17,12 @@ func _ready() -> void: # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta: float) -> void: - var label = get_node("Label") + network_timer += delta + if network_timer < timer_1: + return + network_timer = 0 + if label == null: + return var label_text: String = '' for address in IP.get_local_addresses(): label_text += address + '\n' diff --git a/widgets/rotation/pitch_widget.tscn b/widgets/rotation/pitch_widget.tscn index 2d03bf0..a406171 100644 --- a/widgets/rotation/pitch_widget.tscn +++ b/widgets/rotation/pitch_widget.tscn @@ -26,7 +26,7 @@ offset_left = -50.0 offset_top = -22.0 offset_right = 50.0 offset_bottom = 23.0 -theme_override_font_sizes/font_size = 32 +theme_override_font_sizes/font_size = 48 horizontal_alignment = 1 [node name="Line2D" type="Line2D" parent="." unique_id=1285997474] diff --git a/widgets/rotation/roll_widget.tscn b/widgets/rotation/roll_widget.tscn index ae97ce8..a52683f 100644 --- a/widgets/rotation/roll_widget.tscn +++ b/widgets/rotation/roll_widget.tscn @@ -26,7 +26,7 @@ offset_left = -50.0 offset_top = -22.0 offset_right = 50.0 offset_bottom = 23.0 -theme_override_font_sizes/font_size = 32 +theme_override_font_sizes/font_size = 48 horizontal_alignment = 1 [node name="Line2D" type="Line2D" parent="." unique_id=1446923009] diff --git a/widgets/rotation/scripts/pitch_widget_node.gd b/widgets/rotation/scripts/pitch_widget_node.gd index 1c0d12a..b320bd5 100644 --- a/widgets/rotation/scripts/pitch_widget_node.gd +++ b/widgets/rotation/scripts/pitch_widget_node.gd @@ -8,11 +8,12 @@ var label: Label # Called when the node enters the scene tree for the first time. func _ready() -> void: - SensorSignals.pitch_updated.connect(_on_pitch_updated) sprite = get_node("Sprite2D") label = get_node("Label") var label_size = label.size -func _on_pitch_updated(sensor_ip: String, pitch_rad: float): - sprite.rotation = pitch_rad - label.text = str(round(rad_to_deg(pitch_rad)*10)/10) + " \u00B0" +func _update_data(): + if sprite == null or label == null: + return + sprite.rotation = host_vehicle.pitch_rad + label.text = str(int(rad_to_deg(host_vehicle.pitch_rad))) + " \u00B0" diff --git a/widgets/rotation/scripts/roll_widget_node.gd b/widgets/rotation/scripts/roll_widget_node.gd index b62ac80..db12227 100644 --- a/widgets/rotation/scripts/roll_widget_node.gd +++ b/widgets/rotation/scripts/roll_widget_node.gd @@ -7,11 +7,12 @@ var label: Label # Called when the node enters the scene tree for the first time. func _ready() -> void: - SensorSignals.roll_updated.connect(_on_roll_updated) sprite = get_node("Sprite2D") label = get_node("Label") var label_size = label.size -func _on_roll_updated(sensor_ip: String, roll_rad: float): - sprite.rotation = roll_rad - label.text = str(round(rad_to_deg(abs(roll_rad))*10)/10) + " \u00B0" +func _update_data(): + if sprite == null or label == null: + return + sprite.rotation = host_vehicle.roll_rad + label.text = str(abs(int(rad_to_deg(host_vehicle.roll_rad)))) + " \u00B0" diff --git a/widgets/satellites/scripts/satellite_widget_3d_node.gd b/widgets/satellites/scripts/satellite_widget_3d_node.gd index b527d6f..a5d430c 100644 --- a/widgets/satellites/scripts/satellite_widget_3d_node.gd +++ b/widgets/satellites/scripts/satellite_widget_3d_node.gd @@ -42,19 +42,6 @@ func set_host_vehicle(new_vehicle): vehicle_3d_node = Node3D.new() add_child(vehicle_3d_node) -func check_valid_sensor(sensor_ip: String, sensor_class: String): - if host_vehicle == null: - return false - if sensor_ip not in host_vehicle.sensors: - return false - if sensor_class == null: - return true - if sensor_class not in host_vehicle.sensor_classes: - return false - if sensor_ip not in host_vehicle.sensor_classes[sensor_class]: - return false - return true - func _on_sat_position_updated(sensor_ip: String, sat_position_data: Array): if vehicle_3d_node == null: return diff --git a/widgets/speed/scripts/speed_widget_node.gd b/widgets/speed/scripts/speed_widget_node.gd index 88af6ca..0b04ec3 100644 --- a/widgets/speed/scripts/speed_widget_node.gd +++ b/widgets/speed/scripts/speed_widget_node.gd @@ -3,19 +3,17 @@ class_name SpeedWidgetNode var K2MI = 0.6213712 -var speed_kmh: float -var speed_mph: float var label_node: Label # Called when the node enters the scene tree for the first time. func _ready() -> void: label_node = get_node("VBoxContainer/SpeedLabel") - SensorSignals.speed_updated.connect(_on_speed_updated) -func _on_speed_updated(ip_address: String, pnt_speed_kmh: float): - speed_kmh = pnt_speed_kmh - speed_mph = speed_kmh * K2MI +func _update_data(): + if label_node == null: + return + var speed_mph = host_vehicle.speed_kmh * K2MI var display_speed: int = 0 if speed_mph >= 1: display_speed = int(round(speed_mph)) diff --git a/widgets/speed/speed_widget.tscn b/widgets/speed/speed_widget.tscn index cffd42a..9842ab1 100644 --- a/widgets/speed/speed_widget.tscn +++ b/widgets/speed/speed_widget.tscn @@ -14,14 +14,14 @@ offset_bottom = 40.0 [node name="SpeedLabel" type="Label" parent="VBoxContainer" unique_id=2101712075] custom_minimum_size = Vector2(150, 0) layout_mode = 2 -theme_override_font_sizes/font_size = 48 +theme_override_font_sizes/font_size = 64 text = "10" horizontal_alignment = 1 [node name="UnitLabel" type="Label" parent="VBoxContainer" unique_id=123505815] custom_minimum_size = Vector2(100, 0) layout_mode = 2 -theme_override_font_sizes/font_size = 16 +theme_override_font_sizes/font_size = 26 text = "MPH" horizontal_alignment = 1